diff --git a/backend/src/admin/media.controller.ts b/backend/src/admin/media.controller.ts index 44ebc6d..0cbc2c1 100644 --- a/backend/src/admin/media.controller.ts +++ b/backend/src/admin/media.controller.ts @@ -30,9 +30,8 @@ export class MediaController { return { success: true, data }; } - @UseGuards(JwtAuthGuard) @Post('upload') - @ApiOperation({ summary: 'آپلود فایل جدید' }) + @ApiOperation({ summary: 'آپلود فایل جدید (عمومی/ادمین)' }) @UseInterceptors(FileInterceptor('file')) async uploadFile(@UploadedFile() file: Express.Multer.File) { if (!file) throw new BadRequestException('File is missing'); diff --git a/backend/src/prescriptions/prescriptions.controller.ts b/backend/src/prescriptions/prescriptions.controller.ts index f9f0fef..3b47d89 100644 --- a/backend/src/prescriptions/prescriptions.controller.ts +++ b/backend/src/prescriptions/prescriptions.controller.ts @@ -31,7 +31,14 @@ export class PrescriptionsController { @ApiOperation({ summary: 'بارگذاری نسخه جدید توسط کاربر' }) create( @Req() req: UserReqPayload, - @Body() body: { petId?: string; fileUrl: string; notes?: string }, + @Body() + body: { + petId?: string; + petName?: string; + phone?: string; + fileUrl: string; + notes?: string; + }, ) { const userId = req.user?.id || req.user?.userId || null; return this.prescriptionsService.create(userId, body); diff --git a/backend/src/prescriptions/prescriptions.service.ts b/backend/src/prescriptions/prescriptions.service.ts index b0e262f..034dda1 100644 --- a/backend/src/prescriptions/prescriptions.service.ts +++ b/backend/src/prescriptions/prescriptions.service.ts @@ -11,17 +11,73 @@ export class PrescriptionsService { async create( userId: string | null, - data: { petId?: string; fileUrl: string; notes?: string }, + data: { + petId?: string; + petName?: string; + phone?: string; + fileUrl: string; + notes?: string; + }, ) { + let finalUserId = userId; + let finalPetId = data.petId || null; + + // 1. If phone is provided, find or create user automatically + if (data.phone) { + const cleanPhone = data.phone.trim(); + let user = await this.prisma.user.findFirst({ + where: { mobile: cleanPhone }, + }); + + if (!user) { + // Create user with default role Customer + user = await this.prisma.user.create({ + data: { + mobile: cleanPhone, + role: 'Customer', + firstName: data.petName ? `سرپرست ${data.petName}` : 'کاربر', + lastName: 'کانینا', + }, + }); + } + finalUserId = user.id; + + // 2. If petName is provided and user exists, find or create pet + if (data.petName && !finalPetId) { + const cleanPetName = data.petName.trim(); + let pet = await this.prisma.pet.findFirst({ + where: { + userId: user.id, + name: cleanPetName, + }, + }); + + if (!pet) { + pet = await this.prisma.pet.create({ + data: { + userId: user.id, + name: cleanPetName, + type: 'سگ', // Default pet type for prescription consultation + breed: 'نامشخص', + age: 1, + weight: 5.0, + activityLevel: 'متوسط', + }, + }); + } + finalPetId = pet.id; + } + } + return this.prisma.prescription.create({ data: { - userId: userId || undefined, - petId: data.petId, + userId: finalUserId || undefined, + petId: finalPetId || undefined, fileUrl: data.fileUrl, notes: data.notes, status: 'PENDING', }, - include: { pet: true }, + include: { user: true, pet: true }, }); } diff --git a/frontend/application/components/ContactFormClient.tsx b/frontend/application/components/ContactFormClient.tsx index b542240..46fbb26 100644 --- a/frontend/application/components/ContactFormClient.tsx +++ b/frontend/application/components/ContactFormClient.tsx @@ -35,10 +35,17 @@ export default function ContactFormClient() { const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); - if (!name.trim() || !phone.trim() || !message.trim()) { + const cleanPhone = phone.trim(); + if (!name.trim() || !cleanPhone || !message.trim()) { setError("لطفاً نام، شماره موبایل و متن پیام را وارد کنید."); return; } + + if (!/^09\d{9}$/.test(cleanPhone)) { + setError("شماره همراه وارد شده معتبر نیست. (مثال: ۰۹۱۲۳۴۵۶۷۸۹)"); + return; + } + setError(""); setLoading(true); diff --git a/frontend/application/components/PrescriptionUploadModal.tsx b/frontend/application/components/PrescriptionUploadModal.tsx index fe63205..6cc1734 100644 --- a/frontend/application/components/PrescriptionUploadModal.tsx +++ b/frontend/application/components/PrescriptionUploadModal.tsx @@ -25,14 +25,30 @@ export default function PrescriptionUploadModal({ isOpen, onClose }: Prescriptio } }; + const resetForm = () => { + setFile(null); + setPetName(""); + setPhone(""); + setNotes(""); + setIsSubmitting(false); + setIsSuccess(false); + }; + + const handleClose = () => { + resetForm(); + onClose(); + }; + const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!file) { toast.error("لطفاً تصویر یا فایل نسخه پزشکی را انتخاب کنید."); return; } - if (!phone) { - toast.error("لطفاً شماره تماس جهت پیگیری را وارد نمایید."); + + const cleanPhone = phone.trim(); + if (!/^09\d{9}$/.test(cleanPhone)) { + toast.error("شماره همراه وارد شده معتبر نیست. (مثال: ۰۹۱۲۳۴۵۶۷۸۹)"); return; } @@ -46,10 +62,12 @@ export default function PrescriptionUploadModal({ isOpen, onClose }: Prescriptio }); const fileUrl = uploadRes.data?.data?.url || uploadRes.data?.url || uploadRes.data?.filename || file.name; - // Submit prescription to backend prescriptions endpoint + // Submit prescription to backend with petName and phone for automatic user & pet profile creation await api.post("/prescriptions", { fileUrl, - notes: `نام پت: ${petName || "ثبت نشده"} | شماره تماس: ${phone} | توضیحات: ${notes || "ندارد"}` + phone: cleanPhone, + petName: petName.trim() || undefined, + notes: notes.trim() || undefined }); setIsSubmitting(false); @@ -58,8 +76,7 @@ export default function PrescriptionUploadModal({ isOpen, onClose }: Prescriptio } catch (error) { console.error("[PrescriptionUpload] Submission error:", error); setIsSubmitting(false); - setIsSuccess(true); // Fallback friendly UX - toast.success("نسخه پزشکی دریافت شد و جهت بررسی در صف کارشناسان قرار گرفت."); + toast.error("خطا در ارسال نسخه پزشکی. لطفاً مجدداً تلاش کنید."); } }; @@ -75,7 +92,7 @@ export default function PrescriptionUploadModal({ isOpen, onClose }: Prescriptio {/* Header */}