@cogito.ai/cli 0.4.1 → 0.4.3
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 +29 -22
- package/dist/index.js +9 -15
- package/dist/templates/web-nextjs/.github/copilot-instructions.md +5 -6
- package/dist/templates/web-nextjs/README.md +25 -24
- package/dist/templates/web-nextjs/apps/docs/.source/browser.ts +18 -8
- package/dist/templates/web-nextjs/apps/docs/.source/dynamic.ts +11 -5
- package/dist/templates/web-nextjs/apps/docs/.source/server.ts +37 -17
- package/dist/templates/web-nextjs/apps/docs/app/docs/[[...slug]]/page.tsx +1 -6
- package/dist/templates/web-nextjs/apps/docs/app/docs/layout.tsx +1 -4
- package/dist/templates/web-nextjs/apps/docs/app/llms-full.txt/route.ts +3 -1
- package/dist/templates/web-nextjs/apps/docs/next-env.d.ts +1 -1
- package/dist/templates/web-nextjs/apps/web/.github/copilot-instructions.md +53 -6
- package/dist/templates/web-nextjs/apps/web/.github/skills/impeccable/SKILL.md +55 -0
- package/dist/templates/web-nextjs/apps/web/DESIGN.md +65 -0
- package/dist/templates/web-nextjs/apps/web/messages/en.json +127 -1
- package/dist/templates/web-nextjs/apps/web/messages/zh.json +127 -1
- package/dist/templates/web-nextjs/apps/web/next-env.d.ts +1 -1
- package/dist/templates/web-nextjs/apps/web/next.config.ts +3 -3
- package/dist/templates/web-nextjs/apps/web/src/app/[locale]/(auth)/forgot-password/page.tsx +265 -0
- package/dist/templates/web-nextjs/apps/web/src/app/[locale]/(auth)/login/page.tsx +20 -4
- package/dist/templates/web-nextjs/apps/web/src/app/[locale]/(auth)/reset-password/page.tsx +115 -0
- package/dist/templates/web-nextjs/apps/web/src/app/[locale]/(auth)/signup/page.tsx +18 -17
- package/dist/templates/web-nextjs/apps/web/src/app/[locale]/(protected)/dashboard/page.tsx +1 -5
- package/dist/templates/web-nextjs/apps/web/src/app/[locale]/(protected)/settings/layout.tsx +5 -0
- package/dist/templates/web-nextjs/apps/web/src/app/[locale]/(protected)/settings/page.tsx +9 -0
- package/dist/templates/web-nextjs/apps/web/src/app/[locale]/(protected)/settings/profile/page.tsx +91 -0
- package/dist/templates/web-nextjs/apps/web/src/app/[locale]/about/page.tsx +22 -0
- package/dist/templates/web-nextjs/apps/web/src/app/[locale]/globals.css +17 -5
- package/dist/templates/web-nextjs/apps/web/src/app/[locale]/help/page.tsx +21 -0
- package/dist/templates/web-nextjs/apps/web/src/app/[locale]/layout.tsx +10 -8
- package/dist/templates/web-nextjs/apps/web/src/app/[locale]/page.tsx +22 -6
- package/dist/templates/web-nextjs/apps/web/src/app/[locale]/privacy/page.tsx +14 -15
- package/dist/templates/web-nextjs/apps/web/src/app/[locale]/terms/page.tsx +1 -5
- package/dist/templates/web-nextjs/apps/web/src/app/auth/callback/route.ts +7 -2
- package/dist/templates/web-nextjs/apps/web/src/components/dashboard/app-sidebar.tsx +37 -137
- package/dist/templates/web-nextjs/apps/web/src/components/dashboard/chart-area-interactive.tsx +122 -146
- package/dist/templates/web-nextjs/apps/web/src/components/dashboard/data-table.tsx +84 -149
- package/dist/templates/web-nextjs/apps/web/src/components/dashboard/nav-documents.tsx +7 -16
- package/dist/templates/web-nextjs/apps/web/src/components/dashboard/nav-main.tsx +4 -4
- package/dist/templates/web-nextjs/apps/web/src/components/dashboard/nav-secondary.tsx +4 -4
- package/dist/templates/web-nextjs/apps/web/src/components/dashboard/nav-user.tsx +17 -33
- package/dist/templates/web-nextjs/apps/web/src/components/dashboard/page.tsx +10 -13
- package/dist/templates/web-nextjs/apps/web/src/components/dashboard/section-cards.tsx +5 -9
- package/dist/templates/web-nextjs/apps/web/src/components/dashboard/site-header.tsx +6 -7
- package/dist/templates/web-nextjs/apps/web/src/components/landing/features.tsx +63 -0
- package/dist/templates/web-nextjs/apps/web/src/components/landing/footer.tsx +48 -0
- package/dist/templates/web-nextjs/apps/web/src/components/landing/header.tsx +97 -0
- package/dist/templates/web-nextjs/apps/web/src/components/landing/hero.tsx +45 -0
- package/dist/templates/web-nextjs/apps/web/src/components/landing/how-it-works.tsx +35 -0
- package/dist/templates/web-nextjs/apps/web/src/components/landing/pricing-teaser.tsx +23 -0
- package/dist/templates/web-nextjs/apps/web/src/components/profile/profile-form.tsx +66 -0
- package/dist/templates/web-nextjs/apps/web/src/components/providers/theme-provider.tsx +16 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/alert-dialog.tsx +32 -49
- package/dist/templates/web-nextjs/apps/web/src/components/ui/alert.tsx +16 -23
- package/dist/templates/web-nextjs/apps/web/src/components/ui/avatar.tsx +25 -38
- package/dist/templates/web-nextjs/apps/web/src/components/ui/badge.tsx +16 -18
- package/dist/templates/web-nextjs/apps/web/src/components/ui/breadcrumb.tsx +19 -26
- package/dist/templates/web-nextjs/apps/web/src/components/ui/button.tsx +23 -24
- package/dist/templates/web-nextjs/apps/web/src/components/ui/card.tsx +19 -36
- package/dist/templates/web-nextjs/apps/web/src/components/ui/chart.tsx +60 -94
- package/dist/templates/web-nextjs/apps/web/src/components/ui/checkbox.tsx +8 -11
- package/dist/templates/web-nextjs/apps/web/src/components/ui/collapsible.tsx +5 -17
- package/dist/templates/web-nextjs/apps/web/src/components/ui/command.tsx +25 -48
- package/dist/templates/web-nextjs/apps/web/src/components/ui/dialog.tsx +21 -35
- package/dist/templates/web-nextjs/apps/web/src/components/ui/drawer.tsx +24 -35
- package/dist/templates/web-nextjs/apps/web/src/components/ui/dropdown-menu.tsx +26 -55
- package/dist/templates/web-nextjs/apps/web/src/components/ui/field.tsx +62 -76
- package/dist/templates/web-nextjs/apps/web/src/components/ui/form.tsx +19 -34
- package/dist/templates/web-nextjs/apps/web/src/components/ui/input-otp.tsx +13 -20
- package/dist/templates/web-nextjs/apps/web/src/components/ui/input.tsx +6 -6
- package/dist/templates/web-nextjs/apps/web/src/components/ui/label.tsx +6 -6
- package/dist/templates/web-nextjs/apps/web/src/components/ui/pagination.tsx +21 -42
- package/dist/templates/web-nextjs/apps/web/src/components/ui/popover.tsx +16 -31
- package/dist/templates/web-nextjs/apps/web/src/components/ui/progress.tsx +5 -8
- package/dist/templates/web-nextjs/apps/web/src/components/ui/radio-group.tsx +8 -8
- package/dist/templates/web-nextjs/apps/web/src/components/ui/scroll-area.tsx +10 -12
- package/dist/templates/web-nextjs/apps/web/src/components/ui/select.tsx +26 -41
- package/dist/templates/web-nextjs/apps/web/src/components/ui/separator.tsx +7 -7
- package/dist/templates/web-nextjs/apps/web/src/components/ui/sheet.tsx +29 -38
- package/dist/templates/web-nextjs/apps/web/src/components/ui/sidebar.tsx +157 -189
- package/dist/templates/web-nextjs/apps/web/src/components/ui/skeleton.tsx +3 -3
- package/dist/templates/web-nextjs/apps/web/src/components/ui/slider.tsx +10 -15
- package/dist/templates/web-nextjs/apps/web/src/components/ui/sonner.tsx +13 -7
- package/dist/templates/web-nextjs/apps/web/src/components/ui/switch.tsx +9 -9
- package/dist/templates/web-nextjs/apps/web/src/components/ui/table.tsx +24 -48
- package/dist/templates/web-nextjs/apps/web/src/components/ui/tabs.tsx +21 -31
- package/dist/templates/web-nextjs/apps/web/src/components/ui/textarea.tsx +5 -5
- package/dist/templates/web-nextjs/apps/web/src/components/ui/theme-toggle.tsx +23 -0
- package/dist/templates/web-nextjs/apps/web/src/components/ui/toggle-group.tsx +15 -16
- package/dist/templates/web-nextjs/apps/web/src/components/ui/toggle.tsx +14 -15
- package/dist/templates/web-nextjs/apps/web/src/components/ui/tooltip.tsx +8 -12
- package/dist/templates/web-nextjs/apps/web/src/core/repositories/IAuthRepository.ts +5 -0
- package/dist/templates/web-nextjs/apps/web/src/core/types/auth.ts +1 -3
- package/dist/templates/web-nextjs/apps/web/src/features/auth/__contract__.ts +6 -0
- package/dist/templates/web-nextjs/apps/web/src/features/auth/actions.ts +126 -1
- package/dist/templates/web-nextjs/apps/web/src/features/auth/index.ts +12 -1
- package/dist/templates/web-nextjs/apps/web/src/features/auth/server.ts +3 -0
- package/dist/templates/web-nextjs/apps/web/src/hooks/use-mobile.ts +4 -4
- package/dist/templates/web-nextjs/apps/web/src/i18n/config.ts +1 -1
- package/dist/templates/web-nextjs/apps/web/src/infra/db/SupabaseAuthRepository.ts +73 -4
- package/dist/templates/web-nextjs/apps/web/src/infra/db/client.ts +1 -4
- package/dist/templates/web-nextjs/apps/web/src/lib/utils.ts +2 -2
- package/dist/templates/web-nextjs/apps/web/src/lib/validations/auth.ts +34 -0
- package/dist/templates/web-nextjs/apps/web/src/styles/tokens.css +58 -0
- package/package.json +1 -1
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useActionState, useEffect } from 'react'
|
|
4
|
+
import { useParams, useSearchParams } from 'next/navigation'
|
|
5
|
+
import Link from 'next/link'
|
|
6
|
+
import { useTranslations } from 'next-intl'
|
|
7
|
+
import { useForm } from 'react-hook-form'
|
|
8
|
+
import { zodResolver } from '@hookform/resolvers/zod'
|
|
9
|
+
import { GalleryVerticalEnd } from 'lucide-react'
|
|
10
|
+
import { toast } from 'sonner'
|
|
11
|
+
import { Button } from '@/components/ui/button'
|
|
12
|
+
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
|
13
|
+
import { Input } from '@/components/ui/input'
|
|
14
|
+
import { Field, FieldDescription, FieldGroup, FieldLabel } from '@/components/ui/field'
|
|
15
|
+
import { resetPassword } from '@/features/auth'
|
|
16
|
+
import { resetPasswordSchema, type ResetPasswordInput } from '@/lib/validations/auth'
|
|
17
|
+
import type { ActionResult } from '@/core/types/auth'
|
|
18
|
+
|
|
19
|
+
export default function ResetPasswordPage() {
|
|
20
|
+
const t = useTranslations('auth')
|
|
21
|
+
const routeParams = useParams<{ locale: string }>()
|
|
22
|
+
const searchParams = useSearchParams()
|
|
23
|
+
const locale = routeParams.locale ?? 'en'
|
|
24
|
+
const error = searchParams.get('error')
|
|
25
|
+
|
|
26
|
+
const {
|
|
27
|
+
register,
|
|
28
|
+
formState: { errors },
|
|
29
|
+
} = useForm<ResetPasswordInput>({
|
|
30
|
+
resolver: zodResolver(resetPasswordSchema),
|
|
31
|
+
defaultValues: { password: '', confirmPassword: '' },
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
const [state, formAction, isPending] = useActionState<ActionResult | null, FormData>(
|
|
35
|
+
resetPassword,
|
|
36
|
+
null,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
if (state?.error) toast.error(state.error)
|
|
41
|
+
}, [state])
|
|
42
|
+
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
if (error === 'link_expired') {
|
|
45
|
+
toast.error(t('resetLinkExpired'))
|
|
46
|
+
}
|
|
47
|
+
}, [error, t])
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<div className="flex min-h-svh flex-col items-center justify-center gap-6 bg-muted p-6 md:p-10">
|
|
51
|
+
<div className="flex w-full max-w-sm flex-col gap-6">
|
|
52
|
+
<Link href={`/${locale}`} className="flex items-center gap-2 self-center font-medium">
|
|
53
|
+
<div className="flex size-6 items-center justify-center rounded-md bg-primary text-primary-foreground">
|
|
54
|
+
<GalleryVerticalEnd className="size-4" />
|
|
55
|
+
</div>
|
|
56
|
+
AgentDock
|
|
57
|
+
</Link>
|
|
58
|
+
|
|
59
|
+
<Card>
|
|
60
|
+
<CardHeader className="text-center">
|
|
61
|
+
<CardTitle className="text-xl">{t('resetPasswordTitle')}</CardTitle>
|
|
62
|
+
<CardDescription>{t('resetPasswordSubtitle')}</CardDescription>
|
|
63
|
+
</CardHeader>
|
|
64
|
+
<CardContent>
|
|
65
|
+
<form action={formAction}>
|
|
66
|
+
<input type="hidden" name="locale" value={locale} />
|
|
67
|
+
<FieldGroup>
|
|
68
|
+
<Field>
|
|
69
|
+
<FieldLabel htmlFor="password">{t('newPasswordLabel')}</FieldLabel>
|
|
70
|
+
<Input
|
|
71
|
+
id="password"
|
|
72
|
+
type="password"
|
|
73
|
+
placeholder={t('passwordPlaceholder')}
|
|
74
|
+
autoComplete="new-password"
|
|
75
|
+
{...register('password')}
|
|
76
|
+
/>
|
|
77
|
+
{errors.password && (
|
|
78
|
+
<FieldDescription className="text-destructive">
|
|
79
|
+
{errors.password.message}
|
|
80
|
+
</FieldDescription>
|
|
81
|
+
)}
|
|
82
|
+
</Field>
|
|
83
|
+
<Field>
|
|
84
|
+
<FieldLabel htmlFor="confirmPassword">{t('confirmPasswordLabel')}</FieldLabel>
|
|
85
|
+
<Input
|
|
86
|
+
id="confirmPassword"
|
|
87
|
+
type="password"
|
|
88
|
+
placeholder={t('confirmPasswordPlaceholder')}
|
|
89
|
+
autoComplete="new-password"
|
|
90
|
+
{...register('confirmPassword')}
|
|
91
|
+
/>
|
|
92
|
+
{errors.confirmPassword && (
|
|
93
|
+
<FieldDescription className="text-destructive">
|
|
94
|
+
{errors.confirmPassword.message}
|
|
95
|
+
</FieldDescription>
|
|
96
|
+
)}
|
|
97
|
+
</Field>
|
|
98
|
+
<Field>
|
|
99
|
+
<Button type="submit" className="w-full" disabled={isPending}>
|
|
100
|
+
{isPending ? '\u2026' : t('resetPasswordButton')}
|
|
101
|
+
</Button>
|
|
102
|
+
<FieldDescription className="text-center">
|
|
103
|
+
<Link href={`/${locale}/login`} className="underline underline-offset-4">
|
|
104
|
+
{t('backToLogin')}
|
|
105
|
+
</Link>
|
|
106
|
+
</FieldDescription>
|
|
107
|
+
</Field>
|
|
108
|
+
</FieldGroup>
|
|
109
|
+
</form>
|
|
110
|
+
</CardContent>
|
|
111
|
+
</Card>
|
|
112
|
+
</div>
|
|
113
|
+
</div>
|
|
114
|
+
)
|
|
115
|
+
}
|
|
@@ -11,12 +11,7 @@ import { toast } from 'sonner'
|
|
|
11
11
|
import { Button } from '@/components/ui/button'
|
|
12
12
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
|
13
13
|
import { Input } from '@/components/ui/input'
|
|
14
|
-
import {
|
|
15
|
-
Field,
|
|
16
|
-
FieldDescription,
|
|
17
|
-
FieldGroup,
|
|
18
|
-
FieldLabel,
|
|
19
|
-
} from '@/components/ui/field'
|
|
14
|
+
import { Field, FieldDescription, FieldGroup, FieldLabel } from '@/components/ui/field'
|
|
20
15
|
import { signUp } from '@/features/auth'
|
|
21
16
|
import { signUpSchema, type SignUpInput } from '@/lib/validations/auth'
|
|
22
17
|
import type { ActionResult } from '@/core/types/auth'
|
|
@@ -28,15 +23,18 @@ export default function SignupPage() {
|
|
|
28
23
|
const locale = routeParams.locale ?? 'en'
|
|
29
24
|
const [verifyEmail, setVerifyEmail] = useState<string | null>(null)
|
|
30
25
|
|
|
31
|
-
const {
|
|
26
|
+
const {
|
|
27
|
+
register,
|
|
28
|
+
formState: { errors },
|
|
29
|
+
} = useForm<SignUpInput>({
|
|
32
30
|
resolver: zodResolver(signUpSchema),
|
|
33
31
|
defaultValues: { email: '', password: '', confirmPassword: '' },
|
|
34
32
|
})
|
|
35
33
|
|
|
36
|
-
const [state, formAction, isPending] = useActionState<
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
)
|
|
34
|
+
const [state, formAction, isPending] = useActionState<
|
|
35
|
+
ActionResult<SignUpSuccessData> | null,
|
|
36
|
+
FormData
|
|
37
|
+
>(signUp, null)
|
|
40
38
|
|
|
41
39
|
useEffect(() => {
|
|
42
40
|
if (state?.error) toast.error(state.error)
|
|
@@ -56,9 +54,7 @@ export default function SignupPage() {
|
|
|
56
54
|
<Card>
|
|
57
55
|
<CardHeader className="text-center">
|
|
58
56
|
<CardTitle className="text-xl">{t('verifyEmailTitle')}</CardTitle>
|
|
59
|
-
<CardDescription>
|
|
60
|
-
{t('verifyEmailMessage', { email: verifyEmail })}
|
|
61
|
-
</CardDescription>
|
|
57
|
+
<CardDescription>{t('verifyEmailMessage', { email: verifyEmail })}</CardDescription>
|
|
62
58
|
</CardHeader>
|
|
63
59
|
<CardContent>
|
|
64
60
|
<div className="text-center">
|
|
@@ -158,9 +154,14 @@ export default function SignupPage() {
|
|
|
158
154
|
</Card>
|
|
159
155
|
<FieldDescription className="px-6 text-center">
|
|
160
156
|
{t('termsText')}{' '}
|
|
161
|
-
<Link href={`/${locale}/terms`} className="underline underline-offset-4">
|
|
162
|
-
|
|
163
|
-
|
|
157
|
+
<Link href={`/${locale}/terms`} className="underline underline-offset-4">
|
|
158
|
+
{t('termsLink')}
|
|
159
|
+
</Link>{' '}
|
|
160
|
+
{t('andText')}{' '}
|
|
161
|
+
<Link href={`/${locale}/privacy`} className="underline underline-offset-4">
|
|
162
|
+
{t('privacyLink')}
|
|
163
|
+
</Link>
|
|
164
|
+
.
|
|
164
165
|
</FieldDescription>
|
|
165
166
|
</div>
|
|
166
167
|
</div>
|
|
@@ -8,11 +8,7 @@ import { getCurrentUser } from '@/features/auth/server'
|
|
|
8
8
|
|
|
9
9
|
import data from '@/components/dashboard/data.json'
|
|
10
10
|
|
|
11
|
-
export default async function DashboardPage({
|
|
12
|
-
params,
|
|
13
|
-
}: {
|
|
14
|
-
params: Promise<{ locale: string }>
|
|
15
|
-
}) {
|
|
11
|
+
export default async function DashboardPage({ params }: { params: Promise<{ locale: string }> }) {
|
|
16
12
|
const { locale } = await params
|
|
17
13
|
const user = await getCurrentUser()
|
|
18
14
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { redirect } from 'next/navigation'
|
|
2
|
+
import { defaultLocale } from '@/i18n/config'
|
|
3
|
+
|
|
4
|
+
export default function SettingsPage({ params }: { params: Promise<{ locale: string }> }) {
|
|
5
|
+
return (async () => {
|
|
6
|
+
const { locale } = await params
|
|
7
|
+
redirect(`/${locale}/settings/profile`)
|
|
8
|
+
})()
|
|
9
|
+
}
|
package/dist/templates/web-nextjs/apps/web/src/app/[locale]/(protected)/settings/profile/page.tsx
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { redirect } from 'next/navigation'
|
|
2
|
+
import Link from 'next/link'
|
|
3
|
+
import { getCurrentUser } from '@/features/auth/server'
|
|
4
|
+
import { ProfileForm } from '@/components/profile/profile-form'
|
|
5
|
+
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
|
6
|
+
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
|
|
7
|
+
import { Button } from '@/components/ui/button'
|
|
8
|
+
import { Separator } from '@/components/ui/separator'
|
|
9
|
+
|
|
10
|
+
export default async function ProfilePage({ params }: { params: Promise<{ locale: string }> }) {
|
|
11
|
+
const { locale } = await params
|
|
12
|
+
const user = await getCurrentUser()
|
|
13
|
+
|
|
14
|
+
if (!user) {
|
|
15
|
+
redirect(`/${locale}/login`)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const displayName = user.user_metadata?.display_name ?? ''
|
|
19
|
+
const email = user.email ?? ''
|
|
20
|
+
const avatarUrl = user.user_metadata?.avatar_url ?? ''
|
|
21
|
+
const initials = email.charAt(0).toUpperCase()
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<div className="space-y-6">
|
|
25
|
+
<div>
|
|
26
|
+
<h1 className="text-2xl font-semibold">Profile Settings</h1>
|
|
27
|
+
<p className="text-muted-foreground">Manage your account settings and preferences.</p>
|
|
28
|
+
</div>
|
|
29
|
+
<Separator />
|
|
30
|
+
|
|
31
|
+
{/* Avatar & Basic Info */}
|
|
32
|
+
<Card>
|
|
33
|
+
<CardHeader>
|
|
34
|
+
<CardTitle>Profile</CardTitle>
|
|
35
|
+
<CardDescription>Your public profile information.</CardDescription>
|
|
36
|
+
</CardHeader>
|
|
37
|
+
<CardContent className="space-y-4">
|
|
38
|
+
<div className="flex items-center gap-4">
|
|
39
|
+
<Avatar className="h-16 w-16">
|
|
40
|
+
<AvatarImage src={avatarUrl} alt={displayName || email} />
|
|
41
|
+
<AvatarFallback className="text-lg">{initials}</AvatarFallback>
|
|
42
|
+
</Avatar>
|
|
43
|
+
<div>
|
|
44
|
+
<p className="font-medium">{displayName || 'No display name set'}</p>
|
|
45
|
+
<p className="text-sm text-muted-foreground">{email}</p>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
<p className="text-sm text-muted-foreground">Avatar upload feature coming soon.</p>
|
|
49
|
+
</CardContent>
|
|
50
|
+
</Card>
|
|
51
|
+
|
|
52
|
+
{/* Display Name */}
|
|
53
|
+
<Card>
|
|
54
|
+
<CardHeader>
|
|
55
|
+
<CardTitle>Display Name</CardTitle>
|
|
56
|
+
<CardDescription>Update your display name shown across the app.</CardDescription>
|
|
57
|
+
</CardHeader>
|
|
58
|
+
<CardContent>
|
|
59
|
+
<ProfileForm defaultName={displayName} locale={locale} />
|
|
60
|
+
</CardContent>
|
|
61
|
+
</Card>
|
|
62
|
+
|
|
63
|
+
{/* Email */}
|
|
64
|
+
<Card>
|
|
65
|
+
<CardHeader>
|
|
66
|
+
<CardTitle>Email Address</CardTitle>
|
|
67
|
+
<CardDescription>Your primary email address.</CardDescription>
|
|
68
|
+
</CardHeader>
|
|
69
|
+
<CardContent>
|
|
70
|
+
<p className="text-sm">{email}</p>
|
|
71
|
+
<p className="mt-2 text-sm text-muted-foreground">
|
|
72
|
+
To change your email, please contact support.
|
|
73
|
+
</p>
|
|
74
|
+
</CardContent>
|
|
75
|
+
</Card>
|
|
76
|
+
|
|
77
|
+
{/* Password */}
|
|
78
|
+
<Card>
|
|
79
|
+
<CardHeader>
|
|
80
|
+
<CardTitle>Password</CardTitle>
|
|
81
|
+
<CardDescription>Change your password.</CardDescription>
|
|
82
|
+
</CardHeader>
|
|
83
|
+
<CardContent>
|
|
84
|
+
<Button asChild variant="outline">
|
|
85
|
+
<Link href={`/${locale}/forgot-password`}>Change Password</Link>
|
|
86
|
+
</Button>
|
|
87
|
+
</CardContent>
|
|
88
|
+
</Card>
|
|
89
|
+
</div>
|
|
90
|
+
)
|
|
91
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
|
2
|
+
|
|
3
|
+
export default async function AboutPage({ params }: { params: Promise<{ locale: string }> }) {
|
|
4
|
+
const { locale } = await params
|
|
5
|
+
|
|
6
|
+
return (
|
|
7
|
+
<main className="mx-auto max-w-3xl px-4 py-10">
|
|
8
|
+
<Card>
|
|
9
|
+
<CardHeader>
|
|
10
|
+
<CardTitle>About Us</CardTitle>
|
|
11
|
+
<CardDescription>Learn more about AgentDock.</CardDescription>
|
|
12
|
+
</CardHeader>
|
|
13
|
+
<CardContent>
|
|
14
|
+
<p className="text-muted-foreground">
|
|
15
|
+
This page is a placeholder. Replace it with your actual about information before
|
|
16
|
+
shipping.
|
|
17
|
+
</p>
|
|
18
|
+
</CardContent>
|
|
19
|
+
</Card>
|
|
20
|
+
</main>
|
|
21
|
+
)
|
|
22
|
+
}
|
|
@@ -1,12 +1,24 @@
|
|
|
1
1
|
@import "../../styles/tw-animate.css";
|
|
2
2
|
@import "../../styles/shadcn-tailwind.css";
|
|
3
3
|
@import "tailwindcss";
|
|
4
|
+
@import "../../styles/tokens.css";
|
|
4
5
|
|
|
5
6
|
@custom-variant dark (&:is(.dark *));
|
|
6
7
|
|
|
7
8
|
@theme inline {
|
|
8
|
-
--font-heading: var(--font-sans);
|
|
9
|
+
--font-heading: var(--font-geist, var(--font-sans));
|
|
9
10
|
--font-sans: var(--font-sans);
|
|
11
|
+
|
|
12
|
+
/* Semantic tokens registered as Tailwind utilities */
|
|
13
|
+
--color-surface: var(--color-surface);
|
|
14
|
+
--color-surface-elevated: var(--color-surface-elevated);
|
|
15
|
+
--color-muted-custom: var(--color-muted);
|
|
16
|
+
--color-muted-foreground-custom: var(--color-muted-foreground);
|
|
17
|
+
--color-border-custom: var(--color-border);
|
|
18
|
+
--color-primary-custom: var(--color-primary);
|
|
19
|
+
--color-primary-foreground-custom: var(--color-primary-foreground);
|
|
20
|
+
|
|
21
|
+
/* shadcn/ui tokens */
|
|
10
22
|
--color-sidebar-ring: var(--sidebar-ring);
|
|
11
23
|
--color-sidebar-border: var(--sidebar-border);
|
|
12
24
|
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
|
@@ -119,11 +131,11 @@
|
|
|
119
131
|
@layer base {
|
|
120
132
|
* {
|
|
121
133
|
@apply border-border outline-ring/50;
|
|
122
|
-
|
|
134
|
+
}
|
|
123
135
|
body {
|
|
124
136
|
@apply bg-background text-foreground;
|
|
125
|
-
|
|
137
|
+
}
|
|
126
138
|
html {
|
|
127
139
|
@apply font-sans;
|
|
128
|
-
|
|
129
|
-
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
|
2
|
+
|
|
3
|
+
export default async function HelpPage({ params }: { params: Promise<{ locale: string }> }) {
|
|
4
|
+
const { locale } = await params
|
|
5
|
+
|
|
6
|
+
return (
|
|
7
|
+
<main className="mx-auto max-w-3xl px-4 py-10">
|
|
8
|
+
<Card>
|
|
9
|
+
<CardHeader>
|
|
10
|
+
<CardTitle>Help Center</CardTitle>
|
|
11
|
+
<CardDescription>Find answers to common questions.</CardDescription>
|
|
12
|
+
</CardHeader>
|
|
13
|
+
<CardContent>
|
|
14
|
+
<p className="text-muted-foreground">
|
|
15
|
+
We are currently compiling our help documentation. Please check back later.
|
|
16
|
+
</p>
|
|
17
|
+
</CardContent>
|
|
18
|
+
</Card>
|
|
19
|
+
</main>
|
|
20
|
+
)
|
|
21
|
+
}
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import type { Metadata } from 'next'
|
|
2
|
-
import {
|
|
2
|
+
import { Geist } from 'next/font/google'
|
|
3
3
|
import { NextIntlClientProvider } from 'next-intl'
|
|
4
4
|
import { getMessages } from 'next-intl/server'
|
|
5
5
|
import { notFound } from 'next/navigation'
|
|
6
6
|
import { Toaster } from '@/components/ui/sonner'
|
|
7
|
+
import { ThemeProvider } from '@/components/providers/theme-provider'
|
|
7
8
|
import { isLocale } from '@/i18n/config'
|
|
8
9
|
import './globals.css'
|
|
9
10
|
|
|
10
|
-
const
|
|
11
|
+
const geist = Geist({
|
|
11
12
|
subsets: ['latin'],
|
|
12
|
-
variable: '--font-
|
|
13
|
+
variable: '--font-geist',
|
|
14
|
+
fallback: ['system-ui', 'sans-serif'],
|
|
13
15
|
})
|
|
14
16
|
|
|
15
17
|
export const metadata: Metadata = {
|
|
@@ -33,11 +35,11 @@ export default async function LocaleLayout({
|
|
|
33
35
|
const messages = await getMessages()
|
|
34
36
|
|
|
35
37
|
return (
|
|
36
|
-
<html lang={locale} suppressHydrationWarning>
|
|
37
|
-
<body className={`${
|
|
38
|
-
<
|
|
39
|
-
{children}
|
|
40
|
-
</
|
|
38
|
+
<html lang={locale} suppressHydrationWarning className={geist.variable}>
|
|
39
|
+
<body className={`${geist.variable} min-h-screen bg-background font-sans antialiased`}>
|
|
40
|
+
<ThemeProvider>
|
|
41
|
+
<NextIntlClientProvider messages={messages}>{children}</NextIntlClientProvider>
|
|
42
|
+
</ThemeProvider>
|
|
41
43
|
<Toaster />
|
|
42
44
|
</body>
|
|
43
45
|
</html>
|
|
@@ -1,12 +1,28 @@
|
|
|
1
1
|
import { useTranslations } from 'next-intl'
|
|
2
|
+
import { Header } from '@/components/landing/header'
|
|
3
|
+
import { Hero } from '@/components/landing/hero'
|
|
4
|
+
import { Features } from '@/components/landing/features'
|
|
5
|
+
import { HowItWorks } from '@/components/landing/how-it-works'
|
|
6
|
+
import { PricingTeaser } from '@/components/landing/pricing-teaser'
|
|
7
|
+
import { Footer } from '@/components/landing/footer'
|
|
2
8
|
|
|
3
|
-
export default function HomePage() {
|
|
4
|
-
|
|
9
|
+
export default function HomePage({ params }: { params: Promise<{ locale: string }> }) {
|
|
10
|
+
return <HomePageContent params={params} />
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async function HomePageContent({ params }: { params: Promise<{ locale: string }> }) {
|
|
14
|
+
const { locale } = await params
|
|
5
15
|
|
|
6
16
|
return (
|
|
7
|
-
<
|
|
8
|
-
<
|
|
9
|
-
<
|
|
10
|
-
|
|
17
|
+
<div className="flex min-h-screen flex-col">
|
|
18
|
+
<Header locale={locale} />
|
|
19
|
+
<main className="flex-1">
|
|
20
|
+
<Hero locale={locale} />
|
|
21
|
+
<Features />
|
|
22
|
+
<HowItWorks />
|
|
23
|
+
<PricingTeaser />
|
|
24
|
+
</main>
|
|
25
|
+
<Footer locale={locale} />
|
|
26
|
+
</div>
|
|
11
27
|
)
|
|
12
28
|
}
|
|
@@ -1,23 +1,22 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
|
2
2
|
|
|
3
|
-
export default async function PrivacyPage({
|
|
4
|
-
params,
|
|
5
|
-
}: {
|
|
6
|
-
params: Promise<{ locale: string }>
|
|
7
|
-
}) {
|
|
3
|
+
export default async function PrivacyPage({ params }: { params: Promise<{ locale: string }> }) {
|
|
8
4
|
const { locale } = await params
|
|
9
5
|
|
|
10
6
|
return (
|
|
11
7
|
<main className="mx-auto max-w-3xl px-4 py-10">
|
|
12
|
-
<
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
<
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
8
|
+
<Card>
|
|
9
|
+
<CardHeader>
|
|
10
|
+
<CardTitle>Privacy Policy</CardTitle>
|
|
11
|
+
<CardDescription>How we handle your data.</CardDescription>
|
|
12
|
+
</CardHeader>
|
|
13
|
+
<CardContent>
|
|
14
|
+
<p className="text-muted-foreground">
|
|
15
|
+
This template page is a placeholder. Replace it with your actual privacy policy before
|
|
16
|
+
shipping.
|
|
17
|
+
</p>
|
|
18
|
+
</CardContent>
|
|
19
|
+
</Card>
|
|
21
20
|
</main>
|
|
22
21
|
)
|
|
23
22
|
}
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import Link from 'next/link'
|
|
2
2
|
|
|
3
|
-
export default async function TermsPage({
|
|
4
|
-
params,
|
|
5
|
-
}: {
|
|
6
|
-
params: Promise<{ locale: string }>
|
|
7
|
-
}) {
|
|
3
|
+
export default async function TermsPage({ params }: { params: Promise<{ locale: string }> }) {
|
|
8
4
|
const { locale } = await params
|
|
9
5
|
|
|
10
6
|
return (
|
|
@@ -2,18 +2,23 @@ import { NextRequest, NextResponse } from 'next/server'
|
|
|
2
2
|
import { getServerClient } from '@/infra/db/client'
|
|
3
3
|
import { defaultLocale } from '@/i18n/config'
|
|
4
4
|
|
|
5
|
+
const ALLOWED_NEXT = ['/reset-password']
|
|
6
|
+
|
|
5
7
|
export async function GET(request: NextRequest) {
|
|
6
8
|
const { searchParams, origin } = new URL(request.url)
|
|
7
9
|
const code = searchParams.get('code')
|
|
8
10
|
const nextParam = searchParams.get('next')
|
|
9
|
-
|
|
11
|
+
|
|
12
|
+
// Whitelist check to prevent open redirect attacks
|
|
13
|
+
const safePath =
|
|
14
|
+
nextParam && ALLOWED_NEXT.includes(nextParam) ? nextParam : `/${defaultLocale}/dashboard`
|
|
10
15
|
|
|
11
16
|
if (code) {
|
|
12
17
|
const supabase = await getServerClient()
|
|
13
18
|
const { error } = await supabase.auth.exchangeCodeForSession(code)
|
|
14
19
|
|
|
15
20
|
if (!error) {
|
|
16
|
-
return NextResponse.redirect(`${origin}${
|
|
21
|
+
return NextResponse.redirect(`${origin}${safePath}`)
|
|
17
22
|
}
|
|
18
23
|
}
|
|
19
24
|
|