validate([ 'home_mat_label' => 'nullable|string|max:255', 'zoom_meeting_label' => 'nullable|string|max:255', 'zoom_subtitle' => 'nullable|string|max:2000', 'zoom_image_url' => 'nullable|string|max:2048', 'zoom_meeting_url' => 'nullable|string|max:2048', 'home_banner_image' => 'nullable|file|mimes:jpg,jpeg,png,webp|max:5120', 'attendance_etika_file' => 'nullable|file|mimes:pdf,jpg,jpeg,png,webp|max:10240', ]); if ($request->hasFile('home_banner_image')) { $file = $request->file('home_banner_image'); $ext = strtolower($file->getClientOriginalExtension() ?: 'jpg'); $name = 'banner.' . $ext; $relativePath = 'portal/' . $name; Storage::disk('public')->putFileAs('portal', $file, $name); $validated['home_banner_image_path'] = '/storage/' . $relativePath; } if ($request->hasFile('attendance_etika_file')) { $file = $request->file('attendance_etika_file'); $ext = strtolower($file->getClientOriginalExtension() ?: 'pdf'); $name = 'etika.' . $ext; $relativePath = 'portal/' . $name; Storage::disk('public')->putFileAs('portal', $file, $name); $validated['attendance_etika_url'] = '/storage/' . $relativePath; } $setting->fill([ 'home_mat_label' => $validated['home_mat_label'] ?? $setting->home_mat_label, 'home_banner_image_path' => $validated['home_banner_image_path'] ?? $setting->home_banner_image_path, 'zoom_meeting_label' => $validated['zoom_meeting_label'] ?? $setting->zoom_meeting_label, 'zoom_subtitle' => $validated['zoom_subtitle'] ?? $setting->zoom_subtitle, 'zoom_image_url' => $validated['zoom_image_url'] ?? $setting->zoom_image_url, 'zoom_meeting_url' => $validated['zoom_meeting_url'] ?? $setting->zoom_meeting_url, 'attendance_etika_url' => $validated['attendance_etika_url'] ?? $setting->attendance_etika_url, ]); $setting->save(); return response()->json([ 'status' => 'success', 'message' => 'Portal settings updated.', ]); } }