feat: Add comprehensive sandbox mode, public API system, and platform support
This commit adds major features for sandbox isolation, public API access, and platform support ticketing. ## Sandbox Mode - Add sandbox mode toggle for businesses to test features without affecting live data - Implement schema-based isolation for tenant data (appointments, resources, services) - Add is_sandbox field filtering for shared models (customers, staff, tickets) - Create sandbox middleware to detect and set sandbox mode from cookies - Add sandbox context and hooks for React frontend - Display sandbox banner when in test mode - Auto-reload page when switching between live/test modes - Prevent platform support tickets from being created in sandbox mode ## Public API System - Full REST API for external integrations with businesses - API token management with sandbox/live token separation - Test tokens (ss_test_*) show full plaintext for easy testing - Live tokens (ss_live_*) are hashed and secure - Security validation prevents live token plaintext storage - Comprehensive test suite for token security - Rate limiting and throttling per token - Webhook support for real-time event notifications - Scoped permissions system (read/write per resource type) - API documentation page with interactive examples - Token revocation with confirmation modal ## Platform Support - Dedicated support page for businesses to contact SmoothSchedule - View all platform support tickets in one place - Create new support tickets with simplified interface - Reply to existing tickets with conversation history - Platform tickets have no admin controls (no priority/category/assignee/status) - Internal notes hidden for platform tickets (business can't see them) - Quick help section with links to guides and API docs - Sandbox warning prevents ticket creation in test mode - Business ticketing retains full admin controls (priority, assignment, internal notes) ## UI/UX Improvements - Add notification dropdown with real-time updates - Staff permissions UI for ticket access control - Help dropdown in sidebar with Platform Guide, Ticketing Help, API Docs, and Support - Update sidebar "Contact Support" to "Support" with message icon - Fix navigation links to use React Router instead of anchor tags - Remove unused language translations (Japanese, Portuguese, Chinese) ## Technical Details - Sandbox middleware sets request.sandbox_mode from cookies - ViewSets filter data by is_sandbox field - API authentication via custom token auth class - WebSocket support for real-time ticket updates - Migration for sandbox fields on User, Tenant, and Ticket models - Comprehensive documentation in SANDBOX_MODE_IMPLEMENTATION.md 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -39,6 +39,7 @@ import Resources from './pages/Resources';
|
||||
import Services from './pages/Services';
|
||||
import Staff from './pages/Staff';
|
||||
import CustomerDashboard from './pages/customer/CustomerDashboard';
|
||||
import CustomerSupport from './pages/customer/CustomerSupport';
|
||||
import ResourceDashboard from './pages/resource/ResourceDashboard';
|
||||
import BookingPage from './pages/customer/BookingPage';
|
||||
import TrialExpired from './pages/TrialExpired';
|
||||
@@ -47,7 +48,7 @@ import Upgrade from './pages/Upgrade';
|
||||
// Import platform pages
|
||||
import PlatformDashboard from './pages/platform/PlatformDashboard';
|
||||
import PlatformBusinesses from './pages/platform/PlatformBusinesses';
|
||||
import PlatformSupport from './pages/platform/PlatformSupport';
|
||||
import PlatformSupportPage from './pages/platform/PlatformSupport';
|
||||
import PlatformUsers from './pages/platform/PlatformUsers';
|
||||
import PlatformSettings from './pages/platform/PlatformSettings';
|
||||
import ProfileSettings from './pages/ProfileSettings';
|
||||
@@ -56,6 +57,10 @@ import EmailVerificationRequired from './pages/EmailVerificationRequired';
|
||||
import AcceptInvitePage from './pages/AcceptInvitePage';
|
||||
import TenantOnboardPage from './pages/TenantOnboardPage';
|
||||
import Tickets from './pages/Tickets'; // Import Tickets page
|
||||
import HelpGuide from './pages/HelpGuide'; // Import Platform Guide page
|
||||
import HelpTicketing from './pages/HelpTicketing'; // Import Help page for ticketing
|
||||
import HelpApiDocs from './pages/HelpApiDocs'; // Import API documentation page
|
||||
import PlatformSupport from './pages/PlatformSupport'; // Import Platform Support page (for businesses to contact SmoothSchedule)
|
||||
import { Toaster } from 'react-hot-toast'; // Import Toaster for notifications
|
||||
|
||||
const queryClient = new QueryClient({
|
||||
@@ -321,7 +326,10 @@ const AppContent: React.FC = () => {
|
||||
<Route path="/platform/users" element={<PlatformUsers onMasquerade={handleMasquerade} />} />
|
||||
</>
|
||||
)}
|
||||
<Route path="/platform/support" element={<PlatformSupport />} />
|
||||
<Route path="/platform/support" element={<PlatformSupportPage />} />
|
||||
<Route path="/help/guide" element={<HelpGuide />} />
|
||||
<Route path="/help/ticketing" element={<HelpTicketing />} />
|
||||
<Route path="/help/api" element={<HelpApiDocs />} />
|
||||
{user.role === 'superuser' && (
|
||||
<Route path="/platform/settings" element={<PlatformSettings />} />
|
||||
)}
|
||||
@@ -346,19 +354,47 @@ const AppContent: React.FC = () => {
|
||||
|
||||
// Customer users
|
||||
if (user.role === 'customer') {
|
||||
// Wait for business data to load
|
||||
if (businessLoading) {
|
||||
return <LoadingScreen />;
|
||||
}
|
||||
|
||||
// Handle business not found for customers
|
||||
if (!business) {
|
||||
return (
|
||||
<div className="min-h-screen flex items-center justify-center bg-gray-50 dark:bg-gray-900">
|
||||
<div className="text-center max-w-md p-6">
|
||||
<h2 className="text-2xl font-bold text-red-600 dark:text-red-400 mb-4">Business Not Found</h2>
|
||||
<p className="text-gray-600 dark:text-gray-400 mb-4">
|
||||
Unable to load business data. Please try again.
|
||||
</p>
|
||||
<button
|
||||
onClick={handleSignOut}
|
||||
className="px-4 py-2 bg-gray-600 text-white rounded hover:bg-gray-700"
|
||||
>
|
||||
Sign Out
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Routes>
|
||||
<Route
|
||||
element={
|
||||
<CustomerLayout
|
||||
business={business || ({} as any)}
|
||||
business={business}
|
||||
user={user}
|
||||
darkMode={darkMode}
|
||||
toggleTheme={toggleTheme}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<Route path="/" element={<CustomerDashboard />} />
|
||||
<Route path="/book" element={<BookingPage />} />
|
||||
<Route path="/payments" element={<Payments />} />
|
||||
<Route path="/support" element={<CustomerSupport />} />
|
||||
<Route path="/profile" element={<ProfileSettings />} />
|
||||
<Route path="/verify-email" element={<VerifyEmail />} />
|
||||
<Route path="*" element={<Navigate to="/" />} />
|
||||
@@ -470,6 +506,10 @@ const AppContent: React.FC = () => {
|
||||
/>
|
||||
<Route path="/scheduler" element={<Scheduler />} />
|
||||
<Route path="/tickets" element={<Tickets />} />
|
||||
<Route path="/help/guide" element={<HelpGuide />} />
|
||||
<Route path="/help/ticketing" element={<HelpTicketing />} />
|
||||
<Route path="/help/api" element={<HelpApiDocs />} />
|
||||
<Route path="/support" element={<PlatformSupport />} />
|
||||
<Route
|
||||
path="/customers"
|
||||
element={
|
||||
|
||||
Reference in New Issue
Block a user