e30e75b5d4
Changesets / Create Version PR (push) Has been cancelled
Deploy Shadcn Registry / Deploy Production (push) Has been cancelled
Template Metrics / LOC + Bundle Size (push) Has been cancelled
Code Quality / Oxlint + Oxfmt (push) Has been cancelled
Code Quality / Template Sync (push) Has been cancelled
Code Quality / Build Changed Packages (push) Has been cancelled
Code Quality / Test Changed Packages (push) Has been cancelled
Deploy Expo Example / Deploy Production (push) Has been cancelled
Deploy Ink Example / Deploy Production (push) Has been cancelled
Python Tests / pytest (assistant-stream, 3.10) (push) Has been cancelled
Python Tests / pytest (assistant-stream, 3.12) (push) Has been cancelled
Python Tests / pytest (assistant-ui-sync-server-api, 3.10) (push) Has been cancelled
Python Tests / pytest (assistant-ui-sync-server-api, 3.12) (push) Has been cancelled
167 lines
5.8 KiB
TypeScript
167 lines
5.8 KiB
TypeScript
"use client";
|
||
|
||
import { type FormEvent, useCallback, useState } from "react";
|
||
|
||
interface ApplyFormProps {
|
||
roleTitle: string;
|
||
}
|
||
|
||
export const ApplyForm = ({ roleTitle }: ApplyFormProps) => {
|
||
const [fallbackVisible, setFallbackVisible] = useState(false);
|
||
const [mailtoHref, setMailtoHref] = useState("");
|
||
const [composedBody, setComposedBody] = useState("");
|
||
const [copyStatus, setCopyStatus] = useState<"idle" | "success" | "error">(
|
||
"idle",
|
||
);
|
||
|
||
const handleSubmit = useCallback(
|
||
(event: FormEvent<HTMLFormElement>) => {
|
||
event.preventDefault();
|
||
const form = event.currentTarget;
|
||
const formData = new FormData(form);
|
||
|
||
const fullName = (formData.get("full_name") as string)?.trim() ?? "";
|
||
const urlsRaw = (formData.get("urls") as string)?.trim() ?? "";
|
||
const notes = (formData.get("notes") as string)?.trim() ?? "";
|
||
|
||
const urlLines = urlsRaw
|
||
.split(/\r?\n/)
|
||
.map((line) => line.trim())
|
||
.filter(Boolean)
|
||
.map((line) => `- ${line}`);
|
||
|
||
const bodyLines = [
|
||
"Hello,",
|
||
"",
|
||
`I am applying for the ${roleTitle} role.`,
|
||
"",
|
||
"Here are a few interesting links to showcase my profile:",
|
||
urlLines.length ? urlLines.join("\n") : "-",
|
||
];
|
||
|
||
if (notes) {
|
||
bodyLines.push("", notes);
|
||
}
|
||
|
||
bodyLines.push("", "Best,", fullName || "");
|
||
|
||
const body = bodyLines.join("\n");
|
||
|
||
const mailto = `mailto:careers@assistant-ui.com?subject=${encodeURIComponent(
|
||
`Application: ${roleTitle}`,
|
||
)}&body=${encodeURIComponent(body)}`;
|
||
|
||
// Attempt to open the user's default mail client.
|
||
// If it doesn't open (no handler configured), reveal fallbacks.
|
||
setComposedBody(body);
|
||
setMailtoHref(mailto);
|
||
setFallbackVisible(true);
|
||
try {
|
||
window.location.href = mailto;
|
||
} catch {
|
||
// No-op: rely on the fallback UI
|
||
}
|
||
},
|
||
[roleTitle],
|
||
);
|
||
|
||
return (
|
||
<form onSubmit={handleSubmit} className="grid gap-5">
|
||
<label className="grid gap-2 text-sm">
|
||
<span className="text-foreground font-medium">Full Name</span>
|
||
<input
|
||
type="text"
|
||
name="full_name"
|
||
required
|
||
autoComplete="name"
|
||
className="border-border bg-background focus:border-primary rounded-lg border px-3 py-2 text-base shadow-sm ring-0 transition outline-none"
|
||
placeholder="Ada Lovelace"
|
||
/>
|
||
</label>
|
||
|
||
<label className="grid gap-2 text-sm">
|
||
<span className="text-foreground font-medium">
|
||
URLs that best describe you
|
||
</span>
|
||
<textarea
|
||
name="urls"
|
||
required
|
||
rows={3}
|
||
className="border-border bg-background focus:border-primary rounded-lg border px-3 py-2 text-base shadow-sm ring-0 transition outline-none"
|
||
placeholder="Portfolio, GitHub, LinkedIn, blog – one per line"
|
||
></textarea>
|
||
</label>
|
||
|
||
<label className="grid gap-2 text-sm">
|
||
<span className="text-foreground font-medium">
|
||
Anything else?{" "}
|
||
<span className="text-muted-foreground">(optional)</span>
|
||
</span>
|
||
<textarea
|
||
name="notes"
|
||
rows={4}
|
||
className="border-border bg-background focus:border-primary rounded-lg border px-3 py-2 text-base shadow-sm ring-0 transition outline-none"
|
||
placeholder="Tell us about goals, timelines, or anything you'd like us to know."
|
||
></textarea>
|
||
</label>
|
||
|
||
<button
|
||
type="submit"
|
||
className="border-border text-foreground hover:border-primary hover:bg-primary/5 hover:text-primary inline-flex w-fit items-center justify-center rounded-full border px-5 py-2 text-sm font-medium transition"
|
||
>
|
||
Apply now
|
||
</button>
|
||
|
||
{fallbackVisible ? (
|
||
<div className="border-border/70 bg-background/50 mt-2 grid gap-2 rounded-lg border border-dashed p-3">
|
||
<p className="text-muted-foreground text-xs">
|
||
If your email client didn't open, use the options below.
|
||
</p>
|
||
<div className="flex flex-wrap items-center gap-2">
|
||
<a
|
||
href={mailtoHref}
|
||
className="border-border text-foreground hover:border-primary hover:bg-primary/5 hover:text-primary inline-flex items-center justify-center rounded-full border px-4 py-1.5 text-xs font-medium transition"
|
||
>
|
||
Open email client
|
||
</a>
|
||
<button
|
||
type="button"
|
||
className="border-border text-foreground hover:border-primary hover:bg-primary/5 hover:text-primary inline-flex items-center justify-center rounded-full border px-4 py-1.5 text-xs font-medium transition"
|
||
onClick={async () => {
|
||
try {
|
||
const text = `To: careers@assistant-ui.com
|
||
Subject: Application: ${roleTitle}
|
||
|
||
${composedBody}`;
|
||
await navigator.clipboard.writeText(text);
|
||
setCopyStatus("success");
|
||
setTimeout(() => setCopyStatus("idle"), 2000);
|
||
} catch {
|
||
setCopyStatus("error");
|
||
setTimeout(() => setCopyStatus("idle"), 2000);
|
||
}
|
||
}}
|
||
>
|
||
Copy email text
|
||
</button>
|
||
<span className="text-muted-foreground text-xs">
|
||
{copyStatus === "success"
|
||
? "Copied!"
|
||
: copyStatus === "error"
|
||
? "Copy failed"
|
||
: ""}
|
||
</span>
|
||
</div>
|
||
<p className="text-muted-foreground text-[11px]">
|
||
Or email{" "}
|
||
<span className="text-foreground font-medium">
|
||
careers@assistant-ui.com
|
||
</span>{" "}
|
||
with the subject "Application: {roleTitle}".
|
||
</p>
|
||
</div>
|
||
) : null}
|
||
</form>
|
||
);
|
||
};
|