Files
tom goriunovandGitHub f0e713b877 Add support for customizing the UI color theme (#2923)
* UI customizations: new features

Fixes #2905

* colors for graphs

* introduce env variable

* colors for topbar, stats, selected state and tabs

* fix build

* fix validator

* refactor link.primary.hover color token

* refactor selected colors

* update styles for switch and fix some color tokens

* change color for selectable controls

* icon color tokens refactoring

* UI customizations: new features

Fixes #2905

* test for common components

* tweaks

* migrate from color-mode-hex cookie to color-theme cookie

* clean up

* update screenshots

* more screenshot updates

* update default color of chart line

* update envs for mega eth
2025-08-19 11:58:05 +02:00

105 lines
3.5 KiB
TypeScript

import { Box, Text, HStack, Flex } from '@chakra-ui/react';
import { useMutation } from '@tanstack/react-query';
import React, { useCallback, useState } from 'react';
import type { WatchlistAddress } from 'types/api/account';
import useApiFetch from 'lib/api/useApiFetch';
import { Skeleton } from 'toolkit/chakra/skeleton';
import { Switch } from 'toolkit/chakra/switch';
import { Tag } from 'toolkit/chakra/tag';
import { toaster } from 'toolkit/chakra/toaster';
import ListItemMobile from 'ui/shared/ListItemMobile/ListItemMobile';
import TableItemActionButtons from 'ui/shared/TableItemActionButtons';
import WatchListAddressItem from './WatchListAddressItem';
interface Props {
item: WatchlistAddress;
isLoading?: boolean;
onEditClick: (data: WatchlistAddress) => void;
onDeleteClick: (data: WatchlistAddress) => void;
hasEmail: boolean;
}
const WatchListItem = ({ item, isLoading, onEditClick, onDeleteClick, hasEmail }: Props) => {
const [ notificationEnabled, setNotificationEnabled ] = useState(item.notification_methods.email);
const [ switchDisabled, setSwitchDisabled ] = useState(false);
const onItemEditClick = useCallback(() => {
return onEditClick(item);
}, [ item, onEditClick ]);
const onItemDeleteClick = useCallback(() => {
return onDeleteClick(item);
}, [ item, onDeleteClick ]);
const apiFetch = useApiFetch();
const showErrorToast = useCallback(() => {
toaster.error({
title: 'Error',
description: 'There has been an error processing your request',
});
}, [ ]);
const showNotificationToast = useCallback((isOn: boolean) => {
toaster.success({
title: 'Success',
description: isOn ? 'Email notification is ON' : 'Email notification is OFF',
});
}, [ ]);
const { mutate } = useMutation<WatchlistAddress>({
mutationFn: () => {
setSwitchDisabled(true);
const body = { ...item, notification_methods: { email: !notificationEnabled } };
setNotificationEnabled(prevState => !prevState);
return apiFetch('general:watchlist', {
pathParams: { id: String(item.id) },
fetchParams: { method: 'PUT', body },
}) as Promise<WatchlistAddress>;
},
onError: () => {
showErrorToast();
setNotificationEnabled(prevState => !prevState);
setSwitchDisabled(false);
},
onSuccess: (data) => {
setSwitchDisabled(false);
showNotificationToast(data.notification_methods.email);
},
});
const onSwitch = useCallback(() => {
return mutate();
}, [ mutate ]);
return (
<ListItemMobile>
<Box maxW="100%">
<WatchListAddressItem item={ item } isLoading={ isLoading }/>
<HStack gap={ 3 } mt={ 6 }>
<Text textStyle="sm" fontWeight={ 500 }>Private tag</Text>
<Tag loading={ isLoading } truncated>{ item.name }</Tag>
</HStack>
</Box>
<Flex alignItems="center" justifyContent="space-between" mt={ 6 } w="100%">
<HStack gap={ 3 }>
<Text textStyle="sm" fontWeight={ 500 }>Email notification</Text>
<Skeleton loading={ isLoading } display="inline-block">
<Switch
checked={ notificationEnabled }
onCheckedChange={ onSwitch }
aria-label="Email notification"
disabled={ !hasEmail || switchDisabled }
/>
</Skeleton>
</HStack>
<TableItemActionButtons onDeleteClick={ onItemDeleteClick } onEditClick={ onItemEditClick } isLoading={ isLoading }/>
</Flex>
</ListItemMobile>
);
};
export default WatchListItem;