Files
zeekay 260fd6b8ce Rebrand from Papermark to Hanzo Dataroom
- Replace all Papermark branding with Hanzo Dataroom
- Update metadata, titles, descriptions, OG tags
- Update email templates footer and branding
- Replace papermark.io/com URLs with dataroom.hanzo.ai
- Update powered-by component
- Update x-powered-by header
- Update legal references to Hanzo AI, Inc.
- Update social handles to @hanzoai
- Update README, CLA, LICENSE, SECURITY docs
2026-03-01 19:02:19 -08:00

135 lines
3.1 KiB
TypeScript

import { Metadata } from "next";
import { redirect } from "next/navigation";
import NotFound from "@/pages/404";
import { VerificationToken } from "@prisma/client";
import { waitUntil } from "@vercel/functions";
import { hashToken } from "@/lib/api/auth/token";
import prisma from "@/lib/prisma";
import { redis } from "@/lib/redis";
import { sendEmail, subscribe, unsubscribe } from "@/lib/resend";
import { CustomUser } from "@/lib/types";
import EmailUpdated from "@/components/emails/email-updated";
import ConfirmEmailChangePageClient from "./page-client";
import { getSession } from "./utils";
export const runtime = "nodejs";
const data = {
description: "Confirm email change",
title: "Confirm email change | Hanzo Dataroom",
url: "/auth/confirm-email-change",
};
export const metadata: Metadata = {
metadataBase: new URL("https://dataroom.hanzo.ai"),
title: data.title,
description: data.description,
openGraph: {
title: data.title,
description: data.description,
url: data.url,
siteName: "Hanzo Dataroom",
images: [
{
url: "/_static/meta-image.png",
width: 800,
height: 600,
},
],
locale: "en_US",
type: "website",
},
twitter: {
card: "summary_large_image",
title: data.title,
description: data.description,
creator: "@hanzoai",
images: ["/_static/meta-image.png"],
},
};
interface PageProps {
params: Promise<{ token: string }>;
}
export default async function ConfirmEmailChangePage(props: PageProps) {
return (
<div className="flex flex-col items-center justify-center gap-6 text-center">
<VerifyEmailChange {...props} />
</div>
);
}
const VerifyEmailChange = async ({ params }: PageProps) => {
const { token } = await params;
const tokenFound = await prisma.verificationToken.findUnique({
where: {
token: hashToken(token),
},
});
if (!tokenFound || tokenFound.expires < new Date()) return <NotFound />;
const session = await getSession();
if (!session) {
redirect(`/login?next=/auth/confirm-email-change/${token}`);
}
const currentUserId = (session.user as CustomUser).id;
const data = await redis.get<{ email: string; newEmail: string }>(
`email-change-request:user:${currentUserId}`,
);
if (!data) return <NotFound />;
await unsubscribe(data.email);
await prisma.user.update({
where: {
id: currentUserId,
},
data: {
email: data.newEmail,
},
});
waitUntil(
Promise.all([
deleteRequest(tokenFound),
subscribe(data.newEmail),
sendEmail({
to: data.email,
subject: "Your email address has been changed",
system: true,
react: EmailUpdated({
oldEmail: data.email,
newEmail: data.newEmail,
}),
test: process.env.NODE_ENV === "development",
}),
]),
);
return <ConfirmEmailChangePageClient />;
};
const deleteRequest = async (tokenFound: VerificationToken) => {
await Promise.all([
prisma.verificationToken.delete({
where: {
token: tokenFound.token,
},
}),
redis.del(`email-change-request:user:${tokenFound.identifier}`),
]);
};