@claudebernard/therapeutic-alternative-element 2.2.0 → 2.3.0

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.
@@ -26,6 +26,7 @@ export declare class TherapeuticAlternative extends LitElement {
26
26
  private include;
27
27
  private exclude;
28
28
  private quickFilters;
29
+ private quickFilterFacets;
29
30
  private scopeFacets;
30
31
  private includeFacets;
31
32
  private excludeFacets;
@@ -52,6 +53,7 @@ export declare class TherapeuticAlternative extends LitElement {
52
53
  private get currentMedicationRequest();
53
54
  private get sourceProductId();
54
55
  updated(changedProperties: Map<string | number | symbol, unknown>): void;
56
+ private resetAllCriteria;
55
57
  disconnectedCallback(): void;
56
58
  private clearScheduledRefetch;
57
59
  private scheduleRefetch;
@@ -61,7 +63,10 @@ export declare class TherapeuticAlternative extends LitElement {
61
63
  private static buildScopeFacets;
62
64
  private static buildIncludeFacets;
63
65
  private static buildExcludeFacets;
66
+ private static codesOf;
64
67
  private static deriveInitialScope;
68
+ private includePossessedIds;
69
+ private excludePossessedIds;
65
70
  private toggleScope;
66
71
  private toggleExclude;
67
72
  private toggleInclude;
@@ -84,9 +89,11 @@ export declare class TherapeuticAlternative extends LitElement {
84
89
  private renderExclusionSection;
85
90
  private renderIncludeSection;
86
91
  private renderQuickFiltersSection;
92
+ private renderQuickFilterCount;
87
93
  private renderSectionHeader;
88
94
  private matchReasonLabels;
89
95
  private renderResults;
96
+ private renderTitle;
90
97
  render(): TemplateResult<1>;
91
98
  static styles: CSSResult;
92
99
  }
@@ -2306,8 +2306,9 @@ const EXCLUSION_GROUPS = [
2306
2306
  { key: "notableExcipients", idsField: "notableExcipientIds", label: "Excipients à effet notoire" },
2307
2307
  { key: "excipients", idsField: "excipientIds", label: "Excipients" },
2308
2308
  { key: "contraindications", idsField: "contraindicationIds", label: "Utilisation contre-indiquée" },
2309
- { key: "cautions", idsField: "cautionIds", label: "Mises en garde" },
2310
- { key: "precautions", idsField: "precautionIds", label: "Précaution d'emploi" }
2309
+ { key: "cautions", idsField: "cautionIds", label: "Utilisation déconseillée" },
2310
+ { key: "precautions", idsField: "precautionIds", label: "Précaution d'emploi" },
2311
+ { key: "sideEffects", idsField: "sideEffectIds", label: "Effets indésirables" }
2311
2312
  ];
2312
2313
  const QUICK_FILTERS = [
2313
2314
  { key: "sameGalenicForm", label: "Même forme galénique" },
@@ -2326,7 +2327,7 @@ const MATCH_REASON_VERB_BY_DIMENSION = {
2326
2327
  indication: "indiqué pour",
2327
2328
  activeSubstance: "contient"
2328
2329
  };
2329
- const therapeuticAlternativeCSS = '.claudebernard-therapeutic-alternative {\n font-family: var(--custom-font-family, "Ubuntu"), sans-serif;\n padding: 1rem;\n}\n.claudebernard-therapeutic-alternative-without-title {\n padding-top: 0;\n max-width: 70vw;\n width: 60vw;\n max-height: 70vh;\n}\n.claudebernard-therapeutic-alternative-title {\n font-size: 0.75rem;\n font-weight: 700;\n letter-spacing: 0.04em;\n text-transform: uppercase;\n color: var(--bcbd-gray-500-color, #64748B);\n margin-bottom: 0.375rem;\n display: block;\n}\n.claudebernard-therapeutic-alternative__source {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 1rem;\n flex-wrap: wrap;\n}\n.claudebernard-therapeutic-alternative__disclaimer {\n margin-bottom: 1rem;\n}\n.claudebernard-therapeutic-alternative__loading {\n width: 100%;\n height: 30%;\n padding-top: 2rem;\n display: flex;\n justify-content: center;\n}\n.claudebernard-therapeutic-alternative__section {\n border: 1px solid var(--bcbd-border-gray-color, #CBD5E1);\n border-radius: 0.625rem;\n padding: 0.75rem 0.875rem;\n margin-bottom: 1rem;\n}\n.claudebernard-therapeutic-alternative__section-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n width: 100%;\n cursor: pointer;\n background: none;\n border: none;\n padding: 0;\n margin-bottom: 0.625rem;\n font-family: inherit;\n line-height: 1;\n}\n.claudebernard-therapeutic-alternative__section-header span:first-child {\n font-size: 0.75rem;\n font-weight: 700;\n color: var(--bcbd-gray-500-color, #64748B);\n text-transform: uppercase;\n letter-spacing: 0.03em;\n}\n.claudebernard-therapeutic-alternative__chevron {\n font-size: 0.75rem;\n color: var(--bcbd-gray-400-color, #94A3B8);\n transition: transform 0.15s ease-out;\n display: inline-flex;\n}\n.claudebernard-therapeutic-alternative__chevron--expanded {\n transform: rotate(180deg);\n}\n.claudebernard-therapeutic-alternative__pills {\n display: flex;\n gap: 0.5rem;\n flex-wrap: wrap;\n}\n.claudebernard-therapeutic-alternative__pill {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n border: 1px solid var(--bcbd-border-gray-color, #CBD5E1);\n background: #fff;\n color: var(--bcbd-gray-600-color, #475569);\n border-radius: 6.25rem;\n padding: 0.375rem 0.75rem;\n font-size: 0.8125rem;\n font-family: inherit;\n font-weight: 400;\n white-space: nowrap;\n cursor: pointer;\n line-height: 1;\n}\n.claudebernard-therapeutic-alternative__pill--active {\n border-color: var(--bcbd-primary-color, #0C75AD);\n background: color-mix(in srgb, var(--bcbd-primary-color, #0C75AD) 10%, transparent);\n color: var(--bcbd-primary-color, #0C75AD);\n font-weight: 700;\n}\n.claudebernard-therapeutic-alternative__panel {\n border-top: 1px solid var(--bcbd-border-color-200, #E2E8F0);\n margin-top: 0.75rem;\n padding-top: 0.75rem;\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n.claudebernard-therapeutic-alternative__panel-rows {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n max-height: 16.25rem;\n overflow-y: auto;\n padding: 0.25rem 0.125rem;\n}\n.claudebernard-therapeutic-alternative__panel-empty {\n display: block;\n margin-top: 0.75rem;\n font-size: 0.875rem;\n color: var(--bcbd-gray-500-color, #64748B);\n}\n.claudebernard-therapeutic-alternative__panel-expand {\n align-self: flex-start;\n background: none;\n border: none;\n padding: 0.25rem 0 0;\n font-family: inherit;\n font-size: 0.8125rem;\n font-weight: 700;\n color: var(--bcbd-primary-color, #0C75AD);\n cursor: pointer;\n}\n.claudebernard-therapeutic-alternative__panel-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n border-radius: 0.375rem;\n --bcbd-checkbox-font-size: 0.875rem;\n --bcbd-checkbox-size: 0.9375rem;\n}\n.claudebernard-therapeutic-alternative__panel-row--pending {\n background: var(--bcbd-gray-100-color, #F1F5F9);\n padding: 0.25rem 0.375rem;\n margin: -0.25rem -0.375rem;\n}\n.claudebernard-therapeutic-alternative__count-badge {\n font-size: 0.75rem;\n color: var(--bcbd-white-color, #fff);\n background: var(--bcbd-primary-color, #0C75AD);\n border-radius: 0.25rem;\n padding: 0.125rem 0.375rem;\n flex-shrink: 0;\n}\n.claudebernard-therapeutic-alternative__selected-chips {\n display: flex;\n gap: 0.375rem;\n flex-wrap: wrap;\n margin-top: 0.5rem;\n}\n.claudebernard-therapeutic-alternative__chips {\n display: flex;\n gap: 0.5rem;\n flex-wrap: wrap;\n}\n.claudebernard-therapeutic-alternative__chip {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n border: 1px solid var(--bcbd-border-gray-color, #CBD5E1);\n background: #fff;\n color: var(--bcbd-gray-500-color, #64748B);\n border-radius: 6.25rem;\n padding: 0.375rem 0.75rem;\n font-size: 0.8125rem;\n font-family: inherit;\n font-weight: 400;\n white-space: nowrap;\n cursor: pointer;\n line-height: 1;\n}\n.claudebernard-therapeutic-alternative__chip--active {\n border-color: var(--bcbd-primary-color, #0C75AD);\n background: color-mix(in srgb, var(--bcbd-primary-color, #0C75AD) 10%, transparent);\n color: var(--bcbd-primary-color, #0C75AD);\n font-weight: 700;\n}\n.claudebernard-therapeutic-alternative__results {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n.claudebernard-therapeutic-alternative__results-header {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n margin-bottom: 0.625rem;\n}\n.claudebernard-therapeutic-alternative__results-badge {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n background: color-mix(in srgb, var(--bcbd-primary-color, #0C75AD) 10%, transparent);\n color: var(--bcbd-primary-color, #0C75AD);\n border-radius: 6.25rem;\n padding: 0.3125rem 0.75rem;\n font-size: 0.8125rem;\n font-weight: 700;\n line-height: 1;\n}\n.claudebernard-therapeutic-alternative__results-list {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n.claudebernard-therapeutic-alternative__no-results {\n text-align: center;\n padding: 1.5rem 1rem;\n color: var(--bcbd-gray-500-color, #64748B);\n font-size: 0.875rem;\n}\n.claudebernard-therapeutic-alternative__no-medication {\n padding: 1.25rem;\n}';
2330
+ const therapeuticAlternativeCSS = '.claudebernard-therapeutic-alternative {\n font-family: var(--custom-font-family, "Ubuntu"), sans-serif;\n padding: 1rem;\n}\n.claudebernard-therapeutic-alternative-without-title {\n padding-top: 0;\n max-width: 70vw;\n width: 60vw;\n max-height: 70vh;\n}\n.claudebernard-therapeutic-alternative-title {\n font-size: 0.75rem;\n font-weight: 700;\n letter-spacing: 0.04em;\n text-transform: uppercase;\n color: var(--bcbd-gray-500-color, #64748B);\n margin-bottom: 0.375rem;\n display: block;\n}\n.claudebernard-therapeutic-alternative__source {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 1rem;\n flex-wrap: wrap;\n}\n.claudebernard-therapeutic-alternative__source .claudebernard-therapeutic-alternative-title {\n margin-bottom: 0;\n}\n.claudebernard-therapeutic-alternative__source-actions {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n flex-wrap: wrap;\n}\n.claudebernard-therapeutic-alternative__disclaimer {\n margin-bottom: 1rem;\n}\n.claudebernard-therapeutic-alternative__loading {\n width: 100%;\n height: 30%;\n padding-top: 2rem;\n display: flex;\n justify-content: center;\n}\n.claudebernard-therapeutic-alternative__section {\n border: 1px solid var(--bcbd-border-gray-color, #CBD5E1);\n border-radius: 0.625rem;\n padding: 0.75rem 0.875rem;\n margin-bottom: 1rem;\n}\n.claudebernard-therapeutic-alternative__section-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n width: 100%;\n cursor: pointer;\n background: none;\n border: none;\n padding: 0;\n margin-bottom: 0.625rem;\n font-family: inherit;\n line-height: 1;\n}\n.claudebernard-therapeutic-alternative__section-header span:first-child {\n font-size: 0.75rem;\n font-weight: 700;\n color: var(--bcbd-gray-500-color, #64748B);\n text-transform: uppercase;\n letter-spacing: 0.03em;\n}\n.claudebernard-therapeutic-alternative__chevron {\n font-size: 0.75rem;\n color: var(--bcbd-gray-400-color, #94A3B8);\n transition: transform 0.15s ease-out;\n display: inline-flex;\n}\n.claudebernard-therapeutic-alternative__chevron--expanded {\n transform: rotate(180deg);\n}\n.claudebernard-therapeutic-alternative__pills {\n display: flex;\n gap: 0.5rem;\n flex-wrap: wrap;\n}\n.claudebernard-therapeutic-alternative__pill {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n border: 1px solid var(--bcbd-border-gray-color, #CBD5E1);\n background: #fff;\n color: var(--bcbd-gray-600-color, #475569);\n border-radius: 6.25rem;\n padding: 0.375rem 0.75rem;\n font-size: 0.8125rem;\n font-family: inherit;\n font-weight: 400;\n white-space: nowrap;\n cursor: pointer;\n line-height: 1;\n}\n.claudebernard-therapeutic-alternative__pill--active {\n border-color: var(--bcbd-primary-color, #0C75AD);\n background: color-mix(in srgb, var(--bcbd-primary-color, #0C75AD) 10%, transparent);\n color: var(--bcbd-primary-color, #0C75AD);\n font-weight: 700;\n}\n.claudebernard-therapeutic-alternative__panel {\n border-top: 1px solid var(--bcbd-border-color-200, #E2E8F0);\n margin-top: 0.75rem;\n padding-top: 0.75rem;\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n.claudebernard-therapeutic-alternative__panel-rows {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n max-height: 16.25rem;\n overflow-y: auto;\n padding: 0.25rem 0.125rem;\n}\n.claudebernard-therapeutic-alternative__panel-empty {\n display: block;\n margin-top: 0.75rem;\n font-size: 0.875rem;\n color: var(--bcbd-gray-500-color, #64748B);\n}\n.claudebernard-therapeutic-alternative__panel-expand {\n align-self: flex-start;\n background: none;\n border: none;\n padding: 0.25rem 0 0;\n font-family: inherit;\n font-size: 0.8125rem;\n font-weight: 700;\n color: var(--bcbd-primary-color, #0C75AD);\n cursor: pointer;\n}\n.claudebernard-therapeutic-alternative__panel-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n border-radius: 0.375rem;\n --bcbd-checkbox-font-size: 0.875rem;\n --bcbd-checkbox-size: 0.9375rem;\n}\n.claudebernard-therapeutic-alternative__panel-row--pending {\n background: var(--bcbd-gray-100-color, #F1F5F9);\n padding: 0.25rem 0.375rem;\n margin: -0.25rem -0.375rem;\n}\n.claudebernard-therapeutic-alternative__panel-row--possessed {\n font-weight: 700;\n}\n.claudebernard-therapeutic-alternative__count-badge {\n font-size: 0.75rem;\n color: var(--bcbd-white-color, #fff);\n background: var(--bcbd-primary-color, #0C75AD);\n border-radius: 0.25rem;\n padding: 0.125rem 0.375rem;\n flex-shrink: 0;\n}\n.claudebernard-therapeutic-alternative__selected-chips {\n display: flex;\n gap: 0.375rem;\n flex-wrap: wrap;\n margin-top: 0.5rem;\n}\n.claudebernard-therapeutic-alternative__results {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n.claudebernard-therapeutic-alternative__results-header {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n margin-bottom: 0.625rem;\n}\n.claudebernard-therapeutic-alternative__results-badge {\n display: inline-flex;\n align-items: center;\n gap: 0.375rem;\n background: color-mix(in srgb, var(--bcbd-primary-color, #0C75AD) 10%, transparent);\n color: var(--bcbd-primary-color, #0C75AD);\n border-radius: 6.25rem;\n padding: 0.3125rem 0.75rem;\n font-size: 0.8125rem;\n font-weight: 700;\n line-height: 1;\n}\n.claudebernard-therapeutic-alternative__results-list {\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n}\n.claudebernard-therapeutic-alternative__no-results {\n text-align: center;\n padding: 1.5rem 1rem;\n color: var(--bcbd-gray-500-color, #64748B);\n font-size: 0.875rem;\n}\n.claudebernard-therapeutic-alternative__no-medication {\n padding: 1.25rem;\n}';
2330
2331
  function emptyScopeCriteria() {
2331
2332
  return { indicationIds: [], atcClassIds: [] };
2332
2333
  }
@@ -2340,7 +2341,8 @@ function emptyExcludeCriteria() {
2340
2341
  excipientIds: [],
2341
2342
  contraindicationIds: [],
2342
2343
  cautionIds: [],
2343
- precautionIds: []
2344
+ precautionIds: [],
2345
+ sideEffectIds: []
2344
2346
  };
2345
2347
  }
2346
2348
  function emptyQuickFilters() {
@@ -2359,7 +2361,8 @@ function emptyExcludeFacets() {
2359
2361
  excipients: [],
2360
2362
  contraindications: [],
2361
2363
  cautions: [],
2362
- precautions: []
2364
+ precautions: [],
2365
+ sideEffects: []
2363
2366
  };
2364
2367
  }
2365
2368
  function emptyScopeLabels() {
@@ -2386,7 +2389,8 @@ function emptyExcludeLabels() {
2386
2389
  excipients: {},
2387
2390
  contraindications: {},
2388
2391
  cautions: {},
2389
- precautions: {}
2392
+ precautions: {},
2393
+ sideEffects: {}
2390
2394
  };
2391
2395
  }
2392
2396
  var __defProp = Object.defineProperty;
@@ -2415,6 +2419,7 @@ let TherapeuticAlternative = class extends i$1 {
2415
2419
  this.include = emptyIncludeCriteria();
2416
2420
  this.exclude = emptyExcludeCriteria();
2417
2421
  this.quickFilters = emptyQuickFilters();
2422
+ this.quickFilterFacets = {};
2418
2423
  this.scopeFacets = emptyScopeFacets();
2419
2424
  this.includeFacets = emptyIncludeFacets();
2420
2425
  this.excludeFacets = emptyExcludeFacets();
@@ -2457,23 +2462,30 @@ let TherapeuticAlternative = class extends i$1 {
2457
2462
  });
2458
2463
  }
2459
2464
  if (changedProperties.has("medication") && this.currentMedication) {
2460
- this.clearScheduledRefetch();
2461
- this.scope = emptyScopeCriteria();
2462
- this.include = emptyIncludeCriteria();
2463
- this.exclude = emptyExcludeCriteria();
2464
- this.scopeLabels = emptyScopeLabels();
2465
- this.includeLabels = emptyIncludeLabels();
2466
- this.excludeLabels = emptyExcludeLabels();
2467
- this.quickFilters = emptyQuickFilters();
2468
- this.openScopeGroup = null;
2469
- this.openExclusionGroup = null;
2470
- this.openIncludeGroup = null;
2471
- this.expandFacetGroupKey = null;
2472
- this.currentPage = 1;
2473
- this.hasAppliedInitialScope = false;
2474
- this.fetchAlternatives();
2465
+ this.resetAllCriteria();
2475
2466
  }
2476
2467
  }
2468
+ // Shared by a medication change (updated() above) and the user-facing "Réinitialiser" button:
2469
+ // both mean "start over from the initial state for this medication" -- clearing
2470
+ // hasAppliedInitialScope so the next response re-derives and re-applies scope's own pre-check
2471
+ // (see applyResponse) rather than leaving scope empty, which would NOT be the initial state.
2472
+ resetAllCriteria() {
2473
+ this.clearScheduledRefetch();
2474
+ this.scope = emptyScopeCriteria();
2475
+ this.include = emptyIncludeCriteria();
2476
+ this.exclude = emptyExcludeCriteria();
2477
+ this.scopeLabels = emptyScopeLabels();
2478
+ this.includeLabels = emptyIncludeLabels();
2479
+ this.excludeLabels = emptyExcludeLabels();
2480
+ this.quickFilters = emptyQuickFilters();
2481
+ this.openScopeGroup = null;
2482
+ this.openExclusionGroup = null;
2483
+ this.openIncludeGroup = null;
2484
+ this.expandFacetGroupKey = null;
2485
+ this.currentPage = 1;
2486
+ this.hasAppliedInitialScope = false;
2487
+ this.fetchAlternatives();
2488
+ }
2477
2489
  disconnectedCallback() {
2478
2490
  super.disconnectedCallback();
2479
2491
  this.clearScheduledRefetch();
@@ -2541,6 +2553,7 @@ let TherapeuticAlternative = class extends i$1 {
2541
2553
  this.scopeFacets = TherapeuticAlternative.buildScopeFacets(data);
2542
2554
  this.includeFacets = TherapeuticAlternative.buildIncludeFacets(data);
2543
2555
  this.excludeFacets = TherapeuticAlternative.buildExcludeFacets(data);
2556
+ this.quickFilterFacets = data.facets?.quickFilters ?? {};
2544
2557
  this.truncatedGroups = data.facets?.truncatedGroups ?? [];
2545
2558
  if (!this.hasAppliedInitialScope) {
2546
2559
  this.hasAppliedInitialScope = true;
@@ -2566,19 +2579,18 @@ let TherapeuticAlternative = class extends i$1 {
2566
2579
  };
2567
2580
  }
2568
2581
  static buildExcludeFacets(data) {
2569
- return {
2570
- activeSubstances: data.facets?.exclude?.activeSubstances ?? [],
2571
- notableExcipients: data.facets?.exclude?.notableExcipients ?? [],
2572
- excipients: data.facets?.exclude?.excipients ?? [],
2573
- contraindications: data.facets?.exclude?.contraindications ?? [],
2574
- cautions: data.facets?.exclude?.cautions ?? [],
2575
- precautions: data.facets?.exclude?.precautions ?? []
2576
- };
2582
+ const facets = emptyExcludeFacets();
2583
+ for (const group of EXCLUSION_GROUPS) {
2584
+ facets[group.key] = data.facets?.exclude?.[group.key] ?? [];
2585
+ }
2586
+ return facets;
2587
+ }
2588
+ static codesOf(list) {
2589
+ return (list ?? []).map((item) => item.code).filter((code) => !!code);
2577
2590
  }
2578
2591
  static deriveInitialScope(sourceProduct) {
2579
- const codesOf = (list) => (list ?? []).map((item) => item.code).filter((code) => !!code);
2580
2592
  return {
2581
- indicationIds: codesOf(sourceProduct?.extendedProperties?.keywords?.indicationsKeywords),
2593
+ indicationIds: TherapeuticAlternative.codesOf(sourceProduct?.extendedProperties?.keywords?.indicationsKeywords),
2582
2594
  // Contrairement à indications (une liste plate de valeurs propres au produit),
2583
2595
  // sourceProduct.properties.atcClasses est un fil d'Ariane hiérarchique (classe > sous-classe
2584
2596
  // > ... > code le plus spécifique, ex: M, M01, M01A, M01AX, M01AX02) — les mapper tous comme
@@ -2590,6 +2602,54 @@ let TherapeuticAlternative = class extends i$1 {
2590
2602
  atcClassIds: []
2591
2603
  };
2592
2604
  }
2605
+ // The ids to bold in an include checklist panel (see renderChecklistPanel's possessedIds param)
2606
+ // -- what the SOURCE product itself already has for that dimension, not what's currently
2607
+ // selected. galenicForms/dosages are single-valued on the source (a product has exactly one), so
2608
+ // each contributes at most one id; activeSubstances/routesOfAdministration can be multi-valued.
2609
+ // dosages is a best-effort string match (source's raw productDosage against the facet's own
2610
+ // dosage-string ids) -- it can occasionally miss on formatting, unlike the others' exact codes.
2611
+ includePossessedIds(key) {
2612
+ const properties = this.sourceProduct?.properties;
2613
+ const composition = this.sourceProduct?.extendedProperties?.composition;
2614
+ switch (key) {
2615
+ case "activeSubstances":
2616
+ return new Set(TherapeuticAlternative.codesOf(composition?.activeSubstances));
2617
+ case "galenicForms":
2618
+ return properties?.galenicFormCode ? /* @__PURE__ */ new Set([properties.galenicFormCode]) : /* @__PURE__ */ new Set();
2619
+ case "dosages":
2620
+ return properties?.productDosage ? /* @__PURE__ */ new Set([properties.productDosage]) : /* @__PURE__ */ new Set();
2621
+ case "routesOfAdministration":
2622
+ return new Set(TherapeuticAlternative.codesOf(this.sourceProduct?.extendedProperties?.routes));
2623
+ default:
2624
+ return /* @__PURE__ */ new Set();
2625
+ }
2626
+ }
2627
+ // Same idea as includePossessedIds, for the exclude checklist panels: the exclude groups' own
2628
+ // values come from the whole candidate pool (see SearchCustomService.addExcludeMustNotQueries),
2629
+ // not just the source product, so "does the source itself already have this excipient/
2630
+ // contraindication/..." is a real, non-trivial question worth answering here too.
2631
+ excludePossessedIds(key) {
2632
+ const composition = this.sourceProduct?.extendedProperties?.composition;
2633
+ const keywords = this.sourceProduct?.extendedProperties?.keywords;
2634
+ switch (key) {
2635
+ case "activeSubstances":
2636
+ return new Set(TherapeuticAlternative.codesOf(composition?.activeSubstances));
2637
+ case "notableExcipients":
2638
+ return new Set(TherapeuticAlternative.codesOf(composition?.excipientsWithKnownEffects));
2639
+ case "excipients":
2640
+ return new Set(TherapeuticAlternative.codesOf(composition?.excipients));
2641
+ case "contraindications":
2642
+ return new Set(TherapeuticAlternative.codesOf(keywords?.contraindicationsKeywords));
2643
+ case "cautions":
2644
+ return new Set(TherapeuticAlternative.codesOf(keywords?.contraindicationsNotRecommendedKeywords));
2645
+ case "precautions":
2646
+ return new Set(TherapeuticAlternative.codesOf(keywords?.precautionsForUseKeywords));
2647
+ case "sideEffects":
2648
+ return new Set(TherapeuticAlternative.codesOf(keywords?.sideEffectsKeywords));
2649
+ default:
2650
+ return /* @__PURE__ */ new Set();
2651
+ }
2652
+ }
2593
2653
  // label n'est utilisé que sur la branche "coche" (pour alimenter scopeLabels/includeLabels/
2594
2654
  // excludeLabels — voir emptyScopeLabels) ; sur la branche "décoche" l'id est simplement retiré
2595
2655
  // des deux côtés, que l'appelant soit une checkbox du panel (qui a le label sous la main) ou un
@@ -2658,6 +2718,7 @@ let TherapeuticAlternative = class extends i$1 {
2658
2718
  this.includeLabels = { ...this.includeLabels, [group.key]: {} };
2659
2719
  }
2660
2720
  }
2721
+ this.pendingToggleIds = new Set(this.pendingToggleIds).add(key);
2661
2722
  this.scheduleRefetch();
2662
2723
  }
2663
2724
  // The exclude "activeSubstances" group's own backend/truncatedGroups key is
@@ -2761,7 +2822,7 @@ let TherapeuticAlternative = class extends i$1 {
2761
2822
  this.apiReplaceLoading = false;
2762
2823
  }
2763
2824
  }
2764
- renderChecklistPanel(items, selectedIds, showCount, countTooltip, onToggle, testIdPrefix, showCode = false, truncated = false, onExpand) {
2825
+ renderChecklistPanel(items, selectedIds, showCount, countTooltip, onToggle, testIdPrefix, showCode = false, truncated = false, onExpand, possessedIds = /* @__PURE__ */ new Set()) {
2765
2826
  const visibleItems = items.filter((item) => {
2766
2827
  if (item.id !== void 0 && this.pendingToggleIds.has(item.id)) {
2767
2828
  return true;
@@ -2788,7 +2849,8 @@ let TherapeuticAlternative = class extends i$1 {
2788
2849
  const pending = this.pendingToggleIds.has(item.id);
2789
2850
  const rowClasses = [
2790
2851
  `${PREFIX}-therapeutic-alternative__panel-row`,
2791
- pending ? `${PREFIX}-therapeutic-alternative__panel-row--pending` : ""
2852
+ pending ? `${PREFIX}-therapeutic-alternative__panel-row--pending` : "",
2853
+ possessedIds.has(item.id) ? `${PREFIX}-therapeutic-alternative__panel-row--possessed` : ""
2792
2854
  ].join(" ");
2793
2855
  return b`
2794
2856
  <div class=${rowClasses}>
@@ -2974,7 +3036,8 @@ let TherapeuticAlternative = class extends i$1 {
2974
3036
  `exclusion-${openGroup.key}`,
2975
3037
  false,
2976
3038
  canExpand,
2977
- () => this.requestMoreFacetValues(truncatedGroupKey)
3039
+ () => this.requestMoreFacetValues(truncatedGroupKey),
3040
+ this.excludePossessedIds(openGroup.key)
2978
3041
  ) : A}
2979
3042
  `;
2980
3043
  }
@@ -3012,7 +3075,8 @@ let TherapeuticAlternative = class extends i$1 {
3012
3075
  `include-${openGroup.key}`,
3013
3076
  false,
3014
3077
  canExpand,
3015
- () => this.requestMoreFacetValues(truncatedGroupKey)
3078
+ () => this.requestMoreFacetValues(truncatedGroupKey),
3079
+ this.includePossessedIds(openGroup.key)
3016
3080
  ) : A}
3017
3081
  `;
3018
3082
  }
@@ -3020,25 +3084,56 @@ let TherapeuticAlternative = class extends i$1 {
3020
3084
  if (this.sectionCollapsed.quickFilters) {
3021
3085
  return A;
3022
3086
  }
3023
- const chips = QUICK_FILTERS.map((filter) => {
3024
- const active = this.quickFilters[filter.key];
3025
- const chipClasses = [
3026
- `${PREFIX}-therapeutic-alternative__chip`,
3027
- active ? `${PREFIX}-therapeutic-alternative__chip--active` : ""
3087
+ const visibleFilters = QUICK_FILTERS.filter((filter) => {
3088
+ if (this.quickFilters[filter.key] || this.pendingToggleIds.has(filter.key)) {
3089
+ return true;
3090
+ }
3091
+ return this.quickFilterFacets[filter.key] !== 0;
3092
+ });
3093
+ if (visibleFilters.length === 0) {
3094
+ return b`<span class="${PREFIX}-therapeutic-alternative__panel-empty">Aucune valeur disponible.</span>`;
3095
+ }
3096
+ const rows = visibleFilters.map((filter) => {
3097
+ const count = this.quickFilterFacets[filter.key];
3098
+ const pending = this.pendingToggleIds.has(filter.key);
3099
+ const rowClasses = [
3100
+ `${PREFIX}-therapeutic-alternative__panel-row`,
3101
+ pending ? `${PREFIX}-therapeutic-alternative__panel-row--pending` : ""
3028
3102
  ].join(" ");
3029
3103
  return b`
3030
- <button type="button" class=${chipClasses} @click=${() => this.toggleQuickFilter(filter.key)} data-test-id=${`quick-filter-${filter.key}`}>
3031
- ${active ? b`<bcbd-icon icon="check" size="extra-small"></bcbd-icon>` : A}
3032
- ${filter.label}
3033
- </button>
3104
+ <div class=${rowClasses}>
3105
+ <bcbd-checkbox
3106
+ id=${`quick-filter-${filter.key}`}
3107
+ label=${filter.label}
3108
+ ?checked=${this.quickFilters[filter.key]}
3109
+ color="primary"
3110
+ @change=${() => this.toggleQuickFilter(filter.key)}
3111
+ data-test-id=${`quick-filter-${filter.key}`}>
3112
+ </bcbd-checkbox>
3113
+ ${pending ? b`
3114
+ <bcbd-loader theme="standard" size="18" data-test-id=${`quick-filter-loader-${filter.key}`}></bcbd-loader>
3115
+ ` : this.renderQuickFilterCount(filter.key, count)}
3116
+ </div>
3034
3117
  `;
3035
3118
  });
3036
3119
  return b`
3037
- <div class="${PREFIX}-therapeutic-alternative__chips" data-test-id="quick-filters-chips">
3038
- ${chips}
3120
+ <div class="${PREFIX}-therapeutic-alternative__panel" data-test-id="quick-filters-panel">
3121
+ <div class="${PREFIX}-therapeutic-alternative__panel-rows">
3122
+ ${rows}
3123
+ </div>
3039
3124
  </div>
3040
3125
  `;
3041
3126
  }
3127
+ renderQuickFilterCount(key, count) {
3128
+ if (count === void 0) {
3129
+ return A;
3130
+ }
3131
+ return b`
3132
+ <bcbd-tooltip placement="left" content=${INCLUDE_COUNT_TOOLTIP} data-test-id=${`quick-filter-count-tooltip-${key}`}>
3133
+ <span class="${PREFIX}-therapeutic-alternative__count-badge" data-test-id=${`quick-filter-count-${key}`}>${count}</span>
3134
+ </bcbd-tooltip>
3135
+ `;
3136
+ }
3042
3137
  renderSectionHeader(title, section) {
3043
3138
  const collapsed = this.sectionCollapsed[section];
3044
3139
  const chevronClasses = [
@@ -3130,6 +3225,11 @@ let TherapeuticAlternative = class extends i$1 {
3130
3225
  </bcbd-pagination>`}
3131
3226
  `;
3132
3227
  }
3228
+ // The product name in the title replaces the "Produit sélectionné" line when has-title is on; without
3229
+ // a title, that line (see render) is the only place the product name shows.
3230
+ renderTitle(medicationTitle) {
3231
+ return b`<span class="${PREFIX}-therapeutic-alternative-title" data-test-id="title">Alternative Thérapeutique pour ${medicationTitle !== "" ? decodeHtml(medicationTitle) : "ce produit"}</span>`;
3232
+ }
3133
3233
  render() {
3134
3234
  const containerClasses = [
3135
3235
  `${PREFIX}-therapeutic-alternative`,
@@ -3138,16 +3238,23 @@ let TherapeuticAlternative = class extends i$1 {
3138
3238
  const medicationTitle = getMedicationTitle(this.currentMedication);
3139
3239
  return b`
3140
3240
  <div class=${containerClasses} data-test-id="therapeutic-alternative-container">
3141
- ${this.hasTitle ? b`<span class="${PREFIX}-therapeutic-alternative-title">Alternative thérapeutique</span>` : ""}
3142
3241
  ${this.currentMedication ? b`
3143
3242
  <div class="${PREFIX}-therapeutic-alternative__source mb-3" data-test-id="source-product">
3144
- <span data-test-id="source-product-label">
3145
- Produit sélectionné : <span class="text-primary">${medicationTitle !== "" ? decodeHtml(medicationTitle) : "Inconnu"}</span>
3146
- </span>
3147
- <bcbd-button size="small" background-color="primary" outlined
3148
- @click=${this.cancelAlternative} data-test-id="cancel-alternative-button">
3149
- Retour au contrôle d'ordonnance
3150
- </bcbd-button>
3243
+ ${this.hasTitle ? this.renderTitle(medicationTitle) : b`
3244
+ <span data-test-id="source-product-label">
3245
+ Produit sélectionné : <span class="text-primary">${medicationTitle !== "" ? decodeHtml(medicationTitle) : "Inconnu"}</span>
3246
+ </span>`}
3247
+ <div class="${PREFIX}-therapeutic-alternative__source-actions">
3248
+ <bcbd-button size="small" background-color="secondary" outlined
3249
+ ?disabled=${this.hasNoSelectedCriteria()}
3250
+ @click=${this.resetAllCriteria} data-test-id="reset-criteria-button">
3251
+ Réinitialiser
3252
+ </bcbd-button>
3253
+ <bcbd-button size="small" background-color="primary" outlined
3254
+ @click=${this.cancelAlternative} data-test-id="cancel-alternative-button">
3255
+ Annuler
3256
+ </bcbd-button>
3257
+ </div>
3151
3258
  </div>
3152
3259
 
3153
3260
  <div class="${PREFIX}-therapeutic-alternative__disclaimer">
@@ -3190,6 +3297,7 @@ let TherapeuticAlternative = class extends i$1 {
3190
3297
  <div class="${PREFIX}-therapeutic-alternative__results" data-test-id="results-container">
3191
3298
  ${this.renderResults()}
3192
3299
  </div>` : b`
3300
+ ${this.hasTitle ? this.renderTitle(medicationTitle) : ""}
3193
3301
  <div class="${PREFIX}-therapeutic-alternative__no-medication" data-test-id="no-medication-container">
3194
3302
  <bcbd-alert title-message="Pas de médicament sélectionné"
3195
3303
  description-message="Un problème est survenu au moment de sélectionner le produit"
@@ -3243,6 +3351,9 @@ __decorateClass([
3243
3351
  __decorateClass([
3244
3352
  r()
3245
3353
  ], TherapeuticAlternative.prototype, "quickFilters", 2);
3354
+ __decorateClass([
3355
+ r()
3356
+ ], TherapeuticAlternative.prototype, "quickFilterFacets", 2);
3246
3357
  __decorateClass([
3247
3358
  r()
3248
3359
  ], TherapeuticAlternative.prototype, "scopeFacets", 2);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@claudebernard/therapeutic-alternative-element",
3
- "version": "2.2.0",
3
+ "version": "2.3.0",
4
4
  "main": "dist/therapeutic-alternative.es.js",
5
5
  "module": "dist/therapeutic-alternative.es.js",
6
6
  "types": "dist/therapeutic-alternative.d.ts",