@asaleh37/ui-base 25.6.1 → 25.6.2-0.2

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 (161) hide show
  1. package/.github/workflows/publish-npm.yml +31 -0
  2. package/README.md +51 -51
  3. package/dist/index.d.ts +3 -0
  4. package/dist/index.js +6 -6
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.mjs +6 -6
  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 +50 -50
  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/OrgMemberRoleForm.tsx +83 -83
  16. package/src/components/administration/admin/OrganizationApplicationModuleGrid.tsx +107 -107
  17. package/src/components/administration/admin/OrganizationGrid.tsx +82 -82
  18. package/src/components/administration/admin/OrganizationMemberGrid.tsx +176 -176
  19. package/src/components/administration/admin/OrganizationMemberRoleGrid.tsx +87 -87
  20. package/src/components/administration/admin/OrganizationRankGrid.tsx +133 -133
  21. package/src/components/administration/admin/OrganizationUnitGrid.tsx +143 -143
  22. package/src/components/administration/admin/OrganizationUnitTypeGrid.tsx +108 -108
  23. package/src/components/administration/admin/PersonGrid.tsx +334 -231
  24. package/src/components/administration/admin/RoleAuthoritiesForm.tsx +82 -82
  25. package/src/components/administration/admin/SystemApplicationAuthorityGrid.tsx +117 -126
  26. package/src/components/administration/admin/SystemApplicationGrid.tsx +83 -83
  27. package/src/components/administration/admin/SystemApplicationModuleGrid.tsx +96 -96
  28. package/src/components/administration/admin/SystemApplicationRoleAuthorityGrid.tsx +75 -67
  29. package/src/components/administration/admin/SystemApplicationRoleGrid.tsx +116 -116
  30. package/src/components/administration/dev/AttachmentConfigGrid.tsx +223 -223
  31. package/src/components/administration/dev/AttachmentGrid.tsx +172 -172
  32. package/src/components/administration/dev/BluePrintGrid.tsx +129 -129
  33. package/src/components/administration/dev/DashboardGrid.tsx +173 -173
  34. package/src/components/administration/dev/DashboardWidgetGrid.tsx +164 -164
  35. package/src/components/administration/dev/DataQueryGrid.tsx +206 -206
  36. package/src/components/administration/dev/DataQueryParameterGrid.tsx +191 -191
  37. package/src/components/administration/dev/DataQueryParametersForm.tsx +84 -84
  38. package/src/components/administration/dev/DatasourceConnectionGrid.tsx +150 -150
  39. package/src/components/administration/dev/EntityParameterGrid.tsx +279 -279
  40. package/src/components/administration/dev/LookupGrid.tsx +120 -120
  41. package/src/components/administration/dev/MailAttachmentGrid.tsx +155 -155
  42. package/src/components/administration/dev/MailBodyGrid.tsx +216 -216
  43. package/src/components/administration/dev/MailNotificationQueueGrid.tsx +245 -245
  44. package/src/components/administration/dev/MailRecipientGrid.tsx +169 -169
  45. package/src/components/administration/dev/MailSenderConfigGrid.tsx +478 -478
  46. package/src/components/administration/dev/MailTemplateGrid.tsx +384 -384
  47. package/src/components/administration/dev/NotificationGrid.tsx +432 -432
  48. package/src/components/administration/dev/NotificationQueueGrid.tsx +222 -222
  49. package/src/components/administration/dev/ReportGrid.tsx +506 -506
  50. package/src/components/administration/dev/ReportParameterGrid.tsx +186 -186
  51. package/src/components/administration/dev/ReportParametersForm.tsx +84 -84
  52. package/src/components/administration/dev/WidgetGrid.tsx +431 -431
  53. package/src/components/administration/dev/WorkflowDocumentActionGrid.tsx +264 -264
  54. package/src/components/administration/dev/WorkflowDocumentActionHistoryGrid.tsx +172 -172
  55. package/src/components/administration/dev/WorkflowDocumentActionMailGrid.tsx +161 -161
  56. package/src/components/administration/dev/WorkflowDocumentGrid.tsx +377 -377
  57. package/src/components/administration/dev/WorkflowDocumentMailLogGrid.tsx +218 -218
  58. package/src/components/administration/dev/WorkflowDocumentStatusGrid.tsx +243 -243
  59. package/src/components/common/ChangeOrgForm.tsx +81 -81
  60. package/src/components/common/Home.tsx +43 -43
  61. package/src/components/common/LanguageSwitcher.tsx +25 -25
  62. package/src/components/common/LayoutHandlers.tsx +11 -11
  63. package/src/components/common/LoadingMask.tsx +24 -24
  64. package/src/components/common/Login.tsx +214 -214
  65. package/src/components/common/MyNotificationsPanel.tsx +103 -103
  66. package/src/components/common/NotificationItem.tsx +138 -138
  67. package/src/components/index.ts +9 -9
  68. package/src/components/templates/DataEntryTemplates/DataEntryTypes.ts +324 -324
  69. package/src/components/templates/DataEntryTemplates/DataEntryUtil.ts +248 -248
  70. package/src/components/templates/DataEntryTemplates/TemplateDataForm/FormAction.tsx +60 -60
  71. package/src/components/templates/DataEntryTemplates/TemplateDataForm/FormElementField.tsx +231 -231
  72. package/src/components/templates/DataEntryTemplates/TemplateDataForm/FormElementGroup.tsx +106 -106
  73. package/src/components/templates/DataEntryTemplates/TemplateDataForm/FormFields/CheckBox.tsx +64 -64
  74. package/src/components/templates/DataEntryTemplates/TemplateDataForm/FormFields/ComboBox.tsx +93 -93
  75. package/src/components/templates/DataEntryTemplates/TemplateDataForm/FormFields/Datefield.tsx +65 -65
  76. package/src/components/templates/DataEntryTemplates/TemplateDataForm/FormFields/DatetimeField.tsx +64 -64
  77. package/src/components/templates/DataEntryTemplates/TemplateDataForm/FormFields/FiltersPanel.tsx +237 -237
  78. package/src/components/templates/DataEntryTemplates/TemplateDataForm/FormFields/SystemLookupCombobox.tsx +55 -55
  79. package/src/components/templates/DataEntryTemplates/TemplateDataForm/FormFields/TemplateTextField.tsx +17 -17
  80. package/src/components/templates/DataEntryTemplates/TemplateDataForm/TemplateForm.tsx +387 -387
  81. package/src/components/templates/DataEntryTemplates/TemplateDataGrid/DataGridColumnsUtil.tsx +189 -189
  82. package/src/components/templates/DataEntryTemplates/TemplateDataGrid/TemplateGrid.tsx +998 -998
  83. package/src/components/templates/DataEntryTemplates/TemplateDataGrid/TemplateGridMultiRecordAction.tsx +89 -89
  84. package/src/components/templates/DataEntryTemplates/TemplateDataGrid/TemplateGridRecordAction.tsx +95 -95
  85. package/src/components/templates/DataEntryTemplates/TemplateDataGrid/TemplateGridTopBar.tsx +227 -227
  86. package/src/components/templates/TransferList.tsx +257 -257
  87. package/src/components/templates/Window/ConfirmationWindow.tsx +55 -55
  88. package/src/components/templates/attachment/AttachmentCard.tsx +141 -141
  89. package/src/components/templates/attachment/AttachmentImageViewer.tsx +45 -45
  90. package/src/components/templates/attachment/AttachmentPanel.tsx +271 -271
  91. package/src/components/templates/index.ts +33 -33
  92. package/src/components/templates/report/ExcelReportViewer.tsx +71 -71
  93. package/src/components/templates/report/ReportViewer.tsx +382 -382
  94. package/src/components/templates/visuals/DashboardRouteView.tsx +9 -9
  95. package/src/components/templates/visuals/DashboardViewer.tsx +148 -148
  96. package/src/components/templates/visuals/WidgetViewer.tsx +198 -198
  97. package/src/components/templates/visuals/charts/TemplateBarChart.tsx +23 -23
  98. package/src/components/templates/visuals/charts/TemplateDataCard.tsx +35 -35
  99. package/src/components/templates/visuals/charts/TemplateGauge.tsx +21 -21
  100. package/src/components/templates/visuals/charts/TemplateLineChart.tsx +22 -22
  101. package/src/components/templates/visuals/charts/TemplateLineProgress.tsx +42 -42
  102. package/src/components/templates/visuals/charts/TemplatePieChart.tsx +24 -24
  103. package/src/components/templates/workflow/WorkflowDocumentPanel.tsx +606 -606
  104. package/src/components/templates/workflow/WorkflowDocumentTimeLine.tsx +140 -140
  105. package/src/components/templates/workflow/WorkflowRouteComponent.tsx +14 -14
  106. package/src/hooks/UseConfirmationWindow.tsx +54 -54
  107. package/src/hooks/UseMobile.tsx +13 -13
  108. package/src/hooks/UseSession.tsx +59 -40
  109. package/src/hooks/UseWindow.tsx +107 -107
  110. package/src/hooks/index.ts +7 -7
  111. package/src/hooks/useApiActions.ts +124 -124
  112. package/src/hooks/useAxios.tsx +316 -316
  113. package/src/hooks/useInterval.tsx +23 -23
  114. package/src/hooks/useLoadingMask.tsx +16 -16
  115. package/src/hooks/useLookupGridColumn.tsx +35 -35
  116. package/src/index.ts +4 -4
  117. package/src/layout/DrawerHeader.tsx +10 -10
  118. package/src/layout/Layout.tsx +90 -90
  119. package/src/layout/MainContent.tsx +117 -114
  120. package/src/layout/MobileDrawer.tsx +103 -103
  121. package/src/layout/NavigationTree.tsx +298 -295
  122. package/src/layout/NotificationButton.tsx +207 -207
  123. package/src/layout/RouteWrapper.tsx +63 -36
  124. package/src/layout/SideBar.tsx +85 -85
  125. package/src/layout/TopBar.tsx +215 -215
  126. package/src/locales/arabic/adminLocalsAr.json +93 -93
  127. package/src/locales/arabic/common.json +44 -44
  128. package/src/locales/arabic/devLocalsAr.json +317 -317
  129. package/src/locales/arabic/index.ts +9 -9
  130. package/src/locales/english/adminLocalsEn.json +96 -96
  131. package/src/locales/english/common.json +43 -43
  132. package/src/locales/english/devLocalsEn.json +318 -318
  133. package/src/locales/english/index.ts +9 -9
  134. package/src/locales/i18n.ts +8 -8
  135. package/src/locales/index.ts +9 -9
  136. package/src/main.tsx +23 -23
  137. package/src/navigationItems/Administration/adminNavigationItems.tsx +223 -222
  138. package/src/navigationItems/Administration/index.tsx +16 -16
  139. package/src/navigationItems/common/CommonNavigationItems.tsx +12 -12
  140. package/src/navigationItems/common/index.tsx +7 -7
  141. package/src/navigationItems/index.tsx +35 -34
  142. package/src/redux/features/administration/AdministrationStoresMetaData.ts +148 -126
  143. package/src/redux/features/common/AppInfoSlice.ts +63 -63
  144. package/src/redux/features/common/AppLayoutSlice.ts +29 -29
  145. package/src/redux/features/common/CommonStoreSlice.ts +44 -44
  146. package/src/redux/features/common/LoadingMaskSlice.ts +30 -30
  147. package/src/redux/features/common/SideBarSlice.ts +27 -27
  148. package/src/redux/features/common/UserSessionSlice.ts +54 -54
  149. package/src/redux/store.ts +29 -29
  150. package/src/routes/administration/adminRoutes.tsx +99 -99
  151. package/src/routes/administration/devRoutes.tsx +129 -129
  152. package/src/routes/administration/index.ts +8 -8
  153. package/src/routes/index.ts +11 -11
  154. package/src/routes/types/index.ts +6 -5
  155. package/src/styles/index.css +19 -19
  156. package/src/types/index.ts +8 -8
  157. package/src/util/AppUtils.ts +53 -53
  158. package/src/util/constants.ts +6 -6
  159. package/src/util/index.ts +2 -2
  160. package/tsconfig.json +135 -135
  161. package/vite.config.ts +24 -36
@@ -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;