Browse Source

debug

master
mortezaei 2 months ago
parent
commit
0c86e0ca86
  1. 100
      src/components/dev/debug-toast.tsx
  2. 59
      src/lib/http.ts

100
src/components/dev/debug-toast.tsx

@ -6,60 +6,94 @@ interface DebugLog {
id: string; id: string;
timestamp: string; timestamp: string;
url: string; url: string;
fullUrl?: string;
method: string; method: string;
status: number; status: number;
headers: Record<string, string>;
response?: any;
statusText?: string;
requestHeaders: Record<string, string>;
requestBody?: any;
responseData?: any;
error?: string;
duration?: number;
} }
export default function DebugToast() { export default function DebugToast() {
const [logs, setLogs] = useState<DebugLog[]>([]); const [logs, setLogs] = useState<DebugLog[]>([]);
const [isOpen, setIsOpen] = useState(false);
const [isOpen, setIsOpen] = useState(true);
useEffect(() => { useEffect(() => {
const handleDebugLog = (event: CustomEvent<DebugLog>) => {
setLogs((prev) => [event.detail, ...prev].slice(0, 10));
setIsOpen(true);
const handleDebugLog = (event: any) => {
setLogs((prev) => [event.detail, ...prev].slice(0, 20));
}; };
window.addEventListener("debug-log" as any, handleDebugLog);
return () => window.removeEventListener("debug-log" as any, handleDebugLog);
window.addEventListener("debug-log", handleDebugLog);
return () => window.removeEventListener("debug-log", handleDebugLog);
}, []); }, []);
if (!isOpen || logs.length === 0) return null;
const getStatusColor = (status: number) => {
if (status >= 200 && status < 300) return "bg-green-900 border-green-500";
if (status >= 400) return "bg-red-900 border-red-500";
return "bg-yellow-900 border-yellow-500";
};
return ( return (
<div className="fixed top-4 right-4 z-[9999] max-w-md max-h-[80vh] overflow-auto bg-red-900 text-white p-4 rounded-lg shadow-2xl border-2 border-red-500">
<div className="flex justify-between items-center mb-2">
<h3 className="font-bold text-sm">🐛 Debug Log</h3>
<button
onClick={() => setIsOpen(false)}
className="text-white hover:text-red-200"
>
</button>
<div className="fixed top-2 left-2 z-[9999] max-w-[95vw] max-h-[90vh] overflow-auto bg-gray-900 text-white p-3 rounded-lg shadow-2xl border-2 border-gray-600 text-[11px]">
<div className="flex justify-between items-center mb-2 sticky top-0 bg-gray-900 pb-2">
<h3 className="font-bold">🔍 API Debug ({logs.length})</h3>
<div className="flex gap-2">
<button
onClick={() => setLogs([])}
className="text-white hover:text-red-300 px-2"
>
پاک
</button>
<button
onClick={() => setIsOpen(!isOpen)}
className="text-white hover:text-blue-300 px-2"
>
{isOpen ? "−" : "+"}
</button>
</div>
</div> </div>
{logs.map((log) => (
<div key={log.id} className="mb-4 p-2 bg-red-950 rounded text-xs">
<div className="font-bold mb-1">
{log.method} {log.status}
{isOpen && logs.map((log) => (
<div key={log.id} className={`mb-3 p-2 rounded border ${getStatusColor(log.status)}`}>
<div className="font-bold mb-1 flex justify-between">
<span>{log.method} {log.status} {log.statusText}</span>
{log.duration && <span className="text-blue-300">{log.duration}ms</span>}
</div>
<div className="mb-1 text-gray-300 break-all text-[10px]">
{log.fullUrl || log.url}
</div> </div>
<div className="mb-1 text-red-300 break-all">{log.url}</div>
<div className="mb-1 text-yellow-300">{log.timestamp}</div>
<details className="mt-2">
<summary className="cursor-pointer text-blue-300">Headers</summary>
<pre className="mt-1 text-[10px] overflow-auto">
{JSON.stringify(log.headers, null, 2)}
<div className="text-yellow-300 text-[10px] mb-2">{log.timestamp}</div>
{log.error && (
<div className="mb-2 text-red-300 text-[10px]"> {log.error}</div>
)}
<details className="mt-1">
<summary className="cursor-pointer text-blue-300">📤 Request Headers</summary>
<pre className="mt-1 text-[9px] overflow-auto max-h-32 bg-black p-1 rounded">
{JSON.stringify(log.requestHeaders, null, 2)}
</pre> </pre>
</details> </details>
{log.response && (
<details className="mt-2">
<summary className="cursor-pointer text-blue-300">Response</summary>
<pre className="mt-1 text-[10px] overflow-auto">
{JSON.stringify(log.response, null, 2)}
{log.requestBody && (
<details className="mt-1">
<summary className="cursor-pointer text-blue-300">📦 Request Body</summary>
<pre className="mt-1 text-[9px] overflow-auto max-h-32 bg-black p-1 rounded">
{JSON.stringify(log.requestBody, null, 2)}
</pre>
</details>
)}
{log.responseData && (
<details className="mt-1">
<summary className="cursor-pointer text-blue-300">📥 Response</summary>
<pre className="mt-1 text-[9px] overflow-auto max-h-32 bg-black p-1 rounded">
{JSON.stringify(log.responseData, null, 2)}
</pre> </pre>
</details> </details>
)} )}

59
src/lib/http.ts

@ -64,29 +64,54 @@ http.interceptors.request.use((config) => {
config.url = ""; config.url = "";
} }
(config as any).requestStartTime = Date.now();
return config; return config;
}); });
http.interceptors.response.use( http.interceptors.response.use(
(response) => response,
(response) => {
const config = response.config as any;
const debugLog = {
id: Date.now().toString(),
timestamp: new Date().toLocaleString("fa-IR"),
url: config.url || "unknown",
fullUrl: config.baseURL ? `${config.baseURL}${config.url}` : config.url,
method: config.method?.toUpperCase() || "GET",
status: response.status,
statusText: response.statusText,
requestHeaders: config.headers || {},
requestBody: config.data,
responseData: response.data,
duration: Date.now() - (config.requestStartTime || Date.now()),
};
if (typeof window !== "undefined") {
window.dispatchEvent(new CustomEvent("debug-log", { detail: debugLog }));
}
return response;
},
(error) => { (error) => {
if (error.response?.status === 401) {
const debugLog = {
id: Date.now().toString(),
timestamp: new Date().toLocaleString("fa-IR"),
url: error.config?.url || "unknown",
method: error.config?.method?.toUpperCase() || "GET",
status: 401,
headers: error.config?.headers || {},
response: error.response?.data,
};
if (typeof window !== "undefined") {
window.dispatchEvent(
new CustomEvent("debug-log", { detail: debugLog })
);
}
const config = error.config as any;
const debugLog = {
id: Date.now().toString(),
timestamp: new Date().toLocaleString("fa-IR"),
url: config?.url || "unknown",
fullUrl: config?.baseURL ? `${config.baseURL}${config.url}` : config?.url,
method: config?.method?.toUpperCase() || "GET",
status: error.response?.status || 0,
statusText: error.response?.statusText || "Network Error",
requestHeaders: config?.headers || {},
requestBody: config?.data,
responseData: error.response?.data,
error: error.message,
duration: Date.now() - (config?.requestStartTime || Date.now()),
};
if (typeof window !== "undefined") {
window.dispatchEvent(new CustomEvent("debug-log", { detail: debugLog }));
} }
return Promise.reject(error); return Promise.reject(error);
} }
); );
Loading…
Cancel
Save