# Resource Types & Logo Upload - Implementation Summary ## ✅ Completed ### Backend Models 1. **ResourceType Model** (`smoothschedule/schedule/models.py`) - Custom resource type definitions (e.g., "Hair Stylist", "Massage Room") - Category field: STAFF (requires staff assignment) or OTHER - `is_default` flag to prevent deletion of core types - Validation to prevent deletion when in use - Database migration created and applied ✅ 2. **Resource Model Updates** (`smoothschedule/schedule/models.py`) - Added `resource_type` ForeignKey to ResourceType model - Kept legacy `type` field for backwards compatibility - Migration created and applied ✅ 3. **Tenant Model Updates** (`smoothschedule/core/models.py`) - Added `logo` ImageField for business logo upload - Added `logo_display_mode` field with choices: - `logo-only`: Show only logo in sidebar - `text-only`: Show only business name (default) - `logo-and-text`: Show both logo and name - Added `primary_color` and `secondary_color` fields - Database migration created and applied ✅ ### Frontend Updates 1. **TypeScript Types** (`frontend/src/types.ts`) - Added `ResourceTypeDefinition` interface - Added `ResourceTypeCategory` type - Added `logoDisplayMode` to Business interface - Updated Resource interface with `typeId` field 2. **React Hooks** (`frontend/src/hooks/useResourceTypes.ts`) - `useResourceTypes()` - Fetch resource types - `useCreateResourceType()` - Create new type - `useUpdateResourceType()` - Update existing type - `useDeleteResourceType()` - Delete type (with validation) - Includes placeholder data for default types 3. **Sidebar Component** (`frontend/src/components/Sidebar.tsx`) - Updated to display logo based on `logoDisplayMode` - Shows logo image when mode is `logo-only` or `logo-and-text` - Hides business name text when mode is `logo-only` - Maintains fallback to initials when no logo 4. **Resource Modal** (`frontend/src/pages/Resources.tsx`) - Resource type dropdown now works (no longer disabled) - Staff autocomplete fully functional with keyboard navigation - Debounced search to reduce API calls - All three default types available (Staff, Room, Equipment) ## ⏳ Next Steps ### 1. Data Migration for Default Types Create a data migration to populate default ResourceType records for existing tenants: ```bash cd /home/poduck/Desktop/smoothschedule2/smoothschedule docker compose -f docker-compose.local.yml exec django python manage.py makemigrations schedule --empty --name create_default_resource_types ``` Then edit the migration to add: ```python def create_default_types(apps, schema_editor): ResourceType = apps.get_model('schedule', 'ResourceType') # Create default types ResourceType.objects.get_or_create( name='Staff', defaults={ 'category': 'STAFF', 'is_default': True, 'icon_name': 'user' } ) ResourceType.objects.get_or_create( name='Room', defaults={ 'category': 'OTHER', 'is_default': True, 'icon_name': 'home' } ) ResourceType.objects.get_or_create( name='Equipment', defaults={ 'category': 'OTHER', 'is_default': True, 'icon_name': 'wrench' } ) ``` ### 2. API Serializers & Views Create Django REST Framework serializers and viewsets: **File**: `smoothschedule/schedule/serializers.py` ```python class ResourceTypeSerializer(serializers.ModelSerializer): class Meta: model = ResourceType fields = ['id', 'name', 'category', 'is_default', 'icon_name', 'created_at'] read_only_fields = ['id', 'created_at'] def validate_delete(self, instance): if instance.is_default: raise serializers.ValidationError("Cannot delete default resource types.") if instance.resources.exists(): raise serializers.ValidationError(f"Cannot delete - in use by {instance.resources.count()} resources.") ``` **File**: `smoothschedule/schedule/views.py` ```python class ResourceTypeViewSet(viewsets.ModelViewSet): queryset = ResourceType.objects.all() serializer_class = ResourceTypeSerializer permission_classes = [IsAuthenticated] def destroy(self, request, *args, **kwargs): instance = self.get_object() self.serializer_class().validate_delete(instance) return super().destroy(request, *args, **kwargs) ``` **File**: `smoothschedule/schedule/urls.py` ```python router.register(r'resource-types', ResourceTypeViewSet, basename='resourcetype') ``` ### 3. Logo Upload API Add logo upload endpoint to tenant/business API: **File**: `smoothschedule/core/api_views.py` (or similar) ```python class TenantLogoUploadView(APIView): permission_classes = [IsAuthenticated] parser_classes = [MultiPartParser, FormParser] def post(self, request): tenant = request.tenant # From django-tenants middleware logo_file = request.FILES.get('logo') if not logo_file: return Response({'error': 'No logo file provided'}, status=400) # Validate file size (5MB max) if logo_file.size > 5 * 1024 * 1024: return Response({'error': 'Logo file too large (max 5MB)'}, status=400) # Validate file type if not logo_file.content_type.startswith('image/'): return Response({'error': 'File must be an image'}, status=400) tenant.logo = logo_file tenant.save() return Response({ 'logoUrl': tenant.logo.url, 'message': 'Logo uploaded successfully' }) def delete(self, request): tenant = request.tenant tenant.logo.delete() tenant.logo = None tenant.save() return Response({'message': 'Logo removed successfully'}) ``` ### 4. Settings Page UI Components Add to `frontend/src/pages/Settings.tsx`: #### A. Resource Types Tab ```tsx {activeTab === 'resources' && (

Resource Types

Customize how you categorize your bookable resources.

)} ``` #### B. Logo Upload in Branding Section ```tsx

Business Logo

{/* Preview */} {business.logoUrl ? (
Logo
) : (
)} {/* Upload */} {/* Display Mode */}
{/* Preview with menu background */}
{business.logoUrl && (business.logoDisplayMode === 'logo-only' || business.logoDisplayMode === 'logo-and-text') ? ( Logo ) : (
{business.name.substring(0, 2).toUpperCase()}
)} {business.logoDisplayMode !== 'logo-only' && (

{business.name}

{business.subdomain}.smoothschedule.com

)}
``` ### 5. Update Resources Page Modify `frontend/src/pages/Resources.tsx` to use custom resource types: ```tsx const { data: resourceTypes = [] } = useResourceTypes(); // In the modal: {/* Show staff selector if selected type is STAFF category */} {selectedType?.category === 'STAFF' && ( )} ``` ## Testing Checklist - [ ] Create a custom resource type (e.g., "Massage Therapist") - [ ] Delete a custom type (should work if not in use) - [ ] Try to delete a default type (should fail) - [ ] Try to delete a type in use (should fail) - [ ] Upload a business logo - [ ] Change logo display mode and verify sidebar updates - [ ] Remove logo - [ ] Create a resource using custom type - [ ] Verify staff assignment required for STAFF category types ## Files Modified/Created ### Backend - ✅ `smoothschedule/schedule/models.py` - Added ResourceType model, updated Resource - ✅ `smoothschedule/core/models.py` - Added logo fields to Tenant - ✅ `smoothschedule/schedule/migrations/0007_*.py` - ResourceType migration - ✅ `smoothschedule/core/migrations/0003_*.py` - Tenant logo migration - ⏳ `smoothschedule/schedule/serializers.py` - Need ResourceTypeSerializer - ⏳ `smoothschedule/schedule/views.py` - Need ResourceTypeViewSet - ⏳ `smoothschedule/schedule/urls.py` - Need router registration - ⏳ `smoothschedule/core/api_views.py` - Need logo upload endpoint ### Frontend - ✅ `frontend/src/types.ts` - Added ResourceType interfaces - ✅ `frontend/src/hooks/useResourceTypes.ts` - CRUD hooks - ✅ `frontend/src/components/Sidebar.tsx` - Logo display logic - ✅ `frontend/src/pages/Resources.tsx` - Fixed dropdown, autocomplete - ⏳ `frontend/src/pages/Settings.tsx` - Need resource types tab & logo upload UI - ⏳ `frontend/src/components/ResourceTypesManager.tsx` - Need new component ## Database Schema ### ResourceType Table ```sql CREATE TABLE schedule_resourcetype ( id SERIAL PRIMARY KEY, name VARCHAR(100) NOT NULL, category VARCHAR(10) NOT NULL DEFAULT 'OTHER', is_default BOOLEAN NOT NULL DEFAULT FALSE, icon_name VARCHAR(50), created_at TIMESTAMP NOT NULL, updated_at TIMESTAMP NOT NULL ); ``` ### Tenant Table Updates ```sql ALTER TABLE core_tenant ADD COLUMN logo VARCHAR(100); ALTER TABLE core_tenant ADD COLUMN logo_display_mode VARCHAR(20) DEFAULT 'text-only'; ALTER TABLE core_tenant ADD COLUMN primary_color VARCHAR(7) DEFAULT '#2563eb'; ALTER TABLE core_tenant ADD COLUMN secondary_color VARCHAR(7) DEFAULT '#0ea5e9'; ``` ### Resource Table Updates ```sql ALTER TABLE schedule_resource ADD COLUMN resource_type_id INTEGER REFERENCES schedule_resourcetype(id) ON DELETE PROTECT; ``` ## Notes - Logo files stored in `MEDIA_ROOT/tenant_logos/` - Max file size: 5MB - Supported formats: PNG, JPG, SVG - Recommended dimensions: 500x500px (square) or 500x200px (wide) - Default resource types are created via data migration - Legacy `Resource.type` field kept for backwards compatibility