diff --git a/api/src/Sozsoft.Platform.DbMigrator/Seeds/MenusData.json b/api/src/Sozsoft.Platform.DbMigrator/Seeds/MenusData.json index 0ed304d..47dca34 100644 --- a/api/src/Sozsoft.Platform.DbMigrator/Seeds/MenusData.json +++ b/api/src/Sozsoft.Platform.DbMigrator/Seeds/MenusData.json @@ -879,21 +879,11 @@ "RequiredPermissionName": "App.Contact", "IsDisabled": false }, - { - "ParentCode": "App.Administration", - "Code": "App.Listforms.Wizard", - "DisplayName": "App.Listforms.Wizard", - "Order": 5, - "Url": "/admin/listform/wizard", - "Icon": "FcFlashAuto", - "RequiredPermissionName": "App.Listforms.Wizard", - "IsDisabled": false - }, { "ParentCode": "App.Administration", "Code": "App.Routes", "DisplayName": "App.Routes", - "Order": 6, + "Order": 5, "Url": "/admin/list/App.Routes", "Icon": "FaSynagogue", "RequiredPermissionName": "App.Routes", @@ -903,7 +893,7 @@ "ParentCode": "App.Administration", "Code": "App.Menus", "DisplayName": "App.Menus", - "Order": 7, + "Order": 6, "Url": null, "Icon": "FaSchlix", "RequiredPermissionName": null, @@ -933,7 +923,7 @@ "ParentCode": "App.Administration", "Code": "App.Files", "DisplayName": "App.Files", - "Order": 8, + "Order": 7, "Url": "/admin/files", "Icon": "FcFolder", "RequiredPermissionName": "App.Files", @@ -943,7 +933,7 @@ "ParentCode": "App.Administration", "Code": "App.Reports.Management", "DisplayName": "App.Reports.Management", - "Order": 9, + "Order": 8, "Url": null, "Icon": "FcDocument", "RequiredPermissionName": null, @@ -973,7 +963,7 @@ "ParentCode": "App.Administration", "Code": "App.DeveloperKit", "DisplayName": "App.DeveloperKit", - "Order": 10, + "Order": 9, "Url": null, "Icon": "FcAndroidOs", "RequiredPermissionName": null, @@ -1059,6 +1049,16 @@ "RequiredPermissionName": "App.SqlQueryManager", "IsDisabled": false }, + { + "ParentCode": "App.Administration", + "Code": "App.Listforms.Wizard", + "DisplayName": "App.Listforms.Wizard", + "Order": 10, + "Url": "/admin/listform/wizard", + "Icon": "FcFlashAuto", + "RequiredPermissionName": "App.Listforms.Wizard", + "IsDisabled": false + }, { "ParentCode": "App.Administration", "Code": "App.Forum", diff --git a/ui/src/views/admin/listForm/Wizard.tsx b/ui/src/views/admin/listForm/Wizard.tsx index eadc7b4..ef7f2e1 100644 --- a/ui/src/views/admin/listForm/Wizard.tsx +++ b/ui/src/views/admin/listForm/Wizard.tsx @@ -6,14 +6,15 @@ import { Input, Notification, Select, + Steps, toast, } from '@/components/ui' import { ROUTES_ENUM } from '@/routes/route.constant' import { ListFormWizardDto } from '@/proxy/admin/list-form/models' import { SelectBoxOption } from '@/types/shared' import { useLocalization } from '@/utils/hooks/useLocalization' -import { Field, FieldProps, Form, Formik } from 'formik' -import { useEffect, useState } from 'react' +import { Field, FieldProps, Form, Formik, FormikProps } from 'formik' +import { useEffect, useRef, useState } from 'react' import { Helmet } from 'react-helmet' import { useNavigate } from 'react-router-dom' import CreatableSelect from 'react-select/creatable' @@ -47,19 +48,22 @@ const initialValues: ListFormWizardDto = { keyFieldDbSourceType: DbTypeEnum.Int32, // Select: Enum dbSourceTypeOptions } -const listFormValidationSchema = Yup.object().shape({ +const step1ValidationSchema = Yup.object().shape({ listFormCode: Yup.string().required(), + permissionGroupName: Yup.string().required(), + menuParentCode: Yup.string().required(), + menuIcon: Yup.string(), languageTextMenuEn: Yup.string(), languageTextMenuTr: Yup.string(), + languageTextMenuParentEn: Yup.string(), + languageTextMenuParentTr: Yup.string(), +}) + +const step2ValidationSchema = Yup.object().shape({ languageTextTitleEn: Yup.string(), languageTextTitleTr: Yup.string(), languageTextDescEn: Yup.string(), languageTextDescTr: Yup.string(), - languageTextMenuParentEn: Yup.string(), - languageTextMenuParentTr: Yup.string(), - permissionGroupName: Yup.string().required(), - menuParentCode: Yup.string().required(), - menuIcon: Yup.string(), dataSourceCode: Yup.string(), dataSourceConnectionString: Yup.string(), selectCommandType: Yup.string().required(), @@ -68,8 +72,12 @@ const listFormValidationSchema = Yup.object().shape({ keyFieldDbSourceType: Yup.string().required(), }) +const listFormValidationSchema = step1ValidationSchema.concat(step2ValidationSchema) + const Wizard = () => { const { translate } = useLocalization() + const [currentStep, setCurrentStep] = useState(0) + const [isLoadingDataSource, setIsLoadingDataSource] = useState(false) const [dataSourceList, setDataSourceList] = useState([]) const [isDataSourceNew, setIsDataSourceNew] = useState(false) @@ -106,7 +114,6 @@ const Wizard = () => { const [isLoadingPermissionGroup, setIsLoadingPermissionGroup] = useState(false) const [permissionGroupList, setPermissionGroupList] = useState([]) - const [isPermissionGroupNew, setIsPermissionGroupNew] = useState(false) const getPermissionGroupList = async () => { setIsLoadingPermissionGroup(true) const response = await getPermissions('R', '') @@ -128,6 +135,27 @@ const Wizard = () => { }, []) const navigate = useNavigate() + const formikRef = useRef>(null) + + const handleNext = async () => { + if (!formikRef.current) return + const errors = await formikRef.current.validateForm() + const step1Fields = Object.keys(step1ValidationSchema.fields) + const hasStep1Errors = step1Fields.some((f) => errors[f as keyof ListFormWizardDto]) + // Touch all step 1 fields so errors appear + const touchedStep1 = step1Fields.reduce( + (acc, key) => ({ ...acc, [key]: true }), + {} as Record, + ) + formikRef.current.setTouched({ ...formikRef.current.touched, ...touchedStep1 }) + if (!hasStep1Errors) { + setCurrentStep(1) + } + } + + const handleBack = () => { + setCurrentStep(0) + } return ( @@ -137,8 +165,16 @@ const Wizard = () => { defaultTitle={APP_NAME} > +
+ + + + +
+
{ @@ -172,369 +208,384 @@ const Wizard = () => { {({ touched, errors, isSubmitting, values }) => (
- - - - - - {({ field, form }: FieldProps) => ( - o.value === values.menuParentCode) ?? { - label: values.menuParentCode, - value: values.menuParentCode, - }) - : null - } - onChange={(option) => { - form.setFieldValue(field.name, option?.value) - setIsMenuNew( - !!option?.value && !menuList.some((a) => a.value === option?.value), - ) - }} - /> - )} - - - - - -
- {isMenuNew && ( -
+ {/* ─── Step 1: Basic Info ─────────────────────────────── */} + {currentStep === 0 && ( + <> + - + + {({ field, form }: FieldProps) => ( + o.value === values.dataSourceCode) ?? { - label: values.dataSourceCode, - value: values.dataSourceCode, - }) - : null - } - onChange={(option) => { - form.setFieldValue(field.name, option?.value) - setIsDataSourceNew( - !!option?.value && - !dataSourceList.some((a) => a.value === option?.value), - ) - }} - /> - )} - - - {isDataSourceNew && ( - - - - )} -
-
- - - {({ field, form }: FieldProps) => ( - o.value === values.keyFieldDbSourceType, + +
+ + + {({ field, form }: FieldProps) => ( + o.value === values.dataSourceCode, + ) ?? { + label: values.dataSourceCode, + value: values.dataSourceCode, + }) + : null + } + onChange={(option) => { + form.setFieldValue(field.name, option?.value) + setIsDataSourceNew( + !!option?.value && + !dataSourceList.some((a) => a.value === option?.value), + ) + }} + /> + )} + + + + {isDataSourceNew && ( + + + )} - - -
-
- - - - - - -
-
- - - - - - -
-
- - - - - - -
- +
+ +
+ + + {({ field, form }: FieldProps) => ( + o.value === values.keyFieldDbSourceType, + )} + onChange={(o) => form.setFieldValue(field.name, o?.value)} + /> + )} + + +
+ +
+ + +
+ + )} )}