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 { isJSON } from '@procyon/utils';
|
||||||
|
|
||||||
import { FetchTokensParams } from './types';
|
import { UseFetchTokensParams } from './types';
|
||||||
|
|
||||||
export const fetchTokens = async ({
|
export const fetchTokens = async ({
|
||||||
baseUrl,
|
baseUrl,
|
||||||
|
@ -9,7 +9,7 @@ export const fetchTokens = async ({
|
||||||
code,
|
code,
|
||||||
grantType,
|
grantType,
|
||||||
redirectUri,
|
redirectUri,
|
||||||
}: FetchTokensParams) => {
|
}: UseFetchTokensParams) => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${baseUrl}${tokenEndpoint}`, {
|
const response = await fetch(`${baseUrl}${tokenEndpoint}`, {
|
||||||
method: 'post',
|
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 { setAuthTokens } from '@procyon/auth/slice';
|
||||||
|
|
||||||
import { fetchTokens } from '../actions';
|
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 dispatch = useDispatch<any>();
|
||||||
|
|
||||||
const [, setLocation] = useLocation();
|
const [, setLocation] = useLocation();
|
|
@ -1,6 +1,6 @@
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
import { UseAuthParams } from '../types';
|
import { UseLoginParams } from '../types';
|
||||||
|
|
||||||
const generateState = () =>
|
const generateState = () =>
|
||||||
'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
||||||
|
@ -9,7 +9,7 @@ const generateState = () =>
|
||||||
return v.toString(16);
|
return v.toString(16);
|
||||||
});
|
});
|
||||||
|
|
||||||
export const useLogin = ({ baseUrl, clientId, authEndpoint, redirectUri }: UseAuthParams) => {
|
export const useLogin = ({ baseUrl, clientId, authEndpoint, redirectUri }: UseLoginParams) => {
|
||||||
return useCallback(() => {
|
return useCallback(() => {
|
||||||
const state = generateState();
|
const state = generateState();
|
||||||
const urlParams: Record<string, string> = {
|
const urlParams: Record<string, string> = {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
||||||
import { addSeconds } from 'date-fns';
|
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 = {
|
const initialState: AuthAttributes = {
|
||||||
authenticated: undefined,
|
authenticated: undefined,
|
||||||
|
@ -19,7 +19,7 @@ const authSlice = createSlice({
|
||||||
name: AUTH_REDUCER_NAME,
|
name: AUTH_REDUCER_NAME,
|
||||||
initialState,
|
initialState,
|
||||||
reducers: {
|
reducers: {
|
||||||
setAuthTokens: (_, action: PayloadAction<AuthTokenPayload>) => {
|
setAuthTokens: (_, action: PayloadAction<AuthTokens>) => {
|
||||||
const { accessExpiresIn, refreshExpiresIn } = action.payload;
|
const { accessExpiresIn, refreshExpiresIn } = action.payload;
|
||||||
return {
|
return {
|
||||||
...action.payload,
|
...action.payload,
|
||||||
|
@ -34,7 +34,7 @@ const authSlice = createSlice({
|
||||||
...action.payload,
|
...action.payload,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
updateAuthAttribute: (state, action: PayloadAction<ModifyAuthAttribute>) => {
|
updateAuthAttribute: (state, action: PayloadAction<ModifyAuthAttributePayload>) => {
|
||||||
state[action.payload.key] = action.payload.value;
|
state[action.payload.key] = action.payload.value;
|
||||||
},
|
},
|
||||||
deleteAuthAttributes: () => {
|
deleteAuthAttributes: () => {
|
||||||
|
@ -50,9 +50,10 @@ export const setAuthAttribute = authSlice.actions.setAuthAttribute as <T>(
|
||||||
) => PayloadAction<AuthAttributes<T>>;
|
) => PayloadAction<AuthAttributes<T>>;
|
||||||
|
|
||||||
export const updateAuthAttribute = authSlice.actions.updateAuthAttribute as <T>(
|
export const updateAuthAttribute = authSlice.actions.updateAuthAttribute as <T>(
|
||||||
attrs: ModifyAuthAttribute<T>
|
attrs: ModifyAuthAttributePayload<T>
|
||||||
) => PayloadAction<ModifyAuthAttribute<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;
|
export default authSlice.reducer;
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { ROOT_REDUCER_NAME } from '@procyon/constants/redux';
|
||||||
|
|
||||||
export const AUTH_REDUCER_NAME = 'auth';
|
export const AUTH_REDUCER_NAME = 'auth';
|
||||||
|
|
||||||
export type AuthTokenPayload = {
|
export type AuthTokens = {
|
||||||
accessExpiresIn?: number;
|
accessExpiresIn?: number;
|
||||||
accessToken?: string;
|
accessToken?: string;
|
||||||
idToken?: string;
|
idToken?: string;
|
||||||
|
@ -11,14 +11,14 @@ export type AuthTokenPayload = {
|
||||||
sessionState?: string;
|
sessionState?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type AuthAttributes<CustomAttributes = unknown> = {
|
export type AuthAttributes<C = unknown> = {
|
||||||
accessExpiresTime?: string;
|
accessExpiresTime?: string;
|
||||||
authenticated?: boolean;
|
authenticated?: boolean;
|
||||||
refreshExpiresTime?: string;
|
refreshExpiresTime?: string;
|
||||||
} & CustomAttributes &
|
} & C &
|
||||||
AuthTokenPayload;
|
AuthTokens;
|
||||||
|
|
||||||
export type ModifyAuthAttribute<P = unknown> = {
|
export type ModifyAuthAttributePayload<P = unknown> = {
|
||||||
key: keyof AuthAttributes<P>;
|
key: keyof AuthAttributes<P>;
|
||||||
value: any;
|
value: any;
|
||||||
};
|
};
|
||||||
|
@ -29,7 +29,7 @@ export type AuthRootState = {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export type UseAuthParams = {
|
export type UseLoginParams = {
|
||||||
authEndpoint: string;
|
authEndpoint: string;
|
||||||
baseUrl: string;
|
baseUrl: string;
|
||||||
clientId: string;
|
clientId: string;
|
||||||
|
@ -38,7 +38,7 @@ export type UseAuthParams = {
|
||||||
tokenEndpoint: string;
|
tokenEndpoint: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type FetchTokensParams = Pick<UseAuthParams, 'baseUrl' | 'tokenEndpoint' | 'clientId'> & {
|
export type UseFetchTokensParams = Pick<UseLoginParams, 'baseUrl' | 'tokenEndpoint' | 'clientId'> & {
|
||||||
code: string;
|
code: string;
|
||||||
grantType: 'authorization_code';
|
grantType: 'authorization_code';
|
||||||
redirectUri: string;
|
redirectUri: string;
|
||||||
|
|
|
@ -69,7 +69,8 @@ export const DatePicker: React.FC<DatePickerProps<Date>> = (props) => {
|
||||||
label={label}
|
label={label}
|
||||||
value={value ? formatFn(value, props.format ?? DefaultDateFormat) : undefined}
|
value={value ? formatFn(value, props.format ?? DefaultDateFormat) : undefined}
|
||||||
{...omit(['value', 'onClick'], others)}
|
{...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>) {
|
export function ClockTimeIcon(props: React.SVGProps<SVGSVGElement>) {
|
||||||
return (
|
return (
|
||||||
<svg viewBox="0 0 512 512" fill="currentColor" height="1em" width="1em" {...props}>
|
<svg viewBox="0 0 24 24" fill="currentColor" height="1em" width="1em" {...props}>
|
||||||
<path
|
<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" />
|
||||||
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>
|
</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
|
<div
|
||||||
key={option.code}
|
key={option.code}
|
||||||
id={`list-${name}_${i}`}
|
id={`list-${name}_${i}`}
|
||||||
className={clsx('list', className, {
|
className={clsx('list', {
|
||||||
'list-compact': compact,
|
'list-compact': compact,
|
||||||
'list--focus': index === i,
|
'list--focus': index === i,
|
||||||
'list--active': selectedItemCode === option.code,
|
'list--active': selectedItemCode === option.code,
|
||||||
|
@ -146,7 +146,7 @@ const List: React.FC<IProps> = ({
|
||||||
<TextField name="search" label="Hledat" onChange={handleSearch} autoFocus />
|
<TextField name="search" label="Hledat" onChange={handleSearch} autoFocus />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className={clsx('list-container')} onMouseLeave={setCurrentOption(-1)}>
|
<div className={clsx('list-container', className)} onMouseLeave={setCurrentOption(-1)}>
|
||||||
{items}
|
{items}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import React, { useCallback, useEffect, useState } from 'react';
|
import React, { useCallback, useEffect, useState } from 'react';
|
||||||
import { find, propEq, propOr } from 'ramda';
|
import { find, propEq, propOr } from 'ramda';
|
||||||
|
|
||||||
|
import { PointerIcon } from '@procyon/components/Icons/Pointer';
|
||||||
import { ModalId } from '@procyon/components/Modal/context';
|
import { ModalId } from '@procyon/components/Modal/context';
|
||||||
import { useModal } from '@procyon/components/Modal/hooks';
|
import { useModal } from '@procyon/components/Modal/hooks';
|
||||||
import { InputElementType } from '@procyon/types/form';
|
import { InputElementType } from '@procyon/types/form';
|
||||||
|
@ -14,12 +15,11 @@ export type SelectBoxProps<V = Option> = Omit<
|
||||||
autoComplete?: boolean;
|
autoComplete?: boolean;
|
||||||
options: Option[];
|
options: Option[];
|
||||||
} & InputElementType<V>,
|
} & InputElementType<V>,
|
||||||
'onFocus' | 'onClick'
|
'onFocus' | 'onClick' | 'onBlur'
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export const Selectbox: React.FC<SelectBoxProps> = (props) => {
|
export const Selectbox: React.FC<SelectBoxProps> = (props) => {
|
||||||
const { value, options, onBlur, onChange, name, label, autoComplete, ...others } =
|
const { value, options, onChange, name, label, autoComplete, ...others } = props;
|
||||||
props;
|
|
||||||
|
|
||||||
const { openModal, closeModal, registerModal } = useModal();
|
const { openModal, closeModal, registerModal } = useModal();
|
||||||
|
|
||||||
|
@ -32,10 +32,6 @@ export const Selectbox: React.FC<SelectBoxProps> = (props) => {
|
||||||
}
|
}
|
||||||
}, [value, options]);
|
}, [value, options]);
|
||||||
|
|
||||||
const handleBlur = (_: string, e: React.FocusEvent<HTMLInputElement>): void => {
|
|
||||||
onBlur?.(selectedOption ?? undefined, e);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleOptionClick = (option: Option): void => {
|
const handleOptionClick = (option: Option): void => {
|
||||||
setSelectedOption(option);
|
setSelectedOption(option);
|
||||||
onChange?.(option, null);
|
onChange?.(option, null);
|
||||||
|
@ -81,11 +77,9 @@ export const Selectbox: React.FC<SelectBoxProps> = (props) => {
|
||||||
{...others}
|
{...others}
|
||||||
name={name}
|
name={name}
|
||||||
label={label}
|
label={label}
|
||||||
onClick={handleOpenModal}
|
|
||||||
onFocus={handleOpenModal}
|
|
||||||
onBlur={handleBlur}
|
|
||||||
value={propOr('', 'name', selectedOption)}
|
value={propOr('', 'name', selectedOption)}
|
||||||
readonly
|
readonly
|
||||||
|
leftIcon={<PointerIcon className="cursor-pointer text-primary-200" onClick={handleOpenModal} />}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -29,6 +29,7 @@ export const TextField: React.FC<TextFieldProps> = (props) => {
|
||||||
status,
|
status,
|
||||||
autoFocus,
|
autoFocus,
|
||||||
mask,
|
mask,
|
||||||
|
placeholder,
|
||||||
multiline,
|
multiline,
|
||||||
leftIcon,
|
leftIcon,
|
||||||
rightIcon,
|
rightIcon,
|
||||||
|
@ -139,6 +140,7 @@ export const TextField: React.FC<TextFieldProps> = (props) => {
|
||||||
className={clsx(passProps.className, {
|
className={clsx(passProps.className, {
|
||||||
'field-input--nolabel': !label,
|
'field-input--nolabel': !label,
|
||||||
})}
|
})}
|
||||||
|
placeholder={placeholder}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
type={type}
|
type={type}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -42,6 +42,7 @@ const TimeList: React.FC<TimeListProps> = ({ title, onChange, min, max, step, se
|
||||||
selectedCode={selectedCode}
|
selectedCode={selectedCode}
|
||||||
scrollToCode={scrollToCode}
|
scrollToCode={scrollToCode}
|
||||||
enableAutoScroll
|
enableAutoScroll
|
||||||
|
className="h-60"
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
@ -46,7 +46,7 @@ export const TimePicker: FC<TimePickerProps<Date>> = (props) => {
|
||||||
registerModal({
|
registerModal({
|
||||||
id: name,
|
id: name,
|
||||||
title: label,
|
title: label,
|
||||||
style: { width: 250 },
|
style: { width: 200 },
|
||||||
Component: modalComponent,
|
Component: modalComponent,
|
||||||
});
|
});
|
||||||
openModal(name);
|
openModal(name);
|
||||||
|
@ -73,7 +73,9 @@ export const TimePicker: FC<TimePickerProps<Date>> = (props) => {
|
||||||
name={name}
|
name={name}
|
||||||
label={label}
|
label={label}
|
||||||
value={value ? format(value, 'HH:mm') : undefined}
|
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 { GridCol } from '@procyon/components/GridCol';
|
||||||
import TrashIcon from '@procyon/components/Icons/Trash';
|
import TrashIcon from '@procyon/components/Icons/Trash';
|
||||||
import { useModal } from '@procyon/components/Modal/hooks';
|
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 { Option } from '@procyon/types/options';
|
||||||
|
|
||||||
import TimeList from './TimeList';
|
import TimeList from './TimeList';
|
||||||
|
@ -99,10 +99,16 @@ export const TimePickerModal: React.FC<TimePickerModalProps> = (props) => {
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid cols={{ [base]: 2 }} className="mt-4">
|
<Grid cols={{ [base]: 2 }} className="mt-4">
|
||||||
<GridCol>
|
<GridCol>
|
||||||
<Button label="Použít" status={StatusEnum.success} onClick={handleChangeValue} />
|
<Button size={SizeEnum.sm} label="Použít" status={StatusEnum.success} onClick={handleChangeValue} />
|
||||||
</GridCol>
|
</GridCol>
|
||||||
<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>
|
</GridCol>
|
||||||
</Grid>
|
</Grid>
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -48,7 +48,6 @@ export const SelectBoxField: FC<SelectBoxFieldProps> = (props) => {
|
||||||
name={field.name}
|
name={field.name}
|
||||||
value={field.value}
|
value={field.value}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
onBlur={field.onBlur}
|
|
||||||
{...(error ? { status: StatusEnum.error } : {})}
|
{...(error ? { status: StatusEnum.error } : {})}
|
||||||
/>
|
/>
|
||||||
<div className="field-validationMessage">{error?.message}</div>
|
<div className="field-validationMessage">{error?.message}</div>
|
||||||
|
|
|
@ -43,7 +43,7 @@ const field = (theme) => ({
|
||||||
},
|
},
|
||||||
'&-input': {
|
'&-input': {
|
||||||
backgroundColor: 'white',
|
backgroundColor: 'white',
|
||||||
fontSize: '18px',
|
fontSize: '16px',
|
||||||
outline: 'none',
|
outline: 'none',
|
||||||
cursor: 'text',
|
cursor: 'text',
|
||||||
width: 'calc(100% - 0.75rem)',
|
width: 'calc(100% - 0.75rem)',
|
||||||
|
@ -57,7 +57,7 @@ const field = (theme) => ({
|
||||||
},
|
},
|
||||||
'.checkbox-container, .radiobutton-container': {
|
'.checkbox-container, .radiobutton-container': {
|
||||||
'.field-checkbox, .field-radio': {
|
'.field-checkbox, .field-radio': {
|
||||||
fontSize: '18px',
|
fontSize: '16px',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
|
|
|
@ -10,6 +10,7 @@ export type InputElementType<Value> = {
|
||||||
onChange?: (value: Value | undefined, e: React.MouseEvent | React.ChangeEvent | null) => void;
|
onChange?: (value: Value | undefined, e: React.MouseEvent | React.ChangeEvent | null) => void;
|
||||||
onClick?: (value: Value, e: React.MouseEvent) => void;
|
onClick?: (value: Value, e: React.MouseEvent) => void;
|
||||||
onFocus?: (value: Value, e: React.FocusEvent) => void;
|
onFocus?: (value: Value, e: React.FocusEvent) => void;
|
||||||
|
placeholder?: string;
|
||||||
status?: StatusEnum;
|
status?: StatusEnum;
|
||||||
value?: Value;
|
value?: Value;
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,7 +12,7 @@ import hookCode from './helpers/hook?raw';
|
||||||
|
|
||||||
`@procyon/auth` module for authenticated.
|
`@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>
|
<Unstyled>
|
||||||
<Message status={StatusEnum.info}>
|
<Message status={StatusEnum.info}>
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { Meta } from '@storybook/blocks';
|
||||||
|
|
||||||
<Meta title="Auth/Redux" />
|
<Meta title="Auth/Redux" />
|
||||||
|
|
||||||
# Redux slice
|
# Redux
|
||||||
|
|
||||||
## Actions
|
## Actions
|
||||||
|
|
||||||
|
@ -10,13 +10,7 @@ import { Meta } from '@storybook/blocks';
|
||||||
|
|
||||||
`import { setAuthAttribute } from @procyon/auth/slice`
|
`import { setAuthAttribute } from @procyon/auth/slice`
|
||||||
|
|
||||||
Update all avaible stored data in `auth` reducer.
|
Update all available 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.
|
|
||||||
|
|
||||||
### `updateAuthAttribute`
|
### `updateAuthAttribute`
|
||||||
|
|
||||||
|
@ -30,6 +24,12 @@ Update specific value in `auth` reducer.
|
||||||
|
|
||||||
Remove all data from reducer = revoke session.
|
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
|
## Selectors
|
||||||
|
|
||||||
### getAuthAttribute
|
### getAuthAttribute
|
||||||
|
@ -37,3 +37,9 @@ Remove all data from reducer = revoke session.
|
||||||
`import { getAuthAttribute } from @procyon/auth/slice`
|
`import { getAuthAttribute } from @procyon/auth/slice`
|
||||||
|
|
||||||
Return stored value for specific key under `auth` reducer.
|
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 React, { FC } from 'react';
|
||||||
import { useLocation } from 'wouter';
|
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';
|
import { useLogin } from '@procyon/auth/hook/useLogin';
|
||||||
|
|
||||||
const authConfig = {
|
const authConfig = {
|
||||||
|
@ -17,13 +17,13 @@ export const Component: FC = () => {
|
||||||
const [location] = useLocation();
|
const [location] = useLocation();
|
||||||
|
|
||||||
const doLogin = useLogin(authConfig);
|
const doLogin = useLogin(authConfig);
|
||||||
const changeCodeForTokens = useAuthCode(authConfig);
|
const obtainTokens = useFetchTokens(authConfig);
|
||||||
|
|
||||||
if (location === '/login/callback') {
|
if (location === '/login/callback') {
|
||||||
const params = new URLSearchParams(window.location.href);
|
const params = new URLSearchParams(window.location.href);
|
||||||
const code = params.get('code') ?? null;
|
const code = params.get('code') ?? null;
|
||||||
if (code) {
|
if (code) {
|
||||||
changeCodeForTokens(code);
|
obtainTokens(code);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue