formanitor 0.0.41 → 0.0.42

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
@@ -30,326 +30,6 @@ function fieldMetaRequestsMarMedicationOrdersButton(meta) {
30
30
  return meta[MAR_MEDICATION_ORDERS_META_KEY] === true;
31
31
  }
32
32
 
33
- // src/core/urologyClinicalPathwayMetadata.ts
34
- function isUrologyTemplate(template) {
35
- if (!template || typeof template !== "object") return false;
36
- const t = template;
37
- return t.meta?.specialization === "urology" || t.specialization === "urology" || t.id === "uro_prescription";
38
- }
39
- function shouldFoldUrologyClinicalPathway(template, payload) {
40
- if (isUrologyTemplate(template)) return true;
41
- return Object.keys(payload).some(
42
- (k) => k.startsWith("uro_") || k === "chief_complaints" || k === "chief_complaints_chips"
43
- );
44
- }
45
- var UROLOGY_EXTRA_METADATA_KEYS = ["symptoms", "notes", "vitals"];
46
- function isUroPlainObject(v) {
47
- return v !== null && typeof v === "object" && !Array.isArray(v);
48
- }
49
- function coerceUrologyBool(value) {
50
- if (value === true || value === false) return value;
51
- if (value === "true") return true;
52
- if (value === "false") return false;
53
- if (Array.isArray(value)) {
54
- if (value.includes("yes") || value.includes(true)) return true;
55
- if (value.length === 0) return false;
56
- }
57
- return value;
58
- }
59
- function urologyIpssItem(v) {
60
- const n = Number(v);
61
- if (!Number.isFinite(n)) return 0;
62
- return Math.min(5, Math.max(0, Math.round(n)));
63
- }
64
- function urologyIpssSevenTotalFromParts(ipss) {
65
- return ipss.incomplete + ipss.frequency + ipss.intermittency + ipss.urgency + ipss.weakStream + ipss.straining + ipss.nocturia;
66
- }
67
- function buildUrologySmartHistoryFromLegacyFlat(flat) {
68
- return {
69
- socrates_pain_flank_suprapubic: {
70
- site: flat.uro_sh_socrates_site,
71
- onset: flat.uro_sh_socrates_onset,
72
- character: flat.uro_sh_socrates_character,
73
- radiation: flat.uro_sh_socrates_radiation,
74
- associated: flat.uro_sh_socrates_associated,
75
- timing: flat.uro_sh_socrates_timing,
76
- exacerbating: flat.uro_sh_socrates_exacerbating,
77
- severity_0_to_10: flat.uro_sh_socrates_severity
78
- },
79
- ipss_international_symptom_score: {
80
- incomplete_emptying: flat.uro_sh_ipss_incomplete,
81
- frequency_lt_2h: flat.uro_sh_ipss_frequency,
82
- intermittency: flat.uro_sh_ipss_intermittency,
83
- urgency: flat.uro_sh_ipss_urgency,
84
- weak_stream: flat.uro_sh_ipss_weak_stream,
85
- straining: flat.uro_sh_ipss_straining,
86
- nocturia: flat.uro_sh_ipss_nocturia,
87
- qol_0_to_6: flat.uro_sh_ipss_qol,
88
- seven_item_total_computed_max_35: flat.uro_sh_ipss_total_display
89
- },
90
- haematuria_profile: {
91
- present: flat.uro_sh_haem_present,
92
- timing: flat.uro_sh_haem_timing,
93
- painful: flat.uro_sh_haem_painful,
94
- clots: flat.uro_sh_haem_clots
95
- },
96
- sexual_and_reproductive: {
97
- erectile_function: flat.uro_sh_sex_erectile,
98
- libido: flat.uro_sh_sex_libido,
99
- ejaculation: flat.uro_sh_sex_ejaculation,
100
- infertility_months: flat.uro_sh_sex_infertility_months
101
- },
102
- context_prior_stones_surgery_comorbidity: flat.uro_smart_notes_free ?? ""
103
- };
104
- }
105
- function buildUrologySmartHistoryFromComposite(raw, flat) {
106
- const soc = isUroPlainObject(raw.socrates) ? raw.socrates : {};
107
- const ipssIn = isUroPlainObject(raw.ipss) ? raw.ipss : {};
108
- const haem = isUroPlainObject(raw.haematuria) ? raw.haematuria : {};
109
- const sex = isUroPlainObject(raw.sexual) ? raw.sexual : {};
110
- const str2 = (x) => typeof x === "string" ? x : "";
111
- const sev = Number(soc.severity);
112
- const severity0to10 = Number.isFinite(sev) ? Math.min(10, Math.max(0, Math.round(sev))) : 0;
113
- const ipss = {
114
- incomplete: urologyIpssItem(ipssIn.incomplete),
115
- frequency: urologyIpssItem(ipssIn.frequency),
116
- intermittency: urologyIpssItem(ipssIn.intermittency),
117
- urgency: urologyIpssItem(ipssIn.urgency),
118
- weakStream: urologyIpssItem(
119
- ipssIn.weakStream ?? ipssIn.weak_stream
120
- ),
121
- straining: urologyIpssItem(ipssIn.straining),
122
- nocturia: urologyIpssItem(ipssIn.nocturia)
123
- };
124
- const sevenTotal = urologyIpssSevenTotalFromParts(ipss);
125
- const qolRaw = Number(raw.ipssQoL);
126
- const qol = Number.isFinite(qolRaw) ? Math.min(6, Math.max(0, Math.round(qolRaw))) : 0;
127
- const timingRaw = str2(haem.timing);
128
- const pastNotes = str2(raw.pastNotes);
129
- const legacyNotes = flat.uro_smart_notes_free;
130
- const contextPrior = pastNotes !== "" ? pastNotes : typeof legacyNotes === "string" ? legacyNotes : legacyNotes ?? "";
131
- const infertilityRaw = Number(sex.infertilityMonths);
132
- const infertilityMonths = Number.isFinite(infertilityRaw) ? Math.max(0, Math.round(infertilityRaw)) : 0;
133
- return {
134
- socrates_pain_flank_suprapubic: {
135
- site: str2(soc.site),
136
- onset: str2(soc.onset),
137
- character: str2(soc.character),
138
- radiation: str2(soc.radiation),
139
- associated: str2(soc.associated),
140
- timing: str2(soc.timing),
141
- exacerbating: str2(soc.exacerbating),
142
- severity_0_to_10: severity0to10
143
- },
144
- ipss_international_symptom_score: {
145
- incomplete_emptying: ipss.incomplete,
146
- frequency_lt_2h: ipss.frequency,
147
- intermittency: ipss.intermittency,
148
- urgency: ipss.urgency,
149
- weak_stream: ipss.weakStream,
150
- straining: ipss.straining,
151
- nocturia: ipss.nocturia,
152
- qol_0_to_6: qol,
153
- seven_item_total_computed_max_35: sevenTotal
154
- },
155
- haematuria_profile: {
156
- present: haem.present === true,
157
- timing: timingRaw,
158
- painful: haem.painful === true,
159
- clots: haem.clots === true
160
- },
161
- sexual_and_reproductive: {
162
- erectile_function: str2(sex.erectile),
163
- libido: str2(sex.libido),
164
- ejaculation: str2(sex.ejaculation),
165
- infertility_months: infertilityMonths
166
- },
167
- context_prior_stones_surgery_comorbidity: contextPrior
168
- };
169
- }
170
- function buildUrologyExaminationFromLegacyFlat(flat) {
171
- return {
172
- general: {
173
- pallor: flat.uro_ex_general_pallor,
174
- oedema: flat.uro_ex_general_oedema,
175
- icterus: flat.uro_ex_general_icterus,
176
- lymphadenopathy: flat.uro_ex_general_lymph
177
- },
178
- abdomen: {
179
- distension: flat.uro_ex_ab_distension,
180
- surgical_scars: flat.uro_ex_ab_scars,
181
- visible_mass: flat.uro_ex_ab_mass,
182
- kidney_palpable: flat.uro_ex_ab_kidney_palpable,
183
- bladder_palpable: flat.uro_ex_ab_bladder_palpable,
184
- renal_angle_tender: flat.uro_ex_ab_renal_angle_tender,
185
- bladder_dullness_retention: flat.uro_ex_ab_bladder_dull
186
- },
187
- external_genitalia_scrotum: {
188
- meatus_abnormal_hypospadias_query: flat.uro_ex_gu_meatus,
189
- phimosis_paraphimosis: flat.uro_ex_gu_phimosis,
190
- penile_lesions_ulcers: flat.uro_ex_gu_lesions,
191
- scrotal_swelling: flat.uro_ex_gu_scrotal_swelling,
192
- transilluminant: flat.uro_ex_gu_transilluminant,
193
- tender_testis: flat.uro_ex_gu_tender_testis,
194
- hydrocele: flat.uro_ex_gu_hydrocele,
195
- varicocele: flat.uro_ex_gu_varicocele,
196
- suspicious_mass_urgent: flat.uro_ex_gu_suspicious_mass
197
- },
198
- dre_prostate: {
199
- dre_performed: flat.uro_ex_dre_done,
200
- estimated_size_grams: flat.uro_ex_dre_size_g,
201
- consistency: flat.uro_ex_dre_consistency,
202
- median_sulcus: flat.uro_ex_dre_median_sulcus,
203
- tenderness_prostatitis_query: flat.uro_ex_dre_tender
204
- },
205
- examination_notes_free_text: flat.uro_examination_notes ?? ""
206
- };
207
- }
208
- function buildUrologyExaminationFromComposite(raw) {
209
- const regions = Array.isArray(raw.regions) ? raw.regions.filter((x) => typeof x === "string") : [];
210
- const g = isUroPlainObject(raw.general) ? raw.general : {};
211
- const ab = isUroPlainObject(raw.abdomen) ? raw.abdomen : {};
212
- const gu = isUroPlainObject(raw.gu) ? raw.gu : {};
213
- const dr = isUroPlainObject(raw.dre) ? raw.dre : {};
214
- const dreConsistency = typeof dr.consistency === "string" ? dr.consistency : "";
215
- const dreMedian = typeof dr.medianSulcus === "string" ? dr.medianSulcus : typeof dr.median_sulcus === "string" ? dr.median_sulcus : "";
216
- const sizeG = Number(dr.sizeGrams);
217
- const sizeGrams = Number.isFinite(sizeG) && sizeG >= 0 ? Math.round(sizeG) : 0;
218
- const notesRaw = raw.examinationNotes;
219
- const notes = typeof notesRaw === "string" ? notesRaw : "";
220
- const bool = (x) => x === true;
221
- return {
222
- regions_reviewed: regions,
223
- general: {
224
- pallor: bool(g.pallor),
225
- oedema: bool(g.oedema),
226
- icterus: bool(g.icterus),
227
- lymphadenopathy: bool(g.lymphadenopathy)
228
- },
229
- abdomen: {
230
- distension: bool(ab.distension),
231
- surgical_scars: bool(ab.scars),
232
- visible_mass: bool(ab.mass),
233
- kidney_palpable: bool(ab.kidneyPalpable),
234
- bladder_palpable: bool(ab.bladderPalpable),
235
- renal_angle_tender: bool(ab.renalAngleTender),
236
- bladder_dullness_retention: bool(ab.bladderDull)
237
- },
238
- external_genitalia_scrotum: {
239
- meatus_abnormal_hypospadias_query: bool(gu.meatusAbnormal),
240
- phimosis_paraphimosis: bool(gu.phimosis),
241
- penile_lesions_ulcers: bool(gu.lesions),
242
- scrotal_swelling: bool(gu.scrotalSwelling),
243
- transilluminant: bool(gu.transilluminant),
244
- tender_testis: bool(gu.tenderTestis),
245
- hydrocele: bool(gu.hydrocele),
246
- varicocele: bool(gu.varicocele),
247
- suspicious_mass_urgent: bool(gu.suspiciousMass)
248
- },
249
- dre_prostate: {
250
- dre_performed: bool(dr.done),
251
- estimated_size_grams: sizeGrams,
252
- consistency: dreConsistency === "none" ? "" : dreConsistency,
253
- median_sulcus: dreMedian === "none" ? "" : dreMedian,
254
- tenderness_prostatitis_query: bool(dr.tenderness)
255
- },
256
- examination_notes_free_text: notes
257
- };
258
- }
259
- function buildUrologyDecisionEngineAndRisk(flat) {
260
- const comp = flat.uro_pathway;
261
- if (isUroPlainObject(comp)) {
262
- const riskIn = isUroPlainObject(comp.risk) ? comp.risk : {};
263
- return {
264
- decision_engine: {
265
- stone_disease: {
266
- stone_size_mm: comp.stoneSizeMm ?? 0,
267
- hydronephrosis_on_imaging: coerceUrologyBool(comp.hydronephrosis)
268
- },
269
- prostate_bph_flow_lab: {
270
- prostate_volume_cc: comp.prostateVolumeCc ?? 0,
271
- psa_ng_ml: comp.psaNgMl ?? 0,
272
- uroflow_qmax_ml_s: comp.uroflowQmaxMlSec ?? 0
273
- }
274
- },
275
- risk_stratification: {
276
- ckd: coerceUrologyBool(riskIn.ckd),
277
- diabetes: coerceUrologyBool(riskIn.diabetes),
278
- anticoagulants: coerceUrologyBool(riskIn.anticoagulants),
279
- active_infection: coerceUrologyBool(riskIn.activeInfection)
280
- }
281
- };
282
- }
283
- return {
284
- decision_engine: {
285
- stone_disease: {
286
- stone_size_mm: flat.uro_stone_size_mm,
287
- hydronephrosis_on_imaging: coerceUrologyBool(flat.uro_stone_hydronephrosis)
288
- },
289
- prostate_bph_flow_lab: {
290
- prostate_volume_cc: flat.uro_prostate_vol_cc,
291
- psa_ng_ml: flat.uro_psa_ng_ml,
292
- uroflow_qmax_ml_s: flat.uro_flow_qmax
293
- }
294
- },
295
- risk_stratification: {
296
- ckd: coerceUrologyBool(flat.uro_risk_ckd),
297
- diabetes: coerceUrologyBool(flat.uro_risk_diabetes),
298
- anticoagulants: coerceUrologyBool(flat.uro_risk_anticoag),
299
- active_infection: coerceUrologyBool(flat.uro_risk_active_infection)
300
- }
301
- };
302
- }
303
- function attachUrologyClinicalPathwayMetadata(payload, template) {
304
- if (!shouldFoldUrologyClinicalPathway(template, payload)) return;
305
- const extra = UROLOGY_EXTRA_METADATA_KEYS;
306
- const keys = Object.keys(payload).filter(
307
- (k) => k.startsWith("uro_") || k === "chief_complaints" || k === "chief_complaints_chips" || extra.includes(k)
308
- );
309
- if (keys.length === 0) return;
310
- const flat = {};
311
- for (const k of keys) {
312
- flat[k] = payload[k];
313
- delete payload[k];
314
- }
315
- const triage = flat.uro_triage;
316
- const chiefComplaints = {
317
- narrative: flat.chief_complaints ?? "",
318
- chips: flat.chief_complaints_chips ?? [],
319
- duration: flat.uro_chief_duration ?? "",
320
- onset: flat.uro_chief_onset ?? "",
321
- progression: flat.uro_chief_progression ?? "",
322
- active_syndrome: flat.uro_active_syndrome ?? ""
323
- };
324
- const compositeSh = flat.uro_smart_history;
325
- const compositeEx = flat.uro_examination;
326
- const smart_history = isUroPlainObject(compositeSh) ? buildUrologySmartHistoryFromComposite(compositeSh, flat) : buildUrologySmartHistoryFromLegacyFlat(flat);
327
- const examination = isUroPlainObject(compositeEx) ? buildUrologyExaminationFromComposite(compositeEx) : buildUrologyExaminationFromLegacyFlat(flat);
328
- const { decision_engine, risk_stratification } = buildUrologyDecisionEngineAndRisk(flat);
329
- const structured = {
330
- triage_vas_and_flags: triage ?? null,
331
- chief_complaint_engine: chiefComplaints,
332
- smart_history,
333
- examination,
334
- pathway_triggers_objective_scores: decision_engine,
335
- risk_stratification,
336
- encounter_narrative: {
337
- symptoms: flat.symptoms ?? "",
338
- notes: flat.notes ?? "",
339
- vitals: flat.vitals ?? ""
340
- }
341
- };
342
- const existingMetadata = payload.metadata ?? {};
343
- const existingPathways = existingMetadata.clinical_pathways ?? {};
344
- payload.metadata = {
345
- ...existingMetadata,
346
- clinical_pathways: {
347
- ...existingPathways,
348
- urology: structured
349
- }
350
- };
351
- }
352
-
353
33
  // src/core/validate.ts
354
34
  var EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
355
35
  function validateField(value, field) {
@@ -1018,233 +698,6 @@ function formatGeneralSurgeryExaminationToNarrative(v) {
1018
698
  return blocks.join("\n\n");
1019
699
  }
1020
700
 
1021
- // src/core/urologyPathway.ts
1022
- var defaultUrologySmartHistory = () => ({
1023
- socrates: {
1024
- site: "",
1025
- onset: "",
1026
- character: "",
1027
- radiation: "",
1028
- associated: "",
1029
- timing: "",
1030
- exacerbating: "",
1031
- severity: 0
1032
- },
1033
- ipss: {
1034
- incomplete: 0,
1035
- frequency: 0,
1036
- intermittency: 0,
1037
- urgency: 0,
1038
- weakStream: 0,
1039
- straining: 0,
1040
- nocturia: 0
1041
- },
1042
- ipssQoL: 0,
1043
- haematuria: { present: false, timing: "", painful: false, clots: false },
1044
- sexual: { erectile: "", libido: "", ejaculation: "", infertilityMonths: 0 },
1045
- pastNotes: ""
1046
- });
1047
- var defaultUrologyExamination = () => ({
1048
- regions: [],
1049
- general: { pallor: false, oedema: false, icterus: false, lymphadenopathy: false },
1050
- abdomen: {
1051
- distension: false,
1052
- scars: false,
1053
- mass: false,
1054
- kidneyPalpable: false,
1055
- bladderPalpable: false,
1056
- renalAngleTender: false,
1057
- bladderDull: false
1058
- },
1059
- gu: {
1060
- meatusAbnormal: false,
1061
- phimosis: false,
1062
- lesions: false,
1063
- scrotalSwelling: false,
1064
- transilluminant: false,
1065
- tenderTestis: false,
1066
- hydrocele: false,
1067
- varicocele: false,
1068
- suspiciousMass: false
1069
- },
1070
- dre: { done: false, sizeGrams: 0, consistency: "", medianSulcus: "", tenderness: false },
1071
- examinationNotes: ""
1072
- });
1073
- function clampInt(n, lo, hi) {
1074
- if (!Number.isFinite(n)) return lo;
1075
- return Math.min(hi, Math.max(lo, Math.round(n)));
1076
- }
1077
- var SOCRATES_KEYS = [
1078
- "site",
1079
- "onset",
1080
- "character",
1081
- "radiation",
1082
- "associated",
1083
- "timing",
1084
- "exacerbating"
1085
- ];
1086
- function urologyIpssSevenTotal(ipss) {
1087
- return ipss.incomplete + ipss.frequency + ipss.intermittency + ipss.urgency + ipss.weakStream + ipss.straining + ipss.nocturia;
1088
- }
1089
- function urologyIpssBand(total) {
1090
- if (total <= 7) return "Mild";
1091
- if (total <= 19) return "Moderate";
1092
- return "Severe";
1093
- }
1094
- function normalizeUrologySmartHistory(raw) {
1095
- const d = defaultUrologySmartHistory();
1096
- if (!raw || typeof raw !== "object" || Array.isArray(raw)) return d;
1097
- const v = raw;
1098
- const socIn = v.socrates && typeof v.socrates === "object" ? v.socrates : {};
1099
- const socrates = { ...d.socrates };
1100
- for (const k of SOCRATES_KEYS) {
1101
- const x = socIn[k];
1102
- socrates[k] = typeof x === "string" ? x : "";
1103
- }
1104
- const sev = Number(socIn.severity);
1105
- socrates.severity = clampInt(Number.isFinite(sev) ? sev : d.socrates.severity, 0, 10);
1106
- const ipIn = v.ipss && typeof v.ipss === "object" ? v.ipss : {};
1107
- const ipss = { ...d.ipss };
1108
- for (const k of [
1109
- "incomplete",
1110
- "frequency",
1111
- "intermittency",
1112
- "urgency",
1113
- "weakStream",
1114
- "straining",
1115
- "nocturia"
1116
- ]) {
1117
- const n = Number(ipIn[k]);
1118
- ipss[k] = clampInt(Number.isFinite(n) ? n : 0, 0, 5);
1119
- }
1120
- const qol = Number(v.ipssQoL);
1121
- const ipssQoL = clampInt(Number.isFinite(qol) ? qol : d.ipssQoL, 0, 6);
1122
- const haIn = v.haematuria && typeof v.haematuria === "object" ? v.haematuria : {};
1123
- const timingRaw = haIn.timing;
1124
- const haematuria = {
1125
- present: haIn.present === true,
1126
- timing: typeof timingRaw === "string" && timingRaw !== "none" && timingRaw.length > 0 ? timingRaw : "",
1127
- painful: haIn.painful === true,
1128
- clots: haIn.clots === true
1129
- };
1130
- const sxIn = v.sexual && typeof v.sexual === "object" ? v.sexual : {};
1131
- const str2 = (x) => typeof x === "string" && x.length > 0 && x !== "none" ? x : "";
1132
- const inf = Number(sxIn.infertilityMonths);
1133
- const sexual = {
1134
- erectile: str2(sxIn.erectile),
1135
- libido: str2(sxIn.libido),
1136
- ejaculation: str2(sxIn.ejaculation),
1137
- infertilityMonths: Number.isFinite(inf) && inf >= 0 ? Math.round(inf) : 0
1138
- };
1139
- const pastNotes = typeof v.pastNotes === "string" ? v.pastNotes : d.pastNotes;
1140
- return { socrates, ipss, ipssQoL, haematuria, sexual, pastNotes };
1141
- }
1142
- function normalizeUrologyExamination(raw) {
1143
- const d = defaultUrologyExamination();
1144
- if (!raw || typeof raw !== "object" || Array.isArray(raw)) return d;
1145
- const v = raw;
1146
- const strArr = (x) => Array.isArray(x) ? x.filter((i) => typeof i === "string") : [];
1147
- const bool = (x) => x === true;
1148
- const g = v.general && typeof v.general === "object" ? v.general : {};
1149
- const ab = v.abdomen && typeof v.abdomen === "object" ? v.abdomen : {};
1150
- const gu = v.gu && typeof v.gu === "object" ? v.gu : {};
1151
- const dr = v.dre && typeof v.dre === "object" ? v.dre : {};
1152
- const sg = Number(dr.sizeGrams);
1153
- const consistencyRaw = dr.consistency;
1154
- const medianRaw = dr.medianSulcus;
1155
- const dreEmpty = (x) => !(typeof x === "string" && x.length > 0 && x !== "none");
1156
- return {
1157
- regions: strArr(v.regions),
1158
- general: {
1159
- pallor: bool(g.pallor),
1160
- oedema: bool(g.oedema),
1161
- icterus: bool(g.icterus),
1162
- lymphadenopathy: bool(g.lymphadenopathy)
1163
- },
1164
- abdomen: {
1165
- distension: bool(ab.distension),
1166
- scars: bool(ab.scars),
1167
- mass: bool(ab.mass),
1168
- kidneyPalpable: bool(ab.kidneyPalpable),
1169
- bladderPalpable: bool(ab.bladderPalpable),
1170
- renalAngleTender: bool(ab.renalAngleTender),
1171
- bladderDull: bool(ab.bladderDull)
1172
- },
1173
- gu: {
1174
- meatusAbnormal: bool(gu.meatusAbnormal),
1175
- phimosis: bool(gu.phimosis),
1176
- lesions: bool(gu.lesions),
1177
- scrotalSwelling: bool(gu.scrotalSwelling),
1178
- transilluminant: bool(gu.transilluminant),
1179
- tenderTestis: bool(gu.tenderTestis),
1180
- hydrocele: bool(gu.hydrocele),
1181
- varicocele: bool(gu.varicocele),
1182
- suspiciousMass: bool(gu.suspiciousMass)
1183
- },
1184
- dre: {
1185
- done: bool(dr.done),
1186
- sizeGrams: Number.isFinite(sg) && sg >= 0 ? Math.round(sg) : 0,
1187
- consistency: dreEmpty(consistencyRaw) ? "" : String(consistencyRaw),
1188
- medianSulcus: dreEmpty(medianRaw) ? "" : String(medianRaw),
1189
- tenderness: bool(dr.tenderness)
1190
- },
1191
- examinationNotes: typeof v.examinationNotes === "string" ? v.examinationNotes : d.examinationNotes
1192
- };
1193
- }
1194
- var defaultUrologyPathway = () => ({
1195
- stoneSizeMm: 0,
1196
- hydronephrosis: false,
1197
- prostateVolumeCc: 0,
1198
- psaNgMl: 0,
1199
- uroflowQmaxMlSec: 0,
1200
- risk: {
1201
- ckd: false,
1202
- diabetes: false,
1203
- anticoagulants: false,
1204
- activeInfection: false
1205
- }
1206
- });
1207
- function clampNonNegativeNumber(x, fallback) {
1208
- const n = Number(x);
1209
- if (!Number.isFinite(n) || n < 0) return fallback;
1210
- return n;
1211
- }
1212
- function normalizeUrologyPathway(raw) {
1213
- const d = defaultUrologyPathway();
1214
- if (!raw || typeof raw !== "object" || Array.isArray(raw)) return d;
1215
- const v = raw;
1216
- const rIn = v.risk && typeof v.risk === "object" && !Array.isArray(v.risk) ? v.risk : {};
1217
- return {
1218
- stoneSizeMm: clampNonNegativeNumber(v.stoneSizeMm, d.stoneSizeMm),
1219
- hydronephrosis: v.hydronephrosis === true,
1220
- prostateVolumeCc: clampNonNegativeNumber(v.prostateVolumeCc, d.prostateVolumeCc),
1221
- psaNgMl: clampNonNegativeNumber(v.psaNgMl, d.psaNgMl),
1222
- uroflowQmaxMlSec: clampNonNegativeNumber(v.uroflowQmaxMlSec, d.uroflowQmaxMlSec),
1223
- risk: {
1224
- ckd: rIn.ckd === true,
1225
- diabetes: rIn.diabetes === true,
1226
- anticoagulants: rIn.anticoagulants === true,
1227
- activeInfection: rIn.activeInfection === true
1228
- }
1229
- };
1230
- }
1231
- function urologyStoneRecommendation(sizeMm, hydronephrosis) {
1232
- if (sizeMm <= 0) return { plan: "Enter stone size to auto-trigger plan.", surgical: false };
1233
- if (sizeMm < 5) return { plan: "Conservative + MET (\u03B1-blocker), hydration", surgical: false };
1234
- if (sizeMm <= 10)
1235
- return {
1236
- plan: hydronephrosis ? "URS / SWL \u2014 obstruction present" : "Medical expulsive therapy / URS",
1237
- surgical: hydronephrosis
1238
- };
1239
- return { plan: "URS / PCNL \u2014 surgical clearance indicated", surgical: true };
1240
- }
1241
- function urologyProstateProcedure(volumeCc) {
1242
- if (volumeCc <= 0) return "Enter prostate volume.";
1243
- if (volumeCc < 30) return "Medical (\u03B1-blocker \xB1 5-ARI)";
1244
- if (volumeCc <= 80) return "TURP";
1245
- return "HoLEP / Open simple prostatectomy";
1246
- }
1247
-
1248
701
  // src/core/painScaleFlags.ts
1249
702
  function normalizePainScaleFlags(raw, bounds) {
1250
703
  const min = bounds?.min ?? 0;
@@ -1363,12 +816,6 @@ var FormStore = class {
1363
816
  f.defaultValue ?? { pain: f.min ?? 0, flags: [] },
1364
817
  { min: f.min, max: f.max }
1365
818
  );
1366
- } else if (field.type === "urology_smart_history") {
1367
- values[field.id] = field.defaultValue ?? defaultUrologySmartHistory();
1368
- } else if (field.type === "urology_examination") {
1369
- values[field.id] = field.defaultValue ?? defaultUrologyExamination();
1370
- } else if (field.type === "urology_pathway") {
1371
- values[field.id] = field.defaultValue ?? defaultUrologyPathway();
1372
819
  } else values[field.id] = null;
1373
820
  }
1374
821
  });
@@ -1578,7 +1025,6 @@ var FormStore = class {
1578
1025
  }
1579
1026
  }
1580
1027
  });
1581
- attachUrologyClinicalPathwayMetadata(result, this.schema);
1582
1028
  return result;
1583
1029
  }
1584
1030
  // --- Core Logic ---
@@ -6551,7 +5997,7 @@ function safeJsonParse(val) {
6551
5997
  return null;
6552
5998
  }
6553
5999
  }
6554
- function clampInt2(val, min, max) {
6000
+ function clampInt(val, min, max) {
6555
6001
  if (!Number.isFinite(val)) return min;
6556
6002
  return Math.max(min, Math.min(max, Math.trunc(val)));
6557
6003
  }
@@ -6561,10 +6007,10 @@ function parseLegacyString(input) {
6561
6007
  if (gpalMatch) {
6562
6008
  const [, g, p, a, l] = gpalMatch;
6563
6009
  result.gpal = {
6564
- G: clampInt2(Number(g), 0, 20),
6565
- P: clampInt2(Number(p), 0, 20),
6566
- A: clampInt2(Number(a), 0, 20),
6567
- L: clampInt2(Number(l), 0, 20)
6010
+ G: clampInt(Number(g), 0, 20),
6011
+ P: clampInt(Number(p), 0, 20),
6012
+ A: clampInt(Number(a), 0, 20),
6013
+ L: clampInt(Number(l), 0, 20)
6568
6014
  };
6569
6015
  }
6570
6016
  const lmpMatch = input.match(/LMP:\s*([^\n]+)/i);
@@ -6597,10 +6043,10 @@ function normalizeToDraft(value) {
6597
6043
  isNewEntry: false,
6598
6044
  draft: {
6599
6045
  gpal: {
6600
- G: clampInt2(Number(gpal.G ?? 0), 0, 20),
6601
- P: clampInt2(Number(gpal.P ?? 0), 0, 20),
6602
- A: clampInt2(Number(gpal.A ?? 0), 0, 20),
6603
- L: clampInt2(Number(gpal.L ?? 0), 0, 20)
6046
+ G: clampInt(Number(gpal.G ?? 0), 0, 20),
6047
+ P: clampInt(Number(gpal.P ?? 0), 0, 20),
6048
+ A: clampInt(Number(gpal.A ?? 0), 0, 20),
6049
+ L: clampInt(Number(gpal.L ?? 0), 0, 20)
6604
6050
  },
6605
6051
  lmp: typeof lmp === "string" ? lmp : "",
6606
6052
  is_pregnant,
@@ -6618,10 +6064,10 @@ function normalizeToDraft(value) {
6618
6064
  }
6619
6065
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
6620
6066
  const gpalFromFlat = {
6621
- G: clampInt2(Number(parsed.G ?? parsed.g ?? 0), 0, 20),
6622
- P: clampInt2(Number(parsed.P ?? parsed.p ?? 0), 0, 20),
6623
- A: clampInt2(Number(parsed.A ?? parsed.a ?? 0), 0, 20),
6624
- L: clampInt2(Number(parsed.L ?? parsed.l ?? 0), 0, 20)
6067
+ G: clampInt(Number(parsed.G ?? parsed.g ?? 0), 0, 20),
6068
+ P: clampInt(Number(parsed.P ?? parsed.p ?? 0), 0, 20),
6069
+ A: clampInt(Number(parsed.A ?? parsed.a ?? 0), 0, 20),
6070
+ L: clampInt(Number(parsed.L ?? parsed.l ?? 0), 0, 20)
6625
6071
  };
6626
6072
  return {
6627
6073
  isNewEntry: false,
@@ -6773,7 +6219,7 @@ var ObstetricHistoryWidget = ({ fieldId }) => {
6773
6219
  const sanitizeGpalInput = (raw) => {
6774
6220
  const digits = raw.replace(/[^\d]/g, "").slice(0, 2);
6775
6221
  if (!digits) return 0;
6776
- return clampInt2(Number(digits), 0, 20);
6222
+ return clampInt(Number(digits), 0, 20);
6777
6223
  };
6778
6224
  const handleGpalChange = (key, raw) => {
6779
6225
  const prevWasEmpty = draft.gpal[key] === 0 && activeGpalKey === key;
@@ -10101,7 +9547,7 @@ var THYROID_OPTS = [
10101
9547
  { value: "voice_change", label: "Voice change" },
10102
9548
  { value: "thyrotoxicosis", label: "Thyrotoxicosis symptoms" }
10103
9549
  ];
10104
- var SOCRATES_KEYS2 = [
9550
+ var SOCRATES_KEYS = [
10105
9551
  "site",
10106
9552
  "onset",
10107
9553
  "character",
@@ -10195,7 +9641,7 @@ var GsSmartHistoryWidget = ({ fieldId }) => {
10195
9641
  labelEl,
10196
9642
  /* @__PURE__ */ jsxs("div", { className: bodyClass, children: [
10197
9643
  showPain ? /* @__PURE__ */ jsx(Panel, { title: "SOCRATES \u2014 pain", children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2 md:grid-cols-4", children: [
10198
- SOCRATES_KEYS2.map((k) => /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
9644
+ SOCRATES_KEYS.map((k) => /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
10199
9645
  /* @__PURE__ */ jsx("span", { className: "text-[10px] font-medium uppercase tracking-wide text-muted-foreground", children: k }),
10200
9646
  /* @__PURE__ */ jsx(
10201
9647
  Input,
@@ -11132,919 +10578,106 @@ var PainScaleFlagsWidget = ({ fieldId }) => {
11132
10578
  showError && /* @__PURE__ */ jsx("p", { className: "text-xs text-red-500", children: error })
11133
10579
  ] });
11134
10580
  };
11135
- var CHIEF_CHIPS_FIELD3 = "chief_complaints_chips";
11136
- var ACTIVE_SYNDROME_FIELD = "uro_active_syndrome";
11137
- function chipList2(state) {
11138
- const raw = state.values[CHIEF_CHIPS_FIELD3];
11139
- return Array.isArray(raw) ? raw.filter((x) => typeof x === "string") : [];
11140
- }
11141
- var IPSS_LABELS = {
11142
- incomplete: "Incomplete emptying",
11143
- frequency: "Frequency (<2h)",
11144
- intermittency: "Intermittency",
11145
- urgency: "Urgency",
11146
- weakStream: "Weak stream",
11147
- straining: "Straining",
11148
- nocturia: "Nocturia (\xD7/night)"
10581
+ var FieldRenderer = ({ fieldId }) => {
10582
+ const { fieldDef, visible } = useField(fieldId);
10583
+ if (!visible || !fieldDef) {
10584
+ return null;
10585
+ }
10586
+ return renderWidget(fieldId, fieldDef);
11149
10587
  };
11150
- var SOCRATES_KEYS3 = [
11151
- "site",
11152
- "onset",
11153
- "character",
11154
- "radiation",
11155
- "associated",
11156
- "timing",
11157
- "exacerbating"
11158
- ];
11159
- function Panel2({
11160
- title,
11161
- right,
11162
- children
11163
- }) {
11164
- return /* @__PURE__ */ jsxs("div", { className: "overflow-hidden rounded-md border border-[#D0D0D0] bg-white", children: [
11165
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between border-b border-[#D0D0D0] bg-[#FEE8EC]/50 px-3 py-1.5", children: [
11166
- /* @__PURE__ */ jsx("span", { className: "text-xs font-semibold text-slate-700", children: title }),
11167
- right
11168
- ] }),
11169
- /* @__PURE__ */ jsx("div", { className: "p-3", children })
11170
- ] });
11171
- }
11172
- var UrologySmartHistoryWidget = ({ fieldId }) => {
11173
- const { fieldDef, value, setValue, setTouched, error, touched, disabled } = useField(fieldId);
11174
- const syndromeField = useField(ACTIVE_SYNDROME_FIELD);
11175
- const { state } = useForm();
11176
- const showError = !!error && (touched || state.submitAttempted);
11177
- const safe = useMemo(() => normalizeUrologySmartHistory(value), [value]);
11178
- const chips = useMemo(() => chipList2(state), [state]);
11179
- const rawSyndrome = syndromeField.value ?? state.values[ACTIVE_SYNDROME_FIELD];
11180
- const syndrome = typeof rawSyndrome === "string" && rawSyndrome !== "" && rawSyndrome !== "none" ? rawSyndrome : "none";
11181
- const showPain = chips.includes("pain_abdomen_flank") || chips.includes("scrotal_swelling_pain") || syndrome === "stone" || syndrome === "scrotal";
11182
- const showLUTS = syndrome === "luts" || syndrome === "retention" || chips.includes("frequency_urgency") || chips.includes("poor_stream") || chips.includes("acute_retention");
11183
- const showHaem = syndrome === "haematuria" || chips.includes("haematuria");
11184
- const showSex = syndrome === "ed_infertility" || chips.includes("erectile_dysfunction") || chips.includes("infertility_concern");
11185
- const update = (next) => {
11186
- setValue(next);
11187
- setTouched();
11188
- };
11189
- const ipssTotal = urologyIpssSevenTotal(safe.ipss);
11190
- const ipssBandLabel = urologyIpssBand(ipssTotal);
11191
- const bandClass = ipssBandLabel === "Severe" ? "bg-red-500/15 text-red-700" : ipssBandLabel === "Moderate" ? "bg-amber-500/15 text-amber-800" : "bg-emerald-500/15 text-emerald-800";
11192
- const setSocrates = (key, v) => {
11193
- if (key === "severity") {
11194
- const n = typeof v === "number" ? v : Number(v);
11195
- const sev = Number.isFinite(n) ? Math.min(10, Math.max(0, Math.round(n))) : 0;
11196
- update({ ...safe, socrates: { ...safe.socrates, severity: sev } });
11197
- return;
11198
- }
11199
- update({ ...safe, socrates: { ...safe.socrates, [key]: String(v) } });
11200
- };
11201
- const setIpss = (key, v) => {
11202
- update({ ...safe, ipss: { ...safe.ipss, [key]: v } });
11203
- };
11204
- if (!fieldDef) return null;
11205
- const theme = getThemeConfig("textarea", fieldDef.theme);
11206
- const wrapperClass = theme?.wrapperClassName ?? "rounded-md overflow-hidden flex flex-col border border-[#D0D0D0]";
11207
- const labelClass = theme?.labelClassName;
11208
- const labelContent = /* @__PURE__ */ jsxs(Fragment, { children: [
11209
- fieldDef.label,
11210
- fieldDef.required ? /* @__PURE__ */ jsx("span", { className: "ml-1 text-red-500", children: "*" }) : null
11211
- ] });
11212
- const labelEl = theme ? /* @__PURE__ */ jsx(Label, { className: labelClass, children: labelContent }) : /* @__PURE__ */ jsx(Label, { className: "text-sm font-medium", children: labelContent });
11213
- const bodyClass = cn(
11214
- "-mt-1 flex min-w-0 flex-col gap-3 border-t border-[#D0D0D0] bg-white px-3 py-3",
11215
- disabled && "pointer-events-none opacity-60"
11216
- );
11217
- return /* @__PURE__ */ jsxs("div", { className: cn("w-full min-w-0", wrapperClass), children: [
11218
- labelEl,
11219
- /* @__PURE__ */ jsxs("div", { className: bodyClass, children: [
11220
- /* @__PURE__ */ jsx("p", { className: "text-[11px] text-muted-foreground", children: "Panels follow chief complaint chips and active syndrome (Clearsight SmartHistoryUro)." }),
11221
- showPain ? /* @__PURE__ */ jsx(Panel2, { title: "SOCRATES \u2014 Pain (flank / suprapubic / testicular)", children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2 md:grid-cols-4", children: [
11222
- SOCRATES_KEYS3.map((k) => /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
11223
- /* @__PURE__ */ jsx("span", { className: "text-[10px] font-medium uppercase tracking-wide text-muted-foreground", children: k }),
11224
- /* @__PURE__ */ jsx(
11225
- Input,
11226
- {
11227
- className: "h-8 text-xs",
11228
- value: safe.socrates[k],
11229
- onChange: (e) => setSocrates(k, e.target.value),
11230
- placeholder: k === "radiation" ? "e.g. groin \u2192 ureteric" : k === "character" ? "colicky / dull" : "",
11231
- disabled
11232
- }
11233
- )
11234
- ] }, k)),
11235
- /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
11236
- /* @__PURE__ */ jsx("span", { className: "text-[10px] font-medium uppercase tracking-wide text-muted-foreground", children: "Severity 0\u201310" }),
11237
- /* @__PURE__ */ jsx(
11238
- Input,
11239
- {
11240
- type: "number",
11241
- min: 0,
11242
- max: 10,
11243
- className: "h-8 text-xs",
11244
- value: safe.socrates.severity,
11245
- onChange: (e) => setSocrates("severity", e.target.value),
11246
- disabled
11247
- }
11248
- )
11249
- ] })
11250
- ] }) }) : null,
11251
- showLUTS ? /* @__PURE__ */ jsxs(
11252
- Panel2,
11253
- {
11254
- title: "IPSS \u2014 International Prostate Symptom Score",
11255
- right: /* @__PURE__ */ jsxs("span", { className: `rounded-full px-2 py-0.5 text-[10px] font-medium ${bandClass}`, children: [
11256
- ipssTotal,
11257
- "/35 \u2014 ",
11258
- ipssBandLabel
11259
- ] }),
11260
- children: [
11261
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2 md:grid-cols-4", children: [
11262
- Object.keys(IPSS_LABELS).map((k) => /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
11263
- /* @__PURE__ */ jsx("span", { className: "text-[10px] uppercase tracking-wide text-muted-foreground", children: IPSS_LABELS[k] }),
11264
- /* @__PURE__ */ jsxs(
11265
- Select,
11266
- {
11267
- value: String(safe.ipss[k]),
11268
- onValueChange: (val) => setIpss(k, Number(val)),
11269
- disabled,
11270
- children: [
11271
- /* @__PURE__ */ jsx(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsx(SelectValue, {}) }),
11272
- /* @__PURE__ */ jsx(SelectContent, { children: [0, 1, 2, 3, 4, 5].map((n) => /* @__PURE__ */ jsx(SelectItem, { value: String(n), children: n }, n)) })
11273
- ]
11274
- }
11275
- )
11276
- ] }, k)),
11277
- /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
11278
- /* @__PURE__ */ jsx("span", { className: "text-[10px] uppercase tracking-wide text-muted-foreground", children: "QoL (0\u20136)" }),
11279
- /* @__PURE__ */ jsxs(
11280
- Select,
11281
- {
11282
- value: String(safe.ipssQoL),
11283
- onValueChange: (val) => update({ ...safe, ipssQoL: Math.min(6, Math.max(0, Number(val))) }),
11284
- disabled,
11285
- children: [
11286
- /* @__PURE__ */ jsx(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsx(SelectValue, {}) }),
11287
- /* @__PURE__ */ jsx(SelectContent, { children: [0, 1, 2, 3, 4, 5, 6].map((n) => /* @__PURE__ */ jsx(SelectItem, { value: String(n), children: n }, n)) })
11288
- ]
11289
- }
11290
- )
11291
- ] })
11292
- ] }),
11293
- /* @__PURE__ */ jsxs("p", { className: "mt-2 text-[10px] text-muted-foreground", children: [
11294
- "Bands: 0\u20137 mild \xB7 8\u201319 moderate \xB7 20\u201335 severe.",
11295
- " ",
11296
- /* @__PURE__ */ jsx("span", { className: "font-semibold text-foreground", children: "IPSS \u2265 20 \u2192 consider surgical intervention." })
11297
- ] })
11298
- ]
11299
- }
11300
- ) : null,
11301
- showHaem ? /* @__PURE__ */ jsxs(Panel2, { title: "Haematuria profile", children: [
11302
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-3 text-xs md:grid-cols-4", children: [
11303
- /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
11304
- /* @__PURE__ */ jsx(
11305
- Checkbox,
11306
- {
11307
- checked: safe.haematuria.present,
11308
- onCheckedChange: (c) => update({
11309
- ...safe,
11310
- haematuria: { ...safe.haematuria, present: c === true }
11311
- }),
11312
- disabled
11313
- }
11314
- ),
11315
- "Present"
11316
- ] }),
11317
- /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1", children: [
11318
- /* @__PURE__ */ jsx("span", { className: "font-medium", children: "Timing" }),
11319
- /* @__PURE__ */ jsxs(
11320
- Select,
11321
- {
11322
- value: safe.haematuria.timing || "none",
11323
- onValueChange: (val) => update({
11324
- ...safe,
11325
- haematuria: { ...safe.haematuria, timing: val === "none" ? "" : val }
11326
- }),
11327
- disabled,
11328
- children: [
11329
- /* @__PURE__ */ jsx(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "\u2014" }) }),
11330
- /* @__PURE__ */ jsxs(SelectContent, { children: [
11331
- /* @__PURE__ */ jsx(SelectItem, { value: "none", children: "\u2014" }),
11332
- /* @__PURE__ */ jsx(SelectItem, { value: "Initial", children: "Initial" }),
11333
- /* @__PURE__ */ jsx(SelectItem, { value: "Terminal", children: "Terminal" }),
11334
- /* @__PURE__ */ jsx(SelectItem, { value: "Total", children: "Total" })
11335
- ] })
11336
- ]
11337
- }
11338
- )
11339
- ] }),
11340
- /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
11341
- /* @__PURE__ */ jsx(
11342
- Checkbox,
11343
- {
11344
- checked: safe.haematuria.painful,
11345
- onCheckedChange: (c) => update({ ...safe, haematuria: { ...safe.haematuria, painful: c === true } }),
11346
- disabled
11347
- }
11348
- ),
11349
- "Painful"
11350
- ] }),
11351
- /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
11352
- /* @__PURE__ */ jsx(
11353
- Checkbox,
11354
- {
11355
- checked: safe.haematuria.clots,
11356
- onCheckedChange: (c) => update({ ...safe, haematuria: { ...safe.haematuria, clots: c === true } }),
11357
- disabled
11358
- }
11359
- ),
11360
- "Clots"
11361
- ] })
11362
- ] }),
11363
- /* @__PURE__ */ jsx("p", { className: "mt-2 text-[10px] text-red-600", children: "Painless haematuria = malignancy until proven otherwise." })
11364
- ] }) : null,
11365
- showSex ? /* @__PURE__ */ jsx(Panel2, { title: "Sexual & reproductive history", children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-3 text-xs md:grid-cols-4", children: [
11366
- /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1", children: [
11367
- /* @__PURE__ */ jsx("span", { className: "font-medium", children: "Erectile function" }),
11368
- /* @__PURE__ */ jsxs(
11369
- Select,
11370
- {
11371
- value: safe.sexual.erectile || "none",
11372
- onValueChange: (val) => update({
11373
- ...safe,
11374
- sexual: { ...safe.sexual, erectile: val === "none" ? "" : val }
11375
- }),
11376
- disabled,
11377
- children: [
11378
- /* @__PURE__ */ jsx(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "\u2014" }) }),
11379
- /* @__PURE__ */ jsxs(SelectContent, { children: [
11380
- /* @__PURE__ */ jsx(SelectItem, { value: "none", children: "\u2014" }),
11381
- /* @__PURE__ */ jsx(SelectItem, { value: "Normal", children: "Normal" }),
11382
- /* @__PURE__ */ jsx(SelectItem, { value: "Mild", children: "Mild" }),
11383
- /* @__PURE__ */ jsx(SelectItem, { value: "Moderate", children: "Moderate" }),
11384
- /* @__PURE__ */ jsx(SelectItem, { value: "Severe", children: "Severe" })
11385
- ] })
11386
- ]
11387
- }
11388
- )
11389
- ] }),
11390
- /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1", children: [
11391
- /* @__PURE__ */ jsx("span", { className: "font-medium", children: "Libido" }),
11392
- /* @__PURE__ */ jsxs(
11393
- Select,
11394
- {
11395
- value: safe.sexual.libido || "none",
11396
- onValueChange: (val) => update({
11397
- ...safe,
11398
- sexual: { ...safe.sexual, libido: val === "none" ? "" : val }
11399
- }),
11400
- disabled,
11401
- children: [
11402
- /* @__PURE__ */ jsx(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "\u2014" }) }),
11403
- /* @__PURE__ */ jsxs(SelectContent, { children: [
11404
- /* @__PURE__ */ jsx(SelectItem, { value: "none", children: "\u2014" }),
11405
- /* @__PURE__ */ jsx(SelectItem, { value: "Normal", children: "Normal" }),
11406
- /* @__PURE__ */ jsx(SelectItem, { value: "Reduced", children: "Reduced" })
11407
- ] })
11408
- ]
11409
- }
11410
- )
11411
- ] }),
11412
- /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1", children: [
11413
- /* @__PURE__ */ jsx("span", { className: "font-medium", children: "Ejaculation" }),
11414
- /* @__PURE__ */ jsxs(
11415
- Select,
11416
- {
11417
- value: safe.sexual.ejaculation || "none",
11418
- onValueChange: (val) => update({
11419
- ...safe,
11420
- sexual: { ...safe.sexual, ejaculation: val === "none" ? "" : val }
11421
- }),
11422
- disabled,
11423
- children: [
11424
- /* @__PURE__ */ jsx(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "\u2014" }) }),
11425
- /* @__PURE__ */ jsxs(SelectContent, { children: [
11426
- /* @__PURE__ */ jsx(SelectItem, { value: "none", children: "\u2014" }),
11427
- /* @__PURE__ */ jsx(SelectItem, { value: "Normal", children: "Normal" }),
11428
- /* @__PURE__ */ jsx(SelectItem, { value: "Premature", children: "Premature" }),
11429
- /* @__PURE__ */ jsx(SelectItem, { value: "Retrograde", children: "Retrograde" }),
11430
- /* @__PURE__ */ jsx(SelectItem, { value: "Anejaculation", children: "Anejaculation" })
11431
- ] })
11432
- ]
11433
- }
11434
- )
11435
- ] }),
11436
- /* @__PURE__ */ jsxs("label", { className: "flex flex-col gap-1", children: [
11437
- /* @__PURE__ */ jsx("span", { className: "font-medium", children: "Infertility (months)" }),
11438
- /* @__PURE__ */ jsx(
11439
- Input,
11440
- {
11441
- type: "number",
11442
- min: 0,
11443
- className: "h-8 text-xs",
11444
- value: safe.sexual.infertilityMonths,
11445
- onChange: (e) => update({
11446
- ...safe,
11447
- sexual: {
11448
- ...safe.sexual,
11449
- infertilityMonths: Math.max(0, Math.round(Number(e.target.value)) || 0)
11450
- }
11451
- }),
11452
- disabled
11453
- }
11454
- )
11455
- ] })
11456
- ] }) }) : null,
11457
- /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
11458
- /* @__PURE__ */ jsx(Label, { className: "text-xs font-medium text-slate-700", children: "Past history (stones / surgeries / drugs)" }),
11459
- /* @__PURE__ */ jsx(
11460
- Textarea,
11461
- {
11462
- className: "min-h-[72px] rounded-md border border-input bg-white text-sm",
11463
- placeholder: "Prior calculi, urological surgeries, anticoagulants, DM/HTN\u2026",
11464
- value: safe.pastNotes,
11465
- onChange: (e) => update({ ...safe, pastNotes: e.target.value }),
11466
- disabled
11467
- }
11468
- )
11469
- ] })
11470
- ] }),
11471
- showError ? /* @__PURE__ */ jsx("p", { className: "px-3 pb-2 text-xs text-red-500", children: error }) : null
11472
- ] });
11473
- };
11474
- var GENERAL_ROWS = [
11475
- { key: "pallor", label: "Pallor (chronic dz)" },
11476
- { key: "oedema", label: "Oedema (renal)" },
11477
- { key: "icterus", label: "Icterus" },
11478
- { key: "lymphadenopathy", label: "Lymphadenopathy" }
11479
- ];
11480
- var ABD_ROWS = [
11481
- { key: "distension", label: "Distension" },
11482
- { key: "scars", label: "Surgical scars" },
11483
- { key: "mass", label: "Visible mass" },
11484
- { key: "kidneyPalpable", label: "Kidney palpable" },
11485
- { key: "bladderPalpable", label: "Bladder palpable" },
11486
- { key: "renalAngleTender", label: "Renal angle tender" },
11487
- { key: "bladderDull", label: "Bladder dullness (retention)" }
11488
- ];
11489
- var GU_ROWS = [
11490
- { key: "meatusAbnormal", label: "Meatus abnormal (hypospadias?)" },
11491
- { key: "phimosis", label: "Phimosis / paraphimosis" },
11492
- { key: "lesions", label: "Penile lesions / ulcers" },
11493
- { key: "scrotalSwelling", label: "Scrotal swelling" },
11494
- { key: "transilluminant", label: "Transilluminant" },
11495
- { key: "tenderTestis", label: "Tender testis" },
11496
- { key: "hydrocele", label: "Hydrocele" },
11497
- { key: "varicocele", label: "Varicocele" },
11498
- { key: "suspiciousMass", label: "Suspicious mass" }
11499
- ];
11500
- var DRE_CONSISTENCY = ["none", "Soft (benign)", "Firm", "Hard / nodular (malignancy?)"];
11501
- var DRE_SULCUS = ["none", "Preserved", "Obliterated"];
11502
- var UrologyExaminationWidget = ({ fieldId }) => {
11503
- const { fieldDef, value, setValue, setTouched, error, touched, disabled } = useField(fieldId);
11504
- const { state } = useForm();
11505
- const showError = !!error && (touched || state.submitAttempted);
11506
- const safe = useMemo(() => normalizeUrologyExamination(value), [value]);
11507
- const update = (next) => {
11508
- setValue(next);
11509
- setTouched();
11510
- };
11511
- const toggleGeneral = (key) => {
11512
- update({ ...safe, general: { ...safe.general, [key]: !safe.general[key] } });
11513
- };
11514
- const toggleAbdomen = (key) => {
11515
- update({ ...safe, abdomen: { ...safe.abdomen, [key]: !safe.abdomen[key] } });
11516
- };
11517
- const toggleGu = (key) => {
11518
- update({ ...safe, gu: { ...safe.gu, [key]: !safe.gu[key] } });
11519
- };
11520
- if (!fieldDef) return null;
11521
- const theme = getThemeConfig("textarea", fieldDef.theme);
11522
- const wrapperClass = theme?.wrapperClassName ?? "rounded-md overflow-hidden flex flex-col border border-[#D0D0D0]";
11523
- const labelClass = theme?.labelClassName;
11524
- const labelContent = /* @__PURE__ */ jsxs(Fragment, { children: [
11525
- fieldDef.label,
11526
- fieldDef.required ? /* @__PURE__ */ jsx("span", { className: "ml-1 text-red-500", children: "*" }) : null
11527
- ] });
11528
- const labelEl = theme ? /* @__PURE__ */ jsx(Label, { className: labelClass, children: labelContent }) : /* @__PURE__ */ jsx(Label, { className: "text-sm font-medium", children: labelContent });
11529
- const bodyClass = cn(
11530
- "-mt-1 flex min-w-0 flex-col gap-3 border-t border-[#D0D0D0] bg-white px-3 py-3",
11531
- disabled && "pointer-events-none opacity-60"
11532
- );
11533
- return /* @__PURE__ */ jsxs("div", { className: cn("w-full min-w-0", wrapperClass), children: [
11534
- labelEl,
11535
- /* @__PURE__ */ jsxs("div", { className: bodyClass, children: [
11536
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-3 text-xs md:grid-cols-2 xl:grid-cols-4", children: [
11537
- /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
11538
- /* @__PURE__ */ jsx("p", { className: "font-semibold text-slate-800", children: "General" }),
11539
- GENERAL_ROWS.map((r) => /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
11540
- /* @__PURE__ */ jsx(
11541
- Checkbox,
11542
- {
11543
- checked: safe.general[r.key],
11544
- onCheckedChange: () => toggleGeneral(r.key),
11545
- disabled
11546
- }
11547
- ),
11548
- r.label
11549
- ] }, r.key))
11550
- ] }),
11551
- /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
11552
- /* @__PURE__ */ jsx("p", { className: "font-semibold text-slate-800", children: "Abdomen" }),
11553
- ABD_ROWS.map((r) => /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
11554
- /* @__PURE__ */ jsx(
11555
- Checkbox,
11556
- {
11557
- checked: safe.abdomen[r.key],
11558
- onCheckedChange: () => toggleAbdomen(r.key),
11559
- disabled
11560
- }
11561
- ),
11562
- r.label
11563
- ] }, r.key))
11564
- ] }),
11565
- /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
11566
- /* @__PURE__ */ jsx("p", { className: "font-semibold text-slate-800", children: "External genitalia / scrotum" }),
11567
- GU_ROWS.map((r) => /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
11568
- /* @__PURE__ */ jsx(
11569
- Checkbox,
11570
- {
11571
- checked: safe.gu[r.key],
11572
- onCheckedChange: () => toggleGu(r.key),
11573
- disabled
11574
- }
11575
- ),
11576
- r.key === "suspiciousMass" ? /* @__PURE__ */ jsx("span", { className: "font-medium text-red-600", children: r.label }) : r.label
11577
- ] }, r.key))
11578
- ] }),
11579
- /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
11580
- /* @__PURE__ */ jsx("p", { className: "font-semibold text-slate-800", children: "DRE \u2014 Prostate" }),
11581
- /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
11582
- /* @__PURE__ */ jsx(
11583
- Checkbox,
11584
- {
11585
- checked: safe.dre.done,
11586
- onCheckedChange: (c) => update({ ...safe, dre: { ...safe.dre, done: c === true } }),
11587
- disabled
11588
- }
11589
- ),
11590
- "DRE performed"
11591
- ] }),
11592
- /* @__PURE__ */ jsxs("label", { className: "block", children: [
11593
- /* @__PURE__ */ jsx("span", { className: "mb-1 block font-medium", children: "Estimated size (g)" }),
11594
- /* @__PURE__ */ jsx(
11595
- Input,
11596
- {
11597
- type: "number",
11598
- min: 0,
11599
- className: "h-8 text-xs",
11600
- value: safe.dre.sizeGrams,
11601
- onChange: (e) => {
11602
- const n = Number(e.target.value);
11603
- update({
11604
- ...safe,
11605
- dre: {
11606
- ...safe.dre,
11607
- sizeGrams: Number.isFinite(n) && n >= 0 ? Math.round(n) : 0
11608
- }
11609
- });
11610
- },
11611
- disabled
11612
- }
11613
- )
11614
- ] }),
11615
- /* @__PURE__ */ jsxs("label", { className: "block", children: [
11616
- /* @__PURE__ */ jsx("span", { className: "mb-1 block font-medium", children: "Consistency" }),
11617
- /* @__PURE__ */ jsxs(
11618
- Select,
11619
- {
11620
- value: safe.dre.consistency || "none",
11621
- onValueChange: (val) => update({
11622
- ...safe,
11623
- dre: { ...safe.dre, consistency: val === "none" ? "" : val }
11624
- }),
11625
- disabled,
11626
- children: [
11627
- /* @__PURE__ */ jsx(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "\u2014" }) }),
11628
- /* @__PURE__ */ jsx(SelectContent, { children: DRE_CONSISTENCY.map((opt) => /* @__PURE__ */ jsx(SelectItem, { value: opt, children: opt === "none" ? "\u2014" : opt }, opt)) })
11629
- ]
11630
- }
11631
- )
11632
- ] }),
11633
- /* @__PURE__ */ jsxs("label", { className: "block", children: [
11634
- /* @__PURE__ */ jsx("span", { className: "mb-1 block font-medium", children: "Median sulcus" }),
11635
- /* @__PURE__ */ jsxs(
11636
- Select,
11637
- {
11638
- value: safe.dre.medianSulcus || "none",
11639
- onValueChange: (val) => update({
11640
- ...safe,
11641
- dre: { ...safe.dre, medianSulcus: val === "none" ? "" : val }
11642
- }),
11643
- disabled,
11644
- children: [
11645
- /* @__PURE__ */ jsx(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "\u2014" }) }),
11646
- /* @__PURE__ */ jsx(SelectContent, { children: DRE_SULCUS.map((opt) => /* @__PURE__ */ jsx(SelectItem, { value: opt, children: opt === "none" ? "\u2014" : opt }, opt)) })
11647
- ]
11648
- }
11649
- )
11650
- ] }),
11651
- /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
11652
- /* @__PURE__ */ jsx(
11653
- Checkbox,
11654
- {
11655
- checked: safe.dre.tenderness,
11656
- onCheckedChange: (c) => update({ ...safe, dre: { ...safe.dre, tenderness: c === true } }),
11657
- disabled
11658
- }
11659
- ),
11660
- "Tender (prostatitis?)"
11661
- ] })
11662
- ] })
11663
- ] }),
11664
- /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
11665
- /* @__PURE__ */ jsx(Label, { className: "text-xs font-semibold text-slate-700", children: "Examination notes" }),
11666
- /* @__PURE__ */ jsx(
11667
- Textarea,
11668
- {
11669
- className: "min-h-[88px] rounded-md border border-input bg-white text-sm",
11670
- placeholder: "Free-text exam findings\u2026",
11671
- value: safe.examinationNotes,
11672
- onChange: (e) => update({ ...safe, examinationNotes: e.target.value }),
11673
- disabled
11674
- }
11675
- )
11676
- ] })
11677
- ] }),
11678
- showError ? /* @__PURE__ */ jsx("p", { className: "px-3 pb-2 text-xs text-red-500", children: error }) : null
11679
- ] });
11680
- };
11681
- var SMART_HISTORY_FIELD = "uro_smart_history";
11682
- var EXAMINATION_FIELD = "uro_examination";
11683
- var DRE_HARD = "Hard / nodular (malignancy?)";
11684
- function Panel3({
11685
- title,
11686
- className,
11687
- children
11688
- }) {
11689
- return /* @__PURE__ */ jsxs("div", { className: cn("overflow-hidden rounded-md border border-[#D0D0D0] bg-white", className), children: [
11690
- /* @__PURE__ */ jsx("div", { className: "border-b border-[#D0D0D0] bg-[#FEE8EC]/50 px-3 py-1.5", children: /* @__PURE__ */ jsx("span", { className: "text-xs font-semibold text-slate-700", children: title }) }),
11691
- /* @__PURE__ */ jsx("div", { className: "p-3", children })
11692
- ] });
11693
- }
11694
- var UrologyPathwayWidget = ({ fieldId }) => {
11695
- const { fieldDef, value, setValue, setTouched, error, touched, disabled } = useField(fieldId);
11696
- const { state } = useForm();
11697
- const showError = !!error && (touched || state.submitAttempted);
11698
- const safe = useMemo(() => normalizeUrologyPathway(value), [value]);
11699
- const smart = useMemo(
11700
- () => normalizeUrologySmartHistory(state.values[SMART_HISTORY_FIELD]),
11701
- [state.values]
11702
- );
11703
- const exam = useMemo(
11704
- () => normalizeUrologyExamination(state.values[EXAMINATION_FIELD]),
11705
- [state.values]
11706
- );
11707
- const ipssTotal = urologyIpssSevenTotal(smart.ipss);
11708
- const ipssBandCls = ipssTotal >= 20 ? "bg-red-500/15 text-red-700" : ipssTotal >= 8 ? "bg-amber-500/15 text-amber-900" : "bg-emerald-500/15 text-emerald-800";
11709
- const stone = useMemo(
11710
- () => urologyStoneRecommendation(safe.stoneSizeMm, safe.hydronephrosis),
11711
- [safe.stoneSizeMm, safe.hydronephrosis]
11712
- );
11713
- const prostateLine = useMemo(
11714
- () => urologyProstateProcedure(safe.prostateVolumeCc),
11715
- [safe.prostateVolumeCc]
11716
- );
11717
- const psaHigh = safe.psaNgMl > 4;
11718
- const qmaxLow = safe.uroflowQmaxMlSec > 0 && Number.isFinite(safe.uroflowQmaxMlSec) && safe.uroflowQmaxMlSec < 10;
11719
- const update = (next) => {
11720
- setValue(next);
11721
- setTouched();
11722
- };
11723
- const setRisk = (key, next) => {
11724
- update({ ...safe, risk: { ...safe.risk, [key]: next } });
11725
- };
11726
- if (!fieldDef) return null;
11727
- const theme = getThemeConfig("textarea", fieldDef.theme);
11728
- const wrapperClass = theme?.wrapperClassName ?? "rounded-md overflow-hidden flex flex-col border border-[#D0D0D0]";
11729
- const labelClass = theme?.labelClassName;
11730
- const labelContent = /* @__PURE__ */ jsxs(Fragment, { children: [
11731
- fieldDef.label,
11732
- fieldDef.required ? /* @__PURE__ */ jsx("span", { className: "ml-1 text-red-500", children: "*" }) : null
11733
- ] });
11734
- const labelEl = theme ? /* @__PURE__ */ jsx(Label, { className: labelClass, children: labelContent }) : /* @__PURE__ */ jsx(Label, { className: "text-sm font-medium", children: labelContent });
11735
- const bodyClass = cn(
11736
- "-mt-1 flex min-w-0 flex-col gap-3 border-t border-[#D0D0D0] bg-white px-3 py-3",
11737
- disabled && "pointer-events-none opacity-60"
11738
- );
11739
- const subtitle = typeof fieldDef.meta?.subtitle === "string" && fieldDef.meta.subtitle.trim().length > 0 ? fieldDef.meta.subtitle.trim() : "";
11740
- return /* @__PURE__ */ jsxs("div", { className: cn("w-full min-w-0", wrapperClass), children: [
11741
- labelEl,
11742
- /* @__PURE__ */ jsxs("div", { className: bodyClass, children: [
11743
- subtitle ? /* @__PURE__ */ jsx("p", { className: "-mt-0.5 mb-0 text-xs font-semibold tracking-wide text-slate-700", children: subtitle }) : null,
11744
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-3 text-xs md:grid-cols-2 xl:grid-cols-4", children: [
11745
- /* @__PURE__ */ jsxs(Panel3, { title: "Stone disease", children: [
11746
- /* @__PURE__ */ jsxs("label", { className: "block", children: [
11747
- /* @__PURE__ */ jsx("span", { className: "mb-1 block font-medium text-slate-700", children: "Stone size (mm)" }),
11748
- /* @__PURE__ */ jsx(
11749
- Input,
11750
- {
11751
- type: "number",
11752
- min: 0,
11753
- step: "any",
11754
- className: cn(
11755
- "h-8 text-xs",
11756
- disabled && "pointer-events-none"
11757
- ),
11758
- value: safe.stoneSizeMm,
11759
- onChange: (e) => {
11760
- const raw = e.target.value;
11761
- const n = Number(raw);
11762
- update({
11763
- ...safe,
11764
- stoneSizeMm: raw === "" || raw === "-" ? 0 : !Number.isFinite(n) ? 0 : Math.max(0, n)
11765
- });
11766
- },
11767
- disabled
11768
- }
11769
- )
11770
- ] }),
11771
- /* @__PURE__ */ jsxs("label", { className: "mt-2 flex items-center gap-2", children: [
11772
- /* @__PURE__ */ jsx(
11773
- Checkbox,
11774
- {
11775
- checked: safe.hydronephrosis,
11776
- disabled,
11777
- onCheckedChange: (checked) => update({ ...safe, hydronephrosis: checked === true })
11778
- }
11779
- ),
11780
- /* @__PURE__ */ jsx("span", { className: "text-slate-700", children: "Hydronephrosis on imaging" })
11781
- ] }),
11782
- /* @__PURE__ */ jsx(
11783
- "div",
11784
- {
11785
- className: cn(
11786
- "mt-2 rounded p-2 text-[11px]",
11787
- stone.surgical && safe.stoneSizeMm > 0 ? "bg-red-500/10 text-red-800" : safe.stoneSizeMm > 0 ? "bg-emerald-500/10 text-emerald-900" : "bg-muted/40 text-muted-foreground"
11788
- ),
11789
- children: stone.plan
11790
- }
11791
- ),
11792
- /* @__PURE__ */ jsx("p", { className: "mt-1 text-[10px] text-muted-foreground", children: "Trigger: >10 mm OR obstruction \u2192 surgical." })
11793
- ] }),
11794
- /* @__PURE__ */ jsxs(Panel3, { title: "Prostate / BPH", children: [
11795
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2", children: [
11796
- /* @__PURE__ */ jsxs("label", { className: "block", children: [
11797
- /* @__PURE__ */ jsx("span", { className: "mb-1 block font-medium text-slate-700", children: "Volume (cc)" }),
11798
- /* @__PURE__ */ jsx(
11799
- Input,
11800
- {
11801
- type: "number",
11802
- min: 0,
11803
- step: "any",
11804
- className: cn(
11805
- "h-8 text-xs",
11806
- disabled && "pointer-events-none"
11807
- ),
11808
- value: safe.prostateVolumeCc,
11809
- onChange: (e) => {
11810
- const raw = e.target.value;
11811
- const n = Number(raw);
11812
- update({
11813
- ...safe,
11814
- prostateVolumeCc: raw === "" || raw === "-" ? 0 : !Number.isFinite(n) ? 0 : Math.max(0, n)
11815
- });
11816
- },
11817
- disabled
11818
- }
11819
- )
11820
- ] }),
11821
- /* @__PURE__ */ jsxs("label", { className: "block", children: [
11822
- /* @__PURE__ */ jsx("span", { className: "mb-1 block font-medium text-slate-700", children: "PSA (ng/ml)" }),
11823
- /* @__PURE__ */ jsx(
11824
- Input,
11825
- {
11826
- type: "number",
11827
- min: 0,
11828
- step: 0.1,
11829
- className: cn(
11830
- "h-8 text-xs",
11831
- psaHigh && "border-red-400 text-red-800",
11832
- disabled && "pointer-events-none"
11833
- ),
11834
- value: safe.psaNgMl,
11835
- onChange: (e) => {
11836
- const raw = e.target.value;
11837
- const n = Number(raw);
11838
- update({
11839
- ...safe,
11840
- psaNgMl: raw === "" || raw === "-" ? 0 : !Number.isFinite(n) ? 0 : Math.max(0, n)
11841
- });
11842
- },
11843
- disabled
11844
- }
11845
- )
11846
- ] }),
11847
- /* @__PURE__ */ jsxs("label", { className: "col-span-2 block", children: [
11848
- /* @__PURE__ */ jsx("span", { className: "mb-1 block font-medium text-slate-700", children: "Uroflow Qmax (ml/s)" }),
11849
- /* @__PURE__ */ jsx(
11850
- Input,
11851
- {
11852
- type: "number",
11853
- min: 0,
11854
- step: 0.1,
11855
- className: cn(
11856
- "h-8 text-xs",
11857
- qmaxLow && "border-amber-500 text-amber-900",
11858
- disabled && "pointer-events-none"
11859
- ),
11860
- value: safe.uroflowQmaxMlSec,
11861
- onChange: (e) => {
11862
- const raw = e.target.value;
11863
- const n = Number(raw);
11864
- update({
11865
- ...safe,
11866
- uroflowQmaxMlSec: raw === "" || raw === "-" ? 0 : !Number.isFinite(n) ? 0 : Math.max(0, n)
11867
- });
11868
- },
11869
- disabled
11870
- }
11871
- )
11872
- ] })
11873
- ] }),
11874
- /* @__PURE__ */ jsx(
11875
- "div",
11876
- {
11877
- className: cn(
11878
- "mt-2 rounded p-2 text-[11px]",
11879
- safe.prostateVolumeCc > 30 ? "bg-amber-500/10 text-amber-900" : safe.prostateVolumeCc > 0 ? "bg-emerald-500/10 text-emerald-900" : "bg-muted/40 text-muted-foreground"
11880
- ),
11881
- children: prostateLine
11882
- }
11883
- ),
11884
- /* @__PURE__ */ jsx("p", { className: "mt-1 text-[10px] text-muted-foreground", children: "<30 cc medical \xB7 30\u201380 cc TURP \xB7 >80 cc HoLEP/Open" })
11885
- ] }),
11886
- /* @__PURE__ */ jsxs(Panel3, { title: "IPSS & cues", children: [
11887
- /* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center justify-between", children: [
11888
- /* @__PURE__ */ jsx("span", { className: "text-slate-700", children: "IPSS total" }),
11889
- /* @__PURE__ */ jsxs("span", { className: `rounded-full px-2 py-0.5 text-[11px] font-semibold ${ipssBandCls}`, children: [
11890
- ipssTotal,
11891
- "/35 \xB7 ",
11892
- urologyIpssBand(ipssTotal)
11893
- ] })
11894
- ] }),
11895
- /* @__PURE__ */ jsx("div", { className: "mb-3 h-1.5 overflow-hidden rounded-full bg-slate-200", children: /* @__PURE__ */ jsx(
11896
- "div",
11897
- {
11898
- className: cn(
11899
- "h-full transition-[width]",
11900
- ipssTotal >= 20 ? "bg-red-500" : ipssTotal >= 8 ? "bg-amber-500" : "bg-emerald-500"
11901
- ),
11902
- style: { width: `${Math.min(100, ipssTotal / 35 * 100)}%` }
11903
- }
11904
- ) }),
11905
- /* @__PURE__ */ jsxs("p", { className: "mb-3 text-[10px] text-muted-foreground", children: [
11906
- "From smart history (",
11907
- /* @__PURE__ */ jsx("span", { className: "font-mono text-foreground", children: SMART_HISTORY_FIELD }),
11908
- "). \u226520 \u2192 consider surgical intervention."
11909
- ] }),
11910
- /* @__PURE__ */ jsxs("div", { className: "space-y-1.5 text-[11px]", children: [
11911
- smart.haematuria.present && !smart.haematuria.painful ? /* @__PURE__ */ jsx("div", { className: "rounded bg-red-500/10 p-1.5 text-red-800", children: "Painless haematuria \u2014 mandatory cystoscopy" }) : null,
11912
- psaHigh ? /* @__PURE__ */ jsx("div", { className: "rounded bg-amber-500/10 p-1.5 text-amber-900", children: "PSA >4 \u2014 workup for Ca prostate" }) : null,
11913
- exam.dre.consistency === DRE_HARD ? /* @__PURE__ */ jsxs("div", { className: "rounded bg-red-500/10 p-1.5 text-red-800", children: [
11914
- "Hard / nodular prostate (",
11915
- /* @__PURE__ */ jsx("span", { className: "font-mono", children: EXAMINATION_FIELD }),
11916
- ") \u2014 biopsy pathway"
11917
- ] }) : null,
11918
- exam.gu.suspiciousMass ? /* @__PURE__ */ jsx("div", { className: "rounded bg-red-500/10 p-1.5 text-red-800", children: "Suspicious scrotal mass \u2014 urgent surgical eval" }) : null
11919
- ] })
11920
- ] }),
11921
- /* @__PURE__ */ jsx(Panel3, { title: "Risk stratification", children: /* @__PURE__ */ jsx("div", { className: "space-y-2", children: [
11922
- ["ckd", "CKD"],
11923
- ["diabetes", "Diabetes"],
11924
- ["anticoagulants", "Anticoagulants"],
11925
- ["activeInfection", "Active infection"]
11926
- ].map(([key, lab]) => /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2", children: [
11927
- /* @__PURE__ */ jsx(
11928
- Checkbox,
11929
- {
11930
- checked: safe.risk[key],
11931
- disabled,
11932
- onCheckedChange: (c) => setRisk(key, c === true)
11933
- }
11934
- ),
11935
- /* @__PURE__ */ jsx("span", { className: "text-slate-700", children: lab })
11936
- ] }, key)) }) })
11937
- ] })
11938
- ] }),
11939
- showError ? /* @__PURE__ */ jsx("p", { className: "px-3 pb-2 text-xs text-red-500", children: error }) : null
11940
- ] });
11941
- };
11942
- var FieldRenderer = ({ fieldId }) => {
11943
- const { fieldDef, visible } = useField(fieldId);
11944
- if (!visible || !fieldDef) {
11945
- return null;
11946
- }
11947
- return renderWidget(fieldId, fieldDef);
11948
- };
11949
- function renderWidget(fieldId, fieldDef) {
11950
- switch (fieldDef.type) {
11951
- case "text":
11952
- case "number":
11953
- return /* @__PURE__ */ jsx(TextWidget, { fieldId });
11954
- case "slider":
11955
- return /* @__PURE__ */ jsx(SliderWidget, { fieldId });
11956
- case "textarea":
11957
- if (fieldMetaRequestsMarMedicationOrdersButton(fieldDef.meta)) {
11958
- return /* @__PURE__ */ jsx(MarMedicationOrdersWidget, { fieldId });
11959
- }
11960
- return /* @__PURE__ */ jsx(TextWidget, { fieldId });
11961
- case "richtext":
11962
- return /* @__PURE__ */ jsx(RichTextWidget, { fieldId });
11963
- case "date":
11964
- return /* @__PURE__ */ jsx(DateWidget, { fieldId });
11965
- case "datetime":
11966
- return /* @__PURE__ */ jsx(DateTimeWidget, { fieldId });
11967
- case "select":
11968
- return /* @__PURE__ */ jsx(SelectWidget, { fieldId });
11969
- case "radio":
11970
- return /* @__PURE__ */ jsx(RadioWidget, { fieldId });
11971
- case "checkbox":
11972
- return /* @__PURE__ */ jsx(CheckboxWidget, { fieldId });
11973
- case "multiselect":
11974
- return /* @__PURE__ */ jsx(MultiSelectWidget, { fieldId });
11975
- case "repeatable":
11976
- return /* @__PURE__ */ jsx(RepeatableWidget, { fieldId });
11977
- case "image_upload":
11978
- return /* @__PURE__ */ jsx(ImageUploadWidget, { fieldId });
11979
- case "media_upload":
11980
- return /* @__PURE__ */ jsx(MediaUploadWidget, { fieldId });
11981
- case "signature":
11982
- return /* @__PURE__ */ jsx(SignatureUploadWidget, { fieldId });
11983
- case "editable_table":
11984
- return /* @__PURE__ */ jsx(EditableTableWidget, { fieldId });
11985
- case "medications":
11986
- return /* @__PURE__ */ jsx(AddMedicationWidget, { fieldId });
11987
- case "discharge_medication_orders":
11988
- return /* @__PURE__ */ jsx(DischargeMedicationOrdersWidget, { fieldId });
11989
- case "investigations":
11990
- return /* @__PURE__ */ jsx(AddInvestigationWidget, { fieldId });
11991
- case "procedures":
11992
- return /* @__PURE__ */ jsx(AddProcedureWidget, { fieldId });
11993
- case "differential_diagnosis":
11994
- return /* @__PURE__ */ jsx(DifferentialDiagnosisWidget, { fieldId });
11995
- case "vitals":
11996
- return /* @__PURE__ */ jsx(VitalsWidget, { fieldId });
11997
- case "hidden_vitals":
11998
- return /* @__PURE__ */ jsx(HiddenVitalsWidget, { fieldId });
11999
- case "referral":
12000
- return /* @__PURE__ */ jsx(ReferralWidget, { fieldId });
12001
- case "followup":
12002
- return /* @__PURE__ */ jsx(FollowupWidget, { fieldId });
12003
- case "smart_textarea":
12004
- return /* @__PURE__ */ jsx(SmartTextareaWidget, { fieldId });
12005
- case "diagnosis_textarea":
12006
- return /* @__PURE__ */ jsx(DiagnosisTextareaWidget, { fieldId });
12007
- case "obstetric_history":
12008
- return /* @__PURE__ */ jsx(ObstetricHistoryWidget, { fieldId });
12009
- case "eye_prescription":
12010
- return /* @__PURE__ */ jsx(OphthalmologyWidget, { fieldId });
12011
- case "ophthal_diagnosis":
12012
- return /* @__PURE__ */ jsx(OphthalDiagnosisWidget, { fieldId });
12013
- case "orthopedic_exam":
12014
- return /* @__PURE__ */ jsx(OrthopedicExamWidget, { fieldId });
12015
- case "general_surgery_smart_history":
12016
- return /* @__PURE__ */ jsx(GsSmartHistoryWidget, { fieldId });
12017
- case "general_surgery_examination":
12018
- return /* @__PURE__ */ jsx(GsExaminationWidget, { fieldId });
12019
- case "general_surgery_grading":
12020
- return /* @__PURE__ */ jsx(GsGradingWidget, { fieldId });
12021
- case "pain_scale_flags":
12022
- return /* @__PURE__ */ jsx(PainScaleFlagsWidget, { fieldId });
12023
- case "urology_smart_history":
12024
- return /* @__PURE__ */ jsx(UrologySmartHistoryWidget, { fieldId });
12025
- case "urology_examination":
12026
- return /* @__PURE__ */ jsx(UrologyExaminationWidget, { fieldId });
12027
- case "urology_pathway":
12028
- return /* @__PURE__ */ jsx(UrologyPathwayWidget, { fieldId });
12029
- case "toggle": {
12030
- const { value, setValue, setTouched, disabled } = useField(fieldId);
12031
- const store = useFormStore();
12032
- const excludes = fieldDef.excludes ?? [];
12033
- return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
12034
- /* @__PURE__ */ jsx(
12035
- Switch,
12036
- {
12037
- checked: value === true,
12038
- disabled,
12039
- onCheckedChange: (checked) => {
12040
- setValue(checked);
12041
- setTouched();
12042
- if (checked) excludes.forEach((id) => store.setValue(id, false));
12043
- }
12044
- }
12045
- ),
12046
- /* @__PURE__ */ jsx(Label, { className: "text-sm font-medium leading-none cursor-pointer select-none", children: fieldDef.label })
12047
- ] });
10588
+ function renderWidget(fieldId, fieldDef) {
10589
+ switch (fieldDef.type) {
10590
+ case "text":
10591
+ case "number":
10592
+ return /* @__PURE__ */ jsx(TextWidget, { fieldId });
10593
+ case "slider":
10594
+ return /* @__PURE__ */ jsx(SliderWidget, { fieldId });
10595
+ case "textarea":
10596
+ if (fieldMetaRequestsMarMedicationOrdersButton(fieldDef.meta)) {
10597
+ return /* @__PURE__ */ jsx(MarMedicationOrdersWidget, { fieldId });
10598
+ }
10599
+ return /* @__PURE__ */ jsx(TextWidget, { fieldId });
10600
+ case "richtext":
10601
+ return /* @__PURE__ */ jsx(RichTextWidget, { fieldId });
10602
+ case "date":
10603
+ return /* @__PURE__ */ jsx(DateWidget, { fieldId });
10604
+ case "datetime":
10605
+ return /* @__PURE__ */ jsx(DateTimeWidget, { fieldId });
10606
+ case "select":
10607
+ return /* @__PURE__ */ jsx(SelectWidget, { fieldId });
10608
+ case "radio":
10609
+ return /* @__PURE__ */ jsx(RadioWidget, { fieldId });
10610
+ case "checkbox":
10611
+ return /* @__PURE__ */ jsx(CheckboxWidget, { fieldId });
10612
+ case "multiselect":
10613
+ return /* @__PURE__ */ jsx(MultiSelectWidget, { fieldId });
10614
+ case "repeatable":
10615
+ return /* @__PURE__ */ jsx(RepeatableWidget, { fieldId });
10616
+ case "image_upload":
10617
+ return /* @__PURE__ */ jsx(ImageUploadWidget, { fieldId });
10618
+ case "media_upload":
10619
+ return /* @__PURE__ */ jsx(MediaUploadWidget, { fieldId });
10620
+ case "signature":
10621
+ return /* @__PURE__ */ jsx(SignatureUploadWidget, { fieldId });
10622
+ case "editable_table":
10623
+ return /* @__PURE__ */ jsx(EditableTableWidget, { fieldId });
10624
+ case "medications":
10625
+ return /* @__PURE__ */ jsx(AddMedicationWidget, { fieldId });
10626
+ case "discharge_medication_orders":
10627
+ return /* @__PURE__ */ jsx(DischargeMedicationOrdersWidget, { fieldId });
10628
+ case "investigations":
10629
+ return /* @__PURE__ */ jsx(AddInvestigationWidget, { fieldId });
10630
+ case "procedures":
10631
+ return /* @__PURE__ */ jsx(AddProcedureWidget, { fieldId });
10632
+ case "differential_diagnosis":
10633
+ return /* @__PURE__ */ jsx(DifferentialDiagnosisWidget, { fieldId });
10634
+ case "vitals":
10635
+ return /* @__PURE__ */ jsx(VitalsWidget, { fieldId });
10636
+ case "hidden_vitals":
10637
+ return /* @__PURE__ */ jsx(HiddenVitalsWidget, { fieldId });
10638
+ case "referral":
10639
+ return /* @__PURE__ */ jsx(ReferralWidget, { fieldId });
10640
+ case "followup":
10641
+ return /* @__PURE__ */ jsx(FollowupWidget, { fieldId });
10642
+ case "smart_textarea":
10643
+ return /* @__PURE__ */ jsx(SmartTextareaWidget, { fieldId });
10644
+ case "diagnosis_textarea":
10645
+ return /* @__PURE__ */ jsx(DiagnosisTextareaWidget, { fieldId });
10646
+ case "obstetric_history":
10647
+ return /* @__PURE__ */ jsx(ObstetricHistoryWidget, { fieldId });
10648
+ case "eye_prescription":
10649
+ return /* @__PURE__ */ jsx(OphthalmologyWidget, { fieldId });
10650
+ case "ophthal_diagnosis":
10651
+ return /* @__PURE__ */ jsx(OphthalDiagnosisWidget, { fieldId });
10652
+ case "orthopedic_exam":
10653
+ return /* @__PURE__ */ jsx(OrthopedicExamWidget, { fieldId });
10654
+ case "general_surgery_smart_history":
10655
+ return /* @__PURE__ */ jsx(GsSmartHistoryWidget, { fieldId });
10656
+ case "general_surgery_examination":
10657
+ return /* @__PURE__ */ jsx(GsExaminationWidget, { fieldId });
10658
+ case "general_surgery_grading":
10659
+ return /* @__PURE__ */ jsx(GsGradingWidget, { fieldId });
10660
+ case "pain_scale_flags":
10661
+ return /* @__PURE__ */ jsx(PainScaleFlagsWidget, { fieldId });
10662
+ case "toggle": {
10663
+ const { value, setValue, setTouched, disabled } = useField(fieldId);
10664
+ const store = useFormStore();
10665
+ const excludes = fieldDef.excludes ?? [];
10666
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
10667
+ /* @__PURE__ */ jsx(
10668
+ Switch,
10669
+ {
10670
+ checked: value === true,
10671
+ disabled,
10672
+ onCheckedChange: (checked) => {
10673
+ setValue(checked);
10674
+ setTouched();
10675
+ if (checked) excludes.forEach((id) => store.setValue(id, false));
10676
+ }
10677
+ }
10678
+ ),
10679
+ /* @__PURE__ */ jsx(Label, { className: "text-sm font-medium leading-none cursor-pointer select-none", children: fieldDef.label })
10680
+ ] });
12048
10681
  }
12049
10682
  case "suggestion_textarea":
12050
10683
  case "complaint_chips":
@@ -12889,30 +11522,6 @@ var ReadOnlyFieldRenderer = ({
12889
11522
  ].join("\n");
12890
11523
  return /* @__PURE__ */ jsx(ReadOnlyText, { fieldDef, value: lines });
12891
11524
  }
12892
- case "urology_smart_history":
12893
- return /* @__PURE__ */ jsx(
12894
- ReadOnlyText,
12895
- {
12896
- fieldDef,
12897
- value: value && typeof value === "object" ? JSON.stringify(value, null, 2) : value == null || value === "" ? "\u2014" : String(value)
12898
- }
12899
- );
12900
- case "urology_examination":
12901
- return /* @__PURE__ */ jsx(
12902
- ReadOnlyText,
12903
- {
12904
- fieldDef,
12905
- value: value && typeof value === "object" ? JSON.stringify(value, null, 2) : value == null || value === "" ? "\u2014" : String(value)
12906
- }
12907
- );
12908
- case "urology_pathway":
12909
- return /* @__PURE__ */ jsx(
12910
- ReadOnlyText,
12911
- {
12912
- fieldDef,
12913
- value: value && typeof value === "object" ? JSON.stringify(value, null, 2) : value == null || value === "" ? "\u2014" : String(value)
12914
- }
12915
- );
12916
11525
  case "general_surgery_smart_history": {
12917
11526
  const structuredDisplay = value && typeof value === "object" ? JSON.stringify(normalizeGeneralSurgerySmartHistory(value), null, 2) : value == null || value === "" ? "\u2014" : String(value);
12918
11527
  const hopcDef = resolveFieldDef?.("symptoms");
@@ -13154,6 +11763,6 @@ function createUploadHandler(options) {
13154
11763
  };
13155
11764
  }
13156
11765
 
13157
- export { AddInvestigationField, AddMedicationField, DifferentialDiagnosis, DynamicForm, EMAIL_REGEX, FieldRenderer, FormControls, FormProvider, FormStore, ImageUploadWidget, MAR_MEDICATION_ORDERS_META_KEY, MediaUploadWidget, ReadOnlyForm, ReadOnlyImageUpload, ReadOnlyMediaUpload, ReadOnlySignature, ReadOnlyTable, RichTextWidget, SignatureUploadWidget, SmartForm, SmartTextareaWidget, attachUrologyClinicalPathwayMetadata, createUploadHandler, evaluateRules, fieldMetaRequestsMarMedicationOrdersButton, isUrologyTemplate, shouldFoldUrologyClinicalPathway, useField, useFieldHandlers, useForm, useFormStore, useFrequentItems, usePackages, useSmartKeywords, validateField, validateForm };
11766
+ export { AddInvestigationField, AddMedicationField, DifferentialDiagnosis, DynamicForm, EMAIL_REGEX, FieldRenderer, FormControls, FormProvider, FormStore, ImageUploadWidget, MAR_MEDICATION_ORDERS_META_KEY, MediaUploadWidget, ReadOnlyForm, ReadOnlyImageUpload, ReadOnlyMediaUpload, ReadOnlySignature, ReadOnlyTable, RichTextWidget, SignatureUploadWidget, SmartForm, SmartTextareaWidget, createUploadHandler, evaluateRules, fieldMetaRequestsMarMedicationOrdersButton, useField, useFieldHandlers, useForm, useFormStore, useFrequentItems, usePackages, useSmartKeywords, validateField, validateForm };
13158
11767
  //# sourceMappingURL=index.mjs.map
13159
11768
  //# sourceMappingURL=index.mjs.map