Files
sarlink-portal/queries/devices.ts
i701 d2b281281f
All checks were successful
Build and Push Docker Images / Build and Push Docker Images (push) Successful in 11m49s
feat: implement add device functionality with validation and error handling; refactor related components for improved state management
2025-06-25 20:10:32 +05:00

138 lines
3.7 KiB
TypeScript

"use server";
import { authOptions } from "@/app/auth";
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";
import { getServerSession } from "next-auth";
import { revalidatePath } from "next/cache";
type GetDevicesProps = {
query?: string;
offset?: number;
limit?: number;
page?: number;
sortBy?: string;
status?: string;
};
export async function getDevices({ query, offset, limit }: GetDevicesProps) {
const session = await checkSession();
const response = await fetch(
`${process.env.SARLINK_API_BASE_URL}/api/devices/?name=${query}&offset=${offset}&limit=${limit}`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
Authorization: `Token ${session?.apiToken}`,
},
},
);
return handleApiResponse<ApiResponse<Device>>(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<Device>(response, "getDevice");
}
export async function addDeviceAction(
prevState: AddDeviceFormState,
formData: FormData
): Promise<AddDeviceFormState> {
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<Device>(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 blockDevice({
deviceId,
reason_for_blocking,
blocked_by,
}: {
deviceId: string;
reason_for_blocking: string;
blocked_by: "ADMIN" | "PARENT";
}) {
const session = await getServerSession(authOptions);
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: true,
reason_for_blocking: session?.user?.is_superuser
? reason_for_blocking
: "Blocked by parent",
blocked_by: session?.user?.is_superuser ? "ADMIN" : "PARENT",
}),
},
);
return handleApiResponse<Device>(response, "blockDevice");
}