@asaleh37/ui-base 1.2.16 → 1.2.18

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 (59) hide show
  1. package/.env.development +1 -1
  2. package/dist/index.d.ts +27 -5
  3. package/dist/index.js +5 -5
  4. package/dist/index.js.map +1 -1
  5. package/dist/index.mjs +5 -5
  6. package/dist/index.mjs.map +1 -1
  7. package/package.json +1 -1
  8. package/public/no_image.png +0 -0
  9. package/src/components/administration/admin/OrganizationApplicationModuleGrid.tsx +10 -34
  10. package/src/components/administration/admin/OrganizationGrid.tsx +4 -87
  11. package/src/components/administration/admin/OrganizationRankGrid.tsx +34 -16
  12. package/src/components/administration/admin/OrganizationUnitGrid.tsx +34 -30
  13. package/src/components/administration/admin/OrganizationUnitTypeGrid.tsx +3 -16
  14. package/src/components/administration/admin/PersonGrid.tsx +38 -1
  15. package/src/components/administration/admin/RoleAuthoritiesForm.tsx +2 -4
  16. package/src/components/administration/admin/SystemApplicationAuthorityGrid.tsx +2 -18
  17. package/src/components/administration/admin/SystemApplicationGrid.tsx +5 -83
  18. package/src/components/administration/admin/SystemApplicationModuleGrid.tsx +2 -15
  19. package/src/components/administration/admin/SystemApplicationRoleGrid.tsx +1 -15
  20. package/src/components/administration/dev/AttachmentConfigGrid.tsx +213 -0
  21. package/src/components/administration/dev/AttachmentGrid.tsx +172 -0
  22. package/src/components/administration/dev/LookupGrid.tsx +1 -12
  23. package/src/components/common/Home.tsx +24 -22
  24. package/src/components/index.ts +0 -4
  25. package/src/components/templates/DataEntryTemplates/DataEntryTypes.ts +13 -1
  26. package/src/components/templates/DataEntryTemplates/DataEntryUtil.ts +6 -0
  27. package/src/components/templates/DataEntryTemplates/TemplateDataForm/FormElementField.tsx +1 -3
  28. package/src/components/templates/DataEntryTemplates/TemplateDataForm/FormFields/SystemLookupCombobox.tsx +1 -1
  29. package/src/components/templates/DataEntryTemplates/TemplateDataForm/TemplateForm.tsx +100 -8
  30. package/src/components/templates/DataEntryTemplates/TemplateDataGrid/TemplateGrid.tsx +105 -4
  31. package/src/components/templates/attachment/AttachmentCard.tsx +126 -0
  32. package/src/components/templates/attachment/AttachmentImageViewer.tsx +44 -0
  33. package/src/components/templates/attachment/AttachmentPanel.tsx +269 -0
  34. package/src/components/templates/workflow/WorkflowDocumentPanel.tsx +4 -4
  35. package/src/hooks/UseSession.tsx +20 -2
  36. package/src/hooks/useAxios.tsx +71 -11
  37. package/src/hooks/useLookupGridColumn.tsx +2 -2
  38. package/src/layout/MainContent.tsx +49 -46
  39. package/src/layout/TopBar.tsx +6 -1
  40. package/src/locales/arabic/devLocalsAr.json +13 -1
  41. package/src/locales/english/devLocalsEn.json +13 -1
  42. package/src/main.tsx +3 -3
  43. package/src/navigationItems/Administration/adminNavigationItems.tsx +77 -3
  44. package/src/redux/features/administration/AdministrationStoresMetaData.ts +14 -6
  45. package/src/routes/administration/adminRoutes.tsx +21 -0
  46. package/src/routes/administration/devRoutes.tsx +24 -0
  47. package/public/icons/LICENSE.md +0 -5
  48. package/public/icons/arrow-clockwise.svg +0 -4
  49. package/public/icons/arrow-counterclockwise.svg +0 -4
  50. package/public/icons/journal-text.svg +0 -5
  51. package/public/icons/justify.svg +0 -3
  52. package/public/icons/text-center.svg +0 -3
  53. package/public/icons/text-left.svg +0 -3
  54. package/public/icons/text-paragraph.svg +0 -3
  55. package/public/icons/text-right.svg +0 -3
  56. package/public/icons/type-bold.svg +0 -3
  57. package/public/icons/type-italic.svg +0 -3
  58. package/public/icons/type-strikethrough.svg +0 -3
  59. package/public/icons/type-underline.svg +0 -3
@@ -1,3 +1,4 @@
1
+ import { attachment } from "./../attachment/AttachmentCard";
1
2
  import { IconProp } from "@fortawesome/fontawesome-svg-core";
2
3
  import {
3
4
  DataGridPremiumProps,
@@ -96,7 +97,14 @@ export type TemplateGridColDef = GridColDef & {
96
97
  valueField?: string;
97
98
  };
98
99
 
100
+ export type TemplateGridAttachmentProps = {
101
+ attachmentCode: string;
102
+ enableAttachFn?: (record: any) => boolean;
103
+ };
104
+
99
105
  export type TemplateGridProps = {
106
+ workFlowDocumentCode?: string;
107
+ attachment?: TemplateGridAttachmentProps;
100
108
  formElements: Array<FormElementProps>;
101
109
  gridStateKey?: string;
102
110
  data: Array<any>;
@@ -178,7 +186,8 @@ export type RecordFieldProps = {
178
186
  | "combobox"
179
187
  | "checkbox"
180
188
  | "html"
181
- | "lookup";
189
+ | "lookup"
190
+ | "custom";
182
191
  lookupType?: string;
183
192
  required?: boolean;
184
193
  disabled?: boolean;
@@ -259,6 +268,9 @@ export type FormActionProps = {
259
268
  };
260
269
 
261
270
  export type TemplateFormProps = {
271
+ workFlowDocumentCode?: string;
272
+ attachment?: TemplateGridAttachmentProps;
273
+ keyColumnName?: any;
262
274
  elements: Array<FormElementProps>;
263
275
  findByIdParamName?: string;
264
276
  recordIdToEdit?: any;
@@ -164,6 +164,12 @@ export const constructGridColumnsFromFields: (
164
164
  minWidth: 200,
165
165
  });
166
166
  columns.push(column);
167
+ } else {
168
+ const column: TemplateGridColDef = {
169
+ field: tableField.fieldName,
170
+ ...tableField?.gridProps?.muiProps,
171
+ };
172
+ columns.push(column);
167
173
  }
168
174
  }
169
175
  return columns;
@@ -218,9 +218,7 @@ const FormElementField: React.FC<FormElementFieldProps> = (
218
218
  fieldName
219
219
  ]?.message?.toString()}
220
220
  />
221
- ) : (
222
- <>Unknown field type</>
223
- )}
221
+ ) : null}
224
222
  </Grid2>
225
223
  ) : (
226
224
  <></>
@@ -22,7 +22,7 @@ const SystemLookupCombobox: React.FC<SystemLookupListProps> = (props) => {
22
22
 
23
23
  const loadLookupOptions = async () => {
24
24
  await handleGetRequest({
25
- endPointURI: "api/v1/dev/system/lookup",
25
+ endPointURI: "api/v1/public/system/lookup",
26
26
  showMask: true,
27
27
  parameters: { lookupType: props.lookupType },
28
28
  successCallBkFn: (response: any) => {
@@ -4,7 +4,7 @@ import * as z from "zod";
4
4
  import { useForm } from "react-hook-form";
5
5
  import { zodResolver } from "@hookform/resolvers/zod";
6
6
  import { useParams } from "react-router-dom";
7
- import { Button, Grid2 } from "@mui/material";
7
+ import { Button, Grid2, Icon, IconButton, Tooltip } from "@mui/material";
8
8
  import { toast } from "react-toastify";
9
9
  import FormElementGroup from "./FormElementGroup";
10
10
  import FormElementField from "./FormElementField";
@@ -17,10 +17,33 @@ import {
17
17
  } from "../DataEntryTypes";
18
18
  import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
19
19
  import { useTranslation } from "react-i18next";
20
+ import { useWindow } from "../../../../hooks";
21
+ import AttachmentPanel from "../../attachment/AttachmentPanel";
22
+ import WorkflowDocumentPanel from "../../workflow/WorkflowDocumentPanel";
20
23
 
21
24
  const TemplateForm: React.FC<TemplateFormProps> = (
22
25
  props: TemplateFormProps
23
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);
24
47
  const { t } = useTranslation();
25
48
  const fields = getAllFields(props.elements);
26
49
  const initiallyHiddenFields = [];
@@ -141,8 +164,47 @@ const TemplateForm: React.FC<TemplateFormProps> = (
141
164
  loadRecord();
142
165
  }, [props?.recordIdToEdit]);
143
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
+
144
177
  return (
145
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
+
146
208
  <Box
147
209
  sx={{
148
210
  display: "flex",
@@ -218,14 +280,44 @@ const TemplateForm: React.FC<TemplateFormProps> = (
218
280
  justifyContent: "flex-start",
219
281
  }}
220
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}
221
309
  {props?.actions ? (
222
- props.actions.map((action: RecordAction) => {
223
- if (action?.formActionProps?.enabled === true) {
224
- return <FormAction {...action} record={formValues} />;
225
- } else {
226
- return <></>;
227
- }
228
- })
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
+ )
229
321
  ) : (
230
322
  <></>
231
323
  )}
@@ -47,6 +47,8 @@ import { useWindow } from "../../../../hooks/UseWindow";
47
47
  import { useAxios } from "../../../../hooks";
48
48
  import useLookupGridColumn from "../../../../hooks/useLookupGridColumn";
49
49
  import { ContinuousColorLegend } from "@mui/x-charts";
50
+ import AttachmentPanel from "../../attachment/AttachmentPanel";
51
+ import WorkflowDocumentPanel from "../../workflow/WorkflowDocumentPanel";
50
52
  let currentNewRecordIndex = -1;
51
53
 
52
54
  interface GridState {
@@ -78,12 +80,33 @@ const saveGridState = (gridStateKey: string, statePart: GridState) => {
78
80
  const PIN_FIXED_COLUMNS = ["__check__", "actions"];
79
81
 
80
82
  const TemplateGrid: React.FC<TemplateGridProps> = (props) => {
83
+ const { t } = useTranslation();
81
84
  const AppLayout = useSelector((state: any) => state.AppLayout);
85
+ const [selectedRecord, setSelectedRecord] = useState<any>({});
86
+ const [attachmentPanelEnabledForRecord, setAttachmentPanelEnabledForRecord] =
87
+ useState<boolean>(true);
82
88
  const { getLookupOptions } = useLookupGridColumn();
89
+ const { Window: AttachmentWindow, setWindowState: setAttachmentWindowState } =
90
+ useWindow({
91
+ windowTitle: t(props.gridTitle) + " Attachments",
92
+ windowIcon: "paperclip",
93
+ width: "fit-content",
94
+ height: "fit-content",
95
+ minHeight: 500,
96
+ minWidth: 400,
97
+ });
98
+ const { Window: WorkFlowWindow, setWindowState: setWorkFlowWindowState } =
99
+ useWindow({
100
+ windowTitle: t(props.gridTitle) + " Attachments",
101
+ windowIcon: "paperclip",
102
+ width: "fit-content",
103
+ height: "fit-content",
104
+ minHeight: 500,
105
+ minWidth: 400,
106
+ });
83
107
  const [generatedColumns, setGeneratedColumns] = useState<
84
108
  Array<TemplateGridColDef>
85
109
  >([]);
86
- const { t } = useTranslation();
87
110
  const fields = getAllFields(props.formElements);
88
111
  const hiddenFields = [];
89
112
  const savedState = React.useMemo<GridState>(
@@ -174,7 +197,7 @@ const TemplateGrid: React.FC<TemplateGridProps> = (props) => {
174
197
  gridColumn.options = await getLookupOptions(gridColumn.lookupType);
175
198
  gridColumn.valueField = "lookupValue";
176
199
  }
177
- }
200
+ }
178
201
  setGeneratedColumns(gridColumns);
179
202
  };
180
203
  const [rowSelectionModel, setRowSelectionModel] =
@@ -558,6 +581,49 @@ const TemplateGrid: React.FC<TemplateGridProps> = (props) => {
558
581
  }
559
582
  }
560
583
  }
584
+ if (props?.attachment) {
585
+ actions?.push(
586
+ <GridActionsCellItem
587
+ icon={
588
+ <Tooltip title={"Attachments"}>
589
+ <FontAwesomeIcon icon={"paperclip"} />
590
+ </Tooltip>
591
+ }
592
+ label={"Attachments"}
593
+ className="textPrimary"
594
+ color="inherit"
595
+ onClick={() => {
596
+ setSelectedRecord(record);
597
+ if (props?.attachment?.enableAttachFn) {
598
+ setAttachmentPanelEnabledForRecord(
599
+ props.attachment.enableAttachFn(record)
600
+ );
601
+ } else {
602
+ setAttachmentPanelEnabledForRecord(true);
603
+ }
604
+ setAttachmentWindowState(true);
605
+ }}
606
+ />
607
+ );
608
+ }
609
+ if (props?.workFlowDocumentCode) {
610
+ actions?.push(
611
+ <GridActionsCellItem
612
+ icon={
613
+ <Tooltip title={"Approvals"}>
614
+ <FontAwesomeIcon icon={"stamp"} />
615
+ </Tooltip>
616
+ }
617
+ label={"Approvals"}
618
+ className="textPrimary"
619
+ color="inherit"
620
+ onClick={() => {
621
+ setSelectedRecord(record);
622
+ setWorkFlowWindowState(true);
623
+ }}
624
+ />
625
+ );
626
+ }
561
627
  if (props?.rowActions) {
562
628
  for (const rowAction of props.rowActions) {
563
629
  if (
@@ -590,7 +656,9 @@ const TemplateGrid: React.FC<TemplateGridProps> = (props) => {
590
656
  width:
591
657
  (props?.rowActions ? props.rowActions.length * 30 : 0) +
592
658
  (props?.editAction && props?.editAction?.isEnabled ? 30 : 0) +
593
- (props?.deleteAction && props?.deleteAction?.isEnabled ? 30 : 0),
659
+ (props?.deleteAction && props?.deleteAction?.isEnabled ? 30 : 0) +
660
+ (props?.attachment ? 30 : 0) +
661
+ (props?.workFlowDocumentCode ? 30 : 0),
594
662
  getActions: getActionColumnActions,
595
663
  };
596
664
 
@@ -614,6 +682,10 @@ const TemplateGrid: React.FC<TemplateGridProps> = (props) => {
614
682
  adjustGridColumns();
615
683
  }, []);
616
684
 
685
+ useEffect(() => {
686
+ props.apiActions.reloadData(props?.gridLoadParametersValues);
687
+ }, [session.UserInfo?.currentOrganization]);
688
+
617
689
  useEffect(() => {
618
690
  adjustGridColumns();
619
691
  }, [themeDirection, props.formElements]);
@@ -698,6 +770,8 @@ const TemplateGrid: React.FC<TemplateGridProps> = (props) => {
698
770
  />
699
771
  ) : (
700
772
  <TemplateForm
773
+ keyColumnName={props.keyColumnName}
774
+ attachment={props.attachment}
701
775
  formLoadCallBk={props.formLoadCallBk}
702
776
  recordIdToEdit={
703
777
  recordToEdit ? recordToEdit[keyColumnName] : undefined
@@ -818,7 +892,34 @@ const TemplateGrid: React.FC<TemplateGridProps> = (props) => {
818
892
  ) : (
819
893
  <></>
820
894
  )}
821
-
895
+ {props?.attachment ? (
896
+ <AttachmentWindow>
897
+ <AttachmentPanel
898
+ attachmentCode={props.attachment.attachmentCode}
899
+ refKey={selectedRecord[props?.keyColumnName || "id"]}
900
+ enableAttachment={attachmentPanelEnabledForRecord}
901
+ />
902
+ </AttachmentWindow>
903
+ ) : (
904
+ <></>
905
+ )}
906
+ {props?.workFlowDocumentCode ? (
907
+ <WorkFlowWindow>
908
+ <WorkflowDocumentPanel
909
+ workFlowDocumentCode={props.workFlowDocumentCode}
910
+ refDocumentId={selectedRecord[props?.keyColumnName || "id"]}
911
+ postActionCallBk={() => {
912
+ setWorkFlowWindowState(false);
913
+ props.apiActions.reloadData(props.gridLoadParametersValues);
914
+ }}
915
+ cancelActionCallBk={() => {
916
+ setWorkFlowWindowState(false);
917
+ }}
918
+ />
919
+ </WorkFlowWindow>
920
+ ) : (
921
+ <></>
922
+ )}
822
923
  <DataGridPremium
823
924
  {...props?.muiProps}
824
925
  slots={{ toolbar: TemplateGridTopBar }}
@@ -0,0 +1,126 @@
1
+ import Card from "@mui/material/Card";
2
+ import CardActions from "@mui/material/CardActions";
3
+ import CardContent from "@mui/material/CardContent";
4
+ import CardMedia from "@mui/material/CardMedia";
5
+ import Button from "@mui/material/Button";
6
+ import Typography from "@mui/material/Typography";
7
+ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
8
+ import { IconButton, Tooltip } from "@mui/material";
9
+ import { useAxios, useConfirmationWindow } from "../../../hooks";
10
+ import AttachmentImageViewer from "./AttachmentImageViewer";
11
+
12
+ export type attachment = {
13
+ attachmentCode: string;
14
+ setAttachmentConfig: (props: any) => void;
15
+ id: number;
16
+ attachmentConfigId: number;
17
+ attachmentSize: number;
18
+ category: string;
19
+ docType: string;
20
+ fileName: string;
21
+ refKey: string;
22
+ remark: string;
23
+ };
24
+
25
+ const AttachmentCard: React.FC<attachment> = (props) => {
26
+ const { handleGetRequest, handleDeleteRequest } = useAxios();
27
+
28
+ const handleDelete = async () => {
29
+ await handleDeleteRequest({
30
+ endPointURI: "api/v1/attachment/archive",
31
+ parameters: {
32
+ attachmentCode: props.attachmentCode,
33
+ refKey: props.refKey,
34
+ attachmentId: props.id,
35
+ },
36
+ successCallBkFn: (response) => {
37
+ props.setAttachmentConfig(response.data);
38
+ },
39
+ showMask: true,
40
+ });
41
+ };
42
+ const { ConfirmationWindow, setOpen } = useConfirmationWindow({
43
+ title: "Confirmation",
44
+ body: "Are you sure you want to delete this attachment?",
45
+ onConfirmationCallBk: () => {
46
+ handleDelete();
47
+ },
48
+ });
49
+
50
+ const handleDownload = async () => {
51
+ await handleGetRequest({
52
+ endPointURI: "api/v1/attachment/download",
53
+ parameters: {
54
+ attachmentId: props.id,
55
+ },
56
+ showMask: true,
57
+ responseType: "blob",
58
+ successCallBkFn: (response) => {
59
+ const url = window.URL.createObjectURL(new Blob([response.data]));
60
+ const link = document.createElement("a");
61
+ link.href = url;
62
+ link.setAttribute("download", props.fileName);
63
+ document.body.appendChild(link);
64
+ link.click();
65
+ link.remove();
66
+ },
67
+ });
68
+ };
69
+
70
+ return (
71
+ <>
72
+ <ConfirmationWindow />
73
+ <Card sx={{ width: 300, border: "0.5px solid gray" }}>
74
+ <CardMedia
75
+ sx={{
76
+ height: 140,
77
+ width: 300,
78
+ display: "flex",
79
+ alignItems: "center",
80
+ justifyContent: "center",
81
+ }}
82
+ >
83
+ {props?.docType.toLocaleLowerCase().includes("image") ? (
84
+ <AttachmentImageViewer attachmentId={props.id} />
85
+ ) : (
86
+ <FontAwesomeIcon icon="file" size="3x" />
87
+ )}
88
+ </CardMedia>
89
+ <CardContent>
90
+ <Typography gutterBottom variant="h6" component="div">
91
+ {props.fileName}
92
+ </Typography>
93
+ <Typography variant="body2" sx={{ color: "text.secondary" }}>
94
+ {`File Size: ${props?.attachmentSize || "unknown"} kb`}
95
+ </Typography>
96
+ <Typography variant="body2" sx={{ color: "text.secondary" }}>
97
+ {`File Type: ${props?.category || "NA"}`}
98
+ </Typography>
99
+ <Typography variant="body2" sx={{ color: "text.secondary" }}>
100
+ {props.remark}
101
+ </Typography>
102
+ </CardContent>
103
+ <CardActions>
104
+ <IconButton
105
+ size="small"
106
+ onClick={() => {
107
+ setOpen(true);
108
+ }}
109
+ >
110
+ <Tooltip title="Delete Attachment">
111
+ <FontAwesomeIcon icon="trash" />
112
+ </Tooltip>
113
+ </IconButton>
114
+ <div style={{ flex: 1 }}></div>
115
+ <IconButton size="small" onClick={handleDownload}>
116
+ <Tooltip title="Download Attachment">
117
+ <FontAwesomeIcon icon="download" />
118
+ </Tooltip>
119
+ </IconButton>
120
+ </CardActions>
121
+ </Card>
122
+ </>
123
+ );
124
+ };
125
+
126
+ export default AttachmentCard;
@@ -0,0 +1,44 @@
1
+ import { useState } from "react";
2
+ import { useSelector } from "react-redux";
3
+ import { Avatar } from "@mui/material";
4
+
5
+ type AttachmentImageViewerProps = {
6
+ attachmentId?: number;
7
+ attachmentCode?: string;
8
+ refKey?: string;
9
+ category?: string;
10
+ showAsAvatar?: boolean;
11
+ };
12
+
13
+ const AttachmentImageViewer: React.FC<AttachmentImageViewerProps> = (props) => {
14
+ const apiBaseUrl = useSelector(
15
+ (state: any) => state.AppInfo.value.apiBaseUrl
16
+ );
17
+ let imagePath = apiBaseUrl + "/api/v1/attachment/";
18
+ if (props?.attachmentId) {
19
+ imagePath += "download?attachmentId=" + props.attachmentId;
20
+ } else {
21
+ imagePath += `downloadImage?attachmentCode=${props.attachmentCode}&refKey=${props.refKey}`;
22
+ if (props?.category) {
23
+ imagePath += `&category=${props.category}`;
24
+ }
25
+ }
26
+ const [imgSrc, setImgSrc] = useState(imagePath);
27
+ return props?.showAsAvatar ? (
28
+ <Avatar src={imgSrc} />
29
+ ) : (
30
+ <img
31
+ src={imgSrc}
32
+ alt="image"
33
+ onError={() => setImgSrc("/no_image.png")}
34
+ style={{
35
+ width: "100%",
36
+ height: "100%",
37
+ objectFit: "cover",
38
+ display: "block",
39
+ }}
40
+ />
41
+ );
42
+ };
43
+
44
+ export default AttachmentImageViewer;