[DEV] correct models

This commit is contained in:
Edouard DUPIN 2025-02-10 19:40:27 +01:00
parent 44b4fa37d3
commit 332c65360d
73 changed files with 1431 additions and 1283 deletions

View File

@ -1,6 +0,0 @@
{
"display": "2025-02-09",
"version": "0.0.1-dev\n - 2025-02-09T21:15:14+01:00",
"commit": "0.0.1-dev\n",
"date": "2025-02-09T21:15:14+01:00"
}

View File

@ -1,25 +0,0 @@
const dayjs = require('dayjs');
const fs = require('fs');
const generateAppBuild = () => {
const getVersion = () => fs.readFileSync('version.txt', 'utf8');
const commit = process.env.VERCEL_GIT_COMMIT_SHA
? process.env.VERCEL_GIT_COMMIT_SHA
: getVersion();
const appBuildContent = {
display: `${dayjs().format('YYYY-MM-DD')}`,
version: `${commit} - ${dayjs().format()}`,
commit,
date: dayjs().format(),
};
fs.writeFileSync(
'./app-build.json',
JSON.stringify(appBuildContent, null, 2)
);
};
generateAppBuild();

View File

@ -7,11 +7,6 @@ const config: KnipConfig = {
// Related to tests // Related to tests
'tests/**', 'tests/**',
'**.conf.js', '**.conf.js',
'steps.d.ts',
'steps_file.js',
'env_ci/codecept.conf.js',
// Generic components are useful.
'src/components/**',
], ],
}; };

View File

@ -18,7 +18,7 @@
"test": "vitest run", "test": "vitest run",
"test:watch": "vitest watch", "test:watch": "vitest watch",
"build": "tsc && vite build", "build": "tsc && vite build",
"static:build": "node build.js && pnpm build", "static:build": "pnpm build",
"dev": "vite", "dev": "vite",
"pretty": "prettier -w .", "pretty": "prettier -w .",
"lint": "pnpm tsc --noEmit", "lint": "pnpm tsc --noEmit",

View File

@ -1,9 +1,9 @@
import { EnvDevelopment } from './components/EnvDevelopment/EnvDevelopment';
import { ErrorBoundary } from '@/errors/ErrorBoundary'; import { ErrorBoundary } from '@/errors/ErrorBoundary';
import { AppRoutes } from '@/scene/AppRoutes'; import { AppRoutes } from '@/scene/AppRoutes';
import { ServiceContextProvider } from '@/service/ServiceContext'; import { ServiceContextProvider } from '@/service/ServiceContext';
import { EnvDevelopment } from './components/EnvDevelopment/EnvDevelopment';
export const App = () => { export const App = () => {
return ( return (
<ServiceContextProvider> <ServiceContextProvider>

View File

@ -3,13 +3,14 @@ import { ReactElement, useEffect, useState } from 'react';
import { Box, BoxProps, Flex, FlexProps } 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 { Icon } from './Icon';
import { ObjectId } from '@/back-api'; import { ObjectId } from '@/back-api';
import { DataUrlAccess } from '@/utils/data-url-access';
export type CoversProps = Omit<BoxProps, "iconEmpty"> & { import { Icon } from './Icon';
export type CoversProps = Omit<BoxProps, 'iconEmpty'> & {
data?: ObjectId[]; data?: ObjectId[];
size?: BoxProps["width"]; size?: BoxProps['width'];
iconEmpty?: ReactElement; iconEmpty?: ReactElement;
slideshow?: boolean; slideshow?: boolean;
}; };
@ -33,7 +34,9 @@ export const Covers = ({
setPreviousImageIndex(currentImageIndex); setPreviousImageIndex(currentImageIndex);
setTopOpacity(0.0); setTopOpacity(0.0);
setTimeout(() => { setTimeout(() => {
setCurrentImageIndex((prevIndex) => (prevIndex + 1) % (data?.length ?? 1)); setCurrentImageIndex(
(prevIndex) => (prevIndex + 1) % (data?.length ?? 1)
);
setTopOpacity(1.0); setTopOpacity(1.0);
}, 1500); }, 1500);
}, 3000); }, 3000);
@ -60,17 +63,26 @@ 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 return (
<Flex
position="relative" position="relative"
// {...rest} // {...rest}
maxWidth={size} maxWidth={size}
width={size} width={size}
height={size} height={size}
overflow="hidden"> overflow="hidden"
>
<Image <Image
src={urlPrevious} src={urlPrevious}
loading="lazy" loading="lazy"
@ -96,4 +108,5 @@ export const Covers = ({
zIndex={2} zIndex={2}
/> />
</Flex> </Flex>
);
}; };

View File

@ -1,26 +1,25 @@
import { import {
Box, Box,
Button, Button,
createListCollection,
Dialog, Dialog,
Select, Select,
Span, Span,
Stack, Stack,
Text, Text,
createListCollection,
useDisclosure, useDisclosure,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { useSessionService } from '@/service/session';
import { useLogin } from '@/scene/connection/useLogin'; import { useLogin } from '@/scene/connection/useLogin';
import { useSessionService } from '@/service/session';
export const USERS_COLLECTION = createListCollection({ export const USERS_COLLECTION = createListCollection({
items: [ items: [
{ label: "karadmin", value: "adminA@666" }, { label: 'karadmin', value: 'adminA@666' },
{ label: "karuser", value: "userA@666" }, { label: 'karuser', value: 'userA@666' },
{ label: "NO_USER", value: "" }, { label: 'NO_USER', value: '' },
], ],
}) });
export const EnvDevelopment = () => { export const EnvDevelopment = () => {
const dialog = useDisclosure(); const dialog = useDisclosure();
@ -86,14 +85,23 @@ export const EnvDevelopment = () => {
<Dialog.Header>Development tools</Dialog.Header> <Dialog.Header>Development tools</Dialog.Header>
<Dialog.Body> <Dialog.Body>
<Stack> <Stack>
<Text>User <Span color="red" fontWeight="bold">{lastError}</Span></Text> <Text>
User{' '}
<Span color="red" fontWeight="bold">
{lastError}
</Span>
</Text>
<Select.Root collection={USERS_COLLECTION}> <Select.Root collection={USERS_COLLECTION}>
<Select.Trigger> <Select.Trigger>
<Select.ValueText placeholder="Select test user" /> <Select.ValueText placeholder="Select test user" />
</Select.Trigger> </Select.Trigger>
<Select.Content> <Select.Content>
{USERS_COLLECTION.items.map((value) => ( {USERS_COLLECTION.items.map((value) => (
<Select.Item item={value} key={value.value}onClick={()=>handleChange(value.label, value.value)} > <Select.Item
item={value}
key={value.value}
onClick={() => handleChange(value.label, value.value)}
>
{value.label} {value.label}
</Select.Item> </Select.Item>
))} ))}
@ -110,4 +118,3 @@ export const EnvDevelopment = () => {
</> </>
); );
}; };

View File

@ -1,9 +1,6 @@
import { import { ReactNode, forwardRef } from 'react';
Box,
Flex, import { Box, Flex, FlexProps } from '@chakra-ui/react';
FlexProps,
} from '@chakra-ui/react';
import { forwardRef, ReactNode } from 'react';
export type IconProps = FlexProps & { export type IconProps = FlexProps & {
children: ReactNode; children: ReactNode;
@ -14,7 +11,8 @@ export type IconProps = FlexProps & {
export const Icon = forwardRef<HTMLDivElement, IconProps>( export const Icon = forwardRef<HTMLDivElement, IconProps>(
({ children, color, sizeIcon = '1em', ...rest }, ref) => { ({ children, color, sizeIcon = '1em', ...rest }, ref) => {
return ( return (
<Flex flex="none" <Flex
flex="none"
minWidth={sizeIcon} minWidth={sizeIcon}
minHeight={sizeIcon} minHeight={sizeIcon}
maxWidth={sizeIcon} maxWidth={sizeIcon}
@ -22,7 +20,8 @@ export const Icon = forwardRef<HTMLDivElement, IconProps>(
align="center" align="center"
padding="1px" padding="1px"
ref={ref} ref={ref}
{...rest}> {...rest}
>
<Box <Box
marginX="auto" marginX="auto"
width="100%" width="100%"

View File

@ -4,8 +4,8 @@ import { Flex, FlexProps } from '@chakra-ui/react';
import { useLocation } from 'react-router-dom'; import { useLocation } from 'react-router-dom';
import { PageLayout } from '@/components/Layout/PageLayout'; import { PageLayout } from '@/components/Layout/PageLayout';
import { colors } from '@/theme/colors';
import { useColorModeValue } from '@/components/ui/color-mode'; import { useColorModeValue } from '@/components/ui/color-mode';
import { colors } from '@/theme/colors';
export type LayoutProps = FlexProps & { export type LayoutProps = FlexProps & {
children: ReactNode; children: ReactNode;

View File

@ -1,22 +1,20 @@
export { export {
ParameterLayoutContent as Content, ParameterLayoutContent as Content,
type ParameterLayoutContentProps as ContentProps type ParameterLayoutContentProps as ContentProps,
} from './ParameterLayoutContent'; } from './ParameterLayoutContent';
export { export {
ParameterLayoutFooter as Footer, ParameterLayoutFooter as Footer,
type ParameterLayoutFooterProps as FooterProps type ParameterLayoutFooterProps as FooterProps,
} from './ParameterLayoutFooter'; } from './ParameterLayoutFooter';
export { export {
ParameterLayoutHeader as Header, ParameterLayoutHeader as Header,
type ParameterLayoutHeaderProps as HeaderProps type ParameterLayoutHeaderProps as HeaderProps,
} from './ParameterLayoutHeader'; } from './ParameterLayoutHeader';
export { export {
ParameterLayoutHeaderBase as HeaderBase, ParameterLayoutHeaderBase as HeaderBase,
type ParameterLayoutHeaderBaseProps as HeaderBaseProps type ParameterLayoutHeaderBaseProps as HeaderBaseProps,
} from './ParameterLayoutHeaderBase'; } from './ParameterLayoutHeaderBase';
export { export {
ParameterLayoutRoot as Root, ParameterLayoutRoot as Root,
type ParameterLayoutRootProps as RootProps type ParameterLayoutRootProps as RootProps,
} from './ParameterLayoutRoot'; } from './ParameterLayoutRoot';

View File

@ -1,19 +1,25 @@
import { Flex } from "@chakra-ui/react"; import { ReactNode } from 'react';
import { ReactNode } from "react";
import { Flex } from '@chakra-ui/react';
export type ParameterLayoutContentProps = { export type ParameterLayoutContentProps = {
children?: ReactNode; children?: ReactNode;
} };
export const ParameterLayoutContent = ({children}:ParameterLayoutContentProps) => { export const ParameterLayoutContent = ({
return <Flex children,
}: ParameterLayoutContentProps) => {
return (
<Flex
direction="column" direction="column"
width="full" width="full"
borderY="1px solid black" borderY="1px solid black"
paddingY="15px" paddingY="15px"
paddingX="25px" paddingX="25px"
minHeight="10px" minHeight="10px"
background="gray.700"> background="gray.700"
>
{children} {children}
</Flex> </Flex>
} );
};

View File

@ -1,16 +1,17 @@
import { Flex } from "@chakra-ui/react"; import { ReactNode } from 'react';
import { ReactNode } from "react";
import { Flex } from '@chakra-ui/react';
export type ParameterLayoutFooterProps = { export type ParameterLayoutFooterProps = {
children?: ReactNode; children?: ReactNode;
} };
export const ParameterLayoutFooter = ({children}:ParameterLayoutFooterProps) => { export const ParameterLayoutFooter = ({
return <Flex children,
width="full" }: ParameterLayoutFooterProps) => {
paddingY="15px" return (
paddingX="25px" <Flex width="full" paddingY="15px" paddingX="25px" minHeight="10px">
minHeight="10px">
{children} {children}
</Flex> </Flex>
} );
};

View File

@ -1,17 +1,17 @@
import { Flex } from "@chakra-ui/react"; import { ReactNode } from 'react';
import { ReactNode } from "react";
import { Flex } from '@chakra-ui/react';
export type ParameterLayoutHeaderProps = { export type ParameterLayoutHeaderProps = {
children?: ReactNode; children?: ReactNode;
} };
export const ParameterLayoutHeader = ({children}:ParameterLayoutHeaderProps) => { export const ParameterLayoutHeader = ({
return <Flex children,
width="full" }: ParameterLayoutHeaderProps) => {
paddingY="15px" return (
paddingX="25px" <Flex width="full" paddingY="15px" paddingX="25px" minHeight="10px">
minHeight="10px"
>
{children} {children}
</Flex> </Flex>
} );
};

View File

@ -1,23 +1,24 @@
import { Flex, Text } from "@chakra-ui/react"; import { Flex, Text } from '@chakra-ui/react';
import { ParameterLayoutHeader } from "./ParameterLayoutHeader";
import { ParameterLayoutHeader } from './ParameterLayoutHeader';
export type ParameterLayoutHeaderBaseProps = { export type ParameterLayoutHeaderBaseProps = {
title: string; title: string;
description?: string, description?: string;
} };
export const ParameterLayoutHeaderBase = ({ export const ParameterLayoutHeaderBase = ({
title, title,
description, description,
}: ParameterLayoutHeaderBaseProps) => { }: ParameterLayoutHeaderBaseProps) => {
return <ParameterLayoutHeader> return (
<ParameterLayoutHeader>
<Flex direction="column"> <Flex direction="column">
<Text <Text fontSize="25px" fontWeight="bold">
fontSize="25px"
fontWeight="bold">
{title} {title}
</Text> </Text>
{description && <Text>{description}</Text>} {description && <Text>{description}</Text>}
</Flex> </Flex>
</ParameterLayoutHeader> </ParameterLayoutHeader>
} );
};

View File

@ -1,17 +1,24 @@
import { ReactNode } from 'react';
import { VStack } from '@chakra-ui/react'; import { VStack } from '@chakra-ui/react';
import { ReactNode } from 'react';
export type ParameterLayoutRootProps = { export type ParameterLayoutRootProps = {
children?: ReactNode; children?: ReactNode;
} };
export const ParameterLayoutRoot = ({ children }: ParameterLayoutRootProps) => { export const ParameterLayoutRoot = ({ children }: ParameterLayoutRootProps) => {
return <VStack gap="0px" marginX="15%" marginY="20px" justify="center" return (
<VStack
gap="0px"
marginX="15%"
marginY="20px"
justify="center"
//borderRadius="20px" //borderRadius="20px"
borderRadius="0px" borderRadius="0px"
border="1px solid black" border="1px solid black"
background="gray.500"> background="gray.500"
>
{children} {children}
</VStack> </VStack>
} );
};

View File

@ -1,9 +1,6 @@
import { useState } from 'react'; import { useState } from 'react';
import { import { Group, Input } from '@chakra-ui/react';
Group,
Input,
} from '@chakra-ui/react';
import { MdSearch } from 'react-icons/md'; import { MdSearch } from 'react-icons/md';
export type SearchInputProps = { export type SearchInputProps = {

View File

@ -2,15 +2,15 @@ import { ReactNode } from 'react';
import { import {
Box, Box,
Button,
ConditionalValue,
Flex, Flex,
HStack, HStack,
IconButton, IconButton,
Text,
useDisclosure,
Button,
ConditionalValue,
Span, Span,
Text,
chakra, chakra,
useDisclosure,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { import {
LuAlignJustify, LuAlignJustify,
@ -22,13 +22,18 @@ import {
LuSettings, LuSettings,
LuSun, LuSun,
} from 'react-icons/lu'; } from 'react-icons/lu';
import {
MdHelp,
MdHome,
MdKey,
MdMore,
MdOutlineDashboardCustomize,
MdOutlineGroup,
MdSettings,
MdSupervisedUserCircle,
} from 'react-icons/md';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { useServiceContext } from '@/service/ServiceContext';
import { colors } from '@/theme/colors';
import { useSessionService } from '@/service/session';
import { MdHelp, MdHome, MdKey, MdMore, MdOutlineDashboardCustomize, MdOutlineGroup, MdSettings, MdSupervisedUserCircle } from 'react-icons/md';
import { MenuContent, MenuItem, MenuRoot, MenuTrigger } from '@/components/ui/menu';
import { useColorMode, useColorModeValue } from '@/components/ui/color-mode'; import { useColorMode, useColorModeValue } from '@/components/ui/color-mode';
import { import {
DrawerBody, DrawerBody,
@ -36,11 +41,22 @@ import {
DrawerHeader, DrawerHeader,
DrawerRoot, DrawerRoot,
} from '@/components/ui/drawer'; } from '@/components/ui/drawer';
import {
MenuContent,
MenuItem,
MenuRoot,
MenuTrigger,
} from '@/components/ui/menu';
import { useServiceContext } from '@/service/ServiceContext';
import { useSessionService } from '@/service/session';
import { colors } from '@/theme/colors';
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: "ghost" as ConditionalValue<"ghost" | "outline" | "solid" | "subtle" | "surface" | "plain" | undefined>, variant: 'ghost' as ConditionalValue<
'ghost' | 'outline' | 'solid' | 'subtle' | 'surface' | 'plain' | undefined
>,
//colorPalette: "brand", //colorPalette: "brand",
fontSize: '20px', fontSize: '20px',
textTransform: 'uppercase', textTransform: 'uppercase',
@ -52,13 +68,20 @@ export type TopBarProps = {
title?: string; title?: string;
}; };
const ButtonMenuLeft = ({ dest, title, icon, const ButtonMenuLeft = ({
onClickEnd = () => { }, }: { dest,
dest: string, title: string, icon: ReactNode title,
icon,
onClickEnd = () => {},
}: {
dest: string;
title: string;
icon: ReactNode;
onClickEnd?: () => void; onClickEnd?: () => void;
}) => { }) => {
const navigate = useNavigate(); const navigate = useNavigate();
return <> return (
<>
<Button <Button
background="#00000000" background="#00000000"
borderRadius="0px" borderRadius="0px"
@ -69,14 +92,17 @@ const ButtonMenuLeft = ({ dest, title, icon,
width="full" width="full"
{...BUTTON_TOP_BAR_PROPERTY} {...BUTTON_TOP_BAR_PROPERTY}
> >
<Box asChild style={{ width: "45px", height: "45px" }}>{icon}</Box> <Box asChild style={{ width: '45px', height: '45px' }}>
{icon}
</Box>
<Text paddingLeft="3px" fontWeight="bold" marginRight="auto"> <Text paddingLeft="3px" fontWeight="bold" marginRight="auto">
{title} {title}
</Text> </Text>
</Button> </Button>
<Box marginY="5" marginX="10" height="2px" background="brand.600" /> <Box marginY="5" marginX="10" height="2px" background="brand.600" />
</> </>
} );
};
export const TopBar = ({ title, children }: TopBarProps) => { export const TopBar = ({ title, children }: TopBarProps) => {
const { colorMode, toggleColorMode } = useColorMode(); const { colorMode, toggleColorMode } = useColorMode();
@ -138,7 +164,10 @@ export const TopBar = ({ title, children }: TopBarProps) => {
<Flex right="0"> <Flex right="0">
{!session?.token && ( {!session?.token && (
<> <>
<Button {...BUTTON_TOP_BAR_PROPERTY} onClick={() => navigate('/login')}> <Button
{...BUTTON_TOP_BAR_PROPERTY}
onClick={() => navigate('/login')}
>
<LuLogIn /> <LuLogIn />
<Text paddingLeft="3px" fontWeight="bold"> <Text paddingLeft="3px" fontWeight="bold">
Sign-in Sign-in
@ -163,24 +192,55 @@ export const TopBar = ({ title, children }: TopBarProps) => {
//asChild //asChild
{...BUTTON_TOP_BAR_PROPERTY} {...BUTTON_TOP_BAR_PROPERTY}
width={TOP_BAR_HEIGHT} width={TOP_BAR_HEIGHT}
><LuCircleUserRound/></IconButton> >
<LuCircleUserRound />
</IconButton>
</MenuTrigger> </MenuTrigger>
<MenuContent> <MenuContent>
<MenuItem value="user" valueText="user" color={useColorModeValue('brand.800', 'brand.200')}> <MenuItem
value="user"
valueText="user"
color={useColorModeValue('brand.800', 'brand.200')}
>
<MdSupervisedUserCircle /> <MdSupervisedUserCircle />
<Box flex="1">Sign in as {session?.login ?? 'Fail'}</Box> <Box flex="1">Sign in as {session?.login ?? 'Fail'}</Box>
</MenuItem> </MenuItem>
<MenuItem value="Settings" valueText="Settings" onClick={() => navigate('/settings')}><LuSettings />Settings</MenuItem> <MenuItem
<MenuItem value="Help" valueText="Help" onClick={() => navigate('/help')}><MdHelp /> Help</MenuItem> value="Settings"
<MenuItem value="Sign-out" valueText="Sign-out" onClick={() => navigate('/signout')}> valueText="Settings"
onClick={() => navigate('/settings')}
>
<LuSettings />
Settings
</MenuItem>
<MenuItem
value="Help"
valueText="Help"
onClick={() => navigate('/help')}
>
<MdHelp /> Help
</MenuItem>
<MenuItem
value="Sign-out"
valueText="Sign-out"
onClick={() => navigate('/signout')}
>
<LuLogOut /> Sign-out <LuLogOut /> Sign-out
</MenuItem> </MenuItem>
{colorMode === 'light' ? ( {colorMode === 'light' ? (
<MenuItem value="set-dark" valueText="set-dark" onClick={toggleColorMode}> <MenuItem
value="set-dark"
valueText="set-dark"
onClick={toggleColorMode}
>
<LuMoon /> Set dark mode <LuMoon /> Set dark mode
</MenuItem> </MenuItem>
) : ( ) : (
<MenuItem value="set-light" valueText="set-light" onClick={toggleColorMode}> <MenuItem
value="set-light"
valueText="set-light"
onClick={toggleColorMode}
>
<LuSun /> Set light mode <LuSun /> Set light mode
</MenuItem> </MenuItem>
)} )}
@ -194,8 +254,7 @@ export const TopBar = ({ title, children }: TopBarProps) => {
open={drawerDisclose.open} open={drawerDisclose.open}
data-testid="top-bar_drawer-root" data-testid="top-bar_drawer-root"
> >
<DrawerContent <DrawerContent data-testid="top-bar_drawer-content">
data-testid="top-bar_drawer-content">
<DrawerHeader <DrawerHeader
paddingY="auto" paddingY="auto"
as="button" as="button"
@ -205,21 +264,43 @@ export const TopBar = ({ title, children }: TopBarProps) => {
color={useColorModeValue('brand.900', 'brand.50')} color={useColorModeValue('brand.900', 'brand.50')}
textTransform="uppercase" textTransform="uppercase"
> >
<HStack <HStack {...BUTTON_TOP_BAR_PROPERTY} cursor="pointer">
{...BUTTON_TOP_BAR_PROPERTY} cursor="pointer">
<LuArrowBigLeft /> <LuArrowBigLeft />
<Span paddingLeft="3px"> <Span paddingLeft="3px">karso</Span>
karso
</Span>
</HStack> </HStack>
</DrawerHeader> </DrawerHeader>
<DrawerBody paddingX="0px"> <DrawerBody paddingX="0px">
<Box marginY="3" /> <Box marginY="3" />
<ButtonMenuLeft onClickEnd={drawerDisclose.onClose} dest="/" title="Home" icon={<MdHome />} /> <ButtonMenuLeft
<ButtonMenuLeft onClickEnd={drawerDisclose.onClose} dest="/change-password" title="Change password" icon={<MdKey />} /> onClickEnd={drawerDisclose.onClose}
<ButtonMenuLeft onClickEnd={drawerDisclose.onClose} dest="/admin-settings" title="Admin settings" icon={<MdSettings />} /> dest="/"
<ButtonMenuLeft onClickEnd={drawerDisclose.onClose} dest="/manage-account" title="Manage account" icon={<MdOutlineGroup />} /> title="Home"
<ButtonMenuLeft onClickEnd={drawerDisclose.onClose} dest="/manage-application" title="Manage application" icon={<MdOutlineDashboardCustomize />} /> icon={<MdHome />}
/>
<ButtonMenuLeft
onClickEnd={drawerDisclose.onClose}
dest="/change-password"
title="Change password"
icon={<MdKey />}
/>
<ButtonMenuLeft
onClickEnd={drawerDisclose.onClose}
dest="/admin-settings"
title="Admin settings"
icon={<MdSettings />}
/>
<ButtonMenuLeft
onClickEnd={drawerDisclose.onClose}
dest="/manage-account"
title="Manage account"
icon={<MdOutlineGroup />}
/>
<ButtonMenuLeft
onClickEnd={drawerDisclose.onClose}
dest="/manage-application"
title="Manage application"
icon={<MdOutlineDashboardCustomize />}
/>
</DrawerBody> </DrawerBody>
</DrawerContent> </DrawerContent>
</DrawerRoot> </DrawerRoot>

View File

@ -1,9 +1,9 @@
import { ReactNode, useState } from 'react'; import { ReactNode, useState } from 'react';
import { LuMenu } from 'react-icons/lu'; import { LuMenu } from 'react-icons/lu';
import { MenuContent, MenuItem, MenuRoot, MenuTrigger } from '../ui/menu';
import { Button } from '../ui/button';
import { Button } from '../ui/button';
import { MenuContent, MenuItem, MenuRoot, MenuTrigger } from '../ui/menu';
export type MenuElement = { export type MenuElement = {
icon?: ReactNode; icon?: ReactNode;
@ -20,22 +20,28 @@ export const ContextMenu = ({ elements }: ContextMenuProps) => {
return <></>; return <></>;
} }
return ( return (
<MenuRoot <MenuRoot data-testid="context-menu">
data-testid="context-menu"> <MenuTrigger
<MenuTrigger asChild asChild
marginY="auto" marginY="auto"
marginRight="4px" marginRight="4px"
data-testid="context-menu_trigger"> data-testid="context-menu_trigger"
>
{/* This is very stupid, we need to set as span to prevent a button in button... WTF */} {/* This is very stupid, we need to set as span to prevent a button in button... WTF */}
<Button variant="ghost" color="brand.500"> <Button variant="ghost" color="brand.500">
<LuMenu /> <LuMenu />
</Button> </Button>
</MenuTrigger> </MenuTrigger>
<MenuContent <MenuContent data-testid="context-menu_content">
data-testid="context-menu_content">
{elements?.map((data) => ( {elements?.map((data) => (
<MenuItem key={data.name} value={data.name} onClick={data.onClick} height="65px" fontSize="25px" <MenuItem
data-test-id="context-menu_item" > key={data.name}
value={data.name}
onClick={data.onClick}
height="65px"
fontSize="25px"
data-test-id="context-menu_item"
>
{data.icon} {data.icon}
{data.name} {data.name}
</MenuItem> </MenuItem>

View File

@ -3,6 +3,7 @@ import { RefObject } from 'react';
import { Input } from '@chakra-ui/react'; import { Input } from '@chakra-ui/react';
import { FormGroup, FormGroupProps } from '@/components/form/FormGroup'; import { FormGroup, FormGroupProps } from '@/components/form/FormGroup';
import { useFormidableContextElement } from '../formidable'; import { useFormidableContextElement } from '../formidable';
export type FormInputProps = { export type FormInputProps = {
@ -21,10 +22,7 @@ export const FormInput = ({
}: FormInputProps) => { }: FormInputProps) => {
const { value, onChange } = useFormidableContextElement(name); const { value, onChange } = useFormidableContextElement(name);
return ( return (
<FormGroup <FormGroup name={name} {...rest}>
name={name}
{...rest}
>
<Input <Input
ref={ref} ref={ref}
type="text" type="text"

View File

@ -4,6 +4,7 @@ import { Box } from '@chakra-ui/react';
import { FormSelect } from '@/components/form/FormSelect'; import { FormSelect } from '@/components/form/FormSelect';
import { useFormidable } from '@/components/formidable/FormidableConfig'; import { useFormidable } from '@/components/formidable/FormidableConfig';
import { Formidable } from '../formidable'; import { Formidable } from '../formidable';
export default { export default {

View File

@ -4,6 +4,7 @@ import { Box } from '@chakra-ui/react';
import { FormSelectMultiple } from '@/components/form/FormSelectMultiple'; import { FormSelectMultiple } from '@/components/form/FormSelectMultiple';
import { useFormidable } from '@/components/formidable/FormidableConfig'; import { useFormidable } from '@/components/formidable/FormidableConfig';
import { Formidable } from '../formidable'; import { Formidable } from '../formidable';
export default { export default {

View File

@ -1,6 +1,8 @@
export {type FormidableConfig as config, export {
useFormidable type FormidableConfig as config,
useFormidable,
} from './FormidableConfig'; } from './FormidableConfig';
export {FormidableForm as From, export {
type FormidableFormProps as FormProps FormidableForm as From,
type FormidableFormProps as FormProps,
} from './FormidableForm'; } from './FormidableForm';

View File

@ -1,11 +1,7 @@
export * as Formidable from './Fromidable'; export * as Formidable from './Fromidable';
export { export {
useFormidableContext, useFormidableContext,
useFormidableContextElement useFormidableContextElement,
} from './FormidableContext' } from './FormidableContext';
export { export { useFormidable } from './FormidableConfig';
useFormidable export { zodResolver } from './utils';
} from './FormidableConfig';
export {
zodResolver
} from './utils';

View File

@ -1,11 +1,15 @@
import { useRef } from 'react'; import { useRef } from 'react';
import { import { Button, UseDisclosureReturn } from '@chakra-ui/react';
Button,
UseDisclosureReturn, import {
} from '@chakra-ui/react'; DialogBody,
DialogContent,
DialogFooter,
DialogHeader,
DialogRoot,
} from '@/components/ui/dialog';
import { DialogBody, DialogContent, DialogFooter, DialogHeader, DialogRoot } from '@/components/ui/dialog';
export type ConfirmPopUpProps = { export type ConfirmPopUpProps = {
title: string; title: string;
body: string; body: string;
@ -27,7 +31,8 @@ export const ConfirmPopUp = ({
}; };
const cancelRef = useRef<HTMLButtonElement>(null); const cancelRef = useRef<HTMLButtonElement>(null);
return ( return (
<DialogRoot role="alertdialog" <DialogRoot
role="alertdialog"
open={disclosure.open} open={disclosure.open}
//leastDestructiveRef={cancelRef} //leastDestructiveRef={cancelRef}
onOpenChange={disclosure.onClose} onOpenChange={disclosure.onClose}

View File

@ -1,14 +1,14 @@
import { useRef } from 'react'; import { useRef } from 'react';
import { Button, Flex, Progress, Text } from '@chakra-ui/react';
import { import {
Flex, DialogBody,
Progress, DialogContent,
Text, DialogFooter,
Button, DialogHeader,
} from '@chakra-ui/react'; DialogRoot,
} from '@/components/ui/dialog';
import { DialogBody, DialogContent, DialogFooter, DialogHeader, DialogRoot } from '@/components/ui/dialog';
export type PopUpUploadProgressProps = { export type PopUpUploadProgressProps = {
title: string; title: string;

View File

@ -109,7 +109,13 @@ export const SelectMultiple = ({
return ( return (
<Flex direction="column" width="full" gap="0px"> <Flex direction="column" width="full" gap="0px">
{selectedOptions && ( {selectedOptions && (
<HStack wrap="wrap" gap="5px" justify="left" width="full" marginBottom="2px"> <HStack
wrap="wrap"
gap="5px"
justify="left"
width="full"
marginBottom="2px"
>
{selectedOptions.map((data) => ( {selectedOptions.map((data) => (
<Flex align="flex-start" key={data[keyKey]}> <Flex align="flex-start" key={data[keyKey]}>
<Tag.Root <Tag.Root
@ -119,7 +125,10 @@ export const SelectMultiple = ({
backgroundColor="green.800" backgroundColor="green.800"
> >
<Tag.Label>{data[keyValue] ?? `id=${data[keyKey]}`}</Tag.Label> <Tag.Label>{data[keyValue] ?? `id=${data[keyKey]}`}</Tag.Label>
<Tag.CloseTrigger boxSize="5" onClick={() => selectValue(data)} /> <Tag.CloseTrigger
boxSize="5"
onClick={() => selectValue(data)}
/>
</Tag.Root> </Tag.Root>
</Flex> </Flex>
))} ))}
@ -134,7 +143,13 @@ export const SelectMultiple = ({
//onSubmit={onSubmit} //onSubmit={onSubmit}
onFocus={() => setShowList(true)} onFocus={() => setShowList(true)}
onBlur={() => setTimeout(() => setShowList(false), 200)} onBlur={() => setTimeout(() => setShowList(false), 200)}
value={showList ? (currentSearch ?? '') : hasSuggestion ? `suggest: ${currentSearch}` : ''} value={
showList
? (currentSearch ?? '')
: hasSuggestion
? `suggest: ${currentSearch}`
: ''
}
borderRadius="5px 0 0 5px" borderRadius="5px 0 0 5px"
/> />
<Button <Button

View File

@ -50,7 +50,9 @@ export const SelectSingle = ({
onCreate ? suggestion : undefined onCreate ? suggestion : undefined
); );
useEffect(() => { useEffect(() => {
console.log(`Update suggestion : ${onCreate} ${suggestion} ==> ${onCreate ? suggestion : undefined} .. ${onCreate && !isNullOrUndefined(suggestion) ? true : false}`); console.log(
`Update suggestion : ${onCreate} ${suggestion} ==> ${onCreate ? suggestion : undefined} .. ${onCreate && !isNullOrUndefined(suggestion) ? true : false}`
);
setCurrentSearch(onCreate ? suggestion : undefined); setCurrentSearch(onCreate ? suggestion : undefined);
setHasSuggestion(onCreate && !isNullOrUndefined(suggestion) ? true : false); setHasSuggestion(onCreate && !isNullOrUndefined(suggestion) ? true : false);
}, [suggestion]); }, [suggestion]);
@ -110,7 +112,10 @@ export const SelectSingle = ({
onFocus={() => setShowList(true)} onFocus={() => setShowList(true)}
onBlur={() => setTimeout(() => setShowList(false), 200)} onBlur={() => setTimeout(() => setShowList(false), 200)}
value={ value={
showList ? (currentSearch ?? '') : (selectedOptions?.name ?? (hasSuggestion ? `suggest: ${currentSearch}` : '')) showList
? (currentSearch ?? '')
: (selectedOptions?.name ??
(hasSuggestion ? `suggest: ${currentSearch}` : ''))
} }
backgroundColor={ backgroundColor={
showList || !selectedOptions ? undefined : 'green.800' showList || !selectedOptions ? undefined : 'green.800'

View File

@ -1,24 +1,25 @@
"use client" 'use client';
import type { GroupProps, SlotRecipeProps } from "@chakra-ui/react" import * as React from 'react';
import { Avatar as ChakraAvatar, Group } from "@chakra-ui/react"
import * as React from "react"
type ImageProps = React.ImgHTMLAttributes<HTMLImageElement> import type { GroupProps, SlotRecipeProps } from '@chakra-ui/react';
import { Avatar as ChakraAvatar, Group } from '@chakra-ui/react';
type ImageProps = React.ImgHTMLAttributes<HTMLImageElement>;
export interface AvatarProps extends ChakraAvatar.RootProps { export interface AvatarProps extends ChakraAvatar.RootProps {
name?: string name?: string;
src?: string src?: string;
srcSet?: string srcSet?: string;
loading?: ImageProps["loading"] loading?: ImageProps['loading'];
icon?: React.ReactElement icon?: React.ReactElement;
fallback?: React.ReactNode fallback?: React.ReactNode;
} }
export const Avatar = React.forwardRef<HTMLDivElement, AvatarProps>( export const Avatar = React.forwardRef<HTMLDivElement, AvatarProps>(
function Avatar(props, ref) { function Avatar(props, ref) {
const { name, src, srcSet, loading, icon, fallback, children, ...rest } = const { name, src, srcSet, loading, icon, fallback, children, ...rest } =
props props;
return ( return (
<ChakraAvatar.Root ref={ref} {...rest}> <ChakraAvatar.Root ref={ref} {...rest}>
<AvatarFallback name={name} icon={icon}> <AvatarFallback name={name} icon={icon}>
@ -27,18 +28,18 @@ export const Avatar = React.forwardRef<HTMLDivElement, AvatarProps>(
<ChakraAvatar.Image src={src} srcSet={srcSet} loading={loading} /> <ChakraAvatar.Image src={src} srcSet={srcSet} loading={loading} />
{children} {children}
</ChakraAvatar.Root> </ChakraAvatar.Root>
) );
}, }
) );
interface AvatarFallbackProps extends ChakraAvatar.FallbackProps { interface AvatarFallbackProps extends ChakraAvatar.FallbackProps {
name?: string name?: string;
icon?: React.ReactElement icon?: React.ReactElement;
} }
const AvatarFallback = React.forwardRef<HTMLDivElement, AvatarFallbackProps>( const AvatarFallback = React.forwardRef<HTMLDivElement, AvatarFallbackProps>(
function AvatarFallback(props, ref) { function AvatarFallback(props, ref) {
const { name, icon, children, ...rest } = props const { name, icon, children, ...rest } = props;
return ( return (
<ChakraAvatar.Fallback ref={ref} {...rest}> <ChakraAvatar.Fallback ref={ref} {...rest}>
{children} {children}
@ -47,28 +48,28 @@ const AvatarFallback = React.forwardRef<HTMLDivElement, AvatarFallbackProps>(
<ChakraAvatar.Icon asChild={!!icon}>{icon}</ChakraAvatar.Icon> <ChakraAvatar.Icon asChild={!!icon}>{icon}</ChakraAvatar.Icon>
)} )}
</ChakraAvatar.Fallback> </ChakraAvatar.Fallback>
) );
}, }
) );
function getInitials(name: string) { function getInitials(name: string) {
const names = name.trim().split(" ") const names = name.trim().split(' ');
const firstName = names[0] != null ? names[0] : "" const firstName = names[0] != null ? names[0] : '';
const lastName = names.length > 1 ? names[names.length - 1] : "" const lastName = names.length > 1 ? names[names.length - 1] : '';
return firstName && lastName return firstName && lastName
? `${firstName.charAt(0)}${lastName.charAt(0)}` ? `${firstName.charAt(0)}${lastName.charAt(0)}`
: firstName.charAt(0) : firstName.charAt(0);
} }
interface AvatarGroupProps extends GroupProps, SlotRecipeProps<"avatar"> {} interface AvatarGroupProps extends GroupProps, SlotRecipeProps<'avatar'> {}
export const AvatarGroup = React.forwardRef<HTMLDivElement, AvatarGroupProps>( export const AvatarGroup = React.forwardRef<HTMLDivElement, AvatarGroupProps>(
function AvatarGroup(props, ref) { function AvatarGroup(props, ref) {
const { size, variant, borderless, ...rest } = props const { size, variant, borderless, ...rest } = props;
return ( return (
<ChakraAvatar.PropsProvider value={{ size, variant, borderless }}> <ChakraAvatar.PropsProvider value={{ size, variant, borderless }}>
<Group gap="0" spaceX="-3" ref={ref} {...rest} /> <Group gap="0" spaceX="-3" ref={ref} {...rest} />
</ChakraAvatar.PropsProvider> </ChakraAvatar.PropsProvider>
) );
}, }
) );

View File

@ -1,22 +1,23 @@
import type { ButtonProps as ChakraButtonProps } from "@chakra-ui/react" import * as React from 'react';
import type { ButtonProps as ChakraButtonProps } from '@chakra-ui/react';
import { import {
AbsoluteCenter, AbsoluteCenter,
Button as ChakraButton, Button as ChakraButton,
Span, Span,
Spinner, Spinner,
} from "@chakra-ui/react" } from '@chakra-ui/react';
import * as React from "react"
interface ButtonLoadingProps { interface ButtonLoadingProps {
loading?: boolean loading?: boolean;
loadingText?: React.ReactNode loadingText?: React.ReactNode;
} }
export interface ButtonProps extends ChakraButtonProps, ButtonLoadingProps {} export interface ButtonProps extends ChakraButtonProps, ButtonLoadingProps {}
export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>( export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
function Button(props, ref) { function Button(props, ref) {
const { loading, disabled, loadingText, children, ...rest } = props const { loading, disabled, loadingText, children, ...rest } = props;
return ( return (
<ChakraButton disabled={loading || disabled} ref={ref} {...rest}> <ChakraButton disabled={loading || disabled} ref={ref} {...rest}>
{loading && !loadingText ? ( {loading && !loadingText ? (
@ -35,6 +36,6 @@ export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
children children
)} )}
</ChakraButton> </ChakraButton>
) );
}, }
) );

View File

@ -1,15 +1,16 @@
import { Checkbox as ChakraCheckbox } from "@chakra-ui/react" import * as React from 'react';
import * as React from "react"
import { Checkbox as ChakraCheckbox } from '@chakra-ui/react';
export interface CheckboxProps extends ChakraCheckbox.RootProps { export interface CheckboxProps extends ChakraCheckbox.RootProps {
icon?: React.ReactNode icon?: React.ReactNode;
inputProps?: React.InputHTMLAttributes<HTMLInputElement> inputProps?: React.InputHTMLAttributes<HTMLInputElement>;
rootRef?: React.Ref<HTMLLabelElement> rootRef?: React.Ref<HTMLLabelElement>;
} }
export const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>( export const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(
function Checkbox(props, ref) { function Checkbox(props, ref) {
const { icon, children, inputProps, rootRef, ...rest } = props const { icon, children, inputProps, rootRef, ...rest } = props;
return ( return (
<ChakraCheckbox.Root ref={rootRef} {...rest}> <ChakraCheckbox.Root ref={rootRef} {...rest}>
<ChakraCheckbox.HiddenInput ref={ref} {...inputProps} /> <ChakraCheckbox.HiddenInput ref={ref} {...inputProps} />
@ -20,6 +21,6 @@ export const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(
<ChakraCheckbox.Label>{children}</ChakraCheckbox.Label> <ChakraCheckbox.Label>{children}</ChakraCheckbox.Label>
)} )}
</ChakraCheckbox.Root> </ChakraCheckbox.Root>
) );
}, }
) );

View File

@ -1,9 +1,10 @@
import type { ButtonProps } from "@chakra-ui/react" import * as React from 'react';
import { IconButton as ChakraIconButton } from "@chakra-ui/react"
import * as React from "react"
import { LuX } from "react-icons/lu"
export type CloseButtonProps = ButtonProps import type { ButtonProps } from '@chakra-ui/react';
import { IconButton as ChakraIconButton } from '@chakra-ui/react';
import { LuX } from 'react-icons/lu';
export type CloseButtonProps = ButtonProps;
export const CloseButton = React.forwardRef< export const CloseButton = React.forwardRef<
HTMLButtonElement, HTMLButtonElement,
@ -13,5 +14,5 @@ export const CloseButton = React.forwardRef<
<ChakraIconButton variant="ghost" aria-label="Close" ref={ref} {...props}> <ChakraIconButton variant="ghost" aria-label="Close" ref={ref} {...props}>
{props.children ?? <LuX />} {props.children ?? <LuX />}
</ChakraIconButton> </ChakraIconButton>
) );
}) });

View File

@ -1,57 +1,58 @@
"use client" 'use client';
import type { IconButtonProps } from "@chakra-ui/react" import * as React from 'react';
import { ClientOnly, IconButton, Skeleton } from "@chakra-ui/react"
import { ThemeProvider, useTheme } from "next-themes" import type { IconButtonProps } from '@chakra-ui/react';
import type { ThemeProviderProps } from "next-themes" import { ClientOnly, IconButton, Skeleton } from '@chakra-ui/react';
import * as React from "react" import { ThemeProvider, useTheme } from 'next-themes';
import { LuMoon, LuSun } from "react-icons/lu" import type { ThemeProviderProps } from 'next-themes';
import { LuMoon, LuSun } from 'react-icons/lu';
export interface ColorModeProviderProps extends ThemeProviderProps {} export interface ColorModeProviderProps extends ThemeProviderProps {}
export function ColorModeProvider(props: ColorModeProviderProps) { export function ColorModeProvider(props: ColorModeProviderProps) {
return ( return (
<ThemeProvider attribute="class" disableTransitionOnChange {...props} /> <ThemeProvider attribute="class" disableTransitionOnChange {...props} />
) );
} }
export type ColorMode = "light" | "dark" export type ColorMode = 'light' | 'dark';
export interface UseColorModeReturn { export interface UseColorModeReturn {
colorMode: ColorMode colorMode: ColorMode;
setColorMode: (colorMode: ColorMode) => void setColorMode: (colorMode: ColorMode) => void;
toggleColorMode: () => void toggleColorMode: () => void;
} }
export function useColorMode(): UseColorModeReturn { export function useColorMode(): UseColorModeReturn {
const { resolvedTheme, setTheme } = useTheme() const { resolvedTheme, setTheme } = useTheme();
const toggleColorMode = () => { const toggleColorMode = () => {
setTheme(resolvedTheme === "light" ? "dark" : "light") setTheme(resolvedTheme === 'light' ? 'dark' : 'light');
} };
return { return {
colorMode: resolvedTheme as ColorMode, colorMode: resolvedTheme as ColorMode,
setColorMode: setTheme, setColorMode: setTheme,
toggleColorMode, toggleColorMode,
} };
} }
export function useColorModeValue<T>(light: T, dark: T) { export function useColorModeValue<T>(light: T, dark: T) {
const { colorMode } = useColorMode() const { colorMode } = useColorMode();
return colorMode === "dark" ? dark : light return colorMode === 'dark' ? dark : light;
} }
export function ColorModeIcon() { export function ColorModeIcon() {
const { colorMode } = useColorMode() const { colorMode } = useColorMode();
return colorMode === "dark" ? <LuMoon /> : <LuSun /> return colorMode === 'dark' ? <LuMoon /> : <LuSun />;
} }
interface ColorModeButtonProps extends Omit<IconButtonProps, "aria-label"> {} interface ColorModeButtonProps extends Omit<IconButtonProps, 'aria-label'> {}
export const ColorModeButton = React.forwardRef< export const ColorModeButton = React.forwardRef<
HTMLButtonElement, HTMLButtonElement,
ColorModeButtonProps ColorModeButtonProps
>(function ColorModeButton(props, ref) { >(function ColorModeButton(props, ref) {
const { toggleColorMode } = useColorMode() const { toggleColorMode } = useColorMode();
return ( return (
<ClientOnly fallback={<Skeleton boxSize="8" />}> <ClientOnly fallback={<Skeleton boxSize="8" />}>
<IconButton <IconButton
@ -63,13 +64,13 @@ export const ColorModeButton = React.forwardRef<
{...props} {...props}
css={{ css={{
_icon: { _icon: {
width: "5", width: '5',
height: "5", height: '5',
}, },
}} }}
> >
<ColorModeIcon /> <ColorModeIcon />
</IconButton> </IconButton>
</ClientOnly> </ClientOnly>
) );
}) });

View File

@ -1,11 +1,13 @@
import { Dialog as ChakraDialog, Portal } from "@chakra-ui/react" import * as React from 'react';
import { CloseButton } from "./close-button"
import * as React from "react" import { Dialog as ChakraDialog, Portal } from '@chakra-ui/react';
import { CloseButton } from './close-button';
interface DialogContentProps extends ChakraDialog.ContentProps { interface DialogContentProps extends ChakraDialog.ContentProps {
portalled?: boolean portalled?: boolean;
portalRef?: React.RefObject<HTMLElement> portalRef?: React.RefObject<HTMLElement>;
backdrop?: boolean backdrop?: boolean;
} }
export const DialogContent = React.forwardRef< export const DialogContent = React.forwardRef<
@ -18,7 +20,7 @@ export const DialogContent = React.forwardRef<
portalRef, portalRef,
backdrop = true, backdrop = true,
...rest ...rest
} = props } = props;
return ( return (
<Portal disabled={!portalled} container={portalRef}> <Portal disabled={!portalled} container={portalRef}>
@ -29,8 +31,8 @@ export const DialogContent = React.forwardRef<
</ChakraDialog.Content> </ChakraDialog.Content>
</ChakraDialog.Positioner> </ChakraDialog.Positioner>
</Portal> </Portal>
) );
}) });
export const DialogCloseTrigger = React.forwardRef< export const DialogCloseTrigger = React.forwardRef<
HTMLButtonElement, HTMLButtonElement,
@ -48,15 +50,15 @@ export const DialogCloseTrigger = React.forwardRef<
{props.children} {props.children}
</CloseButton> </CloseButton>
</ChakraDialog.CloseTrigger> </ChakraDialog.CloseTrigger>
) );
}) });
export const DialogRoot = ChakraDialog.Root export const DialogRoot = ChakraDialog.Root;
export const DialogFooter = ChakraDialog.Footer export const DialogFooter = ChakraDialog.Footer;
export const DialogHeader = ChakraDialog.Header export const DialogHeader = ChakraDialog.Header;
export const DialogBody = ChakraDialog.Body export const DialogBody = ChakraDialog.Body;
export const DialogBackdrop = ChakraDialog.Backdrop export const DialogBackdrop = ChakraDialog.Backdrop;
export const DialogTitle = ChakraDialog.Title export const DialogTitle = ChakraDialog.Title;
export const DialogDescription = ChakraDialog.Description export const DialogDescription = ChakraDialog.Description;
export const DialogTrigger = ChakraDialog.Trigger export const DialogTrigger = ChakraDialog.Trigger;
export const DialogActionTrigger = ChakraDialog.ActionTrigger export const DialogActionTrigger = ChakraDialog.ActionTrigger;

View File

@ -1,18 +1,20 @@
import { Drawer as ChakraDrawer, Portal } from "@chakra-ui/react" import * as React from 'react';
import { CloseButton } from "./close-button"
import * as React from "react" import { Drawer as ChakraDrawer, Portal } from '@chakra-ui/react';
import { CloseButton } from './close-button';
interface DrawerContentProps extends ChakraDrawer.ContentProps { interface DrawerContentProps extends ChakraDrawer.ContentProps {
portalled?: boolean portalled?: boolean;
portalRef?: React.RefObject<HTMLElement> portalRef?: React.RefObject<HTMLElement>;
offset?: ChakraDrawer.ContentProps["padding"] offset?: ChakraDrawer.ContentProps['padding'];
} }
export const DrawerContent = React.forwardRef< export const DrawerContent = React.forwardRef<
HTMLDivElement, HTMLDivElement,
DrawerContentProps DrawerContentProps
>(function DrawerContent(props, ref) { >(function DrawerContent(props, ref) {
const { children, portalled = true, portalRef, offset, ...rest } = props const { children, portalled = true, portalRef, offset, ...rest } = props;
return ( return (
<Portal disabled={!portalled} container={portalRef}> <Portal disabled={!portalled} container={portalRef}>
<ChakraDrawer.Positioner padding={offset}> <ChakraDrawer.Positioner padding={offset}>
@ -21,8 +23,8 @@ export const DrawerContent = React.forwardRef<
</ChakraDrawer.Content> </ChakraDrawer.Content>
</ChakraDrawer.Positioner> </ChakraDrawer.Positioner>
</Portal> </Portal>
) );
}) });
export const DrawerCloseTrigger = React.forwardRef< export const DrawerCloseTrigger = React.forwardRef<
HTMLButtonElement, HTMLButtonElement,
@ -38,15 +40,15 @@ export const DrawerCloseTrigger = React.forwardRef<
> >
<CloseButton size="sm" ref={ref} /> <CloseButton size="sm" ref={ref} />
</ChakraDrawer.CloseTrigger> </ChakraDrawer.CloseTrigger>
) );
}) });
export const DrawerTrigger = ChakraDrawer.Trigger export const DrawerTrigger = ChakraDrawer.Trigger;
export const DrawerRoot = ChakraDrawer.Root export const DrawerRoot = ChakraDrawer.Root;
export const DrawerFooter = ChakraDrawer.Footer export const DrawerFooter = ChakraDrawer.Footer;
export const DrawerHeader = ChakraDrawer.Header export const DrawerHeader = ChakraDrawer.Header;
export const DrawerBody = ChakraDrawer.Body export const DrawerBody = ChakraDrawer.Body;
export const DrawerBackdrop = ChakraDrawer.Backdrop export const DrawerBackdrop = ChakraDrawer.Backdrop;
export const DrawerDescription = ChakraDrawer.Description export const DrawerDescription = ChakraDrawer.Description;
export const DrawerTitle = ChakraDrawer.Title export const DrawerTitle = ChakraDrawer.Title;
export const DrawerActionTrigger = ChakraDrawer.ActionTrigger export const DrawerActionTrigger = ChakraDrawer.ActionTrigger;

View File

@ -1,17 +1,18 @@
import { Field as ChakraField } from "@chakra-ui/react" import * as React from 'react';
import * as React from "react"
export interface FieldProps extends Omit<ChakraField.RootProps, "label"> { import { Field as ChakraField } from '@chakra-ui/react';
label?: React.ReactNode
helperText?: React.ReactNode export interface FieldProps extends Omit<ChakraField.RootProps, 'label'> {
errorText?: React.ReactNode label?: React.ReactNode;
optionalText?: React.ReactNode helperText?: React.ReactNode;
errorText?: React.ReactNode;
optionalText?: React.ReactNode;
} }
export const Field = React.forwardRef<HTMLDivElement, FieldProps>( export const Field = React.forwardRef<HTMLDivElement, FieldProps>(
function Field(props, ref) { function Field(props, ref) {
const { label, children, helperText, errorText, optionalText, ...rest } = const { label, children, helperText, errorText, optionalText, ...rest } =
props props;
return ( return (
<ChakraField.Root ref={ref} {...rest}> <ChakraField.Root ref={ref} {...rest}>
{label && ( {label && (
@ -28,6 +29,6 @@ export const Field = React.forwardRef<HTMLDivElement, FieldProps>(
<ChakraField.ErrorText>{errorText}</ChakraField.ErrorText> <ChakraField.ErrorText>{errorText}</ChakraField.ErrorText>
)} )}
</ChakraField.Root> </ChakraField.Root>
) );
}, }
) );

View File

@ -1,15 +1,16 @@
import type { BoxProps, InputElementProps } from "@chakra-ui/react" import * as React from 'react';
import { Group, InputElement } from "@chakra-ui/react"
import * as React from "react" import type { BoxProps, InputElementProps } from '@chakra-ui/react';
import { Group, InputElement } from '@chakra-ui/react';
export interface InputGroupProps extends BoxProps { export interface InputGroupProps extends BoxProps {
startElementProps?: InputElementProps startElementProps?: InputElementProps;
endElementProps?: InputElementProps endElementProps?: InputElementProps;
startElement?: React.ReactNode startElement?: React.ReactNode;
endElement?: React.ReactNode endElement?: React.ReactNode;
children: React.ReactElement<InputElementProps> children: React.ReactElement<InputElementProps>;
startOffset?: InputElementProps["paddingStart"] startOffset?: InputElementProps['paddingStart'];
endOffset?: InputElementProps["paddingEnd"] endOffset?: InputElementProps['paddingEnd'];
} }
export const InputGroup = React.forwardRef<HTMLDivElement, InputGroupProps>( export const InputGroup = React.forwardRef<HTMLDivElement, InputGroupProps>(
@ -20,13 +21,13 @@ export const InputGroup = React.forwardRef<HTMLDivElement, InputGroupProps>(
endElement, endElement,
endElementProps, endElementProps,
children, children,
startOffset = "6px", startOffset = '6px',
endOffset = "6px", endOffset = '6px',
...rest ...rest
} = props } = props;
const child = const child =
React.Children.only<React.ReactElement<InputElementProps>>(children) React.Children.only<React.ReactElement<InputElementProps>>(children);
return ( return (
<Group ref={ref} {...rest}> <Group ref={ref} {...rest}>
@ -48,6 +49,6 @@ export const InputGroup = React.forwardRef<HTMLDivElement, InputGroupProps>(
</InputElement> </InputElement>
)} )}
</Group> </Group>
) );
}, }
) );

View File

@ -1,26 +1,27 @@
"use client" 'use client';
import { AbsoluteCenter, Menu as ChakraMenu, Portal } from "@chakra-ui/react" import * as React from 'react';
import * as React from "react"
import { LuCheck, LuChevronRight } from "react-icons/lu" import { AbsoluteCenter, Menu as ChakraMenu, Portal } from '@chakra-ui/react';
import { LuCheck, LuChevronRight } from 'react-icons/lu';
interface MenuContentProps extends ChakraMenu.ContentProps { interface MenuContentProps extends ChakraMenu.ContentProps {
portalled?: boolean portalled?: boolean;
portalRef?: React.RefObject<HTMLElement> portalRef?: React.RefObject<HTMLElement>;
} }
export const MenuContent = React.forwardRef<HTMLDivElement, MenuContentProps>( export const MenuContent = React.forwardRef<HTMLDivElement, MenuContentProps>(
function MenuContent(props, ref) { function MenuContent(props, ref) {
const { portalled = true, portalRef, ...rest } = props const { portalled = true, portalRef, ...rest } = props;
return ( return (
<Portal disabled={!portalled} container={portalRef}> <Portal disabled={!portalled} container={portalRef}>
<ChakraMenu.Positioner> <ChakraMenu.Positioner>
<ChakraMenu.Content ref={ref} {...rest} /> <ChakraMenu.Content ref={ref} {...rest} />
</ChakraMenu.Positioner> </ChakraMenu.Positioner>
</Portal> </Portal>
) );
}, }
) );
export const MenuArrow = React.forwardRef< export const MenuArrow = React.forwardRef<
HTMLDivElement, HTMLDivElement,
@ -30,8 +31,8 @@ export const MenuArrow = React.forwardRef<
<ChakraMenu.Arrow ref={ref} {...props}> <ChakraMenu.Arrow ref={ref} {...props}>
<ChakraMenu.ArrowTip /> <ChakraMenu.ArrowTip />
</ChakraMenu.Arrow> </ChakraMenu.Arrow>
) );
}) });
export const MenuCheckboxItem = React.forwardRef< export const MenuCheckboxItem = React.forwardRef<
HTMLDivElement, HTMLDivElement,
@ -44,14 +45,14 @@ export const MenuCheckboxItem = React.forwardRef<
</ChakraMenu.ItemIndicator> </ChakraMenu.ItemIndicator>
{props.children} {props.children}
</ChakraMenu.CheckboxItem> </ChakraMenu.CheckboxItem>
) );
}) });
export const MenuRadioItem = React.forwardRef< export const MenuRadioItem = React.forwardRef<
HTMLDivElement, HTMLDivElement,
ChakraMenu.RadioItemProps ChakraMenu.RadioItemProps
>(function MenuRadioItem(props, ref) { >(function MenuRadioItem(props, ref) {
const { children, ...rest } = props const { children, ...rest } = props;
return ( return (
<ChakraMenu.RadioItem ps="8" ref={ref} {...rest}> <ChakraMenu.RadioItem ps="8" ref={ref} {...rest}>
<AbsoluteCenter axis="horizontal" left="4" asChild> <AbsoluteCenter axis="horizontal" left="4" asChild>
@ -61,14 +62,14 @@ export const MenuRadioItem = React.forwardRef<
</AbsoluteCenter> </AbsoluteCenter>
<ChakraMenu.ItemText>{children}</ChakraMenu.ItemText> <ChakraMenu.ItemText>{children}</ChakraMenu.ItemText>
</ChakraMenu.RadioItem> </ChakraMenu.RadioItem>
) );
}) });
export const MenuItemGroup = React.forwardRef< export const MenuItemGroup = React.forwardRef<
HTMLDivElement, HTMLDivElement,
ChakraMenu.ItemGroupProps ChakraMenu.ItemGroupProps
>(function MenuItemGroup(props, ref) { >(function MenuItemGroup(props, ref) {
const { title, children, ...rest } = props const { title, children, ...rest } = props;
return ( return (
<ChakraMenu.ItemGroup ref={ref} {...rest}> <ChakraMenu.ItemGroup ref={ref} {...rest}>
{title && ( {title && (
@ -78,33 +79,33 @@ export const MenuItemGroup = React.forwardRef<
)} )}
{children} {children}
</ChakraMenu.ItemGroup> </ChakraMenu.ItemGroup>
) );
}) });
export interface MenuTriggerItemProps extends ChakraMenu.ItemProps { export interface MenuTriggerItemProps extends ChakraMenu.ItemProps {
startIcon?: React.ReactNode startIcon?: React.ReactNode;
} }
export const MenuTriggerItem = React.forwardRef< export const MenuTriggerItem = React.forwardRef<
HTMLDivElement, HTMLDivElement,
MenuTriggerItemProps MenuTriggerItemProps
>(function MenuTriggerItem(props, ref) { >(function MenuTriggerItem(props, ref) {
const { startIcon, children, ...rest } = props const { startIcon, children, ...rest } = props;
return ( return (
<ChakraMenu.TriggerItem ref={ref} {...rest}> <ChakraMenu.TriggerItem ref={ref} {...rest}>
{startIcon} {startIcon}
{children} {children}
<LuChevronRight /> <LuChevronRight />
</ChakraMenu.TriggerItem> </ChakraMenu.TriggerItem>
) );
}) });
export const MenuRadioItemGroup = ChakraMenu.RadioItemGroup export const MenuRadioItemGroup = ChakraMenu.RadioItemGroup;
export const MenuContextTrigger = ChakraMenu.ContextTrigger export const MenuContextTrigger = ChakraMenu.ContextTrigger;
export const MenuRoot = ChakraMenu.Root export const MenuRoot = ChakraMenu.Root;
export const MenuSeparator = ChakraMenu.Separator export const MenuSeparator = ChakraMenu.Separator;
export const MenuItem = ChakraMenu.Item export const MenuItem = ChakraMenu.Item;
export const MenuItemText = ChakraMenu.ItemText export const MenuItemText = ChakraMenu.ItemText;
export const MenuItemCommand = ChakraMenu.ItemCommand export const MenuItemCommand = ChakraMenu.ItemCommand;
export const MenuTrigger = ChakraMenu.Trigger export const MenuTrigger = ChakraMenu.Trigger;

View File

@ -1,5 +1,6 @@
import { NumberInput as ChakraNumberInput } from "@chakra-ui/react" import * as React from 'react';
import * as React from "react"
import { NumberInput as ChakraNumberInput } from '@chakra-ui/react';
export interface NumberInputProps extends ChakraNumberInput.RootProps {} export interface NumberInputProps extends ChakraNumberInput.RootProps {}
@ -7,7 +8,7 @@ export const NumberInputRoot = React.forwardRef<
HTMLDivElement, HTMLDivElement,
NumberInputProps NumberInputProps
>(function NumberInput(props, ref) { >(function NumberInput(props, ref) {
const { children, ...rest } = props const { children, ...rest } = props;
return ( return (
<ChakraNumberInput.Root ref={ref} variant="outline" {...rest}> <ChakraNumberInput.Root ref={ref} variant="outline" {...rest}>
{children} {children}
@ -16,9 +17,9 @@ export const NumberInputRoot = React.forwardRef<
<ChakraNumberInput.DecrementTrigger /> <ChakraNumberInput.DecrementTrigger />
</ChakraNumberInput.Control> </ChakraNumberInput.Control>
</ChakraNumberInput.Root> </ChakraNumberInput.Root>
) );
}) });
export const NumberInputField = ChakraNumberInput.Input export const NumberInputField = ChakraNumberInput.Input;
export const NumberInputScrubber = ChakraNumberInput.Scrubber export const NumberInputScrubber = ChakraNumberInput.Scrubber;
export const NumberInputLabel = ChakraNumberInput.Label export const NumberInputLabel = ChakraNumberInput.Label;

View File

@ -1,25 +1,27 @@
import { Popover as ChakraPopover, Portal } from "@chakra-ui/react" import * as React from 'react';
import { CloseButton } from "./close-button"
import * as React from "react" import { Popover as ChakraPopover, Portal } from '@chakra-ui/react';
import { CloseButton } from './close-button';
interface PopoverContentProps extends ChakraPopover.ContentProps { interface PopoverContentProps extends ChakraPopover.ContentProps {
portalled?: boolean portalled?: boolean;
portalRef?: React.RefObject<HTMLElement> portalRef?: React.RefObject<HTMLElement>;
} }
export const PopoverContent = React.forwardRef< export const PopoverContent = React.forwardRef<
HTMLDivElement, HTMLDivElement,
PopoverContentProps PopoverContentProps
>(function PopoverContent(props, ref) { >(function PopoverContent(props, ref) {
const { portalled = true, portalRef, ...rest } = props const { portalled = true, portalRef, ...rest } = props;
return ( return (
<Portal disabled={!portalled} container={portalRef}> <Portal disabled={!portalled} container={portalRef}>
<ChakraPopover.Positioner> <ChakraPopover.Positioner>
<ChakraPopover.Content ref={ref} {...rest} /> <ChakraPopover.Content ref={ref} {...rest} />
</ChakraPopover.Positioner> </ChakraPopover.Positioner>
</Portal> </Portal>
) );
}) });
export const PopoverArrow = React.forwardRef< export const PopoverArrow = React.forwardRef<
HTMLDivElement, HTMLDivElement,
@ -29,8 +31,8 @@ export const PopoverArrow = React.forwardRef<
<ChakraPopover.Arrow {...props} ref={ref}> <ChakraPopover.Arrow {...props} ref={ref}>
<ChakraPopover.ArrowTip /> <ChakraPopover.ArrowTip />
</ChakraPopover.Arrow> </ChakraPopover.Arrow>
) );
}) });
export const PopoverCloseTrigger = React.forwardRef< export const PopoverCloseTrigger = React.forwardRef<
HTMLButtonElement, HTMLButtonElement,
@ -47,13 +49,13 @@ export const PopoverCloseTrigger = React.forwardRef<
> >
<CloseButton size="sm" /> <CloseButton size="sm" />
</ChakraPopover.CloseTrigger> </ChakraPopover.CloseTrigger>
) );
}) });
export const PopoverTitle = ChakraPopover.Title export const PopoverTitle = ChakraPopover.Title;
export const PopoverDescription = ChakraPopover.Description export const PopoverDescription = ChakraPopover.Description;
export const PopoverFooter = ChakraPopover.Footer export const PopoverFooter = ChakraPopover.Footer;
export const PopoverHeader = ChakraPopover.Header export const PopoverHeader = ChakraPopover.Header;
export const PopoverRoot = ChakraPopover.Root export const PopoverRoot = ChakraPopover.Root;
export const PopoverBody = ChakraPopover.Body export const PopoverBody = ChakraPopover.Body;
export const PopoverTrigger = ChakraPopover.Trigger export const PopoverTrigger = ChakraPopover.Trigger;

View File

@ -1,15 +1,13 @@
"use client" 'use client';
import { ChakraProvider, defaultSystem } from "@chakra-ui/react" import { ChakraProvider, defaultSystem } from '@chakra-ui/react';
import {
ColorModeProvider, import { ColorModeProvider, type ColorModeProviderProps } from './color-mode';
type ColorModeProviderProps,
} from "./color-mode"
export function Provider(props: ColorModeProviderProps) { export function Provider(props: ColorModeProviderProps) {
return ( return (
<ChakraProvider value={defaultSystem}> <ChakraProvider value={defaultSystem}>
<ColorModeProvider {...props} /> <ColorModeProvider {...props} />
</ChakraProvider> </ChakraProvider>
) );
} }

View File

@ -1,14 +1,15 @@
import { RadioGroup as ChakraRadioGroup } from "@chakra-ui/react" import * as React from 'react';
import * as React from "react"
import { RadioGroup as ChakraRadioGroup } from '@chakra-ui/react';
export interface RadioProps extends ChakraRadioGroup.ItemProps { export interface RadioProps extends ChakraRadioGroup.ItemProps {
rootRef?: React.Ref<HTMLDivElement> rootRef?: React.Ref<HTMLDivElement>;
inputProps?: React.InputHTMLAttributes<HTMLInputElement> inputProps?: React.InputHTMLAttributes<HTMLInputElement>;
} }
export const Radio = React.forwardRef<HTMLInputElement, RadioProps>( export const Radio = React.forwardRef<HTMLInputElement, RadioProps>(
function Radio(props, ref) { function Radio(props, ref) {
const { children, inputProps, rootRef, ...rest } = props const { children, inputProps, rootRef, ...rest } = props;
return ( return (
<ChakraRadioGroup.Item ref={rootRef} {...rest}> <ChakraRadioGroup.Item ref={rootRef} {...rest}>
<ChakraRadioGroup.ItemHiddenInput ref={ref} {...inputProps} /> <ChakraRadioGroup.ItemHiddenInput ref={ref} {...inputProps} />
@ -17,8 +18,8 @@ export const Radio = React.forwardRef<HTMLInputElement, RadioProps>(
<ChakraRadioGroup.ItemText>{children}</ChakraRadioGroup.ItemText> <ChakraRadioGroup.ItemText>{children}</ChakraRadioGroup.ItemText>
)} )}
</ChakraRadioGroup.Item> </ChakraRadioGroup.Item>
) );
}, }
) );
export const RadioGroup = ChakraRadioGroup.Root export const RadioGroup = ChakraRadioGroup.Root;

View File

@ -1,23 +1,24 @@
import { Slider as ChakraSlider, For, HStack } from "@chakra-ui/react" import * as React from 'react';
import * as React from "react"
import { Slider as ChakraSlider, For, HStack } from '@chakra-ui/react';
export interface SliderProps extends ChakraSlider.RootProps { export interface SliderProps extends ChakraSlider.RootProps {
marks?: Array<number | { value: number; label: React.ReactNode }> marks?: Array<number | { value: number; label: React.ReactNode }>;
label?: React.ReactNode label?: React.ReactNode;
showValue?: boolean showValue?: boolean;
} }
export const Slider = React.forwardRef<HTMLDivElement, SliderProps>( export const Slider = React.forwardRef<HTMLDivElement, SliderProps>(
function Slider(props, ref) { function Slider(props, ref) {
const { marks: marksProp, label, showValue, ...rest } = props const { marks: marksProp, label, showValue, ...rest } = props;
const value = props.defaultValue ?? props.value const value = props.defaultValue ?? props.value;
const marks = marksProp?.map((mark) => { const marks = marksProp?.map((mark) => {
if (typeof mark === "number") return { value: mark, label: undefined } if (typeof mark === 'number') return { value: mark, label: undefined };
return mark return mark;
}) });
const hasMarkLabel = !!marks?.some((mark) => mark.label) const hasMarkLabel = !!marks?.some((mark) => mark.label);
return ( return (
<ChakraSlider.Root ref={ref} thumbAlignment="center" {...rest}> <ChakraSlider.Root ref={ref} thumbAlignment="center" {...rest}>
@ -38,12 +39,12 @@ export const Slider = React.forwardRef<HTMLDivElement, SliderProps>(
<SliderMarks marks={marks} /> <SliderMarks marks={marks} />
</ChakraSlider.Control> </ChakraSlider.Control>
</ChakraSlider.Root> </ChakraSlider.Root>
) );
}, }
) );
function SliderThumbs(props: { value?: number[] }) { function SliderThumbs(props: { value?: number[] }) {
const { value } = props const { value } = props;
return ( return (
<For each={value}> <For each={value}>
{(_, index) => ( {(_, index) => (
@ -52,31 +53,31 @@ function SliderThumbs(props: { value?: number[] }) {
</ChakraSlider.Thumb> </ChakraSlider.Thumb>
)} )}
</For> </For>
) );
} }
interface SliderMarksProps { interface SliderMarksProps {
marks?: Array<number | { value: number; label: React.ReactNode }> marks?: Array<number | { value: number; label: React.ReactNode }>;
} }
const SliderMarks = React.forwardRef<HTMLDivElement, SliderMarksProps>( const SliderMarks = React.forwardRef<HTMLDivElement, SliderMarksProps>(
function SliderMarks(props, ref) { function SliderMarks(props, ref) {
const { marks } = props const { marks } = props;
if (!marks?.length) return null if (!marks?.length) return null;
return ( return (
<ChakraSlider.MarkerGroup ref={ref}> <ChakraSlider.MarkerGroup ref={ref}>
{marks.map((mark, index) => { {marks.map((mark, index) => {
const value = typeof mark === "number" ? mark : mark.value const value = typeof mark === 'number' ? mark : mark.value;
const label = typeof mark === "number" ? undefined : mark.label const label = typeof mark === 'number' ? undefined : mark.label;
return ( return (
<ChakraSlider.Marker key={index} value={value}> <ChakraSlider.Marker key={index} value={value}>
<ChakraSlider.MarkerIndicator /> <ChakraSlider.MarkerIndicator />
{label} {label}
</ChakraSlider.Marker> </ChakraSlider.Marker>
) );
})} })}
</ChakraSlider.MarkerGroup> </ChakraSlider.MarkerGroup>
) );
}, }
) );

View File

@ -1,6 +1,5 @@
"use client" 'use client';
import { RestErrorResponse } from "@/back-api";
import { import {
Toaster as ChakraToaster, Toaster as ChakraToaster,
Portal, Portal,
@ -8,12 +7,14 @@ import {
Stack, Stack,
Toast, Toast,
createToaster, createToaster,
} from "@chakra-ui/react" } from '@chakra-ui/react';
import { RestErrorResponse } from '@/back-api';
export const toaster = createToaster({ export const toaster = createToaster({
placement: "bottom-end", placement: 'bottom-end',
pauseOnPageIdle: true, pauseOnPageIdle: true,
}) });
export const toasterAPIError = (error: RestErrorResponse) => { export const toasterAPIError = (error: RestErrorResponse) => {
toaster.create({ toaster.create({
@ -25,10 +26,10 @@ export const toasterAPIError = (error: RestErrorResponse) => {
export const Toaster = () => { export const Toaster = () => {
return ( return (
<Portal> <Portal>
<ChakraToaster toaster={toaster} insetInline={{ mdDown: "4" }}> <ChakraToaster toaster={toaster} insetInline={{ mdDown: '4' }}>
{(toast) => ( {(toast) => (
<Toast.Root width={{ md: "sm" }}> <Toast.Root width={{ md: 'sm' }}>
{toast.type === "loading" ? ( {toast.type === 'loading' ? (
<Spinner size="sm" color="blue.solid" /> <Spinner size="sm" color="blue.solid" />
) : ( ) : (
<Toast.Indicator /> <Toast.Indicator />
@ -47,5 +48,5 @@ export const Toaster = () => {
)} )}
</ChakraToaster> </ChakraToaster>
</Portal> </Portal>
) );
} };

View File

@ -1,13 +1,14 @@
import { Tooltip as ChakraTooltip, Portal } from "@chakra-ui/react" import * as React from 'react';
import * as React from "react"
import { Tooltip as ChakraTooltip, Portal } from '@chakra-ui/react';
export interface TooltipProps extends ChakraTooltip.RootProps { export interface TooltipProps extends ChakraTooltip.RootProps {
showArrow?: boolean showArrow?: boolean;
portalled?: boolean portalled?: boolean;
portalRef?: React.RefObject<HTMLElement> portalRef?: React.RefObject<HTMLElement>;
content: React.ReactNode content: React.ReactNode;
contentProps?: ChakraTooltip.ContentProps contentProps?: ChakraTooltip.ContentProps;
disabled?: boolean disabled?: boolean;
} }
export const Tooltip = React.forwardRef<HTMLDivElement, TooltipProps>( export const Tooltip = React.forwardRef<HTMLDivElement, TooltipProps>(
@ -21,9 +22,9 @@ export const Tooltip = React.forwardRef<HTMLDivElement, TooltipProps>(
contentProps, contentProps,
portalRef, portalRef,
...rest ...rest
} = props } = props;
if (disabled) return children if (disabled) return children;
return ( return (
<ChakraTooltip.Root {...rest}> <ChakraTooltip.Root {...rest}>
@ -41,6 +42,6 @@ export const Tooltip = React.forwardRef<HTMLDivElement, TooltipProps>(
</ChakraTooltip.Positioner> </ChakraTooltip.Positioner>
</Portal> </Portal>
</ChakraTooltip.Root> </ChakraTooltip.Root>
) );
}, }
) );

View File

@ -1,28 +0,0 @@
import dayjs from 'dayjs';
import 'dayjs/locale/fr';
import advancedFormat from 'dayjs/plugin/advancedFormat';
import customParseFormat from 'dayjs/plugin/customParseFormat';
import dayOfYear from 'dayjs/plugin/dayOfYear';
import duration from 'dayjs/plugin/duration';
import isBetween from 'dayjs/plugin/isBetween';
import isSameOrAfter from 'dayjs/plugin/isSameOrAfter';
import isToday from 'dayjs/plugin/isToday';
import isTomorrow from 'dayjs/plugin/isTomorrow';
import isYesterday from 'dayjs/plugin/isYesterday';
import quarterOfYear from 'dayjs/plugin/quarterOfYear';
import relativeTime from 'dayjs/plugin/relativeTime';
import weekOfYear from 'dayjs/plugin/weekOfYear';
dayjs.locale('fr');
dayjs.extend(relativeTime);
dayjs.extend(customParseFormat);
dayjs.extend(weekOfYear);
dayjs.extend(isSameOrAfter);
dayjs.extend(isToday);
dayjs.extend(isTomorrow);
dayjs.extend(isYesterday);
dayjs.extend(dayOfYear);
dayjs.extend(isBetween);
dayjs.extend(advancedFormat);
dayjs.extend(quarterOfYear);
dayjs.extend(duration);

View File

@ -1,2 +0,0 @@
import './axios';
import './dayjs';

View File

@ -1,2 +0,0 @@
export const DATE_FORMAT = 'YYYY-MM-DD';
export const DATE_FORMAT_FULL = 'dddd DD MMMM HH:mm';

View File

@ -1,4 +0,0 @@
export const BASE_WRAP_SPACING = { base: "5px", md: "10px", lg: "20px" };
export const BASE_WRAP_WIDTH = { base: "90%", md: "45%", lg: "270px" };
export const BASE_WRAP_HEIGHT = { base: "75px", lg: "120px" };
export const BASE_WRAP_ICON_SIZE = { base: "50px", lg: "100px" };

View File

@ -1 +0,0 @@
export * from './date'

View File

@ -42,8 +42,9 @@ export const isDevelopmentEnvironment = () => {
return import.meta.env.MODE === 'development'; return import.meta.env.MODE === 'development';
}; };
export const environment = isDevelopmentEnvironment() ? environment_local : environment_back_prod; export const environment = isDevelopmentEnvironment()
? environment_local
: environment_back_prod;
/** /**
* get the current REST api URL. Depend on the VITE_API_BASE_URL env variable. * get the current REST api URL. Depend on the VITE_API_BASE_URL env variable.

View File

@ -1,4 +1,4 @@
import { Box, Button, Center, Heading, Link, Text } from '@chakra-ui/react'; import { Box, 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';
@ -10,15 +10,17 @@ export const Error401 = () => {
<TopBar /> <TopBar />
<PageLayoutInfoCenter padding="25px"> <PageLayoutInfoCenter padding="25px">
<Center> <Center>
<MdControlCamera style={{ width: "250px", height: "250px", color: "orange" }} /> <MdControlCamera
style={{ width: '250px', height: '250px', color: 'orange' }}
/>
</Center> </Center>
<Box textAlign="center"> <Box textAlign="center">
<Heading>Erreur 401</Heading> <Heading>Error 401</Heading>
<Text color="red.600"> <Text color="red.600">
Vous n'êtes pas autorisé a accéder a ce contenu. You are not authorized to access this content.
</Text> </Text>
<Link as="a" href="/"> <Link as="a" href="/">
Retour à l'accueil Back to Homepage
</Link> </Link>
</Box> </Box>
</PageLayoutInfoCenter> </PageLayoutInfoCenter>

View File

@ -1,4 +1,4 @@
import { Box, Button, Center, Heading, Link, Text } from '@chakra-ui/react'; import { Box, 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';
@ -10,14 +10,14 @@ export const Error403 = () => {
<TopBar /> <TopBar />
<PageLayoutInfoCenter padding="25px"> <PageLayoutInfoCenter padding="25px">
<Center> <Center>
<MdDangerous style={{ width: "250px", height: "250px", color: "red" }} /> <MdDangerous
style={{ width: '250px', height: '250px', color: 'red' }}
/>
</Center> </Center>
<Box textAlign="center"> <Box textAlign="center">
<Heading>Erreur 403</Heading> <Heading>Error 403</Heading>
<Text color="orange.600">Cette page vous est interdite</Text> <Text color="orange.600">This page is forbidden to you.</Text>
<Link href="/"> <Link href="/">Back to Homepage</Link>
Retour à l'accueil
</Link>
</Box> </Box>
</PageLayoutInfoCenter> </PageLayoutInfoCenter>
</> </>

View File

@ -1,4 +1,4 @@
import { Box, Button, Center, Heading, Link, Text } from '@chakra-ui/react'; import { Box, 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';
@ -10,16 +10,16 @@ export const Error404 = () => {
<TopBar /> <TopBar />
<PageLayoutInfoCenter padding="25px"> <PageLayoutInfoCenter padding="25px">
<Center> <Center>
<MdSignpost style={{ width: "250px", height: "250px", color: "aqua" }} /> <MdSignpost
style={{ width: '250px', height: '250px', color: 'aqua' }}
/>
</Center> </Center>
<Box textAlign="center"> <Box textAlign="center">
<Heading>Erreur 404</Heading> <Heading>Error 404</Heading>
<Text color="gray.600"> <Text color="gray.600">
Cette page n'existe plus ou l'URL a changé This page no longer exists or the URL has changed.
</Text> </Text>
<Link href="/"> <Link href="/">Back to Homepage</Link>
Retour à l'accueil
</Link>
</Box> </Box>
</PageLayoutInfoCenter> </PageLayoutInfoCenter>
</> </>

View File

@ -1,11 +1,6 @@
import React, { FC } from 'react'; import { ReactNode } from 'react';
import { import { Alert, AlertDescription, AlertTitle, Box } from '@chakra-ui/react';
AlertDescription,
AlertTitle,
Box,
Alert,
} from '@chakra-ui/react';
import { import {
FallbackProps, FallbackProps,
ErrorBoundary as ReactErrorBoundary, ErrorBoundary as ReactErrorBoundary,
@ -17,8 +12,15 @@ const ErrorFallback = ({ error }: FallbackProps) => {
<Alert.Root status="error" borderRadius="md"> <Alert.Root status="error" borderRadius="md">
<Alert.Indicator height="75px" width="75px" /> <Alert.Indicator height="75px" width="75px" />
<Box flex="1"> <Box flex="1">
<AlertTitle fontWeight="bold" fontSize="35px">An unexpected error has occurred.</AlertTitle> <AlertTitle fontWeight="bold" fontSize="35px">
<AlertDescription padding="5" marginTop="3" fontSize="20px" lineHeight="1.4"> An unexpected error has occurred.
</AlertTitle>
<AlertDescription
padding="5"
marginTop="3"
fontSize="20px"
lineHeight="1.4"
>
<br /> <br />
{error.message} {error.message}
</AlertDescription> </AlertDescription>
@ -28,6 +30,6 @@ const ErrorFallback = ({ error }: FallbackProps) => {
); );
}; };
export const ErrorBoundary: FC<React.PropsWithChildren<unknown>> = (props) => { export const ErrorBoundary = ({ children }: { children: ReactNode }) => {
return <ReactErrorBoundary FallbackComponent={ErrorFallback} {...props} />; return <ReactErrorBoundary FallbackComponent={ErrorFallback} {...props} />;
}; };

View File

@ -1,13 +1,13 @@
import { StrictMode } from 'react'; import { StrictMode } from 'react';
import { ChakraProvider } from '@chakra-ui/react';
import ReactDOM from 'react-dom/client'; import ReactDOM from 'react-dom/client';
import App from '@/App'; import App from '@/App';
import { ColorModeProvider } from './components/ui/color-mode';
import { ChakraProvider } from '@chakra-ui/react'; import { ColorModeProvider } from './components/ui/color-mode';
import { systemTheme } from './theme/theme';
import { Toaster } from './components/ui/toaster'; import { Toaster } from './components/ui/toaster';
import { systemTheme } from './theme/theme';
// Render the app // Render the app
const rootElement = document.getElementById('root'); const rootElement = document.getElementById('root');

View File

@ -9,11 +9,12 @@ import { Error404 } from '@/errors';
import { HelpPage } from '@/scene/home/HelpPage'; import { HelpPage } from '@/scene/home/HelpPage';
import { HomePage } from '@/scene/home/HomePage'; import { HomePage } from '@/scene/home/HomePage';
import { useHasRight } from '@/service/session'; import { useHasRight } from '@/service/session';
import { SettingsPage } from './home/SettingsPage';
import { ManageAccountPage } from './account/ManageAccountPage';
import { SignInDonePage } from './connection/SignInDonePage';
import { SignInPage } from './connection/SignInPage'; import { SignInPage } from './connection/SignInPage';
import { SignOutPage } from './connection/SignOutPage'; import { SignOutPage } from './connection/SignOutPage';
import { SignInDonePage } from './connection/SignInDonePage'; import { SettingsPage } from './home/SettingsPage';
import { ManageAccountPage } from './account/ManageAccountPage';
export const AppRoutes = () => { export const AppRoutes = () => {
const { isReadable } = useHasRight('USER'); const { isReadable } = useHasRight('USER');
@ -28,8 +29,14 @@ export const AppRoutes = () => {
<> <>
<Route path="/" element={<HomePage />} /> <Route path="/" element={<HomePage />} />
{/* Connection page after SSO */} {/* Connection page after SSO */}
<Route path="signin/:applicationName/:applicationData/*" element={<SignInDonePage />} /> <Route
<Route path="signin/:applicationName/*" element={<SignInDonePage />} /> path="signin/:applicationName/:applicationData/*"
element={<SignInDonePage />}
/>
<Route
path="signin/:applicationName/*"
element={<SignInDonePage />}
/>
<Route path="signout/*" element={<SignOutPage />} /> <Route path="signout/*" element={<SignOutPage />} />
<Route path="manage-account/*" element={<ManageAccountPage />} /> <Route path="manage-account/*" element={<ManageAccountPage />} />
<Route path="help" element={<HelpPage />} /> <Route path="help" element={<HelpPage />} />

View File

@ -1,6 +1,7 @@
import { useEffect } from 'react'; import { useEffect } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { useSessionService } from '@/service/session'; import { useSessionService } from '@/service/session';
export const SignOutPage = () => { export const SignOutPage = () => {

View File

@ -1,11 +1,11 @@
import { useState } from 'react'; import { useState } from 'react';
import { UserResource } from '@/back-api';
import { toaster, toasterAPIError } from '@/components/ui/toaster';
import { useSessionService } from '@/service/session';
//import { useSessionContext } from '@/context/SessionContext'; //import { useSessionContext } from '@/context/SessionContext';
import { getRestConfig } from '@/utils/http'; import { getRestConfig } from '@/utils/http';
import { sha512 } from '@/utils/sha512'; import { sha512 } from '@/utils/sha512';
import { toaster, toasterAPIError } from '@/components/ui/toaster';
import { useSessionService } from '@/service/session';
import { UserResource } from '@/back-api';
export const useLogin = () => { export const useLogin = () => {
const [isConnectionLoading, setIsConnectionLoading] = const [isConnectionLoading, setIsConnectionLoading] =

View File

@ -5,9 +5,7 @@ export const HelpPage = () => {
return ( return (
<> <>
<TopBar title="Help" /> <TopBar title="Help" />
<PageLayout> <PageLayout>No help available right now</PageLayout>
No help available right now
</PageLayout>
</> </>
); );
}; };

View File

@ -1,14 +1,11 @@
import { PageLayout } from '@/components/Layout/PageLayout'; import { PageLayout } from '@/components/Layout/PageLayout';
import { TopBar } from '@/components/TopBar/TopBar'; import { TopBar } from '@/components/TopBar/TopBar';
export const SettingsPage = () => { export const SettingsPage = () => {
return ( return (
<> <>
<TopBar title="Help" /> <TopBar title="Help" />
<PageLayout> <PageLayout>No settings available right now</PageLayout>
No settings available right now
</PageLayout>
</> </>
); );
}; };

View File

@ -1,11 +1,15 @@
import { ApplicationToken, ApplicationTokenResource, CreateTokenRequestWrite, Integer, Long, RestErrorResponse } from '@/back-api'; import {
ApplicationToken,
ApplicationTokenResource,
CreateTokenRequestWrite,
Integer,
Long,
RestErrorResponse,
} from '@/back-api';
import { useSessionService } from '@/service/session'; import { useSessionService } from '@/service/session';
import { useQuery, useQueryCall, useQueryCallProps } from '@/utils/query'; import { useQuery, useQueryCall, useQueryCallProps } from '@/utils/query';
export namespace ApplicationTokenService { export namespace ApplicationTokenService {
export const useApplicationTokens = (applicationId: Long) => { export const useApplicationTokens = (applicationId: Long) => {
const { getRestConfig } = useSessionService(); const { getRestConfig } = useSessionService();
return useQuery({ return useQuery({
@ -13,7 +17,7 @@ export namespace ApplicationTokenService {
return ApplicationTokenResource.gets({ return ApplicationTokenResource.gets({
restConfig: getRestConfig(), restConfig: getRestConfig(),
params: { params: {
applicationId applicationId,
}, },
}); });
}, },
@ -22,10 +26,15 @@ export namespace ApplicationTokenService {
export const useApplicationTokenCreate = ( export const useApplicationTokenCreate = (
applicationId: Long, applicationId: Long,
config: { config?: Omit<useQueryCallProps<ApplicationToken, any>, 'queryFunction'> } config: {
config?: Omit<useQueryCallProps<ApplicationToken, any>, 'queryFunction'>;
}
) => { ) => {
const { getRestConfig } = useSessionService(); const { getRestConfig } = useSessionService();
const { call, ...rest } = useQueryCall<ApplicationToken, CreateTokenRequestWrite>({ const { call, ...rest } = useQueryCall<
ApplicationToken,
CreateTokenRequestWrite
>({
queryFunction: (inputData) => { queryFunction: (inputData) => {
return ApplicationTokenResource.create({ return ApplicationTokenResource.create({
restConfig: getRestConfig(), restConfig: getRestConfig(),
@ -43,15 +52,18 @@ export namespace ApplicationTokenService {
config: { config?: Omit<useQueryCallProps<void, any>, 'queryFunction'> } config: { config?: Omit<useQueryCallProps<void, any>, 'queryFunction'> }
) => { ) => {
const { getRestConfig } = useSessionService(); const { getRestConfig } = useSessionService();
const { call, ...rest } = useQueryCall<void, { const { call, ...rest } = useQueryCall<
tokenId: Integer, void,
}>({ {
tokenId: Integer;
}
>({
queryFunction: (inputData) => { queryFunction: (inputData) => {
return ApplicationTokenResource.remove({ return ApplicationTokenResource.remove({
restConfig: getRestConfig(), restConfig: getRestConfig(),
params: { params: {
applicationId, applicationId,
...inputData ...inputData,
}, },
}); });
}, },
@ -59,5 +71,4 @@ export namespace ApplicationTokenService {
}); });
return { removeApplicationToken: call, ...rest }; return { removeApplicationToken: call, ...rest };
}; };
} }

View File

@ -11,8 +11,6 @@ export type ServiceContextType = {
session: SessionServiceProps; session: SessionServiceProps;
}; };
export const ServiceContext = createContext<ServiceContextType>({ export const ServiceContext = createContext<ServiceContextType>({
session: { session: {
isConnected: false, isConnected: false,

View File

@ -22,7 +22,7 @@ export function getRestConfig(): RESTConfig {
export type SessionServiceProps = { export type SessionServiceProps = {
token?: string; token?: string;
isConnected: boolean, isConnected: boolean;
setToken: (token: string) => void; setToken: (token: string) => void;
clearToken: () => void; clearToken: () => void;
login?: string; login?: string;
@ -59,7 +59,6 @@ export const useSessionServiceWrapped = (): SessionServiceProps => {
localStorage.setItem(TOKEN_KEY, token); localStorage.setItem(TOKEN_KEY, token);
} }
} }
}, [localStorage, parseToken, token]); }, [localStorage, parseToken, token]);
const setTokenLocal = useCallback( const setTokenLocal = useCallback(
@ -71,7 +70,7 @@ export const useSessionServiceWrapped = (): SessionServiceProps => {
); );
const clearToken = useCallback(() => { const clearToken = useCallback(() => {
console.log("Clear Token"); console.log('Clear Token');
setToken(undefined); setToken(undefined);
updateRight(); updateRight();
}, [updateRight, setToken]); }, [updateRight, setToken]);
@ -85,7 +84,9 @@ export const useSessionServiceWrapped = (): SessionServiceProps => {
if (right === undefined) { if (right === undefined) {
return false; return false;
} }
return [PartRight.READ, PartRight.READ_WRITE].includes(right?.[group] ?? 0); return [PartRight.READ, PartRight.READ_WRITE].includes(
right?.[group] ?? 0
);
}, },
[config] [config]
); );
@ -99,7 +100,9 @@ export const useSessionServiceWrapped = (): SessionServiceProps => {
if (right === undefined) { if (right === undefined) {
return false; return false;
} }
return [PartRight.READ, PartRight.READ_WRITE].includes(right?.[group] ?? 0); return [PartRight.READ, PartRight.READ_WRITE].includes(
right?.[group] ?? 0
);
}, },
[config] [config]
); );

View File

@ -3,13 +3,17 @@
* @copyright 2018, Edouard DUPIN, all right reserved * @copyright 2018, Edouard DUPIN, all right reserved
* @license PROPRIETARY (see license file) * @license PROPRIETARY (see license file)
*/ */
import {
RESTConfig,
UserAuthGet,
UserCreateWrite,
UserResource,
} from '@/back-api';
import { useQuery, useQueryCall, useQueryCallProps } from '@/utils/query';
import { RESTConfig, UserAuthGet, UserCreateWrite, UserResource } from "@/back-api"; import { useSessionService } from './session';
import { useQuery, useQueryCall, useQueryCallProps } from "@/utils/query";
import { useSessionService } from "./session";
export namespace UserService { export namespace UserService {
// export const useGetData = <RETURN_TYPE>(queryFunction: (config: RESTConfig) => Promise<RETURN_TYPE>) => { // export const useGetData = <RETURN_TYPE>(queryFunction: (config: RESTConfig) => Promise<RETURN_TYPE>) => {
// const { getRestConfig } = useSessionService(); // const { getRestConfig } = useSessionService();
// return useQuery({ queryFunction: () => queryFunction(getRestConfig()) }); // return useQuery({ queryFunction: () => queryFunction(getRestConfig()) });
@ -26,12 +30,16 @@ export namespace UserService {
return useQuery({ return useQuery({
queryFunction: () => { queryFunction: () => {
return UserResource.gets({ return UserResource.gets({
restConfig: getRestConfig() restConfig: getRestConfig(),
}); });
}, },
}); });
}; };
export const useCreate = ({ config }: { config?: Omit<useQueryCallProps<UserAuthGet, any>, 'queryFunction'> }) => { export const useCreate = ({
config,
}: {
config?: Omit<useQueryCallProps<UserAuthGet, any>, 'queryFunction'>;
}) => {
const { getRestConfig } = useSessionService(); const { getRestConfig } = useSessionService();
return useQueryCall<UserAuthGet, UserCreateWrite>({ return useQueryCall<UserAuthGet, UserCreateWrite>({
queryFunction: (data) => { queryFunction: (data) => {
@ -40,8 +48,7 @@ export namespace UserService {
data: { ...data }, data: { ...data },
}); });
}, },
...config ...config,
}); });
}; };
} }

View File

@ -1,7 +1,6 @@
type PandaColorModel = { type PandaColorModel = {
value: string; value: string;
} };
type ThemeModel = { type ThemeModel = {
50: PandaColorModel; 50: PandaColorModel;
100: PandaColorModel; 100: PandaColorModel;

View File

@ -1,5 +1,11 @@
import { createSystem, defaultConfig, mergeConfigs, SystemConfig } from "@chakra-ui/react" import {
import { colors } from "./colors" SystemConfig,
createSystem,
defaultConfig,
mergeConfigs,
} from '@chakra-ui/react';
import { colors } from './colors';
const baseTheme: SystemConfig = { const baseTheme: SystemConfig = {
globalCss: { globalCss: {
@ -8,25 +14,23 @@ const baseTheme: SystemConfig = {
bg: { _light: 'back.50', _dark: 'back.700' }, bg: { _light: 'back.50', _dark: 'back.700' },
color: { _light: 'text.900', _dark: 'text.50' }, color: { _light: 'text.900', _dark: 'text.50' },
fontFamily: 'Roboto, Helvetica, Arial, "sans-serif"', fontFamily: 'Roboto, Helvetica, Arial, "sans-serif"',
userSelect: 'none', /* Prevents text selection */ userSelect: 'none' /* Prevents text selection */,
}, },
svg: { svg: {
width: "32px", width: '32px',
height: "32px", height: '32px',
aspectRatio: "square", aspectRatio: 'square',
} },
}, },
theme: { theme: {
slotRecipes: { slotRecipes: {
dialog: { dialog: {
slots: [ slots: ['header'],
"header"
],
base: { base: {
header: { header: {
fontWeight: "bold", fontWeight: 'bold',
fontSize: "2xl", fontSize: '2xl',
color: { _dark: "brand.400", _light: "brand.500" } color: { _dark: 'brand.400', _light: 'brand.500' },
}, },
}, },
}, },
@ -36,21 +40,27 @@ const baseTheme: SystemConfig = {
base: { base: {
borderRadius: 0, borderRadius: 0,
_hover: { _hover: {
boxShadow: { _light: "0 8px 20px #000000e6", _dark: "0 8px 20px #000000e6" } boxShadow: {
_light: '0 8px 20px #000000e6',
_dark: '0 8px 20px #000000e6',
},
},
transitionDuration: 'slower',
}, },
transitionDuration: "slower"
}
}, },
input: { input: {
base: { base: {
borderRadius: 0, borderRadius: 0,
_hover: { _hover: {
boxShadow: { _light: "0 2px 5px #000000e6", _dark: "0 2px 5px #000000e6" } boxShadow: {
_light: '0 2px 5px #000000e6',
_dark: '0 2px 5px #000000e6',
},
}, },
//borderColor: { _light: "gray.800", _dark: "gray.50" }, //borderColor: { _light: "gray.800", _dark: "gray.50" },
backgroundColor: { _light: "gray.200", _dark: "gray.700" }, backgroundColor: { _light: 'gray.200', _dark: 'gray.700' },
transitionDuration: "slower" transitionDuration: 'slower',
} },
}, },
}, },
tokens: { tokens: {
@ -62,23 +72,23 @@ const baseTheme: SystemConfig = {
}, },
semanticTokens: { semanticTokens: {
colors: { colors: {
"@danger": { '@danger': {
solid: { value: "{colors.danger.500}" }, solid: { value: '{colors.danger.500}' },
contrast: { value: "{colors.danger.100}" }, contrast: { value: '{colors.danger.100}' },
fg: { value: "{colors.danger.900}" }, fg: { value: '{colors.danger.900}' },
muted: { value: "{colors.danger.100}" }, muted: { value: '{colors.danger.100}' },
subtle: { value: "{colors.danger.200}" }, subtle: { value: '{colors.danger.200}' },
emphasized: { value: "{colors.danger.300}" }, emphasized: { value: '{colors.danger.300}' },
focusRing: { value: "{colors.danger.500}" }, focusRing: { value: '{colors.danger.500}' },
}, },
"brand": { brand: {
solid: { value: "{colors.brand.500}" }, solid: { value: '{colors.brand.500}' },
contrast: { value: "{colors.brand.100}" }, contrast: { value: '{colors.brand.100}' },
fg: { value: "{colors.brand.900}" }, fg: { value: '{colors.brand.900}' },
muted: { value: "{colors.brand.100}" }, muted: { value: '{colors.brand.100}' },
subtle: { value: "{colors.brand.200}" }, subtle: { value: '{colors.brand.200}' },
emphasized: { value: "{colors.brand.300}" }, emphasized: { value: '{colors.brand.300}' },
focusRing: { value: "{colors.brand.500}" }, focusRing: { value: '{colors.brand.500}' },
}, },
}, },
}, },

View File

@ -1,11 +1,8 @@
export function arrayUnique(array: any[]) { export function arrayUnique(array: any[]) {
var a = array.concat(); var a = array.concat();
for (var i = 0; i < a.length; ++i) { for (var i = 0; i < a.length; ++i) {
for (var j = i + 1; j < a.length; ++j) { for (var j = i + 1; j < a.length; ++j) {
if (a[i] === a[j]) if (a[i] === a[j]) a.splice(j--, 1);
a.splice(j--, 1);
} }
} }

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 { isNullOrUndefined } from '@/utils/validator';
import { toasterAPIError } from '@/components/ui/toaster'; import { toasterAPIError } from '@/components/ui/toaster';
import { isNullOrUndefined } from '@/utils/validator';
export type DataStoreType<TYPE> = { export type DataStoreType<TYPE> = {
isLoading: boolean; isLoading: boolean;

View File

@ -1,4 +1,4 @@
import { JwtToken, RESTConfig } from '@/back-api'; import { RESTConfig } from '@/back-api';
import { getApiUrl } from '@/environment'; import { getApiUrl } from '@/environment';
import { getUserToken } from '@/service/session'; import { getUserToken } from '@/service/session';

View File

@ -1,14 +1,15 @@
import { RestErrorResponse } from "@/back-api"; import { useEffect, useState } from 'react';
import { toasterAPIError, toaster } from "@/components/ui/toaster";
import { useSessionService } from "@/service/session"; import { RestErrorResponse } from '@/back-api';
import { useState, useEffect } from "react"; import { toaster, toasterAPIError } from '@/components/ui/toaster';
import { useSessionService } from '@/service/session';
export type useQueryProps<TYPE> = { export type useQueryProps<TYPE> = {
queryFunction: () => Promise<TYPE>; queryFunction: () => Promise<TYPE>;
onSuccess?: (data: TYPE) => Promise<TYPE>; onSuccess?: (data: TYPE) => Promise<TYPE>;
onFail?: (error: RestErrorResponse) => void; onFail?: (error: RestErrorResponse) => void;
} };
export const useQuery = <TYPE,>({ export const useQuery = <TYPE>({
queryFunction, queryFunction,
onSuccess, onSuccess,
onFail, onFail,
@ -18,13 +19,15 @@ export const useQuery = <TYPE,>({
const [isLoading, setIsLoading] = useState<boolean>(true); const [isLoading, setIsLoading] = useState<boolean>(true);
const [error, setError] = useState<RestErrorResponse | undefined>(undefined); const [error, setError] = useState<RestErrorResponse | undefined>(undefined);
useEffect(() => { useEffect(() => {
queryFunction().then((received) => { queryFunction()
.then((received) => {
setData(received); setData(received);
setIsLoading(false); setIsLoading(false);
if (onSuccess) { if (onSuccess) {
onSuccess(received); onSuccess(received);
} }
}).catch((error) => { })
.catch((error) => {
setError(error); setError(error);
setIsLoading(false); setIsLoading(false);
if (onFail) { if (onFail) {
@ -35,19 +38,19 @@ export const useQuery = <TYPE,>({
// Authentication error ==> auto_disconnect // Authentication error ==> auto_disconnect
clearToken(); clearToken();
toaster.create({ toaster.create({
title: "Disconnected by server", title: 'Disconnected by server',
description: "Token is no more available", description: 'Token is no more available',
}); });
} }
}); });
}, [setError, setIsLoading, setData, toasterAPIError, clearToken, toaster]) }, [setError, setIsLoading, setData, toasterAPIError, clearToken, toaster]);
return { data, isLoading, error }; return { data, isLoading, error };
} };
export type useQueryCallProps<RETURN_TYPE, PARAMETER_TYPE> = { export type useQueryCallProps<RETURN_TYPE, PARAMETER_TYPE> = {
queryFunction: (params: PARAMETER_TYPE) => Promise<RETURN_TYPE>; queryFunction: (params: PARAMETER_TYPE) => Promise<RETURN_TYPE>;
onSuccess?: (data: RETURN_TYPE) => Promise<RETURN_TYPE>; onSuccess?: (data: RETURN_TYPE) => Promise<RETURN_TYPE>;
onFail?: (error: RestErrorResponse) => void; onFail?: (error: RestErrorResponse) => void;
} };
export const useQueryCall = <TYPE, PARAMETERS>({ export const useQueryCall = <TYPE, PARAMETERS>({
queryFunction, queryFunction,
onSuccess, onSuccess,
@ -57,12 +60,14 @@ export const useQueryCall = <TYPE, PARAMETERS>({
const [isCalling, setIsCalling] = useState<boolean>(true); const [isCalling, setIsCalling] = useState<boolean>(true);
const [error, setError] = useState<RestErrorResponse | undefined>(undefined); const [error, setError] = useState<RestErrorResponse | undefined>(undefined);
const call = (params: PARAMETERS) => { const call = (params: PARAMETERS) => {
queryFunction(params).then((received) => { queryFunction(params)
.then((received) => {
setIsCalling(false); setIsCalling(false);
if (onSuccess) { if (onSuccess) {
onSuccess(received); onSuccess(received);
} }
}).catch((error) => { })
.catch((error) => {
setIsCalling(false); setIsCalling(false);
if (onFail) { if (onFail) {
onFail(error); onFail(error);
@ -73,11 +78,11 @@ export const useQueryCall = <TYPE, PARAMETERS>({
// Authentication error ==> auto_disconnect // Authentication error ==> auto_disconnect
clearToken(); clearToken();
toaster.create({ toaster.create({
title: "Disconnected by server", title: 'Disconnected by server',
description: "Token is no more available", description: 'Token is no more available',
}); });
} }
}); });
} };
return { call, isCalling, error }; return { call, isCalling, error };
} };

View File

@ -117,7 +117,8 @@ export function sha512(str) {
let len = data.length * charsize; let len = data.length * charsize;
for (let i = 0; i < len; i += charsize) { for (let i = 0; i < len; i += charsize) {
bin[i >> 5] |= (data.charCodeAt(i / charsize) & mask) << (32 - charsize - (i % 32)); bin[i >> 5] |=
(data.charCodeAt(i / charsize) & mask) << (32 - charsize - (i % 32));
} }
return bin; return bin;
@ -131,7 +132,8 @@ export function sha512(str) {
for (let i = 0; i < length; i += 1) { for (let i = 0; i < length; i += 1) {
srcByte = binarray[i >> 2] >> ((3 - (i % 4)) * 8); srcByte = binarray[i >> 2] >> ((3 - (i % 4)) * 8);
data += hex_tab.charAt((srcByte >> 4) & 0xf) + hex_tab.charAt(srcByte & 0xf); data +=
hex_tab.charAt((srcByte >> 4) & 0xf) + hex_tab.charAt(srcByte & 0xf);
} }
return data; return data;
@ -154,8 +156,17 @@ export function sha512(str) {
function safe_add_4(a, b, c, d) { function safe_add_4(a, b, c, d) {
let lsw, msw, lowOrder, highOrder; let lsw, msw, lowOrder, highOrder;
lsw = (a.lowOrder & 0xffff) + (b.lowOrder & 0xffff) + (c.lowOrder & 0xffff) + (d.lowOrder & 0xffff); lsw =
msw = (a.lowOrder >>> 16) + (b.lowOrder >>> 16) + (c.lowOrder >>> 16) + (d.lowOrder >>> 16) + (lsw >>> 16); (a.lowOrder & 0xffff) +
(b.lowOrder & 0xffff) +
(c.lowOrder & 0xffff) +
(d.lowOrder & 0xffff);
msw =
(a.lowOrder >>> 16) +
(b.lowOrder >>> 16) +
(c.lowOrder >>> 16) +
(d.lowOrder >>> 16) +
(lsw >>> 16);
lowOrder = ((msw & 0xffff) << 16) | (lsw & 0xffff); lowOrder = ((msw & 0xffff) << 16) | (lsw & 0xffff);
lsw = lsw =
@ -164,7 +175,12 @@ export function sha512(str) {
(c.highOrder & 0xffff) + (c.highOrder & 0xffff) +
(d.highOrder & 0xffff) + (d.highOrder & 0xffff) +
(msw >>> 16); (msw >>> 16);
msw = (a.highOrder >>> 16) + (b.highOrder >>> 16) + (c.highOrder >>> 16) + (d.highOrder >>> 16) + (lsw >>> 16); msw =
(a.highOrder >>> 16) +
(b.highOrder >>> 16) +
(c.highOrder >>> 16) +
(d.highOrder >>> 16) +
(lsw >>> 16);
highOrder = ((msw & 0xffff) << 16) | (lsw & 0xffff); highOrder = ((msw & 0xffff) << 16) | (lsw & 0xffff);
return new int64(highOrder, lowOrder); return new int64(highOrder, lowOrder);
@ -209,8 +225,12 @@ export function sha512(str) {
function maj(x, y, z) { function maj(x, y, z) {
return new int64( return new int64(
(x.highOrder & y.highOrder) ^ (x.highOrder & z.highOrder) ^ (y.highOrder & z.highOrder), (x.highOrder & y.highOrder) ^
(x.lowOrder & y.lowOrder) ^ (x.lowOrder & z.lowOrder) ^ (y.lowOrder & z.lowOrder) (x.highOrder & z.highOrder) ^
(y.highOrder & z.highOrder),
(x.lowOrder & y.lowOrder) ^
(x.lowOrder & z.lowOrder) ^
(y.lowOrder & z.lowOrder)
); );
} }
@ -281,7 +301,10 @@ export function sha512(str) {
function shr(x, n) { function shr(x, n) {
if (n <= 32) { if (n <= 32) {
return new int64(x.highOrder >>> n, (x.lowOrder >>> n) | (x.highOrder << (32 - n))); return new int64(
x.highOrder >>> n,
(x.lowOrder >>> n) | (x.highOrder << (32 - n))
);
} else { } else {
return new int64(0, x.highOrder << (32 - n)); return new int64(0, x.highOrder << (32 - n));
} }
@ -308,7 +331,12 @@ export function sha512(str) {
if (j < 16) { if (j < 16) {
W[j] = new int64(str[j * 2 + i], str[j * 2 + i + 1]); W[j] = new int64(str[j * 2 + i], str[j * 2 + i + 1]);
} else { } else {
W[j] = safe_add_4(gamma1(W[j - 2]), W[j - 7], gamma0(W[j - 15]), W[j - 16]); W[j] = safe_add_4(
gamma1(W[j - 2]),
W[j - 7],
gamma0(W[j - 15]),
W[j - 16]
);
} }
T1 = safe_add_5(h, sigma1(e), ch(e, f, g), K[j], W[j]); T1 = safe_add_5(h, sigma1(e), ch(e, f, g), K[j], W[j]);

View File

@ -1,4 +1,3 @@
export function isNumeric(val: string): boolean { export function isNumeric(val: string): boolean {
return !isNaN(Number(val)); return !isNaN(Number(val));
} }