Major features: - Add drag-and-drop photo gallery to Service create/edit modals - Add Resource Types management section to Settings (CRUD for custom types) - Add edit icon consistency to Resources table (pencil icon in actions) - Improve Services page with drag-to-reorder and customer preview mockup Backend changes: - Add photos JSONField to Service model with migration - Add ResourceType model with category (STAFF/OTHER), description fields - Add ResourceTypeViewSet with CRUD operations - Add service reorder endpoint for display order Frontend changes: - Services page: two-column layout, drag-reorder, photo upload - Settings page: Resource Types tab with full CRUD modal - Resources page: Edit icon in actions column instead of row click - Sidebar: Payments link visibility based on role and paymentsEnabled - Update types.ts with Service.photos and ResourceTypeDefinition Note: Removed photos from ResourceType (kept only for Service) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
6.1 KiB
SmoothSchedule Frontend Development Guide
Project Overview
This is the React frontend for SmoothSchedule, a multi-tenant scheduling platform.
See also: /home/poduck/Desktop/smoothschedule2/smoothschedule/CLAUDE.md for backend documentation.
Key Paths
/home/poduck/Desktop/smoothschedule2/
├── frontend/ # This React frontend
│ ├── src/
│ │ ├── api/client.ts # Axios API client
│ │ ├── components/ # Reusable components
│ │ ├── hooks/ # React Query hooks (useResources, useAuth, etc.)
│ │ ├── pages/ # Page components
│ │ ├── types.ts # TypeScript interfaces
│ │ ├── i18n/locales/en.json # English translations
│ │ └── utils/cookies.ts # Cookie utilities
│ ├── .env.development # Frontend env vars
│ └── vite.config.ts # Vite configuration
│
└── smoothschedule/ # Django backend (runs in Docker!)
├── docker-compose.local.yml # Docker config
├── .envs/.local/ # Backend env vars
├── config/settings/ # Django settings
└── smoothschedule/
├── schedule/ # Core scheduling app
└── users/ # User management
Local Development Domain Setup
Why lvh.me instead of localhost?
This project uses lvh.me for local development instead of localhost due to cookie domain restrictions in RFC 6265.
The Problem with localhost:
- Browsers reject cookies with
domain=.localhostfor security reasons localhostis treated as a special-use domain where domain cookies don't work- Cannot share cookies across subdomains like
platform.localhostandbusiness.localhost
The Solution - lvh.me:
lvh.meis a public DNS service that resolves all*.lvh.medomains to127.0.0.1- Browsers allow setting cookies with
domain=.lvh.me - Cookies are accessible across all subdomains (platform.lvh.me, business1.lvh.me, etc.)
- No /etc/hosts configuration needed - it just works!
Development URLs
Use these URLs for local development:
- Base domain:
http://lvh.me:5173 - Platform dashboard:
http://platform.lvh.me:5173 - Business subdomains:
http://{subdomain}.lvh.me:5173
Multi-Tenant Architecture
The application uses subdomain-based multi-tenancy:
-
Platform Users (superuser, platform_manager, platform_support)
- Access the app at
http://platform.lvh.me:5173 - See platform dashboard and administrative features
- Access the app at
-
Business Users (owner, manager, staff, resource)
- Access the app at
http://{business_subdomain}.lvh.me:5173 - See business-specific dashboard and features
- Access the app at
Cookie-Based Authentication
Tokens are stored in cookies with domain=.lvh.me to enable cross-subdomain access:
// Set cookie accessible across all *.lvh.me subdomains
setCookie('access_token', token, 7); // domain=.lvh.me
// Cookie is accessible on:
// - platform.lvh.me:5173
// - business1.lvh.me:5173
// - business2.lvh.me:5173
// etc.
Key Files:
/src/utils/cookies.ts- Cookie utilities with cross-subdomain support/src/hooks/useAuth.ts- Authentication hooks using cookies/src/api/client.ts- API client with cookie-based auth
Login Flow
- User navigates to
http://platform.lvh.me:5173 - If not authenticated, shows login page
- User enters credentials and submits
- Backend validates and returns JWT tokens + user data
- Tokens stored in cookies with
domain=.lvh.me - User data stored in React Query cache
- App checks user role:
- Platform users: Stay on platform.lvh.me
- Business users: Redirect to {business_subdomain}.lvh.me
- Cookies accessible on target subdomain - user sees dashboard
Testing with Playwright
Tests use lvh.me for proper subdomain testing:
// Start on platform subdomain
await page.goto('http://platform.lvh.me:5173');
// Login sets cookies with domain=.lvh.me
await page.getByPlaceholder(/username/i).fill('poduck');
await page.getByPlaceholder(/password/i).fill('starry12');
await page.getByRole('button', { name: /sign in/i }).click();
// Cookies accessible, dashboard loads
await expect(page.getByRole('heading', { name: /platform dashboard/i })).toBeVisible();
Running the Development Server
# Install dependencies
npm install
# Start dev server
npm run dev
# Access at http://platform.lvh.me:5173
Running Tests
# Run all tests
npm test
# Run E2E tests
npx playwright test
# Run specific test file
npx playwright test login-flow.spec.ts
# Run with UI
npx playwright test --ui
Production Deployment
In production, replace lvh.me with your actual domain:
-
Update
src/utils/cookies.ts:const domain = window.location.hostname.includes('yourdomain.com') ? '.yourdomain.com' : window.location.hostname; -
Configure DNS:
platform.yourdomain.com→ Your server IP*.yourdomain.com→ Your server IP (wildcard for business subdomains)
-
SSL certificates:
- Get wildcard certificate for
*.yourdomain.com - Or use Let's Encrypt with wildcard support
- Get wildcard certificate for
Troubleshooting
Cookies not working?
- Make sure you're using
lvh.me, notlocalhost - Check browser DevTools → Application → Cookies
- Verify
domain=.lvh.meis set on cookies - Clear cookies and try again
Redirect issues?
- Check
/src/pages/LoginPage.tsxredirect logic - Verify user role and business_subdomain in response
- Check browser console for navigation errors
Can't access lvh.me?
- Verify internet connection (lvh.me requires DNS lookup)
- Try
ping lvh.me- should resolve to127.0.0.1 - Alternative: Use
127.0.0.1.nip.io(similar service)