[FEAT] review the loggin model to be satble and efficient with user interactions
Signed-off-by: Edouard DUPIN <yui.heero@gmail.com>
This commit is contained in:
parent
83f8ec0e9b
commit
4caec9a54a
@ -35,6 +35,7 @@ public class WebLauncherLocal extends WebLauncher {
|
|||||||
ConfigBaseVariable.dbPort = "3906";
|
ConfigBaseVariable.dbPort = "3906";
|
||||||
ConfigBaseVariable.testMode = "true";
|
ConfigBaseVariable.testMode = "true";
|
||||||
}
|
}
|
||||||
|
// Test fail of SSO: ConfigBaseVariable.ssoAdress = null;
|
||||||
try {
|
try {
|
||||||
super.migrateDB();
|
super.migrateDB();
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
|
@ -1,6 +1,13 @@
|
|||||||
import { useEffect, useRef, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
|
|
||||||
import { Box, Flex, IconButton, SliderTrack, Text } from '@chakra-ui/react';
|
import {
|
||||||
|
Box,
|
||||||
|
Flex,
|
||||||
|
IconButton,
|
||||||
|
SliderTrack,
|
||||||
|
Text,
|
||||||
|
chakra,
|
||||||
|
} from '@chakra-ui/react';
|
||||||
import {
|
import {
|
||||||
MdFastForward,
|
MdFastForward,
|
||||||
MdFastRewind,
|
MdFastRewind,
|
||||||
@ -223,6 +230,7 @@ export const AudioPlayer = ({}: AudioPlayerProps) => {
|
|||||||
paddingX="10px"
|
paddingX="10px"
|
||||||
marginX="15px"
|
marginX="15px"
|
||||||
bottom={0}
|
bottom={0}
|
||||||
|
//top="calc(100% - 150px)"
|
||||||
left={0}
|
left={0}
|
||||||
right={0}
|
right={0}
|
||||||
zIndex={1000}
|
zIndex={1000}
|
||||||
@ -318,7 +326,9 @@ export const AudioPlayer = ({}: AudioPlayerProps) => {
|
|||||||
marginLeft="auto"
|
marginLeft="auto"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
>
|
>
|
||||||
<MdNavigateBefore style={{ width: '100%', height: '100%' }} />{' '}
|
<MdNavigateBefore
|
||||||
|
style={{ width: '100%', height: '100%' }}
|
||||||
|
/>{' '}
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<IconButton
|
<IconButton
|
||||||
{...configButton}
|
{...configButton}
|
||||||
@ -357,7 +367,7 @@ export const AudioPlayer = ({}: AudioPlayerProps) => {
|
|||||||
</Flex>
|
</Flex>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<audio
|
<chakra.audio
|
||||||
src={mediaSource}
|
src={mediaSource}
|
||||||
ref={audioRef}
|
ref={audioRef}
|
||||||
//preload={true}
|
//preload={true}
|
||||||
|
@ -29,6 +29,7 @@ import {
|
|||||||
MdMore,
|
MdMore,
|
||||||
MdOutlinePlaylistPlay,
|
MdOutlinePlaylistPlay,
|
||||||
MdOutlineUploadFile,
|
MdOutlineUploadFile,
|
||||||
|
MdRestartAlt,
|
||||||
MdSupervisedUserCircle,
|
MdSupervisedUserCircle,
|
||||||
} from 'react-icons/md';
|
} from 'react-icons/md';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
@ -47,7 +48,6 @@ import {
|
|||||||
MenuTrigger,
|
MenuTrigger,
|
||||||
} from '@/components/ui/menu';
|
} from '@/components/ui/menu';
|
||||||
import { useServiceContext } from '@/service/ServiceContext';
|
import { useServiceContext } from '@/service/ServiceContext';
|
||||||
import { SessionState } from '@/service/SessionState';
|
|
||||||
import { useSessionService } from '@/service/session';
|
import { useSessionService } from '@/service/session';
|
||||||
import { colors } from '@/theme/colors';
|
import { colors } from '@/theme/colors';
|
||||||
import {
|
import {
|
||||||
@ -120,11 +120,16 @@ export const TopBar = ({
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { colorMode, toggleColorMode } = useColorMode();
|
const { colorMode, toggleColorMode } = useColorMode();
|
||||||
const { session } = useServiceContext();
|
const { session } = useServiceContext();
|
||||||
const { clearToken } = useSessionService();
|
const { clearToken, isConnected } = useSessionService();
|
||||||
const backColor = useColorModeValue('back.100', 'back.800');
|
const backColor = useColorModeValue('back.100', 'back.800');
|
||||||
const drawerDisclose = useDisclosure();
|
const drawerDisclose = useDisclosure();
|
||||||
const onChangeTheme = () => {
|
const isVisible = useBreakpointValue({ base: false, md: true });
|
||||||
drawerDisclose.onOpen();
|
const onOpenLeftMenu = () => {
|
||||||
|
if (!isConnected) {
|
||||||
|
onForceReload();
|
||||||
|
} else {
|
||||||
|
drawerDisclose.onOpen();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
const onSignIn = (): void => {
|
const onSignIn = (): void => {
|
||||||
clearToken();
|
clearToken();
|
||||||
@ -141,7 +146,10 @@ export const TopBar = ({
|
|||||||
const onKarso = (): void => {
|
const onKarso = (): void => {
|
||||||
requestOpenSite();
|
requestOpenSite();
|
||||||
};
|
};
|
||||||
const isVisible = useBreakpointValue({ base: false, md: true });
|
const onForceReload = (): void => {
|
||||||
|
// @ts-expect-error
|
||||||
|
window.location.reload(true);
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<Flex
|
<Flex
|
||||||
minWidth="320px"
|
minWidth="320px"
|
||||||
@ -158,7 +166,7 @@ export const TopBar = ({
|
|||||||
boxShadow={'0px 2px 4px ' + colors.back[900]}
|
boxShadow={'0px 2px 4px ' + colors.back[900]}
|
||||||
zIndex={200}
|
zIndex={200}
|
||||||
>
|
>
|
||||||
<Button {...BUTTON_TOP_BAR_PROPERTY} onClick={onChangeTheme}>
|
<Button {...BUTTON_TOP_BAR_PROPERTY} onClick={onOpenLeftMenu}>
|
||||||
<HStack>
|
<HStack>
|
||||||
<LuAlignJustify />
|
<LuAlignJustify />
|
||||||
{isVisible && (
|
{isVisible && (
|
||||||
@ -169,7 +177,7 @@ export const TopBar = ({
|
|||||||
</HStack>
|
</HStack>
|
||||||
</Button>
|
</Button>
|
||||||
{title && (
|
{title && (
|
||||||
<Text
|
<Flex
|
||||||
truncate
|
truncate
|
||||||
fontSize="20px"
|
fontSize="20px"
|
||||||
fontWeight="bold"
|
fontWeight="bold"
|
||||||
@ -183,11 +191,11 @@ export const TopBar = ({
|
|||||||
{titleIcon}
|
{titleIcon}
|
||||||
{title}
|
{title}
|
||||||
</Flex>
|
</Flex>
|
||||||
</Text>
|
</Flex>
|
||||||
)}
|
)}
|
||||||
{children}
|
{children}
|
||||||
<Flex right="0">
|
<Flex right="0">
|
||||||
{session?.state !== SessionState.CONNECTED && (
|
{!session?.isConnected && (
|
||||||
<>
|
<>
|
||||||
<Button {...BUTTON_TOP_BAR_PROPERTY} onClick={onSignIn}>
|
<Button {...BUTTON_TOP_BAR_PROPERTY} onClick={onSignIn}>
|
||||||
<LuLogIn />
|
<LuLogIn />
|
||||||
@ -207,7 +215,7 @@ export const TopBar = ({
|
|||||||
</Button>
|
</Button>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{session?.state === SessionState.CONNECTED && (
|
{session?.isConnected && (
|
||||||
<MenuRoot>
|
<MenuRoot>
|
||||||
<MenuTrigger asChild>
|
<MenuTrigger asChild>
|
||||||
<IconButton {...BUTTON_TOP_BAR_PROPERTY} width={TOP_BAR_HEIGHT}>
|
<IconButton {...BUTTON_TOP_BAR_PROPERTY} width={TOP_BAR_HEIGHT}>
|
||||||
@ -248,6 +256,13 @@ export const TopBar = ({
|
|||||||
<MenuItem value="karso" valueText="Karso" onClick={onKarso}>
|
<MenuItem value="karso" valueText="Karso" onClick={onKarso}>
|
||||||
<LuKeySquare /> Karso (SSO)
|
<LuKeySquare /> Karso (SSO)
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
<MenuItem
|
||||||
|
value="force_reload"
|
||||||
|
valueText="Karso"
|
||||||
|
onClick={onForceReload}
|
||||||
|
>
|
||||||
|
<MdRestartAlt /> force reload
|
||||||
|
</MenuItem>
|
||||||
{colorMode === 'light' ? (
|
{colorMode === 'light' ? (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
value="set-dark"
|
value="set-dark"
|
||||||
@ -269,50 +284,52 @@ export const TopBar = ({
|
|||||||
</MenuRoot>
|
</MenuRoot>
|
||||||
)}
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
<DrawerRoot
|
{session?.isConnected && (
|
||||||
placement="start"
|
<DrawerRoot
|
||||||
onOpenChange={drawerDisclose.onClose}
|
placement="start"
|
||||||
open={drawerDisclose.open}
|
onOpenChange={drawerDisclose.onClose}
|
||||||
data-testid="top-bar_drawer-root"
|
open={drawerDisclose.open}
|
||||||
>
|
data-testid="top-bar_drawer-root"
|
||||||
<DrawerContent data-testid="top-bar_drawer-content">
|
>
|
||||||
<DrawerHeader
|
<DrawerContent data-testid="top-bar_drawer-content">
|
||||||
paddingY="auto"
|
<DrawerHeader
|
||||||
as="button"
|
paddingY="auto"
|
||||||
onClick={drawerDisclose.onClose}
|
as="button"
|
||||||
boxShadow={'0px 2px 4px ' + colors.back[900]}
|
onClick={drawerDisclose.onClose}
|
||||||
backgroundColor={backColor}
|
boxShadow={'0px 2px 4px ' + colors.back[900]}
|
||||||
color={useColorModeValue('brand.900', 'brand.50')}
|
backgroundColor={backColor}
|
||||||
textTransform="uppercase"
|
color={useColorModeValue('brand.900', 'brand.50')}
|
||||||
>
|
textTransform="uppercase"
|
||||||
<HStack {...BUTTON_TOP_BAR_PROPERTY} cursor="pointer">
|
>
|
||||||
<LuArrowBigLeft />
|
<HStack {...BUTTON_TOP_BAR_PROPERTY} cursor="pointer">
|
||||||
<Span paddingLeft="3px">Karusic</Span>
|
<LuArrowBigLeft />
|
||||||
</HStack>
|
<Span paddingLeft="3px">Karusic</Span>
|
||||||
</DrawerHeader>
|
</HStack>
|
||||||
<DrawerBody paddingX="0px">
|
</DrawerHeader>
|
||||||
<Box marginY="3" />
|
<DrawerBody paddingX="0px">
|
||||||
<ButtonMenuLeft
|
<Box marginY="3" />
|
||||||
onClickEnd={drawerDisclose.onClose}
|
<ButtonMenuLeft
|
||||||
dest="/"
|
onClickEnd={drawerDisclose.onClose}
|
||||||
title="Home"
|
dest="/"
|
||||||
icon={<MdHome />}
|
title="Home"
|
||||||
/>
|
icon={<MdHome />}
|
||||||
<ButtonMenuLeft
|
/>
|
||||||
onClickEnd={drawerDisclose.onClose}
|
<ButtonMenuLeft
|
||||||
dest="/on-air"
|
onClickEnd={drawerDisclose.onClose}
|
||||||
title="On air"
|
dest="/on-air"
|
||||||
icon={<MdOutlinePlaylistPlay />}
|
title="On air"
|
||||||
/>
|
icon={<MdOutlinePlaylistPlay />}
|
||||||
<ButtonMenuLeft
|
/>
|
||||||
onClickEnd={drawerDisclose.onClose}
|
<ButtonMenuLeft
|
||||||
dest="/add"
|
onClickEnd={drawerDisclose.onClose}
|
||||||
title="Add Media"
|
dest="/add"
|
||||||
icon={<MdOutlineUploadFile />}
|
title="Add Media"
|
||||||
/>
|
icon={<MdOutlineUploadFile />}
|
||||||
</DrawerBody>
|
/>
|
||||||
</DrawerContent>
|
</DrawerBody>
|
||||||
</DrawerRoot>
|
</DrawerContent>
|
||||||
|
</DrawerRoot>
|
||||||
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -21,7 +21,7 @@ import { SettingsPage } from './home/SettingsPage';
|
|||||||
import { OnAirPage } from './onAir/OnAirPage';
|
import { OnAirPage } from './onAir/OnAirPage';
|
||||||
|
|
||||||
export const AppRoutes = () => {
|
export const AppRoutes = () => {
|
||||||
const { isReadable } = useHasRight('user');
|
const { isReadable } = useHasRight('USER');
|
||||||
return (
|
return (
|
||||||
<HistoryRouter
|
<HistoryRouter
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
|
@ -1,48 +1,58 @@
|
|||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
import { Center, Heading, Image, Text } from '@chakra-ui/react';
|
import { Center, Flex, Heading, Image, Text } from '@chakra-ui/react';
|
||||||
|
import { MdFactCheck, MdWarning } from 'react-icons/md';
|
||||||
import { useNavigate, useParams } from 'react-router-dom';
|
import { useNavigate, useParams } from 'react-router-dom';
|
||||||
|
import { useEffectOnce } from 'react-use';
|
||||||
|
|
||||||
import avatar_generic from '@/assets/images/avatar_generic.svg';
|
import avatar_generic from '@/assets/images/avatar_generic.svg';
|
||||||
|
import { Icon } from '@/components';
|
||||||
import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter';
|
import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter';
|
||||||
import { TopBar } from '@/components/TopBar/TopBar';
|
import { TopBar } from '@/components/TopBar/TopBar';
|
||||||
import { isDevelopmentEnvironment } from '@/environment';
|
import { toaster } from '@/components/ui/toaster';
|
||||||
import { SessionState } from '@/service/SessionState';
|
|
||||||
import { useSessionService } from '@/service/session';
|
import { useSessionService } from '@/service/session';
|
||||||
import { b64_to_utf8 } from '@/utils/sso';
|
import { b64_to_utf8 } from '@/utils/sso';
|
||||||
|
|
||||||
export const SSOPage = () => {
|
export const SSOPage = () => {
|
||||||
const { data, keepConnected, token } = useParams();
|
const { data, keepConnected, token } = useParams();
|
||||||
console.log(`- data: ${data}`);
|
//const { data, keepConnected, token } = useState<string|undefined>();
|
||||||
console.log(`- keepConnected: ${keepConnected}`);
|
// console.log(`- data: ${data}`);
|
||||||
console.log(`- token: ${token}`);
|
// console.log(`- keepConnected: ${keepConnected}`);
|
||||||
|
// console.log(`- token: ${token}`);
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { state, setToken, login, clearToken } = useSessionService();
|
const { isConnected, errorSession, setToken, login } = useSessionService();
|
||||||
useEffect(() => {
|
useEffectOnce(() => {
|
||||||
if (token) {
|
if (token === undefined || token === '') {
|
||||||
setToken(token);
|
return;
|
||||||
} else {
|
|
||||||
clearToken();
|
|
||||||
}
|
}
|
||||||
}, [token, setToken, clearToken]);
|
try {
|
||||||
const delay = isDevelopmentEnvironment() ? 2000 : 2000;
|
setToken(token);
|
||||||
|
} catch (e) {
|
||||||
|
toaster.create({
|
||||||
|
title: 'Connection Fail',
|
||||||
|
description: `invalid token data model.`,
|
||||||
|
type: 'error',
|
||||||
|
});
|
||||||
|
navigate('/');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const delay = 1000;
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (state === SessionState.CONNECTED) {
|
if (isConnected) {
|
||||||
const destination = data ? b64_to_utf8(data) : '/';
|
toaster.create({
|
||||||
console.log(`program redirect to: ${destination} (${delay}ms)`);
|
title: 'Connection Succeed',
|
||||||
|
description: `Welcome back: ${login}.`,
|
||||||
|
type: 'success',
|
||||||
|
});
|
||||||
|
const destination = data ? b64_to_utf8(data) : '/home';
|
||||||
|
const destinationFinal = destination === '' ? '/home' : destination;
|
||||||
|
console.log(`program redirect to: '${destinationFinal}' (${delay}ms)`);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
navigate(`/${destination}`);
|
// note: check if the "navigate" is in the dependence of the use effect!!!
|
||||||
|
navigate(`/${destinationFinal}`, { replace: true });
|
||||||
}, delay);
|
}, delay);
|
||||||
}
|
}
|
||||||
}, [state]);
|
}, [isConnected, login, navigate]);
|
||||||
/*
|
|
||||||
const [searchParams] = useSearchParams();
|
|
||||||
console.log(`data: ${searchParams.get('data')}`);
|
|
||||||
console.log(`keepConnected: ${searchParams.get('keepConnected')}`);
|
|
||||||
console.log(`token: ${searchParams.get('token')}`);
|
|
||||||
const dataFromParam = useGetCreateActionParams();
|
|
||||||
console.log(`data group: ${JSON.stringify(dataFromParam, null, 2)}`);
|
|
||||||
*/
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TopBar />
|
<TopBar />
|
||||||
@ -54,31 +64,53 @@ export const SSOPage = () => {
|
|||||||
<Center w="full">
|
<Center w="full">
|
||||||
<Image src={avatar_generic} boxSize="150px" borderRadius="full" />
|
<Image src={avatar_generic} boxSize="150px" borderRadius="full" />
|
||||||
</Center>
|
</Center>
|
||||||
{token === '__CANCEL__' && (
|
{!isConnected && errorSession !== undefined && (
|
||||||
<Text>
|
|
||||||
<b>ERROR: </b> Request cancel of connection !
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
{token === '__FAIL__' && (
|
|
||||||
<Text>
|
|
||||||
<b>ERROR: </b> Connection FAIL !
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
{token === '__LOGOUT__' && (
|
|
||||||
<Text>
|
|
||||||
<b>Dis-connected: </b> Redirect soon!{' '}
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
{!['__LOGOUT__', '__FAIL__', '__CANCEL__'].includes(token ?? '') && (
|
|
||||||
<>
|
<>
|
||||||
<Text>
|
<Flex color="red.500" fontSize="25px" gap={2} marginX="auto">
|
||||||
<b>Connected: </b> Redirect soon!
|
<Icon sizeIcon="55px">
|
||||||
</Text>
|
<MdWarning />
|
||||||
<Text>
|
</Icon>
|
||||||
<b>Welcome back: </b> {login}
|
<Text marginY="auto">
|
||||||
</Text>
|
<b>ERROR: </b> {errorSession.message}
|
||||||
|
</Text>
|
||||||
|
</Flex>
|
||||||
|
{errorSession.description && (
|
||||||
|
<Text
|
||||||
|
whiteSpace="pre-line"
|
||||||
|
fontSize="25px"
|
||||||
|
gap={2}
|
||||||
|
marginX="auto"
|
||||||
|
>
|
||||||
|
{errorSession.description}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
{!isConnected && errorSession === undefined && (
|
||||||
|
<Flex color="red.500" fontSize="25px" gap={2} marginX="auto">
|
||||||
|
<Icon sizeIcon="55px">
|
||||||
|
<MdWarning />
|
||||||
|
</Icon>
|
||||||
|
<Text marginY="auto">
|
||||||
|
<b>ERROR: </b> Not connected !
|
||||||
|
</Text>
|
||||||
|
</Flex>
|
||||||
|
)}
|
||||||
|
{isConnected && (
|
||||||
|
<Flex direction="column">
|
||||||
|
<Flex color="green.500" fontSize="25px" gap={2} marginX="auto">
|
||||||
|
<MdFactCheck />
|
||||||
|
<Text marginY="auto">
|
||||||
|
<b>Connected: </b> Redirect soon!
|
||||||
|
</Text>
|
||||||
|
</Flex>
|
||||||
|
<Flex fontSize="25px" gap={2} marginX="auto">
|
||||||
|
<Text marginY="auto">
|
||||||
|
<b>Welcome back: </b> {login}
|
||||||
|
</Text>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
)}
|
||||||
</PageLayoutInfoCenter>
|
</PageLayoutInfoCenter>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { useEffect, useMemo, useState } from 'react';
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
import { Album, AlbumResource } from '@/back-api';
|
import { Album, AlbumResource } from '@/back-api';
|
||||||
import { useServiceContext } from '@/service/ServiceContext';
|
import { useServiceContext } from '@/service/ServiceContext';
|
||||||
@ -23,14 +23,14 @@ export const useAlbumServiceWrapped = (
|
|||||||
{
|
{
|
||||||
restApiName: 'ALBUM',
|
restApiName: 'ALBUM',
|
||||||
primaryKey: 'id',
|
primaryKey: 'id',
|
||||||
available: session.token !== undefined,
|
available: session.isConnected,
|
||||||
getsCall: () => {
|
getsCall: () => {
|
||||||
return AlbumResource.gets({
|
return AlbumResource.gets({
|
||||||
restConfig: session.getRestConfig(),
|
restConfig: session.getRestConfig(),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
[session.token]
|
[session.isConnected]
|
||||||
);
|
);
|
||||||
|
|
||||||
return { store };
|
return { store };
|
||||||
|
@ -23,14 +23,14 @@ export const useArtistServiceWrapped = (
|
|||||||
{
|
{
|
||||||
restApiName: 'ARTIST',
|
restApiName: 'ARTIST',
|
||||||
primaryKey: 'id',
|
primaryKey: 'id',
|
||||||
available: session.token !== undefined,
|
available: session.isConnected,
|
||||||
getsCall: () => {
|
getsCall: () => {
|
||||||
return ArtistResource.gets({
|
return ArtistResource.gets({
|
||||||
restConfig: session.getRestConfig(),
|
restConfig: session.getRestConfig(),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
[session.token]
|
[session.isConnected]
|
||||||
);
|
);
|
||||||
|
|
||||||
return { store };
|
return { store };
|
||||||
|
@ -23,14 +23,14 @@ export const useGenderServiceWrapped = (
|
|||||||
{
|
{
|
||||||
restApiName: 'GENDER',
|
restApiName: 'GENDER',
|
||||||
primaryKey: 'id',
|
primaryKey: 'id',
|
||||||
available: session.token !== undefined,
|
available: session.isConnected,
|
||||||
getsCall: () => {
|
getsCall: () => {
|
||||||
return GenderResource.gets({
|
return GenderResource.gets({
|
||||||
restConfig: session.getRestConfig(),
|
restConfig: session.getRestConfig(),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
[session.token]
|
[session.isConnected]
|
||||||
);
|
);
|
||||||
|
|
||||||
return { store };
|
return { store };
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { ReactNode, createContext, useContext, useMemo } from 'react';
|
import { ReactNode, createContext, useContext, useMemo } from 'react';
|
||||||
|
|
||||||
|
import { Album, Artist, Gender, Track } from '@/back-api';
|
||||||
import {
|
import {
|
||||||
ActivePlaylistServiceProps,
|
ActivePlaylistServiceProps,
|
||||||
useActivePlaylistServiceWrapped,
|
useActivePlaylistServiceWrapped,
|
||||||
@ -7,7 +8,6 @@ import {
|
|||||||
import { AlbumServiceProps, useAlbumServiceWrapped } from '@/service/Album';
|
import { AlbumServiceProps, useAlbumServiceWrapped } from '@/service/Album';
|
||||||
import { ArtistServiceProps, useArtistServiceWrapped } from '@/service/Artist';
|
import { ArtistServiceProps, useArtistServiceWrapped } from '@/service/Artist';
|
||||||
import { useGenderServiceWrapped } from '@/service/Gender';
|
import { useGenderServiceWrapped } from '@/service/Gender';
|
||||||
import { SessionState } from '@/service/SessionState';
|
|
||||||
import { TrackServiceProps, useTrackServiceWrapped } from '@/service/Track';
|
import { TrackServiceProps, useTrackServiceWrapped } from '@/service/Track';
|
||||||
import {
|
import {
|
||||||
RightPart,
|
RightPart,
|
||||||
@ -15,7 +15,6 @@ import {
|
|||||||
getRestConfig,
|
getRestConfig,
|
||||||
useSessionServiceWrapped,
|
useSessionServiceWrapped,
|
||||||
} from '@/service/session';
|
} from '@/service/session';
|
||||||
import { Album, Artist, Gender, Track } from '@/back-api';
|
|
||||||
import { DataStoreType } from '@/utils/data-store';
|
import { DataStoreType } from '@/utils/data-store';
|
||||||
|
|
||||||
export type ServiceContextType = {
|
export type ServiceContextType = {
|
||||||
@ -27,7 +26,6 @@ export type ServiceContextType = {
|
|||||||
activePlaylist: ActivePlaylistServiceProps;
|
activePlaylist: ActivePlaylistServiceProps;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
function emptyStore<TYPE>(): DataStoreType<TYPE> {
|
function emptyStore<TYPE>(): DataStoreType<TYPE> {
|
||||||
return {
|
return {
|
||||||
data: [] as TYPE[],
|
data: [] as TYPE[],
|
||||||
@ -43,22 +41,29 @@ function emptyStore<TYPE>(): DataStoreType<TYPE> {
|
|||||||
error: undefined,
|
error: undefined,
|
||||||
update: (_request: Promise<TYPE>, _key?: string) => {
|
update: (_request: Promise<TYPE>, _key?: string) => {
|
||||||
console.error('!!! WTF !!!');
|
console.error('!!! WTF !!!');
|
||||||
return new Promise((resolve, reject) => { reject("fail") });
|
return new Promise((resolve, reject) => {
|
||||||
|
reject('fail');
|
||||||
|
});
|
||||||
},
|
},
|
||||||
updateRaw: (_data: TYPE, _key?: string) => { },
|
updateRaw: (_data: TYPE, _key?: string) => {},
|
||||||
remove: (_id: number | string, _request: Promise<void>, _key?: string): void => {
|
remove: (
|
||||||
|
_id: number | string,
|
||||||
|
_request: Promise<void>,
|
||||||
|
_key?: string
|
||||||
|
): void => {
|
||||||
console.error('!!! WTF !!!');
|
console.error('!!! WTF !!!');
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ServiceContext = createContext<ServiceContextType>({
|
export const ServiceContext = createContext<ServiceContextType>({
|
||||||
session: {
|
session: {
|
||||||
setToken: (token: string) => { },
|
isConnected: false,
|
||||||
clearToken: () => { },
|
errorSession: undefined,
|
||||||
|
setToken: (token: string) => {},
|
||||||
|
clearToken: () => {},
|
||||||
hasReadRight: (part: RightPart) => false,
|
hasReadRight: (part: RightPart) => false,
|
||||||
hasWriteRight: (part: RightPart) => false,
|
hasWriteRight: (part: RightPart) => false,
|
||||||
state: SessionState.NO_USER,
|
|
||||||
getRestConfig: getRestConfig,
|
getRestConfig: getRestConfig,
|
||||||
},
|
},
|
||||||
track: {
|
track: {
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
export enum SessionState {
|
|
||||||
NO_USER,
|
|
||||||
CONNECTING,
|
|
||||||
CONNECTION_FAIL,
|
|
||||||
CONNECTED,
|
|
||||||
DISCONNECT,
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
import { Track, TrackResource } from '@/back-api';
|
import { Track, TrackResource } from '@/back-api';
|
||||||
import { useServiceContext } from '@/service/ServiceContext';
|
import { useServiceContext } from '@/service/ServiceContext';
|
||||||
@ -23,14 +23,14 @@ export const useTrackServiceWrapped = (
|
|||||||
{
|
{
|
||||||
restApiName: 'TRACK',
|
restApiName: 'TRACK',
|
||||||
primaryKey: 'id',
|
primaryKey: 'id',
|
||||||
available: session.token !== undefined,
|
available: session.isConnected,
|
||||||
getsCall: () => {
|
getsCall: () => {
|
||||||
return TrackResource.gets({
|
return TrackResource.gets({
|
||||||
restConfig: session.getRestConfig(),
|
restConfig: session.getRestConfig(),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
[session.token]
|
[session.isConnected]
|
||||||
);
|
);
|
||||||
|
|
||||||
return { store };
|
return { store };
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
|
|
||||||
import { createListCollection } from '@chakra-ui/react';
|
import { createListCollection } from '@chakra-ui/react';
|
||||||
import { useEffectOnce } from 'react-use';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
JwtToken,
|
||||||
PartRight,
|
PartRight,
|
||||||
RESTConfig,
|
RESTConfig,
|
||||||
UserMe,
|
RestErrorResponse,
|
||||||
UserResource,
|
UserResource,
|
||||||
setErrorApiGlobalCallback,
|
setErrorApiGlobalCallback,
|
||||||
} from '@/back-api';
|
} from '@/back-api';
|
||||||
|
import { toaster } from '@/components/ui/toaster';
|
||||||
import { environment, getApiUrl } from '@/environment';
|
import { environment, getApiUrl } from '@/environment';
|
||||||
import { useServiceContext } from '@/service/ServiceContext';
|
import { useServiceContext } from '@/service/ServiceContext';
|
||||||
import { SessionState } from '@/service/SessionState';
|
|
||||||
import { isBrowser } from '@/utils/layout';
|
import { isBrowser } from '@/utils/layout';
|
||||||
import { parseToken } from '@/utils/sso';
|
import { parseToken } from '@/utils/sso';
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ export const USERS = {
|
|||||||
export const getUserToken = () => {
|
export const getUserToken = () => {
|
||||||
return localStorage.getItem(TOKEN_KEY);
|
return localStorage.getItem(TOKEN_KEY);
|
||||||
};
|
};
|
||||||
export type RightPart = 'admin' | 'user';
|
export type RightPart = 'ADMIN' | 'USER';
|
||||||
|
|
||||||
export function getRestConfig(): RESTConfig {
|
export function getRestConfig(): RESTConfig {
|
||||||
return {
|
return {
|
||||||
@ -46,14 +46,48 @@ export function getRestConfig(): RESTConfig {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getDeltaPrint = (date: Date): string => {
|
||||||
|
const now = new Date();
|
||||||
|
let deltaSeconds = Math.floor((date.getTime() - now.getTime()) / 1000);
|
||||||
|
const isPast = deltaSeconds < 0;
|
||||||
|
|
||||||
|
deltaSeconds = Math.abs(deltaSeconds);
|
||||||
|
|
||||||
|
const days = Math.floor(deltaSeconds / 86400);
|
||||||
|
deltaSeconds %= 86400;
|
||||||
|
|
||||||
|
const hours = Math.floor(deltaSeconds / 3600);
|
||||||
|
deltaSeconds %= 3600;
|
||||||
|
|
||||||
|
const minutes = Math.floor(deltaSeconds / 60);
|
||||||
|
const seconds = deltaSeconds % 60;
|
||||||
|
|
||||||
|
const result = [days > 0 ? `${days}j` : '', `${hours}h${minutes}:${seconds}s`]
|
||||||
|
.filter(Boolean)
|
||||||
|
.join(' ');
|
||||||
|
|
||||||
|
return `${result}${isPast ? ' ago' : ''}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const isInThePast = (date: Date): boolean => {
|
||||||
|
const now = new Date();
|
||||||
|
return date.getTime() < now.getTime();
|
||||||
|
};
|
||||||
|
|
||||||
|
export type SessionErrorType = {
|
||||||
|
message: string;
|
||||||
|
description?: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type SessionServiceProps = {
|
export type SessionServiceProps = {
|
||||||
token?: string;
|
token?: string;
|
||||||
|
isConnected: boolean;
|
||||||
|
errorSession?: SessionErrorType;
|
||||||
setToken: (token: string) => void;
|
setToken: (token: string) => void;
|
||||||
clearToken: () => void;
|
clearToken: () => void;
|
||||||
login?: string;
|
login?: string;
|
||||||
hasReadRight: (part: RightPart) => boolean;
|
hasReadRight: (part: RightPart) => boolean;
|
||||||
hasWriteRight: (part: RightPart) => boolean;
|
hasWriteRight: (part: RightPart) => boolean;
|
||||||
state: SessionState;
|
|
||||||
getRestConfig: () => RESTConfig;
|
getRestConfig: () => RESTConfig;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -63,115 +97,161 @@ export const useSessionService = (): SessionServiceProps => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const useSessionServiceWrapped = (): SessionServiceProps => {
|
export const useSessionServiceWrapped = (): SessionServiceProps => {
|
||||||
const [token, setToken] = useState<string | undefined>(
|
// Load the token from the system (init)
|
||||||
|
const [tokenStorage, setTokenStorage] = useState<string | undefined>(
|
||||||
isBrowser ? (localStorage.getItem(TOKEN_KEY) ?? undefined) : undefined
|
isBrowser ? (localStorage.getItem(TOKEN_KEY) ?? undefined) : undefined
|
||||||
);
|
);
|
||||||
const [state, setState] = useState<SessionState>(SessionState.NO_USER);
|
// Token that is ready to use
|
||||||
const [config, setConfig] = useState<UserMe | undefined>(undefined);
|
const [tokenStr, setTokenStr] = useState<string>('');
|
||||||
|
const [errorSession, setErrorSession] = useState<
|
||||||
|
SessionErrorType | undefined
|
||||||
|
>(undefined);
|
||||||
|
const [token, setToken] = useState<JwtToken | undefined>(undefined);
|
||||||
|
|
||||||
useEffectOnce(() => {
|
const getRestConfigLocal = useCallback((): RESTConfig => {
|
||||||
setErrorApiGlobalCallback((response: Response) => {
|
return {
|
||||||
if (response.status == 401) {
|
server: getApiUrl(),
|
||||||
console.error('Detect 401 error ==> remove token');
|
token: tokenStr,
|
||||||
clearToken();
|
};
|
||||||
}
|
}, [tokenStr]);
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const updateRight = useCallback(() => {
|
const updateRight = useEffect(() => {
|
||||||
console.log('update right...');
|
//console.log('Detect a new token...');
|
||||||
if (isBrowser) {
|
if (isBrowser) {
|
||||||
console.log('Detect a new token...');
|
//console.log('update internal property');
|
||||||
|
if (tokenStorage === undefined) {
|
||||||
if (token === undefined) {
|
//console.log(` ==> No User`);
|
||||||
console.log(` ==> No User`);
|
setToken(undefined);
|
||||||
setState(SessionState.NO_USER);
|
setTokenStr('');
|
||||||
setConfig(undefined);
|
|
||||||
localStorage.removeItem(TOKEN_KEY);
|
localStorage.removeItem(TOKEN_KEY);
|
||||||
} else {
|
} else {
|
||||||
console.log(' ==> Login ... (try to keep right)');
|
//console.log(' ==> Login ... (try to keep right)');
|
||||||
setState(SessionState.CONNECTING);
|
let tokenParsed: JwtToken | undefined = undefined;
|
||||||
localStorage.setItem(TOKEN_KEY, token);
|
try {
|
||||||
|
tokenParsed = parseToken(tokenStorage);
|
||||||
|
} catch (e) {
|
||||||
|
setErrorSession({
|
||||||
|
message: 'Fail to parse the token',
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//console.log(`get new token: ${JSON.stringify(tokenParsed, null, 2)}`);
|
||||||
|
const exp = new Date(tokenParsed.payload.exp * 1000);
|
||||||
|
if (isInThePast(exp)) {
|
||||||
|
//console.log(`token expired at: exp: ${exp.toISOString()}: delta=${getDeltaPrint(exp)}`);
|
||||||
|
const iat = new Date(tokenParsed.payload.iat * 1000);
|
||||||
|
//console.log(`iat: ${iat.toISOString()}: delta=${getDeltaPrint(iat)}`);
|
||||||
|
setErrorSession({
|
||||||
|
message: 'The inserted token has expired',
|
||||||
|
description: `It expired at ${exp.toISOString()}\nSince: ${getDeltaPrint(exp)}`,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Validate token on the server:
|
||||||
UserResource.getMe({
|
UserResource.getMe({
|
||||||
restConfig: getRestConfig(),
|
restConfig: {
|
||||||
|
server: getApiUrl(),
|
||||||
|
token: tokenStorage,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
.then((response: UserMe) => {
|
.then((_response) => {
|
||||||
//console.log(` ==> New right arrived to '${response.login}'`);
|
// if the login work well, then the token does not fail with authentication
|
||||||
setState(SessionState.CONNECTED);
|
//console.log('Authentication finished: ...');
|
||||||
setConfig(response);
|
setTokenStr(tokenStorage);
|
||||||
|
setToken(tokenParsed);
|
||||||
|
localStorage.setItem(TOKEN_KEY, tokenStorage);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error: RestErrorResponse) => {
|
||||||
setState(SessionState.CONNECTION_FAIL);
|
setErrorSession({
|
||||||
setConfig(undefined);
|
message: 'The server reject the token.',
|
||||||
//console.log(` ==> Fail to get right: '${error}'`);
|
description: `name: ${error.name}\nmessage: "${error.message}"`,
|
||||||
|
});
|
||||||
|
setTokenStr('');
|
||||||
|
setToken(undefined);
|
||||||
localStorage.removeItem(TOKEN_KEY);
|
localStorage.removeItem(TOKEN_KEY);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [localStorage, parseToken, token]);
|
}, [
|
||||||
|
localStorage,
|
||||||
|
parseToken,
|
||||||
|
setErrorSession,
|
||||||
|
setToken,
|
||||||
|
setTokenStr,
|
||||||
|
tokenStorage,
|
||||||
|
]);
|
||||||
|
|
||||||
const setTokenLocal = useCallback(
|
const setTokenLocal = useCallback(
|
||||||
(token?: string) => {
|
(token?: string) => {
|
||||||
if (token ? token.startsWith('__') : false) {
|
if (token ? token.startsWith('__') : false) {
|
||||||
token = undefined;
|
token = undefined;
|
||||||
}
|
}
|
||||||
setToken(token);
|
localStorage.removeItem(TOKEN_KEY);
|
||||||
updateRight();
|
setTokenStorage(token);
|
||||||
|
setTokenStr('');
|
||||||
|
setToken(undefined);
|
||||||
|
setErrorSession(undefined);
|
||||||
},
|
},
|
||||||
[updateRight, setToken]
|
[updateRight, setToken]
|
||||||
);
|
);
|
||||||
const clearToken = useCallback(() => {
|
const clearToken = useCallback(() => {
|
||||||
|
localStorage.removeItem(TOKEN_KEY);
|
||||||
|
setTokenLocal(undefined);
|
||||||
setToken(undefined);
|
setToken(undefined);
|
||||||
updateRight();
|
|
||||||
}, [updateRight, setToken]);
|
}, [updateRight, setToken]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setErrorApiGlobalCallback((response: Response) => {
|
||||||
|
if (response.status == 401) {
|
||||||
|
toaster.create({
|
||||||
|
title: 'API request rejected',
|
||||||
|
description: `API Authentication rejected by server.`,
|
||||||
|
type: 'error',
|
||||||
|
});
|
||||||
|
clearToken();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, [clearToken]);
|
||||||
|
|
||||||
const hasReadRight = useCallback(
|
const hasReadRight = useCallback(
|
||||||
(part: RightPart) => {
|
(part: RightPart) => {
|
||||||
//console.log(`config = ${JSON.stringify(config, null, 2)}`);
|
//console.log(`right = ${JSON.stringify(token?.payload?.right?.[environment.applName], null, 2)}`);
|
||||||
const right = config?.rights[environment.applName];
|
const right = token?.payload?.right?.[environment.applName];
|
||||||
if (right === undefined) {
|
if (right === undefined) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return [PartRight.READ, PartRight.READ_WRITE].includes(right[part]);
|
return [PartRight.READ, PartRight.READ_WRITE].includes(right[part]);
|
||||||
},
|
},
|
||||||
[config]
|
[token]
|
||||||
);
|
);
|
||||||
const hasWriteRight = useCallback(
|
const hasWriteRight = useCallback(
|
||||||
(part: RightPart) => {
|
(part: RightPart) => {
|
||||||
const right = config?.rights[environment.applName];
|
const right = token?.payload?.right?.[environment.applName];
|
||||||
if (right === undefined) {
|
if (right === undefined) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return [PartRight.READ, PartRight.READ_WRITE].includes(right[part]);
|
return [PartRight.READ, PartRight.READ_WRITE].includes(right[part]);
|
||||||
},
|
},
|
||||||
[config]
|
[token]
|
||||||
);
|
);
|
||||||
|
|
||||||
const getRestConfig = useCallback((): RESTConfig => {
|
|
||||||
return {
|
|
||||||
server: getApiUrl(),
|
|
||||||
token: token ?? '',
|
|
||||||
};
|
|
||||||
}, [token]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
updateRight();
|
|
||||||
}, [updateRight]);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
token,
|
token: tokenStr,
|
||||||
|
isConnected: token !== undefined,
|
||||||
|
errorSession,
|
||||||
setToken: setTokenLocal,
|
setToken: setTokenLocal,
|
||||||
clearToken,
|
clearToken,
|
||||||
login: config?.login,
|
login: token?.payload?.login,
|
||||||
hasReadRight,
|
hasReadRight,
|
||||||
hasWriteRight,
|
hasWriteRight,
|
||||||
state,
|
getRestConfig: getRestConfigLocal,
|
||||||
getRestConfig,
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useHasRight = (part: RightPart) => {
|
export const useHasRight = (part: RightPart) => {
|
||||||
const { token, hasReadRight, hasWriteRight } = useSessionService();
|
const { token, hasReadRight, hasWriteRight } = useSessionService();
|
||||||
const isReadable = useMemo(() => {
|
const isReadable = useMemo(() => {
|
||||||
console.log(`get is read for: ${part} ==> ${hasReadRight(part)}`);
|
//console.log(`get is read for: ${part} ==> ${hasReadRight(part)}`);
|
||||||
return hasReadRight(part);
|
return hasReadRight(part);
|
||||||
}, [token, hasReadRight, part]);
|
}, [token, hasReadRight, part]);
|
||||||
const isWritable = useMemo(() => {
|
const isWritable = useMemo(() => {
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
import { RESTConfig } from '@/back-api';
|
|
||||||
import { getApiUrl } from '@/environment';
|
|
||||||
import { getUserToken } from '@/service/session';
|
|
||||||
|
|
||||||
export function getRestConfig(): RESTConfig {
|
|
||||||
return {
|
|
||||||
server: getApiUrl(),
|
|
||||||
token: getUserToken() ?? '',
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,3 +1,4 @@
|
|||||||
|
import { JwtToken, ZodJwtToken } from '@/back-api';
|
||||||
import { environment } from '@/environment';
|
import { environment } from '@/environment';
|
||||||
import { getApplicationLocation } from '@/utils/applPath';
|
import { getApplicationLocation } from '@/utils/applPath';
|
||||||
|
|
||||||
@ -72,19 +73,28 @@ export function unHashLocalData(data: string): string | undefined {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function parseToken(token: string): object {
|
const convertBase64asJson = (data: string) => {
|
||||||
const cut = token.split('.');
|
try {
|
||||||
const decoded = b64_to_utf8(cut[1]);
|
const jsonBuffer = b64_to_utf8(data);
|
||||||
const jsonModel = JSON.parse(decoded);
|
return JSON.parse(jsonBuffer);
|
||||||
if (jsonModel.right === undefined) {
|
} catch (e) {
|
||||||
return {};
|
console.error(`FAil to convert base64 data: ${e}`);
|
||||||
}
|
}
|
||||||
if (jsonModel.right[environment.applName] === undefined) {
|
};
|
||||||
return {};
|
|
||||||
}
|
|
||||||
return jsonModel.right[environment.applName];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
export function parseToken(token: string): JwtToken {
|
||||||
|
const parts = token.split('.');
|
||||||
|
if (parts.length !== 3) {
|
||||||
|
console.error(`Wrong token model ${token}`);
|
||||||
|
throw new Error('Token JWT invalid');
|
||||||
|
}
|
||||||
|
const result = {
|
||||||
|
header: convertBase64asJson(parts[0]),
|
||||||
|
payload: convertBase64asJson(parts[1]),
|
||||||
|
signature: parts[2],
|
||||||
|
};
|
||||||
|
return ZodJwtToken.parse(result);
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Request Open SSO Global website
|
* Request Open SSO Global website
|
||||||
*/
|
*/
|
||||||
@ -98,14 +108,14 @@ export function requestSignIn(name?: string): void {
|
|||||||
console.log(
|
console.log(
|
||||||
`Request sign-in: '${environment.ssoSignIn}' + '${hashLocalData(name)}'`
|
`Request sign-in: '${environment.ssoSignIn}' + '${hashLocalData(name)}'`
|
||||||
);
|
);
|
||||||
window.location.href = environment.ssoSignIn + hashLocalData(name) + "/";
|
window.location.href = environment.ssoSignIn + hashLocalData(name) + '/';
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Request SSO Disconnect
|
* Request SSO Disconnect
|
||||||
*/
|
*/
|
||||||
export function requestSignOut(name?: string): void {
|
export function requestSignOut(name?: string): void {
|
||||||
const url = environment.ssoSignOut + hashLocalData(name);
|
const url = environment.ssoSignOut + hashLocalData(name);
|
||||||
console.log(`Request just to the SSO: ${url}`)
|
console.log(`Request just to the SSO: ${url}`);
|
||||||
// unlog from the SSO
|
// unlog from the SSO
|
||||||
window.location.href = url;
|
window.location.href = url;
|
||||||
}
|
}
|
||||||
@ -114,7 +124,7 @@ export function requestSignOut(name?: string): void {
|
|||||||
*/
|
*/
|
||||||
export function requestSignUp(name?: string): void {
|
export function requestSignUp(name?: string): void {
|
||||||
const url = environment.ssoSignUp + hashLocalData(name);
|
const url = environment.ssoSignUp + hashLocalData(name);
|
||||||
console.log(`Request just to the SSO: ${url}`)
|
console.log(`Request just to the SSO: ${url}`);
|
||||||
// unlog from the SSO
|
// unlog from the SSO
|
||||||
window.location.href = url;
|
window.location.href = url;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user