@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.
- package/.env.example +2 -3
- package/CHANGELOG.md +11 -0
- package/app/components/Connect/Account/Create/Name.vue +24 -22
- package/app/components/Connect/Account/Create/index.vue +29 -21
- package/app/components/Connect/Header/Notifications.vue +26 -11
- package/app/composables/useConnectHeaderOptions.ts +2 -20
- package/app/middleware/connect-auth.ts +4 -5
- package/app/pages/auth/account/select.vue +51 -26
- package/app/pages/auth/terms-of-use.vue +9 -9
- package/app/plugins/auth-api.ts +26 -21
- package/app/plugins/connect-account-bootstrap.client.ts +33 -0
- package/app/plugins/connect-auth.client.ts +102 -88
- package/app/services/auth/index.ts +4 -0
- package/app/services/auth/mutate.ts +83 -0
- package/app/services/auth/query-keys.ts +26 -0
- package/app/services/auth/query.ts +87 -0
- package/app/services/auth/service.ts +125 -0
- package/app/services/helpers/get-cached-or-fetch.ts +43 -0
- package/app/services/helpers/index.ts +1 -0
- package/app/services/index.ts +1 -0
- package/app/stores/connect-account.ts +38 -146
- package/app/types/auth-nuxt-hooks.d.ts +7 -0
- package/app/utils/index.ts +1 -0
- package/app/utils/schemas/account.ts +32 -1
- package/app/utils/schemas/index.ts +1 -0
- package/nuxt.config.ts +1 -1
- package/package.json +3 -3
- package/app/composables/useAuthApi.ts +0 -156
- package/app/middleware/01.setup-accounts.global.ts +0 -13
- /package/app/middleware/{02.keycloak-params.global.ts → 01.keycloak-params.global.ts} +0 -0
- /package/app/middleware/{03.app-config-presets.global.ts → 02.app-config-presets.global.ts} +0 -0
- /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
|
-
#
|
|
34
|
-
|
|
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
|
|
9
|
-
const
|
|
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
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
}
|
|
28
|
-
|
|
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="
|
|
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 '#
|
|
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
|
-
|
|
5
|
+
defineEmits<{
|
|
6
|
+
submit: [event: FormSubmitEvent<AccountProfileSchema>]
|
|
7
|
+
}>()
|
|
7
8
|
|
|
8
|
-
const
|
|
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(
|
|
37
|
-
if (
|
|
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
|
|
58
|
-
:state
|
|
64
|
+
:schema
|
|
65
|
+
:state
|
|
59
66
|
@error="onFormSubmitError"
|
|
60
|
-
@submit="
|
|
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="
|
|
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="
|
|
110
|
-
<!-- v-model:country-iso2="
|
|
111
|
-
<!-- :is-invalid="!
|
|
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="
|
|
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="
|
|
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="
|
|
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
|
-
|
|
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="
|
|
26
|
+
<UDropdownMenu :items="dropdownItems">
|
|
9
27
|
<UChip
|
|
10
28
|
color="error"
|
|
11
29
|
position="top-left"
|
|
12
30
|
inset
|
|
13
|
-
:show="
|
|
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
|
|
20
|
-
:icon="isLargeScreen ? 'i-mdi-caret-down' : ''"
|
|
21
|
-
|
|
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
|
-
|
|
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
|
-
|
|
93
|
+
accountStore.switchCurrentAccount(account.id)
|
|
94
94
|
}
|
|
95
95
|
} else {
|
|
96
|
-
|
|
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
|
|
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
|
|
28
|
-
|
|
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().
|
|
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
|
|
12
|
+
const store = useConnectAccountStore()
|
|
11
13
|
const { authUser } = useConnectAuth()
|
|
12
14
|
const { finalRedirect } = useConnectAccountFlowRedirect()
|
|
13
|
-
const
|
|
14
|
-
const {
|
|
15
|
-
const
|
|
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
|
-
|
|
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
|
-
|
|
27
|
-
|
|
28
|
-
finalRedirect(
|
|
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
|
-
|
|
33
|
-
|
|
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>{{
|
|
49
|
-
<ConnectAccountExistingAlert v-if="
|
|
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="
|
|
56
|
-
:accounts="
|
|
80
|
+
v-if="showAccountList"
|
|
81
|
+
:accounts="store.userAccounts"
|
|
57
82
|
@select="selectAndRedirect"
|
|
58
83
|
/>
|
|
59
84
|
|
|
60
85
|
<ConnectAccountCreate
|
|
61
86
|
v-else
|
|
62
|
-
|
|
87
|
+
@submit="onSubmitCreateAccount"
|
|
63
88
|
/>
|
|
64
89
|
</ConnectTransitionFade>
|
|
65
90
|
|
|
66
91
|
<!-- Select Account Actions -->
|
|
67
92
|
<div
|
|
68
|
-
v-if="
|
|
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="
|
|
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="
|
|
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="
|
|
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="
|
|
133
|
+
@click="addNew = false"
|
|
109
134
|
/>
|
|
110
135
|
<UButton
|
|
111
136
|
:label="$t('connect.label.saveAndContinue')"
|
|
112
|
-
:loading="
|
|
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 } =
|
|
20
|
-
const {
|
|
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="
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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>
|
package/app/plugins/auth-api.ts
CHANGED
|
@@ -1,28 +1,33 @@
|
|
|
1
|
-
export default defineNuxtPlugin(
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
const api = $fetch.create({
|
|
12
|
+
baseURL: authApiUrl,
|
|
13
|
+
async onRequest({ options }) {
|
|
14
|
+
const auth = useConnectAuth()
|
|
15
|
+
const accountStore = useConnectAccountStore()
|
|
12
16
|
|
|
13
|
-
|
|
14
|
-
|
|
17
|
+
const token = await auth.getToken()
|
|
18
|
+
const accountId = accountStore.currentAccount.id
|
|
15
19
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
+
})
|