formanitor 0.2.2 → 0.2.4
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/BpeChartWidget-HATASHAC.mjs +7 -0
- package/dist/BpeChartWidget-HATASHAC.mjs.map +1 -0
- package/dist/BpeChartWidget-VZRH7M7L.cjs +28 -0
- package/dist/BpeChartWidget-VZRH7M7L.cjs.map +1 -0
- package/dist/{DateTimeWidget-3AUBZYYK.mjs → DateTimeWidget-KRX4O6OD.mjs} +5 -4
- package/dist/DateTimeWidget-KRX4O6OD.mjs.map +1 -0
- package/dist/{DateTimeWidget-OS7ER5F6.cjs → DateTimeWidget-RJ7SATVA.cjs} +6 -5
- package/dist/DateTimeWidget-RJ7SATVA.cjs.map +1 -0
- package/dist/{DateWidget-KCTE6N5G.mjs → DateWidget-JEKDKPNS.mjs} +4 -3
- package/dist/DateWidget-JEKDKPNS.mjs.map +1 -0
- package/dist/{DateWidget-UNLX544Z.cjs → DateWidget-T7IQUWEA.cjs} +8 -7
- package/dist/DateWidget-T7IQUWEA.cjs.map +1 -0
- package/dist/DentalChartWidget-LYLOFWZU.cjs +21 -0
- package/dist/DentalChartWidget-LYLOFWZU.cjs.map +1 -0
- package/dist/DentalChartWidget-P2YPKAMO.mjs +8 -0
- package/dist/DentalChartWidget-P2YPKAMO.mjs.map +1 -0
- package/dist/{EditableTable-VQ72UEFF.cjs → EditableTable-OW5LC6OC.cjs} +6 -5
- package/dist/EditableTable-OW5LC6OC.cjs.map +1 -0
- package/dist/{EditableTable-XFCPKSUY.mjs → EditableTable-VZ66IXYI.mjs} +5 -4
- package/dist/EditableTable-VZ66IXYI.mjs.map +1 -0
- package/dist/ExtraOralExamWidget-JVKJ4ZWC.mjs +438 -0
- package/dist/ExtraOralExamWidget-JVKJ4ZWC.mjs.map +1 -0
- package/dist/ExtraOralExamWidget-ZIOSKMIO.cjs +440 -0
- package/dist/ExtraOralExamWidget-ZIOSKMIO.cjs.map +1 -0
- package/dist/{FollowupWidget-MAYTHM2E.cjs → FollowupWidget-2STSJSDY.cjs} +8 -7
- package/dist/FollowupWidget-2STSJSDY.cjs.map +1 -0
- package/dist/{FollowupWidget-BFZ6P2JE.mjs → FollowupWidget-GCGPWZVY.mjs} +4 -3
- package/dist/FollowupWidget-GCGPWZVY.mjs.map +1 -0
- package/dist/{OBGPathwayWidget-X67XKRIH.mjs → OBGPathwayWidget-QJNWUIEM.mjs} +4 -3
- package/dist/OBGPathwayWidget-QJNWUIEM.mjs.map +1 -0
- package/dist/{OBGPathwayWidget-XGN3HEWS.cjs → OBGPathwayWidget-YRU36UL7.cjs} +13 -12
- package/dist/OBGPathwayWidget-YRU36UL7.cjs.map +1 -0
- package/dist/{ObstetricHistoryWidget-Z4VAXH3E.mjs → ObstetricHistoryWidget-EW6JLNQ7.mjs} +4 -3
- package/dist/ObstetricHistoryWidget-EW6JLNQ7.mjs.map +1 -0
- package/dist/{ObstetricHistoryWidget-RP7NY4PV.cjs → ObstetricHistoryWidget-OOWCVFRB.cjs} +10 -9
- package/dist/ObstetricHistoryWidget-OOWCVFRB.cjs.map +1 -0
- package/dist/PregnancyStatusWidget-QTTVFBOE.cjs +96 -0
- package/dist/PregnancyStatusWidget-QTTVFBOE.cjs.map +1 -0
- package/dist/PregnancyStatusWidget-U2BEJGBJ.mjs +94 -0
- package/dist/PregnancyStatusWidget-U2BEJGBJ.mjs.map +1 -0
- package/dist/{SuggestionTextareaWidget-DY6M5JPO.cjs → SuggestionTextareaWidget-FWRZ46MV.cjs} +5 -5
- package/dist/{SuggestionTextareaWidget-DY6M5JPO.cjs.map → SuggestionTextareaWidget-FWRZ46MV.cjs.map} +1 -1
- package/dist/{SuggestionTextareaWidget-GQTWCFBG.mjs → SuggestionTextareaWidget-UNL3FZRI.mjs} +3 -3
- package/dist/{SuggestionTextareaWidget-GQTWCFBG.mjs.map → SuggestionTextareaWidget-UNL3FZRI.mjs.map} +1 -1
- package/dist/TreatmentPlanWidget-665HLKYV.mjs +317 -0
- package/dist/TreatmentPlanWidget-665HLKYV.mjs.map +1 -0
- package/dist/TreatmentPlanWidget-TATWSPLY.cjs +319 -0
- package/dist/TreatmentPlanWidget-TATWSPLY.cjs.map +1 -0
- package/dist/{chunk-4PMNVBJD.mjs → chunk-2OMQV2ZB.mjs} +4 -3
- package/dist/chunk-2OMQV2ZB.mjs.map +1 -0
- package/dist/chunk-5RT3S67O.cjs +30 -0
- package/dist/chunk-5RT3S67O.cjs.map +1 -0
- package/dist/chunk-6YUVILN5.mjs +42 -0
- package/dist/chunk-6YUVILN5.mjs.map +1 -0
- package/dist/{chunk-YEFM2ERQ.cjs → chunk-7OQFO6TM.cjs} +8 -7
- package/dist/chunk-7OQFO6TM.cjs.map +1 -0
- package/dist/chunk-BBD3Y37O.cjs +220 -0
- package/dist/chunk-BBD3Y37O.cjs.map +1 -0
- package/dist/chunk-EJ7MKHER.mjs +45 -0
- package/dist/chunk-EJ7MKHER.mjs.map +1 -0
- package/dist/{chunk-XN2QLBLT.mjs → chunk-G6Y4UJPN.mjs} +5 -4
- package/dist/chunk-G6Y4UJPN.mjs.map +1 -0
- package/dist/{chunk-AZSAPO2V.cjs → chunk-HXY3IX3G.cjs} +3 -44
- package/dist/chunk-HXY3IX3G.cjs.map +1 -0
- package/dist/{chunk-BMNY7F6H.mjs → chunk-JM7WNDNT.mjs} +4 -21
- package/dist/chunk-JM7WNDNT.mjs.map +1 -0
- package/dist/chunk-MQHZ7HD2.mjs +215 -0
- package/dist/chunk-MQHZ7HD2.mjs.map +1 -0
- package/dist/{chunk-ML47UEDU.cjs → chunk-O4FSJPU3.cjs} +2 -27
- package/dist/chunk-O4FSJPU3.cjs.map +1 -0
- package/dist/chunk-Q66LXMRR.mjs +28 -0
- package/dist/chunk-Q66LXMRR.mjs.map +1 -0
- package/dist/chunk-RILRMRXB.cjs +50 -0
- package/dist/chunk-RILRMRXB.cjs.map +1 -0
- package/dist/chunk-SQ2KNAUD.cjs +64 -0
- package/dist/chunk-SQ2KNAUD.cjs.map +1 -0
- package/dist/{chunk-TVFUWRTE.cjs → chunk-TCQQUJCL.cjs} +5 -4
- package/dist/chunk-TCQQUJCL.cjs.map +1 -0
- package/dist/chunk-UKSP3B3W.mjs +600 -0
- package/dist/chunk-UKSP3B3W.mjs.map +1 -0
- package/dist/chunk-X4AJCTON.cjs +607 -0
- package/dist/chunk-X4AJCTON.cjs.map +1 -0
- package/dist/chunk-ZZX3IG2T.mjs +25 -0
- package/dist/chunk-ZZX3IG2T.mjs.map +1 -0
- package/dist/index.cjs +107 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +69 -3
- package/dist/index.d.ts +69 -3
- package/dist/index.mjs +73 -43
- package/dist/index.mjs.map +1 -1
- package/dist/read-only-table.d.cts +1 -1
- package/dist/read-only-table.d.ts +1 -1
- package/dist/smart.d.cts +1 -1
- package/dist/smart.d.ts +1 -1
- package/dist/{types-CYtJk8H9.d.ts → types-BbOnd5IN.d.cts} +53 -3
- package/dist/{types-CYtJk8H9.d.cts → types-BbOnd5IN.d.ts} +53 -3
- package/package.json +1 -1
- package/dist/DateTimeWidget-3AUBZYYK.mjs.map +0 -1
- package/dist/DateTimeWidget-OS7ER5F6.cjs.map +0 -1
- package/dist/DateWidget-KCTE6N5G.mjs.map +0 -1
- package/dist/DateWidget-UNLX544Z.cjs.map +0 -1
- package/dist/EditableTable-VQ72UEFF.cjs.map +0 -1
- package/dist/EditableTable-XFCPKSUY.mjs.map +0 -1
- package/dist/FollowupWidget-BFZ6P2JE.mjs.map +0 -1
- package/dist/FollowupWidget-MAYTHM2E.cjs.map +0 -1
- package/dist/OBGPathwayWidget-X67XKRIH.mjs.map +0 -1
- package/dist/OBGPathwayWidget-XGN3HEWS.cjs.map +0 -1
- package/dist/ObstetricHistoryWidget-RP7NY4PV.cjs.map +0 -1
- package/dist/ObstetricHistoryWidget-Z4VAXH3E.mjs.map +0 -1
- package/dist/chunk-4HDMR2LX.mjs +0 -69
- package/dist/chunk-4HDMR2LX.mjs.map +0 -1
- package/dist/chunk-4PMNVBJD.mjs.map +0 -1
- package/dist/chunk-AZSAPO2V.cjs.map +0 -1
- package/dist/chunk-BMNY7F6H.mjs.map +0 -1
- package/dist/chunk-ML47UEDU.cjs.map +0 -1
- package/dist/chunk-TVFUWRTE.cjs.map +0 -1
- package/dist/chunk-XN2QLBLT.mjs.map +0 -1
- package/dist/chunk-YEFM2ERQ.cjs.map +0 -1
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkO4FSJPU3_cjs = require('./chunk-O4FSJPU3.cjs');
|
|
4
|
+
var chunkPHADAQSH_cjs = require('./chunk-PHADAQSH.cjs');
|
|
5
|
+
var chunk5E3APMY6_cjs = require('./chunk-5E3APMY6.cjs');
|
|
6
|
+
var chunk7DISRJAB_cjs = require('./chunk-7DISRJAB.cjs');
|
|
7
|
+
var chunkTJHG5WHX_cjs = require('./chunk-TJHG5WHX.cjs');
|
|
8
|
+
var chunk4KSZUIJE_cjs = require('./chunk-4KSZUIJE.cjs');
|
|
9
|
+
var chunkTB33A4PD_cjs = require('./chunk-TB33A4PD.cjs');
|
|
10
|
+
var chunkJMGUUFOJ_cjs = require('./chunk-JMGUUFOJ.cjs');
|
|
11
|
+
var chunkFHHISVCH_cjs = require('./chunk-FHHISVCH.cjs');
|
|
12
|
+
var react = require('react');
|
|
13
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
14
|
+
|
|
15
|
+
// src/core/treatmentPlanForms.ts
|
|
16
|
+
var TOOTH_FIELD = {
|
|
17
|
+
type: "text",
|
|
18
|
+
key: "teeth",
|
|
19
|
+
label: "Tooth / teeth",
|
|
20
|
+
placeholder: "e.g. 16, 26"
|
|
21
|
+
};
|
|
22
|
+
var NOTES_FIELD = {
|
|
23
|
+
type: "textarea",
|
|
24
|
+
key: "notes",
|
|
25
|
+
label: "Notes",
|
|
26
|
+
placeholder: "Additional details\u2026"
|
|
27
|
+
};
|
|
28
|
+
var TREATMENT_FORM_CONFIGS = {
|
|
29
|
+
"Scaling & Polishing": {
|
|
30
|
+
fields: [
|
|
31
|
+
{ type: "select", key: "frequency", label: "Frequency", options: ["Once", "Twice yearly", "Quarterly", "As needed"] },
|
|
32
|
+
NOTES_FIELD
|
|
33
|
+
]
|
|
34
|
+
},
|
|
35
|
+
"Extraction": {
|
|
36
|
+
fields: [
|
|
37
|
+
TOOTH_FIELD,
|
|
38
|
+
{ type: "select", key: "extractionType", label: "Type", options: ["Simple", "Surgical"] },
|
|
39
|
+
NOTES_FIELD
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
"Filling (Composite)": {
|
|
43
|
+
fields: [
|
|
44
|
+
TOOTH_FIELD,
|
|
45
|
+
{ type: "text", key: "surface", label: "Surface(s)", placeholder: "e.g. MO, DO, MOD" },
|
|
46
|
+
{ type: "select", key: "shade", label: "Shade", options: ["A1", "A2", "A3", "A3.5", "B1", "B2", "B3", "C2", "D3"] },
|
|
47
|
+
NOTES_FIELD
|
|
48
|
+
]
|
|
49
|
+
},
|
|
50
|
+
"Filling (Amalgam)": {
|
|
51
|
+
fields: [
|
|
52
|
+
TOOTH_FIELD,
|
|
53
|
+
{ type: "text", key: "surface", label: "Surface(s)", placeholder: "e.g. MO, DO, MOD" },
|
|
54
|
+
NOTES_FIELD
|
|
55
|
+
]
|
|
56
|
+
},
|
|
57
|
+
"Root Canal Treatment (RCT)": {
|
|
58
|
+
fields: [
|
|
59
|
+
TOOTH_FIELD,
|
|
60
|
+
{ type: "number", key: "sessions", label: "Sessions planned", min: 1, max: 10, placeholder: "1" },
|
|
61
|
+
NOTES_FIELD
|
|
62
|
+
]
|
|
63
|
+
},
|
|
64
|
+
"Crown": {
|
|
65
|
+
fields: [
|
|
66
|
+
TOOTH_FIELD,
|
|
67
|
+
{ type: "select", key: "material", label: "Material", options: ["PFM", "Zirconia", "E-max", "Metal", "Acrylic (temp)"] },
|
|
68
|
+
NOTES_FIELD
|
|
69
|
+
]
|
|
70
|
+
},
|
|
71
|
+
"Bridge": {
|
|
72
|
+
fields: [
|
|
73
|
+
{ type: "text", key: "span", label: "Span (from \u2013 to)", placeholder: "e.g. 14\u201316" },
|
|
74
|
+
{ type: "select", key: "material", label: "Material", options: ["PFM", "Zirconia", "E-max", "Metal"] },
|
|
75
|
+
NOTES_FIELD
|
|
76
|
+
]
|
|
77
|
+
},
|
|
78
|
+
"Implant": {
|
|
79
|
+
fields: [
|
|
80
|
+
{ type: "text", key: "site", label: "Implant site", placeholder: "e.g. 36" },
|
|
81
|
+
{ type: "select", key: "timing", label: "Timing", options: ["Immediate", "Delayed", "Staged"] },
|
|
82
|
+
NOTES_FIELD
|
|
83
|
+
]
|
|
84
|
+
},
|
|
85
|
+
"Orthodontic Treatment": {
|
|
86
|
+
fields: [
|
|
87
|
+
{ type: "select", key: "applianceType", label: "Appliance", options: ["Metal braces", "Ceramic braces", "Clear aligners", "Retainer", "Functional appliance"] },
|
|
88
|
+
{ type: "number", key: "durationMonths", label: "Est. duration (months)", min: 1, max: 60, placeholder: "12" },
|
|
89
|
+
NOTES_FIELD
|
|
90
|
+
]
|
|
91
|
+
},
|
|
92
|
+
"Dentures (Complete)": {
|
|
93
|
+
fields: [
|
|
94
|
+
{ type: "select", key: "jaw", label: "Jaw", options: ["Upper", "Lower", "Both"] },
|
|
95
|
+
{ type: "select", key: "material", label: "Material", options: ["Acrylic", "Flexible (Valplast)", "Metal-based"] },
|
|
96
|
+
NOTES_FIELD
|
|
97
|
+
]
|
|
98
|
+
},
|
|
99
|
+
"Dentures (Partial)": {
|
|
100
|
+
fields: [
|
|
101
|
+
{ type: "select", key: "jaw", label: "Jaw", options: ["Upper", "Lower", "Both"] },
|
|
102
|
+
{ type: "text", key: "missingTeeth", label: "Missing teeth", placeholder: "e.g. 14, 15, 24" },
|
|
103
|
+
{ type: "select", key: "material", label: "Material", options: ["Acrylic", "Flexible (Valplast)", "Cast metal (Co-Cr)"] },
|
|
104
|
+
NOTES_FIELD
|
|
105
|
+
]
|
|
106
|
+
},
|
|
107
|
+
"Fluoride Application": {
|
|
108
|
+
fields: [
|
|
109
|
+
{ type: "select", key: "fluorideType", label: "Type", options: ["Varnish", "Gel", "Foam"] },
|
|
110
|
+
{ type: "select", key: "concentration", label: "Concentration", options: ["1000 ppm", "2800 ppm", "5000 ppm"] },
|
|
111
|
+
NOTES_FIELD
|
|
112
|
+
]
|
|
113
|
+
},
|
|
114
|
+
"Fissure Sealant": {
|
|
115
|
+
fields: [
|
|
116
|
+
TOOTH_FIELD,
|
|
117
|
+
NOTES_FIELD
|
|
118
|
+
]
|
|
119
|
+
},
|
|
120
|
+
"Pulpotomy": {
|
|
121
|
+
fields: [TOOTH_FIELD, NOTES_FIELD]
|
|
122
|
+
},
|
|
123
|
+
"Pulpectomy": {
|
|
124
|
+
fields: [TOOTH_FIELD, NOTES_FIELD]
|
|
125
|
+
},
|
|
126
|
+
"Surgical Extraction": {
|
|
127
|
+
fields: [
|
|
128
|
+
TOOTH_FIELD,
|
|
129
|
+
NOTES_FIELD
|
|
130
|
+
]
|
|
131
|
+
},
|
|
132
|
+
"Periodontal Surgery": {
|
|
133
|
+
fields: [
|
|
134
|
+
{ type: "select", key: "surgeryType", label: "Procedure", options: ["Flap surgery", "Bone graft", "GTR", "Gingivectomy", "Crown lengthening"] },
|
|
135
|
+
{ type: "text", key: "region", label: "Region", placeholder: "e.g. upper right quadrant" },
|
|
136
|
+
NOTES_FIELD
|
|
137
|
+
]
|
|
138
|
+
},
|
|
139
|
+
"Whitening / Bleaching": {
|
|
140
|
+
fields: [
|
|
141
|
+
{ type: "select", key: "whiteningType", label: "Type", options: ["In-office", "Home kit", "Combined"] },
|
|
142
|
+
{ type: "select", key: "shadeGoal", label: "Shade goal", options: ["A1", "B1", "B0.5", "As white as possible"] },
|
|
143
|
+
NOTES_FIELD
|
|
144
|
+
]
|
|
145
|
+
},
|
|
146
|
+
"Referral \u2013 Specialist": {
|
|
147
|
+
fields: [
|
|
148
|
+
{ type: "select", key: "specialty", label: "Specialty", options: ["Orthodontist", "Periodontist", "Oral Surgeon", "Endodontist", "Prosthodontist", "Paedodontist", "Oral Medicine", "Other"] },
|
|
149
|
+
{ type: "text", key: "referTo", label: "Refer to (name / clinic)", placeholder: "Dr. / Clinic name" },
|
|
150
|
+
NOTES_FIELD
|
|
151
|
+
]
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
var DEFAULT_TREATMENT_FORM = {
|
|
155
|
+
fields: [NOTES_FIELD]
|
|
156
|
+
};
|
|
157
|
+
function getTreatmentFormConfig(treatmentValue) {
|
|
158
|
+
return TREATMENT_FORM_CONFIGS[treatmentValue] ?? DEFAULT_TREATMENT_FORM;
|
|
159
|
+
}
|
|
160
|
+
function normalizeTreatmentPlan(raw) {
|
|
161
|
+
if (Array.isArray(raw)) {
|
|
162
|
+
return { selected: raw.filter((x) => typeof x === "string"), details: {} };
|
|
163
|
+
}
|
|
164
|
+
if (raw && typeof raw === "object" && !Array.isArray(raw)) {
|
|
165
|
+
const o = raw;
|
|
166
|
+
const selected = Array.isArray(o.selected) ? o.selected.filter((x) => typeof x === "string") : [];
|
|
167
|
+
const details = o.details && typeof o.details === "object" && !Array.isArray(o.details) ? o.details : {};
|
|
168
|
+
return { selected, details };
|
|
169
|
+
}
|
|
170
|
+
return { selected: [], details: {} };
|
|
171
|
+
}
|
|
172
|
+
function normalizeOptions(raw) {
|
|
173
|
+
if (!Array.isArray(raw) || raw.length === 0) return [];
|
|
174
|
+
if (typeof raw[0] === "string") {
|
|
175
|
+
return raw.map((s) => ({ label: s, value: s }));
|
|
176
|
+
}
|
|
177
|
+
return raw;
|
|
178
|
+
}
|
|
179
|
+
function TreatmentField({
|
|
180
|
+
field,
|
|
181
|
+
value,
|
|
182
|
+
onChange,
|
|
183
|
+
disabled
|
|
184
|
+
}) {
|
|
185
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "space-y-1 block", children: [
|
|
186
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "block text-xs font-medium text-slate-700", children: field.label }),
|
|
187
|
+
field.type === "select" ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
188
|
+
chunk4KSZUIJE_cjs.Select,
|
|
189
|
+
{
|
|
190
|
+
value: value || "none",
|
|
191
|
+
onValueChange: (v) => onChange(v === "none" ? "" : v),
|
|
192
|
+
disabled,
|
|
193
|
+
children: [
|
|
194
|
+
/* @__PURE__ */ jsxRuntime.jsx(chunk4KSZUIJE_cjs.SelectTrigger, { className: "h-7 text-xs", children: /* @__PURE__ */ jsxRuntime.jsx(chunk4KSZUIJE_cjs.SelectValue, { placeholder: "\u2014" }) }),
|
|
195
|
+
/* @__PURE__ */ jsxRuntime.jsxs(chunk4KSZUIJE_cjs.SelectContent, { children: [
|
|
196
|
+
/* @__PURE__ */ jsxRuntime.jsx(chunk4KSZUIJE_cjs.SelectItem, { value: "none", children: "\u2014" }),
|
|
197
|
+
field.options.map((opt) => /* @__PURE__ */ jsxRuntime.jsx(chunk4KSZUIJE_cjs.SelectItem, { value: opt, children: opt }, opt))
|
|
198
|
+
] })
|
|
199
|
+
]
|
|
200
|
+
}
|
|
201
|
+
) : field.type === "textarea" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
202
|
+
chunkPHADAQSH_cjs.Textarea,
|
|
203
|
+
{
|
|
204
|
+
className: "min-h-[52px] resize-none text-xs",
|
|
205
|
+
placeholder: field.placeholder,
|
|
206
|
+
value,
|
|
207
|
+
onChange: (e) => onChange(e.target.value),
|
|
208
|
+
disabled
|
|
209
|
+
}
|
|
210
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
211
|
+
chunkTJHG5WHX_cjs.Input,
|
|
212
|
+
{
|
|
213
|
+
type: field.type === "number" ? "number" : "text",
|
|
214
|
+
className: "h-7 text-xs",
|
|
215
|
+
placeholder: field.placeholder,
|
|
216
|
+
value,
|
|
217
|
+
min: field.type === "number" ? field.min : void 0,
|
|
218
|
+
max: field.type === "number" ? field.max : void 0,
|
|
219
|
+
onChange: (e) => onChange(e.target.value),
|
|
220
|
+
disabled
|
|
221
|
+
}
|
|
222
|
+
)
|
|
223
|
+
] });
|
|
224
|
+
}
|
|
225
|
+
var TreatmentPlanWidget = ({ fieldId }) => {
|
|
226
|
+
const { fieldDef, value, setValue, setTouched, error, disabled, touched } = chunkTB33A4PD_cjs.useField(fieldId);
|
|
227
|
+
const { state } = chunk7DISRJAB_cjs.useForm();
|
|
228
|
+
const showError = !!error && (touched || state.submitAttempted);
|
|
229
|
+
const options = react.useMemo(
|
|
230
|
+
() => normalizeOptions(fieldDef?.options),
|
|
231
|
+
[fieldDef]
|
|
232
|
+
);
|
|
233
|
+
const safe = react.useMemo(() => normalizeTreatmentPlan(value), [value]);
|
|
234
|
+
const update = (next) => {
|
|
235
|
+
setValue(next);
|
|
236
|
+
setTouched();
|
|
237
|
+
};
|
|
238
|
+
const toggleTreatment = (val) => {
|
|
239
|
+
const isSelected = safe.selected.includes(val);
|
|
240
|
+
const nextSelected = isSelected ? safe.selected.filter((v) => v !== val) : [...safe.selected, val];
|
|
241
|
+
const nextDetails = { ...safe.details };
|
|
242
|
+
if (isSelected) delete nextDetails[val];
|
|
243
|
+
update({ selected: nextSelected, details: nextDetails });
|
|
244
|
+
};
|
|
245
|
+
const updateDetail = (treatment, key, val) => {
|
|
246
|
+
update({
|
|
247
|
+
...safe,
|
|
248
|
+
details: {
|
|
249
|
+
...safe.details,
|
|
250
|
+
[treatment]: { ...safe.details[treatment] ?? {}, [key]: val }
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
};
|
|
254
|
+
if (!fieldDef) return null;
|
|
255
|
+
const showLabel = chunk5E3APMY6_cjs.isLabelVisible(fieldDef);
|
|
256
|
+
const bodyClass = chunkFHHISVCH_cjs.cn(
|
|
257
|
+
"flex min-w-0 flex-col gap-3 bg-white px-3 py-3",
|
|
258
|
+
disabled && "pointer-events-none opacity-60"
|
|
259
|
+
);
|
|
260
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: chunk5E3APMY6_cjs.fieldWrapperClass(fieldDef, "space-y-2"), children: [
|
|
261
|
+
showLabel && /* @__PURE__ */ jsxRuntime.jsxs(chunkJMGUUFOJ_cjs.Label, { className: chunk5E3APMY6_cjs.fieldLabelClass(fieldDef), children: [
|
|
262
|
+
fieldDef.label,
|
|
263
|
+
" ",
|
|
264
|
+
/* @__PURE__ */ jsxRuntime.jsx(chunk5E3APMY6_cjs.FieldRequiredIndicator, { fieldDef })
|
|
265
|
+
] }),
|
|
266
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: chunkFHHISVCH_cjs.cn(
|
|
267
|
+
"w-full min-w-0 overflow-hidden rounded-md border border-[#D0D0D0] flex flex-col",
|
|
268
|
+
showError && "border-red-500"
|
|
269
|
+
), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: bodyClass, children: [
|
|
270
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
|
|
271
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "Select treatments to add details" }),
|
|
272
|
+
options.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: "No options configured" }),
|
|
273
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-2", children: options.map((opt) => {
|
|
274
|
+
const on = safe.selected.includes(opt.value);
|
|
275
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
276
|
+
"button",
|
|
277
|
+
{
|
|
278
|
+
type: "button",
|
|
279
|
+
onClick: () => toggleTreatment(opt.value),
|
|
280
|
+
disabled,
|
|
281
|
+
"aria-pressed": on,
|
|
282
|
+
className: chunkFHHISVCH_cjs.cn(
|
|
283
|
+
"rounded-full border px-3 py-1 text-[11px] transition-colors",
|
|
284
|
+
on ? "border-rose-500 bg-rose-50 text-rose-700" : "border-slate-300 bg-white text-slate-600 hover:bg-slate-50"
|
|
285
|
+
),
|
|
286
|
+
children: opt.label
|
|
287
|
+
},
|
|
288
|
+
opt.value
|
|
289
|
+
);
|
|
290
|
+
}) })
|
|
291
|
+
] }),
|
|
292
|
+
safe.selected.map((val) => {
|
|
293
|
+
const cfg = getTreatmentFormConfig(val);
|
|
294
|
+
const detail = safe.details[val] ?? {};
|
|
295
|
+
return /* @__PURE__ */ jsxRuntime.jsx(chunkO4FSJPU3_cjs.Panel, { title: val, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 gap-3 md:grid-cols-3", children: cfg.fields.map((field) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
296
|
+
"div",
|
|
297
|
+
{
|
|
298
|
+
className: field.type === "textarea" ? "col-span-2 md:col-span-3" : "",
|
|
299
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
300
|
+
TreatmentField,
|
|
301
|
+
{
|
|
302
|
+
field,
|
|
303
|
+
value: detail[field.key] ?? "",
|
|
304
|
+
onChange: (v) => updateDetail(val, field.key, v),
|
|
305
|
+
disabled
|
|
306
|
+
}
|
|
307
|
+
)
|
|
308
|
+
},
|
|
309
|
+
field.key
|
|
310
|
+
)) }) }, val);
|
|
311
|
+
})
|
|
312
|
+
] }) }),
|
|
313
|
+
showError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-red-500", children: error })
|
|
314
|
+
] });
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
exports.TreatmentPlanWidget = TreatmentPlanWidget;
|
|
318
|
+
//# sourceMappingURL=TreatmentPlanWidget-TATWSPLY.cjs.map
|
|
319
|
+
//# sourceMappingURL=TreatmentPlanWidget-TATWSPLY.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/treatmentPlanForms.ts","../src/ui/widgets/TreatmentPlanWidget.tsx"],"names":["jsxs","jsx","Select","SelectTrigger","SelectValue","SelectContent","SelectItem","Textarea","Input","useField","useForm","useMemo","isLabelVisible","cn","fieldWrapperClass","Label","fieldLabelClass","FieldRequiredIndicator","Panel"],"mappings":"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","file":"TreatmentPlanWidget-TATWSPLY.cjs","sourcesContent":["/** Per-treatment mini-form configuration for TreatmentPlanWidget */\n\n// ─── Field types ──────────────────────────────────────────────────────────────\n\nexport type TreatmentFormField =\n | { type: 'text'; key: string; label: string; placeholder?: string }\n | { type: 'select'; key: string; label: string; options: string[] }\n | { type: 'number'; key: string; label: string; min?: number; max?: number; placeholder?: string }\n | { type: 'textarea'; key: string; label: string; placeholder?: string };\n\nexport type TreatmentFormConfig = {\n fields: TreatmentFormField[];\n};\n\n// ─── Per-treatment form configs ───────────────────────────────────────────────\n\nconst TOOTH_FIELD: TreatmentFormField = {\n type: 'text', key: 'teeth', label: 'Tooth / teeth', placeholder: 'e.g. 16, 26',\n};\nconst NOTES_FIELD: TreatmentFormField = {\n type: 'textarea', key: 'notes', label: 'Notes', placeholder: 'Additional details…',\n};\n\nexport const TREATMENT_FORM_CONFIGS: Record<string, TreatmentFormConfig> = {\n 'Scaling & Polishing': {\n fields: [\n { type: 'select', key: 'frequency', label: 'Frequency', options: ['Once', 'Twice yearly', 'Quarterly', 'As needed'] },\n NOTES_FIELD,\n ],\n },\n 'Extraction': {\n fields: [\n TOOTH_FIELD,\n { type: 'select', key: 'extractionType', label: 'Type', options: ['Simple', 'Surgical'] },\n NOTES_FIELD,\n ],\n },\n 'Filling (Composite)': {\n fields: [\n TOOTH_FIELD,\n { type: 'text', key: 'surface', label: 'Surface(s)', placeholder: 'e.g. MO, DO, MOD' },\n { type: 'select', key: 'shade', label: 'Shade', options: ['A1', 'A2', 'A3', 'A3.5', 'B1', 'B2', 'B3', 'C2', 'D3'] },\n NOTES_FIELD,\n ],\n },\n 'Filling (Amalgam)': {\n fields: [\n TOOTH_FIELD,\n { type: 'text', key: 'surface', label: 'Surface(s)', placeholder: 'e.g. MO, DO, MOD' },\n NOTES_FIELD,\n ],\n },\n 'Root Canal Treatment (RCT)': {\n fields: [\n TOOTH_FIELD,\n { type: 'number', key: 'sessions', label: 'Sessions planned', min: 1, max: 10, placeholder: '1' },\n NOTES_FIELD,\n ],\n },\n 'Crown': {\n fields: [\n TOOTH_FIELD,\n { type: 'select', key: 'material', label: 'Material', options: ['PFM', 'Zirconia', 'E-max', 'Metal', 'Acrylic (temp)'] },\n NOTES_FIELD,\n ],\n },\n 'Bridge': {\n fields: [\n { type: 'text', key: 'span', label: 'Span (from – to)', placeholder: 'e.g. 14–16' },\n { type: 'select', key: 'material', label: 'Material', options: ['PFM', 'Zirconia', 'E-max', 'Metal'] },\n NOTES_FIELD,\n ],\n },\n 'Implant': {\n fields: [\n { type: 'text', key: 'site', label: 'Implant site', placeholder: 'e.g. 36' },\n { type: 'select', key: 'timing', label: 'Timing', options: ['Immediate', 'Delayed', 'Staged'] },\n NOTES_FIELD,\n ],\n },\n 'Orthodontic Treatment': {\n fields: [\n { type: 'select', key: 'applianceType', label: 'Appliance', options: ['Metal braces', 'Ceramic braces', 'Clear aligners', 'Retainer', 'Functional appliance'] },\n { type: 'number', key: 'durationMonths', label: 'Est. duration (months)', min: 1, max: 60, placeholder: '12' },\n NOTES_FIELD,\n ],\n },\n 'Dentures (Complete)': {\n fields: [\n { type: 'select', key: 'jaw', label: 'Jaw', options: ['Upper', 'Lower', 'Both'] },\n { type: 'select', key: 'material', label: 'Material', options: ['Acrylic', 'Flexible (Valplast)', 'Metal-based'] },\n NOTES_FIELD,\n ],\n },\n 'Dentures (Partial)': {\n fields: [\n { type: 'select', key: 'jaw', label: 'Jaw', options: ['Upper', 'Lower', 'Both'] },\n { type: 'text', key: 'missingTeeth', label: 'Missing teeth', placeholder: 'e.g. 14, 15, 24' },\n { type: 'select', key: 'material', label: 'Material', options: ['Acrylic', 'Flexible (Valplast)', 'Cast metal (Co-Cr)'] },\n NOTES_FIELD,\n ],\n },\n 'Fluoride Application': {\n fields: [\n { type: 'select', key: 'fluorideType', label: 'Type', options: ['Varnish', 'Gel', 'Foam'] },\n { type: 'select', key: 'concentration', label: 'Concentration', options: ['1000 ppm', '2800 ppm', '5000 ppm'] },\n NOTES_FIELD,\n ],\n },\n 'Fissure Sealant': {\n fields: [\n TOOTH_FIELD,\n NOTES_FIELD,\n ],\n },\n 'Pulpotomy': {\n fields: [TOOTH_FIELD, NOTES_FIELD],\n },\n 'Pulpectomy': {\n fields: [TOOTH_FIELD, NOTES_FIELD],\n },\n 'Surgical Extraction': {\n fields: [\n TOOTH_FIELD,\n NOTES_FIELD,\n ],\n },\n 'Periodontal Surgery': {\n fields: [\n { type: 'select', key: 'surgeryType', label: 'Procedure', options: ['Flap surgery', 'Bone graft', 'GTR', 'Gingivectomy', 'Crown lengthening'] },\n { type: 'text', key: 'region', label: 'Region', placeholder: 'e.g. upper right quadrant' },\n NOTES_FIELD,\n ],\n },\n 'Whitening / Bleaching': {\n fields: [\n { type: 'select', key: 'whiteningType', label: 'Type', options: ['In-office', 'Home kit', 'Combined'] },\n { type: 'select', key: 'shadeGoal', label: 'Shade goal', options: ['A1', 'B1', 'B0.5', 'As white as possible'] },\n NOTES_FIELD,\n ],\n },\n 'Referral – Specialist': {\n fields: [\n { type: 'select', key: 'specialty', label: 'Specialty', options: ['Orthodontist', 'Periodontist', 'Oral Surgeon', 'Endodontist', 'Prosthodontist', 'Paedodontist', 'Oral Medicine', 'Other'] },\n { type: 'text', key: 'referTo', label: 'Refer to (name / clinic)', placeholder: 'Dr. / Clinic name' },\n NOTES_FIELD,\n ],\n },\n};\n\n/** Fallback config for any custom option not in the map above */\nexport const DEFAULT_TREATMENT_FORM: TreatmentFormConfig = {\n fields: [NOTES_FIELD],\n};\n\nexport function getTreatmentFormConfig(treatmentValue: string): TreatmentFormConfig {\n return TREATMENT_FORM_CONFIGS[treatmentValue] ?? DEFAULT_TREATMENT_FORM;\n}\n\n// ─── Value shape ──────────────────────────────────────────────────────────────\n\nexport type TreatmentPlanValue = {\n selected: string[];\n details: Record<string, Record<string, string>>;\n};\n\nexport function normalizeTreatmentPlan(raw: unknown): TreatmentPlanValue {\n if (Array.isArray(raw)) {\n // Legacy: plain string[] — lift to new shape\n return { selected: raw.filter((x) => typeof x === 'string'), details: {} };\n }\n if (raw && typeof raw === 'object' && !Array.isArray(raw)) {\n const o = raw as Record<string, unknown>;\n const selected = Array.isArray(o.selected)\n ? (o.selected as unknown[]).filter((x): x is string => typeof x === 'string')\n : [];\n const details =\n o.details && typeof o.details === 'object' && !Array.isArray(o.details)\n ? (o.details as Record<string, Record<string, string>>)\n : {};\n return { selected, details };\n }\n return { selected: [], details: {} };\n}\n","import React, { useMemo } from 'react';\nimport { useField } from '../../react/useField';\nimport { useForm } from '../../react/useForm';\nimport { Label } from '../shadcn/label';\nimport { Input } from '../shadcn/input';\nimport { Textarea } from '../shadcn/textarea';\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '../shadcn/select';\nimport { cn } from '../../core/utils';\nimport { Panel } from './_obgPanels';\nimport {\n normalizeTreatmentPlan,\n getTreatmentFormConfig,\n type TreatmentPlanValue,\n type TreatmentFormField,\n} from '../../core/treatmentPlanForms';\nimport type { TreatmentPlanFieldDef } from '../../core/types';\nimport {\n FieldRequiredIndicator,\n fieldLabelClass,\n fieldWrapperClass,\n isLabelVisible,\n} from '../../react/fieldStyle';\n\n/** Normalises the `options` field — accepts both `string[]` and `{label,value}[]`. */\nfunction normalizeOptions(raw: TreatmentPlanFieldDef['options']): { label: string; value: string }[] {\n if (!Array.isArray(raw) || raw.length === 0) return [];\n if (typeof raw[0] === 'string') {\n return (raw as string[]).map((s) => ({ label: s, value: s }));\n }\n return raw as { label: string; value: string }[];\n}\n\n// ─── Mini form field renderer ─────────────────────────────────────────────────\n\nfunction TreatmentField({\n field,\n value,\n onChange,\n disabled,\n}: {\n field: TreatmentFormField;\n value: string;\n onChange: (v: string) => void;\n disabled: boolean;\n}) {\n return (\n <label className=\"space-y-1 block\">\n <span className=\"block text-xs font-medium text-slate-700\">{field.label}</span>\n {field.type === 'select' ? (\n <Select\n value={value || 'none'}\n onValueChange={(v) => onChange(v === 'none' ? '' : v)}\n disabled={disabled}\n >\n <SelectTrigger className=\"h-7 text-xs\">\n <SelectValue placeholder=\"—\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"none\">—</SelectItem>\n {field.options.map((opt) => (\n <SelectItem key={opt} value={opt}>{opt}</SelectItem>\n ))}\n </SelectContent>\n </Select>\n ) : field.type === 'textarea' ? (\n <Textarea\n className=\"min-h-[52px] resize-none text-xs\"\n placeholder={field.placeholder}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n disabled={disabled}\n />\n ) : (\n <Input\n type={field.type === 'number' ? 'number' : 'text'}\n className=\"h-7 text-xs\"\n placeholder={field.placeholder}\n value={value}\n min={field.type === 'number' ? field.min : undefined}\n max={field.type === 'number' ? field.max : undefined}\n onChange={(e) => onChange(e.target.value)}\n disabled={disabled}\n />\n )}\n </label>\n );\n}\n\n// ─── Widget ───────────────────────────────────────────────────────────────────\n\nexport const TreatmentPlanWidget: React.FC<{ fieldId: string }> = ({ fieldId }) => {\n const { fieldDef, value, setValue, setTouched, error, disabled, touched } = useField(fieldId);\n const { state } = useForm();\n const showError = !!error && (touched || state.submitAttempted);\n\n const options = useMemo(\n () => normalizeOptions((fieldDef as TreatmentPlanFieldDef | undefined)?.options),\n [fieldDef],\n );\n\n const safe = useMemo(() => normalizeTreatmentPlan(value), [value]);\n\n const update = (next: TreatmentPlanValue) => {\n setValue(next);\n setTouched();\n };\n\n const toggleTreatment = (val: string) => {\n const isSelected = safe.selected.includes(val);\n const nextSelected = isSelected\n ? safe.selected.filter((v) => v !== val)\n : [...safe.selected, val];\n const nextDetails = { ...safe.details };\n if (isSelected) delete nextDetails[val];\n update({ selected: nextSelected, details: nextDetails });\n };\n\n const updateDetail = (treatment: string, key: string, val: string) => {\n update({\n ...safe,\n details: {\n ...safe.details,\n [treatment]: { ...(safe.details[treatment] ?? {}), [key]: val },\n },\n });\n };\n\n if (!fieldDef) return null;\n const showLabel = isLabelVisible(fieldDef);\n\n const bodyClass = cn(\n 'flex min-w-0 flex-col gap-3 bg-white px-3 py-3',\n disabled && 'pointer-events-none opacity-60',\n );\n\n return (\n <div className={fieldWrapperClass(fieldDef, 'space-y-2')}>\n {showLabel && (\n <Label className={fieldLabelClass(fieldDef)}>\n {fieldDef.label} <FieldRequiredIndicator fieldDef={fieldDef} />\n </Label>\n )}\n\n <div className={cn(\n 'w-full min-w-0 overflow-hidden rounded-md border border-[#D0D0D0] flex flex-col',\n showError && 'border-red-500',\n )}>\n <div className={bodyClass}>\n {/* Treatment chips */}\n <div className=\"space-y-1\">\n <span className=\"text-xs font-medium text-muted-foreground\">\n Select treatments to add details\n </span>\n {options.length === 0 && (\n <p className=\"text-xs text-muted-foreground\">No options configured</p>\n )}\n <div className=\"flex flex-wrap gap-2\">\n {options.map((opt) => {\n const on = safe.selected.includes(opt.value);\n return (\n <button\n key={opt.value}\n type=\"button\"\n onClick={() => toggleTreatment(opt.value)}\n disabled={disabled}\n aria-pressed={on}\n className={cn(\n 'rounded-full border px-3 py-1 text-[11px] transition-colors',\n on\n ? 'border-rose-500 bg-rose-50 text-rose-700'\n : 'border-slate-300 bg-white text-slate-600 hover:bg-slate-50',\n )}\n >\n {opt.label}\n </button>\n );\n })}\n </div>\n </div>\n\n {/* Mini form panel per selected treatment */}\n {safe.selected.map((val) => {\n const cfg = getTreatmentFormConfig(val);\n const detail = safe.details[val] ?? {};\n return (\n <Panel key={val} title={val}>\n <div className=\"grid grid-cols-2 gap-3 md:grid-cols-3\">\n {cfg.fields.map((field) => (\n <div\n key={field.key}\n className={field.type === 'textarea' ? 'col-span-2 md:col-span-3' : ''}\n >\n <TreatmentField\n field={field}\n value={detail[field.key] ?? ''}\n onChange={(v) => updateDetail(val, field.key, v)}\n disabled={disabled}\n />\n </div>\n ))}\n </div>\n </Panel>\n );\n })}\n </div>\n </div>\n\n {showError && (\n <p className=\"text-xs text-red-500\">{error}</p>\n )}\n </div>\n );\n};\n"]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Input } from './chunk-VNFBUAZD.mjs';
|
|
2
|
-
import {
|
|
2
|
+
import { Calendar as Calendar$1 } from './chunk-JM7WNDNT.mjs';
|
|
3
|
+
import { Popover, PopoverTrigger, PopoverContent } from './chunk-ZZX3IG2T.mjs';
|
|
3
4
|
import { Button } from './chunk-GXXWMHAA.mjs';
|
|
4
5
|
import { cn } from './chunk-VPU66PI6.mjs';
|
|
5
6
|
import * as React from 'react';
|
|
@@ -117,5 +118,5 @@ function DateTimePicker({
|
|
|
117
118
|
}
|
|
118
119
|
|
|
119
120
|
export { DateTimePicker };
|
|
120
|
-
//# sourceMappingURL=chunk-
|
|
121
|
-
//# sourceMappingURL=chunk-
|
|
121
|
+
//# sourceMappingURL=chunk-2OMQV2ZB.mjs.map
|
|
122
|
+
//# sourceMappingURL=chunk-2OMQV2ZB.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/ui/shadcn/datetime-picker.tsx"],"names":["CalendarIcon","Calendar"],"mappings":"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","file":"chunk-2OMQV2ZB.mjs","sourcesContent":["import * as React from \"react\"\nimport { format } from \"date-fns\"\nimport { Calendar as CalendarIcon, Clock } from \"lucide-react\"\n\nimport { cn } from \"../../core/utils\"\nimport { Button } from \"./button\"\nimport { Calendar } from \"./calendar\"\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from \"./popover\"\nimport { Input } from \"./input\"\n\nexport interface DateTimePickerProps {\n /**\n * The current value as a Date object.\n */\n dateTime?: Date\n /**\n * Setter for the value. Use undefined to clear.\n */\n setDateTime?: (value: Date | undefined) => void\n className?: string\n placeholder?: string\n}\n\nfunction parseTimeString(value: string): { hours: number; minutes: number } | null {\n if (!value) return null\n const [h, m] = value.split(\":\").map((v) => Number(v))\n if (\n Number.isNaN(h) ||\n Number.isNaN(m) ||\n h < 0 ||\n h > 23 ||\n m < 0 ||\n m > 59\n ) {\n return null\n }\n return { hours: h, minutes: m }\n}\n\nexport function DateTimePicker({\n dateTime,\n setDateTime,\n className,\n placeholder = \"Pick date & time\",\n}: DateTimePickerProps) {\n const [internalDate, setInternalDate] = React.useState<Date | undefined>(dateTime)\n const [timeString, setTimeString] = React.useState<string>(() => {\n if (!dateTime) return \"\"\n const hours = dateTime.getHours().toString().padStart(2, \"0\")\n const minutes = dateTime.getMinutes().toString().padStart(2, \"0\")\n return `${hours}:${minutes}`\n })\n\n React.useEffect(() => {\n setInternalDate(dateTime)\n if (!dateTime) {\n setTimeString(\"\")\n } else {\n const hours = dateTime.getHours().toString().padStart(2, \"0\")\n const minutes = dateTime.getMinutes().toString().padStart(2, \"0\")\n setTimeString(`${hours}:${minutes}`)\n }\n }, [dateTime])\n\n const handleDateSelect = (date: Date | undefined) => {\n setInternalDate(date)\n if (!setDateTime) return\n if (!date) {\n setDateTime(undefined)\n return\n }\n\n const parsed = parseTimeString(timeString)\n const next = new Date(date)\n if (parsed) {\n next.setHours(parsed.hours, parsed.minutes, 0, 0)\n }\n setDateTime(next)\n }\n\n const handleTimeChange: React.ChangeEventHandler<HTMLInputElement> = (e) => {\n const value = e.target.value\n setTimeString(value)\n if (!setDateTime) return\n\n const parsed = parseTimeString(value)\n if (!parsed) {\n // Don't propagate invalid time, just keep local string\n return\n }\n\n const base = internalDate ?? new Date()\n const next = new Date(base)\n next.setHours(parsed.hours, parsed.minutes, 0, 0)\n setInternalDate(next)\n setDateTime(next)\n }\n\n const hasValue = !!dateTime\n\n return (\n <Popover>\n <PopoverTrigger asChild>\n <Button\n variant={\"outline\"}\n className={cn(\n \"w-[280px] justify-start text-left font-normal\",\n !hasValue && \"text-muted-foreground\",\n className\n )}\n >\n <CalendarIcon className=\"mr-2 h-4 w-4\" />\n {hasValue ? (\n <span className=\"flex items-center gap-1\">\n {format(dateTime as Date, \"PPP\")}\n <span className=\"text-muted-foreground\">•</span>\n <span className=\"inline-flex items-center gap-1\">\n <Clock className=\"h-3 w-3\" />\n {format(dateTime as Date, \"HH:mm\")}\n </span>\n </span>\n ) : (\n <span>{placeholder}</span>\n )}\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"w-auto p-0\">\n <div className=\"flex flex-col md:flex-row\">\n <Calendar\n mode=\"single\"\n selected={internalDate}\n onSelect={handleDateSelect}\n initialFocus\n />\n <div className=\"border-t md:border-t-0 md:border-l p-3 flex flex-col gap-2 min-w-[220px]\">\n <label className=\"text-xs font-medium text-muted-foreground\">\n Time (24h)\n </label>\n <Input\n type=\"time\"\n value={timeString}\n onChange={handleTimeChange}\n className=\"w-full\"\n />\n </div>\n </div>\n </PopoverContent>\n </Popover>\n )\n}\n\n"]}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkQKJ7BQSR_cjs = require('./chunk-QKJ7BQSR.cjs');
|
|
4
|
+
var chunkTB33A4PD_cjs = require('./chunk-TB33A4PD.cjs');
|
|
5
|
+
|
|
6
|
+
// src/ui/widgets/_obgSymptomsSync.ts
|
|
7
|
+
var SYMPTOMS_FIELD = "symptoms";
|
|
8
|
+
function useObgSymptomsSync() {
|
|
9
|
+
const symptomsField = chunkTB33A4PD_cjs.useField(SYMPTOMS_FIELD);
|
|
10
|
+
const writeSymptoms = (prev, next, overrideProse) => {
|
|
11
|
+
if (symptomsField.disabled) return;
|
|
12
|
+
const cur = typeof symptomsField.value === "string" ? symptomsField.value : "";
|
|
13
|
+
const { prose: curProse } = chunkTB33A4PD_cjs.parseProseAndChipTokens(
|
|
14
|
+
cur,
|
|
15
|
+
chunkQKJ7BQSR_cjs.OBG_ZONE_ALLOWED_CHIP_LABELS
|
|
16
|
+
);
|
|
17
|
+
const prevProse = chunkQKJ7BQSR_cjs.formatObgPathwayProse(prev);
|
|
18
|
+
const generatedProse = chunkQKJ7BQSR_cjs.formatObgPathwayProse(next);
|
|
19
|
+
const isAutoOwned = curProse === "" || curProse === prevProse;
|
|
20
|
+
const proseInput = overrideProse !== void 0 ? overrideProse : isAutoOwned ? generatedProse : curProse;
|
|
21
|
+
const chipLabels = next.zones.map(chunkQKJ7BQSR_cjs.obgZoneLabel);
|
|
22
|
+
const composed = chunkTB33A4PD_cjs.composeProseAndChips(proseInput, chipLabels);
|
|
23
|
+
if (composed !== cur) symptomsField.setValue(composed);
|
|
24
|
+
};
|
|
25
|
+
return { writeSymptoms, symptomsField };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
exports.useObgSymptomsSync = useObgSymptomsSync;
|
|
29
|
+
//# sourceMappingURL=chunk-5RT3S67O.cjs.map
|
|
30
|
+
//# sourceMappingURL=chunk-5RT3S67O.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/ui/widgets/_obgSymptomsSync.ts"],"names":["useField","parseProseAndChipTokens","OBG_ZONE_ALLOWED_CHIP_LABELS","formatObgPathwayProse","obgZoneLabel","composeProseAndChips"],"mappings":";;;;;;AAYA,IAAM,cAAA,GAAiB,UAAA;AAgBhB,SAAS,kBAAA,GAAqB;AACnC,EAAA,MAAM,aAAA,GAAgBA,2BAAS,cAAc,CAAA;AAE7C,EAAA,MAAM,aAAA,GAAgB,CACpB,IAAA,EACA,IAAA,EACA,aAAA,KACG;AACH,IAAA,IAAI,cAAc,QAAA,EAAU;AAC5B,IAAA,MAAM,MACJ,OAAO,aAAA,CAAc,KAAA,KAAU,QAAA,GAAW,cAAc,KAAA,GAAQ,EAAA;AAClE,IAAA,MAAM,EAAE,KAAA,EAAO,QAAA,EAAS,GAAIC,yCAAA;AAAA,MAC1B,GAAA;AAAA,MACAC;AAAA,KACF;AAEA,IAAA,MAAM,SAAA,GAAYC,wCAAsB,IAAI,CAAA;AAC5C,IAAA,MAAM,cAAA,GAAiBA,wCAAsB,IAAI,CAAA;AACjD,IAAA,MAAM,WAAA,GAAc,QAAA,KAAa,EAAA,IAAM,QAAA,KAAa,SAAA;AAEpD,IAAA,MAAM,UAAA,GACJ,aAAA,KAAkB,MAAA,GACd,aAAA,GACA,cACE,cAAA,GACA,QAAA;AAER,IAAA,MAAM,UAAA,GAAa,IAAA,CAAK,KAAA,CAAM,GAAA,CAAIC,8BAAY,CAAA;AAC9C,IAAA,MAAM,QAAA,GAAWC,sCAAA,CAAqB,UAAA,EAAY,UAAU,CAAA;AAC5D,IAAA,IAAI,QAAA,KAAa,GAAA,EAAK,aAAA,CAAc,QAAA,CAAS,QAAQ,CAAA;AAAA,EACvD,CAAA;AAEA,EAAA,OAAO,EAAE,eAAe,aAAA,EAAc;AACxC","file":"chunk-5RT3S67O.cjs","sourcesContent":["import { useField } from '../../react/useField';\nimport {\n formatObgPathwayProse,\n obgZoneLabel,\n OBG_ZONE_ALLOWED_CHIP_LABELS,\n type ObgPathwayValue,\n} from '../../core/obgPathway';\nimport {\n composeProseAndChips,\n parseProseAndChipTokens,\n} from '../../core/suggestionTokens';\n\nconst SYMPTOMS_FIELD = 'symptoms';\n\n/**\n * Mirror an OBG pathway value into the `symptoms` (HOPC) textarea as\n * prose + chips. Multiple widgets (OBGPathwayWidget, AntenatalPanels) write\n * through this hook simultaneously, so the \"is current prose user-owned?\"\n * check is stateless: we compare the current prose against the prose that\n * the *previous* pathway value would have generated. If they match, the\n * textarea is still auto-owned and may be refreshed; otherwise the user has\n * edited prose and we preserve it (only the chip line is kept in sync).\n *\n * Because `formatObgPathwayProse` is deterministic, this approach is\n * correct across multiple writers and across remounts without any shared\n * ref — a previous `lastAutoProseRef`-based design fought itself when\n * OBGPathwayWidget and AntenatalPanels both wrote on the same tick.\n */\nexport function useObgSymptomsSync() {\n const symptomsField = useField(SYMPTOMS_FIELD);\n\n const writeSymptoms = (\n prev: ObgPathwayValue,\n next: ObgPathwayValue,\n overrideProse?: string,\n ) => {\n if (symptomsField.disabled) return;\n const cur =\n typeof symptomsField.value === 'string' ? symptomsField.value : '';\n const { prose: curProse } = parseProseAndChipTokens(\n cur,\n OBG_ZONE_ALLOWED_CHIP_LABELS,\n );\n\n const prevProse = formatObgPathwayProse(prev);\n const generatedProse = formatObgPathwayProse(next);\n const isAutoOwned = curProse === '' || curProse === prevProse;\n\n const proseInput =\n overrideProse !== undefined\n ? overrideProse\n : isAutoOwned\n ? generatedProse\n : curProse;\n\n const chipLabels = next.zones.map(obgZoneLabel);\n const composed = composeProseAndChips(proseInput, chipLabels);\n if (composed !== cur) symptomsField.setValue(composed);\n };\n\n return { writeSymptoms, symptomsField };\n}\n"]}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { cn } from './chunk-VPU66PI6.mjs';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { jsx } from 'react/jsx-runtime';
|
|
4
|
+
|
|
5
|
+
var Switch = React.forwardRef(
|
|
6
|
+
({ className, checked, onCheckedChange, disabled, ...props }, ref) => {
|
|
7
|
+
return /* @__PURE__ */ jsx(
|
|
8
|
+
"button",
|
|
9
|
+
{
|
|
10
|
+
type: "button",
|
|
11
|
+
role: "switch",
|
|
12
|
+
"aria-checked": checked,
|
|
13
|
+
"data-state": checked ? "checked" : "unchecked",
|
|
14
|
+
disabled,
|
|
15
|
+
ref,
|
|
16
|
+
onClick: () => {
|
|
17
|
+
if (!disabled && onCheckedChange) {
|
|
18
|
+
onCheckedChange(!checked);
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
className: cn(
|
|
22
|
+
"peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
|
|
23
|
+
className
|
|
24
|
+
),
|
|
25
|
+
...props,
|
|
26
|
+
children: /* @__PURE__ */ jsx(
|
|
27
|
+
"span",
|
|
28
|
+
{
|
|
29
|
+
"data-state": checked ? "checked" : "unchecked",
|
|
30
|
+
className: "pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform",
|
|
31
|
+
style: { transform: checked ? "translateX(1rem)" : "translateX(0)" }
|
|
32
|
+
}
|
|
33
|
+
)
|
|
34
|
+
}
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
);
|
|
38
|
+
Switch.displayName = "Switch";
|
|
39
|
+
|
|
40
|
+
export { Switch };
|
|
41
|
+
//# sourceMappingURL=chunk-6YUVILN5.mjs.map
|
|
42
|
+
//# sourceMappingURL=chunk-6YUVILN5.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/ui/shadcn/switch.tsx"],"names":[],"mappings":";;;;AASA,IAAM,MAAA,GAAe,KAAA,CAAA,UAAA;AAAA,EACnB,CAAC,EAAE,SAAA,EAAW,OAAA,EAAS,iBAAiB,QAAA,EAAU,GAAG,KAAA,EAAM,EAAG,GAAA,KAAQ;AACpE,IAAA,uBACE,GAAA;AAAA,MAAC,QAAA;AAAA,MAAA;AAAA,QACC,IAAA,EAAK,QAAA;AAAA,QACL,IAAA,EAAK,QAAA;AAAA,QACL,cAAA,EAAc,OAAA;AAAA,QACd,YAAA,EAAY,UAAU,SAAA,GAAY,WAAA;AAAA,QAClC,QAAA;AAAA,QACA,GAAA;AAAA,QACA,SAAS,MAAM;AACb,UAAA,IAAI,CAAC,YAAY,eAAA,EAAiB;AAChC,YAAA,eAAA,CAAgB,CAAC,OAAO,CAAA;AAAA,UAC1B;AAAA,QACF,CAAA;AAAA,QACA,SAAA,EAAW,EAAA;AAAA,UACT,mXAAA;AAAA,UACA;AAAA,SACF;AAAA,QACC,GAAG,KAAA;AAAA,QAEJ,QAAA,kBAAA,GAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YACC,YAAA,EAAY,UAAU,SAAA,GAAY,WAAA;AAAA,YAClC,SAAA,EAAU,oGAAA;AAAA,YACV,KAAA,EAAO,EAAE,SAAA,EAAW,OAAA,GAAU,qBAAqB,eAAA;AAAgB;AAAA;AACrE;AAAA,KACF;AAAA,EAEJ;AACF;AACA,MAAA,CAAO,WAAA,GAAc,QAAA","file":"chunk-6YUVILN5.mjs","sourcesContent":["import * as React from \"react\";\nimport { cn } from \"../../core/utils\";\n\nexport interface SwitchProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n checked?: boolean;\n onCheckedChange?: (checked: boolean) => void;\n}\n\nconst Switch = React.forwardRef<HTMLButtonElement, SwitchProps>(\n ({ className, checked, onCheckedChange, disabled, ...props }, ref) => {\n return (\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={checked}\n data-state={checked ? \"checked\" : \"unchecked\"}\n disabled={disabled}\n ref={ref}\n onClick={() => {\n if (!disabled && onCheckedChange) {\n onCheckedChange(!checked);\n }\n }}\n className={cn(\n \"peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input\",\n className\n )}\n {...props}\n >\n <span\n data-state={checked ? \"checked\" : \"unchecked\"}\n className=\"pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform\"\n style={{ transform: checked ? 'translateX(1rem)' : 'translateX(0)' }}\n />\n </button>\n );\n }\n);\nSwitch.displayName = \"Switch\";\n\nexport { Switch };\n"]}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var chunkTJHG5WHX_cjs = require('./chunk-TJHG5WHX.cjs');
|
|
4
|
-
var
|
|
4
|
+
var chunkHXY3IX3G_cjs = require('./chunk-HXY3IX3G.cjs');
|
|
5
|
+
var chunkRILRMRXB_cjs = require('./chunk-RILRMRXB.cjs');
|
|
5
6
|
var chunkO3VQBPEW_cjs = require('./chunk-O3VQBPEW.cjs');
|
|
6
7
|
var chunkFHHISVCH_cjs = require('./chunk-FHHISVCH.cjs');
|
|
7
8
|
var React = require('react');
|
|
@@ -89,8 +90,8 @@ function DateTimePicker({
|
|
|
89
90
|
setDateTime(next);
|
|
90
91
|
};
|
|
91
92
|
const hasValue = !!dateTime;
|
|
92
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
93
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
93
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(chunkRILRMRXB_cjs.Popover, { children: [
|
|
94
|
+
/* @__PURE__ */ jsxRuntime.jsx(chunkRILRMRXB_cjs.PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
94
95
|
chunkO3VQBPEW_cjs.Button,
|
|
95
96
|
{
|
|
96
97
|
variant: "outline",
|
|
@@ -112,9 +113,9 @@ function DateTimePicker({
|
|
|
112
113
|
]
|
|
113
114
|
}
|
|
114
115
|
) }),
|
|
115
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
116
|
+
/* @__PURE__ */ jsxRuntime.jsx(chunkRILRMRXB_cjs.PopoverContent, { className: "w-auto p-0", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col md:flex-row", children: [
|
|
116
117
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
117
|
-
|
|
118
|
+
chunkHXY3IX3G_cjs.Calendar,
|
|
118
119
|
{
|
|
119
120
|
mode: "single",
|
|
120
121
|
selected: internalDate,
|
|
@@ -139,5 +140,5 @@ function DateTimePicker({
|
|
|
139
140
|
}
|
|
140
141
|
|
|
141
142
|
exports.DateTimePicker = DateTimePicker;
|
|
142
|
-
//# sourceMappingURL=chunk-
|
|
143
|
-
//# sourceMappingURL=chunk-
|
|
143
|
+
//# sourceMappingURL=chunk-7OQFO6TM.cjs.map
|
|
144
|
+
//# sourceMappingURL=chunk-7OQFO6TM.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/ui/shadcn/datetime-picker.tsx"],"names":["React","Popover","jsx","PopoverTrigger","jsxs","Button","cn","CalendarIcon","format","Clock","PopoverContent","Calendar","Input"],"mappings":"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","file":"chunk-7OQFO6TM.cjs","sourcesContent":["import * as React from \"react\"\nimport { format } from \"date-fns\"\nimport { Calendar as CalendarIcon, Clock } from \"lucide-react\"\n\nimport { cn } from \"../../core/utils\"\nimport { Button } from \"./button\"\nimport { Calendar } from \"./calendar\"\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from \"./popover\"\nimport { Input } from \"./input\"\n\nexport interface DateTimePickerProps {\n /**\n * The current value as a Date object.\n */\n dateTime?: Date\n /**\n * Setter for the value. Use undefined to clear.\n */\n setDateTime?: (value: Date | undefined) => void\n className?: string\n placeholder?: string\n}\n\nfunction parseTimeString(value: string): { hours: number; minutes: number } | null {\n if (!value) return null\n const [h, m] = value.split(\":\").map((v) => Number(v))\n if (\n Number.isNaN(h) ||\n Number.isNaN(m) ||\n h < 0 ||\n h > 23 ||\n m < 0 ||\n m > 59\n ) {\n return null\n }\n return { hours: h, minutes: m }\n}\n\nexport function DateTimePicker({\n dateTime,\n setDateTime,\n className,\n placeholder = \"Pick date & time\",\n}: DateTimePickerProps) {\n const [internalDate, setInternalDate] = React.useState<Date | undefined>(dateTime)\n const [timeString, setTimeString] = React.useState<string>(() => {\n if (!dateTime) return \"\"\n const hours = dateTime.getHours().toString().padStart(2, \"0\")\n const minutes = dateTime.getMinutes().toString().padStart(2, \"0\")\n return `${hours}:${minutes}`\n })\n\n React.useEffect(() => {\n setInternalDate(dateTime)\n if (!dateTime) {\n setTimeString(\"\")\n } else {\n const hours = dateTime.getHours().toString().padStart(2, \"0\")\n const minutes = dateTime.getMinutes().toString().padStart(2, \"0\")\n setTimeString(`${hours}:${minutes}`)\n }\n }, [dateTime])\n\n const handleDateSelect = (date: Date | undefined) => {\n setInternalDate(date)\n if (!setDateTime) return\n if (!date) {\n setDateTime(undefined)\n return\n }\n\n const parsed = parseTimeString(timeString)\n const next = new Date(date)\n if (parsed) {\n next.setHours(parsed.hours, parsed.minutes, 0, 0)\n }\n setDateTime(next)\n }\n\n const handleTimeChange: React.ChangeEventHandler<HTMLInputElement> = (e) => {\n const value = e.target.value\n setTimeString(value)\n if (!setDateTime) return\n\n const parsed = parseTimeString(value)\n if (!parsed) {\n // Don't propagate invalid time, just keep local string\n return\n }\n\n const base = internalDate ?? new Date()\n const next = new Date(base)\n next.setHours(parsed.hours, parsed.minutes, 0, 0)\n setInternalDate(next)\n setDateTime(next)\n }\n\n const hasValue = !!dateTime\n\n return (\n <Popover>\n <PopoverTrigger asChild>\n <Button\n variant={\"outline\"}\n className={cn(\n \"w-[280px] justify-start text-left font-normal\",\n !hasValue && \"text-muted-foreground\",\n className\n )}\n >\n <CalendarIcon className=\"mr-2 h-4 w-4\" />\n {hasValue ? (\n <span className=\"flex items-center gap-1\">\n {format(dateTime as Date, \"PPP\")}\n <span className=\"text-muted-foreground\">•</span>\n <span className=\"inline-flex items-center gap-1\">\n <Clock className=\"h-3 w-3\" />\n {format(dateTime as Date, \"HH:mm\")}\n </span>\n </span>\n ) : (\n <span>{placeholder}</span>\n )}\n </Button>\n </PopoverTrigger>\n <PopoverContent className=\"w-auto p-0\">\n <div className=\"flex flex-col md:flex-row\">\n <Calendar\n mode=\"single\"\n selected={internalDate}\n onSelect={handleDateSelect}\n initialFocus\n />\n <div className=\"border-t md:border-t-0 md:border-l p-3 flex flex-col gap-2 min-w-[220px]\">\n <label className=\"text-xs font-medium text-muted-foreground\">\n Time (24h)\n </label>\n <Input\n type=\"time\"\n value={timeString}\n onChange={handleTimeChange}\n className=\"w-full\"\n />\n </div>\n </div>\n </PopoverContent>\n </Popover>\n )\n}\n\n"]}
|