61 lines
2.6 KiB
JavaScript
61 lines
2.6 KiB
JavaScript
/* Дашборд по ссылке для маркетолога: та же таблица, что «По неделям» в админке (weekly.js),
|
||
только просмотр. Токен — в адресе после «#»: он не уходит на сервер в адресе, в журналы и в Referer;
|
||
запрос несёт его в заголовке Authorization. */
|
||
const $ = (s) => document.querySelector(s);
|
||
const el = (t, p = {}) => Object.assign(document.createElement(t), p);
|
||
|
||
function toast(msg, bad) {
|
||
if (!$('#sh-error').hidden) return; // страница ошибки уже всё сказала
|
||
const t = $('#toast');
|
||
t.textContent = msg; t.className = 'toast show' + (bad ? ' bad' : '');
|
||
setTimeout(() => { t.className = 'toast'; }, 2600);
|
||
}
|
||
|
||
// Клиника приходит с сервера вместе с данными: ссылка привязана к одной клинике.
|
||
const ReportClinic = {
|
||
key: '',
|
||
brand: '',
|
||
brands: { dana: 'DANA Medical', ochevidno: 'Очевидно' },
|
||
q: (path) => path,
|
||
};
|
||
|
||
const Share = {
|
||
token: decodeURIComponent(location.hash.slice(1)),
|
||
|
||
fail(text) {
|
||
$('#sh-main').hidden = true;
|
||
$('#sh-error').hidden = false;
|
||
if (text) $('#sh-error-text').textContent = text;
|
||
},
|
||
|
||
start() {
|
||
WeeklyDashboard.readOnly = true;
|
||
if (Share.token.length < 40) { Share.fail(); return; }
|
||
$('#sh-main').hidden = false;
|
||
for (const b of document.querySelectorAll('.sh-head [data-mode]')) {
|
||
b.onclick = () => {
|
||
WeeklyDashboard.setMode(b.dataset.mode);
|
||
for (const x of document.querySelectorAll('.sh-head [data-mode]')) x.setAttribute('aria-selected', String(x === b));
|
||
};
|
||
}
|
||
WeeklyDashboard.load();
|
||
},
|
||
};
|
||
|
||
async function api(path) {
|
||
if (path !== '/share/weekly-reports') throw new Error('Недоступно по ссылке');
|
||
const r = await fetch('/api/v1/share/weekly-reports', {
|
||
headers: { Authorization: 'Bearer ' + Share.token },
|
||
credentials: 'omit',
|
||
cache: 'no-store',
|
||
});
|
||
const body = await r.json().catch(() => ({}));
|
||
if (r.status === 401) { Share.fail(body.error?.message); throw new Error(body.error?.message || 'Ссылка недействительна'); }
|
||
if (!r.ok) throw new Error(body.error?.message || 'Ошибка ' + r.status);
|
||
ReportClinic.key = body.meta?.clinic || '';
|
||
ReportClinic.brand = ReportClinic.brands[ReportClinic.key] || body.meta?.title || '';
|
||
document.title = `${ReportClinic.brand} — маркетинговая аналитика`;
|
||
$('#sh-title').textContent = `${ReportClinic.brand} — маркетинговая аналитика`;
|
||
return body;
|
||
}
|