"use server"; import { revalidatePath } from "next/cache"; import { getServerSession } from "next-auth"; import { authOptions } from "@/app/auth"; import { BlockDeviceFormState } from "@/components/block-device-dialog"; import type { AddDeviceFormState, initialState } from "@/components/user/add-device-dialog"; import type { ApiError, ApiResponse, Device } from "@/lib/backend-types"; import { checkSession } from "@/utils/session"; import { handleApiResponse } from "@/utils/tryCatch"; type GetDevicesProps = { name?: string; offset?: number; limit?: number; page?: number; sortBy?: string; status?: string; [key: string]: string | number | undefined; // Allow additional properties for flexibility }; export async function getDevices(params: GetDevicesProps, allDevices = false) { const session = await checkSession(); // Build query string from all defined params const query = Object.entries(params) .filter(([_, value]) => value !== undefined && value !== "") .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`) .join("&"); const response = await fetch( `${process.env.SARLINK_API_BASE_URL}/api/devices/?${query}&all_devices=${allDevices}`, { method: "GET", headers: { "Content-Type": "application/json", Authorization: `Token ${session?.apiToken}`, }, }, ); return handleApiResponse>(response, "getDevices"); } export async function getDevice({ deviceId }: { deviceId: string }) { const session = await checkSession(); const response = await fetch( `${process.env.SARLINK_API_BASE_URL}/api/devices/${deviceId}/`, { method: "GET", headers: { "Content-Type": "application/json", Authorization: `Token ${session?.apiToken}`, }, }, ); return handleApiResponse(response, "getDevice"); } export async function addDeviceAction( prevState: AddDeviceFormState, formData: FormData ): Promise { const name = formData.get("name") as string; const mac_address = formData.get("mac_address") as string; const errors: typeof initialState.fieldErrors = {}; if (!name || name.length < 2) { errors.name = ["Device name is required and must be at least 2 characters."]; } if (!mac_address || !/^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/.test(mac_address)) { errors.mac_address = ["Invalid MAC address format."]; } if (Object.keys(errors).length > 0) { return { message: "Validation failed.", fieldErrors: errors, payload: formData, }; } try { const session = await getServerSession(authOptions); if (!session?.apiToken) { return { message: "Authentication required.", fieldErrors: {}, payload: formData }; } const response = await fetch( `${process.env.SARLINK_API_BASE_URL}/api/devices/`, { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Token ${session.apiToken}`, }, body: JSON.stringify({ name: name, mac: mac_address, registered: true, }), }, ); await handleApiResponse(response, "addDeviceAction"); revalidatePath("/devices"); return { message: "Device successfully added!", fieldErrors: {}, payload: formData }; } catch (error: unknown) { console.error("Server Action Error:", error); return { message: (error as ApiError).message || "An unexpected error occurred.", fieldErrors: {}, payload: formData }; } } export async function blockDeviceAction( prevState: BlockDeviceFormState, formData: FormData ): Promise { const deviceId = formData.get("deviceId") as string; const reason_for_blocking = formData.get("reason_for_blocking") as string; const action = formData.get("action") as "block" | "unblock" | "simple-block"; const blocked_by = formData.get("blocked_by") as "ADMIN" | "PARENT"; try { const session = await getServerSession(authOptions); if (!session?.apiToken) { return { success: false, message: "Authentication required.", fieldErrors: {}, payload: formData }; } // Validation only for admin block with reason if (action === "block" && session?.user?.is_superuser && (!reason_for_blocking || reason_for_blocking.trim().length < 5)) { return { success: false, message: "Reason for blocking is required and must be at least 5 characters.", fieldErrors: { reason_for_blocking: ["Reason is required and must be at least 5 characters."] }, payload: formData }; } const isBlocking = action === "block" || action === "simple-block"; const response = await fetch( `${process.env.SARLINK_API_BASE_URL}/api/devices/${deviceId}/block/`, { method: "PUT", headers: { "Content-Type": "application/json", Authorization: `Token ${session.apiToken}`, }, body: JSON.stringify({ blocked: isBlocking, reason_for_blocking: session?.user?.is_superuser ? reason_for_blocking || (action === "simple-block" ? "Blocked by admin" : "") : isBlocking ? "Blocked by parent" : "", blocked_by: session?.user?.is_superuser ? blocked_by : "PARENT", }), }, ); const result = await handleApiResponse(response, "blockDeviceAction"); revalidatePath("/devices"); revalidatePath("/parental-control"); return { success: true, message: isBlocking ? "Device blocked successfully!" : "Device unblocked successfully!", fieldErrors: {}, payload: formData }; } catch (error: unknown) { console.error("Block Device Action Error:", error); return { success: false, message: (error as ApiError).message || "An unexpected error occurred.", fieldErrors: {}, payload: formData }; } }