chore: Update cancel sub modal
This commit is contained in:
@@ -493,8 +493,7 @@
|
||||
"TITLE": "Cancel Subscription",
|
||||
"WARNING_TITLE": "Are you sure?",
|
||||
"WARNING_MESSAGE": "Cancelling your subscription will stop monthly credit renewals. Any remaining credits will still be available until used.",
|
||||
"REASON_LABEL": "Reason for cancellation",
|
||||
"OPTIONAL": "(optional)",
|
||||
"REASON_LABEL": "Reason for cancellation (optional)",
|
||||
"REASON_PLACEHOLDER": "Help us improve by sharing why you're cancelling...",
|
||||
"INFO": "You can resubscribe anytime to continue receiving monthly credits.",
|
||||
"KEEP_SUBSCRIPTION": "Keep Subscription",
|
||||
|
||||
+49
-67
@@ -1,94 +1,76 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import Modal from 'dashboard/components/Modal.vue';
|
||||
import ButtonV4 from 'next/button/Button.vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import Icon from 'dashboard/components-next/icon/Icon.vue';
|
||||
import Dialog from 'dashboard/components-next/dialog/Dialog.vue';
|
||||
import TextArea from 'dashboard/components-next/textarea/TextArea.vue';
|
||||
|
||||
const props = defineProps({
|
||||
defineProps({
|
||||
isCanceling: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['close', 'cancel']);
|
||||
const emit = defineEmits(['cancel']);
|
||||
|
||||
const show = ref(true);
|
||||
const { t } = useI18n();
|
||||
|
||||
const dialogRef = ref(null);
|
||||
const reason = ref('');
|
||||
|
||||
const handleCancel = () => {
|
||||
emit('cancel', reason.value);
|
||||
};
|
||||
|
||||
const close = () => {
|
||||
show.value = false;
|
||||
emit('close');
|
||||
};
|
||||
defineExpose({ dialogRef });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Modal v-model:show="show" :on-close="close">
|
||||
<div class="flex flex-col h-auto overflow-auto">
|
||||
<div class="w-full px-5 py-4 border-b border-n-weak">
|
||||
<h3 class="text-lg font-semibold text-n-800">
|
||||
{{ $t('BILLING_SETTINGS_V2.CANCEL_MODAL.TITLE') }}
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div class="p-5 space-y-4">
|
||||
<!-- Warning -->
|
||||
<div class="p-4 bg-r-50 rounded-lg">
|
||||
<div class="flex gap-3">
|
||||
<span
|
||||
class="i-lucide-alert-triangle text-r-700 flex-shrink-0 mt-0.5"
|
||||
/>
|
||||
<div>
|
||||
<h4 class="text-sm font-semibold text-r-800">
|
||||
{{ $t('BILLING_SETTINGS_V2.CANCEL_MODAL.WARNING_TITLE') }}
|
||||
</h4>
|
||||
<p class="mt-1 text-sm text-r-700">
|
||||
{{ $t('BILLING_SETTINGS_V2.CANCEL_MODAL.WARNING_MESSAGE') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Reason -->
|
||||
<div>
|
||||
<label class="block mb-2 text-sm font-medium text-n-700">
|
||||
{{ $t('BILLING_SETTINGS_V2.CANCEL_MODAL.REASON_LABEL') }}
|
||||
<span class="text-n-500">{{
|
||||
$t('BILLING_SETTINGS_V2.CANCEL_MODAL.OPTIONAL')
|
||||
}}</span>
|
||||
</label>
|
||||
<textarea
|
||||
v-model="reason"
|
||||
rows="4"
|
||||
class="w-full px-3 py-2 border border-n-weak rounded-lg focus:outline-none focus:ring-2 focus:ring-b-500 resize-none"
|
||||
:placeholder="
|
||||
$t('BILLING_SETTINGS_V2.CANCEL_MODAL.REASON_PLACEHOLDER')
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Info -->
|
||||
<div class="p-3 bg-n-25 rounded-lg">
|
||||
<div class="flex gap-2">
|
||||
<span class="i-lucide-info text-n-600 flex-shrink-0 mt-0.5" />
|
||||
<p class="text-xs text-n-700">
|
||||
{{ $t('BILLING_SETTINGS_V2.CANCEL_MODAL.INFO') }}
|
||||
<Dialog
|
||||
ref="dialogRef"
|
||||
type="alert"
|
||||
width="xl"
|
||||
:title="t('BILLING_SETTINGS_V2.CANCEL_MODAL.TITLE')"
|
||||
:confirm-button-label="t('BILLING_SETTINGS_V2.CANCEL_MODAL.CONFIRM_CANCEL')"
|
||||
:cancel-button-label="
|
||||
t('BILLING_SETTINGS_V2.CANCEL_MODAL.KEEP_SUBSCRIPTION')
|
||||
"
|
||||
:is-loading="isCanceling"
|
||||
@confirm="handleCancel"
|
||||
>
|
||||
<div class="space-y-4">
|
||||
<!-- Warning -->
|
||||
<div
|
||||
class="p-4 rounded-xl outline outline-1 outline-n-ruby-4 bg-n-ruby-3 text-n-ruby-11"
|
||||
>
|
||||
<div class="flex gap-3 items-start">
|
||||
<Icon icon="i-lucide-alert-triangle" class="flex-shrink-0 mt-0.5" />
|
||||
<div>
|
||||
<h4 class="text-sm font-semibold text-n-ruby-11">
|
||||
{{ t('BILLING_SETTINGS_V2.CANCEL_MODAL.WARNING_TITLE') }}
|
||||
</h4>
|
||||
<p class="mt-1 text-sm">
|
||||
{{ t('BILLING_SETTINGS_V2.CANCEL_MODAL.WARNING_MESSAGE') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end gap-2 px-5 py-4 border-t border-n-weak">
|
||||
<ButtonV4 sm faded slate :disabled="isCanceling" @click="close">
|
||||
{{ $t('BILLING_SETTINGS_V2.CANCEL_MODAL.KEEP_SUBSCRIPTION') }}
|
||||
</ButtonV4>
|
||||
<ButtonV4 sm solid red :is-loading="isCanceling" @click="handleCancel">
|
||||
{{ $t('BILLING_SETTINGS_V2.CANCEL_MODAL.CONFIRM_CANCEL') }}
|
||||
</ButtonV4>
|
||||
<TextArea
|
||||
v-model="reason"
|
||||
:label="t('BILLING_SETTINGS_V2.CANCEL_MODAL.REASON_LABEL')"
|
||||
:placeholder="t('BILLING_SETTINGS_V2.CANCEL_MODAL.REASON_PLACEHOLDER')"
|
||||
:max-length="1500"
|
||||
auto-height
|
||||
/>
|
||||
|
||||
<div class="flex gap-1.5 items-center">
|
||||
<Icon icon="i-lucide-info" class="flex-shrink-0" />
|
||||
<p class="text-xs text-n-slate-12">
|
||||
{{ t('BILLING_SETTINGS_V2.CANCEL_MODAL.INFO') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
+14
-15
@@ -36,7 +36,7 @@ const { t } = useI18n();
|
||||
const store = useStore();
|
||||
|
||||
const showSubscribeModal = ref(false);
|
||||
const showCancelModal = ref(false);
|
||||
const cancelModalRef = ref(null);
|
||||
const selectedPlan = ref(null);
|
||||
const selectedQuantity = ref(1);
|
||||
|
||||
@@ -112,16 +112,6 @@ const formatNextBillingDate = () => {
|
||||
}).format(date);
|
||||
};
|
||||
|
||||
const currentPlan = computed(() => {
|
||||
if (!currentPlanId.value) return null;
|
||||
return transformedPlans.value.find(plan => plan.id === currentPlanId.value);
|
||||
});
|
||||
|
||||
const pendingPlan = computed(() => {
|
||||
if (!pendingPlanId.value) return null;
|
||||
return transformedPlans.value.find(plan => plan.id === pendingPlanId.value);
|
||||
});
|
||||
|
||||
// Transform backend component structure to flat structure
|
||||
const transformedPlans = computed(() => {
|
||||
return props.plans.map(plan => {
|
||||
@@ -145,6 +135,16 @@ const transformedPlans = computed(() => {
|
||||
});
|
||||
});
|
||||
|
||||
const currentPlan = computed(() => {
|
||||
if (!currentPlanId.value) return null;
|
||||
return transformedPlans.value.find(plan => plan.id === currentPlanId.value);
|
||||
});
|
||||
|
||||
const pendingPlan = computed(() => {
|
||||
if (!pendingPlanId.value) return null;
|
||||
return transformedPlans.value.find(plan => plan.id === pendingPlanId.value);
|
||||
});
|
||||
|
||||
const formatPrice = price => {
|
||||
if (!price) return '$0';
|
||||
return new Intl.NumberFormat('en-US', {
|
||||
@@ -186,7 +186,7 @@ const handleSubscribe = async data => {
|
||||
};
|
||||
|
||||
const openCancelModal = () => {
|
||||
showCancelModal.value = true;
|
||||
cancelModalRef.value?.dialogRef?.open();
|
||||
};
|
||||
|
||||
const handleCancelSubscription = async reason => {
|
||||
@@ -195,7 +195,7 @@ const handleCancelSubscription = async reason => {
|
||||
});
|
||||
if (result.success) {
|
||||
useAlert(t('BILLING_SETTINGS_V2.PRICING_PLANS.CANCEL_SUCCESS'));
|
||||
showCancelModal.value = false;
|
||||
cancelModalRef.value?.dialogRef?.close();
|
||||
} else if (result.error) {
|
||||
useAlert(result.error);
|
||||
}
|
||||
@@ -553,9 +553,8 @@ const isCurrentPlan = plan => {
|
||||
|
||||
<!-- Cancel Subscription Modal -->
|
||||
<CancelSubscriptionModal
|
||||
v-if="showCancelModal"
|
||||
ref="cancelModalRef"
|
||||
:is-canceling="isCanceling"
|
||||
@close="showCancelModal = false"
|
||||
@cancel="handleCancelSubscription"
|
||||
/>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user