dana-medical-site/web/src/context/SiteData.jsx
2026-10-23 07:23:20 +00:00

70 lines
2.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { createContext, useContext, useEffect, useState } from 'react';
import { api } from '../api.js';
import { useInitialApiData } from './ApiData.jsx';
// Показывается, пока не пришли данные, и если API недоступен — шапка и подвал не должны пустеть.
const FALLBACK = {
phone: '+7 928 962-00-94',
hours: 'Пн–Вс: 08:00–20:00',
addresses: ['Махачкала, ул. Ляхова, 22', 'Махачкала, ул. Ляхова, 7'],
branches: [],
coords: null,
maxUrl: '',
email: '',
legal: null, // реквизиты: org_name, org_short, inn, ogrn, address, license, email
};
const SiteDataContext = createContext(FALLBACK);
// «г. Махачкала, ул. Ляхова, 22(3 этаж)» → «Махачкала, ул. Ляхова, 22 (3 этаж)»
function normalizeAddress(address) {
return String(address || '')
.replace(/^г\.\s*/, '')
.replace(/(\d)\(/g, '$1 (')
.trim();
}
export function SiteDataProvider({ children }) {
const initial = useInitialApiData('site');
const receivedAt = useInitialApiData('__receivedAt');
const [value, setValue] = useState(initial || FALLBACK);
useEffect(() => {
if (initial && receivedAt && Date.now() - receivedAt < 30_000) return undefined;
const ctrl = new AbortController();
const opts = { signal: ctrl.signal };
Promise.allSettled([api.branches(opts), api.settings(opts)]).then(([branchesRes, settingsRes]) => {
if (ctrl.signal.aborted) return;
const next = { ...FALLBACK };
const branches = branchesRes.status === 'fulfilled' ? branchesRes.value.data || [] : [];
if (branches.length) {
const first = branches[0];
next.branches = branches;
next.phone = first.phones?.[0] || FALLBACK.phone;
next.hours = first.work_hours?.[0] || FALLBACK.hours;
next.addresses = branches.map((b) => normalizeAddress(b.address));
const withCoords = branches.find((b) => b.lat && b.lon);
next.coords = withCoords ? { lat: withCoords.lat, lon: withCoords.lon } : null;
}
const settings = settingsRes.status === 'fulfilled' ? settingsRes.value.data || {} : {};
// Ссылки на MAX у клиники пока нет: иконка появится, когда её заведут в настройках.
if (typeof settings.max_url === 'string') next.maxUrl = settings.max_url;
if (typeof settings.email === 'string') next.email = settings.email;
if (settings.legal && typeof settings.legal === 'object') next.legal = settings.legal;
setValue(next);
});
return () => ctrl.abort();
}, []);
return <SiteDataContext.Provider value={value}>{children}</SiteDataContext.Provider>;
}
export function useSiteData() {
return useContext(SiteDataContext);
}