From 076d837e3b5959ee104e1bc37026a7fd6a82dfcc Mon Sep 17 00:00:00 2001 From: WANJIN Date: Mon, 2 Dec 2024 22:39:12 +0900 Subject: [PATCH] feat: add confirm-route-leave composable (#5121) * refactor(go-back): use vue-router's useRouter for navigation Signed-off-by: Wanjin Noh * feat(confirm-back-modal): add close and cancel events to ConfirmBackModal and DeleteModal Signed-off-by: Wanjin Noh * feat: add confirm route leave composable for navigation confirmation Signed-off-by: Wanjin Noh * feat(confirm-route-leave): enhance confirmation modal functionality and naming Signed-off-by: Wanjin Noh * feat(field-group): add no-spacing prop to PFieldGroup component Signed-off-by: Wanjin Noh * feat: add loading spinner component for navigation module Signed-off-by: Wanjin Noh * feat(field-group): remove no-spacing class and adjust spacing styles Signed-off-by: Wanjin Noh * feat(badge): add new subtle styles for peacock, coral, and red colors Signed-off-by: Wanjin Noh * feat(go-back): replace useRouter with SpaceRouter for navigation handling Signed-off-by: Wanjin Noh * feat: update route handling to use SpaceRouter instead of useRouter Signed-off-by: Wanjin Noh --------- Signed-off-by: Wanjin Noh --- .../components/modals/ConfirmBackModal.vue | 8 ++- .../common/components/modals/DeleteModal.vue | 5 ++ .../composables/confirm-route-leave/index.ts | 52 +++++++++++++++++++ .../src/common/composables/go-back/index.ts | 2 + .../navigations/new-lsb/LSBLoadingSpinner.vue | 19 +++++++ .../forms/field-group/PFieldGroup.mdx | 5 ++ .../forms/field-group/PFieldGroup.stories.ts | 27 ++++++++++ .../forms/field-group/PFieldGroup.vue | 32 +++++++++++- .../forms/field-group/story-helper.ts | 16 ++++++ .../mirinae/src/data-display/badge/PBadge.vue | 3 ++ .../mirinae/src/data-display/badge/type.ts | 3 ++ 11 files changed, 169 insertions(+), 3 deletions(-) create mode 100644 apps/web/src/common/composables/confirm-route-leave/index.ts create mode 100644 apps/web/src/common/modules/navigations/new-lsb/LSBLoadingSpinner.vue diff --git a/apps/web/src/common/components/modals/ConfirmBackModal.vue b/apps/web/src/common/components/modals/ConfirmBackModal.vue index 9cd8a13918..e828325966 100644 --- a/apps/web/src/common/components/modals/ConfirmBackModal.vue +++ b/apps/web/src/common/components/modals/ConfirmBackModal.vue @@ -2,10 +2,13 @@ import DeleteModal from '@/common/components/modals/DeleteModal.vue'; const props = defineProps<{ - visible: boolean + visible: boolean; + hideCloseButton?: boolean; }>(); const emit = defineEmits<{(e: 'update:visible', value: boolean): void; (e: 'confirm'): void; + (e: 'close'): void; + (e: 'cancel'): void; }>(); const handleClickConfirm = () => { emit('update:visible', false); @@ -18,7 +21,10 @@ const handleClickConfirm = () => { :header-title="$t('COMMON.CONFIRM_BACK_MODAL.TITLE')" :visible="props.visible" :contents="$t('COMMON.CONFIRM_BACK_MODAL.CANNOT_CANCEL')" + :hide-close-button="props.hideCloseButton" @update:visible="emit('update:visible', $event)" @confirm="handleClickConfirm" + @close="emit('close')" + @cancel="emit('cancel')" /> diff --git a/apps/web/src/common/components/modals/DeleteModal.vue b/apps/web/src/common/components/modals/DeleteModal.vue index 6ae4cee969..607ee52c05 100644 --- a/apps/web/src/common/components/modals/DeleteModal.vue +++ b/apps/web/src/common/components/modals/DeleteModal.vue @@ -9,6 +9,7 @@ :hide-footer="hideFooter" theme-color="alert" :loading="loading" + :hide-header-close-button="hideCloseButton" @confirm="handleConfirm" @close="$emit('close')" @cancel="$emit('cancel')" @@ -96,6 +97,10 @@ export default { type: Boolean, default: false, }, + hideCloseButton: { + type: Boolean, + default: false, + }, }, setup(props, { emit }: SetupContext) { const state = reactive({ diff --git a/apps/web/src/common/composables/confirm-route-leave/index.ts b/apps/web/src/common/composables/confirm-route-leave/index.ts new file mode 100644 index 0000000000..eddaa49985 --- /dev/null +++ b/apps/web/src/common/composables/confirm-route-leave/index.ts @@ -0,0 +1,52 @@ +import type { Ref } from 'vue'; +import { + ref, readonly, +} from 'vue'; +import type { Location } from 'vue-router'; + +// CAUTION: Do not change to useRouter() because useRouter is only available in script setup +import { SpaceRouter } from '@/router'; + +export const useConfirmRouteLeave = ({ + passConfirmation, +}: { + passConfirmation?: Ref +} = {}) => { + const isConfirmLeaveModalVisible = ref(false); + const isConfirmed = ref(false); + let nextRoute: Location|undefined; + + const openConfirmBackModal = () => { + isConfirmLeaveModalVisible.value = true; + }; + const confirmRouteLeave = () => { + isConfirmed.value = true; + isConfirmLeaveModalVisible.value = false; + if (nextRoute) SpaceRouter.router.push(nextRoute); + }; + const stopRouteLeave = () => { + isConfirmLeaveModalVisible.value = false; + nextRoute = undefined; + }; + + const handleBeforeRouteLeave = (to, from, next) => { + if (passConfirmation?.value) { + next(); + return; + } + if (!isConfirmed.value) { + nextRoute = to; + openConfirmBackModal(); + next(false); + } else { + next(); + } + }; + + return { + isConfirmLeaveModalVisible: readonly(isConfirmLeaveModalVisible), + confirmRouteLeave, + stopRouteLeave, + handleBeforeRouteLeave, + }; +}; diff --git a/apps/web/src/common/composables/go-back/index.ts b/apps/web/src/common/composables/go-back/index.ts index 6388aa9751..56e69aaf19 100644 --- a/apps/web/src/common/composables/go-back/index.ts +++ b/apps/web/src/common/composables/go-back/index.ts @@ -1,5 +1,6 @@ import type { Location } from 'vue-router'; +// CAUTION: Do not change to useRouter() because useRouter is only available in script setup import { SpaceRouter } from '@/router'; export const useGoBack = (mainRoute: Location) => { @@ -21,5 +22,6 @@ export const useGoBack = (mainRoute: Location) => { return { setPathFrom, handleClickBackButton, + goBack: handleClickBackButton, }; }; diff --git a/apps/web/src/common/modules/navigations/new-lsb/LSBLoadingSpinner.vue b/apps/web/src/common/modules/navigations/new-lsb/LSBLoadingSpinner.vue new file mode 100644 index 0000000000..a6c860c0ae --- /dev/null +++ b/apps/web/src/common/modules/navigations/new-lsb/LSBLoadingSpinner.vue @@ -0,0 +1,19 @@ + + + diff --git a/packages/mirinae/src/controls/forms/field-group/PFieldGroup.mdx b/packages/mirinae/src/controls/forms/field-group/PFieldGroup.mdx index 832b43cf7d..a1443f8223 100644 --- a/packages/mirinae/src/controls/forms/field-group/PFieldGroup.mdx +++ b/packages/mirinae/src/controls/forms/field-group/PFieldGroup.mdx @@ -37,6 +37,11 @@ import * as PFieldGroupStories from './PFieldGroup.stories';
+## No Spacing + + +
+ ## Playground diff --git a/packages/mirinae/src/controls/forms/field-group/PFieldGroup.stories.ts b/packages/mirinae/src/controls/forms/field-group/PFieldGroup.stories.ts index 47c949af0a..36303a8ad4 100644 --- a/packages/mirinae/src/controls/forms/field-group/PFieldGroup.stories.ts +++ b/packages/mirinae/src/controls/forms/field-group/PFieldGroup.stories.ts @@ -38,6 +38,7 @@ const Template: Story = { :help-text="helpText" :required="required" :label="label" :style-type="styleType" + :no-spacing="noSpacing" >