Refactor code structure for improved readability and maintainability

This commit is contained in:
Poyraz Avsever
2026-05-08 11:18:55 +03:00
parent e98972597d
commit 9adc34418e
21 changed files with 1194 additions and 393 deletions
+81 -92
View File
@@ -1,23 +1,27 @@
"use client";
import { useMemo } from "react";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Activity, Brain, PenTool, CheckCircle } from "lucide-react";
import { useLiveQuery } from "dexie-react-hooks";
import { db } from "@/lib/db";
import { Activity, Brain, CheckCircle, PenTool } from "lucide-react";
import {
LineChart,
Bar,
BarChart,
CartesianGrid,
Legend,
Line,
LineChart,
ResponsiveContainer,
Tooltip,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
ResponsiveContainer,
BarChart,
Bar,
Legend,
} from "recharts";
import { db, type Journal, type Task } from "@/lib/db";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
const EMPTY_JOURNALS: Journal[] = [];
const EMPTY_TASKS: Task[] = [];
const moodScores: Record<string, number> = {
happy: 4,
neutral: 3,
@@ -26,65 +30,71 @@ const moodScores: Record<string, number> = {
};
export default function DashboardPage() {
const journals =
useLiveQuery(() => db.journals.orderBy("date").toArray()) || [];
const tasks = useLiveQuery(() => db.tasks.toArray()) || [];
const liveJournals = useLiveQuery<Journal[]>(() =>
db.journals.orderBy("date").toArray(),
);
const liveTasks = useLiveQuery<Task[]>(() => db.tasks.toArray());
const pendingTasksCount = tasks.filter((t) => t.status === "todo").length;
const journals = liveJournals ?? EMPTY_JOURNALS;
const tasks = liveTasks ?? EMPTY_TASKS;
const pendingTasksCount = tasks.filter((task) => task.status === "todo").length;
// Bugüne ait enerji seviyesi
const today = new Date().toISOString().split("T")[0];
const todaysJournal = journals.find((j) => j.date === today);
const todaysJournal = journals.find((journal) => journal.date === today);
const todaysEnergy = todaysJournal ? todaysJournal.energy : "--";
// 1. Grafik: Son 7 günün Ruh Hali ve Enerji trendi
const trendData = useMemo(() => {
const dataMap: Record<
string,
{ date: string; moodSum: number; energySum: number; count: number }
> = {};
journals.forEach((j) => {
if (!dataMap[j.date]) {
dataMap[j.date] = { date: j.date, moodSum: 0, energySum: 0, count: 0 };
journals.forEach((journal) => {
if (!dataMap[journal.date]) {
dataMap[journal.date] = {
date: journal.date,
moodSum: 0,
energySum: 0,
count: 0,
};
}
dataMap[j.date].moodSum += moodScores[j.mood] || 3;
dataMap[j.date].energySum += j.energy;
dataMap[j.date].count += 1;
dataMap[journal.date].moodSum += moodScores[journal.mood] || 3;
dataMap[journal.date].energySum += journal.energy;
dataMap[journal.date].count += 1;
});
return Object.values(dataMap)
.map((d) => ({
date: d.date.slice(5), // Sadece MM-DD formatı alalım
Mood: Number((d.moodSum / d.count).toFixed(1)),
Enerji: Number((d.energySum / d.count).toFixed(1)),
.map((entry) => ({
date: entry.date.slice(5),
Mood: Number((entry.moodSum / entry.count).toFixed(1)),
Enerji: Number((entry.energySum / entry.count).toFixed(1)),
}))
.slice(-7); // Sadece son 7 günü göster
.slice(-7);
}, [journals]);
// 2. Grafik: En çok kullanılan AI etiketleri
const tagData = useMemo(() => {
const counts: Record<string, number> = {};
journals.forEach((j) => {
if (j.ai_tags) {
j.ai_tags.forEach((tag) => {
counts[tag] = (counts[tag] || 0) + 1;
});
}
journals.forEach((journal) => {
journal.ai_tags?.forEach((tag) => {
counts[tag] = (counts[tag] || 0) + 1;
});
});
return Object.entries(counts)
.map(([name, value]) => ({ name, Değer: value }))
.sort((a, b) => b.Değer - a.Değer)
.slice(0, 5); // En çok geçen 5 etiket
.slice(0, 5);
}, [journals]);
// Son günlüğe ait AI Summary
const lastInsight = [...journals]
.reverse()
.find((j) => j.ai_summary)?.ai_summary;
.find((journal) => journal.ai_summary)?.ai_summary;
return (
<div className="space-y-6 max-w-6xl mx-auto animate-in fade-in slide-in-from-bottom-4 duration-500">
<div className="mx-auto max-w-6xl animate-in space-y-6 fade-in slide-in-from-bottom-4 duration-500">
<div className="flex flex-col gap-2">
<h1 className="text-3xl font-bold tracking-tight">Bugün Nasılsın?</h1>
<p className="text-muted-foreground">
@@ -94,15 +104,13 @@ export default function DashboardPage() {
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
<Card>
<CardHeader className="flex flex-row items-center justify-between pb-2 space-y-0">
<CardTitle className="text-sm font-medium">
Günlük Kayıtları
</CardTitle>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Günlük Kayıtları</CardTitle>
<PenTool className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{journals.length}</div>
<p className="text-xs text-muted-foreground mt-1">
<p className="mt-1 text-xs text-muted-foreground">
{journals.length === 0
? "Henüz kayıt girilmedi"
: "Toplam kayıt eklendi"}
@@ -111,58 +119,49 @@ export default function DashboardPage() {
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between pb-2 space-y-0">
<CardTitle className="text-sm font-medium">
Aktif Görevler
</CardTitle>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Aktif Görevler</CardTitle>
<CheckCircle className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{pendingTasksCount}</div>
<p className="text-xs text-muted-foreground mt-1">Bekleyen görev</p>
<p className="mt-1 text-xs text-muted-foreground">Bekleyen görev</p>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between pb-2 space-y-0">
<CardTitle className="text-sm font-medium">
Bugünkü Enerji
</CardTitle>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Bugünkü Enerji</CardTitle>
<Activity className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{todaysEnergy}</div>
<p className="text-xs text-muted-foreground mt-1">
{todaysJournal ? "/ 5 Seviyesinde" : "Kayıt bekleniyor"}
<p className="mt-1 text-xs text-muted-foreground">
{todaysJournal ? "/ 5 seviyesinde" : "Kayıt bekleniyor"}
</p>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between pb-2 space-y-0">
<CardTitle className="text-sm font-medium">
Local AI Durumu
</CardTitle>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Local AI Durumu</CardTitle>
<Brain className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold text-green-500">Hazır</div>
<p className="text-xs text-muted-foreground mt-1">
<p className="mt-1 text-xs text-muted-foreground">
Ollama / Veri bekliyor
</p>
</CardContent>
</Card>
</div>
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-7 ">
{/* Line Chart */}
<Card className="lg:col-span-4 p-6 flex flex-col justify-between">
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-7">
<Card className="flex flex-col justify-between p-6 lg:col-span-4">
<div className="mb-4">
<h3 className="text-lg font-medium mb-1">
Ruh Hali & Enerji Trendi
</h3>
<h3 className="mb-1 text-lg font-medium">Ruh Hali ve Enerji Trendi</h3>
<p className="text-sm text-muted-foreground">
Son 7 günlük ortalamalar (1-5 Arası Puanlama)
Son 7 günlük ortalamalar (1-5 arası puanlama)
</p>
</div>
<div className="h-[250px] w-full">
@@ -196,9 +195,7 @@ export default function DashboardPage() {
}}
itemStyle={{ fontWeight: "500" }}
/>
<Legend
wrapperStyle={{ paddingTop: "10px", fontSize: "14px" }}
/>
<Legend wrapperStyle={{ paddingTop: "10px", fontSize: "14px" }} />
<Line
type="monotone"
dataKey="Mood"
@@ -218,32 +215,25 @@ export default function DashboardPage() {
</LineChart>
</ResponsiveContainer>
) : (
<div className="h-full flex items-center justify-center border-2 border-dashed rounded-md bg-muted/20">
<p className="text-sm text-muted-foreground">
Veri bekleniyor...
</p>
<div className="flex h-full items-center justify-center rounded-md border-2 border-dashed bg-muted/20">
<p className="text-sm text-muted-foreground">Veri bekleniyor...</p>
</div>
)}
</div>
</Card>
{/* Bar Chart & Insight */}
<div className="lg:col-span-3 space-y-4 flex flex-col">
<Card className="p-6 flex-1 flex flex-col">
<div className="flex flex-col space-y-4 lg:col-span-3">
<Card className="flex flex-1 flex-col p-6">
<div className="mb-4">
<h3 className="text-lg font-medium mb-1">AI Konu Dağılımı</h3>
<h3 className="mb-1 text-lg font-medium">AI Konu Dağılımı</h3>
<p className="text-sm text-muted-foreground">
Günlüklerinden çıkarılan en sık 5 etiket
</p>
</div>
<div className="h-[150px] w-full mt-auto">
<div className="mt-auto h-[150px] w-full">
{tagData.length > 0 ? (
<ResponsiveContainer width="100%" height="100%">
<BarChart
data={tagData}
layout="vertical"
margin={{ left: -20 }}
>
<BarChart data={tagData} layout="vertical" margin={{ left: -20 }}>
<CartesianGrid
strokeDasharray="3 3"
horizontal={false}
@@ -276,20 +266,19 @@ export default function DashboardPage() {
</BarChart>
</ResponsiveContainer>
) : (
<div className="h-full flex items-center justify-center border-2 border-dashed rounded-md bg-muted/20">
<p className="text-sm text-muted-foreground">
Yeterli etiket yok.
</p>
<div className="flex h-full items-center justify-center rounded-md border-2 border-dashed bg-muted/20">
<p className="text-sm text-muted-foreground">Yeterli etiket yok.</p>
</div>
)}
</div>
</Card>
<Card className="p-6 bg-primary/5 border-primary/20 flex-1">
<h3 className="text-lg font-medium mb-3 flex items-center gap-2">
<Brain className="w-5 h-5 text-primary" /> Son AI İçgörüsü
<Card className="flex-1 border-primary/20 bg-primary/5 p-6">
<h3 className="mb-3 flex items-center gap-2 text-lg font-medium">
<Brain className="h-5 w-5 text-primary" />
Son AI İçgörüsü
</h3>
<p className="text-sm text-foreground/80 leading-relaxed italic">
<p className="text-sm italic leading-relaxed text-foreground/80">
{lastInsight
? `"${lastInsight}"`
: "Henüz bir içgörü oluşmadı. Biraz günlük yaz, AI analiz yapsın."}