feat: Email templates, bulk delete, communication credits, plan features
- Add email template presets for Browse Templates tab (12 templates) - Add bulk selection and deletion for My Templates tab - Add communication credits system with Twilio integration - Add payment views for credit purchases and auto-reload - Add SMS reminder and masked calling plan permissions - Fix appointment status mapping (frontend/backend mismatch) - Clear masquerade stack on login/logout for session hygiene - Update platform settings with credit configuration - Add new migrations for Twilio and Stripe payment fields 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
154
frontend/src/layouts/SettingsLayout.tsx
Normal file
154
frontend/src/layouts/SettingsLayout.tsx
Normal file
@@ -0,0 +1,154 @@
|
||||
/**
|
||||
* Settings Layout
|
||||
*
|
||||
* Provides a sidebar navigation for settings pages with grouped sections.
|
||||
* Used as a wrapper for all /settings/* routes.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Outlet, Link, useLocation, useNavigate, useOutletContext } from 'react-router-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
ArrowLeft,
|
||||
Building2,
|
||||
Palette,
|
||||
Layers,
|
||||
Globe,
|
||||
Key,
|
||||
Lock,
|
||||
Mail,
|
||||
Phone,
|
||||
CreditCard,
|
||||
Webhook,
|
||||
} from 'lucide-react';
|
||||
import {
|
||||
SettingsSidebarSection,
|
||||
SettingsSidebarItem,
|
||||
} from '../components/navigation/SidebarComponents';
|
||||
import { Business, User } from '../types';
|
||||
|
||||
interface ParentContext {
|
||||
user: User;
|
||||
business: Business;
|
||||
updateBusiness: (updates: Partial<Business>) => void;
|
||||
}
|
||||
|
||||
const SettingsLayout: React.FC = () => {
|
||||
const { t } = useTranslation();
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
|
||||
// Get context from parent route (BusinessLayout)
|
||||
const parentContext = useOutletContext<ParentContext>();
|
||||
|
||||
return (
|
||||
<div className="flex h-full bg-gray-50 dark:bg-gray-900">
|
||||
{/* Settings Sidebar */}
|
||||
<aside className="w-64 bg-white dark:bg-gray-800 border-r border-gray-200 dark:border-gray-700 flex flex-col shrink-0">
|
||||
{/* Back Button */}
|
||||
<div className="p-4 border-b border-gray-200 dark:border-gray-700">
|
||||
<button
|
||||
onClick={() => navigate('/')}
|
||||
className="flex items-center gap-2 text-sm text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white transition-colors"
|
||||
>
|
||||
<ArrowLeft size={16} />
|
||||
<span>{t('settings.backToApp', 'Back to App')}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Settings Title */}
|
||||
<div className="px-4 py-4">
|
||||
<h2 className="text-lg font-semibold text-gray-900 dark:text-white">
|
||||
{t('settings.title', 'Settings')}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
{/* Navigation */}
|
||||
<nav className="flex-1 px-2 pb-4 space-y-3 overflow-y-auto">
|
||||
{/* Business Section */}
|
||||
<SettingsSidebarSection title={t('settings.sections.business', 'Business')}>
|
||||
<SettingsSidebarItem
|
||||
to="/settings/general"
|
||||
icon={Building2}
|
||||
label={t('settings.general.title', 'General')}
|
||||
description={t('settings.general.description', 'Name, timezone, contact')}
|
||||
/>
|
||||
<SettingsSidebarItem
|
||||
to="/settings/branding"
|
||||
icon={Palette}
|
||||
label={t('settings.branding.title', 'Branding')}
|
||||
description={t('settings.branding.description', 'Logo, colors, appearance')}
|
||||
/>
|
||||
<SettingsSidebarItem
|
||||
to="/settings/resource-types"
|
||||
icon={Layers}
|
||||
label={t('settings.resourceTypes.title', 'Resource Types')}
|
||||
description={t('settings.resourceTypes.description', 'Staff, rooms, equipment')}
|
||||
/>
|
||||
</SettingsSidebarSection>
|
||||
|
||||
{/* Integrations Section */}
|
||||
<SettingsSidebarSection title={t('settings.sections.integrations', 'Integrations')}>
|
||||
<SettingsSidebarItem
|
||||
to="/settings/domains"
|
||||
icon={Globe}
|
||||
label={t('settings.domains.title', 'Domains')}
|
||||
description={t('settings.domains.description', 'Custom domain setup')}
|
||||
/>
|
||||
<SettingsSidebarItem
|
||||
to="/settings/api"
|
||||
icon={Key}
|
||||
label={t('settings.api.title', 'API & Webhooks')}
|
||||
description={t('settings.api.description', 'API tokens, webhooks')}
|
||||
/>
|
||||
</SettingsSidebarSection>
|
||||
|
||||
{/* Access Section */}
|
||||
<SettingsSidebarSection title={t('settings.sections.access', 'Access')}>
|
||||
<SettingsSidebarItem
|
||||
to="/settings/authentication"
|
||||
icon={Lock}
|
||||
label={t('settings.authentication.title', 'Authentication')}
|
||||
description={t('settings.authentication.description', 'OAuth, social login')}
|
||||
/>
|
||||
</SettingsSidebarSection>
|
||||
|
||||
{/* Communication Section */}
|
||||
<SettingsSidebarSection title={t('settings.sections.communication', 'Communication')}>
|
||||
<SettingsSidebarItem
|
||||
to="/settings/email"
|
||||
icon={Mail}
|
||||
label={t('settings.email.title', 'Email Setup')}
|
||||
description={t('settings.email.description', 'Email addresses for tickets')}
|
||||
/>
|
||||
<SettingsSidebarItem
|
||||
to="/settings/sms-calling"
|
||||
icon={Phone}
|
||||
label={t('settings.smsCalling.title', 'SMS & Calling')}
|
||||
description={t('settings.smsCalling.description', 'Credits, phone numbers')}
|
||||
/>
|
||||
</SettingsSidebarSection>
|
||||
|
||||
{/* Billing Section */}
|
||||
<SettingsSidebarSection title={t('settings.sections.billing', 'Billing')}>
|
||||
<SettingsSidebarItem
|
||||
to="/settings/billing"
|
||||
icon={CreditCard}
|
||||
label={t('settings.billing.title', 'Plan & Billing')}
|
||||
description={t('settings.billing.description', 'Subscription, invoices')}
|
||||
/>
|
||||
</SettingsSidebarSection>
|
||||
</nav>
|
||||
</aside>
|
||||
|
||||
{/* Content Area */}
|
||||
<main className="flex-1 overflow-y-auto">
|
||||
<div className="max-w-4xl mx-auto p-8">
|
||||
<Outlet context={parentContext} />
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SettingsLayout;
|
||||
Reference in New Issue
Block a user