@sbc-connect/nuxt-base 0.3.0 → 0.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # @sbc-connect/nuxt-base
2
2
 
3
+ ## 0.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#106](https://github.com/bcgov/connect-nuxt/pull/106) [`f5d34df`](https://github.com/bcgov/connect-nuxt/commit/f5d34df0bbb2b37cbeda8a9dd39c6bce098c564f) Thanks [@deetz99](https://github.com/deetz99)! - <br>
8
+ - ConnectModalError component
9
+ - getErrorStatus util
10
+ - getErrorMessage util
11
+
3
12
  ## 0.3.0
4
13
 
5
14
  ### Minor Changes
@@ -0,0 +1,76 @@
1
+ <script setup lang="ts">
2
+ import type { VNode } from 'vue'
3
+ // https://vue-i18n.intlify.dev/api/composition.html#te-key-locale
4
+ const { t, te } = useI18n()
5
+
6
+ interface ErrorModalProps {
7
+ error: unknown
8
+ i18nPrefix: string
9
+ buttons?: ConnectModalButton[]
10
+ contactInfo?: VNode
11
+ preferErrorMessage?: boolean
12
+ }
13
+
14
+ const {
15
+ error,
16
+ i18nPrefix,
17
+ buttons = [
18
+ { label: useNuxtApp().$i18n.t('label.close'), shouldClose: true }
19
+ ],
20
+ preferErrorMessage = false
21
+ } = defineProps<ErrorModalProps>()
22
+ defineEmits<{ close: [] }>()
23
+
24
+ const status = getErrorStatus(error)
25
+ const message = getErrorMessage(error)
26
+
27
+ const titleKey = `${i18nPrefix}.${status}.title`
28
+ const descKey = `${i18nPrefix}.${status}.description`
29
+
30
+ const title = te(titleKey) ? t(titleKey) : t(`${i18nPrefix}.undefined.title`)
31
+ const i18nDescription = te(descKey) ? t(descKey) : t(`${i18nPrefix}.undefined.description`)
32
+
33
+ const description = (preferErrorMessage && message)
34
+ ? message
35
+ : i18nDescription
36
+ </script>
37
+
38
+ <template>
39
+ <UModal
40
+ id="connect-error-modal"
41
+ overlay
42
+ :title
43
+ :description
44
+ :dismissible="false"
45
+ >
46
+ <template #content>
47
+ <div class="p-10 flex flex-col gap-6">
48
+ <h2 class="text-2xl font-semibold text-neutral-highlighted">
49
+ {{ title }}
50
+ </h2>
51
+ <p>{{ description }}</p>
52
+ <component :is="contactInfo" v-if="contactInfo" />
53
+ <div class="flex flex-wrap items-center justify-center gap-4">
54
+ <template
55
+ v-for="button in buttons"
56
+ :key="button.label"
57
+ >
58
+ <UButton
59
+ v-if="button.shouldClose"
60
+ v-bind="button"
61
+ size="xl"
62
+ class="w-full justify-center sm:w-min sm:justify-normal"
63
+ @click="$emit('close')"
64
+ />
65
+ <UButton
66
+ v-else
67
+ v-bind="button"
68
+ size="xl"
69
+ class="w-full justify-center sm:w-min sm:justify-normal"
70
+ />
71
+ </template>
72
+ </div>
73
+ </div>
74
+ </template>
75
+ </UModal>
76
+ </template>
@@ -1,11 +1,13 @@
1
- import { ConnectModal } from '#components'
1
+ import { ConnectModal, ConnectModalError } from '#components'
2
2
 
3
3
  export const useConnectModal = () => {
4
4
  const overlay = useOverlay()
5
5
 
6
6
  const baseModal = overlay.create(ConnectModal)
7
+ const errorModal = overlay.create(ConnectModalError)
7
8
 
8
9
  return {
9
- baseModal
10
+ baseModal,
11
+ errorModal
10
12
  }
11
13
  }
@@ -0,0 +1,42 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+
3
+ /**
4
+ * Safely extracts an error message from an unknown error object.
5
+ *
6
+ * The search order (Highest Priority to Lowest) is:
7
+ * 1. Current object's 'message' (must be a non-empty string).
8
+ * 2. Current object's 'detail' (must be a non-empty string).
9
+ * 3. Recursively searches the 'error.data.rootCause' object.
10
+ * 4. Recursively searches the 'error.data' object.
11
+ *
12
+ * This function will return the first valid, non-empty string message found.
13
+ *
14
+ * @param error - The error object (unknown).
15
+ * @returns The error message if found, else 'undefined'.
16
+ */
17
+ export function getErrorMessage(error: unknown): string | undefined {
18
+ if (error && typeof error === 'object') {
19
+ const errorObject = error as Record<string, any>
20
+
21
+ const message = errorObject.message
22
+ if (message && typeof message === 'string' && message.length > 0) {
23
+ return message
24
+ }
25
+ const detail = errorObject.detail
26
+ if (detail && typeof detail === 'string' && detail.length > 0) {
27
+ return detail
28
+ }
29
+
30
+ const rootCauseMessage = getErrorMessage(errorObject?.data?.rootCause)
31
+ if (rootCauseMessage) {
32
+ return rootCauseMessage
33
+ }
34
+
35
+ const dataMessage = getErrorMessage(errorObject?.data)
36
+ if (dataMessage) {
37
+ return dataMessage
38
+ }
39
+ }
40
+
41
+ return undefined
42
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Safely extracts the HTTP status code from a thrown error.
3
+ *
4
+ * This provides a reliable way to get a status code from an `unknown` error type.
5
+ *
6
+ * @param error - The error object to inspect. It can be of any type.
7
+ * @returns The numeric HTTP status code if found, otherwise `undefined`.
8
+ *
9
+ * @example
10
+ * getErrorStatus({ response: { status: 404 } }); // returns 404
11
+ *
12
+ * @example
13
+ * getErrorStatus({ statusCode: 403 }); // returns 403
14
+ *
15
+ * @example
16
+ * getErrorStatus(new Error("Network failed")); // returns undefined
17
+ */
18
+ export function getErrorStatus(error: unknown): number | undefined {
19
+ // check if error is valid object
20
+ if (
21
+ error
22
+ && typeof error === 'object'
23
+ && ('statusCode' in error || 'response' in error)
24
+ ) {
25
+ // handle case where error.response.status
26
+ if ('response' in error && error.response && typeof error.response === 'object' && 'status' in error.response) {
27
+ return error.response.status as number
28
+ }
29
+ // handle case where no error.response.status, fallback to error.statusCode
30
+ if ('statusCode' in error) {
31
+ return error.statusCode as number
32
+ }
33
+ }
34
+
35
+ // return undefined if no status or statusCode
36
+ return undefined
37
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sbc-connect/nuxt-base",
3
3
  "type": "module",
4
- "version": "0.3.0",
4
+ "version": "0.4.0",
5
5
  "repository": "github:bcgov/connect-nuxt",
6
6
  "license": "BSD-3-Clause",
7
7
  "main": "./nuxt.config.ts",