Add comprehensive tenant API documentation and settings help pages

- Create 6 new tenant API documentation pages:
  - HelpApiOverview: Authentication, scopes, rate limits, errors
  - HelpApiAppointments: CRUD operations for appointments
  - HelpApiServices: Read-only service catalog access
  - HelpApiResources: Staff, rooms, equipment endpoints
  - HelpApiCustomers: Customer management endpoints
  - HelpApiWebhooks: Real-time event subscriptions

- Create 6 new settings help pages for granular documentation

- Update HelpComprehensive with API section linking to new docs
- Update platform HelpApiDocs with comprehensive endpoint coverage
- Fix non-clickable /api/v1/docs/ links (now opens in new tab)
- Add routes for all new help pages in App.tsx
- Update FloatingHelpButton with new help page mappings

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
poduck
2025-12-16 23:16:30 -05:00
parent 94e37a2522
commit e52b56d51c
21 changed files with 7061 additions and 8 deletions

View File

@@ -92,6 +92,12 @@ const HelpPayments = React.lazy(() => import('./pages/help/HelpPayments'));
const HelpContracts = React.lazy(() => import('./pages/help/HelpContracts'));
const HelpAutomations = React.lazy(() => import('./pages/help/HelpAutomations'));
const HelpSiteBuilder = React.lazy(() => import('./pages/help/HelpSiteBuilder'));
const HelpApiOverview = React.lazy(() => import('./pages/help/HelpApiOverview'));
const HelpApiAppointments = React.lazy(() => import('./pages/help/HelpApiAppointments'));
const HelpApiServices = React.lazy(() => import('./pages/help/HelpApiServices'));
const HelpApiResources = React.lazy(() => import('./pages/help/HelpApiResources'));
const HelpApiCustomers = React.lazy(() => import('./pages/help/HelpApiCustomers'));
const HelpApiWebhooks = React.lazy(() => import('./pages/help/HelpApiWebhooks'));
const HelpSettingsGeneral = React.lazy(() => import('./pages/help/HelpSettingsGeneral'));
const HelpSettingsResourceTypes = React.lazy(() => import('./pages/help/HelpSettingsResourceTypes'));
const HelpSettingsBooking = React.lazy(() => import('./pages/help/HelpSettingsBooking'));
@@ -102,6 +108,12 @@ const HelpSettingsApi = React.lazy(() => import('./pages/help/HelpSettingsApi'))
const HelpSettingsAuth = React.lazy(() => import('./pages/help/HelpSettingsAuth'));
const HelpSettingsBilling = React.lazy(() => import('./pages/help/HelpSettingsBilling'));
const HelpSettingsQuota = React.lazy(() => import('./pages/help/HelpSettingsQuota'));
const HelpLocations = React.lazy(() => import('./pages/help/HelpLocations'));
const HelpSettingsBusinessHours = React.lazy(() => import('./pages/help/HelpSettingsBusinessHours'));
const HelpSettingsEmailTemplates = React.lazy(() => import('./pages/help/HelpSettingsEmailTemplates'));
const HelpSettingsEmbedWidget = React.lazy(() => import('./pages/help/HelpSettingsEmbedWidget'));
const HelpSettingsStaffRoles = React.lazy(() => import('./pages/help/HelpSettingsStaffRoles'));
const HelpSettingsCommunication = React.lazy(() => import('./pages/help/HelpSettingsCommunication'));
const HelpComprehensive = React.lazy(() => import('./pages/help/HelpComprehensive'));
const StaffHelp = React.lazy(() => import('./pages/help/StaffHelp'));
const PlatformSupport = React.lazy(() => import('./pages/PlatformSupport')); // Import Platform Support page (for businesses to contact SmoothSchedule)
@@ -762,6 +774,12 @@ const AppContent: React.FC = () => {
<Route path="/dashboard/help/contracts" element={<HelpContracts />} />
<Route path="/dashboard/help/automations" element={<HelpAutomations />} />
<Route path="/dashboard/help/site-builder" element={<HelpSiteBuilder />} />
<Route path="/dashboard/help/api" element={<HelpApiOverview />} />
<Route path="/dashboard/help/api/appointments" element={<HelpApiAppointments />} />
<Route path="/dashboard/help/api/services" element={<HelpApiServices />} />
<Route path="/dashboard/help/api/resources" element={<HelpApiResources />} />
<Route path="/dashboard/help/api/customers" element={<HelpApiCustomers />} />
<Route path="/dashboard/help/api/webhooks" element={<HelpApiWebhooks />} />
<Route path="/dashboard/help/settings/general" element={<HelpSettingsGeneral />} />
<Route path="/dashboard/help/settings/resource-types" element={<HelpSettingsResourceTypes />} />
<Route path="/dashboard/help/settings/booking" element={<HelpSettingsBooking />} />
@@ -772,6 +790,12 @@ const AppContent: React.FC = () => {
<Route path="/dashboard/help/settings/auth" element={<HelpSettingsAuth />} />
<Route path="/dashboard/help/settings/billing" element={<HelpSettingsBilling />} />
<Route path="/dashboard/help/settings/quota" element={<HelpSettingsQuota />} />
<Route path="/dashboard/help/locations" element={<HelpLocations />} />
<Route path="/dashboard/help/settings/business-hours" element={<HelpSettingsBusinessHours />} />
<Route path="/dashboard/help/settings/email-templates" element={<HelpSettingsEmailTemplates />} />
<Route path="/dashboard/help/settings/embed-widget" element={<HelpSettingsEmbedWidget />} />
<Route path="/dashboard/help/settings/staff-roles" element={<HelpSettingsStaffRoles />} />
<Route path="/dashboard/help/settings/communication" element={<HelpSettingsCommunication />} />
<Route
path="/dashboard/automations/marketplace"
element={

View File

@@ -16,10 +16,12 @@ const routeToHelpSuffix: Record<string, string> = {
'/': 'dashboard',
'/dashboard': 'dashboard',
'/scheduler': 'scheduler',
'/my-schedule': 'scheduler',
'/tasks': 'tasks',
'/customers': 'customers',
'/services': 'services',
'/resources': 'resources',
'/locations': 'locations',
'/staff': 'staff',
'/time-blocks': 'time-blocks',
'/my-availability': 'time-blocks',
@@ -39,7 +41,13 @@ const routeToHelpSuffix: Record<string, string> = {
'/settings/resource-types': 'settings/resource-types',
'/settings/booking': 'settings/booking',
'/settings/appearance': 'settings/appearance',
'/settings/branding': 'settings/appearance',
'/settings/business-hours': 'settings/business-hours',
'/settings/email': 'settings/email',
'/settings/email-templates': 'settings/email-templates',
'/settings/embed-widget': 'settings/embed-widget',
'/settings/staff-roles': 'settings/staff-roles',
'/settings/sms-calling': 'settings/communication',
'/settings/domains': 'settings/domains',
'/settings/api': 'settings/api',
'/settings/auth': 'settings/auth',

View File

@@ -84,6 +84,42 @@ describe('FloatingHelpButton', () => {
const link = screen.getByRole('link');
expect(link).toHaveAttribute('href', '/dashboard/help/site-builder');
});
it('links to /dashboard/help/locations for /dashboard/locations', () => {
renderWithRouter('/dashboard/locations');
const link = screen.getByRole('link');
expect(link).toHaveAttribute('href', '/dashboard/help/locations');
});
it('links to /dashboard/help/settings/business-hours for /dashboard/settings/business-hours', () => {
renderWithRouter('/dashboard/settings/business-hours');
const link = screen.getByRole('link');
expect(link).toHaveAttribute('href', '/dashboard/help/settings/business-hours');
});
it('links to /dashboard/help/settings/email-templates for /dashboard/settings/email-templates', () => {
renderWithRouter('/dashboard/settings/email-templates');
const link = screen.getByRole('link');
expect(link).toHaveAttribute('href', '/dashboard/help/settings/email-templates');
});
it('links to /dashboard/help/settings/embed-widget for /dashboard/settings/embed-widget', () => {
renderWithRouter('/dashboard/settings/embed-widget');
const link = screen.getByRole('link');
expect(link).toHaveAttribute('href', '/dashboard/help/settings/embed-widget');
});
it('links to /dashboard/help/settings/staff-roles for /dashboard/settings/staff-roles', () => {
renderWithRouter('/dashboard/settings/staff-roles');
const link = screen.getByRole('link');
expect(link).toHaveAttribute('href', '/dashboard/help/settings/staff-roles');
});
it('links to /dashboard/help/settings/communication for /dashboard/settings/sms-calling', () => {
renderWithRouter('/dashboard/settings/sms-calling');
const link = screen.getByRole('link');
expect(link).toHaveAttribute('href', '/dashboard/help/settings/communication');
});
});
describe('non-dashboard routes (public/platform)', () => {
@@ -111,6 +147,42 @@ describe('FloatingHelpButton', () => {
expect(link).toHaveAttribute('href', '/help/settings/general');
});
it('links to /help/locations for /locations', () => {
renderWithRouter('/locations');
const link = screen.getByRole('link');
expect(link).toHaveAttribute('href', '/help/locations');
});
it('links to /help/settings/business-hours for /settings/business-hours', () => {
renderWithRouter('/settings/business-hours');
const link = screen.getByRole('link');
expect(link).toHaveAttribute('href', '/help/settings/business-hours');
});
it('links to /help/settings/email-templates for /settings/email-templates', () => {
renderWithRouter('/settings/email-templates');
const link = screen.getByRole('link');
expect(link).toHaveAttribute('href', '/help/settings/email-templates');
});
it('links to /help/settings/embed-widget for /settings/embed-widget', () => {
renderWithRouter('/settings/embed-widget');
const link = screen.getByRole('link');
expect(link).toHaveAttribute('href', '/help/settings/embed-widget');
});
it('links to /help/settings/staff-roles for /settings/staff-roles', () => {
renderWithRouter('/settings/staff-roles');
const link = screen.getByRole('link');
expect(link).toHaveAttribute('href', '/help/settings/staff-roles');
});
it('links to /help/settings/communication for /settings/sms-calling', () => {
renderWithRouter('/settings/sms-calling');
const link = screen.getByRole('link');
expect(link).toHaveAttribute('href', '/help/settings/communication');
});
it('returns null on /help pages', () => {
const { container } = renderWithRouter('/help/dashboard');
expect(container.firstChild).toBeNull();

View File

@@ -1591,7 +1591,13 @@
"billing": "Abrechnung",
"apiSettings": "API-Einstellungen",
"authentication": "Authentifizierung",
"usageQuota": "Nutzung & Kontingent"
"usageQuota": "Nutzung & Kontingent",
"locations": "Standorte",
"businessHours": "Geschäftszeiten",
"emailTemplates": "E-Mail-Vorlagen",
"embedWidget": "Eingebettetes Widget",
"staffRoles": "Mitarbeiterrollen",
"smsCalling": "SMS und Anrufe"
},
"introduction": {
"title": "Einführung",
@@ -1851,6 +1857,19 @@
"contractsDocumentation": "Vertragsdokumentation",
"contractsDocumentationDesc": "Vollständige Anleitung zu Vorlagen, Unterzeichnung und Konformitätsfunktionen"
},
"locations": {
"title": "Standorte",
"description": "Verwalten Sie mehrere Geschäftsstandorte, jeweils mit eigener Adresse, Kontaktdaten und zugewiesenen Ressourcen und Dienstleistungen.",
"keyFeatures": "Hauptfunktionen",
"primaryLocation": "Hauptstandort",
"primaryLocationDesc": "Legen Sie einen Standort als Ihre Hauptgeschäftsadresse fest",
"activateDeactivate": "Aktivieren/Deaktivieren",
"activateDeactivateDesc": "Deaktivieren Sie Standorte vorübergehend, ohne sie zu löschen",
"addressManagement": "Adressverwaltung",
"addressManagementDesc": "Vollständige Adresse, Telefon, E-Mail und Zeitzone für jeden Standort",
"locationsDocumentation": "Standort-Dokumentation",
"locationsDocumentationDesc": "Vollständige Anleitung zur Multi-Standort-Verwaltung"
},
"settings": {
"title": "Einstellungen",
"description": "In den Einstellungen konfigurieren Geschäftsinhaber ihre Terminplanungsplattform. Die meisten Einstellungen sind nur für Inhaber und beeinflussen den Geschäftsbetrieb.",
@@ -1898,7 +1917,17 @@
"apiSettingsLink": "API-Einstellungen",
"apiSettingsLinkDesc": "API-Schlüssel und Webhooks",
"usageQuotaLink": "Nutzung & Kontingent",
"usageQuotaLinkDesc": "Nutzung und Limits verfolgen"
"usageQuotaLinkDesc": "Nutzung und Limits verfolgen",
"businessHoursLink": "Geschäftszeiten",
"businessHoursLinkDesc": "Konfigurieren Sie die Öffnungszeiten für jeden Tag",
"emailTemplatesFullLink": "E-Mail-Vorlagen",
"emailTemplatesFullLinkDesc": "Passen Sie den Inhalt automatischer E-Mails an",
"embedWidgetLink": "Eingebettetes Widget",
"embedWidgetLinkDesc": "Fügen Sie Buchungen zu externen Websites hinzu",
"staffRolesLink": "Mitarbeiterrollen",
"staffRolesLinkDesc": "Konfigurieren Sie Berechtigungen für Mitarbeiter",
"smsCallingLink": "SMS und Anrufe",
"smsCallingLinkDesc": "Verwalten Sie Kommunikationsguthaben und Telefonnummern"
},
"footer": {
"title": "Benötigen Sie weitere Hilfe?",

View File

@@ -3059,6 +3059,7 @@
"timeBlocks": "Time Blocks",
"plugins": "Plugins",
"contracts": "Contracts",
"locations": "Locations",
"settings": "Settings",
"servicesSetup": "Services Setup",
"resourcesSetup": "Resources Setup",
@@ -3070,7 +3071,12 @@
"billing": "Billing",
"apiSettings": "API Settings",
"authentication": "Authentication",
"usageQuota": "Usage & Quota"
"usageQuota": "Usage & Quota",
"businessHours": "Business Hours",
"emailTemplates": "Email Templates",
"embedWidget": "Embed Widget",
"staffRoles": "Staff Roles",
"smsCalling": "SMS &amp; Calling"
},
"introduction": {
"title": "Introduction",
@@ -3336,6 +3342,19 @@
"contractsDocumentation": "Contracts Documentation",
"contractsDocumentationDesc": "Complete guide to templates, signing, and compliance features"
},
"locations": {
"title": "Locations",
"description": "Manage multiple business locations, each with their own address, contact info, and assigned resources and services.",
"keyFeatures": "Key Features",
"primaryLocation": "Primary Location",
"primaryLocationDesc": "Designate one location as your primary business address",
"activateDeactivate": "Activate/Deactivate",
"activateDeactivateDesc": "Temporarily disable locations without deleting them",
"addressManagement": "Address Management",
"addressManagementDesc": "Full address, phone, email, and timezone for each location",
"locationsDocumentation": "Locations Documentation",
"locationsDocumentationDesc": "Complete guide to multi-location management"
},
"settings": {
"title": "Settings",
"description": "Settings is where business owners configure their scheduling platform. Most settings are owner-only and affect how your business operates.",
@@ -3383,7 +3402,17 @@
"apiSettingsLink": "API Settings",
"apiSettingsLinkDesc": "API keys and webhooks",
"usageQuotaLink": "Usage & Quota",
"usageQuotaLinkDesc": "Track usage and limits"
"usageQuotaLinkDesc": "Track usage and limits",
"businessHoursLink": "Business Hours",
"businessHoursLinkDesc": "Configure operating hours for each day",
"emailTemplatesFullLink": "Email Templates",
"emailTemplatesFullLinkDesc": "Customize automated email content",
"embedWidgetLink": "Embed Widget",
"embedWidgetLinkDesc": "Add booking to external websites",
"staffRolesLink": "Staff Roles",
"staffRolesLinkDesc": "Configure permissions for staff members",
"smsCallingLink": "SMS &amp; Calling",
"smsCallingLinkDesc": "Manage communication credits and phone numbers"
},
"footer": {
"title": "Need More Help?",

View File

@@ -1662,7 +1662,13 @@
"billing": "Facturación",
"apiSettings": "Configuración de API",
"authentication": "Autenticación",
"usageQuota": "Uso y Cuota"
"usageQuota": "Uso y Cuota",
"locations": "Ubicaciones",
"businessHours": "Horario Comercial",
"emailTemplates": "Plantillas de Email",
"embedWidget": "Widget Integrado",
"staffRoles": "Roles del Personal",
"smsCalling": "SMS y Llamadas"
},
"introduction": {
"title": "Introducción",
@@ -1928,6 +1934,19 @@
"contractsDocumentation": "Documentación de Contratos",
"contractsDocumentationDesc": "Guía completa de plantillas, firma y funciones de cumplimiento"
},
"locations": {
"title": "Ubicaciones",
"description": "Gestiona múltiples ubicaciones de negocio, cada una con su propia dirección, información de contacto y recursos y servicios asignados.",
"keyFeatures": "Características Principales",
"primaryLocation": "Ubicación Principal",
"primaryLocationDesc": "Designa una ubicación como tu dirección comercial principal",
"activateDeactivate": "Activar/Desactivar",
"activateDeactivateDesc": "Desactiva temporalmente ubicaciones sin eliminarlas",
"addressManagement": "Gestión de Direcciones",
"addressManagementDesc": "Dirección completa, teléfono, email y zona horaria para cada ubicación",
"locationsDocumentation": "Documentación de Ubicaciones",
"locationsDocumentationDesc": "Guía completa para la gestión de múltiples ubicaciones"
},
"settings": {
"title": "Configuración",
"description": "Configuración es donde los propietarios del negocio configuran su plataforma de programación. La mayoría de las configuraciones son solo para propietarios y afectan cómo opera tu negocio.",
@@ -1966,8 +1985,18 @@
"otherSettings": "Otras Configuraciones",
"resourceTypesLink": "Tipos de Recurso",
"resourceTypesLinkDesc": "Configura tipos de personal, sala, equipo",
"businessHoursLink": "Horario Comercial",
"businessHoursLinkDesc": "Configura las horas de operación para cada día",
"emailTemplatesLink": "Plantillas de Email",
"emailTemplatesLinkDesc": "Personaliza notificaciones por email",
"emailTemplatesFullLink": "Plantillas de Email",
"emailTemplatesFullLinkDesc": "Personaliza el contenido de los emails automáticos",
"embedWidgetLink": "Widget Integrado",
"embedWidgetLinkDesc": "Añade reservas a sitios web externos",
"staffRolesLink": "Roles del Personal",
"staffRolesLinkDesc": "Configura permisos para los miembros del personal",
"smsCallingLink": "SMS y Llamadas",
"smsCallingLinkDesc": "Gestiona créditos de comunicación y números de teléfono",
"customDomainsLink": "Dominios Personalizados",
"customDomainsLinkDesc": "Usa tu propio dominio para reservas",
"billingLink": "Facturación",

View File

@@ -1591,6 +1591,7 @@
"timeBlocks": "Blocs de Temps",
"plugins": "Plugins",
"contracts": "Contrats",
"locations": "Emplacements",
"settings": "Paramètres",
"servicesSetup": "Configuration des Services",
"resourcesSetup": "Configuration des Ressources",
@@ -1602,7 +1603,12 @@
"billing": "Facturation",
"apiSettings": "Paramètres API",
"authentication": "Authentification",
"usageQuota": "Utilisation et Quota"
"usageQuota": "Utilisation et Quota",
"businessHours": "Heures d'Ouverture",
"emailTemplates": "Modèles d'Email",
"embedWidget": "Widget Intégré",
"staffRoles": "Rôles du Personnel",
"smsCalling": "SMS et Appels"
},
"introduction": {
"title": "Introduction",
@@ -1868,6 +1874,19 @@
"contractsDocumentation": "Documentation des Contrats",
"contractsDocumentationDesc": "Guide complet sur les modèles, la signature et les fonctions de conformité"
},
"locations": {
"title": "Emplacements",
"description": "Gérez plusieurs emplacements commerciaux, chacun avec sa propre adresse, coordonnées et ressources et services assignés.",
"keyFeatures": "Fonctionnalités Clés",
"primaryLocation": "Emplacement Principal",
"primaryLocationDesc": "Désignez un emplacement comme votre adresse commerciale principale",
"activateDeactivate": "Activer/Désactiver",
"activateDeactivateDesc": "Désactivez temporairement des emplacements sans les supprimer",
"addressManagement": "Gestion des Adresses",
"addressManagementDesc": "Adresse complète, téléphone, email et fuseau horaire pour chaque emplacement",
"locationsDocumentation": "Documentation des Emplacements",
"locationsDocumentationDesc": "Guide complet pour la gestion multi-emplacements"
},
"settings": {
"title": "Paramètres",
"description": "Paramètres est l'endroit où les propriétaires d'entreprise configurent leur plateforme de planification. La plupart des paramètres sont réservés aux propriétaires et affectent le fonctionnement de votre entreprise.",
@@ -1915,7 +1934,17 @@
"apiSettingsLink": "Paramètres API",
"apiSettingsLinkDesc": "Clés API et webhooks",
"usageQuotaLink": "Utilisation et Quota",
"usageQuotaLinkDesc": "Suivez l'utilisation et les limites"
"usageQuotaLinkDesc": "Suivez l'utilisation et les limites",
"businessHoursLink": "Heures d'Ouverture",
"businessHoursLinkDesc": "Configurez les heures d'ouverture pour chaque jour",
"emailTemplatesFullLink": "Modèles d'Email",
"emailTemplatesFullLinkDesc": "Personnalisez le contenu des emails automatiques",
"embedWidgetLink": "Widget Intégré",
"embedWidgetLinkDesc": "Ajoutez la réservation sur des sites externes",
"staffRolesLink": "Rôles du Personnel",
"staffRolesLinkDesc": "Configurez les permissions pour le personnel",
"smsCallingLink": "SMS et Appels",
"smsCallingLinkDesc": "Gérez les crédits de communication et les numéros de téléphone"
},
"footer": {
"title": "Besoin de Plus d'Aide ?",

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,430 @@
/**
* Help API Appointments Page
*
* User-friendly documentation for the Appointments API.
*/
import React from 'react';
import { useTranslation } from 'react-i18next';
import { useNavigate, Link } from 'react-router-dom';
import {
ArrowLeft,
Calendar,
Clock,
CheckCircle,
XCircle,
AlertCircle,
Code,
BookOpen,
HelpCircle,
} from 'lucide-react';
const HelpApiAppointments: React.FC = () => {
const { t } = useTranslation();
const navigate = useNavigate();
return (
<div className="max-w-4xl mx-auto py-8 px-4">
{/* Back Button */}
<button
onClick={() => navigate(-1)}
className="flex items-center gap-2 text-brand-600 hover:text-brand-700 dark:text-brand-400 mb-6"
>
<ArrowLeft size={20} />
{t('common.back', 'Back')}
</button>
{/* Header */}
<div className="mb-8">
<div className="flex items-center gap-3 mb-4">
<div className="w-12 h-12 rounded-xl bg-brand-100 dark:bg-brand-900/30 flex items-center justify-center">
<Calendar size={24} className="text-brand-600 dark:text-brand-400" />
</div>
<div>
<h1 className="text-3xl font-bold text-gray-900 dark:text-white">
Appointments API
</h1>
<p className="text-gray-500 dark:text-gray-400">
Manage appointments and bookings programmatically
</p>
</div>
</div>
</div>
{/* Overview Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Calendar size={20} className="text-brand-500" />
Overview
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<p className="text-gray-600 dark:text-gray-300 mb-4">
The Appointments API allows you to programmatically manage appointments, bookings, and scheduling
events in your SmoothSchedule account. Create, retrieve, update, and cancel appointments with
full control over resources, customers, and scheduling.
</p>
<div className="bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-lg p-4">
<p className="text-sm text-blue-800 dark:text-blue-200">
<strong>Required OAuth Scopes:</strong> <code className="bg-white dark:bg-gray-800 px-2 py-0.5 rounded">bookings:read</code>, <code className="bg-white dark:bg-gray-800 px-2 py-0.5 rounded">bookings:write</code>
</p>
</div>
</div>
</section>
{/* Endpoints Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Code size={20} className="text-brand-500" />
API Endpoints
</h2>
{/* List Appointments */}
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6 mb-6">
<div className="flex items-center gap-2 mb-3">
<span className="px-2 py-1 bg-green-100 dark:bg-green-900/30 text-green-800 dark:text-green-200 text-xs font-semibold rounded">GET</span>
<code className="text-sm text-gray-900 dark:text-white font-mono">/api/v1/appointments/</code>
</div>
<p className="text-gray-600 dark:text-gray-300 mb-4">Retrieve a list of appointments with optional filtering.</p>
<h4 className="font-medium text-gray-900 dark:text-white mb-2">Query Parameters:</h4>
<ul className="text-sm text-gray-600 dark:text-gray-300 space-y-1 mb-4">
<li><code className="bg-gray-100 dark:bg-gray-700 px-2 py-0.5 rounded">start_date</code> - Filter by start date (YYYY-MM-DD)</li>
<li><code className="bg-gray-100 dark:bg-gray-700 px-2 py-0.5 rounded">end_date</code> - Filter by end date (YYYY-MM-DD)</li>
<li><code className="bg-gray-100 dark:bg-gray-700 px-2 py-0.5 rounded">status</code> - Filter by status (scheduled, confirmed, completed, etc.)</li>
<li><code className="bg-gray-100 dark:bg-gray-700 px-2 py-0.5 rounded">customer_id</code> - Filter by customer UUID</li>
</ul>
<div className="bg-gray-900 dark:bg-gray-950 rounded-lg p-4 overflow-x-auto">
<pre className="text-sm text-gray-100 font-mono">
{`curl -X GET "https://api.smoothschedule.com/api/v1/appointments/?start_date=2025-12-01" \\
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"`}
</pre>
</div>
</div>
{/* Get Appointment */}
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6 mb-6">
<div className="flex items-center gap-2 mb-3">
<span className="px-2 py-1 bg-green-100 dark:bg-green-900/30 text-green-800 dark:text-green-200 text-xs font-semibold rounded">GET</span>
<code className="text-sm text-gray-900 dark:text-white font-mono">/api/v1/appointments/&#123;id&#125;/</code>
</div>
<p className="text-gray-600 dark:text-gray-300 mb-4">Retrieve a single appointment by ID.</p>
<div className="bg-gray-900 dark:bg-gray-950 rounded-lg p-4 overflow-x-auto">
<pre className="text-sm text-gray-100 font-mono">
{`curl -X GET "https://api.smoothschedule.com/api/v1/appointments/a1b2c3d4-5678-90ab-cdef-1234567890ab/" \\
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"`}
</pre>
</div>
</div>
{/* Create Appointment */}
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6 mb-6">
<div className="flex items-center gap-2 mb-3">
<span className="px-2 py-1 bg-blue-100 dark:bg-blue-900/30 text-blue-800 dark:text-blue-200 text-xs font-semibold rounded">POST</span>
<code className="text-sm text-gray-900 dark:text-white font-mono">/api/v1/appointments/</code>
</div>
<p className="text-gray-600 dark:text-gray-300 mb-4">Create a new appointment.</p>
<h4 className="font-medium text-gray-900 dark:text-white mb-2">Request Body:</h4>
<div className="bg-gray-900 dark:bg-gray-950 rounded-lg p-4 overflow-x-auto mb-4">
<pre className="text-sm text-gray-100 font-mono">
{`{
"service_id": "uuid",
"resource_id": "uuid", // optional
"customer_id": "uuid", // or use customer_email/name/phone
"customer_email": "john@example.com", // if customer_id not provided
"customer_name": "John Doe",
"customer_phone": "+1234567890",
"start_time": "2025-12-16T14:00:00Z",
"notes": "Customer requested window seat"
}`}
</pre>
</div>
<div className="bg-gray-900 dark:bg-gray-950 rounded-lg p-4 overflow-x-auto">
<pre className="text-sm text-gray-100 font-mono">
{`curl -X POST "https://api.smoothschedule.com/api/v1/appointments/" \\
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \\
-H "Content-Type: application/json" \\
-d '{
"service_id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
"customer_email": "john@example.com",
"customer_name": "John Doe",
"start_time": "2025-12-16T14:00:00Z",
"notes": "Customer requested window seat"
}'`}
</pre>
</div>
</div>
{/* Update Appointment */}
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6 mb-6">
<div className="flex items-center gap-2 mb-3">
<span className="px-2 py-1 bg-yellow-100 dark:bg-yellow-900/30 text-yellow-800 dark:text-yellow-200 text-xs font-semibold rounded">PATCH</span>
<code className="text-sm text-gray-900 dark:text-white font-mono">/api/v1/appointments/&#123;id&#125;/</code>
</div>
<p className="text-gray-600 dark:text-gray-300 mb-4">Update an existing appointment.</p>
<h4 className="font-medium text-gray-900 dark:text-white mb-2">Request Body (partial update):</h4>
<div className="bg-gray-900 dark:bg-gray-950 rounded-lg p-4 overflow-x-auto mb-4">
<pre className="text-sm text-gray-100 font-mono">
{`{
"start_time": "2025-12-16T15:00:00Z",
"resource_id": "new-resource-uuid",
"notes": "Updated notes"
}`}
</pre>
</div>
<div className="bg-gray-900 dark:bg-gray-950 rounded-lg p-4 overflow-x-auto">
<pre className="text-sm text-gray-100 font-mono">
{`curl -X PATCH "https://api.smoothschedule.com/api/v1/appointments/a1b2c3d4-5678-90ab-cdef-1234567890ab/" \\
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \\
-H "Content-Type: application/json" \\
-d '{
"start_time": "2025-12-16T15:00:00Z",
"notes": "Rescheduled to 3 PM"
}'`}
</pre>
</div>
</div>
{/* Cancel Appointment */}
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<div className="flex items-center gap-2 mb-3">
<span className="px-2 py-1 bg-red-100 dark:bg-red-900/30 text-red-800 dark:text-red-200 text-xs font-semibold rounded">DELETE</span>
<code className="text-sm text-gray-900 dark:text-white font-mono">/api/v1/appointments/&#123;id&#125;/</code>
</div>
<p className="text-gray-600 dark:text-gray-300 mb-4">Cancel an appointment. Optionally provide a cancellation reason.</p>
<h4 className="font-medium text-gray-900 dark:text-white mb-2">Request Body (optional):</h4>
<div className="bg-gray-900 dark:bg-gray-950 rounded-lg p-4 overflow-x-auto mb-4">
<pre className="text-sm text-gray-100 font-mono">
{`{
"reason": "Customer requested cancellation"
}`}
</pre>
</div>
<div className="bg-gray-900 dark:bg-gray-950 rounded-lg p-4 overflow-x-auto">
<pre className="text-sm text-gray-100 font-mono">
{`curl -X DELETE "https://api.smoothschedule.com/api/v1/appointments/a1b2c3d4-5678-90ab-cdef-1234567890ab/" \\
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \\
-H "Content-Type: application/json" \\
-d '{"reason": "Customer requested cancellation"}'`}
</pre>
</div>
</div>
</section>
{/* Appointment Object Schema */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<BookOpen size={20} className="text-brand-500" />
Appointment Object
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<p className="text-gray-600 dark:text-gray-300 mb-4">
Each appointment object contains the following fields:
</p>
<div className="overflow-x-auto">
<table className="w-full text-sm">
<thead className="border-b border-gray-200 dark:border-gray-700">
<tr>
<th className="text-left py-2 px-3 font-semibold text-gray-900 dark:text-white">Field</th>
<th className="text-left py-2 px-3 font-semibold text-gray-900 dark:text-white">Type</th>
<th className="text-left py-2 px-3 font-semibold text-gray-900 dark:text-white">Description</th>
</tr>
</thead>
<tbody className="text-gray-600 dark:text-gray-300">
<tr className="border-b border-gray-100 dark:border-gray-700/50">
<td className="py-2 px-3 font-mono">id</td>
<td className="py-2 px-3">UUID</td>
<td className="py-2 px-3">Unique appointment identifier</td>
</tr>
<tr className="border-b border-gray-100 dark:border-gray-700/50">
<td className="py-2 px-3 font-mono">service</td>
<td className="py-2 px-3">Object</td>
<td className="py-2 px-3">Service details (id, name, duration, price)</td>
</tr>
<tr className="border-b border-gray-100 dark:border-gray-700/50">
<td className="py-2 px-3 font-mono">resource</td>
<td className="py-2 px-3">Object</td>
<td className="py-2 px-3">Assigned resource (id, name, type)</td>
</tr>
<tr className="border-b border-gray-100 dark:border-gray-700/50">
<td className="py-2 px-3 font-mono">customer</td>
<td className="py-2 px-3">Object</td>
<td className="py-2 px-3">Customer details (id, email, name, phone)</td>
</tr>
<tr className="border-b border-gray-100 dark:border-gray-700/50">
<td className="py-2 px-3 font-mono">start_time</td>
<td className="py-2 px-3">ISO 8601</td>
<td className="py-2 px-3">Appointment start time (UTC)</td>
</tr>
<tr className="border-b border-gray-100 dark:border-gray-700/50">
<td className="py-2 px-3 font-mono">end_time</td>
<td className="py-2 px-3">ISO 8601</td>
<td className="py-2 px-3">Appointment end time (UTC)</td>
</tr>
<tr className="border-b border-gray-100 dark:border-gray-700/50">
<td className="py-2 px-3 font-mono">status</td>
<td className="py-2 px-3">String</td>
<td className="py-2 px-3">Current status (see Status Values below)</td>
</tr>
<tr className="border-b border-gray-100 dark:border-gray-700/50">
<td className="py-2 px-3 font-mono">notes</td>
<td className="py-2 px-3">String</td>
<td className="py-2 px-3">Additional notes or instructions</td>
</tr>
<tr>
<td className="py-2 px-3 font-mono">created_at</td>
<td className="py-2 px-3">ISO 8601</td>
<td className="py-2 px-3">When the appointment was created</td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
{/* Status Values */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<AlertCircle size={20} className="text-brand-500" />
Status Values
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<p className="text-gray-600 dark:text-gray-300 mb-4">
Appointments can have one of the following status values:
</p>
<div className="space-y-3">
<div className="flex items-center gap-3">
<span className="px-3 py-1 bg-blue-100 dark:bg-blue-900/30 text-blue-800 dark:text-blue-200 text-sm font-medium rounded-full">
SCHEDULED
</span>
<span className="text-gray-600 dark:text-gray-300">Appointment has been scheduled but not yet confirmed</span>
</div>
<div className="flex items-center gap-3">
<span className="px-3 py-1 bg-green-100 dark:bg-green-900/30 text-green-800 dark:text-green-200 text-sm font-medium rounded-full">
CONFIRMED
</span>
<span className="text-gray-600 dark:text-gray-300">Customer has confirmed the appointment</span>
</div>
<div className="flex items-center gap-3">
<span className="px-3 py-1 bg-yellow-100 dark:bg-yellow-900/30 text-yellow-800 dark:text-yellow-200 text-sm font-medium rounded-full">
IN_PROGRESS
</span>
<span className="text-gray-600 dark:text-gray-300">Appointment is currently in progress</span>
</div>
<div className="flex items-center gap-3">
<span className="px-3 py-1 bg-gray-100 dark:bg-gray-700 text-gray-800 dark:text-gray-200 text-sm font-medium rounded-full">
COMPLETED
</span>
<span className="text-gray-600 dark:text-gray-300">Appointment has been completed successfully</span>
</div>
<div className="flex items-center gap-3">
<span className="px-3 py-1 bg-red-100 dark:bg-red-900/30 text-red-800 dark:text-red-200 text-sm font-medium rounded-full">
CANCELLED
</span>
<span className="text-gray-600 dark:text-gray-300">Appointment was cancelled</span>
</div>
<div className="flex items-center gap-3">
<span className="px-3 py-1 bg-orange-100 dark:bg-orange-900/30 text-orange-800 dark:text-orange-200 text-sm font-medium rounded-full">
NO_SHOW
</span>
<span className="text-gray-600 dark:text-gray-300">Customer did not show up for the appointment</span>
</div>
</div>
</div>
</section>
{/* Response Example */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Code size={20} className="text-brand-500" />
Example Response
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<p className="text-gray-600 dark:text-gray-300 mb-4">
A typical appointment object in the API response:
</p>
<div className="bg-gray-900 dark:bg-gray-950 rounded-lg p-4 overflow-x-auto">
<pre className="text-sm text-gray-100 font-mono">
{`{
"id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
"service": {
"id": "srv-uuid",
"name": "Haircut",
"duration": 60,
"price": 5000
},
"resource": {
"id": "res-uuid",
"name": "Sarah Johnson",
"type": "STAFF"
},
"customer": {
"id": "cust-uuid",
"email": "john@example.com",
"name": "John Doe",
"phone": "+1234567890"
},
"start_time": "2025-12-16T14:00:00Z",
"end_time": "2025-12-16T15:00:00Z",
"status": "confirmed",
"notes": "Customer requested window seat",
"created_at": "2025-12-01T10:30:00Z"
}`}
</pre>
</div>
</div>
</section>
{/* Rate Limiting */}
<section className="mb-10">
<div className="bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 rounded-xl p-6">
<div className="flex items-start gap-4">
<Clock size={24} className="text-yellow-600 dark:text-yellow-400 mt-1" />
<div className="flex-1">
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-2">
Rate Limiting
</h3>
<p className="text-gray-600 dark:text-gray-300 mb-3">
API requests are limited to <strong>1000 requests per hour</strong> per API key.
Rate limit information is included in response headers:
</p>
<div className="bg-gray-900 dark:bg-gray-950 rounded-lg p-3 overflow-x-auto">
<pre className="text-sm text-gray-100 font-mono">
{`X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 987
X-RateLimit-Reset: 1702742400`}
</pre>
</div>
</div>
</div>
</div>
</section>
{/* Need More Help */}
<section className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6 text-center">
<HelpCircle size={32} className="mx-auto text-brand-500 mb-3" />
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-2">
Need More Help?
</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Our support team is ready to help with API integration and technical questions.
</p>
<button
onClick={() => navigate('/dashboard/tickets')}
className="px-6 py-2 bg-brand-600 text-white rounded-lg hover:bg-brand-700 transition-colors"
>
Contact Support
</button>
</section>
</div>
);
};
export default HelpApiAppointments;

View File

@@ -0,0 +1,386 @@
/**
* Help API Customers Page
*
* User-friendly help documentation for the Customers API.
*/
import React from 'react';
import { useTranslation } from 'react-i18next';
import { useNavigate } from 'react-router-dom';
import {
ArrowLeft,
Users,
Mail,
Phone,
Calendar,
Code,
HelpCircle,
} from 'lucide-react';
const HelpApiCustomers: React.FC = () => {
const { t } = useTranslation();
const navigate = useNavigate();
return (
<div className="max-w-4xl mx-auto py-8 px-4">
{/* Back Button */}
<button
onClick={() => navigate(-1)}
className="flex items-center gap-2 text-brand-600 hover:text-brand-700 dark:text-brand-400 mb-6"
>
<ArrowLeft size={20} />
{t('common.back', 'Back')}
</button>
{/* Header */}
<div className="mb-8">
<div className="flex items-center gap-3 mb-4">
<div className="w-12 h-12 rounded-xl bg-brand-100 dark:bg-brand-900/30 flex items-center justify-center">
<Users size={24} className="text-brand-600 dark:text-brand-400" />
</div>
<div>
<h1 className="text-3xl font-bold text-gray-900 dark:text-white">
Customers API
</h1>
<p className="text-gray-500 dark:text-gray-400">
Manage customer records programmatically
</p>
</div>
</div>
</div>
{/* Overview Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Users size={20} className="text-brand-500" />
Overview
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<p className="text-gray-600 dark:text-gray-300 mb-4">
The Customers API allows you to manage customer records in your SmoothSchedule account.
Create, retrieve, update, and list customer information programmatically.
</p>
<div className="bg-blue-50 dark:bg-blue-900/20 rounded-lg p-4 border border-blue-200 dark:border-blue-800">
<p className="text-sm text-blue-800 dark:text-blue-300">
<strong>Required Scopes:</strong> <code className="bg-blue-100 dark:bg-blue-900/50 px-2 py-0.5 rounded">customers:read</code> for reading,
<code className="bg-blue-100 dark:bg-blue-900/50 px-2 py-0.5 rounded ml-2">customers:write</code> for creating/updating
</p>
</div>
</div>
</section>
{/* Endpoints Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Code size={20} className="text-brand-500" />
Endpoints
</h2>
{/* List Customers */}
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6 mb-4">
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-3">
List Customers
</h3>
<div className="bg-gray-50 dark:bg-gray-900/50 rounded-lg p-4 mb-4">
<code className="text-green-600 dark:text-green-400 font-mono">GET /api/v1/customers/</code>
</div>
<p className="text-gray-600 dark:text-gray-300 mb-3">
Retrieve a paginated list of customers. Results are limited to 100 customers per request.
</p>
<div className="space-y-2">
<p className="text-sm font-medium text-gray-700 dark:text-gray-300">Query Parameters:</p>
<ul className="space-y-1 text-sm text-gray-600 dark:text-gray-400">
<li><code className="bg-gray-100 dark:bg-gray-800 px-2 py-0.5 rounded">email</code> - Filter by exact email address</li>
<li><code className="bg-gray-100 dark:bg-gray-800 px-2 py-0.5 rounded">search</code> - Search by name or email (partial match)</li>
</ul>
</div>
</div>
{/* Get Customer */}
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6 mb-4">
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-3">
Get Customer
</h3>
<div className="bg-gray-50 dark:bg-gray-900/50 rounded-lg p-4 mb-4">
<code className="text-green-600 dark:text-green-400 font-mono">GET /api/v1/customers/&#123;id&#125;/</code>
</div>
<p className="text-gray-600 dark:text-gray-300">
Retrieve a specific customer by their UUID.
</p>
</div>
{/* Create Customer */}
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6 mb-4">
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-3">
Create Customer
</h3>
<div className="bg-gray-50 dark:bg-gray-900/50 rounded-lg p-4 mb-4">
<code className="text-orange-600 dark:text-orange-400 font-mono">POST /api/v1/customers/</code>
</div>
<p className="text-gray-600 dark:text-gray-300 mb-3">
Create a new customer record.
</p>
<div className="space-y-2">
<p className="text-sm font-medium text-gray-700 dark:text-gray-300">Request Body:</p>
<ul className="space-y-1 text-sm text-gray-600 dark:text-gray-400">
<li><code className="bg-gray-100 dark:bg-gray-800 px-2 py-0.5 rounded">email</code> - <span className="text-red-500">*required</span> Email address (must be unique)</li>
<li><code className="bg-gray-100 dark:bg-gray-800 px-2 py-0.5 rounded">name</code> - Customer's full name</li>
<li><code className="bg-gray-100 dark:bg-gray-800 px-2 py-0.5 rounded">phone</code> - Phone number</li>
</ul>
</div>
<div className="bg-yellow-50 dark:bg-yellow-900/20 rounded-lg p-4 border border-yellow-200 dark:border-yellow-800 mt-3">
<p className="text-sm text-yellow-800 dark:text-yellow-300">
<strong>Note:</strong> Returns <code className="bg-yellow-100 dark:bg-yellow-900/50 px-2 py-0.5 rounded">409 Conflict</code> if a customer with the email already exists.
</p>
</div>
</div>
{/* Update Customer */}
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-3">
Update Customer
</h3>
<div className="bg-gray-50 dark:bg-gray-900/50 rounded-lg p-4 mb-4">
<code className="text-blue-600 dark:text-blue-400 font-mono">PATCH /api/v1/customers/&#123;id&#125;/</code>
</div>
<p className="text-gray-600 dark:text-gray-300 mb-3">
Update an existing customer's information.
</p>
<div className="space-y-2">
<p className="text-sm font-medium text-gray-700 dark:text-gray-300">Request Body:</p>
<ul className="space-y-1 text-sm text-gray-600 dark:text-gray-400">
<li><code className="bg-gray-100 dark:bg-gray-800 px-2 py-0.5 rounded">name</code> - Customer's full name</li>
<li><code className="bg-gray-100 dark:bg-gray-800 px-2 py-0.5 rounded">phone</code> - Phone number</li>
</ul>
</div>
<div className="bg-red-50 dark:bg-red-900/20 rounded-lg p-4 border border-red-200 dark:border-red-800 mt-3">
<p className="text-sm text-red-800 dark:text-red-300">
<strong>Important:</strong> Email addresses cannot be changed after creation.
</p>
</div>
</div>
</section>
{/* Customer Object Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Users size={20} className="text-brand-500" />
Customer Object
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 overflow-hidden">
<div className="overflow-x-auto">
<table className="w-full">
<thead className="bg-gray-50 dark:bg-gray-900/50">
<tr>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
Field
</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
Type
</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
Description
</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-200 dark:divide-gray-700">
<tr>
<td className="px-6 py-4 whitespace-nowrap">
<code className="text-sm text-purple-600 dark:text-purple-400">id</code>
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-600 dark:text-gray-400">
UUID
</td>
<td className="px-6 py-4 text-sm text-gray-600 dark:text-gray-400">
Unique customer identifier
</td>
</tr>
<tr>
<td className="px-6 py-4 whitespace-nowrap">
<code className="text-sm text-purple-600 dark:text-purple-400">email</code>
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-600 dark:text-gray-400">
string
</td>
<td className="px-6 py-4 text-sm text-gray-600 dark:text-gray-400">
Customer's email address (unique)
</td>
</tr>
<tr>
<td className="px-6 py-4 whitespace-nowrap">
<code className="text-sm text-purple-600 dark:text-purple-400">name</code>
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-600 dark:text-gray-400">
string
</td>
<td className="px-6 py-4 text-sm text-gray-600 dark:text-gray-400">
Customer's full name
</td>
</tr>
<tr>
<td className="px-6 py-4 whitespace-nowrap">
<code className="text-sm text-purple-600 dark:text-purple-400">phone</code>
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-600 dark:text-gray-400">
string | null
</td>
<td className="px-6 py-4 text-sm text-gray-600 dark:text-gray-400">
Customer's phone number
</td>
</tr>
<tr>
<td className="px-6 py-4 whitespace-nowrap">
<code className="text-sm text-purple-600 dark:text-purple-400">created_at</code>
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-600 dark:text-gray-400">
ISO 8601
</td>
<td className="px-6 py-4 text-sm text-gray-600 dark:text-gray-400">
Timestamp when customer was created
</td>
</tr>
<tr>
<td className="px-6 py-4 whitespace-nowrap">
<code className="text-sm text-purple-600 dark:text-purple-400">total_appointments</code>
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-600 dark:text-gray-400">
integer
</td>
<td className="px-6 py-4 text-sm text-gray-600 dark:text-gray-400">
Total number of appointments for this customer
</td>
</tr>
<tr>
<td className="px-6 py-4 whitespace-nowrap">
<code className="text-sm text-purple-600 dark:text-purple-400">last_appointment_at</code>
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-600 dark:text-gray-400">
ISO 8601 | null
</td>
<td className="px-6 py-4 text-sm text-gray-600 dark:text-gray-400">
Timestamp of customer's most recent appointment
</td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
{/* Example Response Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Code size={20} className="text-brand-500" />
Example Response
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<pre className="bg-gray-50 dark:bg-gray-900/50 rounded-lg p-4 overflow-x-auto">
<code className="text-sm text-gray-800 dark:text-gray-200">
{`{
"id": "123e4567-e89b-12d3-a456-426614174000",
"email": "customer@example.com",
"name": "Jane Doe",
"phone": "+1234567890",
"created_at": "2024-01-01T10:00:00Z",
"total_appointments": 5,
"last_appointment_at": "2024-12-01T14:00:00Z"
}`}
</code>
</pre>
</div>
</section>
{/* Code Examples Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Code size={20} className="text-brand-500" />
Code Examples
</h2>
{/* List Customers Example */}
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6 mb-4">
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-3">
List All Customers
</h3>
<pre className="bg-gray-50 dark:bg-gray-900/50 rounded-lg p-4 overflow-x-auto">
<code className="text-sm text-gray-800 dark:text-gray-200">
{`curl -X GET "https://yourbusiness.smoothschedule.com/api/v1/customers/" \\
-H "Authorization: Bearer YOUR_API_KEY" \\
-H "Content-Type: application/json"`}
</code>
</pre>
</div>
{/* Search Customers Example */}
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6 mb-4">
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-3">
Search Customers
</h3>
<pre className="bg-gray-50 dark:bg-gray-900/50 rounded-lg p-4 overflow-x-auto">
<code className="text-sm text-gray-800 dark:text-gray-200">
{`curl -X GET "https://yourbusiness.smoothschedule.com/api/v1/customers/?search=jane" \\
-H "Authorization: Bearer YOUR_API_KEY" \\
-H "Content-Type: application/json"`}
</code>
</pre>
</div>
{/* Create Customer Example */}
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6 mb-4">
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-3">
Create Customer
</h3>
<pre className="bg-gray-50 dark:bg-gray-900/50 rounded-lg p-4 overflow-x-auto">
<code className="text-sm text-gray-800 dark:text-gray-200">
{`curl -X POST "https://yourbusiness.smoothschedule.com/api/v1/customers/" \\
-H "Authorization: Bearer YOUR_API_KEY" \\
-H "Content-Type: application/json" \\
-d '{
"email": "customer@example.com",
"name": "Jane Doe",
"phone": "+1234567890"
}'`}
</code>
</pre>
</div>
{/* Update Customer Example */}
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-3">
Update Customer
</h3>
<pre className="bg-gray-50 dark:bg-gray-900/50 rounded-lg p-4 overflow-x-auto">
<code className="text-sm text-gray-800 dark:text-gray-200">
{`curl -X PATCH "https://yourbusiness.smoothschedule.com/api/v1/customers/123e4567-e89b-12d3-a456-426614174000/" \\
-H "Authorization: Bearer YOUR_API_KEY" \\
-H "Content-Type: application/json" \\
-d '{
"name": "Jane Smith",
"phone": "+1987654321"
}'`}
</code>
</pre>
</div>
</section>
{/* Need More Help */}
<section className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6 text-center">
<HelpCircle size={32} className="mx-auto text-brand-500 mb-3" />
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-2">
Need More Help?
</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Our support team is ready to help with any questions about the Customers API.
</p>
<button
onClick={() => navigate('/dashboard/tickets')}
className="px-6 py-2 bg-brand-600 text-white rounded-lg hover:bg-brand-700 transition-colors"
>
Contact Support
</button>
</section>
</div>
);
};
export default HelpApiCustomers;

View File

@@ -0,0 +1,551 @@
/**
* Help API Overview Page
*
* Tenant-facing API documentation overview.
*/
import React from 'react';
import { useTranslation } from 'react-i18next';
import { useNavigate, Link } from 'react-router-dom';
import {
ArrowLeft,
Code,
Key,
Shield,
AlertCircle,
Zap,
Book,
HelpCircle,
ChevronRight,
Calendar,
Users,
Settings,
Webhook,
CheckCircle,
XCircle,
} from 'lucide-react';
const HelpApiOverview: React.FC = () => {
const { t } = useTranslation();
const navigate = useNavigate();
return (
<div className="max-w-4xl mx-auto py-8 px-4">
{/* Back Button */}
<button
onClick={() => navigate(-1)}
className="flex items-center gap-2 text-brand-600 hover:text-brand-700 dark:text-brand-400 mb-6"
>
<ArrowLeft size={20} />
{t('common.back', 'Back')}
</button>
{/* Header */}
<div className="mb-8">
<div className="flex items-center gap-3 mb-4">
<div className="w-12 h-12 rounded-xl bg-brand-100 dark:bg-brand-900/30 flex items-center justify-center">
<Code size={24} className="text-brand-600 dark:text-brand-400" />
</div>
<div>
<h1 className="text-3xl font-bold text-gray-900 dark:text-white">
API Overview
</h1>
<p className="text-gray-500 dark:text-gray-400">
REST API for third-party integrations
</p>
</div>
</div>
</div>
{/* Introduction Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Book size={20} className="text-brand-500" />
Introduction
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<p className="text-gray-600 dark:text-gray-300 mb-4">
SmoothSchedule provides a comprehensive REST API that allows you to integrate your scheduling
platform with third-party applications, build custom tools, and automate workflows.
</p>
<div className="bg-gray-50 dark:bg-gray-700/50 rounded-lg p-4 mb-4">
<h4 className="font-medium text-gray-900 dark:text-white mb-2">Base URL</h4>
<code className="text-sm text-brand-600 dark:text-brand-400">
https://your-subdomain.smoothschedule.com/api/v1/
</code>
</div>
<div className="bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-lg p-4">
<div className="flex items-start gap-2">
<Book size={18} className="text-blue-600 dark:text-blue-400 mt-0.5" />
<div>
<p className="text-sm text-blue-800 dark:text-blue-300">
<strong>Interactive Documentation:</strong> Explore and test API endpoints at{' '}
<a
href="/api/v1/docs/"
target="_blank"
rel="noopener noreferrer"
className="bg-blue-100 dark:bg-blue-900/40 px-1 rounded font-mono hover:underline"
>
/api/v1/docs/
</a>
</p>
</div>
</div>
</div>
</div>
</section>
{/* Authentication Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Key size={20} className="text-brand-500" />
Authentication
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<p className="text-gray-600 dark:text-gray-300 mb-4">
All API requests require authentication using Bearer tokens in the Authorization header.
</p>
<div className="mb-6">
<h4 className="font-medium text-gray-900 dark:text-white mb-3">Token Format</h4>
<div className="space-y-2">
<div className="flex items-start gap-3 p-3 bg-gray-50 dark:bg-gray-700/50 rounded-lg">
<CheckCircle size={18} className="text-green-500 mt-0.5" />
<div>
<code className="text-sm text-gray-900 dark:text-white font-mono">ss_live_xxxxxxxxx</code>
<p className="text-xs text-gray-500 dark:text-gray-400 mt-1">Production environment</p>
</div>
</div>
<div className="flex items-start gap-3 p-3 bg-gray-50 dark:bg-gray-700/50 rounded-lg">
<AlertCircle size={18} className="text-yellow-500 mt-0.5" />
<div>
<code className="text-sm text-gray-900 dark:text-white font-mono">ss_test_xxxxxxxxx</code>
<p className="text-xs text-gray-500 dark:text-gray-400 mt-1">Sandbox environment (safe for testing)</p>
</div>
</div>
</div>
</div>
<div className="mb-6">
<h4 className="font-medium text-gray-900 dark:text-white mb-3">Example Request</h4>
<div className="bg-gray-900 dark:bg-black rounded-lg p-4 overflow-x-auto">
<pre className="text-sm text-gray-100 font-mono">
{`curl -X GET "https://demo.smoothschedule.com/api/v1/services/" \\
-H "Authorization: Bearer ss_live_xxxxxxxxx" \\
-H "Content-Type: application/json"`}
</pre>
</div>
</div>
<div className="bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 rounded-lg p-4">
<div className="flex items-start gap-2">
<Shield size={18} className="text-yellow-600 dark:text-yellow-400 mt-0.5" />
<div>
<p className="text-sm text-yellow-800 dark:text-yellow-300">
<strong>Security:</strong> API tokens are created in Business Settings API.
Each token has configurable scopes that control access to specific endpoints and operations.
</p>
</div>
</div>
</div>
</div>
</section>
{/* Available Scopes Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Shield size={20} className="text-brand-500" />
Available Scopes
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<p className="text-gray-600 dark:text-gray-300 mb-4">
Control which operations your API token can perform by selecting scopes:
</p>
<div className="overflow-x-auto">
<table className="w-full text-sm">
<thead>
<tr className="border-b border-gray-200 dark:border-gray-700">
<th className="text-left py-3 px-4 font-medium text-gray-900 dark:text-white">Scope</th>
<th className="text-left py-3 px-4 font-medium text-gray-900 dark:text-white">Description</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-200 dark:divide-gray-700">
<tr>
<td className="py-3 px-4">
<code className="text-xs bg-gray-100 dark:bg-gray-700 px-2 py-1 rounded">services:read</code>
</td>
<td className="py-3 px-4 text-gray-600 dark:text-gray-300">View services and pricing</td>
</tr>
<tr>
<td className="py-3 px-4">
<code className="text-xs bg-gray-100 dark:bg-gray-700 px-2 py-1 rounded">resources:read</code>
</td>
<td className="py-3 px-4 text-gray-600 dark:text-gray-300">View resources and staff</td>
</tr>
<tr>
<td className="py-3 px-4">
<code className="text-xs bg-gray-100 dark:bg-gray-700 px-2 py-1 rounded">availability:read</code>
</td>
<td className="py-3 px-4 text-gray-600 dark:text-gray-300">Check time slot availability</td>
</tr>
<tr>
<td className="py-3 px-4">
<code className="text-xs bg-gray-100 dark:bg-gray-700 px-2 py-1 rounded">bookings:read</code>
</td>
<td className="py-3 px-4 text-gray-600 dark:text-gray-300">View appointments</td>
</tr>
<tr>
<td className="py-3 px-4">
<code className="text-xs bg-gray-100 dark:bg-gray-700 px-2 py-1 rounded">bookings:write</code>
</td>
<td className="py-3 px-4 text-gray-600 dark:text-gray-300">Create, update, cancel appointments</td>
</tr>
<tr>
<td className="py-3 px-4">
<code className="text-xs bg-gray-100 dark:bg-gray-700 px-2 py-1 rounded">customers:read</code>
</td>
<td className="py-3 px-4 text-gray-600 dark:text-gray-300">View customer information</td>
</tr>
<tr>
<td className="py-3 px-4">
<code className="text-xs bg-gray-100 dark:bg-gray-700 px-2 py-1 rounded">customers:write</code>
</td>
<td className="py-3 px-4 text-gray-600 dark:text-gray-300">Create and update customers</td>
</tr>
<tr>
<td className="py-3 px-4">
<code className="text-xs bg-gray-100 dark:bg-gray-700 px-2 py-1 rounded">business:read</code>
</td>
<td className="py-3 px-4 text-gray-600 dark:text-gray-300">View business information</td>
</tr>
<tr>
<td className="py-3 px-4">
<code className="text-xs bg-gray-100 dark:bg-gray-700 px-2 py-1 rounded">webhooks:manage</code>
</td>
<td className="py-3 px-4 text-gray-600 dark:text-gray-300">Manage webhook subscriptions</td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
{/* Rate Limiting Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Zap size={20} className="text-brand-500" />
Rate Limiting
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<p className="text-gray-600 dark:text-gray-300 mb-4">
API requests are rate-limited to ensure fair usage and platform stability:
</p>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
<div className="flex items-start gap-3 p-4 bg-gray-50 dark:bg-gray-700/50 rounded-lg">
<Zap size={20} className="text-blue-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Global Limit</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">1,000 requests per hour</p>
</div>
</div>
<div className="flex items-start gap-3 p-4 bg-gray-50 dark:bg-gray-700/50 rounded-lg">
<Zap size={20} className="text-orange-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Burst Limit</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">100 requests per minute</p>
</div>
</div>
</div>
<div className="bg-gray-50 dark:bg-gray-700/50 rounded-lg p-4">
<h4 className="font-medium text-gray-900 dark:text-white mb-2">Response Headers</h4>
<div className="space-y-1 text-sm font-mono text-gray-600 dark:text-gray-300">
<div><code>X-RateLimit-Limit</code> - Maximum requests allowed</div>
<div><code>X-RateLimit-Remaining</code> - Requests remaining in window</div>
<div><code>X-RateLimit-Reset</code> - Unix timestamp when limit resets</div>
</div>
</div>
</div>
</section>
{/* Error Responses Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<AlertCircle size={20} className="text-brand-500" />
Error Responses
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<p className="text-gray-600 dark:text-gray-300 mb-4">
All errors follow a consistent JSON format:
</p>
<div className="bg-gray-900 dark:bg-black rounded-lg p-4 overflow-x-auto mb-4">
<pre className="text-sm text-gray-100 font-mono">
{`{
"error": "validation_error",
"message": "Invalid request data",
"details": {
"start_time": ["This field is required."],
"service_id": ["Invalid service ID."]
}
}`}
</pre>
</div>
<h4 className="font-medium text-gray-900 dark:text-white mb-3">HTTP Status Codes</h4>
<div className="overflow-x-auto">
<table className="w-full text-sm">
<thead>
<tr className="border-b border-gray-200 dark:border-gray-700">
<th className="text-left py-3 px-4 font-medium text-gray-900 dark:text-white">Code</th>
<th className="text-left py-3 px-4 font-medium text-gray-900 dark:text-white">Status</th>
<th className="text-left py-3 px-4 font-medium text-gray-900 dark:text-white">Description</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-200 dark:divide-gray-700">
<tr>
<td className="py-3 px-4"><code className="text-green-600 dark:text-green-400">200</code></td>
<td className="py-3 px-4 text-gray-900 dark:text-white">OK</td>
<td className="py-3 px-4 text-gray-600 dark:text-gray-300">Request succeeded</td>
</tr>
<tr>
<td className="py-3 px-4"><code className="text-green-600 dark:text-green-400">201</code></td>
<td className="py-3 px-4 text-gray-900 dark:text-white">Created</td>
<td className="py-3 px-4 text-gray-600 dark:text-gray-300">Resource created successfully</td>
</tr>
<tr>
<td className="py-3 px-4"><code className="text-red-600 dark:text-red-400">400</code></td>
<td className="py-3 px-4 text-gray-900 dark:text-white">Bad Request</td>
<td className="py-3 px-4 text-gray-600 dark:text-gray-300">Invalid request data</td>
</tr>
<tr>
<td className="py-3 px-4"><code className="text-red-600 dark:text-red-400">401</code></td>
<td className="py-3 px-4 text-gray-900 dark:text-white">Unauthorized</td>
<td className="py-3 px-4 text-gray-600 dark:text-gray-300">Missing or invalid token</td>
</tr>
<tr>
<td className="py-3 px-4"><code className="text-red-600 dark:text-red-400">403</code></td>
<td className="py-3 px-4 text-gray-900 dark:text-white">Forbidden</td>
<td className="py-3 px-4 text-gray-600 dark:text-gray-300">Insufficient scope permissions</td>
</tr>
<tr>
<td className="py-3 px-4"><code className="text-red-600 dark:text-red-400">404</code></td>
<td className="py-3 px-4 text-gray-900 dark:text-white">Not Found</td>
<td className="py-3 px-4 text-gray-600 dark:text-gray-300">Resource does not exist</td>
</tr>
<tr>
<td className="py-3 px-4"><code className="text-red-600 dark:text-red-400">409</code></td>
<td className="py-3 px-4 text-gray-900 dark:text-white">Conflict</td>
<td className="py-3 px-4 text-gray-600 dark:text-gray-300">Resource conflict (e.g., double booking)</td>
</tr>
<tr>
<td className="py-3 px-4"><code className="text-red-600 dark:text-red-400">429</code></td>
<td className="py-3 px-4 text-gray-900 dark:text-white">Too Many Requests</td>
<td className="py-3 px-4 text-gray-600 dark:text-gray-300">Rate limit exceeded</td>
</tr>
<tr>
<td className="py-3 px-4"><code className="text-red-600 dark:text-red-400">500</code></td>
<td className="py-3 px-4 text-gray-900 dark:text-white">Internal Server Error</td>
<td className="py-3 px-4 text-gray-600 dark:text-gray-300">Server error (contact support)</td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
{/* Sandbox Mode Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Settings size={20} className="text-brand-500" />
Sandbox Mode
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<p className="text-gray-600 dark:text-gray-300 mb-4">
Test your integration safely without affecting production data:
</p>
<ul className="space-y-3 mb-4">
<li className="flex items-start gap-3">
<CheckCircle size={18} className="text-green-500 mt-0.5" />
<div>
<p className="text-gray-900 dark:text-white font-medium">Test Tokens</p>
<p className="text-sm text-gray-600 dark:text-gray-300">
Tokens prefixed with <code className="bg-gray-100 dark:bg-gray-700 px-1 rounded text-xs">ss_test_</code> work with sandbox data only
</p>
</div>
</li>
<li className="flex items-start gap-3">
<CheckCircle size={18} className="text-green-500 mt-0.5" />
<div>
<p className="text-gray-900 dark:text-white font-medium">Safe Testing</p>
<p className="text-sm text-gray-600 dark:text-gray-300">
Create, update, and delete test appointments without affecting real bookings
</p>
</div>
</li>
<li className="flex items-start gap-3">
<CheckCircle size={18} className="text-green-500 mt-0.5" />
<div>
<p className="text-gray-900 dark:text-white font-medium">Easy Toggle</p>
<p className="text-sm text-gray-600 dark:text-gray-300">
Switch between test and live modes in Business Settings API
</p>
</div>
</li>
</ul>
<div className="bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 rounded-lg p-4">
<div className="flex items-start gap-2">
<AlertCircle size={18} className="text-yellow-600 dark:text-yellow-400 mt-0.5" />
<div>
<p className="text-sm text-yellow-800 dark:text-yellow-300">
<strong>Tip:</strong> Always test with sandbox tokens before using production tokens in your application.
</p>
</div>
</div>
</div>
</div>
</section>
{/* Quick Links Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Book size={20} className="text-brand-500" />
API Endpoints
</h2>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<Link
to="/dashboard/help/api/appointments"
className="group bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6 hover:border-brand-500 dark:hover:border-brand-500 transition-colors"
>
<div className="flex items-start gap-3 mb-3">
<div className="w-10 h-10 rounded-lg bg-blue-100 dark:bg-blue-900/30 flex items-center justify-center flex-shrink-0">
<Calendar size={20} className="text-blue-600 dark:text-blue-400" />
</div>
<div>
<h4 className="font-semibold text-gray-900 dark:text-white group-hover:text-brand-600 dark:group-hover:text-brand-400 mb-1">
Appointments API
</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
Create, manage, and query appointments
</p>
</div>
</div>
<div className="flex items-center justify-end text-brand-600 dark:text-brand-400 text-sm font-medium">
View Docs
<ChevronRight size={16} className="ml-1" />
</div>
</Link>
<Link
to="/dashboard/help/api/services"
className="group bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6 hover:border-brand-500 dark:hover:border-brand-500 transition-colors"
>
<div className="flex items-start gap-3 mb-3">
<div className="w-10 h-10 rounded-lg bg-green-100 dark:bg-green-900/30 flex items-center justify-center flex-shrink-0">
<Settings size={20} className="text-green-600 dark:text-green-400" />
</div>
<div>
<h4 className="font-semibold text-gray-900 dark:text-white group-hover:text-brand-600 dark:group-hover:text-brand-400 mb-1">
Services API
</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
Access service catalog and pricing
</p>
</div>
</div>
<div className="flex items-center justify-end text-brand-600 dark:text-brand-400 text-sm font-medium">
View Docs
<ChevronRight size={16} className="ml-1" />
</div>
</Link>
<Link
to="/dashboard/help/api/resources"
className="group bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6 hover:border-brand-500 dark:hover:border-brand-500 transition-colors"
>
<div className="flex items-start gap-3 mb-3">
<div className="w-10 h-10 rounded-lg bg-purple-100 dark:bg-purple-900/30 flex items-center justify-center flex-shrink-0">
<Users size={20} className="text-purple-600 dark:text-purple-400" />
</div>
<div>
<h4 className="font-semibold text-gray-900 dark:text-white group-hover:text-brand-600 dark:group-hover:text-brand-400 mb-1">
Resources API
</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
Staff, rooms, and equipment data
</p>
</div>
</div>
<div className="flex items-center justify-end text-brand-600 dark:text-brand-400 text-sm font-medium">
View Docs
<ChevronRight size={16} className="ml-1" />
</div>
</Link>
<Link
to="/dashboard/help/api/customers"
className="group bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6 hover:border-brand-500 dark:hover:border-brand-500 transition-colors"
>
<div className="flex items-start gap-3 mb-3">
<div className="w-10 h-10 rounded-lg bg-orange-100 dark:bg-orange-900/30 flex items-center justify-center flex-shrink-0">
<Users size={20} className="text-orange-600 dark:text-orange-400" />
</div>
<div>
<h4 className="font-semibold text-gray-900 dark:text-white group-hover:text-brand-600 dark:group-hover:text-brand-400 mb-1">
Customers API
</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
Customer profiles and contact info
</p>
</div>
</div>
<div className="flex items-center justify-end text-brand-600 dark:text-brand-400 text-sm font-medium">
View Docs
<ChevronRight size={16} className="ml-1" />
</div>
</Link>
<Link
to="/dashboard/help/api/webhooks"
className="group bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6 hover:border-brand-500 dark:hover:border-brand-500 transition-colors"
>
<div className="flex items-start gap-3 mb-3">
<div className="w-10 h-10 rounded-lg bg-pink-100 dark:bg-pink-900/30 flex items-center justify-center flex-shrink-0">
<Webhook size={20} className="text-pink-600 dark:text-pink-400" />
</div>
<div>
<h4 className="font-semibold text-gray-900 dark:text-white group-hover:text-brand-600 dark:group-hover:text-brand-400 mb-1">
Webhooks
</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
Real-time event notifications
</p>
</div>
</div>
<div className="flex items-center justify-end text-brand-600 dark:text-brand-400 text-sm font-medium">
View Docs
<ChevronRight size={16} className="ml-1" />
</div>
</Link>
</div>
</section>
{/* Need More Help */}
<section className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6 text-center">
<HelpCircle size={32} className="mx-auto text-brand-500 mb-3" />
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-2">
Need More Help?
</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Our support team is ready to help with API integration questions.
</p>
<button
onClick={() => navigate('/dashboard/tickets')}
className="px-6 py-2 bg-brand-600 text-white rounded-lg hover:bg-brand-700 transition-colors"
>
Contact Support
</button>
</section>
</div>
);
};
export default HelpApiOverview;

View File

@@ -0,0 +1,337 @@
/**
* Help API Resources Page
*
* User-friendly help documentation for the Resources API.
*/
import React from 'react';
import { useTranslation } from 'react-i18next';
import { useNavigate, Link } from 'react-router-dom';
import {
ArrowLeft,
Users,
User,
Building,
Wrench,
Code,
BookOpen,
HelpCircle,
CheckCircle,
ChevronRight,
} from 'lucide-react';
const HelpApiResources: React.FC = () => {
const { t } = useTranslation();
const navigate = useNavigate();
return (
<div className="max-w-4xl mx-auto py-8 px-4">
{/* Back Button */}
<button
onClick={() => navigate(-1)}
className="flex items-center gap-2 text-brand-600 hover:text-brand-700 dark:text-brand-400 mb-6"
>
<ArrowLeft size={20} />
{t('common.back', 'Back')}
</button>
{/* Header */}
<div className="mb-8">
<div className="flex items-center gap-3 mb-4">
<div className="w-12 h-12 rounded-xl bg-brand-100 dark:bg-brand-900/30 flex items-center justify-center">
<Users size={24} className="text-brand-600 dark:text-brand-400" />
</div>
<div>
<h1 className="text-3xl font-bold text-gray-900 dark:text-white">
Resources API
</h1>
<p className="text-gray-500 dark:text-gray-400">
Access bookable resources via the public API
</p>
</div>
</div>
</div>
{/* Overview Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Users size={20} className="text-brand-500" />
Overview
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<p className="text-gray-600 dark:text-gray-300 mb-4">
The Resources API provides read-only access to your bookable resources including staff members,
rooms, and equipment. Use this API to list available resources and retrieve their details.
</p>
<div className="flex items-start gap-3 p-4 bg-blue-50 dark:bg-blue-900/20 rounded-lg border border-blue-200 dark:border-blue-800">
<CheckCircle size={20} className="text-blue-600 dark:text-blue-400 mt-0.5" />
<div>
<p className="text-sm text-blue-900 dark:text-blue-100">
<strong>Required OAuth Scope:</strong> <code className="px-1.5 py-0.5 bg-blue-100 dark:bg-blue-900/40 rounded">resources:read</code>
</p>
<p className="text-sm text-blue-700 dark:text-blue-300 mt-1">
Resources are read-only via the public API. To create or modify resources, use the main dashboard.
</p>
</div>
</div>
</div>
</section>
{/* Endpoints Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Code size={20} className="text-brand-500" />
Endpoints
</h2>
{/* List Resources */}
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6 mb-4">
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-3 flex items-center gap-2">
<Users size={18} className="text-green-500" />
List Resources
</h3>
<div className="bg-gray-50 dark:bg-gray-900 rounded-lg p-4 mb-4 font-mono text-sm">
<span className="text-green-600 dark:text-green-400 font-semibold">GET</span>{' '}
<span className="text-gray-900 dark:text-gray-100">/api/v1/resources/</span>
</div>
<p className="text-gray-600 dark:text-gray-300 mb-3">
Returns a list of all active resources in your account.
</p>
<div className="mt-4">
<h4 className="font-medium text-gray-900 dark:text-white mb-2">Query Parameters</h4>
<div className="overflow-x-auto">
<table className="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
<thead>
<tr className="bg-gray-50 dark:bg-gray-900">
<th className="px-4 py-2 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Parameter</th>
<th className="px-4 py-2 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Type</th>
<th className="px-4 py-2 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Description</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-200 dark:divide-gray-700">
<tr>
<td className="px-4 py-2 text-sm font-mono text-gray-900 dark:text-gray-100">type</td>
<td className="px-4 py-2 text-sm text-gray-600 dark:text-gray-400">string</td>
<td className="px-4 py-2 text-sm text-gray-600 dark:text-gray-400">Filter by resource type (STAFF, ROOM, EQUIPMENT)</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
{/* Get Resource */}
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-3 flex items-center gap-2">
<User size={18} className="text-blue-500" />
Get Resource
</h3>
<div className="bg-gray-50 dark:bg-gray-900 rounded-lg p-4 mb-4 font-mono text-sm">
<span className="text-green-600 dark:text-green-400 font-semibold">GET</span>{' '}
<span className="text-gray-900 dark:text-gray-100">/api/v1/resources/</span>
<span className="text-blue-600 dark:text-blue-400">{'{id}'}</span>
<span className="text-gray-900 dark:text-gray-100">/</span>
</div>
<p className="text-gray-600 dark:text-gray-300">
Retrieve details for a specific resource by its ID.
</p>
</div>
</section>
{/* Resource Object Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<BookOpen size={20} className="text-brand-500" />
Resource Object
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<div className="overflow-x-auto">
<table className="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
<thead>
<tr className="bg-gray-50 dark:bg-gray-900">
<th className="px-4 py-2 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Field</th>
<th className="px-4 py-2 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Type</th>
<th className="px-4 py-2 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase">Description</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-200 dark:divide-gray-700">
<tr>
<td className="px-4 py-2 text-sm font-mono text-gray-900 dark:text-gray-100">id</td>
<td className="px-4 py-2 text-sm text-gray-600 dark:text-gray-400">UUID</td>
<td className="px-4 py-2 text-sm text-gray-600 dark:text-gray-400">Unique identifier</td>
</tr>
<tr>
<td className="px-4 py-2 text-sm font-mono text-gray-900 dark:text-gray-100">name</td>
<td className="px-4 py-2 text-sm text-gray-600 dark:text-gray-400">string</td>
<td className="px-4 py-2 text-sm text-gray-600 dark:text-gray-400">Resource name</td>
</tr>
<tr>
<td className="px-4 py-2 text-sm font-mono text-gray-900 dark:text-gray-100">description</td>
<td className="px-4 py-2 text-sm text-gray-600 dark:text-gray-400">string (nullable)</td>
<td className="px-4 py-2 text-sm text-gray-600 dark:text-gray-400">Resource description</td>
</tr>
<tr>
<td className="px-4 py-2 text-sm font-mono text-gray-900 dark:text-gray-100">resource_type</td>
<td className="px-4 py-2 text-sm text-gray-600 dark:text-gray-400">object</td>
<td className="px-4 py-2 text-sm text-gray-600 dark:text-gray-400">Resource type object with id, name, category</td>
</tr>
<tr>
<td className="px-4 py-2 text-sm font-mono text-gray-900 dark:text-gray-100">photo_url</td>
<td className="px-4 py-2 text-sm text-gray-600 dark:text-gray-400">string (nullable)</td>
<td className="px-4 py-2 text-sm text-gray-600 dark:text-gray-400">URL to resource photo</td>
</tr>
<tr>
<td className="px-4 py-2 text-sm font-mono text-gray-900 dark:text-gray-100">is_active</td>
<td className="px-4 py-2 text-sm text-gray-600 dark:text-gray-400">boolean</td>
<td className="px-4 py-2 text-sm text-gray-600 dark:text-gray-400">Whether resource is active</td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
{/* Resource Types Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Users size={20} className="text-brand-500" />
Resource Types
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<div className="flex items-start gap-3 p-4 bg-gray-50 dark:bg-gray-700/50 rounded-lg">
<User size={20} className="text-blue-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">STAFF</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Team members who provide services</p>
</div>
</div>
<div className="flex items-start gap-3 p-4 bg-gray-50 dark:bg-gray-700/50 rounded-lg">
<Building size={20} className="text-green-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">ROOM</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Physical spaces for appointments</p>
</div>
</div>
<div className="flex items-start gap-3 p-4 bg-gray-50 dark:bg-gray-700/50 rounded-lg">
<Wrench size={20} className="text-purple-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">EQUIPMENT</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Tools or equipment needed for services</p>
</div>
</div>
</div>
</div>
</section>
{/* Example Response Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Code size={20} className="text-brand-500" />
Example Response
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<pre className="bg-gray-50 dark:bg-gray-900 rounded-lg p-4 overflow-x-auto text-sm">
<code className="text-gray-900 dark:text-gray-100">{`{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "John Smith",
"description": "Senior Stylist with 10 years experience",
"resource_type": {
"id": "660e8400-e29b-41d4-a716-446655440000",
"name": "Stylist",
"category": "STAFF"
},
"photo_url": "https://example.com/photos/john-smith.jpg",
"is_active": true
}`}</code>
</pre>
</div>
</section>
{/* Code Examples Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Code size={20} className="text-brand-500" />
Code Examples
</h2>
{/* List All Resources */}
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6 mb-4">
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-3">
List All Resources
</h3>
<pre className="bg-gray-50 dark:bg-gray-900 rounded-lg p-4 overflow-x-auto text-sm">
<code className="text-gray-900 dark:text-gray-100">{`curl -X GET "https://yourbusiness.smoothschedule.com/api/v1/resources/" \\
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"`}</code>
</pre>
</div>
{/* Filter by Type */}
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6 mb-4">
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-3">
Filter by Type
</h3>
<pre className="bg-gray-50 dark:bg-gray-900 rounded-lg p-4 overflow-x-auto text-sm">
<code className="text-gray-900 dark:text-gray-100">{`curl -X GET "https://yourbusiness.smoothschedule.com/api/v1/resources/?type=STAFF" \\
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"`}</code>
</pre>
</div>
{/* Get Specific Resource */}
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-3">
Get Specific Resource
</h3>
<pre className="bg-gray-50 dark:bg-gray-900 rounded-lg p-4 overflow-x-auto text-sm">
<code className="text-gray-900 dark:text-gray-100">{`curl -X GET "https://yourbusiness.smoothschedule.com/api/v1/resources/550e8400-e29b-41d4-a716-446655440000/" \\
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"`}</code>
</pre>
</div>
</section>
{/* Back to API Docs */}
<section className="mb-10">
<div className="bg-gradient-to-r from-brand-50 to-purple-50 dark:from-brand-900/20 dark:to-purple-900/20 rounded-xl border border-brand-200 dark:border-brand-800 p-6">
<div className="flex items-start gap-4">
<BookOpen size={24} className="text-brand-600 dark:text-brand-400 mt-1" />
<div className="flex-1">
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-2">
Explore More API Endpoints
</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
The Resources API is just one part of our comprehensive public API.
View the full documentation to learn about appointments, customers, services, and more.
</p>
<Link
to="/dashboard/help/api"
className="inline-flex items-center gap-2 px-4 py-2 bg-brand-600 text-white rounded-lg hover:bg-brand-700 transition-colors"
>
View Full API Docs
<ChevronRight size={16} />
</Link>
</div>
</div>
</div>
</section>
{/* Need More Help */}
<section className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6 text-center">
<HelpCircle size={32} className="mx-auto text-brand-500 mb-3" />
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-2">
Need More Help?
</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Our support team is ready to help with any questions about the API.
</p>
<button
onClick={() => navigate('/dashboard/tickets')}
className="px-6 py-2 bg-brand-600 text-white rounded-lg hover:bg-brand-700 transition-colors"
>
Contact Support
</button>
</section>
</div>
);
};
export default HelpApiResources;

View File

@@ -0,0 +1,307 @@
/**
* Help API Services Page
*
* User-friendly help documentation for the Services API.
*/
import React from 'react';
import { useTranslation } from 'react-i18next';
import { useNavigate } from 'react-router-dom';
import {
ArrowLeft,
Briefcase,
DollarSign,
Clock,
Image,
Code,
HelpCircle,
} from 'lucide-react';
const HelpApiServices: React.FC = () => {
const { t } = useTranslation();
const navigate = useNavigate();
return (
<div className="max-w-4xl mx-auto py-8 px-4">
{/* Back Button */}
<button
onClick={() => navigate(-1)}
className="flex items-center gap-2 text-brand-600 hover:text-brand-700 dark:text-brand-400 mb-6"
>
<ArrowLeft size={20} />
{t('common.back', 'Back')}
</button>
{/* Header */}
<div className="mb-8">
<div className="flex items-center gap-3 mb-4">
<div className="w-12 h-12 rounded-xl bg-brand-100 dark:bg-brand-900/30 flex items-center justify-center">
<Briefcase size={24} className="text-brand-600 dark:text-brand-400" />
</div>
<div>
<h1 className="text-3xl font-bold text-gray-900 dark:text-white">
Services API
</h1>
<p className="text-gray-500 dark:text-gray-400">
Access your service catalog via API
</p>
</div>
</div>
</div>
{/* Overview Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Briefcase size={20} className="text-brand-500" />
Overview
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<div className="space-y-4">
<p className="text-gray-600 dark:text-gray-300">
Access your service catalog via the public API to integrate scheduling capabilities into your own applications, websites, or mobile apps.
</p>
<div className="bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-lg p-4">
<p className="text-sm text-blue-900 dark:text-blue-300">
<strong>Required scope:</strong> <code className="px-2 py-1 bg-blue-100 dark:bg-blue-800/50 rounded">services:read</code>
</p>
</div>
<div className="bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800 rounded-lg p-4">
<p className="text-sm text-amber-900 dark:text-amber-300">
<strong>Note:</strong> Services are read-only via the public API. Use the dashboard to create, update, or delete services.
</p>
</div>
</div>
</div>
</section>
{/* Endpoints Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Code size={20} className="text-brand-500" />
Endpoints
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6 space-y-6">
{/* List Services */}
<div>
<div className="flex items-center gap-2 mb-3">
<span className="px-2 py-1 bg-green-100 dark:bg-green-900/30 text-green-800 dark:text-green-300 text-xs font-mono rounded">
GET
</span>
<code className="text-sm text-gray-900 dark:text-gray-100 font-mono">
/api/v1/services/
</code>
</div>
<p className="text-sm text-gray-600 dark:text-gray-300 mb-2">
Returns all active services ordered by <code className="text-xs px-1 bg-gray-100 dark:bg-gray-700 rounded">display_order</code>.
</p>
</div>
{/* Get Service */}
<div>
<div className="flex items-center gap-2 mb-3">
<span className="px-2 py-1 bg-green-100 dark:bg-green-900/30 text-green-800 dark:text-green-300 text-xs font-mono rounded">
GET
</span>
<code className="text-sm text-gray-900 dark:text-gray-100 font-mono">
/api/v1/services/{'{id}'}/
</code>
</div>
<p className="text-sm text-gray-600 dark:text-gray-300 mb-2">
Returns detailed information for a specific service by UUID.
</p>
</div>
</div>
</section>
{/* Service Object Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Briefcase size={20} className="text-brand-500" />
Service Object
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 overflow-hidden">
<div className="overflow-x-auto">
<table className="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
<thead className="bg-gray-50 dark:bg-gray-700/50">
<tr>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
Field
</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
Type
</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
Description
</th>
</tr>
</thead>
<tbody className="bg-white dark:bg-gray-800 divide-y divide-gray-200 dark:divide-gray-700">
<tr>
<td className="px-6 py-4 whitespace-nowrap">
<code className="text-sm font-mono text-purple-600 dark:text-purple-400">id</code>
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-600 dark:text-gray-300">
UUID
</td>
<td className="px-6 py-4 text-sm text-gray-600 dark:text-gray-300">
Unique identifier for the service
</td>
</tr>
<tr>
<td className="px-6 py-4 whitespace-nowrap">
<code className="text-sm font-mono text-purple-600 dark:text-purple-400">name</code>
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-600 dark:text-gray-300">
string
</td>
<td className="px-6 py-4 text-sm text-gray-600 dark:text-gray-300">
Service name (e.g., "Haircut", "Oil Change")
</td>
</tr>
<tr>
<td className="px-6 py-4 whitespace-nowrap">
<code className="text-sm font-mono text-purple-600 dark:text-purple-400">description</code>
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-600 dark:text-gray-300">
string | null
</td>
<td className="px-6 py-4 text-sm text-gray-600 dark:text-gray-300">
Optional detailed description of the service
</td>
</tr>
<tr>
<td className="px-6 py-4 whitespace-nowrap">
<div className="flex items-center gap-2">
<Clock size={14} className="text-blue-500" />
<code className="text-sm font-mono text-purple-600 dark:text-purple-400">duration</code>
</div>
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-600 dark:text-gray-300">
integer
</td>
<td className="px-6 py-4 text-sm text-gray-600 dark:text-gray-300">
Duration in minutes (e.g., 30, 60, 90)
</td>
</tr>
<tr>
<td className="px-6 py-4 whitespace-nowrap">
<div className="flex items-center gap-2">
<DollarSign size={14} className="text-green-500" />
<code className="text-sm font-mono text-purple-600 dark:text-purple-400">price</code>
</div>
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-600 dark:text-gray-300">
decimal | null
</td>
<td className="px-6 py-4 text-sm text-gray-600 dark:text-gray-300">
Price in dollars (null for variable pricing)
</td>
</tr>
<tr>
<td className="px-6 py-4 whitespace-nowrap">
<div className="flex items-center gap-2">
<Image size={14} className="text-purple-500" />
<code className="text-sm font-mono text-purple-600 dark:text-purple-400">photos</code>
</div>
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-600 dark:text-gray-300">
array
</td>
<td className="px-6 py-4 text-sm text-gray-600 dark:text-gray-300">
Array of photo URLs for the service
</td>
</tr>
<tr>
<td className="px-6 py-4 whitespace-nowrap">
<code className="text-sm font-mono text-purple-600 dark:text-purple-400">is_active</code>
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-600 dark:text-gray-300">
boolean
</td>
<td className="px-6 py-4 text-sm text-gray-600 dark:text-gray-300">
Whether the service is currently active
</td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
{/* Example Response Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Code size={20} className="text-brand-500" />
Example Response
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<pre className="bg-gray-900 dark:bg-black text-gray-100 p-4 rounded-lg overflow-x-auto text-sm font-mono">
{`{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Haircut",
"description": "Professional haircut service",
"duration": 30,
"price": "45.00",
"photos": [
"https://smoothschedule.nyc3.digitaloceanspaces.com/..."
],
"is_active": true
}`}
</pre>
</div>
</section>
{/* Code Examples Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Code size={20} className="text-brand-500" />
Code Examples
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6 space-y-6">
{/* List Services */}
<div>
<h3 className="text-sm font-semibold text-gray-900 dark:text-white mb-3">
List All Services
</h3>
<pre className="bg-gray-900 dark:bg-black text-gray-100 p-4 rounded-lg overflow-x-auto text-sm font-mono">
{`curl -X GET "https://yourbusiness.smoothschedule.com/api/v1/services/" \\
-H "Authorization: Bearer YOUR_API_KEY" \\
-H "Content-Type: application/json"`}
</pre>
</div>
{/* Get Service */}
<div>
<h3 className="text-sm font-semibold text-gray-900 dark:text-white mb-3">
Get Specific Service
</h3>
<pre className="bg-gray-900 dark:bg-black text-gray-100 p-4 rounded-lg overflow-x-auto text-sm font-mono">
{`curl -X GET "https://yourbusiness.smoothschedule.com/api/v1/services/550e8400-e29b-41d4-a716-446655440000/" \\
-H "Authorization: Bearer YOUR_API_KEY" \\
-H "Content-Type: application/json"`}
</pre>
</div>
</div>
</section>
{/* Need More Help */}
<section className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6 text-center">
<HelpCircle size={32} className="mx-auto text-brand-500 mb-3" />
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-2">
Need More Help?
</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Our support team is ready to help with any questions about the Services API.
</p>
<button
onClick={() => navigate('/dashboard/tickets')}
className="px-6 py-2 bg-brand-600 text-white rounded-lg hover:bg-brand-700 transition-colors"
>
Contact Support
</button>
</section>
</div>
);
};
export default HelpApiServices;

View File

@@ -0,0 +1,513 @@
/**
* Help API Webhooks Page
*
* User-friendly help documentation for Webhooks API.
*/
import React from 'react';
import { useTranslation } from 'react-i18next';
import { useNavigate } from 'react-router-dom';
import {
ArrowLeft,
Link as LinkIcon,
Bell,
Shield,
RefreshCw,
CheckCircle,
HelpCircle,
Code,
List,
Plus,
Edit,
Trash2,
Send,
Clock,
} from 'lucide-react';
const HelpApiWebhooks: React.FC = () => {
const { t } = useTranslation();
const navigate = useNavigate();
return (
<div className="max-w-4xl mx-auto py-8 px-4">
{/* Back Button */}
<button
onClick={() => navigate(-1)}
className="flex items-center gap-2 text-brand-600 hover:text-brand-700 dark:text-brand-400 mb-6"
>
<ArrowLeft size={20} />
{t('common.back', 'Back')}
</button>
{/* Header */}
<div className="mb-8">
<div className="flex items-center gap-3 mb-4">
<div className="w-12 h-12 rounded-xl bg-brand-100 dark:bg-brand-900/30 flex items-center justify-center">
<LinkIcon size={24} className="text-brand-600 dark:text-brand-400" />
</div>
<div>
<h1 className="text-3xl font-bold text-gray-900 dark:text-white">
Webhooks API
</h1>
<p className="text-gray-500 dark:text-gray-400">
Receive real-time notifications when events occur in your account
</p>
</div>
</div>
</div>
{/* Overview Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Bell size={20} className="text-brand-500" />
Overview
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<p className="text-gray-600 dark:text-gray-300 mb-4">
Webhooks allow your application to receive real-time notifications when events occur in your SmoothSchedule account.
Instead of polling the API, webhooks POST JSON payloads to your specified endpoint whenever subscribed events happen.
</p>
<div className="space-y-2 text-sm text-gray-600 dark:text-gray-300">
<div className="flex items-start gap-2">
<CheckCircle size={16} className="text-green-500 mt-0.5" />
<span><strong>Required scope:</strong> <code className="px-1 py-0.5 bg-gray-100 dark:bg-gray-700 rounded">webhooks:manage</code></span>
</div>
<div className="flex items-start gap-2">
<CheckCircle size={16} className="text-green-500 mt-0.5" />
<span><strong>Format:</strong> JSON payloads POSTed to your endpoint</span>
</div>
<div className="flex items-start gap-2">
<CheckCircle size={16} className="text-green-500 mt-0.5" />
<span><strong>Security:</strong> HMAC-SHA256 signature verification</span>
</div>
</div>
</div>
</section>
{/* API Endpoints */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Code size={20} className="text-brand-500" />
API Endpoints
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6 space-y-6">
{/* List Subscriptions */}
<div className="border-b border-gray-200 dark:border-gray-700 pb-6 last:border-0 last:pb-0">
<div className="flex items-start gap-3 mb-3">
<List size={18} className="text-blue-500 mt-1" />
<div className="flex-1">
<h3 className="font-semibold text-gray-900 dark:text-white">List Subscriptions</h3>
<code className="text-sm text-gray-600 dark:text-gray-400">GET /api/v1/webhooks/</code>
<p className="text-sm text-gray-500 dark:text-gray-400 mt-2">
Returns a list of all webhook subscriptions for your account.
</p>
</div>
</div>
</div>
{/* Create Subscription */}
<div className="border-b border-gray-200 dark:border-gray-700 pb-6 last:border-0 last:pb-0">
<div className="flex items-start gap-3 mb-3">
<Plus size={18} className="text-green-500 mt-1" />
<div className="flex-1">
<h3 className="font-semibold text-gray-900 dark:text-white">Create Subscription</h3>
<code className="text-sm text-gray-600 dark:text-gray-400">POST /api/v1/webhooks/</code>
<p className="text-sm text-gray-500 dark:text-gray-400 mt-2 mb-3">
Create a new webhook subscription. Returns the subscription including a <strong>secret</strong> for signature verification.
</p>
<div className="bg-gray-50 dark:bg-gray-900 rounded-lg p-4 mt-3">
<p className="text-xs text-gray-500 dark:text-gray-400 mb-2">Request Body:</p>
<pre className="text-xs overflow-x-auto">
{`{
"url": "https://example.com/webhooks",
"events": ["appointment.created", "appointment.cancelled"],
"description": "Production webhook endpoint"
}`}
</pre>
</div>
<div className="bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800 rounded-lg p-3 mt-3">
<p className="text-sm text-amber-800 dark:text-amber-200">
<strong>Important:</strong> The <code>secret</code> is only shown once in the response. Store it securely for signature verification.
</p>
</div>
</div>
</div>
</div>
{/* Get Subscription */}
<div className="border-b border-gray-200 dark:border-gray-700 pb-6 last:border-0 last:pb-0">
<div className="flex items-start gap-3 mb-3">
<LinkIcon size={18} className="text-purple-500 mt-1" />
<div className="flex-1">
<h3 className="font-semibold text-gray-900 dark:text-white">Get Subscription</h3>
<code className="text-sm text-gray-600 dark:text-gray-400">GET /api/v1/webhooks/{`{id}`}/</code>
<p className="text-sm text-gray-500 dark:text-gray-400 mt-2">
Retrieve details of a specific webhook subscription.
</p>
</div>
</div>
</div>
{/* Update Subscription */}
<div className="border-b border-gray-200 dark:border-gray-700 pb-6 last:border-0 last:pb-0">
<div className="flex items-start gap-3 mb-3">
<Edit size={18} className="text-orange-500 mt-1" />
<div className="flex-1">
<h3 className="font-semibold text-gray-900 dark:text-white">Update Subscription</h3>
<code className="text-sm text-gray-600 dark:text-gray-400">PATCH /api/v1/webhooks/{`{id}`}/</code>
<p className="text-sm text-gray-500 dark:text-gray-400 mt-2">
Update an existing webhook subscription (URL, events, or description).
</p>
</div>
</div>
</div>
{/* Delete Subscription */}
<div className="border-b border-gray-200 dark:border-gray-700 pb-6 last:border-0 last:pb-0">
<div className="flex items-start gap-3 mb-3">
<Trash2 size={18} className="text-red-500 mt-1" />
<div className="flex-1">
<h3 className="font-semibold text-gray-900 dark:text-white">Delete Subscription</h3>
<code className="text-sm text-gray-600 dark:text-gray-400">DELETE /api/v1/webhooks/{`{id}`}/</code>
<p className="text-sm text-gray-500 dark:text-gray-400 mt-2">
Delete a webhook subscription permanently.
</p>
</div>
</div>
</div>
{/* List Event Types */}
<div className="border-b border-gray-200 dark:border-gray-700 pb-6 last:border-0 last:pb-0">
<div className="flex items-start gap-3 mb-3">
<Bell size={18} className="text-blue-500 mt-1" />
<div className="flex-1">
<h3 className="font-semibold text-gray-900 dark:text-white">List Event Types</h3>
<code className="text-sm text-gray-600 dark:text-gray-400">GET /api/v1/webhooks/events/</code>
<p className="text-sm text-gray-500 dark:text-gray-400 mt-2">
Get a list of all available webhook event types.
</p>
</div>
</div>
</div>
{/* Send Test Webhook */}
<div className="border-b border-gray-200 dark:border-gray-700 pb-6 last:border-0 last:pb-0">
<div className="flex items-start gap-3 mb-3">
<Send size={18} className="text-green-500 mt-1" />
<div className="flex-1">
<h3 className="font-semibold text-gray-900 dark:text-white">Send Test Webhook</h3>
<code className="text-sm text-gray-600 dark:text-gray-400">POST /api/v1/webhooks/{`{id}`}/test/</code>
<p className="text-sm text-gray-500 dark:text-gray-400 mt-2">
Send a test webhook to verify your endpoint is working correctly.
</p>
</div>
</div>
</div>
{/* View Delivery History */}
<div className="border-b border-gray-200 dark:border-gray-700 pb-6 last:border-0 last:pb-0">
<div className="flex items-start gap-3 mb-3">
<Clock size={18} className="text-purple-500 mt-1" />
<div className="flex-1">
<h3 className="font-semibold text-gray-900 dark:text-white">View Delivery History</h3>
<code className="text-sm text-gray-600 dark:text-gray-400">GET /api/v1/webhooks/{`{id}`}/deliveries/</code>
<p className="text-sm text-gray-500 dark:text-gray-400 mt-2">
View delivery history and status for a webhook subscription.
</p>
</div>
</div>
</div>
</div>
</section>
{/* Available Events */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Bell size={20} className="text-brand-500" />
Available Events
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<p className="text-gray-600 dark:text-gray-300 mb-4">
Subscribe to one or more of these events to receive notifications:
</p>
<div className="overflow-x-auto">
<table className="w-full text-sm">
<thead className="bg-gray-50 dark:bg-gray-900 border-b border-gray-200 dark:border-gray-700">
<tr>
<th className="text-left py-3 px-4 font-semibold text-gray-900 dark:text-white">Event</th>
<th className="text-left py-3 px-4 font-semibold text-gray-900 dark:text-white">Description</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-200 dark:divide-gray-700">
<tr>
<td className="py-3 px-4"><code className="text-xs bg-gray-100 dark:bg-gray-900 px-2 py-1 rounded">appointment.created</code></td>
<td className="py-3 px-4 text-gray-600 dark:text-gray-300">Triggered when a new appointment is created</td>
</tr>
<tr>
<td className="py-3 px-4"><code className="text-xs bg-gray-100 dark:bg-gray-900 px-2 py-1 rounded">appointment.updated</code></td>
<td className="py-3 px-4 text-gray-600 dark:text-gray-300">Triggered when an appointment is updated</td>
</tr>
<tr>
<td className="py-3 px-4"><code className="text-xs bg-gray-100 dark:bg-gray-900 px-2 py-1 rounded">appointment.cancelled</code></td>
<td className="py-3 px-4 text-gray-600 dark:text-gray-300">Triggered when an appointment is cancelled</td>
</tr>
<tr>
<td className="py-3 px-4"><code className="text-xs bg-gray-100 dark:bg-gray-900 px-2 py-1 rounded">customer.created</code></td>
<td className="py-3 px-4 text-gray-600 dark:text-gray-300">Triggered when a new customer is created</td>
</tr>
<tr>
<td className="py-3 px-4"><code className="text-xs bg-gray-100 dark:bg-gray-900 px-2 py-1 rounded">customer.updated</code></td>
<td className="py-3 px-4 text-gray-600 dark:text-gray-300">Triggered when customer information is updated</td>
</tr>
<tr>
<td className="py-3 px-4"><code className="text-xs bg-gray-100 dark:bg-gray-900 px-2 py-1 rounded">service.created</code></td>
<td className="py-3 px-4 text-gray-600 dark:text-gray-300">Triggered when a new service is created</td>
</tr>
<tr>
<td className="py-3 px-4"><code className="text-xs bg-gray-100 dark:bg-gray-900 px-2 py-1 rounded">service.updated</code></td>
<td className="py-3 px-4 text-gray-600 dark:text-gray-300">Triggered when a service is updated</td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
{/* Webhook Payload Format */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Code size={20} className="text-brand-500" />
Webhook Payload Format
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<p className="text-gray-600 dark:text-gray-300 mb-4">
All webhook payloads follow this standard format:
</p>
<div className="bg-gray-50 dark:bg-gray-900 rounded-lg p-4">
<pre className="text-xs overflow-x-auto text-gray-700 dark:text-gray-300">
{`{
"event": "appointment.created",
"timestamp": "2024-12-16T10:00:00Z",
"data": {
"id": "123",
"customer": {
"id": "456",
"email": "customer@example.com",
"name": "John Doe"
},
"service": {
"id": "789",
"name": "Haircut",
"duration": 30
},
"start_time": "2024-12-20T14:00:00Z",
"end_time": "2024-12-20T14:30:00Z",
"status": "confirmed"
// ... additional event-specific fields
}
}`}
</pre>
</div>
</div>
</section>
{/* Signature Verification */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Shield size={20} className="text-brand-500" />
Signature Verification
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<p className="text-gray-600 dark:text-gray-300 mb-4">
All webhooks include an <code className="px-1 py-0.5 bg-gray-100 dark:bg-gray-700 rounded">X-Webhook-Signature</code> header
containing an HMAC-SHA256 signature. Verify this signature to ensure the webhook came from SmoothSchedule.
</p>
<div className="space-y-4">
<div>
<h4 className="font-medium text-gray-900 dark:text-white mb-2">Header</h4>
<code className="text-sm bg-gray-100 dark:bg-gray-900 px-3 py-2 rounded block">X-Webhook-Signature: sha256=a1b2c3d4...</code>
</div>
<div>
<h4 className="font-medium text-gray-900 dark:text-white mb-2">Algorithm</h4>
<p className="text-sm text-gray-600 dark:text-gray-300">HMAC-SHA256 of the raw request body using your webhook secret</p>
</div>
<div>
<h4 className="font-medium text-gray-900 dark:text-white mb-2">Python Example</h4>
<div className="bg-gray-50 dark:bg-gray-900 rounded-lg p-4">
<pre className="text-xs overflow-x-auto text-gray-700 dark:text-gray-300">
{`import hmac
import hashlib
def verify_webhook(request, secret):
signature = request.headers.get('X-Webhook-Signature', '')
expected = 'sha256=' + hmac.new(
secret.encode(),
request.body,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected)`}
</pre>
</div>
</div>
<div>
<h4 className="font-medium text-gray-900 dark:text-white mb-2">Node.js Example</h4>
<div className="bg-gray-50 dark:bg-gray-900 rounded-lg p-4">
<pre className="text-xs overflow-x-auto text-gray-700 dark:text-gray-300">
{`const crypto = require('crypto');
function verifyWebhook(request, secret) {
const signature = request.headers['x-webhook-signature'];
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(request.rawBody)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}`}
</pre>
</div>
</div>
</div>
</div>
</section>
{/* Retry Policy */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<RefreshCw size={20} className="text-brand-500" />
Retry Policy
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<p className="text-gray-600 dark:text-gray-300 mb-4">
If your endpoint fails to respond with a 2xx status code, SmoothSchedule will automatically retry delivery:
</p>
<div className="space-y-3 text-sm text-gray-600 dark:text-gray-300">
<div className="flex items-start gap-2">
<CheckCircle size={16} className="text-blue-500 mt-0.5" />
<span><strong>Retry attempts:</strong> 3 automatic retries</span>
</div>
<div className="flex items-start gap-2">
<CheckCircle size={16} className="text-blue-500 mt-0.5" />
<span><strong>Backoff schedule:</strong> 1 minute, 5 minutes, 30 minutes</span>
</div>
<div className="flex items-start gap-2">
<CheckCircle size={16} className="text-blue-500 mt-0.5" />
<span><strong>Auto-disable:</strong> Subscription disabled after 10 consecutive failures</span>
</div>
</div>
<div className="bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800 rounded-lg p-4 mt-4">
<p className="text-sm text-amber-800 dark:text-amber-200">
<strong>Important:</strong> Your endpoint should respond within 5 seconds and return a 2xx status code to acknowledge receipt.
Process the webhook asynchronously if needed.
</p>
</div>
</div>
</section>
{/* Code Examples */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Code size={20} className="text-brand-500" />
Code Examples
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6 space-y-6">
<div>
<h4 className="font-medium text-gray-900 dark:text-white mb-3">Creating a Webhook Subscription</h4>
<div className="bg-gray-50 dark:bg-gray-900 rounded-lg p-4">
<pre className="text-xs overflow-x-auto text-gray-700 dark:text-gray-300">
{`# Using curl
curl -X POST https://api.smoothschedule.com/api/v1/webhooks/ \\
-H "Authorization: Bearer YOUR_API_KEY" \\
-H "Content-Type: application/json" \\
-d '{
"url": "https://example.com/webhooks",
"events": ["appointment.created", "appointment.cancelled"],
"description": "Production webhook endpoint"
}'
# Response (save the secret!)
{
"id": "wh_abc123",
"url": "https://example.com/webhooks",
"events": ["appointment.created", "appointment.cancelled"],
"description": "Production webhook endpoint",
"secret": "whsec_xyz789...", // Only shown once!
"is_active": true,
"created_at": "2024-12-16T10:00:00Z"
}`}
</pre>
</div>
</div>
<div>
<h4 className="font-medium text-gray-900 dark:text-white mb-3">Handling Webhook in Express.js</h4>
<div className="bg-gray-50 dark:bg-gray-900 rounded-lg p-4">
<pre className="text-xs overflow-x-auto text-gray-700 dark:text-gray-300">
{`const express = require('express');
const crypto = require('crypto');
const app = express();
// Important: Use raw body for signature verification
app.post('/webhooks',
express.raw({ type: 'application/json' }),
(req, res) => {
// Verify signature
const signature = req.headers['x-webhook-signature'];
const expected = 'sha256=' + crypto
.createHmac('sha256', process.env.WEBHOOK_SECRET)
.update(req.body)
.digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
return res.status(401).send('Invalid signature');
}
// Parse and process webhook
const payload = JSON.parse(req.body);
console.log('Received event:', payload.event);
// Process asynchronously
processWebhook(payload).catch(console.error);
// Respond immediately
res.status(200).send('OK');
}
);`}
</pre>
</div>
</div>
</div>
</section>
{/* Need More Help */}
<section className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6 text-center">
<HelpCircle size={32} className="mx-auto text-brand-500 mb-3" />
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-2">
Need More Help?
</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Our support team is ready to help with any questions about webhooks.
</p>
<button
onClick={() => navigate('/dashboard/tickets')}
className="px-6 py-2 bg-brand-600 text-white rounded-lg hover:bg-brand-700 transition-colors"
>
Contact Support
</button>
</section>
</div>
);
};
export default HelpApiWebhooks;

View File

@@ -14,7 +14,7 @@ import {
Clock, Eye, Palette, Link2, Mail, Globe, CreditCard, Zap, Search, Filter,
Plus, Edit, Trash2, ArrowUpDown, GripVertical, Image, Save, ExternalLink,
MessageSquare, Tag, UserPlus, Shield, Copy, Layers, Play, Pause, Puzzle,
FileSignature, Send, Download, Link as LinkIcon, CalendarOff,
FileSignature, Send, Download, Link as LinkIcon, CalendarOff, MapPin, Code,
} from 'lucide-react';
interface TocSubItem {
@@ -55,9 +55,11 @@ const HelpComprehensive: React.FC = () => {
{ id: 'customers', label: t('helpComprehensive.toc.customers'), icon: <Users size={16} /> },
{ id: 'staff', label: t('helpComprehensive.toc.staff'), icon: <UserCog size={16} /> },
{ id: 'time-blocks', label: t('helpComprehensive.toc.timeBlocks'), icon: <CalendarOff size={16} /> },
{ id: 'locations', label: 'Locations', icon: <MapPin size={16} /> },
{ id: 'site-builder', label: 'Site Builder', icon: <Layers size={16} /> },
{ id: 'automations', label: 'Automations', icon: <Puzzle size={16} /> },
{ id: 'contracts', label: t('helpComprehensive.toc.contracts'), icon: <FileSignature size={16} /> },
{ id: 'api', label: 'API', icon: <Code size={16} /> },
{
id: 'settings',
label: t('helpComprehensive.toc.settings'),
@@ -70,6 +72,11 @@ const HelpComprehensive: React.FC = () => {
{ label: t('helpComprehensive.toc.apiSettings'), href: '/help/settings/api' },
{ label: t('helpComprehensive.toc.authentication'), href: '/help/settings/auth' },
{ label: t('helpComprehensive.toc.usageQuota'), href: '/help/settings/quota' },
{ label: 'Business Hours', href: '/help/settings/business-hours' },
{ label: 'Email Templates', href: '/help/settings/email-templates' },
{ label: 'Embed Widget', href: '/help/settings/embed-widget' },
{ label: 'Staff Roles', href: '/help/settings/staff-roles' },
{ label: 'SMS & Calling', href: '/help/settings/communication' },
],
},
];
@@ -716,6 +723,58 @@ const HelpComprehensive: React.FC = () => {
</Link>
</section>
{/* ============================================== */}
{/* LOCATIONS */}
{/* ============================================== */}
<section id="locations" className="mb-16 scroll-mt-24">
<div className="flex items-center gap-3 mb-6">
<div className="w-10 h-10 rounded-lg bg-cyan-100 dark:bg-cyan-900/30 flex items-center justify-center">
<MapPin size={20} className="text-cyan-600 dark:text-cyan-400" />
</div>
<h2 className="text-2xl font-bold text-gray-900 dark:text-white">Locations</h2>
</div>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6 mb-6">
<p className="text-gray-600 dark:text-gray-300 mb-4">
Manage multiple business locations with ease. Each location can have its own resources, services, and schedule settings while maintaining centralized control.
</p>
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-3">Key Features</h3>
<ul className="space-y-2 text-sm text-gray-600 dark:text-gray-300 mb-6">
<li className="flex items-center gap-2">
<CheckCircle size={16} className="text-green-500" />
<span><strong>Primary Location:</strong> Set a default location for your business operations</span>
</li>
<li className="flex items-center gap-2">
<CheckCircle size={16} className="text-green-500" />
<span><strong>Activate/Deactivate:</strong> Temporarily disable locations without deleting them</span>
</li>
<li className="flex items-center gap-2">
<CheckCircle size={16} className="text-green-500" />
<span><strong>Address Management:</strong> Store complete address information for each location</span>
</li>
<li className="flex items-center gap-2">
<CheckCircle size={16} className="text-green-500" />
<span><strong>Resource Assignment:</strong> Assign staff, rooms, and equipment to specific locations</span>
</li>
<li className="flex items-center gap-2">
<CheckCircle size={16} className="text-green-500" />
<span><strong>Service Assignment:</strong> Configure which services are available at each location</span>
</li>
</ul>
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-3">Learn More</h3>
<Link to="/dashboard/help/locations" onClick={scrollToTop} className="flex items-center gap-3 p-4 bg-gray-50 dark:bg-gray-700/50 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors">
<MapPin size={24} className="text-cyan-500" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Locations Documentation</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Complete guide to managing multiple business locations</p>
</div>
<ChevronRight size={20} className="text-gray-400 ml-auto" />
</Link>
</div>
</section>
{/* ============================================== */}
{/* SITE BUILDER */}
{/* ============================================== */}
@@ -1000,6 +1059,100 @@ const HelpComprehensive: React.FC = () => {
</Link>
</section>
{/* ============================================== */}
{/* API DOCUMENTATION */}
{/* ============================================== */}
<section id="api" className="mb-16 scroll-mt-24">
<div className="flex items-center gap-3 mb-6">
<div className="w-10 h-10 rounded-lg bg-indigo-100 dark:bg-indigo-900/30 flex items-center justify-center">
<Code size={20} className="text-indigo-600 dark:text-indigo-400" />
</div>
<h2 className="text-2xl font-bold text-gray-900 dark:text-white">API Documentation</h2>
</div>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6 mb-6">
<p className="text-gray-600 dark:text-gray-300 mb-4">
SmoothSchedule provides a comprehensive REST API for third-party integrations. Build custom applications, mobile apps, or connect with external services using our secure and well-documented API.
</p>
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-3">Key Features</h3>
<ul className="space-y-2 text-sm text-gray-600 dark:text-gray-300 mb-6">
<li className="flex items-center gap-2">
<CheckCircle size={16} className="text-indigo-500" />
<span><strong>REST API:</strong> Simple, intuitive REST API with JSON responses</span>
</li>
<li className="flex items-center gap-2">
<CheckCircle size={16} className="text-indigo-500" />
<span><strong>Token-based Authentication:</strong> Secure API tokens with configurable expiration</span>
</li>
<li className="flex items-center gap-2">
<CheckCircle size={16} className="text-indigo-500" />
<span><strong>Scope-based Permissions:</strong> Fine-grained control over API access</span>
</li>
<li className="flex items-center gap-2">
<CheckCircle size={16} className="text-indigo-500" />
<span><strong>Webhook Support:</strong> Receive real-time events for appointments, bookings, and more</span>
</li>
<li className="flex items-center gap-2">
<CheckCircle size={16} className="text-indigo-500" />
<span><strong>Rate Limiting:</strong> 1000 requests per hour (configurable per token)</span>
</li>
<li className="flex items-center gap-2">
<CheckCircle size={16} className="text-indigo-500" />
<span><strong>Sandbox Mode:</strong> Test your integration without affecting live data</span>
</li>
</ul>
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-3">API Documentation</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-3 mb-6">
<Link to="/dashboard/help/api" onClick={scrollToTop} className="p-3 bg-gray-50 dark:bg-gray-700/50 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors">
<h4 className="font-medium text-gray-900 dark:text-white text-sm">API Overview</h4>
<p className="text-xs text-gray-500 dark:text-gray-400">Authentication, rate limits, and getting started</p>
</Link>
<Link to="/dashboard/help/api/appointments" onClick={scrollToTop} className="p-3 bg-gray-50 dark:bg-gray-700/50 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors">
<h4 className="font-medium text-gray-900 dark:text-white text-sm">Appointments API</h4>
<p className="text-xs text-gray-500 dark:text-gray-400">Create, update, and manage appointments</p>
</Link>
<Link to="/dashboard/help/api/services" onClick={scrollToTop} className="p-3 bg-gray-50 dark:bg-gray-700/50 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors">
<h4 className="font-medium text-gray-900 dark:text-white text-sm">Services API</h4>
<p className="text-xs text-gray-500 dark:text-gray-400">Manage services and availability</p>
</Link>
<Link to="/dashboard/help/api/resources" onClick={scrollToTop} className="p-3 bg-gray-50 dark:bg-gray-700/50 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors">
<h4 className="font-medium text-gray-900 dark:text-white text-sm">Resources API</h4>
<p className="text-xs text-gray-500 dark:text-gray-400">Access and update staff, rooms, and equipment</p>
</Link>
<Link to="/dashboard/help/api/customers" onClick={scrollToTop} className="p-3 bg-gray-50 dark:bg-gray-700/50 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors">
<h4 className="font-medium text-gray-900 dark:text-white text-sm">Customers API</h4>
<p className="text-xs text-gray-500 dark:text-gray-400">Manage customer data and preferences</p>
</Link>
<Link to="/dashboard/help/api/webhooks" onClick={scrollToTop} className="p-3 bg-gray-50 dark:bg-gray-700/50 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors">
<h4 className="font-medium text-gray-900 dark:text-white text-sm">Webhooks</h4>
<p className="text-xs text-gray-500 dark:text-gray-400">Configure real-time event notifications</p>
</Link>
</div>
<div className="bg-indigo-50 dark:bg-indigo-900/20 border border-indigo-200 dark:border-indigo-800 rounded-lg p-4">
<div className="flex items-start gap-3">
<Code size={20} className="text-indigo-600 dark:text-indigo-400 mt-0.5 flex-shrink-0" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white text-sm mb-1">Interactive API Documentation</h4>
<p className="text-xs text-gray-600 dark:text-gray-300">
Access interactive API documentation with example requests and responses at{' '}
<a
href="/api/v1/docs/"
target="_blank"
rel="noopener noreferrer"
className="bg-indigo-100 dark:bg-indigo-900/50 px-1.5 py-0.5 rounded text-indigo-700 dark:text-indigo-300 font-mono hover:underline"
>
/api/v1/docs/
</a>
</p>
</div>
</div>
</div>
</div>
</section>
{/* ============================================== */}
{/* SETTINGS */}
{/* ============================================== */}
@@ -1096,6 +1249,26 @@ const HelpComprehensive: React.FC = () => {
<h4 className="font-medium text-gray-900 dark:text-white text-sm">{t('helpComprehensive.settings.usageQuotaLink')}</h4>
<p className="text-xs text-gray-500 dark:text-gray-400">{t('helpComprehensive.settings.usageQuotaLinkDesc')}</p>
</Link>
<Link to="/dashboard/help/settings/business-hours" onClick={scrollToTop} className="p-3 bg-gray-50 dark:bg-gray-700/50 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors">
<h4 className="font-medium text-gray-900 dark:text-white text-sm">Business Hours</h4>
<p className="text-xs text-gray-500 dark:text-gray-400">Configure operating hours and availability</p>
</Link>
<Link to="/dashboard/help/settings/email-templates" onClick={scrollToTop} className="p-3 bg-gray-50 dark:bg-gray-700/50 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors">
<h4 className="font-medium text-gray-900 dark:text-white text-sm">Email Templates</h4>
<p className="text-xs text-gray-500 dark:text-gray-400">Customize automated email templates</p>
</Link>
<Link to="/dashboard/help/settings/embed-widget" onClick={scrollToTop} className="p-3 bg-gray-50 dark:bg-gray-700/50 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors">
<h4 className="font-medium text-gray-900 dark:text-white text-sm">Embed Widget</h4>
<p className="text-xs text-gray-500 dark:text-gray-400">Embed booking widget on your website</p>
</Link>
<Link to="/dashboard/help/settings/staff-roles" onClick={scrollToTop} className="p-3 bg-gray-50 dark:bg-gray-700/50 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors">
<h4 className="font-medium text-gray-900 dark:text-white text-sm">Staff Roles</h4>
<p className="text-xs text-gray-500 dark:text-gray-400">Manage team permissions and access levels</p>
</Link>
<Link to="/dashboard/help/settings/communication" onClick={scrollToTop} className="p-3 bg-gray-50 dark:bg-gray-700/50 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors">
<h4 className="font-medium text-gray-900 dark:text-white text-sm">SMS & Calling</h4>
<p className="text-xs text-gray-500 dark:text-gray-400">Configure SMS and calling features</p>
</Link>
</div>
</div>
</div>

View File

@@ -0,0 +1,358 @@
/**
* Help Locations Page
*
* User-friendly help documentation for Locations.
*/
import React from 'react';
import { useTranslation } from 'react-i18next';
import { useNavigate } from 'react-router-dom';
import {
ArrowLeft,
MapPin,
Building2,
Star,
Power,
PowerOff,
Edit,
Trash2,
Phone,
Mail,
Globe,
Clock,
CheckCircle,
HelpCircle,
Users,
Briefcase,
} from 'lucide-react';
const HelpLocations: React.FC = () => {
const { t } = useTranslation();
const navigate = useNavigate();
return (
<div className="max-w-4xl mx-auto py-8 px-4">
{/* Back Button */}
<button
onClick={() => navigate(-1)}
className="flex items-center gap-2 text-brand-600 hover:text-brand-700 dark:text-brand-400 mb-6"
>
<ArrowLeft size={20} />
{t('common.back', 'Back')}
</button>
{/* Header */}
<div className="mb-8">
<div className="flex items-center gap-3 mb-4">
<div className="w-12 h-12 rounded-xl bg-brand-100 dark:bg-brand-900/30 flex items-center justify-center">
<MapPin size={24} className="text-brand-600 dark:text-brand-400" />
</div>
<div>
<h1 className="text-3xl font-bold text-gray-900 dark:text-white">
Locations Guide
</h1>
<p className="text-gray-500 dark:text-gray-400">
Manage multiple business locations with ease
</p>
</div>
</div>
</div>
{/* Overview Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Building2 size={20} className="text-brand-500" />
Overview
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<p className="text-gray-600 dark:text-gray-300 mb-4">
Locations allow you to manage multiple business sites from a single account. Whether you have
multiple offices, retail stores, or service areas, each location can have its own address,
contact information, timezone settings, and dedicated resources and services.
</p>
<p className="text-gray-600 dark:text-gray-300">
Assign resources (staff, rooms, equipment) and services to specific locations to keep your
scheduling organized and ensure customers book appointments at the right place.
</p>
</div>
</section>
{/* Location Information Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<MapPin size={20} className="text-brand-500" />
Location Information
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<p className="text-gray-600 dark:text-gray-300 mb-4">
Each location stores comprehensive information to help customers find and contact you:
</p>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="flex items-start gap-3 p-4 bg-gray-50 dark:bg-gray-700/50 rounded-lg">
<Building2 size={20} className="text-blue-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Name & Address</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Location name, street address, city, state, postal code, and country</p>
</div>
</div>
<div className="flex items-start gap-3 p-4 bg-gray-50 dark:bg-gray-700/50 rounded-lg">
<Phone size={20} className="text-green-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Contact Details</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Phone number and email address for customer inquiries</p>
</div>
</div>
<div className="flex items-start gap-3 p-4 bg-gray-50 dark:bg-gray-700/50 rounded-lg">
<Clock size={20} className="text-purple-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Timezone</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Set the local timezone for accurate appointment scheduling</p>
</div>
</div>
<div className="flex items-start gap-3 p-4 bg-gray-50 dark:bg-gray-700/50 rounded-lg">
<Star size={20} className="text-yellow-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Primary Status</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Designate one location as your primary business location</p>
</div>
</div>
</div>
</div>
</section>
{/* Primary Location Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Star size={20} className="text-brand-500" />
Primary Location
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<p className="text-gray-600 dark:text-gray-300 mb-4">
You can designate one location as your <strong>primary location</strong>. This is your main
business address and will be used as the default location for new resources and services.
</p>
<div className="space-y-3">
<div className="flex items-start gap-3">
<Star size={18} className="text-yellow-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Setting a Primary Location</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Click the star icon next to any location to make it primary. The previous primary location will automatically be unmarked.</p>
</div>
</div>
<div className="flex items-start gap-3">
<CheckCircle size={18} className="text-green-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Benefits</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Primary location appears first in lists and is pre-selected when creating new resources or services.</p>
</div>
</div>
</div>
</div>
</section>
{/* Managing Locations Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Building2 size={20} className="text-brand-500" />
Managing Locations
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<div className="space-y-6">
<div>
<h3 className="font-semibold text-gray-900 dark:text-white mb-3 flex items-center gap-2">
<Building2 size={18} className="text-blue-500" />
Creating a Location
</h3>
<ol className="space-y-2 ml-7">
<li className="text-sm text-gray-600 dark:text-gray-300">
1. Navigate to <strong>Settings Locations</strong>
</li>
<li className="text-sm text-gray-600 dark:text-gray-300">
2. Click <strong>Add Location</strong>
</li>
<li className="text-sm text-gray-600 dark:text-gray-300">
3. Fill in the location name, address, and contact details
</li>
<li className="text-sm text-gray-600 dark:text-gray-300">
4. Select the appropriate timezone for the location
</li>
<li className="text-sm text-gray-600 dark:text-gray-300">
5. Optionally mark it as the primary location
</li>
<li className="text-sm text-gray-600 dark:text-gray-300">
6. Click <strong>Save</strong>
</li>
</ol>
</div>
<div>
<h3 className="font-semibold text-gray-900 dark:text-white mb-3 flex items-center gap-2">
<Edit size={18} className="text-green-500" />
Editing a Location
</h3>
<p className="text-sm text-gray-600 dark:text-gray-300 ml-7">
Click the <strong>Edit</strong> button next to any location to update its information.
All changes are saved immediately and will apply to future bookings.
</p>
</div>
<div>
<h3 className="font-semibold text-gray-900 dark:text-white mb-3 flex items-center gap-2">
<Power size={18} className="text-orange-500" />
Activating/Deactivating Locations
</h3>
<div className="ml-7 space-y-2">
<p className="text-sm text-gray-600 dark:text-gray-300">
Instead of deleting locations, you can temporarily deactivate them:
</p>
<ul className="space-y-1 text-sm text-gray-600 dark:text-gray-300">
<li className="flex items-center gap-2">
<PowerOff size={14} className="text-red-500" />
<span><strong>Deactivate:</strong> Location is hidden from scheduling but data is preserved</span>
</li>
<li className="flex items-center gap-2">
<Power size={14} className="text-green-500" />
<span><strong>Activate:</strong> Location becomes available for scheduling again</span>
</li>
</ul>
</div>
</div>
<div>
<h3 className="font-semibold text-gray-900 dark:text-white mb-3 flex items-center gap-2">
<Trash2 size={18} className="text-red-500" />
Deleting a Location
</h3>
<div className="ml-7 space-y-2">
<p className="text-sm text-gray-600 dark:text-gray-300">
Click the <strong>Delete</strong> button to permanently remove a location.
</p>
<div className="bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg p-3">
<p className="text-sm text-red-800 dark:text-red-300">
<strong>Warning:</strong> You cannot delete a location that has associated resources or services.
Reassign or delete them first, or use the deactivate option instead.
</p>
</div>
</div>
</div>
</div>
</div>
</section>
{/* Resource & Service Counts Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Users size={20} className="text-brand-500" />
Resources & Services
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<p className="text-gray-600 dark:text-gray-300 mb-4">
Each location displays counts of associated resources and services to help you understand
how your business is organized:
</p>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="flex items-start gap-3 p-4 bg-gray-50 dark:bg-gray-700/50 rounded-lg">
<Users size={20} className="text-blue-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Resources</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
See how many staff members, rooms, or equipment items are assigned to each location
</p>
</div>
</div>
<div className="flex items-start gap-3 p-4 bg-gray-50 dark:bg-gray-700/50 rounded-lg">
<Briefcase size={20} className="text-green-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Services</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
Track which services are available at each location for accurate booking
</p>
</div>
</div>
</div>
</div>
</section>
{/* Tips Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Globe size={20} className="text-brand-500" />
Tips & Best Practices
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<div className="space-y-4">
<div className="flex items-start gap-3">
<Clock size={18} className="text-purple-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Set Accurate Timezones</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
Always configure the correct timezone for each location to ensure appointment times are displayed
correctly for both staff and customers in different time zones.
</p>
</div>
</div>
<div className="flex items-start gap-3">
<Building2 size={18} className="text-blue-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Use Descriptive Names</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
Give locations clear, recognizable names like "Downtown Office" or "West Side Clinic" to help
staff and customers easily identify the right location.
</p>
</div>
</div>
<div className="flex items-start gap-3">
<Star size={18} className="text-yellow-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Choose Your Primary Wisely</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
Select your main or headquarters location as primary. This becomes the default for new resources
and services and appears first in location lists.
</p>
</div>
</div>
<div className="flex items-start gap-3">
<PowerOff size={18} className="text-orange-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Deactivate Instead of Delete</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
If a location is temporarily closed or inactive, deactivate it instead of deleting. This preserves
historical data and allows you to reactivate it later if needed.
</p>
</div>
</div>
<div className="flex items-start gap-3">
<Mail size={18} className="text-green-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Keep Contact Info Current</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
Regularly update phone numbers and email addresses to ensure customers can reach the right location
if they need to contact you about their appointment.
</p>
</div>
</div>
</div>
</div>
</section>
{/* Need More Help */}
<section className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6 text-center">
<HelpCircle size={32} className="mx-auto text-brand-500 mb-3" />
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-2">
Need More Help?
</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Our support team is ready to help with any questions about locations.
</p>
<button
onClick={() => navigate('/dashboard/tickets')}
className="px-6 py-2 bg-brand-600 text-white rounded-lg hover:bg-brand-700 transition-colors"
>
Contact Support
</button>
</section>
</div>
);
};
export default HelpLocations;

View File

@@ -0,0 +1,275 @@
/**
* Help Business Hours Settings Page
*
* User-friendly help documentation for Business Hours settings.
*/
import React from 'react';
import { useTranslation } from 'react-i18next';
import { useNavigate } from 'react-router-dom';
import {
ArrowLeft,
Clock,
Calendar,
Settings,
CheckCircle,
HelpCircle,
Sun,
Moon,
Users,
AlertCircle,
} from 'lucide-react';
const HelpSettingsBusinessHours: React.FC = () => {
const { t } = useTranslation();
const navigate = useNavigate();
return (
<div className="max-w-4xl mx-auto py-8 px-4">
{/* Back Button */}
<button
onClick={() => navigate(-1)}
className="flex items-center gap-2 text-brand-600 hover:text-brand-700 dark:text-brand-400 mb-6"
>
<ArrowLeft size={20} />
{t('common.back', 'Back')}
</button>
{/* Header */}
<div className="mb-8">
<div className="flex items-center gap-3 mb-4">
<div className="w-12 h-12 rounded-xl bg-brand-100 dark:bg-brand-900/30 flex items-center justify-center">
<Clock size={24} className="text-brand-600 dark:text-brand-400" />
</div>
<div>
<h1 className="text-3xl font-bold text-gray-900 dark:text-white">
Business Hours Guide
</h1>
<p className="text-gray-500 dark:text-gray-400">
Configure your operating hours and availability
</p>
</div>
</div>
</div>
{/* Overview Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Clock size={20} className="text-brand-500" />
Overview
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<p className="text-gray-600 dark:text-gray-300 mb-4">
Business Hours define when your business is open and accepting appointments. Setting accurate
hours is essential for providing a smooth booking experience for your customers.
</p>
<p className="text-gray-600 dark:text-gray-300">
Customers can only book appointments during your configured business hours. Any time slots
outside these hours will be automatically hidden from the booking interface.
</p>
</div>
</section>
{/* Setting Your Hours Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Settings size={20} className="text-brand-500" />
Setting Your Hours
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<ol className="space-y-4">
<li className="flex items-start gap-3">
<span className="flex-shrink-0 w-6 h-6 rounded-full bg-brand-600 text-white text-sm flex items-center justify-center">1</span>
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Navigate to Settings</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Go to Settings &rarr; Business Hours from your dashboard.</p>
</div>
</li>
<li className="flex items-start gap-3">
<span className="flex-shrink-0 w-6 h-6 rounded-full bg-brand-600 text-white text-sm flex items-center justify-center">2</span>
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Select Each Day</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Each day of the week can have different hours. Toggle each day on or off.</p>
</div>
</li>
<li className="flex items-start gap-3">
<span className="flex-shrink-0 w-6 h-6 rounded-full bg-brand-600 text-white text-sm flex items-center justify-center">3</span>
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Set Open and Close Times</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">For each enabled day, choose when you open and close using the time pickers.</p>
</div>
</li>
<li className="flex items-start gap-3">
<span className="flex-shrink-0 w-6 h-6 rounded-full bg-brand-600 text-white text-sm flex items-center justify-center">4</span>
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Save Changes</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Click "Save Business Hours" to apply your changes. They take effect immediately.</p>
</div>
</li>
</ol>
</div>
</section>
{/* Closed Days Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Moon size={20} className="text-brand-500" />
Closed Days
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<p className="text-gray-600 dark:text-gray-300 mb-4">
To mark a day as closed, simply toggle it off in the Business Hours settings. Common scenarios:
</p>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="flex items-start gap-3 p-4 bg-gray-50 dark:bg-gray-700/50 rounded-lg">
<Calendar size={20} className="text-blue-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Weekends</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Disable Saturday and Sunday if you're closed on weekends</p>
</div>
</div>
<div className="flex items-start gap-3 p-4 bg-gray-50 dark:bg-gray-700/50 rounded-lg">
<Sun size={20} className="text-orange-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Specific Days</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Turn off any day you're regularly closed (e.g., Mondays)</p>
</div>
</div>
<div className="flex items-start gap-3 p-4 bg-gray-50 dark:bg-gray-700/50 rounded-lg">
<Clock size={20} className="text-green-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Different Hours</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Set different hours for different days (e.g., shorter hours on Friday)</p>
</div>
</div>
<div className="flex items-start gap-3 p-4 bg-gray-50 dark:bg-gray-700/50 rounded-lg">
<AlertCircle size={20} className="text-purple-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Holidays</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Use Time Blocks for one-time closures like holidays</p>
</div>
</div>
</div>
</div>
</section>
{/* How It Affects Booking Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Users size={20} className="text-brand-500" />
How It Affects Booking
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<p className="text-gray-600 dark:text-gray-300 mb-4">
Your business hours directly control when customers can book appointments:
</p>
<div className="space-y-4">
<div className="flex items-start gap-3">
<CheckCircle size={18} className="text-green-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Available Time Slots</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
Only time slots within your business hours will be shown to customers in the booking calendar.
</p>
</div>
</div>
<div className="flex items-start gap-3">
<CheckCircle size={18} className="text-green-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Closed Days Hidden</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
Days that are disabled won't appear as available booking options for customers.
</p>
</div>
</div>
<div className="flex items-start gap-3">
<CheckCircle size={18} className="text-green-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Service Duration Respected</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
Appointments must end before closing time. A 2-hour service can't start 1 hour before close.
</p>
</div>
</div>
<div className="flex items-start gap-3">
<CheckCircle size={18} className="text-green-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Immediate Effect</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
Changes to business hours take effect immediately and apply to all future bookings.
</p>
</div>
</div>
</div>
</div>
</section>
{/* Tips Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<CheckCircle size={20} className="text-brand-500" />
Tips
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<div className="space-y-4">
<div className="flex items-start gap-3 p-4 bg-blue-50 dark:bg-blue-900/20 rounded-lg border border-blue-200 dark:border-blue-800">
<Clock size={18} className="text-blue-600 dark:text-blue-400 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Account for Buffer Time</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
Set closing time 15-30 minutes after your last desired appointment to account for cleanup and staff departure.
</p>
</div>
</div>
<div className="flex items-start gap-3 p-4 bg-green-50 dark:bg-green-900/20 rounded-lg border border-green-200 dark:border-green-800">
<Calendar size={18} className="text-green-600 dark:text-green-400 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Use Time Blocks for Exceptions</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
For one-time closures (holidays, maintenance), use Time Blocks instead of changing business hours.
</p>
</div>
</div>
<div className="flex items-start gap-3 p-4 bg-purple-50 dark:bg-purple-900/20 rounded-lg border border-purple-200 dark:border-purple-800">
<Settings size={18} className="text-purple-600 dark:text-purple-400 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Coordinate with Resources</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
If specific staff have different schedules, use Resource availability settings in addition to business hours.
</p>
</div>
</div>
<div className="flex items-start gap-3 p-4 bg-orange-50 dark:bg-orange-900/20 rounded-lg border border-orange-200 dark:border-orange-800">
<AlertCircle size={18} className="text-orange-600 dark:text-orange-400 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Review Regularly</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
Update your hours seasonally or as your business evolves to ensure accurate availability.
</p>
</div>
</div>
</div>
</div>
</section>
{/* Need More Help */}
<section className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6 text-center">
<HelpCircle size={32} className="mx-auto text-brand-500 mb-3" />
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-2">
Need More Help?
</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Our support team is ready to help with any questions about business hours settings.
</p>
<button
onClick={() => navigate('/dashboard/tickets')}
className="px-6 py-2 bg-brand-600 text-white rounded-lg hover:bg-brand-700 transition-colors"
>
Contact Support
</button>
</section>
</div>
);
};
export default HelpSettingsBusinessHours;

View File

@@ -0,0 +1,425 @@
/**
* Help Settings Communication Page
*
* User-friendly help documentation for Communication (SMS/Calling) Settings.
*/
import React from 'react';
import { useTranslation } from 'react-i18next';
import { useNavigate } from 'react-router-dom';
import {
ArrowLeft,
Phone,
MessageSquare,
CreditCard,
RefreshCw,
DollarSign,
Settings,
History,
HelpCircle,
ChevronRight,
Bell,
ShieldCheck,
TrendingUp,
Clock,
CheckCircle,
} from 'lucide-react';
const HelpSettingsCommunication: React.FC = () => {
const { t } = useTranslation();
const navigate = useNavigate();
return (
<div className="max-w-4xl mx-auto py-8 px-4">
{/* Back Button */}
<button
onClick={() => navigate(-1)}
className="flex items-center gap-2 text-brand-600 hover:text-brand-700 dark:text-brand-400 mb-6"
>
<ArrowLeft size={20} />
{t('common.back', 'Back')}
</button>
{/* Header */}
<div className="mb-8">
<div className="flex items-center gap-3 mb-4">
<div className="w-12 h-12 rounded-xl bg-brand-100 dark:bg-brand-900/30 flex items-center justify-center">
<Phone size={24} className="text-brand-600 dark:text-brand-400" />
</div>
<div>
<h1 className="text-3xl font-bold text-gray-900 dark:text-white">
Communication Settings Guide
</h1>
<p className="text-gray-500 dark:text-gray-400">
Manage SMS and calling features for your business
</p>
</div>
</div>
</div>
{/* Overview Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Phone size={20} className="text-brand-500" />
Overview
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<p className="text-gray-600 dark:text-gray-300 mb-4">
Communication settings enable you to send SMS reminders to customers and make masked calls
through your business phone number. The system uses a credit-based model powered by Twilio,
ensuring reliable delivery and professional communication.
</p>
<p className="text-gray-600 dark:text-gray-300">
Set up automatic appointment reminders, make calls that display your business number,
and manage your communication budget with auto-reload features.
</p>
</div>
</section>
{/* Getting Started */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Settings size={20} className="text-brand-500" />
Getting Started
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<ol className="space-y-4">
<li className="flex items-start gap-3">
<span className="flex-shrink-0 w-6 h-6 rounded-full bg-brand-600 text-white text-sm flex items-center justify-center">1</span>
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Complete Setup Wizard</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Answer a few questions about your business size and communication needs to estimate your monthly usage.</p>
</div>
</li>
<li className="flex items-start gap-3">
<span className="flex-shrink-0 w-6 h-6 rounded-full bg-brand-600 text-white text-sm flex items-center justify-center">2</span>
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Purchase Initial Credits</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Add credits to your account based on the wizard's recommendation or choose your own amount.</p>
</div>
</li>
<li className="flex items-start gap-3">
<span className="flex-shrink-0 w-6 h-6 rounded-full bg-brand-600 text-white text-sm flex items-center justify-center">3</span>
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Provision Phone Number</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Search for and claim a local phone number in your area code for SMS and calls.</p>
</div>
</li>
<li className="flex items-start gap-3">
<span className="flex-shrink-0 w-6 h-6 rounded-full bg-brand-600 text-white text-sm flex items-center justify-center">4</span>
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Configure Auto-Reload</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Set up automatic credit top-ups to ensure uninterrupted service.</p>
</div>
</li>
</ol>
</div>
</section>
{/* Credit System */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<DollarSign size={20} className="text-brand-500" />
Credit System
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<p className="text-gray-600 dark:text-gray-300 mb-4">
Credits are used for both SMS and calling features. Your balance is displayed prominently
in the Communication Settings page.
</p>
<div className="space-y-4">
<div className="flex items-start gap-3">
<MessageSquare size={18} className="text-blue-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">SMS Pricing</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Approximately $0.01 - $0.02 per SMS depending on destination country. Long messages may use multiple credits.</p>
</div>
</div>
<div className="flex items-start gap-3">
<Phone size={18} className="text-green-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Call Pricing</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Charged per minute of talk time. Pricing varies by country but typically ranges from $0.01 - $0.05 per minute.</p>
</div>
</div>
<div className="flex items-start gap-3">
<CreditCard size={18} className="text-purple-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Purchasing Credits</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Buy credits in bulk with minimum purchase of $10. Larger purchases may qualify for volume discounts.</p>
</div>
</div>
</div>
</div>
</section>
{/* Auto-Reload Configuration */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<RefreshCw size={20} className="text-brand-500" />
Auto-Reload Configuration
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<p className="text-gray-600 dark:text-gray-300 mb-4">
Auto-reload ensures you never run out of credits during important communications.
Configure threshold and reload amounts to match your usage patterns.
</p>
<div className="bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-lg p-4 mb-4">
<div className="flex items-start gap-3">
<Bell size={18} className="text-blue-600 dark:text-blue-400 mt-0.5" />
<div>
<h4 className="font-medium text-blue-900 dark:text-blue-100 text-sm">How It Works</h4>
<p className="text-xs text-blue-700 dark:text-blue-300 mt-1">
When your balance falls below the threshold amount (e.g., $10), we automatically
charge your payment method and add the reload amount (e.g., $50) to your account.
</p>
</div>
</div>
</div>
<ul className="space-y-2 text-sm text-gray-600 dark:text-gray-300">
<li className="flex items-center gap-2">
<CheckCircle size={16} className="text-green-500" />
<span><strong>Threshold:</strong> Set the balance level that triggers auto-reload (minimum $5)</span>
</li>
<li className="flex items-center gap-2">
<CheckCircle size={16} className="text-green-500" />
<span><strong>Reload Amount:</strong> Choose how much to add when triggered (minimum $10)</span>
</li>
<li className="flex items-center gap-2">
<CheckCircle size={16} className="text-green-500" />
<span><strong>Email Notifications:</strong> Receive confirmation emails when auto-reload occurs</span>
</li>
</ul>
</div>
</section>
{/* Phone Number Provisioning */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Phone size={20} className="text-brand-500" />
Phone Number Provisioning
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<p className="text-gray-600 dark:text-gray-300 mb-4">
Your business needs a dedicated phone number for sending SMS and making masked calls.
Search and provision numbers directly through the settings page.
</p>
<div className="space-y-4">
<div className="flex items-start gap-3">
<span className="text-2xl">🔍</span>
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Search by Area Code</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Enter your desired area code (e.g., 303 for Denver) to see available local numbers.</p>
</div>
</div>
<div className="flex items-start gap-3">
<span className="text-2xl">📱</span>
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Choose Your Number</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Select from available numbers. Local numbers build trust and improve answer rates.</p>
</div>
</div>
<div className="flex items-start gap-3">
<span className="text-2xl">💰</span>
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Monthly Fee</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Phone numbers have a small monthly fee (typically $1-2) automatically deducted from your credits.</p>
</div>
</div>
</div>
</div>
</section>
{/* SMS Reminders */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<MessageSquare size={20} className="text-brand-500" />
SMS Reminders
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<p className="text-gray-600 dark:text-gray-300 mb-4">
Reduce no-shows by automatically sending SMS reminders to customers before their appointments.
</p>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
<div className="flex items-start gap-3 p-4 bg-gray-50 dark:bg-gray-700/50 rounded-lg">
<Clock size={20} className="text-blue-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">24-Hour Reminders</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Sent one day before appointments</p>
</div>
</div>
<div className="flex items-start gap-3 p-4 bg-gray-50 dark:bg-gray-700/50 rounded-lg">
<Clock size={20} className="text-green-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">2-Hour Reminders</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Sent shortly before appointments</p>
</div>
</div>
</div>
<div className="bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800 rounded-lg p-4">
<div className="flex items-start gap-3">
<ShieldCheck size={18} className="text-amber-600 dark:text-amber-400 mt-0.5" />
<div>
<h4 className="font-medium text-amber-900 dark:text-amber-100 text-sm">Customer Consent</h4>
<p className="text-xs text-amber-700 dark:text-amber-300 mt-1">
Only send SMS to customers who have provided their phone number and consented to
receive communications. Respect opt-out requests immediately.
</p>
</div>
</div>
</div>
</div>
</section>
{/* Masked Calling */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Phone size={20} className="text-brand-500" />
Masked Calling
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<p className="text-gray-600 dark:text-gray-300 mb-4">
Make calls to customers that display your business phone number instead of personal cell phones.
Protects staff privacy while maintaining professional communication.
</p>
<div className="space-y-4">
<div className="flex items-start gap-3">
<ShieldCheck size={18} className="text-purple-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Privacy Protection</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Your personal phone number remains hidden. Customers see only your business number.</p>
</div>
</div>
<div className="flex items-start gap-3">
<TrendingUp size={18} className="text-blue-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Higher Answer Rates</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Customers are more likely to answer calls from recognized local numbers.</p>
</div>
</div>
<div className="flex items-start gap-3">
<History size={18} className="text-green-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Call Recording</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Optional call recording for quality assurance and training purposes.</p>
</div>
</div>
</div>
</div>
</section>
{/* Transaction History */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<History size={20} className="text-brand-500" />
Transaction History
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<p className="text-gray-600 dark:text-gray-300 mb-4">
View detailed logs of all communication activity including credit purchases, SMS sends,
and call minutes used.
</p>
<ul className="space-y-2 text-sm text-gray-600 dark:text-gray-300">
<li className="flex items-center gap-2">
<CreditCard size={16} className="text-blue-500" />
<span><strong>Credit Purchases:</strong> Track all top-ups and auto-reload transactions</span>
</li>
<li className="flex items-center gap-2">
<MessageSquare size={16} className="text-green-500" />
<span><strong>SMS Usage:</strong> See each message sent, recipient, and cost</span>
</li>
<li className="flex items-center gap-2">
<Phone size={16} className="text-purple-500" />
<span><strong>Call Logs:</strong> Review call duration, destination, and charges</span>
</li>
<li className="flex items-center gap-2">
<RefreshCw size={16} className="text-orange-500" />
<span><strong>Monthly Fees:</strong> Monitor phone number rental and other recurring charges</span>
</li>
</ul>
</div>
</section>
{/* Tips and Best Practices */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<CheckCircle size={20} className="text-brand-500" />
Tips and Best Practices
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<div className="space-y-4">
<div className="flex items-start gap-3 p-4 bg-green-50 dark:bg-green-900/20 rounded-lg border border-green-200 dark:border-green-800">
<span className="text-2xl">💡</span>
<div>
<h4 className="font-medium text-green-900 dark:text-green-100">Start with the Setup Wizard</h4>
<p className="text-sm text-green-700 dark:text-green-300">
The wizard provides accurate usage estimates based on your business size and helps
you avoid over or under-purchasing credits.
</p>
</div>
</div>
<div className="flex items-start gap-3 p-4 bg-blue-50 dark:bg-blue-900/20 rounded-lg border border-blue-200 dark:border-blue-800">
<span className="text-2xl">🔄</span>
<div>
<h4 className="font-medium text-blue-900 dark:text-blue-100">Enable Auto-Reload</h4>
<p className="text-sm text-blue-700 dark:text-blue-300">
Prevent service interruptions by setting up auto-reload. Set the threshold to 20-30%
of your typical monthly usage for best results.
</p>
</div>
</div>
<div className="flex items-start gap-3 p-4 bg-purple-50 dark:bg-purple-900/20 rounded-lg border border-purple-200 dark:border-purple-800">
<span className="text-2xl">📊</span>
<div>
<h4 className="font-medium text-purple-900 dark:text-purple-100">Monitor Your Usage</h4>
<p className="text-sm text-purple-700 dark:text-purple-300">
Check the transaction history monthly to understand patterns and optimize your
auto-reload settings. Look for opportunities to reduce no-shows.
</p>
</div>
</div>
<div className="flex items-start gap-3 p-4 bg-amber-50 dark:bg-amber-900/20 rounded-lg border border-amber-200 dark:border-amber-800">
<span className="text-2xl">📱</span>
<div>
<h4 className="font-medium text-amber-900 dark:text-amber-100">Choose Local Numbers</h4>
<p className="text-sm text-amber-700 dark:text-amber-300">
Local area codes increase trust and answer rates. Customers are more likely to
respond to numbers they recognize as being from their area.
</p>
</div>
</div>
<div className="flex items-start gap-3 p-4 bg-red-50 dark:bg-red-900/20 rounded-lg border border-red-200 dark:border-red-800">
<span className="text-2xl">⚖️</span>
<div>
<h4 className="font-medium text-red-900 dark:text-red-100">Comply with Regulations</h4>
<p className="text-sm text-red-700 dark:text-red-300">
Always obtain customer consent before sending SMS or making calls. Honor opt-out
requests immediately and maintain do-not-contact lists.
</p>
</div>
</div>
</div>
</div>
</section>
{/* Need More Help */}
<section className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6 text-center">
<HelpCircle size={32} className="mx-auto text-brand-500 mb-3" />
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-2">
Need More Help?
</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Our support team is ready to help with communication settings and troubleshooting.
</p>
<button
onClick={() => navigate('/dashboard/tickets')}
className="px-6 py-2 bg-brand-600 text-white rounded-lg hover:bg-brand-700 transition-colors"
>
Contact Support
</button>
</section>
</div>
);
};
export default HelpSettingsCommunication;

View File

@@ -0,0 +1,478 @@
/**
* Help Settings Email Templates Page
*
* User-friendly help documentation for Email Templates settings.
*/
import React from 'react';
import { useTranslation } from 'react-i18next';
import { useNavigate } from 'react-router-dom';
import {
ArrowLeft,
Mail,
FileText,
Eye,
RefreshCw,
Palette,
Code,
CheckCircle,
HelpCircle,
Settings,
User,
Calendar,
DollarSign,
MessageSquare,
} from 'lucide-react';
const HelpSettingsEmailTemplates: React.FC = () => {
const { t } = useTranslation();
const navigate = useNavigate();
return (
<div className="max-w-4xl mx-auto py-8 px-4">
{/* Back Button */}
<button
onClick={() => navigate(-1)}
className="flex items-center gap-2 text-brand-600 hover:text-brand-700 dark:text-brand-400 mb-6"
>
<ArrowLeft size={20} />
{t('common.back', 'Back')}
</button>
{/* Header */}
<div className="mb-8">
<div className="flex items-center gap-3 mb-4">
<div className="w-12 h-12 rounded-xl bg-brand-100 dark:bg-brand-900/30 flex items-center justify-center">
<Mail size={24} className="text-brand-600 dark:text-brand-400" />
</div>
<div>
<h1 className="text-3xl font-bold text-gray-900 dark:text-white">
Email Templates Guide
</h1>
<p className="text-gray-500 dark:text-gray-400">
Customize your automated email communications
</p>
</div>
</div>
</div>
{/* Overview Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Mail size={20} className="text-brand-500" />
Overview
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<p className="text-gray-600 dark:text-gray-300 mb-4">
Email Templates allow you to customize all automated emails sent from your scheduling platform.
Using our visual drag-and-drop editor powered by Puck, you can create professional, branded
emails without any coding knowledge.
</p>
<p className="text-gray-600 dark:text-gray-300">
Each template supports dynamic content through template tags, allowing you to personalize
messages with customer names, appointment details, and other relevant information.
</p>
</div>
</section>
{/* Template Categories Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<FileText size={20} className="text-brand-500" />
Template Categories
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<div className="space-y-4">
<div className="flex items-start gap-3 p-4 bg-gray-50 dark:bg-gray-700/50 rounded-lg">
<User size={20} className="text-blue-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Welcome Email</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
Sent when a new customer account is created. Sets the tone for their relationship with your business.
</p>
</div>
</div>
<div className="flex items-start gap-3 p-4 bg-gray-50 dark:bg-gray-700/50 rounded-lg">
<Calendar size={20} className="text-green-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Appointment Templates</h4>
<p className="text-sm text-gray-500 dark:text-gray-400 mb-2">
Four templates for the complete appointment lifecycle:
</p>
<ul className="text-sm text-gray-500 dark:text-gray-400 space-y-1 ml-4">
<li><strong>Confirmation:</strong> Sent immediately when an appointment is booked</li>
<li><strong>Reminder:</strong> Sent before the appointment (configurable timing)</li>
<li><strong>Rescheduled:</strong> Sent when an appointment time is changed</li>
<li><strong>Cancelled:</strong> Sent when an appointment is cancelled</li>
</ul>
</div>
</div>
<div className="flex items-start gap-3 p-4 bg-gray-50 dark:bg-gray-700/50 rounded-lg">
<FileText size={20} className="text-purple-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Contract Email</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
Sent when a contract or agreement needs to be signed by the customer.
</p>
</div>
</div>
<div className="flex items-start gap-3 p-4 bg-gray-50 dark:bg-gray-700/50 rounded-lg">
<DollarSign size={20} className="text-yellow-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Payment Email</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
Sent for payment confirmations, receipts, or payment reminders.
</p>
</div>
</div>
<div className="flex items-start gap-3 p-4 bg-gray-50 dark:bg-gray-700/50 rounded-lg">
<MessageSquare size={20} className="text-orange-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Ticket Email</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
Sent when support tickets are created, updated, or resolved.
</p>
</div>
</div>
</div>
</div>
</section>
{/* Using the Editor Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Settings size={20} className="text-brand-500" />
Using the Editor
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<p className="text-gray-600 dark:text-gray-300 mb-4">
Our email editor uses Puck, a powerful visual drag-and-drop interface that makes email
design simple and intuitive.
</p>
<ol className="space-y-4">
<li className="flex items-start gap-3">
<span className="flex-shrink-0 w-6 h-6 rounded-full bg-brand-600 text-white text-sm flex items-center justify-center">1</span>
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Select a Template</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
Navigate to Settings &rarr; Email Templates and choose the template you want to customize.
</p>
</div>
</li>
<li className="flex items-start gap-3">
<span className="flex-shrink-0 w-6 h-6 rounded-full bg-brand-600 text-white text-sm flex items-center justify-center">2</span>
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Drag & Drop Components</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
Add text blocks, images, buttons, dividers, and other elements by dragging them from
the component panel into your email layout.
</p>
</div>
</li>
<li className="flex items-start gap-3">
<span className="flex-shrink-0 w-6 h-6 rounded-full bg-brand-600 text-white text-sm flex items-center justify-center">3</span>
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Customize Content</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
Click on any element to edit its properties - text, colors, fonts, spacing, alignment, and more.
</p>
</div>
</li>
<li className="flex items-start gap-3">
<span className="flex-shrink-0 w-6 h-6 rounded-full bg-brand-600 text-white text-sm flex items-center justify-center">4</span>
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Insert Template Tags</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
Use template tags (like &#123;&#123;customer_name&#125;&#125;) to add dynamic content that changes
for each email sent.
</p>
</div>
</li>
<li className="flex items-start gap-3">
<span className="flex-shrink-0 w-6 h-6 rounded-full bg-brand-600 text-white text-sm flex items-center justify-center">5</span>
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Save Changes</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
Click "Save" to apply your changes. The new template will be used for all future emails
of that type.
</p>
</div>
</li>
</ol>
</div>
</section>
{/* Template Tags Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Code size={20} className="text-brand-500" />
Template Tags
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<p className="text-gray-600 dark:text-gray-300 mb-4">
Template tags are placeholders that get replaced with real data when the email is sent.
Wrap tag names in double curly braces: <code className="px-2 py-1 bg-gray-100 dark:bg-gray-700 rounded">&#123;&#123;tag_name&#125;&#125;</code>
</p>
<div className="space-y-4">
<div>
<h4 className="font-medium text-gray-900 dark:text-white mb-2">Customer Tags</h4>
<div className="grid grid-cols-1 md:grid-cols-2 gap-2 text-sm">
<div className="p-2 bg-gray-50 dark:bg-gray-700/50 rounded font-mono">
&#123;&#123;customer_name&#125;&#125;
</div>
<div className="p-2 bg-gray-50 dark:bg-gray-700/50 rounded font-mono">
&#123;&#123;customer_email&#125;&#125;
</div>
<div className="p-2 bg-gray-50 dark:bg-gray-700/50 rounded font-mono">
&#123;&#123;customer_phone&#125;&#125;
</div>
<div className="p-2 bg-gray-50 dark:bg-gray-700/50 rounded font-mono">
&#123;&#123;customer_id&#125;&#125;
</div>
</div>
</div>
<div>
<h4 className="font-medium text-gray-900 dark:text-white mb-2">Appointment Tags</h4>
<div className="grid grid-cols-1 md:grid-cols-2 gap-2 text-sm">
<div className="p-2 bg-gray-50 dark:bg-gray-700/50 rounded font-mono">
&#123;&#123;appointment_date&#125;&#125;
</div>
<div className="p-2 bg-gray-50 dark:bg-gray-700/50 rounded font-mono">
&#123;&#123;appointment_time&#125;&#125;
</div>
<div className="p-2 bg-gray-50 dark:bg-gray-700/50 rounded font-mono">
&#123;&#123;appointment_duration&#125;&#125;
</div>
<div className="p-2 bg-gray-50 dark:bg-gray-700/50 rounded font-mono">
&#123;&#123;service_name&#125;&#125;
</div>
<div className="p-2 bg-gray-50 dark:bg-gray-700/50 rounded font-mono">
&#123;&#123;staff_name&#125;&#125;
</div>
<div className="p-2 bg-gray-50 dark:bg-gray-700/50 rounded font-mono">
&#123;&#123;location&#125;&#125;
</div>
</div>
</div>
<div>
<h4 className="font-medium text-gray-900 dark:text-white mb-2">Business Tags</h4>
<div className="grid grid-cols-1 md:grid-cols-2 gap-2 text-sm">
<div className="p-2 bg-gray-50 dark:bg-gray-700/50 rounded font-mono">
&#123;&#123;business_name&#125;&#125;
</div>
<div className="p-2 bg-gray-50 dark:bg-gray-700/50 rounded font-mono">
&#123;&#123;business_phone&#125;&#125;
</div>
<div className="p-2 bg-gray-50 dark:bg-gray-700/50 rounded font-mono">
&#123;&#123;business_email&#125;&#125;
</div>
<div className="p-2 bg-gray-50 dark:bg-gray-700/50 rounded font-mono">
&#123;&#123;business_address&#125;&#125;
</div>
<div className="p-2 bg-gray-50 dark:bg-gray-700/50 rounded font-mono">
&#123;&#123;business_website&#125;&#125;
</div>
<div className="p-2 bg-gray-50 dark:bg-gray-700/50 rounded font-mono">
&#123;&#123;business_logo&#125;&#125;
</div>
</div>
</div>
<div>
<h4 className="font-medium text-gray-900 dark:text-white mb-2">Other Tags</h4>
<div className="grid grid-cols-1 md:grid-cols-2 gap-2 text-sm">
<div className="p-2 bg-gray-50 dark:bg-gray-700/50 rounded font-mono">
&#123;&#123;confirmation_link&#125;&#125;
</div>
<div className="p-2 bg-gray-50 dark:bg-gray-700/50 rounded font-mono">
&#123;&#123;cancellation_link&#125;&#125;
</div>
<div className="p-2 bg-gray-50 dark:bg-gray-700/50 rounded font-mono">
&#123;&#123;reschedule_link&#125;&#125;
</div>
<div className="p-2 bg-gray-50 dark:bg-gray-700/50 rounded font-mono">
&#123;&#123;current_year&#125;&#125;
</div>
</div>
</div>
</div>
</div>
</section>
{/* Preview & Testing Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Eye size={20} className="text-brand-500" />
Preview & Testing
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<div className="space-y-4">
<div className="flex items-start gap-3">
<Eye size={18} className="text-blue-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Live Preview</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
The editor shows a real-time preview of your email as you make changes. What you see
is what your customers will receive.
</p>
</div>
</div>
<div className="flex items-start gap-3">
<FileText size={18} className="text-green-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">HTML & Plain Text</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
Preview both the HTML version (for modern email clients) and plain text version
(for simple email clients or accessibility).
</p>
</div>
</div>
<div className="flex items-start gap-3">
<Mail size={18} className="text-purple-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Send Test Email</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
Send a test email to yourself to see how it appears in your actual email client.
Template tags will be filled with sample data.
</p>
</div>
</div>
<div className="flex items-start gap-3">
<CheckCircle size={18} className="text-orange-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Mobile Preview</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
Toggle between desktop and mobile views to ensure your emails look great on all devices.
</p>
</div>
</div>
</div>
</div>
</section>
{/* Branding Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Palette size={20} className="text-brand-500" />
Brand Colors & Logo
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<p className="text-gray-600 dark:text-gray-300 mb-4">
Email templates automatically integrate with your business branding settings:
</p>
<ul className="space-y-2 text-sm text-gray-600 dark:text-gray-300">
<li className="flex items-center gap-2">
<Palette size={16} className="text-brand-500" />
<span><strong>Brand Colors:</strong> Your primary brand color is available for buttons, headers, and accents</span>
</li>
<li className="flex items-center gap-2">
<FileText size={16} className="text-blue-500" />
<span><strong>Logo:</strong> Use the &#123;&#123;business_logo&#125;&#125; tag to insert your company logo</span>
</li>
<li className="flex items-center gap-2">
<Settings size={16} className="text-green-500" />
<span><strong>Consistent Styling:</strong> Templates maintain consistent fonts and spacing automatically</span>
</li>
</ul>
</div>
</section>
{/* Reset to Default Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<RefreshCw size={20} className="text-brand-500" />
Reset to Default
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<p className="text-gray-600 dark:text-gray-300 mb-4">
If you want to start over or undo your customizations, you can reset any template to its
default state.
</p>
<div className="bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 rounded-lg p-4">
<div className="flex items-start gap-2">
<RefreshCw size={18} className="text-yellow-600 dark:text-yellow-400 mt-0.5" />
<div>
<p className="text-sm text-yellow-800 dark:text-yellow-200 font-medium mb-1">
Warning: This action cannot be undone
</p>
<p className="text-sm text-yellow-700 dark:text-yellow-300">
Resetting a template will permanently delete all your customizations and restore
the original default template. Make sure to save a copy if you want to keep your work.
</p>
</div>
</div>
</div>
</div>
</section>
{/* Tips Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<CheckCircle size={20} className="text-brand-500" />
Tips & Best Practices
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<ul className="space-y-3 text-sm text-gray-600 dark:text-gray-300">
<li className="flex items-start gap-2">
<CheckCircle size={16} className="text-green-500 mt-0.5 flex-shrink-0" />
<span><strong>Keep it simple:</strong> Avoid cluttered designs. Focus on clear, scannable content with plenty of white space.</span>
</li>
<li className="flex items-start gap-2">
<CheckCircle size={16} className="text-green-500 mt-0.5 flex-shrink-0" />
<span><strong>Mobile-first:</strong> Over 50% of emails are opened on mobile devices. Always check the mobile preview.</span>
</li>
<li className="flex items-start gap-2">
<CheckCircle size={16} className="text-green-500 mt-0.5 flex-shrink-0" />
<span><strong>Clear CTAs:</strong> Make call-to-action buttons prominent with contrasting colors and clear text.</span>
</li>
<li className="flex items-start gap-2">
<CheckCircle size={16} className="text-green-500 mt-0.5 flex-shrink-0" />
<span><strong>Test thoroughly:</strong> Send test emails to different email clients (Gmail, Outlook, Apple Mail) to verify rendering.</span>
</li>
<li className="flex items-start gap-2">
<CheckCircle size={16} className="text-green-500 mt-0.5 flex-shrink-0" />
<span><strong>Personalize:</strong> Use template tags to make emails feel personal and relevant to each recipient.</span>
</li>
<li className="flex items-start gap-2">
<CheckCircle size={16} className="text-green-500 mt-0.5 flex-shrink-0" />
<span><strong>Be concise:</strong> Keep email content brief and to the point. Include only essential information.</span>
</li>
<li className="flex items-start gap-2">
<CheckCircle size={16} className="text-green-500 mt-0.5 flex-shrink-0" />
<span><strong>Brand consistency:</strong> Maintain consistent colors, fonts, and tone across all email templates.</span>
</li>
<li className="flex items-start gap-2">
<CheckCircle size={16} className="text-green-500 mt-0.5 flex-shrink-0" />
<span><strong>Include footer:</strong> Always add contact info and unsubscribe options in the email footer.</span>
</li>
</ul>
</div>
</section>
{/* Need More Help */}
<section className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6 text-center">
<HelpCircle size={32} className="mx-auto text-brand-500 mb-3" />
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-2">
Need More Help?
</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Our support team is ready to help with any questions about email templates.
</p>
<button
onClick={() => navigate('/dashboard/tickets')}
className="px-6 py-2 bg-brand-600 text-white rounded-lg hover:bg-brand-700 transition-colors"
>
Contact Support
</button>
</section>
</div>
);
};
export default HelpSettingsEmailTemplates;

View File

@@ -0,0 +1,299 @@
/**
* Help Embed Widget Settings Page
*
* User-friendly help documentation for the Embed Widget feature.
*/
import React from 'react';
import { useTranslation } from 'react-i18next';
import { useNavigate } from 'react-router-dom';
import {
ArrowLeft,
Code,
ExternalLink,
Copy,
Layout,
Palette,
Globe,
ChevronRight,
HelpCircle,
Monitor,
Smartphone,
Settings,
CheckCircle,
} from 'lucide-react';
const HelpSettingsEmbedWidget: React.FC = () => {
const { t } = useTranslation();
const navigate = useNavigate();
return (
<div className="max-w-4xl mx-auto py-8 px-4">
{/* Back Button */}
<button
onClick={() => navigate(-1)}
className="flex items-center gap-2 text-brand-600 hover:text-brand-700 dark:text-brand-400 mb-6"
>
<ArrowLeft size={20} />
{t('common.back', 'Back')}
</button>
{/* Header */}
<div className="mb-8">
<div className="flex items-center gap-3 mb-4">
<div className="w-12 h-12 rounded-xl bg-brand-100 dark:bg-brand-900/30 flex items-center justify-center">
<Code size={24} className="text-brand-600 dark:text-brand-400" />
</div>
<div>
<h1 className="text-3xl font-bold text-gray-900 dark:text-white">
Embed Widget Guide
</h1>
<p className="text-gray-500 dark:text-gray-400">
Add a booking widget to your website in minutes
</p>
</div>
</div>
</div>
{/* Overview Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Layout size={20} className="text-brand-500" />
Overview
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<p className="text-gray-600 dark:text-gray-300 mb-4">
The Embed Widget lets you add SmoothSchedule's booking functionality directly to your existing website.
Your customers can book appointments without leaving your site, creating a seamless experience that
matches your brand.
</p>
<p className="text-gray-600 dark:text-gray-300">
Works on any website platform including WordPress, Wix, Squarespace, Shopify, or custom HTML sites.
No technical expertise required - just copy and paste the code snippet.
</p>
</div>
</section>
{/* Embed Options Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Code size={20} className="text-brand-500" />
Embed Options
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="flex items-start gap-3 p-4 bg-gray-50 dark:bg-gray-700/50 rounded-lg">
<Layout size={20} className="text-blue-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Iframe Embed</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Simple HTML iframe - works everywhere, fixed size, easy to implement</p>
</div>
</div>
<div className="flex items-start gap-3 p-4 bg-gray-50 dark:bg-gray-700/50 rounded-lg">
<Code size={20} className="text-purple-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">JavaScript Snippet</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Advanced option - responsive sizing, better integration, modal support</p>
</div>
</div>
</div>
<div className="mt-4 p-4 bg-blue-50 dark:bg-blue-900/20 rounded-lg border border-blue-200 dark:border-blue-800">
<p className="text-sm text-blue-800 dark:text-blue-200">
<strong>Recommendation:</strong> Use the iframe for quick setup. Use JavaScript snippet for better responsive design
and if you want the widget to appear as a modal/popup.
</p>
</div>
</div>
</section>
{/* Customization Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Palette size={20} className="text-brand-500" />
Customization Options
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<div className="space-y-4">
<div className="flex items-start gap-3">
<Palette size={18} className="text-pink-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Brand Colors</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Customize primary color, button styles, and backgrounds to match your website</p>
</div>
</div>
<div className="flex items-start gap-3">
<Layout size={18} className="text-blue-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Widget Size</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Set width and height (iframe) or let it adapt to your page layout (JavaScript)</p>
</div>
</div>
<div className="flex items-start gap-3">
<Monitor size={18} className="text-green-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Responsive Design</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Widget automatically adapts to mobile, tablet, and desktop screen sizes</p>
</div>
</div>
<div className="flex items-start gap-3">
<Settings size={18} className="text-orange-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Display Preferences</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Choose default service, hide certain options, or pre-select staff members</p>
</div>
</div>
</div>
</div>
</section>
{/* Installation Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Globe size={20} className="text-brand-500" />
Installation by Platform
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<ol className="space-y-4">
<li className="flex items-start gap-3">
<span className="flex-shrink-0 w-6 h-6 rounded-full bg-brand-600 text-white text-sm flex items-center justify-center">1</span>
<div>
<h4 className="font-medium text-gray-900 dark:text-white">WordPress</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
Add a Custom HTML block to your page, paste the embed code, and publish. Works with any page builder.
</p>
</div>
</li>
<li className="flex items-start gap-3">
<span className="flex-shrink-0 w-6 h-6 rounded-full bg-brand-600 text-white text-sm flex items-center justify-center">2</span>
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Wix</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
Click "Add Elements" → "Embed" → "Embed a Widget" → "HTML iframe" or "Custom Code", then paste your code.
</p>
</div>
</li>
<li className="flex items-start gap-3">
<span className="flex-shrink-0 w-6 h-6 rounded-full bg-brand-600 text-white text-sm flex items-center justify-center">3</span>
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Squarespace</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
Edit your page, add a "Code" block, paste the embed code, and save. Set to HTML mode if prompted.
</p>
</div>
</li>
<li className="flex items-start gap-3">
<span className="flex-shrink-0 w-6 h-6 rounded-full bg-brand-600 text-white text-sm flex items-center justify-center">4</span>
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Shopify</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
Go to Online Store → Pages → Create/Edit page → Show HTML editor → Paste code in desired location.
</p>
</div>
</li>
<li className="flex items-start gap-3">
<span className="flex-shrink-0 w-6 h-6 rounded-full bg-brand-600 text-white text-sm flex items-center justify-center">5</span>
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Custom HTML Website</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
Paste the embed code directly into your HTML file where you want the widget to appear. For JavaScript snippet, add before closing &lt;/body&gt; tag.
</p>
</div>
</li>
</ol>
</div>
</section>
{/* Tips & Best Practices */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<CheckCircle size={20} className="text-brand-500" />
Tips & Best Practices
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<ul className="space-y-3 text-sm text-gray-600 dark:text-gray-300">
<li className="flex items-start gap-2">
<Copy size={16} className="text-green-500 mt-0.5 flex-shrink-0" />
<span>
<strong>Copy-to-clipboard:</strong> Use the built-in copy button in Settings → Embed Widget to easily copy your personalized code.
</span>
</li>
<li className="flex items-start gap-2">
<Monitor size={16} className="text-blue-500 mt-0.5 flex-shrink-0" />
<span>
<strong>Test responsiveness:</strong> Preview the widget on mobile, tablet, and desktop before publishing to ensure it looks good everywhere.
</span>
</li>
<li className="flex items-start gap-2">
<Palette size={16} className="text-purple-500 mt-0.5 flex-shrink-0" />
<span>
<strong>Match your brand:</strong> Customize colors to align with your website's design. The widget should feel like a natural part of your site.
</span>
</li>
<li className="flex items-start gap-2">
<Layout size={16} className="text-orange-500 mt-0.5 flex-shrink-0" />
<span>
<strong>Placement matters:</strong> Put the widget on high-traffic pages like your homepage or services page for maximum bookings.
</span>
</li>
<li className="flex items-start gap-2">
<Smartphone size={16} className="text-pink-500 mt-0.5 flex-shrink-0" />
<span>
<strong>Mobile optimization:</strong> Most bookings happen on mobile. Ensure the widget is easy to use on small screens.
</span>
</li>
<li className="flex items-start gap-2">
<ExternalLink size={16} className="text-teal-500 mt-0.5 flex-shrink-0" />
<span>
<strong>Update anytime:</strong> Changes to your services, availability, or branding automatically appear in the widget - no need to re-embed.
</span>
</li>
</ul>
</div>
</section>
{/* Quick Setup Guide */}
<section className="mb-10">
<div className="bg-gradient-to-r from-brand-50 to-blue-50 dark:from-brand-900/20 dark:to-blue-900/20 rounded-xl border border-brand-200 dark:border-brand-800 p-6">
<div className="flex items-start gap-4">
<Settings size={24} className="text-brand-600 dark:text-brand-400 mt-1" />
<div className="flex-1">
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-2">
Ready to Get Started?
</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Head to your Embed Widget settings to customize your widget, preview it, and copy the code snippet.
You'll have it live on your website in just a few minutes.
</p>
<button
onClick={() => navigate('/dashboard/settings/embed-widget')}
className="inline-flex items-center gap-2 px-4 py-2 bg-brand-600 text-white rounded-lg hover:bg-brand-700 transition-colors"
>
Go to Embed Widget Settings
<ChevronRight size={16} />
</button>
</div>
</div>
</div>
</section>
{/* Need More Help */}
<section className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6 text-center">
<HelpCircle size={32} className="mx-auto text-brand-500 mb-3" />
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-2">
Need More Help?
</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Having trouble embedding the widget? Our support team can help with installation and customization.
</p>
<button
onClick={() => navigate('/dashboard/tickets')}
className="px-6 py-2 bg-brand-600 text-white rounded-lg hover:bg-brand-700 transition-colors"
>
Contact Support
</button>
</section>
</div>
);
};
export default HelpSettingsEmbedWidget;

View File

@@ -0,0 +1,482 @@
/**
* Help Settings Staff Roles Page
*
* User-friendly help documentation for Staff Roles Settings.
*/
import React from 'react';
import { useTranslation } from 'react-i18next';
import { useNavigate } from 'react-router-dom';
import {
ArrowLeft,
Shield,
Users,
Lock,
AlertTriangle,
Settings,
CheckCircle,
ChevronRight,
HelpCircle,
} from 'lucide-react';
const HelpSettingsStaffRoles: React.FC = () => {
const { t } = useTranslation();
const navigate = useNavigate();
return (
<div className="max-w-4xl mx-auto py-8 px-4">
{/* Back Button */}
<button
onClick={() => navigate(-1)}
className="flex items-center gap-2 text-brand-600 hover:text-brand-700 dark:text-brand-400 mb-6"
>
<ArrowLeft size={20} />
{t('common.back', 'Back')}
</button>
{/* Header */}
<div className="mb-8">
<div className="flex items-center gap-3 mb-4">
<div className="w-12 h-12 rounded-xl bg-brand-100 dark:bg-brand-900/30 flex items-center justify-center">
<Shield size={24} className="text-brand-600 dark:text-brand-400" />
</div>
<div>
<h1 className="text-3xl font-bold text-gray-900 dark:text-white">
Staff Roles Guide
</h1>
<p className="text-gray-500 dark:text-gray-400">
Control staff access and permissions with custom roles
</p>
</div>
</div>
</div>
{/* Overview Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Shield size={20} className="text-brand-500" />
Overview
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<p className="text-gray-600 dark:text-gray-300 mb-4">
Staff Roles allow you to control what your staff members can see and do in your scheduling platform.
Create custom roles with specific permissions to match your business needs.
</p>
<p className="text-gray-600 dark:text-gray-300">
Each role defines which menu items staff can access and which dangerous operations (like deleting
customers or appointments) they can perform. Assign roles to staff members to apply these permissions
automatically.
</p>
</div>
</section>
{/* Default Roles Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Users size={20} className="text-brand-500" />
Default Roles
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<p className="text-gray-600 dark:text-gray-300 mb-4">
SmoothSchedule comes with three built-in roles to get you started:
</p>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<div className="flex flex-col gap-2 p-4 bg-gray-50 dark:bg-gray-700/50 rounded-lg">
<div className="flex items-center gap-2">
<Shield size={20} className="text-green-500" />
<h4 className="font-medium text-gray-900 dark:text-white">Full Access Staff</h4>
</div>
<p className="text-sm text-gray-500 dark:text-gray-400">
Access to all menu items and all dangerous permissions. Best for managers and supervisors.
</p>
</div>
<div className="flex flex-col gap-2 p-4 bg-gray-50 dark:bg-gray-700/50 rounded-lg">
<div className="flex items-center gap-2">
<Shield size={20} className="text-blue-500" />
<h4 className="font-medium text-gray-900 dark:text-white">Limited Staff</h4>
</div>
<p className="text-sm text-gray-500 dark:text-gray-400">
Access to Scheduler, Customers, and Messages only. No dangerous permissions. Best for general staff.
</p>
</div>
<div className="flex flex-col gap-2 p-4 bg-gray-50 dark:bg-gray-700/50 rounded-lg">
<div className="flex items-center gap-2">
<Shield size={20} className="text-purple-500" />
<h4 className="font-medium text-gray-900 dark:text-white">Front Desk</h4>
</div>
<p className="text-sm text-gray-500 dark:text-gray-400">
Access to Scheduler, Services, Customers, and Messages. No delete permissions. Best for reception.
</p>
</div>
</div>
</div>
</section>
{/* Creating Custom Roles */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Settings size={20} className="text-brand-500" />
Creating Custom Roles
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<ol className="space-y-4">
<li className="flex items-start gap-3">
<span className="flex-shrink-0 w-6 h-6 rounded-full bg-brand-600 text-white text-sm flex items-center justify-center">1</span>
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Navigate to Settings</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Go to Settings &rarr; Staff Roles.</p>
</div>
</li>
<li className="flex items-start gap-3">
<span className="flex-shrink-0 w-6 h-6 rounded-full bg-brand-600 text-white text-sm flex items-center justify-center">2</span>
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Click "Create Role"</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Click the "Create Role" button to open the role creation form.</p>
</div>
</li>
<li className="flex items-start gap-3">
<span className="flex-shrink-0 w-6 h-6 rounded-full bg-brand-600 text-white text-sm flex items-center justify-center">3</span>
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Enter Role Details</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Provide a name (e.g., "Technician") and optional description.</p>
</div>
</li>
<li className="flex items-start gap-3">
<span className="flex-shrink-0 w-6 h-6 rounded-full bg-brand-600 text-white text-sm flex items-center justify-center">4</span>
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Select Menu Permissions</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Choose which sidebar menu items this role can access.</p>
</div>
</li>
<li className="flex items-start gap-3">
<span className="flex-shrink-0 w-6 h-6 rounded-full bg-brand-600 text-white text-sm flex items-center justify-center">5</span>
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Configure Dangerous Permissions</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Carefully choose delete permissions for critical operations.</p>
</div>
</li>
<li className="flex items-start gap-3">
<span className="flex-shrink-0 w-6 h-6 rounded-full bg-brand-600 text-white text-sm flex items-center justify-center">6</span>
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Save and Assign</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">Save the role and assign it to staff members.</p>
</div>
</li>
</ol>
</div>
</section>
{/* Menu Permissions */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Lock size={20} className="text-brand-500" />
Menu Permissions
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<p className="text-gray-600 dark:text-gray-300 mb-4">
Menu permissions control which sidebar items are visible to staff members with this role.
If a permission is not granted, the menu item will be hidden from the sidebar.
</p>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3">
<div className="flex items-start gap-2 p-3 bg-gray-50 dark:bg-gray-700/50 rounded-lg">
<CheckCircle size={16} className="text-brand-500 mt-0.5" />
<div>
<h5 className="text-sm font-medium text-gray-900 dark:text-white">Scheduler</h5>
<p className="text-xs text-gray-500 dark:text-gray-400">View and manage the calendar</p>
</div>
</div>
<div className="flex items-start gap-2 p-3 bg-gray-50 dark:bg-gray-700/50 rounded-lg">
<CheckCircle size={16} className="text-brand-500 mt-0.5" />
<div>
<h5 className="text-sm font-medium text-gray-900 dark:text-white">Services</h5>
<p className="text-xs text-gray-500 dark:text-gray-400">Manage offered services</p>
</div>
</div>
<div className="flex items-start gap-2 p-3 bg-gray-50 dark:bg-gray-700/50 rounded-lg">
<CheckCircle size={16} className="text-brand-500 mt-0.5" />
<div>
<h5 className="text-sm font-medium text-gray-900 dark:text-white">Resources</h5>
<p className="text-xs text-gray-500 dark:text-gray-400">Manage staff and equipment</p>
</div>
</div>
<div className="flex items-start gap-2 p-3 bg-gray-50 dark:bg-gray-700/50 rounded-lg">
<CheckCircle size={16} className="text-brand-500 mt-0.5" />
<div>
<h5 className="text-sm font-medium text-gray-900 dark:text-white">Staff</h5>
<p className="text-xs text-gray-500 dark:text-gray-400">Manage staff members</p>
</div>
</div>
<div className="flex items-start gap-2 p-3 bg-gray-50 dark:bg-gray-700/50 rounded-lg">
<CheckCircle size={16} className="text-brand-500 mt-0.5" />
<div>
<h5 className="text-sm font-medium text-gray-900 dark:text-white">Customers</h5>
<p className="text-xs text-gray-500 dark:text-gray-400">View customer information</p>
</div>
</div>
<div className="flex items-start gap-2 p-3 bg-gray-50 dark:bg-gray-700/50 rounded-lg">
<CheckCircle size={16} className="text-brand-500 mt-0.5" />
<div>
<h5 className="text-sm font-medium text-gray-900 dark:text-white">Time Blocks</h5>
<p className="text-xs text-gray-500 dark:text-gray-400">Manage availability blocks</p>
</div>
</div>
<div className="flex items-start gap-2 p-3 bg-gray-50 dark:bg-gray-700/50 rounded-lg">
<CheckCircle size={16} className="text-brand-500 mt-0.5" />
<div>
<h5 className="text-sm font-medium text-gray-900 dark:text-white">Messages</h5>
<p className="text-xs text-gray-500 dark:text-gray-400">Access messaging features</p>
</div>
</div>
<div className="flex items-start gap-2 p-3 bg-gray-50 dark:bg-gray-700/50 rounded-lg">
<CheckCircle size={16} className="text-brand-500 mt-0.5" />
<div>
<h5 className="text-sm font-medium text-gray-900 dark:text-white">Tickets</h5>
<p className="text-xs text-gray-500 dark:text-gray-400">Manage support tickets</p>
</div>
</div>
<div className="flex items-start gap-2 p-3 bg-gray-50 dark:bg-gray-700/50 rounded-lg">
<CheckCircle size={16} className="text-brand-500 mt-0.5" />
<div>
<h5 className="text-sm font-medium text-gray-900 dark:text-white">Payments</h5>
<p className="text-xs text-gray-500 dark:text-gray-400">View payment information</p>
</div>
</div>
<div className="flex items-start gap-2 p-3 bg-gray-50 dark:bg-gray-700/50 rounded-lg">
<CheckCircle size={16} className="text-brand-500 mt-0.5" />
<div>
<h5 className="text-sm font-medium text-gray-900 dark:text-white">Contracts</h5>
<p className="text-xs text-gray-500 dark:text-gray-400">Manage contracts and signatures</p>
</div>
</div>
<div className="flex items-start gap-2 p-3 bg-gray-50 dark:bg-gray-700/50 rounded-lg">
<CheckCircle size={16} className="text-brand-500 mt-0.5" />
<div>
<h5 className="text-sm font-medium text-gray-900 dark:text-white">Tasks</h5>
<p className="text-xs text-gray-500 dark:text-gray-400">View automation tasks</p>
</div>
</div>
<div className="flex items-start gap-2 p-3 bg-gray-50 dark:bg-gray-700/50 rounded-lg">
<CheckCircle size={16} className="text-brand-500 mt-0.5" />
<div>
<h5 className="text-sm font-medium text-gray-900 dark:text-white">Site Builder</h5>
<p className="text-xs text-gray-500 dark:text-gray-400">Edit marketing site pages</p>
</div>
</div>
<div className="flex items-start gap-2 p-3 bg-gray-50 dark:bg-gray-700/50 rounded-lg">
<CheckCircle size={16} className="text-brand-500 mt-0.5" />
<div>
<h5 className="text-sm font-medium text-gray-900 dark:text-white">Gallery</h5>
<p className="text-xs text-gray-500 dark:text-gray-400">Manage media gallery</p>
</div>
</div>
<div className="flex items-start gap-2 p-3 bg-gray-50 dark:bg-gray-700/50 rounded-lg">
<CheckCircle size={16} className="text-brand-500 mt-0.5" />
<div>
<h5 className="text-sm font-medium text-gray-900 dark:text-white">Settings</h5>
<p className="text-xs text-gray-500 dark:text-gray-400">Access business settings</p>
</div>
</div>
</div>
</div>
</section>
{/* Dangerous Permissions */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<AlertTriangle size={20} className="text-red-500" />
Dangerous Permissions
</h2>
<div className="bg-red-50 dark:bg-red-900/20 rounded-xl border border-red-200 dark:border-red-800 p-6">
<div className="flex items-start gap-3 mb-4">
<AlertTriangle size={20} className="text-red-600 dark:text-red-400 mt-0.5" />
<div>
<h3 className="font-semibold text-red-900 dark:text-red-100 mb-2">
Exercise Caution with These Permissions
</h3>
<p className="text-red-700 dark:text-red-300 text-sm mb-4">
Dangerous permissions allow staff to perform irreversible delete operations.
Only grant these permissions to trusted staff members.
</p>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="flex items-start gap-3 p-4 bg-white dark:bg-gray-800 rounded-lg border border-red-200 dark:border-red-800">
<AlertTriangle size={18} className="text-red-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Delete Customers</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
Allows staff to permanently delete customer records and all associated data
</p>
</div>
</div>
<div className="flex items-start gap-3 p-4 bg-white dark:bg-gray-800 rounded-lg border border-red-200 dark:border-red-800">
<AlertTriangle size={18} className="text-red-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Delete Appointments</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
Allows staff to permanently delete scheduled appointments
</p>
</div>
</div>
<div className="flex items-start gap-3 p-4 bg-white dark:bg-gray-800 rounded-lg border border-red-200 dark:border-red-800">
<AlertTriangle size={18} className="text-red-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Delete Services</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
Allows staff to permanently delete services from your offerings
</p>
</div>
</div>
<div className="flex items-start gap-3 p-4 bg-white dark:bg-gray-800 rounded-lg border border-red-200 dark:border-red-800">
<AlertTriangle size={18} className="text-red-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Delete Resources</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
Allows staff to permanently delete resources (staff members, rooms, equipment)
</p>
</div>
</div>
</div>
</div>
</section>
{/* Assigning Roles */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<Users size={20} className="text-brand-500" />
Assigning Roles to Staff
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<p className="text-gray-600 dark:text-gray-300 mb-4">
Once you've created a role, you can assign it to staff members to apply the permissions:
</p>
<ol className="space-y-3">
<li className="flex items-start gap-3">
<span className="flex-shrink-0 w-6 h-6 rounded-full bg-brand-600 text-white text-sm flex items-center justify-center">1</span>
<div>
<p className="text-sm text-gray-600 dark:text-gray-300">
Navigate to <strong>Staff</strong> in the sidebar
</p>
</div>
</li>
<li className="flex items-start gap-3">
<span className="flex-shrink-0 w-6 h-6 rounded-full bg-brand-600 text-white text-sm flex items-center justify-center">2</span>
<div>
<p className="text-sm text-gray-600 dark:text-gray-300">
Click on a staff member to edit their details
</p>
</div>
</li>
<li className="flex items-start gap-3">
<span className="flex-shrink-0 w-6 h-6 rounded-full bg-brand-600 text-white text-sm flex items-center justify-center">3</span>
<div>
<p className="text-sm text-gray-600 dark:text-gray-300">
Select the desired role from the <strong>Staff Role</strong> dropdown
</p>
</div>
</li>
<li className="flex items-start gap-3">
<span className="flex-shrink-0 w-6 h-6 rounded-full bg-brand-600 text-white text-sm flex items-center justify-center">4</span>
<div>
<p className="text-sm text-gray-600 dark:text-gray-300">
Save changes - permissions apply immediately
</p>
</div>
</li>
</ol>
<div className="mt-4 p-4 bg-blue-50 dark:bg-blue-900/20 rounded-lg border border-blue-200 dark:border-blue-800">
<p className="text-sm text-blue-700 dark:text-blue-300">
<strong>Note:</strong> The Staff Roles page shows how many staff members are assigned to each role.
This helps you track role usage across your team.
</p>
</div>
</div>
</section>
{/* Tips Section */}
<section className="mb-10">
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<CheckCircle size={20} className="text-brand-500" />
Best Practices & Tips
</h2>
<div className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6">
<ul className="space-y-3">
<li className="flex items-start gap-3">
<CheckCircle size={18} className="text-green-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Start with Default Roles</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
Use the built-in roles (Full Access, Limited, Front Desk) as templates when creating custom roles
</p>
</div>
</li>
<li className="flex items-start gap-3">
<CheckCircle size={18} className="text-green-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Principle of Least Privilege</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
Only grant permissions that staff members need to do their job - nothing more
</p>
</div>
</li>
<li className="flex items-start gap-3">
<CheckCircle size={18} className="text-green-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Use Descriptive Names</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
Name roles clearly (e.g., "Massage Therapist", "Receptionist") so their purpose is obvious
</p>
</div>
</li>
<li className="flex items-start gap-3">
<CheckCircle size={18} className="text-green-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Limit Dangerous Permissions</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
Be very selective about granting delete permissions - these operations cannot be undone
</p>
</div>
</li>
<li className="flex items-start gap-3">
<CheckCircle size={18} className="text-green-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Review Regularly</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
Periodically review staff roles and permissions to ensure they're still appropriate
</p>
</div>
</li>
<li className="flex items-start gap-3">
<CheckCircle size={18} className="text-green-500 mt-0.5" />
<div>
<h4 className="font-medium text-gray-900 dark:text-white">Add Descriptions</h4>
<p className="text-sm text-gray-500 dark:text-gray-400">
Include a description when creating roles to document their intended purpose and use cases
</p>
</div>
</li>
</ul>
</div>
</section>
{/* Need More Help */}
<section className="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 p-6 text-center">
<HelpCircle size={32} className="mx-auto text-brand-500 mb-3" />
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-2">
Need More Help?
</h3>
<p className="text-gray-600 dark:text-gray-300 mb-4">
Our support team is ready to help with any questions about staff roles and permissions.
</p>
<button
onClick={() => navigate('/dashboard/tickets')}
className="px-6 py-2 bg-brand-600 text-white rounded-lg hover:bg-brand-700 transition-colors"
>
Contact Support
</button>
</section>
</div>
);
};
export default HelpSettingsStaffRoles;