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:
| Id | Item | Address | Shown |
|---|---|---|---|
home | Home | The role's home page from src/custom/home.ts | When that home is not /user/dashboard and not an admin page |
dashboard | Dashboard | /user/dashboard | When the person may open the member pages (below) |
payments, account, premium | Payments, Account & Billing, Premium | /user/payments, /account, /user/premium | With the payments feature, when the person may open the member pages |
profile | Profile | /user/profile | When the person may open the member pages |
plans | Plans | /pricing | With 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:
-
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 {} -
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:
- An item without
allowRolesis shown to everyone who sees the menu; with it, only to those roles. (In the admin menu an item needsallowRolesto be shown at all.) - Sign out is a button below the menu, not an item, so no change can remove it.
- A change to an item the person does not get (Home when their home is the dashboard, the member pages for a locked app account, the payment pages with payments off) is ignored for them. Items you add are shown whatever the member pages rule says: they are your pages.
- An item with
subItemsshows its sub-items indented below it, always open. - Words only members see need a Hindi or other translation only when you offer that language to members (Member languages). Every
labelKeymust be insrc/custom/i18n/en.jsonor core's English file: the test suite fails otherwise.
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.