Phase 2: Media Uploader Unification
Created by: devin-ai-integration[bot]
Phase 2: Extract Shared Media Upload Logic
Summary
This PR extracts duplicated upload logic from GalleryUploader and ImageUploader into shared helper functions in mediaHelpers.ts. This is Phase 2 of the admin form system unification plan.
Changes:
- Added
validateImageFile()helper for file type and size validation - Added
uploadMediaFiles()function to centralize/api/media/uploadfetch logic - Added
SerializedMediatype to properly represent API responses (dates as strings) - Replaced inline upload icon SVGs with existing
FileIconcomponent - Refactored both uploaders to use the new shared helpers
Impact:
- Removes ~165 lines of duplicated code
- Makes upload behavior consistent across components
- Easier to maintain and extend upload functionality in the future
Review & Testing Checklist for Human
-
Upload single image with description in ImageUploader - Verify the description field is saved correctly (this now uses extraFieldsparameter instead of direct FormData append - this is the highest risk change) -
Upload multiple images in GalleryUploader - Verify all files upload successfully and display correctly -
Test file validation errors - Try uploading non-image files and files over the size limit to ensure error messages display correctly -
Verify upload progress indicators - Check that the progress bars/spinners still work during upload -
Check date handling - The refactored code returns SerializedMedia(string dates) cast toMedia(Date objects). Verify no date-related bugs appear in the UI
Notes
Type Safety Concern: The uploadMediaFiles function returns SerializedMedia[] (with string dates from JSON), which is then cast to Media[] (with Date objects). This works because the components handle both string and Date types (as fixed in Phase 1), but it's worth being aware of this type mismatch.
Incomplete Refactoring: The uploadMediaFiles function has an onProgress callback parameter that isn't used yet. Both uploaders still do their own progress simulation with setInterval. This is intentional - further progress refactoring can be done in a future PR if needed.
Code Quality: All changes pass eslint src/ with zero errors and introduce no new TypeScript errors per pnpm run check.
Session: https://app.devin.ai/sessions/9c28151548c1410ca9948853ad0c04ad
Requested by: Justin Edmund (@jedmund)