feat(01-06): add subscription management page
- Display all plans (Free, Creator, Pro) in card grid - Highlight current plan with 'Piano attuale' badge - Add feature comparison table - Include FAQ section - Show payment deferral notice - All text in Italian
This commit is contained in:
179
src/app/(dashboard)/subscription/page.tsx
Normal file
179
src/app/(dashboard)/subscription/page.tsx
Normal file
@@ -0,0 +1,179 @@
|
||||
import { createClient } from '@/lib/supabase/server'
|
||||
import { redirect } from 'next/navigation'
|
||||
import { PlanCard } from '@/components/subscription/plan-card'
|
||||
import { Plan, PlanFeatures } from '@/types/database'
|
||||
import { PLAN_DISPLAY_ORDER } from '@/lib/plans'
|
||||
|
||||
export default async function SubscriptionPage() {
|
||||
const supabase = await createClient()
|
||||
|
||||
const { data: { user } } = await supabase.auth.getUser()
|
||||
|
||||
if (!user) {
|
||||
redirect('/login')
|
||||
}
|
||||
|
||||
// Get user's current plan
|
||||
const { data: profile } = await supabase
|
||||
.from('profiles')
|
||||
.select('plan_id')
|
||||
.eq('id', user.id)
|
||||
.single()
|
||||
|
||||
// Get all plans
|
||||
const { data: plans, error: plansError } = await supabase
|
||||
.from('plans')
|
||||
.select('*')
|
||||
.order('price_monthly', { ascending: true })
|
||||
|
||||
if (plansError || !plans) {
|
||||
return (
|
||||
<div className="text-center py-12">
|
||||
<p className="text-red-600">Errore nel caricamento dei piani</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
// Sort plans by our display order
|
||||
const sortedPlans = [...plans].sort((a, b) => {
|
||||
return PLAN_DISPLAY_ORDER.indexOf(a.name as typeof PLAN_DISPLAY_ORDER[number]) -
|
||||
PLAN_DISPLAY_ORDER.indexOf(b.name as typeof PLAN_DISPLAY_ORDER[number])
|
||||
})
|
||||
|
||||
return (
|
||||
<div className="space-y-8">
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold text-gray-900">Il tuo abbonamento</h1>
|
||||
<p className="text-gray-500 mt-1">
|
||||
Scegli il piano piu adatto alle tue esigenze
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Info banner */}
|
||||
<div className="bg-blue-50 border border-blue-200 rounded-lg p-4">
|
||||
<p className="text-sm text-blue-800">
|
||||
<strong>Nota:</strong> Il pagamento verra implementato nelle prossime versioni.
|
||||
Per ora puoi passare liberamente tra i piani per testare le funzionalita.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Plans grid */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
{sortedPlans.map((plan) => (
|
||||
<PlanCard
|
||||
key={plan.id}
|
||||
plan={plan as Plan}
|
||||
isCurrentPlan={plan.id === profile?.plan_id}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Feature comparison */}
|
||||
<div className="mt-12">
|
||||
<h2 className="text-xl font-semibold text-gray-900 mb-4">
|
||||
Confronto funzionalita
|
||||
</h2>
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full border-collapse">
|
||||
<thead>
|
||||
<tr className="border-b">
|
||||
<th className="text-left py-3 px-4 font-medium text-gray-600">
|
||||
Funzionalita
|
||||
</th>
|
||||
{sortedPlans.map((plan) => (
|
||||
<th key={plan.id} className="text-center py-3 px-4 font-medium text-gray-900">
|
||||
{plan.display_name_it}
|
||||
</th>
|
||||
))}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<FeatureRow
|
||||
feature="Post al mese"
|
||||
plans={sortedPlans as Plan[]}
|
||||
getValue={(p) => (p.features as PlanFeatures).posts_per_month.toString()}
|
||||
/>
|
||||
<FeatureRow
|
||||
feature="Account social"
|
||||
plans={sortedPlans as Plan[]}
|
||||
getValue={(p) => (p.features as PlanFeatures).social_accounts.toString()}
|
||||
/>
|
||||
<FeatureRow
|
||||
feature="Modelli AI"
|
||||
plans={sortedPlans as Plan[]}
|
||||
getValue={(p) => (p.features as PlanFeatures).ai_models.length.toString()}
|
||||
/>
|
||||
<FeatureRow
|
||||
feature="Generazione immagini"
|
||||
plans={sortedPlans as Plan[]}
|
||||
getValue={(p) => (p.features as PlanFeatures).image_generation ? '\u2713' : '\u2014'}
|
||||
/>
|
||||
<FeatureRow
|
||||
feature="Automazione"
|
||||
plans={sortedPlans as Plan[]}
|
||||
getValue={(p) => {
|
||||
const auto = (p.features as PlanFeatures).automation
|
||||
if (auto === false) return '\u2014'
|
||||
if (auto === 'manual') return 'Manuale'
|
||||
if (auto === 'full') return 'Completa'
|
||||
return '\u2014'
|
||||
}}
|
||||
/>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* FAQ */}
|
||||
<div className="mt-12">
|
||||
<h2 className="text-xl font-semibold text-gray-900 mb-4">
|
||||
Domande frequenti
|
||||
</h2>
|
||||
<div className="space-y-4">
|
||||
<FaqItem
|
||||
question="Posso cambiare piano in qualsiasi momento?"
|
||||
answer="Si, puoi passare a un piano superiore o inferiore quando vuoi. Le modifiche sono immediate."
|
||||
/>
|
||||
<FaqItem
|
||||
question="Cosa succede se supero i limiti del mio piano?"
|
||||
answer="Riceverai un avviso quando ti avvicini al limite mensile. Non potrai creare nuovi post fino al rinnovo o all'upgrade."
|
||||
/>
|
||||
<FaqItem
|
||||
question="Come funziona il pagamento?"
|
||||
answer="Il sistema di pagamento verra implementato a breve. Per ora tutti i piani sono disponibili gratuitamente per i test."
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function FeatureRow({
|
||||
feature,
|
||||
plans,
|
||||
getValue,
|
||||
}: {
|
||||
feature: string
|
||||
plans: Plan[]
|
||||
getValue: (plan: Plan) => string
|
||||
}) {
|
||||
return (
|
||||
<tr className="border-b">
|
||||
<td className="py-3 px-4 text-gray-600">{feature}</td>
|
||||
{plans.map((plan) => (
|
||||
<td key={plan.id} className="text-center py-3 px-4">
|
||||
{getValue(plan)}
|
||||
</td>
|
||||
))}
|
||||
</tr>
|
||||
)
|
||||
}
|
||||
|
||||
function FaqItem({ question, answer }: { question: string; answer: string }) {
|
||||
return (
|
||||
<div className="bg-gray-50 rounded-lg p-4">
|
||||
<h3 className="font-medium text-gray-900 mb-2">{question}</h3>
|
||||
<p className="text-sm text-gray-600">{answer}</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user