mirror of
https://github.com/RoboSats/robosats.git
synced 2025-01-31 02:21:35 +00:00
Makes filtering by multiple payment methods in desktop possible (#1172)
* Make the payments autocomplete header text independant on isFilter prop * makes filtering by MULTIPLE PAYMENT METHODS possible without great impact in the current experience on DESKTOP only --------- Co-authored-by: Reckless_Satoshi <90936742+Reckless-Satoshi@users.noreply.github.com>
This commit is contained in:
parent
2b5bc9062e
commit
09f70c493b
@ -229,9 +229,10 @@ const BookControl = ({
|
|||||||
helperText={''}
|
helperText={''}
|
||||||
label={fav.currency === 1000 ? t('DESTINATION') : t('METHOD')}
|
label={fav.currency === 1000 ? t('DESTINATION') : t('METHOD')}
|
||||||
tooltipTitle=''
|
tooltipTitle=''
|
||||||
listHeaderText=''
|
|
||||||
addNewButtonText=''
|
addNewButtonText=''
|
||||||
isFilter={true}
|
isFilter={true}
|
||||||
|
multiple={true}
|
||||||
|
optionsDisplayLimit={1}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
) : null}
|
) : null}
|
||||||
|
@ -11,6 +11,7 @@ import {
|
|||||||
useTheme,
|
useTheme,
|
||||||
type SxProps,
|
type SxProps,
|
||||||
type Theme,
|
type Theme,
|
||||||
|
Chip,
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import { fiatMethods, swapMethods, PaymentIcon } from '../PaymentMethods';
|
import { fiatMethods, swapMethods, PaymentIcon } from '../PaymentMethods';
|
||||||
|
|
||||||
@ -114,8 +115,8 @@ const InputWrapper = styled('div')(
|
|||||||
|
|
||||||
interface TagProps {
|
interface TagProps {
|
||||||
label: string;
|
label: string;
|
||||||
icon: string;
|
icon?: string;
|
||||||
onDelete: () => void;
|
onDelete?: () => void;
|
||||||
onClick: () => void;
|
onClick: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,22 +125,53 @@ const Tag: React.FC<TagProps> = ({ label, icon, onDelete, onClick, ...other }) =
|
|||||||
const iconSize = 1.5 * theme.typography.fontSize;
|
const iconSize = 1.5 * theme.typography.fontSize;
|
||||||
return (
|
return (
|
||||||
<div {...other}>
|
<div {...other}>
|
||||||
|
{icon ? (
|
||||||
<div style={{ position: 'relative', left: '-5px', top: '0.28em' }} onClick={onClick}>
|
<div style={{ position: 'relative', left: '-5px', top: '0.28em' }} onClick={onClick}>
|
||||||
<PaymentIcon width={iconSize} height={iconSize} icon={icon} />
|
<PaymentIcon width={iconSize} height={iconSize} icon={icon} />
|
||||||
</div>
|
</div>
|
||||||
|
) : null}
|
||||||
<span style={{ position: 'relative', left: '2px' }} onClick={onClick}>
|
<span style={{ position: 'relative', left: '2px' }} onClick={onClick}>
|
||||||
{label}
|
{label}
|
||||||
</span>
|
</span>
|
||||||
<CloseIcon onClick={onDelete} />
|
<CloseIcon className='delete-icon' onClick={onDelete} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const StyledChip = styled(Chip)(
|
||||||
|
({ theme, sx }) => `
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
height: ${String(sx?.height ?? '1.6rem')};
|
||||||
|
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;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
);
|
||||||
|
|
||||||
const StyledTag = styled(Tag)(
|
const StyledTag = styled(Tag)(
|
||||||
({ theme, sx }) => `
|
({ theme, sx }) => `
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
height: ${String(sx?.height ?? '2.1em')};
|
height: ${String(sx?.height ?? '1.6rem')};
|
||||||
margin: 2px;
|
margin: 2px;
|
||||||
line-height: 1.5em;
|
line-height: 1.5em;
|
||||||
background-color: ${theme.palette.mode === 'dark' ? 'rgba(255,255,255,0.08)' : '#fafafa'};
|
background-color: ${theme.palette.mode === 'dark' ? 'rgba(255,255,255,0.08)' : '#fafafa'};
|
||||||
@ -244,11 +276,19 @@ interface AutocompletePaymentsProps {
|
|||||||
sx: SxProps<Theme>;
|
sx: SxProps<Theme>;
|
||||||
addNewButtonText: string;
|
addNewButtonText: string;
|
||||||
isFilter: boolean;
|
isFilter: boolean;
|
||||||
|
multiple: number;
|
||||||
|
optionsDisplayLimit?: number;
|
||||||
listHeaderText: string;
|
listHeaderText: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const AutocompletePayments: React.FC<AutocompletePaymentsProps> = (props) => {
|
const AutocompletePayments: React.FC<AutocompletePaymentsProps> = (props) => {
|
||||||
|
// ** State
|
||||||
|
const [val, setVal] = useState('');
|
||||||
|
const [showFilterInput, setShowFilterInput] = useState(false);
|
||||||
|
|
||||||
|
// ** Hooks
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const filterInputRef = React.useRef<HTMLInputElement>(null);
|
||||||
const {
|
const {
|
||||||
getRootProps,
|
getRootProps,
|
||||||
getInputLabelProps,
|
getInputLabelProps,
|
||||||
@ -258,7 +298,7 @@ const AutocompletePayments: React.FC<AutocompletePaymentsProps> = (props) => {
|
|||||||
getOptionProps,
|
getOptionProps,
|
||||||
groupedOptions,
|
groupedOptions,
|
||||||
value,
|
value,
|
||||||
focused = true,
|
popupOpen,
|
||||||
setAnchorEl,
|
setAnchorEl,
|
||||||
} = useAutocomplete({
|
} = useAutocomplete({
|
||||||
fullWidth: true,
|
fullWidth: true,
|
||||||
@ -266,19 +306,23 @@ const AutocompletePayments: React.FC<AutocompletePaymentsProps> = (props) => {
|
|||||||
multiple: true,
|
multiple: true,
|
||||||
value: props.value,
|
value: props.value,
|
||||||
options: props.optionsType === 'fiat' ? fiatMethods : swapMethods,
|
options: props.optionsType === 'fiat' ? fiatMethods : swapMethods,
|
||||||
|
open: props.isFilter ? showFilterInput : undefined,
|
||||||
getOptionLabel: (option) => option.name,
|
getOptionLabel: (option) => option.name,
|
||||||
onInputChange: (e) => {
|
onInputChange: (e) => {
|
||||||
setVal(e?.target?.value ?? '');
|
if (e?.target) setVal(e?.target?.value ?? '');
|
||||||
},
|
},
|
||||||
onChange: (event, value) => {
|
onChange: (event, value) => {
|
||||||
|
if (props.isFilter) setShowFilterInput(false);
|
||||||
props.onAutocompleteChange(value);
|
props.onAutocompleteChange(value);
|
||||||
},
|
},
|
||||||
|
onOpen: () => {
|
||||||
|
if (props.isFilter) setShowFilterInput(true);
|
||||||
|
},
|
||||||
onClose: () => {
|
onClose: () => {
|
||||||
setVal(() => '');
|
setVal(() => '');
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const [val, setVal] = useState('');
|
|
||||||
const fewerOptions = groupedOptions.length > 8 ? groupedOptions.slice(0, 8) : groupedOptions;
|
const fewerOptions = groupedOptions.length > 8 ? groupedOptions.slice(0, 8) : groupedOptions;
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const iconSize = 1.5 * theme.typography.fontSize;
|
const iconSize = 1.5 * theme.typography.fontSize;
|
||||||
@ -293,6 +337,21 @@ const AutocompletePayments: React.FC<AutocompletePaymentsProps> = (props) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const tagsToDisplay = value.length
|
||||||
|
? props.optionsDisplayLimit
|
||||||
|
? value.slice(0, props.optionsDisplayLimit)
|
||||||
|
: value
|
||||||
|
: [];
|
||||||
|
|
||||||
|
const qttHiddenTags = props.optionsDisplayLimit ? value.length - props.optionsDisplayLimit : 0;
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (showFilterInput && props.isFilter) {
|
||||||
|
filterInputRef.current?.focus();
|
||||||
|
document.getElementById('payment-methods')?.focus();
|
||||||
|
}
|
||||||
|
}, [showFilterInput]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Root>
|
<Root>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
@ -320,31 +379,70 @@ const AutocompletePayments: React.FC<AutocompletePaymentsProps> = (props) => {
|
|||||||
<InputWrapper
|
<InputWrapper
|
||||||
ref={setAnchorEl}
|
ref={setAnchorEl}
|
||||||
error={Boolean(props.error)}
|
error={Boolean(props.error)}
|
||||||
className={focused ? 'focused' : ''}
|
className={popupOpen ? 'focused' : ''}
|
||||||
sx={{
|
sx={{
|
||||||
minHeight: '2.9em',
|
minHeight: '2.9em',
|
||||||
maxHeight: '8.6em',
|
maxHeight: '8.6em',
|
||||||
hoverBorderColor: '#ffffff',
|
hoverBorderColor: '#ffffff',
|
||||||
...props.sx,
|
...props.sx,
|
||||||
}}
|
}}
|
||||||
|
onClick={(evt) => {
|
||||||
|
if (props.isFilter) {
|
||||||
|
if (evt.target instanceof HTMLElement && !evt.target.matches('.delete-icon')) {
|
||||||
|
// Check if click is not on delete
|
||||||
|
setShowFilterInput(!showFilterInput);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{value.map((option, index) => (
|
{!showFilterInput || !props.isFilter ? (
|
||||||
|
<>
|
||||||
|
{tagsToDisplay.map((option, index) => (
|
||||||
<StyledTag
|
<StyledTag
|
||||||
key={index}
|
key={index}
|
||||||
label={t(option.name)}
|
label={t(option.name)}
|
||||||
icon={option.icon}
|
icon={option.icon}
|
||||||
onClick={props.onClick}
|
onClick={props.onClick}
|
||||||
sx={{ height: '2.1em', ...(props.tagProps ?? {}) }}
|
sx={{ height: '1.6rem', ...(props.tagProps ?? {}) }}
|
||||||
{...getTagProps({ index })}
|
{...getTagProps({ index })}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
{value.length > 0 && props.isFilter ? null : <input {...getInputProps()} value={val} />}
|
{qttHiddenTags > 0 ? (
|
||||||
|
<StyledChip
|
||||||
|
sx={{ borderRadius: 1 }}
|
||||||
|
label={`+${qttHiddenTags}`}
|
||||||
|
sx={{ height: '1.6rem' }}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
|
{value.length > 0 && !props.multiple ? null : (
|
||||||
|
<input
|
||||||
|
ref={filterInputRef}
|
||||||
|
autoFocus={true}
|
||||||
|
style={
|
||||||
|
props.isFilter
|
||||||
|
? {
|
||||||
|
position: 'absolute',
|
||||||
|
backgroundColor: 'transparent',
|
||||||
|
display: showFilterInput ? 'block' : 'none',
|
||||||
|
width: '166px',
|
||||||
|
}
|
||||||
|
: {}
|
||||||
|
}
|
||||||
|
{...getInputProps()}
|
||||||
|
value={val}
|
||||||
|
onBlur={() => {
|
||||||
|
if (props.isFilter) setShowFilterInput(false);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</InputWrapper>
|
</InputWrapper>
|
||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Grow in={fewerOptions.length > 0}>
|
<Grow in={fewerOptions.length > 0}>
|
||||||
<Listbox sx={props.listBoxProps?.sx ?? undefined} {...getListboxProps()}>
|
<Listbox sx={props.listBoxProps?.sx ?? undefined} {...getListboxProps()}>
|
||||||
{!props.isFilter ? (
|
{props.listHeaderText ? (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
position: 'fixed',
|
position: 'fixed',
|
||||||
|
@ -880,7 +880,8 @@ const MakerForm = ({
|
|||||||
)}
|
)}
|
||||||
listHeaderText={t('You can add new methods')}
|
listHeaderText={t('You can add new methods')}
|
||||||
addNewButtonText={t('Add New')}
|
addNewButtonText={t('Add New')}
|
||||||
asFilter={false}
|
isFilter={false}
|
||||||
|
multiple={true}
|
||||||
value={maker.paymentMethods}
|
value={maker.paymentMethods}
|
||||||
/>
|
/>
|
||||||
{maker.badPaymentMethod && (
|
{maker.badPaymentMethod && (
|
||||||
|
Loading…
Reference in New Issue
Block a user