chore: Update cancel sub modal

This commit is contained in:
iamsivin
2025-10-31 14:17:25 +05:30
parent 10cd5da09d
commit 76ff8bdd35
3 changed files with 64 additions and 84 deletions
@@ -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",
@@ -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>
@@ -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>