Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,7 @@
"avgTokensPerMessage": "Avg Tokens/Message",
"topModel": "Top Model",
"summary": "Summary",
"last30Days": "last 30 days",
"tokensAcross": "{tokens} tokens across {count} model{count, plural, =1 {} other {s}} in {period}.",
"mostActive": "Most active: {model} ({tokens} tokens).",
"summaryPrefix": "📊 Summary: ",
Expand Down
3 changes: 2 additions & 1 deletion messages/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,8 @@
"failedToSaveImage": "Error al guardar imagen",
"pleaseUploadValidImage": "Por favor sube una imagen válida (JPEG, PNG o WebP)",
"imageSizeMustBeLessThan": "El tamaño de la imagen debe ser menor a 5MB",
"select": "Seleccionar"
"select": "Seleccionar",
"last30Days": "los últimos 30 días"
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion messages/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,8 @@
"failedToSaveImage": "Échec de l'enregistrement de l'image",
"pleaseUploadValidImage": "Veuillez télécharger une image valide (JPEG, PNG ou WebP)",
"imageSizeMustBeLessThan": "La taille de l'image doit être inférieure à 5 Mo",
"select": "Sélectionner"
"select": "Sélectionner",
"last30Days": "les 30 derniers jours"
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion messages/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,8 @@
"failedToSaveImage": "画像の保存に失敗しました",
"pleaseUploadValidImage": "有効な画像をアップロードしてください(JPEG、PNG、またはWebP)",
"imageSizeMustBeLessThan": "画像サイズは5MB未満である必要があります",
"select": "選択"
"select": "選択",
"last30Days": "過去30日間"
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion messages/ko.json
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,8 @@
"failedToSaveImage": "이미지 저장에 실패했습니다",
"pleaseUploadValidImage": "유효한 이미지를 업로드하세요 (JPEG, PNG 또는 WebP)",
"imageSizeMustBeLessThan": "이미지 크기는 5MB 미만이어야 합니다",
"select": "선택"
"select": "선택",
"last30Days": "최근 30일"
}
}
}
Expand Down
1 change: 1 addition & 0 deletions messages/no.json
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,7 @@
"avgTokensPerMessage": "Gj.sn. tokens/melding",
"topModel": "Toppmodell",
"summary": "Sammendrag",
"last30Days": "de siste 30 dagene",
"tokensAcross": "{tokens} tokens på tvers av {count} modell{count, plural, =1 {} other {er}} i {period}.",
"mostActive": "Mest aktiv: {model} ({tokens} tokens).",
"summaryPrefix": "📊 Sammendrag: ",
Expand Down
3 changes: 2 additions & 1 deletion messages/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,8 @@
"failedToSaveImage": "图像保存失败",
"pleaseUploadValidImage": "请上传有效的图像(JPEG、PNG或WebP)",
"imageSizeMustBeLessThan": "图像大小必须小于5MB",
"select": "选择"
"select": "选择",
"last30Days": "过去30天"
}
}
}
Expand Down
22 changes: 6 additions & 16 deletions src/app/(chat)/archive/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,11 @@ import { Card, CardContent, CardHeader } from "ui/card";
import { MessageCircleXIcon } from "lucide-react";
import { ArchiveActionsClient } from "@/app/(chat)/archive/[id]/archive-actions-client";
import { Separator } from "ui/separator";
import { getFormatter, getTranslations } from "next-intl/server";

import LightRays from "ui/light-rays";
import Particles from "ui/particles";

// Simple date formatting function
function formatTimeAgo(date: Date): string {
const now = new Date();
const diffInMs = now.getTime() - date.getTime();
const diffInDays = Math.floor(diffInMs / (1000 * 60 * 60 * 24));

if (diffInDays === 0) return "Today";
if (diffInDays === 1) return "Yesterday";
if (diffInDays < 7) return `${diffInDays} days ago`;
if (diffInDays < 30) return `${Math.floor(diffInDays / 7)} weeks ago`;
if (diffInDays < 365) return `${Math.floor(diffInDays / 30)} months ago`;
return `${Math.floor(diffInDays / 365)} years ago`;
}

interface ArchiveWithThreads {
id: string;
name: string;
Expand Down Expand Up @@ -85,6 +72,9 @@ export default async function ArchivePage({
redirect("/");
}

const format = await getFormatter();
const t = await getTranslations("User.Profile.common");

return (
<>
<>
Expand Down Expand Up @@ -115,7 +105,7 @@ export default async function ArchivePage({
<h1 className="text-2xl font-bold">{archive.name}</h1>
<div className="flex-1" />
<p className="text-xs text-muted-foreground mr-2">
Created {formatTimeAgo(archive.createdAt)}
{t("created")} {format.relativeTime(archive.createdAt)}
</p>
<div className="h-4">
<Separator orientation="vertical" />
Expand Down Expand Up @@ -166,7 +156,7 @@ export default async function ArchivePage({
</h3>
</div>
<span className="text-xs text-muted-foreground">
{formatTimeAgo(
{format.relativeTime(
new Date(thread.lastMessageAt || thread.createdAt),
)}
</span>
Expand Down
5 changes: 3 additions & 2 deletions src/components/admin/users-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { useTransition, useCallback, useRef } from "react";
import { useRouter, useSearchParams } from "next/navigation";
import { format } from "date-fns";
import { useFormatter } from "next-intl";
import {
Table,
TableBody,
Expand Down Expand Up @@ -62,6 +62,7 @@ export function UsersTable({
const formRef = useRef<HTMLFormElement>(null);
const inputRef = useRef<HTMLInputElement>(null);
const t = useTranslations("Admin.Users");
const format = useFormatter();
const shouldAutoFocusRef = useRef<boolean>(false);

const submitForm = useCallback(() => {
Expand Down Expand Up @@ -282,7 +283,7 @@ export function UsersTable({
/>
</TableCell>
<TableCell className="text-muted-foreground">
{format(new Date(user.createdAt), "MMM d, yyyy")}
{format.dateTime(new Date(user.createdAt), "short")}
</TableCell>
<TableCell>
<ChevronRight
Expand Down
12 changes: 4 additions & 8 deletions src/components/chat-preferences-content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import { McpServerCustomizationContent } from "./mcp-customization-popup";
import { MCPServerInfo } from "app-types/mcp";
import { useMcpList } from "@/hooks/queries/use-mcp-list";
import { ChatExportSummary } from "app-types/chat-export";
import { formatDistanceToNow } from "date-fns";
import { useFormatter } from "next-intl";
import { notify } from "lib/notify";

export function UserInstructionsContent() {
Expand Down Expand Up @@ -307,6 +307,7 @@ export function MCPInstructionsContent() {

export function ExportsManagementContent() {
const t = useTranslations();
const format = useFormatter();

const {
data: exports,
Expand Down Expand Up @@ -389,20 +390,15 @@ export function ExportsManagementContent() {
<div className="flex flex-col sm:flex-row sm:items-center gap-1 sm:gap-3 mt-2 text-sm text-muted-foreground">
<span>
{t("Chat.ChatPreferences.exported")}{" "}
{formatDistanceToNow(new Date(exportItem.exportedAt), {
addSuffix: true,
})}
{format.relativeTime(new Date(exportItem.exportedAt))}
</span>
{exportItem.expiresAt && (
<>
<span className="hidden sm:inline">•</span>
<span>
{t("Chat.ChatPreferences.expires")}{" "}
{formatDistanceToNow(
{format.relativeTime(
new Date(exportItem.expiresAt),
{
addSuffix: true,
},
)}
</span>
</>
Expand Down
7 changes: 4 additions & 3 deletions src/components/export/chat-preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@ import {
import { PreviewMessage } from "../message";
import { Avatar, AvatarFallback, AvatarImage } from "ui/avatar";
import { Tooltip, TooltipContent, TooltipTrigger } from "ui/tooltip";
import { formatDate } from "date-fns";
import { getFormatter } from "next-intl/server";

import Particles from "ui/particles";
import Comments from "./comments";

export default function ChatPreview({
export default async function ChatPreview({
thread,
comments,
}: { thread: ChatExportWithUser; comments: ChatExportCommentWithUser[] }) {
const format = await getFormatter();
return (
<div
className="flex flex-col min-w-0 h-full relative"
Expand All @@ -32,7 +33,7 @@ export default function ChatPreview({
{thread.title}
</h1>
<div className="text-xs text-muted-foreground flex items-center gap-2">
{formatDate(thread.exportedAt, "MMM d, yyyy")}
{format.dateTime(new Date(thread.exportedAt), "short")}
<Tooltip>
<TooltipTrigger asChild>
<div className="flex items-center gap-2 text-xs">
Expand Down
7 changes: 3 additions & 4 deletions src/components/export/comment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import { ChatExportCommentWithUser } from "app-types/chat-export";
import { Avatar, AvatarFallback, AvatarImage } from "ui/avatar";
import { Button } from "ui/button";
import { formatDistanceToNow } from "date-fns";
import { useFormatter } from "next-intl";
import { useState } from "react";

import { mutate } from "swr";
Expand All @@ -24,6 +24,7 @@ export default function Comment({
maxReplyDepth?: number;
onReply?: () => void;
}) {
const format = useFormatter();
const [isDeleting, setIsDeleting] = useState(false);

const handleDelete = async () => {
Expand Down Expand Up @@ -67,9 +68,7 @@ export default function Comment({
<div className="flex items-center gap-2 mb-1">
<span className="font-medium text-xs">{comment.authorName}</span>
<span className="text-xs text-muted-foreground">
{formatDistanceToNow(new Date(comment.createdAt), {
addSuffix: true,
})}
{format.relativeTime(new Date(comment.createdAt))}
</span>
</div>

Expand Down
9 changes: 6 additions & 3 deletions src/components/shareable-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ import {
CardTitle,
} from "ui/card";
import { Avatar, AvatarFallback, AvatarImage } from "ui/avatar";
import { useTranslations } from "next-intl";
import { format } from "date-fns";
import { useTranslations, useFormatter } from "next-intl";
import { cn } from "lib/utils";
import { ShareableActions, type Visibility } from "./shareable-actions";
import { WorkflowSummary } from "app-types/workflow";
Expand Down Expand Up @@ -53,6 +52,7 @@ export function ShareableCard({
actionsDisabled,
}: ShareableCardProps) {
const t = useTranslations();
const format = useFormatter();
const isPublished = (item as WorkflowSummary).isPublished;
const isBookmarked =
type === "mcp" ? undefined : (item as AgentSummary).isBookmarked;
Expand Down Expand Up @@ -92,7 +92,10 @@ export function ShareableCard({
</span>
<div className="text-xs text-muted-foreground flex items-center gap-1 min-w-0">
<time className="shrink-0">
{format(item.updatedAt || new Date(), "MMM d, yyyy")}
{format.dateTime(
new Date(item.updatedAt || Date.now()),
"short",
)}
</time>
{type === "workflow" && !isPublished && (
<span className="px-2 rounded-sm bg-secondary text-foreground shrink-0">
Expand Down
6 changes: 4 additions & 2 deletions src/components/tool-invocation/interactive-table.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"use client";

import { useState, useMemo } from "react";
import { useFormatter } from "next-intl";
import {
ArrowDownUp,
Download,
Expand Down Expand Up @@ -85,6 +86,7 @@ const loadXLSX = async () => {

export function InteractiveTable(props: InteractiveTableProps) {
const { title, data, columns, description } = props;
const format = useFormatter();

// Fixed settings for simplicity
const pageSize = 20;
Expand All @@ -107,12 +109,12 @@ export function InteractiveTable(props: InteractiveTableProps) {

switch (columnType) {
case "number":
return typeof value === "number" ? value.toLocaleString() : value;
return typeof value === "number" ? format.number(value) : value;
case "boolean":
return value ? "Yes" : "No";
case "date":
try {
return new Date(value).toLocaleDateString();
return format.dateTime(new Date(value), "short");
} catch {
return value;
}
Expand Down
10 changes: 6 additions & 4 deletions src/components/tool-invocation/web-search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import equal from "lib/equal";
import { notify } from "lib/notify";
import { cn, toAny } from "lib/utils";
import { AlertTriangleIcon } from "lucide-react";
import { useTranslations } from "next-intl";
import { useTranslations, useFormatter } from "next-intl";
import { memo, useMemo, useState } from "react";
import { Avatar, AvatarFallback, AvatarImage } from "ui/avatar";
import { GlobalIcon } from "ui/global-icon";
Expand All @@ -22,6 +22,7 @@ interface WebSearchToolInvocationProps {

function PureWebSearchToolInvocation({ part }: WebSearchToolInvocationProps) {
const t = useTranslations();
const format = useFormatter();

const result = useMemo(() => {
if (!part.state.startsWith("output")) return null;
Expand Down Expand Up @@ -204,9 +205,10 @@ function PureWebSearchToolInvocation({ part }: WebSearchToolInvocationProps) {
{result.publishedDate && (
<div className="text-xs text-muted-foreground">
<span className="font-medium">Published:</span>{" "}
{new Date(
result.publishedDate,
).toLocaleDateString()}
{format.dateTime(
new Date(result.publishedDate),
"short",
)}
</div>
)}
</div>
Expand Down
7 changes: 4 additions & 3 deletions src/components/user/user-detail/user-detail-form-card.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"use client";

import { useActionState, useState } from "react";
import { format } from "date-fns";
import { useFormatter } from "next-intl";
import {
Card,
CardContent,
Expand Down Expand Up @@ -46,6 +46,7 @@ export function UserDetailFormCard({
view,
}: UserDetailFormCardProps) {
const { t, tCommon } = useProfileTranslations(view);
const format = useFormatter();
const [currentUser, setCurrentUser] = useState(user);

const [, detailsUpdateFormAction, isPending] = useActionState<
Expand Down Expand Up @@ -161,7 +162,7 @@ export function UserDetailFormCard({
{tCommon("joined")}
</Label>
<p className="text-sm font-medium" data-testid="user-created-at">
{format(new Date(currentUser.createdAt), "PPP")}
{format.dateTime(new Date(currentUser.createdAt), "long")}
</p>
</div>

Expand All @@ -170,7 +171,7 @@ export function UserDetailFormCard({
{tCommon("lastUpdated")}
</Label>
<p className="text-sm font-medium" data-testid="user-updated-at">
{format(new Date(currentUser.updatedAt), "PPP")}
{format.dateTime(new Date(currentUser.updatedAt), "long")}
</p>
</div>
</div>
Expand Down
Loading
Loading