@digilogiclabs/create-saas-app 1.14.0 → 1.17.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 +134 -29
- package/bin/index.js +1 -1
- package/dist/.tsbuildinfo +1 -1
- package/dist/cli/prompts/project-setup.d.ts.map +1 -1
- package/dist/cli/prompts/project-setup.js +45 -12
- package/dist/cli/prompts/project-setup.js.map +1 -1
- package/dist/generators/template-generator.d.ts.map +1 -1
- package/dist/generators/template-generator.js +27 -4
- package/dist/generators/template-generator.js.map +1 -1
- package/dist/templates/mobile/ui-auth-payments/template/.env.example +20 -0
- package/dist/templates/mobile/ui-auth-payments/template/README.md +218 -0
- package/dist/templates/mobile/ui-auth-payments/template/app/(tabs)/_layout.tsx +153 -0
- package/dist/templates/mobile/ui-auth-payments/template/app/(tabs)/analytics.tsx +668 -0
- package/dist/templates/mobile/ui-auth-payments/template/app/(tabs)/billing.tsx +743 -0
- package/dist/templates/mobile/ui-auth-payments/template/app/(tabs)/index.tsx +676 -0
- package/dist/templates/mobile/ui-auth-payments/template/app/(tabs)/orders.tsx +402 -0
- package/dist/templates/mobile/ui-auth-payments/template/app/(tabs)/profile.tsx +580 -0
- package/dist/templates/mobile/ui-auth-payments/template/app/_layout.tsx +125 -0
- package/dist/templates/mobile/ui-auth-payments/template/app/auth/login.tsx +246 -0
- package/dist/templates/mobile/ui-auth-payments/template/app/auth/signup.tsx +362 -0
- package/dist/templates/mobile/ui-auth-payments/template/app/onboarding/index.tsx +193 -0
- package/dist/templates/mobile/ui-auth-payments/template/app/tour/index.tsx +272 -0
- package/dist/templates/mobile/ui-auth-payments/template/app.json +93 -0
- package/dist/templates/mobile/ui-auth-payments/template/babel.config.js +23 -0
- package/dist/templates/mobile/ui-auth-payments/template/eas.json +45 -0
- package/dist/templates/mobile/ui-auth-payments/template/expo-env.d.ts +3 -0
- package/dist/templates/mobile/ui-auth-payments/template/jest-setup.ts +74 -0
- package/dist/templates/mobile/ui-auth-payments/template/metro.config.js +11 -0
- package/dist/templates/mobile/ui-auth-payments/template/package.json +106 -0
- package/dist/templates/mobile/ui-auth-payments/template/tsconfig.json +31 -0
- package/dist/templates/web/base/template/src/app/dashboard/page.tsx +62 -20
- package/dist/templates/web/ui-auth/template/package.json +1 -1
- package/dist/templates/web/ui-auth-payments/template/package.json +1 -1
- package/dist/templates/web/ui-auth-payments/template/src/app/dashboard/page.tsx +69 -17
- package/dist/templates/web/ui-auth-payments-ai/template/package.json +1 -1
- package/dist/templates/web/ui-auth-payments-ai/template/src/app/billing/page.tsx +218 -7
- package/dist/templates/web/ui-auth-payments-ai/template/src/app/dashboard/page.tsx +62 -9
- package/dist/templates/web/ui-auth-payments-ai/template/src/app/onboarding/page.tsx +364 -0
- package/dist/templates/web/ui-auth-payments-ai/template/src/app/settings/page.tsx +532 -0
- package/dist/templates/web/ui-auth-payments-ai/template/src/components/client/login-form.tsx +70 -51
- package/dist/templates/web/ui-auth-payments-ai/template/src/components/client/signup-form.tsx +76 -60
- package/dist/templates/web/ui-auth-payments-ai/template/src/components/shared/header.tsx +1 -1
- package/dist/templates/web/ui-auth-payments-audio/template/package.json +1 -1
- package/dist/templates/web/ui-auth-payments-audio/template/src/app/dashboard/page.tsx +71 -17
- package/dist/templates/web/ui-auth-payments-audio/template/src/components/shared/header.tsx +1 -1
- package/dist/templates/web/ui-auth-payments-video/template/package.json +1 -1
- package/package.json +1 -1
- package/src/templates/mobile/ui-auth-payments/template/.env.example +20 -0
- package/src/templates/mobile/ui-auth-payments/template/README.md +218 -0
- package/src/templates/mobile/ui-auth-payments/template/app/(tabs)/_layout.tsx +153 -0
- package/src/templates/mobile/ui-auth-payments/template/app/(tabs)/analytics.tsx +668 -0
- package/src/templates/mobile/ui-auth-payments/template/app/(tabs)/billing.tsx +743 -0
- package/src/templates/mobile/ui-auth-payments/template/app/(tabs)/index.tsx +676 -0
- package/src/templates/mobile/ui-auth-payments/template/app/(tabs)/orders.tsx +402 -0
- package/src/templates/mobile/ui-auth-payments/template/app/(tabs)/profile.tsx +580 -0
- package/src/templates/mobile/ui-auth-payments/template/app/_layout.tsx +125 -0
- package/src/templates/mobile/ui-auth-payments/template/app/auth/login.tsx +246 -0
- package/src/templates/mobile/ui-auth-payments/template/app/auth/signup.tsx +362 -0
- package/src/templates/mobile/ui-auth-payments/template/app/onboarding/index.tsx +193 -0
- package/src/templates/mobile/ui-auth-payments/template/app/tour/index.tsx +272 -0
- package/src/templates/mobile/ui-auth-payments/template/app.json +93 -0
- package/src/templates/mobile/ui-auth-payments/template/babel.config.js +23 -0
- package/src/templates/mobile/ui-auth-payments/template/eas.json +45 -0
- package/src/templates/mobile/ui-auth-payments/template/expo-env.d.ts +3 -0
- package/src/templates/mobile/ui-auth-payments/template/jest-setup.ts +74 -0
- package/src/templates/mobile/ui-auth-payments/template/metro.config.js +11 -0
- package/src/templates/mobile/ui-auth-payments/template/package.json +106 -0
- package/src/templates/mobile/ui-auth-payments/template/tsconfig.json +31 -0
- package/src/templates/web/base/template/src/app/dashboard/page.tsx +62 -20
- package/src/templates/web/ui-auth/template/package.json +1 -1
- package/src/templates/web/ui-auth-payments/template/package.json +1 -1
- package/src/templates/web/ui-auth-payments/template/src/app/dashboard/page.tsx +69 -17
- package/src/templates/web/ui-auth-payments-ai/template/package.json +1 -1
- package/src/templates/web/ui-auth-payments-ai/template/src/app/billing/page.tsx +218 -7
- package/src/templates/web/ui-auth-payments-ai/template/src/app/dashboard/page.tsx +62 -9
- package/src/templates/web/ui-auth-payments-ai/template/src/app/onboarding/page.tsx +364 -0
- package/src/templates/web/ui-auth-payments-ai/template/src/app/settings/page.tsx +532 -0
- package/src/templates/web/ui-auth-payments-ai/template/src/components/client/login-form.tsx +70 -51
- package/src/templates/web/ui-auth-payments-ai/template/src/components/client/signup-form.tsx +76 -60
- package/src/templates/web/ui-auth-payments-ai/template/src/components/shared/header.tsx +1 -1
- package/src/templates/web/ui-auth-payments-audio/template/package.json +1 -1
- package/src/templates/web/ui-auth-payments-audio/template/src/app/dashboard/page.tsx +71 -17
- package/src/templates/web/ui-auth-payments-audio/template/src/components/shared/header.tsx +1 -1
- package/src/templates/web/ui-auth-payments-video/template/package.json +1 -1
|
@@ -0,0 +1,532 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import React, { useState } from 'react'
|
|
4
|
+
import {
|
|
5
|
+
FormBuilder,
|
|
6
|
+
FormSection,
|
|
7
|
+
FormField,
|
|
8
|
+
FormProvider,
|
|
9
|
+
Button,
|
|
10
|
+
Card,
|
|
11
|
+
MobileContainer,
|
|
12
|
+
PageTransition,
|
|
13
|
+
Tabs,
|
|
14
|
+
TabsList,
|
|
15
|
+
TabsTrigger,
|
|
16
|
+
TabsContent
|
|
17
|
+
} from '@digilogiclabs/saas-factory-ui'
|
|
18
|
+
import { useAuth } from '@digilogiclabs/saas-factory-auth'
|
|
19
|
+
import { useRouter } from 'next/navigation'
|
|
20
|
+
import {
|
|
21
|
+
User,
|
|
22
|
+
Shield,
|
|
23
|
+
Brain,
|
|
24
|
+
Bell,
|
|
25
|
+
Palette,
|
|
26
|
+
Database,
|
|
27
|
+
Key,
|
|
28
|
+
Users,
|
|
29
|
+
ArrowLeft,
|
|
30
|
+
Save
|
|
31
|
+
} from 'lucide-react'
|
|
32
|
+
import Link from 'next/link'
|
|
33
|
+
|
|
34
|
+
export default function SettingsPage() {
|
|
35
|
+
const { user } = useAuth()
|
|
36
|
+
const router = useRouter()
|
|
37
|
+
const [activeTab, setActiveTab] = useState('profile')
|
|
38
|
+
const [isLoading, setIsLoading] = useState(false)
|
|
39
|
+
|
|
40
|
+
if (!user) {
|
|
41
|
+
router.push('/login')
|
|
42
|
+
return null
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const handleSaveSettings = async (formData: FormData, section: string) => {
|
|
46
|
+
setIsLoading(true)
|
|
47
|
+
console.log(`Saving ${section} settings:`, Object.fromEntries(formData))
|
|
48
|
+
|
|
49
|
+
// Simulate API call
|
|
50
|
+
await new Promise(resolve => setTimeout(resolve, 1000))
|
|
51
|
+
|
|
52
|
+
setIsLoading(false)
|
|
53
|
+
// Show success message
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<PageTransition type="slide" direction="up" duration={300}>
|
|
58
|
+
<main className="min-h-screen bg-gradient-to-br from-primary/5 via-background to-secondary/5">
|
|
59
|
+
<MobileContainer className="py-8">
|
|
60
|
+
{/* Header */}
|
|
61
|
+
<div className="flex items-center justify-between mb-8">
|
|
62
|
+
<div className="flex items-center gap-4">
|
|
63
|
+
<Link href="/dashboard" className="p-2 rounded-xl bg-white/10 backdrop-blur-md border border-white/20 hover:scale-105 transition-transform">
|
|
64
|
+
<ArrowLeft className="w-5 h-5" />
|
|
65
|
+
</Link>
|
|
66
|
+
<div>
|
|
67
|
+
<h1 className="text-2xl font-bold">Settings</h1>
|
|
68
|
+
<p className="text-gray-600 dark:text-gray-300">Manage your account and preferences</p>
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
|
|
73
|
+
<Card className="max-w-6xl mx-auto">
|
|
74
|
+
<Tabs value={activeTab} onValueChange={setActiveTab} className="w-full">
|
|
75
|
+
<TabsList className="grid w-full grid-cols-6 mb-8">
|
|
76
|
+
<TabsTrigger value="profile" className="flex items-center gap-2">
|
|
77
|
+
<User className="w-4 h-4" />
|
|
78
|
+
<span className="hidden sm:inline">Profile</span>
|
|
79
|
+
</TabsTrigger>
|
|
80
|
+
<TabsTrigger value="security" className="flex items-center gap-2">
|
|
81
|
+
<Shield className="w-4 h-4" />
|
|
82
|
+
<span className="hidden sm:inline">Security</span>
|
|
83
|
+
</TabsTrigger>
|
|
84
|
+
<TabsTrigger value="ai" className="flex items-center gap-2">
|
|
85
|
+
<Brain className="w-4 h-4" />
|
|
86
|
+
<span className="hidden sm:inline">AI</span>
|
|
87
|
+
</TabsTrigger>
|
|
88
|
+
<TabsTrigger value="notifications" className="flex items-center gap-2">
|
|
89
|
+
<Bell className="w-4 h-4" />
|
|
90
|
+
<span className="hidden sm:inline">Alerts</span>
|
|
91
|
+
</TabsTrigger>
|
|
92
|
+
<TabsTrigger value="appearance" className="flex items-center gap-2">
|
|
93
|
+
<Palette className="w-4 h-4" />
|
|
94
|
+
<span className="hidden sm:inline">Theme</span>
|
|
95
|
+
</TabsTrigger>
|
|
96
|
+
<TabsTrigger value="team" className="flex items-center gap-2">
|
|
97
|
+
<Users className="w-4 h-4" />
|
|
98
|
+
<span className="hidden sm:inline">Team</span>
|
|
99
|
+
</TabsTrigger>
|
|
100
|
+
</TabsList>
|
|
101
|
+
|
|
102
|
+
{/* Profile Settings */}
|
|
103
|
+
<TabsContent value="profile" className="space-y-6">
|
|
104
|
+
<FormProvider>
|
|
105
|
+
<FormBuilder
|
|
106
|
+
onSubmit={(formData) => handleSaveSettings(formData, 'profile')}
|
|
107
|
+
autoSave={true}
|
|
108
|
+
autoSaveInterval={30000}
|
|
109
|
+
className="space-y-6"
|
|
110
|
+
>
|
|
111
|
+
<FormSection
|
|
112
|
+
title="Personal Information"
|
|
113
|
+
description="Update your basic profile information"
|
|
114
|
+
collapsible={false}
|
|
115
|
+
>
|
|
116
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
117
|
+
<FormField
|
|
118
|
+
name="firstName"
|
|
119
|
+
type="text"
|
|
120
|
+
label="First Name"
|
|
121
|
+
placeholder="Enter your first name"
|
|
122
|
+
defaultValue={user.user_metadata?.first_name || ''}
|
|
123
|
+
validation={['required', 'minLength:2']}
|
|
124
|
+
/>
|
|
125
|
+
|
|
126
|
+
<FormField
|
|
127
|
+
name="lastName"
|
|
128
|
+
type="text"
|
|
129
|
+
label="Last Name"
|
|
130
|
+
placeholder="Enter your last name"
|
|
131
|
+
defaultValue={user.user_metadata?.last_name || ''}
|
|
132
|
+
validation={['required', 'minLength:2']}
|
|
133
|
+
/>
|
|
134
|
+
</div>
|
|
135
|
+
|
|
136
|
+
<FormField
|
|
137
|
+
name="email"
|
|
138
|
+
type="email"
|
|
139
|
+
label="Email Address"
|
|
140
|
+
placeholder="Enter your email"
|
|
141
|
+
defaultValue={user.email || ''}
|
|
142
|
+
validation={['required', 'email']}
|
|
143
|
+
helpText="Changing your email will require verification"
|
|
144
|
+
/>
|
|
145
|
+
|
|
146
|
+
<FormField
|
|
147
|
+
name="avatar"
|
|
148
|
+
type="file"
|
|
149
|
+
label="Profile Picture"
|
|
150
|
+
accept="image/*"
|
|
151
|
+
maxSize={5000000} // 5MB
|
|
152
|
+
helpText="Upload a profile picture (max 5MB)"
|
|
153
|
+
preview={true}
|
|
154
|
+
/>
|
|
155
|
+
|
|
156
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
157
|
+
<FormField
|
|
158
|
+
name="company"
|
|
159
|
+
type="text"
|
|
160
|
+
label="Company"
|
|
161
|
+
placeholder="Enter your company name"
|
|
162
|
+
defaultValue={user.user_metadata?.company || ''}
|
|
163
|
+
/>
|
|
164
|
+
|
|
165
|
+
<FormField
|
|
166
|
+
name="jobTitle"
|
|
167
|
+
type="text"
|
|
168
|
+
label="Job Title"
|
|
169
|
+
placeholder="Enter your job title"
|
|
170
|
+
defaultValue={user.user_metadata?.job_title || ''}
|
|
171
|
+
/>
|
|
172
|
+
</div>
|
|
173
|
+
|
|
174
|
+
<FormField
|
|
175
|
+
name="bio"
|
|
176
|
+
type="textarea"
|
|
177
|
+
label="Bio"
|
|
178
|
+
placeholder="Tell us about yourself..."
|
|
179
|
+
rows={4}
|
|
180
|
+
maxLength={500}
|
|
181
|
+
showCharacterCount={true}
|
|
182
|
+
defaultValue={user.user_metadata?.bio || ''}
|
|
183
|
+
/>
|
|
184
|
+
</FormSection>
|
|
185
|
+
|
|
186
|
+
<FormSection
|
|
187
|
+
title="Contact Information"
|
|
188
|
+
description="How we can reach you"
|
|
189
|
+
collapsible={true}
|
|
190
|
+
>
|
|
191
|
+
<FormField
|
|
192
|
+
name="phone"
|
|
193
|
+
type="tel"
|
|
194
|
+
label="Phone Number"
|
|
195
|
+
placeholder="+1 (555) 123-4567"
|
|
196
|
+
defaultValue={user.user_metadata?.phone || ''}
|
|
197
|
+
validation={['phone']}
|
|
198
|
+
/>
|
|
199
|
+
|
|
200
|
+
<FormField
|
|
201
|
+
name="timezone"
|
|
202
|
+
type="select"
|
|
203
|
+
label="Timezone"
|
|
204
|
+
placeholder="Select your timezone"
|
|
205
|
+
options={[
|
|
206
|
+
{ value: 'America/New_York', label: 'Eastern Time (ET)' },
|
|
207
|
+
{ value: 'America/Chicago', label: 'Central Time (CT)' },
|
|
208
|
+
{ value: 'America/Denver', label: 'Mountain Time (MT)' },
|
|
209
|
+
{ value: 'America/Los_Angeles', label: 'Pacific Time (PT)' },
|
|
210
|
+
{ value: 'Europe/London', label: 'London (GMT)' },
|
|
211
|
+
{ value: 'Europe/Paris', label: 'Paris (CET)' },
|
|
212
|
+
{ value: 'Asia/Tokyo', label: 'Tokyo (JST)' },
|
|
213
|
+
{ value: 'Australia/Sydney', label: 'Sydney (AEST)' }
|
|
214
|
+
]}
|
|
215
|
+
defaultValue={user.user_metadata?.timezone || 'America/New_York'}
|
|
216
|
+
validation={['required']}
|
|
217
|
+
/>
|
|
218
|
+
</FormSection>
|
|
219
|
+
|
|
220
|
+
<div className="flex justify-end">
|
|
221
|
+
<Button type="submit" disabled={isLoading} className="flex items-center gap-2">
|
|
222
|
+
<Save className="w-4 h-4" />
|
|
223
|
+
{isLoading ? 'Saving...' : 'Save Changes'}
|
|
224
|
+
</Button>
|
|
225
|
+
</div>
|
|
226
|
+
</FormBuilder>
|
|
227
|
+
</FormProvider>
|
|
228
|
+
</TabsContent>
|
|
229
|
+
|
|
230
|
+
{/* Security Settings */}
|
|
231
|
+
<TabsContent value="security" className="space-y-6">
|
|
232
|
+
<FormProvider>
|
|
233
|
+
<FormBuilder
|
|
234
|
+
onSubmit={(formData) => handleSaveSettings(formData, 'security')}
|
|
235
|
+
className="space-y-6"
|
|
236
|
+
>
|
|
237
|
+
<FormSection
|
|
238
|
+
title="Password & Authentication"
|
|
239
|
+
description="Manage your login credentials"
|
|
240
|
+
collapsible={false}
|
|
241
|
+
>
|
|
242
|
+
<FormField
|
|
243
|
+
name="currentPassword"
|
|
244
|
+
type="password"
|
|
245
|
+
label="Current Password"
|
|
246
|
+
placeholder="Enter your current password"
|
|
247
|
+
validation={['required']}
|
|
248
|
+
/>
|
|
249
|
+
|
|
250
|
+
<FormField
|
|
251
|
+
name="newPassword"
|
|
252
|
+
type="password"
|
|
253
|
+
label="New Password"
|
|
254
|
+
placeholder="Enter a new password"
|
|
255
|
+
validation={['minLength:8', 'hasUppercase', 'hasLowercase', 'hasNumber']}
|
|
256
|
+
showPasswordStrength={true}
|
|
257
|
+
helpText="Password must be at least 8 characters with uppercase, lowercase, and number"
|
|
258
|
+
/>
|
|
259
|
+
|
|
260
|
+
<FormField
|
|
261
|
+
name="confirmNewPassword"
|
|
262
|
+
type="password"
|
|
263
|
+
label="Confirm New Password"
|
|
264
|
+
placeholder="Confirm your new password"
|
|
265
|
+
validation={['required']}
|
|
266
|
+
/>
|
|
267
|
+
</FormSection>
|
|
268
|
+
|
|
269
|
+
<FormSection
|
|
270
|
+
title="Two-Factor Authentication"
|
|
271
|
+
description="Add an extra layer of security"
|
|
272
|
+
collapsible={true}
|
|
273
|
+
>
|
|
274
|
+
<FormField
|
|
275
|
+
name="enableTwoFactor"
|
|
276
|
+
type="checkbox"
|
|
277
|
+
label="Enable Two-Factor Authentication"
|
|
278
|
+
helpText="Require a code from your phone in addition to your password"
|
|
279
|
+
/>
|
|
280
|
+
|
|
281
|
+
<FormField
|
|
282
|
+
name="twoFactorMethod"
|
|
283
|
+
type="radio"
|
|
284
|
+
label="Authentication Method"
|
|
285
|
+
options={[
|
|
286
|
+
{ value: 'sms', label: 'SMS Text Message' },
|
|
287
|
+
{ value: 'app', label: 'Authenticator App (Recommended)' },
|
|
288
|
+
{ value: 'email', label: 'Email' }
|
|
289
|
+
]}
|
|
290
|
+
defaultValue="app"
|
|
291
|
+
dependsOn="enableTwoFactor"
|
|
292
|
+
/>
|
|
293
|
+
</FormSection>
|
|
294
|
+
|
|
295
|
+
<FormSection
|
|
296
|
+
title="Login Sessions"
|
|
297
|
+
description="Manage your active sessions"
|
|
298
|
+
collapsible={true}
|
|
299
|
+
>
|
|
300
|
+
<div className="space-y-4">
|
|
301
|
+
<div className="p-4 border rounded-lg">
|
|
302
|
+
<div className="flex justify-between items-start">
|
|
303
|
+
<div>
|
|
304
|
+
<div className="font-medium">Current Session</div>
|
|
305
|
+
<div className="text-sm text-gray-600 dark:text-gray-300">
|
|
306
|
+
Chrome on Mac • 192.168.1.100 • Active now
|
|
307
|
+
</div>
|
|
308
|
+
</div>
|
|
309
|
+
<span className="text-xs bg-green-100 text-green-800 px-2 py-1 rounded">Current</span>
|
|
310
|
+
</div>
|
|
311
|
+
</div>
|
|
312
|
+
|
|
313
|
+
<Button variant="outline" size="sm">
|
|
314
|
+
Sign Out All Other Sessions
|
|
315
|
+
</Button>
|
|
316
|
+
</div>
|
|
317
|
+
</FormSection>
|
|
318
|
+
|
|
319
|
+
<div className="flex justify-end">
|
|
320
|
+
<Button type="submit" disabled={isLoading} className="flex items-center gap-2">
|
|
321
|
+
<Shield className="w-4 h-4" />
|
|
322
|
+
{isLoading ? 'Updating...' : 'Update Security'}
|
|
323
|
+
</Button>
|
|
324
|
+
</div>
|
|
325
|
+
</FormBuilder>
|
|
326
|
+
</FormProvider>
|
|
327
|
+
</TabsContent>
|
|
328
|
+
|
|
329
|
+
{/* AI Preferences */}
|
|
330
|
+
<TabsContent value="ai" className="space-y-6">
|
|
331
|
+
<FormProvider>
|
|
332
|
+
<FormBuilder
|
|
333
|
+
onSubmit={(formData) => handleSaveSettings(formData, 'ai')}
|
|
334
|
+
autoSave={true}
|
|
335
|
+
className="space-y-6"
|
|
336
|
+
>
|
|
337
|
+
<FormSection
|
|
338
|
+
title="AI Model Preferences"
|
|
339
|
+
description="Configure your preferred AI models and behavior"
|
|
340
|
+
collapsible={false}
|
|
341
|
+
>
|
|
342
|
+
<FormField
|
|
343
|
+
name="defaultTextModel"
|
|
344
|
+
type="select"
|
|
345
|
+
label="Default Text Model"
|
|
346
|
+
options={[
|
|
347
|
+
{ value: 'gpt-4', label: 'GPT-4 (Most capable)' },
|
|
348
|
+
{ value: 'gpt-4-turbo', label: 'GPT-4 Turbo (Faster)' },
|
|
349
|
+
{ value: 'gpt-3.5-turbo', label: 'GPT-3.5 Turbo (Cost-effective)' },
|
|
350
|
+
{ value: 'claude-3', label: 'Claude 3 (Great for analysis)' }
|
|
351
|
+
]}
|
|
352
|
+
defaultValue="gpt-4"
|
|
353
|
+
validation={['required']}
|
|
354
|
+
/>
|
|
355
|
+
|
|
356
|
+
<FormField
|
|
357
|
+
name="creativityLevel"
|
|
358
|
+
type="range"
|
|
359
|
+
label="Creativity Level"
|
|
360
|
+
min={0}
|
|
361
|
+
max={100}
|
|
362
|
+
defaultValue={70}
|
|
363
|
+
showValue={true}
|
|
364
|
+
helpText="Lower values are more conservative, higher values are more creative"
|
|
365
|
+
/>
|
|
366
|
+
|
|
367
|
+
<FormField
|
|
368
|
+
name="responseLength"
|
|
369
|
+
type="select"
|
|
370
|
+
label="Default Response Length"
|
|
371
|
+
options={[
|
|
372
|
+
{ value: 'short', label: 'Short (1-2 paragraphs)' },
|
|
373
|
+
{ value: 'medium', label: 'Medium (3-5 paragraphs)' },
|
|
374
|
+
{ value: 'long', label: 'Long (6+ paragraphs)' },
|
|
375
|
+
{ value: 'auto', label: 'Auto (context-dependent)' }
|
|
376
|
+
]}
|
|
377
|
+
defaultValue="medium"
|
|
378
|
+
validation={['required']}
|
|
379
|
+
/>
|
|
380
|
+
</FormSection>
|
|
381
|
+
|
|
382
|
+
<FormSection
|
|
383
|
+
title="Content Filters"
|
|
384
|
+
description="Control what content is generated"
|
|
385
|
+
collapsible={true}
|
|
386
|
+
>
|
|
387
|
+
<FormField
|
|
388
|
+
name="contentFilters"
|
|
389
|
+
type="multiSelect"
|
|
390
|
+
label="Enable Content Filters"
|
|
391
|
+
options={[
|
|
392
|
+
{ value: 'violence', label: 'Violence & Gore' },
|
|
393
|
+
{ value: 'adult', label: 'Adult Content' },
|
|
394
|
+
{ value: 'hate', label: 'Hate Speech' },
|
|
395
|
+
{ value: 'harmful', label: 'Harmful Instructions' },
|
|
396
|
+
{ value: 'personal', label: 'Personal Information' }
|
|
397
|
+
]}
|
|
398
|
+
defaultValue={['violence', 'adult', 'hate', 'harmful', 'personal']}
|
|
399
|
+
helpText="These filters help ensure generated content meets community standards"
|
|
400
|
+
/>
|
|
401
|
+
|
|
402
|
+
<FormField
|
|
403
|
+
name="allowCodeGeneration"
|
|
404
|
+
type="checkbox"
|
|
405
|
+
label="Allow Code Generation"
|
|
406
|
+
defaultValue={true}
|
|
407
|
+
helpText="Enable AI to generate code snippets and programming examples"
|
|
408
|
+
/>
|
|
409
|
+
</FormSection>
|
|
410
|
+
|
|
411
|
+
<FormSection
|
|
412
|
+
title="Usage & Limits"
|
|
413
|
+
description="Manage your AI usage preferences"
|
|
414
|
+
collapsible={true}
|
|
415
|
+
>
|
|
416
|
+
<FormField
|
|
417
|
+
name="monthlyLimit"
|
|
418
|
+
type="number"
|
|
419
|
+
label="Monthly Request Limit"
|
|
420
|
+
placeholder="Enter limit (0 for unlimited)"
|
|
421
|
+
min={0}
|
|
422
|
+
defaultValue={0}
|
|
423
|
+
helpText="Set a limit to control your usage and costs"
|
|
424
|
+
/>
|
|
425
|
+
|
|
426
|
+
<FormField
|
|
427
|
+
name="lowUsageAlerts"
|
|
428
|
+
type="checkbox"
|
|
429
|
+
label="Low Usage Alerts"
|
|
430
|
+
defaultValue={true}
|
|
431
|
+
helpText="Get notified when you're approaching your usage limits"
|
|
432
|
+
/>
|
|
433
|
+
</FormSection>
|
|
434
|
+
|
|
435
|
+
<div className="flex justify-end">
|
|
436
|
+
<Button type="submit" disabled={isLoading} className="flex items-center gap-2">
|
|
437
|
+
<Brain className="w-4 h-4" />
|
|
438
|
+
{isLoading ? 'Saving...' : 'Save AI Preferences'}
|
|
439
|
+
</Button>
|
|
440
|
+
</div>
|
|
441
|
+
</FormBuilder>
|
|
442
|
+
</FormProvider>
|
|
443
|
+
</TabsContent>
|
|
444
|
+
|
|
445
|
+
{/* Notification Settings */}
|
|
446
|
+
<TabsContent value="notifications" className="space-y-6">
|
|
447
|
+
<FormProvider>
|
|
448
|
+
<FormBuilder
|
|
449
|
+
onSubmit={(formData) => handleSaveSettings(formData, 'notifications')}
|
|
450
|
+
autoSave={true}
|
|
451
|
+
className="space-y-6"
|
|
452
|
+
>
|
|
453
|
+
<FormSection
|
|
454
|
+
title="Email Notifications"
|
|
455
|
+
description="Choose what emails you want to receive"
|
|
456
|
+
collapsible={false}
|
|
457
|
+
>
|
|
458
|
+
<FormField
|
|
459
|
+
name="emailNotifications"
|
|
460
|
+
type="multiSelect"
|
|
461
|
+
label="Email Preferences"
|
|
462
|
+
options={[
|
|
463
|
+
{ value: 'account', label: 'Account & Security Updates' },
|
|
464
|
+
{ value: 'billing', label: 'Billing & Payment Notifications' },
|
|
465
|
+
{ value: 'features', label: 'New Features & Updates' },
|
|
466
|
+
{ value: 'tips', label: 'Tips & Best Practices' },
|
|
467
|
+
{ value: 'marketing', label: 'Marketing & Promotional Emails' }
|
|
468
|
+
]}
|
|
469
|
+
defaultValue={['account', 'billing', 'features']}
|
|
470
|
+
/>
|
|
471
|
+
|
|
472
|
+
<FormField
|
|
473
|
+
name="emailFrequency"
|
|
474
|
+
type="select"
|
|
475
|
+
label="Email Frequency"
|
|
476
|
+
options={[
|
|
477
|
+
{ value: 'immediate', label: 'Immediate' },
|
|
478
|
+
{ value: 'daily', label: 'Daily Digest' },
|
|
479
|
+
{ value: 'weekly', label: 'Weekly Summary' },
|
|
480
|
+
{ value: 'never', label: 'Never (Critical only)' }
|
|
481
|
+
]}
|
|
482
|
+
defaultValue="daily"
|
|
483
|
+
validation={['required']}
|
|
484
|
+
/>
|
|
485
|
+
</FormSection>
|
|
486
|
+
|
|
487
|
+
<FormSection
|
|
488
|
+
title="Push Notifications"
|
|
489
|
+
description="Browser and mobile push notifications"
|
|
490
|
+
collapsible={true}
|
|
491
|
+
>
|
|
492
|
+
<FormField
|
|
493
|
+
name="pushNotifications"
|
|
494
|
+
type="checkbox"
|
|
495
|
+
label="Enable Push Notifications"
|
|
496
|
+
defaultValue={true}
|
|
497
|
+
helpText="Receive real-time notifications in your browser"
|
|
498
|
+
/>
|
|
499
|
+
|
|
500
|
+
<FormField
|
|
501
|
+
name="pushTypes"
|
|
502
|
+
type="multiSelect"
|
|
503
|
+
label="Push Notification Types"
|
|
504
|
+
options={[
|
|
505
|
+
{ value: 'generation-complete', label: 'AI Generation Complete' },
|
|
506
|
+
{ value: 'usage-alerts', label: 'Usage Limit Alerts' },
|
|
507
|
+
{ value: 'team-invites', label: 'Team Invitations' },
|
|
508
|
+
{ value: 'system-maintenance', label: 'System Maintenance' }
|
|
509
|
+
]}
|
|
510
|
+
defaultValue={['generation-complete', 'usage-alerts']}
|
|
511
|
+
dependsOn="pushNotifications"
|
|
512
|
+
/>
|
|
513
|
+
</FormSection>
|
|
514
|
+
|
|
515
|
+
<div className="flex justify-end">
|
|
516
|
+
<Button type="submit" disabled={isLoading} className="flex items-center gap-2">
|
|
517
|
+
<Bell className="w-4 h-4" />
|
|
518
|
+
{isLoading ? 'Saving...' : 'Save Notification Preferences'}
|
|
519
|
+
</Button>
|
|
520
|
+
</div>
|
|
521
|
+
</FormBuilder>
|
|
522
|
+
</FormProvider>
|
|
523
|
+
</TabsContent>
|
|
524
|
+
|
|
525
|
+
{/* More tabs would continue here... */}
|
|
526
|
+
</Tabs>
|
|
527
|
+
</Card>
|
|
528
|
+
</MobileContainer>
|
|
529
|
+
</main>
|
|
530
|
+
</PageTransition>
|
|
531
|
+
)
|
|
532
|
+
}
|
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
3
|
import React, { useState, useActionState } from 'react'
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
Button,
|
|
6
|
+
Card,
|
|
7
|
+
Input,
|
|
8
|
+
Label,
|
|
9
|
+
SingleStepForm,
|
|
10
|
+
FormField,
|
|
11
|
+
FormProvider
|
|
12
|
+
} from '@digilogiclabs/saas-factory-ui'
|
|
5
13
|
import { useAuth } from '@digilogiclabs/saas-factory-auth'
|
|
6
14
|
import { useRouter } from 'next/navigation'
|
|
7
15
|
import { signInAction } from '@/lib/actions/auth'
|
|
@@ -69,68 +77,79 @@ export function LoginForm() {
|
|
|
69
77
|
<Card className="w-full max-w-md p-8">
|
|
70
78
|
<h1 className="text-2xl font-bold text-center mb-6">Sign In</h1>
|
|
71
79
|
|
|
72
|
-
{/*
|
|
73
|
-
|
|
74
|
-
<
|
|
75
|
-
{
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
80
|
+
{/* Enhanced form with enterprise form system */}
|
|
81
|
+
<FormProvider>
|
|
82
|
+
<SingleStepForm
|
|
83
|
+
onSubmit={async (formData) => {
|
|
84
|
+
try {
|
|
85
|
+
const result = await formAction(formData)
|
|
86
|
+
if (result?.success) {
|
|
87
|
+
const emailValue = formData.get('email') as string
|
|
88
|
+
const passwordValue = formData.get('password') as string
|
|
89
|
+
await signIn(emailValue, passwordValue)
|
|
90
|
+
router.push('/')
|
|
91
|
+
}
|
|
92
|
+
} catch (err) {
|
|
93
|
+
console.error('Login error:', err)
|
|
94
|
+
}
|
|
95
|
+
}}
|
|
96
|
+
className="space-y-4"
|
|
97
|
+
submitButton={{
|
|
98
|
+
text: loading ? 'Signing In...' : 'Sign In',
|
|
99
|
+
disabled: loading,
|
|
100
|
+
className: 'w-full'
|
|
101
|
+
}}
|
|
102
|
+
realTimeValidation={true}
|
|
103
|
+
debounceMs={300}
|
|
104
|
+
>
|
|
105
|
+
<FormField
|
|
91
106
|
name="email"
|
|
92
107
|
type="email"
|
|
93
|
-
|
|
94
|
-
onChange={(e) => setEmail(e.target.value)}
|
|
108
|
+
label="Email"
|
|
95
109
|
placeholder="Enter your email"
|
|
96
|
-
required
|
|
110
|
+
validation={['required', 'email']}
|
|
97
111
|
disabled={loading}
|
|
112
|
+
className="mb-4"
|
|
98
113
|
/>
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
)}
|
|
102
|
-
</div>
|
|
103
|
-
<div>
|
|
104
|
-
<Label htmlFor="password">Password</Label>
|
|
105
|
-
<Input
|
|
106
|
-
id="password"
|
|
114
|
+
|
|
115
|
+
<FormField
|
|
107
116
|
name="password"
|
|
108
117
|
type="password"
|
|
109
|
-
|
|
110
|
-
onChange={(e) => setPassword(e.target.value)}
|
|
118
|
+
label="Password"
|
|
111
119
|
placeholder="Enter your password"
|
|
112
|
-
required
|
|
120
|
+
validation={['required', 'minLength:6']}
|
|
113
121
|
disabled={loading}
|
|
122
|
+
className="mb-6"
|
|
123
|
+
showPasswordStrength={false}
|
|
114
124
|
/>
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
125
|
+
</SingleStepForm>
|
|
126
|
+
</FormProvider>
|
|
127
|
+
|
|
128
|
+
{/* Social Auth */}
|
|
129
|
+
<Button
|
|
130
|
+
type="button"
|
|
131
|
+
variant="outline"
|
|
132
|
+
className="w-full mt-4"
|
|
133
|
+
onClick={handleGoogleLogin}
|
|
134
|
+
disabled={loading}
|
|
135
|
+
>
|
|
136
|
+
Sign in with Google
|
|
137
|
+
</Button>
|
|
138
|
+
|
|
139
|
+
{/* Legacy error display */}
|
|
140
|
+
{actionState?.error && (
|
|
141
|
+
<div className="mt-4 p-3 bg-red-100 border border-red-400 text-red-700 rounded">
|
|
142
|
+
{actionState.error}
|
|
118
143
|
</div>
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
<
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
onClick={handleGoogleLogin}
|
|
127
|
-
disabled={loading}
|
|
128
|
-
>
|
|
129
|
-
Sign in with Google
|
|
130
|
-
</Button>
|
|
131
|
-
</form>
|
|
144
|
+
)}
|
|
145
|
+
|
|
146
|
+
{error && (
|
|
147
|
+
<div className="mt-4 p-3 bg-red-100 border border-red-400 text-red-700 rounded">
|
|
148
|
+
{error.message}
|
|
149
|
+
</div>
|
|
150
|
+
)}
|
|
132
151
|
|
|
133
|
-
<div className="mt-
|
|
152
|
+
<div className="mt-6 text-center">
|
|
134
153
|
<p className="text-sm text-gray-600 dark:text-gray-300">
|
|
135
154
|
Don't have an account?{' '}
|
|
136
155
|
<a href="/signup" className="text-blue-600 hover:underline dark:text-blue-400">
|