mirror of
https://github.com/we-promise/sure.git
synced 2026-04-07 22:34:47 +00:00
feat(transaction): add support for file attachments using Active Storage (#713)
* feat(transaction): add support for file attachments using Active Storage * feat(attachments): implement transaction attachments with upload, show, and delete functionality * feat(attachments): enhance attachment upload functionality to support multiple files and improved error handling * feat(attachments): add attachment upload form and display functionality in transaction views * feat(attachments): implement attachment validation for count, size, and content type; enhance upload form with validation hints * fix(attachments): use correct UI components * feat(attachments): Implement Turbo Stream responses for creating and deleting transaction attachments. * fix(attachments): include auth in activestorage controller * test(attachments): add test coverage for turbostream and auth * feat(attachments): extract strings to i18n * fix(attachments): ensure only newly added attachments are purged when transaction validation fails. * fix(attachments): validate attachment params * refactor(attachments): use stimulus declarative actions * fix(attachments): add auth for other representations * refactor(attachments): use Browse component for attachment uploads * fix(attachments): reject empty values on attachment upload * fix(attachments): hide the upload form if reached max uploads * fix(attachments): correctly purge only newly added attachments on upload failure * fix(attachments): ensure attachment count limit is respected within a transaction lock * fix(attachments): update attachment parameter handling to avoid `ParameterMissing` errors. * fix(components): adjust icon_only logic for buttonish --------- Signed-off-by: Juan José Mata <juanjo.mata@gmail.com> Co-authored-by: Juan José Mata <juanjo.mata@gmail.com>
This commit is contained in:
63
app/javascript/controllers/attachment_upload_controller.js
Normal file
63
app/javascript/controllers/attachment_upload_controller.js
Normal file
@@ -0,0 +1,63 @@
|
||||
import { Controller } from "@hotwired/stimulus"
|
||||
|
||||
export default class AttachmentUploadController extends Controller {
|
||||
static targets = ["fileInput", "submitButton", "fileName", "uploadText"]
|
||||
static values = {
|
||||
maxFiles: Number,
|
||||
maxSize: Number
|
||||
}
|
||||
|
||||
connect() {
|
||||
this.updateSubmitButton()
|
||||
}
|
||||
|
||||
triggerFileInput() {
|
||||
this.fileInputTarget.click()
|
||||
}
|
||||
|
||||
updateSubmitButton() {
|
||||
const files = Array.from(this.fileInputTarget.files)
|
||||
const hasFiles = files.length > 0
|
||||
|
||||
// Basic validation hints (server validates definitively)
|
||||
let isValid = hasFiles
|
||||
let errorMessage = ""
|
||||
|
||||
if (hasFiles) {
|
||||
if (this.hasUploadTextTarget) this.uploadTextTarget.classList.add("hidden")
|
||||
if (this.hasFileNameTarget) {
|
||||
const filenames = files.map(f => f.name).join(", ")
|
||||
const textElement = this.fileNameTarget.querySelector("p")
|
||||
if (textElement) textElement.textContent = filenames
|
||||
this.fileNameTarget.classList.remove("hidden")
|
||||
}
|
||||
|
||||
// Check file count
|
||||
if (files.length > this.maxFilesValue) {
|
||||
isValid = false
|
||||
errorMessage = `Too many files (max ${this.maxFilesValue})`
|
||||
}
|
||||
|
||||
// Check file sizes
|
||||
const oversizedFiles = files.filter(file => file.size > this.maxSizeValue)
|
||||
if (oversizedFiles.length > 0) {
|
||||
isValid = false
|
||||
errorMessage = `File too large (max ${Math.round(this.maxSizeValue / 1024 / 1024)}MB)`
|
||||
}
|
||||
} else {
|
||||
if (this.hasUploadTextTarget) this.uploadTextTarget.classList.remove("hidden")
|
||||
if (this.hasFileNameTarget) this.fileNameTarget.classList.add("hidden")
|
||||
}
|
||||
|
||||
this.submitButtonTarget.disabled = !isValid
|
||||
|
||||
if (hasFiles && isValid) {
|
||||
const count = files.length
|
||||
this.submitButtonTarget.textContent = count === 1 ? "Upload 1 file" : `Upload ${count} files`
|
||||
} else if (errorMessage) {
|
||||
this.submitButtonTarget.textContent = errorMessage
|
||||
} else {
|
||||
this.submitButtonTarget.textContent = "Upload"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user