@claudebernard/therapeutic-alternative-element 2.3.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;
|
|
@@ -46,12 +52,13 @@ export declare class TherapeuticAlternative extends LitElement {
|
|
|
46
52
|
private apiReplaceError;
|
|
47
53
|
private apiReplaceLoading;
|
|
48
54
|
private missingPrescriptionError;
|
|
49
|
-
private hasAppliedInitialScope;
|
|
50
55
|
private refetchTimer;
|
|
51
56
|
private requestSeq;
|
|
52
57
|
private get currentMedication();
|
|
53
58
|
private get currentMedicationRequest();
|
|
54
59
|
private get sourceProductId();
|
|
60
|
+
private get sourceProductLabel();
|
|
61
|
+
private get isParaSource();
|
|
55
62
|
updated(changedProperties: Map<string | number | symbol, unknown>): void;
|
|
56
63
|
private resetAllCriteria;
|
|
57
64
|
disconnectedCallback(): void;
|
|
@@ -64,7 +71,7 @@ export declare class TherapeuticAlternative extends LitElement {
|
|
|
64
71
|
private static buildIncludeFacets;
|
|
65
72
|
private static buildExcludeFacets;
|
|
66
73
|
private static codesOf;
|
|
67
|
-
private
|
|
74
|
+
private scopePossessedIds;
|
|
68
75
|
private includePossessedIds;
|
|
69
76
|
private excludePossessedIds;
|
|
70
77
|
private toggleScope;
|
|
@@ -98,6 +105,27 @@ export declare class TherapeuticAlternative extends LitElement {
|
|
|
98
105
|
static styles: CSSResult;
|
|
99
106
|
}
|
|
100
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
|
+
|
|
101
129
|
|
|
102
130
|
export * from "@claudebernard/web-component-fhir-utils";
|
|
103
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) {
|
|
@@ -2327,7 +2390,7 @@ const MATCH_REASON_VERB_BY_DIMENSION = {
|
|
|
2327
2390
|
indication: "indiqué pour",
|
|
2328
2391
|
activeSubstance: "contient"
|
|
2329
2392
|
};
|
|
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
|
|
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}';
|
|
2331
2394
|
function emptyScopeCriteria() {
|
|
2332
2395
|
return { indicationIds: [], atcClassIds: [] };
|
|
2333
2396
|
}
|
|
@@ -2371,17 +2434,6 @@ function emptyScopeLabels() {
|
|
|
2371
2434
|
function emptyIncludeLabels() {
|
|
2372
2435
|
return { activeSubstances: {}, galenicForms: {}, dosages: {}, routesOfAdministration: {} };
|
|
2373
2436
|
}
|
|
2374
|
-
function labelsForIds(ids, values) {
|
|
2375
|
-
const labelById = new Map(values.filter((v2) => v2.id).map((v2) => [v2.id, v2.label ?? v2.id]));
|
|
2376
|
-
const result = {};
|
|
2377
|
-
for (const id of ids) {
|
|
2378
|
-
const label = labelById.get(id);
|
|
2379
|
-
if (label) {
|
|
2380
|
-
result[id] = label;
|
|
2381
|
-
}
|
|
2382
|
-
}
|
|
2383
|
-
return result;
|
|
2384
|
-
}
|
|
2385
2437
|
function emptyExcludeLabels() {
|
|
2386
2438
|
return {
|
|
2387
2439
|
activeSubstances: {},
|
|
@@ -2439,7 +2491,6 @@ let TherapeuticAlternative = class extends i$1 {
|
|
|
2439
2491
|
this.apiReplaceError = null;
|
|
2440
2492
|
this.apiReplaceLoading = false;
|
|
2441
2493
|
this.missingPrescriptionError = null;
|
|
2442
|
-
this.hasAppliedInitialScope = false;
|
|
2443
2494
|
this.requestSeq = 0;
|
|
2444
2495
|
}
|
|
2445
2496
|
get currentMedication() {
|
|
@@ -2452,6 +2503,16 @@ let TherapeuticAlternative = class extends i$1 {
|
|
|
2452
2503
|
const bcbCoding = this.currentMedication?.code?.coding?.find((coding) => coding.system === "https://platform.claudebernard.fr/fhir/CodeSystem/bcb-code");
|
|
2453
2504
|
return bcbCoding?.code ?? null;
|
|
2454
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
|
+
}
|
|
2455
2516
|
updated(changedProperties) {
|
|
2456
2517
|
if (changedProperties.has("apiUrl")) {
|
|
2457
2518
|
client.setConfig({
|
|
@@ -2466,9 +2527,7 @@ let TherapeuticAlternative = class extends i$1 {
|
|
|
2466
2527
|
}
|
|
2467
2528
|
}
|
|
2468
2529
|
// 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"
|
|
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.
|
|
2530
|
+
// both mean "start over from the initial state for this medication" (nothing selected).
|
|
2472
2531
|
resetAllCriteria() {
|
|
2473
2532
|
this.clearScheduledRefetch();
|
|
2474
2533
|
this.scope = emptyScopeCriteria();
|
|
@@ -2483,7 +2542,6 @@ let TherapeuticAlternative = class extends i$1 {
|
|
|
2483
2542
|
this.openIncludeGroup = null;
|
|
2484
2543
|
this.expandFacetGroupKey = null;
|
|
2485
2544
|
this.currentPage = 1;
|
|
2486
|
-
this.hasAppliedInitialScope = false;
|
|
2487
2545
|
this.fetchAlternatives();
|
|
2488
2546
|
}
|
|
2489
2547
|
disconnectedCallback() {
|
|
@@ -2528,6 +2586,7 @@ let TherapeuticAlternative = class extends i$1 {
|
|
|
2528
2586
|
pageSize: numberOfResults,
|
|
2529
2587
|
...this.expandFacetGroupKey ? { expandFacetGroup: this.expandFacetGroupKey } : {}
|
|
2530
2588
|
};
|
|
2589
|
+
setActiveContext(this.context);
|
|
2531
2590
|
searchApi.searchAlternative({ body, path: { productId } }).then((response) => {
|
|
2532
2591
|
if (seq !== this.requestSeq) {
|
|
2533
2592
|
return;
|
|
@@ -2555,14 +2614,6 @@ let TherapeuticAlternative = class extends i$1 {
|
|
|
2555
2614
|
this.excludeFacets = TherapeuticAlternative.buildExcludeFacets(data);
|
|
2556
2615
|
this.quickFilterFacets = data.facets?.quickFilters ?? {};
|
|
2557
2616
|
this.truncatedGroups = data.facets?.truncatedGroups ?? [];
|
|
2558
|
-
if (!this.hasAppliedInitialScope) {
|
|
2559
|
-
this.hasAppliedInitialScope = true;
|
|
2560
|
-
this.scope = TherapeuticAlternative.deriveInitialScope(this.sourceProduct);
|
|
2561
|
-
this.scopeLabels = {
|
|
2562
|
-
indications: labelsForIds(this.scope.indicationIds, this.scopeFacets.indications),
|
|
2563
|
-
atcClasses: labelsForIds(this.scope.atcClassIds, this.scopeFacets.atcClasses)
|
|
2564
|
-
};
|
|
2565
|
-
}
|
|
2566
2617
|
}
|
|
2567
2618
|
static buildScopeFacets(data) {
|
|
2568
2619
|
return {
|
|
@@ -2588,21 +2639,19 @@ let TherapeuticAlternative = class extends i$1 {
|
|
|
2588
2639
|
static codesOf(list) {
|
|
2589
2640
|
return (list ?? []).map((item) => item.code).filter((code) => !!code);
|
|
2590
2641
|
}
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
atcClassIds: []
|
|
2603
|
-
};
|
|
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));
|
|
2604
2653
|
}
|
|
2605
|
-
// The ids to
|
|
2654
|
+
// The ids to tint in an include checklist panel (see renderChecklistPanel's possessedIds param)
|
|
2606
2655
|
// -- what the SOURCE product itself already has for that dimension, not what's currently
|
|
2607
2656
|
// selected. galenicForms/dosages are single-valued on the source (a product has exactly one), so
|
|
2608
2657
|
// each contributes at most one id; activeSubstances/routesOfAdministration can be multi-valued.
|
|
@@ -2776,6 +2825,7 @@ let TherapeuticAlternative = class extends i$1 {
|
|
|
2776
2825
|
this.apiReplaceLoading = true;
|
|
2777
2826
|
let newMedicationRequest;
|
|
2778
2827
|
try {
|
|
2828
|
+
setActiveContext(this.context);
|
|
2779
2829
|
const response = await prescriptionApi.getFhirPosologies({
|
|
2780
2830
|
body: {
|
|
2781
2831
|
patient: this.patientProfile ?? {},
|
|
@@ -2852,8 +2902,9 @@ let TherapeuticAlternative = class extends i$1 {
|
|
|
2852
2902
|
pending ? `${PREFIX}-therapeutic-alternative__panel-row--pending` : "",
|
|
2853
2903
|
possessedIds.has(item.id) ? `${PREFIX}-therapeutic-alternative__panel-row--possessed` : ""
|
|
2854
2904
|
].join(" ");
|
|
2905
|
+
const possessedTitle = possessedIds.has(item.id) ? `Valeur présente dans le produit d'origine (${this.sourceProductLabel})` : void 0;
|
|
2855
2906
|
return b`
|
|
2856
|
-
<div class=${rowClasses}>
|
|
2907
|
+
<div class=${rowClasses} title=${o$1(possessedTitle)}>
|
|
2857
2908
|
<bcbd-checkbox
|
|
2858
2909
|
id=${`${testIdPrefix}-${item.id}`}
|
|
2859
2910
|
label=${showCode ? `${item.id} : ${item.label ?? ""}` : item.label ?? ""}
|
|
@@ -2998,7 +3049,8 @@ let TherapeuticAlternative = class extends i$1 {
|
|
|
2998
3049
|
// distinct values) response back -- there's no third, even-larger tier to escalate to, so
|
|
2999
3050
|
// showing the button again would just be a no-op click.
|
|
3000
3051
|
openGroup.key === "atcClasses" && this.truncatedGroups.includes("atcClasses") && this.expandFacetGroupKey !== "atcClasses",
|
|
3001
|
-
() => this.requestMoreFacetValues("atcClasses")
|
|
3052
|
+
() => this.requestMoreFacetValues("atcClasses"),
|
|
3053
|
+
this.scopePossessedIds(openGroup.key)
|
|
3002
3054
|
) : A}
|
|
3003
3055
|
`;
|
|
3004
3056
|
}
|
|
@@ -3236,6 +3288,19 @@ let TherapeuticAlternative = class extends i$1 {
|
|
|
3236
3288
|
this.hasTitle ? "" : `${PREFIX}-therapeutic-alternative-without-title`
|
|
3237
3289
|
].join(" ");
|
|
3238
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
|
+
}
|
|
3239
3304
|
return b`
|
|
3240
3305
|
<div class=${containerClasses} data-test-id="therapeutic-alternative-container">
|
|
3241
3306
|
${this.currentMedication ? b`
|
|
@@ -3324,6 +3389,9 @@ __decorateClass([
|
|
|
3324
3389
|
__decorateClass([
|
|
3325
3390
|
n2({ type: String, attribute: "api-key" })
|
|
3326
3391
|
], TherapeuticAlternative.prototype, "apiKey", 2);
|
|
3392
|
+
__decorateClass([
|
|
3393
|
+
n2({ type: Object })
|
|
3394
|
+
], TherapeuticAlternative.prototype, "context", 2);
|
|
3327
3395
|
__decorateClass([
|
|
3328
3396
|
r()
|
|
3329
3397
|
], TherapeuticAlternative.prototype, "sourceProduct", 2);
|
package/package.json
CHANGED