@sqrzro/ui 4.0.0-alpha.8 → 4.0.0-alpha.80
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.
- package/dist/components/buttons/ActionButton/index.d.ts +8 -6
- package/dist/components/buttons/ActionButton/index.js +5 -29
- package/dist/components/buttons/Button/index.d.ts +7 -6
- package/dist/components/buttons/Button/index.js +9 -19
- package/dist/components/collections/Collection/index.d.ts +9 -5
- package/dist/components/collections/Collection/index.js +14 -12
- package/dist/components/collections/DataTable/index.d.ts +14 -0
- package/dist/components/collections/DataTable/index.js +14 -0
- package/dist/components/collections/DefinitionList/index.d.ts +13 -0
- package/dist/components/collections/DefinitionList/index.js +13 -0
- package/dist/components/collections/EmptyMessage/index.d.ts +2 -2
- package/dist/components/collections/EmptyMessage/index.js +6 -4
- package/dist/components/collections/EmptyMessageAction/index.d.ts +2 -2
- package/dist/components/collections/EmptyMessageAction/index.js +3 -3
- package/dist/components/collections/List/index.d.ts +6 -3
- package/dist/components/collections/List/index.js +2 -2
- package/dist/components/collections/ListClientComponent/index.d.ts +7 -4
- package/dist/components/collections/ListClientComponent/index.js +8 -5
- package/dist/components/collections/ListItem/index.d.ts +10 -3
- package/dist/components/collections/ListItem/index.js +15 -23
- package/dist/components/collections/ListItemMenu/index.d.ts +8 -0
- package/dist/components/collections/ListItemMenu/index.js +7 -0
- package/dist/components/collections/ListItemMeta/index.d.ts +6 -4
- package/dist/components/collections/ListItemMeta/index.js +13 -17
- package/dist/components/collections/ListItemSecondary/index.d.ts +5 -3
- package/dist/components/collections/ListItemSecondary/index.js +12 -8
- package/dist/components/collections/Pagination/index.d.ts +1 -1
- package/dist/components/collections/Pagination/index.js +7 -8
- package/dist/components/collections/PaginationLink/index.d.ts +9 -0
- package/dist/components/collections/PaginationLink/index.js +9 -0
- package/dist/components/collections/Table/index.d.ts +3 -4
- package/dist/components/collections/Table/index.js +2 -8
- package/dist/components/collections/TableClientComponent/index.d.ts +7 -6
- package/dist/components/collections/TableClientComponent/index.js +12 -27
- package/dist/components/collections/TableRow/index.d.ts +13 -0
- package/dist/components/collections/TableRow/index.js +15 -0
- package/dist/components/collections/interfaces.d.ts +41 -34
- package/dist/components/collections/lang.js +1 -1
- package/dist/components/collections/utility/is-paginated.d.ts +1 -1
- package/dist/components/collections/utility/is-right-aligned.d.ts +3 -0
- package/dist/components/collections/utility/is-right-aligned.js +11 -0
- package/dist/components/collections/utility/render-cell.d.ts +5 -0
- package/dist/components/collections/utility/render-cell.js +33 -0
- package/dist/components/elements/Badge/index.d.ts +12 -0
- package/dist/components/elements/Badge/index.js +9 -0
- package/dist/components/elements/ContentLink/index.d.ts +4 -0
- package/dist/components/elements/ContentLink/index.js +7 -0
- package/dist/components/elements/InfoPanel/index.d.ts +13 -0
- package/dist/components/elements/InfoPanel/index.js +20 -0
- package/dist/components/{utility → elements}/Link/index.d.ts +3 -2
- package/dist/components/{utility → elements}/Link/index.js +10 -9
- package/dist/components/elements/Menu/index.d.ts +19 -0
- package/dist/components/elements/Menu/index.js +20 -0
- package/dist/components/elements/MenuItem/index.d.ts +9 -0
- package/dist/components/elements/MenuItem/index.js +14 -0
- package/dist/components/elements/Page/index.d.ts +19 -0
- package/dist/components/elements/Page/index.js +18 -0
- package/dist/components/elements/Reference/index.d.ts +9 -0
- package/dist/components/elements/Reference/index.js +16 -0
- package/dist/components/elements/Summary/index.d.ts +13 -0
- package/dist/components/elements/Summary/index.js +22 -0
- package/dist/components/errors/AppError/index.d.ts +19 -0
- package/dist/components/errors/AppError/index.js +9 -0
- package/dist/components/errors/AppForbiddenError/index.d.ts +7 -0
- package/dist/components/errors/AppForbiddenError/index.js +6 -0
- package/dist/components/errors/AppNotFoundError/index.d.ts +7 -0
- package/dist/components/errors/AppNotFoundError/index.js +6 -0
- package/dist/components/errors/AppServerError/index.d.ts +8 -0
- package/dist/components/errors/AppServerError/index.js +17 -0
- package/dist/components/index.d.ts +35 -6
- package/dist/components/index.js +17 -3
- package/dist/components/modals/ConfirmModal/index.d.ts +6 -4
- package/dist/components/modals/ConfirmModal/index.js +4 -4
- package/dist/components/modals/Modal/index.d.ts +4 -4
- package/dist/components/modals/Modal/index.js +3 -3
- package/dist/components/modals/ModalActions/index.d.ts +3 -3
- package/dist/components/modals/ModalActions/index.js +5 -4
- package/dist/components/utility/Action/index.d.ts +11 -0
- package/dist/components/utility/Action/index.js +48 -0
- package/dist/components/utility/ActionList/index.d.ts +5 -5
- package/dist/components/utility/ActionList/index.js +6 -4
- package/dist/components/utility/AppBody/index.d.ts +5 -0
- package/dist/components/utility/AppBody/index.js +9 -0
- package/dist/components/utility/Calendar/index.d.ts +32 -0
- package/dist/components/utility/Calendar/index.js +66 -0
- package/dist/components/utility/CalendarDay/index.d.ts +11 -0
- package/dist/components/utility/CalendarDay/index.js +22 -0
- package/dist/components/utility/Confirmable/index.d.ts +9 -0
- package/dist/components/utility/Confirmable/index.js +14 -0
- package/dist/components/utility/Container/index.d.ts +1 -1
- package/dist/components/utility/Container/index.js +2 -2
- package/dist/components/utility/Loader/index.d.ts +1 -1
- package/dist/components/utility/Loader/index.js +5 -4
- package/dist/components/utility/Popover/index.d.ts +1 -1
- package/dist/components/utility/Popover/index.js +5 -5
- package/dist/components/utility/Toast/index.d.ts +3 -3
- package/dist/components/utility/Toast/index.js +6 -4
- package/dist/components/utility/Toaster/index.js +5 -5
- package/dist/filters/components/FilterBar/index.d.ts +6 -3
- package/dist/filters/components/FilterBarClientComponent/index.d.ts +3 -5
- package/dist/filters/components/FilterBarClientComponent/index.js +4 -44
- package/dist/filters/components/FilterClearButton/index.d.ts +7 -2
- package/dist/filters/components/FilterClearButton/index.js +8 -4
- package/dist/filters/components/FilterControl/index.d.ts +1 -1
- package/dist/filters/components/FilterControl/index.js +11 -4
- package/dist/filters/components/FilterItem/index.d.ts +3 -2
- package/dist/filters/components/FilterItem/index.js +4 -8
- package/dist/filters/components/FilterPanel/index.d.ts +2 -2
- package/dist/filters/{utility/filter.d.ts → filter.d.ts} +1 -1
- package/dist/filters/{utility/filter.js → filter.js} +8 -8
- package/dist/filters/filters/BooleanFilter/index.js +2 -2
- package/dist/filters/filters/CalendarFilter/index.js +3 -2
- package/dist/filters/filters/DateFilter/index.d.ts +1 -1
- package/dist/filters/filters/DateFilter/index.js +9 -4
- package/dist/filters/filters/DropdownFilter/index.js +2 -2
- package/dist/filters/filters/Filter/index.d.ts +6 -5
- package/dist/filters/filters/Filter/index.js +9 -9
- package/dist/filters/filters/SearchFilter/index.d.ts +8 -3
- package/dist/filters/filters/SearchFilter/index.js +10 -10
- package/dist/filters/filters/interfaces.d.ts +1 -3
- package/dist/filters/index.d.ts +2 -1
- package/dist/filters/index.js +2 -1
- package/dist/filters/interfaces.d.ts +3 -3
- package/dist/filters/utility/get-quick-dates.d.ts +1 -1
- package/dist/filters/utility/render-value.js +5 -5
- package/dist/forms/components/Autocomplete/index.d.ts +2 -2
- package/dist/forms/components/Autocomplete/index.js +5 -5
- package/dist/forms/components/AutocompleteList/index.d.ts +7 -0
- package/dist/forms/components/AutocompleteList/index.js +15 -0
- package/dist/forms/components/BaseCalendarInput/index.d.ts +11 -0
- package/dist/forms/components/BaseCalendarInput/index.js +22 -0
- package/dist/forms/components/CSVInput/index.d.ts +11 -0
- package/dist/forms/components/CSVInput/index.js +32 -0
- package/dist/forms/components/CalendarInput/index.d.ts +6 -0
- package/dist/forms/components/CalendarInput/index.js +14 -0
- package/dist/forms/components/CheckboxInput/index.d.ts +12 -0
- package/dist/forms/components/CheckboxInput/index.js +15 -0
- package/dist/forms/components/ChkRad/index.d.ts +19 -0
- package/dist/forms/components/ChkRad/index.js +25 -0
- package/dist/forms/components/ColorInput/index.d.ts +16 -0
- package/dist/forms/components/ColorInput/index.js +14 -0
- package/dist/forms/components/Dropdown/index.d.ts +1 -1
- package/dist/forms/components/Dropdown/index.js +11 -10
- package/dist/forms/components/DropdownItem/index.d.ts +9 -0
- package/dist/forms/components/DropdownItem/index.js +9 -0
- package/dist/forms/components/DropdownList/index.d.ts +2 -2
- package/dist/forms/components/DropdownList/index.js +7 -11
- package/dist/forms/components/EditableForm/index.d.ts +7 -5
- package/dist/forms/components/EditableForm/index.js +19 -15
- package/dist/forms/components/EditableFormField/index.d.ts +1 -1
- package/dist/forms/components/EditableFormField/index.js +3 -3
- package/dist/forms/components/EditableFormFields/index.d.ts +23 -0
- package/dist/forms/components/EditableFormFields/index.js +78 -1
- package/dist/forms/components/Form/index.d.ts +5 -2
- package/dist/forms/components/Form/index.js +7 -6
- package/dist/forms/components/FormError/index.d.ts +2 -2
- package/dist/forms/components/FormError/index.js +7 -5
- package/dist/forms/components/FormField/index.d.ts +8 -6
- package/dist/forms/components/FormField/index.js +16 -8
- package/dist/forms/components/FormFields/index.d.ts +27 -2
- package/dist/forms/components/FormFields/index.js +55 -2
- package/dist/forms/components/FormLabel/index.d.ts +1 -1
- package/dist/forms/components/FormLabel/index.js +4 -3
- package/dist/forms/components/FormSubmit/index.d.ts +1 -1
- package/dist/forms/components/FormSubmit/index.js +1 -1
- package/dist/forms/components/ImageInput/index.d.ts +20 -0
- package/dist/forms/components/ImageInput/index.js +51 -0
- package/dist/forms/components/ImageInputPanel/index.d.ts +10 -0
- package/dist/forms/components/ImageInputPanel/index.js +34 -0
- package/dist/forms/components/ModalForm/index.d.ts +4 -3
- package/dist/forms/components/ModalForm/index.js +8 -7
- package/dist/forms/components/NumberInput/index.d.ts +1 -1
- package/dist/forms/components/PasswordComplexity/index.d.ts +16 -0
- package/dist/forms/components/PasswordComplexity/index.js +14 -0
- package/dist/forms/components/PasswordComplexityItem/index.d.ts +8 -0
- package/dist/forms/components/PasswordComplexityItem/index.js +10 -0
- package/dist/forms/components/PasswordInput/index.d.ts +2 -2
- package/dist/forms/components/PasswordInput/index.js +6 -6
- package/dist/forms/components/PointsInput/index.d.ts +5 -0
- package/dist/forms/components/{MoneyInput → PointsInput}/index.js +3 -3
- package/dist/forms/components/RangeCalendarInput/index.d.ts +6 -0
- package/dist/forms/components/RangeCalendarInput/index.js +14 -0
- package/dist/forms/components/StaticTextInput/index.d.ts +3 -3
- package/dist/forms/components/StaticTextInput/index.js +7 -8
- package/dist/forms/components/Switch/index.d.ts +10 -4
- package/dist/forms/components/Switch/index.js +7 -5
- package/dist/forms/components/TextArea/index.d.ts +14 -0
- package/dist/forms/components/TextArea/index.js +15 -0
- package/dist/forms/components/TextInput/index.d.ts +2 -2
- package/dist/forms/components/TextInput/index.js +5 -4
- package/dist/forms/hooks/useAutocomplete.d.ts +7 -6
- package/dist/forms/hooks/useAutocomplete.js +4 -4
- package/dist/forms/hooks/useDropdown.d.ts +5 -7
- package/dist/forms/hooks/useDropdown.js +5 -5
- package/dist/forms/hooks/useEditableDropdown.d.ts +4 -0
- package/dist/forms/hooks/useEditableDropdown.js +6 -0
- package/dist/forms/hooks/useEditableForm.d.ts +2 -1
- package/dist/forms/hooks/useEditableForm.js +21 -9
- package/dist/forms/hooks/useForm.d.ts +7 -14
- package/dist/forms/hooks/useForm.js +27 -28
- package/dist/forms/hooks/useModalForm.d.ts +2 -2
- package/dist/forms/hooks/useModalForm.js +10 -3
- package/dist/forms/index.d.ts +18 -7
- package/dist/forms/index.js +9 -3
- package/dist/forms/interfaces.d.ts +9 -1
- package/dist/forms/utility/extract-input-props.js +1 -0
- package/dist/forms/utility/format-date-value.d.ts +2 -0
- package/dist/forms/utility/format-date-value.js +13 -0
- package/dist/forms/utility/format-file-size.d.ts +2 -0
- package/dist/forms/utility/format-file-size.js +11 -0
- package/dist/forms/utility/preprocess-image.d.ts +9 -0
- package/dist/forms/utility/preprocess-image.js +61 -0
- package/dist/hooks/index.d.ts +3 -0
- package/dist/hooks/index.js +3 -0
- package/dist/hooks/useConfirmable.d.ts +21 -0
- package/dist/hooks/useConfirmable.js +58 -0
- package/dist/hooks/useDownload.d.ts +2 -0
- package/dist/hooks/useDownload.js +18 -0
- package/dist/hooks/usePopover.d.ts +12 -0
- package/dist/hooks/usePopover.js +24 -0
- package/dist/hooks/useSelected.d.ts +12 -0
- package/dist/hooks/useSelected.js +35 -0
- package/dist/hooks/useServerAction.d.ts +14 -0
- package/dist/hooks/useServerAction.js +30 -0
- package/dist/hooks/useSuccess.d.ts +10 -0
- package/dist/hooks/useSuccess.js +24 -0
- package/dist/mail/Mail/index.d.ts +8 -0
- package/dist/mail/Mail/index.js +108 -0
- package/dist/mail/MailBlock/index.d.ts +5 -0
- package/dist/mail/MailBlock/index.js +5 -0
- package/dist/mail/MailButton/index.d.ts +8 -0
- package/dist/mail/MailButton/index.js +28 -0
- package/dist/mail/MailTable/index.d.ts +9 -0
- package/dist/mail/MailTable/index.js +7 -0
- package/dist/mail/index.d.ts +8 -0
- package/dist/mail/index.js +4 -0
- package/dist/mail/utility/convert-to-datauri.d.ts +2 -0
- package/dist/mail/utility/convert-to-datauri.js +37 -0
- package/dist/mail/utility/interfaces.d.ts +23 -0
- package/dist/mail/utility/mail-config.d.ts +4 -0
- package/dist/mail/utility/mail-config.js +42 -0
- package/dist/navigation/components/AppNavigation/index.d.ts +3 -1
- package/dist/navigation/components/AppNavigation/index.js +4 -4
- package/dist/navigation/components/AppNavigationItem/index.d.ts +6 -4
- package/dist/navigation/components/AppNavigationItem/index.js +16 -7
- package/dist/navigation/components/Tabs/index.js +1 -4
- package/dist/navigation/hooks/useNavigation.d.ts +3 -3
- package/dist/navigation/hooks/useNavigation.js +5 -5
- package/dist/styles/classnames/config.d.ts +97 -0
- package/dist/styles/classnames/config.js +1 -0
- package/dist/styles/classnames/interfaces.d.ts +56 -0
- package/dist/styles/classnames/interfaces.js +1 -0
- package/dist/styles/classnames/utility/apply-sizes.d.ts +3 -0
- package/dist/styles/classnames/utility/apply-sizes.js +21 -0
- package/dist/styles/classnames/utility/apply-variants.d.ts +3 -0
- package/dist/styles/classnames/utility/apply-variants.js +26 -0
- package/dist/styles/classnames/utility/is-classname-object.d.ts +3 -0
- package/dist/styles/classnames/utility/is-classname-object.js +7 -0
- package/dist/styles/classnames/utility/parse-classnames.d.ts +6 -0
- package/dist/styles/classnames/utility/parse-classnames.js +33 -0
- package/dist/styles/context.d.ts +28 -0
- package/dist/styles/context.js +19 -0
- package/dist/styles/icons/config.d.ts +29 -0
- package/dist/styles/icons/config.js +1 -0
- package/dist/styles/icons/interfaces.d.ts +4 -0
- package/dist/styles/icons/interfaces.js +1 -0
- package/dist/styles/index.d.ts +6 -2
- package/dist/styles/index.js +2 -1
- package/dist/styles/styles.css +60 -0
- package/dist/utility/compare-dates.d.ts +2 -0
- package/dist/utility/compare-dates.js +13 -0
- package/dist/utility/get-date-state.d.ts +8 -0
- package/dist/utility/get-date-state.js +63 -0
- package/dist/utility/get-days.d.ts +2 -0
- package/dist/utility/get-days.js +5 -0
- package/dist/utility/get-weeks.d.ts +2 -0
- package/dist/utility/get-weeks.js +31 -0
- package/dist/utility/index.d.ts +1 -1
- package/dist/utility/interfaces.d.ts +33 -17
- package/dist/utility/is-data-object-array.d.ts +3 -0
- package/dist/utility/is-data-object-array.js +5 -0
- package/dist/utility/is-data-object.d.ts +3 -0
- package/dist/utility/is-data-object.js +4 -0
- package/dist/utility/normalize-href.d.ts +2 -0
- package/dist/utility/normalize-href.js +8 -0
- package/package.json +37 -25
- package/dist/components/buttons/ConfirmableButton/index.d.ts +0 -7
- package/dist/components/buttons/ConfirmableButton/index.js +0 -13
- package/dist/components/collections/utility/filter-columns.d.ts +0 -3
- package/dist/components/collections/utility/filter-columns.js +0 -8
- package/dist/components/collections/utility/get-selected-from-search-params.d.ts +0 -2
- package/dist/components/collections/utility/get-selected-from-search-params.js +0 -5
- package/dist/components/collections/utility/set-selected-to-search-params.d.ts +0 -2
- package/dist/components/collections/utility/set-selected-to-search-params.js +0 -4
- package/dist/components/utility/ClassNames/index.d.ts +0 -6
- package/dist/components/utility/ClassNames/index.js +0 -7
- package/dist/components/utility/Page/index.d.ts +0 -18
- package/dist/components/utility/Page/index.js +0 -34
- package/dist/components/utility/RootLayout/index.d.ts +0 -15
- package/dist/components/utility/RootLayout/index.js +0 -14
- package/dist/forms/components/MoneyInput/index.d.ts +0 -5
- package/dist/styles/config.d.ts +0 -64
- package/dist/styles/config.js +0 -43
- package/dist/styles/icons.d.ts +0 -15
- package/dist/styles/icons.js +0 -7
- package/dist/styles/interfaces.d.ts +0 -41
- /package/dist/{styles → mail/utility}/interfaces.js +0 -0
- /package/dist/styles/{tw.d.ts → classnames/utility/tw.d.ts} +0 -0
- /package/dist/styles/{tw.js → classnames/utility/tw.js} +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { useRef, useState, useTransition } from 'react';
|
|
3
3
|
import { formatTitle } from '@sqrzro/utility';
|
|
4
|
-
import { useRouter } from 'next/navigation';
|
|
5
4
|
import useDeepCompareEffect from 'use-deep-compare-effect';
|
|
6
|
-
import
|
|
7
|
-
|
|
5
|
+
import useSuccess from '../../hooks/useSuccess.js';
|
|
6
|
+
import useToast from '../../hooks/useToast.js';
|
|
7
|
+
export const DEFAULT_TOAST_MESSAGES = {
|
|
8
8
|
server: 'There was a problem submitting your request. Please try again later.',
|
|
9
9
|
success: 'Your request was submitted successfully.',
|
|
10
10
|
validation: 'There was a problem with your submission. Please check the form and try again.',
|
|
@@ -120,10 +120,12 @@ function getToastMessage(key, toasts) {
|
|
|
120
120
|
* handling additional form events or integrating with different server APIs.
|
|
121
121
|
*/
|
|
122
122
|
function useForm({ defaults = {}, onError, onSubmit, onSuccess, onValidation, redirectOnSuccess, refreshOnSuccess, toasts, }) {
|
|
123
|
-
const
|
|
124
|
-
const
|
|
125
|
-
const
|
|
123
|
+
const ref = useRef(null);
|
|
124
|
+
const usedFields = useRef(new Set());
|
|
125
|
+
const { handleSuccess } = useSuccess({ onSuccess, redirectOnSuccess, refreshOnSuccess });
|
|
126
|
+
const [isLoading] = useTransition();
|
|
126
127
|
const [errors, setErrors] = useState(null);
|
|
128
|
+
const [uncaughtErrors, setUncaughtErrors] = useState(null);
|
|
127
129
|
const [data, setData] = useState(defaults);
|
|
128
130
|
const { toastError, toastSuccess } = useToast();
|
|
129
131
|
function setFormData(key, value) {
|
|
@@ -132,28 +134,21 @@ function useForm({ defaults = {}, onError, onSubmit, onSuccess, onValidation, re
|
|
|
132
134
|
function handleChange(event) {
|
|
133
135
|
setData((prev) => ({ ...prev, [event.target.name]: event.target.value }));
|
|
134
136
|
}
|
|
135
|
-
async function
|
|
136
|
-
await
|
|
137
|
-
if (redirectOnSuccess) {
|
|
138
|
-
const redirect = typeof redirectOnSuccess === 'function'
|
|
139
|
-
? redirectOnSuccess(response)
|
|
140
|
-
: redirectOnSuccess;
|
|
141
|
-
if (redirect) {
|
|
142
|
-
router.push(redirect);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
if (refreshOnSuccess) {
|
|
146
|
-
router.refresh();
|
|
147
|
-
}
|
|
137
|
+
async function handleFormSuccess(response) {
|
|
138
|
+
await handleSuccess(response);
|
|
148
139
|
toastSuccess(getToastMessage('success', toasts));
|
|
149
140
|
}
|
|
150
|
-
function
|
|
141
|
+
function handleFormError(message) {
|
|
151
142
|
onError?.(message);
|
|
152
143
|
toastError(getToastMessage('server', toasts));
|
|
153
144
|
}
|
|
154
|
-
function
|
|
155
|
-
|
|
145
|
+
function handleFormValidation(messages) {
|
|
146
|
+
const uncaughtMessages = Object.keys(messages)
|
|
147
|
+
.filter((key) => !usedFields.current.has(key))
|
|
148
|
+
.reduce((acc, key) => ({ ...acc, [key]: messages[key] }), {});
|
|
149
|
+
onValidation?.(messages, uncaughtMessages);
|
|
156
150
|
setErrors(messages);
|
|
151
|
+
setUncaughtErrors(uncaughtMessages);
|
|
157
152
|
toastError(getToastMessage('validation', toasts));
|
|
158
153
|
}
|
|
159
154
|
async function handleSubmit() {
|
|
@@ -163,21 +158,22 @@ function useForm({ defaults = {}, onError, onSubmit, onSuccess, onValidation, re
|
|
|
163
158
|
setErrors(null);
|
|
164
159
|
const fnReturn = await onSubmit(data);
|
|
165
160
|
if (fnReturn.error) {
|
|
166
|
-
return
|
|
161
|
+
return handleFormError(fnReturn.error);
|
|
167
162
|
}
|
|
168
163
|
if (fnReturn.validation) {
|
|
169
|
-
return
|
|
164
|
+
return handleFormValidation(fnReturn.validation);
|
|
170
165
|
}
|
|
171
|
-
if (fnReturn.data) {
|
|
172
|
-
return
|
|
166
|
+
if (fnReturn.data !== null) {
|
|
167
|
+
return handleFormSuccess(fnReturn.data);
|
|
173
168
|
}
|
|
174
169
|
}
|
|
175
170
|
function fieldProps(name, label) {
|
|
171
|
+
usedFields.current.add(name);
|
|
176
172
|
return {
|
|
177
173
|
error: getErrorsForField(errors, name),
|
|
178
174
|
label: getLabel(name, label),
|
|
179
175
|
name: name,
|
|
180
|
-
|
|
176
|
+
onFieldChange: handleChange,
|
|
181
177
|
value: data[name],
|
|
182
178
|
};
|
|
183
179
|
}
|
|
@@ -185,6 +181,7 @@ function useForm({ defaults = {}, onError, onSubmit, onSuccess, onValidation, re
|
|
|
185
181
|
setTimeout(() => {
|
|
186
182
|
setData((defaults || {}));
|
|
187
183
|
setErrors(null);
|
|
184
|
+
setUncaughtErrors(null);
|
|
188
185
|
}, 1);
|
|
189
186
|
}
|
|
190
187
|
useDeepCompareEffect(() => {
|
|
@@ -196,13 +193,15 @@ function useForm({ defaults = {}, onError, onSubmit, onSuccess, onValidation, re
|
|
|
196
193
|
formData: data,
|
|
197
194
|
formProps: {
|
|
198
195
|
action: handleSubmit,
|
|
196
|
+
ref,
|
|
197
|
+
uncaughtErrors,
|
|
199
198
|
},
|
|
200
199
|
isLoading,
|
|
201
200
|
resetForm,
|
|
202
201
|
setErrors,
|
|
203
202
|
setFormData,
|
|
204
203
|
submitForm: () => {
|
|
205
|
-
setTimeout(() =>
|
|
204
|
+
setTimeout(() => ref.current?.requestSubmit(), 1);
|
|
206
205
|
},
|
|
207
206
|
};
|
|
208
207
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { SimpleActionObject } from '../../utility/interfaces.js';
|
|
2
2
|
import type { ModalFormProps } from '../components/ModalForm';
|
|
3
3
|
import type { UseFormArgs, UseFormReturn } from './useForm';
|
|
4
4
|
export interface UseModalFormArgs<Request, Response> extends UseFormArgs<Request, Response> {
|
|
5
|
-
actions?:
|
|
5
|
+
actions?: SimpleActionObject[];
|
|
6
6
|
icon?: React.ReactNode;
|
|
7
7
|
submitLabel?: string;
|
|
8
8
|
title?: string;
|
|
@@ -1,19 +1,25 @@
|
|
|
1
1
|
'use client';
|
|
2
|
+
import { useState } from 'react';
|
|
2
3
|
import { useRouter } from 'next/navigation';
|
|
3
|
-
import useSearchParamsHref from '../../hooks/useSearchParamsHref';
|
|
4
|
-
import useForm from './useForm';
|
|
4
|
+
import useSearchParamsHref from '../../hooks/useSearchParamsHref.js';
|
|
5
|
+
import useForm, { DEFAULT_TOAST_MESSAGES } from './useForm';
|
|
5
6
|
function useModalForm({ actions, icon, submitLabel, title, ...useFormArgs }) {
|
|
7
|
+
const [serverError, setServerError] = useState(null);
|
|
6
8
|
const { setSearchParamsHref } = useSearchParamsHref();
|
|
7
9
|
const router = useRouter();
|
|
8
10
|
function handleSuccess(response) {
|
|
9
11
|
useFormArgs.onSuccess?.(response);
|
|
10
|
-
setSearchParamsHref(
|
|
12
|
+
setSearchParamsHref({ action: null, id: null });
|
|
11
13
|
setTimeout(() => {
|
|
12
14
|
router.refresh();
|
|
13
15
|
}, 1);
|
|
14
16
|
}
|
|
15
17
|
const useFormReturn = useForm({
|
|
16
18
|
...useFormArgs,
|
|
19
|
+
onError: (message) => {
|
|
20
|
+
setServerError(DEFAULT_TOAST_MESSAGES.server);
|
|
21
|
+
useFormArgs.onError?.(message);
|
|
22
|
+
},
|
|
17
23
|
onSuccess: handleSuccess,
|
|
18
24
|
toasts: false,
|
|
19
25
|
});
|
|
@@ -22,6 +28,7 @@ function useModalForm({ actions, icon, submitLabel, title, ...useFormArgs }) {
|
|
|
22
28
|
formProps: {
|
|
23
29
|
formProps: useFormReturn.formProps,
|
|
24
30
|
modalProps: { actions, icon, title },
|
|
31
|
+
serverError,
|
|
25
32
|
submitLabel,
|
|
26
33
|
},
|
|
27
34
|
};
|
package/dist/forms/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export * from './interfaces';
|
|
2
2
|
export type { AutocompleteProps } from './components/Autocomplete';
|
|
3
3
|
export { default as Autocomplete } from './components/Autocomplete';
|
|
4
|
+
export type { CSVInputClassNames, CSVInputProps } from './components/CSVInput';
|
|
5
|
+
export { default as CSVInput } from './components/CSVInput';
|
|
4
6
|
export type { DropdownClassNames, DropdownProps } from './components/Dropdown';
|
|
5
7
|
export { default as Dropdown } from './components/Dropdown';
|
|
6
8
|
export type { EditableFormClassNames, EditableFormProps } from './components/EditableForm';
|
|
@@ -9,28 +11,37 @@ export type { EditableFormFieldProps } from './components/EditableFormField';
|
|
|
9
11
|
export { default as EditableFormField } from './components/EditableFormField';
|
|
10
12
|
export type { FormClassNames, FormProps } from './components/Form';
|
|
11
13
|
export { default as Form } from './components/Form';
|
|
14
|
+
export type { FormErrorProps } from './components/FormError';
|
|
15
|
+
export { default as FormError } from './components/FormError';
|
|
12
16
|
export type { FormFieldClassNames, FormFieldProps } from './components/FormField';
|
|
13
17
|
export { default as FormField } from './components/FormField';
|
|
14
18
|
export type { FormSubmitProps } from './components/FormSubmit';
|
|
15
19
|
export { default as FormSubmit } from './components/FormSubmit';
|
|
16
20
|
export type { ModalFormProps } from './components/ModalForm';
|
|
17
21
|
export { default as ModalForm } from './components/ModalForm';
|
|
18
|
-
export type {
|
|
19
|
-
export { default as
|
|
22
|
+
export type { PasswordComplexityProps } from './components/PasswordComplexity';
|
|
23
|
+
export { default as PasswordComplexity } from './components/PasswordComplexity';
|
|
20
24
|
export type { NumberInputProps } from './components/NumberInput';
|
|
21
25
|
export { default as NumberInput } from './components/NumberInput';
|
|
22
26
|
export type { PasswordInputClassNames, PasswordInputProps } from './components/PasswordInput';
|
|
23
27
|
export { default as PasswordInput } from './components/PasswordInput';
|
|
28
|
+
export type { PointsInputProps } from './components/PointsInput';
|
|
29
|
+
export { default as PointsInput } from './components/PointsInput';
|
|
30
|
+
export type { StaticTextInputClassNames, StaticTextInputProps } from './components/StaticTextInput';
|
|
31
|
+
export { default as StaticTextInput } from './components/StaticTextInput';
|
|
32
|
+
export type { TextAreaClassNames, TextAreaProps } from './components/TextArea';
|
|
33
|
+
export { default as TextArea } from './components/TextArea';
|
|
24
34
|
export type { TextInputClassNames, TextInputProps } from './components/TextInput';
|
|
25
35
|
export { default as TextInput } from './components/TextInput';
|
|
26
|
-
export type
|
|
27
|
-
export
|
|
28
|
-
export type
|
|
29
|
-
export
|
|
36
|
+
export type * from './components/EditableFormFields';
|
|
37
|
+
export * from './components/EditableFormFields';
|
|
38
|
+
export type * from './components/FormFields';
|
|
39
|
+
export * from './components/FormFields';
|
|
30
40
|
export type { UseAutocompleteArgs, UseAutocompleteReturn } from './hooks/useAutocomplete';
|
|
31
41
|
export { default as useAutocomplete } from './hooks/useAutocomplete';
|
|
32
|
-
export type { UseDropdownArgs
|
|
42
|
+
export type { UseDropdownArgs } from './hooks/useDropdown';
|
|
33
43
|
export { default as useDropdown } from './hooks/useDropdown';
|
|
44
|
+
export { default as useEditableDropdown } from './hooks/useEditableDropdown';
|
|
34
45
|
export type { UseEditableFormArgs, UseEditableFormReturn } from './hooks/useEditableForm';
|
|
35
46
|
export { default as useEditableForm } from './hooks/useEditableForm';
|
|
36
47
|
export type { UseFormArgs, UseFormReturn } from './hooks/useForm';
|
package/dist/forms/index.js
CHANGED
|
@@ -1,20 +1,26 @@
|
|
|
1
1
|
export * from './interfaces';
|
|
2
2
|
export { default as Autocomplete } from './components/Autocomplete';
|
|
3
|
+
export { default as CSVInput } from './components/CSVInput';
|
|
3
4
|
export { default as Dropdown } from './components/Dropdown';
|
|
4
5
|
export { default as EditableForm } from './components/EditableForm';
|
|
5
6
|
export { default as EditableFormField } from './components/EditableFormField';
|
|
6
7
|
export { default as Form } from './components/Form';
|
|
8
|
+
export { default as FormError } from './components/FormError';
|
|
7
9
|
export { default as FormField } from './components/FormField';
|
|
8
10
|
export { default as FormSubmit } from './components/FormSubmit';
|
|
9
11
|
export { default as ModalForm } from './components/ModalForm';
|
|
10
|
-
export { default as
|
|
12
|
+
export { default as PasswordComplexity } from './components/PasswordComplexity';
|
|
11
13
|
export { default as NumberInput } from './components/NumberInput';
|
|
12
14
|
export { default as PasswordInput } from './components/PasswordInput';
|
|
15
|
+
export { default as PointsInput } from './components/PointsInput';
|
|
16
|
+
export { default as StaticTextInput } from './components/StaticTextInput';
|
|
17
|
+
export { default as TextArea } from './components/TextArea';
|
|
13
18
|
export { default as TextInput } from './components/TextInput';
|
|
14
|
-
export
|
|
15
|
-
export
|
|
19
|
+
export * from './components/EditableFormFields';
|
|
20
|
+
export * from './components/FormFields';
|
|
16
21
|
export { default as useAutocomplete } from './hooks/useAutocomplete';
|
|
17
22
|
export { default as useDropdown } from './hooks/useDropdown';
|
|
23
|
+
export { default as useEditableDropdown } from './hooks/useEditableDropdown';
|
|
18
24
|
export { default as useEditableForm } from './hooks/useEditableForm';
|
|
19
25
|
export { default as useForm } from './hooks/useForm';
|
|
20
26
|
export { default as useModalForm } from './hooks/useModalForm';
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import type { EditableFormFieldProps } from './components/EditableFormField';
|
|
2
2
|
import type { FormFieldProps } from './components/FormField';
|
|
3
|
+
export interface AwaitedFormResponse<M> {
|
|
4
|
+
data: M | null;
|
|
5
|
+
error: string | null;
|
|
6
|
+
validation: Record<string, string> | null;
|
|
7
|
+
}
|
|
8
|
+
export type FormResponse<M> = Promise<AwaitedFormResponse<M>>;
|
|
3
9
|
export type Default<T> = {
|
|
4
10
|
[K in keyof T]?: T[K] | null;
|
|
5
11
|
};
|
|
@@ -7,7 +13,7 @@ export interface DropdownObject<T = string> {
|
|
|
7
13
|
$data?: Record<string, string>;
|
|
8
14
|
details?: string | null;
|
|
9
15
|
isDisabled?: boolean;
|
|
10
|
-
label:
|
|
16
|
+
label: React.ReactNode;
|
|
11
17
|
value: T;
|
|
12
18
|
}
|
|
13
19
|
export type EditingStatus = 'CANCELLED' | 'EDITING' | 'SAVED';
|
|
@@ -25,9 +31,11 @@ export interface InputProps<V, T extends V = V> {
|
|
|
25
31
|
hasError?: boolean;
|
|
26
32
|
id?: string;
|
|
27
33
|
isDisabled?: boolean;
|
|
34
|
+
isReadOnly?: boolean;
|
|
28
35
|
name: string;
|
|
29
36
|
ref?: React.Ref<HTMLInputElement>;
|
|
30
37
|
onChange?: (event: InputEvent<T>) => void;
|
|
38
|
+
onError?: (error: string) => void;
|
|
31
39
|
onKeyDown?: React.KeyboardEventHandler;
|
|
32
40
|
value?: V;
|
|
33
41
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { formatDate } from '@sqrzro/utility';
|
|
2
|
+
function formatDateValue(date) {
|
|
3
|
+
if (!date) {
|
|
4
|
+
return null;
|
|
5
|
+
}
|
|
6
|
+
const dateArray = Array.isArray(date) ? date : [date];
|
|
7
|
+
const formattedArray = dateArray.map((item) => formatDate(item));
|
|
8
|
+
if (formattedArray[0] === formattedArray[1]) {
|
|
9
|
+
return formattedArray[0];
|
|
10
|
+
}
|
|
11
|
+
return formattedArray.join(' - ');
|
|
12
|
+
}
|
|
13
|
+
export default formatDateValue;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const BYTES_IN_KB = 1024;
|
|
2
|
+
const DECIMAL_PLACES = 3;
|
|
3
|
+
function formatFileSize(size) {
|
|
4
|
+
const units = ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'];
|
|
5
|
+
const exponent = Math.min(Math.floor(Math.log(size) / Math.log(BYTES_IN_KB)), units.length - 1);
|
|
6
|
+
const approx = size / BYTES_IN_KB ** exponent;
|
|
7
|
+
return exponent === 0
|
|
8
|
+
? `${size} bytes`
|
|
9
|
+
: `${approx.toFixed(DECIMAL_PLACES)} ${units[exponent]} (${size} bytes)`;
|
|
10
|
+
}
|
|
11
|
+
export default formatFileSize;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type ImageTypeKey = 'jpg' | 'png' | 'gif' | 'svg' | 'webp';
|
|
2
|
+
interface PreprocessImageOptions {
|
|
3
|
+
accept?: ImageTypeKey[];
|
|
4
|
+
format?: ImageTypeKey;
|
|
5
|
+
maxSize?: [number?, number?];
|
|
6
|
+
minSize?: [number?, number?];
|
|
7
|
+
}
|
|
8
|
+
export declare function preprocessImage(file: File, options?: PreprocessImageOptions): Promise<File>;
|
|
9
|
+
export default preprocessImage;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
const DEFAULT_FORMAT = 'webp';
|
|
2
|
+
const DEFAULT_ACCEPT = ['jpg', 'png', 'gif', 'svg', 'webp'];
|
|
3
|
+
const imageTypeMap = {
|
|
4
|
+
jpg: 'image/jpeg',
|
|
5
|
+
png: 'image/png',
|
|
6
|
+
gif: 'image/gif',
|
|
7
|
+
svg: 'image/svg+xml',
|
|
8
|
+
webp: 'image/webp',
|
|
9
|
+
};
|
|
10
|
+
function isAccepted(file, accept = DEFAULT_ACCEPT) {
|
|
11
|
+
return accept.map((key) => imageTypeMap[key]).includes(file.type);
|
|
12
|
+
}
|
|
13
|
+
function fitWithinMaxSize(width, height, maxWidth, maxHeight) {
|
|
14
|
+
const scale = Math.min(maxWidth / width, maxHeight / height, 1);
|
|
15
|
+
return [Math.round(width * scale), Math.round(height * scale)];
|
|
16
|
+
}
|
|
17
|
+
export async function preprocessImage(file, options = {}) {
|
|
18
|
+
if (!isAccepted(file, options.accept)) {
|
|
19
|
+
throw new Error('Unsupported file type');
|
|
20
|
+
}
|
|
21
|
+
if (file.type === 'image/svg+xml') {
|
|
22
|
+
return file;
|
|
23
|
+
}
|
|
24
|
+
const bitmap = await createImageBitmap(file);
|
|
25
|
+
const { maxSize, minSize } = options;
|
|
26
|
+
const maxWidth = maxSize?.[0] || 1000;
|
|
27
|
+
const maxHeight = maxSize?.[1] || 1000;
|
|
28
|
+
const minWidth = minSize?.[0] || 0;
|
|
29
|
+
const minHeight = minSize?.[1] || 0;
|
|
30
|
+
let { width, height } = bitmap;
|
|
31
|
+
if (width < minWidth || height < minHeight) {
|
|
32
|
+
throw new Error(`Image is smaller than the minimum size`);
|
|
33
|
+
}
|
|
34
|
+
const [newWidth, newHeight] = fitWithinMaxSize(width, height, maxWidth, maxHeight);
|
|
35
|
+
const canvas = document.createElement('canvas');
|
|
36
|
+
canvas.width = newWidth;
|
|
37
|
+
canvas.height = newHeight;
|
|
38
|
+
const ctx = canvas.getContext('2d');
|
|
39
|
+
if (!ctx) {
|
|
40
|
+
throw new Error('Could not get canvas context');
|
|
41
|
+
}
|
|
42
|
+
ctx.drawImage(bitmap, 0, 0, newWidth, newHeight);
|
|
43
|
+
const format = options.format || DEFAULT_FORMAT;
|
|
44
|
+
const blob = await new Promise((resolve, reject) => {
|
|
45
|
+
canvas.toBlob((data) => {
|
|
46
|
+
if (data) {
|
|
47
|
+
resolve(data);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
reject(new Error(`Failed to create ${format.toUpperCase()} blob`));
|
|
51
|
+
}
|
|
52
|
+
}, imageTypeMap[format], 1);
|
|
53
|
+
});
|
|
54
|
+
const baseName = file.name.replace(/\.\w+$/, '');
|
|
55
|
+
const newName = `${baseName}.${format}`;
|
|
56
|
+
return new File([blob], newName, {
|
|
57
|
+
type: imageTypeMap[format],
|
|
58
|
+
lastModified: Date.now(),
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
export default preprocessImage;
|
package/dist/hooks/index.d.ts
CHANGED
package/dist/hooks/index.js
CHANGED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ActionEvent } from '../utility/interfaces.js';
|
|
2
|
+
interface UseConfirmableArgs {
|
|
3
|
+
isLoading?: boolean;
|
|
4
|
+
onBeforeConfirm?: () => void;
|
|
5
|
+
onConfirm: (event: ActionEvent, currentRef: HTMLButtonElement | null) => void;
|
|
6
|
+
onSuccess?: () => Promise<void> | void;
|
|
7
|
+
redirectOnSuccess?: string | false | ((response: Response) => string | false);
|
|
8
|
+
refreshOnSuccess?: boolean;
|
|
9
|
+
}
|
|
10
|
+
interface UseConfirmableReturn {
|
|
11
|
+
handle: (event?: ActionEvent) => void;
|
|
12
|
+
isOpen: boolean;
|
|
13
|
+
modalProps: {
|
|
14
|
+
isLoading: boolean;
|
|
15
|
+
onCancel: () => void;
|
|
16
|
+
onConfirm: () => void;
|
|
17
|
+
};
|
|
18
|
+
ref: React.RefObject<HTMLButtonElement | null>;
|
|
19
|
+
}
|
|
20
|
+
declare function useConfirmable({ isLoading, onBeforeConfirm, onConfirm, onSuccess, redirectOnSuccess, refreshOnSuccess, }: Readonly<UseConfirmableArgs>): UseConfirmableReturn;
|
|
21
|
+
export default useConfirmable;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useEffect, useRef, useState } from 'react';
|
|
3
|
+
import { useRouter } from 'next/navigation';
|
|
4
|
+
function useConfirmable({ isLoading, onBeforeConfirm, onConfirm, onSuccess, redirectOnSuccess, refreshOnSuccess, }) {
|
|
5
|
+
const ref = useRef(null);
|
|
6
|
+
const router = useRouter();
|
|
7
|
+
const [isModalOpen, setIsModalOpen] = useState(false);
|
|
8
|
+
const [isConfirmed, setIsConfirmed] = useState(false);
|
|
9
|
+
const [refEvent, setRefEvent] = useState();
|
|
10
|
+
function handle(event) {
|
|
11
|
+
onBeforeConfirm?.();
|
|
12
|
+
if (!isConfirmed) {
|
|
13
|
+
event?.preventDefault();
|
|
14
|
+
setIsModalOpen(true);
|
|
15
|
+
}
|
|
16
|
+
setRefEvent(event);
|
|
17
|
+
setIsConfirmed(false);
|
|
18
|
+
}
|
|
19
|
+
function handleConfirm() {
|
|
20
|
+
setIsConfirmed(true);
|
|
21
|
+
setTimeout(() => {
|
|
22
|
+
if (refEvent) {
|
|
23
|
+
onConfirm(refEvent, ref.current);
|
|
24
|
+
}
|
|
25
|
+
// If `isLoading` hasn't been set, we can just close the modal now. If it has, by
|
|
26
|
+
// setting `isConfirmed` to true above, we trigger the useEffect below to wait until
|
|
27
|
+
// after loading to close the modal.
|
|
28
|
+
if (typeof isLoading === 'undefined') {
|
|
29
|
+
setIsConfirmed(false);
|
|
30
|
+
setIsModalOpen(false);
|
|
31
|
+
}
|
|
32
|
+
}, 0);
|
|
33
|
+
}
|
|
34
|
+
function handleCancel() {
|
|
35
|
+
setIsModalOpen(false);
|
|
36
|
+
}
|
|
37
|
+
function handleSuccess() {
|
|
38
|
+
setIsConfirmed(false);
|
|
39
|
+
setIsModalOpen(false);
|
|
40
|
+
router.refresh();
|
|
41
|
+
}
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
if (!isLoading && isConfirmed) {
|
|
44
|
+
handleSuccess();
|
|
45
|
+
}
|
|
46
|
+
}, [isLoading]);
|
|
47
|
+
return {
|
|
48
|
+
handle,
|
|
49
|
+
isOpen: isModalOpen,
|
|
50
|
+
modalProps: {
|
|
51
|
+
isLoading: isLoading ?? false,
|
|
52
|
+
onCancel: handleCancel,
|
|
53
|
+
onConfirm: handleConfirm,
|
|
54
|
+
},
|
|
55
|
+
ref,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
export default useConfirmable;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
function download(data, filename) {
|
|
2
|
+
const href = typeof data === 'string' ? data : URL.createObjectURL(data);
|
|
3
|
+
// Create a temporary link element to trigger the download
|
|
4
|
+
const link = document.createElement('a');
|
|
5
|
+
link.href = href;
|
|
6
|
+
link.download = filename;
|
|
7
|
+
document.body.appendChild(link);
|
|
8
|
+
link.click();
|
|
9
|
+
// Clean up
|
|
10
|
+
document.body.removeChild(link);
|
|
11
|
+
if (typeof data !== 'string') {
|
|
12
|
+
URL.revokeObjectURL(href);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function useDownload() {
|
|
16
|
+
return download;
|
|
17
|
+
}
|
|
18
|
+
export default useDownload;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
interface UsePopoverReturn<T extends HTMLElement = HTMLElement> {
|
|
2
|
+
controlProps: {
|
|
3
|
+
onClick: () => void;
|
|
4
|
+
};
|
|
5
|
+
isOpen: boolean;
|
|
6
|
+
ref: React.RefObject<T | null>;
|
|
7
|
+
targetProps: {
|
|
8
|
+
isOpen: boolean;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
declare function usePopover<T extends HTMLElement = HTMLElement>(): UsePopoverReturn<T>;
|
|
12
|
+
export default usePopover;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
import useClickOutside from './useClickOutside';
|
|
3
|
+
import { usePathname } from 'next/navigation';
|
|
4
|
+
function usePopover() {
|
|
5
|
+
const pathname = usePathname();
|
|
6
|
+
const [isOpen, setIsOpen, ref] = useClickOutside();
|
|
7
|
+
function toggleIsOpen() {
|
|
8
|
+
setIsOpen(!isOpen);
|
|
9
|
+
}
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
setIsOpen(false);
|
|
12
|
+
}, [pathname]);
|
|
13
|
+
return {
|
|
14
|
+
controlProps: {
|
|
15
|
+
onClick: toggleIsOpen,
|
|
16
|
+
},
|
|
17
|
+
isOpen,
|
|
18
|
+
ref,
|
|
19
|
+
targetProps: {
|
|
20
|
+
isOpen,
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export default usePopover;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { InputEvent } from '../forms/interfaces.js';
|
|
2
|
+
interface UseSelectedReturn {
|
|
3
|
+
checkSelected: (id: string) => boolean;
|
|
4
|
+
isAllSelected: boolean;
|
|
5
|
+
onSelect: (event: InputEvent<boolean>) => void;
|
|
6
|
+
onSelectAll: () => void;
|
|
7
|
+
selected: string[];
|
|
8
|
+
}
|
|
9
|
+
declare function useSelected(data: {
|
|
10
|
+
id: string;
|
|
11
|
+
}[]): UseSelectedReturn;
|
|
12
|
+
export default useSelected;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { toggleArrayItem } from '@sqrzro/utility';
|
|
2
|
+
import { useSearchParams } from 'next/navigation';
|
|
3
|
+
import useSearchParamsHref from './useSearchParamsHref';
|
|
4
|
+
function getSelectedFromSearchParams(searchParams) {
|
|
5
|
+
const selected = searchParams.get('selected');
|
|
6
|
+
return selected ? selected.split('|') : [];
|
|
7
|
+
}
|
|
8
|
+
function setSelectedToSearchParams(selected) {
|
|
9
|
+
return selected.length ? selected.join('|') : null;
|
|
10
|
+
}
|
|
11
|
+
function useSelected(data) {
|
|
12
|
+
const { setSearchParamsHref } = useSearchParamsHref();
|
|
13
|
+
const searchParams = useSearchParams();
|
|
14
|
+
const selected = getSelectedFromSearchParams(searchParams);
|
|
15
|
+
function onSelect(event) {
|
|
16
|
+
const value = toggleArrayItem(selected, event.target.name);
|
|
17
|
+
setSearchParamsHref({ selected: setSelectedToSearchParams(value) });
|
|
18
|
+
}
|
|
19
|
+
function onSelectAll() {
|
|
20
|
+
const value = selected.length === data.length ? [] : data.map((item) => item.id);
|
|
21
|
+
setSearchParamsHref({ selected: setSelectedToSearchParams(value) });
|
|
22
|
+
}
|
|
23
|
+
const isAllSelected = data.length > 0 && selected.length === data.length;
|
|
24
|
+
function checkSelected(id) {
|
|
25
|
+
return selected.includes(id);
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
checkSelected,
|
|
29
|
+
isAllSelected,
|
|
30
|
+
onSelect,
|
|
31
|
+
onSelectAll,
|
|
32
|
+
selected,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export default useSelected;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { UseSuccessArgs } from './useSuccess';
|
|
2
|
+
export interface ToastsArgs {
|
|
3
|
+
error?: string | false;
|
|
4
|
+
success?: string | false;
|
|
5
|
+
}
|
|
6
|
+
interface UseServerActionArgs<Response> extends UseSuccessArgs<Response> {
|
|
7
|
+
toasts?: ToastsArgs | false;
|
|
8
|
+
}
|
|
9
|
+
interface UseServerActionReturn {
|
|
10
|
+
handleClick: () => void;
|
|
11
|
+
isLoading: boolean;
|
|
12
|
+
}
|
|
13
|
+
declare function useServerAction<Response>(fn?: () => Promise<Response>, args?: UseServerActionArgs<Response>): UseServerActionReturn;
|
|
14
|
+
export default useServerAction;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { useTransition } from 'react';
|
|
2
|
+
import useSuccess from './useSuccess';
|
|
3
|
+
import useToast from './useToast';
|
|
4
|
+
const DEFAULT_TOAST_MESSAGES = {
|
|
5
|
+
error: 'There was a problem submitting your request. Please try again later.',
|
|
6
|
+
success: 'Your request was submitted successfully.',
|
|
7
|
+
};
|
|
8
|
+
function getToastMessage(key, toasts) {
|
|
9
|
+
if (toasts === false || toasts?.[key] === false) {
|
|
10
|
+
return '';
|
|
11
|
+
}
|
|
12
|
+
return toasts?.[key] || DEFAULT_TOAST_MESSAGES[key];
|
|
13
|
+
}
|
|
14
|
+
function useServerAction(fn, args = {}) {
|
|
15
|
+
const { handleSuccess } = useSuccess(args);
|
|
16
|
+
const { toastSuccess } = useToast();
|
|
17
|
+
const [isLoading, startTransition] = useTransition();
|
|
18
|
+
function handleClick() {
|
|
19
|
+
startTransition(async () => {
|
|
20
|
+
if (!fn) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const response = await fn();
|
|
24
|
+
await handleSuccess(response);
|
|
25
|
+
toastSuccess(getToastMessage('success', args.toasts));
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
return { handleClick, isLoading };
|
|
29
|
+
}
|
|
30
|
+
export default useServerAction;
|