StudioCard
The studio itself, in setup: its name and craft, and where clients find it — the address, Instagram and website, all optional. The owner edits it in place; every change reaches onChange as a checked draft patch. Its crafts stand one under another on a phone, two by two in a wide card; Other opens a field for what the owner calls their craft.
Playground
Studio
Edit a field: the patch it sends shows here.
import { StudioCard } from "@/components/shared/studio-card";
<StudioCard
studio={draft}
onChange={(patch) => saveDraft(patch)}
onLogo={(file) => uploadLogo(file)}
onRemoveLogo={() => removeLogo()}
/>Saving as the owner goes
Text saves when the field loses focus or on Enter, never per keystroke; Escape brings back what was saved. What's saved is normalized: “@Atelier.Mila” keeps as atelier.mila, “atelier-mila.sk” as https://atelier-mila.sk/. Something that can't be saved — a website that isn't one — stays in the field with the reason under it. The craft saves on choosing.
Studio
Edit a field: the patch it sends shows here.
import { StudioCard } from "@/components/shared/studio-card";
<StudioCard studio={draft} onChange={saveDraft} />One topic a card
In setup's conversation the studio comes a topic at a time, so each card reads at a glance: part="studio" its name, logo and colours, as soon as the name is saved; part="craft" what it does, when Okami asks; part="details" the optional address, Instagram and website, at the end. Each collapses to its own line. Left out, the card is all of it.
Studio
What you do
Details
Edit a field: the patch it sends shows here.
import { StudioCard } from "@/components/shared/studio-card";
<StudioCard part="studio" studio={draft} onChange={saveDraft} onLogo={pickLogo} />
<StudioCard part="craft" studio={draft} onChange={saveDraft} />
<StudioCard part="details" studio={draft} onChange={saveDraft} />Collapsed
When a card shows again lower in the conversation, its earlier place keeps one line: the topic, then name · craft · address.
import { StudioCard } from "@/components/shared/studio-card";
<StudioCard studio={draft} onChange={saveDraft} collapsed />In the owner's language
Every word is a label, English by default. Pass the owner's from translations; any left out stay English.
Štúdio
import { StudioCard } from "@/components/shared/studio-card";
<StudioCard
studio={draft}
onChange={saveDraft}
labels={{
title: t("studio.title"), // "Štúdio"
name: t("studio.name"), // "Názov štúdia"
crafts: { nails: t("crafts.nails"), … },
optional: t("optional"), // "nepovinné"
}}
/>API reference
| Prop | Type | Default | Description |
|---|---|---|---|
| part | "all" | "studio" | "craft" | "details" | "all" | One topic: the name, logo and colours; what it does; or the optional details. All of it by default. |
| studio | Pick<SetupDraft, …> | — | What's saved: name, vertical, address, instagram, website, logo. Any may be missing. |
| onChange | (patch: DraftPatch) => void | — | Called with a checked, normalized patch for each saved change. Apply it with applyPatch, or save it through the server. |
| labels | Partial<StudioCardLabels> | English | Every word on the card: field names, placeholders, the eight crafts and Other's field, the errors. |
| collapsed | boolean | false | One line: the topic and a summary. |
| onLogo | (file: File) => void | — | Takes the logo the owner picked. Given, a logo row under the name shows the studio's mark with Add logo (or Change logo); without it there's no logo row. |
| onRemoveLogo | () => void | — | Takes the logo off, once a ConfirmDialog has asked. Given, a ghost Remove sits beside Change logo while there's a logo. |
| logoBusy | boolean | false | A logo is on its way: the button waits. |
| hideTitle | boolean | false | The heading is read, not shown — in the conversation, where Okami's line introduces the card. |
| className | string | — | Layout only, on the card. |
Guidelines
- Show it when the studio comes up in setup, not before. Okami asks; the card is where the answer can be corrected.
- Keep the card in step with the draft: pass what's saved, and apply each patch at once, so a field never jumps back.
- Instagram is only a handle to show on the booking page. Setup never signs in to Instagram or reads it.