← back to Open Seo

src/client/features/keywords/hooks/usePreferredKeywordLocation.ts

72 lines

import { useEffect, useState } from "react";
import { z } from "zod";
import {
  DEFAULT_LOCATION_CODE,
  isSupportedLocationCode,
} from "@/client/features/keywords/locations";

// Scoped per project: a location picked while working on one project must not
// shadow another project's own default market.
const storageKey = (projectId: string) =>
  `keyword-preferred-location:${projectId}`;
const locationCodeSchema = z.number().int().positive();

function loadPreferredLocationCode(projectId: string) {
  try {
    const raw = localStorage.getItem(storageKey(projectId));
    if (!raw) return null;

    const parsed = locationCodeSchema.parse(JSON.parse(raw));
    return isSupportedLocationCode(parsed) ? parsed : null;
  } catch {
    return null;
  }
}

function savePreferredLocationCode(projectId: string, locationCode: number) {
  try {
    localStorage.setItem(storageKey(projectId), JSON.stringify(locationCode));
  } catch {
    // storage full or unavailable - silently ignore
  }
}

/**
 * Preference order: the user's explicit choice for this project (persisted per
 * browser) > the project's default market (may arrive async from the projects
 * query) > the US fallback.
 */
export function usePreferredKeywordLocation(
  projectId: string,
  projectDefaultLocationCode?: number,
) {
  const [preference, setPreference] = useState(() => ({
    projectId,
    locationCode: loadPreferredLocationCode(projectId),
  }));
  const chosenLocationCode =
    preference.projectId === projectId
      ? preference.locationCode
      : loadPreferredLocationCode(projectId);

  useEffect(() => {
    if (preference.projectId === projectId) return;
    setPreference({ projectId, locationCode: chosenLocationCode });
  }, [chosenLocationCode, preference.projectId, projectId]);

  const preferredLocationCode =
    chosenLocationCode ?? projectDefaultLocationCode ?? DEFAULT_LOCATION_CODE;

  function setPreferredLocationCode(locationCode: number) {
    if (!isSupportedLocationCode(locationCode)) return;
    setPreference({ projectId, locationCode });
    savePreferredLocationCode(projectId, locationCode);
  }

  return {
    preferredLocationCode,
    selectedLocationCode: chosenLocationCode ?? undefined,
    setPreferredLocationCode,
  };
}