@digilogiclabs/create-saas-app 2.10.0 → 2.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +153 -113
- package/dist/.tsbuildinfo +1 -1
- package/dist/cli/commands/create.d.ts.map +1 -1
- package/dist/cli/commands/create.js +2 -6
- package/dist/cli/commands/create.js.map +1 -1
- package/dist/templates/web/ai-platform/template/src/app/api/auth/route.ts +57 -0
- package/dist/templates/web/ai-platform/template/src/app/login/page.tsx +112 -0
- package/dist/templates/web/ai-platform/template/src/app/models/page.tsx +186 -0
- package/dist/templates/web/ai-platform/template/src/app/playground/page.tsx +251 -0
- package/dist/templates/web/ai-platform/template/src/app/settings/page.tsx +190 -0
- package/dist/templates/web/ai-platform/template/src/app/signup/page.tsx +133 -0
- package/dist/templates/web/ai-platform/template/src/lib/auth-session.ts +52 -0
- package/dist/templates/web/iot-dashboard/template/src/app/alerts/page.tsx +157 -0
- package/dist/templates/web/iot-dashboard/template/src/app/api/auth/route.ts +57 -0
- package/dist/templates/web/iot-dashboard/template/src/app/devices/[id]/page.tsx +204 -0
- package/dist/templates/web/iot-dashboard/template/src/app/devices/new/page.tsx +139 -0
- package/dist/templates/web/iot-dashboard/template/src/app/devices/page.tsx +171 -0
- package/dist/templates/web/iot-dashboard/template/src/app/login/page.tsx +112 -0
- package/dist/templates/web/iot-dashboard/template/src/app/settings/page.tsx +186 -0
- package/dist/templates/web/iot-dashboard/template/src/app/signup/page.tsx +133 -0
- package/dist/templates/web/iot-dashboard/template/src/lib/auth-session.ts +52 -0
- package/dist/templates/web/marketplace/template/src/app/api/auth/route.ts +57 -0
- package/dist/templates/web/marketplace/template/src/app/login/page.tsx +112 -0
- package/dist/templates/web/marketplace/template/src/app/orders/page.tsx +160 -0
- package/dist/templates/web/marketplace/template/src/app/products/[id]/page.tsx +218 -0
- package/dist/templates/web/marketplace/template/src/app/settings/page.tsx +150 -0
- package/dist/templates/web/marketplace/template/src/app/signup/page.tsx +133 -0
- package/dist/templates/web/marketplace/template/src/lib/auth-session.ts +52 -0
- package/dist/templates/web/micro-saas/template/src/app/api/auth/route.ts +57 -0
- package/dist/templates/web/micro-saas/template/src/app/login/page.tsx +14 -3
- package/dist/templates/web/micro-saas/template/src/app/signup/page.tsx +15 -4
- package/dist/templates/web/micro-saas/template/src/lib/auth-session.ts +52 -0
- package/package.json +1 -1
- package/src/templates/web/ai-platform/template/src/app/api/auth/route.ts +57 -0
- package/src/templates/web/ai-platform/template/src/app/login/page.tsx +112 -0
- package/src/templates/web/ai-platform/template/src/app/models/page.tsx +186 -0
- package/src/templates/web/ai-platform/template/src/app/playground/page.tsx +251 -0
- package/src/templates/web/ai-platform/template/src/app/settings/page.tsx +190 -0
- package/src/templates/web/ai-platform/template/src/app/signup/page.tsx +133 -0
- package/src/templates/web/ai-platform/template/src/lib/auth-session.ts +52 -0
- package/src/templates/web/iot-dashboard/template/src/app/alerts/page.tsx +157 -0
- package/src/templates/web/iot-dashboard/template/src/app/api/auth/route.ts +57 -0
- package/src/templates/web/iot-dashboard/template/src/app/devices/[id]/page.tsx +204 -0
- package/src/templates/web/iot-dashboard/template/src/app/devices/new/page.tsx +139 -0
- package/src/templates/web/iot-dashboard/template/src/app/devices/page.tsx +171 -0
- package/src/templates/web/iot-dashboard/template/src/app/login/page.tsx +112 -0
- package/src/templates/web/iot-dashboard/template/src/app/settings/page.tsx +186 -0
- package/src/templates/web/iot-dashboard/template/src/app/signup/page.tsx +133 -0
- package/src/templates/web/iot-dashboard/template/src/lib/auth-session.ts +52 -0
- package/src/templates/web/marketplace/template/src/app/api/auth/route.ts +57 -0
- package/src/templates/web/marketplace/template/src/app/login/page.tsx +112 -0
- package/src/templates/web/marketplace/template/src/app/orders/page.tsx +160 -0
- package/src/templates/web/marketplace/template/src/app/products/[id]/page.tsx +218 -0
- package/src/templates/web/marketplace/template/src/app/settings/page.tsx +150 -0
- package/src/templates/web/marketplace/template/src/app/signup/page.tsx +133 -0
- package/src/templates/web/marketplace/template/src/lib/auth-session.ts +52 -0
- package/src/templates/web/micro-saas/template/src/app/api/auth/route.ts +57 -0
- package/src/templates/web/micro-saas/template/src/app/login/page.tsx +14 -3
- package/src/templates/web/micro-saas/template/src/app/signup/page.tsx +15 -4
- package/src/templates/web/micro-saas/template/src/lib/auth-session.ts +52 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useState } from 'react'
|
|
4
|
+
import { Button, Card } from '@digilogiclabs/saas-factory-ui'
|
|
5
|
+
import { Package, ChevronDown, ChevronUp, ShoppingBag } from 'lucide-react'
|
|
6
|
+
import Link from 'next/link'
|
|
7
|
+
|
|
8
|
+
interface OrderItem {
|
|
9
|
+
name: string
|
|
10
|
+
vendor: string
|
|
11
|
+
price: number
|
|
12
|
+
quantity: number
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface Order {
|
|
16
|
+
id: string
|
|
17
|
+
date: string
|
|
18
|
+
status: 'Delivered' | 'Processing' | 'Shipped'
|
|
19
|
+
total: number
|
|
20
|
+
items: OrderItem[]
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const ORDERS: Order[] = [
|
|
24
|
+
{
|
|
25
|
+
id: 'ORD-2024-001',
|
|
26
|
+
date: 'Mar 15, 2024',
|
|
27
|
+
status: 'Delivered',
|
|
28
|
+
total: 179.98,
|
|
29
|
+
items: [
|
|
30
|
+
{ name: 'Premium Widget Pro', vendor: 'TechCo', price: 49.99, quantity: 1 },
|
|
31
|
+
{ name: 'Developer Toolkit', vendor: 'DevTools', price: 129.99, quantity: 1 },
|
|
32
|
+
],
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
id: 'ORD-2024-002',
|
|
36
|
+
date: 'Mar 18, 2024',
|
|
37
|
+
status: 'Shipped',
|
|
38
|
+
total: 79.99,
|
|
39
|
+
items: [
|
|
40
|
+
{ name: 'UI Design Pack', vendor: 'CreativeStudio', price: 79.99, quantity: 1 },
|
|
41
|
+
],
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
id: 'ORD-2024-003',
|
|
45
|
+
date: 'Mar 20, 2024',
|
|
46
|
+
status: 'Processing',
|
|
47
|
+
total: 239.97,
|
|
48
|
+
items: [
|
|
49
|
+
{ name: 'Analytics Dashboard', vendor: 'DataCorp', price: 199.99, quantity: 1 },
|
|
50
|
+
{ name: 'Marketing Templates', vendor: 'GrowthLab', price: 39.99, quantity: 1 },
|
|
51
|
+
],
|
|
52
|
+
},
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
const STATUS_STYLES: Record<Order['status'], string> = {
|
|
56
|
+
Delivered: 'bg-green-500/10 text-green-600',
|
|
57
|
+
Processing: 'bg-blue-500/10 text-blue-600',
|
|
58
|
+
Shipped: 'bg-amber-500/10 text-amber-600',
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function OrderCard({ order }: { order: Order }) {
|
|
62
|
+
const [expanded, setExpanded] = useState(false)
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
<Card className="overflow-hidden">
|
|
66
|
+
<button
|
|
67
|
+
onClick={() => setExpanded(!expanded)}
|
|
68
|
+
className="w-full p-6 text-left cursor-pointer"
|
|
69
|
+
>
|
|
70
|
+
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4">
|
|
71
|
+
<div className="flex items-center gap-4">
|
|
72
|
+
<div className="w-10 h-10 bg-primary/10 rounded-lg flex items-center justify-center flex-shrink-0">
|
|
73
|
+
<Package className="w-5 h-5 text-primary" />
|
|
74
|
+
</div>
|
|
75
|
+
<div>
|
|
76
|
+
<p className="font-semibold text-foreground">{order.id}</p>
|
|
77
|
+
<p className="text-sm text-muted-foreground">{order.date}</p>
|
|
78
|
+
</div>
|
|
79
|
+
</div>
|
|
80
|
+
|
|
81
|
+
<div className="flex items-center gap-4 sm:gap-6">
|
|
82
|
+
<span className={`px-3 py-1 text-xs font-medium rounded-full ${STATUS_STYLES[order.status]}`}>
|
|
83
|
+
{order.status}
|
|
84
|
+
</span>
|
|
85
|
+
<span className="text-sm text-muted-foreground">
|
|
86
|
+
{order.items.length} {order.items.length === 1 ? 'item' : 'items'}
|
|
87
|
+
</span>
|
|
88
|
+
<span className="font-bold text-foreground">${order.total.toFixed(2)}</span>
|
|
89
|
+
{expanded ? (
|
|
90
|
+
<ChevronUp className="w-4 h-4 text-muted-foreground" />
|
|
91
|
+
) : (
|
|
92
|
+
<ChevronDown className="w-4 h-4 text-muted-foreground" />
|
|
93
|
+
)}
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
</button>
|
|
97
|
+
|
|
98
|
+
{expanded && (
|
|
99
|
+
<div className="border-t border-border px-6 pb-6">
|
|
100
|
+
<div className="space-y-3 pt-4">
|
|
101
|
+
{order.items.map((item, index) => (
|
|
102
|
+
<div key={index} className="flex items-center gap-4">
|
|
103
|
+
<div className="w-12 h-12 bg-muted rounded-lg flex-shrink-0" />
|
|
104
|
+
<div className="flex-1">
|
|
105
|
+
<p className="font-medium text-foreground">{item.name}</p>
|
|
106
|
+
<p className="text-sm text-muted-foreground">by {item.vendor}</p>
|
|
107
|
+
</div>
|
|
108
|
+
<div className="text-right">
|
|
109
|
+
<p className="font-medium text-foreground">${item.price.toFixed(2)}</p>
|
|
110
|
+
<p className="text-sm text-muted-foreground">Qty: {item.quantity}</p>
|
|
111
|
+
</div>
|
|
112
|
+
</div>
|
|
113
|
+
))}
|
|
114
|
+
</div>
|
|
115
|
+
</div>
|
|
116
|
+
)}
|
|
117
|
+
</Card>
|
|
118
|
+
)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export default function OrdersPage() {
|
|
122
|
+
// Note: In production, wrap with requireAuth() in a server component parent
|
|
123
|
+
// or use a layout-level auth check. This page uses 'use client' for expand/collapse.
|
|
124
|
+
const orders = ORDERS
|
|
125
|
+
|
|
126
|
+
return (
|
|
127
|
+
<div className="min-h-screen bg-background">
|
|
128
|
+
<div className="max-w-4xl mx-auto px-4 py-8">
|
|
129
|
+
{/* Header */}
|
|
130
|
+
<div className="mb-8">
|
|
131
|
+
<h1 className="text-3xl font-bold text-foreground">Your Orders</h1>
|
|
132
|
+
<p className="text-muted-foreground mt-1">
|
|
133
|
+
{orders.length} {orders.length === 1 ? 'order' : 'orders'}
|
|
134
|
+
</p>
|
|
135
|
+
</div>
|
|
136
|
+
|
|
137
|
+
{orders.length === 0 ? (
|
|
138
|
+
<Card className="p-12 text-center">
|
|
139
|
+
<ShoppingBag className="w-16 h-16 mx-auto mb-4 text-muted-foreground" />
|
|
140
|
+
<h2 className="text-xl font-semibold text-foreground mb-2">
|
|
141
|
+
No orders yet
|
|
142
|
+
</h2>
|
|
143
|
+
<p className="text-muted-foreground mb-6">
|
|
144
|
+
When you make a purchase, your orders will appear here.
|
|
145
|
+
</p>
|
|
146
|
+
<Link href="/products">
|
|
147
|
+
<Button>Browse Products</Button>
|
|
148
|
+
</Link>
|
|
149
|
+
</Card>
|
|
150
|
+
) : (
|
|
151
|
+
<div className="space-y-4">
|
|
152
|
+
{orders.map((order) => (
|
|
153
|
+
<OrderCard key={order.id} order={order} />
|
|
154
|
+
))}
|
|
155
|
+
</div>
|
|
156
|
+
)}
|
|
157
|
+
</div>
|
|
158
|
+
</div>
|
|
159
|
+
)
|
|
160
|
+
}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { Button, Card } from '@digilogiclabs/saas-factory-ui'
|
|
2
|
+
import { ArrowLeft, Star, ShoppingCart, MessageCircle, ShoppingBag } from 'lucide-react'
|
|
3
|
+
import Link from 'next/link'
|
|
4
|
+
|
|
5
|
+
const PRODUCTS: Record<string, {
|
|
6
|
+
id: string
|
|
7
|
+
name: string
|
|
8
|
+
price: number
|
|
9
|
+
vendor: string
|
|
10
|
+
rating: number
|
|
11
|
+
reviews: number
|
|
12
|
+
category: string
|
|
13
|
+
description: string
|
|
14
|
+
features: string[]
|
|
15
|
+
}> = {
|
|
16
|
+
'1': {
|
|
17
|
+
id: '1',
|
|
18
|
+
name: 'Premium Widget Pro',
|
|
19
|
+
price: 49.99,
|
|
20
|
+
vendor: 'TechCo',
|
|
21
|
+
rating: 4.8,
|
|
22
|
+
reviews: 124,
|
|
23
|
+
category: 'Software',
|
|
24
|
+
description: 'A comprehensive widget toolkit that helps developers build beautiful, responsive interfaces in minutes. Includes 50+ pre-built components, dark mode support, and full TypeScript definitions. Perfect for startups and teams looking to ship faster without sacrificing quality.',
|
|
25
|
+
features: ['50+ Pre-built Components', 'Dark Mode Support', 'TypeScript Definitions', 'Lifetime Updates'],
|
|
26
|
+
},
|
|
27
|
+
'2': {
|
|
28
|
+
id: '2',
|
|
29
|
+
name: 'Developer Toolkit',
|
|
30
|
+
price: 129.99,
|
|
31
|
+
vendor: 'DevTools',
|
|
32
|
+
rating: 4.9,
|
|
33
|
+
reviews: 87,
|
|
34
|
+
category: 'Software',
|
|
35
|
+
description: 'The ultimate developer toolkit packed with debugging utilities, code generators, and productivity boosters. Streamline your development workflow with intelligent code analysis, automated refactoring tools, and seamless CI/CD integration.',
|
|
36
|
+
features: ['Code Generator', 'Debugging Utilities', 'CI/CD Integration', 'Team Collaboration'],
|
|
37
|
+
},
|
|
38
|
+
'3': {
|
|
39
|
+
id: '3',
|
|
40
|
+
name: 'UI Design Pack',
|
|
41
|
+
price: 79.99,
|
|
42
|
+
vendor: 'CreativeStudio',
|
|
43
|
+
rating: 4.7,
|
|
44
|
+
reviews: 203,
|
|
45
|
+
category: 'Templates',
|
|
46
|
+
description: 'A stunning collection of UI design templates for web and mobile applications. Each template is fully customizable and built with modern design principles. Includes Figma source files, responsive layouts, and component documentation.',
|
|
47
|
+
features: ['Figma Source Files', 'Responsive Layouts', 'Component Docs', '100+ Screens'],
|
|
48
|
+
},
|
|
49
|
+
'4': {
|
|
50
|
+
id: '4',
|
|
51
|
+
name: 'Analytics Dashboard',
|
|
52
|
+
price: 199.99,
|
|
53
|
+
vendor: 'DataCorp',
|
|
54
|
+
rating: 4.6,
|
|
55
|
+
reviews: 56,
|
|
56
|
+
category: 'Software',
|
|
57
|
+
description: 'Real-time analytics dashboard with advanced data visualization capabilities. Track key metrics, create custom reports, and share insights with your team. Supports multiple data sources and provides AI-powered trend analysis.',
|
|
58
|
+
features: ['Real-time Analytics', 'Custom Reports', 'AI Trend Analysis', 'Multi-source Support'],
|
|
59
|
+
},
|
|
60
|
+
'5': {
|
|
61
|
+
id: '5',
|
|
62
|
+
name: 'Marketing Templates',
|
|
63
|
+
price: 39.99,
|
|
64
|
+
vendor: 'GrowthLab',
|
|
65
|
+
rating: 4.5,
|
|
66
|
+
reviews: 312,
|
|
67
|
+
category: 'Templates',
|
|
68
|
+
description: 'Ready-to-use marketing templates for landing pages, email campaigns, and social media. Conversion-optimized designs backed by A/B testing data from thousands of campaigns.',
|
|
69
|
+
features: ['Landing Pages', 'Email Templates', 'Social Media Kit', 'A/B Tested Designs'],
|
|
70
|
+
},
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const RELATED_PRODUCTS = [
|
|
74
|
+
{ id: '2', name: 'Developer Toolkit', price: 129.99, vendor: 'DevTools', rating: 4.9, category: 'Software' },
|
|
75
|
+
{ id: '3', name: 'UI Design Pack', price: 79.99, vendor: 'CreativeStudio', rating: 4.7, category: 'Templates' },
|
|
76
|
+
{ id: '5', name: 'Marketing Templates', price: 39.99, vendor: 'GrowthLab', rating: 4.5, category: 'Templates' },
|
|
77
|
+
]
|
|
78
|
+
|
|
79
|
+
function StarRating({ rating, reviews }: { rating: number; reviews: number }) {
|
|
80
|
+
return (
|
|
81
|
+
<div className="flex items-center gap-2">
|
|
82
|
+
<div className="flex items-center">
|
|
83
|
+
{[...Array(5)].map((_, i) => (
|
|
84
|
+
<Star
|
|
85
|
+
key={i}
|
|
86
|
+
className={`w-5 h-5 ${
|
|
87
|
+
i < Math.floor(rating)
|
|
88
|
+
? 'text-amber-500 fill-amber-500'
|
|
89
|
+
: i < rating
|
|
90
|
+
? 'text-amber-500 fill-amber-500/50'
|
|
91
|
+
: 'text-muted-foreground/30'
|
|
92
|
+
}`}
|
|
93
|
+
/>
|
|
94
|
+
))}
|
|
95
|
+
</div>
|
|
96
|
+
<span className="text-sm text-muted-foreground">
|
|
97
|
+
{rating} ({reviews} reviews)
|
|
98
|
+
</span>
|
|
99
|
+
</div>
|
|
100
|
+
)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export default async function ProductDetailPage({
|
|
104
|
+
params,
|
|
105
|
+
}: {
|
|
106
|
+
params: Promise<{ id: string }>
|
|
107
|
+
}) {
|
|
108
|
+
const { id } = await params
|
|
109
|
+
const product = PRODUCTS[id] || PRODUCTS['1']
|
|
110
|
+
|
|
111
|
+
const relatedProducts = RELATED_PRODUCTS.filter(p => p.id !== product.id).slice(0, 3)
|
|
112
|
+
|
|
113
|
+
return (
|
|
114
|
+
<div className="min-h-screen bg-background">
|
|
115
|
+
<div className="max-w-7xl mx-auto px-4 py-8">
|
|
116
|
+
{/* Back Link */}
|
|
117
|
+
<Link
|
|
118
|
+
href="/products"
|
|
119
|
+
className="inline-flex items-center text-sm text-muted-foreground hover:text-foreground mb-6 transition-colors"
|
|
120
|
+
>
|
|
121
|
+
<ArrowLeft className="w-4 h-4 mr-1" />
|
|
122
|
+
Back to Products
|
|
123
|
+
</Link>
|
|
124
|
+
|
|
125
|
+
{/* Product Detail */}
|
|
126
|
+
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8 mb-16">
|
|
127
|
+
{/* Product Image */}
|
|
128
|
+
<div className="aspect-video bg-muted rounded-xl flex items-center justify-center border border-border">
|
|
129
|
+
<div className="text-center">
|
|
130
|
+
<ShoppingBag className="w-16 h-16 mx-auto text-muted-foreground/30 mb-2" />
|
|
131
|
+
<p className="text-sm text-muted-foreground">Product Preview</p>
|
|
132
|
+
</div>
|
|
133
|
+
</div>
|
|
134
|
+
|
|
135
|
+
{/* Product Info */}
|
|
136
|
+
<div>
|
|
137
|
+
<div className="mb-4">
|
|
138
|
+
<span className="inline-block px-3 py-1 text-xs font-medium bg-primary text-primary-foreground rounded-full mb-3">
|
|
139
|
+
{product.category}
|
|
140
|
+
</span>
|
|
141
|
+
<h1 className="text-2xl font-bold text-foreground mb-2">
|
|
142
|
+
{product.name}
|
|
143
|
+
</h1>
|
|
144
|
+
<p className="text-muted-foreground">
|
|
145
|
+
by {product.vendor}
|
|
146
|
+
</p>
|
|
147
|
+
</div>
|
|
148
|
+
|
|
149
|
+
<StarRating rating={product.rating} reviews={product.reviews} />
|
|
150
|
+
|
|
151
|
+
<p className="text-3xl font-bold text-primary mt-4 mb-6">
|
|
152
|
+
${product.price}
|
|
153
|
+
</p>
|
|
154
|
+
|
|
155
|
+
<p className="text-muted-foreground leading-relaxed mb-6">
|
|
156
|
+
{product.description}
|
|
157
|
+
</p>
|
|
158
|
+
|
|
159
|
+
{/* Features */}
|
|
160
|
+
<div className="mb-6">
|
|
161
|
+
<h3 className="text-sm font-semibold text-foreground mb-3">What's Included</h3>
|
|
162
|
+
<ul className="grid grid-cols-2 gap-2">
|
|
163
|
+
{product.features.map((feature) => (
|
|
164
|
+
<li key={feature} className="flex items-center text-sm text-muted-foreground">
|
|
165
|
+
<span className="w-1.5 h-1.5 bg-primary rounded-full mr-2 flex-shrink-0" />
|
|
166
|
+
{feature}
|
|
167
|
+
</li>
|
|
168
|
+
))}
|
|
169
|
+
</ul>
|
|
170
|
+
</div>
|
|
171
|
+
|
|
172
|
+
{/* Actions */}
|
|
173
|
+
<div className="flex gap-3">
|
|
174
|
+
<Button size="lg" className="flex-1">
|
|
175
|
+
<ShoppingCart className="w-4 h-4 mr-2" />
|
|
176
|
+
Add to Cart
|
|
177
|
+
</Button>
|
|
178
|
+
<Button variant="outline" size="lg" className="flex-1">
|
|
179
|
+
<MessageCircle className="w-4 h-4 mr-2" />
|
|
180
|
+
Contact Vendor
|
|
181
|
+
</Button>
|
|
182
|
+
</div>
|
|
183
|
+
</div>
|
|
184
|
+
</div>
|
|
185
|
+
|
|
186
|
+
{/* Related Products */}
|
|
187
|
+
<div>
|
|
188
|
+
<h2 className="text-2xl font-bold text-foreground mb-6">Related Products</h2>
|
|
189
|
+
<div className="grid grid-cols-1 sm:grid-cols-3 gap-6">
|
|
190
|
+
{relatedProducts.map((item) => (
|
|
191
|
+
<Card key={item.id} className="overflow-hidden hover:shadow-lg transition-shadow">
|
|
192
|
+
<div className="aspect-square bg-muted relative">
|
|
193
|
+
<span className="absolute top-2 left-2 bg-primary text-primary-foreground text-xs px-2 py-1 rounded">
|
|
194
|
+
{item.category}
|
|
195
|
+
</span>
|
|
196
|
+
</div>
|
|
197
|
+
<div className="p-4">
|
|
198
|
+
<h3 className="font-semibold text-foreground mb-1">{item.name}</h3>
|
|
199
|
+
<p className="text-sm text-muted-foreground mb-2">by {item.vendor}</p>
|
|
200
|
+
<div className="flex items-center justify-between mb-3">
|
|
201
|
+
<span className="text-lg font-bold text-primary">${item.price}</span>
|
|
202
|
+
<div className="flex items-center text-amber-500">
|
|
203
|
+
<Star className="w-4 h-4 fill-current" />
|
|
204
|
+
<span className="text-sm ml-1">{item.rating}</span>
|
|
205
|
+
</div>
|
|
206
|
+
</div>
|
|
207
|
+
<Link href={`/products/${item.id}`}>
|
|
208
|
+
<Button variant="outline" size="sm" className="w-full">View Details</Button>
|
|
209
|
+
</Link>
|
|
210
|
+
</div>
|
|
211
|
+
</Card>
|
|
212
|
+
))}
|
|
213
|
+
</div>
|
|
214
|
+
</div>
|
|
215
|
+
</div>
|
|
216
|
+
</div>
|
|
217
|
+
)
|
|
218
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { Button, Card } from '@digilogiclabs/saas-factory-ui'
|
|
2
|
+
import { User, Bell, CreditCard } from 'lucide-react'
|
|
3
|
+
import { requireAuth } from '@/lib/auth-server'
|
|
4
|
+
|
|
5
|
+
function ToggleSwitch({ defaultChecked = false }: { defaultChecked?: boolean }) {
|
|
6
|
+
return (
|
|
7
|
+
<label className="relative inline-flex items-center cursor-pointer">
|
|
8
|
+
<input type="checkbox" className="sr-only peer" defaultChecked={defaultChecked} />
|
|
9
|
+
<div className="w-11 h-6 bg-muted rounded-full peer peer-checked:bg-primary peer-focus:ring-2 peer-focus:ring-ring after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-background after:border after:border-border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:after:translate-x-full" />
|
|
10
|
+
</label>
|
|
11
|
+
)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export default async function SettingsPage() {
|
|
15
|
+
const user = await requireAuth()
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<div className="min-h-screen bg-background">
|
|
19
|
+
<div className="max-w-3xl mx-auto px-4 py-8">
|
|
20
|
+
{/* Header */}
|
|
21
|
+
<div className="mb-8">
|
|
22
|
+
<h1 className="text-3xl font-bold text-foreground">Settings</h1>
|
|
23
|
+
<p className="text-muted-foreground mt-1">
|
|
24
|
+
Manage your account preferences
|
|
25
|
+
</p>
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<div className="space-y-6">
|
|
29
|
+
{/* Profile Section */}
|
|
30
|
+
<Card className="p-6">
|
|
31
|
+
<div className="flex items-center gap-3 mb-6">
|
|
32
|
+
<User className="w-5 h-5 text-primary" />
|
|
33
|
+
<h2 className="text-lg font-semibold text-foreground">Profile</h2>
|
|
34
|
+
</div>
|
|
35
|
+
|
|
36
|
+
<div className="space-y-4">
|
|
37
|
+
{/* Avatar */}
|
|
38
|
+
<div className="flex items-center gap-4 mb-6">
|
|
39
|
+
<div className="w-16 h-16 bg-muted rounded-full flex items-center justify-center border border-border">
|
|
40
|
+
<User className="w-8 h-8 text-muted-foreground" />
|
|
41
|
+
</div>
|
|
42
|
+
<Button variant="outline" size="sm">Change Avatar</Button>
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
{/* Name */}
|
|
46
|
+
<div>
|
|
47
|
+
<label htmlFor="name" className="block text-sm font-medium text-foreground mb-1.5">
|
|
48
|
+
Display Name
|
|
49
|
+
</label>
|
|
50
|
+
<input
|
|
51
|
+
id="name"
|
|
52
|
+
type="text"
|
|
53
|
+
defaultValue={user.name || ''}
|
|
54
|
+
placeholder="Your name"
|
|
55
|
+
className="w-full px-4 py-2 border border-input rounded-lg focus:ring-2 focus:ring-ring bg-background text-foreground"
|
|
56
|
+
/>
|
|
57
|
+
</div>
|
|
58
|
+
|
|
59
|
+
{/* Email (read-only) */}
|
|
60
|
+
<div>
|
|
61
|
+
<label htmlFor="email" className="block text-sm font-medium text-foreground mb-1.5">
|
|
62
|
+
Email Address
|
|
63
|
+
</label>
|
|
64
|
+
<input
|
|
65
|
+
id="email"
|
|
66
|
+
type="email"
|
|
67
|
+
value={user.email || ''}
|
|
68
|
+
readOnly
|
|
69
|
+
className="w-full px-4 py-2 border border-input rounded-lg bg-muted text-muted-foreground cursor-not-allowed"
|
|
70
|
+
/>
|
|
71
|
+
<p className="text-xs text-muted-foreground mt-1">
|
|
72
|
+
Email cannot be changed. Contact support if you need to update it.
|
|
73
|
+
</p>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
</Card>
|
|
77
|
+
|
|
78
|
+
{/* Notification Preferences */}
|
|
79
|
+
<Card className="p-6">
|
|
80
|
+
<div className="flex items-center gap-3 mb-6">
|
|
81
|
+
<Bell className="w-5 h-5 text-primary" />
|
|
82
|
+
<h2 className="text-lg font-semibold text-foreground">Notifications</h2>
|
|
83
|
+
</div>
|
|
84
|
+
|
|
85
|
+
<div className="space-y-4">
|
|
86
|
+
<div className="flex items-center justify-between py-2">
|
|
87
|
+
<div>
|
|
88
|
+
<p className="font-medium text-foreground">Order Updates</p>
|
|
89
|
+
<p className="text-sm text-muted-foreground">
|
|
90
|
+
Get notified when your order status changes
|
|
91
|
+
</p>
|
|
92
|
+
</div>
|
|
93
|
+
<ToggleSwitch defaultChecked />
|
|
94
|
+
</div>
|
|
95
|
+
|
|
96
|
+
<div className="border-t border-border" />
|
|
97
|
+
|
|
98
|
+
<div className="flex items-center justify-between py-2">
|
|
99
|
+
<div>
|
|
100
|
+
<p className="font-medium text-foreground">Marketing Emails</p>
|
|
101
|
+
<p className="text-sm text-muted-foreground">
|
|
102
|
+
Receive deals, promotions, and product recommendations
|
|
103
|
+
</p>
|
|
104
|
+
</div>
|
|
105
|
+
<ToggleSwitch />
|
|
106
|
+
</div>
|
|
107
|
+
|
|
108
|
+
<div className="border-t border-border" />
|
|
109
|
+
|
|
110
|
+
<div className="flex items-center justify-between py-2">
|
|
111
|
+
<div>
|
|
112
|
+
<p className="font-medium text-foreground">Vendor Messages</p>
|
|
113
|
+
<p className="text-sm text-muted-foreground">
|
|
114
|
+
Get notified when a vendor replies to your message
|
|
115
|
+
</p>
|
|
116
|
+
</div>
|
|
117
|
+
<ToggleSwitch defaultChecked />
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
</Card>
|
|
121
|
+
|
|
122
|
+
{/* Payment Methods */}
|
|
123
|
+
<Card className="p-6">
|
|
124
|
+
<div className="flex items-center gap-3 mb-6">
|
|
125
|
+
<CreditCard className="w-5 h-5 text-primary" />
|
|
126
|
+
<h2 className="text-lg font-semibold text-foreground">Payment Methods</h2>
|
|
127
|
+
</div>
|
|
128
|
+
|
|
129
|
+
<div className="text-center py-6">
|
|
130
|
+
<CreditCard className="w-12 h-12 mx-auto mb-3 text-muted-foreground/50" />
|
|
131
|
+
<p className="text-muted-foreground mb-4">
|
|
132
|
+
No payment methods saved yet
|
|
133
|
+
</p>
|
|
134
|
+
<Button variant="outline">
|
|
135
|
+
Add Payment Method
|
|
136
|
+
</Button>
|
|
137
|
+
</div>
|
|
138
|
+
</Card>
|
|
139
|
+
|
|
140
|
+
{/* Save Button */}
|
|
141
|
+
<div className="flex justify-end">
|
|
142
|
+
<Button size="lg">
|
|
143
|
+
Save Changes
|
|
144
|
+
</Button>
|
|
145
|
+
</div>
|
|
146
|
+
</div>
|
|
147
|
+
</div>
|
|
148
|
+
</div>
|
|
149
|
+
)
|
|
150
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useState } from 'react'
|
|
4
|
+
import { Button, Card, CardContent } from '@digilogiclabs/saas-factory-ui'
|
|
5
|
+
import { ShoppingBag } from 'lucide-react'
|
|
6
|
+
import { useRouter } from 'next/navigation'
|
|
7
|
+
import Link from 'next/link'
|
|
8
|
+
|
|
9
|
+
export default function SignupPage() {
|
|
10
|
+
const [email, setEmail] = useState('')
|
|
11
|
+
const [password, setPassword] = useState('')
|
|
12
|
+
const [confirmPassword, setConfirmPassword] = useState('')
|
|
13
|
+
const [error, setError] = useState('')
|
|
14
|
+
const [loading, setLoading] = useState(false)
|
|
15
|
+
const router = useRouter()
|
|
16
|
+
|
|
17
|
+
const handleSubmit = async (e: React.FormEvent) => {
|
|
18
|
+
e.preventDefault()
|
|
19
|
+
setError('')
|
|
20
|
+
if (password !== confirmPassword) {
|
|
21
|
+
setError('Passwords do not match')
|
|
22
|
+
return
|
|
23
|
+
}
|
|
24
|
+
setLoading(true)
|
|
25
|
+
try {
|
|
26
|
+
const res = await fetch('/api/auth', {
|
|
27
|
+
method: 'POST',
|
|
28
|
+
headers: { 'Content-Type': 'application/json' },
|
|
29
|
+
body: JSON.stringify({ email, password, action: 'signup' }),
|
|
30
|
+
})
|
|
31
|
+
if (!res.ok) {
|
|
32
|
+
const data = await res.json()
|
|
33
|
+
throw new Error(data.error || 'Failed to create account')
|
|
34
|
+
}
|
|
35
|
+
router.push('/dashboard')
|
|
36
|
+
router.refresh()
|
|
37
|
+
} catch (err) {
|
|
38
|
+
setError(err instanceof Error ? err.message : 'Failed to create account')
|
|
39
|
+
} finally {
|
|
40
|
+
setLoading(false)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<div className="min-h-screen flex items-center justify-center bg-background px-4">
|
|
46
|
+
<div className="w-full max-w-md">
|
|
47
|
+
{/* Logo */}
|
|
48
|
+
<Link href="/" className="flex items-center justify-center gap-2 mb-8 hover:opacity-80 transition-opacity">
|
|
49
|
+
<div className="w-10 h-10 rounded-xl bg-gradient-to-br from-brand-from via-brand-via to-brand-to flex items-center justify-center">
|
|
50
|
+
<ShoppingBag className="w-5 h-5 text-white" />
|
|
51
|
+
</div>
|
|
52
|
+
<span className="font-bold text-xl">Marketplace</span>
|
|
53
|
+
</Link>
|
|
54
|
+
|
|
55
|
+
<Card className="border border-border">
|
|
56
|
+
<CardContent className="p-8">
|
|
57
|
+
<div className="text-center mb-8">
|
|
58
|
+
<h1 className="text-2xl font-bold">Create your account</h1>
|
|
59
|
+
<p className="text-muted-foreground mt-2">Start buying and selling today</p>
|
|
60
|
+
</div>
|
|
61
|
+
|
|
62
|
+
{error && (
|
|
63
|
+
<div className="bg-destructive/10 text-destructive p-3 rounded-lg mb-6 text-sm" role="alert">
|
|
64
|
+
{error}
|
|
65
|
+
</div>
|
|
66
|
+
)}
|
|
67
|
+
|
|
68
|
+
<form onSubmit={handleSubmit} className="space-y-4">
|
|
69
|
+
<div>
|
|
70
|
+
<label htmlFor="email" className="block text-sm font-medium mb-1.5">
|
|
71
|
+
Email
|
|
72
|
+
</label>
|
|
73
|
+
<input
|
|
74
|
+
id="email"
|
|
75
|
+
type="email"
|
|
76
|
+
value={email}
|
|
77
|
+
onChange={(e) => setEmail(e.target.value)}
|
|
78
|
+
className="w-full px-3 py-2.5 rounded-lg border border-input bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:border-transparent transition-shadow"
|
|
79
|
+
placeholder="you@example.com"
|
|
80
|
+
required
|
|
81
|
+
/>
|
|
82
|
+
</div>
|
|
83
|
+
|
|
84
|
+
<div>
|
|
85
|
+
<label htmlFor="password" className="block text-sm font-medium mb-1.5">
|
|
86
|
+
Password
|
|
87
|
+
</label>
|
|
88
|
+
<input
|
|
89
|
+
id="password"
|
|
90
|
+
type="password"
|
|
91
|
+
value={password}
|
|
92
|
+
onChange={(e) => setPassword(e.target.value)}
|
|
93
|
+
className="w-full px-3 py-2.5 rounded-lg border border-input bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:border-transparent transition-shadow"
|
|
94
|
+
placeholder="Minimum 8 characters"
|
|
95
|
+
required
|
|
96
|
+
minLength={8}
|
|
97
|
+
/>
|
|
98
|
+
</div>
|
|
99
|
+
|
|
100
|
+
<div>
|
|
101
|
+
<label htmlFor="confirmPassword" className="block text-sm font-medium mb-1.5">
|
|
102
|
+
Confirm Password
|
|
103
|
+
</label>
|
|
104
|
+
<input
|
|
105
|
+
id="confirmPassword"
|
|
106
|
+
type="password"
|
|
107
|
+
value={confirmPassword}
|
|
108
|
+
onChange={(e) => setConfirmPassword(e.target.value)}
|
|
109
|
+
className="w-full px-3 py-2.5 rounded-lg border border-input bg-background text-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:border-transparent transition-shadow"
|
|
110
|
+
placeholder="Re-enter your password"
|
|
111
|
+
required
|
|
112
|
+
/>
|
|
113
|
+
</div>
|
|
114
|
+
|
|
115
|
+
<Button type="submit" className="w-full h-11 text-base cursor-pointer hover:brightness-110 active:scale-[0.98] transition-all duration-200" disabled={loading}>
|
|
116
|
+
{loading ? 'Creating account...' : 'Create Account'}
|
|
117
|
+
</Button>
|
|
118
|
+
</form>
|
|
119
|
+
|
|
120
|
+
<div className="mt-6 text-center">
|
|
121
|
+
<p className="text-muted-foreground text-sm">
|
|
122
|
+
Already have an account?{' '}
|
|
123
|
+
<Link href="/login" className="text-primary hover:underline font-medium">
|
|
124
|
+
Sign in
|
|
125
|
+
</Link>
|
|
126
|
+
</p>
|
|
127
|
+
</div>
|
|
128
|
+
</CardContent>
|
|
129
|
+
</Card>
|
|
130
|
+
</div>
|
|
131
|
+
</div>
|
|
132
|
+
)
|
|
133
|
+
}
|