robosats/frontend/src/components/MakerForm/AutocompletePayments.js
Reckless_Satoshi a4a3dbb95e Add RoboSats PRO frame as react layout grid playground (#299)
* Add react layout grid playground

* Add BookWidget and style

* Rename basic.js back to main.js
2022-10-22 14:32:33 +00:00

360 lines
10 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, useTheme } 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: 2em;
box-sizing: border-box;
padding: 0.28em 0.4em;
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 theme = useTheme();
const { label, icon, onDelete, ...other } = props;
const iconSize = 1.5 * theme.typography.fontSize;
return (
<div {...other}>
<div style={{ position: 'relative', left: '-5px', top: '0.28em' }}>
<PaymentIcon width={iconSize} height={iconSize} 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 0.28em 0 0.65em;
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: 0.28em;
}
`,
);
const ListHeader = styled('span')(
({ theme }) => `
color: ${theme.palette.mode === 'dark' ? '#90caf9' : '#1976d2'};
align: left;
line-height:0.7em;
max-height: 10.7em;
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;
const theme = useTheme();
const iconSize = 1.5 * theme.typography.fontSize;
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={iconSize} height={iconSize} 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>
);
}