Skip to content

Commit 5352913

Browse files
author
CsB-Polymesh
committed
code cleanup by Claude
1 parent 4601058 commit 5352913

20 files changed

Lines changed: 890 additions & 574 deletions

src/layouts/SecondaryKeys/components/AddPermission/components/AssetPermissionSelector.tsx

Lines changed: 104 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import styled from 'styled-components';
33
import { AssetContext } from '~/context/AssetContext';
44
import { Icon } from '~/components';
55
import { formatUuid, stringToColor } from '~/helpers/formatters';
6+
import { formatAssetDisplay } from '../../../utils';
67

78
interface IAssetPermissionSelectorProps {
89
selectedAssets: string[];
@@ -192,6 +193,45 @@ const SelectedAssetsList = styled.div`
192193
margin-top: 12px;
193194
`;
194195

196+
const SelectedAssetsHeader = styled.div`
197+
display: flex;
198+
align-items: center;
199+
justify-content: space-between;
200+
margin-top: 12px;
201+
`;
202+
203+
const SelectedAssetsCount = styled.span`
204+
font-size: 14px;
205+
font-weight: 500;
206+
color: ${({ theme }) => theme.colors.textPrimary};
207+
`;
208+
209+
const ClearAllButton = styled.button`
210+
display: flex;
211+
align-items: center;
212+
justify-content: center;
213+
gap: 4px;
214+
padding: 0 12px;
215+
background-color: transparent;
216+
font-weight: 500;
217+
font-size: 14px;
218+
color: ${({ theme }) => theme.colors.textPink};
219+
border: none;
220+
cursor: pointer;
221+
transition: color 250ms ease-out;
222+
223+
&:hover:not(:disabled) {
224+
color: ${({ theme }) => theme.colors.textBlue};
225+
}
226+
227+
&:disabled {
228+
color: ${({ theme }) => theme.colors.textDisabled};
229+
cursor: not-allowed;
230+
}
231+
`;
232+
233+
const SelectedAssetsContainer = styled.div``;
234+
195235
const SelectedAssetItem = styled.div`
196236
display: flex;
197237
align-items: center;
@@ -358,6 +398,10 @@ export const AssetPermissionSelector = ({
358398
}
359399
};
360400

401+
const handleClearAll = () => {
402+
onChange([]);
403+
};
404+
361405
return (
362406
<>
363407
<SelectWrapper ref={ref}>
@@ -386,28 +430,32 @@ export const AssetPermissionSelector = ({
386430
onChange={(e) => setSearchQuery(e.target.value)}
387431
onClick={(e) => e.stopPropagation()}
388432
/>
389-
{assetsLoading ? (
433+
{assetsLoading && (
390434
<StyledOption $selected={false}>Loading assets...</StyledOption>
391-
) : filteredAssets.length > 0 ? (
392-
filteredAssets.map((asset) => (
393-
<StyledOption
394-
key={asset.id}
395-
$selected={selectedAssets.includes(asset.id)}
396-
onClick={() => handleToggle(asset.id)}
397-
>
398-
<IconWrapper $background={stringToColor(asset.id)}>
399-
<Icon name="Coins" size="16px" />
400-
</IconWrapper>
401-
<div style={{ flex: 1 }}>
402-
{formatUuid(asset.id)} - {asset.name}
403-
{asset.ticker && ` (${asset.ticker})`}
404-
</div>
405-
{selectedAssets.includes(asset.id) && (
406-
<Icon name="Check" size="16px" />
407-
)}
408-
</StyledOption>
409-
))
410-
) : (
435+
)}
436+
{!assetsLoading && filteredAssets.length > 0 && (
437+
<>
438+
{filteredAssets.map((asset) => (
439+
<StyledOption
440+
key={asset.id}
441+
$selected={selectedAssets.includes(asset.id)}
442+
onClick={() => handleToggle(asset.id)}
443+
>
444+
<IconWrapper $background={stringToColor(asset.id)}>
445+
<Icon name="Coins" size="16px" />
446+
</IconWrapper>
447+
<div style={{ flex: 1 }}>
448+
{formatUuid(asset.id)} - {asset.name}
449+
{asset.ticker && ` (${asset.ticker})`}
450+
</div>
451+
{selectedAssets.includes(asset.id) && (
452+
<Icon name="Check" size="16px" />
453+
)}
454+
</StyledOption>
455+
))}
456+
</>
457+
)}
458+
{!assetsLoading && filteredAssets.length === 0 && (
411459
<StyledOption $selected={false}>
412460
{searchQuery ? 'No assets found' : 'No assets available'}
413461
</StyledOption>
@@ -440,27 +488,41 @@ export const AssetPermissionSelector = ({
440488
</AssetIdSection>
441489

442490
{selectedAssets.length > 0 && (
443-
<SelectedAssetsList>
444-
{selectedAssets.map((assetId) => {
445-
const asset = allAssets.find((a) => a.id === assetId);
446-
const displayText = asset
447-
? `${formatUuid(asset.id)}${asset.ticker ? ` (${asset.ticker})` : ''}`
448-
: formatUuid(assetId);
449-
450-
return (
451-
<SelectedAssetItem key={assetId}>
452-
{displayText}
453-
<RemoveButton
454-
type="button"
455-
onClick={() => handleToggle(assetId)}
456-
aria-label="Remove asset"
457-
>
458-
<Icon name="CloseIcon" size="12px" />
459-
</RemoveButton>
460-
</SelectedAssetItem>
461-
);
462-
})}
463-
</SelectedAssetsList>
491+
<SelectedAssetsContainer>
492+
<SelectedAssetsHeader>
493+
<SelectedAssetsCount>
494+
{selectedAssets.length} asset
495+
{selectedAssets.length === 1 ? '' : 's'} selected
496+
</SelectedAssetsCount>
497+
<ClearAllButton
498+
type="button"
499+
onClick={handleClearAll}
500+
disabled={selectedAssets.length === 0}
501+
aria-label="Clear all selected assets"
502+
>
503+
Clear All
504+
<Icon name="Delete" size="14px" />
505+
</ClearAllButton>
506+
</SelectedAssetsHeader>
507+
<SelectedAssetsList>
508+
{selectedAssets.map((assetId) => {
509+
const displayText = formatAssetDisplay(assetId, allAssets);
510+
511+
return (
512+
<SelectedAssetItem key={assetId}>
513+
{displayText}
514+
<RemoveButton
515+
type="button"
516+
onClick={() => handleToggle(assetId)}
517+
aria-label="Remove asset"
518+
>
519+
<Icon name="CloseIcon" size="12px" />
520+
</RemoveButton>
521+
</SelectedAssetItem>
522+
);
523+
})}
524+
</SelectedAssetsList>
525+
</SelectedAssetsContainer>
464526
)}
465527
</>
466528
);
Lines changed: 47 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,7 @@
1-
import { useCallback } from 'react';
2-
import {
3-
FormSection,
4-
RadioGroup,
5-
RadioOption,
6-
RadioLabel,
7-
RadioTitle,
8-
RadioDescription,
9-
SelectWrapper,
10-
Label,
11-
} from '../styles';
1+
import { useMemo } from 'react';
2+
import { GenericPermissionSelector } from './GenericPermissionSelector';
123
import { AssetPermissionSelector } from './AssetPermissionSelector';
4+
import { PermissionType } from '../../../types';
135

146
interface IAssetsPermissionsProps {
157
value: {
@@ -23,102 +15,57 @@ interface IAssetsPermissionsProps {
2315
validationError?: string;
2416
}
2517

18+
const ASSET_RADIO_OPTIONS = [
19+
{
20+
type: 'Whole' as PermissionType,
21+
title: 'Full access to all assets',
22+
description: 'The key can interact with all current and future assets',
23+
},
24+
{
25+
type: 'These' as PermissionType,
26+
title: 'Access to specific assets only',
27+
description: 'Select which assets the key can interact with',
28+
},
29+
{
30+
type: 'Except' as PermissionType,
31+
title: 'Access to all except specific assets',
32+
description: 'The key can access all assets except the ones you specify',
33+
},
34+
] as const;
35+
36+
const AssetSelectorWrapper = ({
37+
selectedItems,
38+
onChange: onItemsChange,
39+
}: {
40+
selectedItems: string[];
41+
onChange: (items: string[]) => void;
42+
}) => (
43+
<AssetPermissionSelector
44+
selectedAssets={selectedItems}
45+
onChange={onItemsChange}
46+
/>
47+
);
48+
2649
export const AssetsPermissions = ({
2750
value,
2851
onChange,
2952
validationError,
3053
}: IAssetsPermissionsProps) => {
31-
const handleTypeChange = useCallback(
32-
(type: 'Whole' | 'These' | 'Except' | 'None') => {
33-
onChange(type, type === 'Whole' ? [] : value.values);
34-
},
35-
[onChange, value.values],
36-
);
37-
38-
const handleAssetsChange = useCallback(
39-
(assets: string[]) => {
40-
onChange(value.type, assets);
41-
},
42-
[onChange, value.type],
54+
const selectorLabel = useMemo(
55+
() => (type: PermissionType) =>
56+
type === 'These' ? 'Select assets to allow' : 'Select assets to exclude',
57+
[],
4358
);
4459

4560
return (
46-
<FormSection>
47-
<RadioGroup>
48-
<RadioOption>
49-
<input
50-
type="radio"
51-
name="assetsPermission"
52-
checked={value.type === 'Whole'}
53-
onChange={() => handleTypeChange('Whole')}
54-
/>
55-
<RadioLabel>
56-
<RadioTitle>Full access to all assets</RadioTitle>
57-
<RadioDescription>
58-
The key can interact with all current and future assets
59-
</RadioDescription>
60-
</RadioLabel>
61-
</RadioOption>
62-
63-
<RadioOption>
64-
<input
65-
type="radio"
66-
name="assetsPermission"
67-
checked={value.type === 'These'}
68-
onChange={() => handleTypeChange('These')}
69-
/>
70-
<RadioLabel>
71-
<RadioTitle>Access to specific assets only</RadioTitle>
72-
<RadioDescription>
73-
Select which assets the key can interact with
74-
</RadioDescription>
75-
</RadioLabel>
76-
</RadioOption>
77-
78-
<RadioOption>
79-
<input
80-
type="radio"
81-
name="assetsPermission"
82-
checked={value.type === 'Except'}
83-
onChange={() => handleTypeChange('Except')}
84-
/>
85-
<RadioLabel>
86-
<RadioTitle>Access to all except specific assets</RadioTitle>
87-
<RadioDescription>
88-
The key can access all assets except the ones you specify
89-
</RadioDescription>
90-
</RadioLabel>
91-
</RadioOption>
92-
</RadioGroup>
93-
94-
{(value.type === 'These' || value.type === 'Except') && (
95-
<SelectWrapper>
96-
<Label>
97-
{value.type === 'These'
98-
? 'Select assets to allow'
99-
: 'Select assets to exclude'}
100-
</Label>
101-
<AssetPermissionSelector
102-
selectedAssets={value.values}
103-
onChange={handleAssetsChange}
104-
/>
105-
{validationError && value.type === 'Except' && (
106-
<div
107-
style={{
108-
padding: '12px',
109-
marginTop: '12px',
110-
backgroundColor: 'rgba(220, 53, 69, 0.1)',
111-
border: '1px solid rgba(220, 53, 69, 0.3)',
112-
borderRadius: '4px',
113-
color: '#dc3545',
114-
fontSize: '14px',
115-
}}
116-
>
117-
{validationError}
118-
</div>
119-
)}
120-
</SelectWrapper>
121-
)}
122-
</FormSection>
61+
<GenericPermissionSelector
62+
value={value}
63+
onChange={onChange}
64+
validationError={validationError}
65+
fieldName="assets"
66+
radioOptions={ASSET_RADIO_OPTIONS}
67+
selectorLabel={selectorLabel}
68+
SelectorComponent={AssetSelectorWrapper}
69+
/>
12370
);
12471
};

0 commit comments

Comments
 (0)