formanitor 0.0.14 → 0.0.16
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/index.cjs +789 -34
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +59 -3
- package/dist/index.d.ts +59 -3
- package/dist/index.mjs +789 -35
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -664,12 +664,27 @@ var FormStore = class {
|
|
|
664
664
|
}
|
|
665
665
|
};
|
|
666
666
|
var FormContext = React11.createContext(null);
|
|
667
|
+
var emptyFrequentItems = {
|
|
668
|
+
medications: [],
|
|
669
|
+
investigations: [],
|
|
670
|
+
procedures: []
|
|
671
|
+
};
|
|
672
|
+
var FrequentItemsContext = React11.createContext(emptyFrequentItems);
|
|
667
673
|
var FieldHandlersContext = React11.createContext({});
|
|
668
674
|
function useFieldHandlers(fieldId) {
|
|
669
675
|
const map = React11.useContext(FieldHandlersContext);
|
|
670
676
|
return map[fieldId] ?? { onSearch: async () => [], recentlyUsed: [] };
|
|
671
677
|
}
|
|
672
|
-
|
|
678
|
+
function useFrequentItems() {
|
|
679
|
+
return React11.useContext(FrequentItemsContext);
|
|
680
|
+
}
|
|
681
|
+
var FormProvider = ({
|
|
682
|
+
schema,
|
|
683
|
+
config,
|
|
684
|
+
fieldHandlers,
|
|
685
|
+
frequentItems,
|
|
686
|
+
children
|
|
687
|
+
}) => {
|
|
673
688
|
const storeRef = React11.useRef(null);
|
|
674
689
|
if (!storeRef.current) {
|
|
675
690
|
storeRef.current = new FormStore(schema, config);
|
|
@@ -682,7 +697,8 @@ var FormProvider = ({ schema, config, fieldHandlers, children }) => {
|
|
|
682
697
|
React11.useEffect(() => {
|
|
683
698
|
storeRef.current?.load();
|
|
684
699
|
}, []);
|
|
685
|
-
|
|
700
|
+
const frequentItemsValue = frequentItems ?? emptyFrequentItems;
|
|
701
|
+
return /* @__PURE__ */ jsxRuntime.jsx(FormContext.Provider, { value: storeRef.current, children: /* @__PURE__ */ jsxRuntime.jsx(FieldHandlersContext.Provider, { value: fieldHandlers ?? {}, children: /* @__PURE__ */ jsxRuntime.jsx(FrequentItemsContext.Provider, { value: frequentItemsValue, children }) }) });
|
|
686
702
|
};
|
|
687
703
|
function useFormStore() {
|
|
688
704
|
const context = React11.useContext(FormContext);
|
|
@@ -2500,6 +2516,7 @@ var AddEntityDialog = ({
|
|
|
2500
2516
|
onClose,
|
|
2501
2517
|
title,
|
|
2502
2518
|
recentlyUsedSlot,
|
|
2519
|
+
chipSectionLabel = "Recently Used",
|
|
2503
2520
|
children,
|
|
2504
2521
|
actionSlot
|
|
2505
2522
|
}) => {
|
|
@@ -2507,7 +2524,7 @@ var AddEntityDialog = ({
|
|
|
2507
2524
|
/* @__PURE__ */ jsxRuntime.jsx(DialogHeader, { className: "px-6 pt-6 pb-4 shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { className: "text-lg font-semibold", children: title }) }),
|
|
2508
2525
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-6 flex flex-col gap-4 overflow-y-auto flex-1 min-h-0 pb-4", children: [
|
|
2509
2526
|
recentlyUsedSlot && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2510
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground mb-2", children:
|
|
2527
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground mb-2", children: chipSectionLabel }),
|
|
2511
2528
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-2", children: recentlyUsedSlot })
|
|
2512
2529
|
] }),
|
|
2513
2530
|
children
|
|
@@ -2532,9 +2549,9 @@ function mapToMedication(result) {
|
|
|
2532
2549
|
};
|
|
2533
2550
|
}
|
|
2534
2551
|
function mapAIMedicationToMedication(ai) {
|
|
2535
|
-
const id =
|
|
2552
|
+
const id = ai.id != null ? String(ai.id) : "";
|
|
2536
2553
|
return {
|
|
2537
|
-
id
|
|
2554
|
+
id,
|
|
2538
2555
|
brand_name: ai.brand_name ?? "",
|
|
2539
2556
|
generic_name: ai.generic_name ?? "",
|
|
2540
2557
|
frequency: "custom",
|
|
@@ -2550,7 +2567,7 @@ function mapAIMedicationToMedication(ai) {
|
|
|
2550
2567
|
}
|
|
2551
2568
|
function createCustomMedication(name, customId) {
|
|
2552
2569
|
return {
|
|
2553
|
-
id: customId,
|
|
2570
|
+
id: String(customId),
|
|
2554
2571
|
brand_name: name.trim(),
|
|
2555
2572
|
generic_name: "",
|
|
2556
2573
|
frequency: "custom",
|
|
@@ -2564,6 +2581,39 @@ function createCustomMedication(name, customId) {
|
|
|
2564
2581
|
notes: ""
|
|
2565
2582
|
};
|
|
2566
2583
|
}
|
|
2584
|
+
function parseDuration(duration) {
|
|
2585
|
+
if (!duration || !duration.trim()) return { value: "3", unit: "days" };
|
|
2586
|
+
const lower = duration.trim().toLowerCase();
|
|
2587
|
+
const match = lower.match(/^(\d+)\s*(day|days|week|weeks|month|months)?$/);
|
|
2588
|
+
if (!match) return { value: "3", unit: "days" };
|
|
2589
|
+
const value = match[1] ?? "3";
|
|
2590
|
+
const unitWord = match[2] ?? "days";
|
|
2591
|
+
const unit = unitWord.startsWith("month") ? "months" : unitWord.startsWith("week") ? "weeks" : "days";
|
|
2592
|
+
return { value, unit };
|
|
2593
|
+
}
|
|
2594
|
+
function mapFrequentItemToMedication(item) {
|
|
2595
|
+
const parsed = parseDuration(item.duration);
|
|
2596
|
+
const duration_value = item.duration_value ?? parsed.value;
|
|
2597
|
+
const duration_unit = item.duration_unit ?? parsed.unit;
|
|
2598
|
+
const before_after = item.before_after === "BEFORE FOOD" ? "BEFORE FOOD" : "AFTER FOOD";
|
|
2599
|
+
const routeNote = item.route ? `Route: ${item.route}` : "";
|
|
2600
|
+
const baseNotes = item.notes?.trim() || "";
|
|
2601
|
+
const combinedNotes = [baseNotes, routeNote.trim()].filter((part) => part.length > 0).join(" \u2014 ");
|
|
2602
|
+
return {
|
|
2603
|
+
id: item.id,
|
|
2604
|
+
brand_name: item.brand_name ?? item.name,
|
|
2605
|
+
generic_name: item.short_name ?? "",
|
|
2606
|
+
frequency: item.frequency ?? "custom",
|
|
2607
|
+
is_custom: false,
|
|
2608
|
+
duration_value,
|
|
2609
|
+
duration_unit,
|
|
2610
|
+
before_after,
|
|
2611
|
+
morning: item.morning ?? "0",
|
|
2612
|
+
afternoon: item.afternoon ?? "0",
|
|
2613
|
+
night: item.night ?? "0",
|
|
2614
|
+
notes: combinedNotes
|
|
2615
|
+
};
|
|
2616
|
+
}
|
|
2567
2617
|
function Spinner({
|
|
2568
2618
|
value,
|
|
2569
2619
|
onChange
|
|
@@ -2611,11 +2661,14 @@ function MedicationCard({
|
|
|
2611
2661
|
onChange: (e) => set("frequency", e.target.value),
|
|
2612
2662
|
children: [
|
|
2613
2663
|
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "custom", children: "select frequency" }),
|
|
2614
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "
|
|
2615
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "
|
|
2616
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "
|
|
2617
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "
|
|
2618
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "
|
|
2664
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "qid", children: "4 times a day (QID)" }),
|
|
2665
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "alternate_day", children: "Alternate day" }),
|
|
2666
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "once_weekly", children: "Once weekly" }),
|
|
2667
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "once_monthly", children: "Once monthly" }),
|
|
2668
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "as_needed", children: "As needed" }),
|
|
2669
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "fort_night", children: "Fort night" }),
|
|
2670
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "at_bed_time", children: "At Bed time" }),
|
|
2671
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "sos", children: "SOS only" })
|
|
2619
2672
|
]
|
|
2620
2673
|
}
|
|
2621
2674
|
),
|
|
@@ -2754,6 +2807,7 @@ var AddMedicationField = ({
|
|
|
2754
2807
|
onChange,
|
|
2755
2808
|
onSearch,
|
|
2756
2809
|
recentlyUsed = [],
|
|
2810
|
+
frequentItems = [],
|
|
2757
2811
|
suggestedMedications = []
|
|
2758
2812
|
}) => {
|
|
2759
2813
|
const [open, setOpen] = React11.useState(false);
|
|
@@ -2799,6 +2853,13 @@ var AddMedicationField = ({
|
|
|
2799
2853
|
onChange([...safeValue, mapToMedication(result)]);
|
|
2800
2854
|
}
|
|
2801
2855
|
}
|
|
2856
|
+
function handleFrequentItemToggle(item) {
|
|
2857
|
+
if (addedIds.has(String(item.id))) {
|
|
2858
|
+
onChange(safeValue.filter((m) => String(m.id) !== String(item.id)));
|
|
2859
|
+
} else {
|
|
2860
|
+
onChange([...safeValue, mapFrequentItemToMedication(item)]);
|
|
2861
|
+
}
|
|
2862
|
+
}
|
|
2802
2863
|
function handleResultClick(result) {
|
|
2803
2864
|
if (addedIds.has(String(result.id))) return;
|
|
2804
2865
|
setAddingResultId(result.id);
|
|
@@ -2849,6 +2910,26 @@ var AddMedicationField = ({
|
|
|
2849
2910
|
r.id
|
|
2850
2911
|
);
|
|
2851
2912
|
});
|
|
2913
|
+
const limitedFrequentItems = frequentItems.slice(0, 25);
|
|
2914
|
+
const frequentItemChips = limitedFrequentItems.length > 0 ? limitedFrequentItems.map((item) => {
|
|
2915
|
+
const isAdded = addedIds.has(String(item.id));
|
|
2916
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2917
|
+
"button",
|
|
2918
|
+
{
|
|
2919
|
+
type: "button",
|
|
2920
|
+
onClick: () => handleFrequentItemToggle(item),
|
|
2921
|
+
className: cn(
|
|
2922
|
+
"rounded-full border text-[11px] px-2 py-0.5 transition-colors cursor-pointer",
|
|
2923
|
+
isAdded ? "border-green-300 bg-green-50 text-green-700" : "border-border bg-white hover:bg-gray-50"
|
|
2924
|
+
),
|
|
2925
|
+
children: [
|
|
2926
|
+
isAdded && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mr-1", children: "\u2713" }),
|
|
2927
|
+
item.brand_name ?? item.name
|
|
2928
|
+
]
|
|
2929
|
+
},
|
|
2930
|
+
item.id
|
|
2931
|
+
);
|
|
2932
|
+
}) : [];
|
|
2852
2933
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-md overflow-hidden flex flex-col border bg-white border-[#D0D0D0] space-y-3 p-3 h-fit", children: [
|
|
2853
2934
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
2854
2935
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold", children: label }),
|
|
@@ -2862,22 +2943,6 @@ var AddMedicationField = ({
|
|
|
2862
2943
|
}
|
|
2863
2944
|
)
|
|
2864
2945
|
] }),
|
|
2865
|
-
suggestedMedications.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-1.5 items-center", children: [
|
|
2866
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground mr-1", children: "Suggestions:" }),
|
|
2867
|
-
suggestedMedications.filter((s) => !addedIds.has(String(s.id))).map((s) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2868
|
-
"button",
|
|
2869
|
-
{
|
|
2870
|
-
type: "button",
|
|
2871
|
-
onClick: () => handleAddSuggestion(s),
|
|
2872
|
-
className: "inline-flex items-center gap-1 rounded-full border border-dashed border-purple-300 bg-purple-50/80 text-purple-800 text-xs px-2.5 py-1 hover:bg-purple-100 transition-colors cursor-pointer",
|
|
2873
|
-
children: [
|
|
2874
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "h-3 w-3" }),
|
|
2875
|
-
s.brand_name || s.generic_name || String(s.id)
|
|
2876
|
-
]
|
|
2877
|
-
},
|
|
2878
|
-
String(s.id)
|
|
2879
|
-
))
|
|
2880
|
-
] }),
|
|
2881
2946
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2", children: safeValue.map((med, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2882
2947
|
MedicationCard,
|
|
2883
2948
|
{
|
|
@@ -2893,7 +2958,8 @@ var AddMedicationField = ({
|
|
|
2893
2958
|
open,
|
|
2894
2959
|
onClose: () => setOpen(false),
|
|
2895
2960
|
title: "Add Medication",
|
|
2896
|
-
recentlyUsedSlot: recentlyUsedChips.length > 0 ? recentlyUsedChips : void 0,
|
|
2961
|
+
recentlyUsedSlot: frequentItemChips.length > 0 ? frequentItemChips : recentlyUsedChips.length > 0 ? recentlyUsedChips : void 0,
|
|
2962
|
+
chipSectionLabel: frequentItemChips.length > 0 ? "Frequently used" : void 0,
|
|
2897
2963
|
actionSlot: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2898
2964
|
"button",
|
|
2899
2965
|
{
|
|
@@ -2918,6 +2984,22 @@ var AddMedicationField = ({
|
|
|
2918
2984
|
className: "border border-border rounded-md focus-visible:ring-0"
|
|
2919
2985
|
}
|
|
2920
2986
|
),
|
|
2987
|
+
suggestedMedications.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-1.5 items-center", children: [
|
|
2988
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground mr-1", children: "Suggestions:" }),
|
|
2989
|
+
suggestedMedications.filter((s) => !addedIds.has(String(s.id))).slice(0, 25).map((s) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2990
|
+
"button",
|
|
2991
|
+
{
|
|
2992
|
+
type: "button",
|
|
2993
|
+
onClick: () => handleAddSuggestion(s),
|
|
2994
|
+
className: "inline-flex items-center gap-1 rounded-full border border-dashed border-purple-300 bg-purple-50/80 text-purple-800 text-[11px] px-2 py-0.5 hover:bg-purple-100 transition-colors cursor-pointer",
|
|
2995
|
+
children: [
|
|
2996
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "h-3 w-3" }),
|
|
2997
|
+
s.brand_name || s.generic_name || String(s.id)
|
|
2998
|
+
]
|
|
2999
|
+
},
|
|
3000
|
+
String(s.id)
|
|
3001
|
+
))
|
|
3002
|
+
] }),
|
|
2921
3003
|
loading && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground text-center py-2", children: "Searching\u2026" }),
|
|
2922
3004
|
!loading && results.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 gap-2 max-h-64 overflow-y-auto", children: results.map((r) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2923
3005
|
SearchResultCard,
|
|
@@ -2937,6 +3019,7 @@ var AddMedicationWidget = ({ fieldId }) => {
|
|
|
2937
3019
|
const { value, setValue } = useField(fieldId);
|
|
2938
3020
|
const handlers = useFieldHandlers(fieldId);
|
|
2939
3021
|
const { medications: suggestedMedications } = useAISuggestions();
|
|
3022
|
+
const { medications: frequentMedications } = useFrequentItems();
|
|
2940
3023
|
const safeValue = Array.isArray(value) ? value : [];
|
|
2941
3024
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2942
3025
|
AddMedicationField,
|
|
@@ -2945,6 +3028,7 @@ var AddMedicationWidget = ({ fieldId }) => {
|
|
|
2945
3028
|
onChange: setValue,
|
|
2946
3029
|
onSearch: handlers.onSearch,
|
|
2947
3030
|
recentlyUsed: handlers.recentlyUsed,
|
|
3031
|
+
frequentItems: frequentMedications,
|
|
2948
3032
|
suggestedMedications
|
|
2949
3033
|
}
|
|
2950
3034
|
);
|
|
@@ -2958,12 +3042,23 @@ function mapToInvestigation(result) {
|
|
|
2958
3042
|
fromAI: false
|
|
2959
3043
|
};
|
|
2960
3044
|
}
|
|
3045
|
+
function mapFrequentItemToInvestigation(item) {
|
|
3046
|
+
return {
|
|
3047
|
+
id: String(item.id),
|
|
3048
|
+
name: item.name,
|
|
3049
|
+
code: item.code ?? void 0,
|
|
3050
|
+
label: item.name,
|
|
3051
|
+
is_custom: false,
|
|
3052
|
+
fromAI: false
|
|
3053
|
+
};
|
|
3054
|
+
}
|
|
2961
3055
|
var AddInvestigationField = ({
|
|
2962
3056
|
label = "Investigations",
|
|
2963
3057
|
value,
|
|
2964
3058
|
onChange,
|
|
2965
3059
|
onSearch,
|
|
2966
|
-
recentlyUsed = []
|
|
3060
|
+
recentlyUsed = [],
|
|
3061
|
+
frequentItems = []
|
|
2967
3062
|
}) => {
|
|
2968
3063
|
const [open, setOpen] = React11.useState(false);
|
|
2969
3064
|
const [query, setQuery] = React11.useState("");
|
|
@@ -3025,6 +3120,14 @@ var AddInvestigationField = ({
|
|
|
3025
3120
|
addInvestigation(result);
|
|
3026
3121
|
}
|
|
3027
3122
|
}
|
|
3123
|
+
function handleFrequentItemToggle(item) {
|
|
3124
|
+
const id = String(item.id);
|
|
3125
|
+
if (addedIds.has(id)) {
|
|
3126
|
+
removeInvestigation(id);
|
|
3127
|
+
} else {
|
|
3128
|
+
onChange([...valueRef.current, mapFrequentItemToInvestigation(item)]);
|
|
3129
|
+
}
|
|
3130
|
+
}
|
|
3028
3131
|
const recentlyUsedChips = recentlyUsed.map((r) => {
|
|
3029
3132
|
const isAdded = addedIds.has(r.id);
|
|
3030
3133
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -3044,6 +3147,27 @@ var AddInvestigationField = ({
|
|
|
3044
3147
|
r.id
|
|
3045
3148
|
);
|
|
3046
3149
|
});
|
|
3150
|
+
const limitedFrequentItems = frequentItems.slice(0, 25);
|
|
3151
|
+
const frequentItemChips = limitedFrequentItems.length > 0 ? limitedFrequentItems.map((item) => {
|
|
3152
|
+
const id = String(item.id);
|
|
3153
|
+
const isAdded = addedIds.has(id);
|
|
3154
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3155
|
+
"button",
|
|
3156
|
+
{
|
|
3157
|
+
type: "button",
|
|
3158
|
+
onClick: () => handleFrequentItemToggle(item),
|
|
3159
|
+
className: cn(
|
|
3160
|
+
"rounded-full border text-xs px-3 py-1 transition-colors",
|
|
3161
|
+
isAdded ? "border-green-300 bg-green-50 text-green-700" : "border-border bg-white hover:bg-gray-50"
|
|
3162
|
+
),
|
|
3163
|
+
children: [
|
|
3164
|
+
isAdded && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mr-1", children: "\u2713" }),
|
|
3165
|
+
item.name
|
|
3166
|
+
]
|
|
3167
|
+
},
|
|
3168
|
+
item.id
|
|
3169
|
+
);
|
|
3170
|
+
}) : [];
|
|
3047
3171
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-md overflow-hidden flex flex-col bg-white border border-[#D0D0D0] space-y-3 p-3 h-fit", children: [
|
|
3048
3172
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-3", children: [
|
|
3049
3173
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold", children: label }),
|
|
@@ -3082,7 +3206,8 @@ var AddInvestigationField = ({
|
|
|
3082
3206
|
open,
|
|
3083
3207
|
onClose: () => setOpen(false),
|
|
3084
3208
|
title: "Add Investigation",
|
|
3085
|
-
recentlyUsedSlot: recentlyUsedChips.length > 0 ? recentlyUsedChips : void 0,
|
|
3209
|
+
recentlyUsedSlot: frequentItemChips.length > 0 ? frequentItemChips : recentlyUsedChips.length > 0 ? recentlyUsedChips : void 0,
|
|
3210
|
+
chipSectionLabel: frequentItemChips.length > 0 ? "Frequently used" : void 0,
|
|
3086
3211
|
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
3087
3212
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3088
3213
|
Input,
|
|
@@ -3122,13 +3247,15 @@ var AddInvestigationField = ({
|
|
|
3122
3247
|
var AddInvestigationWidget = ({ fieldId }) => {
|
|
3123
3248
|
const { value, setValue } = useField(fieldId);
|
|
3124
3249
|
const handlers = useFieldHandlers(fieldId);
|
|
3250
|
+
const { investigations: frequentInvestigations } = useFrequentItems();
|
|
3125
3251
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3126
3252
|
AddInvestigationField,
|
|
3127
3253
|
{
|
|
3128
3254
|
value: value ?? [],
|
|
3129
3255
|
onChange: setValue,
|
|
3130
3256
|
onSearch: handlers.onSearch,
|
|
3131
|
-
recentlyUsed: handlers.recentlyUsed
|
|
3257
|
+
recentlyUsed: handlers.recentlyUsed,
|
|
3258
|
+
frequentItems: frequentInvestigations
|
|
3132
3259
|
}
|
|
3133
3260
|
);
|
|
3134
3261
|
};
|
|
@@ -3141,12 +3268,23 @@ function mapToProcedure(result) {
|
|
|
3141
3268
|
fromAI: false
|
|
3142
3269
|
};
|
|
3143
3270
|
}
|
|
3271
|
+
function mapFrequentItemToProcedure(item) {
|
|
3272
|
+
return {
|
|
3273
|
+
id: String(item.id),
|
|
3274
|
+
name: item.name,
|
|
3275
|
+
code: item.code ?? void 0,
|
|
3276
|
+
label: item.name,
|
|
3277
|
+
is_custom: false,
|
|
3278
|
+
fromAI: false
|
|
3279
|
+
};
|
|
3280
|
+
}
|
|
3144
3281
|
var AddProcedureField = ({
|
|
3145
3282
|
label = "Procedures",
|
|
3146
3283
|
value,
|
|
3147
3284
|
onChange,
|
|
3148
3285
|
onSearch,
|
|
3149
|
-
recentlyUsed = []
|
|
3286
|
+
recentlyUsed = [],
|
|
3287
|
+
frequentItems = []
|
|
3150
3288
|
}) => {
|
|
3151
3289
|
const [open, setOpen] = React11.useState(false);
|
|
3152
3290
|
const [query, setQuery] = React11.useState("");
|
|
@@ -3208,6 +3346,14 @@ var AddProcedureField = ({
|
|
|
3208
3346
|
addProcedure(result);
|
|
3209
3347
|
}
|
|
3210
3348
|
}
|
|
3349
|
+
function handleFrequentItemToggle(item) {
|
|
3350
|
+
const id = String(item.id);
|
|
3351
|
+
if (addedIds.has(id)) {
|
|
3352
|
+
removeProcedure(id);
|
|
3353
|
+
} else {
|
|
3354
|
+
onChange([...valueRef.current, mapFrequentItemToProcedure(item)]);
|
|
3355
|
+
}
|
|
3356
|
+
}
|
|
3211
3357
|
const recentlyUsedChips = recentlyUsed.map((r) => {
|
|
3212
3358
|
const isAdded = addedIds.has(r.id);
|
|
3213
3359
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -3227,6 +3373,27 @@ var AddProcedureField = ({
|
|
|
3227
3373
|
r.id
|
|
3228
3374
|
);
|
|
3229
3375
|
});
|
|
3376
|
+
const limitedFrequentItems = frequentItems.slice(0, 25);
|
|
3377
|
+
const frequentItemChips = limitedFrequentItems.length > 0 ? limitedFrequentItems.map((item) => {
|
|
3378
|
+
const id = String(item.id);
|
|
3379
|
+
const isAdded = addedIds.has(id);
|
|
3380
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3381
|
+
"button",
|
|
3382
|
+
{
|
|
3383
|
+
type: "button",
|
|
3384
|
+
onClick: () => handleFrequentItemToggle(item),
|
|
3385
|
+
className: cn(
|
|
3386
|
+
"rounded-full border text-xs px-3 py-1 transition-colors",
|
|
3387
|
+
isAdded ? "border-green-300 bg-green-50 text-green-700" : "border-border bg-white hover:bg-gray-50"
|
|
3388
|
+
),
|
|
3389
|
+
children: [
|
|
3390
|
+
isAdded && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mr-1", children: "\u2713" }),
|
|
3391
|
+
item.name
|
|
3392
|
+
]
|
|
3393
|
+
},
|
|
3394
|
+
item.id
|
|
3395
|
+
);
|
|
3396
|
+
}) : [];
|
|
3230
3397
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-md overflow-hidden flex flex-col bg-white border border-[#D0D0D0] space-y-3 p-3 h-fit", children: [
|
|
3231
3398
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-3", children: [
|
|
3232
3399
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold", children: label }),
|
|
@@ -3265,7 +3432,8 @@ var AddProcedureField = ({
|
|
|
3265
3432
|
open,
|
|
3266
3433
|
onClose: () => setOpen(false),
|
|
3267
3434
|
title: "Add Procedure",
|
|
3268
|
-
recentlyUsedSlot: recentlyUsedChips.length > 0 ? recentlyUsedChips : void 0,
|
|
3435
|
+
recentlyUsedSlot: frequentItemChips.length > 0 ? frequentItemChips : recentlyUsedChips.length > 0 ? recentlyUsedChips : void 0,
|
|
3436
|
+
chipSectionLabel: frequentItemChips.length > 0 ? "Frequently used" : void 0,
|
|
3269
3437
|
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
3270
3438
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3271
3439
|
Input,
|
|
@@ -3305,13 +3473,15 @@ var AddProcedureField = ({
|
|
|
3305
3473
|
var AddProcedureWidget = ({ fieldId }) => {
|
|
3306
3474
|
const { value, setValue } = useField(fieldId);
|
|
3307
3475
|
const handlers = useFieldHandlers(fieldId);
|
|
3476
|
+
const { procedures: frequentProcedures } = useFrequentItems();
|
|
3308
3477
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3309
3478
|
AddProcedureField,
|
|
3310
3479
|
{
|
|
3311
3480
|
value: value ?? [],
|
|
3312
3481
|
onChange: setValue,
|
|
3313
3482
|
onSearch: handlers.onSearch,
|
|
3314
|
-
recentlyUsed: handlers.recentlyUsed
|
|
3483
|
+
recentlyUsed: handlers.recentlyUsed,
|
|
3484
|
+
frequentItems: frequentProcedures
|
|
3315
3485
|
}
|
|
3316
3486
|
);
|
|
3317
3487
|
};
|
|
@@ -4244,6 +4414,588 @@ var SmartTextareaWidget = ({ fieldId }) => {
|
|
|
4244
4414
|
showError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-red-500", children: error })
|
|
4245
4415
|
] });
|
|
4246
4416
|
};
|
|
4417
|
+
var DEFAULT_DRAFT = {
|
|
4418
|
+
gpal: { G: 0, P: 0, A: 0, L: 0 },
|
|
4419
|
+
lmp: "",
|
|
4420
|
+
is_pregnant: false,
|
|
4421
|
+
eddUSG: "",
|
|
4422
|
+
primaryEDD: "lmp",
|
|
4423
|
+
complications: "",
|
|
4424
|
+
outcome: null
|
|
4425
|
+
};
|
|
4426
|
+
function pad2(n) {
|
|
4427
|
+
return String(n).padStart(2, "0");
|
|
4428
|
+
}
|
|
4429
|
+
function formatDdMmYyyy(iso) {
|
|
4430
|
+
const [y, m, d] = iso.split("-");
|
|
4431
|
+
if (!y || !m || !d) return iso;
|
|
4432
|
+
return `${pad2(Number(d))}/${pad2(Number(m))}/${y}`;
|
|
4433
|
+
}
|
|
4434
|
+
function todayIso() {
|
|
4435
|
+
const d = /* @__PURE__ */ new Date();
|
|
4436
|
+
const y = d.getFullYear();
|
|
4437
|
+
const m = pad2(d.getMonth() + 1);
|
|
4438
|
+
const day = pad2(d.getDate());
|
|
4439
|
+
return `${y}-${m}-${day}`;
|
|
4440
|
+
}
|
|
4441
|
+
function isValidIsoDate(val) {
|
|
4442
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(val)) return false;
|
|
4443
|
+
const dt = /* @__PURE__ */ new Date(`${val}T00:00:00.000Z`);
|
|
4444
|
+
return !Number.isNaN(dt.getTime());
|
|
4445
|
+
}
|
|
4446
|
+
function safeJsonParse(val) {
|
|
4447
|
+
try {
|
|
4448
|
+
return JSON.parse(val);
|
|
4449
|
+
} catch {
|
|
4450
|
+
return null;
|
|
4451
|
+
}
|
|
4452
|
+
}
|
|
4453
|
+
function clampInt(val, min, max) {
|
|
4454
|
+
if (!Number.isFinite(val)) return min;
|
|
4455
|
+
return Math.max(min, Math.min(max, Math.trunc(val)));
|
|
4456
|
+
}
|
|
4457
|
+
function parseLegacyString(input) {
|
|
4458
|
+
const result = {};
|
|
4459
|
+
const gpalMatch = input.match(/G(\d+)\s*P(\d+)\s*A(\d+)\s*L(\d+)/i);
|
|
4460
|
+
if (gpalMatch) {
|
|
4461
|
+
const [, g, p, a, l] = gpalMatch;
|
|
4462
|
+
result.gpal = {
|
|
4463
|
+
G: clampInt(Number(g), 0, 20),
|
|
4464
|
+
P: clampInt(Number(p), 0, 20),
|
|
4465
|
+
A: clampInt(Number(a), 0, 20),
|
|
4466
|
+
L: clampInt(Number(l), 0, 20)
|
|
4467
|
+
};
|
|
4468
|
+
}
|
|
4469
|
+
const lmpMatch = input.match(/LMP:\s*([^\n]+)/i);
|
|
4470
|
+
if (lmpMatch?.[1]) result.lmp = lmpMatch[1].trim();
|
|
4471
|
+
const eddUsgMatch = input.match(/EDD\s*\(USG\):\s*([^\n]+)/i);
|
|
4472
|
+
if (eddUsgMatch?.[1]) result.eddUSG = eddUsgMatch[1].trim();
|
|
4473
|
+
const primaryMatch = input.match(/Primary\s*EDD:\s*(lmp|usg)/i);
|
|
4474
|
+
if (primaryMatch?.[1]) result.primaryEDD = primaryMatch[1].toLowerCase();
|
|
4475
|
+
const compMatch = input.match(/Complications:\s*([^\n]+)/i);
|
|
4476
|
+
if (compMatch?.[1]) result.complications = compMatch[1].trim();
|
|
4477
|
+
return result;
|
|
4478
|
+
}
|
|
4479
|
+
function normalizeToDraft(value) {
|
|
4480
|
+
if (!value) return { draft: { ...DEFAULT_DRAFT }, isNewEntry: true };
|
|
4481
|
+
let parsed = value;
|
|
4482
|
+
if (typeof value === "string") {
|
|
4483
|
+
const json = safeJsonParse(value);
|
|
4484
|
+
parsed = json ?? value;
|
|
4485
|
+
}
|
|
4486
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed) && "gpal" in parsed && parsed.gpal && typeof parsed.gpal === "object") {
|
|
4487
|
+
const gpal = parsed.gpal ?? {};
|
|
4488
|
+
const edd = parsed.edd ?? null;
|
|
4489
|
+
const eddUSG = (edd && typeof edd === "object" ? edd.usg : void 0) ?? parsed.eddUSG ?? "";
|
|
4490
|
+
const primaryEDD = (edd && typeof edd === "object" ? edd.primary : void 0) ?? parsed.primaryEDD ?? "lmp";
|
|
4491
|
+
const lmp = parsed.lmp ?? "";
|
|
4492
|
+
const complications = parsed.complications ?? "";
|
|
4493
|
+
const outcome = parsed.outcome ?? null;
|
|
4494
|
+
const is_pregnant = !!parsed.is_pregnant;
|
|
4495
|
+
return {
|
|
4496
|
+
isNewEntry: false,
|
|
4497
|
+
draft: {
|
|
4498
|
+
gpal: {
|
|
4499
|
+
G: clampInt(Number(gpal.G ?? 0), 0, 20),
|
|
4500
|
+
P: clampInt(Number(gpal.P ?? 0), 0, 20),
|
|
4501
|
+
A: clampInt(Number(gpal.A ?? 0), 0, 20),
|
|
4502
|
+
L: clampInt(Number(gpal.L ?? 0), 0, 20)
|
|
4503
|
+
},
|
|
4504
|
+
lmp: typeof lmp === "string" ? lmp : "",
|
|
4505
|
+
is_pregnant,
|
|
4506
|
+
eddUSG: typeof eddUSG === "string" ? eddUSG : "",
|
|
4507
|
+
primaryEDD: primaryEDD === "usg" ? "usg" : "lmp",
|
|
4508
|
+
complications: typeof complications === "string" ? complications : "",
|
|
4509
|
+
outcome: outcome && typeof outcome === "object" ? {
|
|
4510
|
+
type: outcome.type ?? "",
|
|
4511
|
+
date: typeof outcome.date === "string" ? outcome.date : "",
|
|
4512
|
+
notes: typeof outcome.notes === "string" ? outcome.notes : "",
|
|
4513
|
+
is_final: !!outcome.is_final
|
|
4514
|
+
} : null
|
|
4515
|
+
}
|
|
4516
|
+
};
|
|
4517
|
+
}
|
|
4518
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
4519
|
+
const gpalFromFlat = {
|
|
4520
|
+
G: clampInt(Number(parsed.G ?? parsed.g ?? 0), 0, 20),
|
|
4521
|
+
P: clampInt(Number(parsed.P ?? parsed.p ?? 0), 0, 20),
|
|
4522
|
+
A: clampInt(Number(parsed.A ?? parsed.a ?? 0), 0, 20),
|
|
4523
|
+
L: clampInt(Number(parsed.L ?? parsed.l ?? 0), 0, 20)
|
|
4524
|
+
};
|
|
4525
|
+
return {
|
|
4526
|
+
isNewEntry: false,
|
|
4527
|
+
draft: {
|
|
4528
|
+
...DEFAULT_DRAFT,
|
|
4529
|
+
gpal: gpalFromFlat,
|
|
4530
|
+
lmp: typeof parsed.lmp === "string" ? parsed.lmp : "",
|
|
4531
|
+
eddUSG: typeof parsed.eddUSG === "string" ? parsed.eddUSG : "",
|
|
4532
|
+
primaryEDD: parsed.primaryEDD === "usg" ? "usg" : "lmp",
|
|
4533
|
+
complications: typeof parsed.complications === "string" ? parsed.complications : "",
|
|
4534
|
+
outcome: parsed.outcome && typeof parsed.outcome === "object" ? {
|
|
4535
|
+
type: parsed.outcome.type ?? "",
|
|
4536
|
+
date: typeof parsed.outcome.date === "string" ? parsed.outcome.date : "",
|
|
4537
|
+
notes: typeof parsed.outcome.notes === "string" ? parsed.outcome.notes : "",
|
|
4538
|
+
is_final: !!parsed.outcome.is_final
|
|
4539
|
+
} : null,
|
|
4540
|
+
is_pregnant: !!parsed.is_pregnant
|
|
4541
|
+
}
|
|
4542
|
+
};
|
|
4543
|
+
}
|
|
4544
|
+
if (typeof parsed === "string") {
|
|
4545
|
+
const legacy = parseLegacyString(parsed);
|
|
4546
|
+
return { isNewEntry: false, draft: { ...DEFAULT_DRAFT, ...legacy } };
|
|
4547
|
+
}
|
|
4548
|
+
return { draft: { ...DEFAULT_DRAFT }, isNewEntry: true };
|
|
4549
|
+
}
|
|
4550
|
+
function computeEddFromLmp(lmpIso) {
|
|
4551
|
+
if (!isValidIsoDate(lmpIso)) return null;
|
|
4552
|
+
const base = /* @__PURE__ */ new Date(`${lmpIso}T00:00:00.000Z`);
|
|
4553
|
+
base.setUTCDate(base.getUTCDate() + 280);
|
|
4554
|
+
const y = base.getUTCFullYear();
|
|
4555
|
+
const m = pad2(base.getUTCMonth() + 1);
|
|
4556
|
+
const d = pad2(base.getUTCDate());
|
|
4557
|
+
return `${y}-${m}-${d}`;
|
|
4558
|
+
}
|
|
4559
|
+
function diffDaysUtc(fromIso, toIso) {
|
|
4560
|
+
if (!isValidIsoDate(fromIso) || !isValidIsoDate(toIso)) return null;
|
|
4561
|
+
const a = (/* @__PURE__ */ new Date(`${fromIso}T00:00:00.000Z`)).getTime();
|
|
4562
|
+
const b = (/* @__PURE__ */ new Date(`${toIso}T00:00:00.000Z`)).getTime();
|
|
4563
|
+
return Math.floor((b - a) / (1e3 * 60 * 60 * 24));
|
|
4564
|
+
}
|
|
4565
|
+
function computeGestationalAgeFromLmp(lmpIso, today) {
|
|
4566
|
+
const days = diffDaysUtc(lmpIso, today);
|
|
4567
|
+
if (days == null || days < 0) return null;
|
|
4568
|
+
const weeks = Math.floor(days / 7);
|
|
4569
|
+
const rem = days % 7;
|
|
4570
|
+
return { weeks, days: rem, totalDays: days, basedOn: "lmp" };
|
|
4571
|
+
}
|
|
4572
|
+
function computeGestationalAgeFromUsgEdd(eddUsgIso, today) {
|
|
4573
|
+
const daysToEdd = diffDaysUtc(today, eddUsgIso);
|
|
4574
|
+
if (daysToEdd == null) return null;
|
|
4575
|
+
const daysElapsed = 280 - daysToEdd;
|
|
4576
|
+
if (daysElapsed < 0) return null;
|
|
4577
|
+
const weeks = Math.floor(daysElapsed / 7);
|
|
4578
|
+
const rem = daysElapsed % 7;
|
|
4579
|
+
return { weeks, days: rem, totalDays: daysElapsed, basedOn: "usg" };
|
|
4580
|
+
}
|
|
4581
|
+
function computeTrimester(ga) {
|
|
4582
|
+
if (!ga) return null;
|
|
4583
|
+
if (ga.weeks < 13) return 1;
|
|
4584
|
+
if (ga.weeks < 27) return 2;
|
|
4585
|
+
if (ga.weeks < 42) return 3;
|
|
4586
|
+
return null;
|
|
4587
|
+
}
|
|
4588
|
+
function buildStored(draft, today) {
|
|
4589
|
+
const lmpIso = isValidIsoDate(draft.lmp) ? draft.lmp : null;
|
|
4590
|
+
const eddUsgIso = isValidIsoDate(draft.eddUSG) ? draft.eddUSG : null;
|
|
4591
|
+
if (!draft.is_pregnant) {
|
|
4592
|
+
return {
|
|
4593
|
+
gpal: draft.gpal,
|
|
4594
|
+
lmp: lmpIso,
|
|
4595
|
+
is_pregnant: false,
|
|
4596
|
+
edd: null,
|
|
4597
|
+
gestationalAge: null,
|
|
4598
|
+
trimester: null,
|
|
4599
|
+
complications: draft.complications.trim() ? draft.complications : null,
|
|
4600
|
+
outcome: draft.outcome
|
|
4601
|
+
};
|
|
4602
|
+
}
|
|
4603
|
+
const eddFromLmp = lmpIso ? computeEddFromLmp(lmpIso) : null;
|
|
4604
|
+
const gaFromLmp = lmpIso ? computeGestationalAgeFromLmp(lmpIso, today) : null;
|
|
4605
|
+
const gaFromUsg = eddUsgIso ? computeGestationalAgeFromUsgEdd(eddUsgIso, today) : null;
|
|
4606
|
+
const primary = draft.primaryEDD;
|
|
4607
|
+
const gaPrimary = primary === "usg" && gaFromUsg ? gaFromUsg : gaFromLmp ? gaFromLmp : null;
|
|
4608
|
+
return {
|
|
4609
|
+
gpal: draft.gpal,
|
|
4610
|
+
lmp: lmpIso,
|
|
4611
|
+
is_pregnant: true,
|
|
4612
|
+
edd: { lmp: eddFromLmp, usg: eddUsgIso, primary },
|
|
4613
|
+
gestationalAge: gaPrimary,
|
|
4614
|
+
trimester: computeTrimester(gaPrimary),
|
|
4615
|
+
complications: draft.complications.trim() ? draft.complications : null,
|
|
4616
|
+
outcome: draft.outcome
|
|
4617
|
+
};
|
|
4618
|
+
}
|
|
4619
|
+
function stripGpalSuffix(label) {
|
|
4620
|
+
return label.replace(/\s*\(G-P-A-L\)\s*$/i, "").trim();
|
|
4621
|
+
}
|
|
4622
|
+
function useDebouncedCommit(commit, delayMs) {
|
|
4623
|
+
const timeoutRef = React11.useRef(null);
|
|
4624
|
+
const latestCommit = React11.useRef(commit);
|
|
4625
|
+
latestCommit.current = commit;
|
|
4626
|
+
React11.useEffect(() => {
|
|
4627
|
+
return () => {
|
|
4628
|
+
if (timeoutRef.current != null) window.clearTimeout(timeoutRef.current);
|
|
4629
|
+
};
|
|
4630
|
+
}, []);
|
|
4631
|
+
return (next) => {
|
|
4632
|
+
if (timeoutRef.current != null) window.clearTimeout(timeoutRef.current);
|
|
4633
|
+
timeoutRef.current = window.setTimeout(() => latestCommit.current(next), delayMs);
|
|
4634
|
+
};
|
|
4635
|
+
}
|
|
4636
|
+
var ObstetricHistoryWidget = ({ fieldId }) => {
|
|
4637
|
+
const { fieldDef, value, setValue, disabled } = useField(fieldId);
|
|
4638
|
+
const [{ draft, isNewEntry }, setDraftState] = React11.useState(() => normalizeToDraft(value));
|
|
4639
|
+
const [lmpError, setLmpError] = React11.useState(null);
|
|
4640
|
+
const [primaryEddError, setPrimaryEddError] = React11.useState(null);
|
|
4641
|
+
const [activeGpalKey, setActiveGpalKey] = React11.useState(null);
|
|
4642
|
+
const refs = {
|
|
4643
|
+
G: React11.useRef(null),
|
|
4644
|
+
P: React11.useRef(null),
|
|
4645
|
+
A: React11.useRef(null),
|
|
4646
|
+
L: React11.useRef(null)
|
|
4647
|
+
};
|
|
4648
|
+
const today = React11.useMemo(() => todayIso(), []);
|
|
4649
|
+
React11.useEffect(() => {
|
|
4650
|
+
const next = normalizeToDraft(value);
|
|
4651
|
+
const currStr = JSON.stringify(buildStored(draft, today));
|
|
4652
|
+
const nextStr = JSON.stringify(buildStored(next.draft, today));
|
|
4653
|
+
if (currStr !== nextStr) setDraftState(next);
|
|
4654
|
+
}, [value]);
|
|
4655
|
+
const commitImmediate = (nextDraft) => {
|
|
4656
|
+
const stored = buildStored(nextDraft, today);
|
|
4657
|
+
setValue(JSON.stringify(stored));
|
|
4658
|
+
};
|
|
4659
|
+
const commitDebounced = useDebouncedCommit(commitImmediate, 500);
|
|
4660
|
+
const storedComputed = React11.useMemo(() => buildStored(draft, today), [draft, today]);
|
|
4661
|
+
const rightPanelEnabled = draft.is_pregnant && (!!storedComputed.lmp || !!storedComputed.edd?.usg);
|
|
4662
|
+
const headerLabel = fieldDef?.label ? stripGpalSuffix(fieldDef.label) : "Obstetric History";
|
|
4663
|
+
const setDraft = (updater, persist) => {
|
|
4664
|
+
setDraftState((prev) => {
|
|
4665
|
+
const nextDraft = updater(prev.draft);
|
|
4666
|
+
const nextState = { ...prev, draft: nextDraft };
|
|
4667
|
+
if (persist === "immediate") commitImmediate(nextDraft);
|
|
4668
|
+
else commitDebounced(nextDraft);
|
|
4669
|
+
return nextState;
|
|
4670
|
+
});
|
|
4671
|
+
};
|
|
4672
|
+
const sanitizeGpalInput = (raw) => {
|
|
4673
|
+
const digits = raw.replace(/[^\d]/g, "").slice(0, 2);
|
|
4674
|
+
if (!digits) return 0;
|
|
4675
|
+
return clampInt(Number(digits), 0, 20);
|
|
4676
|
+
};
|
|
4677
|
+
const handleGpalChange = (key, raw) => {
|
|
4678
|
+
const prevWasEmpty = draft.gpal[key] === 0 && activeGpalKey === key;
|
|
4679
|
+
const val = sanitizeGpalInput(raw);
|
|
4680
|
+
setDraft((prev) => ({ ...prev, gpal: { ...prev.gpal, [key]: val } }), "debounce");
|
|
4681
|
+
const digitsOnly = raw.replace(/[^\d]/g, "");
|
|
4682
|
+
const shouldAutoTab = digitsOnly.length === 1 && (prevWasEmpty || String(draft.gpal[key]).length >= 1);
|
|
4683
|
+
if (shouldAutoTab) {
|
|
4684
|
+
const order = ["G", "P", "A", "L"];
|
|
4685
|
+
const idx = order.indexOf(key);
|
|
4686
|
+
const nextKey = order[idx + 1];
|
|
4687
|
+
if (nextKey) refs[nextKey].current?.focus();
|
|
4688
|
+
}
|
|
4689
|
+
};
|
|
4690
|
+
const handleLmpChange = (nextIso) => {
|
|
4691
|
+
setPrimaryEddError(null);
|
|
4692
|
+
if (nextIso && nextIso > today) {
|
|
4693
|
+
setLmpError("LMP cannot be in the future");
|
|
4694
|
+
return;
|
|
4695
|
+
}
|
|
4696
|
+
setLmpError(null);
|
|
4697
|
+
setDraft((prev) => ({ ...prev, lmp: nextIso }), "debounce");
|
|
4698
|
+
};
|
|
4699
|
+
const handlePregStatus = (isPregnant) => {
|
|
4700
|
+
setLmpError(null);
|
|
4701
|
+
setPrimaryEddError(null);
|
|
4702
|
+
setDraft((prev) => ({ ...prev, is_pregnant: isPregnant }), "immediate");
|
|
4703
|
+
};
|
|
4704
|
+
const handleEddUsgChange = (nextIso) => {
|
|
4705
|
+
setPrimaryEddError(null);
|
|
4706
|
+
setDraft((prev) => ({ ...prev, eddUSG: nextIso }), "debounce");
|
|
4707
|
+
};
|
|
4708
|
+
const handlePrimaryEdd = (next) => {
|
|
4709
|
+
if (next === "usg" && !isValidIsoDate(draft.eddUSG)) {
|
|
4710
|
+
setPrimaryEddError("Please enter EDD from USG first");
|
|
4711
|
+
return;
|
|
4712
|
+
}
|
|
4713
|
+
setPrimaryEddError(null);
|
|
4714
|
+
setDraft((prev) => ({ ...prev, primaryEDD: next }), "immediate");
|
|
4715
|
+
};
|
|
4716
|
+
const ensureOutcome = () => {
|
|
4717
|
+
if (draft.outcome) return;
|
|
4718
|
+
setDraft(
|
|
4719
|
+
(prev) => ({
|
|
4720
|
+
...prev,
|
|
4721
|
+
outcome: { type: "", date: "", notes: "", is_final: false }
|
|
4722
|
+
}),
|
|
4723
|
+
"immediate"
|
|
4724
|
+
);
|
|
4725
|
+
};
|
|
4726
|
+
const clearOutcome = () => {
|
|
4727
|
+
setDraft((prev) => ({ ...prev, outcome: null }), "immediate");
|
|
4728
|
+
};
|
|
4729
|
+
const updateOutcomeImmediate = (updater) => {
|
|
4730
|
+
setDraft(
|
|
4731
|
+
(prev) => {
|
|
4732
|
+
const o = prev.outcome ?? { type: "", date: "", notes: "", is_final: false };
|
|
4733
|
+
return { ...prev, outcome: updater(o) };
|
|
4734
|
+
},
|
|
4735
|
+
"immediate"
|
|
4736
|
+
);
|
|
4737
|
+
};
|
|
4738
|
+
const updateOutcomeNotesDebounced = (notes) => {
|
|
4739
|
+
setDraft(
|
|
4740
|
+
(prev) => {
|
|
4741
|
+
const o = prev.outcome ?? { type: "", date: "", notes: "", is_final: false };
|
|
4742
|
+
return { ...prev, outcome: { ...o, notes } };
|
|
4743
|
+
},
|
|
4744
|
+
"debounce"
|
|
4745
|
+
);
|
|
4746
|
+
};
|
|
4747
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Card, { className: cn("w-full", disabled && "opacity-70 pointer-events-none"), children: [
|
|
4748
|
+
/* @__PURE__ */ jsxRuntime.jsx(CardHeader, { className: "pb-3", children: /* @__PURE__ */ jsxRuntime.jsx(CardTitle, { className: "text-base font-semibold", children: headerLabel }) }),
|
|
4749
|
+
/* @__PURE__ */ jsxRuntime.jsxs(CardContent, { className: "space-y-4", children: [
|
|
4750
|
+
isNewEntry && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-md border border-blue-200 bg-blue-50 px-3 py-2 text-xs text-blue-900", children: "No previous maternity episode found. Please fill obstetric details to start tracking." }),
|
|
4751
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4 items-start", children: [
|
|
4752
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
|
|
4753
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border bg-white p-4", children: [
|
|
4754
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs font-medium text-muted-foreground mb-2", children: "G-P-A-L" }),
|
|
4755
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-4 gap-3", children: ["G", "P", "A", "L"].map((k) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
|
|
4756
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: `${fieldId}-gpal-${k}`, className: "text-[11px] text-muted-foreground", children: k }),
|
|
4757
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4758
|
+
Input,
|
|
4759
|
+
{
|
|
4760
|
+
ref: refs[k],
|
|
4761
|
+
id: `${fieldId}-gpal-${k}`,
|
|
4762
|
+
inputMode: "numeric",
|
|
4763
|
+
pattern: "\\d*",
|
|
4764
|
+
maxLength: 2,
|
|
4765
|
+
value: String(draft.gpal[k] ?? 0),
|
|
4766
|
+
onFocus: () => {
|
|
4767
|
+
setActiveGpalKey(k);
|
|
4768
|
+
const el = refs[k].current;
|
|
4769
|
+
if (el) el.select();
|
|
4770
|
+
},
|
|
4771
|
+
onChange: (e) => handleGpalChange(k, e.target.value),
|
|
4772
|
+
onKeyDown: (e) => {
|
|
4773
|
+
const allowed = ["Backspace", "Delete", "ArrowLeft", "ArrowRight", "Tab", "Home", "End"];
|
|
4774
|
+
if (allowed.includes(e.key)) return;
|
|
4775
|
+
if (/^\d$/.test(e.key)) return;
|
|
4776
|
+
e.preventDefault();
|
|
4777
|
+
},
|
|
4778
|
+
className: "text-center text-base"
|
|
4779
|
+
}
|
|
4780
|
+
)
|
|
4781
|
+
] }, k)) })
|
|
4782
|
+
] }),
|
|
4783
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-3", children: [
|
|
4784
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2 rounded-lg border bg-white p-4", children: [
|
|
4785
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: `${fieldId}-lmp`, className: cn("text-sm", lmpError && "text-red-600"), children: "Last Menstrual Period (LMP)" }),
|
|
4786
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4787
|
+
Input,
|
|
4788
|
+
{
|
|
4789
|
+
id: `${fieldId}-lmp`,
|
|
4790
|
+
type: "date",
|
|
4791
|
+
max: today,
|
|
4792
|
+
value: draft.lmp,
|
|
4793
|
+
onChange: (e) => handleLmpChange(e.target.value),
|
|
4794
|
+
className: cn(lmpError && "border-red-500")
|
|
4795
|
+
}
|
|
4796
|
+
),
|
|
4797
|
+
lmpError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-red-600", children: lmpError })
|
|
4798
|
+
] }),
|
|
4799
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2 rounded-lg border bg-white p-4", children: [
|
|
4800
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium", children: "Pregnancy Status" }),
|
|
4801
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2", children: [
|
|
4802
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4803
|
+
"button",
|
|
4804
|
+
{
|
|
4805
|
+
type: "button",
|
|
4806
|
+
onClick: () => handlePregStatus(false),
|
|
4807
|
+
className: cn(
|
|
4808
|
+
"flex-1 rounded-md border px-3 py-2 text-xs",
|
|
4809
|
+
!draft.is_pregnant ? "bg-green-600 text-white border-green-600" : "bg-white"
|
|
4810
|
+
),
|
|
4811
|
+
children: "Not Pregnant"
|
|
4812
|
+
}
|
|
4813
|
+
),
|
|
4814
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4815
|
+
"button",
|
|
4816
|
+
{
|
|
4817
|
+
type: "button",
|
|
4818
|
+
onClick: () => handlePregStatus(true),
|
|
4819
|
+
className: cn(
|
|
4820
|
+
"flex-1 rounded-md border px-3 py-2 text-xs",
|
|
4821
|
+
draft.is_pregnant ? "bg-green-600 text-white border-green-600" : "bg-white"
|
|
4822
|
+
),
|
|
4823
|
+
children: "Pregnant"
|
|
4824
|
+
}
|
|
4825
|
+
)
|
|
4826
|
+
] })
|
|
4827
|
+
] })
|
|
4828
|
+
] }),
|
|
4829
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2 rounded-lg border bg-white p-4", children: [
|
|
4830
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: `${fieldId}-complications`, className: "text-sm", children: "Previous Pregnancy Complications" }),
|
|
4831
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4832
|
+
Textarea,
|
|
4833
|
+
{
|
|
4834
|
+
id: `${fieldId}-complications`,
|
|
4835
|
+
placeholder: "e.g. Pre-eclampsia, Gestational diabetes, C-section, etc.",
|
|
4836
|
+
value: draft.complications,
|
|
4837
|
+
onChange: (e) => setDraft((prev) => ({ ...prev, complications: e.target.value }), "debounce"),
|
|
4838
|
+
className: "min-h-[140px]"
|
|
4839
|
+
}
|
|
4840
|
+
)
|
|
4841
|
+
] })
|
|
4842
|
+
] }),
|
|
4843
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border bg-white p-4 min-h-[260px]", children: [
|
|
4844
|
+
!draft.is_pregnant && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full flex items-center justify-center text-center text-sm text-muted-foreground px-6 py-10", children: 'Only for "Pregnant Women" and enter LMP to calculate gestational age and EDD' }),
|
|
4845
|
+
draft.is_pregnant && !rightPanelEnabled && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full flex items-center justify-center text-center text-sm text-muted-foreground px-6 py-10", children: "Enter LMP and/or EDD (USG) to enable gestational age and EDD calculations." }),
|
|
4846
|
+
draft.is_pregnant && rightPanelEnabled && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
|
|
4847
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border p-4", children: [
|
|
4848
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
4849
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-semibold text-blue-700", children: "Expected Delivery Date (EDD)" }),
|
|
4850
|
+
storedComputed.gestationalAge?.basedOn && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "rounded-full bg-blue-100 px-2 py-1 text-[11px] text-blue-700", children: [
|
|
4851
|
+
"Based on ",
|
|
4852
|
+
storedComputed.gestationalAge.basedOn.toUpperCase()
|
|
4853
|
+
] })
|
|
4854
|
+
] }),
|
|
4855
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3", children: [
|
|
4856
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-muted-foreground", children: "Gestational Age:" }),
|
|
4857
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-lg font-semibold", children: storedComputed.gestationalAge ? `${storedComputed.gestationalAge.weeks} weeks ${storedComputed.gestationalAge.days} days` : "\u2014" }),
|
|
4858
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-muted-foreground mt-1", children: storedComputed.trimester ? `Trimester ${storedComputed.trimester}` : "Trimester \u2014" })
|
|
4859
|
+
] })
|
|
4860
|
+
] }),
|
|
4861
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
4862
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-muted-foreground", children: "EDD (from LMP):" }),
|
|
4863
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-md border bg-muted/20 px-3 py-2 text-sm font-semibold", children: storedComputed.edd?.lmp ? formatDdMmYyyy(storedComputed.edd.lmp) : "\u2014" })
|
|
4864
|
+
] }),
|
|
4865
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
4866
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: `${fieldId}-edd-usg`, className: "text-sm", children: "EDD (from USG):" }),
|
|
4867
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4868
|
+
Input,
|
|
4869
|
+
{
|
|
4870
|
+
id: `${fieldId}-edd-usg`,
|
|
4871
|
+
type: "date",
|
|
4872
|
+
value: draft.eddUSG,
|
|
4873
|
+
onChange: (e) => handleEddUsgChange(e.target.value)
|
|
4874
|
+
}
|
|
4875
|
+
)
|
|
4876
|
+
] }),
|
|
4877
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
4878
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-medium", children: "Primary EDD:" }),
|
|
4879
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2", children: [
|
|
4880
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4881
|
+
"button",
|
|
4882
|
+
{
|
|
4883
|
+
type: "button",
|
|
4884
|
+
onClick: () => handlePrimaryEdd("lmp"),
|
|
4885
|
+
className: cn(
|
|
4886
|
+
"flex-1 rounded-md border px-3 py-2 text-sm",
|
|
4887
|
+
draft.primaryEDD === "lmp" ? "bg-blue-600 text-white border-blue-600" : "bg-white"
|
|
4888
|
+
),
|
|
4889
|
+
children: "LMP"
|
|
4890
|
+
}
|
|
4891
|
+
),
|
|
4892
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4893
|
+
"button",
|
|
4894
|
+
{
|
|
4895
|
+
type: "button",
|
|
4896
|
+
onClick: () => handlePrimaryEdd("usg"),
|
|
4897
|
+
className: cn(
|
|
4898
|
+
"flex-1 rounded-md border px-3 py-2 text-sm",
|
|
4899
|
+
draft.primaryEDD === "usg" ? "bg-blue-600 text-white border-blue-600" : "bg-white"
|
|
4900
|
+
),
|
|
4901
|
+
children: "USG"
|
|
4902
|
+
}
|
|
4903
|
+
)
|
|
4904
|
+
] }),
|
|
4905
|
+
primaryEddError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-red-600", children: primaryEddError })
|
|
4906
|
+
] })
|
|
4907
|
+
] })
|
|
4908
|
+
] })
|
|
4909
|
+
] }),
|
|
4910
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border bg-yellow-50/60 p-4", children: [
|
|
4911
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
4912
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-semibold", children: "Pregnancy Outcome (Optional - To Close Episode)" }),
|
|
4913
|
+
draft.outcome && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "text-sm text-red-600 hover:underline", onClick: clearOutcome, children: "Clear" })
|
|
4914
|
+
] }),
|
|
4915
|
+
!draft.outcome && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4916
|
+
"button",
|
|
4917
|
+
{
|
|
4918
|
+
type: "button",
|
|
4919
|
+
onClick: ensureOutcome,
|
|
4920
|
+
className: "mt-3 w-full rounded-md border border-yellow-300 bg-yellow-100 px-3 py-2 text-sm font-medium",
|
|
4921
|
+
children: "+ Add Pregnancy Outcome"
|
|
4922
|
+
}
|
|
4923
|
+
),
|
|
4924
|
+
draft.outcome && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4 space-y-3", children: [
|
|
4925
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
4926
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Label, { className: "text-sm", children: [
|
|
4927
|
+
"Outcome Type ",
|
|
4928
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-red-500", children: "*" })
|
|
4929
|
+
] }),
|
|
4930
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
4931
|
+
"select",
|
|
4932
|
+
{
|
|
4933
|
+
className: "w-full rounded-md border px-3 py-2 text-sm bg-white",
|
|
4934
|
+
value: draft.outcome.type,
|
|
4935
|
+
onChange: (e) => updateOutcomeImmediate((o) => ({ ...o, type: e.target.value })),
|
|
4936
|
+
children: [
|
|
4937
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "Select outcome..." }),
|
|
4938
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "delivery", children: "Normal Delivery" }),
|
|
4939
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "cesarean", children: "Cesarean Section" }),
|
|
4940
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "abortion", children: "Abortion" }),
|
|
4941
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "miscarriage", children: "Miscarriage" }),
|
|
4942
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "stillbirth", children: "Stillbirth" })
|
|
4943
|
+
]
|
|
4944
|
+
}
|
|
4945
|
+
)
|
|
4946
|
+
] }),
|
|
4947
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
4948
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Label, { htmlFor: `${fieldId}-outcome-date`, className: "text-sm", children: [
|
|
4949
|
+
"Date ",
|
|
4950
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-red-500", children: "*" })
|
|
4951
|
+
] }),
|
|
4952
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4953
|
+
Input,
|
|
4954
|
+
{
|
|
4955
|
+
id: `${fieldId}-outcome-date`,
|
|
4956
|
+
type: "date",
|
|
4957
|
+
max: today,
|
|
4958
|
+
value: draft.outcome.date,
|
|
4959
|
+
onChange: (e) => updateOutcomeImmediate((o) => ({ ...o, date: e.target.value }))
|
|
4960
|
+
}
|
|
4961
|
+
),
|
|
4962
|
+
draft.outcome.date && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs text-muted-foreground", children: [
|
|
4963
|
+
"Selected: ",
|
|
4964
|
+
formatDdMmYyyy(draft.outcome.date)
|
|
4965
|
+
] })
|
|
4966
|
+
] }),
|
|
4967
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
4968
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: `${fieldId}-outcome-notes`, className: "text-sm", children: "Notes" }),
|
|
4969
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4970
|
+
Textarea,
|
|
4971
|
+
{
|
|
4972
|
+
id: `${fieldId}-outcome-notes`,
|
|
4973
|
+
placeholder: "e.g. Normal vaginal delivery, healthy baby boy, 3.2kg",
|
|
4974
|
+
value: draft.outcome.notes,
|
|
4975
|
+
onChange: (e) => updateOutcomeNotesDebounced(e.target.value),
|
|
4976
|
+
className: "min-h-[90px]"
|
|
4977
|
+
}
|
|
4978
|
+
)
|
|
4979
|
+
] }),
|
|
4980
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-md border bg-white p-3", children: [
|
|
4981
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2 text-sm", children: [
|
|
4982
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4983
|
+
"input",
|
|
4984
|
+
{
|
|
4985
|
+
type: "checkbox",
|
|
4986
|
+
checked: !!draft.outcome.is_final,
|
|
4987
|
+
onChange: (e) => updateOutcomeImmediate((o) => ({ ...o, is_final: e.target.checked }))
|
|
4988
|
+
}
|
|
4989
|
+
),
|
|
4990
|
+
"Close this pregnancy episode"
|
|
4991
|
+
] }),
|
|
4992
|
+
draft.outcome.is_final && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3 rounded-md border border-red-300 bg-red-50 px-3 py-2 text-xs text-red-800", children: "Checking this will mark the pregnancy as completed and is intended to close the maternity episode." })
|
|
4993
|
+
] })
|
|
4994
|
+
] })
|
|
4995
|
+
] })
|
|
4996
|
+
] })
|
|
4997
|
+
] });
|
|
4998
|
+
};
|
|
4247
4999
|
var FieldRenderer = ({ fieldId }) => {
|
|
4248
5000
|
const { fieldDef, visible } = useField(fieldId);
|
|
4249
5001
|
if (!visible || !fieldDef) {
|
|
@@ -4292,6 +5044,8 @@ var FieldRenderer = ({ fieldId }) => {
|
|
|
4292
5044
|
return /* @__PURE__ */ jsxRuntime.jsx(FollowupWidget, { fieldId });
|
|
4293
5045
|
case "smart_textarea":
|
|
4294
5046
|
return /* @__PURE__ */ jsxRuntime.jsx(SmartTextareaWidget, { fieldId });
|
|
5047
|
+
case "obstetric_history":
|
|
5048
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ObstetricHistoryWidget, { fieldId });
|
|
4295
5049
|
case "static_text": {
|
|
4296
5050
|
const def = fieldDef;
|
|
4297
5051
|
const size = def.size ?? "regular";
|
|
@@ -5063,6 +5817,7 @@ exports.useField = useField;
|
|
|
5063
5817
|
exports.useFieldHandlers = useFieldHandlers;
|
|
5064
5818
|
exports.useForm = useForm;
|
|
5065
5819
|
exports.useFormStore = useFormStore;
|
|
5820
|
+
exports.useFrequentItems = useFrequentItems;
|
|
5066
5821
|
exports.useSmartKeywords = useSmartKeywords;
|
|
5067
5822
|
exports.validateField = validateField;
|
|
5068
5823
|
exports.validateForm = validateForm;
|