@olenbetong/synergi-react 2.1.2 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/ob.react.css +1189 -27
- package/dist/esm/ob.react.js +45612 -708
- package/dist/esm/ob.react.min.css +24 -1
- package/dist/esm/ob.react.min.css.map +3 -3
- package/dist/esm/ob.react.min.js +253 -1
- package/dist/esm/ob.react.min.js.map +4 -4
- package/dist/iife/ob.react.css +1189 -27
- package/dist/iife/ob.react.js +45625 -720
- package/dist/iife/ob.react.min.css +24 -1
- package/dist/iife/ob.react.min.css.map +3 -3
- package/dist/iife/ob.react.min.js +253 -1
- package/dist/iife/ob.react.min.js.map +4 -4
- package/dist/styles/styles.css +1 -1
- package/dist/styles/styles.css.map +1 -1
- package/{src → es/components}/ColorCard/index.css +10 -6
- package/es/{DateNavigator → components/DateNavigator}/index.js +2 -0
- package/es/components/FilePond.d.ts +44 -0
- package/es/components/FilePond.js +205 -0
- package/es/{PageBanner → components/PageBanner}/index.js +0 -1
- package/es/{Sidebar → components/Sidebar}/index.d.ts +2 -2
- package/es/{SplitContainer → components/SplitContainer}/index.js +3 -3
- package/es/{ValueToggleGroup → components/ValueToggleGroup}/index.css +18 -16
- package/es/{ValueToggleGroup → components/ValueToggleGroup}/index.js +4 -2
- package/es/elements/ElementDamage/DamageFormButtons.d.ts +9 -0
- package/es/elements/ElementDamage/DamageFormButtons.js +7 -0
- package/es/elements/ElementDamage/DescriptionInput.d.ts +14 -0
- package/es/elements/ElementDamage/DescriptionInput.js +44 -0
- package/es/elements/ElementDamage/DuplicateDamage/DesktopView.d.ts +7 -0
- package/es/elements/ElementDamage/DuplicateDamage/DesktopView.js +16 -0
- package/es/elements/ElementDamage/DuplicateDamage/DublicateElementDamageDialog.d.ts +10 -0
- package/es/elements/ElementDamage/DuplicateDamage/DublicateElementDamageDialog.js +12 -0
- package/es/elements/ElementDamage/DuplicateDamage/PhoneView.d.ts +6 -0
- package/es/elements/ElementDamage/DuplicateDamage/PhoneView.js +8 -0
- package/es/elements/ElementDamage/DuplicateDamage/index.d.ts +36 -0
- package/es/elements/ElementDamage/DuplicateDamage/index.js +40 -0
- package/es/elements/ElementDamage/ElementNumberTextField.d.ts +10 -0
- package/es/elements/ElementDamage/ElementNumberTextField.js +18 -0
- package/es/elements/ElementDamage/HiddenDamageFields.d.ts +6 -0
- package/es/elements/ElementDamage/HiddenDamageFields.js +4 -0
- package/es/elements/ElementDamage/RegisterFix.d.ts +14 -0
- package/es/elements/ElementDamage/RegisterFix.js +45 -0
- package/es/elements/ElementDamage/SubmitButtons.d.ts +20 -0
- package/es/elements/ElementDamage/SubmitButtons.js +7 -0
- package/es/elements/ElementDamage/TransportElementSelect.d.ts +7 -0
- package/es/elements/ElementDamage/TransportElementSelect.js +16 -0
- package/es/elements/ElementDamage/index.css +3 -0
- package/es/elements/ElementLookup.d.ts +20 -0
- package/es/elements/ElementLookup.js +30 -0
- package/es/elements/ElementLookupDialog/BarcodeScanner/DeadIcon.d.ts +2 -0
- package/es/elements/ElementLookupDialog/BarcodeScanner/DeadIcon.js +5 -0
- package/es/elements/ElementLookupDialog/BarcodeScanner/Error.d.ts +4 -0
- package/es/elements/ElementLookupDialog/BarcodeScanner/Error.js +33 -0
- package/es/elements/ElementLookupDialog/BarcodeScanner/index.d.ts +10 -0
- package/es/elements/ElementLookupDialog/BarcodeScanner/index.js +37 -0
- package/es/elements/ElementLookupDialog/BarcodeScanner/useScanner.d.ts +16 -0
- package/es/elements/ElementLookupDialog/BarcodeScanner/useScanner.js +135 -0
- package/es/elements/ElementLookupDialog/HIDScanner/index.css +17 -0
- package/es/elements/ElementLookupDialog/HIDScanner/index.d.ts +4 -0
- package/es/elements/ElementLookupDialog/HIDScanner/index.js +36 -0
- package/es/elements/ElementLookupDialog/HIDScanner/useHIDScanner.d.ts +1 -0
- package/es/elements/ElementLookupDialog/HIDScanner/useHIDScanner.js +27 -0
- package/es/elements/ElementLookupDialog/Manual/ManualForm.d.ts +12 -0
- package/es/elements/ElementLookupDialog/Manual/ManualForm.js +48 -0
- package/es/elements/ElementLookupDialog/getElement.d.ts +23 -0
- package/es/elements/ElementLookupDialog/getElement.js +55 -0
- package/es/elements/ElementLookupDialog/index.d.ts +24 -0
- package/es/elements/ElementLookupDialog/index.js +97 -0
- package/es/elements/ElementLookupDialog/utils/Giai.d.ts +52 -0
- package/es/elements/ElementLookupDialog/utils/Giai.js +158 -0
- package/es/elements/ElementLookupDialog/utils/beep.d.ts +10 -0
- package/es/elements/ElementLookupDialog/utils/beep.js +20 -0
- package/es/elements/ProjectSelect.d.ts +23 -0
- package/es/elements/ProjectSelect.js +42 -0
- package/es/elements/data/dsAttachments.d.ts +15 -0
- package/es/elements/data/dsAttachments.js +85 -0
- package/es/elements/data/dsCurrentAttachment.d.ts +13 -0
- package/es/elements/data/dsCurrentAttachment.js +75 -0
- package/es/elements/data/dsDamages.d.ts +25 -0
- package/es/elements/data/dsDamages.js +127 -0
- package/es/elements/data/dsDamagesDuplicateCheck.d.ts +2 -0
- package/es/elements/data/dsDamagesDuplicateCheck.js +3 -0
- package/es/elements/data/dsElements.d.ts +8 -0
- package/es/elements/data/dsElements.js +47 -0
- package/es/elements/data/dsProjects.d.ts +8 -0
- package/es/elements/data/dsProjects.js +51 -0
- package/es/elements/data/dsReportProjects.d.ts +2 -0
- package/es/elements/data/dsReportProjects.js +3 -0
- package/es/elements/data/dsTransportElements.d.ts +10 -0
- package/es/elements/data/dsTransportElements.js +57 -0
- package/es/elements/data/index.d.ts +11 -0
- package/es/elements/data/index.js +11 -0
- package/es/elements/data/procApproveDamage.d.ts +2 -0
- package/es/elements/data/procApproveDamage.js +18 -0
- package/es/elements/data/procDeleteAttachment.d.ts +2 -0
- package/es/elements/data/procDeleteAttachment.js +18 -0
- package/es/elements/data/procDeleteDamage.d.ts +2 -0
- package/es/elements/data/procDeleteDamage.js +18 -0
- package/es/elements/data/procRemoveDamageFix.d.ts +2 -0
- package/es/elements/data/procRemoveDamageFix.js +18 -0
- package/es/elements/data/procRestoreAttachments.d.ts +2 -0
- package/es/elements/data/procRestoreAttachments.js +18 -0
- package/es/elements/index.d.ts +9 -0
- package/es/elements/index.js +9 -0
- package/es/index.css +1 -1
- package/es/index.d.ts +12 -11
- package/es/index.js +12 -11
- package/package.json +16 -40
- package/src/{Checkbox → components/Checkbox}/index.tsx +1 -1
- package/{es → src/components}/ColorCard/index.css +10 -6
- package/src/{DateNavigator → components/DateNavigator}/index.tsx +2 -0
- package/src/components/FilePond.tsx +312 -0
- package/src/{LinkedCardList → components/LinkedCardList}/index.scss +1 -1
- package/src/{PageBanner → components/PageBanner}/index.scss +1 -1
- package/src/{PageBanner → components/PageBanner}/index.tsx +0 -1
- package/src/{ProgressBar → components/ProgressBar}/index.scss +1 -1
- package/src/{Sidebar → components/Sidebar}/index.tsx +3 -2
- package/src/{SplitContainer → components/SplitContainer}/index.tsx +1 -1
- package/src/{ValueToggleGroup → components/ValueToggleGroup}/index.css +18 -16
- package/src/{ValueToggleGroup → components/ValueToggleGroup}/index.tsx +2 -1
- package/src/elements/ElementDamage/DamageFormButtons.tsx +35 -0
- package/src/elements/ElementDamage/DescriptionInput.tsx +111 -0
- package/src/elements/ElementDamage/DuplicateDamage/DesktopView.tsx +75 -0
- package/src/elements/ElementDamage/DuplicateDamage/DublicateElementDamageDialog.tsx +65 -0
- package/src/elements/ElementDamage/DuplicateDamage/PhoneView.tsx +42 -0
- package/src/elements/ElementDamage/DuplicateDamage/index.tsx +105 -0
- package/src/elements/ElementDamage/ElementNumberTextField.tsx +41 -0
- package/src/elements/ElementDamage/HiddenDamageFields.tsx +13 -0
- package/src/elements/ElementDamage/RegisterFix.tsx +100 -0
- package/src/elements/ElementDamage/SubmitButtons.tsx +40 -0
- package/src/elements/ElementDamage/TransportElementSelect.tsx +52 -0
- package/src/elements/ElementDamage/index.css +3 -0
- package/src/elements/ElementLookup.tsx +90 -0
- package/src/elements/ElementLookupDialog/BarcodeScanner/DeadIcon.tsx +12 -0
- package/src/elements/ElementLookupDialog/BarcodeScanner/Error.tsx +46 -0
- package/src/elements/ElementLookupDialog/BarcodeScanner/index.tsx +75 -0
- package/src/elements/ElementLookupDialog/BarcodeScanner/useScanner.ts +170 -0
- package/src/elements/ElementLookupDialog/HIDScanner/index.css +17 -0
- package/src/elements/ElementLookupDialog/HIDScanner/index.tsx +67 -0
- package/src/elements/ElementLookupDialog/HIDScanner/useHIDScanner.ts +30 -0
- package/src/elements/ElementLookupDialog/Manual/ManualForm.tsx +110 -0
- package/src/elements/ElementLookupDialog/getElement.ts +89 -0
- package/src/elements/ElementLookupDialog/index.tsx +211 -0
- package/src/elements/ElementLookupDialog/utils/Giai.ts +209 -0
- package/src/elements/ElementLookupDialog/utils/beep.ts +35 -0
- package/src/elements/ProjectSelect.tsx +128 -0
- package/src/elements/data/dsAttachments.ts +101 -0
- package/src/elements/data/dsCurrentAttachment.ts +89 -0
- package/src/elements/data/dsDamages.ts +166 -0
- package/src/elements/data/dsDamagesDuplicateCheck.ts +4 -0
- package/src/elements/data/dsElements.ts +56 -0
- package/src/elements/data/dsProjects.ts +60 -0
- package/src/elements/data/dsReportProjects.ts +4 -0
- package/src/elements/data/dsTransportElements.ts +68 -0
- package/src/elements/data/index.ts +11 -0
- package/src/elements/data/procApproveDamage.ts +19 -0
- package/src/elements/data/procDeleteAttachment.ts +19 -0
- package/src/elements/data/procDeleteDamage.ts +19 -0
- package/src/elements/data/procRemoveDamageFix.ts +19 -0
- package/src/elements/data/procRestoreAttachments.ts +19 -0
- package/src/elements/index.ts +9 -0
- package/src/index.scss +10 -10
- package/src/index.ts +13 -13
- /package/es/{Checkbox → components/Checkbox}/index.css +0 -0
- /package/es/{Checkbox → components/Checkbox}/index.d.ts +0 -0
- /package/es/{Checkbox → components/Checkbox}/index.js +0 -0
- /package/es/{ColorCard → components/ColorCard}/index.d.ts +0 -0
- /package/es/{ColorCard → components/ColorCard}/index.js +0 -0
- /package/es/{DateNavigator → components/DateNavigator}/index.css +0 -0
- /package/es/{DateNavigator → components/DateNavigator}/index.d.ts +0 -0
- /package/es/{LinkedCardList → components/LinkedCardList}/index.css +0 -0
- /package/es/{LinkedCardList → components/LinkedCardList}/index.d.ts +0 -0
- /package/es/{LinkedCardList → components/LinkedCardList}/index.js +0 -0
- /package/es/{PageBanner → components/PageBanner}/index.css +0 -0
- /package/es/{PageBanner → components/PageBanner}/index.d.ts +0 -0
- /package/es/{Portal → components/Portal}/index.d.ts +0 -0
- /package/es/{Portal → components/Portal}/index.js +0 -0
- /package/es/{ProgressBar → components/ProgressBar}/index.css +0 -0
- /package/es/{ProgressBar → components/ProgressBar}/index.d.ts +0 -0
- /package/es/{ProgressBar → components/ProgressBar}/index.js +0 -0
- /package/es/{Sidebar → components/Sidebar}/index.css +0 -0
- /package/es/{Sidebar → components/Sidebar}/index.js +0 -0
- /package/es/{Spinner → components/Spinner}/index.css +0 -0
- /package/es/{Spinner → components/Spinner}/index.d.ts +0 -0
- /package/es/{Spinner → components/Spinner}/index.js +0 -0
- /package/es/{SplitContainer → components/SplitContainer}/index.css +0 -0
- /package/es/{SplitContainer → components/SplitContainer}/index.d.ts +0 -0
- /package/es/{ValueToggleGroup → components/ValueToggleGroup}/index.d.ts +0 -0
- /package/src/{Checkbox → components/Checkbox}/index.scss +0 -0
- /package/src/{ColorCard → components/ColorCard}/index.tsx +0 -0
- /package/src/{DateNavigator → components/DateNavigator}/index.css +0 -0
- /package/src/{LinkedCardList → components/LinkedCardList}/index.tsx +0 -0
- /package/src/{Portal → components/Portal}/index.tsx +0 -0
- /package/src/{ProgressBar → components/ProgressBar}/index.tsx +0 -0
- /package/src/{Sidebar → components/Sidebar}/index.scss +0 -0
- /package/src/{Spinner → components/Spinner}/index.css +0 -0
- /package/src/{Spinner → components/Spinner}/index.tsx +0 -0
- /package/src/{SplitContainer → components/SplitContainer}/index.scss +0 -0
|
@@ -67,11 +67,11 @@ type DividerProps = {
|
|
|
67
67
|
|
|
68
68
|
const Divider = forwardRef<HTMLDivElement, DividerProps>(function Divider(props: DividerProps, ref) {
|
|
69
69
|
return (
|
|
70
|
+
// biome-ignore lint/a11y/useSemanticElements: NO!
|
|
70
71
|
<div
|
|
71
72
|
className={clsx("ObSplitContainer-divider", props.className)}
|
|
72
73
|
tabIndex={0}
|
|
73
74
|
ref={ref}
|
|
74
|
-
// biome-ignore lint/a11y/useSemanticElements: this is allowed according to WAI-ARIA
|
|
75
75
|
role="separator"
|
|
76
76
|
aria-orientation={props.direction}
|
|
77
77
|
aria-valuemin={props.min}
|
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
.ObValueToggleOption {
|
|
2
|
+
display: flex;
|
|
3
|
+
align-items: center;
|
|
4
|
+
margin: 0;
|
|
5
|
+
position: relative;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.ObValueToggleLabel {
|
|
9
|
+
font-size: 0.8em;
|
|
10
|
+
margin: 0 0.2em;
|
|
11
|
+
padding: 0.3em 0.5em;
|
|
12
|
+
text-transform: uppercase;
|
|
13
|
+
transition:
|
|
14
|
+
background 0.2s ease,
|
|
15
|
+
color 0.2s ease;
|
|
16
|
+
border-radius: 4px;
|
|
17
|
+
}
|
|
18
|
+
|
|
1
19
|
.ObValueToggleGroup {
|
|
2
20
|
padding: 0.25rem;
|
|
3
21
|
border: 2px solid rgb(0 0 0 / 0.2);
|
|
@@ -26,13 +44,6 @@
|
|
|
26
44
|
}
|
|
27
45
|
}
|
|
28
46
|
|
|
29
|
-
.ObValueToggleOption {
|
|
30
|
-
display: flex;
|
|
31
|
-
align-items: center;
|
|
32
|
-
margin: 0;
|
|
33
|
-
position: relative;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
47
|
.ObValueToggleOption input {
|
|
37
48
|
position: absolute;
|
|
38
49
|
width: 1px;
|
|
@@ -44,15 +55,6 @@
|
|
|
44
55
|
border: 0;
|
|
45
56
|
}
|
|
46
57
|
|
|
47
|
-
.ObValueToggleLabel {
|
|
48
|
-
font-size: 0.8em;
|
|
49
|
-
margin: 0 0.2em;
|
|
50
|
-
padding: 0.3em 0.5em;
|
|
51
|
-
text-transform: uppercase;
|
|
52
|
-
transition: background 0.2s ease, color 0.2s ease;
|
|
53
|
-
border-radius: 4px;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
58
|
.ObValueToggleOption:hover input:not(:disabled) + .ObValueToggleLabel {
|
|
57
59
|
cursor: pointer;
|
|
58
60
|
background: #ccc;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "./index.css";
|
|
2
2
|
|
|
3
|
-
import { forwardRef, useId } from "react";
|
|
4
3
|
import clsx from "clsx";
|
|
4
|
+
import { forwardRef, useId } from "react";
|
|
5
5
|
|
|
6
6
|
export type ValueToggleOption = {
|
|
7
7
|
value: string | number;
|
|
@@ -30,6 +30,7 @@ export const ValueToggleGroup = forwardRef<HTMLFieldSetElement, ValueToggleGroup
|
|
|
30
30
|
let isControlled = value !== undefined;
|
|
31
31
|
|
|
32
32
|
return (
|
|
33
|
+
// biome-ignore lint/a11y/noNoninteractiveElementToInteractiveRole: legacy component
|
|
33
34
|
<fieldset className={clsx("ObValueToggleGroup", orientation, className)} role="radiogroup" ref={ref} style={style}>
|
|
34
35
|
{options.map((opt) => {
|
|
35
36
|
return (
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import Add from "@mui/icons-material/Add";
|
|
2
|
+
import { Button } from "@mui/material";
|
|
3
|
+
import { getLocalizedString } from "@olenbetong/appframe-core";
|
|
4
|
+
|
|
5
|
+
type DamageFormButtonsProps = {
|
|
6
|
+
isEdit: boolean;
|
|
7
|
+
loading: boolean;
|
|
8
|
+
uploadingFile: boolean;
|
|
9
|
+
handleDelete: () => void;
|
|
10
|
+
handleCancel: () => void;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export function DamageFormButtonsProps({
|
|
14
|
+
isEdit,
|
|
15
|
+
loading,
|
|
16
|
+
uploadingFile,
|
|
17
|
+
handleDelete,
|
|
18
|
+
handleCancel,
|
|
19
|
+
}: DamageFormButtonsProps) {
|
|
20
|
+
return (
|
|
21
|
+
<>
|
|
22
|
+
{isEdit && <Button onClick={handleDelete}>{getLocalizedString("Delete")}</Button>}
|
|
23
|
+
<Button onClick={handleCancel}>{getLocalizedString("Cancel")}</Button>
|
|
24
|
+
<Button
|
|
25
|
+
loading={loading || uploadingFile}
|
|
26
|
+
loadingPosition="start"
|
|
27
|
+
startIcon={<Add />}
|
|
28
|
+
type="submit"
|
|
29
|
+
variant="contained"
|
|
30
|
+
>
|
|
31
|
+
{isEdit ? getLocalizedString("Save changes") : getLocalizedString("Register damage")}
|
|
32
|
+
</Button>
|
|
33
|
+
</>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { Autocomplete, Button, TextField } from "@mui/material";
|
|
2
|
+
import { getLocalizedString } from "@olenbetong/appframe-core";
|
|
3
|
+
import { useEffect, useRef, useState } from "react";
|
|
4
|
+
|
|
5
|
+
export type DescriptionInputType = {
|
|
6
|
+
Description?: string | null;
|
|
7
|
+
Cause?: string | null;
|
|
8
|
+
Action?: string | null;
|
|
9
|
+
Date?: Date;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
type DescriptionInputProps = {
|
|
13
|
+
value?: DescriptionInputType | null;
|
|
14
|
+
defaultValue?: DescriptionInputType | null;
|
|
15
|
+
onCopyPrevDamage?: (value: DescriptionInputType) => void;
|
|
16
|
+
onChange?: (value: DescriptionInputType) => void;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export function DescriptionInput({ value, defaultValue, onCopyPrevDamage, onChange }: DescriptionInputProps) {
|
|
20
|
+
let initializedRef = useRef<boolean>(false);
|
|
21
|
+
|
|
22
|
+
let [input, setInput] = useState<DescriptionInputType | null>(defaultValue ?? null);
|
|
23
|
+
let inputValue = value === undefined ? input : value;
|
|
24
|
+
|
|
25
|
+
// biome-ignore lint: intentionally skipping "value" dependency as this should never run when "value" changes
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
if (initializedRef.current) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (value === undefined && defaultValue) {
|
|
32
|
+
setInput(defaultValue);
|
|
33
|
+
initializedRef.current = true;
|
|
34
|
+
}
|
|
35
|
+
}, [defaultValue]);
|
|
36
|
+
|
|
37
|
+
function handleCopyPrevDamage() {
|
|
38
|
+
let description = localStorage.getItem("ElementDamage_Description") ?? "";
|
|
39
|
+
let cause = localStorage.getItem("ElementDamage_Cause") ?? "";
|
|
40
|
+
let action = localStorage.getItem("ElementDamage_Action") ?? "";
|
|
41
|
+
|
|
42
|
+
onCopyPrevDamage?.({
|
|
43
|
+
Description: description,
|
|
44
|
+
Cause: cause,
|
|
45
|
+
Action: action,
|
|
46
|
+
});
|
|
47
|
+
setInput({
|
|
48
|
+
...inputValue,
|
|
49
|
+
Description: description,
|
|
50
|
+
Cause: cause,
|
|
51
|
+
Action: action,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function handleOnChange(value: DescriptionInputType) {
|
|
56
|
+
onChange?.(value);
|
|
57
|
+
setInput(value);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<>
|
|
62
|
+
<TextField
|
|
63
|
+
name="Date"
|
|
64
|
+
type="date"
|
|
65
|
+
value={(inputValue?.Date ?? new Date()).toISOString().split("T")[0]}
|
|
66
|
+
onChange={(event) => handleOnChange({ ...inputValue, Date: new Date(event.target.value) })}
|
|
67
|
+
id="NewElementDamage_Date"
|
|
68
|
+
label={getLocalizedString("Date")}
|
|
69
|
+
fullWidth
|
|
70
|
+
required
|
|
71
|
+
slotProps={{ inputLabel: { shrink: true } }}
|
|
72
|
+
/>
|
|
73
|
+
|
|
74
|
+
<Button variant="contained" onClick={handleCopyPrevDamage}>
|
|
75
|
+
{getLocalizedString("Copy previous damage")}
|
|
76
|
+
</Button>
|
|
77
|
+
|
|
78
|
+
<Autocomplete
|
|
79
|
+
value={inputValue?.Description ?? ""}
|
|
80
|
+
onChange={(_event, value) => handleOnChange({ ...inputValue, Description: value ?? "" })}
|
|
81
|
+
options={[
|
|
82
|
+
getLocalizedString("Tear in element"),
|
|
83
|
+
getLocalizedString("Damage around lifting anchor"),
|
|
84
|
+
getLocalizedString("Damage on underside"),
|
|
85
|
+
]}
|
|
86
|
+
freeSolo
|
|
87
|
+
renderInput={(params) => (
|
|
88
|
+
<TextField name="Description" required {...(params as any)} label={getLocalizedString("Description")} />
|
|
89
|
+
)}
|
|
90
|
+
/>
|
|
91
|
+
|
|
92
|
+
<TextField
|
|
93
|
+
name="Cause"
|
|
94
|
+
id="NewElementDamage_Cause"
|
|
95
|
+
value={inputValue?.Cause ?? ""}
|
|
96
|
+
onChange={(event) => handleOnChange({ ...inputValue, Cause: event.currentTarget.value })}
|
|
97
|
+
label={getLocalizedString("Cause")}
|
|
98
|
+
fullWidth
|
|
99
|
+
/>
|
|
100
|
+
|
|
101
|
+
<TextField
|
|
102
|
+
name="Action"
|
|
103
|
+
id="NewElementDamage_Action"
|
|
104
|
+
value={inputValue?.Action ?? ""}
|
|
105
|
+
onChange={(event) => handleOnChange({ ...inputValue, Action: event.currentTarget.value })}
|
|
106
|
+
label={getLocalizedString("Action")}
|
|
107
|
+
fullWidth
|
|
108
|
+
/>
|
|
109
|
+
</>
|
|
110
|
+
);
|
|
111
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { Grid, type GridSize, Typography } from "@mui/material";
|
|
2
|
+
import { getLocalizedString } from "@olenbetong/appframe-core";
|
|
3
|
+
import { Link } from "@olenbetong/appframe-mui";
|
|
4
|
+
import type { DamagesRecord } from "../../data";
|
|
5
|
+
|
|
6
|
+
type SummaryItemProps = {
|
|
7
|
+
col: GridSize;
|
|
8
|
+
label?: string;
|
|
9
|
+
children?: React.ReactNode;
|
|
10
|
+
em?: boolean;
|
|
11
|
+
align?: "center" | "left" | "right";
|
|
12
|
+
padding?: string | number;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
function SummaryItem({ col, label, children, em, align, padding }: SummaryItemProps) {
|
|
16
|
+
return (
|
|
17
|
+
<Grid size={col} sx={{ p: padding ?? 2, borderBottom: (t) => `1px solid ${t.palette.divider}` }}>
|
|
18
|
+
{label && (
|
|
19
|
+
<Typography variant="body1" fontSize="0.9rem" fontWeight={500} mb={1} textAlign={align}>
|
|
20
|
+
{getLocalizedString(label)}
|
|
21
|
+
</Typography>
|
|
22
|
+
)}
|
|
23
|
+
{children && (
|
|
24
|
+
<Typography
|
|
25
|
+
fontSize={em ? "1.4rem" : "0.9rem"}
|
|
26
|
+
whiteSpace="pre-line"
|
|
27
|
+
fontWeight={em ? 600 : undefined}
|
|
28
|
+
textAlign={align}
|
|
29
|
+
>
|
|
30
|
+
{children}
|
|
31
|
+
</Typography>
|
|
32
|
+
)}
|
|
33
|
+
</Grid>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
type ElementDamagesItemProps = {
|
|
38
|
+
record: DamagesRecord;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export function ElementDamagesItem({ record }: ElementDamagesItemProps) {
|
|
42
|
+
return (
|
|
43
|
+
<>
|
|
44
|
+
<SummaryItem col={1.5}>
|
|
45
|
+
<Link
|
|
46
|
+
href="#"
|
|
47
|
+
onClick={(e) => {
|
|
48
|
+
e.preventDefault();
|
|
49
|
+
window.location.href = `${record.ID}`;
|
|
50
|
+
}}
|
|
51
|
+
>
|
|
52
|
+
{record.ID}
|
|
53
|
+
</Link>
|
|
54
|
+
</SummaryItem>
|
|
55
|
+
<SummaryItem col={2.5} align="right">
|
|
56
|
+
{record.Date.toISOString().split("T")[0]}
|
|
57
|
+
</SummaryItem>
|
|
58
|
+
<SummaryItem col={3}>{record.Description}</SummaryItem>
|
|
59
|
+
<SummaryItem col={2.5}>{record.Cause}</SummaryItem>
|
|
60
|
+
<SummaryItem col={2.5}>{record.Action}</SummaryItem>
|
|
61
|
+
</>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function ElementDamagesHeader() {
|
|
66
|
+
return (
|
|
67
|
+
<>
|
|
68
|
+
<SummaryItem col={1.5} label="ID" />
|
|
69
|
+
<SummaryItem col={2.5} label="Date" align="right" />
|
|
70
|
+
<SummaryItem col={3} label="Description" />
|
|
71
|
+
<SummaryItem col={2.5} label="Cause" />
|
|
72
|
+
<SummaryItem col={2.5} label="Action" />
|
|
73
|
+
</>
|
|
74
|
+
);
|
|
75
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import Add from "@mui/icons-material/Add";
|
|
2
|
+
import { Button, Dialog, DialogActions, DialogContent, DialogTitle, Grid, useMediaQuery } from "@mui/material";
|
|
3
|
+
import { getLocalizedString } from "@olenbetong/appframe-core";
|
|
4
|
+
import { theme } from "@olenbetong/appframe-mui";
|
|
5
|
+
import type { DamagesRecord } from "../../data";
|
|
6
|
+
import { ElementDamagesHeader, ElementDamagesItem } from "./DesktopView";
|
|
7
|
+
import { DuplicatePhoneViewItem } from "./PhoneView";
|
|
8
|
+
|
|
9
|
+
type DuplicateElementDamageDialogProps = {
|
|
10
|
+
open: boolean;
|
|
11
|
+
onClose: () => void;
|
|
12
|
+
record: DamagesRecord[];
|
|
13
|
+
onRegisterAnyway: () => void;
|
|
14
|
+
loading: boolean;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export function DuplicateElementDamageDialog({
|
|
18
|
+
open,
|
|
19
|
+
onClose,
|
|
20
|
+
record,
|
|
21
|
+
onRegisterAnyway,
|
|
22
|
+
loading,
|
|
23
|
+
}: DuplicateElementDamageDialogProps) {
|
|
24
|
+
let matches = useMediaQuery(theme.breakpoints.up("lg"));
|
|
25
|
+
let backgroundColor = "#e9ebee";
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<Dialog open={open} onClose={onClose} fullWidth fullScreen={!matches}>
|
|
29
|
+
<DialogTitle sx={{ backgroundColor: backgroundColor }}>
|
|
30
|
+
{getLocalizedString("This element has one or more unfixed registered damage")}
|
|
31
|
+
</DialogTitle>
|
|
32
|
+
<DialogContent sx={{ backgroundColor: backgroundColor }}>
|
|
33
|
+
<Grid container>
|
|
34
|
+
{matches ? (
|
|
35
|
+
<>
|
|
36
|
+
<ElementDamagesHeader />
|
|
37
|
+
{record.map((record) => (
|
|
38
|
+
<ElementDamagesItem key={record.PrimKey} record={record} />
|
|
39
|
+
))}
|
|
40
|
+
</>
|
|
41
|
+
) : (
|
|
42
|
+
<div className="flow" style={{ width: "100%" }}>
|
|
43
|
+
{record.map((record) => (
|
|
44
|
+
<DuplicatePhoneViewItem key={record.PrimKey} record={record} />
|
|
45
|
+
))}
|
|
46
|
+
</div>
|
|
47
|
+
)}
|
|
48
|
+
</Grid>
|
|
49
|
+
</DialogContent>
|
|
50
|
+
<DialogActions sx={{ backgroundColor: backgroundColor }}>
|
|
51
|
+
<Button onClick={onClose}>{getLocalizedString("Cancel")}</Button>
|
|
52
|
+
<Button
|
|
53
|
+
startIcon={<Add />}
|
|
54
|
+
variant="contained"
|
|
55
|
+
type="submit"
|
|
56
|
+
onClick={onRegisterAnyway}
|
|
57
|
+
loading={loading}
|
|
58
|
+
loadingPosition="start"
|
|
59
|
+
>
|
|
60
|
+
{getLocalizedString("Register damage anyway")}
|
|
61
|
+
</Button>
|
|
62
|
+
</DialogActions>
|
|
63
|
+
</Dialog>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Card, CardContent, Typography } from "@mui/material";
|
|
2
|
+
import { getLocalizedString } from "@olenbetong/appframe-core";
|
|
3
|
+
import type { DamagesRecord } from "../../data";
|
|
4
|
+
|
|
5
|
+
type DuplicatePhoneViewItemProps = {
|
|
6
|
+
record: DamagesRecord;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export function DuplicatePhoneViewItem({ record }: DuplicatePhoneViewItemProps) {
|
|
10
|
+
return (
|
|
11
|
+
<Card
|
|
12
|
+
variant="outlined"
|
|
13
|
+
onClick={() => {
|
|
14
|
+
window.location.href = `${record.ID}`;
|
|
15
|
+
}}
|
|
16
|
+
>
|
|
17
|
+
<CardContent>
|
|
18
|
+
<Typography sx={{ fontSize: 14 }} color="text.secondary" gutterBottom>
|
|
19
|
+
{record.Date.toLocaleDateString()}
|
|
20
|
+
</Typography>
|
|
21
|
+
<Typography variant="h5" mb={1.5}>
|
|
22
|
+
{record.ElementID} - {record.DisplayName}
|
|
23
|
+
</Typography>
|
|
24
|
+
|
|
25
|
+
<Typography>{getLocalizedString("Description")}:</Typography>
|
|
26
|
+
<Typography mb={1.5} color="text.secondary">
|
|
27
|
+
{record.Description}
|
|
28
|
+
</Typography>
|
|
29
|
+
|
|
30
|
+
<Typography>{getLocalizedString("Cause")}: </Typography>
|
|
31
|
+
<Typography mb={1.5} color="text.secondary">
|
|
32
|
+
{record.Cause}
|
|
33
|
+
</Typography>
|
|
34
|
+
|
|
35
|
+
<Typography>{getLocalizedString("Action")}: </Typography>
|
|
36
|
+
<Typography mb={1.5} color="text.secondary">
|
|
37
|
+
{record.Action}
|
|
38
|
+
</Typography>
|
|
39
|
+
</CardContent>
|
|
40
|
+
</Card>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { useDataWithFilter } from "@olenbetong/appframe-react";
|
|
2
|
+
import { forwardRef, useImperativeHandle, useMemo, useState } from "react";
|
|
3
|
+
import { type DamagesRecord, dsDamagesDuplicateCheck } from "../../data";
|
|
4
|
+
import type { Element } from "../../ElementLookup";
|
|
5
|
+
import { DuplicateElementDamageDialog } from "./DublicateElementDamageDialog";
|
|
6
|
+
|
|
7
|
+
export { DuplicateElementDamageDialog } from "./DublicateElementDamageDialog";
|
|
8
|
+
|
|
9
|
+
export type DuplicateElementDamageHandle = {
|
|
10
|
+
onClose: () => void;
|
|
11
|
+
checkDuplicate: () => Promise<DamagesRecord[] | null>;
|
|
12
|
+
record: DamagesRecord[];
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
type DuplicateElementDamageProps = {
|
|
16
|
+
element: Element | null;
|
|
17
|
+
/**
|
|
18
|
+
* External control of dialog visibility
|
|
19
|
+
*/
|
|
20
|
+
open?: boolean;
|
|
21
|
+
onOpenChange?: (value: boolean) => void;
|
|
22
|
+
/**
|
|
23
|
+
* Skip duplicate checking (used in edit mode)
|
|
24
|
+
*/
|
|
25
|
+
disableCheck?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Loading state for submit button
|
|
28
|
+
*/
|
|
29
|
+
loading?: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Called when duplicate or duplicates are found
|
|
32
|
+
* @param record Array with all of the duplicate damages
|
|
33
|
+
* @returns void
|
|
34
|
+
*/
|
|
35
|
+
onDuplicateFound?: (record: DamagesRecord[]) => void;
|
|
36
|
+
/**
|
|
37
|
+
* Called when user presses register anyway in dialog
|
|
38
|
+
* @returns void
|
|
39
|
+
*/
|
|
40
|
+
onRegisterAnyway?: () => void;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const DuplicateElementDamage = forwardRef<DuplicateElementDamageHandle, DuplicateElementDamageProps>(
|
|
44
|
+
function DuplicateElementDamage(
|
|
45
|
+
{
|
|
46
|
+
element,
|
|
47
|
+
open: controlledOpen,
|
|
48
|
+
onOpenChange,
|
|
49
|
+
disableCheck = false,
|
|
50
|
+
loading = false,
|
|
51
|
+
onRegisterAnyway,
|
|
52
|
+
}: DuplicateElementDamageProps,
|
|
53
|
+
ref,
|
|
54
|
+
) {
|
|
55
|
+
let [record, setRecord] = useState<DamagesRecord[]>([]);
|
|
56
|
+
let [uncontrolledOpen, setUncontrolledOpen] = useState<boolean>(false);
|
|
57
|
+
let open = controlledOpen === undefined ? uncontrolledOpen : controlledOpen;
|
|
58
|
+
|
|
59
|
+
let whereClause = useMemo(() => {
|
|
60
|
+
if (!element) {
|
|
61
|
+
return "1=0";
|
|
62
|
+
}
|
|
63
|
+
return `Domain = '${element.Domain}' AND ElementID = '${element.ElementID}' AND ProjectID = '${element.ProjectID}'`;
|
|
64
|
+
}, [element]);
|
|
65
|
+
|
|
66
|
+
let duplicateRecord = useDataWithFilter(dsDamagesDuplicateCheck, whereClause, "whereClause");
|
|
67
|
+
|
|
68
|
+
async function runDuplicateCheck(): Promise<DamagesRecord[] | null> {
|
|
69
|
+
// If we are editing a record, we don't need to check for duplicates
|
|
70
|
+
if (disableCheck) {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (duplicateRecord.length > 0) {
|
|
75
|
+
setRecord(duplicateRecord);
|
|
76
|
+
setUncontrolledOpen(true);
|
|
77
|
+
|
|
78
|
+
return duplicateRecord;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function handleOpenChange(value: boolean) {
|
|
85
|
+
setUncontrolledOpen(value);
|
|
86
|
+
onOpenChange?.(value);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
useImperativeHandle(ref, () => ({
|
|
90
|
+
onClose: () => setUncontrolledOpen(false),
|
|
91
|
+
checkDuplicate: () => runDuplicateCheck(),
|
|
92
|
+
record: record,
|
|
93
|
+
}));
|
|
94
|
+
|
|
95
|
+
return (
|
|
96
|
+
<DuplicateElementDamageDialog
|
|
97
|
+
open={open}
|
|
98
|
+
onClose={() => handleOpenChange(false)}
|
|
99
|
+
record={record}
|
|
100
|
+
onRegisterAnyway={onRegisterAnyway ?? (() => {})}
|
|
101
|
+
loading={loading ?? false}
|
|
102
|
+
/>
|
|
103
|
+
);
|
|
104
|
+
},
|
|
105
|
+
);
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type SxProps, TextField, type Theme } from "@mui/material";
|
|
2
|
+
import { getLocalizedString } from "@olenbetong/appframe-core";
|
|
3
|
+
import { useEffect, useState } from "react";
|
|
4
|
+
|
|
5
|
+
type ElementNumberTextFieldProps = {
|
|
6
|
+
value?: string | null;
|
|
7
|
+
defaultValue?: string | null;
|
|
8
|
+
onChange?: (value: string) => void;
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
sx?: SxProps<Theme>;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export function ElementNumberTextField({ value, defaultValue, onChange, disabled, sx }: ElementNumberTextFieldProps) {
|
|
14
|
+
let [elementNumber, setElementNumber] = useState<string>(defaultValue ?? "");
|
|
15
|
+
let elementNumberValue = value === undefined ? elementNumber : value;
|
|
16
|
+
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
if (value === undefined && defaultValue) {
|
|
19
|
+
setElementNumber(defaultValue);
|
|
20
|
+
}
|
|
21
|
+
}, [defaultValue, value]);
|
|
22
|
+
|
|
23
|
+
function handleChange(value: string) {
|
|
24
|
+
onChange?.(value);
|
|
25
|
+
setElementNumber(value);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<TextField
|
|
30
|
+
name="ElementNumber"
|
|
31
|
+
id="NewElementDamage_ElementNr"
|
|
32
|
+
value={elementNumberValue}
|
|
33
|
+
onChange={(event) => handleChange(event.currentTarget.value)}
|
|
34
|
+
label={getLocalizedString("Element number")}
|
|
35
|
+
fullWidth
|
|
36
|
+
autoComplete="off"
|
|
37
|
+
disabled={disabled ?? false}
|
|
38
|
+
sx={{ ...sx }}
|
|
39
|
+
/>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
type HiddenDamageFieldsProps = {
|
|
2
|
+
primKey: string;
|
|
3
|
+
ID: number;
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
export function HiddenDamageFields({ primKey, ID }: HiddenDamageFieldsProps) {
|
|
7
|
+
return (
|
|
8
|
+
<>
|
|
9
|
+
<input type="hidden" name="PrimKey" value={primKey} />
|
|
10
|
+
<input type="hidden" name="ID" value={ID} />
|
|
11
|
+
</>
|
|
12
|
+
);
|
|
13
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import CheckIcon from "@mui/icons-material/Check";
|
|
2
|
+
import { Button, Checkbox, FormControlLabel, Typography } from "@mui/material";
|
|
3
|
+
import { getLocalizedString, localize } from "@olenbetong/appframe-core";
|
|
4
|
+
|
|
5
|
+
import { useEffect, useRef, useState } from "react";
|
|
6
|
+
|
|
7
|
+
import { procApproveDamage } from "../data";
|
|
8
|
+
|
|
9
|
+
const formatter = new Intl.DateTimeFormat(af.userSession.culture, {
|
|
10
|
+
day: "numeric",
|
|
11
|
+
month: "long",
|
|
12
|
+
year: "numeric",
|
|
13
|
+
hour: "2-digit",
|
|
14
|
+
minute: "2-digit",
|
|
15
|
+
timeZone: "UTC",
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
type RegisterFixType = {
|
|
19
|
+
ID: number;
|
|
20
|
+
RegisteredFixFullName: string | null;
|
|
21
|
+
RegisteredFix: Date | null;
|
|
22
|
+
RegisteredFixBy: string | null;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
type ApproveDamageProcedureRecord = {
|
|
26
|
+
Table: Array<Required<RegisterFixType>>;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
type RegisterFixProps = {
|
|
30
|
+
value?: RegisterFixType | null;
|
|
31
|
+
defaultValue?: RegisterFixType | null;
|
|
32
|
+
onFix?: (ID: number) => void;
|
|
33
|
+
edit?: boolean;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export function RegisterFix({ value, defaultValue, onFix, edit }: RegisterFixProps) {
|
|
37
|
+
let [loading, setLoading] = useState<boolean>(false);
|
|
38
|
+
let initializedRef = useRef<boolean>(false);
|
|
39
|
+
|
|
40
|
+
let [fix, setFix] = useState<RegisterFixType | null>(defaultValue ?? null);
|
|
41
|
+
let fixValue = value === undefined ? fix : value;
|
|
42
|
+
|
|
43
|
+
// biome-ignore lint: intentionally skipping "value" dependency as this should never run when "value" changes
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
if (initializedRef.current) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (value === undefined && defaultValue) {
|
|
50
|
+
setFix(defaultValue);
|
|
51
|
+
initializedRef.current = true;
|
|
52
|
+
}
|
|
53
|
+
}, [defaultValue]);
|
|
54
|
+
|
|
55
|
+
async function handleRegisterFix() {
|
|
56
|
+
try {
|
|
57
|
+
if (confirm(getLocalizedString("Are you sure you want to register a fix for this damage?"))) {
|
|
58
|
+
setLoading(true);
|
|
59
|
+
let record = (await procApproveDamage.execute({ ID: fixValue?.ID })) as ApproveDamageProcedureRecord;
|
|
60
|
+
|
|
61
|
+
setFix({ ...record.Table[0] });
|
|
62
|
+
|
|
63
|
+
setLoading(false);
|
|
64
|
+
onFix?.(fixValue?.ID ?? -1);
|
|
65
|
+
}
|
|
66
|
+
} catch (error) {
|
|
67
|
+
alert((error as Error).message);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<>
|
|
73
|
+
{edit ? (
|
|
74
|
+
<Button
|
|
75
|
+
loading={loading}
|
|
76
|
+
loadingPosition="end"
|
|
77
|
+
endIcon={<CheckIcon />}
|
|
78
|
+
onClick={handleRegisterFix}
|
|
79
|
+
disabled={!!fixValue?.RegisteredFix}
|
|
80
|
+
variant="contained"
|
|
81
|
+
>
|
|
82
|
+
{getLocalizedString("Register fix")}
|
|
83
|
+
</Button>
|
|
84
|
+
) : (
|
|
85
|
+
<FormControlLabel
|
|
86
|
+
control={<Checkbox />}
|
|
87
|
+
label={getLocalizedString("Register fixed")}
|
|
88
|
+
name="RegisteredFix"
|
|
89
|
+
id="NewElementDamage_RegisteredFix"
|
|
90
|
+
/>
|
|
91
|
+
)}
|
|
92
|
+
|
|
93
|
+
{fixValue?.RegisteredFix && (
|
|
94
|
+
<Typography mb={1.5} color="text.secondary">
|
|
95
|
+
{localize`Registered fix by ${fixValue.RegisteredFixFullName ?? fixValue.RegisteredFixBy} on the ${formatter.format(fixValue.RegisteredFix)}`}
|
|
96
|
+
</Typography>
|
|
97
|
+
)}
|
|
98
|
+
</>
|
|
99
|
+
);
|
|
100
|
+
}
|