Edit & Delete Flush Feature#
Overview#
This feature allows users to edit and delete their own flush records directly from their profile page. The implementation includes a modal interface for editing, client-side validation, and proper handling through the AT Protocol and Jetstream firehose.
What Was Added#
1. API Client Functions (src/lib/api-client.ts)#
Added two new functions to handle record management:
deleteFlushRecord(session, recordUri): Deletes a flush record using the AT Protocol'sdeleteRecordmethodupdateFlushRecord(session, recordUri, text, emoji, originalCreatedAt): Updates a flush record using the AT Protocol'sputRecordmethod
Both functions:
- Parse AT URIs correctly (format:
at://did:plc:xxx/collection.name/rkey) - Use the OAuth session's Agent for authenticated requests
- Include proper error handling and logging
- Preserve the original
createdAttimestamp on updates
2. Edit Modal Component (src/components/EditFlushModal.tsx)#
A beautiful modal dialog that provides:
- Pre-populated form with the flush's current text and emoji
- Character counter (59 character limit)
- Emoji selector with all approved emojis
- Content validation (banned words, character limits)
- Delete confirmation workflow
- Loading states for all async operations
- Error handling with user-friendly messages
- Backdrop click to close
- Responsive design for mobile devices
3. Profile Page Updates (src/app/profile/[handle]/page.tsx)#
Enhanced the profile page with:
- Edit button on each flush (only visible to the flush owner)
- Authentication check using
useAuth()hook to compare DIDs - Integration with
EditFlushModalcomponent - State management for editing operations
- Success/error message display
- Optimistic UI updates (updates local state immediately)
New state variables:
editingFlush: Tracks which flush is being editedactionError: Displays error messagesactionSuccess: Displays success messages
New functions:
isOwnProfile(): Checks if the logged-in user owns the profilehandleUpdateFlush(): Handles the update operationhandleDeleteFlush(): Handles the delete operation
4. Profile Styles (src/app/profile/[handle]/profile.module.css)#
Added styles for:
.contentRight: Container for timestamp and edit button.editButton: Pencil icon button with hover effects.actionError: Error message styling.actionSuccess: Success message styling
5. Edit Modal Styles (src/components/EditFlushModal.module.css)#
Complete styling for the modal including:
- Dark backdrop overlay
- Centered modal with max-width
- Form inputs and emoji grid
- Action buttons (Save, Cancel, Delete)
- Delete confirmation UI
- Responsive mobile layout
- Smooth transitions and hover effects
6. Jetstream Consumer (scripts/firehose-worker.js)#
Updated to properly handle:
- Delete operations: Removes records from Supabase when deleted from the network
- Update operations: Updates existing records with new content
- URI construction for record matching
- Proper error handling for database operations
How It Works#
User Flow#
-
User navigates to their own profile
- Edit buttons appear next to each of their flushes
- Buttons are hidden for other users' profiles
-
User clicks edit button
- Modal opens with pre-filled form
- Current text and emoji are displayed
- User can modify text and/or emoji
- Character counter shows remaining characters
-
User saves changes
- Validation runs (banned words, character limits)
- API call made to update the record via AT Protocol
- Local state updates immediately (optimistic UI)
- Success message displayed
- Modal closes automatically
-
User deletes a flush
- Clicks "Delete Flush" button
- Confirmation prompt appears
- On confirmation, record is deleted via AT Protocol
- Record removed from local state
- Success message displayed
- Modal closes
Technical Flow#
Update Operation#
User clicks Save
→ Validation (client-side)
→ updateFlushRecord(session, uri, text, emoji, createdAt)
→ Agent.api.com.atproto.repo.putRecord()
→ PDS updates the record
→ Jetstream firehose emits 'update' event
→ Worker processes event
→ Supabase record updated
→ UI updates optimistically
Delete Operation#
User confirms delete
→ deleteFlushRecord(session, uri)
→ Agent.api.com.atproto.repo.deleteRecord()
→ PDS deletes the record
→ Jetstream firehose emits 'delete' event
→ Worker processes event
→ Supabase record deleted
→ UI updates optimistically
Authorization#
- Uses OAuth session from
@atproto/oauth-client-browser - Compares
session.sub(user's DID) withprofileData.did - Edit buttons only visible when DIDs match
- AT Protocol handles authorization at the PDS level
- Users can only edit/delete their own records
Validation#
All validation from the original flush creation is preserved:
- Character limit: 59 characters
- Banned words: Content filtering via
containsBannedWords() - Text sanitization: via
sanitizeText() - Emoji validation: Only approved emojis from the list
- Authentication: Must be logged in
Error Handling#
Comprehensive error handling at every level:
- Network failures
- Authorization errors
- Validation errors
- User-friendly error messages
- Console logging for debugging
- Graceful degradation
Responsive Design#
The modal and edit buttons work beautifully on:
- Desktop screens
- Tablets
- Mobile devices
Features:
- Touch-friendly button sizes
- Readable text at all sizes
- Scrollable modal content
- Proper spacing and padding
Future Enhancements#
Potential improvements:
- Edit history: Track when records were edited
- Undo functionality: Allow users to revert changes
- Bulk operations: Edit/delete multiple flushes at once
- Keyboard shortcuts: Quick access to edit/delete
- Inline editing: Edit directly in the feed without modal
- Draft saving: Save edits as drafts before publishing
Testing Checklist#
To verify the feature works correctly:
- Edit button appears on own profile only
- Edit button hidden on other users' profiles
- Modal opens when edit button clicked
- Form pre-populates with current values
- Text changes are validated
- Emoji selection works
- Character counter updates correctly
- Save button updates the record
- Delete button shows confirmation
- Delete confirmation works
- Cancel buttons close modal
- Success messages display
- Error messages display
- Local state updates optimistically
- Jetstream updates Supabase correctly
- Mobile layout works properly
Notes#
- Records maintain their original
createdAttimestamp when updated - Updates create a new CID (Content Identifier) for the record
- The URI remains the same (same
rkey) - Deletes are permanent and cannot be undone
- All operations respect AT Protocol's distributed architecture