orderBy('name') ->get(); return response()->json(['error' => false, 'data' => $templates]); } public function show(int $id): JsonResponse { $tpl = EmailNotificationTemplate::findOrFail($id); $tpl['block_field_definitions'] = EmailNotificationTemplate::blockFieldDefinitions(); return response()->json(['error' => false, 'data' => $tpl]); } public function store(Request $request): JsonResponse { $validated = $request->validate([ 'name' => 'required|string|max:255', 'type' => 'required|string|in:invoice_notification,vm_credentials', 'subject' => 'required|string|max:500', 'header_color' => 'nullable|string|max:20', 'header_title' => 'nullable|string|max:255', 'blocks' => 'nullable|array', 'is_active' => 'boolean', ]); // Use default blocks if none provided if (empty($validated['blocks'])) { $validated['blocks'] = EmailNotificationTemplate::defaultBlocks($validated['type']); } // If activating this template, deactivate others of the same type if ($validated['is_active'] ?? true) { EmailNotificationTemplate::where('type', $validated['type'])->update(['is_active' => false]); } $tpl = EmailNotificationTemplate::create($validated); return response()->json(['error' => false, 'data' => $tpl], 201); } public function update(Request $request, int $id): JsonResponse { $tpl = EmailNotificationTemplate::findOrFail($id); $validated = $request->validate([ 'name' => 'sometimes|string|max:255', 'subject' => 'sometimes|string|max:500', 'header_color' => 'nullable|string|max:20', 'header_title' => 'nullable|string|max:255', 'blocks' => 'nullable|array', 'is_active' => 'boolean', ]); // If activating this template, deactivate others of the same type if (!empty($validated['is_active'])) { EmailNotificationTemplate::where('type', $tpl->type) ->where('id', '!=', $id) ->update(['is_active' => false]); } $tpl->update($validated); return response()->json(['error' => false, 'data' => $tpl->fresh()]); } public function destroy(int $id): JsonResponse { EmailNotificationTemplate::findOrFail($id)->delete(); return response()->json(['error' => false, 'message' => 'Đã xoá template.']); } public function preview(int $id): JsonResponse { $tpl = EmailNotificationTemplate::findOrFail($id); $html = $this->renderer->renderPreview($tpl); return response()->json(['error' => false, 'html' => $html]); } public function fieldDefinitions(): JsonResponse { return response()->json([ 'error' => false, 'data' => [ 'block_types' => $this->blockTypeDefinitions(), 'block_field_definitions' => EmailNotificationTemplate::blockFieldDefinitions(), 'default_blocks' => EmailNotificationTemplate::defaultBlocks(), ], ]); } private function blockTypeDefinitions(): array { return [ // Dùng cho cả 2 loại ['type' => 'greeting', 'label' => 'Lời chào', 'description' => 'Chào hỏi khách hàng theo tên', 'for' => ['invoice_notification', 'vm_credentials']], ['type' => 'custom_text', 'label' => 'Văn bản tùy chỉnh', 'description' => 'Nội dung HTML hoặc text tự do', 'for' => ['invoice_notification', 'vm_credentials']], ['type' => 'footer', 'label' => 'Chữ ký kết thúc', 'description' => 'Trân trọng + tên công ty', 'for' => ['invoice_notification', 'vm_credentials']], // invoice_notification ['type' => 'invoice_info', 'label' => 'Thông tin hóa đơn', 'description' => 'Số HĐ, ngày tạo, tổng tiền, trạng thái...', 'for' => ['invoice_notification']], ['type' => 'customer_info', 'label' => 'Thông tin khách hàng', 'description' => 'Tên, email, địa chỉ khách hàng', 'for' => ['invoice_notification']], ['type' => 'order_items', 'label' => 'Chi tiết sản phẩm', 'description' => 'Bảng sản phẩm từ đơn hàng', 'for' => ['invoice_notification']], ['type' => 'attachments', 'label' => 'File đính kèm', 'description' => 'Danh sách file đính kèm hóa đơn', 'for' => ['invoice_notification']], // vm_credentials ['type' => 'vm_credentials', 'label' => 'Thông tin truy cập VPS', 'description' => 'IP, username, port, password, OS', 'for' => ['vm_credentials']], ['type' => 'product_info', 'label' => 'Thông tin dịch vụ', 'description' => 'Tên sản phẩm, chu kỳ, giá, hạn dùng', 'for' => ['vm_credentials']], ]; } }