@digilogiclabs/create-saas-app 1.5.2 → 1.5.4
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/dist/.tsbuildinfo +1 -1
- package/dist/templates/mobile/base/template/.env.example +15 -0
- package/dist/templates/mobile/base/template/App.tsx +88 -0
- package/dist/templates/mobile/base/template/app/(auth)/login.tsx +44 -0
- package/dist/templates/mobile/base/template/app/(auth)/signup.tsx +43 -0
- package/dist/templates/mobile/base/template/app/checkout.tsx +20 -0
- package/dist/templates/mobile/base/template/package.json +38 -0
- package/dist/templates/shared/auth/firebase/web/config.ts +23 -0
- package/dist/templates/shared/auth/supabase/web/config.ts +8 -0
- package/dist/templates/web/base/template/.env.example +15 -0
- package/dist/templates/web/base/template/.eslintrc.js +8 -0
- package/dist/templates/web/base/template/README.md +68 -0
- package/dist/templates/web/base/template/next.config.js +15 -0
- package/dist/templates/web/base/template/package.json +58 -0
- package/dist/templates/web/base/template/postcss.config.js +7 -0
- package/dist/templates/web/base/template/src/app/auth/callback/route.ts +18 -0
- package/dist/templates/web/base/template/src/app/checkout/page.tsx +28 -0
- package/dist/templates/web/base/template/src/app/error.tsx +97 -0
- package/dist/templates/web/base/template/src/app/globals.css +60 -0
- package/dist/templates/web/base/template/src/app/layout.tsx +35 -0
- package/dist/templates/web/base/template/src/app/loading.tsx +34 -0
- package/dist/templates/web/base/template/src/app/login/page.tsx +39 -0
- package/dist/templates/web/base/template/src/app/page.tsx +132 -0
- package/dist/templates/web/base/template/src/app/signup/page.tsx +39 -0
- package/dist/templates/web/base/template/src/components/__tests__/example.test.tsx +49 -0
- package/dist/templates/web/base/template/src/components/providers/app-providers.tsx +33 -0
- package/dist/templates/web/base/template/src/components/providers/theme-provider.tsx +94 -0
- package/dist/templates/web/base/template/src/components/shared/footer.tsx +36 -0
- package/dist/templates/web/base/template/src/components/shared/header.tsx +44 -0
- package/dist/templates/web/base/template/src/components/ui/badge.tsx +36 -0
- package/dist/templates/web/base/template/src/components/ui/button.tsx +56 -0
- package/dist/templates/web/base/template/src/components/ui/card.tsx +71 -0
- package/dist/templates/web/base/template/src/components/ui/theme-toggle.tsx +34 -0
- package/dist/templates/web/base/template/src/lib/auth-server.ts +177 -0
- package/dist/templates/web/base/template/src/lib/env.ts +46 -0
- package/dist/templates/web/base/template/src/lib/utils.ts +140 -0
- package/dist/templates/web/base/template/src/test/setup.ts +79 -0
- package/dist/templates/web/base/template/tailwind.config.js +77 -0
- package/dist/templates/web/base/template/tsconfig.json +33 -0
- package/dist/templates/web/base/template/vitest.config.ts +17 -0
- package/dist/templates/web/base/template.backup/.env.example +15 -0
- package/dist/templates/web/base/template.backup.20250817/.env.example +15 -0
- package/dist/templates/web/ui-auth/template/.env.example +15 -0
- package/dist/templates/web/ui-auth/template/.eslintrc.js +8 -0
- package/dist/templates/web/ui-auth/template/README.md +68 -0
- package/dist/templates/web/ui-auth/template/next.config.js +12 -0
- package/dist/templates/web/ui-auth/template/package.json +50 -0
- package/dist/templates/web/ui-auth/template/postcss.config.js +7 -0
- package/dist/templates/web/ui-auth/template/src/app/auth/callback/route.ts +12 -0
- package/dist/templates/web/ui-auth/template/src/app/checkout/page.tsx +25 -0
- package/dist/templates/web/ui-auth/template/src/app/error.tsx +67 -0
- package/dist/templates/web/ui-auth/template/src/app/globals.css +42 -0
- package/dist/templates/web/ui-auth/template/src/app/layout.tsx +33 -0
- package/dist/templates/web/ui-auth/template/src/app/loading.tsx +20 -0
- package/dist/templates/web/ui-auth/template/src/app/login/page.tsx +109 -0
- package/dist/templates/web/ui-auth/template/src/app/page.tsx +129 -0
- package/dist/templates/web/ui-auth/template/src/app/signup/page.tsx +128 -0
- package/dist/templates/web/ui-auth/template/src/components/__tests__/example.test.tsx +49 -0
- package/dist/templates/web/ui-auth/template/src/components/providers/app-providers.tsx +29 -0
- package/dist/templates/web/ui-auth/template/src/components/providers/theme-provider.tsx +94 -0
- package/dist/templates/web/ui-auth/template/src/components/shared/footer.tsx +36 -0
- package/dist/templates/web/ui-auth/template/src/components/shared/header.tsx +53 -0
- package/dist/templates/web/ui-auth/template/src/components/ui/badge.tsx +36 -0
- package/dist/templates/web/ui-auth/template/src/components/ui/theme-toggle.tsx +34 -0
- package/dist/templates/web/ui-auth/template/src/lib/env.ts +49 -0
- package/dist/templates/web/ui-auth/template/src/lib/utils.ts +140 -0
- package/dist/templates/web/ui-auth/template/src/test/setup.ts +79 -0
- package/dist/templates/web/ui-auth/template/tailwind.config.js +77 -0
- package/dist/templates/web/ui-auth/template/tsconfig.json +33 -0
- package/dist/templates/web/ui-auth/template/vitest.config.ts +17 -0
- package/dist/templates/web/ui-auth/template.backup/.env.example +15 -0
- package/dist/templates/web/ui-auth/template.backup.20250817/.env.example +15 -0
- package/dist/templates/web/ui-auth-payments/template/.env.example +15 -0
- package/dist/templates/web/ui-auth-payments/template/README.md +165 -0
- package/dist/templates/web/ui-auth-payments/template/middleware.ts +68 -0
- package/dist/templates/web/ui-auth-payments/template/next.config.js +12 -0
- package/dist/templates/web/ui-auth-payments/template/package-lock.json +12240 -0
- package/dist/templates/web/ui-auth-payments/template/package.json +52 -0
- package/dist/templates/web/ui-auth-payments/template/postcss.config.js +7 -0
- package/dist/templates/web/ui-auth-payments/template/src/app/auth/callback/route.ts +12 -0
- package/dist/templates/web/ui-auth-payments/template/src/app/billing/page.tsx +211 -0
- package/dist/templates/web/ui-auth-payments/template/src/app/checkout/page.tsx +142 -0
- package/dist/templates/web/ui-auth-payments/template/src/app/dashboard/layout.tsx +22 -0
- package/dist/templates/web/ui-auth-payments/template/src/app/dashboard/page.tsx +183 -0
- package/dist/templates/web/ui-auth-payments/template/src/app/error.tsx +67 -0
- package/dist/templates/web/ui-auth-payments/template/src/app/globals.css +42 -0
- package/dist/templates/web/ui-auth-payments/template/src/app/layout.tsx +33 -0
- package/dist/templates/web/ui-auth-payments/template/src/app/loading.tsx +20 -0
- package/dist/templates/web/ui-auth-payments/template/src/app/login/loading.tsx +38 -0
- package/dist/templates/web/ui-auth-payments/template/src/app/login/page.tsx +109 -0
- package/dist/templates/web/ui-auth-payments/template/src/app/page.tsx +143 -0
- package/dist/templates/web/ui-auth-payments/template/src/app/signup/loading.tsx +50 -0
- package/dist/templates/web/ui-auth-payments/template/src/app/signup/page.tsx +128 -0
- package/dist/templates/web/ui-auth-payments/template/src/components/__tests__/example.test.tsx +49 -0
- package/dist/templates/web/ui-auth-payments/template/src/components/client/auth-status.tsx +52 -0
- package/dist/templates/web/ui-auth-payments/template/src/components/client/login-form.tsx +144 -0
- package/dist/templates/web/ui-auth-payments/template/src/components/client/newsletter-signup.tsx +68 -0
- package/dist/templates/web/ui-auth-payments/template/src/components/client/signup-form.tsx +185 -0
- package/dist/templates/web/ui-auth-payments/template/src/components/providers/app-providers.tsx +32 -0
- package/dist/templates/web/ui-auth-payments/template/src/components/providers/theme-provider.tsx +94 -0
- package/dist/templates/web/ui-auth-payments/template/src/components/shared/footer.tsx +36 -0
- package/dist/templates/web/ui-auth-payments/template/src/components/shared/header.tsx +62 -0
- package/dist/templates/web/ui-auth-payments/template/src/components/ui/badge.tsx +36 -0
- package/dist/templates/web/ui-auth-payments/template/src/components/ui/theme-toggle.tsx +34 -0
- package/dist/templates/web/ui-auth-payments/template/src/lib/actions/auth.ts +246 -0
- package/dist/templates/web/ui-auth-payments/template/src/lib/actions/index.ts +340 -0
- package/dist/templates/web/ui-auth-payments/template/src/lib/auth-server.ts +177 -0
- package/dist/templates/web/ui-auth-payments/template/src/lib/env.ts +49 -0
- package/dist/templates/web/ui-auth-payments/template/src/lib/utils.ts +140 -0
- package/dist/templates/web/ui-auth-payments/template/src/test/setup.ts +79 -0
- package/dist/templates/web/ui-auth-payments/template/tailwind.config.js +77 -0
- package/dist/templates/web/ui-auth-payments/template/tsconfig.json +33 -0
- package/dist/templates/web/ui-auth-payments/template/tsconfig.tsbuildinfo +1 -0
- package/dist/templates/web/ui-auth-payments/template/vitest.config.ts +17 -0
- package/dist/templates/web/ui-auth-payments-audio/template/.env.example +15 -0
- package/dist/templates/web/ui-auth-payments-audio/template/README.md +187 -0
- package/dist/templates/web/ui-auth-payments-audio/template/middleware.ts +68 -0
- package/dist/templates/web/ui-auth-payments-audio/template/next.config.js +12 -0
- package/dist/templates/web/ui-auth-payments-audio/template/package-lock.json +12241 -0
- package/dist/templates/web/ui-auth-payments-audio/template/package.json +53 -0
- package/dist/templates/web/ui-auth-payments-audio/template/postcss.config.js +7 -0
- package/dist/templates/web/ui-auth-payments-audio/template/src/app/auth/callback/route.ts +12 -0
- package/dist/templates/web/ui-auth-payments-audio/template/src/app/billing/page.tsx +211 -0
- package/dist/templates/web/ui-auth-payments-audio/template/src/app/checkout/page.tsx +142 -0
- package/dist/templates/web/ui-auth-payments-audio/template/src/app/dashboard/layout.tsx +22 -0
- package/dist/templates/web/ui-auth-payments-audio/template/src/app/dashboard/page.tsx +183 -0
- package/dist/templates/web/ui-auth-payments-audio/template/src/app/error.tsx +67 -0
- package/dist/templates/web/ui-auth-payments-audio/template/src/app/globals.css +42 -0
- package/dist/templates/web/ui-auth-payments-audio/template/src/app/layout.tsx +35 -0
- package/dist/templates/web/ui-auth-payments-audio/template/src/app/loading.tsx +20 -0
- package/dist/templates/web/ui-auth-payments-audio/template/src/app/login/page.tsx +6 -0
- package/dist/templates/web/ui-auth-payments-audio/template/src/app/page.tsx +181 -0
- package/dist/templates/web/ui-auth-payments-audio/template/src/app/signup/page.tsx +6 -0
- package/dist/templates/web/ui-auth-payments-audio/template/src/components/__tests__/example.test.tsx +49 -0
- package/dist/templates/web/ui-auth-payments-audio/template/src/components/client/auth-status.tsx +52 -0
- package/dist/templates/web/ui-auth-payments-audio/template/src/components/client/login-form.tsx +144 -0
- package/dist/templates/web/ui-auth-payments-audio/template/src/components/client/signup-form.tsx +185 -0
- package/dist/templates/web/ui-auth-payments-audio/template/src/components/providers/app-providers.tsx +32 -0
- package/dist/templates/web/ui-auth-payments-audio/template/src/components/providers/theme-provider.tsx +94 -0
- package/dist/templates/web/ui-auth-payments-audio/template/src/components/shared/footer.tsx +36 -0
- package/dist/templates/web/ui-auth-payments-audio/template/src/components/shared/header.tsx +62 -0
- package/dist/templates/web/ui-auth-payments-audio/template/src/components/ui/badge.tsx +36 -0
- package/dist/templates/web/ui-auth-payments-audio/template/src/components/ui/theme-toggle.tsx +34 -0
- package/dist/templates/web/ui-auth-payments-audio/template/src/lib/actions/auth.ts +246 -0
- package/dist/templates/web/ui-auth-payments-audio/template/src/lib/actions/index.ts +14 -0
- package/dist/templates/web/ui-auth-payments-audio/template/src/lib/auth-server.ts +177 -0
- package/dist/templates/web/ui-auth-payments-audio/template/src/lib/env.ts +49 -0
- package/dist/templates/web/ui-auth-payments-audio/template/src/lib/utils.ts +140 -0
- package/dist/templates/web/ui-auth-payments-audio/template/src/test/setup.ts +79 -0
- package/dist/templates/web/ui-auth-payments-audio/template/tailwind.config.js +77 -0
- package/dist/templates/web/ui-auth-payments-audio/template/tsconfig.json +33 -0
- package/dist/templates/web/ui-auth-payments-audio/template/tsconfig.tsbuildinfo +1 -0
- package/dist/templates/web/ui-auth-payments-audio/template/vitest.config.ts +17 -0
- package/dist/templates/web/ui-auth-payments-video/template/.env.example +15 -0
- package/dist/templates/web/ui-auth-payments-video/template/README.md +190 -0
- package/dist/templates/web/ui-auth-payments-video/template/next.config.js +12 -0
- package/dist/templates/web/ui-auth-payments-video/template/package.json +53 -0
- package/dist/templates/web/ui-auth-payments-video/template/postcss.config.js +7 -0
- package/dist/templates/web/ui-auth-payments-video/template/src/app/auth/callback/route.ts +12 -0
- package/dist/templates/web/ui-auth-payments-video/template/src/app/billing/page.tsx +211 -0
- package/dist/templates/web/ui-auth-payments-video/template/src/app/checkout/page.tsx +142 -0
- package/dist/templates/web/ui-auth-payments-video/template/src/app/error.tsx +67 -0
- package/dist/templates/web/ui-auth-payments-video/template/src/app/globals.css +42 -0
- package/dist/templates/web/ui-auth-payments-video/template/src/app/layout.tsx +33 -0
- package/dist/templates/web/ui-auth-payments-video/template/src/app/loading.tsx +20 -0
- package/dist/templates/web/ui-auth-payments-video/template/src/app/login/page.tsx +109 -0
- package/dist/templates/web/ui-auth-payments-video/template/src/app/page.tsx +187 -0
- package/dist/templates/web/ui-auth-payments-video/template/src/app/signup/page.tsx +128 -0
- package/dist/templates/web/ui-auth-payments-video/template/src/components/__tests__/example.test.tsx +49 -0
- package/dist/templates/web/ui-auth-payments-video/template/src/components/providers/app-providers.tsx +32 -0
- package/dist/templates/web/ui-auth-payments-video/template/src/components/providers/theme-provider.tsx +94 -0
- package/dist/templates/web/ui-auth-payments-video/template/src/components/shared/footer.tsx +36 -0
- package/dist/templates/web/ui-auth-payments-video/template/src/components/shared/header.tsx +62 -0
- package/dist/templates/web/ui-auth-payments-video/template/src/components/ui/badge.tsx +36 -0
- package/dist/templates/web/ui-auth-payments-video/template/src/components/ui/theme-toggle.tsx +34 -0
- package/dist/templates/web/ui-auth-payments-video/template/src/lib/env.ts +49 -0
- package/dist/templates/web/ui-auth-payments-video/template/src/lib/utils.ts +140 -0
- package/dist/templates/web/ui-auth-payments-video/template/src/test/setup.ts +79 -0
- package/dist/templates/web/ui-auth-payments-video/template/tailwind.config.js +77 -0
- package/dist/templates/web/ui-auth-payments-video/template/tsconfig.json +33 -0
- package/dist/templates/web/ui-auth-payments-video/template/vitest.config.ts +17 -0
- package/dist/templates/web/ui-only/template/.env.example +15 -0
- package/dist/templates/web/ui-only/template/.eslintrc.js +8 -0
- package/dist/templates/web/ui-only/template/README.md +68 -0
- package/dist/templates/web/ui-only/template/next.config.js +12 -0
- package/dist/templates/web/ui-only/template/package.json +49 -0
- package/dist/templates/web/ui-only/template/postcss.config.js +7 -0
- package/dist/templates/web/ui-only/template/src/app/auth/callback/route.ts +12 -0
- package/dist/templates/web/ui-only/template/src/app/checkout/page.tsx +25 -0
- package/dist/templates/web/ui-only/template/src/app/error.tsx +67 -0
- package/dist/templates/web/ui-only/template/src/app/globals.css +42 -0
- package/dist/templates/web/ui-only/template/src/app/layout.tsx +33 -0
- package/dist/templates/web/ui-only/template/src/app/loading.tsx +20 -0
- package/dist/templates/web/ui-only/template/src/app/login/page.tsx +63 -0
- package/dist/templates/web/ui-only/template/src/app/page.tsx +91 -0
- package/dist/templates/web/ui-only/template/src/app/signup/page.tsx +79 -0
- package/dist/templates/web/ui-only/template/src/components/__tests__/example.test.tsx +49 -0
- package/dist/templates/web/ui-only/template/src/components/providers/app-providers.tsx +26 -0
- package/dist/templates/web/ui-only/template/src/components/providers/theme-provider.tsx +94 -0
- package/dist/templates/web/ui-only/template/src/components/shared/footer.tsx +36 -0
- package/dist/templates/web/ui-only/template/src/components/shared/header.tsx +53 -0
- package/dist/templates/web/ui-only/template/src/components/ui/badge.tsx +36 -0
- package/dist/templates/web/ui-only/template/src/components/ui/theme-toggle.tsx +34 -0
- package/dist/templates/web/ui-only/template/src/lib/env.ts +49 -0
- package/dist/templates/web/ui-only/template/src/lib/utils.ts +140 -0
- package/dist/templates/web/ui-only/template/src/test/setup.ts +79 -0
- package/dist/templates/web/ui-only/template/tailwind.config.js +77 -0
- package/dist/templates/web/ui-only/template/tsconfig.json +33 -0
- package/dist/templates/web/ui-only/template/vitest.config.ts +17 -0
- package/dist/templates/web/ui-only/template.backup/.env.example +15 -0
- package/dist/templates/web/ui-only/template.backup.20250817/.env.example +15 -0
- package/dist/templates/web/ui-package-test/template/next-env.d.ts +5 -0
- package/dist/templates/web/ui-package-test/template/package.json +42 -0
- package/dist/templates/web/ui-package-test/template/src/app/page.tsx +106 -0
- package/dist/templates/web/ui-package-test/template/tsconfig.json +41 -0
- package/package.json +3 -2
- package/src/templates/mobile/base/template/package.json +38 -38
- package/src/templates/web/base/template/package.json +1 -1
- 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-audio/template/package.json +1 -1
- package/src/templates/web/ui-auth-payments-video/template/package.json +1 -1
- package/src/templates/web/ui-only/template/package.json +1 -1
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
3
|
+
import { cn } from "@/lib/utils"
|
|
4
|
+
|
|
5
|
+
const badgeVariants = cva(
|
|
6
|
+
"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
|
|
7
|
+
{
|
|
8
|
+
variants: {
|
|
9
|
+
variant: {
|
|
10
|
+
default:
|
|
11
|
+
"border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
|
|
12
|
+
secondary:
|
|
13
|
+
"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
14
|
+
destructive:
|
|
15
|
+
"border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
|
|
16
|
+
outline: "text-foreground",
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
defaultVariants: {
|
|
20
|
+
variant: "default",
|
|
21
|
+
},
|
|
22
|
+
}
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
export interface BadgeProps
|
|
26
|
+
extends React.HTMLAttributes<HTMLDivElement>,
|
|
27
|
+
VariantProps<typeof badgeVariants> {}
|
|
28
|
+
|
|
29
|
+
function Badge({ className, variant, ...props }: BadgeProps) {
|
|
30
|
+
return (
|
|
31
|
+
<div className={cn(badgeVariants({ variant }), className)} {...props} />
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export { Badge, badgeVariants }
|
|
36
|
+
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import { Moon, Sun } from "lucide-react"
|
|
5
|
+
import { useTheme } from "next-themes"
|
|
6
|
+
|
|
7
|
+
import { Button } from "@digilogiclabs/saas-factory-ui"
|
|
8
|
+
|
|
9
|
+
export function ThemeToggle() {
|
|
10
|
+
const { theme, setTheme } = useTheme()
|
|
11
|
+
|
|
12
|
+
const toggleTheme = () => {
|
|
13
|
+
if (theme === 'light') {
|
|
14
|
+
setTheme('dark')
|
|
15
|
+
} else if (theme === 'dark') {
|
|
16
|
+
setTheme('system')
|
|
17
|
+
} else {
|
|
18
|
+
setTheme('light')
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<Button
|
|
24
|
+
variant="outline"
|
|
25
|
+
size="icon"
|
|
26
|
+
onClick={toggleTheme}
|
|
27
|
+
className="h-9 w-9"
|
|
28
|
+
>
|
|
29
|
+
<Sun className="h-4 w-4 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
|
|
30
|
+
<Moon className="absolute h-4 w-4 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
|
|
31
|
+
<span className="sr-only">Toggle theme</span>
|
|
32
|
+
</Button>
|
|
33
|
+
)
|
|
34
|
+
}
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
'use server'
|
|
2
|
+
|
|
3
|
+
import { redirect } from 'next/navigation'
|
|
4
|
+
import { cookies } from 'next/headers'
|
|
5
|
+
import { z } from 'zod'
|
|
6
|
+
|
|
7
|
+
// Schema for form validation
|
|
8
|
+
const signInSchema = z.object({
|
|
9
|
+
email: z.string().email('Invalid email address'),
|
|
10
|
+
password: z.string().min(6, 'Password must be at least 6 characters'),
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
const signUpSchema = z.object({
|
|
14
|
+
email: z.string().email('Invalid email address'),
|
|
15
|
+
password: z.string().min(6, 'Password must be at least 6 characters'),
|
|
16
|
+
confirmPassword: z.string(),
|
|
17
|
+
name: z.string().min(2, 'Name must be at least 2 characters').optional(),
|
|
18
|
+
}).refine((data) => data.password === data.confirmPassword, {
|
|
19
|
+
message: "Passwords don't match",
|
|
20
|
+
path: ["confirmPassword"],
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
// Response types
|
|
24
|
+
type ActionResult = {
|
|
25
|
+
success: boolean
|
|
26
|
+
error?: string
|
|
27
|
+
fieldErrors?: Record<string, string[]>
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Server action for signing in
|
|
32
|
+
* This works alongside the client-side @digilogiclabs/saas-factory-auth
|
|
33
|
+
*/
|
|
34
|
+
export async function signInAction(prevState: any, formData: FormData): Promise<ActionResult> {
|
|
35
|
+
try {
|
|
36
|
+
const rawData = {
|
|
37
|
+
email: formData.get('email') as string,
|
|
38
|
+
password: formData.get('password') as string,
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Validate form data
|
|
42
|
+
const validationResult = signInSchema.safeParse(rawData)
|
|
43
|
+
|
|
44
|
+
if (!validationResult.success) {
|
|
45
|
+
return {
|
|
46
|
+
success: false,
|
|
47
|
+
error: 'Please check your input',
|
|
48
|
+
fieldErrors: validationResult.error.formErrors.fieldErrors,
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const { email, password } = validationResult.data
|
|
53
|
+
|
|
54
|
+
// Note: The actual authentication is handled by the client-side library
|
|
55
|
+
// This server action is mainly for form validation and server-side processing
|
|
56
|
+
// You might want to add additional server-side logic here like:
|
|
57
|
+
// - Rate limiting
|
|
58
|
+
// - Logging
|
|
59
|
+
// - Analytics
|
|
60
|
+
|
|
61
|
+
// For now, we'll return success and let the client handle the actual auth
|
|
62
|
+
return {
|
|
63
|
+
success: true,
|
|
64
|
+
}
|
|
65
|
+
} catch (error) {
|
|
66
|
+
console.error('Sign in error:', error)
|
|
67
|
+
return {
|
|
68
|
+
success: false,
|
|
69
|
+
error: 'An unexpected error occurred. Please try again.',
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Server action for signing up
|
|
76
|
+
*/
|
|
77
|
+
export async function signUpAction(prevState: any, formData: FormData): Promise<ActionResult> {
|
|
78
|
+
try {
|
|
79
|
+
const rawData = {
|
|
80
|
+
email: formData.get('email') as string,
|
|
81
|
+
password: formData.get('password') as string,
|
|
82
|
+
confirmPassword: formData.get('confirmPassword') as string,
|
|
83
|
+
name: formData.get('name') as string,
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Validate form data
|
|
87
|
+
const validationResult = signUpSchema.safeParse(rawData)
|
|
88
|
+
|
|
89
|
+
if (!validationResult.success) {
|
|
90
|
+
return {
|
|
91
|
+
success: false,
|
|
92
|
+
error: 'Please check your input',
|
|
93
|
+
fieldErrors: validationResult.error.formErrors.fieldErrors,
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const { email, password, name } = validationResult.data
|
|
98
|
+
|
|
99
|
+
// Additional server-side processing can go here
|
|
100
|
+
// - User existence check
|
|
101
|
+
// - Welcome email preparation
|
|
102
|
+
// - User analytics setup
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
success: true,
|
|
106
|
+
}
|
|
107
|
+
} catch (error) {
|
|
108
|
+
console.error('Sign up error:', error)
|
|
109
|
+
return {
|
|
110
|
+
success: false,
|
|
111
|
+
error: 'An unexpected error occurred. Please try again.',
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Server action for signing out
|
|
118
|
+
*/
|
|
119
|
+
export async function signOutAction(): Promise<void> {
|
|
120
|
+
try {
|
|
121
|
+
const cookieStore = await cookies()
|
|
122
|
+
|
|
123
|
+
// Clear auth cookies (adjust cookie names based on the auth library)
|
|
124
|
+
cookieStore.delete('saas-factory-auth-token')
|
|
125
|
+
cookieStore.delete('saas-factory-auth-user')
|
|
126
|
+
|
|
127
|
+
// Additional cleanup can go here
|
|
128
|
+
// - Clear session data
|
|
129
|
+
// - Log sign out event
|
|
130
|
+
// - Clear cache
|
|
131
|
+
|
|
132
|
+
} catch (error) {
|
|
133
|
+
console.error('Sign out error:', error)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
redirect('/')
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Server action for OAuth redirect handling
|
|
141
|
+
*/
|
|
142
|
+
export async function handleOAuthCallback(provider: string, code: string): Promise<ActionResult> {
|
|
143
|
+
try {
|
|
144
|
+
// This would handle OAuth callback processing
|
|
145
|
+
// For now, we'll delegate to the client-side library
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
success: true,
|
|
149
|
+
}
|
|
150
|
+
} catch (error) {
|
|
151
|
+
console.error('OAuth callback error:', error)
|
|
152
|
+
return {
|
|
153
|
+
success: false,
|
|
154
|
+
error: 'Authentication failed. Please try again.',
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Server action for password reset request
|
|
161
|
+
*/
|
|
162
|
+
export async function requestPasswordReset(prevState: any, formData: FormData): Promise<ActionResult> {
|
|
163
|
+
try {
|
|
164
|
+
const email = formData.get('email') as string
|
|
165
|
+
|
|
166
|
+
if (!email) {
|
|
167
|
+
return {
|
|
168
|
+
success: false,
|
|
169
|
+
error: 'Email is required',
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const emailSchema = z.string().email()
|
|
174
|
+
const validationResult = emailSchema.safeParse(email)
|
|
175
|
+
|
|
176
|
+
if (!validationResult.success) {
|
|
177
|
+
return {
|
|
178
|
+
success: false,
|
|
179
|
+
error: 'Please enter a valid email address',
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Password reset logic would go here
|
|
184
|
+
// - Generate reset token
|
|
185
|
+
// - Send reset email
|
|
186
|
+
// - Log reset request
|
|
187
|
+
|
|
188
|
+
return {
|
|
189
|
+
success: true,
|
|
190
|
+
}
|
|
191
|
+
} catch (error) {
|
|
192
|
+
console.error('Password reset error:', error)
|
|
193
|
+
return {
|
|
194
|
+
success: false,
|
|
195
|
+
error: 'An unexpected error occurred. Please try again.',
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Server action for updating user profile
|
|
202
|
+
*/
|
|
203
|
+
export async function updateProfileAction(prevState: any, formData: FormData): Promise<ActionResult> {
|
|
204
|
+
try {
|
|
205
|
+
// This would require authentication check
|
|
206
|
+
const cookieStore = await cookies()
|
|
207
|
+
const authToken = cookieStore.get('saas-factory-auth-token')?.value
|
|
208
|
+
|
|
209
|
+
if (!authToken) {
|
|
210
|
+
redirect('/login')
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const name = formData.get('name') as string
|
|
214
|
+
const email = formData.get('email') as string
|
|
215
|
+
|
|
216
|
+
const updateSchema = z.object({
|
|
217
|
+
name: z.string().min(2, 'Name must be at least 2 characters').optional(),
|
|
218
|
+
email: z.string().email('Invalid email address').optional(),
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
const validationResult = updateSchema.safeParse({ name, email })
|
|
222
|
+
|
|
223
|
+
if (!validationResult.success) {
|
|
224
|
+
return {
|
|
225
|
+
success: false,
|
|
226
|
+
error: 'Please check your input',
|
|
227
|
+
fieldErrors: validationResult.error.formErrors.fieldErrors,
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Profile update logic would go here
|
|
232
|
+
// - Update user in database
|
|
233
|
+
// - Update auth cookies
|
|
234
|
+
// - Send confirmation email if email changed
|
|
235
|
+
|
|
236
|
+
return {
|
|
237
|
+
success: true,
|
|
238
|
+
}
|
|
239
|
+
} catch (error) {
|
|
240
|
+
console.error('Profile update error:', error)
|
|
241
|
+
return {
|
|
242
|
+
success: false,
|
|
243
|
+
error: 'An unexpected error occurred. Please try again.',
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
'use server'
|
|
2
|
+
|
|
3
|
+
import { after } from 'next/server'
|
|
4
|
+
import { revalidateTag, revalidatePath } from 'next/cache'
|
|
5
|
+
import { getCurrentUser } from '@/lib/auth-server'
|
|
6
|
+
import { z } from 'zod'
|
|
7
|
+
|
|
8
|
+
// Common response type
|
|
9
|
+
export type ActionResponse<T = any> = {
|
|
10
|
+
success: boolean
|
|
11
|
+
data?: T
|
|
12
|
+
error?: string
|
|
13
|
+
fieldErrors?: Record<string, string[]>
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Example server action for contact form
|
|
18
|
+
*/
|
|
19
|
+
export async function submitContactForm(prevState: any, formData: FormData): Promise<ActionResponse> {
|
|
20
|
+
try {
|
|
21
|
+
const contactSchema = z.object({
|
|
22
|
+
name: z.string().min(2, 'Name must be at least 2 characters'),
|
|
23
|
+
email: z.string().email('Invalid email address'),
|
|
24
|
+
subject: z.string().min(5, 'Subject must be at least 5 characters'),
|
|
25
|
+
message: z.string().min(10, 'Message must be at least 10 characters'),
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
const rawData = {
|
|
29
|
+
name: formData.get('name') as string,
|
|
30
|
+
email: formData.get('email') as string,
|
|
31
|
+
subject: formData.get('subject') as string,
|
|
32
|
+
message: formData.get('message') as string,
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const validationResult = contactSchema.safeParse(rawData)
|
|
36
|
+
|
|
37
|
+
if (!validationResult.success) {
|
|
38
|
+
return {
|
|
39
|
+
success: false,
|
|
40
|
+
error: 'Please check your input',
|
|
41
|
+
fieldErrors: validationResult.error.formErrors.fieldErrors,
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const { name, email, subject, message } = validationResult.data
|
|
46
|
+
|
|
47
|
+
// Process contact form submission
|
|
48
|
+
// This could involve:
|
|
49
|
+
// - Sending email to admin
|
|
50
|
+
// - Saving to database
|
|
51
|
+
// - Sending auto-reply to user
|
|
52
|
+
|
|
53
|
+
// Use after() for non-blocking operations (Next.js 15.3 feature)
|
|
54
|
+
after(async () => {
|
|
55
|
+
// Send notification email to admin (non-blocking)
|
|
56
|
+
console.log('Sending notification email for contact form submission')
|
|
57
|
+
|
|
58
|
+
// Log analytics event (non-blocking)
|
|
59
|
+
console.log('Logging contact form submission analytics')
|
|
60
|
+
|
|
61
|
+
// Update dashboard statistics (non-blocking)
|
|
62
|
+
console.log('Updating contact form statistics')
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
success: true,
|
|
67
|
+
data: { message: 'Thank you for your message. We\'ll get back to you soon!' }
|
|
68
|
+
}
|
|
69
|
+
} catch (error) {
|
|
70
|
+
console.error('Contact form error:', error)
|
|
71
|
+
return {
|
|
72
|
+
success: false,
|
|
73
|
+
error: 'An unexpected error occurred. Please try again.',
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Example server action for newsletter signup
|
|
80
|
+
*/
|
|
81
|
+
export async function subscribeToNewsletter(prevState: any, formData: FormData): Promise<ActionResponse> {
|
|
82
|
+
try {
|
|
83
|
+
const email = formData.get('email') as string
|
|
84
|
+
|
|
85
|
+
const emailSchema = z.string().email('Invalid email address')
|
|
86
|
+
const validationResult = emailSchema.safeParse(email)
|
|
87
|
+
|
|
88
|
+
if (!validationResult.success) {
|
|
89
|
+
return {
|
|
90
|
+
success: false,
|
|
91
|
+
error: 'Please enter a valid email address',
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Add to newsletter list
|
|
96
|
+
// This could involve:
|
|
97
|
+
// - Adding to email service provider (Mailchimp, ConvertKit, etc.)
|
|
98
|
+
// - Saving to database
|
|
99
|
+
// - Sending welcome email
|
|
100
|
+
|
|
101
|
+
after(async () => {
|
|
102
|
+
// Send welcome email (non-blocking)
|
|
103
|
+
console.log(`Sending welcome email to ${email}`)
|
|
104
|
+
|
|
105
|
+
// Add to email marketing platform (non-blocking)
|
|
106
|
+
console.log(`Adding ${email} to newsletter list`)
|
|
107
|
+
|
|
108
|
+
// Track conversion (non-blocking)
|
|
109
|
+
console.log('Tracking newsletter signup conversion')
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
success: true,
|
|
114
|
+
data: { message: 'Successfully subscribed to newsletter!' }
|
|
115
|
+
}
|
|
116
|
+
} catch (error) {
|
|
117
|
+
console.error('Newsletter subscription error:', error)
|
|
118
|
+
return {
|
|
119
|
+
success: false,
|
|
120
|
+
error: 'An unexpected error occurred. Please try again.',
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Example authenticated server action
|
|
127
|
+
*/
|
|
128
|
+
export async function createPost(prevState: any, formData: FormData): Promise<ActionResponse> {
|
|
129
|
+
try {
|
|
130
|
+
// Require authentication
|
|
131
|
+
const user = await getCurrentUser()
|
|
132
|
+
if (!user) {
|
|
133
|
+
return {
|
|
134
|
+
success: false,
|
|
135
|
+
error: 'Authentication required',
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const postSchema = z.object({
|
|
140
|
+
title: z.string().min(3, 'Title must be at least 3 characters'),
|
|
141
|
+
content: z.string().min(10, 'Content must be at least 10 characters'),
|
|
142
|
+
published: z.boolean().default(false),
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
const rawData = {
|
|
146
|
+
title: formData.get('title') as string,
|
|
147
|
+
content: formData.get('content') as string,
|
|
148
|
+
published: formData.get('published') === 'true',
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const validationResult = postSchema.safeParse(rawData)
|
|
152
|
+
|
|
153
|
+
if (!validationResult.success) {
|
|
154
|
+
return {
|
|
155
|
+
success: false,
|
|
156
|
+
error: 'Please check your input',
|
|
157
|
+
fieldErrors: validationResult.error.formErrors.fieldErrors,
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const { title, content, published } = validationResult.data
|
|
162
|
+
|
|
163
|
+
// Create post in database
|
|
164
|
+
const post = {
|
|
165
|
+
id: Math.random().toString(36).substr(2, 9),
|
|
166
|
+
title,
|
|
167
|
+
content,
|
|
168
|
+
published,
|
|
169
|
+
authorId: user.id,
|
|
170
|
+
createdAt: new Date().toISOString(),
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Revalidate relevant paths and tags
|
|
174
|
+
revalidateTag('posts')
|
|
175
|
+
revalidatePath('/posts')
|
|
176
|
+
if (published) {
|
|
177
|
+
revalidatePath('/')
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Non-blocking operations
|
|
181
|
+
after(async () => {
|
|
182
|
+
// Send notifications to subscribers (non-blocking)
|
|
183
|
+
if (published) {
|
|
184
|
+
console.log('Notifying subscribers of new post')
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Update search index (non-blocking)
|
|
188
|
+
console.log('Updating search index')
|
|
189
|
+
|
|
190
|
+
// Track content creation analytics (non-blocking)
|
|
191
|
+
console.log('Tracking post creation analytics')
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
return {
|
|
195
|
+
success: true,
|
|
196
|
+
data: { post, message: published ? 'Post published successfully!' : 'Post saved as draft!' }
|
|
197
|
+
}
|
|
198
|
+
} catch (error) {
|
|
199
|
+
console.error('Create post error:', error)
|
|
200
|
+
return {
|
|
201
|
+
success: false,
|
|
202
|
+
error: 'An unexpected error occurred. Please try again.',
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Example action for updating user preferences
|
|
209
|
+
*/
|
|
210
|
+
export async function updatePreferences(prevState: any, formData: FormData): Promise<ActionResponse> {
|
|
211
|
+
try {
|
|
212
|
+
const user = await getCurrentUser()
|
|
213
|
+
if (!user) {
|
|
214
|
+
return {
|
|
215
|
+
success: false,
|
|
216
|
+
error: 'Authentication required',
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const preferencesSchema = z.object({
|
|
221
|
+
emailNotifications: z.boolean().default(true),
|
|
222
|
+
pushNotifications: z.boolean().default(false),
|
|
223
|
+
marketingEmails: z.boolean().default(false),
|
|
224
|
+
theme: z.enum(['light', 'dark', 'system']).default('system'),
|
|
225
|
+
})
|
|
226
|
+
|
|
227
|
+
const rawData = {
|
|
228
|
+
emailNotifications: formData.get('emailNotifications') === 'true',
|
|
229
|
+
pushNotifications: formData.get('pushNotifications') === 'true',
|
|
230
|
+
marketingEmails: formData.get('marketingEmails') === 'true',
|
|
231
|
+
theme: formData.get('theme') as 'light' | 'dark' | 'system' | null || 'system',
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const validationResult = preferencesSchema.safeParse(rawData)
|
|
235
|
+
|
|
236
|
+
if (!validationResult.success) {
|
|
237
|
+
return {
|
|
238
|
+
success: false,
|
|
239
|
+
error: 'Please check your input',
|
|
240
|
+
fieldErrors: validationResult.error.formErrors.fieldErrors,
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const preferences = validationResult.data
|
|
245
|
+
|
|
246
|
+
// Update user preferences in database
|
|
247
|
+
// This would typically involve a database update
|
|
248
|
+
|
|
249
|
+
after(async () => {
|
|
250
|
+
// Update notification service settings (non-blocking)
|
|
251
|
+
console.log('Updating notification service settings')
|
|
252
|
+
|
|
253
|
+
// Log preference changes for analytics (non-blocking)
|
|
254
|
+
console.log('Logging preference changes')
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
return {
|
|
258
|
+
success: true,
|
|
259
|
+
data: { preferences, message: 'Preferences updated successfully!' }
|
|
260
|
+
}
|
|
261
|
+
} catch (error) {
|
|
262
|
+
console.error('Update preferences error:', error)
|
|
263
|
+
return {
|
|
264
|
+
success: false,
|
|
265
|
+
error: 'An unexpected error occurred. Please try again.',
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Example action with file upload
|
|
272
|
+
*/
|
|
273
|
+
export async function uploadAvatar(prevState: any, formData: FormData): Promise<ActionResponse> {
|
|
274
|
+
try {
|
|
275
|
+
const user = await getCurrentUser()
|
|
276
|
+
if (!user) {
|
|
277
|
+
return {
|
|
278
|
+
success: false,
|
|
279
|
+
error: 'Authentication required',
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const file = formData.get('avatar') as File
|
|
284
|
+
|
|
285
|
+
if (!file || file.size === 0) {
|
|
286
|
+
return {
|
|
287
|
+
success: false,
|
|
288
|
+
error: 'Please select a file to upload',
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Validate file type and size
|
|
293
|
+
const allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp']
|
|
294
|
+
const maxSize = 5 * 1024 * 1024 // 5MB
|
|
295
|
+
|
|
296
|
+
if (!allowedTypes.includes(file.type)) {
|
|
297
|
+
return {
|
|
298
|
+
success: false,
|
|
299
|
+
error: 'Please upload a valid image file (JPEG, PNG, GIF, or WebP)',
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (file.size > maxSize) {
|
|
304
|
+
return {
|
|
305
|
+
success: false,
|
|
306
|
+
error: 'File size must be less than 5MB',
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Process file upload
|
|
311
|
+
// This would typically involve:
|
|
312
|
+
// - Uploading to cloud storage (AWS S3, Cloudinary, etc.)
|
|
313
|
+
// - Resizing/optimizing the image
|
|
314
|
+
// - Updating user record in database
|
|
315
|
+
|
|
316
|
+
const avatarUrl = `https://example.com/avatars/${user.id}-${Date.now()}.${file.type.split('/')[1]}`
|
|
317
|
+
|
|
318
|
+
after(async () => {
|
|
319
|
+
// Generate different image sizes (non-blocking)
|
|
320
|
+
console.log('Generating avatar thumbnails')
|
|
321
|
+
|
|
322
|
+
// Update CDN cache (non-blocking)
|
|
323
|
+
console.log('Updating CDN cache')
|
|
324
|
+
|
|
325
|
+
// Log upload event (non-blocking)
|
|
326
|
+
console.log('Logging avatar upload event')
|
|
327
|
+
})
|
|
328
|
+
|
|
329
|
+
return {
|
|
330
|
+
success: true,
|
|
331
|
+
data: { avatarUrl, message: 'Avatar uploaded successfully!' }
|
|
332
|
+
}
|
|
333
|
+
} catch (error) {
|
|
334
|
+
console.error('Upload avatar error:', error)
|
|
335
|
+
return {
|
|
336
|
+
success: false,
|
|
337
|
+
error: 'An unexpected error occurred. Please try again.',
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|