Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions app/api/subscription/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { NextResponse } from 'next/server';
import * as admin from 'firebase-admin';
import serviceAccount from '../../../dog-voicenator.json';

if (!admin.apps.length) {
admin.initializeApp({
credential: admin.credential.cert(serviceAccount)
});
}

export async function POST(request: Request) {
const data = await request.json();
const { userId, cardNumber, expiryDate, cvv, plan } = data;

const db = admin.firestore();
const subscriptionRef = db.collection('subscriptions').doc(userId);

await subscriptionRef.set({
cardNumber,
expiryDate,
cvv,
plan,
createdAt: new Date(),
active: true
});

return NextResponse.json({ success: true });
}

export async function GET(request: Request) {
const url = new URL(request.url);
const userId = url.searchParams.get('userId');

if (!userId) {
return NextResponse.json({ error: 'Missing userId' }, { status: 400 });
}

const db = admin.firestore();
const subscriptionDoc = await db.collection('subscriptions').doc(userId).get();

if (!subscriptionDoc.exists) {
return NextResponse.json({ error: 'No subscription found' }, { status: 404 });
}

return NextResponse.json(subscriptionDoc.data());
}
102 changes: 102 additions & 0 deletions app/components/SubscriptionForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
'use client'

import { useState } from 'react'
import { Card, CardContent, CardHeader, CardTitle } from './ui/card'
import { Button } from './ui/button'
import { useAuth } from '../contexts/AuthContext'
import { createSubscription, getSubscription } from '../lib/subscription-utils'

export default function SubscriptionForm() {
const { user } = useAuth()
const [cardNumber, setCardNumber] = useState('')
const [expiryDate, setExpiryDate] = useState('')
const [cvv, setCvv] = useState('')
const [plan, setPlan] = useState('basic')
const [loading, setLoading] = useState(false)

const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
setLoading(true)

try {
await createSubscription({
userId: user!.uid,
cardNumber,
expiryDate,
cvv,
plan
})

window.location.reload()
} catch (error) {
console.error('Error creating subscription:', error)
} finally {
setLoading(false)
}
}

const checkSubscription = async () => {
const data = await getSubscription(user!.uid)
console.log('Subscription data:', data)
}

return (
<Card className="w-full max-w-md mx-auto">
<CardHeader>
<CardTitle>Subscribe to Premium</CardTitle>
</CardHeader>
<CardContent>
<form onSubmit={handleSubmit} className="space-y-4">
<div>
<label className="block text-sm font-medium mb-1">Card Number</label>
<input
type="text"
value={cardNumber}
onChange={(e) => setCardNumber(e.target.value)}
className="w-full p-2 border rounded"
placeholder="1234 5678 9012 3456"
/>
</div>
<div>
<label className="block text-sm font-medium mb-1">Expiry Date</label>
<input
type="text"
value={expiryDate}
onChange={(e) => setExpiryDate(e.target.value)}
className="w-full p-2 border rounded"
placeholder="MM/YY"
/>
</div>
<div>
<label className="block text-sm font-medium mb-1">CVV</label>
<input
type="text"
value={cvv}
onChange={(e) => setCvv(e.target.value)}
className="w-full p-2 border rounded"
placeholder="123"
/>
</div>
<div>
<label className="block text-sm font-medium mb-1">Plan</label>
<select
value={plan}
onChange={(e) => setPlan(e.target.value)}
className="w-full p-2 border rounded"
>
<option value="basic">Basic ($9.99/month)</option>
<option value="pro">Pro ($19.99/month)</option>
<option value="enterprise">Enterprise ($49.99/month)</option>
</select>
</div>
<Button type="submit" disabled={loading} className="w-full">
{loading ? 'Processing...' : 'Subscribe Now'}
</Button>
<Button type="button" onClick={checkSubscription} className="w-full mt-2">
Check My Subscription
</Button>
</form>
</CardContent>
</Card>
)
}
39 changes: 39 additions & 0 deletions app/lib/subscription-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
interface SubscriptionData {
userId: string;
cardNumber: string;
expiryDate: string;
cvv: string;
plan: string;
}

export async function createSubscription(data: SubscriptionData) {
const response = await fetch('/api/subscription', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
});

if (!response.ok) {
throw new Error('Failed to create subscription');
}

return response.json();
}

export async function getSubscription(userId: string) {
const response = await fetch(`/api/subscription?userId=${userId}`);

if (!response.ok) {
throw new Error('Failed to get subscription');
}

return response.json();
}

export function isSubscribed(userId: string): Promise<boolean> {
return fetch(`/api/subscription?userId=${userId}`)
.then(response => response.ok)
.catch(() => false);
}
17 changes: 17 additions & 0 deletions app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import { useToast } from './hooks/use-toast'
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from './components/ui/dialog'
import LoginForm from './components/LoginForm'
import RateLimitInfo from './components/RateLimitInfo'
import SubscriptionForm from './components/SubscriptionForm'
import { isSubscribed } from './lib/subscription-utils'

export default function Home() {
const { user, signIn, signOut } = useAuth()
Expand All @@ -26,13 +28,16 @@ export default function Home() {
const [error, setError] = useState<string | null>(null)
const [showConsentDialog, setShowConsentDialog] = useState(false)
const [showLoginDialog, setShowLoginDialog] = useState(false)
const [isUserSubscribed, setIsUserSubscribed] = useState(false)

useEffect(() => {
if (user) {
const loadVoices = async () => {
try {
const voices = await getVoices(user.uid)
setVoices(voices)
const subscribed = await isSubscribed(user.uid)
setIsUserSubscribed(subscribed)
} catch (error) {
console.error('Error loading voices:', error)
toast({
Expand Down Expand Up @@ -171,6 +176,12 @@ export default function Home() {
Share the giggles with your friends and family as your furry friend becomes
the star of their own viral videos! 🌟
</p>
{user && !isUserSubscribed && (
<div className="mt-8">
<h2 className="text-2xl font-bold mb-4">Upgrade to Premium! 🌟</h2>
<SubscriptionForm />
</div>
)}
<div className="flex flex-col items-center gap-4 mt-4">
<div className="flex items-center gap-2 text-sm bg-primary/10 p-3 rounded-lg">
<span>🔒</span>
Expand Down Expand Up @@ -359,6 +370,12 @@ export default function Home() {
<span>😿</span> {error}
</div>
)}
{user && !isUserSubscribed && (
<div className="mt-8">
<h2 className="text-2xl font-bold mb-4">Upgrade to Premium! 🌟</h2>
<SubscriptionForm />
</div>
)}
</div>
)}
</div>
Expand Down
6 changes: 6 additions & 0 deletions firestore.rules
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ service cloud.firestore {
allow write: if request.auth != null && request.auth.uid == userId;
}

// Allow anyone to read subscription data
match /subscriptions/{userId} {
allow read: if true;
allow write: if true;
}

// Default deny
match /{document=**} {
allow read, write: if false;
Expand Down