# Mutation Buttons Audit **Date**: 2025-01-27 **Task**: Action 8.3.1.2 - Audit all mutation buttons **Status**: Complete ## Summary This document lists all mutation buttons in the frontend codebase that use React Query mutations (`mutate` or `mutateAsync`). Each entry includes: - Component location - Mutation type - Button element - Current loading state status - Priority for adding loading states ## Categories ### 1. Playlist Mutations #### 1.1 Create Playlist - **File**: `apps/web/src/features/playlists/components/PlaylistForm.tsx` - **Mutation**: `createMutation.mutateAsync()` - **Button**: Form submit button (line ~140) - **Loading State**: ❌ Missing - **Priority**: HIGH - **Notes**: Form submission button, should show loading during creation #### 1.2 Update Playlist - **File**: `apps/web/src/features/playlists/components/PlaylistForm.tsx` - **Mutation**: `updateMutation.mutateAsync()` - **Button**: Form submit button (line ~140) - **Loading State**: ❌ Missing - **Priority**: HIGH - **Notes**: Form submission button, should show loading during update #### 1.3 Delete Playlist - **File**: `apps/web/src/features/playlists/components/PlaylistActions.tsx` - **Mutation**: `deleteMutation.mutateAsync()` - **Button**: Delete button (line ~92) - **Loading State**: ✅ Present (uses `isPending` on line 112) - **Priority**: N/A (already implemented) - **Notes**: Already has loading state with `Loader2` spinner #### 1.4 Edit Playlist - **File**: `apps/web/src/features/playlists/components/PlaylistActions.tsx` - **Mutation**: `updateMutation.mutateAsync()` - **Button**: Edit button (line ~109) - **Loading State**: ✅ Present (uses `isPending` on line 112, 116) - **Priority**: N/A (already implemented) - **Notes**: Already has loading state with `Loader2` spinner ### 2. Track Mutations #### 2.1 Add Track to Playlist - **File**: `apps/web/src/features/library/pages/LibraryPage.tsx` - **Mutation**: `addTrackToPlaylistMutation.mutateAsync()` - **Button**: DropdownMenuItem in playlist submenu (line ~708-724) - **Loading State**: ✅ Present (Action 8.3.1.1) - **Priority**: N/A (already implemented) - **Notes**: Recently added loading state with `Loader2` spinner #### 2.2 Add Track to Playlist (Modal) - **File**: `apps/web/src/features/playlists/components/AddTrackToPlaylistModal.tsx` - **Mutation**: `addTrackMutation.mutateAsync()` - **Button**: "Add Tracks" button (line ~132) - **Loading State**: ❌ Missing - **Priority**: HIGH - **Notes**: Modal button for adding multiple tracks, should show loading during batch operation #### 2.3 Like Track - **File**: `apps/web/src/features/tracks/components/LikeButton.tsx` - **Mutation**: `likeMutation.mutate()` / `unlikeMutation.mutate()` - **Button**: LikeButton component (line ~156) - **Loading State**: ✅ Present (uses `isPending` on line 152-153, 169-175) - **Priority**: N/A (already implemented) - **Notes**: Already has loading state with `Loader2` spinner #### 2.4 Reorder Playlist Tracks - **File**: `apps/web/src/features/playlists/components/PlaylistTrackList.tsx` - **Mutation**: `reorderMutation.mutateAsync()` - **Button**: Drag-and-drop reorder (line ~193) - **Loading State**: ❌ Missing - **Priority**: MEDIUM - **Notes**: Drag-and-drop operation, could show loading indicator during reorder ### 3. Comment Mutations #### 3.1 Create Comment - **File**: `apps/web/src/features/tracks/components/CommentSection.tsx` - **Mutation**: `createCommentMutation.mutate()` - **Button**: Form submit button (line ~121) - **Loading State**: ❌ Missing - **Priority**: HIGH - **Notes**: Comment form submission, should show loading #### 3.2 Create Reply - **File**: `apps/web/src/features/tracks/components/CommentThread.tsx` - **Mutation**: `createReplyMutation.mutate()` - **Button**: Reply form submit button (line ~322) - **Loading State**: ❌ Missing - **Priority**: HIGH - **Notes**: Reply form submission, should show loading #### 3.3 Update Comment - **File**: `apps/web/src/features/tracks/components/CommentThread.tsx` - **Mutation**: `updateCommentMutation.mutate()` - **Button**: Edit form submit button (line ~328) - **Loading State**: ❌ Missing - **Priority**: HIGH - **Notes**: Edit form submission, should show loading #### 3.4 Delete Comment - **File**: `apps/web/src/features/tracks/components/CommentThread.tsx` - **Mutation**: `deleteCommentMutation.mutate()` - **Button**: Delete button (line ~332) - **Loading State**: ❌ Missing - **Priority**: MEDIUM - **Notes**: Delete action, should show loading ### 4. Playlist Collaboration Mutations #### 4.1 Add Collaborator - **File**: `apps/web/src/features/playlists/components/AddCollaboratorModal.tsx` - **Mutation**: `addCollaboratorMutation.mutateAsync()` - **Button**: "Add Collaborator" button (line ~60, 87) - **Loading State**: ❌ Missing - **Priority**: HIGH - **Notes**: Modal form submission, should show loading #### 4.2 Remove Collaborator - **File**: `apps/web/src/features/playlists/components/CollaboratorList.tsx` - **Mutation**: `removeMutation.mutateAsync()` - **Button**: Remove button (line ~46) - **Loading State**: ❌ Missing - **Priority**: MEDIUM - **Notes**: Remove action with confirmation, should show loading #### 4.3 Update Collaborator Permission - **File**: `apps/web/src/features/playlists/components/CollaboratorList.tsx` - **Mutation**: `updatePermissionMutation.mutateAsync()` - **Button**: Permission dropdown/button (line ~63) - **Loading State**: ❌ Missing - **Priority**: MEDIUM - **Notes**: Permission change action, should show loading ### 5. Playlist Follow Mutations #### 5.1 Follow/Unfollow Playlist - **File**: `apps/web/src/features/playlists/components/PlaylistFollowButton.tsx` - **Mutation**: `followMutation.mutate()` / `unfollowMutation.mutate()` - **Button**: FollowButton component (line ~173) - **Loading State**: ✅ Present (uses `isPending` on line 168-169, 180-184) - **Priority**: N/A (already implemented) - **Notes**: Already has loading state with `Loader2` spinner ### 6. Share Link Mutations #### 6.1 Create Share Link - **File**: `apps/web/src/features/playlists/components/SharePlaylistModal.tsx` - **Mutation**: `createShareLinkMutation.mutateAsync()` - **Button**: Auto-triggered on modal open (line ~42) - **Loading State**: ❌ Missing - **Priority**: MEDIUM - **Notes**: Auto-triggered, should show loading indicator in modal #### 6.2 Create Share Link (Batch) - **File**: `apps/web/src/features/playlists/components/PlaylistBatchActions.tsx` - **Mutation**: `createShareLinkMutation.mutateAsync()` - **Button**: "Share" button in batch actions (line ~141) - **Loading State**: ❌ Missing - **Priority**: MEDIUM - **Notes**: Batch operation, should show loading #### 6.3 Create Share Link (Generic) - **File**: `apps/web/src/components/share/ShareLinkManager.tsx` - **Mutation**: `createShareMutation.mutateAsync()` - **Button**: "Create Share Link" button (line ~172) - **Loading State**: ❌ Missing - **Priority**: MEDIUM - **Notes**: Generic share link creation, should show loading #### 6.4 Revoke Share Link - **File**: `apps/web/src/components/share/ShareLinkManager.tsx` - **Mutation**: `revokeShareMutation.mutate()` - **Button**: Revoke button (line ~199) - **Loading State**: ❌ Missing - **Priority**: MEDIUM - **Notes**: Revoke action, should show loading ### 7. Notification Mutations #### 7.1 Mark Notification as Read - **File**: `apps/web/src/components/notifications/NotificationMenu.tsx` - **Mutation**: `markAsReadMutation.mutate()` - **Button**: Notification item click / mark as read button (line ~163) - **Loading State**: ❌ Missing - **Priority**: LOW - **Notes**: Auto-triggered on click, could show subtle loading indicator #### 7.2 Mark All Notifications as Read - **File**: `apps/web/src/components/notifications/NotificationMenu.tsx` - **Mutation**: `markAllAsReadMutation.mutate()` - **Button**: "Mark All as Read" button (line ~167) - **Loading State**: ❌ Missing - **Priority**: MEDIUM - **Notes**: Batch operation, should show loading #### 7.3 Mark Notification as Read (Page) - **File**: `apps/web/src/features/notifications/pages/NotificationsPage.tsx` - **Mutation**: `markAsReadMutation.mutate()` - **Button**: Notification item click / mark as read button (line ~179) - **Loading State**: ❌ Missing - **Priority**: LOW - **Notes**: Auto-triggered on click, could show subtle loading indicator #### 7.4 Mark All Notifications as Read (Page) - **File**: `apps/web/src/features/notifications/pages/NotificationsPage.tsx` - **Mutation**: `markAllAsReadMutation.mutate()` - **Button**: "Mark All as Read" button (line ~184) - **Loading State**: ❌ Missing - **Priority**: MEDIUM - **Notes**: Batch operation, should show loading ### 8. Chat Mutations #### 8.1 Leave Room - **File**: `apps/web/src/features/chat/components/ChatSidebar.tsx` - **Mutation**: `leaveRoomMutation.mutate()` - **Button**: Leave button (line ~174) - **Loading State**: ❌ Missing - **Priority**: MEDIUM - **Notes**: Leave action with confirmation, should show loading #### 8.2 Delete Room - **File**: `apps/web/src/features/chat/components/ChatSidebar.tsx` - **Mutation**: `deleteRoomMutation.mutate()` - **Button**: Delete button (line ~180) - **Loading State**: ❌ Missing - **Priority**: MEDIUM - **Notes**: Delete action with confirmation, should show loading ### 9. Batch Operations #### 9.1 Delete Multiple Playlists - **File**: `apps/web/src/features/playlists/components/PlaylistBatchActions.tsx` - **Mutation**: `deleteMutation.mutateAsync()` (loop) - **Button**: "Delete Selected" button (line ~107) - **Loading State**: ❌ Missing - **Priority**: HIGH - **Notes**: Batch delete operation, should show loading with progress ## Statistics - **Total Mutation Buttons**: 28 - **With Loading States**: 5 (18%) - **Missing Loading States**: 23 (82%) - **High Priority**: 8 - **Medium Priority**: 11 - **Low Priority**: 4 ## Priority Breakdown ### High Priority (8 buttons) 1. Create Playlist (PlaylistForm) 2. Update Playlist (PlaylistForm) 3. Add Track to Playlist (Modal) 4. Create Comment 5. Create Reply 6. Update Comment 7. Add Collaborator 8. Delete Multiple Playlists (Batch) ### Medium Priority (11 buttons) 1. Reorder Playlist Tracks 2. Delete Comment 3. Remove Collaborator 4. Update Collaborator Permission 5. Create Share Link (SharePlaylistModal) 6. Create Share Link (Batch) 7. Create Share Link (Generic) 8. Revoke Share Link 9. Mark All Notifications as Read (Menu) 10. Mark All Notifications as Read (Page) 11. Leave Room / Delete Room ### Low Priority (4 buttons) 1. Mark Notification as Read (Menu) 2. Mark Notification as Read (Page) ## Patterns Identified ### Already Implemented (Good Examples) 1. **LikeButton** (`LikeButton.tsx`): Uses `isPending`, shows `Loader2` spinner, disables button 2. **PlaylistFollowButton** (`PlaylistFollowButton.tsx`): Uses `isPending`, shows `Loader2` spinner, disables button 3. **PlaylistActions** (`PlaylistActions.tsx`): Uses `isPending`, shows `Loader2` spinner, disables button 4. **LibraryPage addToPlaylist** (`LibraryPage.tsx`): Uses `isPending`, shows `Loader2` spinner, disables menu items ### Missing Patterns 1. Form submission buttons (PlaylistForm, CommentSection, CommentThread) 2. Modal action buttons (AddCollaboratorModal, AddTrackToPlaylistModal) 3. Batch operation buttons (PlaylistBatchActions) 4. Auto-triggered mutations (SharePlaylistModal, NotificationMenu) ## Recommendations 1. **Follow existing pattern**: Use `mutation.isPending` to check loading state 2. **Use Loader2 spinner**: Import from `lucide-react`, show during loading 3. **Disable buttons**: Set `disabled={mutation.isPending}` on buttons 4. **Show loading text**: Replace or append loading text during mutation 5. **Batch operations**: Show progress indicator for batch operations 6. **Auto-triggered**: Show subtle loading indicator in UI (e.g., modal spinner) ## Next Steps 1. Action 8.3.1.3: Add loading states to all high-priority mutation buttons 2. Action 8.3.1.4: Create Spinner component (if needed, though Loader2 is already used) 3. Action 8.3.1.5: Use Spinner in loading states (standardize on Loader2 or create Spinner component)