IKHSAN
ENID Baca dalam Bahasa Indonesia

homeio

Public

Forked from doctor-io/homeio

Branch
main
Latest commit
958d74616 October 2026

useStoreCatalog.ts

Open raw
"use client";

import { useQuery } from "@tanstack/react-query";
import type {
  StoreAppSummary,
  StoreCatalogSource,
} from "@/lib/shared/contracts/apps";
import { queryKeys } from "@/lib/shared/query-keys";

type StoreCatalogCategory = {
  id: string;
  name: string;
  description: string;
  appCount: number;
};

type StoreCatalogResponse = {
  data: StoreAppSummary[];
  meta: {
    count: number;
    categories: StoreCatalogCategory[];
    featuredAppIds: string[];
    recommendedAppIds: string[];
    sourcePath: string;
    sources: StoreCatalogSource[];
  };
};

export type StoreCatalogResult = {
  apps: StoreAppSummary[];
  categories: StoreCatalogCategory[];
  featuredAppIds: string[];
  recommendedAppIds: string[];
  sourcePath: string;
  sources: StoreCatalogSource[];
};

type UseStoreCatalogOptions = {
  category?: string;
  search?: string;
  installedOnly?: boolean;
  updatesOnly?: boolean;
};

function buildCatalogUrl(options?: UseStoreCatalogOptions) {
  const params = new URLSearchParams();

  if (options?.category) params.set("category", options.category);
  if (options?.search) params.set("search", options.search);
  if (options?.installedOnly) params.set("installedOnly", "true");
  if (options?.updatesOnly) params.set("updatesOnly", "true");

  const query = params.toString();
  return query.length > 0 ? `/api/v1/store/apps?${query}` : "/api/v1/store/apps";
}

async function fetchStoreCatalog(options?: UseStoreCatalogOptions): Promise<StoreCatalogResult> {
  const endpoint = buildCatalogUrl(options);

  const response = await fetch(endpoint, {
    cache: "no-store",
  });

  if (!response.ok) {
    throw new Error(`Failed to fetch store catalog (${response.status})`);
  }

  const json = (await response.json()) as StoreCatalogResponse;
  return {
    apps: json.data,
    categories: json.meta.categories,
    featuredAppIds: json.meta.featuredAppIds,
    recommendedAppIds: json.meta.recommendedAppIds,
    sourcePath: json.meta.sourcePath,
    sources: json.meta.sources,
  };
}

export function useStoreCatalog(options?: UseStoreCatalogOptions) {
  return useQuery({
    queryKey: [...queryKeys.storeCatalog, options ?? {}] as const,
    queryFn: () => fetchStoreCatalog(options),
    staleTime: 60_000,
    refetchOnMount: false,
    refetchOnReconnect: false,
    refetchOnWindowFocus: false,
    placeholderData: (previousData) => previousData,
  });
}
bytes
2,409
lines
90
Type
ts
Latest commit
16 October 2026