From 7b0a1fda03513a5745b965ae1810a55a40d2bf0c Mon Sep 17 00:00:00 2001 From: deetz99 <dietrich@wolpert.ca> Date: Thu, 16 Jan 2025 14:33:14 -0800 Subject: [PATCH] simplify expansion handling --- strr-base-web/app/app.vue | 9 +++ .../app/components/connect/ExpansionRoot.vue | 20 ++++++ .../app/composables/useStrrExpansion.ts | 63 ++++++++++++++++++ strr-base-web/app/types/strr-expansion.ts | 13 ++++ .../app/components/Host/SubHeader.vue | 17 +++-- .../app/components/NavigationTabs.vue | 65 ------------------- .../app/composables/useHostExpansion.ts | 30 +++++++++ .../app/pages/examine/[applicationId].vue | 23 +++---- .../app/types/host-details-display-item.ts | 1 - strr-examiner-web/package.json | 2 +- 10 files changed, 159 insertions(+), 84 deletions(-) create mode 100644 strr-base-web/app/components/connect/ExpansionRoot.vue create mode 100644 strr-base-web/app/composables/useStrrExpansion.ts create mode 100644 strr-base-web/app/types/strr-expansion.ts delete mode 100644 strr-examiner-web/app/components/NavigationTabs.vue create mode 100644 strr-examiner-web/app/composables/useHostExpansion.ts delete mode 100644 strr-examiner-web/app/types/host-details-display-item.ts diff --git a/strr-base-web/app/app.vue b/strr-base-web/app/app.vue index 892e9a40..b38189ef 100644 --- a/strr-base-web/app/app.vue +++ b/strr-base-web/app/app.vue @@ -1,4 +1,6 @@ <script setup lang="ts"> +import { expansionInjectionKey } from '~/composables/useStrrExpansion' + const i18nHead = useLocaleHead({ addDirAttribute: true, addSeoAttributes: true @@ -12,6 +14,13 @@ useHead({ } }) +// provide initial expansion state +const initialExpansionState = shallowRef<ExpansionState>({ + component: 'div', + props: {} +}) +provide(expansionInjectionKey, initialExpansionState) + onMounted(async () => { const msgConfig = useAppConfig().strrBaseLayer.sbcWebMsg diff --git a/strr-base-web/app/components/connect/ExpansionRoot.vue b/strr-base-web/app/components/connect/ExpansionRoot.vue new file mode 100644 index 00000000..a18bf128 --- /dev/null +++ b/strr-base-web/app/components/connect/ExpansionRoot.vue @@ -0,0 +1,20 @@ +<script lang="ts" setup> +import { useStrrExpansion, expansionInjectionKey } from '~/composables/useStrrExpansion' + +const expansionState = inject(expansionInjectionKey) + +const { isExpanded } = useStrrExpansion() + +// This will currently only work with 1 component instance at a time (per page) +</script> +<template> + <ConnectTransitionCollapse> + <div v-if="isExpanded"> + <component + :is="expansionState.component" + v-if="expansionState" + v-bind="expansionState.props" + /> + </div> + </ConnectTransitionCollapse> +</template> diff --git a/strr-base-web/app/composables/useStrrExpansion.ts b/strr-base-web/app/composables/useStrrExpansion.ts new file mode 100644 index 00000000..4dee6424 --- /dev/null +++ b/strr-base-web/app/composables/useStrrExpansion.ts @@ -0,0 +1,63 @@ +import type { ShallowRef, Component } from 'vue' +import { createSharedComposable } from '@vueuse/core' +import type { ExpansionState, Expansion, ComponentProps } from '~/types/strr-expansion' + +export const expansionInjectionKey: InjectionKey<ShallowRef<ExpansionState>> = Symbol('strr-examiner-expansion') + +function _useExpansion () { + const expansionState = inject(expansionInjectionKey) + + const isExpanded = ref(false) + + function open<T extends Component> (component: T, props?: Expansion & ComponentProps<T>) { + if (!expansionState) { + throw new Error('useExpansion() is called without provider') + } + // Set the shared expansion state + expansionState.value = { + component, + props: props ?? {} + } + isExpanded.value = true + } + + function close () { + if (!expansionState?.value) { return } + + isExpanded.value = false + reset() + } + + function reset () { + if (!expansionState?.value) { return } + + expansionState.value = { + component: 'div', + props: {} as Expansion & ComponentProps<any> + } + } + + // TODO: implement ? + /** + * Update the expansion props partially. + */ + // function patch<T extends Component = {}>(props: Partial<Expansion & ComponentProps<T>>) { + // expansionState.value = { + // ...expansionState.value, + // props: { + // ...expansionState.value.props, + // ...props + // } + // } + // } + + return { + open, + close, + reset, + // patch, + isExpanded + } +} + +export const useStrrExpansion = createSharedComposable(_useExpansion) diff --git a/strr-base-web/app/types/strr-expansion.ts b/strr-base-web/app/types/strr-expansion.ts new file mode 100644 index 00000000..ef9ad2fe --- /dev/null +++ b/strr-base-web/app/types/strr-expansion.ts @@ -0,0 +1,13 @@ +export type ComponentProps<T> = +T extends new () => { $props: infer P } ? NonNullable<P> : + T extends (props: infer P, ...args: any) => any ? P : + {} + +export interface Expansion { + onClose?: () => void +} + +export interface ExpansionState { + component: Component | string + props: Expansion +} diff --git a/strr-examiner-web/app/components/Host/SubHeader.vue b/strr-examiner-web/app/components/Host/SubHeader.vue index 3ea7151c..c2217fef 100644 --- a/strr-examiner-web/app/components/Host/SubHeader.vue +++ b/strr-examiner-web/app/components/Host/SubHeader.vue @@ -1,11 +1,13 @@ <script setup lang="ts"> const props = defineProps<{ application: HostApplicationResp }>() const reg = props.application.registration -defineEmits<{ - openExpansion: [OpenExpansionEvent] -}>() +// defineEmits<{ +// openExpansion: [OpenExpansionEvent] +// }>() const { t } = useI18n() + +const hostExp = useHostExpansion() </script> <template> <div class="app-inner-container"> @@ -34,8 +36,9 @@ const { t } = useI18n() :label="displayContactFullName(reg.primaryContact!)" :padded="false" variant="link" - @click="$emit('openExpansion', [ExpansionItem.HOST_OWNERS, { display: 'primaryContact' }])" + @click="hostExp.openHostOwners(application, 'primaryContact')" /> + <!-- @click="$emit('openExpansion', [ExpansionItem.HOST_OWNERS, { display: 'primaryContact' }])" --> </div> <div> <UIcon name="i-mdi-at" /> @@ -84,8 +87,9 @@ const { t } = useI18n() : reg?.secondaryContact?.businessLegalName" :padded="false" variant="link" - @click="$emit('openExpansion', [ExpansionItem.HOST_OWNERS, { display: 'secondaryContact' }])" + @click="hostExp.openHostOwners(application, 'secondaryContact')" /> + <!-- @click="$emit('openExpansion', [ExpansionItem.HOST_OWNERS, { display: 'secondaryContact' }])" --> </div> <div v-if="reg?.propertyManager?.propertyManagerType" class="flex items-center gap-1"> @@ -96,8 +100,9 @@ const { t } = useI18n() : reg?.propertyManager?.business?.legalName" :padded="false" variant="link" - @click="$emit('openExpansion', [ExpansionItem.HOST_OWNERS, { display: 'propertyManager' }])" + @click="hostExp.openHostOwners(application, 'propertyManager')" /> + <!-- @click="$emit('openExpansion', [ExpansionItem.HOST_OWNERS, { display: 'propertyManager' }])" --> </div> </div> </div> diff --git a/strr-examiner-web/app/components/NavigationTabs.vue b/strr-examiner-web/app/components/NavigationTabs.vue deleted file mode 100644 index 0d8dd7f5..00000000 --- a/strr-examiner-web/app/components/NavigationTabs.vue +++ /dev/null @@ -1,65 +0,0 @@ -<script setup lang="ts"> -import { RoutesE } from '~/enums/routes' - -const { isAuthenticated } = useKeycloak() - -const localePath = useLocalePath() -const { loading } = storeToRefs(useConnectDetailsHeaderStore()) -const { getNextApplication } = useExaminerStore() -const route = useRoute() - -const activeTab = computed(() => route.path.includes(RoutesE.EXAMINE) ? 0 : 1) - -async function onChange (index: number) { - loading.value = true - const item = items[index] - - let navigateToPath = item.path as string - - if (item.path.includes(RoutesE.EXAMINE)) { - const nextApp = await getNextApplication() - navigateToPath = `${item?.path}/${nextApp}` - } - - return navigateTo(localePath(navigateToPath)) -} - -const items = [ - { - key: 'examine', - label: 'Examine', - path: RoutesE.EXAMINE - }, - { - key: 'dashboard', - label: 'Search', - path: RoutesE.DASHBOARD - }] - -</script> - -<template> - <UTabs - v-if="isAuthenticated" - :items="items" - :ui="{ - wrapper: 'relative h-full space-y-0', - list: { - background: '', - marker: { - background: '' - }, - tab: { - background: 'bg-transparent', - active: 'text-white bg-transparent underline underline-offset-4 font-semibold', - } - } - }" - :model-value="activeTab" - @change="onChange" - /> -</template> - -<style scoped> - -</style> diff --git a/strr-examiner-web/app/composables/useHostExpansion.ts b/strr-examiner-web/app/composables/useHostExpansion.ts new file mode 100644 index 00000000..1b3b4eb8 --- /dev/null +++ b/strr-examiner-web/app/composables/useHostExpansion.ts @@ -0,0 +1,30 @@ +// https://ui.nuxt.com/components/modal#control-programmatically +import { + HostExpansionOwners +} from '#components' + +export const useHostExpansion = () => { + const exp = useStrrExpansion() + + function openHostOwners ( + application: HostApplicationResp, + display: 'primaryContact' | 'secondaryContact' | 'propertyManager' + ) { + exp.open(HostExpansionOwners, { + application, + display, + onClose () { + exp.close() + } + }) + } + + function close () { + exp.close() + } + + return { + openHostOwners, + close + } +} diff --git a/strr-examiner-web/app/pages/examine/[applicationId].vue b/strr-examiner-web/app/pages/examine/[applicationId].vue index 6bf40af0..4f22b148 100644 --- a/strr-examiner-web/app/pages/examine/[applicationId].vue +++ b/strr-examiner-web/app/pages/examine/[applicationId].vue @@ -17,15 +17,15 @@ definePageMeta({ }) const initialMount = ref(true) // flag for whether to fetch next or specific application on mount - true until initial application is loaded -const showExpansion = ref<boolean>(false) // show/hide expansion items -const expansionItem = ref<ExpansionItem | undefined>(undefined) // expansion component to display -const expansionProps: Ref<Record<string, unknown>> = ref({}) // any props passed to expansion components +// const showExpansion = ref<boolean>(false) // show/hide expansion items +// const expansionItem = ref<ExpansionItem | undefined>(undefined) // expansion component to display +// const expansionProps: Ref<Record<string, unknown>> = ref({}) // any props passed to expansion components -const manageExpansion = (e: OpenExpansionEvent) => { - expansionItem.value = e[0] // set expansion component to open - expansionProps.value = e[1] // bind any custom props - showExpansion.value = true -} +// const manageExpansion = (e: OpenExpansionEvent) => { +// expansionItem.value = e[0] // set expansion component to open +// expansionProps.value = e[1] // bind any custom props +// showExpansion.value = true +// } // TODO: fix typing const { data, status, error, refresh } = await useAsyncData<HousApplicationResponse>( @@ -123,18 +123,19 @@ watch( <HostSubHeader v-if="application?.registration.registrationType === ApplicationType.HOST" :application - @open-expansion="manageExpansion" /> + <!-- @open-expansion="manageExpansion" --> </div> <div class="app-inner-container space-y-10 py-10"> - <ExpansionContainer + <ConnectExpansionRoot /> + <!-- <ExpansionContainer v-model="showExpansion" v-bind="expansionProps" :application :expansion-item="expansionItem" @close="showExpansion = false" - /> + /> --> <!-- TODO: other supporting info --> <HostSupportingInfo diff --git a/strr-examiner-web/app/types/host-details-display-item.ts b/strr-examiner-web/app/types/host-details-display-item.ts deleted file mode 100644 index f4a4fe76..00000000 --- a/strr-examiner-web/app/types/host-details-display-item.ts +++ /dev/null @@ -1 +0,0 @@ -export type HostDetailsDisplayItem = 'primaryContact' | 'secondaryContact' | 'propertyManager' | undefined diff --git a/strr-examiner-web/package.json b/strr-examiner-web/package.json index 3cea2535..c297319f 100644 --- a/strr-examiner-web/package.json +++ b/strr-examiner-web/package.json @@ -2,7 +2,7 @@ "name": "strr-examiner-web", "private": true, "type": "module", - "version": "0.0.8", + "version": "0.0.9", "scripts": { "build-check": "nuxt build", "build": "nuxt generate",