@3cr/viewer-browser 0.0.220 → 0.0.246

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 (57) hide show
  1. package/components.d.ts +6 -2
  2. package/dist/Viewer3CR.js +32 -32
  3. package/dist/Viewer3CR.mjs +17808 -14315
  4. package/dist/Viewer3CR.umd.js +32 -32
  5. package/index.html +1 -1
  6. package/package.json +4 -3
  7. package/playground/index.html +4 -12
  8. package/src/App.vue +29 -14
  9. package/src/__tests__/main.spec.ts +4 -4
  10. package/src/assets/styles.scss +6 -2
  11. package/src/components/demo/DemoPatientModal.vue +12 -22
  12. package/src/components/demo/licence/DemoLicenceInfoModal.vue +11 -29
  13. package/src/components/demo/options.ts +42 -39
  14. package/src/components/demo/patient/DemoPatientInfoModal.vue +11 -29
  15. package/src/components/modal/CloseViewerModal.vue +1 -1
  16. package/src/components/modal/MftpWebGL3DRModal.vue +133 -120
  17. package/src/components/modal/ViewerActionRail.vue +0 -6
  18. package/src/components/modal/ViewerNavigationDrawerContent.vue +25 -16
  19. package/src/components/modal/ViewerNavigationDrawerFooter.vue +32 -9
  20. package/src/components/modal/ViewerNavigationDrawerHeader.vue +6 -1
  21. package/src/components/modal/WebGL3DR.vue +7 -0
  22. package/src/components/modal/__tests__/ViewerNavigationDrawerHeader.spec.ts +3 -2
  23. package/src/components/modal/buttons/AutoAnnotateBtn.vue +181 -13
  24. package/src/components/modal/menus/FileMenu.vue +2 -9
  25. package/src/components/modal/menus/SettingsMenu.vue +2 -7
  26. package/src/components/navigation/mcad/McadGlobalActions.vue +20 -0
  27. package/src/components/navigation/mcad/McadGlobalOpacitySlider.vue +103 -0
  28. package/src/components/navigation/mcad/McadGlobalScanViewBtn.vue +28 -0
  29. package/src/components/navigation/mcad/McadGlobalVisibilityBtn.vue +38 -0
  30. package/src/components/shared/LoadingSpinner.vue +27 -36
  31. package/src/components/views/AnnotationTreeView.vue +3 -1
  32. package/src/components/views/MarkupTreeView.vue +3 -1
  33. package/src/components/views/McadObjectTreeView.vue +46 -36
  34. package/src/components/views/modals/DataOverlayGeneralModal.vue +71 -0
  35. package/src/components/views/modals/DataOverlayMarkupModal.vue +60 -0
  36. package/src/components/views/modals/DataOverlayModal.vue +54 -55
  37. package/src/components/views/shared/Opacity.vue +0 -1
  38. package/src/composables/useDebounce.ts +11 -0
  39. package/src/composables/useIntroJs.ts +23 -6
  40. package/src/composables/useViewerOptions.ts +1 -0
  41. package/src/functions/guards/isDataOverlayAngle.ts +6 -0
  42. package/src/functions/guards/isDataOverlayLength.ts +6 -0
  43. package/src/functions/guards/isDataOverlayPolygon.ts +6 -0
  44. package/src/functions/modelHelper.ts +2 -0
  45. package/src/functions/notification.ts +63 -29
  46. package/src/main.ts +22 -13
  47. package/src/models/loadViewerOptions.ts +39 -0
  48. package/src/models/loadViewerPayload.ts +0 -7
  49. package/src/services/viewer-3cr.service.ts +13 -1
  50. package/src/tools/data-overlay.tool.ts +71 -0
  51. package/src/types/data-overlay-event.ts +5 -0
  52. package/src/types/data-overlay-info.ts +4 -0
  53. package/src/types/demo-type.ts +4 -0
  54. package/src/components/modal/actions/HideViewAction.vue +0 -38
  55. package/src/components/views/modals/DataOverlayModalManager.vue +0 -104
  56. package/src/components/views/modals/__tests__/DataOverlayModal.spec.ts +0 -33
  57. package/src/components/views/modals/__tests__/DataOverlayModalManager.spec.ts +0 -93
package/index.html CHANGED
@@ -32,7 +32,7 @@
32
32
  const testVersion = (window.location.href.includes('test.') || window.location.href.includes('localhost')) && new URLSearchParams(window.location.search).get("build_version")
33
33
  const version = testVersion ?? dynamicConfig.value["sdkVersion"] ?? "1.1.0";
34
34
 
35
- await registerViewer(version);
35
+ await registerViewer('#app', version);
36
36
  await loadViewer();
37
37
  </script>
38
38
  </body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@3cr/viewer-browser",
3
- "version": "0.0.220",
3
+ "version": "0.0.246",
4
4
  "main": "./dist/Viewer3CR.umd.js",
5
5
  "module": "dist/Viewer3CR.umd.js",
6
6
  "homepage": "https://docs.3cr.singular.health",
@@ -21,8 +21,9 @@
21
21
  "coverage": "vitest run --coverage"
22
22
  },
23
23
  "dependencies": {
24
- "@3cr/sdk-browser": "^1.0.16",
25
- "@3cr/types-ts": "^1.0.138",
24
+ "@3cr/sdk-browser": "^1.0.17",
25
+ "@3cr/translations-ts": "^1.0.1",
26
+ "@3cr/types-ts": "^1.0.166",
26
27
  "@kyvg/vue3-notification": "^3.2.1",
27
28
  "@mdi/font": "^7.4.47",
28
29
  "@mdi/js": "^7.4.47",
@@ -1,6 +1,5 @@
1
1
  <!DOCTYPE html>
2
2
  <html lang="en">
3
-
4
3
  <head>
5
4
  <meta charset="UTF-8" />
6
5
  <link rel="icon" href="/favicon.ico" />
@@ -14,7 +13,7 @@
14
13
  <meta name="msapplication-TileColor" content="#da532c">
15
14
  <meta name="theme-color" content="#ffffff">
16
15
 
17
- <script src="https://cdn.jsdelivr.net/npm/@3cr/viewer-browser@{{version}}/dist/Viewer3CR.umd.js"> </script>
16
+ <script src="https://cdn.jsdelivr.net/npm/@3cr/viewer-browser@{{version}}/dist/Viewer3CR.umd.js"></script>
18
17
  <script type="module">
19
18
  const channel = new BroadcastChannel('GET_SERVICE_WORKER_BUILD');
20
19
  channel.addEventListener('message', event => {
@@ -69,19 +68,15 @@
69
68
  <script src="https://cdn.jsdelivr.net/npm/@statsig/js-client@latest/build/statsig-js-client+session-replay+web-analytics.min.js"></script>
70
69
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
71
70
  <title>3CR Viewer Playground</title>
72
-
73
71
  </head>
74
-
75
72
  <body>
76
73
  <div id="app"></div>
77
74
  <script type="module">
78
-
79
75
  const { StatsigClient, runStatsigAutoCapture } = window.Statsig;
80
76
  const isTest = (window.location.href.includes('test.') || window.location.href.includes('localhost'))
81
- const client = new StatsigClient(
82
- "client-YaAjxOTTRbuSN3peDAwXEzErieXpI744a3OHDgonzvV",
77
+ const client = new StatsigClient("client-YaAjxOTTRbuSN3peDAwXEzErieXpI744a3OHDgonzvV",
83
78
  { userID: undefined },
84
- {environment: {tier: isTest ? 'development' : 'production'}}
79
+ { environment: { tier: isTest ? 'development' : 'production' } }
85
80
  );
86
81
  client.initializeSync()
87
82
  runStatsigAutoCapture(client);
@@ -93,15 +88,12 @@
93
88
  if (!testVersion) {
94
89
  version = dynamicConfig.value["sdkVersion"] ?? "1.1.0";
95
90
  }
96
- // const version = testVersion || dynamicConfig.value["sdkVersion"] ?? "1.1.0";
97
91
 
98
92
  client.initializeAsync().then(() => {
99
- window.registerViewer(version).then(() => {
93
+ window.registerViewer('#app', version).then(() => {
100
94
  window.loadViewer().then()
101
95
  })
102
96
  }).catch((err) => console.error(err));
103
-
104
97
  </script>
105
98
  </body>
106
-
107
99
  </html>
package/src/App.vue CHANGED
@@ -1,17 +1,34 @@
1
1
  <template>
2
- <v-app style="height: 0; width: 0">
3
- <MftpWebGL3DRModal ref="mftpWebGL3DRModal" :payload="payload" :options="options" />
4
- <Notifications />
5
- <update-snackbar />
6
- </v-app>
2
+ <MftpWebGL3DRModal v-if="show" ref="mftpWebGL3DRModal" :payload="payload" :options="options" />
3
+ <DemoLicenceInfoModal v-model:modal="m_demoLicence" />
4
+ <DemoLicenceShareToMobileModal v-model:modal="m_demoLicenceShareToMobile" />
5
+ <DemoLicenceSendToPartyModal v-model:modal="m_demoLicenceSendToParty" />
6
+ <DemoLicenceEnableCloudStorageModal v-model:modal="m_demoLicenseEnableCloudStorage" />
7
+ <DemoPatientInfoModal v-model:modal="m_demoPatient" />
8
+ <DemoPatientShareToMobileModal v-model:modal="m_demoPatientShareToMobile" />
9
+ <DemoPatientSendToPartyModal v-model:modal="m_demoPatientSendToParty" />
10
+ <DemoPatientEnableCloudStorageModal v-model:modal="m_demoPatientEnableCloudStorage" />
11
+ <Notifications />
12
+ <update-snackbar />
7
13
  </template>
8
14
 
9
15
  <script setup lang="ts">
10
- import { nextTick, ref } from 'vue';
16
+ import { ref } from 'vue';
11
17
  import { Notifications } from '@kyvg/vue3-notification';
12
18
  import { defaultLoadViewerPayload, LoadViewerPayload } from '@/models/loadViewerPayload';
13
19
  import { defaultLoadViewerOptions, LoadViewerOptions } from '@/models/loadViewerOptions';
14
- import { isDemo } from '@/components/demo/options';
20
+ import {
21
+ isDemo,
22
+ m_demoLicence,
23
+ m_demoLicenceSendToParty,
24
+ m_demoLicenceShareToMobile,
25
+ m_demoLicenseEnableCloudStorage,
26
+ m_demoPatient,
27
+ m_demoPatientEnableCloudStorage,
28
+ m_demoPatientSendToParty,
29
+ m_demoPatientShareToMobile,
30
+ show
31
+ } from '@/components/demo/options';
15
32
  import MftpWebGL3DRModal from '@/components/modal/MftpWebGL3DRModal.vue';
16
33
  import LogRocket from 'logrocket';
17
34
 
@@ -26,16 +43,17 @@ const mftpWebGL3DRModal = ref<typeof MftpWebGL3DRModal>();
26
43
  async function loadInstance(payloadIncoming: LoadViewerPayload | undefined, optionsIncoming: LoadViewerOptions) {
27
44
  payload.value = payloadIncoming || payload.value;
28
45
  options.value = optionsIncoming;
29
-
30
- await nextTick();
31
- mftpWebGL3DRModal.value?.alterValue(true);
32
46
  }
33
47
 
34
48
  async function loadSession(url: string): Promise<void> {
35
49
  await mftpWebGL3DRModal.value?.loadSession(url);
36
50
  }
37
51
 
38
- defineExpose({ loadInstance, loadSession });
52
+ async function close(): Promise<void> {
53
+ await mftpWebGL3DRModal.value?.close();
54
+ }
55
+
56
+ defineExpose({ loadInstance, loadSession, close });
39
57
  </script>
40
58
 
41
59
  <style>
@@ -85,9 +103,6 @@ defineExpose({ loadInstance, loadSession });
85
103
  .transparent {
86
104
  background-color: transparent;
87
105
  }
88
- .v-dialog.v-overlay--active:not(.v-tooltip) {
89
- backdrop-filter: blur(4px);
90
- }
91
106
  .card-bg-border {
92
107
  border-radius: 12px !important;
93
108
  border: 2px #ffffffaa solid;
@@ -12,22 +12,22 @@ describe('index tests', () => {
12
12
  });
13
13
 
14
14
  it('should resolve loadViewer', async () => {
15
- await registerViewer('1.0.0');
15
+ await registerViewer(document.body, '1.0.0');
16
16
  expect(loadViewer()).resolves.not.toThrow(errorMessage);
17
17
  });
18
18
 
19
19
  it('should resolve loadSession 3crds url', async () => {
20
- await registerViewer('1.0.0');
20
+ await registerViewer(document.body, '1.0.0');
21
21
  expect(loadSession('https://localhost/example.3crds')).resolves.not.toThrow(errorMessage);
22
22
  });
23
23
 
24
24
  it('should resolve loadSession 3crms url', async () => {
25
- await registerViewer('1.0.0');
25
+ await registerViewer(document.body, '1.0.0');
26
26
  expect(loadSession('https://localhost/example.3crms')).resolves.not.toThrow(errorMessage);
27
27
  });
28
28
 
29
29
  it('should resolve loadSession 3crs url', async () => {
30
- await registerViewer('1.0.0');
30
+ await registerViewer(document.body, '1.0.0');
31
31
  expect(loadSession('https://localhost/example.3crs')).resolves.not.toThrow(errorMessage);
32
32
  });
33
33
 
@@ -1,14 +1,18 @@
1
1
  @import 'vuetify/styles';
2
2
  @import 'intro.js/introjs.css';
3
3
 
4
+ .v-overlay {
5
+ z-index: 3400 !important;
6
+ }
7
+
4
8
  .introjs-tooltipReferenceLayer {
5
- z-index: 2401;
9
+ z-index: 3401;
6
10
  }
7
11
 
8
12
  .introjs-overlay,
9
13
  .introjs-helperLayer {
10
14
  pointer-events: none;
11
- z-index: 2401;
15
+ z-index: 3401;
12
16
  }
13
17
 
14
18
  .introjs-dontShowAgain {
@@ -1,19 +1,19 @@
1
1
  <script setup lang="ts">
2
- import { computed } from "vue";
3
- import {PRICING_URL} from "@/components/demo/options";
2
+ import { computed } from 'vue';
3
+ import { PRICING_URL } from '@/components/demo/options';
4
4
 
5
5
  export interface Props {
6
6
  modal: boolean;
7
- isModalOpen: boolean;
7
+ isModalOpen?: boolean;
8
8
  }
9
9
 
10
10
  const emit = defineEmits<{
11
- "update:modal": [value: boolean];
11
+ 'update:modal': [value: boolean];
12
12
  }>();
13
13
 
14
14
  const props = withDefaults(defineProps<Props>(), {
15
15
  modal: false,
16
- isModalOpen: true,
16
+ isModalOpen: true
17
17
  });
18
18
 
19
19
  const modalState = computed({
@@ -21,11 +21,11 @@ const modalState = computed({
21
21
  return props.modal;
22
22
  },
23
23
  set(value) {
24
- emit("update:modal", value);
25
- },
24
+ emit('update:modal', value);
25
+ }
26
26
  });
27
27
  function openUrl(url: string) {
28
- window.open(url, "_self");
28
+ window.open(url, '_self');
29
29
  }
30
30
  </script>
31
31
 
@@ -35,25 +35,15 @@ function openUrl(url: string) {
35
35
  <v-card-title>Purchase 3Dicom Viewer</v-card-title>
36
36
  <v-card-text> Thank you for trying 3Dicom Online Viewer! </v-card-text>
37
37
  <v-card-text>
38
- This instance of the Online Viewer is a Demo instance. If you would like
39
- to see your scans in 3D, please choose a plan for 3DICOM
38
+ This instance of the Online Viewer is a Demo instance. If you would like to see your scans in 3D, please choose
39
+ a plan for 3DICOM
40
40
  </v-card-text>
41
41
  <v-card-actions>
42
- <v-btn
43
- data-testid="close"
44
- color="error"
45
- @click="modalState = false"
46
- :disabled="!isModalOpen"
47
- >
42
+ <v-btn data-testid="close" color="error" @click="modalState = false" :disabled="!isModalOpen">
48
43
  Continue with Viewer
49
44
  </v-btn>
50
45
  <v-spacer />
51
- <v-btn
52
- data-testid="select-plan"
53
- variant="tonal"
54
- color="success"
55
- @click="openUrl(PRICING_URL)"
56
- >
46
+ <v-btn data-testid="select-plan" variant="tonal" color="success" @click="openUrl(PRICING_URL)">
57
47
  Select a Plan
58
48
  </v-btn>
59
49
  </v-card-actions>
@@ -1,23 +1,19 @@
1
1
  <script setup lang="ts">
2
- import { computed } from "vue";
3
- import {
4
- demoLicenceSubtitles,
5
- demoLicenceTitle,
6
- openUrl, SUPPORT_URL,
7
- } from "@/components/demo/options";
2
+ import { computed } from 'vue';
3
+ import { demoLicenceSubtitles, demoLicenceTitle, openUrl, SUPPORT_URL } from '@/components/demo/options';
8
4
 
9
5
  export interface Props {
10
6
  modal: boolean;
11
- isModalOpen: boolean;
7
+ isModalOpen?: boolean;
12
8
  }
13
9
 
14
10
  const emit = defineEmits<{
15
- "update:modal": [value: boolean];
11
+ 'update:modal': [value: boolean];
16
12
  }>();
17
13
 
18
14
  const props = withDefaults(defineProps<Props>(), {
19
15
  modal: false,
20
- isModalOpen: true,
16
+ isModalOpen: true
21
17
  });
22
18
 
23
19
  const modalState = computed({
@@ -25,25 +21,16 @@ const modalState = computed({
25
21
  return props.modal;
26
22
  },
27
23
  set(value) {
28
- emit("update:modal", value);
29
- },
24
+ emit('update:modal', value);
25
+ }
30
26
  });
31
27
  </script>
32
28
 
33
29
  <template>
34
30
  <v-dialog v-model:model-value="modalState">
35
- <v-card
36
- class="pa-1 ma-auto position-relative motif-background card-bg-border"
37
- theme="dark"
38
- max-width="680"
39
- >
40
- <v-card-title class="text-center mb-4 mt-2 font-weight-bold">{{
41
- demoLicenceTitle
42
- }}</v-card-title>
43
- <v-card-text
44
- class="text-justify"
45
- v-for="subtitle in demoLicenceSubtitles"
46
- :key="subtitle"
31
+ <v-card class="pa-1 ma-auto position-relative motif-background card-bg-border" theme="dark" max-width="680">
32
+ <v-card-title class="text-center mb-4 mt-2 font-weight-bold">{{ demoLicenceTitle }}</v-card-title>
33
+ <v-card-text class="text-justify" v-for="subtitle in demoLicenceSubtitles" :key="subtitle"
47
34
  >{{ subtitle }}
48
35
  </v-card-text>
49
36
  <v-card-actions class="mt-4">
@@ -51,12 +38,7 @@ const modalState = computed({
51
38
  Continue with Demo
52
39
  </v-btn>
53
40
  <v-spacer />
54
- <v-btn
55
- data-testid="confirm"
56
- variant="flat"
57
- color="success"
58
- @click="openUrl(SUPPORT_URL)"
59
- >
41
+ <v-btn data-testid="confirm" variant="flat" color="success" @click="openUrl(SUPPORT_URL)">
60
42
  Enquire about technical integration
61
43
  </v-btn>
62
44
  </v-card-actions>
@@ -1,23 +1,20 @@
1
- import { computed, ref, watch } from 'vue';
1
+ import { computed, ref } from 'vue';
2
2
  import { LoadViewerOptions } from '@/models/loadViewerOptions';
3
3
  import { LoadViewerPayload } from '@/models/loadViewerPayload';
4
+ import { useViewer3cr } from '@/composables/useViewer3cr';
5
+ import { mockDemoViewerStlDecimator } from '@/composables/useViewerOptions';
6
+ import { DemoType } from '@/types/demo-type';
4
7
 
5
8
  export const PRICING_URL = 'https://3dicomviewer.com/pricing';
6
9
 
7
10
  export const SUPPORT_URL = 'https://3dicomviewer.com/contact-3dicom';
8
11
 
9
- export function checkIsDemo(payload: LoadViewerPayload) {
10
- isDemo.value = payload.Url.startsWith('https://webgl-3dr.singular.health/demo');
11
- }
12
- import { useViewer3cr } from '@/composables/useViewer3cr';
13
- import { mockDemoViewerStlDecimator } from '@/composables/useViewerOptions';
14
-
15
- const viewer3cr = useViewer3cr();
16
-
17
12
  const BASE_STATE_URL = 'https://webgl-3dr.singular.health/demo';
18
13
 
14
+ const viewer3cr = useViewer3cr();
19
15
  export const isDemo = ref<boolean>(false);
20
- export const m_demo = ref<boolean>(false);
16
+ export const show = ref<boolean>(true);
17
+ export const m_demoLicence = ref<boolean>(false);
21
18
  export const m_demoLicenceShareToMobile = ref<boolean>(false);
22
19
  export const m_demoLicenceSendToParty = ref<boolean>(false);
23
20
  export const m_demoLicenseEnableCloudStorage = ref<boolean>(false);
@@ -31,13 +28,14 @@ export const demoLicenceTitle = ref<string>('');
31
28
  export const demoLicenceSubtitles = ref<Array<string>>([]);
32
29
 
33
30
  export const demoLicenceOptions: LoadViewerOptions = {
34
- OnClosePopup: () => {},
31
+ OnClosePopup: undefined,
35
32
  OnExitViewer: () => {
36
33
  demoLicenceTitle.value = 'Thank you for trying the 3Dicom Licensing Demo.';
37
34
  demoLicenceSubtitles.value = [
38
35
  'Should you have any further questions or enquiries, please get in touch by emailing support@singular.health'
39
36
  ];
40
- m_demo.value = true;
37
+ m_demoLicence.value = true;
38
+ show.value = false;
41
39
  },
42
40
  OnLoadNewDicomSeries: () => {
43
41
  demoLicenceTitle.value = 'Support multiple medical imaging file types';
@@ -45,26 +43,26 @@ export const demoLicenceOptions: LoadViewerOptions = {
45
43
  '3Dicom’s white-labelled online 2D / 3D DICOM viewer allows the loading of X-Ray (XR), Ultrasound (US), Computed Tomography (CT), Magnetic Resonance Imaging (MRI), and Positron Emitting Tomography (PET) using the global DICOM file format.'
46
44
  ];
47
45
 
48
- m_demo.value = true;
46
+ m_demoLicence.value = true;
49
47
  },
50
48
  OnDownloadDicomSeries: () => {
51
49
  demoLicenceTitle.value = 'Improve interoperability with local download of DICOM series';
52
50
  demoLicenceSubtitles.value = [
53
51
  'Integrate 3Dicom’s white-labelled online 2D/3D viewer into your PACS and/or medical records database to pull DICOM series and allow for local download direct from the viewer. This feature can be hidden upon request.'
54
52
  ];
55
- m_demo.value = true;
53
+ m_demoLicence.value = true;
56
54
  },
57
55
  OnLoadSavedSession: () => {
58
56
  demoLicenceTitle.value = 'Save previous progress and share particular sessions';
59
57
  demoLicenceSubtitles.value = [
60
58
  '3Dicom’s viewer enables session-saving to record any changes made during the viewing of medical scans including orientation of views, editing of labels, visualisation settings, and density settings. Changes made during sessions preserve the integrity of the DICOM file and are overlaid in future sessions.'
61
59
  ];
62
- m_demo.value = true;
60
+ m_demoLicence.value = true;
63
61
  },
64
62
  OnSaveSession: () => {
65
63
  demoLicenceTitle.value = 'Thank you for trying the 3Dicom Licensing Demo.';
66
64
  demoLicenceSubtitles.value = ['Each 3Dicom viewer session can be saved with your changes made for future viewing.'];
67
- m_demo.value = true;
65
+ m_demoLicence.value = true;
68
66
  },
69
67
  OnSendTo3rdParty: () => {
70
68
  m_demoLicenceSendToParty.value = true;
@@ -79,24 +77,20 @@ export const demoLicenceOptions: LoadViewerOptions = {
79
77
  mockDemoViewerStlDecimator();
80
78
  await viewer3cr.loadMcadObjects({ Url: `${BASE_STATE_URL}/state/TotalSegmentator_1722837421466.3crms` });
81
79
  },
82
- OnShare: () => {},
83
- OnScreenshot: () => {},
84
- OnErrorClose: () => {}
80
+ OnShare: undefined,
81
+ OnScreenshot: undefined,
82
+ OnErrorClose: undefined
85
83
  };
86
84
 
87
85
  export const demoPatientOptions: LoadViewerOptions = {
88
- OnClosePopup: () => {},
86
+ OnClosePopup: undefined,
89
87
  OnExitViewer: () => {
90
88
  demoPatientTitle.value = 'Thank you for trying the 3Dicom Patient Demo.';
91
89
  demoPatientSubtitles.value = [
92
90
  'Should you have any further questions or enquiries, please get in touch by emailing support@singular.health'
93
91
  ];
94
92
  m_demoPatient.value = true;
95
- watch(m_demoPatient, () => {
96
- if (!m_demoPatient) {
97
- window.close();
98
- }
99
- });
93
+ show.value = false;
100
94
  },
101
95
  OnLoadNewDicomSeries: () => {
102
96
  demoPatientTitle.value = '3Dicom Patient supports multiple Medical Imaging Formats';
@@ -137,28 +131,37 @@ export const demoPatientOptions: LoadViewerOptions = {
137
131
  m_demoPatientEnableCloudStorage.value = true;
138
132
  },
139
133
  OnAutoAnnotate: demoLicenceOptions.OnAutoAnnotate,
140
- OnShare: () => {},
141
- OnScreenshot: () => {},
142
- OnErrorClose: () => {}
134
+ OnShare: undefined,
135
+ OnScreenshot: undefined,
136
+ OnErrorClose: undefined
143
137
  };
144
138
 
145
- const optionalTypes = ['licence', 'patient'];
139
+ export function checkIsDemo(payload: LoadViewerPayload) {
140
+ isDemo.value = payload.Url.startsWith('https://webgl-3dr.singular.health/demo');
141
+ }
146
142
 
147
143
  export const demoType = computed(() => {
148
144
  const urlParams = new URLSearchParams(window.location.search);
149
- let type = (urlParams.get('demoType') || 'licence').toLowerCase();
150
-
151
- if (type === 'license') type = optionalTypes[0];
152
- return optionalTypes.includes(type) ? type : optionalTypes[0];
145
+ if (urlParams.has('demoType')) {
146
+ const demoType = urlParams.get('demoType')!.toLowerCase();
147
+ switch (demoType) {
148
+ case 'patient':
149
+ return DemoType.Patient;
150
+ case 'licence':
151
+ return DemoType.Licence;
152
+ }
153
+ }
154
+ return DemoType.Patient;
153
155
  });
154
156
 
155
157
  export const demoOptions = computed(() => {
156
- if (demoType.value === 'licence') {
157
- return demoLicenceOptions;
158
- } else if (demoType.value === 'patient') {
159
- return demoPatientOptions;
160
- } else {
161
- throw new Error('Unknown demo type');
158
+ switch (demoType.value) {
159
+ case DemoType.Patient:
160
+ return demoPatientOptions;
161
+ case DemoType.Licence:
162
+ return demoLicenceOptions;
163
+ default:
164
+ throw new Error('Unknown demo type');
162
165
  }
163
166
  });
164
167
 
@@ -1,23 +1,19 @@
1
1
  <script setup lang="ts">
2
- import { computed } from "vue";
3
- import {
4
- demoPatientSubtitles,
5
- demoPatientTitle,
6
- openUrl, PRICING_URL,
7
- } from "@/components/demo/options";
2
+ import { computed } from 'vue';
3
+ import { demoPatientSubtitles, demoPatientTitle, openUrl, PRICING_URL } from '@/components/demo/options';
8
4
 
9
5
  export interface Props {
10
6
  modal: boolean;
11
- isModalOpen: boolean;
7
+ isModalOpen?: boolean;
12
8
  }
13
9
 
14
10
  const emit = defineEmits<{
15
- "update:modal": [value: boolean];
11
+ 'update:modal': [value: boolean];
16
12
  }>();
17
13
 
18
14
  const props = withDefaults(defineProps<Props>(), {
19
15
  modal: false,
20
- isModalOpen: true,
16
+ isModalOpen: true
21
17
  });
22
18
 
23
19
  const modalState = computed({
@@ -25,25 +21,16 @@ const modalState = computed({
25
21
  return props.modal;
26
22
  },
27
23
  set(value) {
28
- emit("update:modal", value);
29
- },
24
+ emit('update:modal', value);
25
+ }
30
26
  });
31
27
  </script>
32
28
 
33
29
  <template>
34
30
  <v-dialog v-model:model-value="modalState">
35
- <v-card
36
- class="pa-1 ma-auto position-relative motif-background card-bg-border"
37
- theme="dark"
38
- max-width="680"
39
- >
40
- <v-card-title class="text-center mb-4 mt-2 font-weight-bold">{{
41
- demoPatientTitle
42
- }}</v-card-title>
43
- <v-card-text
44
- class="text-justify"
45
- v-for="subtitle in demoPatientSubtitles"
46
- :key="subtitle"
31
+ <v-card class="pa-1 ma-auto position-relative motif-background card-bg-border" theme="dark" max-width="680">
32
+ <v-card-title class="text-center mb-4 mt-2 font-weight-bold">{{ demoPatientTitle }}</v-card-title>
33
+ <v-card-text class="text-justify" v-for="subtitle in demoPatientSubtitles" :key="subtitle"
47
34
  >{{ subtitle }}
48
35
  </v-card-text>
49
36
  <v-card-actions class="mt-4">
@@ -51,12 +38,7 @@ const modalState = computed({
51
38
  Continue with Demo
52
39
  </v-btn>
53
40
  <v-spacer />
54
- <v-btn
55
- data-testid="confirm"
56
- variant="flat"
57
- color="success"
58
- @click="openUrl(PRICING_URL)"
59
- >
41
+ <v-btn data-testid="confirm" variant="flat" color="success" @click="openUrl(PRICING_URL)">
60
42
  Purchase 3Dicom Patient
61
43
  </v-btn>
62
44
  </v-card-actions>
@@ -4,7 +4,7 @@
4
4
  <v-card-title class="text-center">Close Viewer?</v-card-title>
5
5
  <v-card-text class="text-center mb-2"> Are you sure you want to close the Online Viewer? </v-card-text>
6
6
  <v-card-actions>
7
- <v-btn data-testid="cancel" variant="flat" color="secondary" @click="modalState = false"> Cancel </v-btn>
7
+ <v-btn data-testid="cancel" variant="text" @click="modalState = false"> Cancel </v-btn>
8
8
  <v-spacer />
9
9
  <v-btn v-if="options?.OnSaveSession" data-testid="close" color="red" variant="flat" @click="closeModal">
10
10
  Close without saving