Merge dev → main: surveys, P/OEM page, trial upsell, catalog-issue report, pcat timings #127
@@ -13,9 +13,17 @@ let initialized = false;
|
||||
// Set once init succeeds so the catalog-degradation helpers below can use the
|
||||
// already-loaded SDK without re-awaiting the dynamic import on every call.
|
||||
let sentryApi: typeof import("@sentry/react") | null = null;
|
||||
// Cache the init promise so concurrent callers (e.g. a degradation reporter that
|
||||
// fires on first paint, racing the main.tsx call) await the SAME init instead of
|
||||
// double-initialising the SDK.
|
||||
let initPromise: Promise<void> | null = null;
|
||||
|
||||
export async function initSentry() {
|
||||
if (initialized) return;
|
||||
export function initSentry(): Promise<void> {
|
||||
if (!initPromise) initPromise = doInitSentry();
|
||||
return initPromise;
|
||||
}
|
||||
|
||||
async function doInitSentry(): Promise<void> {
|
||||
const dsn = import.meta.env.VITE_SENTRY_DSN;
|
||||
if (!dsn) {
|
||||
if (import.meta.env.DEV) {
|
||||
@@ -24,20 +32,18 @@ export async function initSentry() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Both dev.sase.tr (staging) and sase.tr (prod) ship a production Vite build
|
||||
// (MODE === "production"), so MODE can't separate them. Derive from the host at
|
||||
// runtime instead, so dev errors stay filterable from prod in Sentry. An
|
||||
// explicit VITE_SENTRY_ENVIRONMENT still wins.
|
||||
// Hostname is authoritative for the two real deployments — sase.tr (prod) and
|
||||
// dev.sase.tr (staging) — which both ship a production Vite build baking the
|
||||
// SAME VITE_SENTRY_ENVIRONMENT (compose default "production"), so that var can't
|
||||
// tell them apart. Use it only as a fallback for local/preview hosts.
|
||||
const host = typeof window !== "undefined" ? window.location.hostname : "";
|
||||
const environment =
|
||||
(import.meta.env.VITE_SENTRY_ENVIRONMENT as string | undefined) ??
|
||||
(host === "sase.tr" || host === "www.sase.tr"
|
||||
host === "sase.tr" || host === "www.sase.tr"
|
||||
? "production"
|
||||
: host.endsWith("dev.sase.tr")
|
||||
? "staging"
|
||||
: import.meta.env.DEV
|
||||
? "development"
|
||||
: "staging");
|
||||
: (import.meta.env.VITE_SENTRY_ENVIRONMENT as string | undefined) ||
|
||||
(import.meta.env.DEV ? "development" : "staging");
|
||||
const release = import.meta.env.VITE_SENTRY_RELEASE;
|
||||
|
||||
try {
|
||||
@@ -123,11 +129,14 @@ export async function reportCatalogDegradation(
|
||||
ctx: CatalogIssueContext,
|
||||
): Promise<void> {
|
||||
try {
|
||||
const Sentry = sentryApi;
|
||||
if (!Sentry) return;
|
||||
const dedupKey = `${kind}:${ctx.categoryId ?? ctx.vehicleId ?? ""}`;
|
||||
if (reportedThisSession.has(dedupKey)) return;
|
||||
reportedThisSession.add(dedupKey);
|
||||
// The empty/error state can render before the SDK's dynamic import resolves —
|
||||
// wait for init so the failure is never silently dropped.
|
||||
await initSentry();
|
||||
const Sentry = sentryApi;
|
||||
if (!Sentry) return;
|
||||
|
||||
const brand = brandOf(ctx.vehicleLabel);
|
||||
Sentry.captureMessage(`catalog degraded: ${kind} (browser/${brand})`, {
|
||||
@@ -153,6 +162,7 @@ export async function reportCatalogDegradation(
|
||||
*/
|
||||
export async function openCatalogFeedback(ctx: CatalogIssueContext): Promise<void> {
|
||||
try {
|
||||
await initSentry();
|
||||
const Sentry = sentryApi;
|
||||
if (!Sentry) return;
|
||||
Sentry.setTag("catalog_source", ctx.source ?? "unknown");
|
||||
|
||||
Reference in New Issue
Block a user