formanitor 0.0.39 → 0.0.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -65,6 +65,326 @@ function fieldMetaRequestsMarMedicationOrdersButton(meta) {
65
65
  return meta[MAR_MEDICATION_ORDERS_META_KEY] === true;
66
66
  }
67
67
 
68
+ // src/core/urologyClinicalPathwayMetadata.ts
69
+ function isUrologyTemplate(template) {
70
+ if (!template || typeof template !== "object") return false;
71
+ const t = template;
72
+ return t.meta?.specialization === "urology" || t.specialization === "urology" || t.id === "uro_prescription";
73
+ }
74
+ function shouldFoldUrologyClinicalPathway(template, payload) {
75
+ if (isUrologyTemplate(template)) return true;
76
+ return Object.keys(payload).some(
77
+ (k) => k.startsWith("uro_") || k === "chief_complaints" || k === "chief_complaints_chips"
78
+ );
79
+ }
80
+ var UROLOGY_EXTRA_METADATA_KEYS = ["symptoms", "notes", "vitals"];
81
+ function isUroPlainObject(v) {
82
+ return v !== null && typeof v === "object" && !Array.isArray(v);
83
+ }
84
+ function coerceUrologyBool(value) {
85
+ if (value === true || value === false) return value;
86
+ if (value === "true") return true;
87
+ if (value === "false") return false;
88
+ if (Array.isArray(value)) {
89
+ if (value.includes("yes") || value.includes(true)) return true;
90
+ if (value.length === 0) return false;
91
+ }
92
+ return value;
93
+ }
94
+ function urologyIpssItem(v) {
95
+ const n = Number(v);
96
+ if (!Number.isFinite(n)) return 0;
97
+ return Math.min(5, Math.max(0, Math.round(n)));
98
+ }
99
+ function urologyIpssSevenTotalFromParts(ipss) {
100
+ return ipss.incomplete + ipss.frequency + ipss.intermittency + ipss.urgency + ipss.weakStream + ipss.straining + ipss.nocturia;
101
+ }
102
+ function buildUrologySmartHistoryFromLegacyFlat(flat) {
103
+ return {
104
+ socrates_pain_flank_suprapubic: {
105
+ site: flat.uro_sh_socrates_site,
106
+ onset: flat.uro_sh_socrates_onset,
107
+ character: flat.uro_sh_socrates_character,
108
+ radiation: flat.uro_sh_socrates_radiation,
109
+ associated: flat.uro_sh_socrates_associated,
110
+ timing: flat.uro_sh_socrates_timing,
111
+ exacerbating: flat.uro_sh_socrates_exacerbating,
112
+ severity_0_to_10: flat.uro_sh_socrates_severity
113
+ },
114
+ ipss_international_symptom_score: {
115
+ incomplete_emptying: flat.uro_sh_ipss_incomplete,
116
+ frequency_lt_2h: flat.uro_sh_ipss_frequency,
117
+ intermittency: flat.uro_sh_ipss_intermittency,
118
+ urgency: flat.uro_sh_ipss_urgency,
119
+ weak_stream: flat.uro_sh_ipss_weak_stream,
120
+ straining: flat.uro_sh_ipss_straining,
121
+ nocturia: flat.uro_sh_ipss_nocturia,
122
+ qol_0_to_6: flat.uro_sh_ipss_qol,
123
+ seven_item_total_computed_max_35: flat.uro_sh_ipss_total_display
124
+ },
125
+ haematuria_profile: {
126
+ present: flat.uro_sh_haem_present,
127
+ timing: flat.uro_sh_haem_timing,
128
+ painful: flat.uro_sh_haem_painful,
129
+ clots: flat.uro_sh_haem_clots
130
+ },
131
+ sexual_and_reproductive: {
132
+ erectile_function: flat.uro_sh_sex_erectile,
133
+ libido: flat.uro_sh_sex_libido,
134
+ ejaculation: flat.uro_sh_sex_ejaculation,
135
+ infertility_months: flat.uro_sh_sex_infertility_months
136
+ },
137
+ context_prior_stones_surgery_comorbidity: flat.uro_smart_notes_free ?? ""
138
+ };
139
+ }
140
+ function buildUrologySmartHistoryFromComposite(raw, flat) {
141
+ const soc = isUroPlainObject(raw.socrates) ? raw.socrates : {};
142
+ const ipssIn = isUroPlainObject(raw.ipss) ? raw.ipss : {};
143
+ const haem = isUroPlainObject(raw.haematuria) ? raw.haematuria : {};
144
+ const sex = isUroPlainObject(raw.sexual) ? raw.sexual : {};
145
+ const str2 = (x) => typeof x === "string" ? x : "";
146
+ const sev = Number(soc.severity);
147
+ const severity0to10 = Number.isFinite(sev) ? Math.min(10, Math.max(0, Math.round(sev))) : 0;
148
+ const ipss = {
149
+ incomplete: urologyIpssItem(ipssIn.incomplete),
150
+ frequency: urologyIpssItem(ipssIn.frequency),
151
+ intermittency: urologyIpssItem(ipssIn.intermittency),
152
+ urgency: urologyIpssItem(ipssIn.urgency),
153
+ weakStream: urologyIpssItem(
154
+ ipssIn.weakStream ?? ipssIn.weak_stream
155
+ ),
156
+ straining: urologyIpssItem(ipssIn.straining),
157
+ nocturia: urologyIpssItem(ipssIn.nocturia)
158
+ };
159
+ const sevenTotal = urologyIpssSevenTotalFromParts(ipss);
160
+ const qolRaw = Number(raw.ipssQoL);
161
+ const qol = Number.isFinite(qolRaw) ? Math.min(6, Math.max(0, Math.round(qolRaw))) : 0;
162
+ const timingRaw = str2(haem.timing);
163
+ const pastNotes = str2(raw.pastNotes);
164
+ const legacyNotes = flat.uro_smart_notes_free;
165
+ const contextPrior = pastNotes !== "" ? pastNotes : typeof legacyNotes === "string" ? legacyNotes : legacyNotes ?? "";
166
+ const infertilityRaw = Number(sex.infertilityMonths);
167
+ const infertilityMonths = Number.isFinite(infertilityRaw) ? Math.max(0, Math.round(infertilityRaw)) : 0;
168
+ return {
169
+ socrates_pain_flank_suprapubic: {
170
+ site: str2(soc.site),
171
+ onset: str2(soc.onset),
172
+ character: str2(soc.character),
173
+ radiation: str2(soc.radiation),
174
+ associated: str2(soc.associated),
175
+ timing: str2(soc.timing),
176
+ exacerbating: str2(soc.exacerbating),
177
+ severity_0_to_10: severity0to10
178
+ },
179
+ ipss_international_symptom_score: {
180
+ incomplete_emptying: ipss.incomplete,
181
+ frequency_lt_2h: ipss.frequency,
182
+ intermittency: ipss.intermittency,
183
+ urgency: ipss.urgency,
184
+ weak_stream: ipss.weakStream,
185
+ straining: ipss.straining,
186
+ nocturia: ipss.nocturia,
187
+ qol_0_to_6: qol,
188
+ seven_item_total_computed_max_35: sevenTotal
189
+ },
190
+ haematuria_profile: {
191
+ present: haem.present === true,
192
+ timing: timingRaw,
193
+ painful: haem.painful === true,
194
+ clots: haem.clots === true
195
+ },
196
+ sexual_and_reproductive: {
197
+ erectile_function: str2(sex.erectile),
198
+ libido: str2(sex.libido),
199
+ ejaculation: str2(sex.ejaculation),
200
+ infertility_months: infertilityMonths
201
+ },
202
+ context_prior_stones_surgery_comorbidity: contextPrior
203
+ };
204
+ }
205
+ function buildUrologyExaminationFromLegacyFlat(flat) {
206
+ return {
207
+ general: {
208
+ pallor: flat.uro_ex_general_pallor,
209
+ oedema: flat.uro_ex_general_oedema,
210
+ icterus: flat.uro_ex_general_icterus,
211
+ lymphadenopathy: flat.uro_ex_general_lymph
212
+ },
213
+ abdomen: {
214
+ distension: flat.uro_ex_ab_distension,
215
+ surgical_scars: flat.uro_ex_ab_scars,
216
+ visible_mass: flat.uro_ex_ab_mass,
217
+ kidney_palpable: flat.uro_ex_ab_kidney_palpable,
218
+ bladder_palpable: flat.uro_ex_ab_bladder_palpable,
219
+ renal_angle_tender: flat.uro_ex_ab_renal_angle_tender,
220
+ bladder_dullness_retention: flat.uro_ex_ab_bladder_dull
221
+ },
222
+ external_genitalia_scrotum: {
223
+ meatus_abnormal_hypospadias_query: flat.uro_ex_gu_meatus,
224
+ phimosis_paraphimosis: flat.uro_ex_gu_phimosis,
225
+ penile_lesions_ulcers: flat.uro_ex_gu_lesions,
226
+ scrotal_swelling: flat.uro_ex_gu_scrotal_swelling,
227
+ transilluminant: flat.uro_ex_gu_transilluminant,
228
+ tender_testis: flat.uro_ex_gu_tender_testis,
229
+ hydrocele: flat.uro_ex_gu_hydrocele,
230
+ varicocele: flat.uro_ex_gu_varicocele,
231
+ suspicious_mass_urgent: flat.uro_ex_gu_suspicious_mass
232
+ },
233
+ dre_prostate: {
234
+ dre_performed: flat.uro_ex_dre_done,
235
+ estimated_size_grams: flat.uro_ex_dre_size_g,
236
+ consistency: flat.uro_ex_dre_consistency,
237
+ median_sulcus: flat.uro_ex_dre_median_sulcus,
238
+ tenderness_prostatitis_query: flat.uro_ex_dre_tender
239
+ },
240
+ examination_notes_free_text: flat.uro_examination_notes ?? ""
241
+ };
242
+ }
243
+ function buildUrologyExaminationFromComposite(raw) {
244
+ const regions = Array.isArray(raw.regions) ? raw.regions.filter((x) => typeof x === "string") : [];
245
+ const g = isUroPlainObject(raw.general) ? raw.general : {};
246
+ const ab = isUroPlainObject(raw.abdomen) ? raw.abdomen : {};
247
+ const gu = isUroPlainObject(raw.gu) ? raw.gu : {};
248
+ const dr = isUroPlainObject(raw.dre) ? raw.dre : {};
249
+ const dreConsistency = typeof dr.consistency === "string" ? dr.consistency : "";
250
+ const dreMedian = typeof dr.medianSulcus === "string" ? dr.medianSulcus : typeof dr.median_sulcus === "string" ? dr.median_sulcus : "";
251
+ const sizeG = Number(dr.sizeGrams);
252
+ const sizeGrams = Number.isFinite(sizeG) && sizeG >= 0 ? Math.round(sizeG) : 0;
253
+ const notesRaw = raw.examinationNotes;
254
+ const notes = typeof notesRaw === "string" ? notesRaw : "";
255
+ const bool = (x) => x === true;
256
+ return {
257
+ regions_reviewed: regions,
258
+ general: {
259
+ pallor: bool(g.pallor),
260
+ oedema: bool(g.oedema),
261
+ icterus: bool(g.icterus),
262
+ lymphadenopathy: bool(g.lymphadenopathy)
263
+ },
264
+ abdomen: {
265
+ distension: bool(ab.distension),
266
+ surgical_scars: bool(ab.scars),
267
+ visible_mass: bool(ab.mass),
268
+ kidney_palpable: bool(ab.kidneyPalpable),
269
+ bladder_palpable: bool(ab.bladderPalpable),
270
+ renal_angle_tender: bool(ab.renalAngleTender),
271
+ bladder_dullness_retention: bool(ab.bladderDull)
272
+ },
273
+ external_genitalia_scrotum: {
274
+ meatus_abnormal_hypospadias_query: bool(gu.meatusAbnormal),
275
+ phimosis_paraphimosis: bool(gu.phimosis),
276
+ penile_lesions_ulcers: bool(gu.lesions),
277
+ scrotal_swelling: bool(gu.scrotalSwelling),
278
+ transilluminant: bool(gu.transilluminant),
279
+ tender_testis: bool(gu.tenderTestis),
280
+ hydrocele: bool(gu.hydrocele),
281
+ varicocele: bool(gu.varicocele),
282
+ suspicious_mass_urgent: bool(gu.suspiciousMass)
283
+ },
284
+ dre_prostate: {
285
+ dre_performed: bool(dr.done),
286
+ estimated_size_grams: sizeGrams,
287
+ consistency: dreConsistency === "none" ? "" : dreConsistency,
288
+ median_sulcus: dreMedian === "none" ? "" : dreMedian,
289
+ tenderness_prostatitis_query: bool(dr.tenderness)
290
+ },
291
+ examination_notes_free_text: notes
292
+ };
293
+ }
294
+ function buildUrologyDecisionEngineAndRisk(flat) {
295
+ const comp = flat.uro_pathway;
296
+ if (isUroPlainObject(comp)) {
297
+ const riskIn = isUroPlainObject(comp.risk) ? comp.risk : {};
298
+ return {
299
+ decision_engine: {
300
+ stone_disease: {
301
+ stone_size_mm: comp.stoneSizeMm ?? 0,
302
+ hydronephrosis_on_imaging: coerceUrologyBool(comp.hydronephrosis)
303
+ },
304
+ prostate_bph_flow_lab: {
305
+ prostate_volume_cc: comp.prostateVolumeCc ?? 0,
306
+ psa_ng_ml: comp.psaNgMl ?? 0,
307
+ uroflow_qmax_ml_s: comp.uroflowQmaxMlSec ?? 0
308
+ }
309
+ },
310
+ risk_stratification: {
311
+ ckd: coerceUrologyBool(riskIn.ckd),
312
+ diabetes: coerceUrologyBool(riskIn.diabetes),
313
+ anticoagulants: coerceUrologyBool(riskIn.anticoagulants),
314
+ active_infection: coerceUrologyBool(riskIn.activeInfection)
315
+ }
316
+ };
317
+ }
318
+ return {
319
+ decision_engine: {
320
+ stone_disease: {
321
+ stone_size_mm: flat.uro_stone_size_mm,
322
+ hydronephrosis_on_imaging: coerceUrologyBool(flat.uro_stone_hydronephrosis)
323
+ },
324
+ prostate_bph_flow_lab: {
325
+ prostate_volume_cc: flat.uro_prostate_vol_cc,
326
+ psa_ng_ml: flat.uro_psa_ng_ml,
327
+ uroflow_qmax_ml_s: flat.uro_flow_qmax
328
+ }
329
+ },
330
+ risk_stratification: {
331
+ ckd: coerceUrologyBool(flat.uro_risk_ckd),
332
+ diabetes: coerceUrologyBool(flat.uro_risk_diabetes),
333
+ anticoagulants: coerceUrologyBool(flat.uro_risk_anticoag),
334
+ active_infection: coerceUrologyBool(flat.uro_risk_active_infection)
335
+ }
336
+ };
337
+ }
338
+ function attachUrologyClinicalPathwayMetadata(payload, template) {
339
+ if (!shouldFoldUrologyClinicalPathway(template, payload)) return;
340
+ const extra = UROLOGY_EXTRA_METADATA_KEYS;
341
+ const keys = Object.keys(payload).filter(
342
+ (k) => k.startsWith("uro_") || k === "chief_complaints" || k === "chief_complaints_chips" || extra.includes(k)
343
+ );
344
+ if (keys.length === 0) return;
345
+ const flat = {};
346
+ for (const k of keys) {
347
+ flat[k] = payload[k];
348
+ delete payload[k];
349
+ }
350
+ const triage = flat.uro_triage;
351
+ const chiefComplaints = {
352
+ narrative: flat.chief_complaints ?? "",
353
+ chips: flat.chief_complaints_chips ?? [],
354
+ duration: flat.uro_chief_duration ?? "",
355
+ onset: flat.uro_chief_onset ?? "",
356
+ progression: flat.uro_chief_progression ?? "",
357
+ active_syndrome: flat.uro_active_syndrome ?? ""
358
+ };
359
+ const compositeSh = flat.uro_smart_history;
360
+ const compositeEx = flat.uro_examination;
361
+ const smart_history = isUroPlainObject(compositeSh) ? buildUrologySmartHistoryFromComposite(compositeSh, flat) : buildUrologySmartHistoryFromLegacyFlat(flat);
362
+ const examination = isUroPlainObject(compositeEx) ? buildUrologyExaminationFromComposite(compositeEx) : buildUrologyExaminationFromLegacyFlat(flat);
363
+ const { decision_engine, risk_stratification } = buildUrologyDecisionEngineAndRisk(flat);
364
+ const structured = {
365
+ triage_vas_and_flags: triage ?? null,
366
+ chief_complaint_engine: chiefComplaints,
367
+ smart_history,
368
+ examination,
369
+ pathway_triggers_objective_scores: decision_engine,
370
+ risk_stratification,
371
+ encounter_narrative: {
372
+ symptoms: flat.symptoms ?? "",
373
+ notes: flat.notes ?? "",
374
+ vitals: flat.vitals ?? ""
375
+ }
376
+ };
377
+ const existingMetadata = payload.metadata ?? {};
378
+ const existingPathways = existingMetadata.clinical_pathways ?? {};
379
+ payload.metadata = {
380
+ ...existingMetadata,
381
+ clinical_pathways: {
382
+ ...existingPathways,
383
+ urology: structured
384
+ }
385
+ };
386
+ }
387
+
68
388
  // src/core/validate.ts
69
389
  var EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
70
390
  function validateField(value, field) {
@@ -260,8 +580,21 @@ var defaultGeneralSurgerySmartHistory = () => ({
260
580
  gi: { appetite: "", weightLoss: "", bowelHabits: "", checks: [] },
261
581
  breast: { lumpDuration: "", nippleDischarge: "", checks: [] },
262
582
  ano: { checks: [] },
263
- thyroid: { swellingDuration: "", checks: [] },
264
- systemic: ""
583
+ thyroid: { swellingDuration: "", checks: [] }
584
+ });
585
+ var defaultBreastExamSide = () => ({
586
+ size: "",
587
+ quadrant: "",
588
+ tenderness: "",
589
+ fixity: "",
590
+ skinInvolvement: "",
591
+ consistency: "",
592
+ axillaryNodes: false,
593
+ nippleAreolarComplex: false
594
+ });
595
+ var defaultBreastExaminationBlock = () => ({
596
+ left: defaultBreastExamSide(),
597
+ right: defaultBreastExamSide()
265
598
  });
266
599
  var defaultGeneralSurgeryExamination = () => ({
267
600
  general: [],
@@ -274,7 +607,7 @@ var defaultGeneralSurgeryExamination = () => ({
274
607
  bowelSounds: "none"
275
608
  },
276
609
  hernia: { site: "", reducible: false, coughImpulse: false, tenderness: false },
277
- breast: { lumpSizeCm: "", mobile: false, skinInvolvement: false, axillaryNodes: false },
610
+ breast: defaultBreastExaminationBlock(),
278
611
  thyroid: { size: "", mobileDeglutition: false, nodules: false, cervicalNodes: false },
279
612
  anorectal: { inspection: "", dreDone: false, proctoscopyDone: false, notes: "" },
280
613
  limb: { dilatedVeins: false, ulcer: false, oedema: false }
@@ -370,8 +703,32 @@ function normalizeGeneralSurgerySmartHistory(raw) {
370
703
  thyroid: {
371
704
  swellingDuration: str2(thy.swellingDuration),
372
705
  checks: strArr(thy.checks)
373
- },
374
- systemic: typeof v.systemic === "string" ? v.systemic : d.systemic
706
+ }
707
+ };
708
+ }
709
+ function normalizeBreastExamSide(partial) {
710
+ const e = defaultBreastExamSide();
711
+ const str2 = (x) => typeof x === "string" ? x : "";
712
+ const bool = (x) => x === true;
713
+ if (!partial || typeof partial !== "object") return e;
714
+ const p = partial;
715
+ return {
716
+ size: str2(p.size),
717
+ quadrant: str2(p.quadrant),
718
+ tenderness: str2(p.tenderness),
719
+ fixity: str2(p.fixity),
720
+ skinInvolvement: str2(p.skinInvolvement),
721
+ consistency: str2(p.consistency),
722
+ axillaryNodes: bool(p.axillaryNodes),
723
+ nippleAreolarComplex: bool(p.nippleAreolarComplex)
724
+ };
725
+ }
726
+ function normalizeBreastExaminationBlock(raw) {
727
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return defaultBreastExaminationBlock();
728
+ const br = raw;
729
+ return {
730
+ left: normalizeBreastExamSide(br.left),
731
+ right: normalizeBreastExamSide(br.right)
375
732
  };
376
733
  }
377
734
  function normalizeGeneralSurgeryExamination(raw) {
@@ -404,12 +761,7 @@ function normalizeGeneralSurgeryExamination(raw) {
404
761
  coughImpulse: bool(hb.coughImpulse),
405
762
  tenderness: bool(hb.tenderness)
406
763
  },
407
- breast: {
408
- lumpSizeCm: typeof br.lumpSizeCm === "string" ? br.lumpSizeCm : "",
409
- mobile: bool(br.mobile),
410
- skinInvolvement: bool(br.skinInvolvement),
411
- axillaryNodes: bool(br.axillaryNodes)
412
- },
764
+ breast: normalizeBreastExaminationBlock(br),
413
765
  thyroid: {
414
766
  size: typeof th.size === "string" ? th.size : "",
415
767
  mobileDeglutition: bool(th.mobileDeglutition),
@@ -447,6 +799,486 @@ function gsGradingRowVisible(cond, chips, regions, grade) {
447
799
  if (t.regions.some((r) => regions.includes(r))) return true;
448
800
  return false;
449
801
  }
802
+ var SWELLING_OPT_LABELS = {
803
+ reducible_hernia: "Reducible (hernia)",
804
+ cough_impulse: "Cough impulse",
805
+ skin_changes: "Skin changes"
806
+ };
807
+ var GI_OPT_LABELS = {
808
+ bleeding_pr: "Bleeding PR",
809
+ vomiting: "Vomiting",
810
+ haematemesis: "Haematemesis"
811
+ };
812
+ var BREAST_OPT_LABELS = {
813
+ pain: "Pain",
814
+ fh_ca_breast: "Family history of Ca breast"
815
+ };
816
+ var ANO_OPT_LABELS = {
817
+ pain_defecation: "Pain during defecation",
818
+ bleeding: "Bleeding",
819
+ constipation: "Constipation",
820
+ discharge: "Discharge"
821
+ };
822
+ var THYROID_OPT_LABELS = {
823
+ dysphagia: "Dysphagia",
824
+ voice_change: "Voice change",
825
+ thyrotoxicosis: "Thyrotoxicosis symptoms"
826
+ };
827
+ var SOCRATES_LABELS = {
828
+ site: "Site",
829
+ onset: "Onset",
830
+ character: "Character",
831
+ radiation: "Radiation",
832
+ associated: "Associated",
833
+ timing: "Timing",
834
+ exacerbating: "Exacerbating / relieving"
835
+ };
836
+ var GENERAL_EXAM_LABELS = {
837
+ pallor: "Pallor",
838
+ icterus: "Icterus",
839
+ cyanosis: "Cyanosis",
840
+ clubbing: "Clubbing",
841
+ lymphadenopathy: "Lymphadenopathy",
842
+ oedema: "Oedema"
843
+ };
844
+ var REGION_EXAM_LABELS = {
845
+ abdomen: "Abdomen",
846
+ hernia: "Hernia",
847
+ breast: "Breast",
848
+ thyroid: "Thyroid",
849
+ anorectal: "Anorectal",
850
+ limb: "Limb / varicose"
851
+ };
852
+ var ABD_INSP_LABELS = {
853
+ distension: "Distension",
854
+ scars: "Scars",
855
+ visible_peristalsis: "Visible peristalsis"
856
+ };
857
+ var ABD_PALP_LABELS = {
858
+ tenderness: "Tenderness",
859
+ guarding: "Guarding",
860
+ rigidity: "Rigidity",
861
+ mass: "Palpable mass"
862
+ };
863
+ var ABD_PERC_LABELS = {
864
+ tympany: "Tympany",
865
+ shifting_dullness: "Shifting dullness"
866
+ };
867
+ function trimLine(s) {
868
+ return s.replace(/\s+/g, " ").trim();
869
+ }
870
+ var SK_ORDER = ["site", "onset", "character", "radiation", "associated", "timing", "exacerbating"];
871
+ function formatGeneralSurgerySmartHistoryToNarrative(v, chips) {
872
+ const blocks = [];
873
+ const showPain = chips.includes("pain");
874
+ const showSwelling = chips.includes("swelling_lump");
875
+ const showGI = chips.includes("bleeding") || chips.includes("obstruction");
876
+ const showBreast = chips.includes("breast");
877
+ const showAno = chips.includes("anorectal");
878
+ const showThyroid = chips.includes("thyroid");
879
+ if (showPain) {
880
+ const painLines = [];
881
+ for (const key of SK_ORDER) {
882
+ const raw = v.pain[key];
883
+ if (typeof raw === "string" && raw.trim()) {
884
+ painLines.push(`${SOCRATES_LABELS[key]}: ${trimLine(raw)}`);
885
+ }
886
+ }
887
+ if (v.pain.severity > 0) {
888
+ painLines.push(`Severity (0\u201310): ${v.pain.severity}`);
889
+ }
890
+ if (painLines.length > 0) {
891
+ blocks.push(["SOCRATES \u2014 pain", ...painLines.map((l) => `\u2022 ${l}`)].join("\n"));
892
+ }
893
+ }
894
+ if (showSwelling) {
895
+ const parts = [];
896
+ if (v.swelling.duration.trim()) parts.push(`Duration: ${trimLine(v.swelling.duration)}`);
897
+ if (v.swelling.sizeProgression.trim())
898
+ parts.push(`Size progression: ${trimLine(v.swelling.sizeProgression)}`);
899
+ if (v.swelling.painfulPainless.trim())
900
+ parts.push(`Painful / painless: ${trimLine(v.swelling.painfulPainless)}`);
901
+ for (const c of v.swelling.checks) {
902
+ const lb = SWELLING_OPT_LABELS[c] ?? c;
903
+ parts.push(lb);
904
+ }
905
+ if (parts.length > 0) {
906
+ blocks.push(["Swelling history", ...parts.map((p) => `\u2022 ${p}`)].join("\n"));
907
+ }
908
+ }
909
+ if (showGI) {
910
+ const parts = [];
911
+ if (v.gi.appetite.trim()) parts.push(`Appetite: ${trimLine(v.gi.appetite)}`);
912
+ if (v.gi.weightLoss.trim()) parts.push(`Weight loss: ${trimLine(v.gi.weightLoss)}`);
913
+ if (v.gi.bowelHabits.trim()) parts.push(`Bowel habits: ${trimLine(v.gi.bowelHabits)}`);
914
+ for (const c of v.gi.checks) {
915
+ parts.push(GI_OPT_LABELS[c] ?? c);
916
+ }
917
+ if (parts.length > 0) {
918
+ blocks.push(["GI history", ...parts.map((p) => `\u2022 ${p}`)].join("\n"));
919
+ }
920
+ }
921
+ if (showBreast) {
922
+ const parts = [];
923
+ if (v.breast.lumpDuration.trim()) parts.push(`Lump duration: ${trimLine(v.breast.lumpDuration)}`);
924
+ if (v.breast.nippleDischarge.trim())
925
+ parts.push(`Nipple discharge: ${trimLine(v.breast.nippleDischarge)}`);
926
+ for (const c of v.breast.checks) {
927
+ parts.push(BREAST_OPT_LABELS[c] ?? c);
928
+ }
929
+ if (parts.length > 0) {
930
+ blocks.push(["Breast history", ...parts.map((p) => `\u2022 ${p}`)].join("\n"));
931
+ }
932
+ }
933
+ if (showAno) {
934
+ const parts = [];
935
+ for (const c of v.ano.checks) {
936
+ parts.push(ANO_OPT_LABELS[c] ?? c);
937
+ }
938
+ if (parts.length > 0) {
939
+ blocks.push(["Anorectal history", ...parts.map((p) => `\u2022 ${p}`)].join("\n"));
940
+ }
941
+ }
942
+ if (showThyroid) {
943
+ const parts = [];
944
+ if (v.thyroid.swellingDuration.trim())
945
+ parts.push(`Swelling duration: ${trimLine(v.thyroid.swellingDuration)}`);
946
+ for (const c of v.thyroid.checks) {
947
+ parts.push(THYROID_OPT_LABELS[c] ?? c);
948
+ }
949
+ if (parts.length > 0) {
950
+ blocks.push(["Thyroid history", ...parts.map((p) => `\u2022 ${p}`)].join("\n"));
951
+ }
952
+ }
953
+ return blocks.join("\n\n");
954
+ }
955
+ var BOWEL_SOUND_LABELS = {
956
+ none: "\u2014",
957
+ normal: "Normal",
958
+ up: "Increased (\u2191)",
959
+ down: "Decreased (\u2193)",
960
+ absent: "Absent"
961
+ };
962
+ function formatGeneralSurgeryExaminationToNarrative(v) {
963
+ const blocks = [];
964
+ const generalPositive = v.general.map((k) => GENERAL_EXAM_LABELS[k] ?? k).filter(Boolean);
965
+ if (generalPositive.length > 0) {
966
+ blocks.push(
967
+ ["General examination", ...generalPositive.map((g) => `\u2022 ${g}`)].join("\n")
968
+ );
969
+ }
970
+ if (v.regions.length > 0) {
971
+ const names = v.regions.map((r) => REGION_EXAM_LABELS[r] ?? r);
972
+ blocks.push(`Regional examination: ${names.join(", ")}`);
973
+ }
974
+ if (v.regions.includes("abdomen")) {
975
+ const sub = [];
976
+ const ins = v.abdomen.inspection.map((x) => ABD_INSP_LABELS[x] ?? x);
977
+ const pal = v.abdomen.palpation.map((x) => ABD_PALP_LABELS[x] ?? x);
978
+ const per = v.abdomen.percussion.map((x) => ABD_PERC_LABELS[x] ?? x);
979
+ if (ins.length) sub.push(`Inspection: ${ins.join(", ")}`);
980
+ if (pal.length) sub.push(`Palpation: ${pal.join(", ")}`);
981
+ if (v.abdomen.massNotes.trim()) sub.push(`Mass / mobility: ${trimLine(v.abdomen.massNotes)}`);
982
+ if (per.length) sub.push(`Percussion: ${per.join(", ")}`);
983
+ const bs = BOWEL_SOUND_LABELS[v.abdomen.bowelSounds];
984
+ if (v.abdomen.bowelSounds !== "none") {
985
+ sub.push(`Bowel sounds: ${bs}`);
986
+ }
987
+ if (sub.length > 0) {
988
+ blocks.push(["Abdomen", ...sub.map((s) => `\u2022 ${s}`)].join("\n"));
989
+ }
990
+ }
991
+ if (v.regions.includes("hernia")) {
992
+ const sub = [];
993
+ if (v.hernia.site.trim()) sub.push(`Site: ${trimLine(v.hernia.site)}`);
994
+ if (v.hernia.reducible) sub.push("Reducible");
995
+ if (v.hernia.coughImpulse) sub.push("Cough impulse positive");
996
+ if (v.hernia.tenderness) sub.push("Tenderness");
997
+ if (sub.length > 0) {
998
+ blocks.push(["Hernia", ...sub.map((s) => `\u2022 ${s}`)].join("\n"));
999
+ }
1000
+ }
1001
+ if (v.regions.includes("breast")) {
1002
+ const sub = [];
1003
+ const appendSide = (label, s) => {
1004
+ const lines = [];
1005
+ if (s.size.trim()) lines.push(`Size: ${trimLine(s.size)}`);
1006
+ if (s.quadrant.trim()) lines.push(`Quadrant: ${trimLine(s.quadrant)}`);
1007
+ if (s.tenderness.trim()) lines.push(`Tenderness: ${trimLine(s.tenderness)}`);
1008
+ if (s.fixity.trim()) lines.push(`Fixity: ${trimLine(s.fixity)}`);
1009
+ if (s.skinInvolvement.trim()) lines.push(`Skin involvement: ${trimLine(s.skinInvolvement)}`);
1010
+ if (s.consistency.trim()) lines.push(`Consistency: ${trimLine(s.consistency)}`);
1011
+ if (s.axillaryNodes) lines.push("Axillary nodes");
1012
+ if (s.nippleAreolarComplex) lines.push("Nipple-areolar complex");
1013
+ if (lines.length > 0) {
1014
+ sub.push(`${label}: ${lines.join("; ")}`);
1015
+ }
1016
+ };
1017
+ appendSide("Left breast", v.breast.left);
1018
+ appendSide("Right breast", v.breast.right);
1019
+ if (sub.length > 0) {
1020
+ blocks.push(["Breast", ...sub.map((s) => `\u2022 ${s}`)].join("\n"));
1021
+ }
1022
+ }
1023
+ if (v.regions.includes("thyroid")) {
1024
+ const sub = [];
1025
+ if (v.thyroid.size.trim()) sub.push(`Size: ${trimLine(v.thyroid.size)}`);
1026
+ if (v.thyroid.mobileDeglutition) sub.push("Mobile with deglutition");
1027
+ if (v.thyroid.nodules) sub.push("Nodules");
1028
+ if (v.thyroid.cervicalNodes) sub.push("Cervical lymph nodes");
1029
+ if (sub.length > 0) {
1030
+ blocks.push(["Thyroid", ...sub.map((s) => `\u2022 ${s}`)].join("\n"));
1031
+ }
1032
+ }
1033
+ if (v.regions.includes("anorectal")) {
1034
+ const sub = [];
1035
+ if (v.anorectal.inspection.trim())
1036
+ sub.push(`Inspection: ${trimLine(v.anorectal.inspection)}`);
1037
+ if (v.anorectal.dreDone) sub.push("DRE done");
1038
+ if (v.anorectal.proctoscopyDone) sub.push("Proctoscopy done");
1039
+ if (v.anorectal.notes.trim()) sub.push(`DRE / proctoscopy notes: ${trimLine(v.anorectal.notes)}`);
1040
+ if (sub.length > 0) {
1041
+ blocks.push(["Anorectal", ...sub.map((s) => `\u2022 ${s}`)].join("\n"));
1042
+ }
1043
+ }
1044
+ if (v.regions.includes("limb")) {
1045
+ const sub = [];
1046
+ if (v.limb.dilatedVeins) sub.push("Dilated veins");
1047
+ if (v.limb.ulcer) sub.push("Ulcer");
1048
+ if (v.limb.oedema) sub.push("Oedema");
1049
+ if (sub.length > 0) {
1050
+ blocks.push(["Limb / varicose", ...sub.map((s) => `\u2022 ${s}`)].join("\n"));
1051
+ }
1052
+ }
1053
+ return blocks.join("\n\n");
1054
+ }
1055
+
1056
+ // src/core/urologyPathway.ts
1057
+ var defaultUrologySmartHistory = () => ({
1058
+ socrates: {
1059
+ site: "",
1060
+ onset: "",
1061
+ character: "",
1062
+ radiation: "",
1063
+ associated: "",
1064
+ timing: "",
1065
+ exacerbating: "",
1066
+ severity: 0
1067
+ },
1068
+ ipss: {
1069
+ incomplete: 0,
1070
+ frequency: 0,
1071
+ intermittency: 0,
1072
+ urgency: 0,
1073
+ weakStream: 0,
1074
+ straining: 0,
1075
+ nocturia: 0
1076
+ },
1077
+ ipssQoL: 0,
1078
+ haematuria: { present: false, timing: "", painful: false, clots: false },
1079
+ sexual: { erectile: "", libido: "", ejaculation: "", infertilityMonths: 0 },
1080
+ pastNotes: ""
1081
+ });
1082
+ var defaultUrologyExamination = () => ({
1083
+ regions: [],
1084
+ general: { pallor: false, oedema: false, icterus: false, lymphadenopathy: false },
1085
+ abdomen: {
1086
+ distension: false,
1087
+ scars: false,
1088
+ mass: false,
1089
+ kidneyPalpable: false,
1090
+ bladderPalpable: false,
1091
+ renalAngleTender: false,
1092
+ bladderDull: false
1093
+ },
1094
+ gu: {
1095
+ meatusAbnormal: false,
1096
+ phimosis: false,
1097
+ lesions: false,
1098
+ scrotalSwelling: false,
1099
+ transilluminant: false,
1100
+ tenderTestis: false,
1101
+ hydrocele: false,
1102
+ varicocele: false,
1103
+ suspiciousMass: false
1104
+ },
1105
+ dre: { done: false, sizeGrams: 0, consistency: "", medianSulcus: "", tenderness: false },
1106
+ examinationNotes: ""
1107
+ });
1108
+ function clampInt(n, lo, hi) {
1109
+ if (!Number.isFinite(n)) return lo;
1110
+ return Math.min(hi, Math.max(lo, Math.round(n)));
1111
+ }
1112
+ var SOCRATES_KEYS = [
1113
+ "site",
1114
+ "onset",
1115
+ "character",
1116
+ "radiation",
1117
+ "associated",
1118
+ "timing",
1119
+ "exacerbating"
1120
+ ];
1121
+ function urologyIpssSevenTotal(ipss) {
1122
+ return ipss.incomplete + ipss.frequency + ipss.intermittency + ipss.urgency + ipss.weakStream + ipss.straining + ipss.nocturia;
1123
+ }
1124
+ function urologyIpssBand(total) {
1125
+ if (total <= 7) return "Mild";
1126
+ if (total <= 19) return "Moderate";
1127
+ return "Severe";
1128
+ }
1129
+ function normalizeUrologySmartHistory(raw) {
1130
+ const d = defaultUrologySmartHistory();
1131
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return d;
1132
+ const v = raw;
1133
+ const socIn = v.socrates && typeof v.socrates === "object" ? v.socrates : {};
1134
+ const socrates = { ...d.socrates };
1135
+ for (const k of SOCRATES_KEYS) {
1136
+ const x = socIn[k];
1137
+ socrates[k] = typeof x === "string" ? x : "";
1138
+ }
1139
+ const sev = Number(socIn.severity);
1140
+ socrates.severity = clampInt(Number.isFinite(sev) ? sev : d.socrates.severity, 0, 10);
1141
+ const ipIn = v.ipss && typeof v.ipss === "object" ? v.ipss : {};
1142
+ const ipss = { ...d.ipss };
1143
+ for (const k of [
1144
+ "incomplete",
1145
+ "frequency",
1146
+ "intermittency",
1147
+ "urgency",
1148
+ "weakStream",
1149
+ "straining",
1150
+ "nocturia"
1151
+ ]) {
1152
+ const n = Number(ipIn[k]);
1153
+ ipss[k] = clampInt(Number.isFinite(n) ? n : 0, 0, 5);
1154
+ }
1155
+ const qol = Number(v.ipssQoL);
1156
+ const ipssQoL = clampInt(Number.isFinite(qol) ? qol : d.ipssQoL, 0, 6);
1157
+ const haIn = v.haematuria && typeof v.haematuria === "object" ? v.haematuria : {};
1158
+ const timingRaw = haIn.timing;
1159
+ const haematuria = {
1160
+ present: haIn.present === true,
1161
+ timing: typeof timingRaw === "string" && timingRaw !== "none" && timingRaw.length > 0 ? timingRaw : "",
1162
+ painful: haIn.painful === true,
1163
+ clots: haIn.clots === true
1164
+ };
1165
+ const sxIn = v.sexual && typeof v.sexual === "object" ? v.sexual : {};
1166
+ const str2 = (x) => typeof x === "string" && x.length > 0 && x !== "none" ? x : "";
1167
+ const inf = Number(sxIn.infertilityMonths);
1168
+ const sexual = {
1169
+ erectile: str2(sxIn.erectile),
1170
+ libido: str2(sxIn.libido),
1171
+ ejaculation: str2(sxIn.ejaculation),
1172
+ infertilityMonths: Number.isFinite(inf) && inf >= 0 ? Math.round(inf) : 0
1173
+ };
1174
+ const pastNotes = typeof v.pastNotes === "string" ? v.pastNotes : d.pastNotes;
1175
+ return { socrates, ipss, ipssQoL, haematuria, sexual, pastNotes };
1176
+ }
1177
+ function normalizeUrologyExamination(raw) {
1178
+ const d = defaultUrologyExamination();
1179
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return d;
1180
+ const v = raw;
1181
+ const strArr = (x) => Array.isArray(x) ? x.filter((i) => typeof i === "string") : [];
1182
+ const bool = (x) => x === true;
1183
+ const g = v.general && typeof v.general === "object" ? v.general : {};
1184
+ const ab = v.abdomen && typeof v.abdomen === "object" ? v.abdomen : {};
1185
+ const gu = v.gu && typeof v.gu === "object" ? v.gu : {};
1186
+ const dr = v.dre && typeof v.dre === "object" ? v.dre : {};
1187
+ const sg = Number(dr.sizeGrams);
1188
+ const consistencyRaw = dr.consistency;
1189
+ const medianRaw = dr.medianSulcus;
1190
+ const dreEmpty = (x) => !(typeof x === "string" && x.length > 0 && x !== "none");
1191
+ return {
1192
+ regions: strArr(v.regions),
1193
+ general: {
1194
+ pallor: bool(g.pallor),
1195
+ oedema: bool(g.oedema),
1196
+ icterus: bool(g.icterus),
1197
+ lymphadenopathy: bool(g.lymphadenopathy)
1198
+ },
1199
+ abdomen: {
1200
+ distension: bool(ab.distension),
1201
+ scars: bool(ab.scars),
1202
+ mass: bool(ab.mass),
1203
+ kidneyPalpable: bool(ab.kidneyPalpable),
1204
+ bladderPalpable: bool(ab.bladderPalpable),
1205
+ renalAngleTender: bool(ab.renalAngleTender),
1206
+ bladderDull: bool(ab.bladderDull)
1207
+ },
1208
+ gu: {
1209
+ meatusAbnormal: bool(gu.meatusAbnormal),
1210
+ phimosis: bool(gu.phimosis),
1211
+ lesions: bool(gu.lesions),
1212
+ scrotalSwelling: bool(gu.scrotalSwelling),
1213
+ transilluminant: bool(gu.transilluminant),
1214
+ tenderTestis: bool(gu.tenderTestis),
1215
+ hydrocele: bool(gu.hydrocele),
1216
+ varicocele: bool(gu.varicocele),
1217
+ suspiciousMass: bool(gu.suspiciousMass)
1218
+ },
1219
+ dre: {
1220
+ done: bool(dr.done),
1221
+ sizeGrams: Number.isFinite(sg) && sg >= 0 ? Math.round(sg) : 0,
1222
+ consistency: dreEmpty(consistencyRaw) ? "" : String(consistencyRaw),
1223
+ medianSulcus: dreEmpty(medianRaw) ? "" : String(medianRaw),
1224
+ tenderness: bool(dr.tenderness)
1225
+ },
1226
+ examinationNotes: typeof v.examinationNotes === "string" ? v.examinationNotes : d.examinationNotes
1227
+ };
1228
+ }
1229
+ var defaultUrologyPathway = () => ({
1230
+ stoneSizeMm: 0,
1231
+ hydronephrosis: false,
1232
+ prostateVolumeCc: 0,
1233
+ psaNgMl: 0,
1234
+ uroflowQmaxMlSec: 0,
1235
+ risk: {
1236
+ ckd: false,
1237
+ diabetes: false,
1238
+ anticoagulants: false,
1239
+ activeInfection: false
1240
+ }
1241
+ });
1242
+ function clampNonNegativeNumber(x, fallback) {
1243
+ const n = Number(x);
1244
+ if (!Number.isFinite(n) || n < 0) return fallback;
1245
+ return n;
1246
+ }
1247
+ function normalizeUrologyPathway(raw) {
1248
+ const d = defaultUrologyPathway();
1249
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return d;
1250
+ const v = raw;
1251
+ const rIn = v.risk && typeof v.risk === "object" && !Array.isArray(v.risk) ? v.risk : {};
1252
+ return {
1253
+ stoneSizeMm: clampNonNegativeNumber(v.stoneSizeMm, d.stoneSizeMm),
1254
+ hydronephrosis: v.hydronephrosis === true,
1255
+ prostateVolumeCc: clampNonNegativeNumber(v.prostateVolumeCc, d.prostateVolumeCc),
1256
+ psaNgMl: clampNonNegativeNumber(v.psaNgMl, d.psaNgMl),
1257
+ uroflowQmaxMlSec: clampNonNegativeNumber(v.uroflowQmaxMlSec, d.uroflowQmaxMlSec),
1258
+ risk: {
1259
+ ckd: rIn.ckd === true,
1260
+ diabetes: rIn.diabetes === true,
1261
+ anticoagulants: rIn.anticoagulants === true,
1262
+ activeInfection: rIn.activeInfection === true
1263
+ }
1264
+ };
1265
+ }
1266
+ function urologyStoneRecommendation(sizeMm, hydronephrosis) {
1267
+ if (sizeMm <= 0) return { plan: "Enter stone size to auto-trigger plan.", surgical: false };
1268
+ if (sizeMm < 5) return { plan: "Conservative + MET (\u03B1-blocker), hydration", surgical: false };
1269
+ if (sizeMm <= 10)
1270
+ return {
1271
+ plan: hydronephrosis ? "URS / SWL \u2014 obstruction present" : "Medical expulsive therapy / URS",
1272
+ surgical: hydronephrosis
1273
+ };
1274
+ return { plan: "URS / PCNL \u2014 surgical clearance indicated", surgical: true };
1275
+ }
1276
+ function urologyProstateProcedure(volumeCc) {
1277
+ if (volumeCc <= 0) return "Enter prostate volume.";
1278
+ if (volumeCc < 30) return "Medical (\u03B1-blocker \xB1 5-ARI)";
1279
+ if (volumeCc <= 80) return "TURP";
1280
+ return "HoLEP / Open simple prostatectomy";
1281
+ }
450
1282
 
451
1283
  // src/core/painScaleFlags.ts
452
1284
  function normalizePainScaleFlags(raw, bounds) {
@@ -566,6 +1398,12 @@ var FormStore = class {
566
1398
  f.defaultValue ?? { pain: f.min ?? 0, flags: [] },
567
1399
  { min: f.min, max: f.max }
568
1400
  );
1401
+ } else if (field.type === "urology_smart_history") {
1402
+ values[field.id] = field.defaultValue ?? defaultUrologySmartHistory();
1403
+ } else if (field.type === "urology_examination") {
1404
+ values[field.id] = field.defaultValue ?? defaultUrologyExamination();
1405
+ } else if (field.type === "urology_pathway") {
1406
+ values[field.id] = field.defaultValue ?? defaultUrologyPathway();
569
1407
  } else values[field.id] = null;
570
1408
  }
571
1409
  });
@@ -775,6 +1613,7 @@ var FormStore = class {
775
1613
  }
776
1614
  }
777
1615
  });
1616
+ attachUrologyClinicalPathwayMetadata(result, this.schema);
778
1617
  return result;
779
1618
  }
780
1619
  // --- Core Logic ---
@@ -5747,7 +6586,7 @@ function safeJsonParse(val) {
5747
6586
  return null;
5748
6587
  }
5749
6588
  }
5750
- function clampInt(val, min, max) {
6589
+ function clampInt2(val, min, max) {
5751
6590
  if (!Number.isFinite(val)) return min;
5752
6591
  return Math.max(min, Math.min(max, Math.trunc(val)));
5753
6592
  }
@@ -5757,10 +6596,10 @@ function parseLegacyString(input) {
5757
6596
  if (gpalMatch) {
5758
6597
  const [, g, p, a, l] = gpalMatch;
5759
6598
  result.gpal = {
5760
- G: clampInt(Number(g), 0, 20),
5761
- P: clampInt(Number(p), 0, 20),
5762
- A: clampInt(Number(a), 0, 20),
5763
- L: clampInt(Number(l), 0, 20)
6599
+ G: clampInt2(Number(g), 0, 20),
6600
+ P: clampInt2(Number(p), 0, 20),
6601
+ A: clampInt2(Number(a), 0, 20),
6602
+ L: clampInt2(Number(l), 0, 20)
5764
6603
  };
5765
6604
  }
5766
6605
  const lmpMatch = input.match(/LMP:\s*([^\n]+)/i);
@@ -5793,10 +6632,10 @@ function normalizeToDraft(value) {
5793
6632
  isNewEntry: false,
5794
6633
  draft: {
5795
6634
  gpal: {
5796
- G: clampInt(Number(gpal.G ?? 0), 0, 20),
5797
- P: clampInt(Number(gpal.P ?? 0), 0, 20),
5798
- A: clampInt(Number(gpal.A ?? 0), 0, 20),
5799
- L: clampInt(Number(gpal.L ?? 0), 0, 20)
6635
+ G: clampInt2(Number(gpal.G ?? 0), 0, 20),
6636
+ P: clampInt2(Number(gpal.P ?? 0), 0, 20),
6637
+ A: clampInt2(Number(gpal.A ?? 0), 0, 20),
6638
+ L: clampInt2(Number(gpal.L ?? 0), 0, 20)
5800
6639
  },
5801
6640
  lmp: typeof lmp === "string" ? lmp : "",
5802
6641
  is_pregnant,
@@ -5814,10 +6653,10 @@ function normalizeToDraft(value) {
5814
6653
  }
5815
6654
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
5816
6655
  const gpalFromFlat = {
5817
- G: clampInt(Number(parsed.G ?? parsed.g ?? 0), 0, 20),
5818
- P: clampInt(Number(parsed.P ?? parsed.p ?? 0), 0, 20),
5819
- A: clampInt(Number(parsed.A ?? parsed.a ?? 0), 0, 20),
5820
- L: clampInt(Number(parsed.L ?? parsed.l ?? 0), 0, 20)
6656
+ G: clampInt2(Number(parsed.G ?? parsed.g ?? 0), 0, 20),
6657
+ P: clampInt2(Number(parsed.P ?? parsed.p ?? 0), 0, 20),
6658
+ A: clampInt2(Number(parsed.A ?? parsed.a ?? 0), 0, 20),
6659
+ L: clampInt2(Number(parsed.L ?? parsed.l ?? 0), 0, 20)
5821
6660
  };
5822
6661
  return {
5823
6662
  isNewEntry: false,
@@ -5969,7 +6808,7 @@ var ObstetricHistoryWidget = ({ fieldId }) => {
5969
6808
  const sanitizeGpalInput = (raw) => {
5970
6809
  const digits = raw.replace(/[^\d]/g, "").slice(0, 2);
5971
6810
  if (!digits) return 0;
5972
- return clampInt(Number(digits), 0, 20);
6811
+ return clampInt2(Number(digits), 0, 20);
5973
6812
  };
5974
6813
  const handleGpalChange = (key, raw) => {
5975
6814
  const prevWasEmpty = draft.gpal[key] === 0 && activeGpalKey === key;
@@ -6669,7 +7508,11 @@ var OphthalmologyWidget = ({ fieldId }) => {
6669
7508
  ] })
6670
7509
  ] }),
6671
7510
  /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
6672
- /* @__PURE__ */ jsxRuntime.jsx("td", { className: refractionLabelCellClass, children: "Current Glass" }),
7511
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: `${refractionLabelCellClass} whitespace-normal`, children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "block leading-tight", children: [
7512
+ "Current",
7513
+ /* @__PURE__ */ jsxRuntime.jsx("br", {}),
7514
+ "Glass"
7515
+ ] }) }),
6673
7516
  /* @__PURE__ */ jsxRuntime.jsx("td", { className: refractionDataCellClass, children: /* @__PURE__ */ jsxRuntime.jsx(
6674
7517
  Input,
6675
7518
  {
@@ -6924,12 +7767,12 @@ var OphthalmologyWidget = ({ fieldId }) => {
6924
7767
  /* @__PURE__ */ jsxRuntime.jsx("th", { className: refractionHeaderCellClass, children: "Sph" }),
6925
7768
  /* @__PURE__ */ jsxRuntime.jsx("th", { className: refractionHeaderCellClass, children: "Cyl" }),
6926
7769
  /* @__PURE__ */ jsxRuntime.jsx("th", { className: refractionHeaderCellClass, children: "Axis" }),
6927
- /* @__PURE__ */ jsxRuntime.jsx("th", { className: refractionHeaderCellClass, children: "V/A" }),
7770
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: refractionHeaderCellClass, children: "BCVA" }),
6928
7771
  /* @__PURE__ */ jsxRuntime.jsx("th", { className: refractionHeaderCellClass, children: "P/D" }),
6929
7772
  /* @__PURE__ */ jsxRuntime.jsx("th", { className: refractionHeaderCellClass, children: "Sph" }),
6930
7773
  /* @__PURE__ */ jsxRuntime.jsx("th", { className: refractionHeaderCellClass, children: "Cyl" }),
6931
7774
  /* @__PURE__ */ jsxRuntime.jsx("th", { className: refractionHeaderCellClass, children: "Axis" }),
6932
- /* @__PURE__ */ jsxRuntime.jsx("th", { className: refractionHeaderCellClass, children: "V/A" }),
7775
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: refractionHeaderCellClass, children: "BCVA" }),
6933
7776
  /* @__PURE__ */ jsxRuntime.jsx("th", { className: refractionHeaderCellClass, children: "P/D" })
6934
7777
  ] })
6935
7778
  ] }),
@@ -9267,6 +10110,7 @@ var SliderWidget = ({ fieldId }) => {
9267
10110
  ] });
9268
10111
  };
9269
10112
  var CHIEF_CHIPS_FIELD = "chief_complaints_chips";
10113
+ var GS_SYMPTOMS_FIELD = "symptoms";
9270
10114
  var SWELLING_OPTS = [
9271
10115
  { value: "reducible_hernia", label: "Reducible (hernia)" },
9272
10116
  { value: "cough_impulse", label: "Cough impulse" },
@@ -9292,7 +10136,7 @@ var THYROID_OPTS = [
9292
10136
  { value: "voice_change", label: "Voice change" },
9293
10137
  { value: "thyrotoxicosis", label: "Thyrotoxicosis symptoms" }
9294
10138
  ];
9295
- var SOCRATES_KEYS = [
10139
+ var SOCRATES_KEYS2 = [
9296
10140
  "site",
9297
10141
  "onset",
9298
10142
  "character",
@@ -9307,16 +10151,26 @@ function Panel({ title, children }) {
9307
10151
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-3", children })
9308
10152
  ] });
9309
10153
  }
9310
- function chipList(state) {
9311
- const raw = state.values[CHIEF_CHIPS_FIELD];
10154
+ function chipListFromRaw(raw) {
9312
10155
  return Array.isArray(raw) ? raw.filter((x) => typeof x === "string") : [];
9313
10156
  }
9314
10157
  var GsSmartHistoryWidget = ({ fieldId }) => {
9315
10158
  const { fieldDef, value, setValue, setTouched, error, touched, disabled } = useField(fieldId);
10159
+ const hopcField = useField(GS_SYMPTOMS_FIELD);
9316
10160
  const { state } = useForm();
9317
10161
  const showError = !!error && (touched || state.submitAttempted);
9318
10162
  const safe = React15.useMemo(() => normalizeGeneralSurgerySmartHistory(value), [value]);
9319
- const chips = React15.useMemo(() => chipList(state), [state]);
10163
+ const chiefChipsRaw = state.values[CHIEF_CHIPS_FIELD];
10164
+ const chips = React15.useMemo(() => chipListFromRaw(chiefChipsRaw), [chiefChipsRaw]);
10165
+ const [hopcNarrativeLocked, setHopcNarrativeLocked] = React15.useState(false);
10166
+ React15.useEffect(() => {
10167
+ if (hopcNarrativeLocked) return;
10168
+ const next = formatGeneralSurgerySmartHistoryToNarrative(
10169
+ normalizeGeneralSurgerySmartHistory(value),
10170
+ chips
10171
+ );
10172
+ hopcField.setValue(next);
10173
+ }, [value, chips, hopcNarrativeLocked]);
9320
10174
  const showPain = chips.includes("pain");
9321
10175
  const showSwelling = chips.includes("swelling_lump");
9322
10176
  const showGI = chips.includes("bleeding") || chips.includes("obstruction");
@@ -9376,7 +10230,7 @@ var GsSmartHistoryWidget = ({ fieldId }) => {
9376
10230
  labelEl,
9377
10231
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: bodyClass, children: [
9378
10232
  showPain ? /* @__PURE__ */ jsxRuntime.jsx(Panel, { title: "SOCRATES \u2014 pain", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-2 md:grid-cols-4", children: [
9379
- SOCRATES_KEYS.map((k) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
10233
+ SOCRATES_KEYS2.map((k) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
9380
10234
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-medium uppercase tracking-wide text-muted-foreground", children: k }),
9381
10235
  /* @__PURE__ */ jsxRuntime.jsx(
9382
10236
  Input,
@@ -9582,15 +10436,51 @@ var GsSmartHistoryWidget = ({ fieldId }) => {
9582
10436
  ] }, o.value)) })
9583
10437
  ] }) : null,
9584
10438
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
9585
- /* @__PURE__ */ jsxRuntime.jsx(Label, { className: "text-xs font-medium text-slate-700", children: "Systemic surgical screening" }),
10439
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [
10440
+ /* @__PURE__ */ jsxRuntime.jsx(Label, { className: "text-xs font-semibold text-slate-700", children: hopcField.fieldDef?.label ?? "History of presenting complaint" }),
10441
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
10442
+ hopcNarrativeLocked ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "rounded bg-amber-50 px-1.5 py-0.5 text-[10px] font-medium text-amber-900 ring-1 ring-amber-200/80", children: [
10443
+ "You edited this summary. Use",
10444
+ " ",
10445
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "italic", children: "'Regenerate'" }),
10446
+ " ",
10447
+ "to update it from the form."
10448
+ ] }) : null,
10449
+ hopcNarrativeLocked ? /* @__PURE__ */ jsxRuntime.jsx(
10450
+ Button,
10451
+ {
10452
+ type: "button",
10453
+ variant: "outline",
10454
+ size: "sm",
10455
+ className: "h-7 shrink-0 px-2 text-xs",
10456
+ disabled: disabled || hopcField.disabled,
10457
+ onClick: () => {
10458
+ setHopcNarrativeLocked(false);
10459
+ hopcField.setValue(
10460
+ formatGeneralSurgerySmartHistoryToNarrative(
10461
+ normalizeGeneralSurgerySmartHistory(value),
10462
+ chips
10463
+ )
10464
+ );
10465
+ },
10466
+ children: "Regenerate"
10467
+ }
10468
+ ) : null
10469
+ ] })
10470
+ ] }),
10471
+ hopcNarrativeLocked ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[10px] text-muted-foreground", children: "Edit this box anytime. Use Regenerate to replace with fresh text from the structured fields." }) : null,
9586
10472
  /* @__PURE__ */ jsxRuntime.jsx(
9587
10473
  Textarea,
9588
10474
  {
9589
- className: "min-h-[72px] rounded-md border border-input bg-white text-sm",
9590
- placeholder: "Fever, weight loss, appetite loss, fatigue, malignancy red flags\u2026",
9591
- value: safe.systemic,
9592
- onChange: (e) => update({ ...safe, systemic: e.target.value }),
9593
- disabled
10475
+ className: "min-h-[88px] rounded-md border border-input bg-white text-sm",
10476
+ placeholder: "Onset, progression, associated symptoms, relevant negatives\u2026",
10477
+ value: typeof hopcField.value === "string" ? hopcField.value : hopcField.value == null ? "" : String(hopcField.value),
10478
+ onChange: (e) => {
10479
+ setHopcNarrativeLocked(true);
10480
+ hopcField.setValue(e.target.value);
10481
+ hopcField.setTouched();
10482
+ },
10483
+ disabled: disabled || hopcField.disabled
9594
10484
  }
9595
10485
  )
9596
10486
  ] })
@@ -9642,12 +10532,72 @@ function RegionCard({ title, children }) {
9642
10532
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-3", children })
9643
10533
  ] });
9644
10534
  }
10535
+ var BREAST_TEXT_KEYS = [
10536
+ { key: "size", label: "Size" },
10537
+ { key: "quadrant", label: "Quadrant" },
10538
+ { key: "tenderness", label: "Tenderness" },
10539
+ { key: "fixity", label: "Fixity" },
10540
+ { key: "skinInvolvement", label: "Skin involvement" },
10541
+ { key: "consistency", label: "Consistency" }
10542
+ ];
10543
+ function BreastLumpColumn({
10544
+ title,
10545
+ data,
10546
+ onChange,
10547
+ disabled
10548
+ }) {
10549
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2 rounded-md border border-[#D0D0D0] bg-slate-50/50 p-3", children: [
10550
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[11px] font-semibold uppercase tracking-wide text-muted-foreground", children: title }),
10551
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 gap-2 sm:grid-cols-2", children: BREAST_TEXT_KEYS.map(({ key, label }) => /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "block", children: [
10552
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mb-1 block font-medium", children: label }),
10553
+ /* @__PURE__ */ jsxRuntime.jsx(
10554
+ Input,
10555
+ {
10556
+ className: "h-8 text-xs",
10557
+ value: data[key],
10558
+ onChange: (e) => onChange({ [key]: e.target.value }),
10559
+ disabled
10560
+ }
10561
+ )
10562
+ ] }, key)) }),
10563
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-x-4 gap-y-2 pt-1", children: [
10564
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2", children: [
10565
+ /* @__PURE__ */ jsxRuntime.jsx(
10566
+ Checkbox,
10567
+ {
10568
+ checked: data.axillaryNodes,
10569
+ onCheckedChange: (c) => onChange({ axillaryNodes: c === true }),
10570
+ disabled
10571
+ }
10572
+ ),
10573
+ "Axillary nodes"
10574
+ ] }),
10575
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2", children: [
10576
+ /* @__PURE__ */ jsxRuntime.jsx(
10577
+ Checkbox,
10578
+ {
10579
+ checked: data.nippleAreolarComplex,
10580
+ onCheckedChange: (c) => onChange({ nippleAreolarComplex: c === true }),
10581
+ disabled
10582
+ }
10583
+ ),
10584
+ "Nipple-areolar complex"
10585
+ ] })
10586
+ ] })
10587
+ ] });
10588
+ }
9645
10589
  var GsExaminationWidget = ({ fieldId }) => {
9646
10590
  const { fieldDef, value, setValue, setTouched, error, touched, disabled } = useField(fieldId);
9647
10591
  const clinicalField = useField(GS_CLINICAL_EXAMINATION_FIELD);
9648
10592
  const { state } = useForm();
9649
10593
  const showError = !!error && (touched || state.submitAttempted);
9650
10594
  const safe = React15.useMemo(() => normalizeGeneralSurgeryExamination(value), [value]);
10595
+ const [clinicalNarrativeLocked, setClinicalNarrativeLocked] = React15.useState(false);
10596
+ React15.useEffect(() => {
10597
+ if (clinicalNarrativeLocked) return;
10598
+ const next = formatGeneralSurgeryExaminationToNarrative(normalizeGeneralSurgeryExamination(value));
10599
+ clinicalField.setValue(next);
10600
+ }, [value, clinicalNarrativeLocked]);
9651
10601
  const update = (next) => {
9652
10602
  setValue(next);
9653
10603
  setTouched();
@@ -9839,56 +10789,35 @@ var GsExaminationWidget = ({ fieldId }) => {
9839
10789
  "Tenderness"
9840
10790
  ] })
9841
10791
  ] }) }) : null,
9842
- has("breast") ? /* @__PURE__ */ jsxRuntime.jsx(RegionCard, { title: "Breast exam", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 gap-3 text-xs md:grid-cols-4", children: [
10792
+ has("breast") ? /* @__PURE__ */ jsxRuntime.jsx(RegionCard, { title: "Breast exam", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 gap-4 text-xs md:grid-cols-2", children: [
10793
+ /* @__PURE__ */ jsxRuntime.jsx(
10794
+ BreastLumpColumn,
10795
+ {
10796
+ title: "Left breast",
10797
+ data: safe.breast.left,
10798
+ onChange: (p) => update({
10799
+ ...safe,
10800
+ breast: { ...safe.breast, left: { ...safe.breast.left, ...p } }
10801
+ }),
10802
+ disabled
10803
+ }
10804
+ ),
10805
+ /* @__PURE__ */ jsxRuntime.jsx(
10806
+ BreastLumpColumn,
10807
+ {
10808
+ title: "Right breast",
10809
+ data: safe.breast.right,
10810
+ onChange: (p) => update({
10811
+ ...safe,
10812
+ breast: { ...safe.breast, right: { ...safe.breast.right, ...p } }
10813
+ }),
10814
+ disabled
10815
+ }
10816
+ )
10817
+ ] }) }) : null,
10818
+ has("thyroid") ? /* @__PURE__ */ jsxRuntime.jsx(RegionCard, { title: "Thyroid exam", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 gap-3 text-xs md:grid-cols-4", children: [
9843
10819
  /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "block", children: [
9844
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mb-1 block font-medium", children: "Lump size (cm)" }),
9845
- /* @__PURE__ */ jsxRuntime.jsx(
9846
- Input,
9847
- {
9848
- className: "h-8 text-xs",
9849
- value: safe.breast.lumpSizeCm,
9850
- onChange: (e) => update({ ...safe, breast: { ...safe.breast, lumpSizeCm: e.target.value } }),
9851
- disabled
9852
- }
9853
- )
9854
- ] }),
9855
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2", children: [
9856
- /* @__PURE__ */ jsxRuntime.jsx(
9857
- Checkbox,
9858
- {
9859
- checked: safe.breast.mobile,
9860
- onCheckedChange: (c) => update({ ...safe, breast: { ...safe.breast, mobile: c === true } }),
9861
- disabled
9862
- }
9863
- ),
9864
- "Mobile"
9865
- ] }),
9866
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2", children: [
9867
- /* @__PURE__ */ jsxRuntime.jsx(
9868
- Checkbox,
9869
- {
9870
- checked: safe.breast.skinInvolvement,
9871
- onCheckedChange: (c) => update({ ...safe, breast: { ...safe.breast, skinInvolvement: c === true } }),
9872
- disabled
9873
- }
9874
- ),
9875
- "Skin involvement"
9876
- ] }),
9877
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2", children: [
9878
- /* @__PURE__ */ jsxRuntime.jsx(
9879
- Checkbox,
9880
- {
9881
- checked: safe.breast.axillaryNodes,
9882
- onCheckedChange: (c) => update({ ...safe, breast: { ...safe.breast, axillaryNodes: c === true } }),
9883
- disabled
9884
- }
9885
- ),
9886
- "Axillary nodes"
9887
- ] })
9888
- ] }) }) : null,
9889
- has("thyroid") ? /* @__PURE__ */ jsxRuntime.jsx(RegionCard, { title: "Thyroid exam", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 gap-3 text-xs md:grid-cols-4", children: [
9890
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "block", children: [
9891
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mb-1 block font-medium", children: "Size" }),
10820
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mb-1 block font-medium", children: "Size" }),
9892
10821
  /* @__PURE__ */ jsxRuntime.jsx(
9893
10822
  Input,
9894
10823
  {
@@ -10019,13 +10948,43 @@ var GsExaminationWidget = ({ fieldId }) => {
10019
10948
  ] }) }) : null
10020
10949
  ] }),
10021
10950
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
10022
- /* @__PURE__ */ jsxRuntime.jsx(Label, { className: "text-xs font-semibold text-slate-700", children: clinicalField.fieldDef?.label ?? "Clinical examination" }),
10951
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [
10952
+ /* @__PURE__ */ jsxRuntime.jsx(Label, { className: "text-xs font-semibold text-slate-700", children: clinicalField.fieldDef?.label ?? "Clinical examination" }),
10953
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
10954
+ clinicalNarrativeLocked ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "rounded bg-amber-50 px-1.5 py-0.5 text-[10px] font-medium text-amber-900 ring-1 ring-amber-200/80", children: [
10955
+ "You edited this summary. Use",
10956
+ " ",
10957
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "italic", children: "'Regenerate'" }),
10958
+ " ",
10959
+ "to update it from the form."
10960
+ ] }) : null,
10961
+ clinicalNarrativeLocked ? /* @__PURE__ */ jsxRuntime.jsx(
10962
+ Button,
10963
+ {
10964
+ type: "button",
10965
+ variant: "outline",
10966
+ size: "sm",
10967
+ className: "h-7 shrink-0 px-2 text-xs",
10968
+ disabled: disabled || clinicalField.disabled,
10969
+ onClick: () => {
10970
+ setClinicalNarrativeLocked(false);
10971
+ clinicalField.setValue(
10972
+ formatGeneralSurgeryExaminationToNarrative(normalizeGeneralSurgeryExamination(value))
10973
+ );
10974
+ },
10975
+ children: "Regenerate"
10976
+ }
10977
+ ) : null
10978
+ ] })
10979
+ ] }),
10980
+ clinicalNarrativeLocked ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[10px] text-muted-foreground", children: "Edit this box anytime. Use Regenerate to replace with fresh text from the structured examination." }) : null,
10023
10981
  /* @__PURE__ */ jsxRuntime.jsx(
10024
10982
  Textarea,
10025
10983
  {
10026
10984
  className: "min-h-[88px] rounded-md border border-input bg-white text-sm",
10027
10985
  value: typeof clinicalField.value === "string" ? clinicalField.value : clinicalField.value == null ? "" : String(clinicalField.value),
10028
10986
  onChange: (e) => {
10987
+ setClinicalNarrativeLocked(true);
10029
10988
  clinicalField.setValue(e.target.value);
10030
10989
  clinicalField.setTouched();
10031
10990
  },
@@ -10039,7 +10998,7 @@ var GsExaminationWidget = ({ fieldId }) => {
10039
10998
  };
10040
10999
  var CHIEF_CHIPS_FIELD2 = "chief_complaints_chips";
10041
11000
  var GS_EXAMINATION_FIELD = "gs_examination";
10042
- function chipList2(state) {
11001
+ function chipList(state) {
10043
11002
  const raw = state.values[CHIEF_CHIPS_FIELD2];
10044
11003
  return Array.isArray(raw) ? raw.filter((x) => typeof x === "string") : [];
10045
11004
  }
@@ -10053,7 +11012,7 @@ var GsGradingWidget = ({ fieldId }) => {
10053
11012
  const { state } = useForm();
10054
11013
  const showError = !!error && (touched || state.submitAttempted);
10055
11014
  const safe = React15.useMemo(() => normalizeGeneralSurgeryGrading(value), [value]);
10056
- const chips = React15.useMemo(() => chipList2(state), [state]);
11015
+ const chips = React15.useMemo(() => chipList(state), [state]);
10057
11016
  const regions = React15.useMemo(() => regionList(state), [state]);
10058
11017
  const visibleRows = React15.useMemo(() => {
10059
11018
  return ALL_GS_CONDITIONS.filter(
@@ -10208,6 +11167,813 @@ var PainScaleFlagsWidget = ({ fieldId }) => {
10208
11167
  showError && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-red-500", children: error })
10209
11168
  ] });
10210
11169
  };
11170
+ var CHIEF_CHIPS_FIELD3 = "chief_complaints_chips";
11171
+ var ACTIVE_SYNDROME_FIELD = "uro_active_syndrome";
11172
+ function chipList2(state) {
11173
+ const raw = state.values[CHIEF_CHIPS_FIELD3];
11174
+ return Array.isArray(raw) ? raw.filter((x) => typeof x === "string") : [];
11175
+ }
11176
+ var IPSS_LABELS = {
11177
+ incomplete: "Incomplete emptying",
11178
+ frequency: "Frequency (<2h)",
11179
+ intermittency: "Intermittency",
11180
+ urgency: "Urgency",
11181
+ weakStream: "Weak stream",
11182
+ straining: "Straining",
11183
+ nocturia: "Nocturia (\xD7/night)"
11184
+ };
11185
+ var SOCRATES_KEYS3 = [
11186
+ "site",
11187
+ "onset",
11188
+ "character",
11189
+ "radiation",
11190
+ "associated",
11191
+ "timing",
11192
+ "exacerbating"
11193
+ ];
11194
+ function Panel2({
11195
+ title,
11196
+ right,
11197
+ children
11198
+ }) {
11199
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "overflow-hidden rounded-md border border-[#D0D0D0] bg-white", children: [
11200
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between border-b border-[#D0D0D0] bg-[#FEE8EC]/50 px-3 py-1.5", children: [
11201
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-semibold text-slate-700", children: title }),
11202
+ right
11203
+ ] }),
11204
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-3", children })
11205
+ ] });
11206
+ }
11207
+ var UrologySmartHistoryWidget = ({ fieldId }) => {
11208
+ const { fieldDef, value, setValue, setTouched, error, touched, disabled } = useField(fieldId);
11209
+ const syndromeField = useField(ACTIVE_SYNDROME_FIELD);
11210
+ const { state } = useForm();
11211
+ const showError = !!error && (touched || state.submitAttempted);
11212
+ const safe = React15.useMemo(() => normalizeUrologySmartHistory(value), [value]);
11213
+ const chips = React15.useMemo(() => chipList2(state), [state]);
11214
+ const rawSyndrome = syndromeField.value ?? state.values[ACTIVE_SYNDROME_FIELD];
11215
+ const syndrome = typeof rawSyndrome === "string" && rawSyndrome !== "" && rawSyndrome !== "none" ? rawSyndrome : "none";
11216
+ const showPain = chips.includes("pain_abdomen_flank") || chips.includes("scrotal_swelling_pain") || syndrome === "stone" || syndrome === "scrotal";
11217
+ const showLUTS = syndrome === "luts" || syndrome === "retention" || chips.includes("frequency_urgency") || chips.includes("poor_stream") || chips.includes("acute_retention");
11218
+ const showHaem = syndrome === "haematuria" || chips.includes("haematuria");
11219
+ const showSex = syndrome === "ed_infertility" || chips.includes("erectile_dysfunction") || chips.includes("infertility_concern");
11220
+ const update = (next) => {
11221
+ setValue(next);
11222
+ setTouched();
11223
+ };
11224
+ const ipssTotal = urologyIpssSevenTotal(safe.ipss);
11225
+ const ipssBandLabel = urologyIpssBand(ipssTotal);
11226
+ 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";
11227
+ const setSocrates = (key, v) => {
11228
+ if (key === "severity") {
11229
+ const n = typeof v === "number" ? v : Number(v);
11230
+ const sev = Number.isFinite(n) ? Math.min(10, Math.max(0, Math.round(n))) : 0;
11231
+ update({ ...safe, socrates: { ...safe.socrates, severity: sev } });
11232
+ return;
11233
+ }
11234
+ update({ ...safe, socrates: { ...safe.socrates, [key]: String(v) } });
11235
+ };
11236
+ const setIpss = (key, v) => {
11237
+ update({ ...safe, ipss: { ...safe.ipss, [key]: v } });
11238
+ };
11239
+ if (!fieldDef) return null;
11240
+ const theme = getThemeConfig("textarea", fieldDef.theme);
11241
+ const wrapperClass = theme?.wrapperClassName ?? "rounded-md overflow-hidden flex flex-col border border-[#D0D0D0]";
11242
+ const labelClass = theme?.labelClassName;
11243
+ const labelContent = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
11244
+ fieldDef.label,
11245
+ fieldDef.required ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-1 text-red-500", children: "*" }) : null
11246
+ ] });
11247
+ const labelEl = theme ? /* @__PURE__ */ jsxRuntime.jsx(Label, { className: labelClass, children: labelContent }) : /* @__PURE__ */ jsxRuntime.jsx(Label, { className: "text-sm font-medium", children: labelContent });
11248
+ const bodyClass = cn(
11249
+ "-mt-1 flex min-w-0 flex-col gap-3 border-t border-[#D0D0D0] bg-white px-3 py-3",
11250
+ disabled && "pointer-events-none opacity-60"
11251
+ );
11252
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("w-full min-w-0", wrapperClass), children: [
11253
+ labelEl,
11254
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: bodyClass, children: [
11255
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[11px] text-muted-foreground", children: "Panels follow chief complaint chips and active syndrome (Clearsight SmartHistoryUro)." }),
11256
+ showPain ? /* @__PURE__ */ jsxRuntime.jsx(Panel2, { title: "SOCRATES \u2014 Pain (flank / suprapubic / testicular)", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-2 md:grid-cols-4", children: [
11257
+ SOCRATES_KEYS3.map((k) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
11258
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-medium uppercase tracking-wide text-muted-foreground", children: k }),
11259
+ /* @__PURE__ */ jsxRuntime.jsx(
11260
+ Input,
11261
+ {
11262
+ className: "h-8 text-xs",
11263
+ value: safe.socrates[k],
11264
+ onChange: (e) => setSocrates(k, e.target.value),
11265
+ placeholder: k === "radiation" ? "e.g. groin \u2192 ureteric" : k === "character" ? "colicky / dull" : "",
11266
+ disabled
11267
+ }
11268
+ )
11269
+ ] }, k)),
11270
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
11271
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-medium uppercase tracking-wide text-muted-foreground", children: "Severity 0\u201310" }),
11272
+ /* @__PURE__ */ jsxRuntime.jsx(
11273
+ Input,
11274
+ {
11275
+ type: "number",
11276
+ min: 0,
11277
+ max: 10,
11278
+ className: "h-8 text-xs",
11279
+ value: safe.socrates.severity,
11280
+ onChange: (e) => setSocrates("severity", e.target.value),
11281
+ disabled
11282
+ }
11283
+ )
11284
+ ] })
11285
+ ] }) }) : null,
11286
+ showLUTS ? /* @__PURE__ */ jsxRuntime.jsxs(
11287
+ Panel2,
11288
+ {
11289
+ title: "IPSS \u2014 International Prostate Symptom Score",
11290
+ right: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: `rounded-full px-2 py-0.5 text-[10px] font-medium ${bandClass}`, children: [
11291
+ ipssTotal,
11292
+ "/35 \u2014 ",
11293
+ ipssBandLabel
11294
+ ] }),
11295
+ children: [
11296
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-2 md:grid-cols-4", children: [
11297
+ Object.keys(IPSS_LABELS).map((k) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
11298
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] uppercase tracking-wide text-muted-foreground", children: IPSS_LABELS[k] }),
11299
+ /* @__PURE__ */ jsxRuntime.jsxs(
11300
+ Select,
11301
+ {
11302
+ value: String(safe.ipss[k]),
11303
+ onValueChange: (val) => setIpss(k, Number(val)),
11304
+ disabled,
11305
+ children: [
11306
+ /* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, {}) }),
11307
+ /* @__PURE__ */ jsxRuntime.jsx(SelectContent, { children: [0, 1, 2, 3, 4, 5].map((n) => /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: String(n), children: n }, n)) })
11308
+ ]
11309
+ }
11310
+ )
11311
+ ] }, k)),
11312
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
11313
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] uppercase tracking-wide text-muted-foreground", children: "QoL (0\u20136)" }),
11314
+ /* @__PURE__ */ jsxRuntime.jsxs(
11315
+ Select,
11316
+ {
11317
+ value: String(safe.ipssQoL),
11318
+ onValueChange: (val) => update({ ...safe, ipssQoL: Math.min(6, Math.max(0, Number(val))) }),
11319
+ disabled,
11320
+ children: [
11321
+ /* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, {}) }),
11322
+ /* @__PURE__ */ jsxRuntime.jsx(SelectContent, { children: [0, 1, 2, 3, 4, 5, 6].map((n) => /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: String(n), children: n }, n)) })
11323
+ ]
11324
+ }
11325
+ )
11326
+ ] })
11327
+ ] }),
11328
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "mt-2 text-[10px] text-muted-foreground", children: [
11329
+ "Bands: 0\u20137 mild \xB7 8\u201319 moderate \xB7 20\u201335 severe.",
11330
+ " ",
11331
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold text-foreground", children: "IPSS \u2265 20 \u2192 consider surgical intervention." })
11332
+ ] })
11333
+ ]
11334
+ }
11335
+ ) : null,
11336
+ showHaem ? /* @__PURE__ */ jsxRuntime.jsxs(Panel2, { title: "Haematuria profile", children: [
11337
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-3 text-xs md:grid-cols-4", children: [
11338
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2", children: [
11339
+ /* @__PURE__ */ jsxRuntime.jsx(
11340
+ Checkbox,
11341
+ {
11342
+ checked: safe.haematuria.present,
11343
+ onCheckedChange: (c) => update({
11344
+ ...safe,
11345
+ haematuria: { ...safe.haematuria, present: c === true }
11346
+ }),
11347
+ disabled
11348
+ }
11349
+ ),
11350
+ "Present"
11351
+ ] }),
11352
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex flex-col gap-1", children: [
11353
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: "Timing" }),
11354
+ /* @__PURE__ */ jsxRuntime.jsxs(
11355
+ Select,
11356
+ {
11357
+ value: safe.haematuria.timing || "none",
11358
+ onValueChange: (val) => update({
11359
+ ...safe,
11360
+ haematuria: { ...safe.haematuria, timing: val === "none" ? "" : val }
11361
+ }),
11362
+ disabled,
11363
+ children: [
11364
+ /* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, { placeholder: "\u2014" }) }),
11365
+ /* @__PURE__ */ jsxRuntime.jsxs(SelectContent, { children: [
11366
+ /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "none", children: "\u2014" }),
11367
+ /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "Initial", children: "Initial" }),
11368
+ /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "Terminal", children: "Terminal" }),
11369
+ /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "Total", children: "Total" })
11370
+ ] })
11371
+ ]
11372
+ }
11373
+ )
11374
+ ] }),
11375
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2", children: [
11376
+ /* @__PURE__ */ jsxRuntime.jsx(
11377
+ Checkbox,
11378
+ {
11379
+ checked: safe.haematuria.painful,
11380
+ onCheckedChange: (c) => update({ ...safe, haematuria: { ...safe.haematuria, painful: c === true } }),
11381
+ disabled
11382
+ }
11383
+ ),
11384
+ "Painful"
11385
+ ] }),
11386
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2", children: [
11387
+ /* @__PURE__ */ jsxRuntime.jsx(
11388
+ Checkbox,
11389
+ {
11390
+ checked: safe.haematuria.clots,
11391
+ onCheckedChange: (c) => update({ ...safe, haematuria: { ...safe.haematuria, clots: c === true } }),
11392
+ disabled
11393
+ }
11394
+ ),
11395
+ "Clots"
11396
+ ] })
11397
+ ] }),
11398
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-[10px] text-red-600", children: "Painless haematuria = malignancy until proven otherwise." })
11399
+ ] }) : null,
11400
+ showSex ? /* @__PURE__ */ jsxRuntime.jsx(Panel2, { title: "Sexual & reproductive history", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-3 text-xs md:grid-cols-4", children: [
11401
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex flex-col gap-1", children: [
11402
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: "Erectile function" }),
11403
+ /* @__PURE__ */ jsxRuntime.jsxs(
11404
+ Select,
11405
+ {
11406
+ value: safe.sexual.erectile || "none",
11407
+ onValueChange: (val) => update({
11408
+ ...safe,
11409
+ sexual: { ...safe.sexual, erectile: val === "none" ? "" : val }
11410
+ }),
11411
+ disabled,
11412
+ children: [
11413
+ /* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, { placeholder: "\u2014" }) }),
11414
+ /* @__PURE__ */ jsxRuntime.jsxs(SelectContent, { children: [
11415
+ /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "none", children: "\u2014" }),
11416
+ /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "Normal", children: "Normal" }),
11417
+ /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "Mild", children: "Mild" }),
11418
+ /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "Moderate", children: "Moderate" }),
11419
+ /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "Severe", children: "Severe" })
11420
+ ] })
11421
+ ]
11422
+ }
11423
+ )
11424
+ ] }),
11425
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex flex-col gap-1", children: [
11426
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: "Libido" }),
11427
+ /* @__PURE__ */ jsxRuntime.jsxs(
11428
+ Select,
11429
+ {
11430
+ value: safe.sexual.libido || "none",
11431
+ onValueChange: (val) => update({
11432
+ ...safe,
11433
+ sexual: { ...safe.sexual, libido: val === "none" ? "" : val }
11434
+ }),
11435
+ disabled,
11436
+ children: [
11437
+ /* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, { placeholder: "\u2014" }) }),
11438
+ /* @__PURE__ */ jsxRuntime.jsxs(SelectContent, { children: [
11439
+ /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "none", children: "\u2014" }),
11440
+ /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "Normal", children: "Normal" }),
11441
+ /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "Reduced", children: "Reduced" })
11442
+ ] })
11443
+ ]
11444
+ }
11445
+ )
11446
+ ] }),
11447
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex flex-col gap-1", children: [
11448
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: "Ejaculation" }),
11449
+ /* @__PURE__ */ jsxRuntime.jsxs(
11450
+ Select,
11451
+ {
11452
+ value: safe.sexual.ejaculation || "none",
11453
+ onValueChange: (val) => update({
11454
+ ...safe,
11455
+ sexual: { ...safe.sexual, ejaculation: val === "none" ? "" : val }
11456
+ }),
11457
+ disabled,
11458
+ children: [
11459
+ /* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, { placeholder: "\u2014" }) }),
11460
+ /* @__PURE__ */ jsxRuntime.jsxs(SelectContent, { children: [
11461
+ /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "none", children: "\u2014" }),
11462
+ /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "Normal", children: "Normal" }),
11463
+ /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "Premature", children: "Premature" }),
11464
+ /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "Retrograde", children: "Retrograde" }),
11465
+ /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: "Anejaculation", children: "Anejaculation" })
11466
+ ] })
11467
+ ]
11468
+ }
11469
+ )
11470
+ ] }),
11471
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex flex-col gap-1", children: [
11472
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: "Infertility (months)" }),
11473
+ /* @__PURE__ */ jsxRuntime.jsx(
11474
+ Input,
11475
+ {
11476
+ type: "number",
11477
+ min: 0,
11478
+ className: "h-8 text-xs",
11479
+ value: safe.sexual.infertilityMonths,
11480
+ onChange: (e) => update({
11481
+ ...safe,
11482
+ sexual: {
11483
+ ...safe.sexual,
11484
+ infertilityMonths: Math.max(0, Math.round(Number(e.target.value)) || 0)
11485
+ }
11486
+ }),
11487
+ disabled
11488
+ }
11489
+ )
11490
+ ] })
11491
+ ] }) }) : null,
11492
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
11493
+ /* @__PURE__ */ jsxRuntime.jsx(Label, { className: "text-xs font-medium text-slate-700", children: "Past history (stones / surgeries / drugs)" }),
11494
+ /* @__PURE__ */ jsxRuntime.jsx(
11495
+ Textarea,
11496
+ {
11497
+ className: "min-h-[72px] rounded-md border border-input bg-white text-sm",
11498
+ placeholder: "Prior calculi, urological surgeries, anticoagulants, DM/HTN\u2026",
11499
+ value: safe.pastNotes,
11500
+ onChange: (e) => update({ ...safe, pastNotes: e.target.value }),
11501
+ disabled
11502
+ }
11503
+ )
11504
+ ] })
11505
+ ] }),
11506
+ showError ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "px-3 pb-2 text-xs text-red-500", children: error }) : null
11507
+ ] });
11508
+ };
11509
+ var GENERAL_ROWS = [
11510
+ { key: "pallor", label: "Pallor (chronic dz)" },
11511
+ { key: "oedema", label: "Oedema (renal)" },
11512
+ { key: "icterus", label: "Icterus" },
11513
+ { key: "lymphadenopathy", label: "Lymphadenopathy" }
11514
+ ];
11515
+ var ABD_ROWS = [
11516
+ { key: "distension", label: "Distension" },
11517
+ { key: "scars", label: "Surgical scars" },
11518
+ { key: "mass", label: "Visible mass" },
11519
+ { key: "kidneyPalpable", label: "Kidney palpable" },
11520
+ { key: "bladderPalpable", label: "Bladder palpable" },
11521
+ { key: "renalAngleTender", label: "Renal angle tender" },
11522
+ { key: "bladderDull", label: "Bladder dullness (retention)" }
11523
+ ];
11524
+ var GU_ROWS = [
11525
+ { key: "meatusAbnormal", label: "Meatus abnormal (hypospadias?)" },
11526
+ { key: "phimosis", label: "Phimosis / paraphimosis" },
11527
+ { key: "lesions", label: "Penile lesions / ulcers" },
11528
+ { key: "scrotalSwelling", label: "Scrotal swelling" },
11529
+ { key: "transilluminant", label: "Transilluminant" },
11530
+ { key: "tenderTestis", label: "Tender testis" },
11531
+ { key: "hydrocele", label: "Hydrocele" },
11532
+ { key: "varicocele", label: "Varicocele" },
11533
+ { key: "suspiciousMass", label: "Suspicious mass" }
11534
+ ];
11535
+ var DRE_CONSISTENCY = ["none", "Soft (benign)", "Firm", "Hard / nodular (malignancy?)"];
11536
+ var DRE_SULCUS = ["none", "Preserved", "Obliterated"];
11537
+ var UrologyExaminationWidget = ({ fieldId }) => {
11538
+ const { fieldDef, value, setValue, setTouched, error, touched, disabled } = useField(fieldId);
11539
+ const { state } = useForm();
11540
+ const showError = !!error && (touched || state.submitAttempted);
11541
+ const safe = React15.useMemo(() => normalizeUrologyExamination(value), [value]);
11542
+ const update = (next) => {
11543
+ setValue(next);
11544
+ setTouched();
11545
+ };
11546
+ const toggleGeneral = (key) => {
11547
+ update({ ...safe, general: { ...safe.general, [key]: !safe.general[key] } });
11548
+ };
11549
+ const toggleAbdomen = (key) => {
11550
+ update({ ...safe, abdomen: { ...safe.abdomen, [key]: !safe.abdomen[key] } });
11551
+ };
11552
+ const toggleGu = (key) => {
11553
+ update({ ...safe, gu: { ...safe.gu, [key]: !safe.gu[key] } });
11554
+ };
11555
+ if (!fieldDef) return null;
11556
+ const theme = getThemeConfig("textarea", fieldDef.theme);
11557
+ const wrapperClass = theme?.wrapperClassName ?? "rounded-md overflow-hidden flex flex-col border border-[#D0D0D0]";
11558
+ const labelClass = theme?.labelClassName;
11559
+ const labelContent = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
11560
+ fieldDef.label,
11561
+ fieldDef.required ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-1 text-red-500", children: "*" }) : null
11562
+ ] });
11563
+ const labelEl = theme ? /* @__PURE__ */ jsxRuntime.jsx(Label, { className: labelClass, children: labelContent }) : /* @__PURE__ */ jsxRuntime.jsx(Label, { className: "text-sm font-medium", children: labelContent });
11564
+ const bodyClass = cn(
11565
+ "-mt-1 flex min-w-0 flex-col gap-3 border-t border-[#D0D0D0] bg-white px-3 py-3",
11566
+ disabled && "pointer-events-none opacity-60"
11567
+ );
11568
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("w-full min-w-0", wrapperClass), children: [
11569
+ labelEl,
11570
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: bodyClass, children: [
11571
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 gap-3 text-xs md:grid-cols-2 xl:grid-cols-4", children: [
11572
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
11573
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-semibold text-slate-800", children: "General" }),
11574
+ GENERAL_ROWS.map((r) => /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2", children: [
11575
+ /* @__PURE__ */ jsxRuntime.jsx(
11576
+ Checkbox,
11577
+ {
11578
+ checked: safe.general[r.key],
11579
+ onCheckedChange: () => toggleGeneral(r.key),
11580
+ disabled
11581
+ }
11582
+ ),
11583
+ r.label
11584
+ ] }, r.key))
11585
+ ] }),
11586
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
11587
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-semibold text-slate-800", children: "Abdomen" }),
11588
+ ABD_ROWS.map((r) => /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2", children: [
11589
+ /* @__PURE__ */ jsxRuntime.jsx(
11590
+ Checkbox,
11591
+ {
11592
+ checked: safe.abdomen[r.key],
11593
+ onCheckedChange: () => toggleAbdomen(r.key),
11594
+ disabled
11595
+ }
11596
+ ),
11597
+ r.label
11598
+ ] }, r.key))
11599
+ ] }),
11600
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
11601
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-semibold text-slate-800", children: "External genitalia / scrotum" }),
11602
+ GU_ROWS.map((r) => /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2", children: [
11603
+ /* @__PURE__ */ jsxRuntime.jsx(
11604
+ Checkbox,
11605
+ {
11606
+ checked: safe.gu[r.key],
11607
+ onCheckedChange: () => toggleGu(r.key),
11608
+ disabled
11609
+ }
11610
+ ),
11611
+ r.key === "suspiciousMass" ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-red-600", children: r.label }) : r.label
11612
+ ] }, r.key))
11613
+ ] }),
11614
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
11615
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-semibold text-slate-800", children: "DRE \u2014 Prostate" }),
11616
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2", children: [
11617
+ /* @__PURE__ */ jsxRuntime.jsx(
11618
+ Checkbox,
11619
+ {
11620
+ checked: safe.dre.done,
11621
+ onCheckedChange: (c) => update({ ...safe, dre: { ...safe.dre, done: c === true } }),
11622
+ disabled
11623
+ }
11624
+ ),
11625
+ "DRE performed"
11626
+ ] }),
11627
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "block", children: [
11628
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mb-1 block font-medium", children: "Estimated size (g)" }),
11629
+ /* @__PURE__ */ jsxRuntime.jsx(
11630
+ Input,
11631
+ {
11632
+ type: "number",
11633
+ min: 0,
11634
+ className: "h-8 text-xs",
11635
+ value: safe.dre.sizeGrams,
11636
+ onChange: (e) => {
11637
+ const n = Number(e.target.value);
11638
+ update({
11639
+ ...safe,
11640
+ dre: {
11641
+ ...safe.dre,
11642
+ sizeGrams: Number.isFinite(n) && n >= 0 ? Math.round(n) : 0
11643
+ }
11644
+ });
11645
+ },
11646
+ disabled
11647
+ }
11648
+ )
11649
+ ] }),
11650
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "block", children: [
11651
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mb-1 block font-medium", children: "Consistency" }),
11652
+ /* @__PURE__ */ jsxRuntime.jsxs(
11653
+ Select,
11654
+ {
11655
+ value: safe.dre.consistency || "none",
11656
+ onValueChange: (val) => update({
11657
+ ...safe,
11658
+ dre: { ...safe.dre, consistency: val === "none" ? "" : val }
11659
+ }),
11660
+ disabled,
11661
+ children: [
11662
+ /* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, { placeholder: "\u2014" }) }),
11663
+ /* @__PURE__ */ jsxRuntime.jsx(SelectContent, { children: DRE_CONSISTENCY.map((opt) => /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: opt, children: opt === "none" ? "\u2014" : opt }, opt)) })
11664
+ ]
11665
+ }
11666
+ )
11667
+ ] }),
11668
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "block", children: [
11669
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mb-1 block font-medium", children: "Median sulcus" }),
11670
+ /* @__PURE__ */ jsxRuntime.jsxs(
11671
+ Select,
11672
+ {
11673
+ value: safe.dre.medianSulcus || "none",
11674
+ onValueChange: (val) => update({
11675
+ ...safe,
11676
+ dre: { ...safe.dre, medianSulcus: val === "none" ? "" : val }
11677
+ }),
11678
+ disabled,
11679
+ children: [
11680
+ /* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { className: "h-8 text-xs", children: /* @__PURE__ */ jsxRuntime.jsx(SelectValue, { placeholder: "\u2014" }) }),
11681
+ /* @__PURE__ */ jsxRuntime.jsx(SelectContent, { children: DRE_SULCUS.map((opt) => /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: opt, children: opt === "none" ? "\u2014" : opt }, opt)) })
11682
+ ]
11683
+ }
11684
+ )
11685
+ ] }),
11686
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2", children: [
11687
+ /* @__PURE__ */ jsxRuntime.jsx(
11688
+ Checkbox,
11689
+ {
11690
+ checked: safe.dre.tenderness,
11691
+ onCheckedChange: (c) => update({ ...safe, dre: { ...safe.dre, tenderness: c === true } }),
11692
+ disabled
11693
+ }
11694
+ ),
11695
+ "Tender (prostatitis?)"
11696
+ ] })
11697
+ ] })
11698
+ ] }),
11699
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
11700
+ /* @__PURE__ */ jsxRuntime.jsx(Label, { className: "text-xs font-semibold text-slate-700", children: "Examination notes" }),
11701
+ /* @__PURE__ */ jsxRuntime.jsx(
11702
+ Textarea,
11703
+ {
11704
+ className: "min-h-[88px] rounded-md border border-input bg-white text-sm",
11705
+ placeholder: "Free-text exam findings\u2026",
11706
+ value: safe.examinationNotes,
11707
+ onChange: (e) => update({ ...safe, examinationNotes: e.target.value }),
11708
+ disabled
11709
+ }
11710
+ )
11711
+ ] })
11712
+ ] }),
11713
+ showError ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "px-3 pb-2 text-xs text-red-500", children: error }) : null
11714
+ ] });
11715
+ };
11716
+ var SMART_HISTORY_FIELD = "uro_smart_history";
11717
+ var EXAMINATION_FIELD = "uro_examination";
11718
+ var DRE_HARD = "Hard / nodular (malignancy?)";
11719
+ function Panel3({
11720
+ title,
11721
+ className,
11722
+ children
11723
+ }) {
11724
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("overflow-hidden rounded-md border border-[#D0D0D0] bg-white", className), children: [
11725
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-b border-[#D0D0D0] bg-[#FEE8EC]/50 px-3 py-1.5", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-semibold text-slate-700", children: title }) }),
11726
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-3", children })
11727
+ ] });
11728
+ }
11729
+ var UrologyPathwayWidget = ({ fieldId }) => {
11730
+ const { fieldDef, value, setValue, setTouched, error, touched, disabled } = useField(fieldId);
11731
+ const { state } = useForm();
11732
+ const showError = !!error && (touched || state.submitAttempted);
11733
+ const safe = React15.useMemo(() => normalizeUrologyPathway(value), [value]);
11734
+ const smart = React15.useMemo(
11735
+ () => normalizeUrologySmartHistory(state.values[SMART_HISTORY_FIELD]),
11736
+ [state.values]
11737
+ );
11738
+ const exam = React15.useMemo(
11739
+ () => normalizeUrologyExamination(state.values[EXAMINATION_FIELD]),
11740
+ [state.values]
11741
+ );
11742
+ const ipssTotal = urologyIpssSevenTotal(smart.ipss);
11743
+ 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";
11744
+ const stone = React15.useMemo(
11745
+ () => urologyStoneRecommendation(safe.stoneSizeMm, safe.hydronephrosis),
11746
+ [safe.stoneSizeMm, safe.hydronephrosis]
11747
+ );
11748
+ const prostateLine = React15.useMemo(
11749
+ () => urologyProstateProcedure(safe.prostateVolumeCc),
11750
+ [safe.prostateVolumeCc]
11751
+ );
11752
+ const psaHigh = safe.psaNgMl > 4;
11753
+ const qmaxLow = safe.uroflowQmaxMlSec > 0 && Number.isFinite(safe.uroflowQmaxMlSec) && safe.uroflowQmaxMlSec < 10;
11754
+ const update = (next) => {
11755
+ setValue(next);
11756
+ setTouched();
11757
+ };
11758
+ const setRisk = (key, next) => {
11759
+ update({ ...safe, risk: { ...safe.risk, [key]: next } });
11760
+ };
11761
+ if (!fieldDef) return null;
11762
+ const theme = getThemeConfig("textarea", fieldDef.theme);
11763
+ const wrapperClass = theme?.wrapperClassName ?? "rounded-md overflow-hidden flex flex-col border border-[#D0D0D0]";
11764
+ const labelClass = theme?.labelClassName;
11765
+ const labelContent = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
11766
+ fieldDef.label,
11767
+ fieldDef.required ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-1 text-red-500", children: "*" }) : null
11768
+ ] });
11769
+ const labelEl = theme ? /* @__PURE__ */ jsxRuntime.jsx(Label, { className: labelClass, children: labelContent }) : /* @__PURE__ */ jsxRuntime.jsx(Label, { className: "text-sm font-medium", children: labelContent });
11770
+ const bodyClass = cn(
11771
+ "-mt-1 flex min-w-0 flex-col gap-3 border-t border-[#D0D0D0] bg-white px-3 py-3",
11772
+ disabled && "pointer-events-none opacity-60"
11773
+ );
11774
+ const subtitle = typeof fieldDef.meta?.subtitle === "string" && fieldDef.meta.subtitle.trim().length > 0 ? fieldDef.meta.subtitle.trim() : "";
11775
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("w-full min-w-0", wrapperClass), children: [
11776
+ labelEl,
11777
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: bodyClass, children: [
11778
+ subtitle ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "-mt-0.5 mb-0 text-xs font-semibold tracking-wide text-slate-700", children: subtitle }) : null,
11779
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 gap-3 text-xs md:grid-cols-2 xl:grid-cols-4", children: [
11780
+ /* @__PURE__ */ jsxRuntime.jsxs(Panel3, { title: "Stone disease", children: [
11781
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "block", children: [
11782
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mb-1 block font-medium text-slate-700", children: "Stone size (mm)" }),
11783
+ /* @__PURE__ */ jsxRuntime.jsx(
11784
+ Input,
11785
+ {
11786
+ type: "number",
11787
+ min: 0,
11788
+ step: "any",
11789
+ className: cn(
11790
+ "h-8 text-xs",
11791
+ disabled && "pointer-events-none"
11792
+ ),
11793
+ value: safe.stoneSizeMm,
11794
+ onChange: (e) => {
11795
+ const raw = e.target.value;
11796
+ const n = Number(raw);
11797
+ update({
11798
+ ...safe,
11799
+ stoneSizeMm: raw === "" || raw === "-" ? 0 : !Number.isFinite(n) ? 0 : Math.max(0, n)
11800
+ });
11801
+ },
11802
+ disabled
11803
+ }
11804
+ )
11805
+ ] }),
11806
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "mt-2 flex items-center gap-2", children: [
11807
+ /* @__PURE__ */ jsxRuntime.jsx(
11808
+ Checkbox,
11809
+ {
11810
+ checked: safe.hydronephrosis,
11811
+ disabled,
11812
+ onCheckedChange: (checked) => update({ ...safe, hydronephrosis: checked === true })
11813
+ }
11814
+ ),
11815
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-slate-700", children: "Hydronephrosis on imaging" })
11816
+ ] }),
11817
+ /* @__PURE__ */ jsxRuntime.jsx(
11818
+ "div",
11819
+ {
11820
+ className: cn(
11821
+ "mt-2 rounded p-2 text-[11px]",
11822
+ 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"
11823
+ ),
11824
+ children: stone.plan
11825
+ }
11826
+ ),
11827
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-[10px] text-muted-foreground", children: "Trigger: >10 mm OR obstruction \u2192 surgical." })
11828
+ ] }),
11829
+ /* @__PURE__ */ jsxRuntime.jsxs(Panel3, { title: "Prostate / BPH", children: [
11830
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 gap-2", children: [
11831
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "block", children: [
11832
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mb-1 block font-medium text-slate-700", children: "Volume (cc)" }),
11833
+ /* @__PURE__ */ jsxRuntime.jsx(
11834
+ Input,
11835
+ {
11836
+ type: "number",
11837
+ min: 0,
11838
+ step: "any",
11839
+ className: cn(
11840
+ "h-8 text-xs",
11841
+ disabled && "pointer-events-none"
11842
+ ),
11843
+ value: safe.prostateVolumeCc,
11844
+ onChange: (e) => {
11845
+ const raw = e.target.value;
11846
+ const n = Number(raw);
11847
+ update({
11848
+ ...safe,
11849
+ prostateVolumeCc: raw === "" || raw === "-" ? 0 : !Number.isFinite(n) ? 0 : Math.max(0, n)
11850
+ });
11851
+ },
11852
+ disabled
11853
+ }
11854
+ )
11855
+ ] }),
11856
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "block", children: [
11857
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mb-1 block font-medium text-slate-700", children: "PSA (ng/ml)" }),
11858
+ /* @__PURE__ */ jsxRuntime.jsx(
11859
+ Input,
11860
+ {
11861
+ type: "number",
11862
+ min: 0,
11863
+ step: 0.1,
11864
+ className: cn(
11865
+ "h-8 text-xs",
11866
+ psaHigh && "border-red-400 text-red-800",
11867
+ disabled && "pointer-events-none"
11868
+ ),
11869
+ value: safe.psaNgMl,
11870
+ onChange: (e) => {
11871
+ const raw = e.target.value;
11872
+ const n = Number(raw);
11873
+ update({
11874
+ ...safe,
11875
+ psaNgMl: raw === "" || raw === "-" ? 0 : !Number.isFinite(n) ? 0 : Math.max(0, n)
11876
+ });
11877
+ },
11878
+ disabled
11879
+ }
11880
+ )
11881
+ ] }),
11882
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "col-span-2 block", children: [
11883
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mb-1 block font-medium text-slate-700", children: "Uroflow Qmax (ml/s)" }),
11884
+ /* @__PURE__ */ jsxRuntime.jsx(
11885
+ Input,
11886
+ {
11887
+ type: "number",
11888
+ min: 0,
11889
+ step: 0.1,
11890
+ className: cn(
11891
+ "h-8 text-xs",
11892
+ qmaxLow && "border-amber-500 text-amber-900",
11893
+ disabled && "pointer-events-none"
11894
+ ),
11895
+ value: safe.uroflowQmaxMlSec,
11896
+ onChange: (e) => {
11897
+ const raw = e.target.value;
11898
+ const n = Number(raw);
11899
+ update({
11900
+ ...safe,
11901
+ uroflowQmaxMlSec: raw === "" || raw === "-" ? 0 : !Number.isFinite(n) ? 0 : Math.max(0, n)
11902
+ });
11903
+ },
11904
+ disabled
11905
+ }
11906
+ )
11907
+ ] })
11908
+ ] }),
11909
+ /* @__PURE__ */ jsxRuntime.jsx(
11910
+ "div",
11911
+ {
11912
+ className: cn(
11913
+ "mt-2 rounded p-2 text-[11px]",
11914
+ 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"
11915
+ ),
11916
+ children: prostateLine
11917
+ }
11918
+ ),
11919
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-[10px] text-muted-foreground", children: "<30 cc medical \xB7 30\u201380 cc TURP \xB7 >80 cc HoLEP/Open" })
11920
+ ] }),
11921
+ /* @__PURE__ */ jsxRuntime.jsxs(Panel3, { title: "IPSS & cues", children: [
11922
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-2 flex items-center justify-between", children: [
11923
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-slate-700", children: "IPSS total" }),
11924
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: `rounded-full px-2 py-0.5 text-[11px] font-semibold ${ipssBandCls}`, children: [
11925
+ ipssTotal,
11926
+ "/35 \xB7 ",
11927
+ urologyIpssBand(ipssTotal)
11928
+ ] })
11929
+ ] }),
11930
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-3 h-1.5 overflow-hidden rounded-full bg-slate-200", children: /* @__PURE__ */ jsxRuntime.jsx(
11931
+ "div",
11932
+ {
11933
+ className: cn(
11934
+ "h-full transition-[width]",
11935
+ ipssTotal >= 20 ? "bg-red-500" : ipssTotal >= 8 ? "bg-amber-500" : "bg-emerald-500"
11936
+ ),
11937
+ style: { width: `${Math.min(100, ipssTotal / 35 * 100)}%` }
11938
+ }
11939
+ ) }),
11940
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "mb-3 text-[10px] text-muted-foreground", children: [
11941
+ "From smart history (",
11942
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-foreground", children: SMART_HISTORY_FIELD }),
11943
+ "). \u226520 \u2192 consider surgical intervention."
11944
+ ] }),
11945
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5 text-[11px]", children: [
11946
+ smart.haematuria.present && !smart.haematuria.painful ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded bg-red-500/10 p-1.5 text-red-800", children: "Painless haematuria \u2014 mandatory cystoscopy" }) : null,
11947
+ psaHigh ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded bg-amber-500/10 p-1.5 text-amber-900", children: "PSA >4 \u2014 workup for Ca prostate" }) : null,
11948
+ exam.dre.consistency === DRE_HARD ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded bg-red-500/10 p-1.5 text-red-800", children: [
11949
+ "Hard / nodular prostate (",
11950
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono", children: EXAMINATION_FIELD }),
11951
+ ") \u2014 biopsy pathway"
11952
+ ] }) : null,
11953
+ exam.gu.suspiciousMass ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded bg-red-500/10 p-1.5 text-red-800", children: "Suspicious scrotal mass \u2014 urgent surgical eval" }) : null
11954
+ ] })
11955
+ ] }),
11956
+ /* @__PURE__ */ jsxRuntime.jsx(Panel3, { title: "Risk stratification", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2", children: [
11957
+ ["ckd", "CKD"],
11958
+ ["diabetes", "Diabetes"],
11959
+ ["anticoagulants", "Anticoagulants"],
11960
+ ["activeInfection", "Active infection"]
11961
+ ].map(([key, lab]) => /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "flex items-center gap-2", children: [
11962
+ /* @__PURE__ */ jsxRuntime.jsx(
11963
+ Checkbox,
11964
+ {
11965
+ checked: safe.risk[key],
11966
+ disabled,
11967
+ onCheckedChange: (c) => setRisk(key, c === true)
11968
+ }
11969
+ ),
11970
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-slate-700", children: lab })
11971
+ ] }, key)) }) })
11972
+ ] })
11973
+ ] }),
11974
+ showError ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "px-3 pb-2 text-xs text-red-500", children: error }) : null
11975
+ ] });
11976
+ };
10211
11977
  var FieldRenderer = ({ fieldId }) => {
10212
11978
  const { fieldDef, visible } = useField(fieldId);
10213
11979
  if (!visible || !fieldDef) {
@@ -10289,6 +12055,12 @@ function renderWidget(fieldId, fieldDef) {
10289
12055
  return /* @__PURE__ */ jsxRuntime.jsx(GsGradingWidget, { fieldId });
10290
12056
  case "pain_scale_flags":
10291
12057
  return /* @__PURE__ */ jsxRuntime.jsx(PainScaleFlagsWidget, { fieldId });
12058
+ case "urology_smart_history":
12059
+ return /* @__PURE__ */ jsxRuntime.jsx(UrologySmartHistoryWidget, { fieldId });
12060
+ case "urology_examination":
12061
+ return /* @__PURE__ */ jsxRuntime.jsx(UrologyExaminationWidget, { fieldId });
12062
+ case "urology_pathway":
12063
+ return /* @__PURE__ */ jsxRuntime.jsx(UrologyPathwayWidget, { fieldId });
10292
12064
  case "toggle": {
10293
12065
  const { value, setValue, setTouched, disabled } = useField(fieldId);
10294
12066
  const store = useFormStore();
@@ -11152,7 +12924,43 @@ var ReadOnlyFieldRenderer = ({
11152
12924
  ].join("\n");
11153
12925
  return /* @__PURE__ */ jsxRuntime.jsx(ReadOnlyText, { fieldDef, value: lines });
11154
12926
  }
11155
- case "general_surgery_smart_history":
12927
+ case "urology_smart_history":
12928
+ return /* @__PURE__ */ jsxRuntime.jsx(
12929
+ ReadOnlyText,
12930
+ {
12931
+ fieldDef,
12932
+ value: value && typeof value === "object" ? JSON.stringify(value, null, 2) : value == null || value === "" ? "\u2014" : String(value)
12933
+ }
12934
+ );
12935
+ case "urology_examination":
12936
+ return /* @__PURE__ */ jsxRuntime.jsx(
12937
+ ReadOnlyText,
12938
+ {
12939
+ fieldDef,
12940
+ value: value && typeof value === "object" ? JSON.stringify(value, null, 2) : value == null || value === "" ? "\u2014" : String(value)
12941
+ }
12942
+ );
12943
+ case "urology_pathway":
12944
+ return /* @__PURE__ */ jsxRuntime.jsx(
12945
+ ReadOnlyText,
12946
+ {
12947
+ fieldDef,
12948
+ value: value && typeof value === "object" ? JSON.stringify(value, null, 2) : value == null || value === "" ? "\u2014" : String(value)
12949
+ }
12950
+ );
12951
+ case "general_surgery_smart_history": {
12952
+ const structuredDisplay = value && typeof value === "object" ? JSON.stringify(normalizeGeneralSurgerySmartHistory(value), null, 2) : value == null || value === "" ? "\u2014" : String(value);
12953
+ const hopcDef = resolveFieldDef?.("symptoms");
12954
+ const hopcRaw = allValues?.["symptoms"];
12955
+ const hopcStr = typeof hopcRaw === "string" ? hopcRaw : hopcRaw != null && hopcRaw !== "" ? String(hopcRaw) : "";
12956
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
12957
+ /* @__PURE__ */ jsxRuntime.jsx(ReadOnlyText, { fieldDef, value: structuredDisplay }),
12958
+ hopcDef ? /* @__PURE__ */ jsxRuntime.jsx(ReadOnlyText, { fieldDef: hopcDef, value: hopcStr }) : hopcStr ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
12959
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-gray-700", children: "History of presenting complaint" }),
12960
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-900 border border-gray-200 rounded-md p-3 bg-gray-50 min-h-[2.5rem] whitespace-pre-wrap", children: hopcStr })
12961
+ ] }) : null
12962
+ ] });
12963
+ }
11156
12964
  case "general_surgery_grading":
11157
12965
  return /* @__PURE__ */ jsxRuntime.jsx(
11158
12966
  ReadOnlyText,
@@ -11402,9 +13210,12 @@ exports.RichTextWidget = RichTextWidget;
11402
13210
  exports.SignatureUploadWidget = SignatureUploadWidget;
11403
13211
  exports.SmartForm = SmartForm;
11404
13212
  exports.SmartTextareaWidget = SmartTextareaWidget;
13213
+ exports.attachUrologyClinicalPathwayMetadata = attachUrologyClinicalPathwayMetadata;
11405
13214
  exports.createUploadHandler = createUploadHandler;
11406
13215
  exports.evaluateRules = evaluateRules;
11407
13216
  exports.fieldMetaRequestsMarMedicationOrdersButton = fieldMetaRequestsMarMedicationOrdersButton;
13217
+ exports.isUrologyTemplate = isUrologyTemplate;
13218
+ exports.shouldFoldUrologyClinicalPathway = shouldFoldUrologyClinicalPathway;
11408
13219
  exports.useField = useField;
11409
13220
  exports.useFieldHandlers = useFieldHandlers;
11410
13221
  exports.useForm = useForm;