@uxland/primary-shell 2.0.1-rc.2 → 2.1.1

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.
Files changed (65) hide show
  1. package/dist/UI/components/patient-header/patient-header.d.ts +9 -0
  2. package/dist/UI/components/patient-header/template.d.ts +3 -0
  3. package/dist/UI/components/professional-header/professional-header.d.ts +9 -0
  4. package/dist/UI/components/professional-header/template.d.ts +3 -0
  5. package/dist/api/api.d.ts +2 -6
  6. package/dist/api/http-client/http-client.d.ts +6 -0
  7. package/dist/features/bootstrapper.d.ts +4 -0
  8. package/dist/features/get-patient-info/backend-adapter.d.ts +9 -0
  9. package/dist/features/get-patient-info/bootstrapper.d.ts +2 -0
  10. package/dist/features/get-patient-info/handler.d.ts +11 -0
  11. package/dist/features/get-patient-info/model.d.ts +7 -0
  12. package/dist/features/get-patient-info/request.d.ts +5 -0
  13. package/dist/features/get-user-info/backend-adapter.d.ts +9 -0
  14. package/dist/features/get-user-info/bootstrapper.d.ts +2 -0
  15. package/dist/features/get-user-info/handler.d.ts +11 -0
  16. package/dist/features/get-user-info/model.d.ts +8 -0
  17. package/dist/features/get-user-info/request.d.ts +5 -0
  18. package/dist/features/utils.d.ts +7 -0
  19. package/dist/index.js +12500 -8992
  20. package/dist/index.js.map +1 -1
  21. package/dist/index.umd.cjs +386 -345
  22. package/dist/index.umd.cjs.map +1 -1
  23. package/dist/infrastructure/ioc/container.d.ts +7 -0
  24. package/dist/infrastructure/ioc/types.d.ts +5 -0
  25. package/dist/plugin.d.ts +1 -1
  26. package/dist/style.css +1 -1
  27. package/package.json +18 -11
  28. package/src/UI/components/index.ts +2 -0
  29. package/src/UI/components/patient-header/patient-header.ts +28 -0
  30. package/src/UI/components/patient-header/styles.scss +25 -0
  31. package/src/UI/components/patient-header/template.ts +18 -0
  32. package/src/UI/components/primaria-shell/template.ts +4 -0
  33. package/src/UI/components/professional-header/professional-header.ts +27 -0
  34. package/src/UI/components/professional-header/styles.scss +25 -0
  35. package/src/UI/components/professional-header/template.ts +18 -0
  36. package/src/UI/fonts/fonts.css +48 -0
  37. package/src/UI/fonts/open-sans-v40-latin-300.woff2 +0 -0
  38. package/src/UI/fonts/open-sans-v40-latin-500.woff2 +0 -0
  39. package/src/UI/fonts/open-sans-v40-latin-600.woff2 +0 -0
  40. package/src/UI/fonts/open-sans-v40-latin-700.woff2 +0 -0
  41. package/src/UI/fonts/open-sans-v40-latin-800.woff2 +0 -0
  42. package/src/UI/fonts/open-sans-v40-latin-regular.woff2 +0 -0
  43. package/src/UI/shared-components/primaria-interaction/components/notifier-component.ts +2 -2
  44. package/src/UI/styles/index.css +18 -0
  45. package/src/api/api.ts +3 -13
  46. package/src/api/broker/factory.test.ts +8 -3
  47. package/src/api/broker/factory.ts +3 -0
  48. package/src/api/global-state/global-state.test.ts +1 -1
  49. package/src/api/global-state/global-state.ts +1 -1
  50. package/src/api/http-client/http-client.ts +14 -0
  51. package/src/features/bootstrapper.ts +16 -0
  52. package/src/features/get-patient-info/backend-adapter.ts +24 -0
  53. package/src/features/get-patient-info/bootstrapper.ts +17 -0
  54. package/src/features/get-patient-info/handler.ts +25 -0
  55. package/src/features/get-patient-info/model.ts +7 -0
  56. package/src/features/get-patient-info/request.ts +4 -0
  57. package/src/features/get-user-info/backend-adapter.ts +24 -0
  58. package/src/features/get-user-info/bootstrapper.ts +17 -0
  59. package/src/features/get-user-info/handler.ts +26 -0
  60. package/src/features/get-user-info/model.ts +8 -0
  61. package/src/features/get-user-info/request.ts +4 -0
  62. package/src/features/utils.ts +20 -0
  63. package/src/infrastructure/ioc/container.ts +14 -0
  64. package/src/infrastructure/ioc/types.ts +5 -0
  65. package/src/initializer.ts +12 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uxland/primary-shell",
3
- "version": "2.0.1-rc.2",
3
+ "version": "2.1.1",
4
4
  "description": "Primaria Shell",
5
5
  "author": "UXLand <dev@uxland.es>",
6
6
  "homepage": "https://github.com/uxland/harmonix/tree/app#readme",
@@ -9,7 +9,10 @@
9
9
  "main": "src/index.ts",
10
10
  "types": "dist/index.d.ts",
11
11
  "module": "dist/index.js",
12
- "files": ["dist", "src"],
12
+ "files": [
13
+ "dist",
14
+ "src"
15
+ ],
13
16
  "publishConfig": {
14
17
  "access": "public",
15
18
  "registry": "https://registry.npmjs.org/"
@@ -18,18 +21,12 @@
18
21
  "type": "git",
19
22
  "url": "git+https://github.com/uxland/harmonix.git"
20
23
  },
21
- "scripts": {
22
- "serve": "vite",
23
- "start": "ng serve --host 0.0.0.0",
24
- "build": "vite build",
25
- "preview": "vite preview",
26
- "publish-rc": "npm publish --tag rc"
27
- },
28
24
  "bugs": {
29
25
  "url": "https://github.com/uxland/harmonix/issues"
30
26
  },
31
27
  "dependencies": {
32
- "@uxland/harmonix": "^1.0.0"
28
+ "@uxland/harmonix": "^1.0.0",
29
+ "axios": "^1.7.2"
33
30
  },
34
31
  "devDependencies": {
35
32
  "lit": "^3.1.0",
@@ -43,6 +40,16 @@
43
40
  "mediatr-ts": "^1.2.1",
44
41
  "tslib": "^2.3.0",
45
42
  "vite": "^5.2.8",
43
+ "inversify": "^6.0.2",
44
+ "inversify-inject-decorators": "^3.1.0",
45
+ "jwt-decode": "^4.0.0",
46
46
  "@salut/design-system-salut": "1.6.0"
47
+ },
48
+ "scripts": {
49
+ "serve": "vite",
50
+ "start": "ng serve --host 0.0.0.0",
51
+ "build": "vite build",
52
+ "preview": "vite preview",
53
+ "publish-rc": "npm publish --tag rc"
47
54
  }
48
- }
55
+ }
@@ -3,3 +3,5 @@ import "./clinical-monitoring/clinical-monitoring";
3
3
  import "./title-view/title-view";
4
4
  import "./primaria-breadcumbs/primaria-breadcumbs";
5
5
  import "../shared-components";
6
+ import "../components/patient-header/patient-header";
7
+ import "../components/professional-header/professional-header";
@@ -0,0 +1,28 @@
1
+ import { LitElement, css, html, unsafeCSS } from "lit";
2
+ import { customElement, property } from "lit/decorators.js";
3
+ import styles from "./styles.scss?inline";
4
+ import { template } from "./template";
5
+ import { shellApi } from "../../../api/api";
6
+ import { IPatientInfo } from "primary/shell/src/features/get-patient-info/model";
7
+ import { GetPatientInfo } from "../../../features/get-patient-info/request";
8
+
9
+ @customElement("patient-header")
10
+ export class PatientHeader extends LitElement {
11
+ render() {
12
+ return html`${template(this)}`;
13
+ }
14
+
15
+ static styles = css`
16
+ ${unsafeCSS(styles)}
17
+ `;
18
+
19
+ @property({ type: Object })
20
+ patient: IPatientInfo;
21
+
22
+ connectedCallback() {
23
+ super.connectedCallback();
24
+ shellApi.broker.send(new GetPatientInfo()).then((response: IPatientInfo) => {
25
+ this.patient = response;
26
+ });
27
+ }
28
+ }
@@ -0,0 +1,25 @@
1
+ .wrapper {
2
+ gap: 16px;
3
+ @include layout-horizontal;
4
+ @include layout-center;
5
+ .details {
6
+ color: var(--color-neutral-500);
7
+ }
8
+ }
9
+
10
+ .name-details {
11
+ display: flex;
12
+ @include layout-vertical;
13
+ line-height: 24px;
14
+ size: 14px;
15
+ .name {
16
+ font-family: var(--font-semibold);
17
+ color: var(--color-primary-700);
18
+ font-weight: 600;
19
+ text-decoration: underline;
20
+ }
21
+ .details {
22
+ font-weight: 400;
23
+ font-family: var(--font-regular);
24
+ }
25
+ }
@@ -0,0 +1,18 @@
1
+ import { html } from "lit";
2
+ import { PatientHeader } from "./patient-header";
3
+
4
+ export const template = (props: PatientHeader) => html`
5
+ <div class="wrapper">
6
+ <dss-avatar size="lg" name="${props.patient.firstName.charAt(
7
+ 0,
8
+ )}" surname="${props.patient.lastName.charAt(0)}"></dss-avatar>
9
+ <div class="name-details">
10
+ <div class="name">
11
+ ${props.patient.firstName} ${props.patient.lastName}
12
+ </div>
13
+ <div class="details">
14
+ ${props.patient.patientId}
15
+ </div>
16
+ </div>
17
+ </div>
18
+ `;
@@ -1,5 +1,7 @@
1
1
  import "@salut/design-system-salut";
2
2
  import "@salut/design-system-salut/css/main.css";
3
+ import "../../fonts/fonts.css";
4
+ import "../../styles/index.css";
3
5
  import { html } from "lit";
4
6
  import gencatLogo from "../../../UI/images/Gencat_Logotip.svg";
5
7
  import salutLogo from "../../../UI/images/Salut_Logotip.svg";
@@ -13,9 +15,11 @@ export const template = (props: PrimariaShell) => html`
13
15
  <img src=${salutLogo} alt="logo" />
14
16
  </div>
15
17
  <primaria-content-switcher id="header-region-container"></primaria-content-switcher>
18
+ <patient-header></patient-header>
16
19
  </div>
17
20
  <div class="header__right">
18
21
  <div id="header-actions-region-container"></div>
22
+ <professional-header></professional-header>
19
23
  </div>
20
24
  </div>
21
25
  <div class="main-container">
@@ -0,0 +1,27 @@
1
+ import { LitElement, css, html, unsafeCSS } from "lit";
2
+ import { customElement, property } from "lit/decorators.js";
3
+ import styles from "./styles.scss?inline";
4
+ import { template } from "./template";
5
+ import { shellApi } from "../../../api/api";
6
+ import { IUserInfo } from "primary/shell/src/features/get-user-info/model";
7
+ import { GetUserInfo } from "../../../features/get-user-info/request";
8
+
9
+ @customElement("professional-header")
10
+ export class ProfessionalHeader extends LitElement {
11
+ render() {
12
+ return html`${template(this)}`;
13
+ }
14
+
15
+ static styles = css`
16
+ ${unsafeCSS(styles)}
17
+ `;
18
+ @property({ type: Object })
19
+ professional: IUserInfo;
20
+
21
+ connectedCallback() {
22
+ super.connectedCallback();
23
+ shellApi.broker.send(new GetUserInfo()).then((response: IUserInfo) => {
24
+ this.professional = response;
25
+ });
26
+ }
27
+ }
@@ -0,0 +1,25 @@
1
+ .wrapper {
2
+ gap: 16px;
3
+ @include layout-horizontal;
4
+ @include layout-center;
5
+ .details {
6
+ color: var(--color-neutral-500);
7
+ }
8
+ }
9
+
10
+ .name-details {
11
+ display: flex;
12
+ @include layout-vertical;
13
+ line-height: 24px;
14
+ size: 14px;
15
+ .name {
16
+ font-family: var(--font-semibold);
17
+ color: var(--color-primary-700);
18
+ font-weight: 600;
19
+ text-decoration: underline;
20
+ }
21
+ .details {
22
+ font-weight: 400;
23
+ font-family: var(--font-regular);
24
+ }
25
+ }
@@ -0,0 +1,18 @@
1
+ import { html } from "lit";
2
+ import { ProfessionalHeader } from "./professional-header";
3
+
4
+ export const template = (props: ProfessionalHeader) => html`
5
+ <div class="wrapper">
6
+ <dss-avatar size="lg" name="${props.professional.firstName.charAt(
7
+ 0,
8
+ )}" surname="${props.professional.lastName.charAt(0)}"></dss-avatar>
9
+ <div class="name-details">
10
+ <div class="name">
11
+ ${props.professional.firstName} ${props.professional.lastName}
12
+ </div>
13
+ <div class="details">
14
+ ${props.professional.speciality}
15
+ </div>
16
+ </div>
17
+ </div>
18
+ `;
@@ -0,0 +1,48 @@
1
+ /* open-sans-300 - latin */
2
+ @font-face {
3
+ font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
4
+ font-family: 'Open Sans';
5
+ font-style: normal;
6
+ font-weight: 300;
7
+ src: url('open-sans-v40-latin-300.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
8
+ }
9
+ /* open-sans-regular - latin */
10
+ @font-face {
11
+ font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
12
+ font-family: 'Open Sans';
13
+ font-style: normal;
14
+ font-weight: 400;
15
+ src: url('open-sans-v40-latin-regular.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
16
+ }
17
+ /* open-sans-500 - latin */
18
+ @font-face {
19
+ font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
20
+ font-family: 'Open Sans';
21
+ font-style: normal;
22
+ font-weight: 500;
23
+ src: url('open-sans-v40-latin-500.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
24
+ }
25
+ /* open-sans-600 - latin */
26
+ @font-face {
27
+ font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
28
+ font-family: 'Open Sans';
29
+ font-style: normal;
30
+ font-weight: 600;
31
+ src: url('open-sans-v40-latin-600.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
32
+ }
33
+ /* open-sans-700 - latin */
34
+ @font-face {
35
+ font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
36
+ font-family: 'Open Sans';
37
+ font-style: normal;
38
+ font-weight: 700;
39
+ src: url('open-sans-v40-latin-700.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
40
+ }
41
+ /* open-sans-800 - latin */
42
+ @font-face {
43
+ font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
44
+ font-family: 'Open Sans';
45
+ font-style: normal;
46
+ font-weight: 800;
47
+ src: url('open-sans-v40-latin-800.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
48
+ }
@@ -22,9 +22,9 @@ export class NotifierComponent extends LitElement {
22
22
  render() {
23
23
  return html`
24
24
  <div class="snackbar ${this.options.type}">
25
- <i class="dss-icon-button dss-icon-button--primary dss-icon-button--md ">
25
+ <dss-container><i class="dss-icon-button dss-icon-button--primary dss-icon-button--md ">
26
26
  <span class="dss-icon">${ifDefined(getIcon(this.options.type))}</span>
27
- </i>
27
+ </i></dss-container>
28
28
  <div class="snackbar__message">${this.options.message ?? ""}</div>
29
29
  <div class="snackbar__action">
30
30
  <dss-container><button class="dss-icon-button dss-icon-button--success dss-icon-button--md">
@@ -0,0 +1,18 @@
1
+ body {
2
+ margin: 0;
3
+ overflow: hidden;
4
+ font-size: 14px;
5
+ background-color: #f5f6fa;
6
+ font-family: 'Open Sans', sans-serif;
7
+ pointer-events: auto !important;
8
+ width: 100%;
9
+ height: 100%;
10
+ }
11
+
12
+ html {
13
+ font-size: 14px;
14
+ overflow: hidden;
15
+ font-family: 'Open Sans', sans-serif;
16
+ width: 100%;
17
+ height: 100%;
18
+ }
package/src/api/api.ts CHANGED
@@ -15,15 +15,12 @@ import {
15
15
  import { PrimariaGlobalStateManager, createGlobalStateManager } from "./global-state/global-state";
16
16
  import { PrimariaBroker } from "./broker/primaria-broker";
17
17
  import { createBroker } from "./broker/factory";
18
+ import { HttpClient, createHttpClient } from "./http-client/http-client";
18
19
  const broker = createBroker();
19
20
 
20
- interface PrimariaHttpClient {
21
- get(url: string): Promise<any>;
22
- post(url: string, data: any): Promise<any>;
23
- }
24
21
 
25
22
  export interface PrimariaApi extends HarmonixApi {
26
- httpClient: PrimariaHttpClient;
23
+ httpClient: HttpClient;
27
24
  interactionManager: PrimariaInteractionManager;
28
25
  broker: PrimariaBroker;
29
26
  regionManager: PrimariaRegionManager;
@@ -45,14 +42,7 @@ export const primariaApiFactory: ApiFactory<PrimariaApi> = (
45
42
  return {
46
43
  pluginInfo: pluginInfo,
47
44
  regionManager: createRegionManagerProxy(pluginInfo, regionManager),
48
- httpClient: {
49
- get: (url: string) => fetch(url).then((r) => r.json()),
50
- post: (url: string, data: any) =>
51
- fetch(url, {
52
- method: "POST",
53
- body: JSON.stringify(data),
54
- }).then((r) => r.json()),
55
- },
45
+ httpClient: createHttpClient(),
56
46
  interactionManager: { ...createInteractionManager() },
57
47
  broker: broker,
58
48
  createLocaleManager: createLocaleManager(pluginInfo.pluginId) as any,
@@ -40,7 +40,7 @@ describe("Broker test", () => {
40
40
  describe("Given some subscriptions for an event", () => {
41
41
  let handlers: Mock[];
42
42
  beforeEach(() => {
43
- handlers = Array.from({ length: 5 }).map(() => {
43
+ handlers = Array.from({length: 5}).map(() => {
44
44
  const handler = vi.fn();
45
45
  sut.subscribe("MyEvent", handler);
46
46
  return handler;
@@ -48,15 +48,20 @@ describe("Broker test", () => {
48
48
  });
49
49
  describe("When event is published", () => {
50
50
  beforeEach(() => {
51
- sut.publish("MyEvent", { greeting: "Hello" });
51
+ sut.publish("MyEvent", {greeting: "Hello"});
52
52
  });
53
53
  it("Then handler is called", () => {
54
54
  for (const handler of handlers) {
55
- expect(handler).toBeCalledWith({ greeting: "Hello" });
55
+ expect(handler).toBeCalledWith({greeting: "Hello"});
56
56
  }
57
57
  });
58
58
  });
59
59
  });
60
+ describe("Given no subscriptions for an event", () => {
61
+ it("When event is published, Then nothing happens", () => {
62
+ expect(() => sut.publish("MyEvent", { greeting: "Hello" })).not.toThrow();
63
+ });
64
+ });
60
65
  });
61
66
  });
62
67
  describe("Message broker test", () => {
@@ -30,6 +30,9 @@ class Broker implements PrimariaBroker {
30
30
  publish(event: string | IEvent, payload?: unknown): Promise<void> {
31
31
  const eventPayload =
32
32
  typeof event === "string" ? this.getEvent(event as string, payload) : event;
33
+ const classConstructor = eventPayload.constructor || Object.getPrototypeOf(eventPayload).constructor;
34
+ const handlerSubscriptions = mediatorSettings.dispatcher.notifications._mappings.filter(m => m.notification === classConstructor);
35
+ if (!handlerSubscriptions.length) return Promise.resolve();
33
36
  return this.mediator.publish(eventPayload);
34
37
  }
35
38
  subscribe<TEvent extends IEvent>(
@@ -25,7 +25,7 @@ describe("PrimariaGlobalStateManagerImpl", () => {
25
25
  globalStateManager.setData(key, value);
26
26
 
27
27
  expect(globalStateManager.getData(key)).toBe(value);
28
- expect(brokerMock.publish).toHaveBeenCalledWith("data-setted", {
28
+ expect(brokerMock.publish).toHaveBeenCalledWith("data_set", {
29
29
  key: key,
30
30
  value: value,
31
31
  });
@@ -19,7 +19,7 @@ class PrimariaGlobalStateManagerImpl implements PrimariaGlobalStateManager {
19
19
  */
20
20
  setData(key: string, value: any): void {
21
21
  this.state[key] = value;
22
- this.broker.publish("data-setted", {
22
+ this.broker.publish("data_set", {
23
23
  key: key,
24
24
  value: value,
25
25
  });
@@ -0,0 +1,14 @@
1
+
2
+ import axios, { AxiosRequestConfig, AxiosResponse } from "axios";
3
+ const token = "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJ1S2hQbXhscHB4d2sxUDVfWmQ5am9CeTV6N2p5MHFPd0ZWY3RwZjBDa0E4In0.eyJleHAiOjE3MjEzMDc3MTcsImlhdCI6MTcyMTMwNzQxNywianRpIjoiNWRkMDE1YzgtNTQ5Yy00ZGM2LWE4YWItMTUzNDJiMWRhNThmIiwiaXNzIjoiaHR0cHM6Ly9pbnRlZ3JhY2lvLnBkcy5oZXMuY2F0c2FsdXQuaW50cmFuZXQuZ2VuY2F0LmNhdC9hdXRoL3JlYWxtcy9FVEMiLCJzdWIiOiJlMjRlMzFlMC01NWZiLTRhZmEtYTQzNi0yYmRhOGYyYWQ0ZWUiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJldGMtY2NmLWludCIsInNlc3Npb25fc3RhdGUiOiJhY2M2ZDBlYi1iMTBjLTQ3ZDEtYjFlOC0xYWQ5ODU5NTAyNTkiLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsiZGVmYXVsdC1yb2xlcy1oZXMtY2FtIl19LCJzY29wZSI6IiIsInNpZCI6ImFjYzZkMGViLWIxMGMtNDdkMS1iMWU4LTFhZDk4NTk1MDI1OSIsImNsaWVudEhvc3QiOiIxMC41My4yNTQuMTUwIiwiYWNjZXNzX3J1bGVzIjp7fSwiYWNjZXNzX2luZm8iOnsicGF0aWVudF9nZW5kZXIiOiIxIiwicGF0aWVudF9iaXJ0aGRhdGUiOiIxOTk5MDEwMSIsInByb2Zlc3Npb25hbF9yb2xlIjoiQURNIiwicHJvZmVzc2lvbmFsX2lkIjoiMTIzNDU2Nzg5MCIsInVwX2NvZGUiOiIwNzczMyIsInBhdGllbnRfZ2l2ZW5fbmFtZSI6ImNhc3RhbnkiLCJwYXRpZW50X2lkIjoiMTIzNDU2Nzg5MCIsInByb2Zlc3Npb25hbF9zcGVjaWFsaXR5IjoiU1BFQzAxIiwicHJvZmVzc2lvbmFsX3NlcnZpY2UiOiJTRVJWMDEiLCJwYXRpZW50X2xhc3RfbmFtZSI6IkFSRUdBTEwiLCJlcF9jb2RlIjoiMDIwOCJ9LCJjbGllbnRBZGRyZXNzIjoiMTAuNTMuMjU0LjE1MCIsImNsaWVudF9pZCI6ImV0Yy1jY2YtaW50In0.NiDKnMchNB4zqL9zOdq15G8y2BYGOyjk8n1xofB2WyxhVpbTXhXAgApS-4DCqczmdPt4sOwtt-FVVxcYku2gKcQQ1Leapb7CmHoUT_ak5ovOE8ZrD5Ryz6rfC_O1lO8Ut4M_J-KzMxj7WvUNYhkIqcHFSMwDdNC6xxc4ZYMOUI4bOif_Tiy7CxvMIpFGm1YS_jiGS2PGI8Y1o_1DApqMs88MxK9ItO-DIfQgKcR3wV6J-QZueaKVtih-kLma33TZc0jz7xG1EyOMJ5cC4r1Sxp877b9ut4JCmMaWOfWNf2tldLcpXTvV_BWg53YpwYOl4pvZdg3lFWEb009DofTQbQ"
4
+ let instance = axios.create({
5
+ headers: {
6
+ "Authorization": "Bearer "+ token
7
+ }
8
+ });
9
+ export interface HttpClient {
10
+ request<T = any, R = AxiosResponse<T>, D = any>(config: AxiosRequestConfig<D>): Promise<R>;
11
+ }
12
+ export const createHttpClient = () : HttpClient => {
13
+ return {request: instance.request}
14
+ };
@@ -0,0 +1,16 @@
1
+ import { PrimariaApi } from "@uxland/primary-shell";
2
+ import { container } from "../infrastructure/ioc/container";
3
+ import { TYPES } from "../infrastructure/ioc/types";
4
+ import { bootstrapGetUserInfo, teardownGetUserInfo } from "./get-user-info/bootstrapper";
5
+ import { bootstrapGetPatientInfo, teardownGetPatientInfo } from "./get-patient-info/bootstrapper";
6
+
7
+ export const bootstrapFeatures = (api: PrimariaApi) => {
8
+ container.bind(TYPES.primaryApi).toConstantValue(api);
9
+ bootstrapGetUserInfo();
10
+ bootstrapGetPatientInfo();
11
+ };
12
+
13
+ export const teardownFeatures = () => {
14
+ teardownGetUserInfo();
15
+ teardownGetPatientInfo();
16
+ };
@@ -0,0 +1,24 @@
1
+ import { injectable } from "inversify";
2
+ import { IPatientInfo } from "./model";
3
+ import { jwtDecode } from "jwt-decode";
4
+
5
+ export abstract class PatientInfoBackendAdapter {
6
+ abstract getPatientInfo(): Promise<IPatientInfo>;
7
+ }
8
+ @injectable()
9
+ export class GetPatientInfoBackendAdapter implements PatientInfoBackendAdapter {
10
+ token =
11
+ "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJ1S2hQbXhscHB4d2sxUDVfWmQ5am9CeTV6N2p5MHFPd0ZWY3RwZjBDa0E4In0.eyJleHAiOjE3MjEzMDc3MTcsImlhdCI6MTcyMTMwNzQxNywianRpIjoiNWRkMDE1YzgtNTQ5Yy00ZGM2LWE4YWItMTUzNDJiMWRhNThmIiwiaXNzIjoiaHR0cHM6Ly9pbnRlZ3JhY2lvLnBkcy5oZXMuY2F0c2FsdXQuaW50cmFuZXQuZ2VuY2F0LmNhdC9hdXRoL3JlYWxtcy9FVEMiLCJzdWIiOiJlMjRlMzFlMC01NWZiLTRhZmEtYTQzNi0yYmRhOGYyYWQ0ZWUiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJldGMtY2NmLWludCIsInNlc3Npb25fc3RhdGUiOiJhY2M2ZDBlYi1iMTBjLTQ3ZDEtYjFlOC0xYWQ5ODU5NTAyNTkiLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsiZGVmYXVsdC1yb2xlcy1oZXMtY2FtIl19LCJzY29wZSI6IiIsInNpZCI6ImFjYzZkMGViLWIxMGMtNDdkMS1iMWU4LTFhZDk4NTk1MDI1OSIsImNsaWVudEhvc3QiOiIxMC41My4yNTQuMTUwIiwiYWNjZXNzX3J1bGVzIjp7fSwiYWNjZXNzX2luZm8iOnsicGF0aWVudF9nZW5kZXIiOiIxIiwicGF0aWVudF9iaXJ0aGRhdGUiOiIxOTk5MDEwMSIsInByb2Zlc3Npb25hbF9yb2xlIjoiQURNIiwicHJvZmVzc2lvbmFsX2lkIjoiMTIzNDU2Nzg5MCIsInVwX2NvZGUiOiIwNzczMyIsInBhdGllbnRfZ2l2ZW5fbmFtZSI6ImNhc3RhbnkiLCJwYXRpZW50X2lkIjoiMTIzNDU2Nzg5MCIsInByb2Zlc3Npb25hbF9zcGVjaWFsaXR5IjoiU1BFQzAxIiwicHJvZmVzc2lvbmFsX3NlcnZpY2UiOiJTRVJWMDEiLCJwYXRpZW50X2xhc3RfbmFtZSI6IkFSRUdBTEwiLCJlcF9jb2RlIjoiMDIwOCJ9LCJjbGllbnRBZGRyZXNzIjoiMTAuNTMuMjU0LjE1MCIsImNsaWVudF9pZCI6ImV0Yy1jY2YtaW50In0.NiDKnMchNB4zqL9zOdq15G8y2BYGOyjk8n1xofB2WyxhVpbTXhXAgApS-4DCqczmdPt4sOwtt-FVVxcYku2gKcQQ1Leapb7CmHoUT_ak5ovOE8ZrD5Ryz6rfC_O1lO8Ut4M_J-KzMxj7WvUNYhkIqcHFSMwDdNC6xxc4ZYMOUI4bOif_Tiy7CxvMIpFGm1YS_jiGS2PGI8Y1o_1DApqMs88MxK9ItO-DIfQgKcR3wV6J-QZueaKVtih-kLma33TZc0jz7xG1EyOMJ5cC4r1Sxp877b9ut4JCmMaWOfWNf2tldLcpXTvV_BWg53YpwYOl4pvZdg3lFWEb009DofTQbQ";
12
+ getPatientInfo(): Promise<IPatientInfo> {
13
+ const decodedToken = jwtDecode(this.token);
14
+ console.log(decodedToken);
15
+ const patientInfo: IPatientInfo = {
16
+ patientId: decodedToken.access_info.professional_id,
17
+ firstName: decodedToken.access_info.patient_given_name,
18
+ lastName: decodedToken.access_info.patient_last_name,
19
+ gender: decodedToken.access_info.patient_gender,
20
+ birthdate: decodedToken.access_info.patient_birthdate,
21
+ };
22
+ return Promise.resolve(patientInfo);
23
+ }
24
+ }
@@ -0,0 +1,17 @@
1
+ import { shellApi } from "../../api/api";
2
+ import { container, registerDep, unregisterDep } from "../../infrastructure/ioc/container";
3
+ import { registerRequest, unregisterRequest } from "../utils";
4
+ import { GetPatientInfoBackendAdapter } from "./backend-adapter";
5
+ import { GetPatientInfoHandler } from "./handler";
6
+ import { GetPatientInfo } from "./request";
7
+
8
+ export const bootstrapGetPatientInfo = () => {
9
+ teardownGetPatientInfo();
10
+ registerRequest(shellApi, container)(GetPatientInfo, GetPatientInfoHandler);
11
+ registerDep(GetPatientInfoBackendAdapter);
12
+ };
13
+
14
+ export const teardownGetPatientInfo = () => {
15
+ unregisterRequest(container)(GetPatientInfoHandler);
16
+ unregisterDep(GetPatientInfoBackendAdapter);
17
+ };
@@ -0,0 +1,25 @@
1
+ import { inject } from "inversify";
2
+ import { TYPES } from "../../infrastructure/ioc/types";
3
+ import { PrimariaApi } from "@uxland/primary-shell";
4
+ import { GetPatientInfoBackendAdapter, PatientInfoBackendAdapter } from "./backend-adapter";
5
+ import { GetPatientInfo } from "./request";
6
+ import { IPatientInfo } from "./model";
7
+
8
+ export class GetPatientInfoHandler {
9
+ constructor(
10
+ @inject(TYPES.primaryApi) private api: PrimariaApi,
11
+ @inject(GetPatientInfoBackendAdapter) private backendAdapter: PatientInfoBackendAdapter,
12
+ ) {}
13
+ async handle(message: GetPatientInfo): Promise<IPatientInfo | undefined> {
14
+ try {
15
+ const patientInfo = await this.backendAdapter.getPatientInfo();
16
+ this.api.globalStateManager.setData("patientInfo", patientInfo);
17
+ return patientInfo;
18
+ } catch (error) {
19
+ this.api.interactionManager.notify({
20
+ type: "error",
21
+ message: error.message,
22
+ });
23
+ }
24
+ }
25
+ }
@@ -0,0 +1,7 @@
1
+ export interface IPatientInfo {
2
+ patientId: string;
3
+ firstName: string;
4
+ lastName: string;
5
+ gender: string;
6
+ birthdate: string;
7
+ }
@@ -0,0 +1,4 @@
1
+ import { IRequest } from "@uxland/primary-shell";
2
+ import { IPatientInfo } from "./model";
3
+
4
+ export class GetPatientInfo implements IRequest<IPatientInfo> {}
@@ -0,0 +1,24 @@
1
+ import { injectable } from "inversify";
2
+ import { IUserInfo } from "./model";
3
+ import { jwtDecode } from "jwt-decode";
4
+
5
+ export abstract class UserInfoBackendAdapter {
6
+ abstract getUserInfo(): Promise<IUserInfo>;
7
+ }
8
+ @injectable()
9
+ export class GetUserInfoBackendAdapter implements UserInfoBackendAdapter {
10
+ token =
11
+ "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJ1S2hQbXhscHB4d2sxUDVfWmQ5am9CeTV6N2p5MHFPd0ZWY3RwZjBDa0E4In0.eyJleHAiOjE3MjEzMDc3MTcsImlhdCI6MTcyMTMwNzQxNywianRpIjoiNWRkMDE1YzgtNTQ5Yy00ZGM2LWE4YWItMTUzNDJiMWRhNThmIiwiaXNzIjoiaHR0cHM6Ly9pbnRlZ3JhY2lvLnBkcy5oZXMuY2F0c2FsdXQuaW50cmFuZXQuZ2VuY2F0LmNhdC9hdXRoL3JlYWxtcy9FVEMiLCJzdWIiOiJlMjRlMzFlMC01NWZiLTRhZmEtYTQzNi0yYmRhOGYyYWQ0ZWUiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJldGMtY2NmLWludCIsInNlc3Npb25fc3RhdGUiOiJhY2M2ZDBlYi1iMTBjLTQ3ZDEtYjFlOC0xYWQ5ODU5NTAyNTkiLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsiZGVmYXVsdC1yb2xlcy1oZXMtY2FtIl19LCJzY29wZSI6IiIsInNpZCI6ImFjYzZkMGViLWIxMGMtNDdkMS1iMWU4LTFhZDk4NTk1MDI1OSIsImNsaWVudEhvc3QiOiIxMC41My4yNTQuMTUwIiwiYWNjZXNzX3J1bGVzIjp7fSwiYWNjZXNzX2luZm8iOnsicGF0aWVudF9nZW5kZXIiOiIxIiwicGF0aWVudF9iaXJ0aGRhdGUiOiIxOTk5MDEwMSIsInByb2Zlc3Npb25hbF9yb2xlIjoiQURNIiwicHJvZmVzc2lvbmFsX2lkIjoiMTIzNDU2Nzg5MCIsInVwX2NvZGUiOiIwNzczMyIsInBhdGllbnRfZ2l2ZW5fbmFtZSI6ImNhc3RhbnkiLCJwYXRpZW50X2lkIjoiMTIzNDU2Nzg5MCIsInByb2Zlc3Npb25hbF9zcGVjaWFsaXR5IjoiU1BFQzAxIiwicHJvZmVzc2lvbmFsX3NlcnZpY2UiOiJTRVJWMDEiLCJwYXRpZW50X2xhc3RfbmFtZSI6IkFSRUdBTEwiLCJlcF9jb2RlIjoiMDIwOCJ9LCJjbGllbnRBZGRyZXNzIjoiMTAuNTMuMjU0LjE1MCIsImNsaWVudF9pZCI6ImV0Yy1jY2YtaW50In0.NiDKnMchNB4zqL9zOdq15G8y2BYGOyjk8n1xofB2WyxhVpbTXhXAgApS-4DCqczmdPt4sOwtt-FVVxcYku2gKcQQ1Leapb7CmHoUT_ak5ovOE8ZrD5Ryz6rfC_O1lO8Ut4M_J-KzMxj7WvUNYhkIqcHFSMwDdNC6xxc4ZYMOUI4bOif_Tiy7CxvMIpFGm1YS_jiGS2PGI8Y1o_1DApqMs88MxK9ItO-DIfQgKcR3wV6J-QZueaKVtih-kLma33TZc0jz7xG1EyOMJ5cC4r1Sxp877b9ut4JCmMaWOfWNf2tldLcpXTvV_BWg53YpwYOl4pvZdg3lFWEb009DofTQbQ";
12
+ getUserInfo(): Promise<IUserInfo> {
13
+ const decodedToken = jwtDecode(this.token);
14
+ const userInfo: IUserInfo = {
15
+ userId: decodedToken.access_info.professional_id,
16
+ firstName: "Nom", // TODO get professional data
17
+ lastName: "Cognom", // TODO get professional data
18
+ role: decodedToken.access_info.professional_role,
19
+ speciality: decodedToken.access_info.professional_speciality,
20
+ service: decodedToken.access_info.professional_service,
21
+ };
22
+ return Promise.resolve(userInfo);
23
+ }
24
+ }
@@ -0,0 +1,17 @@
1
+ import { shellApi } from "../../api/api";
2
+ import { container, registerDep, unregisterDep } from "../../infrastructure/ioc/container";
3
+ import { registerRequest, unregisterRequest } from "../utils";
4
+ import { GetUserInfoBackendAdapter } from "./backend-adapter";
5
+ import { GetUserInfoHandler } from "./handler";
6
+ import { GetUserInfo } from "./request";
7
+
8
+ export const bootstrapGetUserInfo = () => {
9
+ teardownGetUserInfo();
10
+ registerRequest(shellApi, container)(GetUserInfo, GetUserInfoHandler);
11
+ registerDep(GetUserInfoBackendAdapter);
12
+ };
13
+
14
+ export const teardownGetUserInfo = () => {
15
+ unregisterRequest(container)(GetUserInfoHandler);
16
+ unregisterDep(GetUserInfoBackendAdapter);
17
+ };
@@ -0,0 +1,26 @@
1
+ import { PrimariaApi } from "@uxland/primary-shell";
2
+ import { TYPES } from "../../infrastructure/ioc/types";
3
+ import { inject } from "inversify";
4
+ import { GetUserInfo } from "./request";
5
+ import { IUserInfo } from "./model";
6
+ import { UserInfoBackendAdapter } from "./backend-adapter";
7
+ import { GetUserInfoBackendAdapter } from "./backend-adapter";
8
+
9
+ export class GetUserInfoHandler {
10
+ constructor(
11
+ @inject(TYPES.primaryApi) private api: PrimariaApi,
12
+ @inject(GetUserInfoBackendAdapter) private backendAdapter: UserInfoBackendAdapter,
13
+ ) {}
14
+ async handle(message: GetUserInfo): Promise<IUserInfo | undefined> {
15
+ try {
16
+ const userInfo = await this.backendAdapter.getUserInfo();
17
+ this.api.globalStateManager.setData("userInfo", userInfo);
18
+ return userInfo;
19
+ } catch (error) {
20
+ this.api.interactionManager.notify({
21
+ type: "error",
22
+ message: error.message,
23
+ });
24
+ }
25
+ }
26
+ }
@@ -0,0 +1,8 @@
1
+ export interface IUserInfo {
2
+ userId: string;
3
+ firstName: string;
4
+ lastName: string;
5
+ role: string;
6
+ speciality: string;
7
+ service: string;
8
+ }
@@ -0,0 +1,4 @@
1
+ import { IRequest } from "@uxland/primary-shell";
2
+ import { IUserInfo } from "./model";
3
+
4
+ export class GetUserInfo implements IRequest<IUserInfo> {}