Compare commits
2 commits
d0c0ad1319
...
a3ac22d694
Author | SHA1 | Date | |
---|---|---|---|
a3ac22d694 | |||
b4ebc22edd |
25 changed files with 124 additions and 68 deletions
1
.devcontainer/Dockerfile
Normal file
1
.devcontainer/Dockerfile
Normal file
|
@ -0,0 +1 @@
|
|||
FROM local/nodejs-dev:n18_j11
|
6
.devcontainer/devcontainer.json
Normal file
6
.devcontainer/devcontainer.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"name": "procyon",
|
||||
"workspaceFolder": "/home/project/procyon",
|
||||
"dockerComposeFile": "docker-compose.yml",
|
||||
"service": "procyon",
|
||||
}
|
12
.devcontainer/docker-compose.yml
Normal file
12
.devcontainer/docker-compose.yml
Normal file
|
@ -0,0 +1,12 @@
|
|||
version: "3"
|
||||
|
||||
name: procyon
|
||||
|
||||
services:
|
||||
procyon:
|
||||
build:
|
||||
context: .
|
||||
container_name: procyon
|
||||
volumes:
|
||||
- ../:/home/project/procyon
|
||||
command: sleep infinity
|
|
@ -1,6 +1,6 @@
|
|||
import { isJSON } from '@procyon/utils';
|
||||
|
||||
import { FetchTokensParams } from './types';
|
||||
import { UseFetchTokensParams } from './types';
|
||||
|
||||
export const fetchTokens = async ({
|
||||
baseUrl,
|
||||
|
@ -9,7 +9,7 @@ export const fetchTokens = async ({
|
|||
code,
|
||||
grantType,
|
||||
redirectUri,
|
||||
}: FetchTokensParams) => {
|
||||
}: UseFetchTokensParams) => {
|
||||
try {
|
||||
const response = await fetch(`${baseUrl}${tokenEndpoint}`, {
|
||||
method: 'post',
|
||||
|
|
8
packages/auth/src/hook/useAuthAttributes.ts
Executable file
8
packages/auth/src/hook/useAuthAttributes.ts
Executable file
|
@ -0,0 +1,8 @@
|
|||
import { useSelector } from 'react-redux';
|
||||
|
||||
import { AUTH_REDUCER_NAME, AuthRootState } from '@procyon/auth/types';
|
||||
import { ROOT_REDUCER_NAME } from '@procyon/constants/redux';
|
||||
|
||||
export const useAuthAttributes = () => {
|
||||
return useSelector<AuthRootState>((state) => state[ROOT_REDUCER_NAME][AUTH_REDUCER_NAME]);
|
||||
};
|
|
@ -5,9 +5,9 @@ import { useLocation } from 'wouter';
|
|||
import { setAuthTokens } from '@procyon/auth/slice';
|
||||
|
||||
import { fetchTokens } from '../actions';
|
||||
import { UseAuthParams } from '../types';
|
||||
import { UseLoginParams } from '../types';
|
||||
|
||||
export const useAuthCode = ({ baseUrl, clientId, tokenEndpoint, redirectUri }: UseAuthParams) => {
|
||||
export const useFetchTokens = ({ baseUrl, clientId, tokenEndpoint, redirectUri }: UseLoginParams) => {
|
||||
const dispatch = useDispatch<any>();
|
||||
|
||||
const [, setLocation] = useLocation();
|
|
@ -1,6 +1,6 @@
|
|||
import { useCallback } from 'react';
|
||||
|
||||
import { UseAuthParams } from '../types';
|
||||
import { UseLoginParams } from '../types';
|
||||
|
||||
const generateState = () =>
|
||||
'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
||||
|
@ -9,7 +9,7 @@ const generateState = () =>
|
|||
return v.toString(16);
|
||||
});
|
||||
|
||||
export const useLogin = ({ baseUrl, clientId, authEndpoint, redirectUri }: UseAuthParams) => {
|
||||
export const useLogin = ({ baseUrl, clientId, authEndpoint, redirectUri }: UseLoginParams) => {
|
||||
return useCallback(() => {
|
||||
const state = generateState();
|
||||
const urlParams: Record<string, string> = {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
||||
import { addSeconds } from 'date-fns';
|
||||
|
||||
import { AUTH_REDUCER_NAME, AuthAttributes, AuthRootState, AuthTokenPayload, ModifyAuthAttribute } from './types';
|
||||
import { AUTH_REDUCER_NAME, AuthAttributes, AuthRootState, AuthTokens, ModifyAuthAttributePayload } from './types';
|
||||
|
||||
const initialState: AuthAttributes = {
|
||||
authenticated: undefined,
|
||||
|
@ -19,7 +19,7 @@ const authSlice = createSlice({
|
|||
name: AUTH_REDUCER_NAME,
|
||||
initialState,
|
||||
reducers: {
|
||||
setAuthTokens: (_, action: PayloadAction<AuthTokenPayload>) => {
|
||||
setAuthTokens: (_, action: PayloadAction<AuthTokens>) => {
|
||||
const { accessExpiresIn, refreshExpiresIn } = action.payload;
|
||||
return {
|
||||
...action.payload,
|
||||
|
@ -34,7 +34,7 @@ const authSlice = createSlice({
|
|||
...action.payload,
|
||||
};
|
||||
},
|
||||
updateAuthAttribute: (state, action: PayloadAction<ModifyAuthAttribute>) => {
|
||||
updateAuthAttribute: (state, action: PayloadAction<ModifyAuthAttributePayload>) => {
|
||||
state[action.payload.key] = action.payload.value;
|
||||
},
|
||||
deleteAuthAttributes: () => {
|
||||
|
@ -50,9 +50,10 @@ export const setAuthAttribute = authSlice.actions.setAuthAttribute as <T>(
|
|||
) => PayloadAction<AuthAttributes<T>>;
|
||||
|
||||
export const updateAuthAttribute = authSlice.actions.updateAuthAttribute as <T>(
|
||||
attrs: ModifyAuthAttribute<T>
|
||||
) => PayloadAction<ModifyAuthAttribute<T>>;
|
||||
attrs: ModifyAuthAttributePayload<T>
|
||||
) => PayloadAction<ModifyAuthAttributePayload<T>>;
|
||||
|
||||
export const getAuthAttribute = (state: AuthRootState, name: keyof AuthAttributes) => state.procyon.auth[name];
|
||||
export const getAuthAttribute = <T>(state: AuthRootState, name: keyof AuthAttributes<T>) =>
|
||||
state.procyon.auth[name as any];
|
||||
|
||||
export default authSlice.reducer;
|
||||
|
|
|
@ -2,7 +2,7 @@ import { ROOT_REDUCER_NAME } from '@procyon/constants/redux';
|
|||
|
||||
export const AUTH_REDUCER_NAME = 'auth';
|
||||
|
||||
export type AuthTokenPayload = {
|
||||
export type AuthTokens = {
|
||||
accessExpiresIn?: number;
|
||||
accessToken?: string;
|
||||
idToken?: string;
|
||||
|
@ -11,14 +11,14 @@ export type AuthTokenPayload = {
|
|||
sessionState?: string;
|
||||
};
|
||||
|
||||
export type AuthAttributes<CustomAttributes = unknown> = {
|
||||
export type AuthAttributes<C = unknown> = {
|
||||
accessExpiresTime?: string;
|
||||
authenticated?: boolean;
|
||||
refreshExpiresTime?: string;
|
||||
} & CustomAttributes &
|
||||
AuthTokenPayload;
|
||||
} & C &
|
||||
AuthTokens;
|
||||
|
||||
export type ModifyAuthAttribute<P = unknown> = {
|
||||
export type ModifyAuthAttributePayload<P = unknown> = {
|
||||
key: keyof AuthAttributes<P>;
|
||||
value: any;
|
||||
};
|
||||
|
@ -29,7 +29,7 @@ export type AuthRootState = {
|
|||
};
|
||||
};
|
||||
|
||||
export type UseAuthParams = {
|
||||
export type UseLoginParams = {
|
||||
authEndpoint: string;
|
||||
baseUrl: string;
|
||||
clientId: string;
|
||||
|
@ -38,7 +38,7 @@ export type UseAuthParams = {
|
|||
tokenEndpoint: string;
|
||||
};
|
||||
|
||||
export type FetchTokensParams = Pick<UseAuthParams, 'baseUrl' | 'tokenEndpoint' | 'clientId'> & {
|
||||
export type UseFetchTokensParams = Pick<UseLoginParams, 'baseUrl' | 'tokenEndpoint' | 'clientId'> & {
|
||||
code: string;
|
||||
grantType: 'authorization_code';
|
||||
redirectUri: string;
|
||||
|
|
|
@ -69,7 +69,8 @@ export const DatePicker: React.FC<DatePickerProps<Date>> = (props) => {
|
|||
label={label}
|
||||
value={value ? formatFn(value, props.format ?? DefaultDateFormat) : undefined}
|
||||
{...omit(['value', 'onClick'], others)}
|
||||
leftIcon={<TodayIcon onClick={handleOpenModal} className="cursor-pointer" />}
|
||||
leftIcon={<TodayIcon onClick={handleOpenModal} className="cursor-pointer text-primary-200" />}
|
||||
placeholder={format ?? DefaultDateFormat}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
10
packages/components/src/Icons/ButtonCursor.tsx
Executable file
10
packages/components/src/Icons/ButtonCursor.tsx
Executable file
|
@ -0,0 +1,10 @@
|
|||
// icon:button-cursor | Material Design Icons https://materialdesignicons.com/ | Austin Andrews
|
||||
import * as React from 'react';
|
||||
|
||||
export function ButtonCursorIcon(props: React.SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg viewBox="0 0 24 24" fill="currentColor" height="1em" width="1em" {...props}>
|
||||
<path d="M18.1 15.3c-.1.1-.3.2-.4.3l-2.4.4 1.7 3.6c.2.4 0 .8-.4 1l-2.8 1.3c-.1.1-.2.1-.3.1-.3 0-.6-.2-.7-.4L11.2 18l-1.9 1.5c-.1.1-.3.2-.5.2-.4 0-.8-.3-.8-.8V7.5c0-.5.3-.8.8-.8.2 0 .4.1.5.2l8.7 7.4c.3.2.4.7.1 1M6 12H4V4h16v8h-1.6l2.2 1.9c.8-.3 1.3-1 1.3-1.9V4c0-1.1-.9-2-2-2H4c-1.1 0-2 .9-2 2v8c0 1.1.9 2 2 2h2v-2z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
|
@ -3,22 +3,8 @@ import * as React from 'react';
|
|||
|
||||
export function ClockTimeIcon(props: React.SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg viewBox="0 0 512 512" fill="currentColor" height="1em" width="1em" {...props}>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeMiterlimit={10}
|
||||
strokeWidth={32}
|
||||
d="M256 64C150 64 64 150 64 256s86 192 192 192 192-86 192-192S362 64 256 64z"
|
||||
/>
|
||||
<path
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={32}
|
||||
d="M256 128v144h96"
|
||||
/>
|
||||
<svg viewBox="0 0 24 24" fill="currentColor" height="1em" width="1em" {...props}>
|
||||
<path d="M12 20c4.4 0 8-3.6 8-8s-3.6-8-8-8-8 3.6-8 8 3.6 8 8 8m0-18c5.5 0 10 4.5 10 10s-4.5 10-10 10S2 17.5 2 12 6.5 2 12 2m3.3 14.2L14 17l-3-5.2V7h1.5v4.4l2.8 4.8z" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
|
20
packages/components/src/Icons/Pointer.tsx
Executable file
20
packages/components/src/Icons/Pointer.tsx
Executable file
|
@ -0,0 +1,20 @@
|
|||
// icon:pointer | Lucide https://lucide.dev/ | Lucide
|
||||
import * as React from 'react';
|
||||
|
||||
export function PointerIcon(props: React.SVGProps<SVGSVGElement>) {
|
||||
return (
|
||||
<svg
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
viewBox="0 0 24 24"
|
||||
height="1em"
|
||||
width="1em"
|
||||
{...props}>
|
||||
<path d="M22 14a8 8 0 01-8 8M18 11v-1a2 2 0 00-2-2v0a2 2 0 00-2 2v0M14 10V9a2 2 0 00-2-2v0a2 2 0 00-2 2v1M10 9.5V4a2 2 0 00-2-2v0a2 2 0 00-2 2v10" />
|
||||
<path d="M18 11a2 2 0 114 0v3a8 8 0 01-8 8h-2c-2.8 0-4.5-.86-5.99-2.34l-3.6-3.6a2 2 0 012.83-2.82L7 15" />
|
||||
</svg>
|
||||
);
|
||||
}
|
|
@ -122,7 +122,7 @@ const List: React.FC<IProps> = ({
|
|||
<div
|
||||
key={option.code}
|
||||
id={`list-${name}_${i}`}
|
||||
className={clsx('list', className, {
|
||||
className={clsx('list', {
|
||||
'list-compact': compact,
|
||||
'list--focus': index === i,
|
||||
'list--active': selectedItemCode === option.code,
|
||||
|
@ -146,7 +146,7 @@ const List: React.FC<IProps> = ({
|
|||
<TextField name="search" label="Hledat" onChange={handleSearch} autoFocus />
|
||||
</div>
|
||||
)}
|
||||
<div className={clsx('list-container')} onMouseLeave={setCurrentOption(-1)}>
|
||||
<div className={clsx('list-container', className)} onMouseLeave={setCurrentOption(-1)}>
|
||||
{items}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { find, propEq, propOr } from 'ramda';
|
||||
|
||||
import { PointerIcon } from '@procyon/components/Icons/Pointer';
|
||||
import { ModalId } from '@procyon/components/Modal/context';
|
||||
import { useModal } from '@procyon/components/Modal/hooks';
|
||||
import { InputElementType } from '@procyon/types/form';
|
||||
|
@ -14,12 +15,11 @@ export type SelectBoxProps<V = Option> = Omit<
|
|||
autoComplete?: boolean;
|
||||
options: Option[];
|
||||
} & InputElementType<V>,
|
||||
'onFocus' | 'onClick'
|
||||
'onFocus' | 'onClick' | 'onBlur'
|
||||
>;
|
||||
|
||||
export const Selectbox: React.FC<SelectBoxProps> = (props) => {
|
||||
const { value, options, onBlur, onChange, name, label, autoComplete, ...others } =
|
||||
props;
|
||||
const { value, options, onChange, name, label, autoComplete, ...others } = props;
|
||||
|
||||
const { openModal, closeModal, registerModal } = useModal();
|
||||
|
||||
|
@ -32,10 +32,6 @@ export const Selectbox: React.FC<SelectBoxProps> = (props) => {
|
|||
}
|
||||
}, [value, options]);
|
||||
|
||||
const handleBlur = (_: string, e: React.FocusEvent<HTMLInputElement>): void => {
|
||||
onBlur?.(selectedOption ?? undefined, e);
|
||||
};
|
||||
|
||||
const handleOptionClick = (option: Option): void => {
|
||||
setSelectedOption(option);
|
||||
onChange?.(option, null);
|
||||
|
@ -81,11 +77,9 @@ export const Selectbox: React.FC<SelectBoxProps> = (props) => {
|
|||
{...others}
|
||||
name={name}
|
||||
label={label}
|
||||
onClick={handleOpenModal}
|
||||
onFocus={handleOpenModal}
|
||||
onBlur={handleBlur}
|
||||
value={propOr('', 'name', selectedOption)}
|
||||
readonly
|
||||
leftIcon={<PointerIcon className="cursor-pointer text-primary-200" onClick={handleOpenModal} />}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -29,6 +29,7 @@ export const TextField: React.FC<TextFieldProps> = (props) => {
|
|||
status,
|
||||
autoFocus,
|
||||
mask,
|
||||
placeholder,
|
||||
multiline,
|
||||
leftIcon,
|
||||
rightIcon,
|
||||
|
@ -139,6 +140,7 @@ export const TextField: React.FC<TextFieldProps> = (props) => {
|
|||
className={clsx(passProps.className, {
|
||||
'field-input--nolabel': !label,
|
||||
})}
|
||||
placeholder={placeholder}
|
||||
autoComplete="off"
|
||||
type={type}
|
||||
/>
|
||||
|
|
|
@ -42,6 +42,7 @@ const TimeList: React.FC<TimeListProps> = ({ title, onChange, min, max, step, se
|
|||
selectedCode={selectedCode}
|
||||
scrollToCode={scrollToCode}
|
||||
enableAutoScroll
|
||||
className="h-60"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -46,7 +46,7 @@ export const TimePicker: FC<TimePickerProps<Date>> = (props) => {
|
|||
registerModal({
|
||||
id: name,
|
||||
title: label,
|
||||
style: { width: 250 },
|
||||
style: { width: 200 },
|
||||
Component: modalComponent,
|
||||
});
|
||||
openModal(name);
|
||||
|
@ -73,7 +73,9 @@ export const TimePicker: FC<TimePickerProps<Date>> = (props) => {
|
|||
name={name}
|
||||
label={label}
|
||||
value={value ? format(value, 'HH:mm') : undefined}
|
||||
leftIcon={<ClockTimeIcon onClick={handleOpenModal} className="cursor-pointer" />}
|
||||
leftIcon={<ClockTimeIcon onClick={handleOpenModal} className="cursor-pointer text-primary-200" />}
|
||||
placeholder="HH:mm"
|
||||
mask="99:99"
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -6,7 +6,7 @@ import { Grid, GridSizeEnum } from '@procyon/components/Grid';
|
|||
import { GridCol } from '@procyon/components/GridCol';
|
||||
import TrashIcon from '@procyon/components/Icons/Trash';
|
||||
import { useModal } from '@procyon/components/Modal/hooks';
|
||||
import { StatusEnum } from '@procyon/types/common';
|
||||
import { SizeEnum, StatusEnum } from '@procyon/types/common';
|
||||
import { Option } from '@procyon/types/options';
|
||||
|
||||
import TimeList from './TimeList';
|
||||
|
@ -99,10 +99,16 @@ export const TimePickerModal: React.FC<TimePickerModalProps> = (props) => {
|
|||
</Grid>
|
||||
<Grid cols={{ [base]: 2 }} className="mt-4">
|
||||
<GridCol>
|
||||
<Button label="Použít" status={StatusEnum.success} onClick={handleChangeValue} />
|
||||
<Button size={SizeEnum.sm} label="Použít" status={StatusEnum.success} onClick={handleChangeValue} />
|
||||
</GridCol>
|
||||
<GridCol>
|
||||
<Button label={<TrashIcon fontSize={20} />} status={StatusEnum.error} blank onClick={handleClearValue} />
|
||||
<Button
|
||||
label={<TrashIcon fontSize={20} />}
|
||||
size={SizeEnum.sm}
|
||||
status={StatusEnum.error}
|
||||
blank
|
||||
onClick={handleClearValue}
|
||||
/>
|
||||
</GridCol>
|
||||
</Grid>
|
||||
</>
|
||||
|
|
|
@ -48,7 +48,6 @@ export const SelectBoxField: FC<SelectBoxFieldProps> = (props) => {
|
|||
name={field.name}
|
||||
value={field.value}
|
||||
onChange={handleChange}
|
||||
onBlur={field.onBlur}
|
||||
{...(error ? { status: StatusEnum.error } : {})}
|
||||
/>
|
||||
<div className="field-validationMessage">{error?.message}</div>
|
||||
|
|
|
@ -43,7 +43,7 @@ const field = (theme) => ({
|
|||
},
|
||||
'&-input': {
|
||||
backgroundColor: 'white',
|
||||
fontSize: '18px',
|
||||
fontSize: '16px',
|
||||
outline: 'none',
|
||||
cursor: 'text',
|
||||
width: 'calc(100% - 0.75rem)',
|
||||
|
@ -57,7 +57,7 @@ const field = (theme) => ({
|
|||
},
|
||||
'.checkbox-container, .radiobutton-container': {
|
||||
'.field-checkbox, .field-radio': {
|
||||
fontSize: '18px',
|
||||
fontSize: '16px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
cursor: 'pointer',
|
||||
|
|
|
@ -10,6 +10,7 @@ export type InputElementType<Value> = {
|
|||
onChange?: (value: Value | undefined, e: React.MouseEvent | React.ChangeEvent | null) => void;
|
||||
onClick?: (value: Value, e: React.MouseEvent) => void;
|
||||
onFocus?: (value: Value, e: React.FocusEvent) => void;
|
||||
placeholder?: string;
|
||||
status?: StatusEnum;
|
||||
value?: Value;
|
||||
};
|
||||
|
|
|
@ -12,7 +12,7 @@ import hookCode from './helpers/hook?raw';
|
|||
|
||||
`@procyon/auth` module for authenticated.
|
||||
|
||||
For work with IdP (Identity Provider) server use `useLogin` and `useAuthCode` hooks.
|
||||
For work with IdP (Identity Provider) server use `useLogin` and `useFetchTokens` hooks.
|
||||
|
||||
<Unstyled>
|
||||
<Message status={StatusEnum.info}>
|
||||
|
|
|
@ -2,7 +2,7 @@ import { Meta } from '@storybook/blocks';
|
|||
|
||||
<Meta title="Auth/Redux" />
|
||||
|
||||
# Redux slice
|
||||
# Redux
|
||||
|
||||
## Actions
|
||||
|
||||
|
@ -10,13 +10,7 @@ import { Meta } from '@storybook/blocks';
|
|||
|
||||
`import { setAuthAttribute } from @procyon/auth/slice`
|
||||
|
||||
Update all avaible stored data in `auth` reducer.
|
||||
|
||||
### `setAuthTokens`
|
||||
|
||||
`import { setAuthTokens } from @procyon/auth/slice`
|
||||
|
||||
Set new tokens from IdP. Action will automaticaly calculate datetime, when tokens will be revoked.
|
||||
Update all available stored data in `auth` reducer.
|
||||
|
||||
### `updateAuthAttribute`
|
||||
|
||||
|
@ -30,6 +24,12 @@ Update specific value in `auth` reducer.
|
|||
|
||||
Remove all data from reducer = revoke session.
|
||||
|
||||
### `setAuthTokens`
|
||||
|
||||
`import { setAuthTokens } from @procyon/auth/slice`
|
||||
|
||||
Set new tokens from IdP. Action will automatically calculate datetime, when tokens will be revoked.
|
||||
|
||||
## Selectors
|
||||
|
||||
### getAuthAttribute
|
||||
|
@ -37,3 +37,9 @@ Remove all data from reducer = revoke session.
|
|||
`import { getAuthAttribute } from @procyon/auth/slice`
|
||||
|
||||
Return stored value for specific key under `auth` reducer.
|
||||
|
||||
## Hooks
|
||||
|
||||
### useAuthAttributes
|
||||
|
||||
Insted of `getAuthAttribute` you can use `useAuthAttributes` hook for obtain all stored attributes.
|
|
@ -1,7 +1,7 @@
|
|||
import React, { FC } from 'react';
|
||||
import { useLocation } from 'wouter';
|
||||
|
||||
import { useAuthCode } from '@procyon/auth/hook/useAuthCode';
|
||||
import { useFetchTokens } from '@procyon/auth/hook/useFetchTokens';
|
||||
import { useLogin } from '@procyon/auth/hook/useLogin';
|
||||
|
||||
const authConfig = {
|
||||
|
@ -17,13 +17,13 @@ export const Component: FC = () => {
|
|||
const [location] = useLocation();
|
||||
|
||||
const doLogin = useLogin(authConfig);
|
||||
const changeCodeForTokens = useAuthCode(authConfig);
|
||||
const obtainTokens = useFetchTokens(authConfig);
|
||||
|
||||
if (location === '/login/callback') {
|
||||
const params = new URLSearchParams(window.location.href);
|
||||
const code = params.get('code') ?? null;
|
||||
if (code) {
|
||||
changeCodeForTokens(code);
|
||||
obtainTokens(code);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue