diff --git a/driver-pwa/frontend/src/components/AppHeader.tsx b/driver-pwa/frontend/src/components/AppHeader.tsx index b34d92c..224ce07 100644 --- a/driver-pwa/frontend/src/components/AppHeader.tsx +++ b/driver-pwa/frontend/src/components/AppHeader.tsx @@ -1,7 +1,35 @@ +import { useNavigate } from "react-router-dom"; +import { useRef } from "react"; + +/** Долгое нажатие, после которого открывается вход для сотрудника. */ +const LONG_PRESS_MS = 1500; + export function AppHeader() { + const nav = useNavigate(); + const timer = useRef(null); + + // Ссылки «для сотрудника» на экранах водителя нет намеренно: водителю она + // ничего не даёт, а место занимает. Но сотруднику, уже вошедшему водителем, + // адрес /dev иначе приходится набирать руками — отсюда долгий тап по названию. + const start = () => { + timer.current = window.setTimeout(() => nav("/dev"), LONG_PRESS_MS); + }; + const cancel = () => { + if (timer.current) window.clearTimeout(timer.current); + timer.current = null; + }; + return (
- Премиум Водитель + e.preventDefault()} + > + Премиум Водитель +
); } diff --git a/driver-pwa/frontend/src/components/DriverPicker.tsx b/driver-pwa/frontend/src/components/DriverPicker.tsx index 741aa43..8804293 100644 --- a/driver-pwa/frontend/src/components/DriverPicker.tsx +++ b/driver-pwa/frontend/src/components/DriverPicker.tsx @@ -11,7 +11,7 @@ import { Spinner } from "@/components/Spinner"; * первый вход сотрудника (/dev) и смена водителя на вкладке «Отладка». */ export function DriverPicker({ onPicked }: { onPicked: (d: DriverBrief) => void }) { - const setSession = useAuth((s) => s.setSession); + const startImpersonation = useAuth((s) => s.startImpersonation); const [q, setQ] = useState(""); const [list, setList] = useState([]); const [loading, setLoading] = useState(true); @@ -35,7 +35,7 @@ export function DriverPicker({ onPicked }: { onPicked: (d: DriverBrief) => void setBusyId(d.id); try { const r = await impersonate(d.id); - setSession(r.token, r.driver.id, { impersonated: true, driverName: r.driver.fio }); + startImpersonation(r.token, r.driver.id, r.driver.fio); onPicked(r.driver); } catch (e: unknown) { toast.error(await apiErrorText(e, "Не удалось открыть приложение за водителя")); diff --git a/driver-pwa/frontend/src/pages/DebugPage.test.tsx b/driver-pwa/frontend/src/pages/DebugPage.test.tsx index 4f08bcc..38ab8d0 100644 --- a/driver-pwa/frontend/src/pages/DebugPage.test.tsx +++ b/driver-pwa/frontend/src/pages/DebugPage.test.tsx @@ -65,3 +65,35 @@ describe("вкладка отладки", () => { expect(screen.getByText("123 мс")).toBeInTheDocument(); }); }); + +describe("возврат к своему аккаунту", () => { + beforeEach(() => { useAuth.getState().clear(); useStaff.getState().clear(); clearLog(); }); + + it("свой вход не теряется при просмотре чужого экрана", () => { + useAuth.getState().setSession("мой-токен", 91); + useAuth.getState().startImpersonation("чужой-токен", 6866, "Тест Тестовый тестович"); + let s = useAuth.getState(); + expect([s.token, s.driverId, s.impersonated]).toEqual(["чужой-токен", 6866, true]); + + // смена водителя внутри просмотра не должна подменять отложенный свой вход + useAuth.getState().startImpersonation("третий-токен", 2869, "Тестик Николай"); + expect(useAuth.getState().own).toEqual({ token: "мой-токен", driverId: 91 }); + + expect(useAuth.getState().stopImpersonation()).toBe(true); + s = useAuth.getState(); + expect([s.token, s.driverId, s.impersonated, s.own]).toEqual(["мой-токен", 91, false, null]); + }); + + it("если своего входа не было — просмотр просто заканчивается выходом", () => { + useAuth.getState().startImpersonation("чужой-токен", 6866, "Тест"); + expect(useAuth.getState().stopImpersonation()).toBe(false); + expect(useAuth.getState().token).toBeNull(); + }); + + it("кнопка предлагает вернуться к себе, когда есть куда", async () => { + useAuth.getState().setSession("мой-токен", 91); + useAuth.getState().startImpersonation("чужой-токен", 6866, "Тест Тестовый тестович"); + renderAt("/debug"); + expect(screen.getByRole("button", { name: /Вернуться к своему аккаунту/ })).toBeInTheDocument(); + }); +}); diff --git a/driver-pwa/frontend/src/pages/DebugPage.tsx b/driver-pwa/frontend/src/pages/DebugPage.tsx index 56d886e..2d4b731 100644 --- a/driver-pwa/frontend/src/pages/DebugPage.tsx +++ b/driver-pwa/frontend/src/pages/DebugPage.tsx @@ -27,7 +27,7 @@ function Row({ k, v }: { k: string; v: string }) { */ export function DebugPage() { const nav = useNavigate(); - const { token, driverId, driverName, impersonated, clear } = useAuth(); + const { token, driverId, driverName, impersonated, own, clear, stopImpersonation } = useAuth(); const staff = useStaff(); const log = useSyncExternalStore(subscribe, getLog); const [switching, setSwitching] = useState(false); @@ -112,9 +112,16 @@ export function DebugPage() { {staff.token && (