85 lines
2.5 KiB
TypeScript
85 lines
2.5 KiB
TypeScript
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
|
import { useApi } from "../api/context";
|
|
import { serverNow, syncClock } from "../clock/clock";
|
|
import { errorMessage, useLoadedPlayer } from "../state/actions";
|
|
import { PLAYER_STATE_KEY } from "../state/player";
|
|
import { Button } from "../ui";
|
|
|
|
const MINUTE = 60_000;
|
|
|
|
/**
|
|
* Settings → Developer (non-production builds only, CR-011): fast-forward the
|
|
* server clock, add credits, or land every flight now.
|
|
*/
|
|
export function DevTools() {
|
|
const api = useApi();
|
|
const queryClient = useQueryClient();
|
|
const state = useLoadedPlayer();
|
|
const refresh = async () => {
|
|
await syncClock(api);
|
|
await queryClient.invalidateQueries({ queryKey: PLAYER_STATE_KEY });
|
|
await queryClient.invalidateQueries({ queryKey: ["board"] });
|
|
};
|
|
const advance = useMutation({
|
|
mutationFn: (advanceMs: number) => api.call("devAdvanceClock", { advanceMs }),
|
|
onSuccess: refresh,
|
|
});
|
|
const credits = useMutation({
|
|
mutationFn: () => api.call("devAddCredits", { amount: 10_000 }),
|
|
onSuccess: refresh,
|
|
});
|
|
const lastArrival = Math.max(0, ...state.activeDispatches.map((d) => d.arrivalAt));
|
|
const busy = advance.isPending || credits.isPending;
|
|
const error = advance.error ?? credits.error;
|
|
|
|
return (
|
|
<div className="space-y-2">
|
|
<div className="flex flex-wrap gap-2">
|
|
<Button
|
|
needsServer
|
|
variant="secondary"
|
|
size="sm"
|
|
disabled={busy}
|
|
onClick={() => advance.mutate(10 * MINUTE)}
|
|
>
|
|
Advance 10 minutes
|
|
</Button>
|
|
<Button
|
|
needsServer
|
|
variant="secondary"
|
|
size="sm"
|
|
disabled={busy}
|
|
onClick={() => advance.mutate(60 * MINUTE)}
|
|
>
|
|
Advance 1 hour
|
|
</Button>
|
|
<Button
|
|
needsServer
|
|
variant="secondary"
|
|
size="sm"
|
|
disabled={busy}
|
|
onClick={() => credits.mutate()}
|
|
>
|
|
Add 10,000 credits
|
|
</Button>
|
|
<Button
|
|
needsServer
|
|
variant="secondary"
|
|
size="sm"
|
|
disabled={busy || lastArrival <= serverNow()}
|
|
onClick={() =>
|
|
advance.mutate(Math.max(1000, Math.ceil(lastArrival - serverNow()) + 1000))
|
|
}
|
|
>
|
|
Finish all flights
|
|
</Button>
|
|
</div>
|
|
{error && (
|
|
<p role="alert" className="text-sm text-rose-300">
|
|
{errorMessage(error)}
|
|
</p>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|