fix: replace createClient with shared supabase singleton in useAdminStats and errorLogger

This commit is contained in:
root 2026-05-27 10:59:37 +00:00
parent 2fea387d43
commit 58a96355f1
2 changed files with 32 additions and 31 deletions

View File

@ -1,13 +1,13 @@
import { useState, useEffect, useCallback } from "react";
import { supabase, hasSupabaseConfig } from "../supabaseClient";
const PERIOD_DAYS = { today: 1, "7d": 7, "30d": 30, all: 0 };
const rpcCall = async (fnName, params) => {
const { createClient } = await import("@supabase/supabase-js");
const supabaseUrl = window.__SUPABASE_URL__ || import.meta.env.VITE_SUPABASE_URL;
const supabaseAnonKey = window.__SUPABASE_ANON_KEY__ || import.meta.env.VITE_SUPABASE_ANON_KEY;
const client = createClient(supabaseUrl, supabaseAnonKey);
const { data, error } = await client.rpc(fnName, params);
if (!hasSupabaseConfig || !supabase) {
throw new Error("Supabase не сконфигурирован");
}
const { data, error } = await supabase.rpc(fnName, params);
if (error) throw error;
return data;
};

View File

@ -1,25 +1,27 @@
import { createClient } from '@supabase/supabase-js';
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL;
const supabaseAnonKey = import.meta.env.VITE_SUPABASE_ANON_KEY;
const supabase = createClient(supabaseUrl, supabaseAnonKey);
import { supabase, hasSupabaseConfig } from "../supabaseClient";
// Debounce tracking: message -> last timestamp
const recentErrors = new Map();
const DEBOUNCE_MS = 10000;
function getUserId() {
// Try to get from Supabase auth session in localStorage
// Try to get from Supabase auth session in sessionStorage
try {
const keys = Object.keys(localStorage);
const keys = Object.keys(sessionStorage);
const authKey = keys.find(
(k) => k.startsWith('sb-') && k.endsWith('-auth-token')
(k) => k.startsWith("sb-") && k.endsWith("-auth-token")
);
if (authKey) {
const data = JSON.parse(localStorage.getItem(authKey));
const data = JSON.parse(sessionStorage.getItem(authKey));
return data?.user?.id || null;
}
// Also check supersam secure storage format
const ssKey = keys.find((k) => k === "supersam-auth");
if (ssKey) {
const data = JSON.parse(sessionStorage.getItem(ssKey));
// The secure storage obfuscates values, but the key structure is known
// Fall through to window.__supersam_user_id__ set by AuthContext
}
} catch {
// ignore
}
@ -46,19 +48,20 @@ function isDebounced(message) {
async function insertErrorLog(entry) {
try {
await supabase.from('client_error_logs').insert([entry]);
if (!hasSupabaseConfig || !supabase) return;
await supabase.from("client_error_logs").insert([entry]);
} catch {
// Fire-and-forget — swallow insertion errors
}
}
function logError(error, componentInfo) {
if (!(error instanceof Error) && typeof error !== 'object' && typeof error !== 'string') {
if (!(error instanceof Error) && typeof error !== "object" && typeof error !== "string") {
return;
}
const message =
typeof error === 'string'
typeof error === "string"
? error
: error?.message || String(error);
@ -66,7 +69,7 @@ function logError(error, componentInfo) {
if (isDebounced(message)) return;
const stack =
typeof error === 'object' && error !== null ? error.stack || null : null;
typeof error === "object" && error !== null ? error.stack || null : null;
let line_number = null;
let column_number = null;
@ -83,16 +86,16 @@ function logError(error, componentInfo) {
}
const entry = {
user_id: getUserId(),
user_id: getUserId() || window.__supersam_user_id__ || null,
message,
stack,
url,
line_number,
column_number,
error_type:
typeof error === 'object' && error !== null
? error.constructor?.name || 'Error'
: 'String',
typeof error === "object" && error !== null
? error.constructor?.name || "Error"
: "String",
component: componentInfo?.component || null,
props: componentInfo?.props
? JSON.stringify(componentInfo.props)
@ -106,16 +109,14 @@ function logError(error, componentInfo) {
}
function initErrorLogging(userId) {
// If a userId is provided, override the getUserId logic
// If a userId is provided, store it for future logError calls
if (userId) {
const origGetUserId = getUserId;
// We store it so future logError calls can use it
window.__supersam_user_id__ = userId;
}
// Catch synchronous errors
window.onerror = function (message, source, lineno, colno, error) {
const msg = typeof message === 'string' ? message : String(message);
const msg = typeof message === "string" ? message : String(message);
if (isDebounced(msg)) return;
@ -126,7 +127,7 @@ function initErrorLogging(userId) {
url: source || null,
line_number: lineno || null,
column_number: colno || null,
error_type: error?.constructor?.name || 'Error',
error_type: error?.constructor?.name || "Error",
component: null,
props: null,
user_agent: navigator.userAgent,
@ -142,7 +143,7 @@ function initErrorLogging(userId) {
const message =
error instanceof Error
? error.message
: typeof error === 'string'
: typeof error === "string"
? error
: String(error);
@ -170,8 +171,8 @@ function initErrorLogging(userId) {
column_number,
error_type:
error instanceof Error
? error.constructor?.name || 'Error'
: 'UnhandledRejection',
? error.constructor?.name || "Error"
: "UnhandledRejection",
component: null,
props: null,
user_agent: navigator.userAgent,