refactor(web): unify local datetime formatting across governance and review pages (#73)

This commit is contained in:
dongmucat 2026-03-17 20:34:54 +08:00 committed by GitHub
parent 8708cab18c
commit f2de3d5d51
11 changed files with 23 additions and 12 deletions

View file

@ -1,5 +1,6 @@
import { useTranslation } from 'react-i18next'
import type { GovernanceActivityItem } from '@/api/types'
import { formatLocalDateTime } from '@/shared/lib/date-time'
import { Card } from '@/shared/ui/card'
interface GovernanceActivityProps {
@ -25,7 +26,7 @@ export function GovernanceActivity({ items, isLoading }: GovernanceActivityProps
<div className="flex items-center justify-between gap-3">
<div className="font-medium">{item.action}</div>
<div className="text-xs text-muted-foreground">
{item.timestamp ? new Date(item.timestamp).toLocaleString(i18n.language) : '-'}
{item.timestamp ? formatLocalDateTime(item.timestamp, i18n.language) : '-'}
</div>
</div>
<div className="text-sm text-muted-foreground">

View file

@ -1,6 +1,7 @@
import { useNavigate } from '@tanstack/react-router'
import { useTranslation } from 'react-i18next'
import type { GovernanceInboxItem } from '@/api/types'
import { formatLocalDateTime } from '@/shared/lib/date-time'
import { Card } from '@/shared/ui/card'
import { Button } from '@/shared/ui/button'
@ -54,7 +55,7 @@ export function GovernanceInbox({ items, isLoading }: GovernanceInboxProps) {
{item.subtitle ? <div className="text-sm text-muted-foreground">{item.subtitle}</div> : null}
</div>
<div className="text-xs text-muted-foreground">
{item.timestamp ? new Date(item.timestamp).toLocaleString(i18n.language) : '-'}
{item.timestamp ? formatLocalDateTime(item.timestamp, i18n.language) : '-'}
</div>
</div>
<div className="flex justify-end">

View file

@ -1,5 +1,6 @@
import { useTranslation } from 'react-i18next'
import type { GovernanceNotification } from '@/api/types'
import { formatLocalDateTime } from '@/shared/lib/date-time'
import { Card } from '@/shared/ui/card'
import { Button } from '@/shared/ui/button'
@ -33,7 +34,7 @@ export function GovernanceNotifications({ items, isLoading, onMarkRead, isMarkin
</div>
{item.createdAt ? (
<div className="text-xs text-muted-foreground">
{new Date(item.createdAt).toLocaleString(i18n.language)}
{formatLocalDateTime(item.createdAt, i18n.language)}
</div>
) : null}
{item.bodyJson ? <div className="text-sm text-muted-foreground break-all">{item.bodyJson}</div> : null}

View file

@ -1,5 +1,6 @@
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import { formatLocalDateTime } from '@/shared/lib/date-time'
import { Card } from '@/shared/ui/card'
import { Input } from '@/shared/ui/input'
import { Button } from '@/shared/ui/button'
@ -60,7 +61,7 @@ export function AuditLogPage() {
})
const formatDate = (dateString: string) => {
return new Date(dateString).toLocaleString(i18n.language)
return formatLocalDateTime(dateString, i18n.language)
}
return (

View file

@ -1,5 +1,6 @@
import { KeyboardEvent, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { formatLocalDateTime } from '@/shared/lib/date-time'
import { Card } from '@/shared/ui/card'
import { Input } from '@/shared/ui/input'
import { Button } from '@/shared/ui/button'
@ -56,7 +57,7 @@ export function AdminUsersPage() {
const enableUserMutation = useEnableUser()
const formatDate = (dateString: string) => {
return new Date(dateString).toLocaleString(i18n.language)
return formatLocalDateTime(dateString, i18n.language)
}
useEffect(() => {

View file

@ -1,6 +1,7 @@
import { useState } from 'react'
import { useParams } from '@tanstack/react-router'
import { useTranslation } from 'react-i18next'
import { formatLocalDateTime } from '@/shared/lib/date-time'
import { AddNamespaceMemberDialog } from '@/features/namespace/add-namespace-member-dialog'
import { NamespaceHeader } from '@/features/namespace/namespace-header'
import { ConfirmDialog } from '@/shared/components/confirm-dialog'
@ -217,7 +218,7 @@ export function NamespaceMembersPage() {
)}
</td>
<td className="p-4 text-sm text-muted-foreground">
{new Date(member.createdAt).toLocaleDateString(i18n.language)}
{formatLocalDateTime(member.createdAt, i18n.language, { dateStyle: 'medium' })}
</td>
<td className="p-4 text-right">
<Button

View file

@ -1,5 +1,6 @@
import { useParams } from '@tanstack/react-router'
import { useTranslation } from 'react-i18next'
import { formatLocalDateTime } from '@/shared/lib/date-time'
import { Card } from '@/shared/ui/card'
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/shared/ui/tabs'
import { useNamespaceDetail } from '@/shared/hooks/use-skill-queries'
@ -8,7 +9,7 @@ import { DashboardPageHeader } from '@/shared/components/dashboard-page-header'
import { NamespaceHeader } from '@/features/namespace/namespace-header'
function ReviewListSection({ namespaceId }: { namespaceId?: number }) {
const { t } = useTranslation()
const { t, i18n } = useTranslation()
const { data: pending } = useReviewList('PENDING', namespaceId)
const { data: approved } = useReviewList('APPROVED', namespaceId)
const { data: rejected } = useReviewList('REJECTED', namespaceId)
@ -26,7 +27,7 @@ function ReviewListSection({ namespaceId }: { namespaceId?: number }) {
<div className="font-semibold font-heading">{review.namespace}/{review.skillSlug}</div>
<div className="text-sm text-muted-foreground">{t('nsReviews.version', { version: review.version })}</div>
</div>
<div className="text-sm text-muted-foreground">{new Date(review.submittedAt).toLocaleString('zh-CN')}</div>
<div className="text-sm text-muted-foreground">{formatLocalDateTime(review.submittedAt, i18n.language)}</div>
</div>
{review.reviewComment ? (
<p className="mt-3 text-sm text-muted-foreground">{review.reviewComment}</p>

View file

@ -1,6 +1,7 @@
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useApprovePromotion, usePromotionList, useRejectPromotion } from '@/features/promotion/use-promotion-list'
import { formatLocalDateTime } from '@/shared/lib/date-time'
import { Button } from '@/shared/ui/button'
import { Card } from '@/shared/ui/card'
import { Input } from '@/shared/ui/input'
@ -33,7 +34,7 @@ function PromotionSection({ status }: { status: 'PENDING' | 'APPROVED' | 'REJECT
{item.sourceVersion} {'->'} @{item.targetNamespace}
</div>
</div>
<div className="text-sm text-muted-foreground">{new Date(item.submittedAt).toLocaleString(i18n.language)}</div>
<div className="text-sm text-muted-foreground">{formatLocalDateTime(item.submittedAt, i18n.language)}</div>
</div>
{status === 'PENDING' ? (
<>

View file

@ -1,6 +1,7 @@
import { useState } from 'react'
import { useNavigate } from '@tanstack/react-router'
import { useTranslation } from 'react-i18next'
import { formatLocalDateTime } from '@/shared/lib/date-time'
import { DashboardPageHeader } from '@/shared/components/dashboard-page-header'
import { Card } from '@/shared/ui/card'
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/shared/ui/tabs'
@ -26,7 +27,7 @@ export function ReportsPage() {
const resolveMutation = useResolveSkillReport()
const dismissMutation = useDismissSkillReport()
const formatDate = (dateString: string) => new Date(dateString).toLocaleString(i18n.language)
const formatDate = (dateString: string) => formatLocalDateTime(dateString, i18n.language)
const handleOpenSkill = (namespace?: string, skillSlug?: string) => {
if (!namespace || !skillSlug) {

View file

@ -1,6 +1,7 @@
import { useState } from 'react'
import { useNavigate, useParams } from '@tanstack/react-router'
import { useTranslation } from 'react-i18next'
import { formatLocalDateTime } from '@/shared/lib/date-time'
import { Button } from '@/shared/ui/button'
import { Card } from '@/shared/ui/card'
import { Textarea } from '@/shared/ui/textarea'
@ -42,7 +43,7 @@ export function ReviewDetailPage() {
const [rejectDialog, setRejectDialog] = useState(false)
const formatDate = (dateString: string) => {
return new Date(dateString).toLocaleString(i18n.language)
return formatLocalDateTime(dateString, i18n.language)
}
const handleApprove = async () => {

View file

@ -12,6 +12,7 @@ import {
} from '@/shared/ui/table'
import { useReviewList } from '@/features/review/use-review-list'
import { DashboardPageHeader } from '@/shared/components/dashboard-page-header'
import { formatLocalDateTime } from '@/shared/lib/date-time'
export function ReviewsPage() {
const { t, i18n } = useTranslation()
@ -21,7 +22,7 @@ export function ReviewsPage() {
const { data: rejectedReviews, isLoading: isRejectedLoading } = useReviewList('REJECTED')
const formatDate = (dateString: string) => {
return new Date(dateString).toLocaleString(i18n.language)
return formatLocalDateTime(dateString, i18n.language)
}
const handleRowClick = (reviewId: number) => {