Skip to content

Commit

Permalink
Add a little X to the chains added from the other chains modal (#127)
Browse files Browse the repository at this point in the history
  • Loading branch information
portdeveloper authored Jul 2, 2024
1 parent bfdad70 commit 28f4977
Showing 1 changed file with 70 additions and 16 deletions.
86 changes: 70 additions & 16 deletions packages/nextjs/components/NetworksDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { getPopularTargetNetworks } from "~~/utils/scaffold-eth";
type Options = {
value: number | string;
label: string;
icon?: string | ReactNode;
icon: string | ReactNode;
isTestnet?: boolean;
};

Expand All @@ -36,7 +36,7 @@ const getIconComponent = (iconName: string | undefined) => {
};

const networks = getPopularTargetNetworks();
const groupedOptions = networks.reduce<GroupedOptions>(
const initialGroupedOptions = networks.reduce<GroupedOptions>(
(groups, network) => {
if (network.id === 31337) {
groups.localhost.options.push({
Expand Down Expand Up @@ -103,31 +103,61 @@ const mapChainsToOptions = (chains: Chain[]): Options[] => {
}));
};

const CUSTOM_CHAINS_LOCAL_STORAGE_KEY = "customChains";
const getStoredChains = (): Options[] => {
if (typeof window !== "undefined") {
const storedChains = localStorage.getItem("customChains");
const storedChains = localStorage.getItem(CUSTOM_CHAINS_LOCAL_STORAGE_KEY);
return storedChains ? JSON.parse(storedChains) : [];
}
return [];
};

const isChainStored = (chain: Options): boolean => {
const storedChains = getStoredChains();
return storedChains.some(storedChain => storedChain.value === chain.value);
};

const networkIds = new Set(networks.map(network => network.id));

const { Option } = components;
const IconOption = (props: OptionProps<Options>) => (
<Option {...props}>
<div className="flex items-center">
{typeof props.data.icon === "string" ? getIconComponent(props.data.icon) : props.data.icon}
{props.data.label}
</div>
</Option>
);

type CustomOptionProps = OptionProps<Options, false, { label: string; options: Options[] }> & {
onDelete: (chain: Options) => void;
};
const CustomOption = (props: CustomOptionProps) => {
const { data } = props;
const handleDelete = (e: React.MouseEvent) => {
e.stopPropagation();
props.onDelete(data);
};

return (
<Option {...props}>
<div className="flex items-center justify-between">
<div className="flex items-center">
{typeof data.icon === "string" ? getIconComponent(data.icon) : data.icon}
{data.label}
</div>

{isChainStored(data) && (
<div
className="h-4 w-4 text-red-500 cursor-pointer font-bold flex items-center justify-center"
onClick={handleDelete}
>
</div>
)}
</div>
</Option>
);
};

export const NetworksDropdown = ({ onChange }: { onChange: (options: any) => any }) => {
const [isMobile, setIsMobile] = useState(false);
const { resolvedTheme } = useTheme();
const [selectedOption, setSelectedOption] = useState<SingleValue<Options>>(groupedOptions.mainnet.options[0]);
const [selectedOption, setSelectedOption] = useState<SingleValue<Options>>(initialGroupedOptions.mainnet.options[0]);
const [searchTerm, setSearchTerm] = useState("");
const [groupedOptions, setGroupedOptions] = useState<GroupedOptions>(initialGroupedOptions);

const searchInputRef = useRef<HTMLInputElement>(null);
const seeAllModalRef = useRef<HTMLDialogElement>(null);
Expand All @@ -141,10 +171,11 @@ export const NetworksDropdown = ({ onChange }: { onChange: (options: any) => any
const customChains = getStoredChains();
customChains.forEach((chain: Options) => {
const groupName = chain.isTestnet ? "testnet" : "mainnet";
if (!groupedOptions[groupName].options.some(option => option.value === chain.value)) {
groupedOptions[groupName].options.push(chain);
if (!initialGroupedOptions[groupName].options.some(option => option.value === chain.value)) {
initialGroupedOptions[groupName].options.push(chain);
}
});
setGroupedOptions({ ...initialGroupedOptions });
}, []);

useEffect(() => {
Expand Down Expand Up @@ -176,7 +207,8 @@ export const NetworksDropdown = ({ onChange }: { onChange: (options: any) => any
groupedOptions[groupName].options.push(option);
}
const customChains = [...getStoredChains(), option];
localStorage.setItem("customChains", JSON.stringify(customChains));
localStorage.setItem(CUSTOM_CHAINS_LOCAL_STORAGE_KEY, JSON.stringify(customChains));
setGroupedOptions({ ...groupedOptions });
setSelectedOption(option);
onChange(option);
if (seeAllModalRef.current) {
Expand Down Expand Up @@ -206,6 +238,28 @@ export const NetworksDropdown = ({ onChange }: { onChange: (options: any) => any
`${chain.label} ${chain.value}`.toLowerCase().includes(searchTerm.toLowerCase()),
);

const handleDeleteCustomChain = (chain: Options) => {
const updatedChains = getStoredChains().filter((c: Options) => c.value !== chain.value);

if (typeof window !== "undefined") {
localStorage.setItem(CUSTOM_CHAINS_LOCAL_STORAGE_KEY, JSON.stringify(updatedChains));
}

const updatedGroupedOptions = { ...groupedOptions };
Object.keys(updatedGroupedOptions).forEach(groupName => {
updatedGroupedOptions[groupName as keyof GroupedOptions].options = updatedGroupedOptions[
groupName as keyof GroupedOptions
].options.filter(option => option.value !== chain.value);
});

setGroupedOptions(updatedGroupedOptions);

if (selectedOption?.value === chain.value) {
setSelectedOption(updatedGroupedOptions.mainnet.options[0]);
onChange(updatedGroupedOptions.mainnet.options[0]);
}
};

if (!mounted) return <div className="skeleton bg-neutral max-w-xs w-44 relative h-[38px]" />;

return (
Expand All @@ -216,7 +270,7 @@ export const NetworksDropdown = ({ onChange }: { onChange: (options: any) => any
instanceId="network-select"
options={Object.values(groupedOptions)}
onChange={handleSelectChange}
components={{ Option: IconOption }}
components={{ Option: props => <CustomOption {...props} onDelete={handleDeleteCustomChain} /> }}
isSearchable={!isMobile}
className="max-w-xs relative text-sm w-44"
theme={theme => ({
Expand Down

0 comments on commit 28f4977

Please sign in to comment.