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.mjs CHANGED
@@ -634,12 +634,27 @@ var FormStore = class {
634
634
  }
635
635
  };
636
636
  var FormContext = createContext(null);
637
+ var emptyFrequentItems = {
638
+ medications: [],
639
+ investigations: [],
640
+ procedures: []
641
+ };
642
+ var FrequentItemsContext = createContext(emptyFrequentItems);
637
643
  var FieldHandlersContext = createContext({});
638
644
  function useFieldHandlers(fieldId) {
639
645
  const map = useContext(FieldHandlersContext);
640
646
  return map[fieldId] ?? { onSearch: async () => [], recentlyUsed: [] };
641
647
  }
642
- var FormProvider = ({ schema, config, fieldHandlers, children }) => {
648
+ function useFrequentItems() {
649
+ return useContext(FrequentItemsContext);
650
+ }
651
+ var FormProvider = ({
652
+ schema,
653
+ config,
654
+ fieldHandlers,
655
+ frequentItems,
656
+ children
657
+ }) => {
643
658
  const storeRef = useRef(null);
644
659
  if (!storeRef.current) {
645
660
  storeRef.current = new FormStore(schema, config);
@@ -652,7 +667,8 @@ var FormProvider = ({ schema, config, fieldHandlers, children }) => {
652
667
  useEffect(() => {
653
668
  storeRef.current?.load();
654
669
  }, []);
655
- return /* @__PURE__ */ jsx(FormContext.Provider, { value: storeRef.current, children: /* @__PURE__ */ jsx(FieldHandlersContext.Provider, { value: fieldHandlers ?? {}, children }) });
670
+ const frequentItemsValue = frequentItems ?? emptyFrequentItems;
671
+ return /* @__PURE__ */ jsx(FormContext.Provider, { value: storeRef.current, children: /* @__PURE__ */ jsx(FieldHandlersContext.Provider, { value: fieldHandlers ?? {}, children: /* @__PURE__ */ jsx(FrequentItemsContext.Provider, { value: frequentItemsValue, children }) }) });
656
672
  };
657
673
  function useFormStore() {
658
674
  const context = useContext(FormContext);
@@ -2470,6 +2486,7 @@ var AddEntityDialog = ({
2470
2486
  onClose,
2471
2487
  title,
2472
2488
  recentlyUsedSlot,
2489
+ chipSectionLabel = "Recently Used",
2473
2490
  children,
2474
2491
  actionSlot
2475
2492
  }) => {
@@ -2477,7 +2494,7 @@ var AddEntityDialog = ({
2477
2494
  /* @__PURE__ */ jsx(DialogHeader, { className: "px-6 pt-6 pb-4 shrink-0", children: /* @__PURE__ */ jsx(DialogTitle, { className: "text-lg font-semibold", children: title }) }),
2478
2495
  /* @__PURE__ */ jsxs("div", { className: "px-6 flex flex-col gap-4 overflow-y-auto flex-1 min-h-0 pb-4", children: [
2479
2496
  recentlyUsedSlot && /* @__PURE__ */ jsxs("div", { children: [
2480
- /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mb-2", children: "Recently Used" }),
2497
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground mb-2", children: chipSectionLabel }),
2481
2498
  /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: recentlyUsedSlot })
2482
2499
  ] }),
2483
2500
  children
@@ -2502,9 +2519,9 @@ function mapToMedication(result) {
2502
2519
  };
2503
2520
  }
2504
2521
  function mapAIMedicationToMedication(ai) {
2505
- const id = typeof ai.id === "string" ? Number.parseInt(ai.id, 10) || 0 : Number(ai.id);
2522
+ const id = ai.id != null ? String(ai.id) : "";
2506
2523
  return {
2507
- id: Number.isNaN(id) ? 0 : id,
2524
+ id,
2508
2525
  brand_name: ai.brand_name ?? "",
2509
2526
  generic_name: ai.generic_name ?? "",
2510
2527
  frequency: "custom",
@@ -2520,7 +2537,7 @@ function mapAIMedicationToMedication(ai) {
2520
2537
  }
2521
2538
  function createCustomMedication(name, customId) {
2522
2539
  return {
2523
- id: customId,
2540
+ id: String(customId),
2524
2541
  brand_name: name.trim(),
2525
2542
  generic_name: "",
2526
2543
  frequency: "custom",
@@ -2534,6 +2551,39 @@ function createCustomMedication(name, customId) {
2534
2551
  notes: ""
2535
2552
  };
2536
2553
  }
2554
+ function parseDuration(duration) {
2555
+ if (!duration || !duration.trim()) return { value: "3", unit: "days" };
2556
+ const lower = duration.trim().toLowerCase();
2557
+ const match = lower.match(/^(\d+)\s*(day|days|week|weeks|month|months)?$/);
2558
+ if (!match) return { value: "3", unit: "days" };
2559
+ const value = match[1] ?? "3";
2560
+ const unitWord = match[2] ?? "days";
2561
+ const unit = unitWord.startsWith("month") ? "months" : unitWord.startsWith("week") ? "weeks" : "days";
2562
+ return { value, unit };
2563
+ }
2564
+ function mapFrequentItemToMedication(item) {
2565
+ const parsed = parseDuration(item.duration);
2566
+ const duration_value = item.duration_value ?? parsed.value;
2567
+ const duration_unit = item.duration_unit ?? parsed.unit;
2568
+ const before_after = item.before_after === "BEFORE FOOD" ? "BEFORE FOOD" : "AFTER FOOD";
2569
+ const routeNote = item.route ? `Route: ${item.route}` : "";
2570
+ const baseNotes = item.notes?.trim() || "";
2571
+ const combinedNotes = [baseNotes, routeNote.trim()].filter((part) => part.length > 0).join(" \u2014 ");
2572
+ return {
2573
+ id: item.id,
2574
+ brand_name: item.brand_name ?? item.name,
2575
+ generic_name: item.short_name ?? "",
2576
+ frequency: item.frequency ?? "custom",
2577
+ is_custom: false,
2578
+ duration_value,
2579
+ duration_unit,
2580
+ before_after,
2581
+ morning: item.morning ?? "0",
2582
+ afternoon: item.afternoon ?? "0",
2583
+ night: item.night ?? "0",
2584
+ notes: combinedNotes
2585
+ };
2586
+ }
2537
2587
  function Spinner({
2538
2588
  value,
2539
2589
  onChange
@@ -2581,11 +2631,14 @@ function MedicationCard({
2581
2631
  onChange: (e) => set("frequency", e.target.value),
2582
2632
  children: [
2583
2633
  /* @__PURE__ */ jsx("option", { value: "custom", children: "select frequency" }),
2584
- /* @__PURE__ */ jsx("option", { value: "OD", children: "OD" }),
2585
- /* @__PURE__ */ jsx("option", { value: "BD", children: "BD" }),
2586
- /* @__PURE__ */ jsx("option", { value: "TDS", children: "TDS" }),
2587
- /* @__PURE__ */ jsx("option", { value: "QID", children: "QID" }),
2588
- /* @__PURE__ */ jsx("option", { value: "SOS", children: "SOS" })
2634
+ /* @__PURE__ */ jsx("option", { value: "qid", children: "4 times a day (QID)" }),
2635
+ /* @__PURE__ */ jsx("option", { value: "alternate_day", children: "Alternate day" }),
2636
+ /* @__PURE__ */ jsx("option", { value: "once_weekly", children: "Once weekly" }),
2637
+ /* @__PURE__ */ jsx("option", { value: "once_monthly", children: "Once monthly" }),
2638
+ /* @__PURE__ */ jsx("option", { value: "as_needed", children: "As needed" }),
2639
+ /* @__PURE__ */ jsx("option", { value: "fort_night", children: "Fort night" }),
2640
+ /* @__PURE__ */ jsx("option", { value: "at_bed_time", children: "At Bed time" }),
2641
+ /* @__PURE__ */ jsx("option", { value: "sos", children: "SOS only" })
2589
2642
  ]
2590
2643
  }
2591
2644
  ),
@@ -2724,6 +2777,7 @@ var AddMedicationField = ({
2724
2777
  onChange,
2725
2778
  onSearch,
2726
2779
  recentlyUsed = [],
2780
+ frequentItems = [],
2727
2781
  suggestedMedications = []
2728
2782
  }) => {
2729
2783
  const [open, setOpen] = useState(false);
@@ -2769,6 +2823,13 @@ var AddMedicationField = ({
2769
2823
  onChange([...safeValue, mapToMedication(result)]);
2770
2824
  }
2771
2825
  }
2826
+ function handleFrequentItemToggle(item) {
2827
+ if (addedIds.has(String(item.id))) {
2828
+ onChange(safeValue.filter((m) => String(m.id) !== String(item.id)));
2829
+ } else {
2830
+ onChange([...safeValue, mapFrequentItemToMedication(item)]);
2831
+ }
2832
+ }
2772
2833
  function handleResultClick(result) {
2773
2834
  if (addedIds.has(String(result.id))) return;
2774
2835
  setAddingResultId(result.id);
@@ -2819,6 +2880,26 @@ var AddMedicationField = ({
2819
2880
  r.id
2820
2881
  );
2821
2882
  });
2883
+ const limitedFrequentItems = frequentItems.slice(0, 25);
2884
+ const frequentItemChips = limitedFrequentItems.length > 0 ? limitedFrequentItems.map((item) => {
2885
+ const isAdded = addedIds.has(String(item.id));
2886
+ return /* @__PURE__ */ jsxs(
2887
+ "button",
2888
+ {
2889
+ type: "button",
2890
+ onClick: () => handleFrequentItemToggle(item),
2891
+ className: cn(
2892
+ "rounded-full border text-[11px] px-2 py-0.5 transition-colors cursor-pointer",
2893
+ isAdded ? "border-green-300 bg-green-50 text-green-700" : "border-border bg-white hover:bg-gray-50"
2894
+ ),
2895
+ children: [
2896
+ isAdded && /* @__PURE__ */ jsx("span", { className: "mr-1", children: "\u2713" }),
2897
+ item.brand_name ?? item.name
2898
+ ]
2899
+ },
2900
+ item.id
2901
+ );
2902
+ }) : [];
2822
2903
  return /* @__PURE__ */ jsxs("div", { className: "rounded-md overflow-hidden flex flex-col border bg-white border-[#D0D0D0] space-y-3 p-3 h-fit", children: [
2823
2904
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
2824
2905
  /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold", children: label }),
@@ -2832,22 +2913,6 @@ var AddMedicationField = ({
2832
2913
  }
2833
2914
  )
2834
2915
  ] }),
2835
- suggestedMedications.length > 0 && /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-1.5 items-center", children: [
2836
- /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground mr-1", children: "Suggestions:" }),
2837
- suggestedMedications.filter((s) => !addedIds.has(String(s.id))).map((s) => /* @__PURE__ */ jsxs(
2838
- "button",
2839
- {
2840
- type: "button",
2841
- onClick: () => handleAddSuggestion(s),
2842
- 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",
2843
- children: [
2844
- /* @__PURE__ */ jsx(Plus, { className: "h-3 w-3" }),
2845
- s.brand_name || s.generic_name || String(s.id)
2846
- ]
2847
- },
2848
- String(s.id)
2849
- ))
2850
- ] }),
2851
2916
  /* @__PURE__ */ jsx("div", { className: "space-y-2", children: safeValue.map((med, i) => /* @__PURE__ */ jsx(
2852
2917
  MedicationCard,
2853
2918
  {
@@ -2863,7 +2928,8 @@ var AddMedicationField = ({
2863
2928
  open,
2864
2929
  onClose: () => setOpen(false),
2865
2930
  title: "Add Medication",
2866
- recentlyUsedSlot: recentlyUsedChips.length > 0 ? recentlyUsedChips : void 0,
2931
+ recentlyUsedSlot: frequentItemChips.length > 0 ? frequentItemChips : recentlyUsedChips.length > 0 ? recentlyUsedChips : void 0,
2932
+ chipSectionLabel: frequentItemChips.length > 0 ? "Frequently used" : void 0,
2867
2933
  actionSlot: /* @__PURE__ */ jsx(
2868
2934
  "button",
2869
2935
  {
@@ -2888,6 +2954,22 @@ var AddMedicationField = ({
2888
2954
  className: "border border-border rounded-md focus-visible:ring-0"
2889
2955
  }
2890
2956
  ),
2957
+ suggestedMedications.length > 0 && /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-1.5 items-center", children: [
2958
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground mr-1", children: "Suggestions:" }),
2959
+ suggestedMedications.filter((s) => !addedIds.has(String(s.id))).slice(0, 25).map((s) => /* @__PURE__ */ jsxs(
2960
+ "button",
2961
+ {
2962
+ type: "button",
2963
+ onClick: () => handleAddSuggestion(s),
2964
+ 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",
2965
+ children: [
2966
+ /* @__PURE__ */ jsx(Plus, { className: "h-3 w-3" }),
2967
+ s.brand_name || s.generic_name || String(s.id)
2968
+ ]
2969
+ },
2970
+ String(s.id)
2971
+ ))
2972
+ ] }),
2891
2973
  loading && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground text-center py-2", children: "Searching\u2026" }),
2892
2974
  !loading && results.length > 0 && /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-2 max-h-64 overflow-y-auto", children: results.map((r) => /* @__PURE__ */ jsx(
2893
2975
  SearchResultCard,
@@ -2907,6 +2989,7 @@ var AddMedicationWidget = ({ fieldId }) => {
2907
2989
  const { value, setValue } = useField(fieldId);
2908
2990
  const handlers = useFieldHandlers(fieldId);
2909
2991
  const { medications: suggestedMedications } = useAISuggestions();
2992
+ const { medications: frequentMedications } = useFrequentItems();
2910
2993
  const safeValue = Array.isArray(value) ? value : [];
2911
2994
  return /* @__PURE__ */ jsx(
2912
2995
  AddMedicationField,
@@ -2915,6 +2998,7 @@ var AddMedicationWidget = ({ fieldId }) => {
2915
2998
  onChange: setValue,
2916
2999
  onSearch: handlers.onSearch,
2917
3000
  recentlyUsed: handlers.recentlyUsed,
3001
+ frequentItems: frequentMedications,
2918
3002
  suggestedMedications
2919
3003
  }
2920
3004
  );
@@ -2928,12 +3012,23 @@ function mapToInvestigation(result) {
2928
3012
  fromAI: false
2929
3013
  };
2930
3014
  }
3015
+ function mapFrequentItemToInvestigation(item) {
3016
+ return {
3017
+ id: String(item.id),
3018
+ name: item.name,
3019
+ code: item.code ?? void 0,
3020
+ label: item.name,
3021
+ is_custom: false,
3022
+ fromAI: false
3023
+ };
3024
+ }
2931
3025
  var AddInvestigationField = ({
2932
3026
  label = "Investigations",
2933
3027
  value,
2934
3028
  onChange,
2935
3029
  onSearch,
2936
- recentlyUsed = []
3030
+ recentlyUsed = [],
3031
+ frequentItems = []
2937
3032
  }) => {
2938
3033
  const [open, setOpen] = useState(false);
2939
3034
  const [query, setQuery] = useState("");
@@ -2995,6 +3090,14 @@ var AddInvestigationField = ({
2995
3090
  addInvestigation(result);
2996
3091
  }
2997
3092
  }
3093
+ function handleFrequentItemToggle(item) {
3094
+ const id = String(item.id);
3095
+ if (addedIds.has(id)) {
3096
+ removeInvestigation(id);
3097
+ } else {
3098
+ onChange([...valueRef.current, mapFrequentItemToInvestigation(item)]);
3099
+ }
3100
+ }
2998
3101
  const recentlyUsedChips = recentlyUsed.map((r) => {
2999
3102
  const isAdded = addedIds.has(r.id);
3000
3103
  return /* @__PURE__ */ jsxs(
@@ -3014,6 +3117,27 @@ var AddInvestigationField = ({
3014
3117
  r.id
3015
3118
  );
3016
3119
  });
3120
+ const limitedFrequentItems = frequentItems.slice(0, 25);
3121
+ const frequentItemChips = limitedFrequentItems.length > 0 ? limitedFrequentItems.map((item) => {
3122
+ const id = String(item.id);
3123
+ const isAdded = addedIds.has(id);
3124
+ return /* @__PURE__ */ jsxs(
3125
+ "button",
3126
+ {
3127
+ type: "button",
3128
+ onClick: () => handleFrequentItemToggle(item),
3129
+ className: cn(
3130
+ "rounded-full border text-xs px-3 py-1 transition-colors",
3131
+ isAdded ? "border-green-300 bg-green-50 text-green-700" : "border-border bg-white hover:bg-gray-50"
3132
+ ),
3133
+ children: [
3134
+ isAdded && /* @__PURE__ */ jsx("span", { className: "mr-1", children: "\u2713" }),
3135
+ item.name
3136
+ ]
3137
+ },
3138
+ item.id
3139
+ );
3140
+ }) : [];
3017
3141
  return /* @__PURE__ */ jsxs("div", { className: "rounded-md overflow-hidden flex flex-col bg-white border border-[#D0D0D0] space-y-3 p-3 h-fit", children: [
3018
3142
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-3", children: [
3019
3143
  /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold", children: label }),
@@ -3052,7 +3176,8 @@ var AddInvestigationField = ({
3052
3176
  open,
3053
3177
  onClose: () => setOpen(false),
3054
3178
  title: "Add Investigation",
3055
- recentlyUsedSlot: recentlyUsedChips.length > 0 ? recentlyUsedChips : void 0,
3179
+ recentlyUsedSlot: frequentItemChips.length > 0 ? frequentItemChips : recentlyUsedChips.length > 0 ? recentlyUsedChips : void 0,
3180
+ chipSectionLabel: frequentItemChips.length > 0 ? "Frequently used" : void 0,
3056
3181
  children: /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
3057
3182
  /* @__PURE__ */ jsx(
3058
3183
  Input,
@@ -3092,13 +3217,15 @@ var AddInvestigationField = ({
3092
3217
  var AddInvestigationWidget = ({ fieldId }) => {
3093
3218
  const { value, setValue } = useField(fieldId);
3094
3219
  const handlers = useFieldHandlers(fieldId);
3220
+ const { investigations: frequentInvestigations } = useFrequentItems();
3095
3221
  return /* @__PURE__ */ jsx(
3096
3222
  AddInvestigationField,
3097
3223
  {
3098
3224
  value: value ?? [],
3099
3225
  onChange: setValue,
3100
3226
  onSearch: handlers.onSearch,
3101
- recentlyUsed: handlers.recentlyUsed
3227
+ recentlyUsed: handlers.recentlyUsed,
3228
+ frequentItems: frequentInvestigations
3102
3229
  }
3103
3230
  );
3104
3231
  };
@@ -3111,12 +3238,23 @@ function mapToProcedure(result) {
3111
3238
  fromAI: false
3112
3239
  };
3113
3240
  }
3241
+ function mapFrequentItemToProcedure(item) {
3242
+ return {
3243
+ id: String(item.id),
3244
+ name: item.name,
3245
+ code: item.code ?? void 0,
3246
+ label: item.name,
3247
+ is_custom: false,
3248
+ fromAI: false
3249
+ };
3250
+ }
3114
3251
  var AddProcedureField = ({
3115
3252
  label = "Procedures",
3116
3253
  value,
3117
3254
  onChange,
3118
3255
  onSearch,
3119
- recentlyUsed = []
3256
+ recentlyUsed = [],
3257
+ frequentItems = []
3120
3258
  }) => {
3121
3259
  const [open, setOpen] = useState(false);
3122
3260
  const [query, setQuery] = useState("");
@@ -3178,6 +3316,14 @@ var AddProcedureField = ({
3178
3316
  addProcedure(result);
3179
3317
  }
3180
3318
  }
3319
+ function handleFrequentItemToggle(item) {
3320
+ const id = String(item.id);
3321
+ if (addedIds.has(id)) {
3322
+ removeProcedure(id);
3323
+ } else {
3324
+ onChange([...valueRef.current, mapFrequentItemToProcedure(item)]);
3325
+ }
3326
+ }
3181
3327
  const recentlyUsedChips = recentlyUsed.map((r) => {
3182
3328
  const isAdded = addedIds.has(r.id);
3183
3329
  return /* @__PURE__ */ jsxs(
@@ -3197,6 +3343,27 @@ var AddProcedureField = ({
3197
3343
  r.id
3198
3344
  );
3199
3345
  });
3346
+ const limitedFrequentItems = frequentItems.slice(0, 25);
3347
+ const frequentItemChips = limitedFrequentItems.length > 0 ? limitedFrequentItems.map((item) => {
3348
+ const id = String(item.id);
3349
+ const isAdded = addedIds.has(id);
3350
+ return /* @__PURE__ */ jsxs(
3351
+ "button",
3352
+ {
3353
+ type: "button",
3354
+ onClick: () => handleFrequentItemToggle(item),
3355
+ className: cn(
3356
+ "rounded-full border text-xs px-3 py-1 transition-colors",
3357
+ isAdded ? "border-green-300 bg-green-50 text-green-700" : "border-border bg-white hover:bg-gray-50"
3358
+ ),
3359
+ children: [
3360
+ isAdded && /* @__PURE__ */ jsx("span", { className: "mr-1", children: "\u2713" }),
3361
+ item.name
3362
+ ]
3363
+ },
3364
+ item.id
3365
+ );
3366
+ }) : [];
3200
3367
  return /* @__PURE__ */ jsxs("div", { className: "rounded-md overflow-hidden flex flex-col bg-white border border-[#D0D0D0] space-y-3 p-3 h-fit", children: [
3201
3368
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-3", children: [
3202
3369
  /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold", children: label }),
@@ -3235,7 +3402,8 @@ var AddProcedureField = ({
3235
3402
  open,
3236
3403
  onClose: () => setOpen(false),
3237
3404
  title: "Add Procedure",
3238
- recentlyUsedSlot: recentlyUsedChips.length > 0 ? recentlyUsedChips : void 0,
3405
+ recentlyUsedSlot: frequentItemChips.length > 0 ? frequentItemChips : recentlyUsedChips.length > 0 ? recentlyUsedChips : void 0,
3406
+ chipSectionLabel: frequentItemChips.length > 0 ? "Frequently used" : void 0,
3239
3407
  children: /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
3240
3408
  /* @__PURE__ */ jsx(
3241
3409
  Input,
@@ -3275,13 +3443,15 @@ var AddProcedureField = ({
3275
3443
  var AddProcedureWidget = ({ fieldId }) => {
3276
3444
  const { value, setValue } = useField(fieldId);
3277
3445
  const handlers = useFieldHandlers(fieldId);
3446
+ const { procedures: frequentProcedures } = useFrequentItems();
3278
3447
  return /* @__PURE__ */ jsx(
3279
3448
  AddProcedureField,
3280
3449
  {
3281
3450
  value: value ?? [],
3282
3451
  onChange: setValue,
3283
3452
  onSearch: handlers.onSearch,
3284
- recentlyUsed: handlers.recentlyUsed
3453
+ recentlyUsed: handlers.recentlyUsed,
3454
+ frequentItems: frequentProcedures
3285
3455
  }
3286
3456
  );
3287
3457
  };
@@ -4214,6 +4384,588 @@ var SmartTextareaWidget = ({ fieldId }) => {
4214
4384
  showError && /* @__PURE__ */ jsx("p", { className: "text-xs text-red-500", children: error })
4215
4385
  ] });
4216
4386
  };
4387
+ var DEFAULT_DRAFT = {
4388
+ gpal: { G: 0, P: 0, A: 0, L: 0 },
4389
+ lmp: "",
4390
+ is_pregnant: false,
4391
+ eddUSG: "",
4392
+ primaryEDD: "lmp",
4393
+ complications: "",
4394
+ outcome: null
4395
+ };
4396
+ function pad2(n) {
4397
+ return String(n).padStart(2, "0");
4398
+ }
4399
+ function formatDdMmYyyy(iso) {
4400
+ const [y, m, d] = iso.split("-");
4401
+ if (!y || !m || !d) return iso;
4402
+ return `${pad2(Number(d))}/${pad2(Number(m))}/${y}`;
4403
+ }
4404
+ function todayIso() {
4405
+ const d = /* @__PURE__ */ new Date();
4406
+ const y = d.getFullYear();
4407
+ const m = pad2(d.getMonth() + 1);
4408
+ const day = pad2(d.getDate());
4409
+ return `${y}-${m}-${day}`;
4410
+ }
4411
+ function isValidIsoDate(val) {
4412
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(val)) return false;
4413
+ const dt = /* @__PURE__ */ new Date(`${val}T00:00:00.000Z`);
4414
+ return !Number.isNaN(dt.getTime());
4415
+ }
4416
+ function safeJsonParse(val) {
4417
+ try {
4418
+ return JSON.parse(val);
4419
+ } catch {
4420
+ return null;
4421
+ }
4422
+ }
4423
+ function clampInt(val, min, max) {
4424
+ if (!Number.isFinite(val)) return min;
4425
+ return Math.max(min, Math.min(max, Math.trunc(val)));
4426
+ }
4427
+ function parseLegacyString(input) {
4428
+ const result = {};
4429
+ const gpalMatch = input.match(/G(\d+)\s*P(\d+)\s*A(\d+)\s*L(\d+)/i);
4430
+ if (gpalMatch) {
4431
+ const [, g, p, a, l] = gpalMatch;
4432
+ result.gpal = {
4433
+ G: clampInt(Number(g), 0, 20),
4434
+ P: clampInt(Number(p), 0, 20),
4435
+ A: clampInt(Number(a), 0, 20),
4436
+ L: clampInt(Number(l), 0, 20)
4437
+ };
4438
+ }
4439
+ const lmpMatch = input.match(/LMP:\s*([^\n]+)/i);
4440
+ if (lmpMatch?.[1]) result.lmp = lmpMatch[1].trim();
4441
+ const eddUsgMatch = input.match(/EDD\s*\(USG\):\s*([^\n]+)/i);
4442
+ if (eddUsgMatch?.[1]) result.eddUSG = eddUsgMatch[1].trim();
4443
+ const primaryMatch = input.match(/Primary\s*EDD:\s*(lmp|usg)/i);
4444
+ if (primaryMatch?.[1]) result.primaryEDD = primaryMatch[1].toLowerCase();
4445
+ const compMatch = input.match(/Complications:\s*([^\n]+)/i);
4446
+ if (compMatch?.[1]) result.complications = compMatch[1].trim();
4447
+ return result;
4448
+ }
4449
+ function normalizeToDraft(value) {
4450
+ if (!value) return { draft: { ...DEFAULT_DRAFT }, isNewEntry: true };
4451
+ let parsed = value;
4452
+ if (typeof value === "string") {
4453
+ const json = safeJsonParse(value);
4454
+ parsed = json ?? value;
4455
+ }
4456
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed) && "gpal" in parsed && parsed.gpal && typeof parsed.gpal === "object") {
4457
+ const gpal = parsed.gpal ?? {};
4458
+ const edd = parsed.edd ?? null;
4459
+ const eddUSG = (edd && typeof edd === "object" ? edd.usg : void 0) ?? parsed.eddUSG ?? "";
4460
+ const primaryEDD = (edd && typeof edd === "object" ? edd.primary : void 0) ?? parsed.primaryEDD ?? "lmp";
4461
+ const lmp = parsed.lmp ?? "";
4462
+ const complications = parsed.complications ?? "";
4463
+ const outcome = parsed.outcome ?? null;
4464
+ const is_pregnant = !!parsed.is_pregnant;
4465
+ return {
4466
+ isNewEntry: false,
4467
+ draft: {
4468
+ gpal: {
4469
+ G: clampInt(Number(gpal.G ?? 0), 0, 20),
4470
+ P: clampInt(Number(gpal.P ?? 0), 0, 20),
4471
+ A: clampInt(Number(gpal.A ?? 0), 0, 20),
4472
+ L: clampInt(Number(gpal.L ?? 0), 0, 20)
4473
+ },
4474
+ lmp: typeof lmp === "string" ? lmp : "",
4475
+ is_pregnant,
4476
+ eddUSG: typeof eddUSG === "string" ? eddUSG : "",
4477
+ primaryEDD: primaryEDD === "usg" ? "usg" : "lmp",
4478
+ complications: typeof complications === "string" ? complications : "",
4479
+ outcome: outcome && typeof outcome === "object" ? {
4480
+ type: outcome.type ?? "",
4481
+ date: typeof outcome.date === "string" ? outcome.date : "",
4482
+ notes: typeof outcome.notes === "string" ? outcome.notes : "",
4483
+ is_final: !!outcome.is_final
4484
+ } : null
4485
+ }
4486
+ };
4487
+ }
4488
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
4489
+ const gpalFromFlat = {
4490
+ G: clampInt(Number(parsed.G ?? parsed.g ?? 0), 0, 20),
4491
+ P: clampInt(Number(parsed.P ?? parsed.p ?? 0), 0, 20),
4492
+ A: clampInt(Number(parsed.A ?? parsed.a ?? 0), 0, 20),
4493
+ L: clampInt(Number(parsed.L ?? parsed.l ?? 0), 0, 20)
4494
+ };
4495
+ return {
4496
+ isNewEntry: false,
4497
+ draft: {
4498
+ ...DEFAULT_DRAFT,
4499
+ gpal: gpalFromFlat,
4500
+ lmp: typeof parsed.lmp === "string" ? parsed.lmp : "",
4501
+ eddUSG: typeof parsed.eddUSG === "string" ? parsed.eddUSG : "",
4502
+ primaryEDD: parsed.primaryEDD === "usg" ? "usg" : "lmp",
4503
+ complications: typeof parsed.complications === "string" ? parsed.complications : "",
4504
+ outcome: parsed.outcome && typeof parsed.outcome === "object" ? {
4505
+ type: parsed.outcome.type ?? "",
4506
+ date: typeof parsed.outcome.date === "string" ? parsed.outcome.date : "",
4507
+ notes: typeof parsed.outcome.notes === "string" ? parsed.outcome.notes : "",
4508
+ is_final: !!parsed.outcome.is_final
4509
+ } : null,
4510
+ is_pregnant: !!parsed.is_pregnant
4511
+ }
4512
+ };
4513
+ }
4514
+ if (typeof parsed === "string") {
4515
+ const legacy = parseLegacyString(parsed);
4516
+ return { isNewEntry: false, draft: { ...DEFAULT_DRAFT, ...legacy } };
4517
+ }
4518
+ return { draft: { ...DEFAULT_DRAFT }, isNewEntry: true };
4519
+ }
4520
+ function computeEddFromLmp(lmpIso) {
4521
+ if (!isValidIsoDate(lmpIso)) return null;
4522
+ const base = /* @__PURE__ */ new Date(`${lmpIso}T00:00:00.000Z`);
4523
+ base.setUTCDate(base.getUTCDate() + 280);
4524
+ const y = base.getUTCFullYear();
4525
+ const m = pad2(base.getUTCMonth() + 1);
4526
+ const d = pad2(base.getUTCDate());
4527
+ return `${y}-${m}-${d}`;
4528
+ }
4529
+ function diffDaysUtc(fromIso, toIso) {
4530
+ if (!isValidIsoDate(fromIso) || !isValidIsoDate(toIso)) return null;
4531
+ const a = (/* @__PURE__ */ new Date(`${fromIso}T00:00:00.000Z`)).getTime();
4532
+ const b = (/* @__PURE__ */ new Date(`${toIso}T00:00:00.000Z`)).getTime();
4533
+ return Math.floor((b - a) / (1e3 * 60 * 60 * 24));
4534
+ }
4535
+ function computeGestationalAgeFromLmp(lmpIso, today) {
4536
+ const days = diffDaysUtc(lmpIso, today);
4537
+ if (days == null || days < 0) return null;
4538
+ const weeks = Math.floor(days / 7);
4539
+ const rem = days % 7;
4540
+ return { weeks, days: rem, totalDays: days, basedOn: "lmp" };
4541
+ }
4542
+ function computeGestationalAgeFromUsgEdd(eddUsgIso, today) {
4543
+ const daysToEdd = diffDaysUtc(today, eddUsgIso);
4544
+ if (daysToEdd == null) return null;
4545
+ const daysElapsed = 280 - daysToEdd;
4546
+ if (daysElapsed < 0) return null;
4547
+ const weeks = Math.floor(daysElapsed / 7);
4548
+ const rem = daysElapsed % 7;
4549
+ return { weeks, days: rem, totalDays: daysElapsed, basedOn: "usg" };
4550
+ }
4551
+ function computeTrimester(ga) {
4552
+ if (!ga) return null;
4553
+ if (ga.weeks < 13) return 1;
4554
+ if (ga.weeks < 27) return 2;
4555
+ if (ga.weeks < 42) return 3;
4556
+ return null;
4557
+ }
4558
+ function buildStored(draft, today) {
4559
+ const lmpIso = isValidIsoDate(draft.lmp) ? draft.lmp : null;
4560
+ const eddUsgIso = isValidIsoDate(draft.eddUSG) ? draft.eddUSG : null;
4561
+ if (!draft.is_pregnant) {
4562
+ return {
4563
+ gpal: draft.gpal,
4564
+ lmp: lmpIso,
4565
+ is_pregnant: false,
4566
+ edd: null,
4567
+ gestationalAge: null,
4568
+ trimester: null,
4569
+ complications: draft.complications.trim() ? draft.complications : null,
4570
+ outcome: draft.outcome
4571
+ };
4572
+ }
4573
+ const eddFromLmp = lmpIso ? computeEddFromLmp(lmpIso) : null;
4574
+ const gaFromLmp = lmpIso ? computeGestationalAgeFromLmp(lmpIso, today) : null;
4575
+ const gaFromUsg = eddUsgIso ? computeGestationalAgeFromUsgEdd(eddUsgIso, today) : null;
4576
+ const primary = draft.primaryEDD;
4577
+ const gaPrimary = primary === "usg" && gaFromUsg ? gaFromUsg : gaFromLmp ? gaFromLmp : null;
4578
+ return {
4579
+ gpal: draft.gpal,
4580
+ lmp: lmpIso,
4581
+ is_pregnant: true,
4582
+ edd: { lmp: eddFromLmp, usg: eddUsgIso, primary },
4583
+ gestationalAge: gaPrimary,
4584
+ trimester: computeTrimester(gaPrimary),
4585
+ complications: draft.complications.trim() ? draft.complications : null,
4586
+ outcome: draft.outcome
4587
+ };
4588
+ }
4589
+ function stripGpalSuffix(label) {
4590
+ return label.replace(/\s*\(G-P-A-L\)\s*$/i, "").trim();
4591
+ }
4592
+ function useDebouncedCommit(commit, delayMs) {
4593
+ const timeoutRef = useRef(null);
4594
+ const latestCommit = useRef(commit);
4595
+ latestCommit.current = commit;
4596
+ useEffect(() => {
4597
+ return () => {
4598
+ if (timeoutRef.current != null) window.clearTimeout(timeoutRef.current);
4599
+ };
4600
+ }, []);
4601
+ return (next) => {
4602
+ if (timeoutRef.current != null) window.clearTimeout(timeoutRef.current);
4603
+ timeoutRef.current = window.setTimeout(() => latestCommit.current(next), delayMs);
4604
+ };
4605
+ }
4606
+ var ObstetricHistoryWidget = ({ fieldId }) => {
4607
+ const { fieldDef, value, setValue, disabled } = useField(fieldId);
4608
+ const [{ draft, isNewEntry }, setDraftState] = useState(() => normalizeToDraft(value));
4609
+ const [lmpError, setLmpError] = useState(null);
4610
+ const [primaryEddError, setPrimaryEddError] = useState(null);
4611
+ const [activeGpalKey, setActiveGpalKey] = useState(null);
4612
+ const refs = {
4613
+ G: useRef(null),
4614
+ P: useRef(null),
4615
+ A: useRef(null),
4616
+ L: useRef(null)
4617
+ };
4618
+ const today = useMemo(() => todayIso(), []);
4619
+ useEffect(() => {
4620
+ const next = normalizeToDraft(value);
4621
+ const currStr = JSON.stringify(buildStored(draft, today));
4622
+ const nextStr = JSON.stringify(buildStored(next.draft, today));
4623
+ if (currStr !== nextStr) setDraftState(next);
4624
+ }, [value]);
4625
+ const commitImmediate = (nextDraft) => {
4626
+ const stored = buildStored(nextDraft, today);
4627
+ setValue(JSON.stringify(stored));
4628
+ };
4629
+ const commitDebounced = useDebouncedCommit(commitImmediate, 500);
4630
+ const storedComputed = useMemo(() => buildStored(draft, today), [draft, today]);
4631
+ const rightPanelEnabled = draft.is_pregnant && (!!storedComputed.lmp || !!storedComputed.edd?.usg);
4632
+ const headerLabel = fieldDef?.label ? stripGpalSuffix(fieldDef.label) : "Obstetric History";
4633
+ const setDraft = (updater, persist) => {
4634
+ setDraftState((prev) => {
4635
+ const nextDraft = updater(prev.draft);
4636
+ const nextState = { ...prev, draft: nextDraft };
4637
+ if (persist === "immediate") commitImmediate(nextDraft);
4638
+ else commitDebounced(nextDraft);
4639
+ return nextState;
4640
+ });
4641
+ };
4642
+ const sanitizeGpalInput = (raw) => {
4643
+ const digits = raw.replace(/[^\d]/g, "").slice(0, 2);
4644
+ if (!digits) return 0;
4645
+ return clampInt(Number(digits), 0, 20);
4646
+ };
4647
+ const handleGpalChange = (key, raw) => {
4648
+ const prevWasEmpty = draft.gpal[key] === 0 && activeGpalKey === key;
4649
+ const val = sanitizeGpalInput(raw);
4650
+ setDraft((prev) => ({ ...prev, gpal: { ...prev.gpal, [key]: val } }), "debounce");
4651
+ const digitsOnly = raw.replace(/[^\d]/g, "");
4652
+ const shouldAutoTab = digitsOnly.length === 1 && (prevWasEmpty || String(draft.gpal[key]).length >= 1);
4653
+ if (shouldAutoTab) {
4654
+ const order = ["G", "P", "A", "L"];
4655
+ const idx = order.indexOf(key);
4656
+ const nextKey = order[idx + 1];
4657
+ if (nextKey) refs[nextKey].current?.focus();
4658
+ }
4659
+ };
4660
+ const handleLmpChange = (nextIso) => {
4661
+ setPrimaryEddError(null);
4662
+ if (nextIso && nextIso > today) {
4663
+ setLmpError("LMP cannot be in the future");
4664
+ return;
4665
+ }
4666
+ setLmpError(null);
4667
+ setDraft((prev) => ({ ...prev, lmp: nextIso }), "debounce");
4668
+ };
4669
+ const handlePregStatus = (isPregnant) => {
4670
+ setLmpError(null);
4671
+ setPrimaryEddError(null);
4672
+ setDraft((prev) => ({ ...prev, is_pregnant: isPregnant }), "immediate");
4673
+ };
4674
+ const handleEddUsgChange = (nextIso) => {
4675
+ setPrimaryEddError(null);
4676
+ setDraft((prev) => ({ ...prev, eddUSG: nextIso }), "debounce");
4677
+ };
4678
+ const handlePrimaryEdd = (next) => {
4679
+ if (next === "usg" && !isValidIsoDate(draft.eddUSG)) {
4680
+ setPrimaryEddError("Please enter EDD from USG first");
4681
+ return;
4682
+ }
4683
+ setPrimaryEddError(null);
4684
+ setDraft((prev) => ({ ...prev, primaryEDD: next }), "immediate");
4685
+ };
4686
+ const ensureOutcome = () => {
4687
+ if (draft.outcome) return;
4688
+ setDraft(
4689
+ (prev) => ({
4690
+ ...prev,
4691
+ outcome: { type: "", date: "", notes: "", is_final: false }
4692
+ }),
4693
+ "immediate"
4694
+ );
4695
+ };
4696
+ const clearOutcome = () => {
4697
+ setDraft((prev) => ({ ...prev, outcome: null }), "immediate");
4698
+ };
4699
+ const updateOutcomeImmediate = (updater) => {
4700
+ setDraft(
4701
+ (prev) => {
4702
+ const o = prev.outcome ?? { type: "", date: "", notes: "", is_final: false };
4703
+ return { ...prev, outcome: updater(o) };
4704
+ },
4705
+ "immediate"
4706
+ );
4707
+ };
4708
+ const updateOutcomeNotesDebounced = (notes) => {
4709
+ setDraft(
4710
+ (prev) => {
4711
+ const o = prev.outcome ?? { type: "", date: "", notes: "", is_final: false };
4712
+ return { ...prev, outcome: { ...o, notes } };
4713
+ },
4714
+ "debounce"
4715
+ );
4716
+ };
4717
+ return /* @__PURE__ */ jsxs(Card, { className: cn("w-full", disabled && "opacity-70 pointer-events-none"), children: [
4718
+ /* @__PURE__ */ jsx(CardHeader, { className: "pb-3", children: /* @__PURE__ */ jsx(CardTitle, { className: "text-base font-semibold", children: headerLabel }) }),
4719
+ /* @__PURE__ */ jsxs(CardContent, { className: "space-y-4", children: [
4720
+ isNewEntry && /* @__PURE__ */ 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." }),
4721
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4 items-start", children: [
4722
+ /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
4723
+ /* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-white p-4", children: [
4724
+ /* @__PURE__ */ jsx("div", { className: "text-xs font-medium text-muted-foreground mb-2", children: "G-P-A-L" }),
4725
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-4 gap-3", children: ["G", "P", "A", "L"].map((k) => /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
4726
+ /* @__PURE__ */ jsx(Label, { htmlFor: `${fieldId}-gpal-${k}`, className: "text-[11px] text-muted-foreground", children: k }),
4727
+ /* @__PURE__ */ jsx(
4728
+ Input,
4729
+ {
4730
+ ref: refs[k],
4731
+ id: `${fieldId}-gpal-${k}`,
4732
+ inputMode: "numeric",
4733
+ pattern: "\\d*",
4734
+ maxLength: 2,
4735
+ value: String(draft.gpal[k] ?? 0),
4736
+ onFocus: () => {
4737
+ setActiveGpalKey(k);
4738
+ const el = refs[k].current;
4739
+ if (el) el.select();
4740
+ },
4741
+ onChange: (e) => handleGpalChange(k, e.target.value),
4742
+ onKeyDown: (e) => {
4743
+ const allowed = ["Backspace", "Delete", "ArrowLeft", "ArrowRight", "Tab", "Home", "End"];
4744
+ if (allowed.includes(e.key)) return;
4745
+ if (/^\d$/.test(e.key)) return;
4746
+ e.preventDefault();
4747
+ },
4748
+ className: "text-center text-base"
4749
+ }
4750
+ )
4751
+ ] }, k)) })
4752
+ ] }),
4753
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-3", children: [
4754
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2 rounded-lg border bg-white p-4", children: [
4755
+ /* @__PURE__ */ jsx(Label, { htmlFor: `${fieldId}-lmp`, className: cn("text-sm", lmpError && "text-red-600"), children: "Last Menstrual Period (LMP)" }),
4756
+ /* @__PURE__ */ jsx(
4757
+ Input,
4758
+ {
4759
+ id: `${fieldId}-lmp`,
4760
+ type: "date",
4761
+ max: today,
4762
+ value: draft.lmp,
4763
+ onChange: (e) => handleLmpChange(e.target.value),
4764
+ className: cn(lmpError && "border-red-500")
4765
+ }
4766
+ ),
4767
+ lmpError && /* @__PURE__ */ jsx("p", { className: "text-xs text-red-600", children: lmpError })
4768
+ ] }),
4769
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2 rounded-lg border bg-white p-4", children: [
4770
+ /* @__PURE__ */ jsx("div", { className: "text-sm font-medium", children: "Pregnancy Status" }),
4771
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
4772
+ /* @__PURE__ */ jsx(
4773
+ "button",
4774
+ {
4775
+ type: "button",
4776
+ onClick: () => handlePregStatus(false),
4777
+ className: cn(
4778
+ "flex-1 rounded-md border px-3 py-2 text-xs",
4779
+ !draft.is_pregnant ? "bg-green-600 text-white border-green-600" : "bg-white"
4780
+ ),
4781
+ children: "Not Pregnant"
4782
+ }
4783
+ ),
4784
+ /* @__PURE__ */ jsx(
4785
+ "button",
4786
+ {
4787
+ type: "button",
4788
+ onClick: () => handlePregStatus(true),
4789
+ className: cn(
4790
+ "flex-1 rounded-md border px-3 py-2 text-xs",
4791
+ draft.is_pregnant ? "bg-green-600 text-white border-green-600" : "bg-white"
4792
+ ),
4793
+ children: "Pregnant"
4794
+ }
4795
+ )
4796
+ ] })
4797
+ ] })
4798
+ ] }),
4799
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2 rounded-lg border bg-white p-4", children: [
4800
+ /* @__PURE__ */ jsx(Label, { htmlFor: `${fieldId}-complications`, className: "text-sm", children: "Previous Pregnancy Complications" }),
4801
+ /* @__PURE__ */ jsx(
4802
+ Textarea,
4803
+ {
4804
+ id: `${fieldId}-complications`,
4805
+ placeholder: "e.g. Pre-eclampsia, Gestational diabetes, C-section, etc.",
4806
+ value: draft.complications,
4807
+ onChange: (e) => setDraft((prev) => ({ ...prev, complications: e.target.value }), "debounce"),
4808
+ className: "min-h-[140px]"
4809
+ }
4810
+ )
4811
+ ] })
4812
+ ] }),
4813
+ /* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-white p-4 min-h-[260px]", children: [
4814
+ !draft.is_pregnant && /* @__PURE__ */ 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' }),
4815
+ draft.is_pregnant && !rightPanelEnabled && /* @__PURE__ */ 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." }),
4816
+ draft.is_pregnant && rightPanelEnabled && /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
4817
+ /* @__PURE__ */ jsxs("div", { className: "rounded-lg border p-4", children: [
4818
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
4819
+ /* @__PURE__ */ jsx("div", { className: "text-sm font-semibold text-blue-700", children: "Expected Delivery Date (EDD)" }),
4820
+ storedComputed.gestationalAge?.basedOn && /* @__PURE__ */ jsxs("span", { className: "rounded-full bg-blue-100 px-2 py-1 text-[11px] text-blue-700", children: [
4821
+ "Based on ",
4822
+ storedComputed.gestationalAge.basedOn.toUpperCase()
4823
+ ] })
4824
+ ] }),
4825
+ /* @__PURE__ */ jsxs("div", { className: "mt-3", children: [
4826
+ /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground", children: "Gestational Age:" }),
4827
+ /* @__PURE__ */ jsx("div", { className: "text-lg font-semibold", children: storedComputed.gestationalAge ? `${storedComputed.gestationalAge.weeks} weeks ${storedComputed.gestationalAge.days} days` : "\u2014" }),
4828
+ /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground mt-1", children: storedComputed.trimester ? `Trimester ${storedComputed.trimester}` : "Trimester \u2014" })
4829
+ ] })
4830
+ ] }),
4831
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
4832
+ /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground", children: "EDD (from LMP):" }),
4833
+ /* @__PURE__ */ 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" })
4834
+ ] }),
4835
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
4836
+ /* @__PURE__ */ jsx(Label, { htmlFor: `${fieldId}-edd-usg`, className: "text-sm", children: "EDD (from USG):" }),
4837
+ /* @__PURE__ */ jsx(
4838
+ Input,
4839
+ {
4840
+ id: `${fieldId}-edd-usg`,
4841
+ type: "date",
4842
+ value: draft.eddUSG,
4843
+ onChange: (e) => handleEddUsgChange(e.target.value)
4844
+ }
4845
+ )
4846
+ ] }),
4847
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
4848
+ /* @__PURE__ */ jsx("div", { className: "text-sm font-medium", children: "Primary EDD:" }),
4849
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
4850
+ /* @__PURE__ */ jsx(
4851
+ "button",
4852
+ {
4853
+ type: "button",
4854
+ onClick: () => handlePrimaryEdd("lmp"),
4855
+ className: cn(
4856
+ "flex-1 rounded-md border px-3 py-2 text-sm",
4857
+ draft.primaryEDD === "lmp" ? "bg-blue-600 text-white border-blue-600" : "bg-white"
4858
+ ),
4859
+ children: "LMP"
4860
+ }
4861
+ ),
4862
+ /* @__PURE__ */ jsx(
4863
+ "button",
4864
+ {
4865
+ type: "button",
4866
+ onClick: () => handlePrimaryEdd("usg"),
4867
+ className: cn(
4868
+ "flex-1 rounded-md border px-3 py-2 text-sm",
4869
+ draft.primaryEDD === "usg" ? "bg-blue-600 text-white border-blue-600" : "bg-white"
4870
+ ),
4871
+ children: "USG"
4872
+ }
4873
+ )
4874
+ ] }),
4875
+ primaryEddError && /* @__PURE__ */ jsx("p", { className: "text-xs text-red-600", children: primaryEddError })
4876
+ ] })
4877
+ ] })
4878
+ ] })
4879
+ ] }),
4880
+ /* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-yellow-50/60 p-4", children: [
4881
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
4882
+ /* @__PURE__ */ jsx("div", { className: "text-sm font-semibold", children: "Pregnancy Outcome (Optional - To Close Episode)" }),
4883
+ draft.outcome && /* @__PURE__ */ jsx("button", { type: "button", className: "text-sm text-red-600 hover:underline", onClick: clearOutcome, children: "Clear" })
4884
+ ] }),
4885
+ !draft.outcome && /* @__PURE__ */ jsx(
4886
+ "button",
4887
+ {
4888
+ type: "button",
4889
+ onClick: ensureOutcome,
4890
+ className: "mt-3 w-full rounded-md border border-yellow-300 bg-yellow-100 px-3 py-2 text-sm font-medium",
4891
+ children: "+ Add Pregnancy Outcome"
4892
+ }
4893
+ ),
4894
+ draft.outcome && /* @__PURE__ */ jsxs("div", { className: "mt-4 space-y-3", children: [
4895
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
4896
+ /* @__PURE__ */ jsxs(Label, { className: "text-sm", children: [
4897
+ "Outcome Type ",
4898
+ /* @__PURE__ */ jsx("span", { className: "text-red-500", children: "*" })
4899
+ ] }),
4900
+ /* @__PURE__ */ jsxs(
4901
+ "select",
4902
+ {
4903
+ className: "w-full rounded-md border px-3 py-2 text-sm bg-white",
4904
+ value: draft.outcome.type,
4905
+ onChange: (e) => updateOutcomeImmediate((o) => ({ ...o, type: e.target.value })),
4906
+ children: [
4907
+ /* @__PURE__ */ jsx("option", { value: "", children: "Select outcome..." }),
4908
+ /* @__PURE__ */ jsx("option", { value: "delivery", children: "Normal Delivery" }),
4909
+ /* @__PURE__ */ jsx("option", { value: "cesarean", children: "Cesarean Section" }),
4910
+ /* @__PURE__ */ jsx("option", { value: "abortion", children: "Abortion" }),
4911
+ /* @__PURE__ */ jsx("option", { value: "miscarriage", children: "Miscarriage" }),
4912
+ /* @__PURE__ */ jsx("option", { value: "stillbirth", children: "Stillbirth" })
4913
+ ]
4914
+ }
4915
+ )
4916
+ ] }),
4917
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
4918
+ /* @__PURE__ */ jsxs(Label, { htmlFor: `${fieldId}-outcome-date`, className: "text-sm", children: [
4919
+ "Date ",
4920
+ /* @__PURE__ */ jsx("span", { className: "text-red-500", children: "*" })
4921
+ ] }),
4922
+ /* @__PURE__ */ jsx(
4923
+ Input,
4924
+ {
4925
+ id: `${fieldId}-outcome-date`,
4926
+ type: "date",
4927
+ max: today,
4928
+ value: draft.outcome.date,
4929
+ onChange: (e) => updateOutcomeImmediate((o) => ({ ...o, date: e.target.value }))
4930
+ }
4931
+ ),
4932
+ draft.outcome.date && /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", children: [
4933
+ "Selected: ",
4934
+ formatDdMmYyyy(draft.outcome.date)
4935
+ ] })
4936
+ ] }),
4937
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
4938
+ /* @__PURE__ */ jsx(Label, { htmlFor: `${fieldId}-outcome-notes`, className: "text-sm", children: "Notes" }),
4939
+ /* @__PURE__ */ jsx(
4940
+ Textarea,
4941
+ {
4942
+ id: `${fieldId}-outcome-notes`,
4943
+ placeholder: "e.g. Normal vaginal delivery, healthy baby boy, 3.2kg",
4944
+ value: draft.outcome.notes,
4945
+ onChange: (e) => updateOutcomeNotesDebounced(e.target.value),
4946
+ className: "min-h-[90px]"
4947
+ }
4948
+ )
4949
+ ] }),
4950
+ /* @__PURE__ */ jsxs("div", { className: "rounded-md border bg-white p-3", children: [
4951
+ /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-sm", children: [
4952
+ /* @__PURE__ */ jsx(
4953
+ "input",
4954
+ {
4955
+ type: "checkbox",
4956
+ checked: !!draft.outcome.is_final,
4957
+ onChange: (e) => updateOutcomeImmediate((o) => ({ ...o, is_final: e.target.checked }))
4958
+ }
4959
+ ),
4960
+ "Close this pregnancy episode"
4961
+ ] }),
4962
+ draft.outcome.is_final && /* @__PURE__ */ 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." })
4963
+ ] })
4964
+ ] })
4965
+ ] })
4966
+ ] })
4967
+ ] });
4968
+ };
4217
4969
  var FieldRenderer = ({ fieldId }) => {
4218
4970
  const { fieldDef, visible } = useField(fieldId);
4219
4971
  if (!visible || !fieldDef) {
@@ -4262,6 +5014,8 @@ var FieldRenderer = ({ fieldId }) => {
4262
5014
  return /* @__PURE__ */ jsx(FollowupWidget, { fieldId });
4263
5015
  case "smart_textarea":
4264
5016
  return /* @__PURE__ */ jsx(SmartTextareaWidget, { fieldId });
5017
+ case "obstetric_history":
5018
+ return /* @__PURE__ */ jsx(ObstetricHistoryWidget, { fieldId });
4265
5019
  case "static_text": {
4266
5020
  const def = fieldDef;
4267
5021
  const size = def.size ?? "regular";
@@ -5010,6 +5764,6 @@ function createUploadHandler(options) {
5010
5764
  };
5011
5765
  }
5012
5766
 
5013
- export { AddInvestigationField, AddMedicationField, DifferentialDiagnosis, DynamicForm, EMAIL_REGEX, FieldRenderer, FormControls, FormProvider, FormStore, ImageUploadWidget, ReadOnlyForm, ReadOnlyImageUpload, ReadOnlySignature, ReadOnlyTable, SignatureUploadWidget, SmartForm, SmartTextareaWidget, createUploadHandler, evaluateRules, useField, useFieldHandlers, useForm, useFormStore, useSmartKeywords, validateField, validateForm };
5767
+ export { AddInvestigationField, AddMedicationField, DifferentialDiagnosis, DynamicForm, EMAIL_REGEX, FieldRenderer, FormControls, FormProvider, FormStore, ImageUploadWidget, ReadOnlyForm, ReadOnlyImageUpload, ReadOnlySignature, ReadOnlyTable, SignatureUploadWidget, SmartForm, SmartTextareaWidget, createUploadHandler, evaluateRules, useField, useFieldHandlers, useForm, useFormStore, useFrequentItems, useSmartKeywords, validateField, validateForm };
5014
5768
  //# sourceMappingURL=index.mjs.map
5015
5769
  //# sourceMappingURL=index.mjs.map