robosats/frontend/src/components/MakerForm/AutocompletePayments.js
Reckless_Satoshi 1dea4e73b6 Refactor and Init RoboSats PRO (#296)
commit 9c6d55cfc77d42471da3e865f2729167597868e5
Author: Reckless_Satoshi <reckless.satoshi@protonmail.com>
Date:   Thu Oct 20 10:35:49 2022 -0700

    Small fixes

commit 23d6c00ccb5e78593e768c36b866d02f26031e7b
Author: Reckless_Satoshi <reckless.satoshi@protonmail.com>
Date:   Thu Oct 20 06:12:42 2022 -0700

    Refactor frontend

commit b2c21d4a98c49f6168bc3ff6e6a3d7b9f8943a12
Author: Reckless_Satoshi <reckless.satoshi@protonmail.com>
Date:   Wed Oct 19 07:26:00 2022 -0700

    Small fixes (more)

commit 78a8ab799dc33e8f8b8f14e22e155bbc7104c3a9
Author: Reckless_Satoshi <reckless.satoshi@protonmail.com>
Date:   Wed Oct 19 02:11:03 2022 -0700

    Try out to revert depth chart

commit ef73c980a8cfc4ae760e720e3bca99acc30b7270
Author: Reckless_Satoshi <reckless.satoshi@protonmail.com>
Date:   Tue Oct 18 11:43:37 2022 -0700

    Small fixes

commit fa3e60208f8f292256dd90813e7beff15db3057a
Author: Reckless_Satoshi <reckless.satoshi@protonmail.com>
Date:   Tue Oct 18 09:43:03 2022 -0700

    Add old UserGen and BottomBar to new main.tsx

commit 1e257d1924df20e2fa4feb7f6afce4f31f2a9acc
Author: Reckless_Satoshi <reckless.satoshi@protonmail.com>
Date:   Tue Oct 18 04:01:53 2022 -0700

    Add Maker and Book page to new main.tsx

commit 037d46ceef34df09530e645a2e01c9fbd9b3efd4
Author: Reckless_Satoshi <reckless.satoshi@protonmail.com>
Date:   Mon Oct 17 08:54:55 2022 -0700

    Add Main component WIP

commit e43b274c33a75ab5050be360a3d01f655e1e8142
Author: Reckless_Satoshi <reckless.satoshi@protonmail.com>
Date:   Mon Oct 17 04:32:43 2022 -0700

    App as functional component
2022-10-20 11:06:16 -07:00

356 lines
9.8 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useState } from 'react';
import PropTypes from 'prop-types';
import { useTranslation } from 'react-i18next';
import { useAutocomplete } from '@mui/base/AutocompleteUnstyled';
import { styled } from '@mui/material/styles';
import { Button, Fade, Tooltip, Typography, Grow } from '@mui/material';
import { fiatMethods, swapMethods, PaymentIcon } from '../PaymentMethods';
// Icons
import DashboardCustomizeIcon from '@mui/icons-material/DashboardCustomize';
import CheckIcon from '@mui/icons-material/Check';
import CloseIcon from '@mui/icons-material/Close';
const Root = styled('div')(
({ theme }) => `
color: ${theme.palette.text.primary};
font-size: ${theme.typography.fontSize};
`,
);
const Label = styled('label')(
({ theme, error, sx }) => `
color: ${
theme.palette.mode === 'dark' ? (error ? '#f44336' : '#cfcfcf') : error ? '#dd0000' : '#717171'
};
pointer-events: none;
position: relative;
left: 1em;
top: ${sx.top};
maxHeight: 0em;
height: 0em;
white-space: no-wrap;
font-size: 1em;
`,
);
const InputWrapper = styled('div')(
({ theme, error, sx }) => `
min-height: ${sx.minHeight};
max-height: ${sx.maxHeight};
border: 1px solid ${
theme.palette.mode === 'dark' ? (error ? '#f44336' : '#434343') : error ? '#dd0000' : '#c4c4c4'
};
background-color: ${theme.palette.mode === 'dark' ? '#141414' : '#fff'};
border-radius: 4px;
border-color: ${sx.borderColor ? `border-color ${sx.borderColor}` : ''}
padding: 1px;
display: flex;
flex-wrap: wrap;
overflow-y:auto;
align-items: center;
&:hover {
border-color: ${
theme.palette.mode === 'dark'
? error
? '#f44336'
: sx.hoverBorderColor
: error
? '#dd0000'
: '#2f2f2f'
};
}
&.focused {
border: 2px solid ${
theme.palette.mode === 'dark'
? error
? '#f44336'
: '#90caf9'
: error
? '#dd0000'
: '#1976d2'
};
}
& input {
background-color: ${theme.palette.mode === 'dark' ? '#141414' : '#fff'};
color: ${theme.palette.mode === 'dark' ? 'rgba(255,255,255,0.65)' : 'rgba(0,0,0,.85)'};
height: 2.15em;
box-sizing: border-box;
padding: 4px 6px;
width: 0;
min-width: 2.15em;
font-size: ${theme.typography.fontSize * 1.0714};
flex-grow: 1;
border: 0;
margin: 0;
outline: 0;
max-height: 8.6em;
}
`,
);
function Tag(props) {
const { label, icon, onDelete, ...other } = props;
return (
<div {...other}>
<div style={{ position: 'relative', left: '-5px', top: '4px' }}>
<PaymentIcon width={22} height={22} icon={icon} />
</div>
<span style={{ position: 'relative', left: '2px' }}>{label}</span>
<CloseIcon onClick={onDelete} />
</div>
);
}
Tag.propTypes = {
label: PropTypes.string.isRequired,
icon: PropTypes.string.isRequired,
onDelete: PropTypes.func.isRequired,
};
const StyledTag = styled(Tag)(
({ theme, sx }) => `
display: flex;
align-items: center;
height: ${sx.height};
margin: 2px;
line-height: 1.5em;
background-color: ${theme.palette.mode === 'dark' ? 'rgba(255,255,255,0.08)' : '#fafafa'};
border: 1px solid ${theme.palette.mode === 'dark' ? '#303030' : '#e8e8e8'};
border-radius: 2px;
box-sizing: content-box;
padding: 0 4px 0 10px;
outline: 0;
overflow: hidden;
&:focus {
border-color: ${theme.palette.mode === 'dark' ? '#177ddc' : '#40a9ff'};
background-color: ${theme.palette.mode === 'dark' ? '#003b57' : '#e6f7ff'};
}
& span {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
font-size: 0.928em;
}
& svg {
font-size: 0.857em;
cursor: pointer;
padding: 4px;
}
`,
);
const ListHeader = styled('span')(
({ theme }) => `
color: ${theme.palette.mode === 'dark' ? '#90caf9' : '#1976d2'};
align: left;
line-height:10px;
max-height: 10px;
display: inline-block;
background-color: ${theme.palette.mode === 'dark' ? '#141414' : '#ffffff'};
font-size: 0.875em;
pointer-events: none;
`,
);
const Listbox = styled('ul')(
({ theme, sx }) => `
width: ${sx ? sx.width : '15.6em'};
margin: 2px 0 0;
padding: 0;
position: absolute;
list-style: none;
background-color: ${theme.palette.mode === 'dark' ? '#141414' : '#fff'};
overflow: auto;
max-height: 17em;
border-radius: 4px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
z-index: 999;
& li {
padding: 0em 0em;
display: flex;
& span {
flex-grow: 1;
}
& svg {
color: transparent;
}
}
& li[aria-selected='true'] {
background-color: ${theme.palette.mode === 'dark' ? '#2b2b2b' : '#fafafa'};
font-weight: 600;
& svg {
color: ${theme.palette.primary.main};
}
}
& li[data-focus='true'] {
background-color: ${theme.palette.mode === 'dark' ? '#003b57' : '#e6f7ff'};
cursor: pointer;
& svg {
color: currentColor;
}
}
`,
);
export default function AutocompletePayments(props) {
const { t } = useTranslation();
const {
getRootProps,
getInputLabelProps,
getInputProps,
getTagProps,
getListboxProps,
getOptionProps,
groupedOptions,
value,
focused = 'true',
setAnchorEl,
} = useAutocomplete({
fullWidth: true,
id: 'payment-methods',
multiple: true,
value: props.value,
options: props.optionsType == 'fiat' ? fiatMethods : swapMethods,
getOptionLabel: (option) => option.name,
onInputChange: (e) => setVal(e ? (e.target.value ? e.target.value : '') : ''),
onChange: (event, value) => props.onAutocompleteChange(value),
onClose: () => setVal(() => ''),
});
const [val, setVal] = useState('');
const fewerOptions = groupedOptions.length > 8 ? groupedOptions.slice(0, 8) : groupedOptions;
function handleAddNew(inputProps) {
fiatMethods.push({ name: inputProps.value, icon: 'custom' });
const a = value.push({ name: inputProps.value, icon: 'custom' });
setVal(() => '');
if (a || a == null) {
props.onAutocompleteChange(value);
}
return false;
}
return (
<Root>
<Tooltip
placement='top'
enterTouchDelay={props.tooltipTitle == '' ? 99999 : 300}
enterDelay={props.tooltipTitle == '' ? 99999 : 700}
enterNextDelay={2000}
title={props.tooltipTitle}
>
<div {...getRootProps()}>
<Fade
appear={false}
in={fewerOptions.length == 0 && value.length == 0 && val.length == 0}
>
<div style={{ height: 0, display: 'flex', alignItems: 'flex-start' }}>
<Label
{...getInputLabelProps()}
sx={{ top: '0.72em', ...(props.labelProps ? props.labelProps.sx : {}) }}
error={props.error ? 'error' : null}
>
{props.label}
</Label>
</div>
</Fade>
<InputWrapper
ref={setAnchorEl}
error={props.error ? 'error' : null}
className={focused ? 'focused' : ''}
sx={{
minHeight: '2.9em',
maxHeight: '8.6em',
hoverBorderColor: '#ffffff',
...props.sx,
}}
>
{value.map((option, index) => (
<StyledTag
label={t(option.name)}
icon={option.icon}
sx={{ height: '2.1em', ...(props.tagProps ? props.tagProps.sx : {}) }}
{...getTagProps({ index })}
/>
))}
{value.length > 0 && props.isFilter ? null : <input {...getInputProps()} value={val} />}
</InputWrapper>
</div>
</Tooltip>
<Grow in={fewerOptions.length > 0}>
<Listbox sx={props.listBoxProps ? props.listBoxProps.sx : undefined} {...getListboxProps()}>
{!props.isFilter ? (
<div
style={{
position: 'fixed',
minHeight: '1.428em',
marginLeft: `${3 - props.listHeaderText.length * 0.05}em`,
marginTop: '-0.928em',
}}
>
<ListHeader>
<i>{props.listHeaderText + ''} </i>{' '}
</ListHeader>
</div>
) : null}
{fewerOptions.map((option, index) => (
<li key={option.name} {...getOptionProps({ option, index })}>
<Button
fullWidth={true}
color='inherit'
size='small'
sx={{ textTransform: 'none' }}
style={{ justifyContent: 'flex-start' }}
>
<div style={{ padding: '0.286em', position: 'relative', top: '0.35em' }}>
<PaymentIcon width={22} height={22} icon={option.icon} />
</div>
<Typography variant='inherit' align='left'>
{t(option.name)}
</Typography>
</Button>
<div style={{ position: 'relative', top: '0.357em' }}>
<CheckIcon />
</div>
</li>
))}
{val != null || !props.isFilter ? (
val.length > 2 ? (
<Button size='small' fullWidth={true} onClick={() => handleAddNew(getInputProps())}>
<DashboardCustomizeIcon sx={{ width: '1em', height: '1em' }} />
{props.addNewButtonText}
</Button>
) : null
) : null}
</Listbox>
</Grow>
{/* Here goes what happens if there is no fewerOptions */}
<Grow in={getInputProps().value.length > 0 && !props.isFilter && fewerOptions.length === 0}>
<Listbox {...getListboxProps()}>
<Button fullWidth={true} onClick={() => handleAddNew(getInputProps())}>
<DashboardCustomizeIcon sx={{ width: '1.28em', height: '1.28em' }} />
{props.addNewButtonText}
</Button>
</Listbox>
</Grow>
</Root>
);
}