From d751c9f4638e9b7422ba525331507e39531755d7 Mon Sep 17 00:00:00 2001 From: Trevor Clark Date: Thu, 25 Apr 2024 18:01:11 -0700 Subject: [PATCH] initial auth scaffold and what sam needs to begin with --- strr-web/README.md | 40 +++++++++++++++++++++ strr-web/components/Footer.vue | 8 ++--- strr-web/components/Header.vue | 13 ++++--- strr-web/components/header/Menu.vue | 2 +- strr-web/components/tooltip/index.vue | 37 ++++++++++++++++++++ strr-web/composables/useBcrosNavigate.ts | 5 +-- strr-web/enums/route-name-e.ts | 5 +++ strr-web/interfaces/account-i.ts | 10 ++++++ strr-web/interfaces/header-menu-item-i.ts | 7 ++++ strr-web/interfaces/user-settings-i.ts | 14 ++++++++ strr-web/lang/en.json | 22 ++++++++++++ strr-web/layouts/default.vue | 11 +++--- strr-web/middleware/setupAuth.global.ts | 42 +++++++++++++++++++++++ strr-web/nuxt.config.ts | 3 +- strr-web/pages/accountselect.vue | 34 ++++++++++++++++++ strr-web/pages/index.vue | 9 ++--- strr-web/stores/account.ts | 31 +++++++++++++++++ strr-web/stores/keycloak.ts | 2 ++ 18 files changed, 271 insertions(+), 24 deletions(-) create mode 100644 strr-web/README.md create mode 100644 strr-web/components/tooltip/index.vue create mode 100644 strr-web/enums/route-name-e.ts create mode 100644 strr-web/interfaces/header-menu-item-i.ts create mode 100644 strr-web/interfaces/user-settings-i.ts create mode 100644 strr-web/middleware/setupAuth.global.ts create mode 100644 strr-web/pages/accountselect.vue diff --git a/strr-web/README.md b/strr-web/README.md new file mode 100644 index 00000000..4191342d --- /dev/null +++ b/strr-web/README.md @@ -0,0 +1,40 @@ +# Nuxt 3 Minimal Starter + +Look at the [Nuxt 3 documentation](https://nuxt.com/docs/getting-started/introduction) to learn more. + +## Setup + +Make sure to install the dependencies: + +```bash +# pnpm +pnpm install + +``` + +## Development Server + +Start the development server on `http://localhost:3000`: + +```bash +# pnpm +pnpm run dev +``` + +## Production + +Build the application for production: + +```bash +# pnpm +pnpm run build +``` + +Locally preview production build: + +```bash +# pnpm +pnpm run preview +``` + +Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information. \ No newline at end of file diff --git a/strr-web/components/Footer.vue b/strr-web/components/Footer.vue index 46bad430..25615ffc 100644 --- a/strr-web/components/Footer.vue +++ b/strr-web/components/Footer.vue @@ -20,10 +20,10 @@
-
- + @@ -40,9 +40,9 @@ diff --git a/strr-web/composables/useBcrosNavigate.ts b/strr-web/composables/useBcrosNavigate.ts index 5af329c1..9b24b2ea 100644 --- a/strr-web/composables/useBcrosNavigate.ts +++ b/strr-web/composables/useBcrosNavigate.ts @@ -17,8 +17,9 @@ export const useBcrosNavigate = () => { // common redirects function goToBcrosHome () { redirect(config.public.registryHomeURL) } function goToBcrosLogin (idpHint: string) { - /** Redirect to bcros login page given the login type. */ - window.location.assign(`${config.public.registryHomeURL}signin/${idpHint}`) + // using current window location as redirect for now + // TODO: TC - review this once test deploy for redirects is complete + window.location.assign(`${config.public.authWebURL}signin/${idpHint}/${window.location.href}`) } function goToEditProfile () { redirect(config.public.authWebURL + 'userprofile') } function goToAccountInfo () { diff --git a/strr-web/enums/route-name-e.ts b/strr-web/enums/route-name-e.ts new file mode 100644 index 00000000..f3d3d160 --- /dev/null +++ b/strr-web/enums/route-name-e.ts @@ -0,0 +1,5 @@ +export enum RouteNameE { + BEN_OWNR_CHNG = 'beneficial-owner-change', + MY_REG_DETAILS = 'my-registries-details', + REVIEW_CONFIRM = 'review-confirm' +} diff --git a/strr-web/interfaces/account-i.ts b/strr-web/interfaces/account-i.ts index be446a55..d9b8e8fe 100644 --- a/strr-web/interfaces/account-i.ts +++ b/strr-web/interfaces/account-i.ts @@ -11,4 +11,14 @@ export interface AccountI { type: UserSettingsTypeE.ACCOUNT urlpath: string urlorigin: string + mailingAddress?: AddressI +} + +export interface AddressI { + city: string + country: string + postalCode: string + region: string + street: string + streetAdditional: string } diff --git a/strr-web/interfaces/header-menu-item-i.ts b/strr-web/interfaces/header-menu-item-i.ts new file mode 100644 index 00000000..66455cb9 --- /dev/null +++ b/strr-web/interfaces/header-menu-item-i.ts @@ -0,0 +1,7 @@ +export interface HeaderMenuItemI { + label: string, + action?: () => any + args?: any + icon?: string + setActive?: boolean +} diff --git a/strr-web/interfaces/user-settings-i.ts b/strr-web/interfaces/user-settings-i.ts new file mode 100644 index 00000000..a2b78439 --- /dev/null +++ b/strr-web/interfaces/user-settings-i.ts @@ -0,0 +1,14 @@ +import { AccountTypeE } from '~/enums/account-type-e' +import { AccountStatusE } from '~/enums/account-status-e' +import { UserSettingsTypeE } from '~/enums/user-settings-type-e' + +export interface UserSettingsI { + id: string + type: UserSettingsTypeE + urlpath: string + urlorigin: string + accountType?: AccountTypeE + accountStatus?: AccountStatusE + additionalLabel?: string + label?: string +} diff --git a/strr-web/lang/en.json b/strr-web/lang/en.json index fb06529c..0d66deae 100644 --- a/strr-web/lang/en.json +++ b/strr-web/lang/en.json @@ -3,6 +3,21 @@ "title": "STRR", "buttons": { "createAccount": "Create Account" + }, + "menus": { + "headers": { + "accountSettings": "Account Settings", + "selectLogin": "Select log in method", + "switchAccount": "Switch Account" + }, + "labels": { + "accountInfo": "Account Info", + "createAccount": "Create Account", + "editProfile": "Edit Profile", + "logOut": "Log Out", + "teamMembers": "Team Members", + "transactions": "Transactions" + } } }, "footer": { @@ -13,5 +28,12 @@ "accessibility": "Accessibility", "copyright": "Copyright" } + }, + "labels": { + "services": { + "bcsc": "BC Services Card", + "bceid": "BCeID", + "idir": "IDIR" + } } } diff --git a/strr-web/layouts/default.vue b/strr-web/layouts/default.vue index e8ae59fa..92cc6f31 100644 --- a/strr-web/layouts/default.vue +++ b/strr-web/layouts/default.vue @@ -1,8 +1,9 @@ diff --git a/strr-web/middleware/setupAuth.global.ts b/strr-web/middleware/setupAuth.global.ts new file mode 100644 index 00000000..62682461 --- /dev/null +++ b/strr-web/middleware/setupAuth.global.ts @@ -0,0 +1,42 @@ +export default defineNuxtRouteMiddleware(async (to) => { + // setup auth + if ((!to.query.error) && !process.env.VITEST_WORKER_ID) { + // keycloak redirects with the error param when not logged in (nuxt/keycloak issue) + // - removing ^ condition will cause an infinite loop of keycloak redirects when not authenticated + const { kcURL, kcRealm, kcClient } = useRuntimeConfig().public + await useBcrosAuth().setupAuth( + { url: kcURL, realm: kcRealm, clientId: kcClient }, + to.params.currentAccountId as string || to.query.currentAccountId as string + ) + + // if (process.client && sessionStorage?.getItem('FAKE_LOGIN')) { + // const { kc } = useBcrosKeycloak() + // // set test kc values + // kc.tokenParsed = { + // firstname: 'TestFirst', + // lastname: 'TestLast', + // name: 'TestFirst TestLast', + // username: 'testUsername', + // email: 'testEmail@test.com', + // sub: 'testSub', + // loginSource: 'IDIR', + // realm_access: { roles: ['basic'] } + // } + // kc.authenticated = true + // const account = useBcrosAccount() + // await account.setUserName() + // await account.setAccountInfo() + // } + } + // // initialize ldarkly + // useBcrosLaunchdarkly().init() + // remove query params in url added by keycloak + if (to.query) { + const params = new URLSearchParams(to.fullPath.split('?')[1]) + params.delete('state') + params.delete('session_state') + params.delete('code') + params.delete('error') + to.fullPath = to.path + (params.size > 0 ? `?${params}` : '') + to.hash + } +}) diff --git a/strr-web/nuxt.config.ts b/strr-web/nuxt.config.ts index 8514e8cc..47f4cce8 100644 --- a/strr-web/nuxt.config.ts +++ b/strr-web/nuxt.config.ts @@ -59,7 +59,8 @@ export default defineNuxtConfig({ payApiURL: `${process.env.VUE_APP_PAY_API_URL || ''}${process.env.VUE_APP_PAY_API_VERSION || ''}`, btrApiURL: `${process.env.VUE_APP_BTR_API_URL || ''}${process.env.VUE_APP_BTR_API_VERSION || ''}`, registryHomeURL: process.env.VUE_APP_REGISTRY_HOME_URL || '', - appEnv: `${process.env.VUE_APP_POD_NAMESPACE || 'unknown'}` + appEnv: `${process.env.VUE_APP_POD_NAMESPACE || 'unknown'}`, + version: `0.1.0`, } }, css: ['~/./assets/scss/global.scss'], diff --git a/strr-web/pages/accountselect.vue b/strr-web/pages/accountselect.vue new file mode 100644 index 00000000..37791d3a --- /dev/null +++ b/strr-web/pages/accountselect.vue @@ -0,0 +1,34 @@ + + + diff --git a/strr-web/pages/index.vue b/strr-web/pages/index.vue index 04cf6292..71375f7a 100644 --- a/strr-web/pages/index.vue +++ b/strr-web/pages/index.vue @@ -1,6 +1,7 @@ + + diff --git a/strr-web/stores/account.ts b/strr-web/stores/account.ts index a5d7e0f8..b735919a 100644 --- a/strr-web/stores/account.ts +++ b/strr-web/stores/account.ts @@ -69,6 +69,26 @@ export const useBcrosAccount = defineStore('bcros/account', () => { userLastName.value = user.value?.lastName || '' } + /** Get details for an account (org) */ + async function getAccountDetails (orgId: string) { + const apiURL = useRuntimeConfig().public.authApiURL + return await axios.get(`${apiURL}/orgs/${orgId}`) + .then((response) => { + const data = response?.data + if (!data) { throw new Error('Invalid AUTH API response') } + return data + }) + .catch((error) => { + console.warn('Error fetching user account details.') + // TODO: TC - add error handling + errors.value.push({ + statusCode: error?.response?.status || StatusCodes.INTERNAL_SERVER_ERROR, + message: error?.response?.data?.message, + category: ErrorCategoryE.ACCOUNT_LIST + }) + }) + } + /** Get the user's account list */ async function getUserAccounts (keycloakGuid: string) { const apiURL = useRuntimeConfig().public.authApiURL @@ -96,6 +116,7 @@ export const useBcrosAccount = defineStore('bcros/account', () => { } if (user.value?.keycloakGuid) { userAccounts.value = await getUserAccounts(user.value?.keycloakGuid) || [] + if (userAccounts && userAccounts.value.length > 0) { currentAccount.value = userAccounts.value[0] if (currentAccountId) { @@ -104,6 +125,16 @@ export const useBcrosAccount = defineStore('bcros/account', () => { } sessionStorage.setItem(SessionStorageKeyE.CURRENT_ACCOUNT, JSON.stringify(currentAccount.value)) } + + // TODO: TC - loading mail addresses into the store here + // Is there a better endpoint to use for this, or should we build our own into API instead + + userAccounts.value.forEach(async (account) => { + const details = await getAccountDetails(account.id) + if (details) { + account.mailingAddress = details.mailingAddress + } + }) } } diff --git a/strr-web/stores/keycloak.ts b/strr-web/stores/keycloak.ts index 6937a557..20667c27 100644 --- a/strr-web/stores/keycloak.ts +++ b/strr-web/stores/keycloak.ts @@ -38,6 +38,8 @@ export const useBcrosKeycloak = defineStore('bcros/keycloak', () => { sessionStorage.removeItem(SessionStorageKeyE.KEYCLOAK_TOKEN_REFRESH) sessionStorage.removeItem(SessionStorageKeyE.KEYCLOAK_TOKEN_ID) sessionStorage.removeItem(SessionStorageKeyE.KEYCLOAK_SYNCED) + // TODO: TC - investigate if this fix for "not quite logged out redirect issue" + sessionStorage.removeItem(SessionStorageKeyE.CURRENT_ACCOUNT) } function syncSessionStorage () {