nurseitaly-components 0.0.13 → 0.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,14 @@
1
+ import { FieldValues, UseFormReturn } from 'react-hook-form';
2
+ import type { SelectItem } from '../SelectField/SelectField';
3
+ import '../CheckboxField/style.scss';
4
+ import './style.scss';
5
+ type CheckboxGroupFieldProps<TFieldValues extends FieldValues = FieldValues, TContext = any, TTransformedValues = TFieldValues> = {
6
+ attr: string;
7
+ createdForm: UseFormReturn<TFieldValues, TContext, TTransformedValues>;
8
+ options: SelectItem[];
9
+ disabled?: boolean;
10
+ className?: string;
11
+ onChange?: (attr: string, value: Array<string | number>) => void;
12
+ };
13
+ export default function CheckboxGroupField<TFieldValues extends FieldValues = FieldValues, TContext = any, TTransformedValues = TFieldValues>({ attr, createdForm, options, disabled, className, onChange, }: CheckboxGroupFieldProps<TFieldValues, TContext, TTransformedValues>): import("react").JSX.Element;
14
+ export {};
@@ -0,0 +1,29 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Checkbox, FormControlLabel } from '@mui/material';
3
+ import cx from 'classnames';
4
+ import { Controller, } from 'react-hook-form';
5
+ import '../CheckboxField/style.scss';
6
+ import './style.scss';
7
+ function toValueList(value) {
8
+ if (!Array.isArray(value)) {
9
+ return [];
10
+ }
11
+ return value;
12
+ }
13
+ export default function CheckboxGroupField({ attr, createdForm, options = [], disabled = false, className, onChange, }) {
14
+ const fieldName = attr;
15
+ const { control } = createdForm;
16
+ return (_jsx(Controller, { name: fieldName, control: control, render: ({ field }) => {
17
+ const selected = toValueList(field.value);
18
+ const toggle = (optionValue, checked) => {
19
+ const next = checked
20
+ ? selected.includes(optionValue)
21
+ ? selected
22
+ : [...selected, optionValue]
23
+ : selected.filter((v) => v !== optionValue);
24
+ field.onChange(next);
25
+ onChange?.(attr, next);
26
+ };
27
+ return (_jsx("div", { className: cx('ds-checkbox-group', className), children: options.map((option) => (_jsx(FormControlLabel, { className: "ds-checkbox", disabled: disabled, control: _jsx(Checkbox, { checked: selected.includes(option.value), onChange: (e) => toggle(option.value, e.target.checked), onBlur: field.onBlur, inputRef: field.ref }), label: option.label }, String(option.value)))) }));
28
+ } }));
29
+ }
@@ -0,0 +1,2 @@
1
+ import CheckboxGroupField from './CheckboxGroupField';
2
+ export default CheckboxGroupField;
@@ -0,0 +1,2 @@
1
+ import CheckboxGroupField from './CheckboxGroupField';
2
+ export default CheckboxGroupField;
@@ -0,0 +1,5 @@
1
+ .ds-checkbox-group {
2
+ display: flex;
3
+ flex-direction: column;
4
+ gap: 8px;
5
+ }
@@ -3,6 +3,7 @@ export { default as Badge } from './Badge';
3
3
  export { default as Button } from './Button';
4
4
  export type { ButtonDSColors, ButtonDSModes, ButtonDSPositions, ButtonDSSizes, } from './Button/Button';
5
5
  export { default as CheckboxField } from './CheckboxField';
6
+ export { default as CheckboxGroupField } from './CheckboxGroupField';
6
7
  export { default as DatePickerField } from './DatePickerField';
7
8
  export { default as DropdownButton } from './DropdownButton';
8
9
  export { default as DropdownList } from './DropdownList';
@@ -4,6 +4,7 @@ export { default as Avatar } from './Avatar';
4
4
  export { default as Badge } from './Badge';
5
5
  export { default as Button } from './Button';
6
6
  export { default as CheckboxField } from './CheckboxField';
7
+ export { default as CheckboxGroupField } from './CheckboxGroupField';
7
8
  export { default as DatePickerField } from './DatePickerField';
8
9
  export { default as DropdownButton } from './DropdownButton';
9
10
  export { default as DropdownList } from './DropdownList';
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { AsyncSelectField, CheckboxField, DatePickerField, SelectField, SelectMultipleField, SwitchField, TextField, } from "../../basic";
2
+ import { AsyncSelectField, CheckboxField, CheckboxGroupField, DatePickerField, SelectField, SelectMultipleField, SwitchField, TextField, } from "../../basic";
3
3
  import FormColorField from "./FormColorField";
4
4
  import { getFieldFlexStyle, groupFieldsIntoRows } from "./groupFieldsIntoRows";
5
5
  import "./style.scss";
@@ -47,6 +47,10 @@ export default function AppForm({ fields, form, prefix, onChangeFunctions = {},
47
47
  return (_jsx(SelectField, { ...selectProps, allowEmpty: field.allowEmpty }, name));
48
48
  }
49
49
  if (field.type === "check") {
50
+ if (field.multiple) {
51
+ const checkOptions = getOptions(field.attr) || field.options || [];
52
+ return (_jsx(CheckboxGroupField, { attr: name, createdForm: form, options: checkOptions, disabled: field.disabled, onChange: (_attr, value) => handleChange?.(value) }, name));
53
+ }
50
54
  return (_jsx(CheckboxField, { attr: name, label: field.name, createdForm: form, disabled: field.disabled }, name));
51
55
  }
52
56
  if (field.type === "switch") {
@@ -0,0 +1,15 @@
1
+ import type { AxiosError } from 'axios';
2
+ export type ApiErrorHandled = AxiosError & {
3
+ apiErrorHandled?: boolean;
4
+ /** @deprecated use apiErrorHandled */
5
+ authErrorHandled?: boolean;
6
+ };
7
+ export declare function isServerError(status: number | undefined): boolean;
8
+ export declare function markApiErrorHandled(error: AxiosError): void;
9
+ export declare function isHandledApiError(reason: unknown): boolean;
10
+ /** @deprecated use markApiErrorHandled */
11
+ export declare const markAuthErrorHandled: typeof markApiErrorHandled;
12
+ /** @deprecated use isHandledApiError */
13
+ export declare const isHandledAuthError: typeof isHandledApiError;
14
+ /** @deprecated use ApiErrorHandled */
15
+ export type AuthErrorHandled = ApiErrorHandled;
@@ -0,0 +1,21 @@
1
+ export function isServerError(status) {
2
+ return status !== undefined && status >= 500 && status < 600;
3
+ }
4
+ export function markApiErrorHandled(error) {
5
+ error.apiErrorHandled = true;
6
+ }
7
+ export function isHandledApiError(reason) {
8
+ if (!reason || typeof reason !== 'object')
9
+ return false;
10
+ const error = reason;
11
+ if (error.apiErrorHandled || error.authErrorHandled)
12
+ return true;
13
+ const status = error.response?.status;
14
+ if (!error.config || status === undefined)
15
+ return false;
16
+ return isServerError(status);
17
+ }
18
+ /** @deprecated use markApiErrorHandled */
19
+ export const markAuthErrorHandled = markApiErrorHandled;
20
+ /** @deprecated use isHandledApiError */
21
+ export const isHandledAuthError = isHandledApiError;
@@ -0,0 +1,13 @@
1
+ import type { AxiosInstance } from 'axios';
2
+ export type AuthErrorHandling = 'toast' | 'redirect' | 'none';
3
+ export type ApplyAuthErrorHandlingOptions = {
4
+ authErrorHandling?: AuthErrorHandling;
5
+ authStatuses?: Array<401 | 403>;
6
+ redirect?: {
7
+ on401?: string;
8
+ on403?: string;
9
+ };
10
+ onBeforeRedirect?: (status: 401 | 403) => void;
11
+ skipAuthHandlingInStorybook?: boolean;
12
+ };
13
+ export declare function applyAuthErrorHandling(api: AxiosInstance, options: ApplyAuthErrorHandlingOptions): AxiosInstance;
@@ -0,0 +1,70 @@
1
+ import { markApiErrorHandled } from './apiHandledError';
2
+ import CookieStorage from '../CookieStorage';
3
+ import { messageAction, loggedAction } from '../sessionTypes';
4
+ import { getCommonDispatch } from '../commonDispatch';
5
+ import { getErrorMessageValue } from '../useMessageUtils';
6
+ import i18n from 'i18next';
7
+ function isStorybook() {
8
+ return (typeof window !== 'undefined' &&
9
+ (window.location.port === '6006' ||
10
+ Boolean(window.__STORYBOOK__)));
11
+ }
12
+ function defaultRedirectUrls() {
13
+ const publicUrl = import.meta.env.VITE_APP_PUBLIC_URL;
14
+ return {
15
+ on401: import.meta.env.VITE_APP_AUTH_URL,
16
+ on403: import.meta.env.VITE_APP_UNAUTHORIZED_URL ??
17
+ (publicUrl ? `${publicUrl}/unauthorized` : undefined),
18
+ };
19
+ }
20
+ function clearAuthStorage() {
21
+ CookieStorage.removeJwtToken();
22
+ sessionStorage.clear();
23
+ localStorage.clear();
24
+ }
25
+ function handleToastAuthError(status) {
26
+ if (status === 401) {
27
+ clearAuthStorage();
28
+ getCommonDispatch()?.(loggedAction(undefined));
29
+ }
30
+ const value = getErrorMessageValue({
31
+ err: { response: { status } },
32
+ t: i18n.t.bind(i18n),
33
+ });
34
+ getCommonDispatch()?.(messageAction({ value, type: 'error' }));
35
+ }
36
+ function handleRedirectAuthError(status, redirect, onBeforeRedirect, skipAuthHandlingInStorybook = true) {
37
+ if (skipAuthHandlingInStorybook && isStorybook())
38
+ return;
39
+ onBeforeRedirect?.(status);
40
+ if (status === 401) {
41
+ clearAuthStorage();
42
+ if (redirect.on401)
43
+ window.location.replace(redirect.on401);
44
+ return;
45
+ }
46
+ if (redirect.on403)
47
+ window.location.href = redirect.on403;
48
+ }
49
+ export function applyAuthErrorHandling(api, options) {
50
+ const { authErrorHandling = 'none', authStatuses = [401, 403], redirect: redirectOverrides, onBeforeRedirect, skipAuthHandlingInStorybook = true, } = options;
51
+ if (authErrorHandling === 'none')
52
+ return api;
53
+ const redirect = { ...defaultRedirectUrls(), ...redirectOverrides };
54
+ api.interceptors.response.use((response) => response, async (error) => {
55
+ const status = error.response?.status;
56
+ if (status === 401 || status === 403) {
57
+ if (!authStatuses.includes(status))
58
+ return Promise.reject(error);
59
+ if (authErrorHandling === 'toast') {
60
+ handleToastAuthError(status);
61
+ }
62
+ else if (authErrorHandling === 'redirect') {
63
+ handleRedirectAuthError(status, redirect, onBeforeRedirect, skipAuthHandlingInStorybook);
64
+ }
65
+ markApiErrorHandled(error);
66
+ }
67
+ return Promise.reject(error);
68
+ });
69
+ return api;
70
+ }
@@ -0,0 +1,9 @@
1
+ import { AxiosInstance, InternalAxiosRequestConfig } from 'axios';
2
+ export type ServerErrorHandling = 'toast' | 'none';
3
+ export type CreateApiClientOptions = {
4
+ baseURL: string;
5
+ attachJwt?: boolean;
6
+ serverErrorHandling?: ServerErrorHandling;
7
+ augmentRequest?: (config: InternalAxiosRequestConfig) => InternalAxiosRequestConfig;
8
+ };
9
+ export declare function createApiClient(options: CreateApiClientOptions): AxiosInstance;
@@ -0,0 +1,51 @@
1
+ import axios from 'axios';
2
+ import CookieStorage from '../CookieStorage';
3
+ import { dispatchServerApiError } from './dispatchApiError';
4
+ import { isServerError, markApiErrorHandled } from './apiHandledError';
5
+ const DEFAULT_HEADERS = {
6
+ 'Cache-Control': 'no-cache, no-store, must-revalidate',
7
+ Pragma: 'no-cache',
8
+ 'Content-Type': 'application/json',
9
+ Accept: 'application/json',
10
+ };
11
+ function toHandledServerErrorResponse(error) {
12
+ return {
13
+ data: null,
14
+ status: error.response?.status ?? 500,
15
+ statusText: error.response?.statusText ?? 'Internal Server Error',
16
+ headers: error.response?.headers ?? {},
17
+ config: error.config,
18
+ };
19
+ }
20
+ export function createApiClient(options) {
21
+ const { baseURL, attachJwt = true, serverErrorHandling = 'toast', augmentRequest, } = options;
22
+ const api = axios.create({
23
+ headers: DEFAULT_HEADERS,
24
+ baseURL,
25
+ });
26
+ api.interceptors.response.use((response) => response, async (error) => {
27
+ const status = error.response?.status;
28
+ if (isServerError(status) && serverErrorHandling === 'toast') {
29
+ dispatchServerApiError({ err: error });
30
+ markApiErrorHandled(error);
31
+ return toHandledServerErrorResponse(error);
32
+ }
33
+ if (error.status === null) {
34
+ console.log(JSON.stringify(error));
35
+ }
36
+ return Promise.reject(error);
37
+ });
38
+ api.interceptors.request.use((config) => {
39
+ if (!config?.headers) {
40
+ throw new Error('no header available');
41
+ }
42
+ if (attachJwt) {
43
+ const token = CookieStorage.getJwtToken();
44
+ if (token) {
45
+ config.headers.Authorization = `Bearer ${token}`;
46
+ }
47
+ }
48
+ return augmentRequest ? augmentRequest(config) : config;
49
+ });
50
+ return api;
51
+ }
@@ -0,0 +1,10 @@
1
+ import type { TFunction } from 'i18next';
2
+ export declare function dispatchApiError({ err, t, key, }: {
3
+ err: unknown;
4
+ t?: TFunction;
5
+ key?: string;
6
+ }): void;
7
+ export declare function dispatchServerApiError({ err, t, }: {
8
+ err: unknown;
9
+ t?: TFunction;
10
+ }): void;
@@ -0,0 +1,16 @@
1
+ import i18n from 'i18next';
2
+ import { getErrorMessageValue } from '../useMessageUtils';
3
+ import { messageAction } from '../sessionTypes';
4
+ import { getCommonDispatch } from '../commonDispatch';
5
+ export function dispatchApiError({ err, t, key, }) {
6
+ const translate = t ?? i18n.t.bind(i18n);
7
+ const value = getErrorMessageValue({ err, t: translate, key });
8
+ getCommonDispatch()?.(messageAction({ value, type: 'error' }));
9
+ }
10
+ export function dispatchServerApiError({ err, t, }) {
11
+ dispatchApiError({
12
+ err,
13
+ t,
14
+ key: 'common',
15
+ });
16
+ }
@@ -0,0 +1,16 @@
1
+ export declare const platformApi: {
2
+ base: string;
3
+ revision: string;
4
+ catalog: string;
5
+ editor: string;
6
+ };
7
+ export declare const parserApiBase: string;
8
+ declare const api: import("axios").AxiosInstance;
9
+ export { createApiClient } from './createApiClient';
10
+ export type { CreateApiClientOptions, ServerErrorHandling, } from './createApiClient';
11
+ export { applyAuthErrorHandling } from './applyAuthErrorHandling';
12
+ export type { ApplyAuthErrorHandlingOptions, AuthErrorHandling, } from './applyAuthErrorHandling';
13
+ export { isHandledApiError, isHandledAuthError, markApiErrorHandled, markAuthErrorHandled, } from './apiHandledError';
14
+ export type { ApiErrorHandled, AuthErrorHandled } from './apiHandledError';
15
+ export { dispatchApiError, dispatchServerApiError } from './dispatchApiError';
16
+ export default api;
@@ -0,0 +1,16 @@
1
+ import { applyAuthErrorHandling } from './applyAuthErrorHandling';
2
+ import { createApiClient } from './createApiClient';
3
+ const platformApiBase = import.meta.env.VITE_APP_PLATFORM_API;
4
+ export const platformApi = {
5
+ base: platformApiBase,
6
+ revision: `${platformApiBase}/revision`,
7
+ catalog: `${platformApiBase}/catalog`,
8
+ editor: `${platformApiBase}/editor`,
9
+ };
10
+ export const parserApiBase = import.meta.env.VITE_APP_PARSER_API;
11
+ const api = applyAuthErrorHandling(createApiClient({ baseURL: platformApiBase }), { authErrorHandling: 'redirect' });
12
+ export { createApiClient } from './createApiClient';
13
+ export { applyAuthErrorHandling } from './applyAuthErrorHandling';
14
+ export { isHandledApiError, isHandledAuthError, markApiErrorHandled, markAuthErrorHandled, } from './apiHandledError';
15
+ export { dispatchApiError, dispatchServerApiError } from './dispatchApiError';
16
+ export default api;
@@ -1,10 +1,2 @@
1
- /** Platform API roots (formerly separate env vars per service). */
2
- export declare const platformApi: {
3
- base: string;
4
- revision: string;
5
- catalog: string;
6
- editor: string;
7
- };
8
- export declare const parserApiBase: string;
9
- declare const api: import("axios").AxiosInstance;
10
- export default api;
1
+ export * from './api/index';
2
+ export { default } from './api/index';
@@ -1,52 +1,2 @@
1
- import axios from 'axios';
2
- import CookieStorage from './CookieStorage';
3
- const platformApiBase = import.meta.env.VITE_APP_PLATFORM_API;
4
- /** Platform API roots (formerly separate env vars per service). */
5
- export const platformApi = {
6
- base: platformApiBase,
7
- revision: `${platformApiBase}/revision`,
8
- catalog: `${platformApiBase}/catalog`,
9
- editor: `${platformApiBase}/editor`,
10
- };
11
- export const parserApiBase = import.meta.env.VITE_APP_PARSER_API;
12
- const api = axios.create({
13
- headers: {
14
- 'Cache-Control': 'no-cache, no-store, must-revalidate',
15
- Pragma: 'no-cache',
16
- 'Content-Type': 'application/json',
17
- Accept: 'application/json',
18
- },
19
- baseURL: platformApiBase,
20
- });
21
- const isStorybook = () => typeof window !== 'undefined' &&
22
- (window.location.port === '6006' ||
23
- window.__STORYBOOK__);
24
- api.interceptors.response.use((response) => response, async (error) => {
25
- if (error.response?.status === 401) {
26
- CookieStorage.removeJwtToken();
27
- sessionStorage.clear();
28
- localStorage.clear();
29
- if (!isStorybook()) {
30
- window.location.replace(import.meta.env.VITE_APP_AUTH_URL);
31
- }
32
- }
33
- else if (error.response?.status === 403 && !isStorybook()) {
34
- window.location.href = import.meta.env.VITE_APP_UNAUTHORIZED_URL;
35
- }
36
- else if (error.status === null) {
37
- console.log(JSON.stringify(error));
38
- }
39
- return Promise.reject(error);
40
- });
41
- api.interceptors.request.use((config) => {
42
- if (!config?.headers) {
43
- throw new Error('no header available');
44
- }
45
- const token = CookieStorage.getJwtToken();
46
- if (!token)
47
- return config;
48
- // eslint-disable-next-line no-param-reassign
49
- config.headers.Authorization = `Bearer ${token}`;
50
- return config;
51
- });
52
- export default api;
1
+ export * from './api/index';
2
+ export { default } from './api/index';
@@ -1,5 +1,6 @@
1
1
  export { default as CommonContext, CommonProvider } from './CommonContext';
2
2
  export { default as CommonDispatchBridge } from './CommonDispatchBridge';
3
+ export * from './api/index';
3
4
  export { getCommonDispatch, registerCommonDispatch, } from './commonDispatch';
4
5
  export { default as CookieStorage } from './CookieStorage';
5
6
  export { commonLocalization, commonResources, featureResources, mergeResources, } from './Localization';
@@ -1,5 +1,6 @@
1
1
  export { default as CommonContext, CommonProvider } from './CommonContext';
2
2
  export { default as CommonDispatchBridge } from './CommonDispatchBridge';
3
+ export * from './api/index';
3
4
  export { getCommonDispatch, registerCommonDispatch, } from './commonDispatch';
4
5
  export { default as CookieStorage } from './CookieStorage';
5
6
  export { commonLocalization, commonResources, featureResources, mergeResources, } from './Localization';
@@ -79,11 +79,9 @@ body {
79
79
  display: flex !important;
80
80
  }
81
81
 
82
- .tablet-only {
83
- display: none !important;
84
- }
85
-
86
- .mobile-only {
82
+ .tablet-only,
83
+ .mobile-only,
84
+ .desktop-never {
87
85
  display: none !important;
88
86
  }
89
87
 
@@ -94,7 +92,8 @@ body {
94
92
  display: none !important;
95
93
  }
96
94
 
97
- .tablet-only {
95
+ .tablet-only,
96
+ .desktop-never {
98
97
  display: flex !important;
99
98
  }
100
99
  }
@@ -106,7 +105,8 @@ body {
106
105
  display: none !important;
107
106
  }
108
107
 
109
- .mobile-only {
108
+ .mobile-only,
109
+ .desktop-never {
110
110
  display: flex !important;
111
111
  }
112
112
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nurseitaly-components",
3
3
  "private": false,
4
- "version": "0.0.13",
4
+ "version": "0.0.15",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "exports": {
@@ -1,9 +0,0 @@
1
- import './styles.scss';
2
- export declare const DummyModes: readonly ["white", "blue"];
3
- type DummyModes = (typeof DummyModes)[number];
4
- export type Props = {
5
- className?: string;
6
- mode?: DummyModes;
7
- };
8
- export default function Dummy({ className, mode }: Props): import("react").JSX.Element;
9
- export {};
@@ -1,8 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import cx from 'classnames';
3
- import './styles.scss';
4
- export const DummyModes = ['white', 'blue'];
5
- export default function Dummy({ className, mode = 'blue' }) {
6
- const getClassNames = cx('ds-dummy', className, mode);
7
- return _jsx("div", { className: getClassNames, children: "aaaa" });
8
- }
@@ -1,2 +0,0 @@
1
- import Dummy from './Dummy';
2
- export default Dummy;
@@ -1,2 +0,0 @@
1
- import Dummy from './Dummy';
2
- export default Dummy;
@@ -1,4 +0,0 @@
1
- .ds-dummy {
2
- display: flex;
3
- align-items: center;
4
- }