diff --git a/backend/src/components/admin/reports.tsx b/backend/src/components/admin/reports.tsx index 7eb75ed..a58854f 100644 --- a/backend/src/components/admin/reports.tsx +++ b/backend/src/components/admin/reports.tsx @@ -25,6 +25,7 @@ export default async function Reports({ searchParams }: { searchParams: { status ]); const totalPages = Math.ceil(total / PAGE_SIZE); + const FRONTEND_URL = process.env.NEXT_PUBLIC_FRONTEND_URL; const updateStatus = async (formData: FormData) => { "use server"; @@ -88,21 +89,24 @@ export default async function Reports({ searchParams }: { searchParams: { status

Target ID

- + {report.targetId}

Creator ID

- + {report.creatorId}

Reporter

- + {report.authorId}
diff --git a/frontend/src/pages/mii.tsx b/frontend/src/pages/mii.tsx index 3237365..a7b5e5b 100644 --- a/frontend/src/pages/mii.tsx +++ b/frontend/src/pages/mii.tsx @@ -54,8 +54,36 @@ export default function MiiPage() { if (loading || !mii) return
Loading...
; const images = [...Array.from({ length: mii.imageCount ?? 0 }, (_, index) => `${API_URL}/mii/${mii.id}/image?type=image${index}`)]; + const metaTitle = `${mii.name} - TomodachiShare`; + const platformLabel = mii.platform === "SWITCH" ? "Switch Living the Dream" : "3DS"; + const metaDescription = `Check out '${mii.name}', a ${platformLabel} Tomodachi Life Mii created by ${mii.user.name} on TomodachiShare with ${mii.likeCount ?? 0} likes.`; + const metaImage = `${import.meta.env.VITE_API_URL}/mii/${mii.id}/image?type=metadata`; + const metaImageAlt = `${mii.name}, ${mii.tags?.join(", ")} ${mii.gender} Mii character`; + return (
+ {metaTitle} + + + + + {/* Open Graph */} + + + + + + + + + {/* Twitter / X */} + + + + + + +
{mii.quarantined && (
diff --git a/frontend/src/pages/profile/layout.tsx b/frontend/src/pages/profile/layout.tsx index 2847fe2..a2c4987 100644 --- a/frontend/src/pages/profile/layout.tsx +++ b/frontend/src/pages/profile/layout.tsx @@ -13,10 +13,10 @@ export default function ProfileLayout() { const [loading, setLoading] = useState(true); const $session = useStore(session); + const userId = Number($session ? id : $session?.user?.id); + useEffect(() => { if ($session === undefined) return; // session still loading - - const userId = id ?? $session?.user?.id; if (!userId) { navigate("/404"); return; @@ -44,14 +44,38 @@ export default function ProfileLayout() { return
Loading...
; } - const sessionUserId = $session?.user?.id ? Number($session.user.id) : null; - const page = location.pathname; - const isAdmin = sessionUserId === Number(import.meta.env.VITE_ADMIN_USER_ID); + const isAdmin = userId === Number(import.meta.env.VITE_ADMIN_USER_ID); const isContributor = import.meta.env.VITE_CONTRIBUTORS_USER_IDS?.split(",").includes(String(user?.id)); - const isOwnProfile = sessionUserId === user?.id; + const isOwnProfile = userId === user?.id; + + const joinDate = new Date(user.createdAt).toLocaleDateString("en-US", { month: "long", year: "numeric" }); + const metaTitle = `${user.name} - TomodachiShare`; + const metaDescription = `View ${user.name}'s profile on TomodachiShare. Creator of ${user._count.miis} Miis. Member since ${joinDate}.`; + const metaImage = user.image.startsWith("/profile") + ? `${import.meta.env.VITE_API_URL}${user.image}` + : (user.image ?? `${import.meta.env.VITE_API_URL}/guest.png`); return (
+ {metaTitle} + + + + + {/* Open Graph */} + + + + + + + {/* Twitter / X */} + + + + + +
{/* Profile picture */} @@ -110,19 +134,19 @@ export default function ProfileLayout() { Admin )} - {isOwnProfile && page !== "/profile/likes" && ( + {isOwnProfile && location.pathname !== "/profile/likes" && ( My Likes )} - {isOwnProfile && page !== "/profile/settings" && ( + {isOwnProfile && location.pathname !== "/profile/settings" && ( Settings )} - {(page === "/profile/likes" || page === "/profile/settings") && ( + {(location.pathname === "/profile/likes" || location.pathname === "/profile/settings") && ( Back