Build the member area

Signed-in people who are not admins use the member area: a side menu with Dashboard and Profile, plus payment pages when payments is on. Your app decides what the dashboard shows and where each role lands after signing in.

What is there

The member area is in src/app/pages/user/. Its layout, app-user-shell, shows the site's name at the top (from Admin, Settings, About, else the app's src/custom/brand.ts, as on the sign-in page), the person's name, and the member menu:

IdItemAddressShown
homeHomeThe role's home page from src/custom/home.tsWhen that home is not /user/dashboard and not an admin page
dashboardDashboard/user/dashboardWhen the person may open the member pages (below)
payments, account, premiumPayments, Account & Billing, Premium/user/payments, /account, /user/premiumWith the payments feature, when the person may open the member pages
profileProfile/user/profileWhen the person may open the member pages
plansPlans/pricingWith the payments feature

Below the menu, the Sign out button is always there. The ids are what CUSTOM_NAV_CHANGES names to change the menu (Change the member menu); the list is in src/app/core/nav/member-menu.ts.

What members see on these pages is described in What members see. These pages are guarded by memberPagesGuard, which is userGuard plus one rule: an account your app manages (App accounts) sees a read-only profile, and is kept out of these pages altogether when src/custom/app-accounts.ts says so (The member pages).

Show your own dashboard

As shipped, /user/dashboard shows a greeting and an empty card. To show your own page there:

  1. Create the page, such as src/custom/pages/my-dashboard.ts, and wrap it in <app-user-shell> to keep the member menu:

    import { Component } from '@angular/core';
    import { UserShellComponent } from '../../app/pages/user/user-shell.component';
    import { PageHeaderComponent } from '../../shared/components/page-header/page-header.component';
    
    @Component({
      standalone: true,
      imports: [UserShellComponent, PageHeaderComponent],
      template: `
        <app-user-shell>
          <arc-page-header title="Your lessons"></arc-page-header>
          <!-- the app's own content -->
        </app-user-shell>
      `,
    })
    export default class MyDashboard {}
  2. Name it in src/custom/user-dashboard.ts:

    import type { Type } from '@angular/core';
    
    export type UserDashboardLoader = () => Promise<Type<unknown>>;
    
    export const CUSTOM_USER_DASHBOARD: UserDashboardLoader | null = () =>
      import('./pages/my-dashboard').then((m) => m.default);

The route keeps its guard: signed-out visitors go to sign-up and come back after signing in.

The file name my-dashboard.ts has no .page in it, so the page has no second address of its own (Pages found by file name).

Add more member pages

Give each page a route with userGuard (Who may open a page) and wrap its template in <app-user-shell>. To link it from the member menu, add it with CUSTOM_NAV_CHANGES (below), or make it the role's home page, which brings a Home item.

Change the member menu

The member list of CUSTOM_NAV_CHANGES, in src/custom/nav-changes.ts, changes the member menu the way its admin list changes the admin menu: change, hide, add and move items by their id (the table above), for every role or only the roles a change names. The full rules are in Change Arc CMS's items.

import type { NavChanges } from '../app/core/nav/nav-changes';

export const CUSTOM_NAV_CHANGES: NavChanges = {
  member: [
    // No Premium for the user role
    { id: 'premium', hide: true, roles: ['user'] },
    // The app's lessons, just before Profile
    { add: { id: 'lessons', label: 'Lessons', labelKey: 'custom.nav.lessons', route: '/learn',
             icon: 'fa-solid fa-book-open' }, before: 'profile' },
    // A page only teachers see
    { add: { id: 'classes', label: 'Classes', labelKey: 'custom.nav.classes', route: '/classes',
             icon: 'fa-solid fa-school', allowRoles: ['teacher'] } },
  ],
};

What is different in the member menu:

The menu only shows links. A page you add needs its own route guard: hiding Premium does not stop anyone opening /user/premium, and adding a link does not let anyone in.

Choose where people land after signing in

By default, admins land on /admin/dashboard and everyone else on /user/dashboard. To send members to one of your pages instead, set their home in src/custom/home.ts:

import type { HomePages } from '../app/core/home/home';

export const CUSTOM_HOME: HomePages = { user: '/learn' };

When a role's home is not /user/dashboard (and not an admin page), the member menu gets a Home item that leads there. A sign-in that started from a guarded page returns to that page instead. The keys, the '*' fallback and the return-to-page rules are in Set up sign-in.

Content for paying members

With the payments feature, guard a whole page with entitledGuard, or show part of a page to paying members with *appIfEntitled, both from src/app/pages/user/. See Add payments and premium features.

Hiding content in the browser does not protect it. Keep paid data behind security rules or a Cloud Function that checks the entitlement.

Where a member's data lives

Store each person's app data under their user record, users/{userDocId}/..., so it is protected by one rule and deleted with the account. See Follow the account contract.