fix: panelde saatler 3 saat geri gösteriliyordu (sunucu UTC, Türkiye UTC+3)
.toLocaleString("tr-TR") tarih formatını Türkçe yapıyor ama saat değerini
hâlâ sunucunun sistem saat dilimiyle (Coolify/Hetzner container'ı UTC)
hesaplıyordu. Tüm tarih gösterimleri artık ortak formatTr() helper'ı
üzerinden timeZone: "Europe/Istanbul" ile sabitleniyor.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,7 @@ import { notFound } from "next/navigation";
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { prisma } from "@streamclipper/db";
|
import { prisma } from "@streamclipper/db";
|
||||||
import { fetchChannelStatuses } from "../../../lib/apiDaemon";
|
import { fetchChannelStatuses } from "../../../lib/apiDaemon";
|
||||||
|
import { formatTr } from "../../../lib/formatDate";
|
||||||
import {
|
import {
|
||||||
deleteRawSegment,
|
deleteRawSegment,
|
||||||
deleteCandidateSegment,
|
deleteCandidateSegment,
|
||||||
@@ -113,7 +114,7 @@ export default async function ChannelDetailPage({ params }: { params: Promise<{
|
|||||||
<CardContent className="flex flex-col gap-3">
|
<CardContent className="flex flex-col gap-3">
|
||||||
<p className="font-mono-num text-xs text-muted-foreground">
|
<p className="font-mono-num text-xs text-muted-foreground">
|
||||||
Aktif: {channel.isActive ? "evet" : "hayır"} · Son kontrol:{" "}
|
Aktif: {channel.isActive ? "evet" : "hayır"} · Son kontrol:{" "}
|
||||||
{channel.lastCheckedAt ? new Date(channel.lastCheckedAt).toLocaleString("tr-TR") : "—"}
|
{channel.lastCheckedAt ? formatTr(channel.lastCheckedAt) : "—"}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<form
|
<form
|
||||||
@@ -157,7 +158,7 @@ export default async function ChannelDetailPage({ params }: { params: Promise<{
|
|||||||
son poll hatası
|
son poll hatası
|
||||||
</Badge>
|
</Badge>
|
||||||
<span className="font-mono-num text-xs text-muted-foreground">
|
<span className="font-mono-num text-xs text-muted-foreground">
|
||||||
{new Date(status.lastPollError.at).toLocaleString("tr-TR")}
|
{formatTr(status.lastPollError.at)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<pre className="font-mono-num whitespace-pre-wrap rounded-md border border-border bg-background/60 p-3 text-[0.7rem] text-muted-foreground">
|
<pre className="font-mono-num whitespace-pre-wrap rounded-md border border-border bg-background/60 p-3 text-[0.7rem] text-muted-foreground">
|
||||||
@@ -199,8 +200,8 @@ export default async function ChannelDetailPage({ params }: { params: Promise<{
|
|||||||
<Card key={session.id}>
|
<Card key={session.id}>
|
||||||
<CardHeader className="flex-row items-center justify-between">
|
<CardHeader className="flex-row items-center justify-between">
|
||||||
<span className="font-mono-num text-xs text-muted-foreground">
|
<span className="font-mono-num text-xs text-muted-foreground">
|
||||||
{new Date(session.startedAt).toLocaleString("tr-TR")}
|
{formatTr(session.startedAt)}
|
||||||
{session.endedAt ? ` – ${new Date(session.endedAt).toLocaleString("tr-TR")}` : " (devam ediyor)"}
|
{session.endedAt ? ` – ${formatTr(session.endedAt)}` : " (devam ediyor)"}
|
||||||
</span>
|
</span>
|
||||||
<Badge variant="muted">{session.totalSegments} segment</Badge>
|
<Badge variant="muted">{session.totalSegments} segment</Badge>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import Link from "next/link";
|
|||||||
import { prisma } from "@streamclipper/db";
|
import { prisma } from "@streamclipper/db";
|
||||||
import { addChannel, toggleChannelActive, toggleAllChannels, checkChannelNow } from "./actions";
|
import { addChannel, toggleChannelActive, toggleAllChannels, checkChannelNow } from "./actions";
|
||||||
import { fetchChannelStatuses } from "../lib/apiDaemon";
|
import { fetchChannelStatuses } from "../lib/apiDaemon";
|
||||||
|
import { formatTr } from "../lib/formatDate";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
@@ -94,7 +95,7 @@ export default async function DashboardPage() {
|
|||||||
{status?.lastPollError && (
|
{status?.lastPollError && (
|
||||||
<Badge
|
<Badge
|
||||||
variant="err"
|
variant="err"
|
||||||
title={`${new Date(status.lastPollError.at).toLocaleString("tr-TR")} — ${status.lastPollError.message}`}
|
title={`${formatTr(status.lastPollError.at)} — ${status.lastPollError.message}`}
|
||||||
>
|
>
|
||||||
hata
|
hata
|
||||||
</Badge>
|
</Badge>
|
||||||
@@ -102,7 +103,7 @@ export default async function DashboardPage() {
|
|||||||
</div>
|
</div>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className="font-mono-num text-xs text-muted-foreground">
|
<TableCell className="font-mono-num text-xs text-muted-foreground">
|
||||||
{c.lastCheckedAt ? new Date(c.lastCheckedAt).toLocaleString("tr-TR") : "—"}
|
{c.lastCheckedAt ? formatTr(c.lastCheckedAt) : "—"}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<div className="flex justify-end gap-1.5">
|
<div className="flex justify-end gap-1.5">
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { prisma } from "@streamclipper/db";
|
import { prisma } from "@streamclipper/db";
|
||||||
import { deleteRawSegment, deleteCandidateSegment, retryRender, cancelRender } from "../actions";
|
import { deleteRawSegment, deleteCandidateSegment, retryRender, cancelRender } from "../actions";
|
||||||
|
import { formatTr } from "../../lib/formatDate";
|
||||||
import { ConfirmButton } from "../components/ConfirmButton";
|
import { ConfirmButton } from "../components/ConfirmButton";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Badge, type badgeVariants } from "@/components/ui/badge";
|
import { Badge, type badgeVariants } from "@/components/ui/badge";
|
||||||
@@ -46,7 +47,7 @@ export default async function SegmentsPage() {
|
|||||||
<div>
|
<div>
|
||||||
<span className="font-mono-num text-xs text-muted-foreground">{segment.filePath}</span>
|
<span className="font-mono-num text-xs text-muted-foreground">{segment.filePath}</span>
|
||||||
<p className="font-mono-num text-xs text-muted-foreground">
|
<p className="font-mono-num text-xs text-muted-foreground">
|
||||||
{segment.duration}sn · {new Date(segment.startedAt).toLocaleString("tr-TR")}
|
{segment.duration}sn · {formatTr(segment.startedAt)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<Badge variant={STATUS_BADGE[segment.status] ?? "muted"}>{segment.status}</Badge>
|
<Badge variant={STATUS_BADGE[segment.status] ?? "muted"}>{segment.status}</Badge>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { prisma } from "@streamclipper/db";
|
import { prisma } from "@streamclipper/db";
|
||||||
import { updateYtdlpCookies, updateSystemSettings, updateNotificationPrefs, updateSttEnabled } from "../actions";
|
import { updateYtdlpCookies, updateSystemSettings, updateNotificationPrefs, updateSttEnabled } from "../actions";
|
||||||
|
import { formatTr } from "../../lib/formatDate";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
@@ -38,7 +39,7 @@ export default async function SettingsPage() {
|
|||||||
<CardHeader className="flex-row items-center justify-between">
|
<CardHeader className="flex-row items-center justify-between">
|
||||||
<CardTitle className="text-sm font-medium text-muted-foreground">YouTube Cookie'leri</CardTitle>
|
<CardTitle className="text-sm font-medium text-muted-foreground">YouTube Cookie'leri</CardTitle>
|
||||||
<span className="font-mono-num text-xs text-muted-foreground">
|
<span className="font-mono-num text-xs text-muted-foreground">
|
||||||
{setting ? `son güncelleme: ${setting.updatedAt.toLocaleString("tr-TR")}` : "hiç ayarlanmadı"}
|
{setting ? `son güncelleme: ${formatTr(setting.updatedAt)}` : "hiç ayarlanmadı"}
|
||||||
</span>
|
</span>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="flex flex-col gap-3">
|
<CardContent className="flex flex-col gap-3">
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { prisma } from "@streamclipper/db";
|
import { prisma } from "@streamclipper/db";
|
||||||
import { getSession } from "../../lib/auth";
|
import { getSession } from "../../lib/auth";
|
||||||
import { addUser, deleteUser } from "./actions";
|
import { addUser, deleteUser } from "./actions";
|
||||||
|
import { formatTr } from "../../lib/formatDate";
|
||||||
import { ConfirmButton } from "../components/ConfirmButton";
|
import { ConfirmButton } from "../components/ConfirmButton";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
@@ -56,7 +57,7 @@ export default async function UsersPage() {
|
|||||||
)}
|
)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className="font-mono-num text-xs text-muted-foreground">
|
<TableCell className="font-mono-num text-xs text-muted-foreground">
|
||||||
{u.createdAt.toLocaleString("tr-TR")}
|
{formatTr(u.createdAt)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className="text-right">
|
<TableCell className="text-right">
|
||||||
{u.id !== session?.sub && users.length > 1 && (
|
{u.id !== session?.sub && users.length > 1 && (
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
/**
|
||||||
|
* Server (Coolify/Hetzner) runs in UTC, but the panel is used from Turkey
|
||||||
|
* (UTC+3, no DST since 2016) — `.toLocaleString("tr-TR")` alone formats
|
||||||
|
* with tr-TR conventions but still uses the *server's* timezone for the
|
||||||
|
* actual time value, which was showing everything 3h behind. Always pin
|
||||||
|
* the timezone explicitly instead of relying on the runtime's default.
|
||||||
|
*/
|
||||||
|
export function formatTr(date: Date | string): string {
|
||||||
|
return new Date(date).toLocaleString("tr-TR", { timeZone: "Europe/Istanbul" });
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user