Files
dragonsstash/src/app/(auth)/register/page.tsx
admin ab558e00f5 feat: add preview management, channel controls, invite polish, and recovery
- Auto-extract preview images from ZIP/RAR/7z archives during ingestion
- Upload custom preview images via package drawer
- Select preview from archive contents with on-demand extraction UI
- Manually add Telegram channels by t.me link, username, or invite link
- Invite code UX: bulk create, copy link, usage tracking, delete confirm
- Incomplete upload recovery: verify dest messages on worker startup
- Rebuild package DB by scanning destination channel with live progress

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 00:09:59 +01:00

202 lines
6.2 KiB
TypeScript

"use client";
import { useState, useTransition } from "react";
import { useRouter, useSearchParams } from "next/navigation";
import Link from "next/link";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { Flame } from "lucide-react";
import { registerSchema, type RegisterInput } from "@/schemas/auth.schema";
import { registerUser } from "./actions";
import { loginAction } from "../login/actions";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { APP_NAME } from "@/lib/constants";
export default function RegisterPage() {
const router = useRouter();
const searchParams = useSearchParams();
const [error, setError] = useState<string | null>(null);
const [isPending, startTransition] = useTransition();
const form = useForm<RegisterInput>({
resolver: zodResolver(registerSchema),
defaultValues: {
name: "",
email: "",
password: "",
confirmPassword: "",
inviteCode: searchParams.get("code") ?? "",
},
});
function onSubmit(values: RegisterInput) {
setError(null);
startTransition(async () => {
const result = await registerUser(values);
if (!result.success) {
setError(result.error);
return;
}
// Auto-login after registration using server action
try {
const loginResult = await loginAction({
email: values.email,
password: values.password,
});
if (loginResult?.error) {
setError("Account created but sign in failed. Please try logging in.");
return;
}
router.push("/dashboard");
router.refresh();
} catch {
// Redirect from server action
router.push("/dashboard");
router.refresh();
}
});
}
return (
<>
<div className="flex flex-col items-center gap-2 text-center">
<Flame className="h-10 w-10 text-primary" />
<h1 className="text-2xl font-bold tracking-tight">{APP_NAME}</h1>
<p className="text-sm text-muted-foreground">Create an account to get started</p>
</div>
<Card>
<CardHeader>
<CardTitle>Create Account</CardTitle>
<CardDescription>You need an invite code to register</CardDescription>
</CardHeader>
<CardContent>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
{error && (
<div className="rounded-md bg-destructive/10 p-3 text-sm text-destructive">
{error}
</div>
)}
<FormField
control={form.control}
name="inviteCode"
render={({ field }) => (
<FormItem>
<FormLabel>Invite Code</FormLabel>
<FormControl>
<Input
placeholder="Enter your invite code"
autoComplete="off"
{...field}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="name"
render={({ field }) => (
<FormItem>
<FormLabel>Name</FormLabel>
<FormControl>
<Input placeholder="Your name" autoComplete="name" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem>
<FormLabel>Email</FormLabel>
<FormControl>
<Input
type="email"
placeholder="you@example.com"
autoComplete="email"
{...field}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="password"
render={({ field }) => (
<FormItem>
<FormLabel>Password</FormLabel>
<FormControl>
<Input
type="password"
placeholder="At least 6 characters"
autoComplete="new-password"
{...field}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="confirmPassword"
render={({ field }) => (
<FormItem>
<FormLabel>Confirm Password</FormLabel>
<FormControl>
<Input
type="password"
placeholder="Repeat your password"
autoComplete="new-password"
{...field}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit" className="w-full" disabled={isPending}>
{isPending ? "Creating account..." : "Create Account"}
</Button>
</form>
</Form>
<p className="mt-4 text-center text-sm text-muted-foreground">
Already have an account?{" "}
<Link href="/login" className="text-primary underline-offset-4 hover:underline">
Sign in
</Link>
</p>
</CardContent>
</Card>
</>
);
}