Fixed an issue where media manager only shows files uploaded in specific sections. Fixed an issue with icon picker names. Removed jumbo rounding and a few other style tweaks.
88 lines
2.8 KiB
TypeScript
88 lines
2.8 KiB
TypeScript
"use client";
|
|
|
|
import { useRouter } from "next/navigation";
|
|
import { useState, useTransition } from "react";
|
|
import { Button } from "@/components/ui/button";
|
|
import { Input } from "@/components/ui/input";
|
|
import { Switch } from "@/components/ui/switch";
|
|
import { Textarea } from "@/components/ui/textarea";
|
|
import { MediaPicker } from "@/features/media/components/media-picker";
|
|
import { updateProfileAction } from "../actions/profile";
|
|
|
|
export interface ProfileFormInitial {
|
|
name: string;
|
|
phone: string;
|
|
image: string;
|
|
bio: string;
|
|
isBookableOnline: boolean;
|
|
}
|
|
|
|
export function ProfileForm({ initial }: { initial: ProfileFormInitial }) {
|
|
const router = useRouter();
|
|
const [name, setName] = useState(initial.name);
|
|
const [phone, setPhone] = useState(initial.phone);
|
|
const [image, setImage] = useState(initial.image);
|
|
const [bio, setBio] = useState(initial.bio);
|
|
const [isBookableOnline, setIsBookableOnline] = useState(initial.isBookableOnline);
|
|
const [error, setError] = useState<string | null>(null);
|
|
const [saved, setSaved] = useState(false);
|
|
const [isPending, startTransition] = useTransition();
|
|
|
|
const handleSave = () => {
|
|
setError(null);
|
|
setSaved(false);
|
|
startTransition(async () => {
|
|
const result = await updateProfileAction({ name, phone, image, bio, isBookableOnline });
|
|
if (!result.success) {
|
|
setError(result.error ?? "Couldn't save your profile.");
|
|
return;
|
|
}
|
|
setSaved(true);
|
|
router.refresh();
|
|
});
|
|
};
|
|
|
|
return (
|
|
<div className="space-y-4">
|
|
<Input label="Display name" value={name} onChange={(e) => setName(e.target.value)} />
|
|
<Input
|
|
label="Phone"
|
|
type="tel"
|
|
placeholder="+1 555 123 4567"
|
|
value={phone}
|
|
onChange={(e) => setPhone(e.target.value)}
|
|
/>
|
|
<MediaPicker label="Photo" value={image} onChange={(url) => setImage(url ?? "")} category="staff" />
|
|
<Textarea
|
|
label="Bio"
|
|
placeholder="A short introduction customers will see on your profile"
|
|
value={bio}
|
|
onChange={(e) => setBio(e.target.value)}
|
|
/>
|
|
|
|
<div className="rounded-md border border-line bg-white p-5">
|
|
<Switch
|
|
label="Visible for online booking"
|
|
description="Customers can find and book you when this is on."
|
|
checked={isBookableOnline}
|
|
onCheckedChange={setIsBookableOnline}
|
|
/>
|
|
</div>
|
|
|
|
{error && (
|
|
<p role="alert" className="text-danger text-sm font-medium">
|
|
{error}
|
|
</p>
|
|
)}
|
|
{saved && !error && (
|
|
<p role="status" className="text-accent-foreground text-sm font-medium">
|
|
Saved.
|
|
</p>
|
|
)}
|
|
<Button className="w-full" isLoading={isPending} onClick={handleSave}>
|
|
Save
|
|
</Button>
|
|
</div>
|
|
);
|
|
}
|