- Resolve brand from account: /me returns brand (praktika/kopylov->praktika); useBrand uses ?brand= param OR me.brand (param wins) -> praktika auto-branded on login (no manual ?brand= needed). - Result IA (Brusnika-style): single «Ожидаемая цена сделки» headline (lower, -X% vs asking, 5-12% note); two DISTINCT reference figures (asking объявления vs ДКП Росреестр) + price bars; sources row; 3 always-on explainer cards (asking!=real, ремонт по состоянию, скрытые расходы <=15%). - Defer commercial buyback value (Brusnika p.4): OfferCard stub + TODO, no invented numbers (pending Praktika commercial terms). - tsc clean, ruff clean, 35 backend tests (7 new /me-brand). Refs #657
52 lines
1.7 KiB
TypeScript
52 lines
1.7 KiB
TypeScript
"use client";
|
||
|
||
/**
|
||
* MIRROR of main frontend `frontend/src/lib/useMe.ts` — keep in sync manually.
|
||
*
|
||
* Tradein-mvp — отдельный Next.js bundle с basePath=/trade-in. `apiFetch`
|
||
* автоматически префиксит `API_BASE_URL` (= `/trade-in` в проде, "" в dev),
|
||
* поэтому путь `/api/v1/me` в проде превращается в `/trade-in/api/v1/me` →
|
||
* Caddy `uri strip_prefix /trade-in` → tradein-backend `/api/v1/me`.
|
||
* Tradein-backend имеет mirror endpoint `/me` (см. `tradein-mvp/backend/app/api/v1/me.py`).
|
||
*/
|
||
|
||
import { useQuery } from "@tanstack/react-query";
|
||
|
||
import { apiFetchWithStatus, HTTPError } from "@/lib/api";
|
||
|
||
export type Role = "admin" | "pilot";
|
||
|
||
export interface UserScope {
|
||
username: string;
|
||
role: Role;
|
||
allowed_paths: string[];
|
||
deny_paths: string[];
|
||
// #657 brand-by-account: slug бренда, привязанный к аккаунту (praktika→"praktika").
|
||
// null/undefined = generic UI. useBrand применяет его автоматически на login.
|
||
brand?: string | null;
|
||
}
|
||
|
||
export const ME_QUERY_KEY = ["auth", "me"] as const;
|
||
|
||
async function fetchMe(): Promise<UserScope> {
|
||
const { body } = await apiFetchWithStatus<UserScope>("/api/v1/me");
|
||
return body;
|
||
}
|
||
|
||
export function useMe() {
|
||
return useQuery<UserScope, Error>({
|
||
queryKey: ME_QUERY_KEY,
|
||
queryFn: fetchMe,
|
||
staleTime: Infinity,
|
||
gcTime: Infinity,
|
||
refetchOnWindowFocus: false,
|
||
refetchOnReconnect: false,
|
||
refetchOnMount: false,
|
||
retry: (failureCount, error) => {
|
||
if (error instanceof HTTPError && (error.status === 401 || error.status === 403)) {
|
||
return false;
|
||
}
|
||
return failureCount < 2;
|
||
},
|
||
});
|
||
}
|