mirror of
https://github.com/fosrl/pangolin.git
synced 2025-07-28 14:44:55 +02:00
improve verify email redirect flow
This commit is contained in:
parent
c2cbd7e1a1
commit
5bbf32f6a6
18 changed files with 145 additions and 83 deletions
|
@ -21,9 +21,7 @@ export async function sendEmail(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug("Rendering email templatee...")
|
|
||||||
const emailHtml = await render(template);
|
const emailHtml = await render(template);
|
||||||
logger.debug("Done rendering email templatee")
|
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
from: opts.from,
|
from: opts.from,
|
||||||
|
|
|
@ -33,9 +33,17 @@ export const SendInviteLink = ({
|
||||||
<Html>
|
<Html>
|
||||||
<Head />
|
<Head />
|
||||||
<Preview>{previewText}</Preview>
|
<Preview>{previewText}</Preview>
|
||||||
<Tailwind>
|
<Tailwind config={{
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
colors: {
|
||||||
|
primary: "#F97317"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}>
|
||||||
<Body className="font-sans">
|
<Body className="font-sans">
|
||||||
<Container className="bg-white border border-solid border-gray-200 p-6 max-w-lg mx-auto my-8">
|
<Container className="bg-white border border-solid border-gray-200 p-6 max-w-lg mx-auto my-8 rounded-lg">
|
||||||
<Heading className="text-2xl font-semibold text-gray-800 text-center">
|
<Heading className="text-2xl font-semibold text-gray-800 text-center">
|
||||||
You're invited to join a Fossorial organization
|
You're invited to join a Fossorial organization
|
||||||
</Heading>
|
</Heading>
|
||||||
|
@ -58,7 +66,7 @@ export const SendInviteLink = ({
|
||||||
<Section className="text-center my-6">
|
<Section className="text-center my-6">
|
||||||
<Button
|
<Button
|
||||||
href={inviteLink}
|
href={inviteLink}
|
||||||
className="rounded-md bg-gray-600 px-[12px] py-[12px] text-center font-semibold text-white cursor-pointer"
|
className="rounded-lg bg-primary px-[12px] py-[9px] text-center font-semibold text-white cursor-pointer"
|
||||||
>
|
>
|
||||||
Accept invitation to {orgName}
|
Accept invitation to {orgName}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
@ -14,11 +14,13 @@ import * as React from "react";
|
||||||
interface VerifyEmailProps {
|
interface VerifyEmailProps {
|
||||||
username?: string;
|
username?: string;
|
||||||
verificationCode: string;
|
verificationCode: string;
|
||||||
|
verifyLink: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const VerifyEmail = ({
|
export const VerifyEmail = ({
|
||||||
username,
|
username,
|
||||||
verificationCode,
|
verificationCode,
|
||||||
|
verifyLink,
|
||||||
}: VerifyEmailProps) => {
|
}: VerifyEmailProps) => {
|
||||||
const previewText = `Verify your email, ${username}`;
|
const previewText = `Verify your email, ${username}`;
|
||||||
|
|
||||||
|
@ -26,21 +28,34 @@ export const VerifyEmail = ({
|
||||||
<Html>
|
<Html>
|
||||||
<Head />
|
<Head />
|
||||||
<Preview>{previewText}</Preview>
|
<Preview>{previewText}</Preview>
|
||||||
<Tailwind>
|
<Tailwind
|
||||||
|
config={{
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
colors: {
|
||||||
|
primary: "#F97317",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Body className="font-sans">
|
<Body className="font-sans">
|
||||||
<Container className="bg-white border border-solid border-gray-200 p-6 max-w-lg mx-auto my-8">
|
<Container className="bg-white border border-solid border-gray-200 p-6 max-w-lg mx-auto my-8 rounded-lg">
|
||||||
<Heading className="text-2xl font-semibold text-gray-800 text-center">
|
<Heading className="text-2xl font-semibold text-gray-800 text-center">
|
||||||
Verify Your Email
|
Please verify your email
|
||||||
</Heading>
|
</Heading>
|
||||||
<Text className="text-base text-gray-700 mt-4">
|
<Text className="text-base text-gray-700 mt-4">
|
||||||
Hi {username || "there"},
|
Hi {username || "there"},
|
||||||
</Text>
|
</Text>
|
||||||
<Text className="text-base text-gray-700 mt-2">
|
<Text className="text-base text-gray-700 mt-2">
|
||||||
You’ve requested to verify your email. Please use
|
You’ve requested to verify your email. Please{" "}
|
||||||
the verification code below:
|
<a href={verifyLink} className="text-primary">
|
||||||
|
click here
|
||||||
|
</a>{" "}
|
||||||
|
to verify your email, then enter the following code:
|
||||||
</Text>
|
</Text>
|
||||||
<Section className="text-center my-6">
|
<Section className="text-center my-6">
|
||||||
<Text className="inline-block bg-gray-100 text-xl font-bold text-gray-900 py-2 px-4 border border-gray-300 rounded-md">
|
<Text className="inline-block bg-primary text-xl font-bold text-white py-2 px-4 border border-gray-300 rounded-xl">
|
||||||
{verificationCode}
|
{verificationCode}
|
||||||
</Text>
|
</Text>
|
||||||
</Section>
|
</Section>
|
||||||
|
@ -59,3 +74,5 @@ export const VerifyEmail = ({
|
||||||
</Html>
|
</Html>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default VerifyEmail;
|
||||||
|
|
|
@ -139,7 +139,7 @@ export async function login(
|
||||||
success: true,
|
success: true,
|
||||||
error: false,
|
error: false,
|
||||||
message: "Email verification code sent",
|
message: "Email verification code sent",
|
||||||
status: HttpCode.ACCEPTED,
|
status: HttpCode.OK,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,11 +13,18 @@ export async function sendEmailVerificationCode(
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const code = await generateEmailVerificationCode(userId, email);
|
const code = await generateEmailVerificationCode(userId, email);
|
||||||
|
|
||||||
await sendEmail(VerifyEmail({ username: email, verificationCode: code }), {
|
await sendEmail(
|
||||||
to: email,
|
VerifyEmail({
|
||||||
from: config.email?.no_reply,
|
username: email,
|
||||||
subject: "Verify your email address",
|
verificationCode: code,
|
||||||
});
|
verifyLink: `${config.app.base_url}/auth/verify-email`,
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
to: email,
|
||||||
|
from: config.email?.no_reply,
|
||||||
|
subject: "Verify your email address",
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function generateEmailVerificationCode(
|
async function generateEmailVerificationCode(
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import { internal } from "@app/api";
|
import { internal } from "@app/api";
|
||||||
import { authCookieHeader } from "@app/api/cookies";
|
import { authCookieHeader } from "@app/api/cookies";
|
||||||
|
import { verifySession } from "@app/lib/auth/verifySession";
|
||||||
import { GetOrgResponse } from "@server/routers/org";
|
import { GetOrgResponse } from "@server/routers/org";
|
||||||
|
import { GetOrgUserResponse } from "@server/routers/user";
|
||||||
import { AxiosResponse } from "axios";
|
import { AxiosResponse } from "axios";
|
||||||
import { redirect } from "next/navigation";
|
import { redirect } from "next/navigation";
|
||||||
import { cache } from "react";
|
import { cache } from "react";
|
||||||
|
@ -17,6 +19,25 @@ export default async function OrgLayout(props: {
|
||||||
redirect(`/`);
|
redirect(`/`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getUser = cache(verifySession);
|
||||||
|
const user = await getUser();
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
redirect(`/?redirect=/${orgId}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const getOrgUser = cache(() =>
|
||||||
|
internal.get<AxiosResponse<GetOrgUserResponse>>(
|
||||||
|
`/org/${orgId}/user/${user.userId}`,
|
||||||
|
cookie,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
const orgUser = await getOrgUser();
|
||||||
|
} catch {
|
||||||
|
redirect(`/`);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const getOrg = cache(() =>
|
const getOrg = cache(() =>
|
||||||
internal.get<AxiosResponse<GetOrgResponse>>(
|
internal.get<AxiosResponse<GetOrgResponse>>(
|
||||||
|
|
|
@ -14,27 +14,6 @@ export default async function OrgPage(props: OrgPageProps) {
|
||||||
const params = await props.params;
|
const params = await props.params;
|
||||||
const orgId = params.orgId;
|
const orgId = params.orgId;
|
||||||
|
|
||||||
const getUser = cache(verifySession);
|
|
||||||
const user = await getUser();
|
|
||||||
|
|
||||||
if (!user) {
|
|
||||||
redirect("/auth/login");
|
|
||||||
}
|
|
||||||
|
|
||||||
const cookie = await authCookieHeader();
|
|
||||||
|
|
||||||
try {
|
|
||||||
const getOrgUser = cache(() =>
|
|
||||||
internal.get<AxiosResponse<GetOrgUserResponse>>(
|
|
||||||
`/org/${orgId}/user/${user.userId}`,
|
|
||||||
cookie
|
|
||||||
)
|
|
||||||
);
|
|
||||||
const orgUser = await getOrgUser();
|
|
||||||
} catch {
|
|
||||||
redirect(`/`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<p>Welcome to {orgId} dashboard</p>
|
<p>Welcome to {orgId} dashboard</p>
|
||||||
|
|
|
@ -26,7 +26,7 @@ export default async function GeneralSettingsPage({
|
||||||
const user = await getUser();
|
const user = await getUser();
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
redirect("/auth/login");
|
redirect(`/?redirect=/${orgId}/settings/general`);
|
||||||
}
|
}
|
||||||
|
|
||||||
let orgUser = null;
|
let orgUser = null;
|
||||||
|
@ -34,8 +34,8 @@ export default async function GeneralSettingsPage({
|
||||||
const getOrgUser = cache(async () =>
|
const getOrgUser = cache(async () =>
|
||||||
internal.get<AxiosResponse<GetOrgUserResponse>>(
|
internal.get<AxiosResponse<GetOrgUserResponse>>(
|
||||||
`/org/${orgId}/user/${user.userId}`,
|
`/org/${orgId}/user/${user.userId}`,
|
||||||
await authCookieHeader()
|
await authCookieHeader(),
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
const res = await getOrgUser();
|
const res = await getOrgUser();
|
||||||
orgUser = res.data.data;
|
orgUser = res.data.data;
|
||||||
|
@ -48,8 +48,8 @@ export default async function GeneralSettingsPage({
|
||||||
const getOrg = cache(async () =>
|
const getOrg = cache(async () =>
|
||||||
internal.get<AxiosResponse<GetOrgResponse>>(
|
internal.get<AxiosResponse<GetOrgResponse>>(
|
||||||
`/org/${orgId}`,
|
`/org/${orgId}`,
|
||||||
await authCookieHeader()
|
await authCookieHeader(),
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
const res = await getOrg();
|
const res = await getOrg();
|
||||||
org = res.data.data;
|
org = res.data.data;
|
||||||
|
|
|
@ -55,7 +55,7 @@ export default async function SettingsLayout(props: SettingsLayoutProps) {
|
||||||
const user = await getUser();
|
const user = await getUser();
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
redirect("/auth/login");
|
redirect(`/?redirect=/${params.orgId}/`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const cookie = await authCookieHeader();
|
const cookie = await authCookieHeader();
|
||||||
|
@ -64,8 +64,8 @@ export default async function SettingsLayout(props: SettingsLayoutProps) {
|
||||||
const getOrgUser = cache(() =>
|
const getOrgUser = cache(() =>
|
||||||
internal.get<AxiosResponse<GetOrgUserResponse>>(
|
internal.get<AxiosResponse<GetOrgUserResponse>>(
|
||||||
`/org/${params.orgId}/user/${user.userId}`,
|
`/org/${params.orgId}/user/${user.userId}`,
|
||||||
cookie
|
cookie,
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
const orgUser = await getOrgUser();
|
const orgUser = await getOrgUser();
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ export default async function SettingsLayout(props: SettingsLayoutProps) {
|
||||||
let orgs: ListOrgsResponse["orgs"] = [];
|
let orgs: ListOrgsResponse["orgs"] = [];
|
||||||
try {
|
try {
|
||||||
const getOrgs = cache(() =>
|
const getOrgs = cache(() =>
|
||||||
internal.get<AxiosResponse<ListOrgsResponse>>(`/orgs`, cookie)
|
internal.get<AxiosResponse<ListOrgsResponse>>(`/orgs`, cookie),
|
||||||
);
|
);
|
||||||
const res = await getOrgs();
|
const res = await getOrgs();
|
||||||
if (res && res.data.data.orgs) {
|
if (res && res.data.data.orgs) {
|
||||||
|
|
|
@ -30,7 +30,15 @@ export default function DashboardLoginForm({
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<LoginForm
|
<LoginForm
|
||||||
redirect={redirect}
|
redirect={redirect}
|
||||||
onLogin={() => router.push("/")}
|
onLogin={() => {
|
||||||
|
if (redirect && redirect.includes("http")) {
|
||||||
|
window.location.href = redirect;
|
||||||
|
} else if (redirect) {
|
||||||
|
router.push(redirect);
|
||||||
|
} else {
|
||||||
|
router.push("/");
|
||||||
|
}
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
|
@ -38,6 +38,7 @@ import { LoginResponse } from "@server/routers/auth";
|
||||||
import ResourceAccessDenied from "./ResourceAccessDenied";
|
import ResourceAccessDenied from "./ResourceAccessDenied";
|
||||||
import LoginForm from "@app/components/LoginForm";
|
import LoginForm from "@app/components/LoginForm";
|
||||||
import { AuthWithPasswordResponse } from "@server/routers/resource";
|
import { AuthWithPasswordResponse } from "@server/routers/resource";
|
||||||
|
import { redirect } from "next/dist/server/api-utils";
|
||||||
|
|
||||||
const pinSchema = z.object({
|
const pinSchema = z.object({
|
||||||
pin: z
|
pin: z
|
||||||
|
@ -113,11 +114,6 @@ export default function ResourceAuthPortal(props: ResourceAuthPortalProps) {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
function constructRedirect(redirect: string): string {
|
|
||||||
const redirectUrl = new URL(redirect);
|
|
||||||
return redirectUrl.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
const onPinSubmit = (values: z.infer<typeof pinSchema>) => {
|
const onPinSubmit = (values: z.infer<typeof pinSchema>) => {
|
||||||
setLoadingLogin(true);
|
setLoadingLogin(true);
|
||||||
api.post<AxiosResponse<AuthWithPasswordResponse>>(
|
api.post<AxiosResponse<AuthWithPasswordResponse>>(
|
||||||
|
@ -127,9 +123,7 @@ export default function ResourceAuthPortal(props: ResourceAuthPortalProps) {
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
const session = res.data.data.session;
|
const session = res.data.data.session;
|
||||||
if (session) {
|
if (session) {
|
||||||
const url = constructRedirect(props.redirect);
|
window.location.href = props.redirect;
|
||||||
console.log(url);
|
|
||||||
window.location.href = url;
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
|
@ -152,7 +146,7 @@ export default function ResourceAuthPortal(props: ResourceAuthPortalProps) {
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
const session = res.data.data.session;
|
const session = res.data.data.session;
|
||||||
if (session) {
|
if (session) {
|
||||||
window.location.href = constructRedirect(props.redirect);
|
window.location.href = props.redirect;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
|
@ -172,7 +166,7 @@ export default function ResourceAuthPortal(props: ResourceAuthPortalProps) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!accessDenied) {
|
if (!accessDenied) {
|
||||||
window.location.href = constructRedirect(props.redirect);
|
window.location.href = props.redirect;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -371,6 +365,7 @@ export default function ResourceAuthPortal(props: ResourceAuthPortalProps) {
|
||||||
className={`${numMethods <= 1 ? "mt-0" : ""}`}
|
className={`${numMethods <= 1 ? "mt-0" : ""}`}
|
||||||
>
|
>
|
||||||
<LoginForm
|
<LoginForm
|
||||||
|
redirect={window.location.href}
|
||||||
onLogin={async () =>
|
onLogin={async () =>
|
||||||
await handleSSOAuth()
|
await handleSSOAuth()
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,6 +79,7 @@ export default function VerifyEmailForm({
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
setError(formatAxiosError(e, "An error occurred"));
|
setError(formatAxiosError(e, "An error occurred"));
|
||||||
console.error("Failed to verify email:", e);
|
console.error("Failed to verify email:", e);
|
||||||
|
setIsSubmitting(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res && res.data?.data?.valid) {
|
if (res && res.data?.data?.valid) {
|
||||||
|
@ -125,7 +126,7 @@ export default function VerifyEmailForm({
|
||||||
<div>
|
<div>
|
||||||
<Card className="w-full max-w-md">
|
<Card className="w-full max-w-md">
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle>Verify Your Email</CardTitle>
|
<CardTitle>Verify Email</CardTitle>
|
||||||
<CardDescription>
|
<CardDescription>
|
||||||
Enter the verification code sent to your email address.
|
Enter the verification code sent to your email address.
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
|
@ -234,7 +235,7 @@ export default function VerifyEmailForm({
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<div className="text-center text-muted-foreground mt-4">
|
<div className="text-center text-muted-foreground mt-2">
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
variant="link"
|
variant="link"
|
||||||
|
|
|
@ -8,13 +8,13 @@ export const dynamic = "force-dynamic";
|
||||||
export default async function Page(props: {
|
export default async function Page(props: {
|
||||||
searchParams: Promise<{ [key: string]: string | string[] | undefined }>;
|
searchParams: Promise<{ [key: string]: string | string[] | undefined }>;
|
||||||
}) {
|
}) {
|
||||||
if (process.env.PUBLIC_FLAGS_EMAIL_VERIFICATION_REQUIRED !== "true") {
|
if (process.env.FLAGS_EMAIL_VERIFICATION_REQUIRED !== "true") {
|
||||||
redirect("/");
|
redirect("/");
|
||||||
}
|
}
|
||||||
|
|
||||||
const searchParams = await props.searchParams;
|
const searchParams = await props.searchParams;
|
||||||
const getUser = cache(verifySession);
|
const getUser = cache(verifySession);
|
||||||
const user = await getUser();
|
const user = await getUser({ skipCheckVerifyEmail: true });
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
redirect("/");
|
redirect("/");
|
||||||
|
|
|
@ -21,7 +21,7 @@ export default async function InvitePage(props: {
|
||||||
const user = await verifySession();
|
const user = await verifySession();
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
redirect(`/auth/login?redirect=/invite?token=${params.token}`);
|
redirect(`/?redirect=/invite?token=${params.token}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const parts = tokenParam.split("-");
|
const parts = tokenParam.split("-");
|
||||||
|
|
|
@ -12,21 +12,36 @@ import { cache } from "react";
|
||||||
export const dynamic = "force-dynamic";
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
export default async function Page(props: {
|
export default async function Page(props: {
|
||||||
searchParams: Promise<{ [key: string]: string | string[] | undefined }>;
|
searchParams: Promise<{ redirect: string | undefined }>;
|
||||||
}) {
|
}) {
|
||||||
const params = await props.searchParams; // this is needed to prevent static optimization
|
const params = await props.searchParams; // this is needed to prevent static optimization
|
||||||
const getUser = cache(verifySession);
|
const getUser = cache(verifySession);
|
||||||
const user = await getUser();
|
const user = await getUser({ skipCheckVerifyEmail: true });
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
redirect("/auth/login");
|
if (params.redirect) {
|
||||||
|
redirect(`/auth/login?redirect=${params.redirect}`);
|
||||||
|
} else {
|
||||||
|
redirect(`/auth/login`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
!user.emailVerified &&
|
||||||
|
process.env.FLAGS_EMAIL_VERIFICATION_REQUIRED === "true"
|
||||||
|
) {
|
||||||
|
if (params.redirect) {
|
||||||
|
redirect(`/auth/verify-email?redirect=${params.redirect}`);
|
||||||
|
} else {
|
||||||
|
redirect(`/auth/verify-email`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let orgs: ListOrgsResponse["orgs"] = [];
|
let orgs: ListOrgsResponse["orgs"] = [];
|
||||||
try {
|
try {
|
||||||
const res = await internal.get<AxiosResponse<ListOrgsResponse>>(
|
const res = await internal.get<AxiosResponse<ListOrgsResponse>>(
|
||||||
`/orgs`,
|
`/orgs`,
|
||||||
await authCookieHeader()
|
await authCookieHeader(),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (res && res.data.data.orgs) {
|
if (res && res.data.data.orgs) {
|
||||||
|
|
|
@ -19,7 +19,7 @@ export default async function SetupLayout({
|
||||||
const user = await getUser();
|
const user = await getUser();
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
redirect("/");
|
redirect("/?redirect=/setup");
|
||||||
}
|
}
|
||||||
|
|
||||||
return <div className="mt-32">{children}</div>;
|
return <div className="mt-32">{children}</div>;
|
||||||
|
|
|
@ -72,13 +72,14 @@ export default function LoginForm({ redirect, onLogin }: LoginFormProps) {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log(res);
|
||||||
|
|
||||||
if (res && res.status === 200) {
|
if (res && res.status === 200) {
|
||||||
setError(null);
|
setError(null);
|
||||||
|
|
||||||
console.log(res);
|
|
||||||
|
|
||||||
if (res.data?.data?.emailVerificationRequired) {
|
if (res.data?.data?.emailVerificationRequired) {
|
||||||
if (redirect) {
|
if (redirect) {
|
||||||
|
console.log("here", redirect)
|
||||||
router.push(`/auth/verify-email?redirect=${redirect}`);
|
router.push(`/auth/verify-email?redirect=${redirect}`);
|
||||||
} else {
|
} else {
|
||||||
router.push("/auth/verify-email");
|
router.push("/auth/verify-email");
|
||||||
|
@ -86,14 +87,8 @@ export default function LoginForm({ redirect, onLogin }: LoginFormProps) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (redirect && redirect.includes("http")) {
|
if (onLogin) {
|
||||||
window.location.href = redirect;
|
await onLogin();
|
||||||
} else if (redirect) {
|
|
||||||
router.push(redirect);
|
|
||||||
} else {
|
|
||||||
if (onLogin) {
|
|
||||||
await onLogin();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,15 +3,33 @@ import { authCookieHeader } from "@app/api/cookies";
|
||||||
import { GetUserResponse } from "@server/routers/user";
|
import { GetUserResponse } from "@server/routers/user";
|
||||||
import { AxiosResponse } from "axios";
|
import { AxiosResponse } from "axios";
|
||||||
|
|
||||||
export async function verifySession(): Promise<GetUserResponse | null> {
|
export async function verifySession({
|
||||||
|
skipCheckVerifyEmail,
|
||||||
|
}: {
|
||||||
|
skipCheckVerifyEmail?: boolean;
|
||||||
|
} = {}): Promise<GetUserResponse | null> {
|
||||||
try {
|
try {
|
||||||
const res = await internal.get<AxiosResponse<GetUserResponse>>(
|
const res = await internal.get<AxiosResponse<GetUserResponse>>(
|
||||||
"/user",
|
"/user",
|
||||||
await authCookieHeader()
|
await authCookieHeader(),
|
||||||
);
|
);
|
||||||
|
|
||||||
return res.data.data;
|
const user = res.data.data;
|
||||||
} catch {
|
|
||||||
|
if (!user) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
!skipCheckVerifyEmail &&
|
||||||
|
!user.emailVerified &&
|
||||||
|
process.env.FLAGS_EMAIL_VERIFICATION_REQUIRED == "true"
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return user;
|
||||||
|
} catch (e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue