mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-19 03:01:24 +02:00
- packages/shared-branding/onboarding-templates.ts:
* 7 templates: Alltag / Arbeit / Health / Sport / Lernen / Entdecken
/ Erinnern — each with a phosphor icon name, German name/desc and
an ordered moduleIds list
* resolveModulesForTemplates() — deduplicates the union of selected
templates' modules (priority-ordered) and caps at 8 (2×4 grid)
- packages/shared-branding/onboarding-templates.spec.ts: 10 tests
covering order preservation, dedup-across-templates, cap honouring,
unknown-id tolerance
- /onboarding/templates/+page.svelte:
* Multi-select grid of 7 tiles (checkmark + primary border when on)
* Finish handler: runs resolveModulesForTemplates → creates a new
"Zuhause" scene with those apps → onboardingStatus.markComplete()
→ navigates to /
* Skip still marks complete (no scene — user lands on DEFAULT_HOME_APPS)
* Prefills selection from onboardingFlow store so back-nav is stable
With this, the 3-screen flow runs end-to-end for a new user:
signup → /onboarding/name → /look → /templates → / with a curated
home scene.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
120 lines
3.5 KiB
TypeScript
120 lines
3.5 KiB
TypeScript
/**
|
|
* Onboarding templates — starter-packs a user picks on Screen 3 of the
|
|
* first-login flow (/onboarding/templates). Each template is a named
|
|
* use-case with an ordered list of module IDs. The flow's finish
|
|
* handler deduplicates the union of picked templates' modules (keeping
|
|
* the first occurrence in priority order), caps the total at 8, and
|
|
* writes the result as the user's Home scene.
|
|
*
|
|
* All module IDs are verified against
|
|
* apps/mana/apps/web/src/lib/app-registry/apps.ts — if a template
|
|
* references a module that was removed, catch it in the test below
|
|
* before the user sees an empty tile.
|
|
*
|
|
* See docs/plans/onboarding-flow.md for rationale (why these templates,
|
|
* why multi-select, why a cap).
|
|
*/
|
|
|
|
export type OnboardingTemplateId =
|
|
| 'alltag'
|
|
| 'arbeit'
|
|
| 'health'
|
|
| 'sport'
|
|
| 'lernen'
|
|
| 'entdecken'
|
|
| 'erinnern';
|
|
|
|
export type OnboardingTemplate = {
|
|
id: OnboardingTemplateId;
|
|
/** German name rendered on the tile. */
|
|
name: string;
|
|
/** One-line description under the tile name. */
|
|
shortDescription: string;
|
|
/** Phosphor icon name — resolved by the consuming page. */
|
|
iconName: 'House' | 'Briefcase' | 'Heart' | 'Barbell' | 'GraduationCap' | 'Compass' | 'Camera';
|
|
/**
|
|
* Module IDs in priority order (first = most important). Dedup
|
|
* across templates keeps the earliest occurrence; cap = 8.
|
|
*/
|
|
moduleIds: string[];
|
|
};
|
|
|
|
export const ONBOARDING_TEMPLATES: readonly OnboardingTemplate[] = [
|
|
{
|
|
id: 'alltag',
|
|
name: 'Alltag',
|
|
shortDescription: 'Aufgaben, Termine, Notizen, Kontakte',
|
|
iconName: 'House',
|
|
moduleIds: ['todo', 'calendar', 'notes', 'contacts'],
|
|
},
|
|
{
|
|
id: 'arbeit',
|
|
name: 'Arbeit',
|
|
shortDescription: 'Produktivität für den Job',
|
|
iconName: 'Briefcase',
|
|
moduleIds: ['todo', 'calendar', 'mail', 'chat', 'times', 'notes'],
|
|
},
|
|
{
|
|
id: 'health',
|
|
name: 'Health',
|
|
shortDescription: 'Gesundheit, Stimmung, Ernährung, Zyklus',
|
|
iconName: 'Heart',
|
|
moduleIds: ['habits', 'body', 'mood', 'food', 'period'],
|
|
},
|
|
{
|
|
id: 'sport',
|
|
name: 'Sport',
|
|
shortDescription: 'Training, Ziele, Körper, Ernährung',
|
|
iconName: 'Barbell',
|
|
moduleIds: ['habits', 'body', 'food', 'goals', 'stretch'],
|
|
},
|
|
{
|
|
id: 'lernen',
|
|
name: 'Lernen',
|
|
shortDescription: 'Skills, Quizzes, Notizen, Kontext',
|
|
iconName: 'GraduationCap',
|
|
moduleIds: ['skilltree', 'quiz', 'notes', 'library', 'kontext'],
|
|
},
|
|
{
|
|
id: 'entdecken',
|
|
name: 'Entdecken',
|
|
shortDescription: 'Orte, Fotos, Musik, Wetter',
|
|
iconName: 'Compass',
|
|
moduleIds: ['places', 'citycorners', 'photos', 'music', 'wetter'],
|
|
},
|
|
{
|
|
id: 'erinnern',
|
|
name: 'Erinnern',
|
|
shortDescription: 'Memoro, Journal, Fotos, Zitate',
|
|
iconName: 'Camera',
|
|
moduleIds: ['memoro', 'journal', 'photos', 'moodlit', 'quotes'],
|
|
},
|
|
];
|
|
|
|
/**
|
|
* Pick modules for the user's Home scene based on a multi-selection of
|
|
* templates. Iterates templates in the order provided, collecting their
|
|
* modules while skipping dups and stopping at the cap.
|
|
*
|
|
* Exported so the onboarding page and its test can share the same
|
|
* logic — the page only has to worry about UI state.
|
|
*/
|
|
export function resolveModulesForTemplates(
|
|
selectedIds: readonly OnboardingTemplateId[],
|
|
cap = 8
|
|
): string[] {
|
|
const byId = new Map(ONBOARDING_TEMPLATES.map((t) => [t.id, t]));
|
|
const seen = new Set<string>();
|
|
const out: string[] = [];
|
|
for (const id of selectedIds) {
|
|
const tpl = byId.get(id);
|
|
if (!tpl) continue;
|
|
for (const moduleId of tpl.moduleIds) {
|
|
if (seen.has(moduleId)) continue;
|
|
seen.add(moduleId);
|
|
out.push(moduleId);
|
|
if (out.length >= cap) return out;
|
|
}
|
|
}
|
|
return out;
|
|
}
|