IKHSAN
ENID Baca dalam Bahasa Indonesia

homeio

Public

Forked from doctor-io/homeio

Branch
main
Latest commit
958d74616 October 2026

useNetworkActions.ts

Open raw
"use client";

import { useMutation, useQueryClient } from "@tanstack/react-query";
import type { NetworkStatus } from "@/lib/shared/contracts/network";
import { queryKeys } from "@/lib/shared/query-keys";

type NetworkMutationResponse = {
  data: NetworkStatus;
};

type ErrorResponsePayload = {
  error?: string;
  code?: string;
};

function toNetworkActionErrorMessage(
  endpoint: string,
  status: number,
  payload: ErrorResponsePayload | null,
) {
  const baseMessage = payload?.error?.trim() || `Network action failed (${status}) for ${endpoint}`;
  const code = payload?.code?.trim();
  if (!code) return baseMessage;

  if (code === "helper_unavailable") {
    return "DBus helper unavailable. Check home-server-dbus service status.";
  }

  if (code === "network_manager_unavailable") {
    return "NetworkManager is unavailable on this server.";
  }

  if (code === "auth_failed") {
    return "Wi-Fi authentication failed. Check the network password.";
  }

  return `${baseMessage} [${code}]`;
}

async function parseErrorPayload(response: Response) {
  try {
    return (await response.json()) as ErrorResponsePayload;
  } catch {
    return null;
  }
}

async function postNetworkAction(
  endpoint: string,
  payload: Record<string, unknown>,
) {
  const response = await fetch(endpoint, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify(payload),
  });

  if (!response.ok) {
    const errorPayload = await parseErrorPayload(response);
    throw new Error(
      toNetworkActionErrorMessage(endpoint, response.status, errorPayload),
    );
  }

  const json = (await response.json()) as NetworkMutationResponse;
  return json.data;
}

export function useNetworkActions() {
  const queryClient = useQueryClient();

  const connectMutation = useMutation({
    mutationFn: (input: { ssid: string; password?: string }) =>
      postNetworkAction(
        "/api/v1/network/connect",
        {
          ssid: input.ssid,
          password: input.password,
        },
      ),
    onSuccess: () => {
      void Promise.all([
        queryClient.invalidateQueries({ queryKey: queryKeys.networkStatus }),
        queryClient.invalidateQueries({ queryKey: queryKeys.networkNetworks }),
      ]);
    },
  });

  const disconnectMutation = useMutation({
    mutationFn: (input?: { iface?: string }) =>
      postNetworkAction(
        "/api/v1/network/disconnect",
        input ?? {},
      ),
    onSuccess: () => {
      void Promise.all([
        queryClient.invalidateQueries({ queryKey: queryKeys.networkStatus }),
        queryClient.invalidateQueries({ queryKey: queryKeys.networkNetworks }),
      ]);
    },
  });

  return {
    connectNetwork: connectMutation.mutateAsync,
    disconnectNetwork: disconnectMutation.mutateAsync,
    isConnecting: connectMutation.isPending,
    isDisconnecting: disconnectMutation.isPending,
    actionError: connectMutation.error ?? disconnectMutation.error ?? null,
  };
}
bytes
2,990
lines
113
Type
ts
Latest commit
16 October 2026