Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions src/components/strategy-switcher/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
"use client";

import React, { useCallback, useEffect, useState } from "react";
import React, { useCallback, useEffect, useSyncExternalStore } from "react";
import { useGameStore } from "@/zustand/game-store";
import {
DEFAULT_STRATEGY,
getOrderStrategy,
listOrderStrategies,
setOrderStrategy,
subscribeOrderStrategy,
} from "@/utils/order-strategies";

/**
Expand All @@ -18,8 +20,13 @@ const enabled = process.env.NODE_ENV !== "production";

const StrategySwitcher: React.FC = () => {
const redeal = useGameStore((state) => state.redealCurrentLevel);
const [current, setCurrent] = useState<string>(() =>
enabled ? getOrderStrategy().name : ""
// Hydration-safe read of the active strategy: SSR + first client render use the
// build-time default; after hydration the client snapshot resolves localStorage.
// Re-renders when setOrderStrategy fires (e.g. cycling).
const current = useSyncExternalStore(
subscribeOrderStrategy,
() => getOrderStrategy().name,
() => DEFAULT_STRATEGY
);

const cycle = useCallback(
Expand All @@ -28,7 +35,6 @@ const StrategySwitcher: React.FC = () => {
const idx = names.indexOf(getOrderStrategy().name);
const next = names[(idx + dir + names.length) % names.length];
setOrderStrategy(next);
setCurrent(next);
redeal();
},
[redeal]
Expand Down
12 changes: 12 additions & 0 deletions src/utils/order-strategies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,17 @@ export const listOrderStrategies = (): Array<{ name: string; description: string
const DEV = process.env.NODE_ENV !== "production";

let runtimeOverride: string | null = null;
const strategyListeners = new Set<() => void>();

/** Subscribe to active-strategy changes. Returns an unsubscribe fn.
* Lets the dev switcher reflect the strategy via React's useSyncExternalStore
* (hydration-safe: server snapshot = DEFAULT, client snapshot = resolved). */
export const subscribeOrderStrategy = (cb: () => void): (() => void) => {
strategyListeners.add(cb);
return () => {
strategyListeners.delete(cb);
};
};

/**
* Override the active strategy for this session. Pass a name from `STRATEGIES`,
Expand All @@ -215,6 +226,7 @@ export const setOrderStrategy = (name: string | null): void => {
} catch {
/* localStorage unavailable (SSR / privacy mode) — in-memory override still applies */
}
strategyListeners.forEach((cb) => cb());
};

/**
Expand Down
Loading