@sbc-connect/nuxt-auth 0.11.1 → 0.12.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.
Files changed (32) hide show
  1. package/.env.example +2 -3
  2. package/CHANGELOG.md +11 -0
  3. package/app/components/Connect/Account/Create/Name.vue +24 -22
  4. package/app/components/Connect/Account/Create/index.vue +29 -21
  5. package/app/components/Connect/Header/Notifications.vue +26 -11
  6. package/app/composables/useConnectHeaderOptions.ts +2 -20
  7. package/app/middleware/connect-auth.ts +4 -5
  8. package/app/pages/auth/account/select.vue +51 -26
  9. package/app/pages/auth/terms-of-use.vue +9 -9
  10. package/app/plugins/auth-api.ts +26 -21
  11. package/app/plugins/connect-account-bootstrap.client.ts +33 -0
  12. package/app/plugins/connect-auth.client.ts +102 -88
  13. package/app/services/auth/index.ts +4 -0
  14. package/app/services/auth/mutate.ts +83 -0
  15. package/app/services/auth/query-keys.ts +26 -0
  16. package/app/services/auth/query.ts +87 -0
  17. package/app/services/auth/service.ts +125 -0
  18. package/app/services/helpers/get-cached-or-fetch.ts +43 -0
  19. package/app/services/helpers/index.ts +1 -0
  20. package/app/services/index.ts +1 -0
  21. package/app/stores/connect-account.ts +38 -146
  22. package/app/types/auth-nuxt-hooks.d.ts +7 -0
  23. package/app/utils/index.ts +1 -0
  24. package/app/utils/schemas/account.ts +32 -1
  25. package/app/utils/schemas/index.ts +1 -0
  26. package/nuxt.config.ts +1 -1
  27. package/package.json +3 -3
  28. package/app/composables/useAuthApi.ts +0 -156
  29. package/app/middleware/01.setup-accounts.global.ts +0 -13
  30. /package/app/middleware/{02.keycloak-params.global.ts → 01.keycloak-params.global.ts} +0 -0
  31. /package/app/middleware/{03.app-config-presets.global.ts → 02.app-config-presets.global.ts} +0 -0
  32. /package/app/middleware/{04.idp-enforcement.global.ts → 03.idp-enforcement.global.ts} +0 -0
package/.env.example CHANGED
@@ -30,6 +30,5 @@ NUXT_PUBLIC_TOKEN_MIN_VALIDITY=120000
30
30
  NUXT_PUBLIC_SESSION_INACTIVITY_TIMEOUT=1800000
31
31
  NUXT_PUBLIC_SESSION_MODAL_TIMEOUT=120000
32
32
 
33
- # Playwright Testing
34
- PLAYWRIGHT_TEST_BCSC_USERNAME=""
35
- PLAYWRIGHT_TEST_BCSC_PASSWORD=""
33
+ # Canada Post
34
+ NUXT_PUBLIC_ADDRESS_COMPLETE_KEY=""
package/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # @sbc-connect/nuxt-auth
2
2
 
3
+ ## 0.12.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#170](https://github.com/bcgov/connect-nuxt/pull/170) [`d91712d`](https://github.com/bcgov/connect-nuxt/commit/d91712db74c2e0c6b39f6fd38955fd60e82ce691) Thanks [@deetz99](https://github.com/deetz99)! - - BREAKING CHANGE: remove useAuthApi, replaced with useConnectAuthService
8
+ - refactor account creation implementation (remove from store, update components/page)
9
+ - refactor account store methods to be more streamlined
10
+ - refactor account and user initialization into a global bootstrap plugin, reducing redundant network requests
11
+ - refactor header notifications to use useQuery - removes unnecessary blocker for app mount
12
+ - remove setup accounts middleware (now handled by global bootstrap plugin) and update naming (order prefix) of other middleware
13
+
3
14
  ## 0.11.1
4
15
 
5
16
  ### Patch Changes
@@ -5,31 +5,33 @@ defineProps<{
5
5
  error?: FormError<string>
6
6
  }>()
7
7
 
8
- const authApi = useAuthApi()
9
- const { accountFormState } = useConnectAccountStore()
8
+ const statusCode = defineModel<number | undefined>('statusCode')
9
+ const name = defineModel<string>('name')
10
+
11
+ const service = useConnectAuthService()
10
12
 
11
13
  const isLoading = ref(false)
12
- const statusCode = defineModel<number | undefined>('statusCode')
13
14
 
14
- /** Validate accountName and trigger validation API call */
15
- const validateName = useDebounceFn(async (accountName: string) => {
16
- if (accountName.length) {
17
- isLoading.value = true
18
- try {
19
- const { refetch } = authApi.verifyAccountName(accountName)
20
- const { data } = await refetch()
21
- statusCode.value = data?.status ?? 500 // fallback as undefined is not considered an exception
22
- } catch (err: unknown) {
23
- statusCode.value = getErrorStatus(err) ?? 500
24
- } finally {
25
- isLoading.value = false
15
+ /* Validate accountName and trigger validation API call */
16
+ watchDebounced(
17
+ name,
18
+ async (v) => {
19
+ if (v?.length) {
20
+ isLoading.value = true
21
+ try {
22
+ const { status } = await service.verifyAccountName(v).catch(() => ({ status: undefined }))
23
+ statusCode.value = status ?? 500 // fallback as undefined is not considered an exception
24
+ } catch (err: unknown) {
25
+ statusCode.value = getErrorStatus(err) ?? 500
26
+ } finally {
27
+ isLoading.value = false
28
+ }
29
+ } else {
30
+ statusCode.value = undefined
26
31
  }
27
- } else {
28
- statusCode.value = undefined
29
- }
30
- }, 1000)
31
-
32
- watch(() => accountFormState.accountName, validateName)
32
+ },
33
+ { debounce: 1000 }
34
+ )
33
35
 
34
36
  // Compute UInput props based on loading state and status code
35
37
  const uInputProps = computed<InputProps>(() => {
@@ -63,7 +65,7 @@ provide('UInput-props-account-name-input', uInputProps)
63
65
  padding-class="pt-6 pb-4 px-4 sm:pb-4 sm:pt-8 sm:px-8"
64
66
  >
65
67
  <ConnectFormInput
66
- v-model="accountFormState.accountName"
68
+ v-model="name"
67
69
  name="accountName"
68
70
  input-id="account-name-input"
69
71
  :label="$t('connect.page.createAccount.accountNameLabel')"
@@ -1,15 +1,16 @@
1
1
  <script setup lang="ts">
2
- import type { Form, FormError } from '@nuxt/ui'
3
- import type { AccountProfileSchema } from '#auth/app/utils/schemas/account'
4
- import { getAccountCreateSchema } from '#auth/app/utils/schemas/account'
2
+ import type { Form, FormError, FormSubmitEvent } from '@nuxt/ui'
3
+ import type { AccountProfileSchema } from '#imports'
5
4
 
6
- const statusCode = ref<number | undefined>(undefined)
5
+ defineEmits<{
6
+ submit: [event: FormSubmitEvent<AccountProfileSchema>]
7
+ }>()
7
8
 
8
- const accountStore = useConnectAccountStore()
9
- const { accountFormState, userFullName } = storeToRefs(accountStore)
10
- const { submitCreateAccount } = accountStore
11
- const accountProfileSchema = computed(() => getAccountCreateSchema(statusCode.value))
9
+ const store = useConnectAccountStore()
12
10
  const formRef = useTemplateRef<Form<AccountProfileSchema>>('account-create-form')
11
+ const statusCode = ref<number | undefined>(undefined)
12
+ const schema = computed(() => getAccountCreateSchema(statusCode.value))
13
+ const state = reactive<AccountProfileSchema>(schema.value.parse({}))
13
14
 
14
15
  const formErrors = computed<{
15
16
  accountName: FormError<string> | undefined
@@ -33,12 +34,18 @@ async function validate(fieldName?: keyof AccountProfileSchema) {
33
34
  })
34
35
  }
35
36
 
36
- watch(() => statusCode.value, async () => {
37
- if (statusCode.value !== undefined) {
37
+ watch(statusCode, async (v) => {
38
+ if (v !== undefined) {
38
39
  await nextTick()
39
40
  await validate('accountName')
40
41
  }
41
42
  })
43
+
44
+ onMounted(() => {
45
+ if (store.userEmail) {
46
+ state.emailAddress = store.userEmail
47
+ }
48
+ })
42
49
  </script>
43
50
 
44
51
  <template>
@@ -54,10 +61,10 @@ watch(() => statusCode.value, async () => {
54
61
  ref="account-create-form"
55
62
  no-validate
56
63
  :validate-on="['input', 'change']"
57
- :schema="accountProfileSchema"
58
- :state="accountFormState"
64
+ :schema
65
+ :state
59
66
  @error="onFormSubmitError"
60
- @submit="submitCreateAccount()"
67
+ @submit="$emit('submit', $event)"
61
68
  >
62
69
  <!-- Legal Name -->
63
70
  <ConnectFormFieldWrapper
@@ -66,7 +73,7 @@ watch(() => statusCode.value, async () => {
66
73
  class="py-6 sm:py-8"
67
74
  >
68
75
  <p class="font-bold">
69
- {{ userFullName }}
76
+ {{ store.userFullName }}
70
77
  </p>
71
78
  <p class="mt-3">
72
79
  {{ $t('connect.page.createAccount.yourNameHelp') }}
@@ -78,6 +85,7 @@ watch(() => statusCode.value, async () => {
78
85
  <!-- Account Name -->
79
86
  <ConnectAccountCreateName
80
87
  v-model:status-code="statusCode"
88
+ v-model:name="state.accountName"
81
89
  :error="formErrors.accountName"
82
90
  />
83
91
 
@@ -89,7 +97,7 @@ watch(() => statusCode.value, async () => {
89
97
  padding-class="py-1 px-4 sm:py-2 sm:px-8"
90
98
  >
91
99
  <ConnectFormInput
92
- v-model="accountFormState.emailAddress"
100
+ v-model="state.emailAddress"
93
101
  name="emailAddress"
94
102
  input-id="email-input"
95
103
  :label="$t('connect.page.createAccount.emailPlaceholder')"
@@ -106,13 +114,13 @@ watch(() => statusCode.value, async () => {
106
114
  <div class="flex flex-row gap-2">
107
115
  <!-- Disabling country code selection until Auth Model Supports individual property -->
108
116
  <!-- <ConnectFormPhoneCountryCode -->
109
- <!-- v-model:country-calling-code="accountFormState.phone.countryCode" -->
110
- <!-- v-model:country-iso2="accountFormState.phone.countryIso2" -->
111
- <!-- :is-invalid="!accountFormState.phone.countryIso2" -->
117
+ <!-- v-model:country-calling-code="state.phone.countryCode" -->
118
+ <!-- v-model:country-iso2="state.phone.countryIso2" -->
119
+ <!-- :is-invalid="!state.phone.countryIso2" -->
112
120
  <!-- class="w-40 mt-[-20px]" -->
113
121
  <!-- /> -->
114
122
  <ConnectFormInput
115
- v-model="accountFormState.phone.phoneNumber"
123
+ v-model="state.phone.phoneNumber"
116
124
  name="phone.phoneNumber"
117
125
  input-id="phone-number-input"
118
126
  class="flex-2"
@@ -120,7 +128,7 @@ watch(() => statusCode.value, async () => {
120
128
  mask="(###) ###-####"
121
129
  />
122
130
  <ConnectFormInput
123
- v-model="accountFormState.phone.ext"
131
+ v-model="state.phone.ext"
124
132
  name="phone.ext"
125
133
  input-id="phone-ext-input"
126
134
  :label="$t('connect.page.createAccount.phoneExtensionLabel')"
@@ -137,7 +145,7 @@ watch(() => statusCode.value, async () => {
137
145
  >
138
146
  <ConnectFormAddress
139
147
  id="account-address"
140
- v-model="accountFormState.address"
148
+ v-model="state.address"
141
149
  name="address"
142
150
  schema-prefix="address"
143
151
  @should-validate="validate"
@@ -1,30 +1,45 @@
1
1
  <script setup lang="ts">
2
- const { notificationsOptions } = useConnectHeaderOptions()
2
+ import type { DropdownMenuItem } from '@nuxt/ui'
3
+
4
+ const { t } = useI18n()
5
+ const authWebUrl = useRuntimeConfig().public.authWebUrl
3
6
  const accountStore = useConnectAccountStore()
4
7
  const isLargeScreen = useMediaQuery('(min-width: 1024px)')
8
+
9
+ const query = useConnectAuthQuery()
10
+ const { data } = query.pendingApprovals()
11
+ const count = computed(() => data.value?.count || 0)
12
+
13
+ const dropdownItems = computed<DropdownMenuItem[]>(() => {
14
+ let options: DropdownMenuItem[] = [{ label: t('connect.text.notifications.none') }]
15
+ if (count.value > 0) {
16
+ options = [{
17
+ to: authWebUrl + `account/${accountStore.currentAccount.id}/settings/team-members`,
18
+ label: t('connect.text.notifications.teamMemberApproval', { count: count.value }, count.value)
19
+ }]
20
+ }
21
+ return options
22
+ })
5
23
  </script>
6
24
 
7
25
  <template>
8
- <UDropdownMenu :items="notificationsOptions">
26
+ <UDropdownMenu :items="dropdownItems">
9
27
  <UChip
10
28
  color="error"
11
29
  position="top-left"
12
30
  inset
13
- :show="accountStore.pendingApprovalCount > 0"
31
+ :show="count > 0"
14
32
  >
15
33
  <UButton
16
34
  variant="ghost"
17
35
  color="secondary"
18
36
  :label="isLargeScreen ? $t('connect.label.notifications') : undefined"
19
- :aria-label="$t('connect.label.notificationsAria', { count: accountStore.pendingApprovalCount })"
20
- :icon="isLargeScreen ? 'i-mdi-caret-down' : ''"
21
- trailing
37
+ :aria-label="$t('connect.label.notificationsAria', { count })"
38
+ :trailing-icon="isLargeScreen ? 'i-mdi-caret-down' : ''"
39
+ leading-icon="i-mdi-bell-outline"
22
40
  class="px-2 py-1 text-sm"
23
- >
24
- <template #leading>
25
- <UIcon name="i-mdi-bell-outline" class="size-6 shrink-0" />
26
- </template>
27
- </UButton>
41
+ :ui="{ leadingIcon: 'size-6 shrink-0' }"
42
+ />
28
43
  </UChip>
29
44
  </UDropdownMenu>
30
45
  </template>
@@ -90,10 +90,10 @@ export function useConnectHeaderOptions() {
90
90
  if (route.meta.onAccountChange) {
91
91
  const allowAccountChange = route.meta.onAccountChange(accountStore.currentAccount, account)
92
92
  if (allowAccountChange) {
93
- await accountStore.switchCurrentAccount(account.id)
93
+ accountStore.switchCurrentAccount(account.id)
94
94
  }
95
95
  } else {
96
- await accountStore.switchCurrentAccount(account.id)
96
+ accountStore.switchCurrentAccount(account.id)
97
97
  }
98
98
  }
99
99
  },
@@ -205,23 +205,6 @@ export function useConnectHeaderOptions() {
205
205
  return options
206
206
  })
207
207
 
208
- const notificationsOptions = computed<DropdownMenuItem[][]>(() => {
209
- const count = accountStore.pendingApprovalCount
210
- const options = []
211
- if (count > 0) {
212
- options.push([{
213
- to: authWebUrl + `account/${accountStore.currentAccount.id}/settings/team-members`,
214
- label: t('connect.text.notifications.teamMemberApproval', {
215
- count: accountStore.pendingApprovalCount
216
- }, accountStore.pendingApprovalCount
217
- )
218
- }])
219
- } else {
220
- options.push([{ label: t('connect.text.notifications.none') }])
221
- }
222
- return options
223
- })
224
-
225
208
  return {
226
209
  basicAccountOptions,
227
210
  accountSettingsOptions,
@@ -230,7 +213,6 @@ export function useConnectHeaderOptions() {
230
213
  loggedInUserOptions,
231
214
  loggedOutUserOptions,
232
215
  loggedOutUserOptionsMobile,
233
- notificationsOptions,
234
216
  createAccountUrl
235
217
  }
236
218
  }
@@ -2,7 +2,7 @@ export default defineNuxtRouteMiddleware(async (to) => {
2
2
  const { isAuthenticated } = useConnectAuth()
3
3
  const rtc = useRuntimeConfig().public
4
4
  const localePath = useLocalePath()
5
- const authApi = useAuthApi()
5
+ const service = useConnectAuthService()
6
6
  const { finalRedirect } = useConnectAccountFlowRedirect()
7
7
 
8
8
  const isLoginPage = to.meta.connectLogin === true
@@ -24,9 +24,8 @@ export default defineNuxtRouteMiddleware(async (to) => {
24
24
  }
25
25
 
26
26
  if (isAuthenticated.value) {
27
- const { data, refresh } = await authApi.getAuthUserProfile()
28
- await refresh()
29
- const hasAccepted = data.value?.userTerms.isTermsOfUseAccepted
27
+ const res = await service.getAuthUserProfile().catch(() => undefined)
28
+ const hasAccepted = res?.userTerms.isTermsOfUseAccepted
30
29
  if (!hasAccepted && !isTosPage) {
31
30
  const query = { ...to.query }
32
31
  if (!query.return) {
@@ -56,7 +55,7 @@ export default defineNuxtRouteMiddleware(async (to) => {
56
55
 
57
56
  if (rtc.playwrightFetchTestAccount) {
58
57
  // allows each test to mock the account information with its own data
59
- await useConnectAccountStore().setAccountInfo()
58
+ await useConnectAccountStore().loadUserAccounts(true)
60
59
  } else {
61
60
  currentAccount.value = {
62
61
  id: 1,
@@ -1,4 +1,6 @@
1
1
  <script setup lang="ts">
2
+ import type { FormSubmitEvent } from '@nuxt/ui'
3
+
2
4
  definePageMeta({
3
5
  layout: 'connect-auth',
4
6
  alias: ['/auth/account/create'],
@@ -7,65 +9,88 @@ definePageMeta({
7
9
 
8
10
  const route = useRoute()
9
11
  const rtc = useRuntimeConfig().public
10
- const accountStore = useConnectAccountStore()
12
+ const store = useConnectAccountStore()
11
13
  const { authUser } = useConnectAuth()
12
14
  const { finalRedirect } = useConnectAccountFlowRedirect()
13
- const { clearAccountState } = useConnectAccountStore()
14
- const { isLoading } = storeToRefs(useConnectAccountStore())
15
- const isAccountCreateRoute = computed(() => route.path.includes('create'))
15
+ const mutate = useConnectAuthMutation()
16
+ const { mutateAsync: createAccount } = mutate.createAccount()
17
+ const { mutateAsync: updateContact } = mutate.updateOrCreateUserContact()
16
18
 
19
+ const isSubmitting = ref(false)
17
20
  const addNew = ref(false)
21
+
22
+ const showAccountList = computed(() => !addNew.value)
18
23
  const pageTitle = computed(() =>
19
- !addNew.value ? $t('connect.label.existingAccountFound') : $t('connect.label.sbcAccountCreation')
24
+ showAccountList.value
25
+ ? $t('connect.label.existingAccountFound')
26
+ : $t('connect.label.sbcAccountCreation')
20
27
  )
21
28
 
22
29
  useHead({
23
30
  title: pageTitle
24
31
  })
25
32
 
26
- async function selectAndRedirect(id: number) {
27
- await accountStore.switchCurrentAccount(id)
28
- finalRedirect(useRoute())
33
+ function selectAndRedirect(id: number) {
34
+ store.switchCurrentAccount(id)
35
+ return finalRedirect(route)
36
+ }
37
+
38
+ async function onSubmitCreateAccount(e: FormSubmitEvent<AccountProfileSchema>) {
39
+ const isFirstAccount = store.userAccounts.length === 0
40
+ const contactMethod = isFirstAccount ? 'POST' : 'PUT' // if 0 accounts the contact is new
41
+
42
+ try {
43
+ isSubmitting.value = true
44
+ const { accountPayload, contactPayload } = formatCreateAccountPayload(e.data)
45
+ const res = await createAccount({ payload: accountPayload, silent: true })
46
+ await store.loadUserAccounts(true)
47
+ await updateContact({
48
+ payload: contactPayload,
49
+ silent: true,
50
+ method: contactMethod
51
+ }).catch() // swallow errors from contact update, account was created and user can proceed
52
+ return selectAndRedirect(res.id)
53
+ } catch {
54
+ useConnectAuthModals().openCreateAccountModal()
55
+ isSubmitting.value = false
56
+ }
29
57
  }
30
58
 
31
59
  onBeforeMount(() => {
32
- if ((accountStore.userAccounts.length === 0 && authUser.value.loginSource === ConnectLoginSource.BCSC)
33
- || isAccountCreateRoute.value) {
60
+ const isBcscNoAccounts = store.userAccounts.length === 0 && authUser.value.loginSource === ConnectLoginSource.BCSC
61
+ const isCreatePath = route.path.includes('create')
62
+
63
+ if (isBcscNoAccounts || isCreatePath) {
34
64
  addNew.value = true
35
65
  }
36
66
  })
37
-
38
- const toggleCreateNewAccount = () => {
39
- addNew.value = !addNew.value
40
- clearAccountState()
41
- }
42
67
  </script>
43
68
 
44
69
  <template>
45
70
  <UContainer class="max-w-6xl">
46
71
  <ConnectTransitionFade>
47
72
  <div class="space-y-6 sm:space-y-10">
48
- <h1>{{ !addNew ? $t('connect.label.existingAccountFound') : $t('connect.label.sbcAccountCreation') }}</h1>
49
- <ConnectAccountExistingAlert v-if="!addNew" />
73
+ <h1>{{ pageTitle }}</h1>
74
+ <ConnectAccountExistingAlert v-if="showAccountList" />
50
75
  </div>
51
76
  </ConnectTransitionFade>
52
77
 
53
78
  <ConnectTransitionFade>
54
79
  <ConnectAccountExistingList
55
- v-if="addNew === false"
56
- :accounts="accountStore.userAccounts"
80
+ v-if="showAccountList"
81
+ :accounts="store.userAccounts"
57
82
  @select="selectAndRedirect"
58
83
  />
59
84
 
60
85
  <ConnectAccountCreate
61
86
  v-else
62
- ref="account-create-form-ref"
87
+ @submit="onSubmitCreateAccount"
63
88
  />
64
89
  </ConnectTransitionFade>
65
90
 
66
91
  <!-- Select Account Actions -->
67
92
  <div
68
- v-if="!addNew"
93
+ v-if="showAccountList"
69
94
  class="flex justify-center"
70
95
  data-testid="select-account-button-wrapper"
71
96
  >
@@ -77,7 +102,7 @@ const toggleCreateNewAccount = () => {
77
102
  trailing
78
103
  size="xl"
79
104
  class="w-full justify-center sm:w-min sm:justify-normal"
80
- @click="toggleCreateNewAccount"
105
+ @click="addNew = true"
81
106
  />
82
107
  <UButton
83
108
  v-else
@@ -94,22 +119,22 @@ const toggleCreateNewAccount = () => {
94
119
 
95
120
  <!-- Create Account Actions -->
96
121
  <div
97
- v-if="addNew"
122
+ v-if="!showAccountList"
98
123
  class="flex justify-end gap-x-3"
99
124
  data-testid="create-account-button-wrapper"
100
125
  >
101
126
  <UButton
102
127
  variant="outline"
103
128
  :label="$t('connect.label.back')"
104
- :disabled="isLoading"
129
+ :disabled="isSubmitting"
105
130
  trailing
106
131
  size="xl"
107
132
  class="w-full justify-center sm:w-min sm:justify-normal"
108
- @click="toggleCreateNewAccount"
133
+ @click="addNew = false"
109
134
  />
110
135
  <UButton
111
136
  :label="$t('connect.label.saveAndContinue')"
112
- :loading="isLoading"
137
+ :loading="isSubmitting"
113
138
  form="account-create-form"
114
139
  class="w-full justify-center sm:w-min sm:justify-normal"
115
140
  trailing
@@ -2,7 +2,6 @@
2
2
  import { ConnectTermsOfUseContent, ConnectTermsOfUseForm } from '#components'
3
3
 
4
4
  const { t } = useI18n()
5
- const authApi = useAuthApi()
6
5
  const { finalRedirect } = useConnectAccountFlowRedirect()
7
6
 
8
7
  definePageMeta({
@@ -16,8 +15,8 @@ useHead({
16
15
  title: t('connect.page.termsOfUse.title')
17
16
  })
18
17
 
19
- const { data, status } = await authApi.getTermsOfUse()
20
- const { patchTermsOfUse, isLoading } = authApi.usePatchTermsOfUse()
18
+ const { data, status } = useConnectAuthQuery().termsOfUse()
19
+ const { mutate, isLoading } = useConnectAuthMutation().updateTermsOfUse()
21
20
 
22
21
  const formRef = useTemplateRef<InstanceType<typeof ConnectTermsOfUseForm>>('form-ref')
23
22
  const contentRef = useTemplateRef<InstanceType<typeof ConnectTermsOfUseContent>>('content-ref')
@@ -30,8 +29,6 @@ const hasReachedBottom = computed(() => formTop.value >= tosBottom.value)
30
29
  const disableButtons = computed<boolean>(() => {
31
30
  return isLoading.value || status.value === 'pending' || status.value === 'error' || !data.value?.content
32
31
  })
33
-
34
- // TODO: - FUTURE - add help/contact info to alert?
35
32
  </script>
36
33
 
37
34
  <template>
@@ -67,10 +64,13 @@ const disableButtons = computed<boolean>(() => {
67
64
  :disable-buttons="disableButtons"
68
65
  :has-reached-bottom="hasReachedBottom"
69
66
  :loading="isLoading"
70
- @submit="patchTermsOfUse({
71
- accepted: true,
72
- version: data!.versionId,
73
- successCb: async () => await finalRedirect(useRoute(), true),
67
+ @submit="mutate({
68
+ payload: {
69
+ accepted: true,
70
+ version: data!.versionId,
71
+ },
72
+ silent: false,
73
+ successCb: () => finalRedirect(useRoute(), true),
74
74
  })"
75
75
  />
76
76
  </UContainer>
@@ -1,28 +1,33 @@
1
- export default defineNuxtPlugin((nuxtApp) => {
2
- const rtc = nuxtApp.$config.public
3
- const authApiUrl = rtc.authApiUrl + rtc.authApiVersion
4
- const appName = rtc.appName
5
- const xApiKey = rtc.xApiKey
1
+ export default defineNuxtPlugin({
2
+ name: 'auth-api',
3
+ order: -20,
4
+ parallel: true,
5
+ setup(nuxtApp) {
6
+ const rtc = nuxtApp.$config.public
7
+ const authApiUrl = rtc.authApiUrl + rtc.authApiVersion
8
+ const appName = rtc.appName
9
+ const xApiKey = rtc.xApiKey
6
10
 
7
- const api = $fetch.create({
8
- baseURL: authApiUrl,
9
- async onRequest({ options }) {
10
- const auth = useConnectAuth()
11
- const accountStore = useConnectAccountStore()
11
+ const api = $fetch.create({
12
+ baseURL: authApiUrl,
13
+ async onRequest({ options }) {
14
+ const auth = useConnectAuth()
15
+ const accountStore = useConnectAccountStore()
12
16
 
13
- const token = await auth.getToken()
14
- const accountId = accountStore.currentAccount.id
17
+ const token = await auth.getToken()
18
+ const accountId = accountStore.currentAccount.id
15
19
 
16
- options.headers.set('Authorization', `Bearer ${token}`)
17
- options.headers.set('App-Name', appName)
18
- options.headers.set('X-Apikey', xApiKey)
19
- options.headers.set('Account-Id', String(accountId))
20
- }
21
- })
20
+ options.headers.set('Authorization', `Bearer ${token}`)
21
+ options.headers.set('App-Name', appName)
22
+ options.headers.set('X-Apikey', xApiKey)
23
+ options.headers.set('Account-Id', String(accountId))
24
+ }
25
+ })
22
26
 
23
- return {
24
- provide: {
25
- authApi: api
27
+ return {
28
+ provide: {
29
+ authApi: api
30
+ }
26
31
  }
27
32
  }
28
33
  })
@@ -0,0 +1,33 @@
1
+ export default defineNuxtPlugin({
2
+ name: 'connect-account-bootstrap',
3
+ order: -10,
4
+ dependsOn: ['connect-auth', 'auth-api'],
5
+ parallel: true,
6
+ async setup(nuxtApp) {
7
+ const { isAuthenticated } = useConnectAuth()
8
+ const store = useConnectAccountStore()
9
+
10
+ if (isAuthenticated.value) {
11
+ // initialize user accounts and user profile on app mount
12
+ await Promise.all([
13
+ store.initAccountStore(),
14
+ store.syncUserProfile()
15
+ ])
16
+ }
17
+
18
+ // sync user profile whenever the token is updated
19
+ nuxtApp.hook('connect:auth:refresh', async () => {
20
+ if (isAuthenticated.value) {
21
+ await store.syncUserProfile()
22
+ }
23
+ })
24
+
25
+ addRouteMiddleware('set-account-from-url-param', (to) => {
26
+ if (to.query.accountid) {
27
+ store.switchCurrentAccount(parseInt(to.query.accountid as string))
28
+ }
29
+ },
30
+ { global: true }
31
+ )
32
+ }
33
+ })