mirror of
https://github.com/beilunyang/moemail.git
synced 2026-09-08 16:56:37 +08:00
fix(shared-email): Improve date handling and error resilience in shared email page
This commit is contained in:
@@ -11,8 +11,8 @@ import { EMAIL_CONFIG } from "@/config"
|
||||
interface Email {
|
||||
id: string
|
||||
address: string
|
||||
createdAt: string
|
||||
expiresAt: string
|
||||
createdAt: Date
|
||||
expiresAt: Date
|
||||
}
|
||||
|
||||
interface Message {
|
||||
@@ -20,8 +20,8 @@ interface Message {
|
||||
from_address?: string
|
||||
to_address?: string
|
||||
subject: string
|
||||
received_at?: string
|
||||
sent_at?: string
|
||||
received_at?: Date
|
||||
sent_at?: Date
|
||||
}
|
||||
|
||||
interface MessageDetail extends Message {
|
||||
@@ -144,7 +144,7 @@ export function SharedEmailPageClient({
|
||||
return () => {
|
||||
stopPolling()
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [token])
|
||||
|
||||
const handleLoadMore = () => {
|
||||
@@ -177,9 +177,17 @@ export function SharedEmailPageClient({
|
||||
<div className="container mx-auto p-4 max-w-7xl">
|
||||
<BrandHeader
|
||||
title={email.address}
|
||||
subtitle={new Date(email.expiresAt).getFullYear() === 9999
|
||||
? tShared("permanent")
|
||||
: `${tShared("expiresAt")}: ${new Date(email.expiresAt).toLocaleDateString()} ${new Date(email.expiresAt).toLocaleTimeString()}`}
|
||||
subtitle={(() => {
|
||||
try {
|
||||
const expiresDate = new Date(email.expiresAt)
|
||||
if (isNaN(expiresDate.getTime())) return tShared("sharedMailbox")
|
||||
return expiresDate.getFullYear() === 9999
|
||||
? tShared("permanent")
|
||||
: `${tShared("expiresAt")}: ${expiresDate.toLocaleDateString()} ${expiresDate.toLocaleTimeString()}`
|
||||
} catch {
|
||||
return tShared("sharedMailbox")
|
||||
}
|
||||
})()}
|
||||
showCta={true}
|
||||
ctaText={tShared("createOwnEmail")}
|
||||
/>
|
||||
@@ -190,8 +198,24 @@ export function SharedEmailPageClient({
|
||||
<SharedMessageList
|
||||
messages={messages.map(msg => ({
|
||||
...msg,
|
||||
received_at: msg.received_at ? new Date(msg.received_at as string).getTime() : undefined,
|
||||
sent_at: msg.sent_at ? new Date(msg.sent_at as string).getTime() : undefined
|
||||
received_at: (() => {
|
||||
if (!msg.received_at) return undefined
|
||||
try {
|
||||
const date = new Date(msg.received_at)
|
||||
return isNaN(date.getTime()) ? undefined : date.getTime()
|
||||
} catch {
|
||||
return undefined
|
||||
}
|
||||
})(),
|
||||
sent_at: (() => {
|
||||
if (!msg.sent_at) return undefined
|
||||
try {
|
||||
const date = new Date(msg.sent_at)
|
||||
return isNaN(date.getTime()) ? undefined : date.getTime()
|
||||
} catch {
|
||||
return undefined
|
||||
}
|
||||
})()
|
||||
}))}
|
||||
selectedMessageId={selectedMessage?.id}
|
||||
onMessageSelect={fetchMessageDetail}
|
||||
@@ -216,8 +240,24 @@ export function SharedEmailPageClient({
|
||||
<SharedMessageDetail
|
||||
message={selectedMessage ? {
|
||||
...selectedMessage,
|
||||
received_at: selectedMessage.received_at ? new Date(selectedMessage.received_at as string).getTime() : undefined,
|
||||
sent_at: selectedMessage.sent_at ? new Date(selectedMessage.sent_at as string).getTime() : undefined
|
||||
received_at: (() => {
|
||||
if (!selectedMessage.received_at) return undefined
|
||||
try {
|
||||
const date = new Date(selectedMessage.received_at)
|
||||
return isNaN(date.getTime()) ? undefined : date.getTime()
|
||||
} catch {
|
||||
return undefined
|
||||
}
|
||||
})(),
|
||||
sent_at: (() => {
|
||||
if (!selectedMessage.sent_at) return undefined
|
||||
try {
|
||||
const date = new Date(selectedMessage.sent_at)
|
||||
return isNaN(date.getTime()) ? undefined : date.getTime()
|
||||
} catch {
|
||||
return undefined
|
||||
}
|
||||
})()
|
||||
} : null}
|
||||
loading={messageLoading}
|
||||
t={{
|
||||
@@ -243,8 +283,24 @@ export function SharedEmailPageClient({
|
||||
<SharedMessageList
|
||||
messages={messages.map(msg => ({
|
||||
...msg,
|
||||
received_at: msg.received_at ? new Date(msg.received_at as string).getTime() : undefined,
|
||||
sent_at: msg.sent_at ? new Date(msg.sent_at as string).getTime() : undefined
|
||||
received_at: (() => {
|
||||
if (!msg.received_at) return undefined
|
||||
try {
|
||||
const date = new Date(msg.received_at)
|
||||
return isNaN(date.getTime()) ? undefined : date.getTime()
|
||||
} catch {
|
||||
return undefined
|
||||
}
|
||||
})(),
|
||||
sent_at: (() => {
|
||||
if (!msg.sent_at) return undefined
|
||||
try {
|
||||
const date = new Date(msg.sent_at)
|
||||
return isNaN(date.getTime()) ? undefined : date.getTime()
|
||||
} catch {
|
||||
return undefined
|
||||
}
|
||||
})()
|
||||
}))}
|
||||
selectedMessageId={null}
|
||||
onMessageSelect={fetchMessageDetail}
|
||||
@@ -279,8 +335,24 @@ export function SharedEmailPageClient({
|
||||
<SharedMessageDetail
|
||||
message={{
|
||||
...selectedMessage,
|
||||
received_at: selectedMessage.received_at ? new Date(selectedMessage.received_at as string).getTime() : undefined,
|
||||
sent_at: selectedMessage.sent_at ? new Date(selectedMessage.sent_at as string).getTime() : undefined
|
||||
received_at: (() => {
|
||||
if (!selectedMessage.received_at) return undefined
|
||||
try {
|
||||
const date = new Date(selectedMessage.received_at)
|
||||
return isNaN(date.getTime()) ? undefined : date.getTime()
|
||||
} catch {
|
||||
return undefined
|
||||
}
|
||||
})(),
|
||||
sent_at: (() => {
|
||||
if (!selectedMessage.sent_at) return undefined
|
||||
try {
|
||||
const date = new Date(selectedMessage.sent_at)
|
||||
return isNaN(date.getTime()) ? undefined : date.getTime()
|
||||
} catch {
|
||||
return undefined
|
||||
}
|
||||
})()
|
||||
}}
|
||||
loading={messageLoading}
|
||||
t={{
|
||||
|
||||
@@ -34,16 +34,8 @@ export default async function SharedEmailPage({ params }: PageProps) {
|
||||
|
||||
return (
|
||||
<SharedEmailPageClient
|
||||
email={{
|
||||
...email,
|
||||
createdAt: email.createdAt.toISOString(),
|
||||
expiresAt: email.expiresAt.toISOString()
|
||||
}}
|
||||
initialMessages={messagesResult.messages.map(msg => ({
|
||||
...msg,
|
||||
received_at: msg.received_at?.toISOString(),
|
||||
sent_at: msg.sent_at?.toISOString()
|
||||
}))}
|
||||
email={email}
|
||||
initialMessages={messagesResult.messages}
|
||||
initialNextCursor={messagesResult.nextCursor}
|
||||
initialTotal={messagesResult.total}
|
||||
token={token}
|
||||
|
||||
@@ -256,7 +256,7 @@ export function ShareDialog({ emailId }: ShareDialogProps) {
|
||||
}
|
||||
}}
|
||||
className={cn(
|
||||
"flex-1 text-xs p-1 rounded truncate font-mono transition-colors",
|
||||
"flex-1 text-xs p-1 rounded font-mono transition-colors break-all",
|
||||
isExpired
|
||||
? "bg-destructive/10 text-destructive/70 cursor-not-allowed pointer-events-none"
|
||||
: "bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-300 hover:text-primary dark:hover:text-primary cursor-pointer"
|
||||
@@ -281,7 +281,7 @@ export function ShareDialog({ emailId }: ShareDialogProps) {
|
||||
<Trash2 className="h-4 w-4 text-destructive" />
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex gap-4 text-xs">
|
||||
<div className="flex gap-y-4 gap-x-2 sm:gap-x-4 text-xs">
|
||||
<span className={cn(
|
||||
isExpired ? "text-destructive/70" : "text-gray-500"
|
||||
)}>
|
||||
|
||||
@@ -265,7 +265,7 @@ export function ShareMessageDialog({ emailId, messageId, messageSubject, trigger
|
||||
}
|
||||
}}
|
||||
className={cn(
|
||||
"flex-1 text-xs p-1 rounded truncate font-mono transition-colors",
|
||||
"flex-1 text-xs p-1 rounded font-mono transition-colors break-all",
|
||||
isExpired
|
||||
? "bg-destructive/10 text-destructive/70 cursor-not-allowed pointer-events-none"
|
||||
: "bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-300 hover:text-primary dark:hover:text-primary cursor-pointer"
|
||||
@@ -290,7 +290,7 @@ export function ShareMessageDialog({ emailId, messageId, messageSubject, trigger
|
||||
<Trash2 className="h-4 w-4 text-destructive" />
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex gap-4 text-xs">
|
||||
<div className="flex gap-y-4 gap-x-2 sm:gap-x-4 text-xs">
|
||||
<span className={cn(
|
||||
isExpired ? "text-destructive/70" : "text-gray-500"
|
||||
)}>
|
||||
|
||||
Reference in New Issue
Block a user