mirror of
https://github.com/Luchexx/wacrm.git
synced 2026-11-02 09:19:51 +00:00
Adds a profile tab to /settings with the five things every B2B SaaS
user expects:
- Display name — edits profiles.full_name.
- Avatar — upload / replace / remove, stored in a new `avatars`
Supabase Storage bucket with RLS scoped to the owner's folder.
Migration 008_profile_avatars_storage.sql creates the bucket (public
read, 2 MB cap, image mimes only) and the four storage.objects
policies.
- Email — goes through supabase.auth.updateUser({ email }), which
confirms to both the old and new addresses. UI surfaces a "check
both inboxes" banner after save.
- Password — three-field form with a current-password gate implemented
via a throwaway signInWithPassword() before calling updateUser.
- Active sessions — one-click "sign out of all devices" using
supabase.auth.signOut({ scope: 'global' }), with a confirm dialog.
Plus read-only role, joined date, and user id for operator debugging.
The header avatar and sidebar user row are now both dropdown menus
linking to /settings?tab=profile and /settings?tab=whatsapp; the
settings page reads ?tab= to land on the right tab. useAuth gets a
refreshProfile() callback so the header/sidebar update immediately
after a save without a full reload.
Deferred (separate work): account deletion, 2FA, phone/timezone.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
108 lines
3.5 KiB
TypeScript
108 lines
3.5 KiB
TypeScript
'use client';
|
|
|
|
import { useEffect, useState } from 'react';
|
|
import { useRouter, useSearchParams } from 'next/navigation';
|
|
import { Settings, MessageSquare, Tag, User } from 'lucide-react';
|
|
import { Tabs, TabsList, TabsTrigger, TabsContent } from '@/components/ui/tabs';
|
|
import { WhatsAppConfig } from '@/components/settings/whatsapp-config';
|
|
import { TemplateManager } from '@/components/settings/template-manager';
|
|
import { TagManager } from '@/components/settings/tag-manager';
|
|
import { ProfileForm } from '@/components/settings/profile-form';
|
|
import { PasswordForm } from '@/components/settings/password-form';
|
|
import { SessionsCard } from '@/components/settings/sessions-card';
|
|
|
|
const TAB_VALUES = ['profile', 'whatsapp', 'templates', 'tags'] as const;
|
|
type TabValue = (typeof TAB_VALUES)[number];
|
|
|
|
function isTabValue(v: string | null): v is TabValue {
|
|
return !!v && (TAB_VALUES as readonly string[]).includes(v);
|
|
}
|
|
|
|
export default function SettingsPage() {
|
|
const router = useRouter();
|
|
const searchParams = useSearchParams();
|
|
const initialTab = (() => {
|
|
const q = searchParams.get('tab');
|
|
return isTabValue(q) ? q : 'profile';
|
|
})();
|
|
|
|
const [tab, setTab] = useState<TabValue>(initialTab);
|
|
|
|
// Keep the URL in sync with the active tab so the user-menu deep links
|
|
// work and the tab is bookmarkable / shareable.
|
|
useEffect(() => {
|
|
const q = searchParams.get('tab');
|
|
if (isTabValue(q) && q !== tab) setTab(q);
|
|
}, [searchParams, tab]);
|
|
|
|
const onChange = (next: TabValue) => {
|
|
setTab(next);
|
|
const params = new URLSearchParams(searchParams.toString());
|
|
params.set('tab', next);
|
|
router.replace(`/settings?${params.toString()}`, { scroll: false });
|
|
};
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
<div>
|
|
<h1 className="text-2xl font-bold text-white">Settings</h1>
|
|
<p className="text-sm text-slate-400 mt-1">
|
|
Manage your profile, WhatsApp integration, message templates, and
|
|
tags.
|
|
</p>
|
|
</div>
|
|
|
|
<Tabs value={tab} onValueChange={(v) => onChange(v as TabValue)}>
|
|
<TabsList className="bg-slate-900 border border-slate-700">
|
|
<TabsTrigger
|
|
value="profile"
|
|
className="data-active:bg-slate-800 data-active:text-emerald-400 text-slate-400"
|
|
>
|
|
<User className="size-4" />
|
|
Profile
|
|
</TabsTrigger>
|
|
<TabsTrigger
|
|
value="whatsapp"
|
|
className="data-active:bg-slate-800 data-active:text-emerald-400 text-slate-400"
|
|
>
|
|
<Settings className="size-4" />
|
|
WhatsApp Config
|
|
</TabsTrigger>
|
|
<TabsTrigger
|
|
value="templates"
|
|
className="data-active:bg-slate-800 data-active:text-emerald-400 text-slate-400"
|
|
>
|
|
<MessageSquare className="size-4" />
|
|
Templates
|
|
</TabsTrigger>
|
|
<TabsTrigger
|
|
value="tags"
|
|
className="data-active:bg-slate-800 data-active:text-emerald-400 text-slate-400"
|
|
>
|
|
<Tag className="size-4" />
|
|
Tags
|
|
</TabsTrigger>
|
|
</TabsList>
|
|
|
|
<TabsContent value="profile" className="space-y-6">
|
|
<ProfileForm />
|
|
<PasswordForm />
|
|
<SessionsCard />
|
|
</TabsContent>
|
|
|
|
<TabsContent value="whatsapp">
|
|
<WhatsAppConfig />
|
|
</TabsContent>
|
|
|
|
<TabsContent value="templates">
|
|
<TemplateManager />
|
|
</TabsContent>
|
|
|
|
<TabsContent value="tags">
|
|
<TagManager />
|
|
</TabsContent>
|
|
</Tabs>
|
|
</div>
|
|
);
|
|
}
|