// Creator onboarding modal — 5 steps, one question per step.
// Steps: 1) Full name, 2) Primary social URL (+ add more), 3) Niche selection, 4) Email, 5) Confirmation.
function ApplyModal({ open, onClose }) {
const [step, setStep] = React.useState(0);
const [name, setName] = React.useState("");
const [generation, setGeneration] = React.useState("");
const [socials, setSocials] = React.useState([{ platform: "Instagram", url: "" }]);
const [niches, setNiches] = React.useState([]);
const [email, setEmail] = React.useState("");
const [gdpr, setGdpr] = React.useState(false);
const [submitted, setSubmitted] = React.useState(false);
// Reset on close
React.useEffect(() => {
if (!open) {
setTimeout(() => {
setStep(0); setName(""); setGeneration(""); setSocials([{ platform: "Instagram", url: "" }]); setNiches([]); setEmail(""); setGdpr(false); setSubmitted(false);
}, 250);
}
}, [open]);
// ESC to close
React.useEffect(() => {
if (!open) return;
const h = (e) => { if (e.key === "Escape") onClose(); };
window.addEventListener("keydown", h);
return () => window.removeEventListener("keydown", h);
}, [open, onClose]);
if (!open) return null;
const tint = STEP_TINTS[step];
const onInk = step === 4;
const fg = onInk ? "#fdf8f1" : C.ink;
const fgMuted = onInk ? "rgba(253,248,241,0.55)" : C.muted;
const fgBody = onInk ? "rgba(253,248,241,0.85)" : "#3a3530";
const cardBorder = onInk ? "rgba(253,248,241,0.12)" : "rgba(29,26,23,0.10)";
const NICHES = [
"Food & drink", "Home & interiors", "Beauty", "Fashion",
"Wellness", "Fitness", "Parenting", "Travel",
"Tech & gadgets", "Lifestyle", "Pets", "Sustainability",
];
const TOTAL = 5;
const validName = name.trim().length > 1 && generation !== "";
const validSocials = socials.filter((s) => s.url.trim().length > 4).length > 0;
const validNiches = niches.length > 0;
const validEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
const validSubmit = validEmail && gdpr;
const canAdvance = [validName, validSocials, validNiches, validSubmit][step];
const next = () => {
if (step < 3 && canAdvance) setStep(step + 1);
else if (step === 3 && canAdvance) {
setSubmitted(true);
setStep(4);
}
};
const back = () => { if (step > 0 && step < 4) setStep(step - 1); };
const updateSocial = (i, field, v) => {
const next = [...socials];
next[i] = { ...next[i], [field]: v };
setSocials(next);
};
const removeSocial = (i) => {
if (socials.length === 1) return;
setSocials(socials.filter((_, idx) => idx !== i));
};
const toggleNiche = (n) => {
setNiches(niches.includes(n) ? niches.filter((x) => x !== n) : [...niches, n]);
};
const STEP_META = [
{ eyebrow: "01 / 05", q: "First, your name and age.", helper: "Real name. Pick the generation that fits — brands often brief by age range." },
{ eyebrow: "02 / 05", q: "Drop your social handles.", helper: "Paste the full profile URL. Add as many as you'd like — Instagram, TikTok, YouTube, Substack." },
{ eyebrow: "03 / 05", q: "What's your niche?", helper: "Pick all that genuinely fit. We'll only invite you to campaigns that match." },
{ eyebrow: "04 / 05", q: "Where should we email briefs?", helper: "We'll send active campaign briefs and your dashboard invite to this address." },
{ eyebrow: "05 / 05", q: "You're in the queue.", helper: "We review every applicant within 48 hours. Keep an eye on your inbox." },
];
const meta = STEP_META[step];
return (
e.stopPropagation()}
style={{
background: tint.bg, color: fg,
borderRadius: 22, width: "100%", maxWidth: 600,
padding: "0", overflow: "hidden", position: "relative",
boxShadow: "0 40px 80px -20px rgba(29,26,23,0.5)",
border: `1px solid ${cardBorder}`,
animation: "slideUp .3s cubic-bezier(.2,.7,.3,1)",
transition: "background .35s ease, color .35s ease",
}}
>
{/* Progress bar */}
{/* Close */}
×
{meta.eyebrow}
{meta.q}
{meta.helper}
{/* Step body */}
{step === 0 && (
setName(e.target.value)}
onKeyDown={(e) => { if (e.key === "Enter" && canAdvance) next(); }}
placeholder="Maeve Cooper"
style={inputStyle}
/>
{[
{ id: "Gen Z", label: "Gen Z", sub: "18 – 27" },
{ id: "Millennial", label: "Millennial", sub: "28 – 43" },
{ id: "Gen X", label: "Gen X", sub: "44 – 59" },
].map((g) => {
const on = generation === g.id;
return (
setGeneration(g.id)}
style={{
flex: "1 1 0", minWidth: 120,
padding: "14px 16px", borderRadius: 12,
border: `1.5px solid ${on ? C.ink : "rgba(29,26,23,0.15)"}`,
background: on ? C.ink : C.surface,
color: on ? C.paper : C.ink,
cursor: "pointer", textAlign: "left",
fontFamily: "inherit", transition: "all .15s ease",
display: "flex", flexDirection: "column", gap: 2,
}}
>
{g.label}
{g.sub}
);
})}
)}
{step === 1 && (
{socials.map((s, i) => (
updateSocial(i, "platform", e.target.value)}
style={{
appearance: "none", WebkitAppearance: "none", MozAppearance: "none",
padding: "16px 36px 16px 16px", borderRadius: 12,
border: "1.5px solid rgba(29,26,23,0.15)",
background: "#ffffff", fontSize: 15, fontFamily: "'Inter', system-ui, sans-serif",
fontWeight: 500, color: C.ink, cursor: "pointer",
boxSizing: "border-box", height: "100%",
}}
>
{["Instagram", "TikTok", "YouTube", "Substack", "X / Twitter", "Threads", "LinkedIn", "Other"].map((p) => (
{p}
))}
▾
updateSocial(i, "url", e.target.value)}
placeholder={i === 0 ? "Insert social handle URL" : "Add another"}
style={{ ...inputStyle, marginBottom: 0, flex: 1 }}
/>
{socials.length > 1 && (
removeSocial(i)} aria-label="Remove" style={{
width: 56, borderRadius: 12, border: "1px solid rgba(29,26,23,0.15)",
background: C.surface, cursor: "pointer", color: C.muted,
fontFamily: "inherit", fontSize: 18, flexShrink: 0,
}}>−
)}
))}
setSocials([...socials, { platform: "TikTok", url: "" }])} style={{
display: "inline-flex", alignItems: "center", gap: 8,
padding: "10px 16px", borderRadius: 999,
background: "transparent", border: "1px dashed rgba(29,26,23,0.25)",
color: C.ink, fontSize: 13, fontWeight: 500, cursor: "pointer",
fontFamily: "inherit", marginTop: 4,
}}>+ Add another handle
)}
{step === 2 && (
{NICHES.map((n) => {
const on = niches.includes(n);
return (
toggleNiche(n)}
style={{
padding: "10px 16px", borderRadius: 999,
border: `1px solid ${on ? C.ink : "rgba(29,26,23,0.18)"}`,
background: on ? C.ink : C.surface,
color: on ? C.paper : C.ink,
fontSize: 14, fontWeight: 500, cursor: "pointer",
fontFamily: "inherit", transition: "all .15s",
}}
>{on ? "✓ " : ""}{n}
);
})}
)}
{step === 3 && (
setEmail(e.target.value)}
onKeyDown={(e) => { if (e.key === "Enter" && canAdvance) next(); }}
placeholder="hello@yourdomain.com"
style={inputStyle}
/>
setGdpr(e.target.checked)}
style={{
width: 20, height: 20, marginTop: 1, flexShrink: 0,
accentColor: C.accent, cursor: "pointer",
}}
/>
Yes, I agree to GDPR. {" "}
I've read the{" "}
e.stopPropagation()}
style={{ color: C.accent, fontWeight: 500, textDecoration: "underline", textUnderlineOffset: 2 }}
>UK GDPR Policy {" "}
and consent to Giftfluence processing my personal data to coordinate gifting campaigns.
)}
{step === 4 && (
Thanks, {name || "creator"} . We've logged your details and you're now in the review queue. We'll email {email} within 48 hours with next steps and your dashboard invite.
// REF · GF-{(Math.random() * 9000 + 1000).toFixed(0)}
{niches.length} niche{niches.length === 1 ? "" : "s"} · {socials.filter(s => s.url.trim()).length} handle{socials.filter(s => s.url.trim()).length === 1 ? "" : "s"}
)}
{/* Footer actions */}
{step > 0 && step < 4 ? (
← Back
) :
}
{step < 3 && (
Continue →
)}
{step === 3 && (
Submit application →
)}
{step === 4 && (
Close
)}
);
}
const STEP_TINTS = [
{ bg: "#fdf8f1", surface: "#ffffff" }, // paper / surface
{ bg: "#e3def7", surface: "#ffffff" }, // lavender
{ bg: "#d6ecdb", surface: "#ffffff" }, // mint
{ bg: "#f3eee2", surface: "#ffffff" }, // paper-2
{ bg: "#1d1a17", surface: "#fdf8f1" }, // ink (success)
];
const inputStyle = {
width: "100%", padding: "16px 18px", borderRadius: 12,
border: "1.5px solid rgba(29,26,23,0.15)",
background: "#ffffff", fontSize: 17, fontFamily: "'Inter', system-ui, sans-serif",
color: "#1d1a17", transition: "border-color .15s, box-shadow .15s",
marginBottom: 4, boxSizing: "border-box", display: "block",
};
window.ApplyModal = ApplyModal;