@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.
Files changed (197) hide show
  1. package/dist/esm/ob.react.css +1189 -27
  2. package/dist/esm/ob.react.js +45612 -708
  3. package/dist/esm/ob.react.min.css +24 -1
  4. package/dist/esm/ob.react.min.css.map +3 -3
  5. package/dist/esm/ob.react.min.js +253 -1
  6. package/dist/esm/ob.react.min.js.map +4 -4
  7. package/dist/iife/ob.react.css +1189 -27
  8. package/dist/iife/ob.react.js +45625 -720
  9. package/dist/iife/ob.react.min.css +24 -1
  10. package/dist/iife/ob.react.min.css.map +3 -3
  11. package/dist/iife/ob.react.min.js +253 -1
  12. package/dist/iife/ob.react.min.js.map +4 -4
  13. package/dist/styles/styles.css +1 -1
  14. package/dist/styles/styles.css.map +1 -1
  15. package/{src → es/components}/ColorCard/index.css +10 -6
  16. package/es/{DateNavigator → components/DateNavigator}/index.js +2 -0
  17. package/es/components/FilePond.d.ts +44 -0
  18. package/es/components/FilePond.js +205 -0
  19. package/es/{PageBanner → components/PageBanner}/index.js +0 -1
  20. package/es/{Sidebar → components/Sidebar}/index.d.ts +2 -2
  21. package/es/{SplitContainer → components/SplitContainer}/index.js +3 -3
  22. package/es/{ValueToggleGroup → components/ValueToggleGroup}/index.css +18 -16
  23. package/es/{ValueToggleGroup → components/ValueToggleGroup}/index.js +4 -2
  24. package/es/elements/ElementDamage/DamageFormButtons.d.ts +9 -0
  25. package/es/elements/ElementDamage/DamageFormButtons.js +7 -0
  26. package/es/elements/ElementDamage/DescriptionInput.d.ts +14 -0
  27. package/es/elements/ElementDamage/DescriptionInput.js +44 -0
  28. package/es/elements/ElementDamage/DuplicateDamage/DesktopView.d.ts +7 -0
  29. package/es/elements/ElementDamage/DuplicateDamage/DesktopView.js +16 -0
  30. package/es/elements/ElementDamage/DuplicateDamage/DublicateElementDamageDialog.d.ts +10 -0
  31. package/es/elements/ElementDamage/DuplicateDamage/DublicateElementDamageDialog.js +12 -0
  32. package/es/elements/ElementDamage/DuplicateDamage/PhoneView.d.ts +6 -0
  33. package/es/elements/ElementDamage/DuplicateDamage/PhoneView.js +8 -0
  34. package/es/elements/ElementDamage/DuplicateDamage/index.d.ts +36 -0
  35. package/es/elements/ElementDamage/DuplicateDamage/index.js +40 -0
  36. package/es/elements/ElementDamage/ElementNumberTextField.d.ts +10 -0
  37. package/es/elements/ElementDamage/ElementNumberTextField.js +18 -0
  38. package/es/elements/ElementDamage/HiddenDamageFields.d.ts +6 -0
  39. package/es/elements/ElementDamage/HiddenDamageFields.js +4 -0
  40. package/es/elements/ElementDamage/RegisterFix.d.ts +14 -0
  41. package/es/elements/ElementDamage/RegisterFix.js +45 -0
  42. package/es/elements/ElementDamage/SubmitButtons.d.ts +20 -0
  43. package/es/elements/ElementDamage/SubmitButtons.js +7 -0
  44. package/es/elements/ElementDamage/TransportElementSelect.d.ts +7 -0
  45. package/es/elements/ElementDamage/TransportElementSelect.js +16 -0
  46. package/es/elements/ElementDamage/index.css +3 -0
  47. package/es/elements/ElementLookup.d.ts +20 -0
  48. package/es/elements/ElementLookup.js +30 -0
  49. package/es/elements/ElementLookupDialog/BarcodeScanner/DeadIcon.d.ts +2 -0
  50. package/es/elements/ElementLookupDialog/BarcodeScanner/DeadIcon.js +5 -0
  51. package/es/elements/ElementLookupDialog/BarcodeScanner/Error.d.ts +4 -0
  52. package/es/elements/ElementLookupDialog/BarcodeScanner/Error.js +33 -0
  53. package/es/elements/ElementLookupDialog/BarcodeScanner/index.d.ts +10 -0
  54. package/es/elements/ElementLookupDialog/BarcodeScanner/index.js +37 -0
  55. package/es/elements/ElementLookupDialog/BarcodeScanner/useScanner.d.ts +16 -0
  56. package/es/elements/ElementLookupDialog/BarcodeScanner/useScanner.js +135 -0
  57. package/es/elements/ElementLookupDialog/HIDScanner/index.css +17 -0
  58. package/es/elements/ElementLookupDialog/HIDScanner/index.d.ts +4 -0
  59. package/es/elements/ElementLookupDialog/HIDScanner/index.js +36 -0
  60. package/es/elements/ElementLookupDialog/HIDScanner/useHIDScanner.d.ts +1 -0
  61. package/es/elements/ElementLookupDialog/HIDScanner/useHIDScanner.js +27 -0
  62. package/es/elements/ElementLookupDialog/Manual/ManualForm.d.ts +12 -0
  63. package/es/elements/ElementLookupDialog/Manual/ManualForm.js +48 -0
  64. package/es/elements/ElementLookupDialog/getElement.d.ts +23 -0
  65. package/es/elements/ElementLookupDialog/getElement.js +55 -0
  66. package/es/elements/ElementLookupDialog/index.d.ts +24 -0
  67. package/es/elements/ElementLookupDialog/index.js +97 -0
  68. package/es/elements/ElementLookupDialog/utils/Giai.d.ts +52 -0
  69. package/es/elements/ElementLookupDialog/utils/Giai.js +158 -0
  70. package/es/elements/ElementLookupDialog/utils/beep.d.ts +10 -0
  71. package/es/elements/ElementLookupDialog/utils/beep.js +20 -0
  72. package/es/elements/ProjectSelect.d.ts +23 -0
  73. package/es/elements/ProjectSelect.js +42 -0
  74. package/es/elements/data/dsAttachments.d.ts +15 -0
  75. package/es/elements/data/dsAttachments.js +85 -0
  76. package/es/elements/data/dsCurrentAttachment.d.ts +13 -0
  77. package/es/elements/data/dsCurrentAttachment.js +75 -0
  78. package/es/elements/data/dsDamages.d.ts +25 -0
  79. package/es/elements/data/dsDamages.js +127 -0
  80. package/es/elements/data/dsDamagesDuplicateCheck.d.ts +2 -0
  81. package/es/elements/data/dsDamagesDuplicateCheck.js +3 -0
  82. package/es/elements/data/dsElements.d.ts +8 -0
  83. package/es/elements/data/dsElements.js +47 -0
  84. package/es/elements/data/dsProjects.d.ts +8 -0
  85. package/es/elements/data/dsProjects.js +51 -0
  86. package/es/elements/data/dsReportProjects.d.ts +2 -0
  87. package/es/elements/data/dsReportProjects.js +3 -0
  88. package/es/elements/data/dsTransportElements.d.ts +10 -0
  89. package/es/elements/data/dsTransportElements.js +57 -0
  90. package/es/elements/data/index.d.ts +11 -0
  91. package/es/elements/data/index.js +11 -0
  92. package/es/elements/data/procApproveDamage.d.ts +2 -0
  93. package/es/elements/data/procApproveDamage.js +18 -0
  94. package/es/elements/data/procDeleteAttachment.d.ts +2 -0
  95. package/es/elements/data/procDeleteAttachment.js +18 -0
  96. package/es/elements/data/procDeleteDamage.d.ts +2 -0
  97. package/es/elements/data/procDeleteDamage.js +18 -0
  98. package/es/elements/data/procRemoveDamageFix.d.ts +2 -0
  99. package/es/elements/data/procRemoveDamageFix.js +18 -0
  100. package/es/elements/data/procRestoreAttachments.d.ts +2 -0
  101. package/es/elements/data/procRestoreAttachments.js +18 -0
  102. package/es/elements/index.d.ts +9 -0
  103. package/es/elements/index.js +9 -0
  104. package/es/index.css +1 -1
  105. package/es/index.d.ts +12 -11
  106. package/es/index.js +12 -11
  107. package/package.json +16 -40
  108. package/src/{Checkbox → components/Checkbox}/index.tsx +1 -1
  109. package/{es → src/components}/ColorCard/index.css +10 -6
  110. package/src/{DateNavigator → components/DateNavigator}/index.tsx +2 -0
  111. package/src/components/FilePond.tsx +312 -0
  112. package/src/{LinkedCardList → components/LinkedCardList}/index.scss +1 -1
  113. package/src/{PageBanner → components/PageBanner}/index.scss +1 -1
  114. package/src/{PageBanner → components/PageBanner}/index.tsx +0 -1
  115. package/src/{ProgressBar → components/ProgressBar}/index.scss +1 -1
  116. package/src/{Sidebar → components/Sidebar}/index.tsx +3 -2
  117. package/src/{SplitContainer → components/SplitContainer}/index.tsx +1 -1
  118. package/src/{ValueToggleGroup → components/ValueToggleGroup}/index.css +18 -16
  119. package/src/{ValueToggleGroup → components/ValueToggleGroup}/index.tsx +2 -1
  120. package/src/elements/ElementDamage/DamageFormButtons.tsx +35 -0
  121. package/src/elements/ElementDamage/DescriptionInput.tsx +111 -0
  122. package/src/elements/ElementDamage/DuplicateDamage/DesktopView.tsx +75 -0
  123. package/src/elements/ElementDamage/DuplicateDamage/DublicateElementDamageDialog.tsx +65 -0
  124. package/src/elements/ElementDamage/DuplicateDamage/PhoneView.tsx +42 -0
  125. package/src/elements/ElementDamage/DuplicateDamage/index.tsx +105 -0
  126. package/src/elements/ElementDamage/ElementNumberTextField.tsx +41 -0
  127. package/src/elements/ElementDamage/HiddenDamageFields.tsx +13 -0
  128. package/src/elements/ElementDamage/RegisterFix.tsx +100 -0
  129. package/src/elements/ElementDamage/SubmitButtons.tsx +40 -0
  130. package/src/elements/ElementDamage/TransportElementSelect.tsx +52 -0
  131. package/src/elements/ElementDamage/index.css +3 -0
  132. package/src/elements/ElementLookup.tsx +90 -0
  133. package/src/elements/ElementLookupDialog/BarcodeScanner/DeadIcon.tsx +12 -0
  134. package/src/elements/ElementLookupDialog/BarcodeScanner/Error.tsx +46 -0
  135. package/src/elements/ElementLookupDialog/BarcodeScanner/index.tsx +75 -0
  136. package/src/elements/ElementLookupDialog/BarcodeScanner/useScanner.ts +170 -0
  137. package/src/elements/ElementLookupDialog/HIDScanner/index.css +17 -0
  138. package/src/elements/ElementLookupDialog/HIDScanner/index.tsx +67 -0
  139. package/src/elements/ElementLookupDialog/HIDScanner/useHIDScanner.ts +30 -0
  140. package/src/elements/ElementLookupDialog/Manual/ManualForm.tsx +110 -0
  141. package/src/elements/ElementLookupDialog/getElement.ts +89 -0
  142. package/src/elements/ElementLookupDialog/index.tsx +211 -0
  143. package/src/elements/ElementLookupDialog/utils/Giai.ts +209 -0
  144. package/src/elements/ElementLookupDialog/utils/beep.ts +35 -0
  145. package/src/elements/ProjectSelect.tsx +128 -0
  146. package/src/elements/data/dsAttachments.ts +101 -0
  147. package/src/elements/data/dsCurrentAttachment.ts +89 -0
  148. package/src/elements/data/dsDamages.ts +166 -0
  149. package/src/elements/data/dsDamagesDuplicateCheck.ts +4 -0
  150. package/src/elements/data/dsElements.ts +56 -0
  151. package/src/elements/data/dsProjects.ts +60 -0
  152. package/src/elements/data/dsReportProjects.ts +4 -0
  153. package/src/elements/data/dsTransportElements.ts +68 -0
  154. package/src/elements/data/index.ts +11 -0
  155. package/src/elements/data/procApproveDamage.ts +19 -0
  156. package/src/elements/data/procDeleteAttachment.ts +19 -0
  157. package/src/elements/data/procDeleteDamage.ts +19 -0
  158. package/src/elements/data/procRemoveDamageFix.ts +19 -0
  159. package/src/elements/data/procRestoreAttachments.ts +19 -0
  160. package/src/elements/index.ts +9 -0
  161. package/src/index.scss +10 -10
  162. package/src/index.ts +13 -13
  163. /package/es/{Checkbox → components/Checkbox}/index.css +0 -0
  164. /package/es/{Checkbox → components/Checkbox}/index.d.ts +0 -0
  165. /package/es/{Checkbox → components/Checkbox}/index.js +0 -0
  166. /package/es/{ColorCard → components/ColorCard}/index.d.ts +0 -0
  167. /package/es/{ColorCard → components/ColorCard}/index.js +0 -0
  168. /package/es/{DateNavigator → components/DateNavigator}/index.css +0 -0
  169. /package/es/{DateNavigator → components/DateNavigator}/index.d.ts +0 -0
  170. /package/es/{LinkedCardList → components/LinkedCardList}/index.css +0 -0
  171. /package/es/{LinkedCardList → components/LinkedCardList}/index.d.ts +0 -0
  172. /package/es/{LinkedCardList → components/LinkedCardList}/index.js +0 -0
  173. /package/es/{PageBanner → components/PageBanner}/index.css +0 -0
  174. /package/es/{PageBanner → components/PageBanner}/index.d.ts +0 -0
  175. /package/es/{Portal → components/Portal}/index.d.ts +0 -0
  176. /package/es/{Portal → components/Portal}/index.js +0 -0
  177. /package/es/{ProgressBar → components/ProgressBar}/index.css +0 -0
  178. /package/es/{ProgressBar → components/ProgressBar}/index.d.ts +0 -0
  179. /package/es/{ProgressBar → components/ProgressBar}/index.js +0 -0
  180. /package/es/{Sidebar → components/Sidebar}/index.css +0 -0
  181. /package/es/{Sidebar → components/Sidebar}/index.js +0 -0
  182. /package/es/{Spinner → components/Spinner}/index.css +0 -0
  183. /package/es/{Spinner → components/Spinner}/index.d.ts +0 -0
  184. /package/es/{Spinner → components/Spinner}/index.js +0 -0
  185. /package/es/{SplitContainer → components/SplitContainer}/index.css +0 -0
  186. /package/es/{SplitContainer → components/SplitContainer}/index.d.ts +0 -0
  187. /package/es/{ValueToggleGroup → components/ValueToggleGroup}/index.d.ts +0 -0
  188. /package/src/{Checkbox → components/Checkbox}/index.scss +0 -0
  189. /package/src/{ColorCard → components/ColorCard}/index.tsx +0 -0
  190. /package/src/{DateNavigator → components/DateNavigator}/index.css +0 -0
  191. /package/src/{LinkedCardList → components/LinkedCardList}/index.tsx +0 -0
  192. /package/src/{Portal → components/Portal}/index.tsx +0 -0
  193. /package/src/{ProgressBar → components/ProgressBar}/index.tsx +0 -0
  194. /package/src/{Sidebar → components/Sidebar}/index.scss +0 -0
  195. /package/src/{Spinner → components/Spinner}/index.css +0 -0
  196. /package/src/{Spinner → components/Spinner}/index.tsx +0 -0
  197. /package/src/{SplitContainer → components/SplitContainer}/index.scss +0 -0
@@ -0,0 +1,6 @@
1
+ import type { DamagesRecord } from "../../data";
2
+ type DuplicatePhoneViewItemProps = {
3
+ record: DamagesRecord;
4
+ };
5
+ export declare function DuplicatePhoneViewItem({ record }: DuplicatePhoneViewItemProps): import("react/jsx-runtime").JSX.Element;
6
+ export {};
@@ -0,0 +1,8 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Card, CardContent, Typography } from "@mui/material";
3
+ import { getLocalizedString } from "@olenbetong/appframe-core";
4
+ export function DuplicatePhoneViewItem({ record }) {
5
+ return (_jsx(Card, { variant: "outlined", onClick: () => {
6
+ window.location.href = `${record.ID}`;
7
+ }, children: _jsxs(CardContent, { children: [_jsx(Typography, { sx: { fontSize: 14 }, color: "text.secondary", gutterBottom: true, children: record.Date.toLocaleDateString() }), _jsxs(Typography, { variant: "h5", mb: 1.5, children: [record.ElementID, " - ", record.DisplayName] }), _jsxs(Typography, { children: [getLocalizedString("Description"), ":"] }), _jsx(Typography, { mb: 1.5, color: "text.secondary", children: record.Description }), _jsxs(Typography, { children: [getLocalizedString("Cause"), ": "] }), _jsx(Typography, { mb: 1.5, color: "text.secondary", children: record.Cause }), _jsxs(Typography, { children: [getLocalizedString("Action"), ": "] }), _jsx(Typography, { mb: 1.5, color: "text.secondary", children: record.Action })] }) }));
8
+ }
@@ -0,0 +1,36 @@
1
+ import { type DamagesRecord } from "../../data";
2
+ import type { Element } from "../../ElementLookup";
3
+ export { DuplicateElementDamageDialog } from "./DublicateElementDamageDialog";
4
+ export type DuplicateElementDamageHandle = {
5
+ onClose: () => void;
6
+ checkDuplicate: () => Promise<DamagesRecord[] | null>;
7
+ record: DamagesRecord[];
8
+ };
9
+ type DuplicateElementDamageProps = {
10
+ element: Element | null;
11
+ /**
12
+ * External control of dialog visibility
13
+ */
14
+ open?: boolean;
15
+ onOpenChange?: (value: boolean) => void;
16
+ /**
17
+ * Skip duplicate checking (used in edit mode)
18
+ */
19
+ disableCheck?: boolean;
20
+ /**
21
+ * Loading state for submit button
22
+ */
23
+ loading?: boolean;
24
+ /**
25
+ * Called when duplicate or duplicates are found
26
+ * @param record Array with all of the duplicate damages
27
+ * @returns void
28
+ */
29
+ onDuplicateFound?: (record: DamagesRecord[]) => void;
30
+ /**
31
+ * Called when user presses register anyway in dialog
32
+ * @returns void
33
+ */
34
+ onRegisterAnyway?: () => void;
35
+ };
36
+ export declare const DuplicateElementDamage: import("react").ForwardRefExoticComponent<DuplicateElementDamageProps & import("react").RefAttributes<DuplicateElementDamageHandle>>;
@@ -0,0 +1,40 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useDataWithFilter } from "@olenbetong/appframe-react";
3
+ import { forwardRef, useImperativeHandle, useMemo, useState } from "react";
4
+ import { dsDamagesDuplicateCheck } from "../../data";
5
+ import { DuplicateElementDamageDialog } from "./DublicateElementDamageDialog";
6
+ export { DuplicateElementDamageDialog } from "./DublicateElementDamageDialog";
7
+ export const DuplicateElementDamage = forwardRef(function DuplicateElementDamage({ element, open: controlledOpen, onOpenChange, disableCheck = false, loading = false, onRegisterAnyway, }, ref) {
8
+ let [record, setRecord] = useState([]);
9
+ let [uncontrolledOpen, setUncontrolledOpen] = useState(false);
10
+ let open = controlledOpen === undefined ? uncontrolledOpen : controlledOpen;
11
+ let whereClause = useMemo(() => {
12
+ if (!element) {
13
+ return "1=0";
14
+ }
15
+ return `Domain = '${element.Domain}' AND ElementID = '${element.ElementID}' AND ProjectID = '${element.ProjectID}'`;
16
+ }, [element]);
17
+ let duplicateRecord = useDataWithFilter(dsDamagesDuplicateCheck, whereClause, "whereClause");
18
+ async function runDuplicateCheck() {
19
+ // If we are editing a record, we don't need to check for duplicates
20
+ if (disableCheck) {
21
+ return null;
22
+ }
23
+ if (duplicateRecord.length > 0) {
24
+ setRecord(duplicateRecord);
25
+ setUncontrolledOpen(true);
26
+ return duplicateRecord;
27
+ }
28
+ return null;
29
+ }
30
+ function handleOpenChange(value) {
31
+ setUncontrolledOpen(value);
32
+ onOpenChange?.(value);
33
+ }
34
+ useImperativeHandle(ref, () => ({
35
+ onClose: () => setUncontrolledOpen(false),
36
+ checkDuplicate: () => runDuplicateCheck(),
37
+ record: record,
38
+ }));
39
+ return (_jsx(DuplicateElementDamageDialog, { open: open, onClose: () => handleOpenChange(false), record: record, onRegisterAnyway: onRegisterAnyway ?? (() => { }), loading: loading ?? false }));
40
+ });
@@ -0,0 +1,10 @@
1
+ import { type SxProps, type Theme } from "@mui/material";
2
+ type ElementNumberTextFieldProps = {
3
+ value?: string | null;
4
+ defaultValue?: string | null;
5
+ onChange?: (value: string) => void;
6
+ disabled?: boolean;
7
+ sx?: SxProps<Theme>;
8
+ };
9
+ export declare function ElementNumberTextField({ value, defaultValue, onChange, disabled, sx }: ElementNumberTextFieldProps): import("react/jsx-runtime").JSX.Element;
10
+ export {};
@@ -0,0 +1,18 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { TextField } from "@mui/material";
3
+ import { getLocalizedString } from "@olenbetong/appframe-core";
4
+ import { useEffect, useState } from "react";
5
+ export function ElementNumberTextField({ value, defaultValue, onChange, disabled, sx }) {
6
+ let [elementNumber, setElementNumber] = useState(defaultValue ?? "");
7
+ let elementNumberValue = value === undefined ? elementNumber : value;
8
+ useEffect(() => {
9
+ if (value === undefined && defaultValue) {
10
+ setElementNumber(defaultValue);
11
+ }
12
+ }, [defaultValue, value]);
13
+ function handleChange(value) {
14
+ onChange?.(value);
15
+ setElementNumber(value);
16
+ }
17
+ return (_jsx(TextField, { name: "ElementNumber", id: "NewElementDamage_ElementNr", value: elementNumberValue, onChange: (event) => handleChange(event.currentTarget.value), label: getLocalizedString("Element number"), fullWidth: true, autoComplete: "off", disabled: disabled ?? false, sx: { ...sx } }));
18
+ }
@@ -0,0 +1,6 @@
1
+ type HiddenDamageFieldsProps = {
2
+ primKey: string;
3
+ ID: number;
4
+ };
5
+ export declare function HiddenDamageFields({ primKey, ID }: HiddenDamageFieldsProps): import("react/jsx-runtime").JSX.Element;
6
+ export {};
@@ -0,0 +1,4 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ export function HiddenDamageFields({ primKey, ID }) {
3
+ return (_jsxs(_Fragment, { children: [_jsx("input", { type: "hidden", name: "PrimKey", value: primKey }), _jsx("input", { type: "hidden", name: "ID", value: ID })] }));
4
+ }
@@ -0,0 +1,14 @@
1
+ type RegisterFixType = {
2
+ ID: number;
3
+ RegisteredFixFullName: string | null;
4
+ RegisteredFix: Date | null;
5
+ RegisteredFixBy: string | null;
6
+ };
7
+ type RegisterFixProps = {
8
+ value?: RegisterFixType | null;
9
+ defaultValue?: RegisterFixType | null;
10
+ onFix?: (ID: number) => void;
11
+ edit?: boolean;
12
+ };
13
+ export declare function RegisterFix({ value, defaultValue, onFix, edit }: RegisterFixProps): import("react/jsx-runtime").JSX.Element;
14
+ export {};
@@ -0,0 +1,45 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import CheckIcon from "@mui/icons-material/Check";
3
+ import { Button, Checkbox, FormControlLabel, Typography } from "@mui/material";
4
+ import { getLocalizedString, localize } from "@olenbetong/appframe-core";
5
+ import { useEffect, useRef, useState } from "react";
6
+ import { procApproveDamage } from "../data";
7
+ const formatter = new Intl.DateTimeFormat(af.userSession.culture, {
8
+ day: "numeric",
9
+ month: "long",
10
+ year: "numeric",
11
+ hour: "2-digit",
12
+ minute: "2-digit",
13
+ timeZone: "UTC",
14
+ });
15
+ export function RegisterFix({ value, defaultValue, onFix, edit }) {
16
+ let [loading, setLoading] = useState(false);
17
+ let initializedRef = useRef(false);
18
+ let [fix, setFix] = useState(defaultValue ?? null);
19
+ let fixValue = value === undefined ? fix : value;
20
+ // biome-ignore lint: intentionally skipping "value" dependency as this should never run when "value" changes
21
+ useEffect(() => {
22
+ if (initializedRef.current) {
23
+ return;
24
+ }
25
+ if (value === undefined && defaultValue) {
26
+ setFix(defaultValue);
27
+ initializedRef.current = true;
28
+ }
29
+ }, [defaultValue]);
30
+ async function handleRegisterFix() {
31
+ try {
32
+ if (confirm(getLocalizedString("Are you sure you want to register a fix for this damage?"))) {
33
+ setLoading(true);
34
+ let record = (await procApproveDamage.execute({ ID: fixValue?.ID }));
35
+ setFix({ ...record.Table[0] });
36
+ setLoading(false);
37
+ onFix?.(fixValue?.ID ?? -1);
38
+ }
39
+ }
40
+ catch (error) {
41
+ alert(error.message);
42
+ }
43
+ }
44
+ return (_jsxs(_Fragment, { children: [edit ? (_jsx(Button, { loading: loading, loadingPosition: "end", endIcon: _jsx(CheckIcon, {}), onClick: handleRegisterFix, disabled: !!fixValue?.RegisteredFix, variant: "contained", children: getLocalizedString("Register fix") })) : (_jsx(FormControlLabel, { control: _jsx(Checkbox, {}), label: getLocalizedString("Register fixed"), name: "RegisteredFix", id: "NewElementDamage_RegisteredFix" })), fixValue?.RegisteredFix && (_jsx(Typography, { mb: 1.5, color: "text.secondary", children: localize `Registered fix by ${fixValue.RegisteredFixFullName ?? fixValue.RegisteredFixBy} on the ${formatter.format(fixValue.RegisteredFix)}` }))] }));
45
+ }
@@ -0,0 +1,20 @@
1
+ import { type SxProps, type Theme } from "@mui/material";
2
+ type SubmitButtonsProps = {
3
+ /**
4
+ * Whether the form is in edit mode. If true, delete button is visible and submit button's text changes.
5
+ */
6
+ edit?: boolean;
7
+ /**
8
+ * Set loading state for submit button
9
+ */
10
+ loading?: boolean;
11
+ /**
12
+ * Custom styles for Box wrapper around buttons
13
+ */
14
+ sx?: SxProps<Theme>;
15
+ onDelete?: () => void;
16
+ onCancel?: () => void;
17
+ onSubmit?: () => void;
18
+ };
19
+ export declare function SubmitButtons({ edit, loading, onDelete, onCancel, onSubmit, sx }: SubmitButtonsProps): import("react/jsx-runtime").JSX.Element;
20
+ export {};
@@ -0,0 +1,7 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import Add from "@mui/icons-material/Add";
3
+ import { Box, Button } from "@mui/material";
4
+ import { getLocalizedString } from "@olenbetong/appframe-core";
5
+ export function SubmitButtons({ edit, loading, onDelete, onCancel, onSubmit, sx }) {
6
+ return (_jsxs(Box, { sx: { display: "flex", flexWrap: "wrap", gap: 2, justifyContent: "flex-end", ...sx }, children: [edit && _jsx(Button, { onClick: onDelete, children: getLocalizedString("Delete") }), _jsx(Button, { onClick: onCancel, children: getLocalizedString("Cancel") }), _jsx(Button, { loading: loading, loadingPosition: "start", startIcon: _jsx(Add, {}), type: "submit", variant: "contained", onClick: onSubmit, children: edit ? getLocalizedString("Save changes") : getLocalizedString("Register damage") })] }));
7
+ }
@@ -0,0 +1,7 @@
1
+ import type { TransportElementsRecord } from "../data/dsTransportElements.js";
2
+ type TransportElementSelectProps = {
3
+ elements: TransportElementsRecord[];
4
+ onSelect: (element: TransportElementsRecord) => void;
5
+ };
6
+ export declare function TransportElementSelect({ elements, onSelect }: TransportElementSelectProps): import("react/jsx-runtime").JSX.Element;
7
+ export {};
@@ -0,0 +1,16 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import DropDownArrowIcon from "@mui/icons-material/KeyboardArrowDown";
3
+ import { Button, ListItemText, Menu, MenuItem } from "@mui/material";
4
+ import { getLocalizedString } from "@olenbetong/appframe-core";
5
+ import { useState } from "react";
6
+ export function TransportElementSelect({ elements, onSelect }) {
7
+ let [anchorEl, setAnchorEl] = useState(null);
8
+ let open = !!anchorEl;
9
+ let [selected, setSelected] = useState(null);
10
+ function handleChange(element) {
11
+ setAnchorEl(null);
12
+ onSelect(element);
13
+ setSelected(element);
14
+ }
15
+ return (_jsxs(_Fragment, { children: [_jsx(Button, { id: "select_element", variant: "contained", endIcon: _jsx(DropDownArrowIcon, { style: { transform: open ? "rotate(180deg)" : "rotate(0deg)", transition: "transform 0.2s" } }), sx: { width: "165px" }, "aria-controls": open ? "basic-menu" : undefined, "aria-haspopup": "true", "aria-expanded": open ? "true" : undefined, onClick: (event) => setAnchorEl(event.currentTarget), children: selected ? `${selected.ElementID} - ${selected.Name}` : getLocalizedString("Select element") }), _jsx(Menu, { id: "menu_element", anchorEl: anchorEl, open: open, onClose: () => setAnchorEl(null), children: elements.map((element) => (_jsx(MenuItem, { onClick: () => handleChange(element), children: _jsxs(ListItemText, { children: [element.ElementID, " - ", element.Name] }) }, element.PrimKey))) })] }));
16
+ }
@@ -0,0 +1,3 @@
1
+ .flow > * + * {
2
+ margin-top: var(--spacing, 1rem) !important;
3
+ }
@@ -0,0 +1,20 @@
1
+ import { type RefObject } from "react";
2
+ export type Element = {
3
+ Domain: string;
4
+ PrimKey: string;
5
+ ProjectID: string;
6
+ ProjectName: string;
7
+ ElementID: string | null;
8
+ };
9
+ export type ElementLookupHandle = {
10
+ openDialog: () => void;
11
+ closeDialog: () => void;
12
+ };
13
+ export type ElementLookupProps = {
14
+ value?: Element | null;
15
+ defaultValue?: Element | null;
16
+ ref?: RefObject<ElementLookupHandle | null>;
17
+ openLookupDialogIcon?: boolean;
18
+ onChange?: (value: Element | null) => void;
19
+ };
20
+ export declare function ElementLookup({ value, defaultValue, ref, openLookupDialogIcon, onChange }: ElementLookupProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,30 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import SearchIcon from "@mui/icons-material/Search";
3
+ import { IconButton, TextField } from "@mui/material";
4
+ import { getLocalizedString } from "@olenbetong/appframe-core";
5
+ import { useEffect, useImperativeHandle, useState } from "react";
6
+ import { ElementLookupDialog } from "./ElementLookupDialog";
7
+ export function ElementLookup({ value, defaultValue, ref, openLookupDialogIcon, onChange }) {
8
+ let [openElementLookupDialog, setOpenElementLookupDialog] = useState(false);
9
+ let [element, setElement] = useState(defaultValue ?? null);
10
+ let elementValue = value === undefined ? element : value;
11
+ useEffect(() => {
12
+ if (value === undefined && defaultValue) {
13
+ setElement(defaultValue);
14
+ }
15
+ }, [defaultValue, value]);
16
+ useImperativeHandle(ref, () => ({
17
+ openDialog: () => setOpenElementLookupDialog(true),
18
+ closeDialog: () => setOpenElementLookupDialog(false),
19
+ }));
20
+ async function handleAddElement(addElement) {
21
+ onChange?.(addElement.element);
22
+ setElement(addElement.element);
23
+ }
24
+ return (_jsxs(_Fragment, { children: [_jsx(ElementLookupDialog, { open: openElementLookupDialog, mode: "single", onClose: () => setOpenElementLookupDialog(false), onAdd: handleAddElement }), _jsx("input", { type: "hidden", name: "ProjectID", value: elementValue?.ProjectID ?? "" }), _jsx("input", { type: "hidden", name: "ElementRef", value: elementValue?.PrimKey ?? "" }), _jsx(TextField, { id: "NewElementDamge_Project", value: elementValue ? `${elementValue.ProjectID}: ${elementValue.ProjectName}` : "", label: getLocalizedString("Project"), fullWidth: true, required: true, autoComplete: "off", slotProps: { htmlInput: { readOnly: true } } }), _jsx(TextField, { name: "ElementID", id: "NewElementDamage_ElementID", value: elementValue ? elementValue.ElementID : "", label: getLocalizedString("Element ID"), fullWidth: true, autoComplete: "off", slotProps: {
25
+ htmlInput: { readOnly: true },
26
+ input: {
27
+ endAdornment: openLookupDialogIcon ? (_jsx(IconButton, { onClick: () => setOpenElementLookupDialog(true), children: _jsx(SearchIcon, {}) })) : undefined,
28
+ },
29
+ } })] }));
30
+ }
@@ -0,0 +1,2 @@
1
+ import { type SvgIconProps } from "@mui/material";
2
+ export declare function Dead(props: SvgIconProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,5 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { SvgIcon } from "@mui/material";
3
+ export function Dead(props) {
4
+ return (_jsx(SvgIcon, { ...props, children: _jsx("path", { fill: "currentColor", d: "M12,2C6.47,2 2,6.47 2,12C2,17.53 6.47,22 12,22A10,10 0 0,0 22,12C22,6.47 17.5,2 12,2M6.76,8.82L7.82,7.76L8.88,8.82L9.94,7.76L11,8.82L9.94,9.88L11,10.94L9.94,12L8.88,10.94L7.82,12L6.76,10.94L7.82,9.88L6.76,8.82M6.89,17.5C7.69,15.46 9.67,14 12,14C14.33,14 16.31,15.46 17.11,17.5H6.89M17.24,10.94L16.18,12L15.12,10.94L14.06,12L13,10.94L14.06,9.88L13,8.82L14.06,7.76L15.12,8.82L16.18,7.76L17.24,8.82L16.18,9.88L17.24,10.94Z" }) }));
5
+ }
@@ -0,0 +1,4 @@
1
+ export declare function ErrorIcon({ icon, message }: {
2
+ icon?: string;
3
+ message: string;
4
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,33 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import styled from "@emotion/styled";
3
+ import Camera from "@mui/icons-material/Camera";
4
+ import { Dead as DeadIcon } from "./DeadIcon";
5
+ const BarcodeError = styled.div `
6
+ position: absolute;
7
+ bottom: 0;
8
+ left: 0;
9
+ right: 0;
10
+ top: 0;
11
+
12
+ display: flex;
13
+ align-items: center;
14
+ justify-content: center;
15
+ `;
16
+ const ErrorBox = styled.div `
17
+ background: #111111;
18
+ border: 1px solid #3e3e3e;
19
+ border-radius: 3px;
20
+
21
+ max-width: 100%;
22
+ width: 335px;
23
+
24
+ color: white;
25
+ text-align: center;
26
+ `;
27
+ export function ErrorIcon({ icon, message }) {
28
+ let Icon = DeadIcon;
29
+ if (icon === "camera") {
30
+ Icon = Camera;
31
+ }
32
+ return (_jsx(BarcodeError, { children: _jsxs(ErrorBox, { children: [_jsx(Icon, { sx: { color: "#eee", fontSize: "3.5rem", my: 2 } }), _jsx("br", {}), _jsx("p", { children: message })] }) }));
33
+ }
@@ -0,0 +1,10 @@
1
+ import type BarcodeReaderType from "dynamsoft-javascript-barcode";
2
+ declare global {
3
+ interface Window {
4
+ BarcodeReader: typeof BarcodeReaderType;
5
+ }
6
+ }
7
+ export type BarcodeScannerProps = {
8
+ onRead: (barcode: string) => void;
9
+ };
10
+ export declare function BarcodeScanner({ onRead }: BarcodeScannerProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,37 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import SwitchCameraOutlined from "@mui/icons-material/SwitchCameraOutlined";
3
+ import { Box, IconButton } from "@mui/material";
4
+ import { getLocalizedString } from "@olenbetong/appframe-core";
5
+ import { useRef } from "react";
6
+ import { ErrorIcon } from "./Error";
7
+ import { useScanner } from "./useScanner";
8
+ const frameSx = {
9
+ position: "absolute",
10
+ bottom: 0,
11
+ left: 0,
12
+ right: 0,
13
+ top: 0,
14
+ height: "100%",
15
+ width: "100%",
16
+ };
17
+ export function BarcodeScanner({ onRead }) {
18
+ let readerRoot = useRef(null);
19
+ let canvas = useRef(null);
20
+ let { devices, error, setNextDevice } = useScanner(readerRoot, canvas, onRead);
21
+ return (_jsxs(Box, { sx: {
22
+ position: "relative",
23
+ bgcolor: "black",
24
+ height: "100%",
25
+ }, children: [_jsxs(Box, { height: "100%", ref: readerRoot, children: [_jsx(Box, { component: "video", className: "dbrScanner-video", playsInline: true, sx: frameSx }), _jsx(Box, { component: "canvas", sx: frameSx, width: "1280", height: "720", ref: canvas }), error && _jsx(ErrorIcon, { ...error })] }), _jsxs(Box, { sx: {
26
+ display: "flex",
27
+ alignItems: "center",
28
+ justifyContent: "space-between",
29
+ position: "absolute",
30
+ bottom: 0,
31
+ left: 0,
32
+ right: 0,
33
+ py: 1,
34
+ px: 3,
35
+ color: "white",
36
+ }, children: [devices.length <= 1 && _jsx("span", {}), devices.length > 1 && (_jsx(IconButton, { color: "inherit", "aria-label": getLocalizedString("Switch camera"), onClick: () => setNextDevice(), size: "large", children: _jsx(SwitchCameraOutlined, {}) }))] })] }));
37
+ }
@@ -0,0 +1,16 @@
1
+ import type BarcodeReaderType from "dynamsoft-javascript-barcode";
2
+ import { type RefObject } from "react";
3
+ declare global {
4
+ interface Window {
5
+ BarcodeReader: typeof BarcodeReaderType;
6
+ }
7
+ }
8
+ export declare function useScanner(rootRef: RefObject<HTMLElement | null>, canvasRef: RefObject<HTMLCanvasElement | null>, onRead: (barcode: string) => void): {
9
+ devices: BarcodeReaderType.VideoDeviceInfo[];
10
+ error: {
11
+ message: string;
12
+ icon: string;
13
+ } | null;
14
+ isLoading: boolean;
15
+ setNextDevice: () => void;
16
+ };
@@ -0,0 +1,135 @@
1
+ import { getLocalizedString } from "@olenbetong/appframe-core";
2
+ // import BarcodeReader from "dynamsoft-javascript-barcode";
3
+ import { useEffect, useRef, useState } from "react";
4
+ // (window as any).BarcodeReader = BarcodeReader;
5
+ const { BarcodeReader } = window;
6
+ export function useScanner(rootRef, canvasRef, onRead) {
7
+ const [isLoading, setIsLoading] = useState(true);
8
+ const [error, setError] = useState(null);
9
+ const [rects, setRects] = useState([]);
10
+ const [devices, setDevices] = useState({
11
+ all: [],
12
+ current: { deviceId: "", label: "" },
13
+ width: 0,
14
+ height: 0,
15
+ });
16
+ const currentDevice = useRef(null);
17
+ const onReadRef = useRef(onRead);
18
+ const scanner = useRef(null);
19
+ useEffect(() => {
20
+ onReadRef.current = onRead;
21
+ }, [onRead]);
22
+ useEffect(() => {
23
+ if (!rootRef.current)
24
+ return;
25
+ let cancel = false;
26
+ const iPhone = /iPhone|iPad/.test(navigator.userAgent);
27
+ scanner.current = new BarcodeReader.Scanner({
28
+ duplicateForgetTime: 1000,
29
+ htmlElement: rootRef.current,
30
+ videoSettings: {
31
+ video: {
32
+ width: { ideal: iPhone ? 1280 : 720 },
33
+ height: { ideal: iPhone ? 1280 : 720 },
34
+ facingMode: { ideal: "environment" },
35
+ },
36
+ },
37
+ runtimeSettings: {
38
+ mBarcodeFormatIds: BarcodeReader.EnumBarcodeFormat.DATAMATRIX,
39
+ mAntiDamageLevel: 3,
40
+ mDeblurLevel: 0,
41
+ },
42
+ onFrameRead: (results) => {
43
+ const newRects = [];
44
+ for (let result of results) {
45
+ newRects.push(result.LocalizationResult);
46
+ }
47
+ if (newRects.length > 0) {
48
+ setRects((rects) => [...rects, ...newRects]);
49
+ setTimeout(() => {
50
+ if (!cancel) {
51
+ setRects((rects) => rects.slice(newRects.length));
52
+ }
53
+ }, 300);
54
+ }
55
+ },
56
+ onNewCodeRead: (txt) => {
57
+ if (txt) {
58
+ onReadRef.current(txt);
59
+ }
60
+ },
61
+ });
62
+ scanner.current
63
+ .open()
64
+ .then((videoDeviceInfo) => {
65
+ if (cancel === false) {
66
+ const { all, current } = videoDeviceInfo;
67
+ currentDevice.current = 0;
68
+ if (current?.deviceId) {
69
+ for (let i = 0; i < all.length; i++) {
70
+ if (all[i].deviceId === current.deviceId) {
71
+ currentDevice.current = i;
72
+ }
73
+ }
74
+ }
75
+ setDevices(videoDeviceInfo);
76
+ setIsLoading(false);
77
+ }
78
+ })
79
+ .catch((ex) => {
80
+ if (cancel === false) {
81
+ let error = ex.message || ex;
82
+ setIsLoading(false);
83
+ if (/Webassembly/.test(error)) {
84
+ setError({
85
+ icon: "unsupported",
86
+ message: getLocalizedString("Your browser is not supported. A browser that supports WebAssembly is required."),
87
+ });
88
+ }
89
+ else if (/Permission/i.test(error) ||
90
+ /video/i.test(error) ||
91
+ /device/i.test(error) ||
92
+ /Media/i.test(error) ||
93
+ /agent/.test(error) ||
94
+ /found/.test(error))
95
+ setError({
96
+ icon: "camera",
97
+ message: getLocalizedString("No camera available"),
98
+ });
99
+ else {
100
+ setError({ icon: "generic", message: error });
101
+ }
102
+ }
103
+ });
104
+ return () => {
105
+ cancel = true;
106
+ if (scanner.current && typeof scanner.current.close === "function") {
107
+ scanner.current.close();
108
+ }
109
+ };
110
+ }, [rootRef]);
111
+ useEffect(() => {
112
+ if (canvasRef.current) {
113
+ const ctx = canvasRef.current.getContext("2d");
114
+ ctx.clearRect(0, 0, canvasRef.current.width, canvasRef.current.height);
115
+ ctx.fillStyle = "rgba(254,180,32,0.3)";
116
+ const { width, height } = canvasRef.current;
117
+ const xRatio = width / devices.width;
118
+ const yRatio = height / devices.height;
119
+ for (let rect of rects) {
120
+ const { X1, X2, X3, X4, Y1, Y2, Y3, Y4 } = rect;
121
+ ctx.beginPath();
122
+ ctx.moveTo(X1 * xRatio, Y1 * yRatio);
123
+ ctx.lineTo(X2 * xRatio, Y2 * yRatio);
124
+ ctx.lineTo(X3 * xRatio, Y3 * yRatio);
125
+ ctx.lineTo(X4 * xRatio, Y4 * yRatio);
126
+ ctx.fill();
127
+ }
128
+ }
129
+ }, [devices, canvasRef, rects]);
130
+ function setNextDevice() {
131
+ currentDevice.current = ((currentDevice.current ?? 0) + 1) % devices.all.length;
132
+ scanner.current?.play(devices.all[currentDevice.current].deviceId);
133
+ }
134
+ return { devices: devices.all, error, isLoading, setNextDevice };
135
+ }
@@ -0,0 +1,17 @@
1
+ @property --angle {
2
+ syntax: "<angle>";
3
+ inherits: false;
4
+ initial-value: 0deg;
5
+ }
6
+
7
+ @keyframes MovingBackground {
8
+ 0% {
9
+ --angle: 0deg;
10
+ }
11
+ 50% {
12
+ --angle: 180deg;
13
+ }
14
+ 100% {
15
+ --angle: 360deg;
16
+ }
17
+ }
@@ -0,0 +1,4 @@
1
+ import "./index.css";
2
+ export declare function AddElementHIDScanner({ onScan }: {
3
+ onScan: (id: string) => void;
4
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,36 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ import "./index.css";
3
+ import { Box, Button } from "@mui/material";
4
+ import { getLocalizedString } from "@olenbetong/appframe-core";
5
+ import { useEffect, useRef, useState } from "react";
6
+ import { useHIDScanner } from "./useHIDScanner";
7
+ export function AddElementHIDScanner({ onScan }) {
8
+ let [enabled, setEnabled] = useState(false);
9
+ let root = useRef(null);
10
+ useEffect(() => {
11
+ if (!root.current)
12
+ return;
13
+ let rootElem = root.current;
14
+ function handleFocus() {
15
+ setEnabled(true);
16
+ }
17
+ function handleBlur() {
18
+ setEnabled(false);
19
+ }
20
+ rootElem.addEventListener("focus", handleFocus);
21
+ rootElem.addEventListener("blur", handleBlur);
22
+ rootElem.focus();
23
+ return () => {
24
+ rootElem.removeEventListener("focus", handleFocus);
25
+ rootElem.removeEventListener("blur", handleBlur);
26
+ };
27
+ }, []);
28
+ useHIDScanner(onScan, enabled);
29
+ return (_jsx(Box, { height: "100%", bgcolor: "#ddd", display: "flex", alignItems: "center", justifyContent: "center", tabIndex: 0, ref: root, sx: {
30
+ backgroundImage: enabled ? "linear-gradient(var(--angle), #777, #bbb, #777)" : "none",
31
+ animation: enabled ? "MovingBackground 8s linear infinite" : "none",
32
+ }, children: enabled ? (_jsxs("span", { children: [getLocalizedString("Listening for scanned elements"), "..."] })) : (_jsx(Button, { variant: "contained", onClick: () => {
33
+ if (root.current)
34
+ root.current.focus();
35
+ }, children: getLocalizedString("Start listening") })) }));
36
+ }
@@ -0,0 +1 @@
1
+ export declare function useHIDScanner(onRead: (value: string) => void, enabled?: boolean): void;