quorlasocial/dashboard/web/src/GettingStarted.jsx
metatroncubeswdev 82814f3757 White-label workspace and getting-started checklist
- Settings → Workspace: agency name, logo, brand colour, support email, website
- Logo replaces Quorla's in the app (with 'Powered by Quorla'), sign-in page, client approval page and PDF reports;
  brand colour drives buttons, links and highlights; emails and reports use the agency name
- Getting started checklist on the Clients page for admins, checked against the real state
  (workspace, Meta, first client, team, platforms, email, library, first post, approval link); dismissible

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 10:28:23 -04:00

40 lines
2.3 KiB
JavaScript

import { useEffect, useState } from "react";
import { Link } from "react-router-dom";
import { CircleCheck, Circle, X } from "lucide-react";
import { api } from "./api.js";
import { useAuth } from "./App.jsx";
import { cx } from "./ui.jsx";
/** Admin checklist on the Clients page until every step is done or it's dismissed. */
export default function GettingStarted() {
const { isAdmin } = useAuth();
const [d, setD] = useState(null);
useEffect(() => { if (isAdmin) api("/api/onboarding").then(setD).catch(() => {}); }, [isAdmin]);
if (!d || d.dismissed || d.done === d.total) return null;
const next = d.items.find((s) => !s.done);
return (
<section className="panel p-4" aria-labelledby="gs-title">
<div className="flex items-start justify-between gap-3">
<div>
<h2 id="gs-title" className="text-[15px] font-bold">Getting started</h2>
<p className="text-[12.5px] text-muted">{d.done} of {d.total} done. Next: <b className="text-ink-2">{next.title}</b>.</p>
</div>
<button type="button" onClick={() => api("/api/onboarding/dismiss", { method: "POST", body: { dismissed: true } }).then(setD)} className="p-1.5 rounded hover:bg-canvas text-muted" aria-label="Hide the getting started list"><X className="size-4" /></button>
</div>
<div className="h-1.5 rounded-full bg-canvas mt-3 overflow-hidden" aria-hidden="true"><div className="h-full bg-accent" style={{ width: `${(d.done / d.total) * 100}%` }} /></div>
<ol className="mt-3 grid sm:grid-cols-2 lg:grid-cols-3 gap-x-5 gap-y-2.5">
{d.items.map((s) => (
<li key={s.id} className="flex gap-2.5 items-start">
{s.done ? <CircleCheck className="size-[18px] text-ok shrink-0 mt-0.5" aria-label="Done" /> : <Circle className="size-[18px] text-faint shrink-0 mt-0.5" aria-label="To do" />}
<div className="min-w-0">
{s.done ? <span className="text-[13px] text-muted line-through">{s.title}</span>
: <Link to={s.link} className={cx("text-[13px] font-medium hover:underline", s.id === next.id ? "text-brand-deep" : "text-ink")}>{s.title}</Link>}
{!s.done && <p className="text-[12px] text-muted leading-snug">{s.text}</p>}
</div>
</li>
))}
</ol>
</section>
);
}