@bsol-oss/react-datatable5 12.0.0-beta.56 → 12.0.0-beta.58
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/README.md +192 -0
- package/dist/index.d.ts +76 -2
- package/dist/index.js +676 -60
- package/dist/index.mjs +674 -62
- package/dist/types/components/DatePicker/DatePicker.d.ts +23 -0
- package/dist/types/components/DatePicker/DateTimePicker.d.ts +11 -0
- package/dist/types/components/DatePicker/DurationPicker.d.ts +12 -0
- package/dist/types/components/DatePicker/IsoTimePicker.d.ts +16 -0
- package/dist/types/components/DatePicker/PickerDemo.d.ts +1 -0
- package/dist/types/components/DatePicker/UniversalPicker.d.ts +9 -0
- package/dist/types/components/DatePicker/index.d.ts +7 -0
- package/dist/types/components/Form/SchemaFormContext.d.ts +3 -0
- package/dist/types/components/Form/components/core/FormRoot.d.ts +3 -1
- package/dist/types/components/Form/components/fields/DateTimePicker.d.ts +2 -0
- package/dist/types/components/Form/components/viewers/DateTimeViewer.d.ts +7 -0
- package/dist/types/components/Form/components/viewers/TimeViewer.d.ts +1 -1
- package/dist/types/components/Form/utils/validation.d.ts +49 -0
- package/dist/types/index.d.ts +2 -0
- package/package.json +7 -1
package/dist/index.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import * as React from 'react';
|
|
|
5
5
|
import React__default, { createContext, useContext, useState, useEffect, useRef } from 'react';
|
|
6
6
|
import { LuX, LuCheck, LuChevronRight, LuChevronDown } from 'react-icons/lu';
|
|
7
7
|
import { MdOutlineSort, MdFilterAlt, MdSearch, MdOutlineViewColumn, MdFilterListAlt, MdPushPin, MdCancel, MdClear, MdOutlineChecklist, MdDateRange } from 'react-icons/md';
|
|
8
|
-
import { FaUpDown, FaGripLinesVertical } from 'react-icons/fa6';
|
|
8
|
+
import { FaUpDown, FaGripLinesVertical, FaTrash } from 'react-icons/fa6';
|
|
9
9
|
import { BiDownArrow, BiUpArrow, BiError } from 'react-icons/bi';
|
|
10
10
|
import { CgClose, CgTrash } from 'react-icons/cg';
|
|
11
11
|
import Dayzed from '@bsol-oss/dayzed-react19';
|
|
@@ -28,8 +28,13 @@ import { GrAscend, GrDescend } from 'react-icons/gr';
|
|
|
28
28
|
import { useTranslation } from 'react-i18next';
|
|
29
29
|
import axios from 'axios';
|
|
30
30
|
import { FormProvider, useFormContext, useForm as useForm$1 } from 'react-hook-form';
|
|
31
|
+
import Ajv from 'ajv';
|
|
32
|
+
import addFormats from 'ajv-formats';
|
|
33
|
+
import zh_TW from 'ajv-i18n/localize/zh-TW';
|
|
34
|
+
import zh_CN from 'ajv-i18n/localize/zh';
|
|
31
35
|
import dayjs from 'dayjs';
|
|
32
36
|
import utc from 'dayjs/plugin/utc';
|
|
37
|
+
import timezone from 'dayjs/plugin/timezone';
|
|
33
38
|
import { TiDeleteOutline } from 'react-icons/ti';
|
|
34
39
|
|
|
35
40
|
const DataTableContext = createContext({
|
|
@@ -177,7 +182,7 @@ const monthNamesFull = [
|
|
|
177
182
|
"November",
|
|
178
183
|
"December",
|
|
179
184
|
];
|
|
180
|
-
const weekdayNamesShort
|
|
185
|
+
const weekdayNamesShort = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
181
186
|
function Calendar$1({ calendars, getBackProps, getForwardProps, getDateProps, selected = [], firstDayOfWeek = 0, }) {
|
|
182
187
|
const [hoveredDate, setHoveredDate] = useState();
|
|
183
188
|
const onMouseLeave = () => {
|
|
@@ -212,7 +217,7 @@ function Calendar$1({ calendars, getBackProps, getForwardProps, getDateProps, se
|
|
|
212
217
|
offset: 12,
|
|
213
218
|
}), children: ">>" })] }), jsx(Grid, { templateColumns: "repeat(2, auto)", justifyContent: "center", gap: 4, children: calendars.map((calendar) => (jsxs(Grid, { gap: 4, children: [jsxs(Grid, { justifyContent: "center", children: [monthNamesFull[calendar.month], " ", calendar.year] }), jsx(Grid, { templateColumns: "repeat(7, auto)", justifyContent: "center", children: [0, 1, 2, 3, 4, 5, 6].map((weekdayNum) => {
|
|
214
219
|
const weekday = (weekdayNum + firstDayOfWeek) % 7;
|
|
215
|
-
return (jsx(Box, { minWidth: "48px", textAlign: "center", children: weekdayNamesShort
|
|
220
|
+
return (jsx(Box, { minWidth: "48px", textAlign: "center", children: weekdayNamesShort[weekday] }, `${calendar.month}${calendar.year}${weekday}`));
|
|
216
221
|
}) }), jsx(Grid, { templateColumns: "repeat(7, auto)", justifyContent: "center", children: calendar.weeks.map((week, windex) => week.map((dateObj, index) => {
|
|
217
222
|
const key = `${calendar.month}${calendar.year}${windex}${index}`;
|
|
218
223
|
if (!dateObj) {
|
|
@@ -3668,6 +3673,8 @@ const SchemaFormContext = createContext({
|
|
|
3668
3673
|
onSubmit: async () => { },
|
|
3669
3674
|
rowNumber: 0,
|
|
3670
3675
|
requestOptions: {},
|
|
3676
|
+
validationLocale: 'en',
|
|
3677
|
+
timezone: 'Asia/Hong_Kong',
|
|
3671
3678
|
});
|
|
3672
3679
|
|
|
3673
3680
|
const useSchemaContext = () => {
|
|
@@ -3678,6 +3685,179 @@ const clearEmptyString = (object) => {
|
|
|
3678
3685
|
return Object.fromEntries(Object.entries(object).filter(([, value]) => value !== ""));
|
|
3679
3686
|
};
|
|
3680
3687
|
|
|
3688
|
+
// AJV i18n support
|
|
3689
|
+
const localize = {
|
|
3690
|
+
en: () => { }, // English is default, no localization needed
|
|
3691
|
+
'zh-HK': zh_TW, // Use zh-TW for Hong Kong Traditional Chinese
|
|
3692
|
+
'zh-TW': zh_TW, // Traditional Chinese (Taiwan)
|
|
3693
|
+
'zh-CN': zh_CN, // Simplified Chinese
|
|
3694
|
+
'zh': zh_CN, // Simplified Chinese (short form)
|
|
3695
|
+
};
|
|
3696
|
+
// Create AJV instance with format support
|
|
3697
|
+
const createValidator = () => {
|
|
3698
|
+
const ajv = new Ajv({
|
|
3699
|
+
allErrors: true,
|
|
3700
|
+
verbose: true,
|
|
3701
|
+
removeAdditional: false,
|
|
3702
|
+
strict: false,
|
|
3703
|
+
messages: false, // Disable default messages for i18n
|
|
3704
|
+
});
|
|
3705
|
+
// Add format validation support (date, time, email, etc.)
|
|
3706
|
+
addFormats(ajv);
|
|
3707
|
+
return ajv;
|
|
3708
|
+
};
|
|
3709
|
+
/**
|
|
3710
|
+
* Validates data against a JSON Schema using AJV with i18n support
|
|
3711
|
+
* @param data - The data to validate
|
|
3712
|
+
* @param schema - The JSON Schema to validate against
|
|
3713
|
+
* @param options - Validation options including locale
|
|
3714
|
+
* @returns ValidationResult containing validation status and errors
|
|
3715
|
+
*/
|
|
3716
|
+
const validateData = (data, schema, options = {}) => {
|
|
3717
|
+
const { locale = 'en' } = options;
|
|
3718
|
+
const ajv = createValidator();
|
|
3719
|
+
try {
|
|
3720
|
+
const validate = ajv.compile(schema);
|
|
3721
|
+
const isValid = validate(data);
|
|
3722
|
+
if (isValid) {
|
|
3723
|
+
return {
|
|
3724
|
+
isValid: true,
|
|
3725
|
+
errors: [],
|
|
3726
|
+
};
|
|
3727
|
+
}
|
|
3728
|
+
// Apply localization if not English
|
|
3729
|
+
if (locale !== 'en' && validate.errors && localize[locale]) {
|
|
3730
|
+
try {
|
|
3731
|
+
localize[locale](validate.errors);
|
|
3732
|
+
}
|
|
3733
|
+
catch (error) {
|
|
3734
|
+
console.warn(`Failed to localize validation errors to ${locale}:`, error);
|
|
3735
|
+
}
|
|
3736
|
+
}
|
|
3737
|
+
const errors = (validate.errors || []).map((error) => {
|
|
3738
|
+
const field = error.instancePath?.replace(/^\//, '') || error.schemaPath?.split('/').pop() || 'root';
|
|
3739
|
+
let message = error.message || 'Validation error';
|
|
3740
|
+
// Enhanced error messages for better UX (only if using English or localization failed)
|
|
3741
|
+
if (locale === 'en' || !error.message) {
|
|
3742
|
+
switch (error.keyword) {
|
|
3743
|
+
case 'required':
|
|
3744
|
+
message = `${error.params?.missingProperty || 'Field'} is required`;
|
|
3745
|
+
break;
|
|
3746
|
+
case 'format':
|
|
3747
|
+
message = `Invalid ${error.params?.format} format`;
|
|
3748
|
+
break;
|
|
3749
|
+
case 'type':
|
|
3750
|
+
message = `Expected ${error.params?.type}, got ${typeof error.data}`;
|
|
3751
|
+
break;
|
|
3752
|
+
case 'minLength':
|
|
3753
|
+
message = `Must be at least ${error.params?.limit} characters`;
|
|
3754
|
+
break;
|
|
3755
|
+
case 'maxLength':
|
|
3756
|
+
message = `Must be no more than ${error.params?.limit} characters`;
|
|
3757
|
+
break;
|
|
3758
|
+
case 'minimum':
|
|
3759
|
+
message = `Must be at least ${error.params?.limit}`;
|
|
3760
|
+
break;
|
|
3761
|
+
case 'maximum':
|
|
3762
|
+
message = `Must be no more than ${error.params?.limit}`;
|
|
3763
|
+
break;
|
|
3764
|
+
case 'pattern':
|
|
3765
|
+
message = `Does not match required pattern`;
|
|
3766
|
+
break;
|
|
3767
|
+
case 'enum':
|
|
3768
|
+
message = `Must be one of: ${error.params?.allowedValues?.join(', ')}`;
|
|
3769
|
+
break;
|
|
3770
|
+
default:
|
|
3771
|
+
message = error.message || 'Validation error';
|
|
3772
|
+
}
|
|
3773
|
+
}
|
|
3774
|
+
return {
|
|
3775
|
+
field: field || error.instancePath || 'unknown',
|
|
3776
|
+
message,
|
|
3777
|
+
value: error.data,
|
|
3778
|
+
schemaPath: error.schemaPath,
|
|
3779
|
+
};
|
|
3780
|
+
});
|
|
3781
|
+
return {
|
|
3782
|
+
isValid: false,
|
|
3783
|
+
errors,
|
|
3784
|
+
};
|
|
3785
|
+
}
|
|
3786
|
+
catch (error) {
|
|
3787
|
+
// Handle AJV compilation errors
|
|
3788
|
+
const errorMessage = locale === 'zh-HK' || locale === 'zh-TW'
|
|
3789
|
+
? `架構驗證錯誤: ${error instanceof Error ? error.message : '未知錯誤'}`
|
|
3790
|
+
: locale === 'zh-CN' || locale === 'zh'
|
|
3791
|
+
? `模式验证错误: ${error instanceof Error ? error.message : '未知错误'}`
|
|
3792
|
+
: `Schema validation error: ${error instanceof Error ? error.message : 'Unknown error'}`;
|
|
3793
|
+
return {
|
|
3794
|
+
isValid: false,
|
|
3795
|
+
errors: [
|
|
3796
|
+
{
|
|
3797
|
+
field: 'schema',
|
|
3798
|
+
message: errorMessage,
|
|
3799
|
+
},
|
|
3800
|
+
],
|
|
3801
|
+
};
|
|
3802
|
+
}
|
|
3803
|
+
};
|
|
3804
|
+
/**
|
|
3805
|
+
* Creates a reusable validator function for a specific schema with i18n support
|
|
3806
|
+
* @param schema - The JSON Schema to create validator for
|
|
3807
|
+
* @param locale - The locale to use for error messages
|
|
3808
|
+
* @returns A function that validates data against the schema
|
|
3809
|
+
*/
|
|
3810
|
+
const createSchemaValidator = (schema, locale = 'en') => {
|
|
3811
|
+
const ajv = createValidator();
|
|
3812
|
+
const validate = ajv.compile(schema);
|
|
3813
|
+
return (data) => {
|
|
3814
|
+
const isValid = validate(data);
|
|
3815
|
+
if (isValid) {
|
|
3816
|
+
return {
|
|
3817
|
+
isValid: true,
|
|
3818
|
+
errors: [],
|
|
3819
|
+
};
|
|
3820
|
+
}
|
|
3821
|
+
// Apply localization if not English
|
|
3822
|
+
if (locale !== 'en' && validate.errors && localize[locale]) {
|
|
3823
|
+
try {
|
|
3824
|
+
localize[locale](validate.errors);
|
|
3825
|
+
}
|
|
3826
|
+
catch (error) {
|
|
3827
|
+
console.warn(`Failed to localize validation errors to ${locale}:`, error);
|
|
3828
|
+
}
|
|
3829
|
+
}
|
|
3830
|
+
const errors = (validate.errors || []).map((error) => {
|
|
3831
|
+
const field = error.instancePath?.replace(/^\//, '') || 'root';
|
|
3832
|
+
return {
|
|
3833
|
+
field,
|
|
3834
|
+
message: error.message || 'Validation error',
|
|
3835
|
+
value: error.data,
|
|
3836
|
+
schemaPath: error.schemaPath,
|
|
3837
|
+
};
|
|
3838
|
+
});
|
|
3839
|
+
return {
|
|
3840
|
+
isValid: false,
|
|
3841
|
+
errors,
|
|
3842
|
+
};
|
|
3843
|
+
};
|
|
3844
|
+
};
|
|
3845
|
+
/**
|
|
3846
|
+
* Get available locales for validation error messages
|
|
3847
|
+
* @returns Array of supported locale codes
|
|
3848
|
+
*/
|
|
3849
|
+
const getSupportedLocales = () => {
|
|
3850
|
+
return Object.keys(localize);
|
|
3851
|
+
};
|
|
3852
|
+
/**
|
|
3853
|
+
* Check if a locale is supported
|
|
3854
|
+
* @param locale - The locale to check
|
|
3855
|
+
* @returns Boolean indicating if the locale is supported
|
|
3856
|
+
*/
|
|
3857
|
+
const isLocaleSupported = (locale) => {
|
|
3858
|
+
return locale in localize;
|
|
3859
|
+
};
|
|
3860
|
+
|
|
3681
3861
|
const idPickerSanityCheck = (column, foreign_key) => {
|
|
3682
3862
|
if (!!foreign_key == false) {
|
|
3683
3863
|
throw new Error(`The key foreign_key does not exist in properties of column ${column} when using id-picker.`);
|
|
@@ -3693,7 +3873,7 @@ const idPickerSanityCheck = (column, foreign_key) => {
|
|
|
3693
3873
|
throw new Error(`The key column does not exist in properties of column ${column} when using id-picker.`);
|
|
3694
3874
|
}
|
|
3695
3875
|
};
|
|
3696
|
-
const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, children, order = [], ignore = [], include = [], onSubmit = undefined, rowNumber = undefined, requestOptions = {}, getUpdatedData = () => { }, customErrorRenderer, }) => {
|
|
3876
|
+
const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, children, order = [], ignore = [], include = [], onSubmit = undefined, rowNumber = undefined, requestOptions = {}, getUpdatedData = () => { }, customErrorRenderer, validationLocale = 'en', }) => {
|
|
3697
3877
|
const [isSuccess, setIsSuccess] = useState(false);
|
|
3698
3878
|
const [isError, setIsError] = useState(false);
|
|
3699
3879
|
const [isSubmiting, setIsSubmiting] = useState(false);
|
|
@@ -3727,6 +3907,7 @@ const FormRoot = ({ schema, idMap, setIdMap, form, serverUrl, translate, childre
|
|
|
3727
3907
|
setError,
|
|
3728
3908
|
getUpdatedData,
|
|
3729
3909
|
customErrorRenderer,
|
|
3910
|
+
validationLocale,
|
|
3730
3911
|
}, children: jsx(FormProvider, { ...form, children: children }) }));
|
|
3731
3912
|
};
|
|
3732
3913
|
|
|
@@ -3800,27 +3981,14 @@ const CustomInput = ({ column, schema, prefix }) => {
|
|
|
3800
3981
|
}));
|
|
3801
3982
|
};
|
|
3802
3983
|
|
|
3803
|
-
const monthNamesShort = [
|
|
3804
|
-
"Jan",
|
|
3805
|
-
"Feb",
|
|
3806
|
-
"Mar",
|
|
3807
|
-
"Apr",
|
|
3808
|
-
"May",
|
|
3809
|
-
"Jun",
|
|
3810
|
-
"Jul",
|
|
3811
|
-
"Aug",
|
|
3812
|
-
"Sep",
|
|
3813
|
-
"Oct",
|
|
3814
|
-
"Nov",
|
|
3815
|
-
"Dec",
|
|
3816
|
-
];
|
|
3817
|
-
const weekdayNamesShort = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
3818
3984
|
const Calendar = ({ calendars, getBackProps, getForwardProps, getDateProps, firstDayOfWeek = 0, }) => {
|
|
3985
|
+
const { labels } = useContext(DatePickerContext);
|
|
3986
|
+
const { monthNamesShort, weekdayNamesShort, backButtonLabel, forwardButtonLabel } = labels;
|
|
3819
3987
|
if (calendars.length) {
|
|
3820
3988
|
return (jsxs(Grid, { children: [jsxs(Grid, { templateColumns: "repeat(4, auto)", justifyContent: "center", children: [jsx(Button$1, { variant: "ghost", ...getBackProps({
|
|
3821
3989
|
calendars,
|
|
3822
3990
|
offset: 12,
|
|
3823
|
-
}), children: "<<" }), jsx(Button$1, { variant: "ghost", ...getBackProps({ calendars }), children:
|
|
3991
|
+
}), children: "<<" }), jsx(Button$1, { variant: "ghost", ...getBackProps({ calendars }), children: backButtonLabel }), jsx(Button$1, { variant: "ghost", ...getForwardProps({ calendars }), children: forwardButtonLabel }), jsx(Button$1, { variant: "ghost", ...getForwardProps({
|
|
3824
3992
|
calendars,
|
|
3825
3993
|
offset: 12,
|
|
3826
3994
|
}), children: ">>" })] }), jsx(Grid, { templateColumns: "repeat(2, auto)", justifyContent: "center", children: calendars.map((calendar) => (jsxs(Grid, { gap: 4, children: [jsxs(Grid, { justifyContent: "center", children: [monthNamesShort[calendar.month], " ", calendar.year] }), jsxs(Grid, { templateColumns: "repeat(7, auto)", justifyContent: "center", children: [[0, 1, 2, 3, 4, 5, 6].map((weekdayNum) => {
|
|
@@ -3863,9 +4031,52 @@ const Calendar = ({ calendars, getBackProps, getForwardProps, getDateProps, firs
|
|
|
3863
4031
|
}
|
|
3864
4032
|
return null;
|
|
3865
4033
|
};
|
|
4034
|
+
const DatePickerContext = createContext({
|
|
4035
|
+
labels: {
|
|
4036
|
+
monthNamesShort: [
|
|
4037
|
+
"Jan",
|
|
4038
|
+
"Feb",
|
|
4039
|
+
"Mar",
|
|
4040
|
+
"Apr",
|
|
4041
|
+
"May",
|
|
4042
|
+
"Jun",
|
|
4043
|
+
"Jul",
|
|
4044
|
+
"Aug",
|
|
4045
|
+
"Sep",
|
|
4046
|
+
"Oct",
|
|
4047
|
+
"Nov",
|
|
4048
|
+
"Dec",
|
|
4049
|
+
],
|
|
4050
|
+
weekdayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
|
|
4051
|
+
backButtonLabel: "Back",
|
|
4052
|
+
forwardButtonLabel: "Next",
|
|
4053
|
+
},
|
|
4054
|
+
});
|
|
3866
4055
|
let DatePicker$1 = class DatePicker extends React__default.Component {
|
|
3867
4056
|
render() {
|
|
3868
|
-
|
|
4057
|
+
const { labels = {
|
|
4058
|
+
monthNamesShort: [
|
|
4059
|
+
"Jan",
|
|
4060
|
+
"Feb",
|
|
4061
|
+
"Mar",
|
|
4062
|
+
"Apr",
|
|
4063
|
+
"May",
|
|
4064
|
+
"Jun",
|
|
4065
|
+
"Jul",
|
|
4066
|
+
"Aug",
|
|
4067
|
+
"Sep",
|
|
4068
|
+
"Oct",
|
|
4069
|
+
"Nov",
|
|
4070
|
+
"Dec",
|
|
4071
|
+
],
|
|
4072
|
+
weekdayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
|
|
4073
|
+
backButtonLabel: "Back",
|
|
4074
|
+
forwardButtonLabel: "Next",
|
|
4075
|
+
}, } = this.props;
|
|
4076
|
+
return (jsx(DatePickerContext.Provider, { value: { labels }, children: jsx(Dayzed, { onDateSelected: this.props.onDateSelected, selected: this.props.selected, firstDayOfWeek: this.props.firstDayOfWeek, showOutsideDays: this.props.showOutsideDays, date: this.props.date, minDate: this.props.minDate, maxDate: this.props.maxDate, monthsToDisplay: this.props.monthsToDisplay, render:
|
|
4077
|
+
// @ts-expect-error - Dayzed types need to be fixed
|
|
4078
|
+
(dayzedData) => (jsx(Calendar, { ...dayzedData,
|
|
4079
|
+
firstDayOfWeek: this.props.firstDayOfWeek })) }) }));
|
|
3869
4080
|
}
|
|
3870
4081
|
};
|
|
3871
4082
|
|
|
@@ -3887,24 +4098,27 @@ const PopoverRoot = Popover.Root;
|
|
|
3887
4098
|
const PopoverBody = Popover.Body;
|
|
3888
4099
|
const PopoverTrigger = Popover.Trigger;
|
|
3889
4100
|
|
|
4101
|
+
function translateWrapper({ prefix, column, label, translate, }) {
|
|
4102
|
+
return translate.t(removeIndex(`${prefix}${column}.${label}`));
|
|
4103
|
+
}
|
|
4104
|
+
|
|
3890
4105
|
dayjs.extend(utc);
|
|
4106
|
+
dayjs.extend(timezone);
|
|
3891
4107
|
const DatePicker = ({ column, schema, prefix }) => {
|
|
3892
4108
|
const { watch, formState: { errors }, setValue, } = useFormContext();
|
|
3893
|
-
const { translate } = useSchemaContext();
|
|
3894
|
-
const { required, gridColumn = "span 4", gridRow = "span 1", displayDateFormat = "YYYY-MM-DD", dateFormat = "YYYY-MM-DD
|
|
4109
|
+
const { translate, timezone } = useSchemaContext();
|
|
4110
|
+
const { required, gridColumn = "span 4", gridRow = "span 1", displayDateFormat = "YYYY-MM-DD", dateFormat = "YYYY-MM-DD", } = schema;
|
|
3895
4111
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
3896
4112
|
const colLabel = `${prefix}${column}`;
|
|
3897
4113
|
const [open, setOpen] = useState(false);
|
|
3898
4114
|
const selectedDate = watch(colLabel);
|
|
3899
|
-
const displayDate = dayjs
|
|
4115
|
+
const displayDate = dayjs(selectedDate).tz(timezone).format(displayDateFormat);
|
|
3900
4116
|
useEffect(() => {
|
|
3901
4117
|
try {
|
|
3902
4118
|
if (selectedDate) {
|
|
3903
4119
|
// Parse the selectedDate as UTC or in a specific timezone to avoid +8 hour shift
|
|
3904
4120
|
// For example, parse as UTC:
|
|
3905
|
-
const parsedDate = dayjs
|
|
3906
|
-
// Or if you want to parse in local timezone without shifting:
|
|
3907
|
-
// const parsedDate = dayjs.tz(selectedDate, dayjs.tz.guess());
|
|
4121
|
+
const parsedDate = dayjs(selectedDate).tz(timezone);
|
|
3908
4122
|
if (!parsedDate.isValid())
|
|
3909
4123
|
return;
|
|
3910
4124
|
// Format according to dateFormat from schema
|
|
@@ -3922,19 +4136,48 @@ const DatePicker = ({ column, schema, prefix }) => {
|
|
|
3922
4136
|
console.error(e);
|
|
3923
4137
|
}
|
|
3924
4138
|
}, [selectedDate, dateFormat, colLabel, setValue]);
|
|
3925
|
-
|
|
4139
|
+
const customTranslate = (label) => {
|
|
4140
|
+
return translateWrapper({ prefix, column, label, translate });
|
|
4141
|
+
};
|
|
4142
|
+
return (jsxs(Field, { label: `${customTranslate(`field_label`)}`, required: isRequired, alignItems: "stretch", gridColumn,
|
|
3926
4143
|
gridRow, children: [jsxs(PopoverRoot, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, children: [jsx(PopoverTrigger, { asChild: true, children: jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
|
|
3927
4144
|
setOpen(true);
|
|
3928
|
-
}, justifyContent: "start", children: [jsx(MdDateRange, {}), selectedDate !== undefined ? `${displayDate}` : ""] }) }), jsx(PopoverContent, { children: jsxs(PopoverBody, { children: [jsx(PopoverTitle, {}), jsx(DatePicker$1
|
|
3929
|
-
// @ts-expect-error TODO: find appropriate types
|
|
3930
|
-
, {
|
|
3931
|
-
// @ts-expect-error TODO: find appropriate types
|
|
3932
|
-
selected: new Date(selectedDate),
|
|
3933
|
-
// @ts-expect-error TODO: find appropriate types
|
|
3934
|
-
onDateSelected: ({ date }) => {
|
|
4145
|
+
}, justifyContent: "start", children: [jsx(MdDateRange, {}), selectedDate !== undefined ? `${displayDate}` : ""] }) }), jsx(PopoverContent, { children: jsxs(PopoverBody, { children: [jsx(PopoverTitle, {}), jsx(DatePicker$1, { selected: new Date(selectedDate), onDateSelected: ({ date }) => {
|
|
3935
4146
|
setValue(colLabel, dayjs(date).format(dateFormat));
|
|
3936
4147
|
setOpen(false);
|
|
3937
|
-
}
|
|
4148
|
+
}, labels: {
|
|
4149
|
+
monthNamesShort: [
|
|
4150
|
+
translate.t(`common.month_1`, { defaultValue: "January" }),
|
|
4151
|
+
translate.t(`common.month_2`, { defaultValue: "February" }),
|
|
4152
|
+
translate.t(`common.month_3`, { defaultValue: "March" }),
|
|
4153
|
+
translate.t(`common.month_4`, { defaultValue: "April" }),
|
|
4154
|
+
translate.t(`common.month_5`, { defaultValue: "May" }),
|
|
4155
|
+
translate.t(`common.month_6`, { defaultValue: "June" }),
|
|
4156
|
+
translate.t(`common.month_7`, { defaultValue: "July" }),
|
|
4157
|
+
translate.t(`common.month_8`, { defaultValue: "August" }),
|
|
4158
|
+
translate.t(`common.month_9`, { defaultValue: "September" }),
|
|
4159
|
+
translate.t(`common.month_10`, { defaultValue: "October" }),
|
|
4160
|
+
translate.t(`common.month_11`, { defaultValue: "November" }),
|
|
4161
|
+
translate.t(`common.month_12`, { defaultValue: "December" }),
|
|
4162
|
+
],
|
|
4163
|
+
weekdayNamesShort: [
|
|
4164
|
+
translate.t(`common.weekday_1`, { defaultValue: "Sun" }),
|
|
4165
|
+
translate.t(`common.weekday_2`, { defaultValue: "Mon" }),
|
|
4166
|
+
translate.t(`common.weekday_3`, { defaultValue: "Tue" }),
|
|
4167
|
+
translate.t(`common.weekday_4`, {
|
|
4168
|
+
defaultValue: "Wed",
|
|
4169
|
+
}),
|
|
4170
|
+
translate.t(`common.weekday_5`, { defaultValue: "Thu" }),
|
|
4171
|
+
translate.t(`common.weekday_6`, { defaultValue: "Fri" }),
|
|
4172
|
+
translate.t(`common.weekday_7`, { defaultValue: "Sat" }),
|
|
4173
|
+
],
|
|
4174
|
+
backButtonLabel: translate.t(`common.back_button`, {
|
|
4175
|
+
defaultValue: "Back",
|
|
4176
|
+
}),
|
|
4177
|
+
forwardButtonLabel: translate.t(`common.forward_button`, {
|
|
4178
|
+
defaultValue: "Forward",
|
|
4179
|
+
}),
|
|
4180
|
+
} })] }) })] }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: customTranslate(`field_required`) }))] }));
|
|
3938
4181
|
};
|
|
3939
4182
|
|
|
3940
4183
|
function filterArray(array, searchTerm) {
|
|
@@ -4622,7 +4865,7 @@ const IdPicker = ({ column, schema, prefix, isMultiple = false, }) => {
|
|
|
4622
4865
|
|
|
4623
4866
|
const NumberInputRoot = React.forwardRef(function NumberInput$1(props, ref) {
|
|
4624
4867
|
const { children, ...rest } = props;
|
|
4625
|
-
return (
|
|
4868
|
+
return (jsx(NumberInput.Root, { ref: ref, variant: "outline", ...rest, children: children }));
|
|
4626
4869
|
});
|
|
4627
4870
|
const NumberInputField$1 = NumberInput.Input;
|
|
4628
4871
|
NumberInput.Scrubber;
|
|
@@ -4917,22 +5160,23 @@ function TimePicker$1({ hour, setHour, minute, setMinute, meridiem, setMeridiem,
|
|
|
4917
5160
|
return (jsx(Flex, { direction: "column", gap: 3, children: jsxs(Grid, { justifyContent: "center", alignItems: "center", templateColumns: "60px 10px 60px 90px auto", gap: "2", width: "auto", minWidth: "250px", children: [jsx(Input, { ref: hourInputRef, type: "text", value: hour === null ? "" : hour.toString().padStart(2, "0"), onKeyDown: (e) => handleKeyDown(e, "hour"), placeholder: "HH", maxLength: 2, textAlign: "center" }), jsx(Text, { children: ":" }), jsx(Input, { ref: minuteInputRef, type: "text", value: minute === null ? "" : minute.toString().padStart(2, "0"), onKeyDown: (e) => handleKeyDown(e, "minute"), placeholder: "MM", maxLength: 2, textAlign: "center" }), jsxs(Flex, { gap: "1", children: [jsx(Button$1, { size: "sm", colorScheme: meridiem === "am" ? "blue" : "gray", variant: meridiem === "am" ? "solid" : "outline", onClick: () => handleMeridiemClick("am"), width: "40px", children: meridiemLabel.am }), jsx(Button$1, { size: "sm", colorScheme: meridiem === "pm" ? "blue" : "gray", variant: meridiem === "pm" ? "solid" : "outline", onClick: () => handleMeridiemClick("pm"), width: "40px", children: meridiemLabel.pm })] }), jsx(Button$1, { onClick: handleClear, size: "sm", variant: "ghost", children: jsx(MdCancel, {}) })] }) }));
|
|
4918
5161
|
}
|
|
4919
5162
|
|
|
5163
|
+
dayjs.extend(timezone);
|
|
4920
5164
|
const TimePicker = ({ column, schema, prefix }) => {
|
|
4921
5165
|
const { watch, formState: { errors }, setValue, } = useFormContext();
|
|
4922
|
-
const { translate } = useSchemaContext();
|
|
4923
|
-
const { required, gridColumn = "span 4", gridRow = "span 1", timeFormat = "HH:mm:
|
|
5166
|
+
const { translate, timezone } = useSchemaContext();
|
|
5167
|
+
const { required, gridColumn = "span 4", gridRow = "span 1", timeFormat = "HH:mm:ssZ", displayTimeFormat = "hh:mm A", } = schema;
|
|
4924
5168
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
4925
5169
|
const colLabel = `${prefix}${column}`;
|
|
4926
5170
|
const [open, setOpen] = useState(false);
|
|
4927
5171
|
const value = watch(colLabel);
|
|
4928
|
-
const displayedTime = dayjs(`1970-01-01T${value}
|
|
4929
|
-
? dayjs(`1970-01-01T${value}
|
|
5172
|
+
const displayedTime = dayjs(`1970-01-01T${value}`).tz(timezone).isValid()
|
|
5173
|
+
? dayjs(`1970-01-01T${value}`).tz(timezone).format(displayTimeFormat)
|
|
4930
5174
|
: "";
|
|
4931
5175
|
// Parse the initial time parts from the ISO time string (HH:mm:ss)
|
|
4932
5176
|
const parseTime = (isoTime) => {
|
|
4933
5177
|
if (!isoTime)
|
|
4934
5178
|
return { hour: 12, minute: 0, meridiem: "am" };
|
|
4935
|
-
const parsed = dayjs(`1970-01-01T${isoTime}
|
|
5179
|
+
const parsed = dayjs(`1970-01-01T${isoTime}`).tz(timezone);
|
|
4936
5180
|
if (!parsed.isValid())
|
|
4937
5181
|
return { hour: 12, minute: 0, meridiem: "am" };
|
|
4938
5182
|
let hour = parsed.hour();
|
|
@@ -4963,8 +5207,8 @@ const TimePicker = ({ column, schema, prefix }) => {
|
|
|
4963
5207
|
h = 0;
|
|
4964
5208
|
else if (meridiem === "pm" && hour < 12)
|
|
4965
5209
|
h = hour + 12;
|
|
4966
|
-
return dayjs(`1970-01-01T${h.toString().padStart(2, "0")}:${minute.toString().padStart(2, "0")}:
|
|
4967
|
-
.
|
|
5210
|
+
return dayjs(`1970-01-01T${h.toString().padStart(2, "0")}:${minute.toString().padStart(2, "0")}:00`)
|
|
5211
|
+
.tz(timezone)
|
|
4968
5212
|
.format(timeFormat);
|
|
4969
5213
|
};
|
|
4970
5214
|
// Handle changes to time parts
|
|
@@ -4980,11 +5224,289 @@ const TimePicker = ({ column, schema, prefix }) => {
|
|
|
4980
5224
|
gridRow, children: [jsxs(Popover.Root, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, children: [jsx(Popover.Trigger, { asChild: true, children: jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
|
|
4981
5225
|
setOpen(true);
|
|
4982
5226
|
}, justifyContent: "start", children: [jsx(IoMdClock, {}), !!value ? `${displayedTime}` : ""] }) }), jsx(Portal, { children: jsx(Popover.Positioner, { children: jsx(Popover.Content, { ref: containerRef, children: jsx(Popover.Body, { children: jsx(TimePicker$1, { hour: hour, setHour: setHour, minute: minute, setMinute: setMinute, meridiem: meridiem, setMeridiem: setMeridiem, onChange: handleTimeChange, meridiemLabel: {
|
|
4983
|
-
am: translate.t(
|
|
4984
|
-
pm: translate.t(
|
|
5227
|
+
am: translate.t(`common.am`, { defaultValue: "AM" }),
|
|
5228
|
+
pm: translate.t(`common.pm`, { defaultValue: "PM" }),
|
|
4985
5229
|
} }) }) }) }) })] }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }));
|
|
4986
5230
|
};
|
|
4987
5231
|
|
|
5232
|
+
function IsoTimePicker({ hour, setHour, minute, setMinute, second, setSecond, onChange = (_newValue) => { }, }) {
|
|
5233
|
+
// Refs for focus management
|
|
5234
|
+
const hourInputRef = useRef(null);
|
|
5235
|
+
const minuteInputRef = useRef(null);
|
|
5236
|
+
const secondInputRef = useRef(null);
|
|
5237
|
+
// Centralized handler for key events, value changes, and focus management
|
|
5238
|
+
const handleKeyDown = (e, field) => {
|
|
5239
|
+
const input = e.target;
|
|
5240
|
+
const value = input.value;
|
|
5241
|
+
// Handle navigation between fields
|
|
5242
|
+
if (e.key === "Tab") {
|
|
5243
|
+
return;
|
|
5244
|
+
}
|
|
5245
|
+
if (e.key === ":" && field === "hour") {
|
|
5246
|
+
e.preventDefault();
|
|
5247
|
+
minuteInputRef.current?.focus();
|
|
5248
|
+
return;
|
|
5249
|
+
}
|
|
5250
|
+
if (e.key === ":" && field === "minute") {
|
|
5251
|
+
e.preventDefault();
|
|
5252
|
+
secondInputRef.current?.focus();
|
|
5253
|
+
return;
|
|
5254
|
+
}
|
|
5255
|
+
if (e.key === "Backspace" && value === "") {
|
|
5256
|
+
e.preventDefault();
|
|
5257
|
+
if (field === "minute") {
|
|
5258
|
+
hourInputRef.current?.focus();
|
|
5259
|
+
}
|
|
5260
|
+
else if (field === "second") {
|
|
5261
|
+
minuteInputRef.current?.focus();
|
|
5262
|
+
}
|
|
5263
|
+
return;
|
|
5264
|
+
}
|
|
5265
|
+
// Handle number inputs
|
|
5266
|
+
if (field === "hour") {
|
|
5267
|
+
if (e.key.match(/^[0-9]$/)) {
|
|
5268
|
+
const newValue = value + e.key;
|
|
5269
|
+
const numValue = parseInt(newValue, 10);
|
|
5270
|
+
if (numValue > 23) {
|
|
5271
|
+
const digitValue = parseInt(e.key, 10);
|
|
5272
|
+
setHour(digitValue);
|
|
5273
|
+
onChange({ hour: digitValue, minute, second });
|
|
5274
|
+
return;
|
|
5275
|
+
}
|
|
5276
|
+
if (numValue >= 0 && numValue <= 23) {
|
|
5277
|
+
setHour(numValue);
|
|
5278
|
+
onChange({ hour: numValue, minute, second });
|
|
5279
|
+
e.preventDefault();
|
|
5280
|
+
minuteInputRef.current?.focus();
|
|
5281
|
+
}
|
|
5282
|
+
}
|
|
5283
|
+
}
|
|
5284
|
+
else if (field === "minute") {
|
|
5285
|
+
if (e.key.match(/^[0-9]$/)) {
|
|
5286
|
+
const newValue = value + e.key;
|
|
5287
|
+
const numValue = parseInt(newValue, 10);
|
|
5288
|
+
if (numValue > 59) {
|
|
5289
|
+
const digitValue = parseInt(e.key, 10);
|
|
5290
|
+
setMinute(digitValue);
|
|
5291
|
+
onChange({ hour, minute: digitValue, second });
|
|
5292
|
+
return;
|
|
5293
|
+
}
|
|
5294
|
+
if (numValue >= 0 && numValue <= 59) {
|
|
5295
|
+
setMinute(numValue);
|
|
5296
|
+
onChange({ hour, minute: numValue, second });
|
|
5297
|
+
e.preventDefault();
|
|
5298
|
+
secondInputRef.current?.focus();
|
|
5299
|
+
}
|
|
5300
|
+
}
|
|
5301
|
+
}
|
|
5302
|
+
else if (field === "second") {
|
|
5303
|
+
if (e.key.match(/^[0-9]$/)) {
|
|
5304
|
+
const newValue = value + e.key;
|
|
5305
|
+
const numValue = parseInt(newValue, 10);
|
|
5306
|
+
if (numValue > 59) {
|
|
5307
|
+
const digitValue = parseInt(e.key, 10);
|
|
5308
|
+
setSecond(digitValue);
|
|
5309
|
+
onChange({ hour, minute, second: digitValue });
|
|
5310
|
+
return;
|
|
5311
|
+
}
|
|
5312
|
+
if (numValue >= 0 && numValue <= 59) {
|
|
5313
|
+
setSecond(numValue);
|
|
5314
|
+
onChange({ hour, minute, second: numValue });
|
|
5315
|
+
}
|
|
5316
|
+
}
|
|
5317
|
+
}
|
|
5318
|
+
};
|
|
5319
|
+
const handleClear = () => {
|
|
5320
|
+
setHour(null);
|
|
5321
|
+
setMinute(null);
|
|
5322
|
+
setSecond(null);
|
|
5323
|
+
onChange({ hour: null, minute: null, second: null });
|
|
5324
|
+
hourInputRef.current?.focus();
|
|
5325
|
+
};
|
|
5326
|
+
return (jsx(Flex, { direction: "column", gap: 3, children: jsxs(Grid, { justifyContent: "center", alignItems: "center", templateColumns: "60px 10px 60px 10px 60px auto", gap: "2", width: "auto", minWidth: "300px", children: [jsx(Input, { ref: hourInputRef, type: "text", value: hour === null ? "" : hour.toString().padStart(2, "0"), onKeyDown: (e) => handleKeyDown(e, "hour"), placeholder: "HH", maxLength: 2, textAlign: "center" }), jsx(Text, { children: ":" }), jsx(Input, { ref: minuteInputRef, type: "text", value: minute === null ? "" : minute.toString().padStart(2, "0"), onKeyDown: (e) => handleKeyDown(e, "minute"), placeholder: "MM", maxLength: 2, textAlign: "center" }), jsx(Text, { children: ":" }), jsx(Input, { ref: secondInputRef, type: "text", value: second === null ? "" : second.toString().padStart(2, "0"), onKeyDown: (e) => handleKeyDown(e, "second"), placeholder: "SS", maxLength: 2, textAlign: "center" }), jsx(Button$1, { onClick: handleClear, size: "sm", variant: "ghost", children: jsx(MdCancel, {}) })] }) }));
|
|
5327
|
+
}
|
|
5328
|
+
|
|
5329
|
+
function DateTimePicker$1({ value, onChange, format = "date-time", showSeconds = false, labels = {
|
|
5330
|
+
monthNamesShort: [
|
|
5331
|
+
"Jan",
|
|
5332
|
+
"Feb",
|
|
5333
|
+
"Mar",
|
|
5334
|
+
"Apr",
|
|
5335
|
+
"May",
|
|
5336
|
+
"Jun",
|
|
5337
|
+
"Jul",
|
|
5338
|
+
"Aug",
|
|
5339
|
+
"Sep",
|
|
5340
|
+
"Oct",
|
|
5341
|
+
"Nov",
|
|
5342
|
+
"Dec",
|
|
5343
|
+
],
|
|
5344
|
+
weekdayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
|
|
5345
|
+
backButtonLabel: "Back",
|
|
5346
|
+
forwardButtonLabel: "Next",
|
|
5347
|
+
}, timezone = "Asia/Hong_Kong", }) {
|
|
5348
|
+
const [selectedDate, setSelectedDate] = useState(value || "");
|
|
5349
|
+
// Time state for 12-hour format
|
|
5350
|
+
const [hour12, setHour12] = useState(value ? dayjs(value).hour() % 12 || 12 : null);
|
|
5351
|
+
const [minute, setMinute] = useState(value ? dayjs(value).minute() : null);
|
|
5352
|
+
const [meridiem, setMeridiem] = useState(value ? (dayjs(value).hour() >= 12 ? "pm" : "am") : null);
|
|
5353
|
+
// Time state for 24-hour format
|
|
5354
|
+
const [hour24, setHour24] = useState(value ? dayjs(value).hour() : null);
|
|
5355
|
+
const [second, setSecond] = useState(value ? dayjs(value).second() : null);
|
|
5356
|
+
const handleDateChange = (date) => {
|
|
5357
|
+
setSelectedDate(date);
|
|
5358
|
+
updateDateTime(dayjs(date).tz(timezone).toISOString());
|
|
5359
|
+
};
|
|
5360
|
+
const handleTimeChange = (timeData) => {
|
|
5361
|
+
if (format === "iso-date-time") {
|
|
5362
|
+
setHour24(timeData.hour);
|
|
5363
|
+
setMinute(timeData.minute);
|
|
5364
|
+
if (showSeconds)
|
|
5365
|
+
setSecond(timeData.second);
|
|
5366
|
+
}
|
|
5367
|
+
else {
|
|
5368
|
+
setHour12(timeData.hour);
|
|
5369
|
+
setMinute(timeData.minute);
|
|
5370
|
+
setMeridiem(timeData.meridiem);
|
|
5371
|
+
}
|
|
5372
|
+
updateDateTime(dayjs(selectedDate).tz(timezone).toISOString(), timeData);
|
|
5373
|
+
};
|
|
5374
|
+
const updateDateTime = (date, timeData) => {
|
|
5375
|
+
if (!date) {
|
|
5376
|
+
onChange?.(undefined);
|
|
5377
|
+
return;
|
|
5378
|
+
}
|
|
5379
|
+
// use dayjs to convert the date to the timezone
|
|
5380
|
+
const newDate = dayjs(date).tz(timezone).toDate();
|
|
5381
|
+
if (format === "iso-date-time") {
|
|
5382
|
+
const h = timeData?.hour ?? hour24;
|
|
5383
|
+
const m = timeData?.minute ?? minute;
|
|
5384
|
+
const s = showSeconds ? timeData?.second ?? second : 0;
|
|
5385
|
+
if (h !== null)
|
|
5386
|
+
newDate.setHours(h);
|
|
5387
|
+
if (m !== null)
|
|
5388
|
+
newDate.setMinutes(m);
|
|
5389
|
+
if (s !== null)
|
|
5390
|
+
newDate.setSeconds(s);
|
|
5391
|
+
}
|
|
5392
|
+
else {
|
|
5393
|
+
const h = timeData?.hour ?? hour12;
|
|
5394
|
+
const m = timeData?.minute ?? minute;
|
|
5395
|
+
const mer = timeData?.meridiem ?? meridiem;
|
|
5396
|
+
if (h !== null && mer !== null) {
|
|
5397
|
+
let hour24 = h;
|
|
5398
|
+
if (mer === "am" && h === 12)
|
|
5399
|
+
hour24 = 0;
|
|
5400
|
+
else if (mer === "pm" && h < 12)
|
|
5401
|
+
hour24 = h + 12;
|
|
5402
|
+
newDate.setHours(hour24);
|
|
5403
|
+
}
|
|
5404
|
+
if (m !== null)
|
|
5405
|
+
newDate.setMinutes(m);
|
|
5406
|
+
newDate.setSeconds(0);
|
|
5407
|
+
}
|
|
5408
|
+
onChange?.(dayjs(newDate).tz(timezone).toISOString());
|
|
5409
|
+
};
|
|
5410
|
+
const handleClear = () => {
|
|
5411
|
+
setSelectedDate("");
|
|
5412
|
+
setHour12(null);
|
|
5413
|
+
setHour24(null);
|
|
5414
|
+
setMinute(null);
|
|
5415
|
+
setSecond(null);
|
|
5416
|
+
setMeridiem(null);
|
|
5417
|
+
onChange?.(undefined);
|
|
5418
|
+
};
|
|
5419
|
+
const isISO = format === "iso-date-time";
|
|
5420
|
+
return (jsxs(Flex, { direction: "column", gap: 4, p: 4, border: "1px solid", borderColor: "gray.200", borderRadius: "md", children: [jsx(DatePicker$1, { selected: selectedDate
|
|
5421
|
+
? dayjs(selectedDate).tz(timezone).toDate()
|
|
5422
|
+
: new Date(), onDateSelected: ({ date }) => handleDateChange(dayjs(date).tz(timezone).toISOString()), monthsToDisplay: 1, labels: labels }), jsxs(Grid, { templateColumns: "1fr auto", alignItems: "center", gap: 4, children: [isISO ? (jsx(IsoTimePicker, { hour: hour24, setHour: setHour24, minute: minute, setMinute: setMinute, second: second, setSecond: setSecond, onChange: handleTimeChange })) : (jsx(TimePicker$1, { hour: hour12, setHour: setHour12, minute: minute, setMinute: setMinute, meridiem: meridiem, setMeridiem: setMeridiem, onChange: handleTimeChange })), jsx(Button$1, { onClick: handleClear, size: "sm", variant: "outline", colorScheme: "red", children: jsx(Icon, { as: FaTrash }) })] }), selectedDate && (jsxs(Flex, { gap: 2, children: [jsx(Text, { fontSize: "sm", color: { base: "gray.600", _dark: "gray.600" }, children: dayjs(value).format(isISO
|
|
5423
|
+
? showSeconds
|
|
5424
|
+
? "YYYY-MM-DD HH:mm:ss"
|
|
5425
|
+
: "YYYY-MM-DD HH:mm"
|
|
5426
|
+
: "YYYY-MM-DD hh:mm A ") }), jsx(Text, { fontSize: "sm", color: { base: "gray.600", _dark: "gray.600" }, children: dayjs(value).tz(timezone).format("Z") }), jsx(Text, { fontSize: "sm", color: { base: "gray.600", _dark: "gray.600" }, children: timezone })] }))] }));
|
|
5427
|
+
}
|
|
5428
|
+
|
|
5429
|
+
dayjs.extend(utc);
|
|
5430
|
+
dayjs.extend(timezone);
|
|
5431
|
+
const DateTimePicker = ({ column, schema, prefix, }) => {
|
|
5432
|
+
const { watch, formState: { errors }, setValue, } = useFormContext();
|
|
5433
|
+
const { translate, timezone } = useSchemaContext();
|
|
5434
|
+
const { required, gridColumn = "span 4", gridRow = "span 1", displayDateFormat = "YYYY-MM-DD HH:mm:ss",
|
|
5435
|
+
// with timezone
|
|
5436
|
+
dateFormat = "YYYY-MM-DD[T]HH:mm:ssZ", } = schema;
|
|
5437
|
+
const isRequired = required?.some((columnId) => columnId === column);
|
|
5438
|
+
const colLabel = `${prefix}${column}`;
|
|
5439
|
+
const [open, setOpen] = useState(false);
|
|
5440
|
+
const selectedDate = watch(colLabel);
|
|
5441
|
+
const displayDate = dayjs(selectedDate)
|
|
5442
|
+
.tz(timezone)
|
|
5443
|
+
.format(displayDateFormat);
|
|
5444
|
+
useEffect(() => {
|
|
5445
|
+
try {
|
|
5446
|
+
if (selectedDate) {
|
|
5447
|
+
// Parse the selectedDate as UTC or in a specific timezone to avoid +8 hour shift
|
|
5448
|
+
// For example, parse as UTC:
|
|
5449
|
+
const parsedDate = dayjs(selectedDate).tz(timezone);
|
|
5450
|
+
if (!parsedDate.isValid())
|
|
5451
|
+
return;
|
|
5452
|
+
// Format according to dateFormat from schema
|
|
5453
|
+
const formatted = parsedDate.format(dateFormat);
|
|
5454
|
+
// Update the form value only if different to avoid loops
|
|
5455
|
+
if (formatted !== selectedDate) {
|
|
5456
|
+
setValue(colLabel, formatted, {
|
|
5457
|
+
shouldValidate: true,
|
|
5458
|
+
shouldDirty: true,
|
|
5459
|
+
});
|
|
5460
|
+
}
|
|
5461
|
+
}
|
|
5462
|
+
}
|
|
5463
|
+
catch (e) {
|
|
5464
|
+
console.error(e);
|
|
5465
|
+
}
|
|
5466
|
+
}, [selectedDate, dateFormat, colLabel, setValue]);
|
|
5467
|
+
const customTranslate = (label) => {
|
|
5468
|
+
return translateWrapper({ prefix, column, label, translate });
|
|
5469
|
+
};
|
|
5470
|
+
return (jsxs(Field, { label: `${customTranslate(`field_label`)}`, required: isRequired, alignItems: "stretch", gridColumn,
|
|
5471
|
+
gridRow, children: [jsxs(PopoverRoot, { open: open, onOpenChange: (e) => setOpen(e.open), closeOnInteractOutside: true, children: [jsx(PopoverTrigger, { asChild: true, children: jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
|
|
5472
|
+
setOpen(true);
|
|
5473
|
+
}, justifyContent: "start", children: [jsx(MdDateRange, {}), selectedDate !== undefined ? `${displayDate}` : ""] }) }), jsx(PopoverContent, { minW: "450px", children: jsxs(PopoverBody, { children: [jsx(PopoverTitle, {}), jsx(DateTimePicker$1, { value: selectedDate, onChange: (date) => {
|
|
5474
|
+
setValue(colLabel, dayjs(date).tz(timezone).format(dateFormat));
|
|
5475
|
+
}, timezone: timezone, labels: {
|
|
5476
|
+
monthNamesShort: [
|
|
5477
|
+
translate.t(`common.month_1`, { defaultValue: "January" }),
|
|
5478
|
+
translate.t(`common.month_2`, { defaultValue: "February" }),
|
|
5479
|
+
translate.t(`common.month_3`, { defaultValue: "March" }),
|
|
5480
|
+
translate.t(`common.month_4`, { defaultValue: "April" }),
|
|
5481
|
+
translate.t(`common.month_5`, { defaultValue: "May" }),
|
|
5482
|
+
translate.t(`common.month_6`, { defaultValue: "June" }),
|
|
5483
|
+
translate.t(`common.month_7`, { defaultValue: "July" }),
|
|
5484
|
+
translate.t(`common.month_8`, { defaultValue: "August" }),
|
|
5485
|
+
translate.t(`common.month_9`, { defaultValue: "September" }),
|
|
5486
|
+
translate.t(`common.month_10`, { defaultValue: "October" }),
|
|
5487
|
+
translate.t(`common.month_11`, { defaultValue: "November" }),
|
|
5488
|
+
translate.t(`common.month_12`, { defaultValue: "December" }),
|
|
5489
|
+
],
|
|
5490
|
+
weekdayNamesShort: [
|
|
5491
|
+
translate.t(`common.weekday_1`, { defaultValue: "Sun" }),
|
|
5492
|
+
translate.t(`common.weekday_2`, { defaultValue: "Mon" }),
|
|
5493
|
+
translate.t(`common.weekday_3`, { defaultValue: "Tue" }),
|
|
5494
|
+
translate.t(`common.weekday_4`, {
|
|
5495
|
+
defaultValue: "Wed",
|
|
5496
|
+
}),
|
|
5497
|
+
translate.t(`common.weekday_5`, { defaultValue: "Thu" }),
|
|
5498
|
+
translate.t(`common.weekday_6`, { defaultValue: "Fri" }),
|
|
5499
|
+
translate.t(`common.weekday_7`, { defaultValue: "Sat" }),
|
|
5500
|
+
],
|
|
5501
|
+
backButtonLabel: translate.t(`common.back_button`, {
|
|
5502
|
+
defaultValue: "Back",
|
|
5503
|
+
}),
|
|
5504
|
+
forwardButtonLabel: translate.t(`common.forward_button`, {
|
|
5505
|
+
defaultValue: "Forward",
|
|
5506
|
+
}),
|
|
5507
|
+
} })] }) })] }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: customTranslate(`field_required`) }))] }));
|
|
5508
|
+
};
|
|
5509
|
+
|
|
4988
5510
|
const SchemaRenderer = ({ schema, prefix, column, }) => {
|
|
4989
5511
|
const colSchema = schema;
|
|
4990
5512
|
const { type, variant, properties: innerProperties, foreign_key, format, items, } = schema;
|
|
@@ -5005,6 +5527,9 @@ const SchemaRenderer = ({ schema, prefix, column, }) => {
|
|
|
5005
5527
|
if (format === "time") {
|
|
5006
5528
|
return jsx(TimePicker, { schema: colSchema, prefix, column });
|
|
5007
5529
|
}
|
|
5530
|
+
if (format === "date-time") {
|
|
5531
|
+
return jsx(DateTimePicker, { schema: colSchema, prefix, column });
|
|
5532
|
+
}
|
|
5008
5533
|
if (variant === "text-area") {
|
|
5009
5534
|
return jsx(TextAreaInput, { schema: colSchema, prefix, column });
|
|
5010
5535
|
}
|
|
@@ -5096,20 +5621,16 @@ const CustomViewer = ({ column, schema, prefix }) => {
|
|
|
5096
5621
|
|
|
5097
5622
|
const DateViewer = ({ column, schema, prefix }) => {
|
|
5098
5623
|
const { watch, formState: { errors }, } = useFormContext();
|
|
5099
|
-
const { translate } = useSchemaContext();
|
|
5624
|
+
const { translate, timezone } = useSchemaContext();
|
|
5100
5625
|
const { required, gridColumn = "span 4", gridRow = "span 1", displayDateFormat = "YYYY-MM-DD", } = schema;
|
|
5101
5626
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
5102
5627
|
const colLabel = `${prefix}${column}`;
|
|
5103
5628
|
const selectedDate = watch(colLabel);
|
|
5104
|
-
const displayDate = dayjs
|
|
5629
|
+
const displayDate = dayjs(selectedDate).tz(timezone).format(displayDateFormat);
|
|
5105
5630
|
return (jsxs(Field, { label: `${translate.t(removeIndex(`${column}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
|
|
5106
5631
|
gridRow, children: [jsxs(Text, { children: [" ", selectedDate !== undefined ? displayDate : ""] }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(`${column}.field_required`) }))] }));
|
|
5107
5632
|
};
|
|
5108
5633
|
|
|
5109
|
-
function translateWrapper({ prefix, column, label, translate, }) {
|
|
5110
|
-
return translate.t(removeIndex(`${prefix}${column}.${label}`));
|
|
5111
|
-
}
|
|
5112
|
-
|
|
5113
5634
|
const EnumViewer = ({ column, isMultiple = false, schema, prefix, }) => {
|
|
5114
5635
|
const { watch, formState: { errors }, } = useFormContext();
|
|
5115
5636
|
const { translate } = useSchemaContext();
|
|
@@ -5365,20 +5886,34 @@ const TextAreaViewer = ({ column, schema, prefix, }) => {
|
|
|
5365
5886
|
return (jsx(Fragment, { children: jsxs(Field, { label: `${translate.t(removeIndex(`${colLabel}.field_label`))}`, required: isRequired, gridColumn: gridColumn, gridRow: gridRow, children: [jsx(Text, { whiteSpace: "pre-wrap", children: value }), " ", errors[colLabel] && (jsx(Text, { color: "red.400", children: translate.t(removeIndex(`${colLabel}.field_required`)) }))] }) }));
|
|
5366
5887
|
};
|
|
5367
5888
|
|
|
5368
|
-
const TimeViewer = ({ column, schema, prefix
|
|
5889
|
+
const TimeViewer = ({ column, schema, prefix }) => {
|
|
5369
5890
|
const { watch, formState: { errors }, } = useFormContext();
|
|
5370
|
-
const { translate } = useSchemaContext();
|
|
5371
|
-
const { required, gridColumn = "span 4", gridRow = "span 1", displayTimeFormat = "hh:mm A" } = schema;
|
|
5891
|
+
const { translate, timezone } = useSchemaContext();
|
|
5892
|
+
const { required, gridColumn = "span 4", gridRow = "span 1", displayTimeFormat = "hh:mm A", } = schema;
|
|
5372
5893
|
const isRequired = required?.some((columnId) => columnId === column);
|
|
5373
5894
|
const colLabel = `${prefix}${column}`;
|
|
5374
5895
|
const selectedDate = watch(colLabel);
|
|
5375
|
-
const displayedTime = dayjs(`1970-01-01T${selectedDate}
|
|
5376
|
-
|
|
5896
|
+
const displayedTime = dayjs(`1970-01-01T${selectedDate}`)
|
|
5897
|
+
.tz(timezone)
|
|
5898
|
+
.isValid()
|
|
5899
|
+
? dayjs(`1970-01-01T${selectedDate}`).tz(timezone).format(displayTimeFormat)
|
|
5377
5900
|
: "";
|
|
5378
5901
|
return (jsxs(Field, { label: `${translate.t(removeIndex(`${column}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
|
|
5379
5902
|
gridRow, children: [jsx(Text, { children: displayedTime }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(`${column}.field_required`) }))] }));
|
|
5380
5903
|
};
|
|
5381
5904
|
|
|
5905
|
+
const DateTimeViewer = ({ column, schema, prefix }) => {
|
|
5906
|
+
const { watch, formState: { errors }, } = useFormContext();
|
|
5907
|
+
const { translate, timezone } = useSchemaContext();
|
|
5908
|
+
const { required, gridColumn = "span 4", gridRow = "span 1", displayDateFormat = "YYYY-MM-DD HH:mm:ss", } = schema;
|
|
5909
|
+
const isRequired = required?.some((columnId) => columnId === column);
|
|
5910
|
+
const colLabel = `${prefix}${column}`;
|
|
5911
|
+
const selectedDate = watch(colLabel);
|
|
5912
|
+
const displayDate = dayjs(selectedDate).tz(timezone).format(displayDateFormat);
|
|
5913
|
+
return (jsxs(Field, { label: `${translate.t(removeIndex(`${column}.field_label`))}`, required: isRequired, alignItems: "stretch", gridColumn,
|
|
5914
|
+
gridRow, children: [jsxs(Text, { children: [" ", selectedDate !== undefined ? displayDate : ""] }), errors[`${column}`] && (jsx(Text, { color: "red.400", children: translate.t(`${column}.field_required`) }))] }));
|
|
5915
|
+
};
|
|
5916
|
+
|
|
5382
5917
|
const SchemaViewer = ({ schema, prefix, column, }) => {
|
|
5383
5918
|
const colSchema = schema;
|
|
5384
5919
|
const { type, variant, properties: innerProperties, foreign_key, items, format, } = schema;
|
|
@@ -5399,6 +5934,9 @@ const SchemaViewer = ({ schema, prefix, column, }) => {
|
|
|
5399
5934
|
if (format === "date") {
|
|
5400
5935
|
return jsx(DateViewer, { schema: colSchema, prefix, column });
|
|
5401
5936
|
}
|
|
5937
|
+
if (format === "date-time") {
|
|
5938
|
+
return jsx(DateTimeViewer, { schema: colSchema, prefix, column });
|
|
5939
|
+
}
|
|
5402
5940
|
if (variant === "text-area") {
|
|
5403
5941
|
return jsx(TextAreaViewer, { schema: colSchema, prefix, column });
|
|
5404
5942
|
}
|
|
@@ -5450,10 +5988,28 @@ const ColumnViewer = ({ column, properties, prefix, }) => {
|
|
|
5450
5988
|
};
|
|
5451
5989
|
|
|
5452
5990
|
const SubmitButton = () => {
|
|
5453
|
-
const { translate, setValidatedData, setIsError, setIsConfirming } = useSchemaContext();
|
|
5991
|
+
const { translate, setValidatedData, setIsError, setIsConfirming, setError, schema, validationLocale } = useSchemaContext();
|
|
5454
5992
|
const methods = useFormContext();
|
|
5455
5993
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5456
5994
|
const onValid = (data) => {
|
|
5995
|
+
// Validate data using AJV before proceeding to confirmation
|
|
5996
|
+
const validationResult = validateData(data, schema, { locale: validationLocale });
|
|
5997
|
+
if (!validationResult.isValid) {
|
|
5998
|
+
// Set validation errors with i18n support
|
|
5999
|
+
const validationErrorMessage = {
|
|
6000
|
+
type: 'validation',
|
|
6001
|
+
errors: validationResult.errors,
|
|
6002
|
+
message: validationLocale === 'zh-HK' || validationLocale === 'zh-TW'
|
|
6003
|
+
? '表單驗證失敗'
|
|
6004
|
+
: validationLocale === 'zh-CN' || validationLocale === 'zh'
|
|
6005
|
+
? '表单验证失败'
|
|
6006
|
+
: 'Form validation failed'
|
|
6007
|
+
};
|
|
6008
|
+
setError(validationErrorMessage);
|
|
6009
|
+
setIsError(true);
|
|
6010
|
+
return;
|
|
6011
|
+
}
|
|
6012
|
+
// If validation passes, proceed to confirmation
|
|
5457
6013
|
setValidatedData(data);
|
|
5458
6014
|
setIsError(false);
|
|
5459
6015
|
setIsConfirming(true);
|
|
@@ -5464,7 +6020,7 @@ const SubmitButton = () => {
|
|
|
5464
6020
|
};
|
|
5465
6021
|
|
|
5466
6022
|
const FormBody = () => {
|
|
5467
|
-
const { schema, requestUrl, order, ignore, include, onSubmit, rowNumber, translate, requestOptions, isSuccess, setIsSuccess, isError, setIsError, isSubmiting, setIsSubmiting, isConfirming, setIsConfirming, validatedData, setValidatedData, error, setError, getUpdatedData, customErrorRenderer, } = useSchemaContext();
|
|
6023
|
+
const { schema, requestUrl, order, ignore, include, onSubmit, rowNumber, translate, requestOptions, isSuccess, setIsSuccess, isError, setIsError, isSubmiting, setIsSubmiting, isConfirming, setIsConfirming, validatedData, setValidatedData, error, setError, getUpdatedData, customErrorRenderer, validationLocale, } = useSchemaContext();
|
|
5468
6024
|
const methods = useFormContext();
|
|
5469
6025
|
const { properties } = schema;
|
|
5470
6026
|
const onBeforeSubmit = () => {
|
|
@@ -5480,6 +6036,27 @@ const FormBody = () => {
|
|
|
5480
6036
|
const onSubmitSuccess = () => {
|
|
5481
6037
|
setIsSuccess(true);
|
|
5482
6038
|
};
|
|
6039
|
+
// Enhanced validation function using AJV with i18n support
|
|
6040
|
+
const validateFormData = (data) => {
|
|
6041
|
+
try {
|
|
6042
|
+
const validationResult = validateData(data, schema, { locale: validationLocale });
|
|
6043
|
+
return validationResult;
|
|
6044
|
+
}
|
|
6045
|
+
catch (error) {
|
|
6046
|
+
const errorMessage = validationLocale === 'zh-HK' || validationLocale === 'zh-TW'
|
|
6047
|
+
? `驗證錯誤: ${error instanceof Error ? error.message : '未知驗證錯誤'}`
|
|
6048
|
+
: validationLocale === 'zh-CN' || validationLocale === 'zh'
|
|
6049
|
+
? `验证错误: ${error instanceof Error ? error.message : '未知验证错误'}`
|
|
6050
|
+
: `Validation error: ${error instanceof Error ? error.message : 'Unknown validation error'}`;
|
|
6051
|
+
return {
|
|
6052
|
+
isValid: false,
|
|
6053
|
+
errors: [{
|
|
6054
|
+
field: 'validation',
|
|
6055
|
+
message: errorMessage
|
|
6056
|
+
}]
|
|
6057
|
+
};
|
|
6058
|
+
}
|
|
6059
|
+
};
|
|
5483
6060
|
const defaultOnSubmit = async (promise) => {
|
|
5484
6061
|
try {
|
|
5485
6062
|
onBeforeSubmit();
|
|
@@ -5504,12 +6081,47 @@ const FormBody = () => {
|
|
|
5504
6081
|
};
|
|
5505
6082
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5506
6083
|
const onFormSubmit = async (data) => {
|
|
6084
|
+
// Validate data using AJV before submission
|
|
6085
|
+
const validationResult = validateFormData(data);
|
|
6086
|
+
if (!validationResult.isValid) {
|
|
6087
|
+
// Set validation errors
|
|
6088
|
+
const validationErrorMessage = {
|
|
6089
|
+
type: 'validation',
|
|
6090
|
+
errors: validationResult.errors,
|
|
6091
|
+
message: validationLocale === 'zh-HK' || validationLocale === 'zh-TW'
|
|
6092
|
+
? '表單驗證失敗'
|
|
6093
|
+
: validationLocale === 'zh-CN' || validationLocale === 'zh'
|
|
6094
|
+
? '表单验证失败'
|
|
6095
|
+
: 'Form validation failed'
|
|
6096
|
+
};
|
|
6097
|
+
onSubmitError(validationErrorMessage);
|
|
6098
|
+
return;
|
|
6099
|
+
}
|
|
5507
6100
|
if (onSubmit === undefined) {
|
|
5508
6101
|
await defaultOnSubmit(defaultSubmitPromise(data));
|
|
5509
6102
|
return;
|
|
5510
6103
|
}
|
|
5511
6104
|
await defaultOnSubmit(onSubmit(data));
|
|
5512
6105
|
};
|
|
6106
|
+
// Custom error renderer for validation errors with i18n support
|
|
6107
|
+
const renderValidationErrors = (validationErrors) => {
|
|
6108
|
+
const title = validationLocale === 'zh-HK' || validationLocale === 'zh-TW'
|
|
6109
|
+
? `表單驗證失敗 (${validationErrors.length} 個錯誤${validationErrors.length > 1 ? '' : ''})`
|
|
6110
|
+
: validationLocale === 'zh-CN' || validationLocale === 'zh'
|
|
6111
|
+
? `表单验证失败 (${validationErrors.length} 个错误${validationErrors.length > 1 ? '' : ''})`
|
|
6112
|
+
: `Form Validation Failed (${validationErrors.length} error${validationErrors.length > 1 ? 's' : ''})`;
|
|
6113
|
+
const formLabel = validationLocale === 'zh-HK' || validationLocale === 'zh-TW'
|
|
6114
|
+
? '表單'
|
|
6115
|
+
: validationLocale === 'zh-CN' || validationLocale === 'zh'
|
|
6116
|
+
? '表单'
|
|
6117
|
+
: 'Form';
|
|
6118
|
+
const currentValueLabel = validationLocale === 'zh-HK' || validationLocale === 'zh-TW'
|
|
6119
|
+
? '目前值:'
|
|
6120
|
+
: validationLocale === 'zh-CN' || validationLocale === 'zh'
|
|
6121
|
+
? '当前值:'
|
|
6122
|
+
: 'Current value:';
|
|
6123
|
+
return (jsxs(Alert.Root, { status: "error", children: [jsx(Alert.Indicator, {}), jsx(Alert.Title, { children: jsx(AccordionRoot, { collapsible: true, defaultValue: [], children: jsxs(AccordionItem, { value: "validation-errors", children: [jsx(AccordionItemTrigger, { children: title }), jsx(AccordionItemContent, { children: jsx(Box, { mt: 2, children: validationErrors.map((err, index) => (jsxs(Box, { mb: 2, p: 2, bg: "red.50", borderLeft: "4px solid", borderColor: "red.500", children: [jsxs(Text, { fontWeight: "bold", color: "red.700", children: [err.field === 'root' ? formLabel : err.field, ":"] }), jsx(Text, { color: "red.600", children: err.message }), err.value !== undefined && (jsxs(Text, { fontSize: "sm", color: "red.500", mt: 1, children: [currentValueLabel, " ", JSON.stringify(err.value)] }))] }, index))) }) })] }) }) })] }));
|
|
6124
|
+
};
|
|
5513
6125
|
const renderColumns = ({ order, keys, ignore, include, }) => {
|
|
5514
6126
|
const included = include.length > 0 ? include : keys;
|
|
5515
6127
|
const not_exist = included.filter((columnA) => !order.some((columnB) => columnA === columnB));
|
|
@@ -5545,7 +6157,7 @@ const FormBody = () => {
|
|
|
5545
6157
|
setIsConfirming(false);
|
|
5546
6158
|
}, variant: "subtle", children: translate.t("cancel") }), jsx(Button$1, { onClick: () => {
|
|
5547
6159
|
onFormSubmit(validatedData);
|
|
5548
|
-
}, children: translate.t("confirm") })] }), isSubmiting && (jsx(Box, { pos: "absolute", inset: "0", bg: "bg/80", children: jsx(Center, { h: "full", children: jsx(Spinner, { color: "teal.500" }) }) })), isError && (jsx(Fragment, { children: customErrorRenderer ? (customErrorRenderer(error)) : (jsx(Alert.Root, { status: "error", children: jsx(Alert.Title, { children: jsx(AccordionRoot, { collapsible: true, defaultValue: [], children: jsxs(AccordionItem, { value: "b", children: [jsxs(AccordionItemTrigger, { children: [jsx(Alert.Indicator, {}), `${error}`] }), jsx(AccordionItemContent, { children: `${JSON.stringify(error)}` })] }) }) }) })) }))] }));
|
|
6160
|
+
}, children: translate.t("confirm") })] }), isSubmiting && (jsx(Box, { pos: "absolute", inset: "0", bg: "bg/80", children: jsx(Center, { h: "full", children: jsx(Spinner, { color: "teal.500" }) }) })), isError && (jsx(Fragment, { children: customErrorRenderer ? (customErrorRenderer(error)) : (jsx(Fragment, { children: error?.type === 'validation' && error?.errors ? (renderValidationErrors(error.errors)) : (jsx(Alert.Root, { status: "error", children: jsx(Alert.Title, { children: jsx(AccordionRoot, { collapsible: true, defaultValue: [], children: jsxs(AccordionItem, { value: "b", children: [jsxs(AccordionItemTrigger, { children: [jsx(Alert.Indicator, {}), `${error}`] }), jsx(AccordionItemContent, { children: `${JSON.stringify(error)}` })] }) }) }) })) })) }))] }));
|
|
5549
6161
|
}
|
|
5550
6162
|
return (jsxs(Flex, { flexFlow: "column", gap: "2", children: [jsx(Grid, { gap: "4", gridTemplateColumns: "repeat(12, 1fr)", autoFlow: "row", children: ordered.map((column) => {
|
|
5551
6163
|
return (jsx(ColumnRenderer
|
|
@@ -5555,7 +6167,7 @@ const FormBody = () => {
|
|
|
5555
6167
|
properties: properties, prefix: ``, column }, `form-input-${column}`));
|
|
5556
6168
|
}) }), jsxs(Flex, { justifyContent: "end", gap: "2", children: [jsx(Button$1, { onClick: () => {
|
|
5557
6169
|
methods.reset();
|
|
5558
|
-
}, variant: "subtle", children: translate.t("reset") }), jsx(SubmitButton, {})] })] }));
|
|
6170
|
+
}, variant: "subtle", children: translate.t("reset") }), jsx(SubmitButton, {})] }), isError && error?.type === 'validation' && (jsx(Box, { mt: 4, children: error?.errors && renderValidationErrors(error.errors) }))] }));
|
|
5559
6171
|
};
|
|
5560
6172
|
|
|
5561
6173
|
const FormTitle = () => {
|
|
@@ -5597,4 +6209,4 @@ const getMultiDates = ({ selected, selectedDate, selectedDates, selectable, }) =
|
|
|
5597
6209
|
}
|
|
5598
6210
|
};
|
|
5599
6211
|
|
|
5600
|
-
export { CardHeader, DataDisplay, DataTable, DataTableServer, DefaultCardTitle, DefaultForm, DefaultTable, DensityToggleButton, EditSortingButton, EmptyState$1 as EmptyState, ErrorAlert, FilterDialog, FormBody, FormRoot, FormTitle, GlobalFilter, PageSizeControl, Pagination, RecordDisplay, ReloadButton, ResetFilteringButton, ResetSelectionButton, ResetSortingButton, RowCountText, Table, TableBody, TableCardContainer, TableCards, TableComponent, TableControls, TableDataDisplay, TableFilter, TableFilterTags, TableFooter, TableHeader, TableLoadingComponent, TableSelector, TableSorter, TableViewer, TextCell, ViewDialog, getColumns, getMultiDates, getRangeDates, idPickerSanityCheck, useDataTable, useDataTableContext, useDataTableServer, useForm, widthSanityCheck };
|
|
6212
|
+
export { CardHeader, DataDisplay, DataTable, DataTableServer, DefaultCardTitle, DefaultForm, DefaultTable, DensityToggleButton, EditSortingButton, EmptyState$1 as EmptyState, ErrorAlert, FilterDialog, FormBody, FormRoot, FormTitle, GlobalFilter, PageSizeControl, Pagination, RecordDisplay, ReloadButton, ResetFilteringButton, ResetSelectionButton, ResetSortingButton, RowCountText, Table, TableBody, TableCardContainer, TableCards, TableComponent, TableControls, TableDataDisplay, TableFilter, TableFilterTags, TableFooter, TableHeader, TableLoadingComponent, TableSelector, TableSorter, TableViewer, TextCell, ViewDialog, createSchemaValidator, getColumns, getMultiDates, getRangeDates, getSupportedLocales, idPickerSanityCheck, isLocaleSupported, useDataTable, useDataTableContext, useDataTableServer, useForm, validateData, widthSanityCheck };
|