chore: Update credit grants

This commit is contained in:
iamsivin
2025-10-31 15:46:52 +05:30
parent 6211406681
commit fb0f5cd696
2 changed files with 73 additions and 58 deletions
@@ -460,11 +460,14 @@
"CREDIT_GRANTS": {
"TITLE": "Credit History",
"DESCRIPTION": "View all your credit grants including topups and monthly credits.",
"CREDITS": "credits",
"CREDITS": "{credits} credits",
"EXPIRES": "Expires",
"NO_EXPIRY": "Never expires",
"ADDED": "Added",
"NO_GRANTS": "No credit grants yet."
"ADDED": "Added on {date}",
"VOIDED": "Voided",
"NO_GRANTS": "No credit grants yet.",
"TOPUPS": "Topups",
"MONTHLY": "Monthly"
},
"SUBSCRIBE_MODAL": {
"TITLE": "Confirm Subscription",
@@ -1,7 +1,9 @@
<script setup>
import { computed } from 'vue';
import { useI18n } from 'vue-i18n';
import BillingCard from '../../billing/components/BillingCard.vue';
import format from 'date-fns/format';
import BillingCard from 'dashboard/routes/dashboard/settings/billing/components/BillingCard.vue';
import Spinner from 'dashboard/components-next/spinner/Spinner.vue';
const props = defineProps({
grants: {
@@ -18,34 +20,35 @@ const { t } = useI18n();
const formatDate = dateStr => {
if (!dateStr) return null;
const date = new Date(dateStr);
return new Intl.DateTimeFormat('en-US', {
year: 'numeric',
month: 'short',
day: 'numeric',
}).format(date);
return format(new Date(dateStr), 'MMM dd, yyyy');
};
const formatNumber = num => {
return new Intl.NumberFormat('en-US').format(num);
};
const formatNumber = num => new Intl.NumberFormat('en-US').format(num);
const sortedGrants = computed(() => {
return [...props.grants].sort((a, b) => {
// Sort by: active first, then by creation date (newest first)
if (a.voided_at && !b.voided_at) return 1;
if (!a.voided_at && b.voided_at) return -1;
return new Date(b.created_at) - new Date(a.created_at);
});
const sortedGrants = computed(
() =>
[...props.grants]?.sort((a, b) => {
if (a.voided_at && !b.voided_at) return 1;
if (!a.voided_at && b.voided_at) return -1;
return new Date(b.created_at) - new Date(a.created_at);
}) || []
);
const CATEGORY_CONFIG = computed(() => {
return {
paid: {
label: t('BILLING_SETTINGS_V2.CREDIT_GRANTS.TOPUPS'),
class: 'bg-n-blue-3 text-n-blue-11 outline outline-1 outline-n-blue-4',
},
granted: {
label: t('BILLING_SETTINGS_V2.CREDIT_GRANTS.MONTHLY'),
class: 'bg-n-teal-3 text-n-teal-11 outline outline-1 outline-n-teal-4',
},
};
});
const getCategoryColor = category => {
return category === 'paid' ? 'bg-b-50 text-b-700' : 'bg-g-50 text-g-700';
};
const getCategoryLabel = category => {
return category === 'paid' ? 'Topup' : 'Monthly';
};
const getCategoryConfig = category =>
CATEGORY_CONFIG.value[category] || CATEGORY_CONFIG.value.granted;
</script>
<template>
@@ -54,64 +57,73 @@ const getCategoryLabel = category => {
:description="$t('BILLING_SETTINGS_V2.CREDIT_GRANTS.DESCRIPTION')"
>
<div class="px-5 pb-5">
<!-- Grants List -->
<div class="space-y-3">
<div v-if="sortedGrants.length" class="space-y-3">
<div
v-for="grant in sortedGrants"
:key="grant.id"
class="p-4 border border-n-weak rounded-lg"
class="p-4 rounded-xl outline outline-1 outline-n-weak transition-opacity"
:class="{ 'opacity-50': grant.voided_at }"
>
<div class="flex items-start justify-between">
<div class="flex-1">
<div class="flex items-start justify-between gap-4">
<div class="flex-1 min-w-0">
<div class="flex items-center gap-2 mb-2">
<span
class="px-2 py-0.5 text-xs font-semibold rounded"
:class="getCategoryColor(grant.category)"
class="px-2 py-0.5 text-xs font-semibold rounded-md"
:class="getCategoryConfig(grant.category).class"
>
{{ getCategoryLabel(grant.category) }}
{{ getCategoryConfig(grant.category).label }}
</span>
<span
v-if="grant.voided_at"
class="px-2 py-0.5 text-xs font-semibold rounded bg-r-50 text-r-700"
class="px-2 py-0.5 text-xs font-semibold rounded-md bg-n-ruby-3 text-n-ruby-11 outline outline-1 outline-n-ruby-4"
>
Voided
{{ t('BILLING_SETTINGS_V2.CREDIT_GRANTS.VOIDED') }}
</span>
</div>
<h4 class="text-sm font-semibold text-n-800">
<h4 class="text-sm font-semibold text-n-slate-12 truncate">
{{ grant.name }}
</h4>
<p class="mt-1 text-xs text-n-600">
{{ formatNumber(grant.credits) }}
{{ $t('BILLING_SETTINGS_V2.CREDIT_GRANTS.CREDITS') }}
<p class="mt-1 text-xs text-n-slate-11">
{{
t('BILLING_SETTINGS_V2.CREDIT_GRANTS.CREDITS', {
credits: formatNumber(grant.credits),
})
}}
</p>
</div>
<div class="text-right">
<div v-if="grant.expires_at" class="text-xs text-n-600">
<span class="font-medium">{{
$t('BILLING_SETTINGS_V2.CREDIT_GRANTS.EXPIRES')
}}</span>
<br />
{{ formatDate(grant.expires_at) }}
<div class="text-right flex-shrink-0">
<div v-if="grant.expires_at" class="text-xs text-n-slate-11">
<span class="font-medium">
{{ t('BILLING_SETTINGS_V2.CREDIT_GRANTS.EXPIRES') }}
</span>
<div class="mt-0.5">{{ formatDate(grant.expires_at) }}</div>
</div>
<div v-else class="text-xs text-g-600 font-medium">
{{ $t('BILLING_SETTINGS_V2.CREDIT_GRANTS.NO_EXPIRY') }}
<div v-else class="text-xs text-n-teal-10 font-medium">
{{ t('BILLING_SETTINGS_V2.CREDIT_GRANTS.NO_EXPIRY') }}
</div>
<div class="mt-1 text-xs text-n-500">
{{ $t('BILLING_SETTINGS_V2.CREDIT_GRANTS.ADDED') }}
{{ formatDate(grant.created_at) }}
<div v-if="grant.created_at" class="mt-1 text-xs text-n-slate-10">
{{
t('BILLING_SETTINGS_V2.CREDIT_GRANTS.ADDED', {
date: formatDate(grant.created_at),
})
}}
</div>
</div>
</div>
</div>
</div>
<!-- Empty State -->
<div v-if="grants.length === 0 && !isLoading" class="py-8 text-center">
<p class="text-sm text-n-600">
{{ $t('BILLING_SETTINGS_V2.CREDIT_GRANTS.NO_GRANTS') }}
<div v-else-if="!isLoading" class="py-8 text-center">
<p class="text-sm text-n-slate-11">
{{ t('BILLING_SETTINGS_V2.CREDIT_GRANTS.NO_GRANTS') }}
</p>
</div>
<div v-else class="py-8 flex justify-center items-center">
<Spinner class="text-n-brand" />
</div>
</div>
</BillingCard>
</template>