@asaleh37/ui-base 25.8.1-3 → 25.8.1-6

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.
Files changed (162) hide show
  1. package/.github/workflows/publish-npm.yml +49 -49
  2. package/README.md +51 -51
  3. package/dist/index.d.ts +2 -1
  4. package/dist/index.js +4 -4
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.mjs +4 -4
  7. package/dist/index.mjs.map +1 -1
  8. package/eslint.config.js +29 -29
  9. package/index.html +13 -13
  10. package/package.json +120 -120
  11. package/rollup.config-1748377725725.cjs +34 -34
  12. package/rollup.config.js +45 -45
  13. package/src/components/App.tsx +123 -123
  14. package/src/components/BaseApp.tsx +53 -53
  15. package/src/components/administration/admin/ChangePasswordPanel.tsx +128 -128
  16. package/src/components/administration/admin/OrgMemberRoleForm.tsx +83 -83
  17. package/src/components/administration/admin/OrganizationApplicationModuleGrid.tsx +107 -107
  18. package/src/components/administration/admin/OrganizationGrid.tsx +118 -118
  19. package/src/components/administration/admin/OrganizationMemberGrid.tsx +176 -176
  20. package/src/components/administration/admin/OrganizationMemberRoleGrid.tsx +87 -87
  21. package/src/components/administration/admin/OrganizationRankGrid.tsx +133 -133
  22. package/src/components/administration/admin/OrganizationUnitGrid.tsx +143 -143
  23. package/src/components/administration/admin/OrganizationUnitTypeGrid.tsx +108 -108
  24. package/src/components/administration/admin/PersonGrid.tsx +361 -361
  25. package/src/components/administration/admin/RoleAuthoritiesForm.tsx +82 -82
  26. package/src/components/administration/admin/SystemApplicationAuthorityGrid.tsx +117 -117
  27. package/src/components/administration/admin/SystemApplicationGrid.tsx +83 -83
  28. package/src/components/administration/admin/SystemApplicationModuleGrid.tsx +96 -96
  29. package/src/components/administration/admin/SystemApplicationRoleAuthorityGrid.tsx +75 -75
  30. package/src/components/administration/admin/SystemApplicationRoleGrid.tsx +116 -116
  31. package/src/components/administration/dev/AttachmentConfigGrid.tsx +223 -223
  32. package/src/components/administration/dev/AttachmentGrid.tsx +172 -172
  33. package/src/components/administration/dev/BluePrintGrid.tsx +129 -129
  34. package/src/components/administration/dev/DashboardGrid.tsx +173 -173
  35. package/src/components/administration/dev/DashboardWidgetGrid.tsx +164 -164
  36. package/src/components/administration/dev/DataQueryGrid.tsx +206 -206
  37. package/src/components/administration/dev/DataQueryParameterGrid.tsx +191 -191
  38. package/src/components/administration/dev/DataQueryParametersForm.tsx +84 -84
  39. package/src/components/administration/dev/DatasourceConnectionGrid.tsx +150 -150
  40. package/src/components/administration/dev/EntityParameterGrid.tsx +279 -279
  41. package/src/components/administration/dev/LookupGrid.tsx +120 -120
  42. package/src/components/administration/dev/MailAttachmentGrid.tsx +155 -155
  43. package/src/components/administration/dev/MailBodyGrid.tsx +216 -216
  44. package/src/components/administration/dev/MailNotificationQueueGrid.tsx +245 -245
  45. package/src/components/administration/dev/MailRecipientGrid.tsx +169 -169
  46. package/src/components/administration/dev/MailSenderConfigGrid.tsx +478 -478
  47. package/src/components/administration/dev/MailTemplateGrid.tsx +384 -384
  48. package/src/components/administration/dev/NotificationGrid.tsx +432 -432
  49. package/src/components/administration/dev/NotificationQueueGrid.tsx +222 -222
  50. package/src/components/administration/dev/ReportGrid.tsx +506 -506
  51. package/src/components/administration/dev/ReportParameterGrid.tsx +186 -186
  52. package/src/components/administration/dev/ReportParametersForm.tsx +84 -84
  53. package/src/components/administration/dev/WidgetGrid.tsx +431 -431
  54. package/src/components/administration/dev/WorkflowDocumentActionGrid.tsx +264 -264
  55. package/src/components/administration/dev/WorkflowDocumentActionHistoryGrid.tsx +172 -172
  56. package/src/components/administration/dev/WorkflowDocumentActionMailGrid.tsx +161 -161
  57. package/src/components/administration/dev/WorkflowDocumentGrid.tsx +377 -377
  58. package/src/components/administration/dev/WorkflowDocumentMailLogGrid.tsx +218 -218
  59. package/src/components/administration/dev/WorkflowDocumentStatusGrid.tsx +243 -243
  60. package/src/components/common/ChangeOrgForm.tsx +81 -81
  61. package/src/components/common/Home.tsx +43 -43
  62. package/src/components/common/LanguageSwitcher.tsx +25 -25
  63. package/src/components/common/LayoutHandlers.tsx +11 -11
  64. package/src/components/common/LoadingMask.tsx +24 -24
  65. package/src/components/common/Login.tsx +214 -214
  66. package/src/components/common/MyNotificationsPanel.tsx +109 -109
  67. package/src/components/common/NotificationItem.tsx +138 -138
  68. package/src/components/index.ts +11 -9
  69. package/src/components/templates/DataEntryTemplates/DataEntryTypes.ts +324 -324
  70. package/src/components/templates/DataEntryTemplates/DataEntryUtil.ts +248 -248
  71. package/src/components/templates/DataEntryTemplates/TemplateDataForm/FormAction.tsx +60 -60
  72. package/src/components/templates/DataEntryTemplates/TemplateDataForm/FormElementField.tsx +231 -231
  73. package/src/components/templates/DataEntryTemplates/TemplateDataForm/FormElementGroup.tsx +106 -106
  74. package/src/components/templates/DataEntryTemplates/TemplateDataForm/FormFields/CheckBox.tsx +64 -64
  75. package/src/components/templates/DataEntryTemplates/TemplateDataForm/FormFields/ComboBox.tsx +93 -93
  76. package/src/components/templates/DataEntryTemplates/TemplateDataForm/FormFields/Datefield.tsx +65 -65
  77. package/src/components/templates/DataEntryTemplates/TemplateDataForm/FormFields/DatetimeField.tsx +64 -64
  78. package/src/components/templates/DataEntryTemplates/TemplateDataForm/FormFields/FiltersPanel.tsx +237 -237
  79. package/src/components/templates/DataEntryTemplates/TemplateDataForm/FormFields/SystemLookupCombobox.tsx +55 -55
  80. package/src/components/templates/DataEntryTemplates/TemplateDataForm/FormFields/TemplateTextField.tsx +17 -17
  81. package/src/components/templates/DataEntryTemplates/TemplateDataForm/TemplateForm.tsx +387 -387
  82. package/src/components/templates/DataEntryTemplates/TemplateDataGrid/DataGridColumnsUtil.tsx +189 -189
  83. package/src/components/templates/DataEntryTemplates/TemplateDataGrid/TemplateGrid.tsx +998 -998
  84. package/src/components/templates/DataEntryTemplates/TemplateDataGrid/TemplateGridMultiRecordAction.tsx +89 -89
  85. package/src/components/templates/DataEntryTemplates/TemplateDataGrid/TemplateGridRecordAction.tsx +95 -95
  86. package/src/components/templates/DataEntryTemplates/TemplateDataGrid/TemplateGridTopBar.tsx +227 -227
  87. package/src/components/templates/TransferList.tsx +256 -256
  88. package/src/components/templates/Window/ConfirmationWindow.tsx +55 -55
  89. package/src/components/templates/attachment/AttachmentCard.tsx +141 -141
  90. package/src/components/templates/attachment/AttachmentImageViewer.tsx +83 -83
  91. package/src/components/templates/attachment/AttachmentPanel.tsx +285 -285
  92. package/src/components/templates/index.ts +33 -33
  93. package/src/components/templates/report/ExcelReportViewer.tsx +71 -71
  94. package/src/components/templates/report/ReportViewer.tsx +382 -382
  95. package/src/components/templates/visuals/DashboardRouteView.tsx +9 -9
  96. package/src/components/templates/visuals/DashboardViewer.tsx +148 -148
  97. package/src/components/templates/visuals/WidgetViewer.tsx +198 -198
  98. package/src/components/templates/visuals/charts/TemplateBarChart.tsx +23 -23
  99. package/src/components/templates/visuals/charts/TemplateDataCard.tsx +35 -35
  100. package/src/components/templates/visuals/charts/TemplateGauge.tsx +21 -21
  101. package/src/components/templates/visuals/charts/TemplateLineChart.tsx +22 -22
  102. package/src/components/templates/visuals/charts/TemplateLineProgress.tsx +42 -42
  103. package/src/components/templates/visuals/charts/TemplatePieChart.tsx +24 -24
  104. package/src/components/templates/workflow/WorkflowDocumentPanel.tsx +606 -606
  105. package/src/components/templates/workflow/WorkflowDocumentTimeLine.tsx +140 -140
  106. package/src/components/templates/workflow/WorkflowRouteComponent.tsx +14 -14
  107. package/src/hooks/UseConfirmationWindow.tsx +54 -54
  108. package/src/hooks/UseMobile.tsx +13 -13
  109. package/src/hooks/UseSession.tsx +59 -59
  110. package/src/hooks/UseWindow.tsx +107 -107
  111. package/src/hooks/index.ts +7 -7
  112. package/src/hooks/useApiActions.ts +124 -124
  113. package/src/hooks/useAxios.tsx +316 -316
  114. package/src/hooks/useInterval.tsx +23 -23
  115. package/src/hooks/useLoadingMask.tsx +16 -16
  116. package/src/hooks/useLookupGridColumn.tsx +35 -35
  117. package/src/index.ts +4 -5
  118. package/src/layout/DrawerHeader.tsx +10 -10
  119. package/src/layout/Layout.tsx +90 -90
  120. package/src/layout/MainContent.tsx +117 -117
  121. package/src/layout/MobileDrawer.tsx +103 -103
  122. package/src/layout/NavigationTree.tsx +298 -298
  123. package/src/layout/NotificationButton.tsx +207 -207
  124. package/src/layout/RouteWrapper.tsx +63 -63
  125. package/src/layout/SideBar.tsx +85 -85
  126. package/src/layout/TopBar.tsx +289 -289
  127. package/src/locales/arabic/adminLocalsAr.json +93 -93
  128. package/src/locales/arabic/common.json +44 -44
  129. package/src/locales/arabic/devLocalsAr.json +317 -317
  130. package/src/locales/arabic/index.ts +9 -9
  131. package/src/locales/english/adminLocalsEn.json +96 -96
  132. package/src/locales/english/common.json +43 -43
  133. package/src/locales/english/devLocalsEn.json +318 -318
  134. package/src/locales/english/index.ts +9 -9
  135. package/src/locales/i18n.ts +8 -8
  136. package/src/locales/index.ts +9 -9
  137. package/src/main.tsx +23 -23
  138. package/src/navigationItems/Administration/adminNavigationItems.tsx +223 -223
  139. package/src/navigationItems/Administration/index.tsx +16 -16
  140. package/src/navigationItems/common/CommonNavigationItems.tsx +12 -12
  141. package/src/navigationItems/common/index.tsx +7 -7
  142. package/src/navigationItems/index.tsx +35 -35
  143. package/src/redux/features/administration/AdministrationStoresMetaData.ts +148 -148
  144. package/src/redux/features/common/AppInfoSlice.ts +65 -65
  145. package/src/redux/features/common/AppLayoutSlice.ts +29 -29
  146. package/src/redux/features/common/CommonStoreSlice.ts +44 -44
  147. package/src/redux/features/common/LoadingMaskSlice.ts +30 -30
  148. package/src/redux/features/common/SideBarSlice.ts +27 -27
  149. package/src/redux/features/common/UserSessionSlice.ts +54 -54
  150. package/src/redux/store.ts +29 -29
  151. package/src/routes/administration/adminRoutes.tsx +99 -99
  152. package/src/routes/administration/devRoutes.tsx +129 -129
  153. package/src/routes/administration/index.ts +8 -8
  154. package/src/routes/index.ts +11 -11
  155. package/src/routes/types/index.ts +6 -6
  156. package/src/styles/index.css +19 -19
  157. package/src/types/index.ts +8 -8
  158. package/src/util/AppUtils.ts +53 -53
  159. package/src/util/constants.ts +6 -6
  160. package/src/util/index.ts +2 -2
  161. package/tsconfig.json +135 -135
  162. package/vite.config.ts +24 -24
@@ -1,387 +1,387 @@
1
- import { Box } from "@mui/system";
2
- import React, { useEffect, useState } from "react";
3
- import * as z from "zod";
4
- import { useForm } from "react-hook-form";
5
- import { zodResolver } from "@hookform/resolvers/zod";
6
- import { useParams } from "react-router-dom";
7
- import { Button, Grid2, Icon, IconButton, Tooltip } from "@mui/material";
8
- import { toast } from "react-toastify";
9
- import FormElementGroup from "./FormElementGroup";
10
- import FormElementField from "./FormElementField";
11
- import FormAction from "./FormAction";
12
- import { constructValidationSchema, getAllFields } from "../DataEntryUtil";
13
- import {
14
- FormElementProps,
15
- RecordAction,
16
- TemplateFormProps,
17
- } from "../DataEntryTypes";
18
- import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
19
- import { useTranslation } from "react-i18next";
20
- import { useWindow } from "../../../../hooks";
21
- import AttachmentPanel from "../../attachment/AttachmentPanel";
22
- import WorkflowDocumentPanel from "../../workflow/WorkflowDocumentPanel";
23
-
24
- const TemplateForm: React.FC<TemplateFormProps> = (
25
- props: TemplateFormProps
26
- ) => {
27
- const { Window: AttachmentWindow, setWindowState: setAttachmentWindowState } =
28
- useWindow({
29
- windowTitle: "Attachments",
30
- windowIcon: "paperclip",
31
- width: "fit-content",
32
- height: "fit-content",
33
- minHeight: 500,
34
- minWidth: 400,
35
- });
36
- const { Window: WorkflowWindow, setWindowState: setWorkflowWindowState } =
37
- useWindow({
38
- windowTitle: "Approvals",
39
- windowIcon: "stamp",
40
- width: "fit-content",
41
- height: "fit-content",
42
- minHeight: 500,
43
- minWidth: 400,
44
- });
45
- const [attachmentPanelEnabledForRecord, setAttachmentPanelEnabledForRecord] =
46
- useState<boolean>(true);
47
- const { t } = useTranslation();
48
- const fields = getAllFields(props.elements);
49
- const initiallyHiddenFields = [];
50
- for (const field of fields) {
51
- if (field?.hidden) {
52
- initiallyHiddenFields.push(field.fieldName);
53
- }
54
- }
55
- const [hiddenFields, setHiddenFields] = useState<string[]>(
56
- initiallyHiddenFields
57
- );
58
- const initialValues: any = {};
59
- for (const element of props.elements) {
60
- if (
61
- element?.type === "field" &&
62
- element?.mode === "props" &&
63
- element?.props?.defaultValue
64
- ) {
65
- initialValues[element.props.fieldName] = element.props.defaultValue;
66
- }
67
- }
68
- const [disabledFields, setDisabledFields] = useState<string[]>([]);
69
- const formSchema = z.object(constructValidationSchema(fields));
70
- type FormData = z.infer<typeof formSchema>;
71
- const formManager = useForm<FormData>({
72
- resolver: zodResolver(formSchema),
73
- defaultValues: initialValues,
74
- });
75
- const formValues = formManager.watch();
76
- const pathParameters = useParams();
77
- const formRouteRecordIdParamName: any = props?.formRouteRecordIdParamName;
78
-
79
- const loadRecord = async () => {
80
- let idToLoad = null;
81
- if (props?.recordIdToEdit) {
82
- idToLoad = props.recordIdToEdit;
83
- } else if (
84
- formRouteRecordIdParamName &&
85
- pathParameters[formRouteRecordIdParamName]
86
- ) {
87
- idToLoad = pathParameters[formRouteRecordIdParamName];
88
- }
89
- if (idToLoad) {
90
- const retrievedRecord: any = await props.apiActions.loadRecordById(
91
- idToLoad
92
- );
93
- if (retrievedRecord) {
94
- formManager.reset({ ...retrievedRecord });
95
- if (props?.formLoadCallBk) {
96
- props?.formLoadCallBk(formActions, formManager, retrievedRecord);
97
- }
98
- for (const field of fields) {
99
- if (
100
- field?.fieldType === "combobox" &&
101
- retrievedRecord[field.fieldName]
102
- ) {
103
- formManager.setValue(
104
- field.fieldName,
105
- retrievedRecord[field.fieldName] + ""
106
- );
107
- }
108
- }
109
- }
110
- } else {
111
- formManager.reset({});
112
- }
113
- };
114
-
115
- const saveRecord = async (record: any) => {
116
- if (props?.preSaveValidation && !props.preSaveValidation(record)) {
117
- return;
118
- }
119
- if (record) {
120
- const savedRecord: any = await props.apiActions.saveRecord(record);
121
- if (savedRecord) {
122
- formManager.reset({ ...savedRecord });
123
- if (props?.formSavedSuccessfullyCallBk) {
124
- props.formSavedSuccessfullyCallBk(savedRecord);
125
- }
126
- if (props?.formCloseCallBk) {
127
- props.formCloseCallBk();
128
- }
129
- }
130
- }
131
- };
132
-
133
- const formActions = {
134
- setFieldValue: (fieldName: string, fieldValue: any) => {
135
- formManager.setValue(fieldName, fieldValue);
136
- },
137
- hideField: (fieldName: string) => {
138
- setHiddenFields((oldValues) => {
139
- const newValues = [...oldValues, fieldName];
140
- return newValues;
141
- });
142
- },
143
- showField: (fieldName: string) => {
144
- setHiddenFields((oldValues) => {
145
- const newValues = oldValues.filter((x) => x !== fieldName);
146
- return newValues;
147
- });
148
- },
149
- disableField: (fieldName: string) => {
150
- setDisabledFields((oldValues) => {
151
- const newValues = [...oldValues, fieldName];
152
- return newValues;
153
- });
154
- },
155
- enableField: (fieldName: string) => {
156
- setDisabledFields((oldValues) => {
157
- const newValues = oldValues.filter((x) => x !== fieldName);
158
- return newValues;
159
- });
160
- },
161
- };
162
-
163
- useEffect(() => {
164
- loadRecord();
165
- }, [props?.recordIdToEdit]);
166
-
167
- useEffect(() => {
168
- if (props?.attachment && props?.attachment?.enableAttachFn) {
169
- setAttachmentPanelEnabledForRecord(
170
- props.attachment.enableAttachFn(formValues)
171
- );
172
- } else {
173
- setAttachmentPanelEnabledForRecord(true);
174
- }
175
- }, [formValues]);
176
-
177
- return (
178
- <>
179
- {props?.attachment ? (
180
- <AttachmentWindow>
181
- <AttachmentPanel
182
- attachmentCode={props.attachment.attachmentCode}
183
- refKey={formValues[props?.keyColumnName || "id"]}
184
- enableAttachment={attachmentPanelEnabledForRecord}
185
- />
186
- </AttachmentWindow>
187
- ) : (
188
- <></>
189
- )}
190
- {props?.workFlowDocumentCode ? (
191
- <WorkflowWindow>
192
- <WorkflowDocumentPanel
193
- workFlowDocumentCode={props.workFlowDocumentCode}
194
- refDocumentId={formValues[props?.keyColumnName || "id"]}
195
- postActionCallBk={() => {
196
- setWorkflowWindowState(false);
197
- loadRecord();
198
- }}
199
- cancelActionCallBk={() => {
200
- setWorkflowWindowState(false);
201
- }}
202
- />
203
- </WorkflowWindow>
204
- ) : (
205
- <></>
206
- )}
207
-
208
- <Box
209
- sx={{
210
- display: "flex",
211
- flex: 1,
212
- width: "100%",
213
- height: "fit-content",
214
- flexDirection: "column",
215
- alignItems: "center",
216
- overflow: "auto",
217
- }}
218
- >
219
- <Grid2 sx={{ width: "100%" }} container>
220
- {props.elements.map((formElement: FormElementProps, index) => {
221
- if (formElement.type === "group") {
222
- return (
223
- <FormElementGroup
224
- key={index}
225
- {...formElement.props}
226
- formManager={formManager}
227
- formValues={formValues}
228
- formActions={formActions}
229
- hiddenFields={hiddenFields}
230
- disabledFields={disabledFields}
231
- />
232
- );
233
- } else if (
234
- formElement.type === "field" &&
235
- formElement.mode === "props"
236
- ) {
237
- return (
238
- <FormElementField
239
- key={index}
240
- fieldInfo={formElement.props}
241
- formManager={formManager}
242
- formValues={formValues}
243
- formActions={formActions}
244
- hiddenFields={hiddenFields}
245
- disabledFields={disabledFields}
246
- />
247
- );
248
- } else if (
249
- formElement.type === "field" &&
250
- formElement.mode === "node"
251
- ) {
252
- return (
253
- <Grid2
254
- key={index}
255
- size={
256
- formElement?.props?.formProps?.fieldSize || {
257
- lg: 3,
258
- md: 6,
259
- xs: 12,
260
- }
261
- }
262
- sx={{ padding: 1, width: "100%" }}
263
- >
264
- <formElement.node
265
- formManager={formManager}
266
- formValues={formValues}
267
- />
268
- </Grid2>
269
- );
270
- }
271
- })}
272
- </Grid2>
273
- </Box>
274
-
275
- <Box
276
- sx={{
277
- display: "flex",
278
- width: "100%",
279
- alignItems: "center",
280
- justifyContent: "flex-start",
281
- }}
282
- >
283
- {formValues[props?.keyColumnName || "id"] ? (
284
- props?.attachment ? (
285
- <Tooltip title="Attachments">
286
- <IconButton
287
- onClick={() => {
288
- setAttachmentWindowState(true);
289
- }}
290
- >
291
- <FontAwesomeIcon icon="paperclip" />
292
- </IconButton>
293
- </Tooltip>
294
- ) : null
295
- ) : null}
296
- {formValues[props?.keyColumnName || "id"] ? (
297
- props?.workFlowDocumentCode ? (
298
- <Tooltip title="Approvals">
299
- <IconButton
300
- onClick={() => {
301
- setWorkflowWindowState(true);
302
- }}
303
- >
304
- <FontAwesomeIcon icon="stamp" />
305
- </IconButton>
306
- </Tooltip>
307
- ) : null
308
- ) : null}
309
- {props?.actions ? (
310
- formValues[props?.keyColumnName || "id"] ? (
311
- props.actions.map((action: RecordAction) => {
312
- if (action?.formActionProps?.enabled === true) {
313
- return <FormAction {...action} record={formValues} />;
314
- } else {
315
- return <></>;
316
- }
317
- })
318
- ) : (
319
- <></>
320
- )
321
- ) : (
322
- <></>
323
- )}
324
- <div style={{ flex: 1 }}></div>
325
- <Button
326
- variant={
327
- props?.saveButtonSpecs?.actionButtonVariant
328
- ? props.saveButtonSpecs.actionButtonVariant
329
- : "contained"
330
- }
331
- sx={{ m: 1 }}
332
- startIcon={
333
- props?.saveButtonSpecs?.icon ? (
334
- <FontAwesomeIcon icon={props.saveButtonSpecs.icon} />
335
- ) : null
336
- }
337
- color={
338
- props?.saveButtonSpecs?.actionButtonColor
339
- ? props.saveButtonSpecs.actionButtonColor
340
- : "primary"
341
- }
342
- onClick={formManager.handleSubmit(
343
- (values) => {
344
- saveRecord(values);
345
- },
346
- (errors) => {
347
- toast.error(
348
- "Form Data is not valid, make sure you have all field with valid data"
349
- );
350
- console.log("form validation error", errors);
351
- }
352
- )}
353
- >
354
- {t(props?.saveButtonSpecs?.label || "SAVE_BTN_LABEL")}
355
- </Button>
356
- <Button
357
- variant={
358
- props?.cancelButtonSpecs?.actionButtonVariant
359
- ? props.cancelButtonSpecs.actionButtonVariant
360
- : "contained"
361
- }
362
- startIcon={
363
- props?.cancelButtonSpecs?.icon ? (
364
- <FontAwesomeIcon icon={props.cancelButtonSpecs.icon} />
365
- ) : null
366
- }
367
- color={
368
- props?.cancelButtonSpecs?.actionButtonColor
369
- ? props.cancelButtonSpecs.actionButtonColor
370
- : "error"
371
- }
372
- sx={{ m: 1 }}
373
- onClick={() => {
374
- if (props?.formCloseCallBk) {
375
- props.formCloseCallBk();
376
- }
377
- formManager.reset(initialValues);
378
- }}
379
- >
380
- {t(props?.cancelButtonSpecs?.label || "CANCEL_BTN_LABEL")}
381
- </Button>
382
- </Box>
383
- </>
384
- );
385
- };
386
-
387
- export default TemplateForm;
1
+ import { Box } from "@mui/system";
2
+ import React, { useEffect, useState } from "react";
3
+ import * as z from "zod";
4
+ import { useForm } from "react-hook-form";
5
+ import { zodResolver } from "@hookform/resolvers/zod";
6
+ import { useParams } from "react-router-dom";
7
+ import { Button, Grid2, Icon, IconButton, Tooltip } from "@mui/material";
8
+ import { toast } from "react-toastify";
9
+ import FormElementGroup from "./FormElementGroup";
10
+ import FormElementField from "./FormElementField";
11
+ import FormAction from "./FormAction";
12
+ import { constructValidationSchema, getAllFields } from "../DataEntryUtil";
13
+ import {
14
+ FormElementProps,
15
+ RecordAction,
16
+ TemplateFormProps,
17
+ } from "../DataEntryTypes";
18
+ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
19
+ import { useTranslation } from "react-i18next";
20
+ import { useWindow } from "../../../../hooks";
21
+ import AttachmentPanel from "../../attachment/AttachmentPanel";
22
+ import WorkflowDocumentPanel from "../../workflow/WorkflowDocumentPanel";
23
+
24
+ const TemplateForm: React.FC<TemplateFormProps> = (
25
+ props: TemplateFormProps
26
+ ) => {
27
+ const { Window: AttachmentWindow, setWindowState: setAttachmentWindowState } =
28
+ useWindow({
29
+ windowTitle: "Attachments",
30
+ windowIcon: "paperclip",
31
+ width: "fit-content",
32
+ height: "fit-content",
33
+ minHeight: 500,
34
+ minWidth: 400,
35
+ });
36
+ const { Window: WorkflowWindow, setWindowState: setWorkflowWindowState } =
37
+ useWindow({
38
+ windowTitle: "Approvals",
39
+ windowIcon: "stamp",
40
+ width: "fit-content",
41
+ height: "fit-content",
42
+ minHeight: 500,
43
+ minWidth: 400,
44
+ });
45
+ const [attachmentPanelEnabledForRecord, setAttachmentPanelEnabledForRecord] =
46
+ useState<boolean>(true);
47
+ const { t } = useTranslation();
48
+ const fields = getAllFields(props.elements);
49
+ const initiallyHiddenFields = [];
50
+ for (const field of fields) {
51
+ if (field?.hidden) {
52
+ initiallyHiddenFields.push(field.fieldName);
53
+ }
54
+ }
55
+ const [hiddenFields, setHiddenFields] = useState<string[]>(
56
+ initiallyHiddenFields
57
+ );
58
+ const initialValues: any = {};
59
+ for (const element of props.elements) {
60
+ if (
61
+ element?.type === "field" &&
62
+ element?.mode === "props" &&
63
+ element?.props?.defaultValue
64
+ ) {
65
+ initialValues[element.props.fieldName] = element.props.defaultValue;
66
+ }
67
+ }
68
+ const [disabledFields, setDisabledFields] = useState<string[]>([]);
69
+ const formSchema = z.object(constructValidationSchema(fields));
70
+ type FormData = z.infer<typeof formSchema>;
71
+ const formManager = useForm<FormData>({
72
+ resolver: zodResolver(formSchema),
73
+ defaultValues: initialValues,
74
+ });
75
+ const formValues = formManager.watch();
76
+ const pathParameters = useParams();
77
+ const formRouteRecordIdParamName: any = props?.formRouteRecordIdParamName;
78
+
79
+ const loadRecord = async () => {
80
+ let idToLoad = null;
81
+ if (props?.recordIdToEdit) {
82
+ idToLoad = props.recordIdToEdit;
83
+ } else if (
84
+ formRouteRecordIdParamName &&
85
+ pathParameters[formRouteRecordIdParamName]
86
+ ) {
87
+ idToLoad = pathParameters[formRouteRecordIdParamName];
88
+ }
89
+ if (idToLoad) {
90
+ const retrievedRecord: any = await props.apiActions.loadRecordById(
91
+ idToLoad
92
+ );
93
+ if (retrievedRecord) {
94
+ formManager.reset({ ...retrievedRecord });
95
+ if (props?.formLoadCallBk) {
96
+ props?.formLoadCallBk(formActions, formManager, retrievedRecord);
97
+ }
98
+ for (const field of fields) {
99
+ if (
100
+ field?.fieldType === "combobox" &&
101
+ retrievedRecord[field.fieldName]
102
+ ) {
103
+ formManager.setValue(
104
+ field.fieldName,
105
+ retrievedRecord[field.fieldName] + ""
106
+ );
107
+ }
108
+ }
109
+ }
110
+ } else {
111
+ formManager.reset({});
112
+ }
113
+ };
114
+
115
+ const saveRecord = async (record: any) => {
116
+ if (props?.preSaveValidation && !props.preSaveValidation(record)) {
117
+ return;
118
+ }
119
+ if (record) {
120
+ const savedRecord: any = await props.apiActions.saveRecord(record);
121
+ if (savedRecord) {
122
+ formManager.reset({ ...savedRecord });
123
+ if (props?.formSavedSuccessfullyCallBk) {
124
+ props.formSavedSuccessfullyCallBk(savedRecord);
125
+ }
126
+ if (props?.formCloseCallBk) {
127
+ props.formCloseCallBk();
128
+ }
129
+ }
130
+ }
131
+ };
132
+
133
+ const formActions = {
134
+ setFieldValue: (fieldName: string, fieldValue: any) => {
135
+ formManager.setValue(fieldName, fieldValue);
136
+ },
137
+ hideField: (fieldName: string) => {
138
+ setHiddenFields((oldValues) => {
139
+ const newValues = [...oldValues, fieldName];
140
+ return newValues;
141
+ });
142
+ },
143
+ showField: (fieldName: string) => {
144
+ setHiddenFields((oldValues) => {
145
+ const newValues = oldValues.filter((x) => x !== fieldName);
146
+ return newValues;
147
+ });
148
+ },
149
+ disableField: (fieldName: string) => {
150
+ setDisabledFields((oldValues) => {
151
+ const newValues = [...oldValues, fieldName];
152
+ return newValues;
153
+ });
154
+ },
155
+ enableField: (fieldName: string) => {
156
+ setDisabledFields((oldValues) => {
157
+ const newValues = oldValues.filter((x) => x !== fieldName);
158
+ return newValues;
159
+ });
160
+ },
161
+ };
162
+
163
+ useEffect(() => {
164
+ loadRecord();
165
+ }, [props?.recordIdToEdit]);
166
+
167
+ useEffect(() => {
168
+ if (props?.attachment && props?.attachment?.enableAttachFn) {
169
+ setAttachmentPanelEnabledForRecord(
170
+ props.attachment.enableAttachFn(formValues)
171
+ );
172
+ } else {
173
+ setAttachmentPanelEnabledForRecord(true);
174
+ }
175
+ }, [formValues]);
176
+
177
+ return (
178
+ <>
179
+ {props?.attachment ? (
180
+ <AttachmentWindow>
181
+ <AttachmentPanel
182
+ attachmentCode={props.attachment.attachmentCode}
183
+ refKey={formValues[props?.keyColumnName || "id"]}
184
+ enableAttachment={attachmentPanelEnabledForRecord}
185
+ />
186
+ </AttachmentWindow>
187
+ ) : (
188
+ <></>
189
+ )}
190
+ {props?.workFlowDocumentCode ? (
191
+ <WorkflowWindow>
192
+ <WorkflowDocumentPanel
193
+ workFlowDocumentCode={props.workFlowDocumentCode}
194
+ refDocumentId={formValues[props?.keyColumnName || "id"]}
195
+ postActionCallBk={() => {
196
+ setWorkflowWindowState(false);
197
+ loadRecord();
198
+ }}
199
+ cancelActionCallBk={() => {
200
+ setWorkflowWindowState(false);
201
+ }}
202
+ />
203
+ </WorkflowWindow>
204
+ ) : (
205
+ <></>
206
+ )}
207
+
208
+ <Box
209
+ sx={{
210
+ display: "flex",
211
+ flex: 1,
212
+ width: "100%",
213
+ height: "fit-content",
214
+ flexDirection: "column",
215
+ alignItems: "center",
216
+ overflow: "auto",
217
+ }}
218
+ >
219
+ <Grid2 sx={{ width: "100%" }} container>
220
+ {props.elements.map((formElement: FormElementProps, index) => {
221
+ if (formElement.type === "group") {
222
+ return (
223
+ <FormElementGroup
224
+ key={index}
225
+ {...formElement.props}
226
+ formManager={formManager}
227
+ formValues={formValues}
228
+ formActions={formActions}
229
+ hiddenFields={hiddenFields}
230
+ disabledFields={disabledFields}
231
+ />
232
+ );
233
+ } else if (
234
+ formElement.type === "field" &&
235
+ formElement.mode === "props"
236
+ ) {
237
+ return (
238
+ <FormElementField
239
+ key={index}
240
+ fieldInfo={formElement.props}
241
+ formManager={formManager}
242
+ formValues={formValues}
243
+ formActions={formActions}
244
+ hiddenFields={hiddenFields}
245
+ disabledFields={disabledFields}
246
+ />
247
+ );
248
+ } else if (
249
+ formElement.type === "field" &&
250
+ formElement.mode === "node"
251
+ ) {
252
+ return (
253
+ <Grid2
254
+ key={index}
255
+ size={
256
+ formElement?.props?.formProps?.fieldSize || {
257
+ lg: 3,
258
+ md: 6,
259
+ xs: 12,
260
+ }
261
+ }
262
+ sx={{ padding: 1, width: "100%" }}
263
+ >
264
+ <formElement.node
265
+ formManager={formManager}
266
+ formValues={formValues}
267
+ />
268
+ </Grid2>
269
+ );
270
+ }
271
+ })}
272
+ </Grid2>
273
+ </Box>
274
+
275
+ <Box
276
+ sx={{
277
+ display: "flex",
278
+ width: "100%",
279
+ alignItems: "center",
280
+ justifyContent: "flex-start",
281
+ }}
282
+ >
283
+ {formValues[props?.keyColumnName || "id"] ? (
284
+ props?.attachment ? (
285
+ <Tooltip title="Attachments">
286
+ <IconButton
287
+ onClick={() => {
288
+ setAttachmentWindowState(true);
289
+ }}
290
+ >
291
+ <FontAwesomeIcon icon="paperclip" />
292
+ </IconButton>
293
+ </Tooltip>
294
+ ) : null
295
+ ) : null}
296
+ {formValues[props?.keyColumnName || "id"] ? (
297
+ props?.workFlowDocumentCode ? (
298
+ <Tooltip title="Approvals">
299
+ <IconButton
300
+ onClick={() => {
301
+ setWorkflowWindowState(true);
302
+ }}
303
+ >
304
+ <FontAwesomeIcon icon="stamp" />
305
+ </IconButton>
306
+ </Tooltip>
307
+ ) : null
308
+ ) : null}
309
+ {props?.actions ? (
310
+ formValues[props?.keyColumnName || "id"] ? (
311
+ props.actions.map((action: RecordAction) => {
312
+ if (action?.formActionProps?.enabled === true) {
313
+ return <FormAction {...action} record={formValues} />;
314
+ } else {
315
+ return <></>;
316
+ }
317
+ })
318
+ ) : (
319
+ <></>
320
+ )
321
+ ) : (
322
+ <></>
323
+ )}
324
+ <div style={{ flex: 1 }}></div>
325
+ <Button
326
+ variant={
327
+ props?.saveButtonSpecs?.actionButtonVariant
328
+ ? props.saveButtonSpecs.actionButtonVariant
329
+ : "contained"
330
+ }
331
+ sx={{ m: 1 }}
332
+ startIcon={
333
+ props?.saveButtonSpecs?.icon ? (
334
+ <FontAwesomeIcon icon={props.saveButtonSpecs.icon} />
335
+ ) : null
336
+ }
337
+ color={
338
+ props?.saveButtonSpecs?.actionButtonColor
339
+ ? props.saveButtonSpecs.actionButtonColor
340
+ : "primary"
341
+ }
342
+ onClick={formManager.handleSubmit(
343
+ (values) => {
344
+ saveRecord(values);
345
+ },
346
+ (errors) => {
347
+ toast.error(
348
+ "Form Data is not valid, make sure you have all field with valid data"
349
+ );
350
+ console.log("form validation error", errors);
351
+ }
352
+ )}
353
+ >
354
+ {t(props?.saveButtonSpecs?.label || "SAVE_BTN_LABEL")}
355
+ </Button>
356
+ <Button
357
+ variant={
358
+ props?.cancelButtonSpecs?.actionButtonVariant
359
+ ? props.cancelButtonSpecs.actionButtonVariant
360
+ : "contained"
361
+ }
362
+ startIcon={
363
+ props?.cancelButtonSpecs?.icon ? (
364
+ <FontAwesomeIcon icon={props.cancelButtonSpecs.icon} />
365
+ ) : null
366
+ }
367
+ color={
368
+ props?.cancelButtonSpecs?.actionButtonColor
369
+ ? props.cancelButtonSpecs.actionButtonColor
370
+ : "error"
371
+ }
372
+ sx={{ m: 1 }}
373
+ onClick={() => {
374
+ if (props?.formCloseCallBk) {
375
+ props.formCloseCallBk();
376
+ }
377
+ formManager.reset(initialValues);
378
+ }}
379
+ >
380
+ {t(props?.cancelButtonSpecs?.label || "CANCEL_BTN_LABEL")}
381
+ </Button>
382
+ </Box>
383
+ </>
384
+ );
385
+ };
386
+
387
+ export default TemplateForm;