Update FE

This commit is contained in:
Koncept Kit
2025-12-08 20:45:40 +07:00
parent d8c1e133ac
commit 1f27c3224b
23 changed files with 438 additions and 438 deletions

View File

@@ -118,16 +118,16 @@ const AdminPlans = () => {
<div className="mb-8">
<div className="flex justify-between items-start mb-4">
<div>
<h1 className="text-4xl md:text-5xl font-semibold fraunces text-[#3D405B] mb-4">
<h1 className="text-4xl md:text-5xl font-semibold text-[#422268] mb-4" style={{ fontFamily: "'Inter', sans-serif" }}>
Subscription Plans
</h1>
<p className="text-lg text-[#6B708D]">
<p className="text-lg text-[#664fa3]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
Manage membership plans and pricing.
</p>
</div>
<Button
onClick={handleCreatePlan}
className="bg-[#E07A5F] hover:bg-[#D0694E] text-white rounded-full px-6"
className="bg-[#DDD8EB] text-[#422268] hover:bg-white rounded-full px-6"
>
<Plus className="h-4 w-4 mr-2" />
Create Plan
@@ -137,27 +137,27 @@ const AdminPlans = () => {
{/* Stats */}
<div className="grid md:grid-cols-4 gap-4 mb-8">
<Card className="p-6 bg-white rounded-2xl border border-[#EAE0D5]">
<p className="text-sm text-[#6B708D] mb-2">Total Plans</p>
<p className="text-3xl font-semibold fraunces text-[#3D405B]">
<Card className="p-6 bg-white rounded-2xl border border-[#ddd8eb]">
<p className="text-sm text-[#664fa3] mb-2" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>Total Plans</p>
<p className="text-3xl font-semibold text-[#422268]" style={{ fontFamily: "'Inter', sans-serif" }}>
{plans.length}
</p>
</Card>
<Card className="p-6 bg-white rounded-2xl border border-[#EAE0D5]">
<p className="text-sm text-[#6B708D] mb-2">Active Plans</p>
<p className="text-3xl font-semibold fraunces text-[#3D405B]">
<Card className="p-6 bg-white rounded-2xl border border-[#ddd8eb]">
<p className="text-sm text-[#664fa3] mb-2" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>Active Plans</p>
<p className="text-3xl font-semibold text-[#422268]" style={{ fontFamily: "'Inter', sans-serif" }}>
{plans.filter(p => p.active).length}
</p>
</Card>
<Card className="p-6 bg-white rounded-2xl border border-[#EAE0D5]">
<p className="text-sm text-[#6B708D] mb-2">Total Subscribers</p>
<p className="text-3xl font-semibold fraunces text-[#3D405B]">
<Card className="p-6 bg-white rounded-2xl border border-[#ddd8eb]">
<p className="text-sm text-[#664fa3] mb-2" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>Total Subscribers</p>
<p className="text-3xl font-semibold text-[#422268]" style={{ fontFamily: "'Inter', sans-serif" }}>
{plans.reduce((sum, p) => sum + (p.subscriber_count || 0), 0)}
</p>
</Card>
<Card className="p-6 bg-white rounded-2xl border border-[#EAE0D5]">
<p className="text-sm text-[#6B708D] mb-2">Revenue (Annual Est.)</p>
<p className="text-3xl font-semibold fraunces text-[#3D405B]">
<Card className="p-6 bg-white rounded-2xl border border-[#ddd8eb]">
<p className="text-sm text-[#664fa3] mb-2" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>Revenue (Annual Est.)</p>
<p className="text-3xl font-semibold text-[#422268]" style={{ fontFamily: "'Inter', sans-serif" }}>
{formatPrice(
plans.reduce((sum, p) => {
const annualPrice = p.billing_cycle === 'yearly'
@@ -171,19 +171,19 @@ const AdminPlans = () => {
</div>
{/* Filters */}
<Card className="p-6 bg-white rounded-2xl border border-[#EAE0D5] mb-8">
<Card className="p-6 bg-white rounded-2xl border border-[#ddd8eb] mb-8">
<div className="grid md:grid-cols-2 gap-4">
<div className="relative">
<Search className="absolute left-4 top-1/2 transform -translate-y-1/2 h-5 w-5 text-[#6B708D]" />
<Search className="absolute left-4 top-1/2 transform -translate-y-1/2 h-5 w-5 text-[#664fa3]" />
<Input
placeholder="Search plans..."
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="pl-12 h-14 rounded-xl border-2 border-[#EAE0D5] focus:border-[#E07A5F]"
className="pl-12 h-14 rounded-xl border-2 border-[#ddd8eb] focus:border-[#664fa3]"
/>
</div>
<Select value={activeFilter} onValueChange={setActiveFilter}>
<SelectTrigger className="h-14 rounded-xl border-2 border-[#EAE0D5]">
<SelectTrigger className="h-14 rounded-xl border-2 border-[#ddd8eb]">
<SelectValue placeholder="Filter by status" />
</SelectTrigger>
<SelectContent>
@@ -198,7 +198,7 @@ const AdminPlans = () => {
{/* Plans Grid */}
{loading ? (
<div className="text-center py-20">
<p className="text-[#6B708D]">Loading plans...</p>
<p className="text-[#664fa3]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>Loading plans...</p>
</div>
) : filteredPlans.length > 0 ? (
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
@@ -207,8 +207,8 @@ const AdminPlans = () => {
key={plan.id}
className={`p-6 bg-white rounded-2xl border-2 transition-all hover:shadow-lg ${
plan.active
? 'border-[#EAE0D5] hover:border-[#E07A5F]'
: 'border-[#6B708D] opacity-60'
? 'border-[#ddd8eb] hover:border-[#664fa3]'
: 'border-gray-400 opacity-60'
}`}
>
{/* Header with badges */}
@@ -217,13 +217,13 @@ const AdminPlans = () => {
className={`${
plan.active
? 'bg-[#81B29A] text-white'
: 'bg-[#6B708D] text-white'
: 'bg-gray-400 text-white'
}`}
>
{plan.active ? 'Active' : 'Inactive'}
</Badge>
{plan.subscriber_count > 0 && (
<Badge className="bg-[#F2CC8F] text-[#3D405B]">
<Badge className="bg-[#DDD8EB] text-[#422268]">
<Users className="h-3 w-3 mr-1" />
{plan.subscriber_count}
</Badge>
@@ -231,23 +231,23 @@ const AdminPlans = () => {
</div>
{/* Plan Name */}
<h3 className="text-2xl font-semibold fraunces text-[#3D405B] mb-2">
<h3 className="text-2xl font-semibold text-[#422268] mb-2" style={{ fontFamily: "'Inter', sans-serif" }}>
{plan.name}
</h3>
{/* Description */}
{plan.description && (
<p className="text-sm text-[#6B708D] mb-4 line-clamp-2">
<p className="text-sm text-[#664fa3] mb-4 line-clamp-2" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
{plan.description}
</p>
)}
{/* Price */}
<div className="mb-4">
<div className="text-3xl font-bold fraunces text-[#E07A5F]">
<div className="text-3xl font-bold text-[#ff9e77]" style={{ fontFamily: "'Inter', sans-serif" }}>
{formatPrice(plan.price_cents)}
</div>
<p className="text-sm text-[#6B708D]">
<p className="text-sm text-[#664fa3]" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
{getBillingCycleLabel(plan.billing_cycle)}
</p>
</div>
@@ -260,19 +260,19 @@ const AdminPlans = () => {
Stripe Integrated
</Badge>
) : (
<Badge className="bg-[#F2CC8F] text-[#3D405B] text-xs">
<Badge className="bg-[#DDD8EB] text-[#422268] text-xs">
Manual/Test Plan
</Badge>
)}
</div>
{/* Actions */}
<div className="flex gap-2 pt-4 border-t border-[#EAE0D5]">
<div className="flex gap-2 pt-4 border-t border-[#ddd8eb]">
<Button
onClick={() => handleEditPlan(plan)}
variant="outline"
size="sm"
className="flex-1 border-[#A3B1C6] text-[#A3B1C6] hover:bg-[#A3B1C6] hover:text-white rounded-full"
className="flex-1 border-[#664fa3] text-[#664fa3] hover:bg-[#664fa3] hover:text-white rounded-full"
>
<Edit className="h-4 w-4 mr-1" />
Edit
@@ -281,7 +281,7 @@ const AdminPlans = () => {
onClick={() => handleDeleteClick(plan)}
variant="outline"
size="sm"
className="flex-1 border-[#E07A5F] text-[#E07A5F] hover:bg-[#E07A5F] hover:text-white rounded-full"
className="flex-1 border-red-500 text-red-500 hover:bg-red-500 hover:text-white rounded-full"
disabled={plan.subscriber_count > 0}
>
<Trash2 className="h-4 w-4 mr-1" />
@@ -291,7 +291,7 @@ const AdminPlans = () => {
{/* Warning for plans with subscribers */}
{plan.subscriber_count > 0 && (
<p className="text-xs text-[#6B708D] mt-2 text-center">
<p className="text-xs text-[#664fa3] mt-2 text-center" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
Cannot delete plan with active subscribers
</p>
)}
@@ -300,11 +300,11 @@ const AdminPlans = () => {
</div>
) : (
<div className="text-center py-20">
<CreditCard className="h-20 w-20 text-[#EAE0D5] mx-auto mb-6" />
<h3 className="text-2xl font-semibold fraunces text-[#3D405B] mb-4">
<CreditCard className="h-20 w-20 text-[#ddd8eb] mx-auto mb-6" />
<h3 className="text-2xl font-semibold text-[#422268] mb-4" style={{ fontFamily: "'Inter', sans-serif" }}>
No Plans Found
</h3>
<p className="text-[#6B708D] mb-6">
<p className="text-[#664fa3] mb-6" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
{searchQuery || activeFilter !== 'all'
? 'Try adjusting your filters'
: 'Create your first subscription plan to get started'}
@@ -312,7 +312,7 @@ const AdminPlans = () => {
{!searchQuery && activeFilter === 'all' && (
<Button
onClick={handleCreatePlan}
className="bg-[#E07A5F] hover:bg-[#D0694E] text-white rounded-full px-8"
className="bg-[#DDD8EB] text-[#422268] hover:bg-white rounded-full px-8"
>
<Plus className="h-4 w-4 mr-2" />
Create First Plan
@@ -333,10 +333,10 @@ const AdminPlans = () => {
{deleteDialogOpen && (
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50">
<Card className="p-8 bg-white rounded-2xl max-w-md mx-4">
<h2 className="text-2xl font-semibold fraunces text-[#3D405B] mb-4">
<h2 className="text-2xl font-semibold text-[#422268] mb-4" style={{ fontFamily: "'Inter', sans-serif" }}>
Delete Plan
</h2>
<p className="text-[#6B708D] mb-6">
<p className="text-[#664fa3] mb-6" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
Are you sure you want to delete "{planToDelete?.name}"? This action
will deactivate the plan and it won't be available for new subscriptions.
</p>
@@ -350,7 +350,7 @@ const AdminPlans = () => {
</Button>
<Button
onClick={handleDeleteConfirm}
className="flex-1 bg-[#E07A5F] hover:bg-[#D0694E] text-white"
className="flex-1 bg-red-500 hover:bg-red-600 text-white"
>
Delete Plan
</Button>