@claudebernard/therapeutic-alternative-element 2.2.0 → 2.4.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.
|
@@ -17,6 +17,12 @@ export declare class TherapeuticAlternative extends LitElement {
|
|
|
17
17
|
patientProfile: Bundle | null;
|
|
18
18
|
apiUrl: string;
|
|
19
19
|
apiKey: string | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* Contexte d'intégration (application consommatrice + chaîne de web components BCB parents)
|
|
22
|
+
* transmis par l'intégrateur, propagé sur chaque appel API sortant via des en-têtes dédiés -
|
|
23
|
+
* voir `@shared/utils/tracing`. N'inclut pas ce composant lui-même dans `ancestry`.
|
|
24
|
+
*/
|
|
25
|
+
context: WebComponentContext | undefined;
|
|
20
26
|
private sourceProduct;
|
|
21
27
|
private results;
|
|
22
28
|
private totalElements;
|
|
@@ -26,6 +32,7 @@ export declare class TherapeuticAlternative extends LitElement {
|
|
|
26
32
|
private include;
|
|
27
33
|
private exclude;
|
|
28
34
|
private quickFilters;
|
|
35
|
+
private quickFilterFacets;
|
|
29
36
|
private scopeFacets;
|
|
30
37
|
private includeFacets;
|
|
31
38
|
private excludeFacets;
|
|
@@ -45,13 +52,15 @@ export declare class TherapeuticAlternative extends LitElement {
|
|
|
45
52
|
private apiReplaceError;
|
|
46
53
|
private apiReplaceLoading;
|
|
47
54
|
private missingPrescriptionError;
|
|
48
|
-
private hasAppliedInitialScope;
|
|
49
55
|
private refetchTimer;
|
|
50
56
|
private requestSeq;
|
|
51
57
|
private get currentMedication();
|
|
52
58
|
private get currentMedicationRequest();
|
|
53
59
|
private get sourceProductId();
|
|
60
|
+
private get sourceProductLabel();
|
|
61
|
+
private get isParaSource();
|
|
54
62
|
updated(changedProperties: Map<string | number | symbol, unknown>): void;
|
|
63
|
+
private resetAllCriteria;
|
|
55
64
|
disconnectedCallback(): void;
|
|
56
65
|
private clearScheduledRefetch;
|
|
57
66
|
private scheduleRefetch;
|
|
@@ -61,7 +70,10 @@ export declare class TherapeuticAlternative extends LitElement {
|
|
|
61
70
|
private static buildScopeFacets;
|
|
62
71
|
private static buildIncludeFacets;
|
|
63
72
|
private static buildExcludeFacets;
|
|
64
|
-
private static
|
|
73
|
+
private static codesOf;
|
|
74
|
+
private scopePossessedIds;
|
|
75
|
+
private includePossessedIds;
|
|
76
|
+
private excludePossessedIds;
|
|
65
77
|
private toggleScope;
|
|
66
78
|
private toggleExclude;
|
|
67
79
|
private toggleInclude;
|
|
@@ -84,13 +96,36 @@ export declare class TherapeuticAlternative extends LitElement {
|
|
|
84
96
|
private renderExclusionSection;
|
|
85
97
|
private renderIncludeSection;
|
|
86
98
|
private renderQuickFiltersSection;
|
|
99
|
+
private renderQuickFilterCount;
|
|
87
100
|
private renderSectionHeader;
|
|
88
101
|
private matchReasonLabels;
|
|
89
102
|
private renderResults;
|
|
103
|
+
private renderTitle;
|
|
90
104
|
render(): TemplateResult<1>;
|
|
91
105
|
static styles: CSSResult;
|
|
92
106
|
}
|
|
93
107
|
|
|
108
|
+
/**
|
|
109
|
+
* Contexte d'intégration porté par une instance du composant : quelle application consommatrice
|
|
110
|
+
* (Equasens, Maiia officine, ...) et quelle chaîne de web components BCB imbriqués ont mené jusqu'à
|
|
111
|
+
* cet appel. Les deux champs sont optionnels et indépendants - un intégrateur peut renseigner l'un
|
|
112
|
+
* sans l'autre.
|
|
113
|
+
*/
|
|
114
|
+
declare interface WebComponentContext {
|
|
115
|
+
/** Application consommatrice, ex: "equasens" ou "equasens@1.3.1". Envoyé tel quel. */
|
|
116
|
+
consumer?: string;
|
|
117
|
+
/**
|
|
118
|
+
* Chaîne des web components BCB parents, du plus extérieur au plus proche - N'INCLUT PAS le
|
|
119
|
+
* composant courant. Ex: pour Equasens -> shared-medication-review -> medication-request-editor
|
|
120
|
+
* -> ce composant, `ancestry` vaut [{name: "shared-medication-review", ...}, {name:
|
|
121
|
+
* "medication-request-editor", ...}].
|
|
122
|
+
*/
|
|
123
|
+
ancestry?: Array<{
|
|
124
|
+
name: string;
|
|
125
|
+
version: string;
|
|
126
|
+
}>;
|
|
127
|
+
}
|
|
128
|
+
|
|
94
129
|
|
|
95
130
|
export * from "@claudebernard/web-component-fhir-utils";
|
|
96
131
|
|
|
@@ -775,6 +775,67 @@ const getFhirPosologies = (options) => (options?.client ?? client$1).post({
|
|
|
775
775
|
...options?.headers
|
|
776
776
|
}
|
|
777
777
|
});
|
|
778
|
+
function random$1(len) {
|
|
779
|
+
return crypto.getRandomValues(new Uint8Array(len));
|
|
780
|
+
}
|
|
781
|
+
const W3C_TRACEPARENT_VERSION = "00";
|
|
782
|
+
const FLAG_SAMPLE = 1;
|
|
783
|
+
const FLAG_RANDOM = 2;
|
|
784
|
+
function traceparent(version, trace_id, parent_id, flags) {
|
|
785
|
+
return {
|
|
786
|
+
version,
|
|
787
|
+
trace_id,
|
|
788
|
+
parent_id,
|
|
789
|
+
flags,
|
|
790
|
+
child() {
|
|
791
|
+
return traceparent(this.version, this.trace_id, random(8), this.flags);
|
|
792
|
+
},
|
|
793
|
+
toString() {
|
|
794
|
+
let flags2 = this.flags.toString(16).padStart(2, "0");
|
|
795
|
+
return `${this.version}-${this.trace_id}-${this.parent_id}-${flags2}`;
|
|
796
|
+
}
|
|
797
|
+
};
|
|
798
|
+
}
|
|
799
|
+
function make() {
|
|
800
|
+
let id = random(24);
|
|
801
|
+
return traceparent(W3C_TRACEPARENT_VERSION, id.slice(0, 32), id.slice(32), FLAG_SAMPLE | FLAG_RANDOM);
|
|
802
|
+
}
|
|
803
|
+
let IDX = 256, HEX = [];
|
|
804
|
+
while (IDX--) HEX[IDX] = (IDX + 256).toString(16).substring(1);
|
|
805
|
+
function random(size) {
|
|
806
|
+
let a2 = random$1(size), i3 = 0, o2 = "";
|
|
807
|
+
for (; i3 < a2.length; i3++) o2 += HEX[a2[i3]];
|
|
808
|
+
return o2;
|
|
809
|
+
}
|
|
810
|
+
const COMPONENT_HEADERS = {
|
|
811
|
+
"Bcb-Web-Component-Package": "@claudebernard/therapeutic-alternative-element",
|
|
812
|
+
"Bcb-Web-Component-Version": "2.4"
|
|
813
|
+
};
|
|
814
|
+
let activeContext;
|
|
815
|
+
function setActiveContext(context) {
|
|
816
|
+
activeContext = context;
|
|
817
|
+
}
|
|
818
|
+
function makeTraceparent() {
|
|
819
|
+
return make().child().toString();
|
|
820
|
+
}
|
|
821
|
+
function buildTracingHeaders() {
|
|
822
|
+
return {
|
|
823
|
+
traceparent: makeTraceparent(),
|
|
824
|
+
...COMPONENT_HEADERS,
|
|
825
|
+
...activeContext?.consumer ? { "Bcb-Consumer-Product": activeContext.consumer } : {},
|
|
826
|
+
...activeContext?.ancestry?.length ? { "Bcb-Web-Component-Chain": activeContext.ancestry.map(({ name, version }) => `${name}@${version}`).join(",") } : {}
|
|
827
|
+
};
|
|
828
|
+
}
|
|
829
|
+
function attachTracingHeaders(request) {
|
|
830
|
+
const defaults = buildTracingHeaders();
|
|
831
|
+
for (const [key, value] of Object.entries(defaults)) {
|
|
832
|
+
if (!request.headers.has(key)) {
|
|
833
|
+
request.headers.set(key, value);
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
return request;
|
|
837
|
+
}
|
|
838
|
+
client$1.interceptors.request.use(attachTracingHeaders);
|
|
778
839
|
const prescriptionApi = {
|
|
779
840
|
getFhirPosologies
|
|
780
841
|
};
|
|
@@ -1559,6 +1620,7 @@ const searchProductsById7 = (options) => (options.client ?? client).post({
|
|
|
1559
1620
|
...options.headers
|
|
1560
1621
|
}
|
|
1561
1622
|
});
|
|
1623
|
+
client.interceptors.request.use(attachTracingHeaders);
|
|
1562
1624
|
const searchApi = {
|
|
1563
1625
|
searchProductsByIndication: searchProductsById7,
|
|
1564
1626
|
searchAlternative
|
|
@@ -1642,7 +1704,7 @@ function findMostAdequateMedicationRequest(entries, threshold = DEFAULT_ADEQUATI
|
|
|
1642
1704
|
const medicationRequestEntry = entries.find((entry) => entry.resource?.resourceType === "MedicationRequest" && getAdequationScore(entry) <= threshold);
|
|
1643
1705
|
return medicationRequestEntry?.resource;
|
|
1644
1706
|
}
|
|
1645
|
-
const t$3 = globalThis, e$4 = t$3.ShadowRoot && (void 0 === t$3.ShadyCSS || t$3.ShadyCSS.nativeShadow) && "adoptedStyleSheets" in Document.prototype && "replace" in CSSStyleSheet.prototype, s$2 = /* @__PURE__ */ Symbol(), o$
|
|
1707
|
+
const t$3 = globalThis, e$4 = t$3.ShadowRoot && (void 0 === t$3.ShadyCSS || t$3.ShadyCSS.nativeShadow) && "adoptedStyleSheets" in Document.prototype && "replace" in CSSStyleSheet.prototype, s$2 = /* @__PURE__ */ Symbol(), o$6 = /* @__PURE__ */ new WeakMap();
|
|
1646
1708
|
let n$3 = class n {
|
|
1647
1709
|
constructor(t2, e2, o2) {
|
|
1648
1710
|
if (this._$cssResult$ = true, o2 !== s$2) throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");
|
|
@@ -1653,7 +1715,7 @@ let n$3 = class n {
|
|
|
1653
1715
|
const s2 = this.t;
|
|
1654
1716
|
if (e$4 && void 0 === t2) {
|
|
1655
1717
|
const e2 = void 0 !== s2 && 1 === s2.length;
|
|
1656
|
-
e2 && (t2 = o$
|
|
1718
|
+
e2 && (t2 = o$6.get(s2)), void 0 === t2 && ((this.o = t2 = new CSSStyleSheet()).replaceSync(this.cssText), e2 && o$6.set(s2, t2));
|
|
1657
1719
|
}
|
|
1658
1720
|
return t2;
|
|
1659
1721
|
}
|
|
@@ -1679,7 +1741,7 @@ const r$4 = (t2) => new n$3("string" == typeof t2 ? t2 : t2 + "", void 0, s$2),
|
|
|
1679
1741
|
for (const s2 of t3.cssRules) e2 += s2.cssText;
|
|
1680
1742
|
return r$4(e2);
|
|
1681
1743
|
})(t2) : t2;
|
|
1682
|
-
const { is: i$3, defineProperty: e$3, getOwnPropertyDescriptor: h$1, getOwnPropertyNames: r$3, getOwnPropertySymbols: o$
|
|
1744
|
+
const { is: i$3, defineProperty: e$3, getOwnPropertyDescriptor: h$1, getOwnPropertyNames: r$3, getOwnPropertySymbols: o$5, getPrototypeOf: n$2 } = Object, a$1 = globalThis, c$1 = a$1.trustedTypes, l$1 = c$1 ? c$1.emptyScript : "", p$1 = a$1.reactiveElementPolyfillSupport, d$1 = (t2, s2) => t2, u$1 = { toAttribute(t2, s2) {
|
|
1683
1745
|
switch (s2) {
|
|
1684
1746
|
case Boolean:
|
|
1685
1747
|
t2 = t2 ? l$1 : null;
|
|
@@ -1744,7 +1806,7 @@ let y$1 = class y extends HTMLElement {
|
|
|
1744
1806
|
static finalize() {
|
|
1745
1807
|
if (this.hasOwnProperty(d$1("finalized"))) return;
|
|
1746
1808
|
if (this.finalized = true, this._$Ei(), this.hasOwnProperty(d$1("properties"))) {
|
|
1747
|
-
const t3 = this.properties, s2 = [...r$3(t3), ...o$
|
|
1809
|
+
const t3 = this.properties, s2 = [...r$3(t3), ...o$5(t3)];
|
|
1748
1810
|
for (const i3 of s2) this.createProperty(i3, t3[i3]);
|
|
1749
1811
|
}
|
|
1750
1812
|
const t2 = this[Symbol.metadata];
|
|
@@ -1891,7 +1953,7 @@ let y$1 = class y extends HTMLElement {
|
|
|
1891
1953
|
}
|
|
1892
1954
|
};
|
|
1893
1955
|
y$1.elementStyles = [], y$1.shadowRootOptions = { mode: "open" }, y$1[d$1("elementProperties")] = /* @__PURE__ */ new Map(), y$1[d$1("finalized")] = /* @__PURE__ */ new Map(), p$1?.({ ReactiveElement: y$1 }), (a$1.reactiveElementVersions ??= []).push("2.1.2");
|
|
1894
|
-
const t$2 = globalThis, i$2 = (t2) => t2, s$1 = t$2.trustedTypes, e$2 = s$1 ? s$1.createPolicy("lit-html", { createHTML: (t2) => t2 }) : void 0, h = "$lit$", o$
|
|
1956
|
+
const t$2 = globalThis, i$2 = (t2) => t2, s$1 = t$2.trustedTypes, e$2 = s$1 ? s$1.createPolicy("lit-html", { createHTML: (t2) => t2 }) : void 0, h = "$lit$", o$4 = `lit$${Math.random().toFixed(9).slice(2)}$`, n$1 = "?" + o$4, r$2 = `<${n$1}>`, l = document, c = () => l.createComment(""), a = (t2) => null === t2 || "object" != typeof t2 && "function" != typeof t2, u = Array.isArray, d = (t2) => u(t2) || "function" == typeof t2?.[Symbol.iterator], f = "[ \n\f\r]", v = /<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g, _ = /-->/g, m = />/g, p = RegExp(`>|${f}(?:([^\\s"'>=/]+)(${f}*=${f}*(?:[^
|
|
1895
1957
|
\f\r"'\`<>=]|("|')|))|$)`, "g"), g = /'/g, $ = /"/g, y2 = /^(?:script|style|textarea|title)$/i, x = (t2) => (i3, ...s2) => ({ _$litType$: t2, strings: i3, values: s2 }), b = x(1), E = /* @__PURE__ */ Symbol.for("lit-noChange"), A = /* @__PURE__ */ Symbol.for("lit-nothing"), C = /* @__PURE__ */ new WeakMap(), P = l.createTreeWalker(l, 129);
|
|
1896
1958
|
function V(t2, i3) {
|
|
1897
1959
|
if (!u(t2) || !t2.hasOwnProperty("raw")) throw Error("invalid template strings array");
|
|
@@ -1905,7 +1967,7 @@ const N = (t2, i3) => {
|
|
|
1905
1967
|
let a2, u2, d2 = -1, f2 = 0;
|
|
1906
1968
|
for (; f2 < s3.length && (c2.lastIndex = f2, u2 = c2.exec(s3), null !== u2); ) f2 = c2.lastIndex, c2 === v ? "!--" === u2[1] ? c2 = _ : void 0 !== u2[1] ? c2 = m : void 0 !== u2[2] ? (y2.test(u2[2]) && (n3 = RegExp("</" + u2[2], "g")), c2 = p) : void 0 !== u2[3] && (c2 = p) : c2 === p ? ">" === u2[0] ? (c2 = n3 ?? v, d2 = -1) : void 0 === u2[1] ? d2 = -2 : (d2 = c2.lastIndex - u2[2].length, a2 = u2[1], c2 = void 0 === u2[3] ? p : '"' === u2[3] ? $ : g) : c2 === $ || c2 === g ? c2 = p : c2 === _ || c2 === m ? c2 = v : (c2 = p, n3 = void 0);
|
|
1907
1969
|
const x2 = c2 === p && t2[i4 + 1].startsWith("/>") ? " " : "";
|
|
1908
|
-
l2 += c2 === v ? s3 + r$2 : d2 >= 0 ? (e2.push(a2), s3.slice(0, d2) + h + s3.slice(d2) + o$
|
|
1970
|
+
l2 += c2 === v ? s3 + r$2 : d2 >= 0 ? (e2.push(a2), s3.slice(0, d2) + h + s3.slice(d2) + o$4 + x2) : s3 + o$4 + (-2 === d2 ? i4 : x2);
|
|
1909
1971
|
}
|
|
1910
1972
|
return [V(t2, l2 + (t2[s2] || "<?>") + (2 === i3 ? "</svg>" : 3 === i3 ? "</math>" : "")), e2];
|
|
1911
1973
|
};
|
|
@@ -1922,11 +1984,11 @@ class S {
|
|
|
1922
1984
|
for (; null !== (r2 = P.nextNode()) && d2.length < u2; ) {
|
|
1923
1985
|
if (1 === r2.nodeType) {
|
|
1924
1986
|
if (r2.hasAttributes()) for (const t3 of r2.getAttributeNames()) if (t3.endsWith(h)) {
|
|
1925
|
-
const i4 = v2[a2++], s2 = r2.getAttribute(t3).split(o$
|
|
1987
|
+
const i4 = v2[a2++], s2 = r2.getAttribute(t3).split(o$4), e3 = /([.?@])?(.*)/.exec(i4);
|
|
1926
1988
|
d2.push({ type: 1, index: l2, name: e3[2], strings: s2, ctor: "." === e3[1] ? I : "?" === e3[1] ? L : "@" === e3[1] ? z : H }), r2.removeAttribute(t3);
|
|
1927
|
-
} else t3.startsWith(o$
|
|
1989
|
+
} else t3.startsWith(o$4) && (d2.push({ type: 6, index: l2 }), r2.removeAttribute(t3));
|
|
1928
1990
|
if (y2.test(r2.tagName)) {
|
|
1929
|
-
const t3 = r2.textContent.split(o$
|
|
1991
|
+
const t3 = r2.textContent.split(o$4), i4 = t3.length - 1;
|
|
1930
1992
|
if (i4 > 0) {
|
|
1931
1993
|
r2.textContent = s$1 ? s$1.emptyScript : "";
|
|
1932
1994
|
for (let s2 = 0; s2 < i4; s2++) r2.append(t3[s2], c()), P.nextNode(), d2.push({ type: 2, index: ++l2 });
|
|
@@ -1936,7 +1998,7 @@ class S {
|
|
|
1936
1998
|
} else if (8 === r2.nodeType) if (r2.data === n$1) d2.push({ type: 2, index: l2 });
|
|
1937
1999
|
else {
|
|
1938
2000
|
let t3 = -1;
|
|
1939
|
-
for (; -1 !== (t3 = r2.data.indexOf(o$
|
|
2001
|
+
for (; -1 !== (t3 = r2.data.indexOf(o$4, t3 + 1)); ) d2.push({ type: 7, index: l2 }), t3 += o$4.length - 1;
|
|
1940
2002
|
}
|
|
1941
2003
|
l2++;
|
|
1942
2004
|
}
|
|
@@ -2139,15 +2201,15 @@ let i$1 = class i extends y$1 {
|
|
|
2139
2201
|
}
|
|
2140
2202
|
};
|
|
2141
2203
|
i$1._$litElement$ = true, i$1["finalized"] = true, s.litElementHydrateSupport?.({ LitElement: i$1 });
|
|
2142
|
-
const o$
|
|
2143
|
-
o$
|
|
2204
|
+
const o$3 = s.litElementPolyfillSupport;
|
|
2205
|
+
o$3?.({ LitElement: i$1 });
|
|
2144
2206
|
(s.litElementVersions ??= []).push("4.2.2");
|
|
2145
2207
|
const t$1 = (t2) => (e2, o2) => {
|
|
2146
2208
|
void 0 !== o2 ? o2.addInitializer(() => {
|
|
2147
2209
|
customElements.define(t2, e2);
|
|
2148
2210
|
}) : customElements.define(t2, e2);
|
|
2149
2211
|
};
|
|
2150
|
-
const o$
|
|
2212
|
+
const o$2 = { attribute: true, type: String, converter: u$1, reflect: false, hasChanged: f$1 }, r$1 = (t2 = o$2, e2, r2) => {
|
|
2151
2213
|
const { kind: n3, metadata: i3 } = r2;
|
|
2152
2214
|
let s2 = globalThis.litPropertyMetadata.get(i3);
|
|
2153
2215
|
if (void 0 === s2 && globalThis.litPropertyMetadata.set(i3, s2 = /* @__PURE__ */ new Map()), "setter" === n3 && ((t2 = Object.create(t2)).wrapped = true), s2.set(r2.name, t2), "accessor" === n3) {
|
|
@@ -2177,6 +2239,7 @@ function n2(t2) {
|
|
|
2177
2239
|
function r(r2) {
|
|
2178
2240
|
return n2({ ...r2, state: true, attribute: false });
|
|
2179
2241
|
}
|
|
2242
|
+
const o$1 = (o2) => o2 ?? A;
|
|
2180
2243
|
const t = { CHILD: 2 }, e$1 = (t2) => (...e2) => ({ _$litDirective$: t2, values: e2 });
|
|
2181
2244
|
class i2 {
|
|
2182
2245
|
constructor(t2) {
|
|
@@ -2306,8 +2369,9 @@ const EXCLUSION_GROUPS = [
|
|
|
2306
2369
|
{ key: "notableExcipients", idsField: "notableExcipientIds", label: "Excipients à effet notoire" },
|
|
2307
2370
|
{ key: "excipients", idsField: "excipientIds", label: "Excipients" },
|
|
2308
2371
|
{ key: "contraindications", idsField: "contraindicationIds", label: "Utilisation contre-indiquée" },
|
|
2309
|
-
{ key: "cautions", idsField: "cautionIds", label: "
|
|
2310
|
-
{ key: "precautions", idsField: "precautionIds", label: "Précaution d'emploi" }
|
|
2372
|
+
{ key: "cautions", idsField: "cautionIds", label: "Utilisation déconseillée" },
|
|
2373
|
+
{ key: "precautions", idsField: "precautionIds", label: "Précaution d'emploi" },
|
|
2374
|
+
{ key: "sideEffects", idsField: "sideEffectIds", label: "Effets indésirables" }
|
|
2311
2375
|
];
|
|
2312
2376
|
const QUICK_FILTERS = [
|
|
2313
2377
|
{ key: "sameGalenicForm", label: "Même forme galénique" },
|
|
@@ -2326,7 +2390,7 @@ const MATCH_REASON_VERB_BY_DIMENSION = {
|
|
|
2326
2390
|
indication: "indiqué pour",
|
|
2327
2391
|
activeSubstance: "contient"
|
|
2328
2392
|
};
|
|
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-
|
|
2393
|
+
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 --bcbd-gray-900-color: var(--bcbd-primary-color, #0C75AD);\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
2394
|
function emptyScopeCriteria() {
|
|
2331
2395
|
return { indicationIds: [], atcClassIds: [] };
|
|
2332
2396
|
}
|
|
@@ -2340,7 +2404,8 @@ function emptyExcludeCriteria() {
|
|
|
2340
2404
|
excipientIds: [],
|
|
2341
2405
|
contraindicationIds: [],
|
|
2342
2406
|
cautionIds: [],
|
|
2343
|
-
precautionIds: []
|
|
2407
|
+
precautionIds: [],
|
|
2408
|
+
sideEffectIds: []
|
|
2344
2409
|
};
|
|
2345
2410
|
}
|
|
2346
2411
|
function emptyQuickFilters() {
|
|
@@ -2359,7 +2424,8 @@ function emptyExcludeFacets() {
|
|
|
2359
2424
|
excipients: [],
|
|
2360
2425
|
contraindications: [],
|
|
2361
2426
|
cautions: [],
|
|
2362
|
-
precautions: []
|
|
2427
|
+
precautions: [],
|
|
2428
|
+
sideEffects: []
|
|
2363
2429
|
};
|
|
2364
2430
|
}
|
|
2365
2431
|
function emptyScopeLabels() {
|
|
@@ -2368,17 +2434,6 @@ function emptyScopeLabels() {
|
|
|
2368
2434
|
function emptyIncludeLabels() {
|
|
2369
2435
|
return { activeSubstances: {}, galenicForms: {}, dosages: {}, routesOfAdministration: {} };
|
|
2370
2436
|
}
|
|
2371
|
-
function labelsForIds(ids, values) {
|
|
2372
|
-
const labelById = new Map(values.filter((v2) => v2.id).map((v2) => [v2.id, v2.label ?? v2.id]));
|
|
2373
|
-
const result = {};
|
|
2374
|
-
for (const id of ids) {
|
|
2375
|
-
const label = labelById.get(id);
|
|
2376
|
-
if (label) {
|
|
2377
|
-
result[id] = label;
|
|
2378
|
-
}
|
|
2379
|
-
}
|
|
2380
|
-
return result;
|
|
2381
|
-
}
|
|
2382
2437
|
function emptyExcludeLabels() {
|
|
2383
2438
|
return {
|
|
2384
2439
|
activeSubstances: {},
|
|
@@ -2386,7 +2441,8 @@ function emptyExcludeLabels() {
|
|
|
2386
2441
|
excipients: {},
|
|
2387
2442
|
contraindications: {},
|
|
2388
2443
|
cautions: {},
|
|
2389
|
-
precautions: {}
|
|
2444
|
+
precautions: {},
|
|
2445
|
+
sideEffects: {}
|
|
2390
2446
|
};
|
|
2391
2447
|
}
|
|
2392
2448
|
var __defProp = Object.defineProperty;
|
|
@@ -2415,6 +2471,7 @@ let TherapeuticAlternative = class extends i$1 {
|
|
|
2415
2471
|
this.include = emptyIncludeCriteria();
|
|
2416
2472
|
this.exclude = emptyExcludeCriteria();
|
|
2417
2473
|
this.quickFilters = emptyQuickFilters();
|
|
2474
|
+
this.quickFilterFacets = {};
|
|
2418
2475
|
this.scopeFacets = emptyScopeFacets();
|
|
2419
2476
|
this.includeFacets = emptyIncludeFacets();
|
|
2420
2477
|
this.excludeFacets = emptyExcludeFacets();
|
|
@@ -2434,7 +2491,6 @@ let TherapeuticAlternative = class extends i$1 {
|
|
|
2434
2491
|
this.apiReplaceError = null;
|
|
2435
2492
|
this.apiReplaceLoading = false;
|
|
2436
2493
|
this.missingPrescriptionError = null;
|
|
2437
|
-
this.hasAppliedInitialScope = false;
|
|
2438
2494
|
this.requestSeq = 0;
|
|
2439
2495
|
}
|
|
2440
2496
|
get currentMedication() {
|
|
@@ -2447,6 +2503,16 @@ let TherapeuticAlternative = class extends i$1 {
|
|
|
2447
2503
|
const bcbCoding = this.currentMedication?.code?.coding?.find((coding) => coding.system === "https://platform.claudebernard.fr/fhir/CodeSystem/bcb-code");
|
|
2448
2504
|
return bcbCoding?.code ?? null;
|
|
2449
2505
|
}
|
|
2506
|
+
get sourceProductLabel() {
|
|
2507
|
+
const title = getMedicationTitle(this.currentMedication);
|
|
2508
|
+
return title !== "" ? decodeHtml(title) : "ce produit";
|
|
2509
|
+
}
|
|
2510
|
+
// Same rule as bcb-cmp-ui's product sheet (isPara): product types 3 to 8 are parapharmacie, for
|
|
2511
|
+
// which there is no therapeutic alternative. Only known once the first response brings sourceProduct.
|
|
2512
|
+
get isParaSource() {
|
|
2513
|
+
const type = this.sourceProduct?.type;
|
|
2514
|
+
return type !== void 0 && type >= 3 && type <= 8;
|
|
2515
|
+
}
|
|
2450
2516
|
updated(changedProperties) {
|
|
2451
2517
|
if (changedProperties.has("apiUrl")) {
|
|
2452
2518
|
client.setConfig({
|
|
@@ -2457,23 +2523,27 @@ let TherapeuticAlternative = class extends i$1 {
|
|
|
2457
2523
|
});
|
|
2458
2524
|
}
|
|
2459
2525
|
if (changedProperties.has("medication") && this.currentMedication) {
|
|
2460
|
-
this.
|
|
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();
|
|
2526
|
+
this.resetAllCriteria();
|
|
2475
2527
|
}
|
|
2476
2528
|
}
|
|
2529
|
+
// Shared by a medication change (updated() above) and the user-facing "Réinitialiser" button:
|
|
2530
|
+
// both mean "start over from the initial state for this medication" (nothing selected).
|
|
2531
|
+
resetAllCriteria() {
|
|
2532
|
+
this.clearScheduledRefetch();
|
|
2533
|
+
this.scope = emptyScopeCriteria();
|
|
2534
|
+
this.include = emptyIncludeCriteria();
|
|
2535
|
+
this.exclude = emptyExcludeCriteria();
|
|
2536
|
+
this.scopeLabels = emptyScopeLabels();
|
|
2537
|
+
this.includeLabels = emptyIncludeLabels();
|
|
2538
|
+
this.excludeLabels = emptyExcludeLabels();
|
|
2539
|
+
this.quickFilters = emptyQuickFilters();
|
|
2540
|
+
this.openScopeGroup = null;
|
|
2541
|
+
this.openExclusionGroup = null;
|
|
2542
|
+
this.openIncludeGroup = null;
|
|
2543
|
+
this.expandFacetGroupKey = null;
|
|
2544
|
+
this.currentPage = 1;
|
|
2545
|
+
this.fetchAlternatives();
|
|
2546
|
+
}
|
|
2477
2547
|
disconnectedCallback() {
|
|
2478
2548
|
super.disconnectedCallback();
|
|
2479
2549
|
this.clearScheduledRefetch();
|
|
@@ -2516,6 +2586,7 @@ let TherapeuticAlternative = class extends i$1 {
|
|
|
2516
2586
|
pageSize: numberOfResults,
|
|
2517
2587
|
...this.expandFacetGroupKey ? { expandFacetGroup: this.expandFacetGroupKey } : {}
|
|
2518
2588
|
};
|
|
2589
|
+
setActiveContext(this.context);
|
|
2519
2590
|
searchApi.searchAlternative({ body, path: { productId } }).then((response) => {
|
|
2520
2591
|
if (seq !== this.requestSeq) {
|
|
2521
2592
|
return;
|
|
@@ -2541,15 +2612,8 @@ let TherapeuticAlternative = class extends i$1 {
|
|
|
2541
2612
|
this.scopeFacets = TherapeuticAlternative.buildScopeFacets(data);
|
|
2542
2613
|
this.includeFacets = TherapeuticAlternative.buildIncludeFacets(data);
|
|
2543
2614
|
this.excludeFacets = TherapeuticAlternative.buildExcludeFacets(data);
|
|
2615
|
+
this.quickFilterFacets = data.facets?.quickFilters ?? {};
|
|
2544
2616
|
this.truncatedGroups = data.facets?.truncatedGroups ?? [];
|
|
2545
|
-
if (!this.hasAppliedInitialScope) {
|
|
2546
|
-
this.hasAppliedInitialScope = true;
|
|
2547
|
-
this.scope = TherapeuticAlternative.deriveInitialScope(this.sourceProduct);
|
|
2548
|
-
this.scopeLabels = {
|
|
2549
|
-
indications: labelsForIds(this.scope.indicationIds, this.scopeFacets.indications),
|
|
2550
|
-
atcClasses: labelsForIds(this.scope.atcClassIds, this.scopeFacets.atcClasses)
|
|
2551
|
-
};
|
|
2552
|
-
}
|
|
2553
2617
|
}
|
|
2554
2618
|
static buildScopeFacets(data) {
|
|
2555
2619
|
return {
|
|
@@ -2566,29 +2630,74 @@ let TherapeuticAlternative = class extends i$1 {
|
|
|
2566
2630
|
};
|
|
2567
2631
|
}
|
|
2568
2632
|
static buildExcludeFacets(data) {
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
}
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2633
|
+
const facets = emptyExcludeFacets();
|
|
2634
|
+
for (const group of EXCLUSION_GROUPS) {
|
|
2635
|
+
facets[group.key] = data.facets?.exclude?.[group.key] ?? [];
|
|
2636
|
+
}
|
|
2637
|
+
return facets;
|
|
2638
|
+
}
|
|
2639
|
+
static codesOf(list) {
|
|
2640
|
+
return (list ?? []).map((item) => item.code).filter((code) => !!code);
|
|
2641
|
+
}
|
|
2642
|
+
// The ids to tint in a scope checklist panel (same highlight as the include/exclude panels, see
|
|
2643
|
+
// renderChecklistPanel's possessedIds param) -- the source product's own indications. They are
|
|
2644
|
+
// only highlighted, never pre-checked: an empty scope.indicationIds sends no indication
|
|
2645
|
+
// constraint, so ticking them would claim a filter that is not applied. The ATC group has none:
|
|
2646
|
+
// sourceProduct.properties.atcClasses is a whole breadcrumb (M > M01 > M01A > ...), not a flat
|
|
2647
|
+
// list of values the source "has".
|
|
2648
|
+
scopePossessedIds(key) {
|
|
2649
|
+
if (key !== "indications") {
|
|
2650
|
+
return /* @__PURE__ */ new Set();
|
|
2651
|
+
}
|
|
2652
|
+
return new Set(TherapeuticAlternative.codesOf(this.sourceProduct?.extendedProperties?.keywords?.indicationsKeywords));
|
|
2653
|
+
}
|
|
2654
|
+
// The ids to tint in an include checklist panel (see renderChecklistPanel's possessedIds param)
|
|
2655
|
+
// -- what the SOURCE product itself already has for that dimension, not what's currently
|
|
2656
|
+
// selected. galenicForms/dosages are single-valued on the source (a product has exactly one), so
|
|
2657
|
+
// each contributes at most one id; activeSubstances/routesOfAdministration can be multi-valued.
|
|
2658
|
+
// dosages is a best-effort string match (source's raw productDosage against the facet's own
|
|
2659
|
+
// dosage-string ids) -- it can occasionally miss on formatting, unlike the others' exact codes.
|
|
2660
|
+
includePossessedIds(key) {
|
|
2661
|
+
const properties = this.sourceProduct?.properties;
|
|
2662
|
+
const composition = this.sourceProduct?.extendedProperties?.composition;
|
|
2663
|
+
switch (key) {
|
|
2664
|
+
case "activeSubstances":
|
|
2665
|
+
return new Set(TherapeuticAlternative.codesOf(composition?.activeSubstances));
|
|
2666
|
+
case "galenicForms":
|
|
2667
|
+
return properties?.galenicFormCode ? /* @__PURE__ */ new Set([properties.galenicFormCode]) : /* @__PURE__ */ new Set();
|
|
2668
|
+
case "dosages":
|
|
2669
|
+
return properties?.productDosage ? /* @__PURE__ */ new Set([properties.productDosage]) : /* @__PURE__ */ new Set();
|
|
2670
|
+
case "routesOfAdministration":
|
|
2671
|
+
return new Set(TherapeuticAlternative.codesOf(this.sourceProduct?.extendedProperties?.routes));
|
|
2672
|
+
default:
|
|
2673
|
+
return /* @__PURE__ */ new Set();
|
|
2674
|
+
}
|
|
2675
|
+
}
|
|
2676
|
+
// Same idea as includePossessedIds, for the exclude checklist panels: the exclude groups' own
|
|
2677
|
+
// values come from the whole candidate pool (see SearchCustomService.addExcludeMustNotQueries),
|
|
2678
|
+
// not just the source product, so "does the source itself already have this excipient/
|
|
2679
|
+
// contraindication/..." is a real, non-trivial question worth answering here too.
|
|
2680
|
+
excludePossessedIds(key) {
|
|
2681
|
+
const composition = this.sourceProduct?.extendedProperties?.composition;
|
|
2682
|
+
const keywords = this.sourceProduct?.extendedProperties?.keywords;
|
|
2683
|
+
switch (key) {
|
|
2684
|
+
case "activeSubstances":
|
|
2685
|
+
return new Set(TherapeuticAlternative.codesOf(composition?.activeSubstances));
|
|
2686
|
+
case "notableExcipients":
|
|
2687
|
+
return new Set(TherapeuticAlternative.codesOf(composition?.excipientsWithKnownEffects));
|
|
2688
|
+
case "excipients":
|
|
2689
|
+
return new Set(TherapeuticAlternative.codesOf(composition?.excipients));
|
|
2690
|
+
case "contraindications":
|
|
2691
|
+
return new Set(TherapeuticAlternative.codesOf(keywords?.contraindicationsKeywords));
|
|
2692
|
+
case "cautions":
|
|
2693
|
+
return new Set(TherapeuticAlternative.codesOf(keywords?.contraindicationsNotRecommendedKeywords));
|
|
2694
|
+
case "precautions":
|
|
2695
|
+
return new Set(TherapeuticAlternative.codesOf(keywords?.precautionsForUseKeywords));
|
|
2696
|
+
case "sideEffects":
|
|
2697
|
+
return new Set(TherapeuticAlternative.codesOf(keywords?.sideEffectsKeywords));
|
|
2698
|
+
default:
|
|
2699
|
+
return /* @__PURE__ */ new Set();
|
|
2700
|
+
}
|
|
2592
2701
|
}
|
|
2593
2702
|
// label n'est utilisé que sur la branche "coche" (pour alimenter scopeLabels/includeLabels/
|
|
2594
2703
|
// excludeLabels — voir emptyScopeLabels) ; sur la branche "décoche" l'id est simplement retiré
|
|
@@ -2658,6 +2767,7 @@ let TherapeuticAlternative = class extends i$1 {
|
|
|
2658
2767
|
this.includeLabels = { ...this.includeLabels, [group.key]: {} };
|
|
2659
2768
|
}
|
|
2660
2769
|
}
|
|
2770
|
+
this.pendingToggleIds = new Set(this.pendingToggleIds).add(key);
|
|
2661
2771
|
this.scheduleRefetch();
|
|
2662
2772
|
}
|
|
2663
2773
|
// The exclude "activeSubstances" group's own backend/truncatedGroups key is
|
|
@@ -2715,6 +2825,7 @@ let TherapeuticAlternative = class extends i$1 {
|
|
|
2715
2825
|
this.apiReplaceLoading = true;
|
|
2716
2826
|
let newMedicationRequest;
|
|
2717
2827
|
try {
|
|
2828
|
+
setActiveContext(this.context);
|
|
2718
2829
|
const response = await prescriptionApi.getFhirPosologies({
|
|
2719
2830
|
body: {
|
|
2720
2831
|
patient: this.patientProfile ?? {},
|
|
@@ -2761,7 +2872,7 @@ let TherapeuticAlternative = class extends i$1 {
|
|
|
2761
2872
|
this.apiReplaceLoading = false;
|
|
2762
2873
|
}
|
|
2763
2874
|
}
|
|
2764
|
-
renderChecklistPanel(items, selectedIds, showCount, countTooltip, onToggle, testIdPrefix, showCode = false, truncated = false, onExpand) {
|
|
2875
|
+
renderChecklistPanel(items, selectedIds, showCount, countTooltip, onToggle, testIdPrefix, showCode = false, truncated = false, onExpand, possessedIds = /* @__PURE__ */ new Set()) {
|
|
2765
2876
|
const visibleItems = items.filter((item) => {
|
|
2766
2877
|
if (item.id !== void 0 && this.pendingToggleIds.has(item.id)) {
|
|
2767
2878
|
return true;
|
|
@@ -2788,10 +2899,12 @@ let TherapeuticAlternative = class extends i$1 {
|
|
|
2788
2899
|
const pending = this.pendingToggleIds.has(item.id);
|
|
2789
2900
|
const rowClasses = [
|
|
2790
2901
|
`${PREFIX}-therapeutic-alternative__panel-row`,
|
|
2791
|
-
pending ? `${PREFIX}-therapeutic-alternative__panel-row--pending` : ""
|
|
2902
|
+
pending ? `${PREFIX}-therapeutic-alternative__panel-row--pending` : "",
|
|
2903
|
+
possessedIds.has(item.id) ? `${PREFIX}-therapeutic-alternative__panel-row--possessed` : ""
|
|
2792
2904
|
].join(" ");
|
|
2905
|
+
const possessedTitle = possessedIds.has(item.id) ? `Valeur présente dans le produit d'origine (${this.sourceProductLabel})` : void 0;
|
|
2793
2906
|
return b`
|
|
2794
|
-
<div class=${rowClasses}>
|
|
2907
|
+
<div class=${rowClasses} title=${o$1(possessedTitle)}>
|
|
2795
2908
|
<bcbd-checkbox
|
|
2796
2909
|
id=${`${testIdPrefix}-${item.id}`}
|
|
2797
2910
|
label=${showCode ? `${item.id} : ${item.label ?? ""}` : item.label ?? ""}
|
|
@@ -2936,7 +3049,8 @@ let TherapeuticAlternative = class extends i$1 {
|
|
|
2936
3049
|
// distinct values) response back -- there's no third, even-larger tier to escalate to, so
|
|
2937
3050
|
// showing the button again would just be a no-op click.
|
|
2938
3051
|
openGroup.key === "atcClasses" && this.truncatedGroups.includes("atcClasses") && this.expandFacetGroupKey !== "atcClasses",
|
|
2939
|
-
() => this.requestMoreFacetValues("atcClasses")
|
|
3052
|
+
() => this.requestMoreFacetValues("atcClasses"),
|
|
3053
|
+
this.scopePossessedIds(openGroup.key)
|
|
2940
3054
|
) : A}
|
|
2941
3055
|
`;
|
|
2942
3056
|
}
|
|
@@ -2974,7 +3088,8 @@ let TherapeuticAlternative = class extends i$1 {
|
|
|
2974
3088
|
`exclusion-${openGroup.key}`,
|
|
2975
3089
|
false,
|
|
2976
3090
|
canExpand,
|
|
2977
|
-
() => this.requestMoreFacetValues(truncatedGroupKey)
|
|
3091
|
+
() => this.requestMoreFacetValues(truncatedGroupKey),
|
|
3092
|
+
this.excludePossessedIds(openGroup.key)
|
|
2978
3093
|
) : A}
|
|
2979
3094
|
`;
|
|
2980
3095
|
}
|
|
@@ -3012,7 +3127,8 @@ let TherapeuticAlternative = class extends i$1 {
|
|
|
3012
3127
|
`include-${openGroup.key}`,
|
|
3013
3128
|
false,
|
|
3014
3129
|
canExpand,
|
|
3015
|
-
() => this.requestMoreFacetValues(truncatedGroupKey)
|
|
3130
|
+
() => this.requestMoreFacetValues(truncatedGroupKey),
|
|
3131
|
+
this.includePossessedIds(openGroup.key)
|
|
3016
3132
|
) : A}
|
|
3017
3133
|
`;
|
|
3018
3134
|
}
|
|
@@ -3020,25 +3136,56 @@ let TherapeuticAlternative = class extends i$1 {
|
|
|
3020
3136
|
if (this.sectionCollapsed.quickFilters) {
|
|
3021
3137
|
return A;
|
|
3022
3138
|
}
|
|
3023
|
-
const
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3139
|
+
const visibleFilters = QUICK_FILTERS.filter((filter) => {
|
|
3140
|
+
if (this.quickFilters[filter.key] || this.pendingToggleIds.has(filter.key)) {
|
|
3141
|
+
return true;
|
|
3142
|
+
}
|
|
3143
|
+
return this.quickFilterFacets[filter.key] !== 0;
|
|
3144
|
+
});
|
|
3145
|
+
if (visibleFilters.length === 0) {
|
|
3146
|
+
return b`<span class="${PREFIX}-therapeutic-alternative__panel-empty">Aucune valeur disponible.</span>`;
|
|
3147
|
+
}
|
|
3148
|
+
const rows = visibleFilters.map((filter) => {
|
|
3149
|
+
const count = this.quickFilterFacets[filter.key];
|
|
3150
|
+
const pending = this.pendingToggleIds.has(filter.key);
|
|
3151
|
+
const rowClasses = [
|
|
3152
|
+
`${PREFIX}-therapeutic-alternative__panel-row`,
|
|
3153
|
+
pending ? `${PREFIX}-therapeutic-alternative__panel-row--pending` : ""
|
|
3028
3154
|
].join(" ");
|
|
3029
3155
|
return b`
|
|
3030
|
-
<
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3156
|
+
<div class=${rowClasses}>
|
|
3157
|
+
<bcbd-checkbox
|
|
3158
|
+
id=${`quick-filter-${filter.key}`}
|
|
3159
|
+
label=${filter.label}
|
|
3160
|
+
?checked=${this.quickFilters[filter.key]}
|
|
3161
|
+
color="primary"
|
|
3162
|
+
@change=${() => this.toggleQuickFilter(filter.key)}
|
|
3163
|
+
data-test-id=${`quick-filter-${filter.key}`}>
|
|
3164
|
+
</bcbd-checkbox>
|
|
3165
|
+
${pending ? b`
|
|
3166
|
+
<bcbd-loader theme="standard" size="18" data-test-id=${`quick-filter-loader-${filter.key}`}></bcbd-loader>
|
|
3167
|
+
` : this.renderQuickFilterCount(filter.key, count)}
|
|
3168
|
+
</div>
|
|
3034
3169
|
`;
|
|
3035
3170
|
});
|
|
3036
3171
|
return b`
|
|
3037
|
-
<div class="${PREFIX}-therapeutic-
|
|
3038
|
-
${
|
|
3172
|
+
<div class="${PREFIX}-therapeutic-alternative__panel" data-test-id="quick-filters-panel">
|
|
3173
|
+
<div class="${PREFIX}-therapeutic-alternative__panel-rows">
|
|
3174
|
+
${rows}
|
|
3175
|
+
</div>
|
|
3039
3176
|
</div>
|
|
3040
3177
|
`;
|
|
3041
3178
|
}
|
|
3179
|
+
renderQuickFilterCount(key, count) {
|
|
3180
|
+
if (count === void 0) {
|
|
3181
|
+
return A;
|
|
3182
|
+
}
|
|
3183
|
+
return b`
|
|
3184
|
+
<bcbd-tooltip placement="left" content=${INCLUDE_COUNT_TOOLTIP} data-test-id=${`quick-filter-count-tooltip-${key}`}>
|
|
3185
|
+
<span class="${PREFIX}-therapeutic-alternative__count-badge" data-test-id=${`quick-filter-count-${key}`}>${count}</span>
|
|
3186
|
+
</bcbd-tooltip>
|
|
3187
|
+
`;
|
|
3188
|
+
}
|
|
3042
3189
|
renderSectionHeader(title, section) {
|
|
3043
3190
|
const collapsed = this.sectionCollapsed[section];
|
|
3044
3191
|
const chevronClasses = [
|
|
@@ -3130,24 +3277,49 @@ let TherapeuticAlternative = class extends i$1 {
|
|
|
3130
3277
|
</bcbd-pagination>`}
|
|
3131
3278
|
`;
|
|
3132
3279
|
}
|
|
3280
|
+
// The product name in the title replaces the "Produit sélectionné" line when has-title is on; without
|
|
3281
|
+
// a title, that line (see render) is the only place the product name shows.
|
|
3282
|
+
renderTitle(medicationTitle) {
|
|
3283
|
+
return b`<span class="${PREFIX}-therapeutic-alternative-title" data-test-id="title">Alternative Thérapeutique pour ${medicationTitle !== "" ? decodeHtml(medicationTitle) : "ce produit"}</span>`;
|
|
3284
|
+
}
|
|
3133
3285
|
render() {
|
|
3134
3286
|
const containerClasses = [
|
|
3135
3287
|
`${PREFIX}-therapeutic-alternative`,
|
|
3136
3288
|
this.hasTitle ? "" : `${PREFIX}-therapeutic-alternative-without-title`
|
|
3137
3289
|
].join(" ");
|
|
3138
3290
|
const medicationTitle = getMedicationTitle(this.currentMedication);
|
|
3291
|
+
if (this.currentMedication && this.isParaSource) {
|
|
3292
|
+
return b`
|
|
3293
|
+
<div class=${containerClasses} data-test-id="therapeutic-alternative-container">
|
|
3294
|
+
${this.hasTitle ? this.renderTitle(medicationTitle) : ""}
|
|
3295
|
+
<div class="${PREFIX}-therapeutic-alternative__disclaimer">
|
|
3296
|
+
<bcbd-alert title-message="Alternative thérapeutique indisponible"
|
|
3297
|
+
description-message="La recherche d'alternative n'est pas disponible pour les produits de parapharmacie."
|
|
3298
|
+
type="info" data-test-id="para-unavailable-alert">
|
|
3299
|
+
</bcbd-alert>
|
|
3300
|
+
</div>
|
|
3301
|
+
</div>
|
|
3302
|
+
`;
|
|
3303
|
+
}
|
|
3139
3304
|
return b`
|
|
3140
3305
|
<div class=${containerClasses} data-test-id="therapeutic-alternative-container">
|
|
3141
|
-
${this.hasTitle ? b`<span class="${PREFIX}-therapeutic-alternative-title">Alternative thérapeutique</span>` : ""}
|
|
3142
3306
|
${this.currentMedication ? b`
|
|
3143
3307
|
<div class="${PREFIX}-therapeutic-alternative__source mb-3" data-test-id="source-product">
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3308
|
+
${this.hasTitle ? this.renderTitle(medicationTitle) : b`
|
|
3309
|
+
<span data-test-id="source-product-label">
|
|
3310
|
+
Produit sélectionné : <span class="text-primary">${medicationTitle !== "" ? decodeHtml(medicationTitle) : "Inconnu"}</span>
|
|
3311
|
+
</span>`}
|
|
3312
|
+
<div class="${PREFIX}-therapeutic-alternative__source-actions">
|
|
3313
|
+
<bcbd-button size="small" background-color="secondary" outlined
|
|
3314
|
+
?disabled=${this.hasNoSelectedCriteria()}
|
|
3315
|
+
@click=${this.resetAllCriteria} data-test-id="reset-criteria-button">
|
|
3316
|
+
Réinitialiser
|
|
3317
|
+
</bcbd-button>
|
|
3318
|
+
<bcbd-button size="small" background-color="primary" outlined
|
|
3319
|
+
@click=${this.cancelAlternative} data-test-id="cancel-alternative-button">
|
|
3320
|
+
Annuler
|
|
3321
|
+
</bcbd-button>
|
|
3322
|
+
</div>
|
|
3151
3323
|
</div>
|
|
3152
3324
|
|
|
3153
3325
|
<div class="${PREFIX}-therapeutic-alternative__disclaimer">
|
|
@@ -3190,6 +3362,7 @@ let TherapeuticAlternative = class extends i$1 {
|
|
|
3190
3362
|
<div class="${PREFIX}-therapeutic-alternative__results" data-test-id="results-container">
|
|
3191
3363
|
${this.renderResults()}
|
|
3192
3364
|
</div>` : b`
|
|
3365
|
+
${this.hasTitle ? this.renderTitle(medicationTitle) : ""}
|
|
3193
3366
|
<div class="${PREFIX}-therapeutic-alternative__no-medication" data-test-id="no-medication-container">
|
|
3194
3367
|
<bcbd-alert title-message="Pas de médicament sélectionné"
|
|
3195
3368
|
description-message="Un problème est survenu au moment de sélectionner le produit"
|
|
@@ -3216,6 +3389,9 @@ __decorateClass([
|
|
|
3216
3389
|
__decorateClass([
|
|
3217
3390
|
n2({ type: String, attribute: "api-key" })
|
|
3218
3391
|
], TherapeuticAlternative.prototype, "apiKey", 2);
|
|
3392
|
+
__decorateClass([
|
|
3393
|
+
n2({ type: Object })
|
|
3394
|
+
], TherapeuticAlternative.prototype, "context", 2);
|
|
3219
3395
|
__decorateClass([
|
|
3220
3396
|
r()
|
|
3221
3397
|
], TherapeuticAlternative.prototype, "sourceProduct", 2);
|
|
@@ -3243,6 +3419,9 @@ __decorateClass([
|
|
|
3243
3419
|
__decorateClass([
|
|
3244
3420
|
r()
|
|
3245
3421
|
], TherapeuticAlternative.prototype, "quickFilters", 2);
|
|
3422
|
+
__decorateClass([
|
|
3423
|
+
r()
|
|
3424
|
+
], TherapeuticAlternative.prototype, "quickFilterFacets", 2);
|
|
3246
3425
|
__decorateClass([
|
|
3247
3426
|
r()
|
|
3248
3427
|
], TherapeuticAlternative.prototype, "scopeFacets", 2);
|
package/package.json
CHANGED