Files
solelog/apps/web/src/app/account/signup/page.tsx
Bas van Rossem d94d0b188b Initial commit: code as received (Create/Anything export)
Insole-production time tracker exported from the Create/Anything AI
platform. Baseline snapshot before any reverse-engineering or cleanup.

- apps/mobile: Expo Router app (iOS/Android/web), the only workspace
- publisher/: standalone OpenNext/AWS deploy tooling for the web side
- Backend (/api/tasks, /api/logs + DB) lives remotely, not in this repo
2026-06-17 10:19:33 +02:00

125 lines
3.6 KiB
TypeScript

/**
* ⚠ ANYTHING PLATFORM — DO NOT REWRITE THIS FILE ⚠
*
* Shipped v2 auth scaffolding. The <form onSubmit>, e.preventDefault(), and
* window.location.href redirect are load-bearing for the mobile WebView auth
* flow (AuthWebView intercepts the navigation to capture the session). A
* prior AI rewrite replaced <form onSubmit> with <button onClick> and broke
* signup platform-wide — "credentials cleared" / "button does nothing" for
* every user until a human reverted it. DO NOT repeat that mistake.
*
* Safe: restyle, rewrite copy, add form fields (pass `name` explicitly).
* Unsafe: replacing <form>, removing preventDefault, bypassing
* authClient.signUp.email, changing the callbackUrl redirect.
*/
"use client";
import { useSearchParams } from "next/navigation";
import { type FormEvent, Suspense, useState } from "react";
import { SocialSignInButtons } from "@/components/SocialSignInButtons";
import { authClient } from "@/lib/auth-client";
function SignUpForm() {
const searchParams = useSearchParams();
const callbackUrl = searchParams.get("callbackUrl") || "/";
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState<string | null>(null);
const [loading, setLoading] = useState(false);
const onSubmit = async (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
setLoading(true);
setError(null);
// The server backfills `name` from the email local-part when it's missing,
// so email + password is enough.
const { error: signUpError } = await authClient.signUp.email({
email,
password,
name: "",
});
if (signUpError) {
setError(signUpError.message ?? "Sign up failed");
setLoading(false);
return;
}
if (typeof window !== "undefined") {
window.location.href = callbackUrl;
} else {
console.warn(
"signup: window is undefined; cannot redirect to callbackUrl",
);
}
};
return (
<main className="flex min-h-screen w-full items-center justify-center bg-gray-50 p-[16px]">
<form
onSubmit={(e) => {
void onSubmit(e);
}}
className="flex w-full max-w-[400px] flex-col gap-[16px] rounded-[12px] bg-white p-[24px] shadow"
>
<h1 className="text-[24px] font-semibold">Create account</h1>
<label className="flex flex-col gap-[4px] text-[14px]">
Email
<input
type="email"
required
value={email}
onChange={(e) => setEmail(e.target.value)}
className="rounded-[8px] border border-gray-300 p-[10px] text-[16px] outline-none focus:border-blue-500"
/>
</label>
<label className="flex flex-col gap-[4px] text-[14px]">
Password
<input
type="password"
required
minLength={8}
value={password}
onChange={(e) => setPassword(e.target.value)}
className="rounded-[8px] border border-gray-300 p-[10px] text-[16px] outline-none focus:border-blue-500"
/>
</label>
{error && (
<div className="rounded-[8px] bg-red-50 p-[10px] text-[14px] text-red-600">
{error}
</div>
)}
<button
type="submit"
disabled={loading}
className="rounded-[8px] bg-blue-600 p-[12px] text-[16px] font-medium text-white disabled:opacity-50"
>
{loading ? "Creating account…" : "Sign Up"}
</button>
<SocialSignInButtons callbackUrl={callbackUrl} />
<a
href={`/account/signin?callbackUrl=${encodeURIComponent(callbackUrl)}`}
className="text-center text-[14px] text-blue-600 hover:underline"
>
Already have an account? Sign in
</a>
</form>
</main>
);
}
export default function SignUpPage() {
return (
<Suspense>
<SignUpForm />
</Suspense>
);
}