Skip to content

refactor(platform): update file upload components#344

Merged
Israeltheminer merged 3 commits into
mainfrom
refactor/file-upload
Feb 3, 2026
Merged

refactor(platform): update file upload components#344
Israeltheminer merged 3 commits into
mainfrom
refactor/file-upload

Conversation

@Israeltheminer
Copy link
Copy Markdown
Collaborator

@Israeltheminer Israeltheminer commented Feb 3, 2026

Summary

  • Refactors file upload UI to use compound component pattern (Root/DropZone/Overlay)
  • Adds new useConvexFileUpload hook for chat file attachments
  • Improves validation and user feedback for file uploads across import forms

Changes

  • FileUpload component: Refactored with compound component pattern for better composition
  • Import forms (vendor, customer, product): Now show toast notifications when unsupported file types are selected
  • useConvexFileUpload hook:
    • Validates storageId response from server
    • Cleans up object URLs on unmount to prevent memory leaks
    • Uploads valid files even when some files in batch are invalid
  • Translations: Added unsupportedFileType validation message

Test plan

  • Verify file upload works in chat input
  • Verify document upload dialog accepts valid files
  • Try uploading an invalid file type in vendor/customer/product import - should show toast
  • Try uploading a mix of valid and invalid files - valid ones should upload

Summary by CodeRabbit

  • Improvements
    • Enhanced file upload experience across the application with a unified, streamlined interface.
    • Improved drag-and-drop functionality with clearer visual feedback and accessibility features.
    • Better error handling with more informative messages for unsupported file types.
    • File uploads now consistently available across automations, customer imports, document uploads, and product/vendor imports.

@Israeltheminer Israeltheminer changed the title refactor(platform): modernize file upload components refactor(platform): update file upload components Feb 3, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 3, 2026

📝 Walkthrough

Walkthrough

This PR refactors the file upload system by introducing a new useConvexFileUpload hook that centralizes file upload management with validation, optional image compression, and Convex storage integration. The FileUploadContextValue is simplified to expose only drag-over state. DropZone is expanded with an onFilesSelected callback and additional configuration options (accept, disabled, inputId, multiple, aria-label). Multiple components (chat-input, automation-assistant, and various import/upload forms) are updated to use the new hook and callback pattern. Localization keys are added for UI text and validation messages.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🤖 Fix all issues with AI agents
In `@services/platform/app/components/ui/forms/file-upload.tsx`:
- Around line 141-153: The DropZone uses a div with role="button" (in
services/platform/app/components/ui/forms/file-upload.tsx) which is both
semantically wrong and causes clicks on child elements to trigger file
selection; either replace the outer div with a real <button> (ensure it supports
disabled, aria-label and keyboard handlers) or modify the handleClick handler to
ignore clicks coming from child elements by checking event.target vs the
container ref and calling event.stopPropagation()/return early when they differ;
update related handlers (handleKeyDown, onClick) and tabIndex/aria-disabled
logic to match the chosen approach.
- Around line 113-117: The handleClick function currently queries the DOM by id
(inputId) which causes collisions when multiple DropZones share the default
'file-upload' id; replace this with a local React ref: create an inputRef via
useRef<HTMLInputElement | null>(null), attach it to the file <input> element,
and change handleClick (and its dependency array) to call
inputRef.current?.click() instead of document.getElementById(inputId); you can
then remove reliance on the default inputId or keep it only for accessibility,
ensuring each DropZone uses its own ref.

In `@services/platform/app/features/chat/hooks/use-convex-file-upload.ts`:
- Around line 94-102: The JSON parsing of the upload response can throw if the
server returns non-JSON (HTML/error page); wrap the await result.json() call in
a try/catch inside useConvexFileUpload (where result and storageId are handled)
and throw a new Error that includes the HTTP status and either the parsed JSON
error message or the raw response text; keep the existing checks for result.ok
and storageId but ensure parsing errors produce a clear error message instead of
an uncaught exception.

In
`@services/platform/app/features/customers/components/customer-import-form.tsx`:
- Around line 139-147: The FileUpload.DropZone usage (component
FileUpload.DropZone with props onFilesSelected, accept, inputId, className) is
missing an aria-label for screen readers; add an aria-label prop that uses the
shared localization key (e.g. aria.dropzone) — for example
aria-label={t('aria.dropzone')} or the app's localization helper — so the drop
zone is announced properly to assistive technologies.
- Around line 49-62: The file type check in handleFilesSelected is too fragile
(file.type.includes('sheet')) and incorrectly rejects .xls; update the
validation to use a whitelist of allowed MIME types (e.g.,
application/vnd.ms-excel,
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, text/csv)
and/or allowed extensions ('.xls', '.xlsx', '.csv') derived from file.name as a
fallback, then call setValue('file', file) when the file matches and show the
toast otherwise; reference handleFilesSelected, setValue, and the toast
invocation when making the change.

In
`@services/platform/app/features/documents/components/document-upload-dialog.tsx`:
- Around line 194-196: In DocumentUploadDialog (the span rendering {file.name}),
replace the invalid Tailwind class "wrap-anywhere" with a valid utility such as
"break-words" (or "break-all"/"overflow-wrap" variant) so the filename wraps
correctly; update the className on the span that currently reads text-sm
wrap-anywhere flex-1 min-w-0 to use text-sm break-words flex-1 min-w-0 (or your
chosen valid Tailwind utility).

In `@services/platform/app/features/products/components/product-import-form.tsx`:
- Around line 34-47: The MIME check in handleFilesSelected is fragile (e.g.,
misses .xls) — replace the inline detection with a shared utility (e.g.,
isSpreadsheetFile) that exports SPREADSHEET_TYPES and SPREADSHEET_EXTENSIONS and
checks both file.type and file.name extensions; update handleFilesSelected to
call isSpreadsheetFile(file) and keep the existing setValue('file', file) and
toast(...) behavior for invalid files so all import forms share consistent
validation.

In `@services/platform/app/features/vendors/components/vendor-import-form.tsx`:
- Around line 47-60: The file-type check in handleFilesSelected is duplicated
and fragile; create a shared utility function isSpreadsheetFile(file: File):
boolean (or in a shared utils module) that encapsulates the logic (check MIME
types, extensions like .csv, .xls, .xlsx) and export it for reuse, then replace
the inline condition in handleFilesSelected with if (isSpreadsheetFile(file)) {
setValue('file', file); } else { toast(...) } to ensure consistent validation
across vendor-import-form and other import forms.

In `@services/platform/messages/en.json`:
- Around line 67-68: The localization key "pickADate" is semantically misplaced
in the "upload" section next to "dropFilesHere"; move the "pickADate" entry out
of the upload group and into the "datePicker" section (or into a new
date-related section) so date strings are grouped together, ensure the JSON
remains valid (remove trailing commas or adjust commas accordingly) and search
for any code references to "pickADate" to confirm no path/name changes are
required after the move.

Comment thread services/platform/app/components/ui/forms/file-upload.tsx
Comment thread services/platform/app/components/ui/forms/file-upload.tsx
Comment thread services/platform/app/features/chat/hooks/use-convex-file-upload.ts
Comment thread services/platform/messages/en.json
…attern

- Refactor FileUpload to use Root/DropZone/Overlay compound pattern
- Update chat-input, automation-assistant, document-upload-dialog
- Simplify drag-and-drop handling with shared context
- Add storageId validation in use-convex-file-upload hook
- Add cleanup effect to revoke object URLs on unmount
- Upload valid files even when some files are invalid
- Add toast notifications for unsupported file types in import forms
- Add unsupportedFileType translation key
- Add PowerPoint MIME types to chat file upload config
- Fix fragile MIME detection in import forms using extension checking
@Israeltheminer Israeltheminer merged commit 4a30b0e into main Feb 3, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant