mirror of
https://github.com/Nezumi-2711/9router.git
synced 2026-09-22 20:00:47 +00:00
fix: update the timezone
This commit is contained in:
@@ -17,6 +17,7 @@ import EndpointRow from "./components/EndpointRow";
|
||||
import StatusAlert from "./components/StatusAlert";
|
||||
import Tooltip from "./components/Tooltip";
|
||||
import SecurityWarning from "./components/SecurityWarning";
|
||||
import { formatVietnamDateTime } from "@/shared/utils/dateTime";
|
||||
export default function APIPageClient({ machineId, isAdmin }) {
|
||||
const [keys, setKeys] = useState([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
@@ -1034,7 +1035,7 @@ export default function APIPageClient({ machineId, isAdmin }) {
|
||||
</div>
|
||||
</div>
|
||||
<p className="hidden text-right text-xs text-text-muted sm:block">
|
||||
Created<br />{new Date(key.createdAt).toLocaleDateString()}
|
||||
Created<br />{formatVietnamDateTime(key.createdAt, { dateStyle: "medium" }) || "—"}
|
||||
</p>
|
||||
<div className="flex items-center gap-1.5">
|
||||
<Toggle
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { useCallback, useEffect, useMemo, useState, useRef } from "react";
|
||||
import { Badge, Button, Card, CardSkeleton, Input, Modal, Toggle, ConfirmModal } from "@/shared/components";
|
||||
import { useNotificationStore } from "@/store/notificationStore";
|
||||
import { formatVietnamDateTime } from "@/shared/utils/dateTime";
|
||||
|
||||
function getStatusVariant(status) {
|
||||
if (status === "active") return "success";
|
||||
@@ -12,9 +13,7 @@ function getStatusVariant(status) {
|
||||
|
||||
function formatDateTime(value) {
|
||||
if (!value) return "Never";
|
||||
const date = new Date(value);
|
||||
if (Number.isNaN(date.getTime())) return "Never";
|
||||
return date.toLocaleString();
|
||||
return formatVietnamDateTime(value, { dateStyle: "medium", timeStyle: "medium" }) || "Never";
|
||||
}
|
||||
|
||||
function normalizeFormData(data = {}) {
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
ResponsiveContainer,
|
||||
} from "recharts";
|
||||
import { Card, Button } from "@/shared/components";
|
||||
import { formatVietnamDateTime } from "@/shared/utils/dateTime";
|
||||
|
||||
const fmtTokens = (n) => {
|
||||
if (n >= 1000000) return `${(n / 1000000).toFixed(2)}M`;
|
||||
@@ -222,7 +223,7 @@ export default function PxpipeClient() {
|
||||
{(stats?.recent || []).slice(0, 50).map((ev, i) => (
|
||||
<tr key={`${ev.ts}-${i}`} className="border-b border-border/50">
|
||||
<td className="py-1.5 pr-3 whitespace-nowrap text-text-muted">
|
||||
{new Date(ev.ts).toLocaleString()}
|
||||
{formatVietnamDateTime(ev.ts, { dateStyle: "medium", timeStyle: "medium" }) || "—"}
|
||||
</td>
|
||||
<td className="py-1.5 pr-3 font-mono text-xs">{ev.provider ? `${ev.provider}/${ev.model}` : ev.model || "—"}</td>
|
||||
<td className="py-1.5 pr-3 text-right font-mono text-xs">
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import { cn } from "@/shared/utils/cn";
|
||||
import { formatResetTime } from "./utils";
|
||||
import { formatVietnamDateTime, formatVietnamTime, isSameVietnamDay } from "@/shared/utils/dateTime";
|
||||
|
||||
// Calculate color based on remaining percentage
|
||||
const getColorClasses = (remainingPercentage) => {
|
||||
@@ -38,25 +39,25 @@ const formatResetTimeDisplay = (resetTime) => {
|
||||
|
||||
try {
|
||||
const resetDate = new Date(resetTime);
|
||||
const now = new Date();
|
||||
const isToday = resetDate.toDateString() === now.toDateString();
|
||||
const isTomorrow = resetDate.toDateString() === new Date(now.getTime() + 86400000).toDateString();
|
||||
if (!Number.isFinite(resetDate.getTime())) return null;
|
||||
const isToday = isSameVietnamDay(resetDate);
|
||||
const isTomorrow = isSameVietnamDay(resetDate, new Date(Date.now() + 86400000));
|
||||
|
||||
const timeStr = resetDate.toLocaleTimeString(undefined, {
|
||||
const timeStr = formatVietnamTime(resetDate, {
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
hour12: true,
|
||||
hourCycle: "h23",
|
||||
});
|
||||
|
||||
if (isToday) return `Today, ${timeStr}`;
|
||||
if (isTomorrow) return `Tomorrow, ${timeStr}`;
|
||||
|
||||
return resetDate.toLocaleString(undefined, {
|
||||
return formatVietnamDateTime(resetDate, {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
hour12: true,
|
||||
hourCycle: "h23",
|
||||
});
|
||||
} catch {
|
||||
return null;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { formatResetTime, getRemainingPercentage } from "./utils";
|
||||
import { formatVietnamDateTime, formatVietnamTime, isSameVietnamDay } from "@/shared/utils/dateTime";
|
||||
|
||||
const PAGE_SIZE = 10;
|
||||
|
||||
@@ -13,24 +14,21 @@ function formatResetTimeDisplay(resetTime) {
|
||||
|
||||
try {
|
||||
const date = new Date(resetTime);
|
||||
const now = new Date();
|
||||
const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
|
||||
const tomorrow = new Date(today);
|
||||
tomorrow.setDate(tomorrow.getDate() + 1);
|
||||
if (!Number.isFinite(date.getTime())) return null;
|
||||
|
||||
let dayStr = "";
|
||||
if (date >= today && date < tomorrow) {
|
||||
if (isSameVietnamDay(date)) {
|
||||
dayStr = "Today";
|
||||
} else if (date >= tomorrow && date < new Date(tomorrow.getTime() + 24 * 60 * 60 * 1000)) {
|
||||
} else if (isSameVietnamDay(date, new Date(Date.now() + 86400000))) {
|
||||
dayStr = "Tomorrow";
|
||||
} else {
|
||||
dayStr = date.toLocaleDateString("en-US", { month: "short", day: "numeric" });
|
||||
dayStr = formatVietnamDateTime(date, { month: "short", day: "numeric" });
|
||||
}
|
||||
|
||||
const timeStr = date.toLocaleTimeString("en-US", {
|
||||
hour: "numeric",
|
||||
const timeStr = formatVietnamTime(date, {
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
hour12: true,
|
||||
hourCycle: "h23",
|
||||
});
|
||||
|
||||
return `${dayStr}, ${timeStr}`;
|
||||
|
||||
@@ -39,6 +39,7 @@ import Card from "@/shared/components/Card";
|
||||
import { ConfirmModal, EditConnectionModal } from "@/shared/components";
|
||||
import { USAGE_SUPPORTED_PROVIDERS } from "@/shared/constants/providers";
|
||||
import { useCopyToClipboard } from "@/shared/hooks/useCopyToClipboard";
|
||||
import { formatVietnamDateTime } from "@/shared/utils/dateTime";
|
||||
|
||||
// Maps the stored providerSpecificData.authMethod to a human label for Kiro.
|
||||
// Values come from the Kiro connect flows: builder-id/idc (device code),
|
||||
@@ -99,15 +100,13 @@ function getCodexResetCreditCount(quota) {
|
||||
|
||||
function formatCreditDate(value) {
|
||||
if (!value) return "N/A";
|
||||
const date = new Date(value);
|
||||
if (!Number.isFinite(date.getTime())) return "N/A";
|
||||
return date.toLocaleString(undefined, {
|
||||
return formatVietnamDateTime(value, {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
year: "numeric",
|
||||
hour: "numeric",
|
||||
minute: "2-digit",
|
||||
});
|
||||
}) || "N/A";
|
||||
}
|
||||
|
||||
function formatTimeRemaining(value) {
|
||||
|
||||
@@ -7,6 +7,7 @@ import Drawer from "@/shared/components/Drawer";
|
||||
import Pagination from "@/shared/components/Pagination";
|
||||
import { cn } from "@/shared/utils/cn";
|
||||
import { AI_PROVIDERS, getProviderByAlias } from "@/shared/constants/providers";
|
||||
import { formatVietnamDateTime } from "@/shared/utils/dateTime";
|
||||
|
||||
let providerNameCache = null;
|
||||
let providerNodesCache = null;
|
||||
@@ -286,7 +287,7 @@ export default function RequestDetailsTab() {
|
||||
className="border-b border-black/5 dark:border-white/5 last:border-b-0 hover:bg-black/[0.02] dark:hover:bg-white/[0.02] transition-colors"
|
||||
>
|
||||
<td className="whitespace-nowrap p-4 text-sm text-text-main">
|
||||
{new Date(detail.timestamp).toLocaleString()}
|
||||
{formatVietnamDateTime(detail.timestamp, { dateStyle: "medium", timeStyle: "medium" }) || "—"}
|
||||
</td>
|
||||
<td className="max-w-[260px] truncate p-4 font-mono text-sm text-text-main">
|
||||
{detail.model}
|
||||
@@ -358,7 +359,7 @@ export default function RequestDetailsTab() {
|
||||
</div>
|
||||
<div>
|
||||
<span className="text-text-muted">Timestamp:</span>{" "}
|
||||
<span className="text-text-main">{new Date(selectedDetail.timestamp).toLocaleString()}</span>
|
||||
<span className="text-text-main">{formatVietnamDateTime(selectedDetail.timestamp, { dateStyle: "medium", timeStyle: "medium" }) || "—"}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span className="text-text-muted">Provider:</span>{" "}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { AI_PROVIDERS } from "@/shared/constants/providers";
|
||||
import { Button, Card, CardSkeleton } from "@/shared/components";
|
||||
import ProviderIcon from "@/shared/components/ProviderIcon";
|
||||
import { formatResetTime, REFRESH_INTERVAL_MS } from "./ProviderLimits/utils";
|
||||
import { formatVietnamDateTime, formatVietnamTime, isSameVietnamDay } from "@/shared/utils/dateTime";
|
||||
|
||||
function getProviderInfo(providerId) {
|
||||
return AI_PROVIDERS[providerId] || {
|
||||
@@ -16,13 +17,11 @@ function getProviderInfo(providerId) {
|
||||
function formatUpdatedAt(value) {
|
||||
if (!value) return "Not updated yet";
|
||||
|
||||
const date = new Date(value);
|
||||
if (!Number.isFinite(date.getTime())) return "Not updated yet";
|
||||
|
||||
return `Updated ${date.toLocaleTimeString(undefined, {
|
||||
const formattedTime = formatVietnamTime(value, {
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
})}`;
|
||||
});
|
||||
return formattedTime ? `Updated ${formattedTime}` : "Not updated yet";
|
||||
}
|
||||
|
||||
function formatResetAt(value) {
|
||||
@@ -31,14 +30,13 @@ function formatResetAt(value) {
|
||||
const date = new Date(value);
|
||||
if (!Number.isFinite(date.getTime())) return null;
|
||||
|
||||
const now = new Date();
|
||||
const isToday = date.toDateString() === now.toDateString();
|
||||
const isTomorrow = date.toDateString() === new Date(now.getTime() + 86400000).toDateString();
|
||||
const time = date.toLocaleTimeString(undefined, { hour: "2-digit", minute: "2-digit" });
|
||||
const isToday = isSameVietnamDay(date);
|
||||
const isTomorrow = isSameVietnamDay(date, new Date(Date.now() + 86400000));
|
||||
const time = formatVietnamTime(date, { hour: "2-digit", minute: "2-digit" });
|
||||
|
||||
if (isToday) return `today at ${time}`;
|
||||
if (isTomorrow) return `tomorrow at ${time}`;
|
||||
return date.toLocaleString(undefined, { month: "short", day: "numeric", hour: "2-digit", minute: "2-digit" });
|
||||
return formatVietnamDateTime(date, { month: "short", day: "numeric", hour: "2-digit", minute: "2-digit" });
|
||||
}
|
||||
|
||||
function getQuotaTone(percentage) {
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useState, useEffect, useCallback, useMemo, Fragment } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import Card from "@/shared/components/Card";
|
||||
import Badge from "@/shared/components/Badge";
|
||||
import { formatVietnamDateTime } from "@/shared/utils/dateTime";
|
||||
|
||||
const fmt = (n) => new Intl.NumberFormat().format(n || 0);
|
||||
const fmtCost = (n) => `$${(n || 0).toFixed(2)}`;
|
||||
@@ -14,7 +15,7 @@ function fmtTime(iso) {
|
||||
if (diffMins < 1) return "Just now";
|
||||
if (diffMins < 60) return `${diffMins}m ago`;
|
||||
if (diffMins < 1440) return `${Math.floor(diffMins / 60)}h ago`;
|
||||
return new Date(iso).toLocaleDateString();
|
||||
return formatVietnamDateTime(iso, { dateStyle: "medium" }) || "Never";
|
||||
}
|
||||
|
||||
function SortIcon({ field, currentSort, currentOrder }) {
|
||||
|
||||
@@ -5,12 +5,13 @@ import { useRouter } from "next/navigation";
|
||||
import { Button, Card, Input } from "@/shared/components";
|
||||
import Modal, { ConfirmModal } from "@/shared/components/Modal";
|
||||
import useUserStore from "@/store/userStore";
|
||||
import { formatVietnamDateTime } from "@/shared/utils/dateTime";
|
||||
|
||||
const EMPTY_FORM = { username: "", password: "", role: "user", isActive: true };
|
||||
|
||||
function formatDate(value) {
|
||||
if (!value) return "—";
|
||||
return new Intl.DateTimeFormat(undefined, { dateStyle: "medium", timeStyle: "short" }).format(new Date(value));
|
||||
return formatVietnamDateTime(value, { dateStyle: "medium", timeStyle: "short" }) || "—";
|
||||
}
|
||||
|
||||
export default function UsersPage() {
|
||||
|
||||
Reference in New Issue
Block a user