[FEAT] doen not work: regacto of the Chakra-ui 3.3 ==> very bad port

This commit is contained in:
Edouard DUPIN 2025-01-12 22:36:30 +01:00
parent eb5a366a12
commit b6896a68c9
68 changed files with 4961 additions and 3327 deletions

View File

@ -1,6 +1,6 @@
{ {
"display": "2025-01-06", "display": "__DEVELOPMENT__",
"version": "0.0.1-dev\n - 2025-01-06T00:49:52+01:00", "version": "__VERSION__",
"commit": "0.0.1-dev\n", "commit": "__COMMIT__",
"date": "2025-01-06T00:49:52+01:00" "date": "__DATE__"
} }

View File

@ -13,7 +13,7 @@
}, },
"scripts": { "scripts": {
"update_packages": "ncu --target minor", "update_packages": "ncu --target minor",
"upgrade_packages": "ncu --upgrade --rejectVersion \"/^[~^<>]| - |\\.x$/\" ", "upgrade_packages": "ncu --upgrade ",
"install_dependency": "pnpm install", "install_dependency": "pnpm install",
"test": "vitest run", "test": "vitest run",
"test:watch": "vitest watch", "test:watch": "vitest watch",
@ -29,46 +29,49 @@
"*.{ts,tsx,js,jsx,json}": "prettier --write" "*.{ts,tsx,js,jsx,json}": "prettier --write"
}, },
"dependencies": { "dependencies": {
"@chakra-ui/anatomy": "~2.2.2", "@ark-ui/react": "4.8.0",
"@chakra-ui/cli": "~2.4.1", "@chakra-ui/anatomy": "2.3.4",
"@chakra-ui/react": "~2.8.2", "@chakra-ui/cli": "3.3.0",
"@chakra-ui/theme-tools": "~2.2.6", "@chakra-ui/react": "3.3.0",
"@dnd-kit/core": "6.3.1", "@dnd-kit/core": "6.3.1",
"@dnd-kit/modifiers": "9.0.0", "@dnd-kit/modifiers": "9.0.0",
"@dnd-kit/sortable": "10.0.0", "@dnd-kit/sortable": "10.0.0",
"@dnd-kit/utilities": "3.2.2", "@dnd-kit/utilities": "3.2.2",
"@emotion/react": "11.14.0", "@emotion/react": "11.14.0",
"@emotion/styled": "11.14.0", "@emotion/styled": "11.14.0",
"@formiz/core": "^2.4.5",
"@formiz/validations": "^2.0.1",
"allotment": "1.20.2", "allotment": "1.20.2",
"css-mediaquery": "0.1.2", "css-mediaquery": "0.1.2",
"dayjs": "1.11.13", "dayjs": "1.11.13",
"history": "5.3.0", "history": "5.3.0",
"react": "18.3.1", "react": "19.0.0",
"react-color-palette": "7.3.0", "react-color-palette": "7.3.0",
"react-currency-input-field": "3.9.0", "react-currency-input-field": "3.9.0",
"react-custom-scrollbars": "4.2.1", "react-custom-scrollbars": "4.2.1",
"react-day-picker": "9.5.0", "react-day-picker": "9.5.0",
"react-dom": "18.3.1", "react-dom": "19.0.0",
"react-error-boundary": "4.0.13", "react-error-boundary": "5.0.0",
"react-focus-lock": "2.13.2", "react-focus-lock": "2.13.5",
"react-icons": "5.3.0", "react-icons": "5.4.0",
"react-popper": "2.3.0", "react-popper": "2.3.0",
"react-router-dom": "6.26.2", "react-router-dom": "7.1.1",
"react-select": "5.9.0", "react-select": "5.9.0",
"react-simple-keyboard": "3.8.33", "react-simple-keyboard": "3.8.35",
"react-sticky-el": "2.1.1", "react-sticky-el": "2.1.1",
"react-use": "17.6.0", "react-use": "17.6.0",
"react-use-draggable-scroll": "0.4.7", "react-use-draggable-scroll": "0.4.7",
"react-virtuoso": "4.12.3", "react-virtuoso": "4.12.3",
"ts-pattern": "5.6.0", "ts-pattern": "5.6.0",
"uuid": "11.0.4", "uuid": "11.0.5",
"zod": "3.24.1", "zod": "3.24.1",
"zustand": "5.0.2" "zustand": "5.0.3"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "7.26.0",
"@babel/eslint-parser": "7.26.5",
"@babel/parser": "7.26.5",
"@babel/plugin-syntax-object-rest-spread": "7.8.3",
"@chakra-ui/styled-system": "^2.12.0", "@chakra-ui/styled-system": "^2.12.0",
"@locator/babel-jsx": "^0.4.4",
"@playwright/test": "1.49.1", "@playwright/test": "1.49.1",
"@storybook/addon-actions": "8.4.7", "@storybook/addon-actions": "8.4.7",
"@storybook/addon-essentials": "8.4.7", "@storybook/addon-essentials": "8.4.7",
@ -83,13 +86,13 @@
"@trivago/prettier-plugin-sort-imports": "5.2.1", "@trivago/prettier-plugin-sort-imports": "5.2.1",
"@types/jest": "29.5.14", "@types/jest": "29.5.14",
"@types/node": "22.10.5", "@types/node": "22.10.5",
"@types/react": "18.3.8", "@types/react": "19.0.5",
"@types/react-dom": "18.3.0", "@types/react-dom": "19.0.3",
"@types/react-sticky-el": "1.0.7", "@types/react-sticky-el": "1.0.7",
"@typescript-eslint/eslint-plugin": "8.19.0", "@typescript-eslint/eslint-plugin": "8.19.1",
"@typescript-eslint/parser": "8.19.0", "@typescript-eslint/parser": "8.19.1",
"@vitejs/plugin-react": "4.3.4", "@vitejs/plugin-react": "4.3.4",
"eslint": "9.17.0", "eslint": "9.18.0",
"eslint-plugin-codeceptjs": "1.3.0", "eslint-plugin-codeceptjs": "1.3.0",
"eslint-plugin-import": "2.31.0", "eslint-plugin-import": "2.31.0",
"eslint-plugin-react": "7.37.3", "eslint-plugin-react": "7.37.3",
@ -97,16 +100,16 @@
"eslint-plugin-storybook": "0.11.2", "eslint-plugin-storybook": "0.11.2",
"jest": "29.7.0", "jest": "29.7.0",
"jest-environment-jsdom": "29.7.0", "jest-environment-jsdom": "29.7.0",
"knip": "5.41.1", "knip": "5.42.0",
"lint-staged": "15.3.0", "lint-staged": "15.3.0",
"npm-check-updates": "^17.1.13", "npm-check-updates": "^17.1.13",
"prettier": "3.4.2", "prettier": "3.4.2",
"puppeteer": "23.11.1", "puppeteer": "24.0.0",
"react-is": "19.0.0", "react-is": "19.0.0",
"storybook": "8.4.7", "storybook": "8.4.7",
"ts-node": "10.9.2", "ts-node": "10.9.2",
"typescript": "5.7.2", "typescript": "5.7.3",
"vite": "6.0.7", "vite": "6.0.7",
"vitest": "2.1.8" "vitest": "2.1.8"
} }
} }

5986
front/pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -1,29 +1,34 @@
import { useState } from 'react'; import { useState } from 'react';
import { ChakraProvider, Select } from '@chakra-ui/react';
import { import {
Box, Box,
Button, Button,
Modal, ChakraProvider,
ModalBody, DialogBody,
ModalCloseButton, DialogContent,
ModalContent, DialogFooter,
ModalFooter, DialogHeader,
ModalHeader, DialogRoot,
ModalOverlay, DialogTrigger,
SelectContent,
SelectItem,
SelectRoot,
SelectTrigger,
SelectValueText,
Stack, Stack,
Text, Text,
defaultSystem,
useDisclosure, useDisclosure,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { environment } from '@/environment'; import { environment } from '@/environment';
import { App as SpaApp } from '@/scene/App'; import { App as SpaApp } from '@/scene/App';
import { USERS } from '@/service/session'; import { USERS, USERS_COLLECTION } from '@/service/session';
import theme from '@/theme';
import { hashLocalData } from '@/utils/sso'; import { hashLocalData } from '@/utils/sso';
import { Toaster } from './components/toaster';
const AppEnvHint = () => { const AppEnvHint = () => {
const modal = useDisclosure(); const dialog = useDisclosure();
const [selectUserTest, setSelectUserTest] = useState<string>('NO_USER'); const [selectUserTest, setSelectUserTest] = useState<string>('NO_USER');
//const setUser = useRightsStore((store) => store.setUser); //const setUser = useRightsStore((store) => store.setUser);
const buildEnv = const buildEnv =
@ -40,7 +45,7 @@ const AppEnvHint = () => {
setSelectUserTest(selectedOption.target.value); setSelectUserTest(selectedOption.target.value);
}; };
const onClose = () => { const onClose = () => {
modal.onClose(); dialog.onClose();
if (selectUserTest == 'NO_USER') { if (selectUserTest == 'NO_USER') {
window.location.href = `/${environment.applName}/sso/${hashLocalData()}/false/__LOGOUT__`; window.location.href = `/${environment.applName}/sso/${hashLocalData()}/false/__LOGOUT__`;
} else { } else {
@ -61,7 +66,7 @@ const AppEnvHint = () => {
as="button" as="button"
cursor="pointer" cursor="pointer"
data-test-id="devtools" data-test-id="devtools"
onClick={modal.onOpen} onClick={dialog.onOpen}
> >
<Text <Text
position="fixed" position="fixed"
@ -80,37 +85,46 @@ const AppEnvHint = () => {
{envName.join(' : ')} {envName.join(' : ')}
</Text> </Text>
</Box> </Box>
<Modal isOpen={modal.isOpen} onClose={modal.onClose}> <DialogRoot open={dialog.open} onOpenChange={dialog.onClose}>
<ModalOverlay /> <DialogContent>
<ModalContent> <DialogHeader>Outils développeurs</DialogHeader>
<ModalHeader>Outils développeurs</ModalHeader> <DialogTrigger asChild>
<ModalCloseButton /> <Button variant="outline" size="sm">
<ModalBody> {dialog.open ? "Close" : "Open"} Dialog
</Button>
</DialogTrigger>
<DialogBody>
<Stack> <Stack>
<Text>Utilisateur</Text> <Text>User</Text>
<Select placeholder="Select test user" onChange={handleChange}> <SelectRoot onChange={handleChange} collection={USERS_COLLECTION}>
{Object.keys(USERS).map((key) => ( <SelectTrigger>
<option value={key} key={key}> <SelectValueText placeholder="Select test user" />
{key} </SelectTrigger>
</option> <SelectContent>
))} {USERS_COLLECTION.items.map((value) => (
</Select> <SelectItem item={value} key={value.value}>
{value.label}
</SelectItem>
))}
</SelectContent>
</SelectRoot>
</Stack> </Stack>
</ModalBody> </DialogBody>
<ModalFooter> <DialogFooter>
<Button onClick={onClose}>Apply</Button> <Button onClick={onClose}>Apply</Button>
</ModalFooter> </DialogFooter>
</ModalContent> </DialogContent>
</Modal> </DialogRoot>
</> </>
); );
}; };
const App = () => { const App = () => {
return ( return (
<ChakraProvider theme={theme}> <ChakraProvider value={defaultSystem}>
<AppEnvHint /> <AppEnvHint />
<SpaApp /> <SpaApp />
<Toaster />
</ChakraProvider> </ChakraProvider>
); );
}; };

View File

@ -2,25 +2,21 @@ import { SyntheticEvent, useEffect, useRef, useState } from 'react';
import { import {
Box, Box,
Button,
Flex, Flex,
IconButton, IconButton,
Slider, Slider,
SliderFilledTrack, SliderRoot,
SliderThumb, SliderThumb,
SliderTrack, SliderTrack,
Text, Text,
position,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { import {
MdCheck,
MdFastForward, MdFastForward,
MdFastRewind, MdFastRewind,
MdGraphicEq, MdGraphicEq,
MdLooksOne, MdLooksOne,
MdNavigateBefore, MdNavigateBefore,
MdNavigateNext, MdNavigateNext,
MdOutlinePlayArrow,
MdPause, MdPause,
MdPlayArrow, MdPlayArrow,
MdRepeat, MdRepeat,
@ -65,7 +61,7 @@ const formatTime = (time) => {
return '00:00'; return '00:00';
}; };
export const AudioPlayer = ({}: AudioPlayerProps) => { export const AudioPlayer = ({ }: AudioPlayerProps) => {
const { mode } = useThemeMode(); const { mode } = useThemeMode();
const { playTrackList, trackOffset, previous, next, first } = const { playTrackList, trackOffset, previous, next, first } =
useActivePlaylistService(); useActivePlaylistService();
@ -202,7 +198,7 @@ export const AudioPlayer = ({}: AudioPlayerProps) => {
console.log(`onTimeUpdate ${audioRef.current.currentTime}`); console.log(`onTimeUpdate ${audioRef.current.currentTime}`);
setTimeProgress(audioRef.current.currentTime); setTimeProgress(audioRef.current.currentTime);
}; };
const onDurationChange = (event) => {}; const onDurationChange = (event) => { };
const onChangeStateToPlay = () => { const onChangeStateToPlay = () => {
setIsPlaying(true); setIsPlaying(true);
}; };
@ -230,59 +226,56 @@ export const AudioPlayer = ({}: AudioPlayerProps) => {
direction="column" direction="column"
> >
<Text <Text
align="left" alignContent="left"
fontSize="20px" fontSize="20px"
fontWeight="bold" fontWeight="bold"
userSelect="none" userSelect="none"
marginRight="auto" marginRight="auto"
overflow="hidden" overflow="hidden"
noOfLines={1} // noOfLines={1}
> >
{dataTrack?.name ?? '???'} {dataTrack?.name ?? '???'}
</Text> </Text>
<Text <Text
align="left" alignContent="left"
fontSize="16px" fontSize="16px"
userSelect="none" userSelect="none"
marginRight="auto" marginRight="auto"
overflow="hidden" overflow="hidden"
noOfLines={1} // noOfLines={1}
> >
{dataArtists.map((data) => data.name).join(', ')} /{' '} {dataArtists.map((data) => data.name).join(', ')} /{' '}
{dataAlbum && dataAlbum?.name} {dataAlbum && dataAlbum?.name}
{dataGender && ` / ${dataGender.name}`} {dataGender && ` / ${dataGender.name}`}
</Text> </Text>
<Box width="full" paddingX="15px"> <Box width="full" paddingX="15px">
<Slider <Slider.Root
aria-label="slider-ex-4" defaultValue={[0]}
defaultValue={0} value={[timeProgress]}
value={timeProgress}
min={0} min={0}
max={duration} max={duration}
step={0.1} step={0.1}
onChange={onSeek} onChange={onSeek}
focusThumbOnChange={false} variant="outline"
// focusThumbOnChange={false}
> >
<SliderTrack bg="gray.200" height="10px" borderRadius="full"> <SliderTrack bg="gray.200" height="10px" borderRadius="full">
<SliderFilledTrack bg="brand.600" /> {/* <SliderFilledTrack bg="brand.600" /> */}
</SliderTrack> </SliderTrack>
<SliderThumb boxSize={6}> </Slider.Root>
<Box color="brand.600" as={MdGraphicEq} />
</SliderThumb>
</Slider>
</Box> </Box>
<Flex> <Flex>
<Text <Text
align="left" alignContent="left"
fontSize="16px" fontSize="16px"
userSelect="none" userSelect="none"
marginRight="auto" marginRight="auto"
overflow="hidden" overflow="hidden"
noOfLines={1} // noOfLines={1}
> >
{formatTime(timeProgress)} {formatTime(timeProgress)}
</Text> </Text>
<Text align="left" fontSize="16px" userSelect="none"> <Text alignContent="left" fontSize="16px" userSelect="none">
{formatTime(duration)} {formatTime(duration)}
</Text> </Text>
</Flex> </Flex>
@ -290,53 +283,46 @@ export const AudioPlayer = ({}: AudioPlayerProps) => {
<IconButton <IconButton
{...configButton} {...configButton}
aria-label={'Play'} aria-label={'Play'}
icon={
isPlaying ? (
<MdPause size="30px" />
) : (
<MdPlayArrow size="30px" />
)
}
onClick={onPlay} onClick={onPlay}
/> >
isPlaying ? (
<MdPause size="30px" />
) : (
<MdPlayArrow size="30px" />
)
</IconButton>
<IconButton <IconButton
{...configButton} {...configButton}
aria-label={'Stop'} aria-label={'Stop'}
icon={<MdStop size="30px" />}
onClick={onStop} onClick={onStop}
/> ><MdStop size="30px" /></IconButton>
<IconButton <IconButton
{...configButton} {...configButton}
aria-label={'Previous track'} aria-label={'Previous track'}
icon={<MdNavigateBefore size="30px" />}
onClick={onNavigatePrevious} onClick={onNavigatePrevious}
marginLeft="auto" marginLeft="auto"
/> ><MdNavigateBefore size="30px" /> </IconButton>
<IconButton <IconButton
{...configButton} {...configButton}
aria-label={'jump 15sec in past'} aria-label={'jump 15sec in past'}
icon={<MdFastRewind size="30px" />}
onClick={onFastRewind} onClick={onFastRewind}
/> ><MdFastRewind size="30px" /></IconButton>
<IconButton <IconButton
{...configButton} {...configButton}
aria-label={'jump 15sec in future'} aria-label={'jump 15sec in future'}
icon={<MdFastForward size="30px" />}
onClick={onFastForward} onClick={onFastForward}
/> ><MdFastForward size="30px" /></IconButton>
<IconButton <IconButton
{...configButton} {...configButton}
aria-label={'Next track'} aria-label={'Next track'}
icon={<MdNavigateNext size="30px" />}
marginRight="auto" marginRight="auto"
onClick={onNavigateNext} onClick={onNavigateNext}
/> ><MdNavigateNext size="30px" /></IconButton>
<IconButton <IconButton
{...configButton} {...configButton}
aria-label={'continue to the end'} aria-label={'continue to the end'}
icon={playModeIcon[playingMode]}
onClick={onTypePlay} onClick={onTypePlay}
/> >playModeIcon[playingMode]</IconButton>
</Flex> </Flex>
</Flex> </Flex>
)} )}

View File

@ -1,16 +1,16 @@
import { ReactElement, useEffect, useState } from 'react'; import { ReactElement, useEffect, useState } from 'react';
import { As, Box, BoxProps, Flex, StyleProps } from '@chakra-ui/react'; import { Box, BoxProps, Flex, FlexProps } from '@chakra-ui/react';
import { Image } from '@chakra-ui/react'; import { Image } from '@chakra-ui/react';
import { DataUrlAccess } from '@/utils/data-url-access'; import { DataUrlAccess } from '@/utils/data-url-access';
import { Icon } from './Icon'; import { Icon } from './Icon';
import { ObjectId } from '@/back-api'; import { ObjectId } from '@/back-api';
export type CoversProps = BoxProps & { export type CoversProps = Omit<BoxProps, "iconEmpty"> & {
data?: ObjectId[]; data?: ObjectId[];
size?: StyleProps["width"]; size?: BoxProps["width"];
iconEmpty?: As; iconEmpty?: ReactElement;
slideshow?: boolean; slideshow?: boolean;
}; };
@ -60,11 +60,17 @@ export const Covers = ({
} }
if (slideshow === false || data.length === 1) { if (slideshow === false || data.length === 1) {
const url = DataUrlAccess.getThumbnailUrl(data[0]); const url = DataUrlAccess.getThumbnailUrl(data[0]);
return <Image loading="lazy" src={url} maxWidth={size} boxSize={size} {...rest} />; return <Image loading="lazy" src={url} maxWidth={size} boxSize={size} /*{...rest}*/ />;
} }
const urlCurrent = DataUrlAccess.getThumbnailUrl(data[currentImageIndex]); const urlCurrent = DataUrlAccess.getThumbnailUrl(data[currentImageIndex]);
const urlPrevious = DataUrlAccess.getThumbnailUrl(data[previousImageIndex]); const urlPrevious = DataUrlAccess.getThumbnailUrl(data[previousImageIndex]);
return <Flex position="relative" {...rest} maxWidth={size} width={size} height={size} overflow="hidden"> return <Flex
position="relative"
// {...rest}
maxWidth={size}
width={size}
height={size}
overflow="hidden">
<Image <Image
src={urlPrevious} src={urlPrevious}
loading="lazy" loading="lazy"

View File

@ -1,22 +1,17 @@
import { import {
As,
Box, Box,
BoxProps,
Icon as ChakraIcon,
IconProps as ChakraIconProps,
Flex, Flex,
FlexProps, FlexProps,
forwardRef,
LayoutProps,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { forwardRef, ReactNode } from 'react';
export type IconProps = FlexProps & { export type IconProps = FlexProps & {
icon: As; icon: ReactNode;
color?: string; color?: string;
sizeIcon?: LayoutProps['width']; sizeIcon?: FlexProps['width'];
}; };
export const Icon = forwardRef<IconProps, 'span'>( export const Icon = forwardRef<HTMLDivElement, IconProps>(
({ icon: IconEl, color, sizeIcon = '1em', ...rest }, ref) => { ({ icon: IconEl, color, sizeIcon = '1em', ...rest }, ref) => {
return ( return (
<Flex flex="none" <Flex flex="none"
@ -30,13 +25,16 @@ export const Icon = forwardRef<IconProps, 'span'>(
{...rest}> {...rest}>
<Box <Box
marginX="auto" marginX="auto"
as={IconEl}
width="100%" width="100%"
minWidth="100%" minWidth="100%"
height="100%" height="100%"
color={color} color={color}
/> >
{IconEl}
</Box>
</Flex> </Flex>
); );
} }
); );
Icon.displayName = 'Icon';

View File

@ -1,9 +1,8 @@
import { useState } from 'react'; import { useState } from 'react';
import { import {
Group,
Input, Input,
InputGroup,
InputLeftElement,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { MdSearch } from 'react-icons/md'; import { MdSearch } from 'react-icons/md';
@ -44,16 +43,14 @@ export const SearchInput = ({
} }
} }
return ( return (
<InputGroup maxWidth="200px" marginLeft="auto" {...searchInputProperty}> <Group maxWidth="200px" marginLeft="auto" {...searchInputProperty}>
<InputLeftElement pointerEvents="none"> <MdSearch color="gray.300" />
<MdSearch color="gray.300" />
</InputLeftElement>
<Input <Input
onFocus={onFocusKeep} onFocus={onFocusKeep}
onBlur={() => setTimeout(() => onFocusLost(), 200)} onBlur={() => setTimeout(() => onFocusLost(), 200)}
onChange={onChange} onChange={onChange}
onSubmit={onSubmit} onSubmit={onSubmit}
/> />
</InputGroup> </Group>
); );
}; };

View File

@ -1,35 +1,28 @@
import { ReactNode } from 'react'; import { ReactNode } from 'react';
import { import {
Box,
Button, Button,
Drawer, Drawer,
DrawerBody, DrawerBody,
DrawerContent, DrawerContent,
DrawerHeader, DrawerHeader,
DrawerOverlay, DrawerRoot,
Flex, Flex,
HStack, HStack,
IconButton, IconButton,
Menu, Menu,
MenuButton,
MenuItem,
MenuList,
Text, Text,
useDisclosure, useDisclosure,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { import {
LuAlignJustify, LuAlignJustify,
LuArrowBigLeft, LuArrowBigLeft,
LuArrowUpSquare,
LuHelpCircle,
LuHome,
LuLogIn, LuLogIn,
LuLogOut, LuLogOut,
LuMoon, LuMoon,
LuPlusCircle,
LuSettings, LuSettings,
LuSun, LuSun,
LuUserCircle,
} from 'react-icons/lu'; } from 'react-icons/lu';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
@ -39,12 +32,12 @@ import { colors } from '@/theme/foundations/colors';
import { requestSignIn, requestSignOut, requestSignUp } from '@/utils/sso'; import { requestSignIn, requestSignOut, requestSignUp } from '@/utils/sso';
import { useThemeMode } from '@/utils/theme-tools'; import { useThemeMode } from '@/utils/theme-tools';
import { useSessionService } from '@/service/session'; import { useSessionService } from '@/service/session';
import { MdHome, MdOutlinePlaylistPlay, MdOutlineUploadFile } from 'react-icons/md'; import { MdHelp, MdHome, MdMore, MdOutlinePlaylistPlay, MdOutlineUploadFile, MdSupervisedUserCircle } from 'react-icons/md';
export const TOP_BAR_HEIGHT = '50px'; export const TOP_BAR_HEIGHT = '50px';
export const BUTTON_TOP_BAR_PROPERTY = { export const BUTTON_TOP_BAR_PROPERTY = {
variant: '@menu', colorPalette: '@menu',
height: TOP_BAR_HEIGHT, height: TOP_BAR_HEIGHT,
}; };
@ -138,7 +131,7 @@ export const TopBar = ({ title, children }: TopBarProps) => {
onClick={onSignUp} onClick={onSignUp}
disabled={true} disabled={true}
> >
<LuPlusCircle /> <MdMore />
<Text paddingLeft="3px" fontWeight="bold"> <Text paddingLeft="3px" fontWeight="bold">
Sign-up Sign-up
</Text> </Text>
@ -146,97 +139,105 @@ export const TopBar = ({ title, children }: TopBarProps) => {
</> </>
)} )}
{session?.state === SessionState.CONNECTED && ( {session?.state === SessionState.CONNECTED && (
<Menu> <Menu.Root>
<MenuButton <Menu.Trigger asChild>
as={IconButton} <IconButton
aria-label="Options" as={IconButton}
icon={<LuUserCircle />} aria-label="Options"
{...BUTTON_TOP_BAR_PROPERTY} {...BUTTON_TOP_BAR_PROPERTY}
width={TOP_BAR_HEIGHT} width={TOP_BAR_HEIGHT}
/> ><MdSupervisedUserCircle /></IconButton>
<MenuList> </Menu.Trigger>
<MenuItem _hover={{}} color={mode('brand.800', 'brand.200')}> <Menu.Positioner>
Sign in as {session?.login ?? 'Fail'} <Menu.Content>
</MenuItem> <Menu.Item value="user" valueText="user" _hover={{}} color={mode('brand.800', 'brand.200')}>
<MenuItem icon={<LuSettings />} onClick={onSettings}>Settings</MenuItem> <MdSupervisedUserCircle />
<MenuItem icon={<LuHelpCircle />} onClick={onHelp}>Help</MenuItem> <Box flex="1">Sign in as {session?.login ?? 'Fail'}</Box>
<MenuItem icon={<LuLogOut />} onClick={onSignOut}> </Menu.Item>
Sign-out <Menu.Item value="Settings" valueText="Settings" onClick={onSettings}><LuSettings />Settings</Menu.Item>
</MenuItem> <Menu.Item value="Help" valueText="Help" onClick={onHelp}><MdHelp /> Help</Menu.Item>
{colorMode === 'light' ? ( <Menu.Item value="Sign-out" valueText="Sign-out" onClick={onSignOut}>
<MenuItem icon={<LuMoon />} onClick={toggleColorMode}> <LuLogOut /> Sign-out
Set dark mode </Menu.Item>
</MenuItem> {colorMode === 'light' ? (
) : ( <Menu.Item value="set-dark" valueText="set-dark" onClick={toggleColorMode}>
<MenuItem icon={<LuSun />} onClick={toggleColorMode}> <LuMoon /> Set dark mode
Set light mode </Menu.Item>
</MenuItem> ) : (
)} <Menu.Item value="set-light" valueText="set-light" onClick={toggleColorMode}>
</MenuList> <LuSun /> Set light mode
</Menu> </Menu.Item>
)}
</Menu.Content>
</Menu.Positioner>
</Menu.Root>
)} )}
</Flex> </Flex>
<Drawer <Drawer.Root
placement="left" placement="start"
onClose={drawerDisclose.onClose} onOpenChange={drawerDisclose.onClose}
isOpen={drawerDisclose.isOpen} open={drawerDisclose.open}
data-testid="top-bar_drawer-root"
> >
<DrawerOverlay /> <Drawer.Positioner>
<DrawerContent> <Drawer.Content
<DrawerHeader data-testid="top-bar_drawer-content">
paddingY="auto" <Drawer.Header
as="button" paddingY="auto"
onClick={drawerDisclose.onClose} as="button"
boxShadow={'0px 2px 4px ' + colors.back[900]} onClick={drawerDisclose.onClose}
backgroundColor={backColor} boxShadow={'0px 2px 4px ' + colors.back[900]}
color={mode('brand.900', 'brand.50')} backgroundColor={backColor}
textTransform="uppercase" color={mode('brand.900', 'brand.50')}
> textTransform="uppercase"
<HStack height={TOP_BAR_HEIGHT}>
<LuArrowBigLeft />
<Text as="span" paddingLeft="3px">
Karusic
</Text>
</HStack>
</DrawerHeader>
<DrawerBody paddingX="0px">
<Button
background="#00000000"
borderRadius="0px"
onClick={onSelectHome}
width="full"
> >
<MdHome /> <HStack height={TOP_BAR_HEIGHT}>
<Text paddingLeft="3px" fontWeight="bold" marginRight="auto"> <LuArrowBigLeft />
Home <Text as="span" paddingLeft="3px">
</Text> Karusic
</Button> </Text>
<Button </HStack>
background="#00000000" </Drawer.Header>
borderRadius="0px" <Drawer.Body paddingX="0px">
onClick={onSelectOnAir} <Button
width="full" background="#00000000"
> borderRadius="0px"
<MdOutlinePlaylistPlay /> onClick={onSelectHome}
<Text paddingLeft="3px" fontWeight="bold" marginRight="auto"> width="full"
On air >
</Text> <MdHome />
</Button> <Text paddingLeft="3px" fontWeight="bold" marginRight="auto">
<hr /> Home
<Button </Text>
background="#00000000" </Button>
borderRadius="0px" <hr />
onClick={onSelectAdd} <Button
width="full" background="#00000000"
> borderRadius="0px"
<MdOutlineUploadFile /> onClick={onSelectOnAir}
<Text paddingLeft="3px" fontWeight="bold" marginRight="auto"> width="full"
Add Media >
</Text> <MdOutlinePlaylistPlay />
</Button> <Text paddingLeft="3px" fontWeight="bold" marginRight="auto">
</DrawerBody> On air
</DrawerContent> </Text>
</Drawer> </Button>
<hr />
<Button
background="#00000000"
borderRadius="0px"
onClick={onSelectAdd}
width="full"
>
<MdOutlineUploadFile />
<Text paddingLeft="3px" fontWeight="bold" marginRight="auto">
Add Media
</Text>
</Button>
</Drawer.Body>
</Drawer.Content>
</Drawer.Positioner>
</Drawer.Root>
</Flex> </Flex>
); );
}; };

View File

@ -19,12 +19,13 @@ export const DisplayAlbum = ({ dataAlbum }: DisplayAlbumProps) => {
); );
} }
return ( return (
<Flex direction="row" width="full" height="full"> <Flex direction="row" width="full" height="full"
data-testid="display-album_flex">
<Covers <Covers
data={dataAlbum?.covers} data={dataAlbum?.covers}
size={BASE_WRAP_ICON_SIZE} size={BASE_WRAP_ICON_SIZE}
flex={1} flex={1}
iconEmpty={LuDisc3} // TODO: iconEmpty={LuDisc3}
/> />
<Flex <Flex
direction="column" direction="column"
@ -37,24 +38,24 @@ export const DisplayAlbum = ({ dataAlbum }: DisplayAlbumProps) => {
> >
<Text <Text
as="span" as="span"
align="left" // align="left"
fontSize="20px" fontSize="20px"
fontWeight="bold" fontWeight="bold"
userSelect="none" userSelect="none"
marginRight="auto" marginRight="auto"
overflow="hidden" overflow="hidden"
noOfLines={[1, 2]} // noOfLines={[1, 2]}
> >
{dataAlbum?.name} {dataAlbum?.name}
</Text> </Text>
<Text <Text
as="span" as="span"
align="left" // align="left"
fontSize="15px" fontSize="15px"
userSelect="none" userSelect="none"
marginRight="auto" marginRight="auto"
overflow="hidden" overflow="hidden"
noOfLines={1} // noOfLines={1}
> >
{countTracksOfAnAlbum} track{countTracksOfAnAlbum >= 1 && 's'} {countTracksOfAnAlbum} track{countTracksOfAnAlbum >= 1 && 's'}
</Text> </Text>

View File

@ -6,5 +6,6 @@ export type DisplayAlbumIdProps = {
}; };
export const DisplayAlbumId = ({ id }: DisplayAlbumIdProps) => { export const DisplayAlbumId = ({ id }: DisplayAlbumIdProps) => {
const { dataAlbum } = useSpecificAlbum(id); const { dataAlbum } = useSpecificAlbum(id);
return <DisplayAlbum dataAlbum={dataAlbum} />; return <DisplayAlbum dataAlbum={dataAlbum}
data-testid="display-album-id" />;
}; };

View File

@ -3,9 +3,6 @@ import { useState } from 'react';
import { import {
IconButton, IconButton,
Menu, Menu,
MenuButton,
MenuItem,
MenuList,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { LuMenu } from 'react-icons/lu'; import { LuMenu } from 'react-icons/lu';
@ -23,20 +20,26 @@ export const ContextMenu = ({ elements }: ContextMenuProps) => {
return <></>; return <></>;
} }
return ( return (
<Menu> <Menu.Root
<MenuButton data-testid="context-menu">
as={IconButton} <Menu.Trigger asChild
aria-label="Options" data-testid="context-menu_trigger">
icon={<LuMenu />} {/* This is very stupid, we need to set as span to prevent a button in button... WTF */}
marginY="auto" <IconButton as='span'>
/> <LuMenu />
<MenuList> </IconButton>
{elements?.map((data) => ( </Menu.Trigger>
<MenuItem key={data.name} onClick={data.onClick}> <Menu.Positioner>
{data.name} <Menu.Content
</MenuItem> data-testid="context-menu_content">
))} {elements?.map((data) => (
</MenuList> <Menu.Item key={data.name} value={data.name} onClick={data.onClick}
</Menu> data-testid="context-menu_item">
{data.name}
</Menu.Item>
))}
</Menu.Content>
</Menu.Positioner>
</Menu.Root>
); );
}; };

View File

@ -7,9 +7,9 @@ import {
Box, Box,
BoxProps, BoxProps,
Center, Center,
Flex,
HStack,
Image, Image,
Wrap,
WrapItem,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { import {
MdHighlightOff, MdHighlightOff,
@ -144,9 +144,9 @@ export const FormCovers = ({
onRestore={() => form.restoreValue({ [variableName]: true })} onRestore={() => form.restoreValue({ [variableName]: true })}
{...rest} {...rest}
> >
<Wrap width="full"> <HStack wrap="wrap" width="full">
{urls.map((data, index) => ( {urls.map((data, index) => (
<WrapItem key={data}> <Flex align="flex-start" key={data}>
<Box width="125px" height="125px" position="relative"> <Box width="125px" height="125px" position="relative">
<Box width="125px" height="125px" position="absolute"> <Box width="125px" height="125px" position="absolute">
<CenterIcon <CenterIcon
@ -161,17 +161,17 @@ export const FormCovers = ({
</Box> </Box>
<Image loading="lazy" src={data} boxSize="full" /> <Image loading="lazy" src={data} boxSize="full" />
</Box> </Box>
</WrapItem> </Flex>
))} ))}
<WrapItem key="data"> <Flex align="flex-start" key="data">
<DragNdrop <DragNdrop
height="125px" height="125px"
width="125px" width="125px"
onFilesSelected={onFilesSelected} onFilesSelected={onFilesSelected}
onUriSelected={onUriSelected} onUriSelected={onUriSelected}
/> />
</WrapItem> </Flex>
</Wrap> </HStack>
</FormGroup> </FormGroup>
); );
}; };

View File

@ -1,19 +1,14 @@
import { RefObject } from 'react'; import { RefObject } from 'react';
import { import {
NumberDecrementStepper,
NumberIncrementStepper,
NumberInput, NumberInput,
NumberInputField,
NumberInputProps,
NumberInputStepper,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { FormGroup } from '@/components/form/FormGroup'; import { FormGroup } from '@/components/form/FormGroup';
import { UseFormidableReturn } from '@/components/form/Formidable'; import { UseFormidableReturn } from '@/components/form/Formidable';
export type FormNumberProps = Pick< export type FormNumberProps = Pick<
NumberInputProps, NumberInput.RootProps,
'step' | 'defaultValue' | 'min' | 'max' 'step' | 'defaultValue' | 'min' | 'max'
> & { > & {
form: UseFormidableReturn; form: UseFormidableReturn;
@ -41,21 +36,17 @@ export const FormNumber = ({
onRestore={() => form.restoreValue({ [variableName]: true })} onRestore={() => form.restoreValue({ [variableName]: true })}
{...rest} {...rest}
> >
<NumberInput <NumberInput.Root
ref={ref} ref={ref}
value={form.values[variableName]} value={form.values[variableName]}
onChange={(_, value) => form.setValues({ [variableName]: value })} onValueChange={(value) => form.setValues({ [variableName]: value })}
step={step} step={step}
defaultValue={defaultValue} defaultValue={defaultValue}
min={min} min={min}
max={max} max={max}
> >
<NumberInputField /> <NumberInput.Input />
<NumberInputStepper> </NumberInput.Root>
<NumberIncrementStepper />
<NumberDecrementStepper />
</NumberInputStepper>
</NumberInput>
</FormGroup> </FormGroup>
); );
}; };

View File

@ -23,7 +23,7 @@ export const DisplayGender = ({ dataGender }: DisplayGenderProps) => {
data={dataGender?.covers} data={dataGender?.covers}
size="100" size="100"
height="full" height="full"
iconEmpty={LuDisc3} //TODO: iconEmpty={LuDisc3}
/> />
<Flex <Flex
direction="column" direction="column"
@ -35,24 +35,24 @@ export const DisplayGender = ({ dataGender }: DisplayGenderProps) => {
> >
<Text <Text
as="span" as="span"
align="left" alignContent="left"
fontSize="20px" fontSize="20px"
fontWeight="bold" fontWeight="bold"
userSelect="none" userSelect="none"
marginRight="auto" marginRight="auto"
overflow="hidden" overflow="hidden"
noOfLines={[1, 2]} //TODO: noOfLines={[1, 2]}
> >
{dataGender?.name} {dataGender?.name}
</Text> </Text>
<Text <Text
as="span" as="span"
align="left" alignContent="left"
fontSize="15px" fontSize="15px"
userSelect="none" userSelect="none"
marginRight="auto" marginRight="auto"
overflow="hidden" overflow="hidden"
noOfLines={1} //TODO: noOfLines={1}
> >
{countTracksOnAGender} track{countTracksOnAGender >= 1 && 's'} {countTracksOnAGender} track{countTracksOnAGender >= 1 && 's'}
</Text> </Text>

View File

@ -3,15 +3,15 @@ import { useRef, useState } from 'react';
import { import {
Button, Button,
Flex, Flex,
Modal, Dialog,
ModalBody, DialogBody,
ModalCloseButton, DialogContent,
ModalContent, DialogFooter,
ModalFooter, DialogHeader,
ModalHeader,
ModalOverlay,
Text, Text,
useDisclosure, useDisclosure,
DialogRoot,
DialogCloseTrigger,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { import {
MdAdminPanelSettings, MdAdminPanelSettings,
@ -65,8 +65,8 @@ export const AlbumEditPopUp = ({ }: AlbumEditPopUpProps) => {
); );
onClose(); onClose();
}; };
const initialRef = useRef(null); const initialRef = useRef<HTMLButtonElement>(null);
const finalRef = useRef(null); const finalRef = useRef<HTMLButtonElement>(null);
const form = useFormidable<Album>({ const form = useFormidable<Album>({
initialValues: dataAlbum, initialValues: dataAlbum,
}); });
@ -141,19 +141,21 @@ export const AlbumEditPopUp = ({ }: AlbumEditPopUpProps) => {
); );
}; };
return ( return (
<Modal <DialogRoot
initialFocusRef={initialRef} //initialFocusRef={initialRef}
finalFocusRef={finalRef} //finalFocusRef={finalRef}
closeOnOverlayClick={false} //closeOnOverlayClick={false}
onClose={onClose} onOpenChange={onClose}
isOpen={true} open={true}
data-testid="album-edit-pop-up"
> >
<ModalOverlay /> {/* <DialogOverlay /> */}
<ModalContent> {/* <DialogCloseTrigger /> */}
<ModalHeader>Edit Album</ModalHeader> <DialogContent>
<ModalCloseButton ref={finalRef} /> <DialogHeader>Edit Album</DialogHeader>
{/* <DialogCloseButton ref={finalRef} /> */}
<ModalBody pb={6} gap="0px" paddingLeft="18px"> <DialogBody pb={6} gap="0px" paddingLeft="18px">
{admin && ( {admin && (
<> <>
<FormGroup isRequired label="Id"> <FormGroup isRequired label="Id">
@ -172,8 +174,8 @@ export const AlbumEditPopUp = ({ }: AlbumEditPopUpProps) => {
<Button <Button
onClick={disclosure.onOpen} onClick={disclosure.onOpen}
marginRight="auto" marginRight="auto"
variant="@danger" colorPalette="red"
isDisabled={countTracksOfAnAlbum !== 0} disabled={countTracksOfAnAlbum !== 0}
> >
<MdDeleteForever /> Remove Media <MdDeleteForever /> Remove Media
</Button> </Button>
@ -215,8 +217,8 @@ export const AlbumEditPopUp = ({ }: AlbumEditPopUpProps) => {
/> />
</> </>
)} )}
</ModalBody> </DialogBody>
<ModalFooter> <DialogFooter>
<Button <Button
onClick={() => setAdmin((value) => !value)} onClick={() => setAdmin((value) => !value)}
marginRight="auto" marginRight="auto"
@ -239,8 +241,8 @@ export const AlbumEditPopUp = ({ }: AlbumEditPopUpProps) => {
</Button> </Button>
)} )}
<Button onClick={onClose}>Cancel</Button> <Button onClick={onClose}>Cancel</Button>
</ModalFooter> </DialogFooter>
</ModalContent> </DialogContent>
</Modal> </DialogRoot>
); );
}; };

View File

@ -3,15 +3,14 @@ import { useRef, useState } from 'react';
import { import {
Button, Button,
Flex, Flex,
Modal, Dialog,
ModalBody, DialogBody,
ModalCloseButton, DialogContent,
ModalContent, DialogFooter,
ModalFooter, DialogHeader,
ModalHeader,
ModalOverlay,
Text, Text,
useDisclosure, useDisclosure,
DialogRoot,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { import {
MdAdminPanelSettings, MdAdminPanelSettings,
@ -65,8 +64,8 @@ export const ArtistEditPopUp = ({ }: ArtistEditPopUpProps) => {
); );
onClose(); onClose();
}; };
const initialRef = useRef(null); const initialRef = useRef<HTMLButtonElement>(null);
const finalRef = useRef(null); const finalRef = useRef<HTMLButtonElement>(null);
const form = useFormidable<Artist>({ const form = useFormidable<Artist>({
initialValues: dataArtist, initialValues: dataArtist,
}); });
@ -140,19 +139,20 @@ export const ArtistEditPopUp = ({ }: ArtistEditPopUpProps) => {
); );
}; };
return ( return (
<Modal <DialogRoot
initialFocusRef={initialRef} //initialFocusRef={initialRef}
finalFocusRef={finalRef} //finalFocusRef={finalRef}
closeOnOverlayClick={false} //closeOnOverlayClick={false}
onClose={onClose} onOpenChange={onClose}
isOpen={true} open={true}
data-testid="artist-edit-pop-up"
> >
<ModalOverlay /> {/* <DialogOverlay /> */}
<ModalContent> <DialogContent>
<ModalHeader>Edit Artist</ModalHeader> <DialogHeader>Edit Artist</DialogHeader>
<ModalCloseButton ref={finalRef} /> {/* <DialogCloseButton ref={finalRef} /> */}
<ModalBody pb={6} gap="0px" paddingLeft="18px"> <DialogBody pb={6} gap="0px" paddingLeft="18px">
{admin && ( {admin && (
<> <>
<FormGroup isRequired label="Id"> <FormGroup isRequired label="Id">
@ -171,8 +171,8 @@ export const ArtistEditPopUp = ({ }: ArtistEditPopUpProps) => {
<Button <Button
onClick={disclosure.onOpen} onClick={disclosure.onOpen}
marginRight="auto" marginRight="auto"
variant="@danger" colorPalette="red"
isDisabled={countTracksOnAnArtist !== 0} disabled={countTracksOnAnArtist !== 0}
> >
<MdDeleteForever /> Remove Media <MdDeleteForever /> Remove Media
</Button> </Button>
@ -217,8 +217,8 @@ export const ArtistEditPopUp = ({ }: ArtistEditPopUpProps) => {
/> />
</> </>
)} )}
</ModalBody> </DialogBody>
<ModalFooter> <DialogFooter>
<Button <Button
onClick={() => setAdmin((value) => !value)} onClick={() => setAdmin((value) => !value)}
marginRight="auto" marginRight="auto"
@ -241,8 +241,8 @@ export const ArtistEditPopUp = ({ }: ArtistEditPopUpProps) => {
</Button> </Button>
)} )}
<Button onClick={onClose}>Cancel</Button> <Button onClick={onClose}>Cancel</Button>
</ModalFooter> </DialogFooter>
</ModalContent> </DialogContent>
</Modal> </DialogRoot>
); );
}; };

View File

@ -1,13 +1,12 @@
import { useRef } from 'react'; import { useRef } from 'react';
import { import {
AlertDialog,
AlertDialogBody,
AlertDialogContent,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogOverlay,
Button, Button,
DialogBody,
DialogContent,
DialogFooter,
DialogHeader,
DialogRoot,
UseDisclosureReturn, UseDisclosureReturn,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
@ -30,31 +29,30 @@ export const ConfirmPopUp = ({
onConfirm(); onConfirm();
disclosure.onClose(); disclosure.onClose();
}; };
const cancelRef = useRef(null); const cancelRef = useRef<HTMLButtonElement>(null);
return ( return (
<AlertDialog <DialogRoot role="alertdialog"
isOpen={disclosure.isOpen} open={disclosure.open}
leastDestructiveRef={cancelRef} //leastDestructiveRef={cancelRef}
onClose={disclosure.onClose} onOpenChange={disclosure.onClose}
data-testid="confirm-pop-up"
> >
<AlertDialogOverlay> <DialogContent>
<AlertDialogContent> <DialogHeader fontSize="lg" fontWeight="bold">
<AlertDialogHeader fontSize="lg" fontWeight="bold"> {title}
{title} </DialogHeader>
</AlertDialogHeader>
<AlertDialogBody>{body}</AlertDialogBody> <DialogBody>{body}</DialogBody>
<AlertDialogFooter> <DialogFooter>
<Button onClick={disclosure.onClose} ref={cancelRef}> <Button onClick={disclosure.onClose} ref={cancelRef}>
Cancel Cancel
</Button> </Button>
<Button colorScheme="red" onClick={onClickConfirm} ml={3}> <Button colorScheme="red" onClick={onClickConfirm} ml={3}>
{confirmTitle} {confirmTitle}
</Button> </Button>
</AlertDialogFooter> </DialogFooter>
</AlertDialogContent> </DialogContent>
</AlertDialogOverlay> </DialogRoot>
</AlertDialog>
); );
}; };

View File

@ -3,15 +3,14 @@ import { useRef, useState } from 'react';
import { import {
Button, Button,
Flex, Flex,
Modal, Dialog,
ModalBody, DialogBody,
ModalCloseButton, DialogContent,
ModalContent, DialogFooter,
ModalFooter, DialogHeader,
ModalHeader,
ModalOverlay,
Text, Text,
useDisclosure, useDisclosure,
DialogRoot,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { import {
MdAdminPanelSettings, MdAdminPanelSettings,
@ -65,8 +64,8 @@ export const GenderEditPopUp = ({ }: GenderEditPopUpProps) => {
); );
onClose(); onClose();
}; };
const initialRef = useRef(null); const initialRef = useRef<HTMLButtonElement>(null);
const finalRef = useRef(null); const finalRef = useRef<HTMLButtonElement>(null);
const form = useFormidable<Gender>({ const form = useFormidable<Gender>({
initialValues: dataGender, initialValues: dataGender,
}); });
@ -139,19 +138,20 @@ export const GenderEditPopUp = ({ }: GenderEditPopUpProps) => {
); );
}; };
return ( return (
<Modal <DialogRoot
initialFocusRef={initialRef} //initialFocusRef={initialRef}
finalFocusRef={finalRef} //finalFocusRef={finalRef}
closeOnOverlayClick={false} //closeOnOverlayClick={false}
onClose={onClose} onOpenChange={onClose}
isOpen={true} open={true}
data-testid="gender-edit-pop-up"
> >
<ModalOverlay /> {/* <DialogOverlay /> */}
<ModalContent> <DialogContent>
<ModalHeader>Edit Gender</ModalHeader> <DialogHeader>Edit Gender</DialogHeader>
<ModalCloseButton ref={finalRef} /> {/* <DialogCloseButton ref={finalRef} /> */}
<ModalBody pb={6} gap="0px" paddingLeft="18px"> <DialogBody pb={6} gap="0px" paddingLeft="18px">
{admin && ( {admin && (
<> <>
<FormGroup isRequired label="Id"> <FormGroup isRequired label="Id">
@ -170,8 +170,8 @@ export const GenderEditPopUp = ({ }: GenderEditPopUpProps) => {
<Button <Button
onClick={disclosure.onOpen} onClick={disclosure.onOpen}
marginRight="auto" marginRight="auto"
variant="@danger" colorPalette="red"
isDisabled={countTracksOnAGender !== 0} disabled={countTracksOnAGender !== 0}
> >
<MdDeleteForever /> Remove gender <MdDeleteForever /> Remove gender
</Button> </Button>
@ -208,8 +208,8 @@ export const GenderEditPopUp = ({ }: GenderEditPopUpProps) => {
/> />
</> </>
)} )}
</ModalBody> </DialogBody>
<ModalFooter> <DialogFooter>
<Button <Button
onClick={() => setAdmin((value) => !value)} onClick={() => setAdmin((value) => !value)}
marginRight="auto" marginRight="auto"
@ -232,8 +232,8 @@ export const GenderEditPopUp = ({ }: GenderEditPopUpProps) => {
</Button> </Button>
)} )}
<Button onClick={onClose}>Cancel</Button> <Button onClick={onClose}>Cancel</Button>
</ModalFooter> </DialogFooter>
</ModalContent> </DialogContent>
</Modal> </DialogRoot>
); );
}; };

View File

@ -3,16 +3,15 @@ import { ReactElement, useRef, useState } from 'react';
import { import {
Button, Button,
Flex, Flex,
Modal, Dialog,
ModalBody, DialogBody,
ModalCloseButton, DialogContent,
ModalContent, DialogFooter,
ModalFooter, DialogHeader,
ModalHeader,
ModalOverlay,
Progress, Progress,
Text, Text,
useDisclosure, useDisclosure,
DialogRoot,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { import {
MdAdminPanelSettings, MdAdminPanelSettings,
@ -63,22 +62,23 @@ export const PopUpUploadProgress = ({
title, title,
totalSize, totalSize,
}: PopUpUploadProgressProps) => { }: PopUpUploadProgressProps) => {
const initialRef = useRef(null); const initialRef = useRef<HTMLButtonElement>(null);
const finalRef = useRef(null); const finalRef = useRef<HTMLButtonElement>(null);
return ( return (
<Modal <DialogRoot
initialFocusRef={initialRef} //initialFocusRef={initialRef}
finalFocusRef={finalRef} //finalFocusRef={finalRef}
closeOnOverlayClick={false} //closeOnOverlayClick={false}
onClose={onClose} onOpenChange={onClose}
isOpen={true} open={true}
data-testid="upload-progress-edit-pop-up"
> >
<ModalOverlay /> {/* <DialogOverlay /> */}
<ModalContent> <DialogContent>
<ModalHeader>{title}</ModalHeader> <DialogHeader>{title}</DialogHeader>
<ModalCloseButton ref={finalRef} /> {/* <DialogCloseButton ref={finalRef} /> */}
<ModalBody pb={6} paddingLeft="18px"> <DialogBody pb={6} paddingLeft="18px">
<Flex direction="column" gap="10px"> <Flex direction="column" gap="10px">
{isFinished ? ( {isFinished ? (
<Text fontSize="20px" fontWeight="bold"> <Text fontSize="20px" fontWeight="bold">
@ -89,11 +89,11 @@ export const PopUpUploadProgress = ({
[{index + 1}/{elements.length}] {elements[index]} [{index + 1}/{elements.length}] {elements[index]}
</Text> </Text>
)} )}
<Progress <Progress.Root
colorScheme="green" colorScheme="green"
hasStripe striped
value={currentSize} value={currentSize}
isAnimated animated
max={totalSize} max={totalSize}
height="24px" height="24px"
/> />
@ -109,10 +109,10 @@ export const PopUpUploadProgress = ({
</Text> </Text>
)} )}
</Flex> </Flex>
</ModalBody> </DialogBody>
<ModalFooter> <DialogFooter>
{isFinished ? ( {isFinished ? (
<Button onClick={onClose} variant="@success"> <Button onClick={onClose} colorPalette="@success">
Ok Ok
</Button> </Button>
) : ( ) : (
@ -120,8 +120,8 @@ export const PopUpUploadProgress = ({
Abort Abort
</Button> </Button>
)} )}
</ModalFooter> </DialogFooter>
</ModalContent> </DialogContent>
</Modal> </DialogRoot>
); );
}; };

View File

@ -2,13 +2,11 @@ import { useRef, useState } from 'react';
import { import {
Button, Button,
Modal, DialogBody,
ModalBody, DialogContent,
ModalCloseButton, DialogFooter,
ModalContent, DialogHeader,
ModalFooter, DialogRoot,
ModalHeader,
ModalOverlay,
Text, Text,
useDisclosure, useDisclosure,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
@ -33,7 +31,7 @@ import { isNullOrUndefined } from '@/utils/validator';
export type TrackEditPopUpProps = {}; export type TrackEditPopUpProps = {};
export const TrackEditPopUp = ({}: TrackEditPopUpProps) => { export const TrackEditPopUp = ({ }: TrackEditPopUpProps) => {
const { trackId } = useParams(); const { trackId } = useParams();
const trackIdInt = isNullOrUndefined(trackId) const trackIdInt = isNullOrUndefined(trackId)
? undefined ? undefined
@ -65,8 +63,8 @@ export const TrackEditPopUp = ({}: TrackEditPopUpProps) => {
); );
onClose(); onClose();
}; };
const initialRef = useRef(null); const initialRef = useRef<HTMLButtonElement>(null);
const finalRef = useRef(null); const finalRef = useRef<HTMLButtonElement>(null);
const form = useFormidable<Track>({ const form = useFormidable<Track>({
//onSubmit, //onSubmit,
//onValuesChange, //onValuesChange,
@ -91,19 +89,20 @@ export const TrackEditPopUp = ({}: TrackEditPopUpProps) => {
); );
}; };
return ( return (
<Modal <DialogRoot
initialFocusRef={initialRef} //initialFocusRef={initialRef}
finalFocusRef={finalRef} //finalFocusRef={finalRef}
closeOnOverlayClick={false} //closeOnOverlayClick={false}
onClose={onClose} onOpenChange={onClose}
isOpen={true} open={true}
data-testid="track-edit-pop-up"
> >
<ModalOverlay /> {/* <DialogOverlay /> */}
<ModalContent> <DialogContent>
<ModalHeader>Edit Track</ModalHeader> <DialogHeader>Edit Track</DialogHeader>
<ModalCloseButton ref={finalRef} /> {/* <DialogCloseButton ref={finalRef} /> */}
<ModalBody pb={6} gap="0px" paddingLeft="18px"> <DialogBody pb={6} gap="0px" paddingLeft="18px">
{admin && ( {admin && (
<> <>
<FormGroup isRequired label="Id"> <FormGroup isRequired label="Id">
@ -116,7 +115,7 @@ export const TrackEditPopUp = ({}: TrackEditPopUpProps) => {
<Button <Button
onClick={disclosure.onOpen} onClick={disclosure.onOpen}
marginRight="auto" marginRight="auto"
variant="@danger" colorPalette="@danger"
> >
<MdDeleteForever /> Remove Media <MdDeleteForever /> Remove Media
</Button> </Button>
@ -167,14 +166,14 @@ export const TrackEditPopUp = ({}: TrackEditPopUpProps) => {
variableName="track" variableName="track"
label="Track n°" label="Track n°"
step={1} step={1}
defaultValue={0} //defaultValue={0}
min={0} min={0}
max={1000} max={1000}
/> />
</> </>
)} )}
</ModalBody> </DialogBody>
<ModalFooter> <DialogFooter>
<Button <Button
onClick={() => setAdmin((value) => !value)} onClick={() => setAdmin((value) => !value)}
marginRight="auto" marginRight="auto"
@ -197,8 +196,8 @@ export const TrackEditPopUp = ({}: TrackEditPopUpProps) => {
</Button> </Button>
)} )}
<Button onClick={onClose}>Cancel</Button> <Button onClick={onClose}>Cancel</Button>
</ModalFooter> </DialogFooter>
</ModalContent> </DialogContent>
</Modal> </DialogRoot>
); );
}; };

View File

@ -3,13 +3,11 @@ import { RefObject, useEffect, useMemo, useRef, useState } from 'react';
import { import {
Button, Button,
Flex, Flex,
HStack,
Input, Input,
Spinner, Spinner,
Tag, Tag,
TagCloseButton,
TagLabel, TagLabel,
Wrap,
WrapItem,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { MdEdit, MdKeyboardArrowDown, MdKeyboardArrowUp } from 'react-icons/md'; import { MdEdit, MdKeyboardArrowDown, MdKeyboardArrowUp } from 'react-icons/md';
@ -111,22 +109,22 @@ export const SelectMultiple = ({
return ( return (
<Flex direction="column" width="full" gap="0px"> <Flex direction="column" width="full" gap="0px">
{selectedOptions && ( {selectedOptions && (
<Wrap spacing="5px" justify="left" width="full" marginBottom="2px"> <HStack wrap="wrap" /*spacing="5px"*/ justify="left" width="full" marginBottom="2px">
{selectedOptions.map((data) => ( {selectedOptions.map((data) => (
<WrapItem key={data[keyKey]}> <Flex align="flex-start" key={data[keyKey]}>
<Tag <Tag.Root
size="md" size="md"
key="md" key="md"
borderRadius="5px" borderRadius="5px"
variant="solid" variant="solid"
backgroundColor="green.500" backgroundColor="green.500"
> >
<TagLabel>{data[keyValue] ?? `id=${data[keyKey]}`}</TagLabel> <Tag.Label>{data[keyValue] ?? `id=${data[keyKey]}`}</Tag.Label>
<TagCloseButton onClick={() => selectValue(data)} /> <Tag.CloseTrigger onClick={() => selectValue(data)} />
</Tag> </Tag.Root>
</WrapItem> </Flex>
))} ))}
</Wrap> </HStack>
)} )}
<Flex> <Flex>

View File

@ -0,0 +1,58 @@
"use client"
import { RestErrorResponse } from "@/back-api";
import {
Toaster as ChakraToaster,
Portal,
Spinner,
Stack,
Toast,
createToaster,
} from "@chakra-ui/react"
import { useCallback } from "react";
export const toaster = createToaster({
duration: 3000,
placement: 'top-end',
// offset: { top: '50px' },
// variant: 'solid',
})
export const toasterAPIError = (error: RestErrorResponse) => {
toaster.create({
title: `[${error.status}] ${error.statusMessage}`,
description: error.message,
});
};
export const Toaster = () => {
return (
<Portal>
<ChakraToaster
toaster={toaster}
insetInline={{ mdDown: "1rem" }}
width={{ md: "356px" }}
>
{(toast) => (
<Toast.Root>
{toast.type === "loading" ? (
<Spinner size="sm" color="blue.solid" />
) : (
<Toast.Indicator />
)}
<Stack gap="1" flex="1" maxWidth="100%">
{toast.title && <Toast.Title>{toast.title}</Toast.Title>}
{toast.description && (
<Toast.Description>{toast.description}</Toast.Description>
)}
</Stack>
{toast.action && (
<Toast.ActionTrigger>{toast.action.label}</Toast.ActionTrigger>
)}
{toast.meta?.closable && <Toast.CloseTrigger />}
</Toast.Root>
)}
</ChakraToaster>
</Portal>
)
}

View File

@ -23,9 +23,9 @@ export const DisplayTrack = ({
data={track?.covers} data={track?.covers}
size="50" size="50"
height="full" height="full"
iconEmpty={ /* TODO: iconEmpty={
trackActive?.id === track.id ? LuPlay : LuMusic2 trackActive?.id === track.id ? LuPlay : LuMusic2
} } */
onClick={onClick} onClick={onClick}
/> />
<Flex <Flex
@ -38,13 +38,13 @@ export const DisplayTrack = ({
> >
<Text <Text
as="span" as="span"
align="left" alignContent="left"
fontSize="20px" fontSize="20px"
fontWeight="bold" fontWeight="bold"
userSelect="none" userSelect="none"
marginRight="auto" marginRight="auto"
overflow="hidden" overflow="hidden"
noOfLines={[1, 2]} // TODO: noOfLines={[1, 2]}
marginY="auto" marginY="auto"
color={trackActive?.id === track.id ? 'green.700' : undefined} color={trackActive?.id === track.id ? 'green.700' : undefined}
> >

View File

@ -26,14 +26,15 @@ export const DisplayTrackFull = ({
const { dataGender } = useSpecificGender(track?.genderId); const { dataGender } = useSpecificGender(track?.genderId);
const { dataArtists } = useSpecificArtists(track?.artists); const { dataArtists } = useSpecificArtists(track?.artists);
return ( return (
<Flex direction="row" width="full" height="full"> <Flex direction="row" width="full" height="full"
data-testid="display-track-full">
<Covers <Covers
data={track?.covers} data={track?.covers}
size="50" size="50"
marginY="auto" marginY="auto"
iconEmpty={ /* TODO: iconEmpty={
trackActive?.id === track.id ? LuPlay : LuMusic2 trackActive?.id === track.id ? LuPlay : LuMusic2
} } */
onClick={onClick} onClick={onClick}
/> />
<Flex <Flex
@ -46,13 +47,13 @@ export const DisplayTrackFull = ({
> >
<Text <Text
as="span" as="span"
align="left" alignContent="left"
fontSize="20px" fontSize="20px"
fontWeight="bold" fontWeight="bold"
userSelect="none" userSelect="none"
marginRight="auto" marginRight="auto"
overflow="hidden" overflow="hidden"
noOfLines={1} // TODO: noOfLines={1}
color={trackActive?.id === track.id ? 'green.700' : undefined} color={trackActive?.id === track.id ? 'green.700' : undefined}
> >
{track.name} {track.track && ` [${track.track}]`} {track.name} {track.track && ` [${track.track}]`}
@ -60,13 +61,13 @@ export const DisplayTrackFull = ({
{dataAlbum && ( {dataAlbum && (
<Text <Text
as="span" as="span"
align="left" alignContent="left"
fontSize="15px" fontSize="15px"
fontWeight="bold" fontWeight="bold"
userSelect="none" userSelect="none"
marginRight="auto" marginRight="auto"
overflow="hidden" overflow="hidden"
noOfLines={1} //noOfLines={1}
marginY="auto" marginY="auto"
color={trackActive?.id === track.id ? 'green.700' : undefined} color={trackActive?.id === track.id ? 'green.700' : undefined}
> >
@ -76,13 +77,13 @@ export const DisplayTrackFull = ({
{dataArtists && ( {dataArtists && (
<Text <Text
as="span" as="span"
align="left" alignContent="left"
fontSize="15px" fontSize="15px"
fontWeight="bold" fontWeight="bold"
userSelect="none" userSelect="none"
marginRight="auto" marginRight="auto"
overflow="hidden" overflow="hidden"
noOfLines={1} //noOfLines={1}
marginY="auto" marginY="auto"
color={trackActive?.id === track.id ? 'green.700' : undefined} color={trackActive?.id === track.id ? 'green.700' : undefined}
> >
@ -92,13 +93,13 @@ export const DisplayTrackFull = ({
{dataGender && ( {dataGender && (
<Text <Text
as="span" as="span"
align="left" alignContent="left"
fontSize="15px" fontSize="15px"
fontWeight="bold" fontWeight="bold"
userSelect="none" userSelect="none"
marginRight="auto" marginRight="auto"
overflow="hidden" overflow="hidden"
noOfLines={1} //noOfLines={1}
marginY="auto" marginY="auto"
color={trackActive?.id === track.id ? 'green.700' : undefined} color={trackActive?.id === track.id ? 'green.700' : undefined}
> >
@ -106,7 +107,8 @@ export const DisplayTrackFull = ({
</Text> </Text>
)} )}
</Flex> </Flex>
<ContextMenu elements={contextMenu} /> <ContextMenu elements={contextMenu}
data-testid="display-track-full_context-menu" />
</Flex> </Flex>
); );
}; };

View File

@ -1,4 +1,4 @@
import { Flex, Skeleton, SkeletonText } from '@chakra-ui/react'; import { Flex, Skeleton } from '@chakra-ui/react';
export const DisplayTrackSkeleton = () => { export const DisplayTrackSkeleton = () => {
return ( return (
@ -17,13 +17,13 @@ export const DisplayTrackSkeleton = () => {
paddingLeft="5px" paddingLeft="5px"
overflowX="hidden" overflowX="hidden"
> >
<SkeletonText {/* <SkeletonText
skeletonHeight="20px" skeletonHeight="20px"
noOfLines={1} noOfLines={1}
spacing={0} spacing={0}
width="50%" width="50%"
marginY="auto" marginY="auto"
/> /> */}
</Flex> </Flex>
</Flex> </Flex>
); );

View File

@ -1,4 +1,4 @@
import { Box, Button, Center, Heading, Text } from '@chakra-ui/react'; import { Box, Button, Center, Heading, Link, Text } from '@chakra-ui/react';
import { MdControlCamera } from 'react-icons/md'; import { MdControlCamera } from 'react-icons/md';
import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter'; import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter';
@ -17,9 +17,9 @@ export const Error401 = () => {
<Text color="red.600"> <Text color="red.600">
Vous n'êtes pas autorisé a accéder a ce contenu. Vous n'êtes pas autorisé a accéder a ce contenu.
</Text> </Text>
<Button as="a" variant="link" href="/"> <Link as="a" href="/">
Retour à l'accueil Retour à l'accueil
</Button> </Link>
</Box> </Box>
</PageLayoutInfoCenter> </PageLayoutInfoCenter>
</> </>

View File

@ -1,4 +1,4 @@
import { Box, Button, Center, Heading, Text } from '@chakra-ui/react'; import { Box, Button, Center, Heading, Link, Text } from '@chakra-ui/react';
import { MdDangerous } from 'react-icons/md'; import { MdDangerous } from 'react-icons/md';
import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter'; import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter';
@ -15,9 +15,9 @@ export const Error403 = () => {
<Box textAlign="center"> <Box textAlign="center">
<Heading>Erreur 401</Heading> <Heading>Erreur 401</Heading>
<Text color="orange.600">Cette page vous est interdite</Text> <Text color="orange.600">Cette page vous est interdite</Text>
<Button as="a" variant="link" href="/"> <Link href="/">
Retour à l'accueil Retour à l'accueil
</Button> </Link>
</Box> </Box>
</PageLayoutInfoCenter> </PageLayoutInfoCenter>
</> </>

View File

@ -1,4 +1,4 @@
import { Box, Button, Center, Heading, Text } from '@chakra-ui/react'; import { Box, Button, Center, Heading, Link, Text } from '@chakra-ui/react';
import { MdSignpost } from 'react-icons/md'; import { MdSignpost } from 'react-icons/md';
import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter'; import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter';
@ -17,9 +17,9 @@ export const Error404 = () => {
<Text color="gray.600"> <Text color="gray.600">
Cette page n'existe plus ou l'URL a changé Cette page n'existe plus ou l'URL a changé
</Text> </Text>
<Button as="a" variant="link" href="/"> <Link href="/">
Retour à l'accueil Retour à l'accueil
</Button> </Link>
</Box> </Box>
</PageLayoutInfoCenter> </PageLayoutInfoCenter>
</> </>

View File

@ -3,11 +3,11 @@ import React, { FC } from 'react';
import { import {
Alert, Alert,
AlertDescription, AlertDescription,
AlertIcon, AlertRoot,
AlertTitle, AlertTitle,
Box, Box,
Button, Button,
Collapse, Collapsible,
useDisclosure, useDisclosure,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { import {
@ -17,31 +17,33 @@ import {
import { LuChevronDown, LuChevronUp } from 'react-icons/lu'; import { LuChevronDown, LuChevronUp } from 'react-icons/lu';
const ErrorFallback = ({ error }: FallbackProps) => { const ErrorFallback = ({ error }: FallbackProps) => {
const { isOpen, onToggle } = useDisclosure(); const { open, onToggle } = useDisclosure();
return ( return (
<Box p="4" m="auto"> <Box p="4" m="auto">
<Alert status="error" borderRadius="md"> <AlertRoot status="error" borderRadius="md">
<AlertIcon /> {/* <AlertIcon /> */}
<Box flex="1"> <Box flex="1">
<AlertTitle>An unexpected error has occurred.</AlertTitle> <AlertTitle>An unexpected error has occurred.</AlertTitle>
<AlertDescription display="block" lineHeight="1.4"> <AlertDescription display="block" lineHeight="1.4">
<Button <Button
variant="link" colorPalette="link"
color="red.800" color="red.800"
size="sm" size="sm"
rightIcon={isOpen ? <LuChevronUp /> : <LuChevronDown />} //rightIcon={open ? <LuChevronUp /> : <LuChevronDown />}
onClick={onToggle} onClick={onToggle}
> >
Show details Show details
</Button> </Button>
<Collapse in={isOpen} animateOpacity> <Collapsible.Root open={open}>
<Box mt={4} fontFamily="monospace"> <Collapsible.Content>
{error.message} <Box mt={4} fontFamily="monospace">
</Box> {error.message}
</Collapse> </Box>
</Collapsible.Content>
</Collapsible.Root>
</AlertDescription> </AlertDescription>
</Box> </Box>
</Alert> </AlertRoot>
</Box> </Box>
); );
}; };

View File

@ -66,7 +66,8 @@ export const AlbumDetailPage = () => {
<MdEdit /> <MdEdit />
</Button> </Button>
</TopBar> </TopBar>
<PageLayout> <PageLayout
data-testid="Album-detail-page_layout">
<Flex <Flex
direction="row" direction="row"
width="80%" width="80%"
@ -76,7 +77,7 @@ export const AlbumDetailPage = () => {
> >
<Covers <Covers
data={dataAlbum?.covers} data={dataAlbum?.covers}
iconEmpty={LuDisc3} // TODO: iconEmpty={LuDisc3}
slideshow slideshow
/> />
<Flex direction="column" width="80%" marginRight="auto"> <Flex direction="column" width="80%" marginRight="auto">
@ -98,6 +99,7 @@ export const AlbumDetailPage = () => {
marginX="auto" marginX="auto"
padding="20px" padding="20px"
width="80%" width="80%"
data-testid="Album-detail-page_flex-list"
> >
{tracksOnAnAlbum?.map((data) => ( {tracksOnAnAlbum?.map((data) => (
<Box <Box
@ -126,6 +128,7 @@ export const AlbumDetailPage = () => {
}, },
{ name: 'Add Playlist', onClick: () => { } }, { name: 'Add Playlist', onClick: () => { } },
]} ]}
data-testid="Album-detail-page_display-detail"
/> />
</Box> </Box>
))} ))}

View File

@ -1,6 +1,5 @@
import { useState } from 'react'; import { useState } from 'react';
import { Wrap, WrapItem } from '@chakra-ui/react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { EmptyEnd } from '@/components/EmptyEnd'; import { EmptyEnd } from '@/components/EmptyEnd';
@ -12,6 +11,7 @@ import { DisplayAlbum } from '@/components/album/DisplayAlbum';
import { useOrderedAlbums } from '@/service/Album'; import { useOrderedAlbums } from '@/service/Album';
import { useThemeMode } from '@/utils/theme-tools'; import { useThemeMode } from '@/utils/theme-tools';
import { BASE_WRAP_SPACING, BASE_WRAP_WIDTH, BASE_WRAP_HEIGHT } from '@/constants/genericSpacing'; import { BASE_WRAP_SPACING, BASE_WRAP_WIDTH, BASE_WRAP_HEIGHT } from '@/constants/genericSpacing';
import { Flex, HStack } from '@chakra-ui/react';
export const AlbumsPage = () => { export const AlbumsPage = () => {
const [filterTitle, setFilterTitle] = useState<string | undefined>(undefined); const [filterTitle, setFilterTitle] = useState<string | undefined>(undefined);
@ -37,9 +37,9 @@ export const AlbumsPage = () => {
<SearchInput onChange={setFilterTitle} /> <SearchInput onChange={setFilterTitle} />
</TopBar> </TopBar>
<PageLayout> <PageLayout>
<Wrap spacing={BASE_WRAP_SPACING} marginX="auto" padding="20px" justify="center"> <HStack wrap="wrap" /*spacing={BASE_WRAP_SPACING}*/ marginX="auto" padding="20px" justify="center">
{dataAlbums.map((data) => ( {dataAlbums.map((data) => (
<WrapItem <Flex align="flex-start"
width={BASE_WRAP_WIDTH} width={BASE_WRAP_WIDTH}
height={BASE_WRAP_HEIGHT} height={BASE_WRAP_HEIGHT}
border="1px" border="1px"
@ -55,9 +55,9 @@ export const AlbumsPage = () => {
onClick={() => onSelectItem(data.id)} onClick={() => onSelectItem(data.id)}
> >
<DisplayAlbum dataAlbum={data} /> <DisplayAlbum dataAlbum={data} />
</WrapItem> </Flex>
))} ))}
</Wrap> </HStack>
<EmptyEnd /> <EmptyEnd />
</PageLayout> </PageLayout>
</> </>

View File

@ -68,7 +68,7 @@ export const ArtistAlbumDetailPage = () => {
data={dataArtist?.covers} data={dataArtist?.covers}
size="35px" size="35px"
borderRadius="full" borderRadius="full"
iconEmpty={MdPerson} // TODO: iconEmpty={MdPerson}
/> />
<Text fontSize="24px" fontWeight="bold"> <Text fontSize="24px" fontWeight="bold">
{dataArtist?.name} {dataArtist?.name}
@ -95,7 +95,7 @@ export const ArtistAlbumDetailPage = () => {
> >
<Covers <Covers
data={dataAlbum?.covers} data={dataAlbum?.covers}
iconEmpty={LuDisc3} // TODO: iconEmpty={LuDisc3}
slideshow slideshow
/> />
<Flex direction="column" width="80%" marginRight="auto"> <Flex direction="column" width="80%" marginRight="auto">

View File

@ -1,4 +1,4 @@
import { Button, Flex, Text, Wrap, WrapItem } from '@chakra-ui/react'; import { Button, Flex, Text, HStack } from '@chakra-ui/react';
import { LuUser } from 'react-icons/lu'; import { LuUser } from 'react-icons/lu';
import { MdEdit, MdGroup } from 'react-icons/md'; import { MdEdit, MdGroup } from 'react-icons/md';
import { Route, Routes, useNavigate, useParams } from 'react-router-dom'; import { Route, Routes, useNavigate, useParams } from 'react-router-dom';
@ -71,7 +71,7 @@ export const ArtistDetailPage = () => {
> >
<Covers <Covers
data={dataArtist?.covers} data={dataArtist?.covers}
iconEmpty={LuUser} // TODO: iconEmpty={LuUser}
slideshow slideshow
/> />
<Flex direction="column" width="80%" marginRight="auto"> <Flex direction="column" width="80%" marginRight="auto">
@ -89,9 +89,9 @@ export const ArtistDetailPage = () => {
</Flex> </Flex>
</Flex> </Flex>
<Wrap spacing={BASE_WRAP_SPACING} marginX="auto" padding="20px" justify="center"> <HStack wrap="wrap" /*spacing={BASE_WRAP_SPACING}*/ marginX="auto" padding="20px" justify="center">
{albumIdsOfAnArtist?.map((data) => ( {albumIdsOfAnArtist?.map((data) => (
<WrapItem <Flex align="flex-start"
width={BASE_WRAP_WIDTH} width={BASE_WRAP_WIDTH}
height={BASE_WRAP_HEIGHT} height={BASE_WRAP_HEIGHT}
border="1px" border="1px"
@ -107,9 +107,9 @@ export const ArtistDetailPage = () => {
onClick={() => onSelectItem(data)} onClick={() => onSelectItem(data)}
> >
<DisplayAlbumId id={data} key={data} /> <DisplayAlbumId id={data} key={data} />
</WrapItem> </Flex>
))} ))}
</Wrap> </HStack>
<EmptyEnd /> <EmptyEnd />
<Routes> <Routes>
<Route path="edit-artist/:artistId" element={<ArtistEditPopUp />} /> <Route path="edit-artist/:artistId" element={<ArtistEditPopUp />} />

View File

@ -1,6 +1,6 @@
import { useState } from 'react'; import { useState } from 'react';
import { Button, Flex, Text, Tooltip, Wrap, WrapItem } from '@chakra-ui/react'; import { Button, Flex, Text, Tooltip, HStack, Span } from '@chakra-ui/react';
import { LuUser } from 'react-icons/lu'; import { LuUser } from 'react-icons/lu';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
@ -58,16 +58,16 @@ export const ArtistsPage = () => {
<> <>
<TopBar title="All artists"> <TopBar title="All artists">
<SearchInput onChange={setFilterName} /> <SearchInput onChange={setFilterName} />
<Tooltip label="Random play"> <Tooltip.Root aria-label="Random play">
<Button {...BUTTON_TOP_BAR_PROPERTY} onClick={onRandomPlay}> <Button {...BUTTON_TOP_BAR_PROPERTY} onClick={onRandomPlay}>
<MdOutlineForkRight /> <MdOutlineForkRight />
</Button> </Button>
</Tooltip> </Tooltip.Root>
</TopBar> </TopBar>
<PageLayout> <PageLayout>
<Wrap spacing={BASE_WRAP_SPACING} marginX="auto" padding="20px" justify="center"> <HStack wrap="wrap" /*spacing={BASE_WRAP_SPACING}*/ marginX="auto" padding="20px" justify="center">
{dataArtist?.map((data) => ( {dataArtist?.map((data) => (
<WrapItem <Flex align="flex-start"
width={BASE_WRAP_WIDTH} width={BASE_WRAP_WIDTH}
height={BASE_WRAP_HEIGHT} height={BASE_WRAP_HEIGHT}
border="1px" border="1px"
@ -87,7 +87,7 @@ export const ArtistsPage = () => {
data={data.covers} data={data.covers}
size={BASE_WRAP_ICON_SIZE} size={BASE_WRAP_ICON_SIZE}
height="full" height="full"
iconEmpty={LuUser} // iconEmpty={LuUser}
/> />
<Flex <Flex
direction="column" direction="column"
@ -98,22 +98,26 @@ export const ArtistsPage = () => {
overflowX="hidden" overflowX="hidden"
> >
<Text <Text
as="span" /*align="left"*/
align="left" /*noOfLines={[1, 2]}*/
fontSize="20px"
fontWeight="bold"
userSelect="none"
marginRight="auto"
overflow="hidden"
noOfLines={[1, 2]}
> >
{data.name} <Span
as="span"
fontSize="20px"
fontWeight="bold"
userSelect="none"
marginRight="auto"
overflow="hidden"
>
{data.name}
</Span>
</Text> </Text>
</Flex> </Flex>
</Flex> </Flex>
</WrapItem> </Flex>
))} ))}
</Wrap> </HStack>
<EmptyEnd /> <EmptyEnd />
</PageLayout> </PageLayout>
</> </>

View File

@ -76,7 +76,7 @@ export const GenderDetailPage = () => {
> >
<Covers <Covers
data={dataGender?.covers} data={dataGender?.covers}
iconEmpty={LuDisc3} // TODO: iconEmpty={LuDisc3}
slideshow slideshow
/> />
<Flex direction="column" width="80%" marginRight="auto"> <Flex direction="column" width="80%" marginRight="auto">

View File

@ -1,6 +1,5 @@
import { useState } from 'react'; import { useState } from 'react';
import { Wrap, WrapItem } from '@chakra-ui/react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { EmptyEnd } from '@/components/EmptyEnd'; import { EmptyEnd } from '@/components/EmptyEnd';
@ -11,6 +10,7 @@ import { TopBar } from '@/components/TopBar/TopBar';
import { DisplayGender } from '@/components/gender/DisplayGender'; import { DisplayGender } from '@/components/gender/DisplayGender';
import { useOrderedGenders } from '@/service/Gender'; import { useOrderedGenders } from '@/service/Gender';
import { useThemeMode } from '@/utils/theme-tools'; import { useThemeMode } from '@/utils/theme-tools';
import { Flex, HStack } from '@chakra-ui/react';
export const GendersPage = () => { export const GendersPage = () => {
const [filterTitle, setFilterTitle] = useState<string | undefined>(undefined); const [filterTitle, setFilterTitle] = useState<string | undefined>(undefined);
@ -36,9 +36,9 @@ export const GendersPage = () => {
<SearchInput onChange={setFilterTitle} /> <SearchInput onChange={setFilterTitle} />
</TopBar> </TopBar>
<PageLayout> <PageLayout>
<Wrap spacing="20px" marginX="auto" padding="20px" justify="center"> <HStack wrap="wrap" /*spacing="20px"*/ marginX="auto" padding="20px" justify="center">
{dataGenders.map((data) => ( {dataGenders.map((data) => (
<WrapItem <Flex align="flex-start"
width="270px" width="270px"
height="120px" height="120px"
border="1px" border="1px"
@ -54,9 +54,9 @@ export const GendersPage = () => {
onClick={() => onSelectItem(data.id)} onClick={() => onSelectItem(data.id)}
> >
<DisplayGender dataGender={data} /> <DisplayGender dataGender={data} />
</WrapItem> </Flex>
))} ))}
</Wrap> </HStack>
<EmptyEnd /> <EmptyEnd />
</PageLayout> </PageLayout>
</> </>

View File

@ -5,13 +5,7 @@ import {
Flex, Flex,
Input, Input,
Table, Table,
TableContainer,
Tbody,
Td,
Text, Text,
Th,
Thead,
Tr,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { LuTrash } from 'react-icons/lu'; import { LuTrash } from 'react-icons/lu';
import { MdCloudUpload } from 'react-icons/md'; import { MdCloudUpload } from 'react-icons/md';
@ -483,153 +477,145 @@ export const AddPage = () => {
addNewItem={addNewAlbum} addNewItem={addNewAlbum}
suggestion={suggestedAlbum} suggestion={suggestedAlbum}
/> />
<TableContainer> <Table.Root
<Table colorPalette="striped"
variant="striped" colorScheme="teal"
colorScheme="teal" background="gray.700"
background="gray.700" >
<Table.Header>
<Table.Row>
<Table.ColumnHeader>track ID</Table.ColumnHeader>
<Table.ColumnHeader width="full">Title</Table.ColumnHeader>
<Table.ColumnHeader>actions</Table.ColumnHeader>
</Table.Row>
</Table.Header>
<Table.Body>
{parsedElement.map((data) => (
<Table.Row key={data.uniqueId}>
<Table.Cell>
<Input
type="number"
pattern="[0-9]{0-4}"
placeholder="e?"
value={data.trackId}
onChange={(e) => onTrackId(data, e.target.value)}
backgroundColor={
data.trackIdDetected === true
? 'darkred'
: undefined
}
/>
</Table.Cell>
<Table.Cell>
<Input
type="text"
placeholder="Name of the Media"
value={data.title}
onChange={(e) => onTitle(data, e.target.value)}
backgroundColor={
data.title === '' ? 'darkred' : undefined
}
/>
{data.nameDetected === true && (
<>
<br />
<Text as="span" color="@danger">
^^^This title already exist !!!
</Text>
</>
)}
</Table.Cell>
<Table.Cell>
<Button
onClick={(e) =>
removeElementFromList(data, e.target)
}
>
<LuTrash /> Remove
</Button>
</Table.Cell>
</Table.Row>
))}
</Table.Body>
</Table.Root>
<Flex marginY="15px">
<Button
colorPalette="@primary"
onClick={sendFile}
disabled={!needSend}
marginLeft="auto"
marginRight="30px"
> >
<Thead> <MdCloudUpload /> Upload
<Tr> </Button>
<Th>track ID</Th> </Flex>
<Th width="full">Title</Th>
<Th>actions</Th>
</Tr>
</Thead>
<Tbody>
{parsedElement.map((data) => (
<Tr key={data.uniqueId}>
<Td>
<Input
type="number"
pattern="[0-9]{0-4}"
placeholder="e?"
value={data.trackId}
onChange={(e) => onTrackId(data, e.target.value)}
backgroundColor={
data.trackIdDetected === true
? 'darkred'
: undefined
}
/>
</Td>
<Td>
<Input
type="text"
placeholder="Name of the Media"
value={data.title}
onChange={(e) => onTitle(data, e.target.value)}
backgroundColor={
data.title === '' ? 'darkred' : undefined
}
/>
{data.nameDetected === true && (
<>
<br />
<Text as="span" color="@danger">
^^^This title already exist !!!
</Text>
</>
)}
</Td>
<Td>
<Button
onClick={(e) =>
removeElementFromList(data, e.target)
}
>
<LuTrash /> Remove
</Button>
</Td>
</Tr>
))}
</Tbody>
</Table>
<Flex marginY="15px">
<Button
variant="@primary"
onClick={sendFile}
disabled={!needSend}
marginLeft="auto"
marginRight="30px"
>
<MdCloudUpload /> Upload
</Button>
</Flex>
</TableContainer>
</> </>
)} )}
{listFileInBdd && ( {listFileInBdd && (
<> <Table.Root
<TableContainer> fontPalette="striped"
<Table colorScheme="teal"
variant="striped" background="gray.700"
colorScheme="teal" >
background="gray.700" <Table.Header>
> <Table.Row>
<Thead> <Table.ColumnHeader>track ID</Table.ColumnHeader>
<Tr> <Table.ColumnHeader width="full">Title</Table.ColumnHeader>
<Th>track ID</Th> <Table.ColumnHeader>actions</Table.ColumnHeader>
<Th width="full">Title</Th> </Table.Row>
<Th>actions</Th> </Table.Header>
</Tr> <Table.Body>
</Thead> {listFileInBdd.map((data) => (
<Tbody> <Table.Row>
{listFileInBdd.map((data) => ( <Table.Cell>
<Tr> <Text
<Td> color={
<Text data.episodeDetected === true ? 'red' : undefined
color={ }
data.episodeDetected === true ? 'red' : undefined >
} {data.trackId}
> </Text>
{data.trackId} </Table.Cell>
</Text> <Table.Cell>
</Td> <Text
<Td> color={
<Text data.nameDetected === true ? 'red' : undefined
color={ }
data.nameDetected === true ? 'red' : undefined >
} {data.title}
> </Text>
{data.title} </Table.Cell>
</Text> <Table.Cell></Table.Cell>
</Td> </Table.Row>
<Td></Td> ))}
</Tr> </Table.Body>
))} </Table.Root>
</Tbody>
</Table>
</TableContainer>
</>
)} )}
{parsedFailedElement && ( {parsedFailedElement && (
<> <>
<Text fontSize="30px">Rejected:</Text> <Text fontSize="30px">Rejected:</Text>
<TableContainer> <Table.Root
<Table colorPalette="striped"
variant="striped" colorScheme="teal"
colorScheme="teal" background="gray.700"
background="gray.700" >
> <Table.Header>
<Thead> <Table.Row>
<Tr> <Table.ColumnHeader maxWidth="80%">file</Table.ColumnHeader>
<Th maxWidth="80%">file</Th> <Table.ColumnHeader>Reason</Table.ColumnHeader>
<Th>Reason</Th> </Table.Row>
</Tr> </Table.Header>
</Thead> <Table.Body>
<Tbody> {parsedFailedElement.map((data) => (
{parsedFailedElement.map((data) => ( <Table.Row key={data.uniqueId}>
<Tr key={data.uniqueId}> <Table.Cell>{data.file.name}</Table.Cell>
<Td>{data.file.name}</Td> <Table.Cell>{data.reason}</Table.Cell>
<Td>{data.reason}</Td> </Table.Row>
</Tr> ))}
))} </Table.Body>
</Tbody> </Table.Root>
</Table>
</TableContainer>
</> </>
)} )}
</Flex> </Flex>

View File

@ -1,6 +1,6 @@
import { ReactElement } from 'react'; import { ReactElement } from 'react';
import { Center, Flex, Text, Wrap, WrapItem } from '@chakra-ui/react'; import { Center, Flex, HStack, Text } from '@chakra-ui/react';
import { LuCrown, LuDisc3, LuEar, LuFileAudio } from 'react-icons/lu'; import { LuCrown, LuDisc3, LuEar, LuFileAudio } from 'react-icons/lu';
import { MdGroup } from 'react-icons/md'; import { MdGroup } from 'react-icons/md';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
@ -58,9 +58,9 @@ export const HomePage = () => {
<> <>
<TopBar title="Home" /> <TopBar title="Home" />
<PageLayout> <PageLayout>
<Wrap spacing="20px" marginX="auto" padding="20px" justify="center"> <HStack wrap="wrap" /*spacing="20px"*/ marginX="auto" padding="20px" justify="center">
{homeList.map((data) => ( {homeList.map((data) => (
<WrapItem <Flex align="flex-start"
width="200px" width="200px"
height="190px" height="190px"
border="1px" border="1px"
@ -88,9 +88,9 @@ export const HomePage = () => {
</Text> </Text>
</Center> </Center>
</Flex> </Flex>
</WrapItem> </Flex>
))} ))}
</Wrap> </HStack>
</PageLayout> </PageLayout>
</> </>
); );

View File

@ -53,7 +53,7 @@ export const OnAirPage = () => {
} }
let newPlayed = trackOffset; let newPlayed = trackOffset;
if (newPlayed != undefined) { if (newPlayed != undefined) {
if (elementToRemoveOffset <= newPlayed) { if (elementToRemoveOffset < newPlayed) {
newPlayed = newPlayed - 1; newPlayed = newPlayed - 1;
} }
playInList(newPlayed, newList); playInList(newPlayed, newList);

View File

@ -1,6 +1,6 @@
import { ReactElement } from 'react'; import { ReactElement } from 'react';
import { Flex, Text, Wrap, WrapItem } from '@chakra-ui/react'; import { Flex, Text, HStack } from '@chakra-ui/react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { PageLayout } from '@/components/Layout/PageLayout'; import { PageLayout } from '@/components/Layout/PageLayout';
@ -48,9 +48,9 @@ export const TrackSelectionPage = () => {
<> <>
<TopBar title="All Tracks" /> <TopBar title="All Tracks" />
<PageLayout> <PageLayout>
<Wrap spacing="20px" marginX="auto" padding="20px" justify="center"> <HStack wrap="wrap" /*spacing="20px"*/ marginX="auto" padding="20px" justify="center">
{possibilities.map((data) => ( {possibilities.map((data) => (
<WrapItem <Flex align="flex-start"
width="75px" width="75px"
height="75px" height="75px"
border="1px" border="1px"
@ -76,9 +76,9 @@ export const TrackSelectionPage = () => {
{data.toUpperCase()} {data.toUpperCase()}
</Text> </Text>
</Flex> </Flex>
</WrapItem> </Flex>
))} ))}
</Wrap> </HStack>
</PageLayout> </PageLayout>
</> </>
); );

View File

@ -1,6 +1,6 @@
import { ReactElement } from 'react'; import { ReactElement } from 'react';
import { Box, Flex, Text, Wrap, WrapItem } from '@chakra-ui/react'; import { Box, Flex, Text } from '@chakra-ui/react';
import { useNavigate, useParams } from 'react-router-dom'; import { useNavigate, useParams } from 'react-router-dom';
import { EmptyEnd } from '@/components/EmptyEnd'; import { EmptyEnd } from '@/components/EmptyEnd';

View File

@ -6,9 +6,16 @@ import { useServiceContext } from '@/service/ServiceContext';
import { SessionState } from '@/service/SessionState'; import { SessionState } from '@/service/SessionState';
import { isBrowser } from '@/utils/layout'; import { isBrowser } from '@/utils/layout';
import { parseToken } from '@/utils/sso'; import { parseToken } from '@/utils/sso';
import { createListCollection } from '@chakra-ui/react';
const TOKEN_KEY = 'karusic-token-key-storage'; const TOKEN_KEY = 'karusic-token-key-storage';
export const USERS_COLLECTION = createListCollection({
items: [
{ label: "admin", value: "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiIxIiwiYXBwbGljYXRpb24iOiJrYXJ1c2ljIiwiaXNzIjoiS2FyQXV0aCIsInJpZ2h0Ijp7ImthcnVzaWMiOnsiQURNSU4iOnRydWUsIlVTRVIiOnRydWV9fSwibG9naW4iOiJIZWVyb1l1aSIsImV4cCI6MTcyNDIwNjc5NCwiaWF0IjoxNzI0MTY2ODM0fQ.TEST_SIGNATURE_FOR_LOCAL_TEST_AND_TEST_E2E" },
{ label: "NO_USER", value: "svelte" },
],
})
export const USERS = { export const USERS = {
admin: admin:
'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiIxIiwiYXBwbGljYXRpb24iOiJrYXJ1c2ljIiwiaXNzIjoiS2FyQXV0aCIsInJpZ2h0Ijp7ImthcnVzaWMiOnsiQURNSU4iOnRydWUsIlVTRVIiOnRydWV9fSwibG9naW4iOiJIZWVyb1l1aSIsImV4cCI6MTcyNDIwNjc5NCwiaWF0IjoxNzI0MTY2ODM0fQ.TEST_SIGNATURE_FOR_LOCAL_TEST_AND_TEST_E2E', 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiIxIiwiYXBwbGljYXRpb24iOiJrYXJ1c2ljIiwiaXNzIjoiS2FyQXV0aCIsInJpZ2h0Ijp7ImthcnVzaWMiOnsiQURNSU4iOnRydWUsIlVTRVIiOnRydWV9fSwibG9naW4iOiJIZWVyb1l1aSIsImV4cCI6MTcyNDIwNjc5NCwiaWF0IjoxNzI0MTY2ODM0fQ.TEST_SIGNATURE_FOR_LOCAL_TEST_AND_TEST_E2E',

View File

@ -1,14 +1,12 @@
import { ReactElement, ReactNode } from 'react'; import { ReactElement, ReactNode } from 'react';
import { ChakraProvider } from '@chakra-ui/react'; import { ChakraProvider, defaultSystem } from '@chakra-ui/react';
import { RenderOptions, render } from '@testing-library/react'; import { RenderOptions, render } from '@testing-library/react';
import { BrowserRouter } from 'react-router-dom'; import { BrowserRouter } from 'react-router-dom';
import theme from '@/theme';
const CustomWrapper = ({ children }: { children: ReactNode }) => { const CustomWrapper = ({ children }: { children: ReactNode }) => {
return ( return (
<ChakraProvider theme={theme}> <ChakraProvider value={defaultSystem}>
<BrowserRouter>{children}</BrowserRouter> <BrowserRouter>{children}</BrowserRouter>
</ChakraProvider> </ChakraProvider>
); );

View File

@ -1,24 +0,0 @@
export default {
sizes: {
'2xs': {
fontSize: '0.5em',
},
xs: {
fontSize: '0.6em',
},
sm: {
fontSize: '0.7em',
},
md: {
fontSize: '0.8em',
textTransform: 'none',
},
lg: {
fontSize: '0.9em',
textTransform: 'none',
},
},
defaultProps: {
size: 'md',
},
};

View File

@ -1,196 +0,0 @@
import { border, defineStyleConfig, keyframes } from '@chakra-ui/react';
import { isAccessible, mode, transparentize } from '@chakra-ui/theme-tools';
import { shadows } from '@/theme/foundations/shadows';
const shimmer = keyframes`
100% {
transform: translateX(100%);
}
`;
const customVariant = ({
theme,
bg,
bgHover = bg,
bgActive = bgHover,
color,
colorHover = color,
boxColorFocus = '#0x000000',
boxShadowHover = 'outline-over',
}) => {
const isColorAccessible = isAccessible(color, bg, {
size: 'large',
level: 'AA',
})(theme);
return {
bg,
color: isColorAccessible ? color : 'black',
border: '1px solid #00000000',
_focus: {
//border: `1px solid ${boxColorFocus}`,
border: `1px solid #000000`,
},
_hover: {
bg: bgHover,
color: isColorAccessible ? colorHover : 'black',
boxShadow: boxShadowHover,
_disabled: {
bg,
boxShadow: 'none',
},
},
_active: { bg: bgActive },
};
};
export default defineStyleConfig({
variants: {
// Custom variants
'@primary': (props) =>
customVariant({
theme: props.theme,
bg: mode('brand.600', 'brand.300')(props),
bgHover: mode('brand.700', 'brand.400')(props),
bgActive: mode('brand.600', 'brand.300')(props),
color: mode('white', 'brand.900')(props),
boxColorFocus: mode('brand.100', 'brand.600')(props),
}),
'@secondary': (props) =>
customVariant({
theme: props.theme,
bg: mode('brand.100', 'brand.900')(props),
bgHover: mode('brand.200', 'brand.800')(props),
bgActive: mode('brand.300', 'brand.700')(props),
color: mode('brand.700', 'brand.50')(props),
colorHover: mode('brand.800', 'brand.100')(props),
boxColorFocus: mode('brand.900', 'brand.300')(props),
}),
'@danger': (props) =>
customVariant({
theme: props.theme,
bg: mode('error.600', 'error.600')(props),
bgHover: mode('error.700', 'error.500')(props),
bgActive: mode('error.600', 'error.500')(props),
color: mode('white', 'error.900')(props),
boxColorFocus: mode('error.900', 'error.500')(props),
}),
'@success': (props) =>
customVariant({
theme: props.theme,
bg: mode('green.300', 'green.300')(props),
bgHover: mode('green.400', 'green.400')(props),
bgActive: mode('green.500', 'green.400')(props),
color: mode('white', 'green.900')(props),
boxColorFocus: mode('green.900', 'green.400')(props),
}),
'@progress': (props) => ({
...customVariant({
theme: props.theme,
bg: mode(`${props.colorScheme}.500`, `${props.colorScheme}.300`)(props),
bgHover: mode(
`${props.colorScheme}.600`,
`${props.colorScheme}.400`
)(props),
bgActive: mode(
`${props.colorScheme}.700`,
`${props.colorScheme}.500`
)(props),
color: mode('white', `${props.colorScheme}.900`)(props),
boxColorFocus: mode(
`${props.colorScheme}.900`,
`${props.colorScheme}.600`
)(props),
}),
overflow: 'hidden',
_after: !props.isLoading
? {
position: 'absolute',
top: 0,
right: 0,
bottom: 0,
left: 0,
transform: 'translateX(-100%)',
bgGradient: `linear(90deg, ${transparentize(
`${props.colorScheme}.100`,
0
)(props.theme)} 0, ${transparentize(
`${props.colorScheme}.100`,
0.2
)(props.theme)} 20%, ${transparentize(
`${props.colorScheme}.100`,
0.5
)(props.theme)} 60%, ${transparentize(
`${props.colorScheme}.100`,
0
)(props.theme)})`,
animation: `${shimmer} 3s infinite`,
content: '""',
}
: undefined,
}),
'@menu': (props) => ({
bg: mode('back.100', 'back.800')(props),
color: mode('brand.900', 'brand.100')(props),
borderRadius: 0,
border: 0,
_hover: { background: mode('back.300', 'back.600')(props) },
_focus: { border: 'none' },
fontSize: '20px',
textTransform: 'uppercase',
}),
// Default variants
solid: (props) => ({
bg:
props.colorScheme === 'gray'
? mode('gray.100', 'whiteAlpha.100')(props)
: `${props.colorScheme}.600`,
_hover: {
bg:
props.colorScheme === 'gray'
? mode('gray.200', 'whiteAlpha.200')(props)
: `${props.colorScheme}.700`,
},
_focus: {
boxShadow: `outline-${props.colorScheme}`,
},
}),
light: (props) => ({
bg:
props.colorScheme === 'gray'
? mode('gray.100', 'whiteAlpha.100')(props)
: `${props.colorScheme}.100`,
color:
props.colorScheme === 'gray'
? mode('gray.700', 'whiteAlpha.700')(props)
: `${props.colorScheme}.700`,
_hover: {
bg:
props.colorScheme === 'gray'
? mode('gray.200', 'whiteAlpha.200')(props)
: `${props.colorScheme}.200`,
color:
props.colorScheme === 'gray'
? mode('gray.800', 'whiteAlpha.800')(props)
: `${props.colorScheme}.800`,
},
_focus: {
boxShadow: `outline-${props.colorScheme}`,
},
}),
ghost: (props) => ({
bg: transparentize(`${props.colorScheme}.50`, 0.05)(props.theme),
borderRadius: 'full',
_hover: {
bg: transparentize(`${props.colorScheme}.50`, 0.15)(props.theme),
},
_focus: {
boxShadow: 'none',
},
}),
},
});

View File

@ -1,5 +0,0 @@
export default {
defaultProps: {
colorScheme: 'brand',
},
};

View File

@ -1,19 +0,0 @@
import { defineStyleConfig } from '@chakra-ui/react';
import { mode } from '@chakra-ui/theme-tools';
const flexTheme = defineStyleConfig({
variants: {
'@menu': (props) => ({
bg: mode('back.100', 'back.800')(props),
color: mode('brand.900', 'brand.100')(props),
borderRadius: 0,
border: 0,
_hover: { background: mode('back.300', 'back.600')(props) },
_focus: { border: 'none' },
fontSize: '20px',
}),
},
});
export default flexTheme;

View File

@ -1,12 +0,0 @@
export { default as Badge } from './badge';
export { default as Button } from './button';
export { default as Checkbox } from './checkbox';
export { default as Input } from './input';
export { default as NumberInput } from './numberInput';
export { default as Popover } from './popover';
export { default as Radio } from './radio';
export { default as Select } from './select';
export { default as Switch } from './switch';
export { default as Textarea } from './textarea';
export { default as Modal } from './modal';
export { default as Flex } from './flex';

View File

@ -1,25 +0,0 @@
import { getColor, mode } from '@chakra-ui/theme-tools';
export default {
variants: {
outline: (props) => {
const focusBorderColor = getColor(
props.theme,
props.focusBorderColor
? props.focusBorderColor
: mode('brand.500', 'brand.300')(props)
);
return {
field: {
bg: mode('gray.50', 'whiteAlpha.50')(props),
borderColor: mode('gray.200', 'whiteAlpha.100')(props),
color: mode('gray.800', 'gray.50')(props),
_focus: {
borderColor: focusBorderColor,
boxShadow: `0 0 0 1px ${focusBorderColor}`,
},
},
};
},
},
};

View File

@ -1,17 +0,0 @@
import { modalAnatomy as parts } from '@chakra-ui/anatomy';
import { createMultiStyleConfigHelpers } from '@chakra-ui/react';
const { definePartsStyle, defineMultiStyleConfig } =
createMultiStyleConfigHelpers(parts.keys);
const baseStyle = definePartsStyle({
header: {
textAlign: 'center',
},
});
const modalTheme = defineMultiStyleConfig({
baseStyle,
});
export default modalTheme;

View File

@ -1,33 +0,0 @@
import { numberInputAnatomy } from '@chakra-ui/anatomy';
import { createMultiStyleConfigHelpers } from '@chakra-ui/react';
import { getColor, mode } from '@chakra-ui/theme-tools';
const { definePartsStyle, defineMultiStyleConfig } =
createMultiStyleConfigHelpers(numberInputAnatomy.keys);
const baseStyle = definePartsStyle((props) => {
const focusBorderColor = getColor(
props.theme,
props.focusBorderColor
? props.focusBorderColor
: mode('brand.500', 'brand.300')(props)
);
return {
field: {
border: 0,
_focusVisible: {
borderColor: focusBorderColor,
boxShadow: `0 0 0 1px ${focusBorderColor}`,
ring: '1px',
ringColor: focusBorderColor,
ringOffset: '1px',
ringOffsetColor: focusBorderColor,
},
},
};
});
export default defineMultiStyleConfig({
baseStyle,
});

View File

@ -1,77 +0,0 @@
export default {
sizes: {
'3xs': {
content: {
width: '3xs',
},
},
'2xs': {
content: {
width: '2xs',
},
},
xs: {
content: {
width: 'xs',
},
},
sm: {
content: {
width: 'sm',
},
},
md: {
content: {
width: 'md',
},
},
lg: {
content: {
width: 'lg',
},
},
xl: {
content: {
width: 'xl',
},
},
'2xl': {
content: {
width: '2xl',
},
},
'3xl': {
content: {
width: '3xl',
},
},
'4xl': {
content: {
width: '4xl',
},
},
'5xl': {
content: {
width: '5xl',
},
},
'6xl': {
content: {
width: '6xl',
},
},
'7xl': {
content: {
width: '7xl',
},
},
'8xl': {
content: {
width: '8xl',
},
},
},
defaultProps: {
size: 'xs',
},
};

View File

@ -1,5 +0,0 @@
export default {
defaultProps: {
colorScheme: 'brand',
},
};

View File

@ -1,24 +0,0 @@
import { getColor, mode } from '@chakra-ui/theme-tools';
export default {
variants: {
outline: (props) => {
const focusBorderColor = getColor(
props.theme,
props.focusBorderColor
? props.focusBorderColor
: mode('brand.500', 'brand.300')(props)
);
return {
field: {
bg: mode('gray.50', 'whiteAlpha.50')(props),
borderColor: mode('blackAlpha.100', 'whiteAlpha.100')(props),
_focus: {
borderColor: focusBorderColor,
boxShadow: `0 0 0 1px ${focusBorderColor}`,
},
},
};
},
},
};

View File

@ -1,5 +0,0 @@
export default {
defaultProps: {
colorScheme: 'brand',
},
};

View File

@ -1,22 +0,0 @@
import { getColor, mode } from '@chakra-ui/theme-tools';
export default {
variants: {
outline: (props) => {
const focusBorderColor = getColor(
props.theme,
props.focusBorderColor
? props.focusBorderColor
: mode('brand.500', 'brand.300')(props)
);
return {
bg: mode('gray.50', 'whiteAlpha.50')(props),
borderColor: mode('blackAlpha.100', 'whiteAlpha.100')(props),
_focus: {
borderColor: focusBorderColor,
boxShadow: `0 0 0 1px ${focusBorderColor}`,
},
};
},
},
};

View File

@ -10,117 +10,100 @@ type ThemeModel = {
800: string; 800: string;
900: string; 900: string;
}; };
const isLightMode = false;
const reverseColor = (data: ThemeModel) => {
return {
50: data[900],
100: data[800],
200: data[700],
300: data[600],
400: data[500],
500: data[400],
600: data[300],
700: data[200],
800: data[100],
900: data[50],
};
};
const back = { const back = {
50: '#ebf4fa', 50: { value: '#ebf4fa' },
100: '#d1dbe0', 100: { value: '#d1dbe0' },
200: '#b6c2c9', 200: { value: '#b6c2c9' },
300: '#99aab4', 300: { value: '#99aab4' },
400: '#7c939e', 400: { value: '#7c939e' },
500: '#637985', 500: { value: '#637985' },
600: '#4d5e67', 600: { value: '#4d5e67' },
700: '#37444a', 700: { value: '#37444a' },
800: '#1f292e', 800: { value: '#1f292e' },
900: '#020f12', 900: { value: '#020f12' },
}; };
const brand = { const brand = {
50: '#e3edff', 50: { value: '#e3edff' },
100: '#b6c9fd', 100: { value: '#b6c9fd' },
200: '#88a5f7', 200: { value: '#88a5f7' },
300: '#5a81f2', 300: { value: '#5a81f2' },
400: '#2c5ded', 400: { value: '#2c5ded' },
500: '#1543d4', 500: { value: '#1543d4' },
600: '#0d34a5', 600: { value: '#0d34a5' },
700: '#062577', 700: { value: '#062577' },
800: '#02164a', 800: { value: '#02164a' },
900: '#00071e', 900: { value: '#00071e' },
}; };
const normalText = { const normalText = {
50: '#f2f2f2', 50: { value: '#f2f2f2' },
100: '#d9d9d9', 100: { value: '#d9d9d9' },
200: '#bfbfbf', 200: { value: '#bfbfbf' },
300: '#a6a6a6', 300: { value: '#a6a6a6' },
400: '#8c8c8c', 400: { value: '#8c8c8c' },
500: '#737373', 500: { value: '#737373' },
600: '#595959', 600: { value: '#595959' },
700: '#404040', 700: { value: '#404040' },
800: '#262626', 800: { value: '#262626' },
900: '#0d0d0d', 900: { value: '#0d0d0d' },
}; };
const green = { const green = {
50: '#f0fdf4', 50: { value: '#f0fdf4' },
100: '#dcfce7', 100: { value: '#dcfce7' },
200: '#bbf7d0', 200: { value: '#bbf7d0' },
300: '#86efac', 300: { value: '#86efac' },
400: '#4ade80', 400: { value: '#4ade80' },
500: '#22c55e', 500: { value: '#22c55e' },
600: '#16a34a', 600: { value: '#16a34a' },
700: '#15803d', 700: { value: '#15803d' },
800: '#166534', 800: { value: '#166534' },
900: '#14532d', 900: { value: '#14532d' },
}; };
const blue = { const blue = {
50: '#eff6ff', 50: { value: '#eff6ff' },
100: '#dbeafe', 100: { value: '#dbeafe' },
200: '#bfdbfe', 200: { value: '#bfdbfe' },
300: '#93c5fd', 300: { value: '#93c5fd' },
400: '#60a5fa', 400: { value: '#60a5fa' },
500: '#3b82f6', 500: { value: '#3b82f6' },
600: '#2563eb', 600: { value: '#2563eb' },
700: '#1d4ed8', 700: { value: '#1d4ed8' },
800: '#1e40af', 800: { value: '#1e40af' },
900: '#1e3a8a', 900: { value: '#1e3a8a' },
}; };
const orange = { const orange = {
50: '#fff7ed', 50: { value: '#fff7ed' },
100: '#ffedd5', 100: { value: '#ffedd5' },
200: '#fed7aa', 200: { value: '#fed7aa' },
300: '#fdba74', 300: { value: '#fdba74' },
400: '#fb923c', 400: { value: '#fb923c' },
500: '#f97316', 500: { value: '#f97316' },
600: '#ea580c', 600: { value: '#ea580c' },
700: '#c2410c', 700: { value: '#c2410c' },
800: '#9a3412', 800: { value: '#9a3412' },
900: '#7c2d12', 900: { value: '#7c2d12' },
}; };
const red = { const red = {
50: '#fef2f2', 50: { value: '#fef2f2' },
100: '#fee2e2', 100: { value: '#fee2e2' },
200: '#fecaca', 200: { value: '#fecaca' },
300: '#fca5a5', 300: { value: '#fca5a5' },
400: '#f87171', 400: { value: '#f87171' },
500: '#ef4444', 500: { value: '#ef4444' },
600: '#dc2626', 600: { value: '#dc2626' },
700: '#b91c1c', 700: { value: '#b91c1c' },
800: '#991b1b', 800: { value: '#991b1b' },
900: '#7f1d1d', 900: { value: '#7f1d1d' },
}; };
export const colors = { export const colors = {
// Update me with other Tailwind colors or with https://smart-swatch.netlify.app/ // Update me with other Tailwind colors or with https://smart-swatch.netlify.app/
brand: brand, brand: brand,
back: back, back: back,
text: normalText, text: normalText,
/// ????
success: green, success: green,
error: red, error: red,
warning: orange, warning: orange,

View File

@ -1,9 +0,0 @@
import { colors } from './colors';
import { shadows } from './shadows';
const foundations = {
colors,
shadows,
};
export default foundations;

View File

@ -1,26 +0,0 @@
import { transparentize } from '@chakra-ui/theme-tools';
import { colors } from './colors';
const createOutline = (colorScheme = 'gray') =>
`0 0 0 3px ${transparentize(`${colorScheme}.500`, 0.3)({ colors })}`;
export const shadows = {
outline: createOutline('brand'),
'outline-brand': '0 0 0 1px brand.900',
'outline-gray': createOutline('gray'),
'outline-over': `4px 4px 5px #00000088`,
'outline-darkgray': `0 0 0 3px ${transparentize(
'gray.500',
0.8
)({ colors })}`,
'outline-success': createOutline('success'),
'outline-warning': createOutline('warning'),
'outline-error': createOutline('error'),
'outline-doing': createOutline('doing'),
'outline-paused': createOutline('paused'),
layout: '0 0 24px 1px rgba(0, 0, 0, 0.05)',
smooth: 'inset 0px 0px 16px rgba(0, 0, 0, 0.05)',
// smooth-light is used for dark backgrounds
'smooth-light': 'inset 0px 0px 16px rgba(255, 255, 255, 0.1)',
};

View File

@ -1 +0,0 @@
export { theme as default } from './theme';

View File

@ -1,4 +1,4 @@
import { Button, ButtonGroup, IconButton, VStack } from '@chakra-ui/react'; import { Button, Group, IconButton, VStack } from '@chakra-ui/react';
import { HiMinus, HiPlus } from 'react-icons/hi'; import { HiMinus, HiPlus } from 'react-icons/hi';
const meta = { const meta = {
@ -9,69 +9,59 @@ export default meta;
export const Default = { export const Default = {
render: () => ( render: () => (
<ButtonGroup> <Group>
<Button>Default Button</Button> <Button>Default Button</Button>
<Button isLoading>Button</Button> <IconButton aria-label="Add" ><HiPlus /></IconButton>
<IconButton icon={<HiPlus />} aria-label="Add" /> </Group>
</ButtonGroup>
), ),
}; };
export const Primary = { export const Primary = {
render: () => ( render: () => (
<ButtonGroup> <Group>
<Button variant="@primary">Primary Button</Button> <Button colorPalette="@primary">Primary Button</Button>
<Button variant="@primary" isLoading> <IconButton colorPalette="@primary" aria-label="Add" ><HiPlus /></IconButton>
Button </Group>
</Button>
<IconButton variant="@primary" icon={<HiPlus />} aria-label="Add" />
</ButtonGroup>
), ),
}; };
export const Secondary = { export const Secondary = {
render: () => ( render: () => (
<ButtonGroup> <Group>
<Button variant="@secondary">Secondary Button</Button> <Button colorPalette="@secondary">Secondary Button</Button>
<Button variant="@secondary" isLoading> <IconButton colorPalette="@secondary" aria-label="Add" ><HiPlus /></IconButton>
Button </Group>
</Button>
<IconButton variant="@secondary" icon={<HiPlus />} aria-label="Add" />
</ButtonGroup>
), ),
}; };
export const Danger = { export const Danger = {
render: () => ( render: () => (
<ButtonGroup> <Group>
<Button variant="@danger">Danger Button</Button> <Button colorPalette="@danger">Danger Button</Button>
<Button variant="@danger" isLoading> <IconButton colorPalette="@danger" aria-label="Remove"><HiMinus /></IconButton>
Button </Group>
</Button>
<IconButton variant="@danger" icon={<HiMinus />} aria-label="Remove" />
</ButtonGroup>
), ),
}; };
export const Progress = { export const Progress = {
render: () => ( render: () => (
<ButtonGroup> <Group>
<VStack> <VStack>
<Button variant="@progress" colorScheme="brand"> <Button variant="solid" colorScheme="brand">
Progress Button with Brand ColorScheme Progress Button with Brand ColorScheme
</Button> </Button>
<Button variant="@progress" colorScheme="error"> <Button variant="solid" colorScheme="error">
Progress Button with Error ColorScheme Progress Button with Error ColorScheme
</Button> </Button>
<Button variant="@progress" isLoading> <Button variant="solid">
Button Button
</Button> </Button>
<IconButton <IconButton
variant="@progress" variant="solid"
icon={<HiMinus />} colorPalette="red"
aria-label="Remove" aria-label="Remove"
/> ><HiMinus /></IconButton>
</VStack> </VStack>
</ButtonGroup> </Group>
), ),
}; };

View File

@ -19,7 +19,7 @@ const Color = ({ children, ...rest }: FlexProps) => (
const Colors = ({ colorScheme = 'gray', ...rest }) => ( const Colors = ({ colorScheme = 'gray', ...rest }) => (
<HStack <HStack
spacing="0" // spacing="0"
overflow="hidden" overflow="hidden"
boxShadow="lg" boxShadow="lg"
color={`${colorScheme}.700`} color={`${colorScheme}.700`}

View File

@ -1,13 +1,13 @@
import { Styles } from '@chakra-ui/theme-tools'; // import { Styles } from '@chakra-ui/theme-tools';
import { mode } from '@chakra-ui/theme-tools'; // import { mode } from '@chakra-ui/theme-tools';
export const styles: Styles = { // export const styles: Styles = {
global: (props) => ({ // global: (props) => ({
body: { // body: {
overflowY: 'none', // overflowY: 'none',
bg: mode('back.50', 'back.700')(props), // bg: mode('back.50', 'back.700')(props),
color: mode('text.900', 'text.50')(props), // color: mode('text.900', 'text.50')(props),
fontFamily: 'Roboto, Helvetica, Arial, "sans-serif"', // fontFamily: 'Roboto, Helvetica, Arial, "sans-serif"',
}, // },
}), // }),
}; // };

View File

@ -1,17 +1,28 @@
import { extendTheme } from '@chakra-ui/react';
import * as components from './components'; import { createSystem, defaultConfig } from "@chakra-ui/react"
import foundations from './foundations'; import { colors } from "./foundations/colors"
import { styles } from './styles';
const config = { export const system = createSystem(defaultConfig, {
initialColorMode: 'dark', theme: {
useSystemColorMode: false, tokens: {
}; fonts: {
heading: { value: `Roboto, Helvetica, Arial, "sans-serif"` },
export const theme = extendTheme({ body: { value: `Roboto, Helvetica, Arial, "sans-serif"` },
config, },
styles, colors,
...foundations, },
components: { ...components }, semanticTokens: {
}); colors: {
brand: {
solid: { value: "{colors.brand.500}" },
contrast: { value: "{colors.brand.100}" },
fg: { value: "{colors.brand.700}" },
muted: { value: "{colors.brand.100}" },
subtle: { value: "{colors.brand.200}" },
emphasized: { value: "{colors.brand.300}" },
focusRing: { value: "{colors.brand.500}" },
},
},
},
},
})

View File

@ -6,8 +6,8 @@
import { DependencyList, useCallback, useEffect, useState } from 'react'; import { DependencyList, useCallback, useEffect, useState } from 'react';
import { RestErrorResponse } from '@/back-api'; import { RestErrorResponse } from '@/back-api';
import { useToastAPIError } from '@/utils/toastHook';
import { isNullOrUndefined } from '@/utils/validator'; import { isNullOrUndefined } from '@/utils/validator';
import { toasterAPIError } from '@/components/toaster';
export type DataStoreType<TYPE> = { export type DataStoreType<TYPE> = {
isLoading: boolean; isLoading: boolean;
@ -37,7 +37,6 @@ export const useDataStore = <TYPE>(
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState<RestErrorResponse | undefined>(undefined); const [error, setError] = useState<RestErrorResponse | undefined>(undefined);
const [data, setData] = useState<TYPE[]>([]); const [data, setData] = useState<TYPE[]>([]);
const toastAPIError = useToastAPIError();
// on instantiation ==> call the request of the data... // on instantiation ==> call the request of the data...
useEffect(() => { useEffect(() => {
@ -58,7 +57,7 @@ export const useDataStore = <TYPE>(
setIsLoading(false); setIsLoading(false);
}) })
.catch((error: RestErrorResponse) => { .catch((error: RestErrorResponse) => {
toastAPIError(error); toasterAPIError(error);
console.log( console.log(
`[${restApiName}] catch error: ${JSON.stringify(error, null, 2)}` `[${restApiName}] catch error: ${JSON.stringify(error, null, 2)}`
); );
@ -117,7 +116,7 @@ export const useDataStore = <TYPE>(
resolve(responseData); resolve(responseData);
}) })
.catch((error: RestErrorResponse) => { .catch((error: RestErrorResponse) => {
toastAPIError(error); toasterAPIError(error);
rejects(error); rejects(error);
}); });
}); });
@ -135,7 +134,7 @@ export const useDataStore = <TYPE>(
setData(filterData); setData(filterData);
}) })
.catch((error) => { .catch((error) => {
toastAPIError(error); toasterAPIError(error);
console.log( console.log(
`catch an error on delete: ... ${JSON.stringify(error, null, 2)}` `catch an error on delete: ... ${JSON.stringify(error, null, 2)}`
); );

View File

@ -1,9 +1,10 @@
import { useCallback } from 'react'; import { useCallback } from 'react';
import { useColorMode } from '@chakra-ui/react';
export const useThemeMode = () => { export const useThemeMode = () => {
const { colorMode, toggleColorMode, setColorMode } = useColorMode(); //const { colorMode, toggleColorMode, setColorMode } = useColorMode();
const colorMode = "dark";
const toggleColorMode = () => { }
const setColorMode = (_value: string) => { }
const mode = useCallback( const mode = useCallback(
(lightValue, darkValue) => (colorMode === 'dark' ? darkValue : lightValue), (lightValue, darkValue) => (colorMode === 'dark' ? darkValue : lightValue),

View File

@ -1,50 +0,0 @@
import { useCallback } from 'react';
import { UseToastOptions, useToast } from '@chakra-ui/react';
import { RestErrorResponse } from '@/back-api';
export const toastDefaultConfig: UseToastOptions = {
duration: 3000,
isClosable: true,
position: 'top-right',
variant: 'solid',
};
export const useToastError = () =>
useToast({
...toastDefaultConfig,
status: 'error',
duration: 5000,
});
export const useToastWarning = () =>
useToast({
...toastDefaultConfig,
status: 'warning',
});
export const useToastSuccess = () =>
useToast({
...toastDefaultConfig,
status: 'success',
});
export const useToastInfo = () =>
useToast({
...toastDefaultConfig,
status: 'info',
});
export const useToastAPIError = () => {
const toastError = useToastError();
return useCallback(
(error: RestErrorResponse) => {
toastError({
title: `[${error.status}] ${error.statusMessage}`,
description: error.message,
});
},
[toastError]
);
};