feat: add invite code system and multi-image Drone pipeline
Some checks failed
continuous-integration/drone/push Build is failing

- Add InviteCode model with code, maxUses, expiry, usage tracking
- Registration now requires a valid invite code
- New users get USER role instead of ADMIN
- Admin-only /invites page to create, manage, and share invite codes
- Invite links auto-fill code via ?code= URL param
- Drone pipeline now builds app, worker, and bot images separately
- Add NEXT_PUBLIC_APP_URL build arg to fix URL redirects
This commit is contained in:
admin
2026-03-21 15:33:12 +01:00
parent 30fb96b3f9
commit 031a4687fb
12 changed files with 403 additions and 18 deletions

View File

@@ -1,7 +1,7 @@
"use client";
import { useState, useTransition } from "react";
import { useRouter } from "next/navigation";
import { useRouter, useSearchParams } from "next/navigation";
import Link from "next/link";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
@@ -24,12 +24,19 @@ 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: "" },
defaultValues: {
name: "",
email: "",
password: "",
confirmPassword: "",
inviteCode: searchParams.get("code") ?? "",
},
});
function onSubmit(values: RegisterInput) {
@@ -75,7 +82,7 @@ export default function RegisterPage() {
<Card>
<CardHeader>
<CardTitle>Create Account</CardTitle>
<CardDescription>Fill in your details below</CardDescription>
<CardDescription>You need an invite code to register</CardDescription>
</CardHeader>
<CardContent>
<Form {...form}>
@@ -86,6 +93,20 @@ export default function RegisterPage() {
</div>
)}
<FormField
control={form.control}
name="inviteCode"
render={({ field }) => (
<FormItem>
<FormLabel>Invite Code</FormLabel>
<FormControl>
<Input placeholder="Enter your invite code" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="name"