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:
@@ -92,6 +92,12 @@ const HelpPayments = React.lazy(() => import('./pages/help/HelpPayments'));
|
|||||||
const HelpContracts = React.lazy(() => import('./pages/help/HelpContracts'));
|
const HelpContracts = React.lazy(() => import('./pages/help/HelpContracts'));
|
||||||
const HelpAutomations = React.lazy(() => import('./pages/help/HelpAutomations'));
|
const HelpAutomations = React.lazy(() => import('./pages/help/HelpAutomations'));
|
||||||
const HelpSiteBuilder = React.lazy(() => import('./pages/help/HelpSiteBuilder'));
|
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 HelpSettingsGeneral = React.lazy(() => import('./pages/help/HelpSettingsGeneral'));
|
||||||
const HelpSettingsResourceTypes = React.lazy(() => import('./pages/help/HelpSettingsResourceTypes'));
|
const HelpSettingsResourceTypes = React.lazy(() => import('./pages/help/HelpSettingsResourceTypes'));
|
||||||
const HelpSettingsBooking = React.lazy(() => import('./pages/help/HelpSettingsBooking'));
|
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 HelpSettingsAuth = React.lazy(() => import('./pages/help/HelpSettingsAuth'));
|
||||||
const HelpSettingsBilling = React.lazy(() => import('./pages/help/HelpSettingsBilling'));
|
const HelpSettingsBilling = React.lazy(() => import('./pages/help/HelpSettingsBilling'));
|
||||||
const HelpSettingsQuota = React.lazy(() => import('./pages/help/HelpSettingsQuota'));
|
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 HelpComprehensive = React.lazy(() => import('./pages/help/HelpComprehensive'));
|
||||||
const StaffHelp = React.lazy(() => import('./pages/help/StaffHelp'));
|
const StaffHelp = React.lazy(() => import('./pages/help/StaffHelp'));
|
||||||
const PlatformSupport = React.lazy(() => import('./pages/PlatformSupport')); // Import Platform Support page (for businesses to contact SmoothSchedule)
|
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/contracts" element={<HelpContracts />} />
|
||||||
<Route path="/dashboard/help/automations" element={<HelpAutomations />} />
|
<Route path="/dashboard/help/automations" element={<HelpAutomations />} />
|
||||||
<Route path="/dashboard/help/site-builder" element={<HelpSiteBuilder />} />
|
<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/general" element={<HelpSettingsGeneral />} />
|
||||||
<Route path="/dashboard/help/settings/resource-types" element={<HelpSettingsResourceTypes />} />
|
<Route path="/dashboard/help/settings/resource-types" element={<HelpSettingsResourceTypes />} />
|
||||||
<Route path="/dashboard/help/settings/booking" element={<HelpSettingsBooking />} />
|
<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/auth" element={<HelpSettingsAuth />} />
|
||||||
<Route path="/dashboard/help/settings/billing" element={<HelpSettingsBilling />} />
|
<Route path="/dashboard/help/settings/billing" element={<HelpSettingsBilling />} />
|
||||||
<Route path="/dashboard/help/settings/quota" element={<HelpSettingsQuota />} />
|
<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
|
<Route
|
||||||
path="/dashboard/automations/marketplace"
|
path="/dashboard/automations/marketplace"
|
||||||
element={
|
element={
|
||||||
|
|||||||
@@ -16,10 +16,12 @@ const routeToHelpSuffix: Record<string, string> = {
|
|||||||
'/': 'dashboard',
|
'/': 'dashboard',
|
||||||
'/dashboard': 'dashboard',
|
'/dashboard': 'dashboard',
|
||||||
'/scheduler': 'scheduler',
|
'/scheduler': 'scheduler',
|
||||||
|
'/my-schedule': 'scheduler',
|
||||||
'/tasks': 'tasks',
|
'/tasks': 'tasks',
|
||||||
'/customers': 'customers',
|
'/customers': 'customers',
|
||||||
'/services': 'services',
|
'/services': 'services',
|
||||||
'/resources': 'resources',
|
'/resources': 'resources',
|
||||||
|
'/locations': 'locations',
|
||||||
'/staff': 'staff',
|
'/staff': 'staff',
|
||||||
'/time-blocks': 'time-blocks',
|
'/time-blocks': 'time-blocks',
|
||||||
'/my-availability': 'time-blocks',
|
'/my-availability': 'time-blocks',
|
||||||
@@ -39,7 +41,13 @@ const routeToHelpSuffix: Record<string, string> = {
|
|||||||
'/settings/resource-types': 'settings/resource-types',
|
'/settings/resource-types': 'settings/resource-types',
|
||||||
'/settings/booking': 'settings/booking',
|
'/settings/booking': 'settings/booking',
|
||||||
'/settings/appearance': 'settings/appearance',
|
'/settings/appearance': 'settings/appearance',
|
||||||
|
'/settings/branding': 'settings/appearance',
|
||||||
|
'/settings/business-hours': 'settings/business-hours',
|
||||||
'/settings/email': 'settings/email',
|
'/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/domains': 'settings/domains',
|
||||||
'/settings/api': 'settings/api',
|
'/settings/api': 'settings/api',
|
||||||
'/settings/auth': 'settings/auth',
|
'/settings/auth': 'settings/auth',
|
||||||
|
|||||||
@@ -84,6 +84,42 @@ describe('FloatingHelpButton', () => {
|
|||||||
const link = screen.getByRole('link');
|
const link = screen.getByRole('link');
|
||||||
expect(link).toHaveAttribute('href', '/dashboard/help/site-builder');
|
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)', () => {
|
describe('non-dashboard routes (public/platform)', () => {
|
||||||
@@ -111,6 +147,42 @@ describe('FloatingHelpButton', () => {
|
|||||||
expect(link).toHaveAttribute('href', '/help/settings/general');
|
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', () => {
|
it('returns null on /help pages', () => {
|
||||||
const { container } = renderWithRouter('/help/dashboard');
|
const { container } = renderWithRouter('/help/dashboard');
|
||||||
expect(container.firstChild).toBeNull();
|
expect(container.firstChild).toBeNull();
|
||||||
|
|||||||
@@ -1591,7 +1591,13 @@
|
|||||||
"billing": "Abrechnung",
|
"billing": "Abrechnung",
|
||||||
"apiSettings": "API-Einstellungen",
|
"apiSettings": "API-Einstellungen",
|
||||||
"authentication": "Authentifizierung",
|
"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": {
|
"introduction": {
|
||||||
"title": "Einführung",
|
"title": "Einführung",
|
||||||
@@ -1851,6 +1857,19 @@
|
|||||||
"contractsDocumentation": "Vertragsdokumentation",
|
"contractsDocumentation": "Vertragsdokumentation",
|
||||||
"contractsDocumentationDesc": "Vollständige Anleitung zu Vorlagen, Unterzeichnung und Konformitätsfunktionen"
|
"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": {
|
"settings": {
|
||||||
"title": "Einstellungen",
|
"title": "Einstellungen",
|
||||||
"description": "In den Einstellungen konfigurieren Geschäftsinhaber ihre Terminplanungsplattform. Die meisten Einstellungen sind nur für Inhaber und beeinflussen den Geschäftsbetrieb.",
|
"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",
|
"apiSettingsLink": "API-Einstellungen",
|
||||||
"apiSettingsLinkDesc": "API-Schlüssel und Webhooks",
|
"apiSettingsLinkDesc": "API-Schlüssel und Webhooks",
|
||||||
"usageQuotaLink": "Nutzung & Kontingent",
|
"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": {
|
"footer": {
|
||||||
"title": "Benötigen Sie weitere Hilfe?",
|
"title": "Benötigen Sie weitere Hilfe?",
|
||||||
|
|||||||
@@ -3059,6 +3059,7 @@
|
|||||||
"timeBlocks": "Time Blocks",
|
"timeBlocks": "Time Blocks",
|
||||||
"plugins": "Plugins",
|
"plugins": "Plugins",
|
||||||
"contracts": "Contracts",
|
"contracts": "Contracts",
|
||||||
|
"locations": "Locations",
|
||||||
"settings": "Settings",
|
"settings": "Settings",
|
||||||
"servicesSetup": "Services Setup",
|
"servicesSetup": "Services Setup",
|
||||||
"resourcesSetup": "Resources Setup",
|
"resourcesSetup": "Resources Setup",
|
||||||
@@ -3070,7 +3071,12 @@
|
|||||||
"billing": "Billing",
|
"billing": "Billing",
|
||||||
"apiSettings": "API Settings",
|
"apiSettings": "API Settings",
|
||||||
"authentication": "Authentication",
|
"authentication": "Authentication",
|
||||||
"usageQuota": "Usage & Quota"
|
"usageQuota": "Usage & Quota",
|
||||||
|
"businessHours": "Business Hours",
|
||||||
|
"emailTemplates": "Email Templates",
|
||||||
|
"embedWidget": "Embed Widget",
|
||||||
|
"staffRoles": "Staff Roles",
|
||||||
|
"smsCalling": "SMS & Calling"
|
||||||
},
|
},
|
||||||
"introduction": {
|
"introduction": {
|
||||||
"title": "Introduction",
|
"title": "Introduction",
|
||||||
@@ -3336,6 +3342,19 @@
|
|||||||
"contractsDocumentation": "Contracts Documentation",
|
"contractsDocumentation": "Contracts Documentation",
|
||||||
"contractsDocumentationDesc": "Complete guide to templates, signing, and compliance features"
|
"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": {
|
"settings": {
|
||||||
"title": "Settings",
|
"title": "Settings",
|
||||||
"description": "Settings is where business owners configure their scheduling platform. Most settings are owner-only and affect how your business operates.",
|
"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",
|
"apiSettingsLink": "API Settings",
|
||||||
"apiSettingsLinkDesc": "API keys and webhooks",
|
"apiSettingsLinkDesc": "API keys and webhooks",
|
||||||
"usageQuotaLink": "Usage & Quota",
|
"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 & Calling",
|
||||||
|
"smsCallingLinkDesc": "Manage communication credits and phone numbers"
|
||||||
},
|
},
|
||||||
"footer": {
|
"footer": {
|
||||||
"title": "Need More Help?",
|
"title": "Need More Help?",
|
||||||
|
|||||||
@@ -1662,7 +1662,13 @@
|
|||||||
"billing": "Facturación",
|
"billing": "Facturación",
|
||||||
"apiSettings": "Configuración de API",
|
"apiSettings": "Configuración de API",
|
||||||
"authentication": "Autenticación",
|
"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": {
|
"introduction": {
|
||||||
"title": "Introducción",
|
"title": "Introducción",
|
||||||
@@ -1928,6 +1934,19 @@
|
|||||||
"contractsDocumentation": "Documentación de Contratos",
|
"contractsDocumentation": "Documentación de Contratos",
|
||||||
"contractsDocumentationDesc": "Guía completa de plantillas, firma y funciones de cumplimiento"
|
"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": {
|
"settings": {
|
||||||
"title": "Configuración",
|
"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.",
|
"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",
|
"otherSettings": "Otras Configuraciones",
|
||||||
"resourceTypesLink": "Tipos de Recurso",
|
"resourceTypesLink": "Tipos de Recurso",
|
||||||
"resourceTypesLinkDesc": "Configura tipos de personal, sala, equipo",
|
"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",
|
"emailTemplatesLink": "Plantillas de Email",
|
||||||
"emailTemplatesLinkDesc": "Personaliza notificaciones por 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",
|
"customDomainsLink": "Dominios Personalizados",
|
||||||
"customDomainsLinkDesc": "Usa tu propio dominio para reservas",
|
"customDomainsLinkDesc": "Usa tu propio dominio para reservas",
|
||||||
"billingLink": "Facturación",
|
"billingLink": "Facturación",
|
||||||
|
|||||||
@@ -1591,6 +1591,7 @@
|
|||||||
"timeBlocks": "Blocs de Temps",
|
"timeBlocks": "Blocs de Temps",
|
||||||
"plugins": "Plugins",
|
"plugins": "Plugins",
|
||||||
"contracts": "Contrats",
|
"contracts": "Contrats",
|
||||||
|
"locations": "Emplacements",
|
||||||
"settings": "Paramètres",
|
"settings": "Paramètres",
|
||||||
"servicesSetup": "Configuration des Services",
|
"servicesSetup": "Configuration des Services",
|
||||||
"resourcesSetup": "Configuration des Ressources",
|
"resourcesSetup": "Configuration des Ressources",
|
||||||
@@ -1602,7 +1603,12 @@
|
|||||||
"billing": "Facturation",
|
"billing": "Facturation",
|
||||||
"apiSettings": "Paramètres API",
|
"apiSettings": "Paramètres API",
|
||||||
"authentication": "Authentification",
|
"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": {
|
"introduction": {
|
||||||
"title": "Introduction",
|
"title": "Introduction",
|
||||||
@@ -1868,6 +1874,19 @@
|
|||||||
"contractsDocumentation": "Documentation des Contrats",
|
"contractsDocumentation": "Documentation des Contrats",
|
||||||
"contractsDocumentationDesc": "Guide complet sur les modèles, la signature et les fonctions de conformité"
|
"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": {
|
"settings": {
|
||||||
"title": "Paramètres",
|
"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.",
|
"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",
|
"apiSettingsLink": "Paramètres API",
|
||||||
"apiSettingsLinkDesc": "Clés API et webhooks",
|
"apiSettingsLinkDesc": "Clés API et webhooks",
|
||||||
"usageQuotaLink": "Utilisation et Quota",
|
"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": {
|
"footer": {
|
||||||
"title": "Besoin de Plus d'Aide ?",
|
"title": "Besoin de Plus d'Aide ?",
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
430
frontend/src/pages/help/HelpApiAppointments.tsx
Normal file
430
frontend/src/pages/help/HelpApiAppointments.tsx
Normal 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/{id}/</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/{id}/</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/{id}/</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;
|
||||||
386
frontend/src/pages/help/HelpApiCustomers.tsx
Normal file
386
frontend/src/pages/help/HelpApiCustomers.tsx
Normal 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/{id}/</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/{id}/</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;
|
||||||
551
frontend/src/pages/help/HelpApiOverview.tsx
Normal file
551
frontend/src/pages/help/HelpApiOverview.tsx
Normal 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;
|
||||||
337
frontend/src/pages/help/HelpApiResources.tsx
Normal file
337
frontend/src/pages/help/HelpApiResources.tsx
Normal 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;
|
||||||
307
frontend/src/pages/help/HelpApiServices.tsx
Normal file
307
frontend/src/pages/help/HelpApiServices.tsx
Normal 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;
|
||||||
513
frontend/src/pages/help/HelpApiWebhooks.tsx
Normal file
513
frontend/src/pages/help/HelpApiWebhooks.tsx
Normal 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;
|
||||||
@@ -14,7 +14,7 @@ import {
|
|||||||
Clock, Eye, Palette, Link2, Mail, Globe, CreditCard, Zap, Search, Filter,
|
Clock, Eye, Palette, Link2, Mail, Globe, CreditCard, Zap, Search, Filter,
|
||||||
Plus, Edit, Trash2, ArrowUpDown, GripVertical, Image, Save, ExternalLink,
|
Plus, Edit, Trash2, ArrowUpDown, GripVertical, Image, Save, ExternalLink,
|
||||||
MessageSquare, Tag, UserPlus, Shield, Copy, Layers, Play, Pause, Puzzle,
|
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';
|
} from 'lucide-react';
|
||||||
|
|
||||||
interface TocSubItem {
|
interface TocSubItem {
|
||||||
@@ -55,9 +55,11 @@ const HelpComprehensive: React.FC = () => {
|
|||||||
{ id: 'customers', label: t('helpComprehensive.toc.customers'), icon: <Users size={16} /> },
|
{ id: 'customers', label: t('helpComprehensive.toc.customers'), icon: <Users size={16} /> },
|
||||||
{ id: 'staff', label: t('helpComprehensive.toc.staff'), icon: <UserCog 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: '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: 'site-builder', label: 'Site Builder', icon: <Layers size={16} /> },
|
||||||
{ id: 'automations', label: 'Automations', icon: <Puzzle size={16} /> },
|
{ id: 'automations', label: 'Automations', icon: <Puzzle size={16} /> },
|
||||||
{ id: 'contracts', label: t('helpComprehensive.toc.contracts'), icon: <FileSignature size={16} /> },
|
{ id: 'contracts', label: t('helpComprehensive.toc.contracts'), icon: <FileSignature size={16} /> },
|
||||||
|
{ id: 'api', label: 'API', icon: <Code size={16} /> },
|
||||||
{
|
{
|
||||||
id: 'settings',
|
id: 'settings',
|
||||||
label: t('helpComprehensive.toc.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.apiSettings'), href: '/help/settings/api' },
|
||||||
{ label: t('helpComprehensive.toc.authentication'), href: '/help/settings/auth' },
|
{ label: t('helpComprehensive.toc.authentication'), href: '/help/settings/auth' },
|
||||||
{ label: t('helpComprehensive.toc.usageQuota'), href: '/help/settings/quota' },
|
{ 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>
|
</Link>
|
||||||
</section>
|
</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 */}
|
{/* SITE BUILDER */}
|
||||||
{/* ============================================== */}
|
{/* ============================================== */}
|
||||||
@@ -1000,6 +1059,100 @@ const HelpComprehensive: React.FC = () => {
|
|||||||
</Link>
|
</Link>
|
||||||
</section>
|
</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 */}
|
{/* 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>
|
<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>
|
<p className="text-xs text-gray-500 dark:text-gray-400">{t('helpComprehensive.settings.usageQuotaLinkDesc')}</p>
|
||||||
</Link>
|
</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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
358
frontend/src/pages/help/HelpLocations.tsx
Normal file
358
frontend/src/pages/help/HelpLocations.tsx
Normal 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;
|
||||||
275
frontend/src/pages/help/HelpSettingsBusinessHours.tsx
Normal file
275
frontend/src/pages/help/HelpSettingsBusinessHours.tsx
Normal 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 → 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;
|
||||||
425
frontend/src/pages/help/HelpSettingsCommunication.tsx
Normal file
425
frontend/src/pages/help/HelpSettingsCommunication.tsx
Normal 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;
|
||||||
478
frontend/src/pages/help/HelpSettingsEmailTemplates.tsx
Normal file
478
frontend/src/pages/help/HelpSettingsEmailTemplates.tsx
Normal 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 → 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 {{customer_name}}) 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">{{tag_name}}</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">
|
||||||
|
{{customer_name}}
|
||||||
|
</div>
|
||||||
|
<div className="p-2 bg-gray-50 dark:bg-gray-700/50 rounded font-mono">
|
||||||
|
{{customer_email}}
|
||||||
|
</div>
|
||||||
|
<div className="p-2 bg-gray-50 dark:bg-gray-700/50 rounded font-mono">
|
||||||
|
{{customer_phone}}
|
||||||
|
</div>
|
||||||
|
<div className="p-2 bg-gray-50 dark:bg-gray-700/50 rounded font-mono">
|
||||||
|
{{customer_id}}
|
||||||
|
</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">
|
||||||
|
{{appointment_date}}
|
||||||
|
</div>
|
||||||
|
<div className="p-2 bg-gray-50 dark:bg-gray-700/50 rounded font-mono">
|
||||||
|
{{appointment_time}}
|
||||||
|
</div>
|
||||||
|
<div className="p-2 bg-gray-50 dark:bg-gray-700/50 rounded font-mono">
|
||||||
|
{{appointment_duration}}
|
||||||
|
</div>
|
||||||
|
<div className="p-2 bg-gray-50 dark:bg-gray-700/50 rounded font-mono">
|
||||||
|
{{service_name}}
|
||||||
|
</div>
|
||||||
|
<div className="p-2 bg-gray-50 dark:bg-gray-700/50 rounded font-mono">
|
||||||
|
{{staff_name}}
|
||||||
|
</div>
|
||||||
|
<div className="p-2 bg-gray-50 dark:bg-gray-700/50 rounded font-mono">
|
||||||
|
{{location}}
|
||||||
|
</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">
|
||||||
|
{{business_name}}
|
||||||
|
</div>
|
||||||
|
<div className="p-2 bg-gray-50 dark:bg-gray-700/50 rounded font-mono">
|
||||||
|
{{business_phone}}
|
||||||
|
</div>
|
||||||
|
<div className="p-2 bg-gray-50 dark:bg-gray-700/50 rounded font-mono">
|
||||||
|
{{business_email}}
|
||||||
|
</div>
|
||||||
|
<div className="p-2 bg-gray-50 dark:bg-gray-700/50 rounded font-mono">
|
||||||
|
{{business_address}}
|
||||||
|
</div>
|
||||||
|
<div className="p-2 bg-gray-50 dark:bg-gray-700/50 rounded font-mono">
|
||||||
|
{{business_website}}
|
||||||
|
</div>
|
||||||
|
<div className="p-2 bg-gray-50 dark:bg-gray-700/50 rounded font-mono">
|
||||||
|
{{business_logo}}
|
||||||
|
</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">
|
||||||
|
{{confirmation_link}}
|
||||||
|
</div>
|
||||||
|
<div className="p-2 bg-gray-50 dark:bg-gray-700/50 rounded font-mono">
|
||||||
|
{{cancellation_link}}
|
||||||
|
</div>
|
||||||
|
<div className="p-2 bg-gray-50 dark:bg-gray-700/50 rounded font-mono">
|
||||||
|
{{reschedule_link}}
|
||||||
|
</div>
|
||||||
|
<div className="p-2 bg-gray-50 dark:bg-gray-700/50 rounded font-mono">
|
||||||
|
{{current_year}}
|
||||||
|
</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 {{business_logo}} 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;
|
||||||
299
frontend/src/pages/help/HelpSettingsEmbedWidget.tsx
Normal file
299
frontend/src/pages/help/HelpSettingsEmbedWidget.tsx
Normal 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 </body> 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;
|
||||||
482
frontend/src/pages/help/HelpSettingsStaffRoles.tsx
Normal file
482
frontend/src/pages/help/HelpSettingsStaffRoles.tsx
Normal 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 → 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;
|
||||||
Reference in New Issue
Block a user