In theory all done expect En|es and light/dark

This commit is contained in:
mdares
2026-01-04 00:53:00 +00:00
parent b6eed8b6db
commit 538b06bd4b
2 changed files with 67 additions and 9 deletions

View File

@@ -10,22 +10,40 @@ type InviteInfo = {
expiresAt: string; expiresAt: string;
}; };
export default function InviteAcceptForm({ token }: { token: string }) { type InviteAcceptFormProps = {
token: string;
initialInvite?: InviteInfo | null;
initialError?: string | null;
};
export default function InviteAcceptForm({
token,
initialInvite = null,
initialError = null,
}: InviteAcceptFormProps) {
const router = useRouter(); const router = useRouter();
const [invite, setInvite] = useState<InviteInfo | null>(null); const cleanedToken = token.trim();
const [loading, setLoading] = useState(true); const [invite, setInvite] = useState<InviteInfo | null>(initialInvite);
const [loading, setLoading] = useState(!initialInvite && !initialError);
const [submitting, setSubmitting] = useState(false); const [submitting, setSubmitting] = useState(false);
const [error, setError] = useState<string | null>(null); const [error, setError] = useState<string | null>(initialError);
const [name, setName] = useState(""); const [name, setName] = useState("");
const [password, setPassword] = useState(""); const [password, setPassword] = useState("");
useEffect(() => { useEffect(() => {
if (initialInvite || initialError) {
setLoading(false);
return;
}
let alive = true; let alive = true;
async function loadInvite() { async function loadInvite() {
setLoading(true); setLoading(true);
setError(null); setError(null);
try { try {
const res = await fetch(`/api/invites/${token}`, { cache: "no-store" }); const res = await fetch(`/api/invites/${encodeURIComponent(cleanedToken)}`, {
cache: "no-store",
});
const data = await res.json().catch(() => ({})); const data = await res.json().catch(() => ({}));
if (!res.ok || !data.ok) { if (!res.ok || !data.ok) {
throw new Error(data.error || "Invite not found"); throw new Error(data.error || "Invite not found");
@@ -42,14 +60,14 @@ export default function InviteAcceptForm({ token }: { token: string }) {
return () => { return () => {
alive = false; alive = false;
}; };
}, [token]); }, [cleanedToken, initialInvite, initialError]);
async function onSubmit(e: React.FormEvent) { async function onSubmit(e: React.FormEvent) {
e.preventDefault(); e.preventDefault();
setError(null); setError(null);
setSubmitting(true); setSubmitting(true);
try { try {
const res = await fetch(`/api/invites/${token}`, { const res = await fetch(`/api/invites/${encodeURIComponent(cleanedToken)}`, {
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name, password }), body: JSON.stringify({ name, password }),

View File

@@ -1,12 +1,52 @@
import { cookies } from "next/headers"; import { cookies } from "next/headers";
import { redirect } from "next/navigation"; import { redirect } from "next/navigation";
import { prisma } from "@/lib/prisma";
import InviteAcceptForm from "./InviteAcceptForm"; import InviteAcceptForm from "./InviteAcceptForm";
export default async function InvitePage({ params }: { params: { token: string } }) { export default async function InvitePage({ params }: { params: { token: string } | Promise<{ token: string }> }) {
const session = (await cookies()).get("mis_session")?.value; const session = (await cookies()).get("mis_session")?.value;
if (session) { if (session) {
redirect("/machines"); redirect("/machines");
} }
return <InviteAcceptForm token={params.token} />; const resolvedParams = await Promise.resolve(params);
const token = String(resolvedParams?.token || "").trim().toLowerCase();
let invite = null;
let error: string | null = null;
if (!token) {
error = "Invite not found";
} else {
invite = await prisma.orgInvite.findFirst({
where: {
token,
revokedAt: null,
acceptedAt: null,
expiresAt: { gt: new Date() },
},
include: {
org: { select: { id: true, name: true, slug: true } },
},
});
if (!invite) {
error = "Invite not found";
}
}
return (
<InviteAcceptForm
token={token}
initialInvite={
invite
? {
email: invite.email,
role: invite.role,
org: invite.org,
expiresAt: invite.expiresAt.toISOString(),
}
: null
}
initialError={error}
/>
);
} }