profile-setup.tsx
"use client";
import { useState, type SyntheticEvent } from "react";
import { LuArrowRight, LuBriefcase, LuGlobe } from "react-icons/lu";
import { Alert, Avatar, Button, Dropzone, Input, Select, SelectOption } from "@nexera-ui/react";
const TIME_ZONES = [
{ id: "Europe/London", label: "London", description: "GMT+00:00 / BST" },
{ id: "Europe/Lisbon", label: "Lisbon", description: "WET+00:00" },
{ id: "Europe/Copenhagen", label: "Copenhagen", description: "CET+01:00" },
{ id: "Asia/Karachi", label: "Lahore and Karachi", description: "PKT+05:00" },
{ id: "Asia/Dubai", label: "Dubai", description: "GST+04:00" },
{ id: "Asia/Tokyo", label: "Tokyo", description: "JST+09:00" },
];
/** Profile setup: photo, job title and time zone in one short first-run form. */
export default function ProfileSetup() {
const [photo, setPhoto] = useState<{ url: string; name: string } | null>(null);
const [saved, setSaved] = useState(false);
const onSelect = (files: File[]) => {
const file = files[0];
if (!file) return;
if (photo) URL.revokeObjectURL(photo.url);
setPhoto({ url: URL.createObjectURL(file), name: file.name }); // upload the file in your app
};
const onSubmit = (event: SyntheticEvent<HTMLFormElement>) => {
event.preventDefault();
setSaved(true); // replace with your profile update request
};
return (
<div className="@container min-h-[560px] bg-page px-4 py-8 @3xl:px-8">
<form
onSubmit={onSubmit}
className="mx-auto grid max-w-3xl gap-6 rounded-xl border border-default bg-surface p-6 @3xl:p-8"
>
<header className="grid gap-1">
<p className="text-body-small text-secondary">Step 2 of 3</p>
<h2 className="text-heading-h3 text-primary">Tell your team about you</h2>
<p className="text-body-default text-secondary">
This shows on your profile, in the directory and next to your requests.
</p>
</header>
{saved ? (
<Alert
tone="success"
title="Profile saved"
description="This is a demo, so nothing was uploaded."
/>
) : null}
<div className="grid gap-6 @3xl:grid-cols-[16rem_minmax(0,1fr)]">
<fieldset className="m-0 grid content-start gap-4 border-0 p-0">
<legend className="mb-3 text-component-label text-primary">Profile photo</legend>
<div className="flex items-center gap-3">
<Avatar
size="xl"
label="Ayesha Khan"
initials="AK"
{...(photo ? { type: "photo" as const, src: photo.url } : {})}
/>
<p className="min-w-0 break-words text-body-small text-secondary">
{photo ? photo.name : "No photo yet. Your initials show instead."}
</p>
</div>
<Dropzone
layout="compact"
title="Drop a photo or browse"
description="JPG or PNG, square works best, up to 5 MB."
acceptedFileTypes={["image/jpeg", "image/png"]}
onSelect={onSelect}
/>
</fieldset>
<div className="grid content-start gap-4">
<Input
label="Full name"
name="name"
autoComplete="name"
defaultValue="Ayesha Khan"
isRequired
/>
<Input
label="Preferred name"
name="nickname"
autoComplete="nickname"
placeholder="e.g. Ayesha"
description="What colleagues call you."
/>
<Input
label="Job title"
name="title"
autoComplete="organization-title"
leadingIcon={<LuBriefcase />}
defaultValue="Senior product designer"
isRequired
/>
<Select
label="Time zone"
name="timezone"
leadingIcon={<LuGlobe />}
defaultValue="Europe/London"
description="Used for meeting times and leave days."
>
{TIME_ZONES.map((zone) => (
<SelectOption
key={zone.id}
id={zone.id}
label={zone.label}
description={zone.description}
/>
))}
</Select>
</div>
</div>
<div className="flex flex-wrap justify-end gap-2 border-t border-subtle pt-4">
<Button variant="ghost" size="md">
Skip for now
</Button>
<Button type="submit" size="md" trailingIcon={<LuArrowRight />}>
Save and continue
</Button>
</div>
</form>
</div>
);
}