Admin operator experience
This module is admin-facing — there is NO customer-facing surface. The "end user" here is the admin operator who clicks the help icon while working in /admin/.... This section describes what they see, where they see it, and what they can/can't do.
Where the help icon appears
A floating circular button at bottom-right on every /admin/... page (the <HelpButton> component is mounted in the admin shell). The button is:
- Hidden on
/admin/io/...pages — the IO panel is for platform operators, not tenant operators, and uses a separate help surface. - Hidden when the
help-tutorialsmodule is disabled. - Hidden when the resolver can't compute a
page_keyfor the current route (e.g. malformed paths). - Visible but disabled while the tutorial fetch is in flight (loading cursor + reduced opacity).
The unread pulse
When a tutorial exists for the current page AND the operator hasn't marked it read, the button:
- Glows green (
bg-green-600). - Shows a 3.5px green dot in the top-right with a ping animation.
- The dot is the "you've got new help" signal.
When the page has been marked read:
- Button is white (
bg-white). - No dot.
- Still clickable to re-open.
Auto-open behaviour
If localStorage["help-tutorials-auto-open"] is true (default for new logins) AND the tutorial is unread AND the page just changed, the panel auto-opens after an 800ms delay (so the page can finish rendering first).
This fires once per page visit — the autoOpenedRef records the page key it auto-opened for, and won't re-fire on the same key until the operator navigates away and back.
To disable auto-open for yourself:
localStorage.setItem("help-tutorials-auto-open", "false");
There is currently no UI toggle for this — it's a power-user opt-out. The module ships auto-open ON because new operators benefit from the prompt.
The panel layout
The <HelpPanel> slides in from the right as a full-height side panel (420px wide on desktop, full-width on mobile). It locks body scroll while open.
The panel structure:
- Header — tutorial title + close (X) button.
- Tabs (only if more than one is relevant):
- Overview — always shown.
- Settings — shown only if the tutorial has
settings_helpentries. - Video — shown only if
video_urlis set.
- Content area — scrollable.
- Footer — full-width green Got it button.
Overview tab
Renders:
- The description in a green callout card (if non-empty).
- The steps as a numbered ordered list. Each step has:
- A green circular number badge.
- Step title (bold).
- Step content (muted text).
- Optional image below (if
image_urlis set).
Settings tab
A collapsible accordion. Each entry:
- Clicking the row expands it (only one open at a time).
- The expanded body shows the description + a blue Impact callout.
- The
field_nameis shown next to the label in parentheses (small muted text) so the operator can match it to the form input.
Video tab
If video_url is a YouTube watch link or a Vimeo URL, the panel embeds a 16:9 iframe with autoplay-on-click controls + a "Watch on YouTube/Vimeo" external-link below.
If video_url is any other format (Loom, Wistia, direct mp4, etc.), the panel falls back to an external-link button.
Marking as read
Clicking the green Got it button at the footer:
- Sets
localStorage["help-tutorials-read"]to include the current page key (client-side, instant). - Sends a fire-and-forget
POST /admin/help-tutorials/{pageKey}/read(server-side, best-effort — failures are silently ignored). - Closes the panel.
The next time the operator lands on this page, the green pulse is gone and auto-open is skipped.
Keyboard
- Escape — closes the panel (without marking as read).
- The backdrop click also closes without marking as read.
Re-opening
Clicking the help icon again opens the panel — even after marking as read. The operator can re-read at any time.
What the operator can NOT do
- They can't edit tutorials from the panel (the panel is read-only).
- They can't disable auto-open from the UI (only via localStorage).
- They can't navigate between tutorials in the panel — closing and visiting another page is the only way.
- They can't share a deep-link to a specific tutorial — the panel state isn't in the URL.
