@sbc-connect/nuxt-auth 0.2.1 → 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 +32 -0
- package/app/app.config.ts +4 -3
- package/app/components/Connect/Account/Create/Name.vue +73 -0
- package/app/components/Connect/Account/Create/index.vue +134 -0
- package/app/components/Connect/Modal/InvalidIdp.vue +45 -0
- package/app/components/Connect/TermsOfUse/Form.vue +1 -1
- package/app/composables/useAuthApi.ts +96 -2
- package/app/composables/useConnectAccountFlowRedirect.ts +0 -4
- package/app/composables/useConnectAppConfig.ts +31 -0
- package/app/composables/useConnectAuthModals.ts +76 -0
- package/app/enums/connect-access-type.ts +3 -0
- package/app/enums/connect-payment-method.ts +3 -0
- package/app/enums/connect-preset-type.ts +4 -0
- package/app/enums/connect-product-code.ts +3 -0
- package/app/enums/connect-product-type.ts +3 -0
- package/app/interfaces/app-config-shapes.ts +33 -0
- package/app/interfaces/connect-account-address.ts +1 -0
- package/app/interfaces/connect-account.ts +13 -0
- package/app/middleware/03.app-config-presets.global.ts +13 -0
- package/app/middleware/04.idp-enforcement.global.ts +39 -0
- package/app/middleware/connect-auth.ts +8 -1
- package/app/pages/auth/account/select.vue +58 -6
- package/app/pages/auth/login.vue +18 -1
- package/app/stores/connect-account.ts +75 -10
- package/app/types/auth-app-config.d.ts +11 -18
- package/app/utils/schemas/account.ts +76 -0
- package/i18n/locales/en-CA.ts +39 -1
- package/nuxt.config.ts +1 -1
- package/package.json +14 -14
- package/app/composables/useConnectTosModals.ts +0 -46
- package/app/middleware/03.allowed-idps.global.ts +0 -20
- package/modules/auth-assets/index.ts +0 -15
- package/modules/auth-assets/runtime/assets/connect-auth-tw.css +0 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
# @sbc-connect/nuxt-auth
|
|
2
2
|
|
|
3
|
+
## 0.4.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#118](https://github.com/bcgov/connect-nuxt/pull/118) [`41e58f4`](https://github.com/bcgov/connect-nuxt/commit/41e58f44e6d216e7de568bccb2e240b2d89b8408) Thanks [@deetz99](https://github.com/deetz99)! - Remove now unnecessary css module workaround.
|
|
8
|
+
|
|
9
|
+
- [#120](https://github.com/bcgov/connect-nuxt/pull/120) [`9f42868`](https://github.com/bcgov/connect-nuxt/commit/9f428681207188292d52cf6d370035f54bdb6ab4) Thanks [@cameron-eyds](https://github.com/cameron-eyds)! - Idp Enforcement Modal and bcsc user welcome msg
|
|
10
|
+
|
|
11
|
+
- [#117](https://github.com/bcgov/connect-nuxt/pull/117) [`e3da105`](https://github.com/bcgov/connect-nuxt/commit/e3da1056247f5c502578dc70f95375e66e3cc1da) Thanks [@deetz99](https://github.com/deetz99)! - Update all dependencies
|
|
12
|
+
|
|
13
|
+
- [#119](https://github.com/bcgov/connect-nuxt/pull/119) [`ee5ba9e`](https://github.com/bcgov/connect-nuxt/commit/ee5ba9e6f7302e8ea11fd0ebfa887c4f6269b0ee) Thanks [@cameron-eyds](https://github.com/cameron-eyds)! - implements Dynamic app.config and idp enforcement
|
|
14
|
+
|
|
15
|
+
- [#114](https://github.com/bcgov/connect-nuxt/pull/114) [`fe3eef1`](https://github.com/bcgov/connect-nuxt/commit/fe3eef1b39cc5883cc5e8560efe0dd89d04d0455) Thanks [@cameron-eyds](https://github.com/cameron-eyds)! - Implements Acct Creation submissions, contact updates and name lookup
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- Updated dependencies [[`41e58f4`](https://github.com/bcgov/connect-nuxt/commit/41e58f44e6d216e7de568bccb2e240b2d89b8408), [`e3da105`](https://github.com/bcgov/connect-nuxt/commit/e3da1056247f5c502578dc70f95375e66e3cc1da), [`fe3eef1`](https://github.com/bcgov/connect-nuxt/commit/fe3eef1b39cc5883cc5e8560efe0dd89d04d0455)]:
|
|
20
|
+
- @sbc-connect/nuxt-forms@0.4.0
|
|
21
|
+
- @sbc-connect/nuxt-base@0.6.0
|
|
22
|
+
|
|
23
|
+
## 0.3.0
|
|
24
|
+
|
|
25
|
+
### Minor Changes
|
|
26
|
+
|
|
27
|
+
- [#108](https://github.com/bcgov/connect-nuxt/pull/108) [`8571754`](https://github.com/bcgov/connect-nuxt/commit/8571754160242c3233838fc039fd1a01ff9d7a82) Thanks [@cameron-eyds](https://github.com/cameron-eyds)! - Implements account creation in Auth and Country Code/Country Flag components in Forms
|
|
28
|
+
|
|
29
|
+
### Patch Changes
|
|
30
|
+
|
|
31
|
+
- Updated dependencies [[`8571754`](https://github.com/bcgov/connect-nuxt/commit/8571754160242c3233838fc039fd1a01ff9d7a82), [`d9d6356`](https://github.com/bcgov/connect-nuxt/commit/d9d63560e27117c43b9e8e54d363c3fdbb620049), [`dd17349`](https://github.com/bcgov/connect-nuxt/commit/dd173497255f35415b468e17f7192722f604d3c8)]:
|
|
32
|
+
- @sbc-connect/nuxt-forms@0.3.0
|
|
33
|
+
- @sbc-connect/nuxt-base@0.5.0
|
|
34
|
+
|
|
3
35
|
## 0.2.1
|
|
4
36
|
|
|
5
37
|
### Patch Changes
|
package/app/app.config.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { ConnectIdpHint } from '#auth/app/enums/connect-idp-hint'
|
|
2
|
+
import type { AppConfigInput } from 'nuxt/schema'
|
|
2
3
|
|
|
3
4
|
export default defineAppConfig({
|
|
4
5
|
connect: {
|
|
5
6
|
login: {
|
|
6
7
|
redirect: '/',
|
|
7
8
|
idps: [ConnectIdpHint.BCSC, ConnectIdpHint.BCEID, ConnectIdpHint.IDIR],
|
|
8
|
-
skipAccountRedirect: false
|
|
9
|
-
|
|
9
|
+
skipAccountRedirect: false,
|
|
10
|
+
idpEnforcement: false
|
|
10
11
|
},
|
|
11
12
|
logout: {
|
|
12
13
|
redirect: ''
|
|
@@ -18,4 +19,4 @@ export default defineAppConfig({
|
|
|
18
19
|
accountOptionsMenu: true
|
|
19
20
|
}
|
|
20
21
|
}
|
|
21
|
-
})
|
|
22
|
+
} satisfies AppConfigInput) // validates input shape without losing inference
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { FormError, InputProps } from '@nuxt/ui'
|
|
3
|
+
|
|
4
|
+
defineProps<{
|
|
5
|
+
error?: FormError<string>
|
|
6
|
+
}>()
|
|
7
|
+
|
|
8
|
+
const authApi = useAuthApi()
|
|
9
|
+
const { accountFormState } = useConnectAccountStore()
|
|
10
|
+
|
|
11
|
+
const isLoading = ref(false)
|
|
12
|
+
const statusCode = defineModel<number | undefined>('statusCode')
|
|
13
|
+
|
|
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
|
|
22
|
+
} catch (err: unknown) {
|
|
23
|
+
statusCode.value = err?.response?.status || 500
|
|
24
|
+
} finally {
|
|
25
|
+
isLoading.value = false
|
|
26
|
+
}
|
|
27
|
+
} else {
|
|
28
|
+
statusCode.value = undefined
|
|
29
|
+
}
|
|
30
|
+
}, 1000)
|
|
31
|
+
|
|
32
|
+
watch(() => accountFormState.accountName, validateName)
|
|
33
|
+
|
|
34
|
+
// Compute UInput props based on loading state and status code
|
|
35
|
+
const uInputProps = computed<InputProps>(() => {
|
|
36
|
+
const iconMap: Record<number, { class: string, name: string }> = {
|
|
37
|
+
204: { class: 'text-success size-7', name: 'i-mdi-check' },
|
|
38
|
+
200: { class: 'text-error size-7', name: 'i-mdi-close' },
|
|
39
|
+
500: { class: 'text-error size-7', name: 'i-mdi-close' }
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const icon = statusCode.value ? iconMap[statusCode.value] : null
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
loading: isLoading.value,
|
|
46
|
+
trailing: true,
|
|
47
|
+
ui: {
|
|
48
|
+
trailingIcon: icon?.class || 'text-primary size-7'
|
|
49
|
+
},
|
|
50
|
+
trailingIcon: icon?.name
|
|
51
|
+
}
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
// Provide custom props for UInput
|
|
55
|
+
provide('UInput-props-account-name-input', uInputProps)
|
|
56
|
+
</script>
|
|
57
|
+
|
|
58
|
+
<template>
|
|
59
|
+
<ConnectFormFieldWrapper
|
|
60
|
+
class="pt-2 my-6"
|
|
61
|
+
:label="$t('connect.page.createAccount.accountNameLabel')"
|
|
62
|
+
orientation="horizontal"
|
|
63
|
+
:error
|
|
64
|
+
>
|
|
65
|
+
<ConnectFormInput
|
|
66
|
+
v-model="accountFormState.accountName"
|
|
67
|
+
name="accountName"
|
|
68
|
+
input-id="account-name-input"
|
|
69
|
+
:label="$t('connect.page.createAccount.accountNameLabel')"
|
|
70
|
+
:help="$t('connect.page.createAccount.accountNameHelp')"
|
|
71
|
+
/>
|
|
72
|
+
</ConnectFormFieldWrapper>
|
|
73
|
+
</template>
|
|
@@ -0,0 +1,134 @@
|
|
|
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'
|
|
5
|
+
|
|
6
|
+
const statusCode = ref<number | undefined>(undefined)
|
|
7
|
+
|
|
8
|
+
const { accountFormState, submitCreateAccount, userFullName } = useConnectAccountStore()
|
|
9
|
+
const accountProfileSchema = computed(() => getAccountCreateSchema(statusCode.value))
|
|
10
|
+
const formRef = useTemplateRef<Form<AccountProfileSchema>>('account-create-form')
|
|
11
|
+
|
|
12
|
+
const formErrors = computed<{
|
|
13
|
+
accountName: FormError<string> | undefined
|
|
14
|
+
emailAddress: FormError<string> | undefined
|
|
15
|
+
phone: FormError<string> | undefined
|
|
16
|
+
address: FormError<string> | undefined
|
|
17
|
+
}>(() => {
|
|
18
|
+
const errors = formRef.value?.getErrors()
|
|
19
|
+
return {
|
|
20
|
+
accountName: errors?.find(e => e.name === 'accountName'),
|
|
21
|
+
emailAddress: errors?.find(e => e.name?.startsWith('emailAddress')),
|
|
22
|
+
phone: errors?.find(e => e.name?.startsWith('phone')),
|
|
23
|
+
address: errors?.find(e => e.name?.startsWith('address'))
|
|
24
|
+
}
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
async function validate() {
|
|
28
|
+
return formRef.value?.validate({ silent: true })
|
|
29
|
+
}
|
|
30
|
+
</script>
|
|
31
|
+
|
|
32
|
+
<template>
|
|
33
|
+
<ConnectPageSection
|
|
34
|
+
:heading="{
|
|
35
|
+
label: $t('connect.label.accountInformation'),
|
|
36
|
+
labelClass: 'font-bold md:ml-4',
|
|
37
|
+
}"
|
|
38
|
+
>
|
|
39
|
+
<UForm
|
|
40
|
+
id="account-create-form"
|
|
41
|
+
ref="account-create-form"
|
|
42
|
+
class="p-8"
|
|
43
|
+
no-validate
|
|
44
|
+
:validate-on="['input', 'change']"
|
|
45
|
+
:schema="accountProfileSchema"
|
|
46
|
+
:state="accountFormState"
|
|
47
|
+
@error="onFormSubmitError"
|
|
48
|
+
@submit="submitCreateAccount()"
|
|
49
|
+
>
|
|
50
|
+
<!-- Legal Name -->
|
|
51
|
+
<ConnectFormFieldWrapper
|
|
52
|
+
:label="$t('connect.page.createAccount.yourNameLabel')"
|
|
53
|
+
orientation="horizontal"
|
|
54
|
+
>
|
|
55
|
+
<p class="font-bold">
|
|
56
|
+
{{ userFullName }}
|
|
57
|
+
</p>
|
|
58
|
+
<p class="mt-3">
|
|
59
|
+
{{ $t('connect.page.createAccount.yourNameHelp') }}
|
|
60
|
+
</p>
|
|
61
|
+
</ConnectFormFieldWrapper>
|
|
62
|
+
|
|
63
|
+
<USeparator orientation="horizontal" class="my-8" />
|
|
64
|
+
|
|
65
|
+
<!-- Account Name -->
|
|
66
|
+
<ConnectAccountCreateName
|
|
67
|
+
v-model:status-code="statusCode"
|
|
68
|
+
:error="formErrors.accountName"
|
|
69
|
+
/>
|
|
70
|
+
|
|
71
|
+
<!-- Account Email -->
|
|
72
|
+
<ConnectFormFieldWrapper
|
|
73
|
+
class="my-6"
|
|
74
|
+
:label="$t('connect.page.createAccount.emailLabel')"
|
|
75
|
+
orientation="horizontal"
|
|
76
|
+
:error="formErrors.emailAddress"
|
|
77
|
+
>
|
|
78
|
+
<ConnectFormInput
|
|
79
|
+
v-model="accountFormState.emailAddress"
|
|
80
|
+
name="emailAddress"
|
|
81
|
+
input-id="email-input"
|
|
82
|
+
:label="$t('connect.page.createAccount.emailPlaceholder')"
|
|
83
|
+
/>
|
|
84
|
+
</ConnectFormFieldWrapper>
|
|
85
|
+
|
|
86
|
+
<!-- Account Phone -->
|
|
87
|
+
<ConnectFieldset
|
|
88
|
+
:label="$t('connect.page.createAccount.phoneLabel')"
|
|
89
|
+
orientation="horizontal"
|
|
90
|
+
:error="formErrors.phone"
|
|
91
|
+
>
|
|
92
|
+
<div class="flex flex-row gap-2">
|
|
93
|
+
<!-- Disabling country code selection until Auth Model Supports individual property -->
|
|
94
|
+
<!-- <ConnectFormPhoneCountryCode -->
|
|
95
|
+
<!-- v-model:country-calling-code="accountFormState.phone.countryCode" -->
|
|
96
|
+
<!-- v-model:country-iso2="accountFormState.phone.countryIso2" -->
|
|
97
|
+
<!-- :is-invalid="!accountFormState.phone.countryIso2" -->
|
|
98
|
+
<!-- class="w-40 mt-[-20px]" -->
|
|
99
|
+
<!-- /> -->
|
|
100
|
+
<ConnectFormInput
|
|
101
|
+
v-model="accountFormState.phone.phoneNumber"
|
|
102
|
+
name="phone.phoneNumber"
|
|
103
|
+
input-id="phone-number-input"
|
|
104
|
+
class="flex-2"
|
|
105
|
+
:label="$t('connect.page.createAccount.phonePlaceholder')"
|
|
106
|
+
mask="(###) ###-####"
|
|
107
|
+
/>
|
|
108
|
+
<ConnectFormInput
|
|
109
|
+
v-model="accountFormState.phone.ext"
|
|
110
|
+
name="phone.ext"
|
|
111
|
+
input-id="phone-ext-input"
|
|
112
|
+
:label="$t('connect.page.createAccount.phoneExtensionLabel')"
|
|
113
|
+
/>
|
|
114
|
+
</div>
|
|
115
|
+
</ConnectFieldset>
|
|
116
|
+
|
|
117
|
+
<!-- Account Address -->
|
|
118
|
+
<ConnectFieldset
|
|
119
|
+
class="my-6"
|
|
120
|
+
:label="$t('connect.page.createAccount.addressLabel')"
|
|
121
|
+
orientation="horizontal"
|
|
122
|
+
:error="formErrors.address"
|
|
123
|
+
>
|
|
124
|
+
<ConnectFormAddress
|
|
125
|
+
id="account-address"
|
|
126
|
+
v-model="accountFormState.address"
|
|
127
|
+
name="address"
|
|
128
|
+
schema-prefix="address"
|
|
129
|
+
@should-validate="validate"
|
|
130
|
+
/>
|
|
131
|
+
</ConnectFieldset>
|
|
132
|
+
</UForm>
|
|
133
|
+
</ConnectPageSection>
|
|
134
|
+
</template>
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
const props = defineProps<{
|
|
3
|
+
currentIdp: ConnectLoginSource
|
|
4
|
+
}>()
|
|
5
|
+
const emit = defineEmits<{ close: [] }>()
|
|
6
|
+
|
|
7
|
+
function closeModal() {
|
|
8
|
+
emit('close')
|
|
9
|
+
}
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<template>
|
|
13
|
+
<UModal
|
|
14
|
+
id="invalid-idp-dialog"
|
|
15
|
+
overlay
|
|
16
|
+
:dismissible="false"
|
|
17
|
+
>
|
|
18
|
+
<template #content>
|
|
19
|
+
<div class="p-10 flex flex-col gap-6">
|
|
20
|
+
<div role="alert">
|
|
21
|
+
<h2
|
|
22
|
+
id="invalid-idp-title"
|
|
23
|
+
class="text-xl font-bold text-neutral-highlighted"
|
|
24
|
+
>
|
|
25
|
+
{{ $t('connect.invalidIdp.title') }} {{ props.currentIdp }}
|
|
26
|
+
</h2>
|
|
27
|
+
</div>
|
|
28
|
+
<div>
|
|
29
|
+
<div role="alert">
|
|
30
|
+
<span>{{ $t('connect.invalidIdp.content') }}</span>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
<div class="flex flex-wrap items-center justify-center gap-4">
|
|
34
|
+
<UButton
|
|
35
|
+
:label="$t('connect.label.logout')"
|
|
36
|
+
:aria-label="$t('connect.label.logout')"
|
|
37
|
+
size="xl"
|
|
38
|
+
class="font-bold"
|
|
39
|
+
@click="closeModal"
|
|
40
|
+
/>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
</template>
|
|
44
|
+
</UModal>
|
|
45
|
+
</template>
|
|
@@ -3,7 +3,7 @@ import { z } from 'zod'
|
|
|
3
3
|
import type { FormErrorEvent, Form } from '@nuxt/ui'
|
|
4
4
|
|
|
5
5
|
const { t } = useI18n()
|
|
6
|
-
const { openDeclineTosModal } =
|
|
6
|
+
const { openDeclineTosModal } = useConnectAuthModals()
|
|
7
7
|
|
|
8
8
|
const props = defineProps<{
|
|
9
9
|
hasReachedBottom: boolean
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { ConnectCreateAccount } from '#auth/app/interfaces/connect-account'
|
|
2
|
+
|
|
1
3
|
export const useAuthApi = () => {
|
|
2
4
|
const { $authApi } = useNuxtApp()
|
|
3
5
|
const queryCache = useQueryCache()
|
|
@@ -13,6 +15,95 @@ export const useAuthApi = () => {
|
|
|
13
15
|
return query()
|
|
14
16
|
}
|
|
15
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Validates whether an account name is available by sending a request to the AUTH service.
|
|
20
|
+
* @param {string} accountName - The account name to validate for uniqueness.
|
|
21
|
+
*/
|
|
22
|
+
function verifyAccountName(accountName: string) {
|
|
23
|
+
const query = defineQuery({
|
|
24
|
+
key: ['auth-account-name', accountName],
|
|
25
|
+
query: () => $authApi.raw(`/orgs?validateName=true&name=${encodeURIComponent(accountName)}`),
|
|
26
|
+
staleTime: 300000
|
|
27
|
+
})
|
|
28
|
+
return query()
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Creates an account by POSTing the given payload to `/orgs`.
|
|
33
|
+
* @returns Object containing mutation state and `createAccount` function.
|
|
34
|
+
*/
|
|
35
|
+
const useCreateAccount = defineMutation(() => {
|
|
36
|
+
const { mutateAsync, ...mutation } = useMutation({
|
|
37
|
+
mutation: (vars: { payload: ConnectCreateAccount, successCb?: () => Promise<unknown> }) => {
|
|
38
|
+
return $authApi<ConnectAuthProfile>('/orgs', {
|
|
39
|
+
method: 'POST',
|
|
40
|
+
body: vars.payload
|
|
41
|
+
})
|
|
42
|
+
},
|
|
43
|
+
onError: (error) => {
|
|
44
|
+
// TODO: FUTURE - add api error message to modal content - remove console.error
|
|
45
|
+
console.error('ERROR: ', error)
|
|
46
|
+
useConnectAuthModals().openCreateAccountModal()
|
|
47
|
+
},
|
|
48
|
+
onSuccess: async (_, _vars) => {
|
|
49
|
+
await queryCache.invalidateQueries({ key: ['auth-user-profile'], exact: true })
|
|
50
|
+
if (_vars.successCb) {
|
|
51
|
+
await _vars.successCb()
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
...mutation,
|
|
58
|
+
createAccount: mutateAsync
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Updates a users contact by PUTing the given payload to `/users/contacts`.
|
|
64
|
+
* @returns Object containing mutation state and `updateUserContact` function.
|
|
65
|
+
*/
|
|
66
|
+
const useUpdateUserContact = defineMutation(() => {
|
|
67
|
+
const { mutateAsync, ...mutation } = useMutation({
|
|
68
|
+
mutation: (vars: {
|
|
69
|
+
email: string
|
|
70
|
+
phone: string
|
|
71
|
+
phoneExtension: string | undefined
|
|
72
|
+
successCb?: () => Promise<unknown>
|
|
73
|
+
errorCb?: (error: unknown) => Promise<unknown>
|
|
74
|
+
}) => {
|
|
75
|
+
return $authApi<ConnectAuthProfile>('/users/contacts', {
|
|
76
|
+
method: 'PUT',
|
|
77
|
+
body: {
|
|
78
|
+
email: vars.email,
|
|
79
|
+
phone: vars.phone,
|
|
80
|
+
phoneExtension: vars.phoneExtension
|
|
81
|
+
}
|
|
82
|
+
})
|
|
83
|
+
},
|
|
84
|
+
onError: async (error, _vars) => {
|
|
85
|
+
// TODO: FUTURE - add api error message to modal content - remove console.error
|
|
86
|
+
console.error('ERROR: ', error)
|
|
87
|
+
await useConnectAuthModals().openUpdateUserContactModal()
|
|
88
|
+
|
|
89
|
+
if (_vars.errorCb) {
|
|
90
|
+
await queryCache.invalidateQueries({ key: ['auth-user-profile'], exact: true })
|
|
91
|
+
await _vars.errorCb(error)
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
onSuccess: async (_, _vars) => {
|
|
95
|
+
if (_vars.successCb) {
|
|
96
|
+
await _vars.successCb()
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
return {
|
|
102
|
+
...mutation,
|
|
103
|
+
updateUserContact: mutateAsync
|
|
104
|
+
}
|
|
105
|
+
})
|
|
106
|
+
|
|
16
107
|
async function getTermsOfUse() {
|
|
17
108
|
const query = defineQuery({
|
|
18
109
|
key: ['auth-terms-of-use'],
|
|
@@ -36,7 +127,7 @@ export const useAuthApi = () => {
|
|
|
36
127
|
onError: (error) => {
|
|
37
128
|
// TODO: FUTURE - add api error message to modal content - remove console.error
|
|
38
129
|
console.error('ERROR: ', error)
|
|
39
|
-
|
|
130
|
+
useConnectAuthModals().openPatchTosErrorModal()
|
|
40
131
|
},
|
|
41
132
|
onSuccess: async (_, _vars) => {
|
|
42
133
|
await queryCache.invalidateQueries({ key: ['auth-user-profile'], exact: true })
|
|
@@ -55,6 +146,9 @@ export const useAuthApi = () => {
|
|
|
55
146
|
return {
|
|
56
147
|
getAuthUserProfile,
|
|
57
148
|
getTermsOfUse,
|
|
58
|
-
|
|
149
|
+
useCreateAccount,
|
|
150
|
+
usePatchTermsOfUse,
|
|
151
|
+
useUpdateUserContact,
|
|
152
|
+
verifyAccountName
|
|
59
153
|
}
|
|
60
154
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { useAppConfig } from '#imports'
|
|
2
|
+
|
|
3
|
+
export const useConnectAppConfig = () => {
|
|
4
|
+
/**
|
|
5
|
+
* Merge preset overrides (from app.config.connectOverrides) into the provided baseConfig.
|
|
6
|
+
* If no override for the preset is found, baseConfig is returned unchanged.
|
|
7
|
+
*/
|
|
8
|
+
function mergeAppConfigOverrides(
|
|
9
|
+
baseConfig: ConnectConfig,
|
|
10
|
+
presetName: ConnectPresetType
|
|
11
|
+
): ConnectConfig {
|
|
12
|
+
const appConfig = useAppConfig()
|
|
13
|
+
const overrides = appConfig.connectOverrides?.[presetName] ?? null
|
|
14
|
+
|
|
15
|
+
return {
|
|
16
|
+
...baseConfig,
|
|
17
|
+
// Apply shallow merge for each subtree when present
|
|
18
|
+
...(overrides?.login
|
|
19
|
+
? { login: { ...baseConfig.login, ...overrides?.login } }
|
|
20
|
+
: { login: baseConfig.login }),
|
|
21
|
+
...(overrides?.header
|
|
22
|
+
? { header: { ...baseConfig.header, ...overrides?.header } }
|
|
23
|
+
: { header: baseConfig.header }),
|
|
24
|
+
logout: baseConfig.logout
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
mergeAppConfigOverrides
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
export const useConnectAuthModals = () => {
|
|
2
|
+
const { baseModal } = useConnectModal()
|
|
3
|
+
const { logout } = useConnectAuth()
|
|
4
|
+
const t = useNuxtApp().$i18n.t
|
|
5
|
+
|
|
6
|
+
function openDeclineTosModal() {
|
|
7
|
+
baseModal.open({
|
|
8
|
+
title: `${t('connect.label.declineTermsOfUse')}?`,
|
|
9
|
+
description: t('connect.text.declineTOSCantAccessService'),
|
|
10
|
+
dismissible: true,
|
|
11
|
+
buttons: [
|
|
12
|
+
{
|
|
13
|
+
label: t('connect.label.declineTermsOfUse'),
|
|
14
|
+
onClick: async () => await logout()
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
label: t('connect.label.cancel'),
|
|
18
|
+
shouldClose: true,
|
|
19
|
+
variant: 'outline'
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
})
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// TODO: better error text
|
|
26
|
+
function openPatchTosErrorModal() {
|
|
27
|
+
baseModal.open({
|
|
28
|
+
title: `${t('connect.text.patchTosError.title')}`,
|
|
29
|
+
description: t('connect.text.patchTosError.description'),
|
|
30
|
+
dismissible: true,
|
|
31
|
+
buttons: [
|
|
32
|
+
{
|
|
33
|
+
label: t('connect.label.close'),
|
|
34
|
+
shouldClose: true
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
// contact info ???
|
|
38
|
+
// include api error message?
|
|
39
|
+
})
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function openCreateAccountModal() {
|
|
43
|
+
baseModal.open({
|
|
44
|
+
title: `${t('connect.text.accountCreationError.title')}`,
|
|
45
|
+
description: t('connect.text.accountCreationError.description'),
|
|
46
|
+
dismissible: true,
|
|
47
|
+
buttons: [
|
|
48
|
+
{
|
|
49
|
+
label: t('connect.label.close'),
|
|
50
|
+
shouldClose: true
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
})
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function openUpdateUserContactModal() {
|
|
57
|
+
baseModal.open({
|
|
58
|
+
title: `${t('connect.text.userContactUpdateError.title')}`,
|
|
59
|
+
description: t('connect.text.userContactUpdateError.description'),
|
|
60
|
+
dismissible: true,
|
|
61
|
+
buttons: [
|
|
62
|
+
{
|
|
63
|
+
label: t('connect.label.close'),
|
|
64
|
+
shouldClose: true
|
|
65
|
+
}
|
|
66
|
+
]
|
|
67
|
+
})
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
openCreateAccountModal,
|
|
72
|
+
openDeclineTosModal,
|
|
73
|
+
openPatchTosErrorModal,
|
|
74
|
+
openUpdateUserContactModal
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export interface ConnectLoginConfig {
|
|
2
|
+
redirect: string
|
|
3
|
+
idps: ConnectIdpHint[]
|
|
4
|
+
skipAccountRedirect: boolean
|
|
5
|
+
idpEnforcement: boolean
|
|
6
|
+
alert?: {
|
|
7
|
+
title?: string
|
|
8
|
+
message?: string
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface ConnectLogoutConfig {
|
|
13
|
+
redirect: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface ConnectHeaderConfig {
|
|
17
|
+
loginMenu: boolean
|
|
18
|
+
createAccount: boolean
|
|
19
|
+
notifications: boolean
|
|
20
|
+
accountOptionsMenu: boolean
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface ConnectConfig {
|
|
24
|
+
login: ConnectLoginConfig
|
|
25
|
+
logout: ConnectLogoutConfig
|
|
26
|
+
header: ConnectHeaderConfig
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface ConnectPresetOverrides {
|
|
30
|
+
login?: Partial<ConnectLoginConfig>
|
|
31
|
+
header?: Partial<ConnectHeaderConfig>
|
|
32
|
+
logout?: Partial<ConnectLogoutConfig>
|
|
33
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type ConnectAccountAddress = Pick<ConnectAddress, Exclude<keyof ConnectAddress, 'locationDescription'>>
|
|
@@ -8,3 +8,16 @@ export interface ConnectAccount {
|
|
|
8
8
|
urlpath: string
|
|
9
9
|
urlorigin: string
|
|
10
10
|
}
|
|
11
|
+
|
|
12
|
+
export interface ConnectCreateAccount {
|
|
13
|
+
accessType: ConnectAccessType
|
|
14
|
+
isBusinessAccount: boolean
|
|
15
|
+
mailingAddress: ConnectAccountAddress
|
|
16
|
+
name: string
|
|
17
|
+
paymentInfo: {
|
|
18
|
+
paymentMethod: ConnectPaymentMethod
|
|
19
|
+
}
|
|
20
|
+
productSubscriptions: Array<{
|
|
21
|
+
productCode: ConnectProductCode
|
|
22
|
+
}>
|
|
23
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { useAppConfig } from '#imports'
|
|
2
|
+
import { useConnectAppConfig } from '#auth/app/composables/useConnectAppConfig'
|
|
3
|
+
|
|
4
|
+
export default defineNuxtRouteMiddleware((to) => {
|
|
5
|
+
const appConfig = useAppConfig()
|
|
6
|
+
const { mergeAppConfigOverrides } = useConnectAppConfig()
|
|
7
|
+
|
|
8
|
+
// Build and assign app.config presets
|
|
9
|
+
appConfig.connect = mergeAppConfigOverrides(
|
|
10
|
+
appConfig.connect as ConnectConfig,
|
|
11
|
+
to.query.preset as ConnectPresetType
|
|
12
|
+
)
|
|
13
|
+
})
|