feat(web): first-time user onboarding flow
Some checks failed
CI / Tests / 🧪 Test (push) Has been cancelled

New user signs in → /dashboard (user) → hits server-side getMyMeshes → 0
results → redirects to /dashboard/meshes/new?onboarding=1. Create-mesh
page renders a welcome banner explaining what a mesh is. After submit,
if ?onboarding=1 was set, the form bounces to
/dashboard/meshes/[id]/invite?onboarding=1 instead of the mesh detail
page. Invite page renders a "🎉 Mesh created" banner with the
`claudemesh join <link>` CLI snippet.

The onboarding flag is URL-driven — no persistence needed, dismissal
happens naturally when the user navigates away.

Also rewrites the /dashboard (user) home page from the placeholder
"Welcome to your Dashboard" TurboStarter card grid to a claudemesh-
native view: top 6 meshes with badges, All meshes / New mesh CTAs.
Removes the unused Card/Icons imports.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Alejandro Gutiérrez
2026-04-04 23:47:52 +01:00
parent 759a22e7c0
commit 138b5a24ae
4 changed files with 127 additions and 63 deletions

View File

@@ -40,7 +40,9 @@ const slugify = (s: string) =>
.replace(/^-+|-+$/g, "")
.slice(0, 40);
export const CreateMeshForm = () => {
export const CreateMeshForm = ({
onboarding = false,
}: { onboarding?: boolean } = {}) => {
const router = useRouter();
const form = useForm<CreateMyMeshInput>({
resolver: zodResolver(createMyMeshInputSchema),
@@ -70,7 +72,11 @@ export const CreateMeshForm = () => {
form.setError("slug", { message: res.error });
return;
}
router.push(pathsConfig.dashboard.user.meshes.mesh(res.id));
router.push(
onboarding
? `${pathsConfig.dashboard.user.meshes.invite(res.id)}?onboarding=1`
: pathsConfig.dashboard.user.meshes.mesh(res.id),
);
} catch (e) {
form.setError("root", {
message: e instanceof Error ? e.message : "Failed to create mesh.",