From 95d14f2cec998028ff0ab81b515edb12c2e761de Mon Sep 17 00:00:00 2001 From: Meghdad Date: Sat, 16 May 2026 22:19:55 +0330 Subject: [PATCH] Improve support attachment validation errors --- .../StoreSupportConversationRequest.php | 3 +- .../Requests/StoreSupportMessageRequest.php | 5 +- app/Rules/SupportAttachmentFile.php | 77 +++++++++++++++++++ .../components/support-attachment-errors.tsx | 28 +++++++ resources/js/pages/admin/support/show.tsx | 9 ++- resources/js/pages/support/index.tsx | 9 +-- resources/js/pages/support/show.tsx | 7 +- tests/Feature/SupportConversationTest.php | 34 +++++++- 8 files changed, 153 insertions(+), 19 deletions(-) create mode 100644 app/Rules/SupportAttachmentFile.php create mode 100644 resources/js/components/support-attachment-errors.tsx diff --git a/app/Http/Requests/StoreSupportConversationRequest.php b/app/Http/Requests/StoreSupportConversationRequest.php index bb1038e..1912de7 100644 --- a/app/Http/Requests/StoreSupportConversationRequest.php +++ b/app/Http/Requests/StoreSupportConversationRequest.php @@ -3,6 +3,7 @@ namespace App\Http\Requests; use App\Models\SupportConversation; +use App\Rules\SupportAttachmentFile; use Illuminate\Foundation\Http\FormRequest; use Illuminate\Validation\Rule; @@ -23,7 +24,7 @@ class StoreSupportConversationRequest extends FormRequest 'subject' => ['required', 'string', 'max:120'], 'body' => ['required', 'string', 'max:2000'], 'attachments' => ['nullable', 'array', 'max:3'], - 'attachments.*' => ['file', 'max:10240', 'mimes:jpg,jpeg,png,webp,gif,pdf,txt,log,json,zip'], + 'attachments.*' => [new SupportAttachmentFile], ]; } } diff --git a/app/Http/Requests/StoreSupportMessageRequest.php b/app/Http/Requests/StoreSupportMessageRequest.php index b419abb..4648dc6 100644 --- a/app/Http/Requests/StoreSupportMessageRequest.php +++ b/app/Http/Requests/StoreSupportMessageRequest.php @@ -2,6 +2,7 @@ namespace App\Http\Requests; +use App\Rules\SupportAttachmentFile; use Illuminate\Foundation\Http\FormRequest; class StoreSupportMessageRequest extends FormRequest @@ -12,14 +13,14 @@ class StoreSupportMessageRequest extends FormRequest } /** - * @return array> + * @return array> */ public function rules(): array { return [ 'body' => ['required', 'string', 'max:2000'], 'attachments' => ['nullable', 'array', 'max:3'], - 'attachments.*' => ['file', 'max:10240', 'mimes:jpg,jpeg,png,webp,gif,pdf,txt,log,json,zip'], + 'attachments.*' => [new SupportAttachmentFile], ]; } } diff --git a/app/Rules/SupportAttachmentFile.php b/app/Rules/SupportAttachmentFile.php new file mode 100644 index 0000000..422e31c --- /dev/null +++ b/app/Rules/SupportAttachmentFile.php @@ -0,0 +1,77 @@ + $value], + [ + 'attachment' => [ + 'file', + 'max:'.self::MAX_UPLOAD_KILOBYTES, + 'mimetypes:'.implode(',', self::ALLOWED_MIME_TYPES), + ], + ], + [ + 'attachment.file' => 'Attachment upload failed. Try the file again or choose a different file.', + 'attachment.max' => 'Attachments must be 200 MB or smaller.', + 'attachment.mimetypes' => 'Unsupported attachment type. Upload media, PDF, text/data, Office, OpenDocument, or archive files.', + ], + ); + + if ($validator->fails()) { + $fail($validator->errors()->first('attachment')); + } + } +} diff --git a/resources/js/components/support-attachment-errors.tsx b/resources/js/components/support-attachment-errors.tsx new file mode 100644 index 0000000..24e1dea --- /dev/null +++ b/resources/js/components/support-attachment-errors.tsx @@ -0,0 +1,28 @@ +type Props = { + errors: Partial>; +}; + +export function SupportAttachmentErrors({ errors }: Props) { + const messages = Object.entries(errors) + .filter( + ([key, message]) => + Boolean(message) && + (key === 'attachments' || key.startsWith('attachments.')), + ) + .map(([key, message]) => ({ + key, + message: message as string, + })); + + if (messages.length === 0) { + return null; + } + + return ( +
+ {messages.map((item) => ( +
{item.message}
+ ))} +
+ ); +} diff --git a/resources/js/pages/admin/support/show.tsx b/resources/js/pages/admin/support/show.tsx index eb5ecf4..e324ad2 100644 --- a/resources/js/pages/admin/support/show.tsx +++ b/resources/js/pages/admin/support/show.tsx @@ -11,6 +11,7 @@ import { } from 'lucide-react'; import type { FormEvent, ReactNode } from 'react'; import { useRef } from 'react'; +import { SupportAttachmentErrors } from '@/components/support-attachment-errors'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; @@ -142,10 +143,7 @@ export default function AdminSupportShow({ conversation }: Props) { maxLength={2000} /> - + )} +