mirror of
https://github.com/beilunyang/moemail.git
synced 2025-12-24 11:30:51 +08:00
refactor(shared-error-page): update error page to use translation keys for dynamic content
This commit is contained in:
@@ -188,7 +188,6 @@ export function SharedEmailPageClient({
|
|||||||
return tShared("sharedMailbox")
|
return tShared("sharedMailbox")
|
||||||
}
|
}
|
||||||
})()}
|
})()}
|
||||||
showCta={true}
|
|
||||||
ctaText={tShared("createOwnEmail")}
|
ctaText={tShared("createOwnEmail")}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { getTranslations } from "next-intl/server"
|
|
||||||
import { getSharedEmail, getSharedEmailMessages } from "@/lib/shared-data"
|
import { getSharedEmail, getSharedEmailMessages } from "@/lib/shared-data"
|
||||||
import { SharedErrorPage } from "@/components/emails/shared-error-page"
|
import { SharedErrorPage } from "@/components/emails/shared-error-page"
|
||||||
import { SharedEmailPageClient } from "./page-client"
|
import { SharedEmailPageClient } from "./page-client"
|
||||||
@@ -12,7 +11,6 @@ interface PageProps {
|
|||||||
|
|
||||||
export default async function SharedEmailPage({ params }: PageProps) {
|
export default async function SharedEmailPage({ params }: PageProps) {
|
||||||
const { token } = await params
|
const { token } = await params
|
||||||
const tShared = await getTranslations("emails.shared")
|
|
||||||
|
|
||||||
// 服务端获取数据
|
// 服务端获取数据
|
||||||
const email = await getSharedEmail(token)
|
const email = await getSharedEmail(token)
|
||||||
@@ -20,11 +18,11 @@ export default async function SharedEmailPage({ params }: PageProps) {
|
|||||||
if (!email) {
|
if (!email) {
|
||||||
return (
|
return (
|
||||||
<SharedErrorPage
|
<SharedErrorPage
|
||||||
title={tShared("emailNotFound")}
|
titleKey="emailNotFound"
|
||||||
subtitle={tShared("linkExpired")}
|
subtitleKey="linkExpired"
|
||||||
error={tShared("linkInvalid")}
|
errorKey="linkInvalid"
|
||||||
description={tShared("linkInvalidDescription")}
|
descriptionKey="linkInvalidDescription"
|
||||||
ctaText={tShared("createOwnEmail")}
|
ctaTextKey="createOwnEmail"
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ export function SharedMessagePageClient({ message }: SharedMessagePageClientProp
|
|||||||
: message.emailExpiresAt
|
: message.emailExpiresAt
|
||||||
? `${tShared("expiresAt")}: ${new Date(message.emailExpiresAt).toLocaleString()}`
|
? `${tShared("expiresAt")}: ${new Date(message.emailExpiresAt).toLocaleString()}`
|
||||||
: tShared("sharedMessage")}
|
: tShared("sharedMessage")}
|
||||||
showCta={true}
|
|
||||||
ctaText={tShared("createOwnEmail")}
|
ctaText={tShared("createOwnEmail")}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { getTranslations } from "next-intl/server"
|
|
||||||
import { getSharedMessage } from "@/lib/shared-data"
|
import { getSharedMessage } from "@/lib/shared-data"
|
||||||
import { SharedErrorPage } from "@/components/emails/shared-error-page"
|
import { SharedErrorPage } from "@/components/emails/shared-error-page"
|
||||||
import { SharedMessagePageClient } from "./page-client"
|
import { SharedMessagePageClient } from "./page-client"
|
||||||
@@ -12,7 +11,6 @@ interface PageProps {
|
|||||||
|
|
||||||
export default async function SharedMessagePage({ params }: PageProps) {
|
export default async function SharedMessagePage({ params }: PageProps) {
|
||||||
const { token } = await params
|
const { token } = await params
|
||||||
const tShared = await getTranslations("emails.shared")
|
|
||||||
|
|
||||||
// 服务端获取数据
|
// 服务端获取数据
|
||||||
const message = await getSharedMessage(token)
|
const message = await getSharedMessage(token)
|
||||||
@@ -20,11 +18,11 @@ export default async function SharedMessagePage({ params }: PageProps) {
|
|||||||
if (!message) {
|
if (!message) {
|
||||||
return (
|
return (
|
||||||
<SharedErrorPage
|
<SharedErrorPage
|
||||||
title={tShared("messageNotFound")}
|
titleKey="messageNotFound"
|
||||||
subtitle={tShared("linkExpired")}
|
subtitleKey="linkExpired"
|
||||||
error={tShared("linkInvalid")}
|
errorKey="linkInvalid"
|
||||||
description={tShared("linkInvalidDescription")}
|
descriptionKey="linkInvalidDescription"
|
||||||
ctaText={tShared("createOwnEmail")}
|
ctaTextKey="createOwnEmail"
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,34 +1,48 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
|
import { useTranslations } from "next-intl"
|
||||||
import { AlertCircle } from "lucide-react"
|
import { AlertCircle } from "lucide-react"
|
||||||
import { Card } from "@/components/ui/card"
|
import { Card } from "@/components/ui/card"
|
||||||
import { BrandHeader } from "@/components/ui/brand-header"
|
import { BrandHeader } from "@/components/ui/brand-header"
|
||||||
import { FloatingLanguageSwitcher } from "@/components/layout/floating-language-switcher"
|
import { FloatingLanguageSwitcher } from "@/components/layout/floating-language-switcher"
|
||||||
|
|
||||||
interface SharedErrorPageProps {
|
interface SharedErrorPageProps {
|
||||||
title: string
|
titleKey: string
|
||||||
subtitle: string
|
subtitleKey: string
|
||||||
error: string
|
errorKey: string
|
||||||
description: string
|
descriptionKey: string
|
||||||
ctaText: string
|
ctaTextKey: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SharedErrorPage({ title, subtitle, error, description, ctaText }: SharedErrorPageProps) {
|
export function SharedErrorPage({
|
||||||
|
titleKey,
|
||||||
|
subtitleKey,
|
||||||
|
errorKey,
|
||||||
|
descriptionKey,
|
||||||
|
ctaTextKey,
|
||||||
|
}: SharedErrorPageProps) {
|
||||||
|
const tShared = useTranslations("emails.shared")
|
||||||
|
|
||||||
|
const resolvedTitle = tShared(titleKey)
|
||||||
|
const resolvedSubtitle = tShared(subtitleKey)
|
||||||
|
const resolvedError = tShared(errorKey)
|
||||||
|
const resolvedDescription = tShared(descriptionKey)
|
||||||
|
const resolvedCtaText = tShared(ctaTextKey)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-gray-50 dark:bg-gray-900">
|
<div className="min-h-screen bg-gray-50 dark:bg-gray-900 flex flex-col justify-center items-center">
|
||||||
<div className="container mx-auto p-4 max-w-4xl">
|
<div className="container mx-auto p-4 max-w-4xl">
|
||||||
<BrandHeader
|
<BrandHeader
|
||||||
title={title}
|
title={resolvedTitle}
|
||||||
subtitle={subtitle}
|
subtitle={resolvedSubtitle}
|
||||||
showCta={true}
|
ctaText={resolvedCtaText}
|
||||||
ctaText={ctaText}
|
|
||||||
/>
|
/>
|
||||||
<div className="text-center">
|
<div className="text-center mt-6">
|
||||||
<Card className="max-w-md mx-auto p-8 text-center space-y-4">
|
<Card className="max-w-md mx-auto p-8 text-center space-y-4">
|
||||||
<AlertCircle className="h-12 w-12 mx-auto text-destructive" />
|
<AlertCircle className="h-12 w-12 mx-auto text-destructive" />
|
||||||
<h2 className="text-2xl font-bold">{error}</h2>
|
<h2 className="text-2xl font-bold">{resolvedError}</h2>
|
||||||
<p className="text-gray-500">
|
<p className="text-gray-500">
|
||||||
{description}
|
{resolvedDescription}
|
||||||
</p>
|
</p>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
@@ -37,4 +51,4 @@ export function SharedErrorPage({ title, subtitle, error, description, ctaText }
|
|||||||
<FloatingLanguageSwitcher />
|
<FloatingLanguageSwitcher />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,28 +8,24 @@ import { ExternalLink, Mail } from "lucide-react"
|
|||||||
interface BrandHeaderProps {
|
interface BrandHeaderProps {
|
||||||
title?: string
|
title?: string
|
||||||
subtitle?: string
|
subtitle?: string
|
||||||
showCta?: boolean
|
|
||||||
ctaText?: string
|
ctaText?: string
|
||||||
ctaHref?: string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function BrandHeader({
|
export function BrandHeader({
|
||||||
title,
|
title,
|
||||||
subtitle,
|
subtitle,
|
||||||
showCta = true,
|
|
||||||
ctaText,
|
ctaText,
|
||||||
ctaHref = "https://moemail.app"
|
|
||||||
}: BrandHeaderProps) {
|
}: BrandHeaderProps) {
|
||||||
const t = useTranslations("emails.shared.brand")
|
const t = useTranslations("emails.shared.brand")
|
||||||
|
|
||||||
const displayTitle = title || t("title")
|
const displayTitle = title || t("title")
|
||||||
const displaySubtitle = subtitle || t("subtitle")
|
const displaySubtitle = subtitle || t("subtitle")
|
||||||
const displayCtaText = ctaText || t("cta")
|
const displayCtaText = ctaText || t("cta")
|
||||||
return (
|
return (
|
||||||
<div className="text-center space-y-4 lg:pb-4">
|
<div className="text-center space-y-4 lg:pb-4">
|
||||||
<div className="flex justify-center pt-2">
|
<div className="flex justify-center pt-2">
|
||||||
<Link
|
<Link
|
||||||
href={ctaHref}
|
href="https://moemail.app"
|
||||||
className="flex items-center gap-3 hover:opacity-80 transition-opacity group"
|
className="flex items-center gap-3 hover:opacity-80 transition-opacity group"
|
||||||
>
|
>
|
||||||
<div className="relative w-12 h-12">
|
<div className="relative w-12 h-12">
|
||||||
@@ -47,32 +43,32 @@ export function BrandHeader({
|
|||||||
d="M4 8h24v16H4V8z"
|
d="M4 8h24v16H4V8z"
|
||||||
className="fill-primary/20"
|
className="fill-primary/20"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* 信封边框 */}
|
{/* 信封边框 */}
|
||||||
<path
|
<path
|
||||||
d="M4 8h24v2H4V8zM4 22h24v2H4v-2z"
|
d="M4 8h24v2H4V8zM4 22h24v2H4v-2z"
|
||||||
className="fill-primary"
|
className="fill-primary"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* @ 符号 */}
|
{/* @ 符号 */}
|
||||||
<path
|
<path
|
||||||
d="M14 12h4v4h-4v-4zM12 14h2v4h-2v-4zM18 14h2v4h-2v-4zM14 18h4v2h-4v-2z"
|
d="M14 12h4v4h-4v-4zM12 14h2v4h-2v-4zM18 14h2v4h-2v-4zM14 18h4v2h-4v-2z"
|
||||||
className="fill-primary"
|
className="fill-primary"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* 折线装饰 */}
|
{/* 折线装饰 */}
|
||||||
<path
|
<path
|
||||||
d="M4 8l12 8 12-8"
|
d="M4 8l12 8 12-8"
|
||||||
className="stroke-primary stroke-2"
|
className="stroke-primary stroke-2"
|
||||||
fill="none"
|
fill="none"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* 装饰点 */}
|
{/* 装饰点 */}
|
||||||
<path
|
<path
|
||||||
d="M8 18h2v2H8v-2zM22 18h2v2h-2v-2z"
|
d="M8 18h2v2H8v-2zM22 18h2v2h-2v-2z"
|
||||||
className="fill-primary/60"
|
className="fill-primary/60"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* 底部装饰线 */}
|
{/* 底部装饰线 */}
|
||||||
<path
|
<path
|
||||||
d="M8 14h2v2H8v-2zM22 14h2v2h-2v-2z"
|
d="M8 14h2v2H8v-2zM22 14h2v2h-2v-2z"
|
||||||
@@ -96,21 +92,19 @@ export function BrandHeader({
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{showCta && (
|
<div className="flex justify-center">
|
||||||
<div className="flex justify-center">
|
<Button
|
||||||
<Button
|
asChild
|
||||||
asChild
|
size="lg"
|
||||||
size="lg"
|
className="gap-2 bg-primary hover:bg-primary/90 text-white px-8 min-h-10 h-auto py-1"
|
||||||
className="gap-2 bg-primary hover:bg-primary/90 text-white px-8 min-h-10 h-auto py-1"
|
>
|
||||||
>
|
<Link href="/" target="_blank" rel="noopener noreferrer">
|
||||||
<Link href={ctaHref} target="_blank" rel="noopener noreferrer">
|
<Mail className="w-5 h-5" />
|
||||||
<Mail className="w-5 h-5" />
|
{displayCtaText}
|
||||||
{displayCtaText}
|
<ExternalLink className="w-4 h-4" />
|
||||||
<ExternalLink className="w-4 h-4" />
|
</Link>
|
||||||
</Link>
|
</Button>
|
||||||
</Button>
|
</div>
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user