mirror of
https://github.com/Luchexx/wacrm.git
synced 2026-11-02 09:19:51 +00:00
Replace the flat 8-tab Settings page with a cleaner information architecture: a grouped left rail (Account / Workspace) plus a new Overview landing with live status tiles. Related concerns are merged — "Login & security" (password + sessions) and "Fields & tags" (tags + custom fields). - New shell: settings-sections (section model + legacy ?tab= mapping, tags/custom-fields -> fields), settings-rail, settings-overview (live counts + identity), security-panel, fields-and-tags-panel, settings-panel-head, settings-chip, role-meta (shared role chip metadata, de-duped from members-tab). - Restyle the light panels to the mockup; reframe the heavy panels (WhatsApp, Templates) with the shared panel header, internals intact. - Tokens: add --card-2 (light+dark) and @theme mappings for primary-hover/soft/soft-2 so the redesign stays fully tokenized. - ?tab= remains the URL source of truth, keeping existing sidebar/header deep-links working. Overview decouples the slow WhatsApp Meta health-ping from the cheap count queries so a flaky ping never blanks the whole landing; template counts use head-only count queries. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
79 lines
2.6 KiB
TypeScript
79 lines
2.6 KiB
TypeScript
import {
|
|
Coins,
|
|
FileText,
|
|
LayoutGrid,
|
|
Palette,
|
|
PlugZap,
|
|
Shield,
|
|
Tags,
|
|
User,
|
|
UsersRound,
|
|
type LucideIcon,
|
|
} from 'lucide-react';
|
|
|
|
/**
|
|
* Settings information architecture for the redesigned page.
|
|
*
|
|
* The flat tab strip became a grouped left rail with a new Overview
|
|
* landing. The URL query param stays `?tab=` (deep-linkable, and it
|
|
* keeps the existing links in sidebar.tsx / header.tsx working) — we
|
|
* just map the old values onto the new sections.
|
|
*/
|
|
export const SETTINGS_SECTIONS = [
|
|
'overview',
|
|
'profile',
|
|
'security',
|
|
'appearance',
|
|
'whatsapp',
|
|
'templates',
|
|
'fields',
|
|
'deals',
|
|
'members',
|
|
] as const;
|
|
|
|
export type SettingsSection = (typeof SETTINGS_SECTIONS)[number];
|
|
|
|
export const DEFAULT_SECTION: SettingsSection = 'overview';
|
|
|
|
/** Rail grouping. `adminOnly` items are hidden for non-admins. */
|
|
export interface SectionMeta {
|
|
id: SettingsSection;
|
|
label: string;
|
|
icon: LucideIcon;
|
|
group: 'top' | 'account' | 'workspace';
|
|
}
|
|
|
|
export const SECTION_META: Record<SettingsSection, SectionMeta> = {
|
|
overview: { id: 'overview', label: 'Overview', icon: LayoutGrid, group: 'top' },
|
|
profile: { id: 'profile', label: 'Your profile', icon: User, group: 'account' },
|
|
security: { id: 'security', label: 'Login & security', icon: Shield, group: 'account' },
|
|
appearance: { id: 'appearance', label: 'Appearance', icon: Palette, group: 'account' },
|
|
whatsapp: { id: 'whatsapp', label: 'WhatsApp', icon: PlugZap, group: 'workspace' },
|
|
templates: { id: 'templates', label: 'Templates', icon: FileText, group: 'workspace' },
|
|
fields: { id: 'fields', label: 'Fields & tags', icon: Tags, group: 'workspace' },
|
|
deals: { id: 'deals', label: 'Deals & currency', icon: Coins, group: 'workspace' },
|
|
members: { id: 'members', label: 'Team members', icon: UsersRound, group: 'workspace' },
|
|
};
|
|
|
|
export const RAIL_GROUPS: { label: string | null; group: SectionMeta['group'] }[] = [
|
|
{ label: null, group: 'top' },
|
|
{ label: 'Account', group: 'account' },
|
|
{ label: 'Workspace', group: 'workspace' },
|
|
];
|
|
|
|
function isSection(value: string | null): value is SettingsSection {
|
|
return !!value && (SETTINGS_SECTIONS as readonly string[]).includes(value);
|
|
}
|
|
|
|
/**
|
|
* Resolve a raw `?tab=` value to a section. Legacy tabs from the old
|
|
* flat layout collapse onto their new home (Tags + Custom fields → the
|
|
* merged "Fields & tags" section). Anything unknown falls back to the
|
|
* Overview landing.
|
|
*/
|
|
export function resolveSection(raw: string | null): SettingsSection {
|
|
if (raw === 'tags' || raw === 'custom-fields') return 'fields';
|
|
if (isSection(raw)) return raw;
|
|
return DEFAULT_SECTION;
|
|
}
|