fix(subscriptions): fix subscription UI and API after store→merchant migration
Store detail page now shows all platform subscriptions instead of always "No Subscription Found". Subscriptions listing page renamed from Store to Merchant throughout (template, JS, menu, i18n) with Platform column added. Tiers API supports platform_id filtering. Merchant detail page no longer hardcodes 'oms' platform — loads all platforms, shows subscription cards per platform with labels, and the Create Subscription modal includes a platform selector with platform-filtered tiers. Create button always accessible in Quick Actions. Edit modal on /admin/subscriptions loads tiers from API filtered by platform instead of hardcoded options, sends tier_code (not tier) to match PATCH schema, and shows platform context. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -32,6 +32,13 @@
|
||||
<span x-html="$icon('edit', 'w-4 h-4 mr-2')"></span>
|
||||
Edit Merchant
|
||||
</a>
|
||||
<button
|
||||
@click="openCreateSubscriptionModal()"
|
||||
x-show="platforms.length > 0"
|
||||
class="flex items-center px-4 py-2 text-sm font-medium leading-5 text-white transition-colors duration-150 bg-green-600 border border-transparent rounded-lg hover:bg-green-700 focus:outline-none focus:shadow-outline-green">
|
||||
<span x-html="$icon('plus', 'w-4 h-4 mr-2')"></span>
|
||||
Create Subscription
|
||||
</button>
|
||||
<button
|
||||
@click="deleteMerchant()"
|
||||
:disabled="merchant?.store_count > 0"
|
||||
@@ -194,94 +201,99 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Subscription Card -->
|
||||
<div class="px-4 py-3 mb-6 bg-white rounded-lg shadow-md dark:bg-gray-800" x-show="subscription">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h3 class="text-lg font-semibold text-gray-700 dark:text-gray-200">
|
||||
Subscription
|
||||
</h3>
|
||||
</div>
|
||||
<!-- Subscription Cards -->
|
||||
<template x-for="entry in subscriptions" :key="entry.subscription.id">
|
||||
<div class="px-4 py-3 mb-6 bg-white rounded-lg shadow-md dark:bg-gray-800">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h3 class="text-lg font-semibold text-gray-700 dark:text-gray-200">
|
||||
Subscription
|
||||
<span x-show="entry.platform_name" class="text-sm font-normal text-gray-500 dark:text-gray-400">
|
||||
— <span x-text="entry.platform_name"></span>
|
||||
</span>
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<!-- Tier and Status -->
|
||||
<div class="flex flex-wrap items-center gap-4 mb-4">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-sm text-gray-600 dark:text-gray-400">Tier:</span>
|
||||
<span class="px-2.5 py-0.5 text-sm font-medium rounded-full"
|
||||
:class="{
|
||||
'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-300': subscription?.tier === 'essential',
|
||||
'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300': subscription?.tier === 'professional',
|
||||
'bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-300': subscription?.tier === 'business',
|
||||
'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300': subscription?.tier === 'enterprise'
|
||||
}"
|
||||
x-text="subscription?.tier ? subscription.tier.charAt(0).toUpperCase() + subscription.tier.slice(1) : '-'">
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-sm text-gray-600 dark:text-gray-400">Status:</span>
|
||||
<span class="px-2.5 py-0.5 text-sm font-medium rounded-full"
|
||||
:class="{
|
||||
'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300': subscription?.status === 'active',
|
||||
'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300': subscription?.status === 'trial',
|
||||
'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300': subscription?.status === 'past_due',
|
||||
'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-300': subscription?.status === 'cancelled' || subscription?.status === 'expired'
|
||||
}"
|
||||
x-text="subscription?.status ? subscription.status.replace('_', ' ').charAt(0).toUpperCase() + subscription.status.slice(1) : '-'">
|
||||
</span>
|
||||
</div>
|
||||
<template x-if="subscription?.is_annual">
|
||||
<span class="px-2.5 py-0.5 text-xs font-medium text-purple-800 bg-purple-100 rounded-full dark:bg-purple-900 dark:text-purple-300">
|
||||
Annual
|
||||
</span>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- Period Info -->
|
||||
<div class="flex flex-wrap gap-4 mb-4 text-sm">
|
||||
<div>
|
||||
<span class="text-gray-600 dark:text-gray-400">Period:</span>
|
||||
<span class="ml-1 text-gray-700 dark:text-gray-300" x-text="formatDate(subscription?.period_start)"></span>
|
||||
<span class="text-gray-400">→</span>
|
||||
<span class="text-gray-700 dark:text-gray-300" x-text="formatDate(subscription?.period_end)"></span>
|
||||
</div>
|
||||
<template x-if="subscription?.trial_ends_at">
|
||||
<div>
|
||||
<span class="text-gray-600 dark:text-gray-400">Trial ends:</span>
|
||||
<span class="ml-1 text-gray-700 dark:text-gray-300" x-text="formatDate(subscription?.trial_ends_at)"></span>
|
||||
<!-- Tier and Status -->
|
||||
<div class="flex flex-wrap items-center gap-4 mb-4">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-sm text-gray-600 dark:text-gray-400">Tier:</span>
|
||||
<span class="px-2.5 py-0.5 text-sm font-medium rounded-full"
|
||||
:class="{
|
||||
'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-300': entry.subscription?.tier === 'essential',
|
||||
'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300': entry.subscription?.tier === 'professional',
|
||||
'bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-300': entry.subscription?.tier === 'business',
|
||||
'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300': entry.subscription?.tier === 'enterprise'
|
||||
}"
|
||||
x-text="entry.subscription?.tier ? entry.subscription.tier.charAt(0).toUpperCase() + entry.subscription.tier.slice(1) : '-'">
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-sm text-gray-600 dark:text-gray-400">Status:</span>
|
||||
<span class="px-2.5 py-0.5 text-sm font-medium rounded-full"
|
||||
:class="{
|
||||
'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300': entry.subscription?.status === 'active',
|
||||
'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300': entry.subscription?.status === 'trial',
|
||||
'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300': entry.subscription?.status === 'past_due',
|
||||
'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-300': entry.subscription?.status === 'cancelled' || entry.subscription?.status === 'expired'
|
||||
}"
|
||||
x-text="entry.subscription?.status ? entry.subscription.status.replace('_', ' ').charAt(0).toUpperCase() + entry.subscription.status.slice(1) : '-'">
|
||||
</span>
|
||||
</div>
|
||||
<template x-if="entry.subscription?.is_annual">
|
||||
<span class="px-2.5 py-0.5 text-xs font-medium text-purple-800 bg-purple-100 rounded-full dark:bg-purple-900 dark:text-purple-300">
|
||||
Annual
|
||||
</span>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- Usage Meters -->
|
||||
<div class="grid gap-4 md:grid-cols-3">
|
||||
<template x-for="metric in usageMetrics" :key="metric.name">
|
||||
<div class="p-3 bg-gray-50 rounded-lg dark:bg-gray-700">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<span class="text-xs font-medium text-gray-600 dark:text-gray-400 uppercase" x-text="metric.name"></span>
|
||||
<!-- Period Info -->
|
||||
<div class="flex flex-wrap gap-4 mb-4 text-sm">
|
||||
<div>
|
||||
<span class="text-gray-600 dark:text-gray-400">Period:</span>
|
||||
<span class="ml-1 text-gray-700 dark:text-gray-300" x-text="formatDate(entry.subscription?.period_start)"></span>
|
||||
<span class="text-gray-400">→</span>
|
||||
<span class="text-gray-700 dark:text-gray-300" x-text="formatDate(entry.subscription?.period_end)"></span>
|
||||
</div>
|
||||
<template x-if="entry.subscription?.trial_ends_at">
|
||||
<div>
|
||||
<span class="text-gray-600 dark:text-gray-400">Trial ends:</span>
|
||||
<span class="ml-1 text-gray-700 dark:text-gray-300" x-text="formatDate(entry.subscription?.trial_ends_at)"></span>
|
||||
</div>
|
||||
<div class="flex items-baseline gap-1">
|
||||
<span class="text-xl font-bold text-gray-700 dark:text-gray-200" x-text="metric.current"></span>
|
||||
<span class="text-sm text-gray-500 dark:text-gray-400">
|
||||
/ <span x-text="metric.is_unlimited ? '∞' : metric.limit"></span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="mt-2 h-1.5 bg-gray-200 rounded-full dark:bg-gray-600" x-show="!metric.is_unlimited">
|
||||
<div class="h-1.5 rounded-full transition-all"
|
||||
:class="getUsageBarColor(metric.current, metric.limit)"
|
||||
:style="`width: ${Math.min(100, metric.percentage || 0)}%`">
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- Usage Meters -->
|
||||
<div class="grid gap-4 md:grid-cols-3">
|
||||
<template x-for="metric in entry.features" :key="metric.name">
|
||||
<div class="p-3 bg-gray-50 rounded-lg dark:bg-gray-700">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<span class="text-xs font-medium text-gray-600 dark:text-gray-400 uppercase" x-text="metric.name"></span>
|
||||
</div>
|
||||
<div class="flex items-baseline gap-1">
|
||||
<span class="text-xl font-bold text-gray-700 dark:text-gray-200" x-text="metric.current"></span>
|
||||
<span class="text-sm text-gray-500 dark:text-gray-400">
|
||||
/ <span x-text="metric.is_unlimited ? '∞' : metric.limit"></span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="mt-2 h-1.5 bg-gray-200 rounded-full dark:bg-gray-600" x-show="!metric.is_unlimited">
|
||||
<div class="h-1.5 rounded-full transition-all"
|
||||
:class="getUsageBarColor(metric.current, metric.limit)"
|
||||
:style="`width: ${Math.min(100, metric.percentage || 0)}%`">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template x-if="usageMetrics.length === 0">
|
||||
<div class="p-3 bg-gray-50 rounded-lg dark:bg-gray-700 md:col-span-3">
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400 text-center">No usage data available</p>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
<template x-if="entry.features.length === 0">
|
||||
<div class="p-3 bg-gray-50 rounded-lg dark:bg-gray-700 md:col-span-3">
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400 text-center">No usage data available</p>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- No Subscription Notice -->
|
||||
<div class="px-4 py-3 mb-6 bg-yellow-50 border border-yellow-200 rounded-lg dark:bg-yellow-900/20 dark:border-yellow-800" x-show="!subscription && !loading && platformId">
|
||||
<div class="px-4 py-3 mb-6 bg-yellow-50 border border-yellow-200 rounded-lg dark:bg-yellow-900/20 dark:border-yellow-800" x-show="subscriptions.length === 0 && !loading && platforms.length > 0">
|
||||
<div class="flex items-center gap-3">
|
||||
<span x-html="$icon('exclamation', 'w-5 h-5 text-yellow-600 dark:text-yellow-400')"></span>
|
||||
<div>
|
||||
@@ -302,6 +314,18 @@
|
||||
<div class="relative z-10 w-full max-w-md p-6 bg-white rounded-lg shadow-xl dark:bg-gray-800">
|
||||
<h3 class="mb-4 text-lg font-semibold text-gray-700 dark:text-gray-200">Create Subscription</h3>
|
||||
|
||||
<!-- Platform Selector -->
|
||||
<div class="mb-4">
|
||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Platform</label>
|
||||
<select x-model="createForm.platform_id"
|
||||
@change="onCreatePlatformChange()"
|
||||
class="w-full px-3 py-2 text-sm border border-gray-300 rounded-lg dark:border-gray-600 dark:bg-gray-700 dark:text-gray-300 focus:outline-none focus:ring-2 focus:ring-purple-500">
|
||||
<template x-for="p in platforms" :key="p.id">
|
||||
<option :value="p.id" x-text="p.name"></option>
|
||||
</template>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Tier Selector -->
|
||||
<div class="mb-4">
|
||||
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Subscription Tier</label>
|
||||
|
||||
@@ -106,100 +106,105 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Subscription Card -->
|
||||
<div class="px-4 py-3 mb-6 bg-white rounded-lg shadow-md dark:bg-gray-800" x-show="subscription">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h3 class="text-lg font-semibold text-gray-700 dark:text-gray-200">
|
||||
Subscription
|
||||
</h3>
|
||||
<a
|
||||
:href="'/admin/merchants/' + store?.merchant_id"
|
||||
class="flex items-center px-3 py-1.5 text-sm font-medium text-purple-600 hover:text-purple-700 dark:text-purple-400 dark:hover:text-purple-300">
|
||||
<span x-html="$icon('external-link', 'w-4 h-4 mr-1')"></span>
|
||||
Manage on Merchant Page
|
||||
</a>
|
||||
</div>
|
||||
<!-- Subscription Cards -->
|
||||
<template x-for="entry in subscriptions" :key="entry.subscription.id">
|
||||
<div class="px-4 py-3 mb-6 bg-white rounded-lg shadow-md dark:bg-gray-800">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h3 class="text-lg font-semibold text-gray-700 dark:text-gray-200">
|
||||
Subscription
|
||||
<span x-show="entry.platform_name" class="text-sm font-normal text-gray-500 dark:text-gray-400">
|
||||
— <span x-text="entry.platform_name"></span>
|
||||
</span>
|
||||
</h3>
|
||||
<a
|
||||
:href="'/admin/merchants/' + store?.merchant_id"
|
||||
class="flex items-center px-3 py-1.5 text-sm font-medium text-purple-600 hover:text-purple-700 dark:text-purple-400 dark:hover:text-purple-300">
|
||||
<span x-html="$icon('external-link', 'w-4 h-4 mr-1')"></span>
|
||||
Manage on Merchant Page
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Tier and Status -->
|
||||
<div class="flex flex-wrap items-center gap-4 mb-4">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-sm text-gray-600 dark:text-gray-400">Tier:</span>
|
||||
<span class="px-2.5 py-0.5 text-sm font-medium rounded-full"
|
||||
:class="{
|
||||
'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-300': subscription?.tier === 'essential',
|
||||
'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300': subscription?.tier === 'professional',
|
||||
'bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-300': subscription?.tier === 'business',
|
||||
'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300': subscription?.tier === 'enterprise'
|
||||
}"
|
||||
x-text="subscription?.tier ? subscription.tier.charAt(0).toUpperCase() + subscription.tier.slice(1) : '-'">
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-sm text-gray-600 dark:text-gray-400">Status:</span>
|
||||
<span class="px-2.5 py-0.5 text-sm font-medium rounded-full"
|
||||
:class="{
|
||||
'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300': subscription?.status === 'active',
|
||||
'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300': subscription?.status === 'trial',
|
||||
'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300': subscription?.status === 'past_due',
|
||||
'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-300': subscription?.status === 'cancelled' || subscription?.status === 'expired'
|
||||
}"
|
||||
x-text="subscription?.status ? subscription.status.replace('_', ' ').charAt(0).toUpperCase() + subscription.status.slice(1) : '-'">
|
||||
</span>
|
||||
</div>
|
||||
<template x-if="subscription?.is_annual">
|
||||
<span class="px-2.5 py-0.5 text-xs font-medium text-purple-800 bg-purple-100 rounded-full dark:bg-purple-900 dark:text-purple-300">
|
||||
Annual
|
||||
</span>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- Period Info -->
|
||||
<div class="flex flex-wrap gap-4 mb-4 text-sm">
|
||||
<div>
|
||||
<span class="text-gray-600 dark:text-gray-400">Period:</span>
|
||||
<span class="ml-1 text-gray-700 dark:text-gray-300" x-text="formatDate(subscription?.period_start)"></span>
|
||||
<span class="text-gray-400">→</span>
|
||||
<span class="text-gray-700 dark:text-gray-300" x-text="formatDate(subscription?.period_end)"></span>
|
||||
</div>
|
||||
<template x-if="subscription?.trial_ends_at">
|
||||
<div>
|
||||
<span class="text-gray-600 dark:text-gray-400">Trial ends:</span>
|
||||
<span class="ml-1 text-gray-700 dark:text-gray-300" x-text="formatDate(subscription?.trial_ends_at)"></span>
|
||||
<!-- Tier and Status -->
|
||||
<div class="flex flex-wrap items-center gap-4 mb-4">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-sm text-gray-600 dark:text-gray-400">Tier:</span>
|
||||
<span class="px-2.5 py-0.5 text-sm font-medium rounded-full"
|
||||
:class="{
|
||||
'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-300': entry.subscription?.tier === 'essential',
|
||||
'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300': entry.subscription?.tier === 'professional',
|
||||
'bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-300': entry.subscription?.tier === 'business',
|
||||
'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300': entry.subscription?.tier === 'enterprise'
|
||||
}"
|
||||
x-text="entry.subscription?.tier ? entry.subscription.tier.charAt(0).toUpperCase() + entry.subscription.tier.slice(1) : '-'">
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-sm text-gray-600 dark:text-gray-400">Status:</span>
|
||||
<span class="px-2.5 py-0.5 text-sm font-medium rounded-full"
|
||||
:class="{
|
||||
'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300': entry.subscription?.status === 'active',
|
||||
'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300': entry.subscription?.status === 'trial',
|
||||
'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300': entry.subscription?.status === 'past_due',
|
||||
'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-300': entry.subscription?.status === 'cancelled' || entry.subscription?.status === 'expired'
|
||||
}"
|
||||
x-text="entry.subscription?.status ? entry.subscription.status.replace('_', ' ').charAt(0).toUpperCase() + entry.subscription.status.slice(1) : '-'">
|
||||
</span>
|
||||
</div>
|
||||
<template x-if="entry.subscription?.is_annual">
|
||||
<span class="px-2.5 py-0.5 text-xs font-medium text-purple-800 bg-purple-100 rounded-full dark:bg-purple-900 dark:text-purple-300">
|
||||
Annual
|
||||
</span>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- Usage Meters -->
|
||||
<div class="grid gap-4 md:grid-cols-3">
|
||||
<template x-for="metric in usageMetrics" :key="metric.name">
|
||||
<div class="p-3 bg-gray-50 rounded-lg dark:bg-gray-700">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<span class="text-xs font-medium text-gray-600 dark:text-gray-400 uppercase" x-text="metric.name"></span>
|
||||
<!-- Period Info -->
|
||||
<div class="flex flex-wrap gap-4 mb-4 text-sm">
|
||||
<div>
|
||||
<span class="text-gray-600 dark:text-gray-400">Period:</span>
|
||||
<span class="ml-1 text-gray-700 dark:text-gray-300" x-text="formatDate(entry.subscription?.period_start)"></span>
|
||||
<span class="text-gray-400">→</span>
|
||||
<span class="text-gray-700 dark:text-gray-300" x-text="formatDate(entry.subscription?.period_end)"></span>
|
||||
</div>
|
||||
<template x-if="entry.subscription?.trial_ends_at">
|
||||
<div>
|
||||
<span class="text-gray-600 dark:text-gray-400">Trial ends:</span>
|
||||
<span class="ml-1 text-gray-700 dark:text-gray-300" x-text="formatDate(entry.subscription?.trial_ends_at)"></span>
|
||||
</div>
|
||||
<div class="flex items-baseline gap-1">
|
||||
<span class="text-xl font-bold text-gray-700 dark:text-gray-200" x-text="metric.current"></span>
|
||||
<span class="text-sm text-gray-500 dark:text-gray-400">
|
||||
/ <span x-text="metric.is_unlimited ? '∞' : metric.limit"></span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="mt-2 h-1.5 bg-gray-200 rounded-full dark:bg-gray-600" x-show="!metric.is_unlimited">
|
||||
<div class="h-1.5 rounded-full transition-all"
|
||||
:class="getUsageBarColor(metric.current, metric.limit)"
|
||||
:style="`width: ${Math.min(100, metric.percentage || 0)}%`">
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- Usage Meters -->
|
||||
<div class="grid gap-4 md:grid-cols-3">
|
||||
<template x-for="metric in entry.features" :key="metric.name">
|
||||
<div class="p-3 bg-gray-50 rounded-lg dark:bg-gray-700">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<span class="text-xs font-medium text-gray-600 dark:text-gray-400 uppercase" x-text="metric.name"></span>
|
||||
</div>
|
||||
<div class="flex items-baseline gap-1">
|
||||
<span class="text-xl font-bold text-gray-700 dark:text-gray-200" x-text="metric.current"></span>
|
||||
<span class="text-sm text-gray-500 dark:text-gray-400">
|
||||
/ <span x-text="metric.is_unlimited ? '∞' : metric.limit"></span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="mt-2 h-1.5 bg-gray-200 rounded-full dark:bg-gray-600" x-show="!metric.is_unlimited">
|
||||
<div class="h-1.5 rounded-full transition-all"
|
||||
:class="getUsageBarColor(metric.current, metric.limit)"
|
||||
:style="`width: ${Math.min(100, metric.percentage || 0)}%`">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template x-if="usageMetrics.length === 0">
|
||||
<div class="p-3 bg-gray-50 rounded-lg dark:bg-gray-700 md:col-span-3">
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400 text-center">No usage data available</p>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
<template x-if="entry.features.length === 0">
|
||||
<div class="p-3 bg-gray-50 rounded-lg dark:bg-gray-700 md:col-span-3">
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400 text-center">No usage data available</p>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- No Subscription Notice -->
|
||||
<div class="px-4 py-3 mb-6 bg-yellow-50 border border-yellow-200 rounded-lg dark:bg-yellow-900/20 dark:border-yellow-800" x-show="!subscription && !loading">
|
||||
<div class="px-4 py-3 mb-6 bg-yellow-50 border border-yellow-200 rounded-lg dark:bg-yellow-900/20 dark:border-yellow-800" x-show="subscriptions.length === 0 && !loading">
|
||||
<div class="flex items-center gap-3">
|
||||
<span x-html="$icon('exclamation', 'w-5 h-5 text-yellow-600 dark:text-yellow-400')"></span>
|
||||
<div>
|
||||
|
||||
Reference in New Issue
Block a user