104 lines
3.3 KiB
TypeScript
104 lines
3.3 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import { toast } from "sonner";
|
|
import { Clock, Link2, Loader2 } from "lucide-react";
|
|
|
|
import { Button } from "@/components/ui/button";
|
|
import {
|
|
Card,
|
|
CardContent,
|
|
CardDescription,
|
|
CardHeader,
|
|
CardTitle,
|
|
} from "@/components/ui/card";
|
|
import { Input } from "@/components/ui/input";
|
|
import { Label } from "@/components/ui/label";
|
|
import { requestAccountLink } from "@/lib/actions/account-links";
|
|
|
|
/**
|
|
* "Request Account Link": asks to link this account with another one on
|
|
* the server by email. On success the form is replaced by the
|
|
* "awaiting confirmation" status, since the recipient still has to accept
|
|
* it from their own Profile page.
|
|
*/
|
|
export function RequestLinkForm() {
|
|
const [email, setEmail] = useState("");
|
|
const [submitting, setSubmitting] = useState(false);
|
|
// Set once a request goes out; the section then shows the awaiting
|
|
// confirmation status until the recipient responds (or it's denied).
|
|
const [requestedEmail, setRequestedEmail] = useState<string | null>(null);
|
|
|
|
async function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
|
|
event.preventDefault();
|
|
if (submitting) return;
|
|
|
|
setSubmitting(true);
|
|
try {
|
|
const result = await requestAccountLink(email);
|
|
if (result?.error) {
|
|
toast.error(result.error);
|
|
return;
|
|
}
|
|
setRequestedEmail(email.trim().toLowerCase());
|
|
toast.success("Link request sent.");
|
|
} catch {
|
|
toast.error("Couldn't send the link request. Try again.");
|
|
} finally {
|
|
setSubmitting(false);
|
|
}
|
|
}
|
|
|
|
return (
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Request Account Link</CardTitle>
|
|
<CardDescription>
|
|
Link this account with another account on this server so you can
|
|
toggle between them. The other account has to accept the request.
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
{requestedEmail ? (
|
|
<div className="flex items-center gap-2 text-sm">
|
|
<Clock className="size-4 shrink-0 text-muted-foreground" />
|
|
<span>
|
|
Request sent to{" "}
|
|
<span className="font-medium">{requestedEmail}</span> — awaiting
|
|
confirmation.
|
|
</span>
|
|
</div>
|
|
) : (
|
|
<form
|
|
onSubmit={handleSubmit}
|
|
className="flex flex-col gap-3 sm:flex-row sm:items-end"
|
|
>
|
|
<div className="flex-1 space-y-1.5">
|
|
<Label htmlFor="link-request-email">Account email</Label>
|
|
<Input
|
|
id="link-request-email"
|
|
type="email"
|
|
required
|
|
autoComplete="off"
|
|
spellCheck={false}
|
|
placeholder="you@example.com"
|
|
value={email}
|
|
disabled={submitting}
|
|
onChange={(e) => setEmail(e.target.value)}
|
|
/>
|
|
</div>
|
|
<Button type="submit" disabled={submitting || !email.trim()}>
|
|
{submitting ? (
|
|
<Loader2 className="size-3.5 animate-spin" />
|
|
) : (
|
|
<Link2 className="size-3.5" />
|
|
)}
|
|
{submitting ? "Requesting…" : "Request Account Link"}
|
|
</Button>
|
|
</form>
|
|
)}
|
|
</CardContent>
|
|
</Card>
|
|
);
|
|
}
|