Skip to content

Commit

Permalink
feat: add confirm-route-leave composable (#5121)
Browse files Browse the repository at this point in the history
* refactor(go-back): use vue-router's useRouter for navigation

Signed-off-by: Wanjin Noh <[email protected]>

* feat(confirm-back-modal): add close and cancel events to ConfirmBackModal and DeleteModal

Signed-off-by: Wanjin Noh <[email protected]>

* feat: add confirm route leave composable for navigation confirmation

Signed-off-by: Wanjin Noh <[email protected]>

* feat(confirm-route-leave): enhance confirmation modal functionality and naming

Signed-off-by: Wanjin Noh <[email protected]>

* feat(field-group): add no-spacing prop to PFieldGroup component

Signed-off-by: Wanjin Noh <[email protected]>

* feat: add loading spinner component for navigation module

Signed-off-by: Wanjin Noh <[email protected]>

* feat(field-group): remove no-spacing class and adjust spacing styles

Signed-off-by: Wanjin Noh <[email protected]>

* feat(badge): add new subtle styles for peacock, coral, and red colors

Signed-off-by: Wanjin Noh <[email protected]>

* feat(go-back): replace useRouter with SpaceRouter for navigation handling

Signed-off-by: Wanjin Noh <[email protected]>

* feat: update route handling to use SpaceRouter instead of useRouter

Signed-off-by: Wanjin Noh <[email protected]>

---------

Signed-off-by: Wanjin Noh <[email protected]>
  • Loading branch information
WANZARGEN authored Dec 2, 2024
1 parent 462d92c commit 076d837
Show file tree
Hide file tree
Showing 11 changed files with 169 additions and 3 deletions.
8 changes: 7 additions & 1 deletion apps/web/src/common/components/modals/ConfirmBackModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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')"
/>
</template>
5 changes: 5 additions & 0 deletions apps/web/src/common/components/modals/DeleteModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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')"
Expand Down Expand Up @@ -96,6 +97,10 @@ export default {
type: Boolean,
default: false,
},
hideCloseButton: {
type: Boolean,
default: false,
},
},
setup(props, { emit }: SetupContext) {
const state = reactive({
Expand Down
52 changes: 52 additions & 0 deletions apps/web/src/common/composables/confirm-route-leave/index.ts
Original file line number Diff line number Diff line change
@@ -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<boolean>
} = {}) => {
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,
};
};
2 changes: 2 additions & 0 deletions apps/web/src/common/composables/go-back/index.ts
Original file line number Diff line number Diff line change
@@ -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) => {
Expand All @@ -21,5 +22,6 @@ export const useGoBack = (mainRoute: Location) => {
return {
setPathFrom,
handleClickBackButton,
goBack: handleClickBackButton,
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<script setup lang="ts">
import {
PSpinner,
} from '@cloudforet/mirinae';
const props = defineProps<{
loading: boolean;
}>();
</script>

<template>
<div class="relative">
<div v-show="props.loading"
class="absolute flex flex-col px-4 w-full"
>
<p-spinner size="md" />
</div>
</div>
</template>
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ import * as PFieldGroupStories from './PFieldGroup.stories';

<br/>

## No Spacing
<Canvas of={PFieldGroupStories.NoSpacing} />

<br/>

## Playground
<Canvas of={PFieldGroupStories.Playground} />
<Controls of={PFieldGroupStories.Playground} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ const Template: Story = {
:help-text="helpText" :required="required"
:label="label"
:style-type="styleType"
:no-spacing="noSpacing"
>
<template v-if="labelSlot" #label>
<div v-html="labelSlot"/>
Expand Down Expand Up @@ -135,6 +136,32 @@ export const StyleType: Story = {
}),
};

export const NoSpacing: Story = {
render: () => ({
components: { PFieldGroup, PTextInput },
template: `
<div>
<p-field-group label="Primary" style-type="primary" no-spacing>
<p-text-input value="Wanjin"/>
</p-field-group>
<br/>
<p-field-group label="Secondary" style-type="secondary" no-spacing>
<p-text-input value="Wanjin"/>
</p-field-group>
<br/>
<p-field-group label="Invalid Text" invalid invalid-text="name is required field." no-spacing>
<p-text-input placeholder="Name" invalid value=""/>
</p-field-group>
<br/>
<p-field-group label="Valid Text" valid valid-text="this is an appropriate name." no-spacing>
<p-text-input placeholder="Name" value="Wanjin"/>
</p-field-group>
<br/>
</div>
`,
}),
};

export const Playground: Story = {
...Template,
};
32 changes: 30 additions & 2 deletions packages/mirinae/src/controls/forms/field-group/PFieldGroup.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<div class="p-field-group"
:class="[styleType]"
:class="{[styleType]: true, 'no-spacing': noSpacing}"
>
<div class="field-title-box">
<p-field-title v-if="label || $scopedSlots.label"
Expand Down Expand Up @@ -61,6 +61,7 @@ interface Props {
valid?: boolean;
required?: boolean;
styleType?: FieldGroupStyleType;
noSpacing?: boolean;
}
export default defineComponent<Props>({
Expand Down Expand Up @@ -99,6 +100,10 @@ export default defineComponent<Props>({
type: String,
default: 'primary',
},
noSpacing: {
type: Boolean,
default: false,
},
},
});
</script>
Expand All @@ -124,8 +129,8 @@ export default defineComponent<Props>({
font-size: 0.75rem;
line-height: 1.4;
margin-left: 0.25rem;
margin-bottom: 0.25rem;
font-weight: normal;
margin-bottom: 0.25rem;
}
.help-msg {
@apply block mb-2;
Expand All @@ -148,6 +153,29 @@ export default defineComponent<Props>({
.is-invalid {
@apply border border-alert;
}
&.no-spacing {
&.primary {
margin-bottom: 0;
}
&.secondary {
margin-bottom: 0;
}
.form-label {
padding-bottom: 0;
}
.optional-mark {
margin-bottom: 0;
}
.help-msg {
margin-bottom: 0;
}
.invalid-feedback {
margin-top: 0;
}
.valid-feedback {
margin-top: 0;
}
}
}
</style>
16 changes: 16 additions & 0 deletions packages/mirinae/src/controls/forms/field-group/story-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export const getPFieldGroupArgs = (): Args => ({
valid: false,
required: false,
styleType: 'primary',
noSpacing: false,
labelSlot: null,
labelExtraSlot: null,
validSlot: null,
Expand Down Expand Up @@ -147,6 +148,21 @@ export const getPFieldGroupArgTypes = (): ArgTypes => ({
control: 'select',
options: ['primary', 'secondary'],
},
noSpacing: {
name: 'noSpacing',
type: { name: 'boolean' },
description: 'Props for hide spacing',
table: {
type: {
summary: 'boolean',
},
category: 'props',
defaultValue: {
summary: false,
},
},
control: 'boolean',
},
labelSlot: {
name: 'label',
description: 'Slot for label',
Expand Down
3 changes: 3 additions & 0 deletions packages/mirinae/src/data-display/badge/PBadge.vue
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@ const state = reactive({
@mixin subtle gray200, theme('colors.gray.200'), theme('colors.gray.900');
@mixin subtle yellow200, theme('colors.yellow.200'), theme('colors.gray.900');
@mixin subtle red100, theme('colors.red.100'), theme('colors.red.500');
@mixin subtle peacock200, theme('colors.peacock.200'), theme('colors.peacock.700');
@mixin subtle coral200, theme('colors.coral.200'), theme('colors.coral.700');
@mixin subtle red200, theme('colors.red.200'), theme('colors.red.700');
}
</style>
3 changes: 3 additions & 0 deletions packages/mirinae/src/data-display/badge/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ export const SUBTLE_STYLE_TYPE = {
gray200: 'gray200',
yellow200: 'yellow200',
red100: 'red100',
peacock200: 'peacock200',
coral200: 'coral200',
red200: 'red200',
} as const;
export const BADGE_STYLE_TYPE = {
...SOLID_STYLE_TYPE,
Expand Down

0 comments on commit 076d837

Please sign in to comment.