Simplify: общий загрузчик файлов и единые ключи на фронте
- Четыре копии «ресайз → FormData → CSRF из cookie → fetch → разбор конверта ошибки» (аватар, фото партии, фото из админки, иконка ачивки) сведены в lib/upload.ts. Иконка по-прежнему уходит оригиналом: ресайз в JPEG убил бы прозрачность герба. - Три копии readCsrfToken и вторая копия resizeImage удалены — берём readCookie из api/client.ts и resizeImage из lib/image.ts с параметром размера. - Ключи, протухающие от партии, собраны в matchAffectedKeys: раньше они были написаны строками мимо реестра qk в двух местах, и переименование ключа сломало бы инвалидацию молча. - Различение «нет сессии» и «нет связи» вынесено в authProbeRetry и применено к обеим пробам. Прошлый заход чинил только игроцкие гварды, и RequireAdmin по-прежнему выкидывал админа на страницу входа при обрыве связи. - ToastContext больше не пересоздаёт значение контекста: провайдер обёрнут вокруг всего приложения, и каждый тост перерисовывал всех потребителей. - PlaceEditor не трогает DOM, пока цель подсветки не изменилась (было querySelectorAll на каждый pointermove). #8 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BoiJK9ux8peeyjLb8TYjFf
This commit is contained in:
@@ -53,6 +53,7 @@ export function PlaceEditor({
|
||||
const elimRef = useRef<HTMLDivElement>(null);
|
||||
const indRef = useRef<HTMLDivElement>(null);
|
||||
const dragRef = useRef<DragState | null>(null);
|
||||
const hintRef = useRef<string | null>(null);
|
||||
|
||||
const byId = new Map(players.map((p) => [p.user_id, p]));
|
||||
const placeOf = (i: number) =>
|
||||
@@ -80,6 +81,7 @@ export function PlaceEditor({
|
||||
};
|
||||
|
||||
const clearHints = () => {
|
||||
hintRef.current = null;
|
||||
if (indRef.current) indRef.current.style.display = "none";
|
||||
listRef.current
|
||||
?.querySelectorAll(".merge-target")
|
||||
@@ -88,7 +90,12 @@ export function PlaceEditor({
|
||||
};
|
||||
|
||||
const showHint = (t: Target, d: DragState) => {
|
||||
// pointermove срабатывает десятки раз в секунду, а цель меняется намного реже:
|
||||
// без этой проверки на каждое движение шёл querySelectorAll и перестановка классов.
|
||||
const key = `${t.type}:${t.type === "elim" ? "" : t.idx}`;
|
||||
if (key === hintRef.current) return;
|
||||
clearHints();
|
||||
hintRef.current = key;
|
||||
if (t.type === "elim") {
|
||||
elimRef.current?.classList.add("highlight");
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user