CI / Generate TypeScript types (push) Successful in 12s
CI / Server unit tests (push) Successful in 26s
CI / Build server (push) Successful in 32s
CI / Build client (push) Successful in 41s
CI / Playwright E2E tests (push) Successful in 1m47s
CI / Build and push Docker image (push) Successful in 49s
CI / Notify (push) Successful in 2s
75 lines
2.7 KiB
TypeScript
75 lines
2.7 KiB
TypeScript
import React from 'react';
|
|
import ReactDOM from 'react-dom/client';
|
|
import { ProvideAuth } from './context/auth';
|
|
import 'react-toastify/dist/ReactToastify.css';
|
|
import './index.css';
|
|
import AppRoutes from './AppRoutes';
|
|
import { BrowserRouter } from 'react-router';
|
|
import { client } from '../../types/gen/client.gen';
|
|
import { getConfig } from '../../types/gen/sdk.gen';
|
|
import { getToken } from './Utils';
|
|
import { toast } from 'react-toastify';
|
|
import * as Sentry from '@sentry/react';
|
|
import { setAppConfig } from './utils/appConfig';
|
|
|
|
client.setConfig({
|
|
auth: () => getToken(),
|
|
baseUrl: '/api', // openapi-ts si to z nějakého důvodu neumí převzít z api.yml
|
|
});
|
|
|
|
// Sentry se inicializuje až podle runtime konfigurace ze serveru (bez DSN zůstává vypnuté).
|
|
// Klient je statický build, takže DSN ani limity nejde zapéct při buildu — server je zná z env.
|
|
getConfig().then(({ data }) => {
|
|
setAppConfig({
|
|
loaded: true,
|
|
trustedHeaders: data?.auth?.trustedHeaders,
|
|
storeAdmin: data?.features?.storeAdmin,
|
|
groupLimits: data?.limits?.group,
|
|
});
|
|
if (data?.sentry.dsn) {
|
|
Sentry.init({
|
|
dsn: data.sentry.dsn,
|
|
environment: data.sentry.environment,
|
|
});
|
|
}
|
|
}).catch(() => {
|
|
// Config endpoint nedostupný — běžíme bez Sentry, s výchozími limity a původním chováním přihlášení
|
|
setAppConfig({ loaded: true });
|
|
});
|
|
|
|
// Interceptor na vyhození toasteru při chybě
|
|
client.interceptors.response.use(async response => {
|
|
// TODO opravit - login je zatím výjimka, voláme ho "naprázdno" abychom zjistili, zda nás nepřihlásily trusted headers
|
|
if (!response.ok && !response.url.includes("/login")) {
|
|
// Čteme z klonu, aby tělo odpovědi zůstalo k dispozici i generovanému SDK
|
|
const json = await response.clone().json();
|
|
toast.error(json.error, { theme: "colored" });
|
|
// Serverové chyby hlásíme do Sentry; 4xx jsou očekávané (chyby uživatele)
|
|
if (response.status >= 500) {
|
|
Sentry.captureMessage(`API ${response.status}: ${new URL(response.url).pathname} — ${json.error}`, 'error');
|
|
}
|
|
}
|
|
return response;
|
|
});
|
|
|
|
const root = ReactDOM.createRoot(
|
|
document.getElementById('root') as HTMLElement
|
|
);
|
|
root.render(
|
|
<React.StrictMode>
|
|
<Sentry.ErrorBoundary fallback={
|
|
<div className="text-center p-5">
|
|
<h4>Něco se pokazilo 😕</h4>
|
|
<p>Chyba byla nahlášena. Zkuste stránku načíst znovu.</p>
|
|
<button className="btn btn-primary" onClick={() => window.location.reload()}>Načíst znovu</button>
|
|
</div>
|
|
}>
|
|
<BrowserRouter>
|
|
<ProvideAuth>
|
|
<AppRoutes />
|
|
</ProvideAuth>
|
|
</BrowserRouter>
|
|
</Sentry.ErrorBoundary>
|
|
</React.StrictMode>
|
|
);
|