diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index beaf1e6a..00000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "WillLuke.nextjs.addTypesOnSave": true, - "WillLuke.nextjs.hasPrompted": true, - "prismaERDPreviewer.preferredTheme": "dark" -} diff --git a/src/app/(admin)/logs/logs.module.css b/src/app/(admin)/logs/logs.module.css deleted file mode 100644 index 42dadbaa..00000000 --- a/src/app/(admin)/logs/logs.module.css +++ /dev/null @@ -1,138 +0,0 @@ -/* app/admin/logs/logs.module.css */ -.container { - padding: 24px; - max-width: 1200px; - margin: 0 auto; - } - - .title { - font-size: 24px; - font-weight: bold; - margin-bottom: 16px; - } - - .filterContainer { - margin-bottom: 16px; - } - - .select { - padding: 8px; - border: 1px solid #ddd; - border-radius: 4px; - min-width: 200px; - } - - .logsContainer { - display: flex; - flex-direction: column; - gap: 8px; - } - - .logItem { - padding: 16px; - border-radius: 4px; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); - } - - .errorLog { - background-color: #fef2f2; - } - - .warnLog { - background-color: #fefce8; - } - - .infoLog { - background-color: #ffffff; - } - - .logHeader { - display: flex; - align-items: center; - gap: 8px; - } - - .timestamp { - font-size: 14px; - color: #666; - } - - .level { - padding: 4px 8px; - border-radius: 4px; - font-size: 12px; - font-weight: 500; - } - - .errorLevel { - background-color: #fee2e2; - color: #991b1b; - } - - .warnLevel { - background-color: #fef3c7; - color: #92400e; - } - - .infoLevel { - background-color: #dbeafe; - color: #1e40af; - } - - .message { - margin-top: 8px; - } - - .metadata { - margin-top: 8px; - padding: 8px; - background-color: #f9fafb; - border-radius: 4px; - font-size: 14px; - overflow-x: auto; - white-space: pre-wrap; - } - - .loading { - text-align: center; - padding: 24px; - color: #666; - } - - .error { - color: #dc2626; - text-align: center; - padding: 24px; - } - - /* Hover effects */ - .logItem:hover { - box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); - } - - .select:hover { - border-color: #999; - } - - /* Focus states */ - .select:focus { - outline: none; - border-color: #2563eb; - box-shadow: 0 0 0 2px rgba(37, 99, 235, 0.2); - } - - /* Responsive adjustments */ - @media (max-width: 768px) { - .container { - padding: 16px; - } - - .logHeader { - flex-direction: column; - align-items: flex-start; - } - - .metadata { - font-size: 12px; - } - } \ No newline at end of file diff --git a/src/app/(admin)/logs/page.tsx b/src/app/(admin)/logs/page.tsx deleted file mode 100644 index 2ac03d42..00000000 --- a/src/app/(admin)/logs/page.tsx +++ /dev/null @@ -1,106 +0,0 @@ -// app/admin/logs/page.tsx -"use client"; - -import { useEffect, useState } from "react"; -import { format } from "date-fns"; -import styles from "./logs.module.css"; - -interface LogEntry { - timestamp: string; - level: string; - message: string; - metadata?: any; -} - -export default function LogsPage() { - const [logs, setLogs] = useState([]); - const [loading, setLoading] = useState(true); - const [error, setError] = useState(null); - const [filter, setFilter] = useState<"all" | "error" | "info" | "warn">( - "all" - ); - - useEffect(() => { - fetchLogs(); - }, []); - - async function fetchLogs() { - try { - const response = await fetch("/api/logs/view"); - if (!response.ok) throw new Error("Failed to fetch logs"); - - const data = await response.json(); - setLogs(data.logs); - } catch (err) { - setError(err instanceof Error ? err.message : "Error fetching logs"); - } finally { - setLoading(false); - } - } - - const filteredLogs = logs.filter((log) => - filter === "all" ? true : log.level === filter - ); - - if (loading) return
Loading logs...
; - if (error) return
Error: {error}
; - - return ( -
-

System Logs

- -
- -
- -
- {filteredLogs.map((log, index) => ( -
-
- - {format(new Date(log.timestamp), "yyyy-MM-dd HH:mm:ss")} - - - {log.level.toUpperCase()} - -
- -
{log.message}
- - {log.metadata && ( -
-                {JSON.stringify(log.metadata, null, 2)}
-              
- )} -
- ))} -
-
- ); -} diff --git a/src/app/api/logs/view/route.ts b/src/app/api/logs/view/route.ts deleted file mode 100644 index b660e323..00000000 --- a/src/app/api/logs/view/route.ts +++ /dev/null @@ -1,71 +0,0 @@ -// app/api/logs/view/route.ts -import { NextRequest, NextResponse } from "next/server"; -import fs from "fs/promises"; -import path from "path"; - -interface LogEntry { - timestamp: string; - level: string; - message: string; - metadata?: any; -} - -async function readLogFiles(directory: string): Promise { - try { - const logPath = path.join(process.cwd(), directory); - const files = await fs.readdir(logPath); - const logFiles = files.filter((file) => file.endsWith(".log")); - - const allLogs: LogEntry[] = []; - - for (const file of logFiles) { - const filePath = path.join(logPath, file); - const content = await fs.readFile(filePath, "utf-8"); - - // Parse setiap baris log - const logs = content - .split("\n") - .filter(Boolean) - .map((line) => { - try { - return JSON.parse(line); - } catch (e) { - return null; - } - }) - .filter(Boolean); - - allLogs.push(...logs); - } - - // Sort berdasarkan timestamp, terbaru di atas - return allLogs.sort( - (a, b) => - new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime() - ); - } catch (error) { - console.error("Error reading log files:", error); - return []; - } -} - -export async function GET(request: NextRequest) { - try { - // Baca logs dari frontend dan backend - const frontendLogs = await readLogFiles("logs/frontend"); - const backendLogs = await readLogFiles("logs/backend"); - - // Gabungkan dan sort semua logs - const allLogs = [...frontendLogs, ...backendLogs].sort( - (a, b) => - new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime() - ); - - return NextResponse.json({ logs: allLogs }); - } catch (error) { - return NextResponse.json( - { error: "Failed to fetch logs" }, - { status: 500 } - ); - } -}