144 lines
3.5 KiB
TypeScript
144 lines
3.5 KiB
TypeScript
import { routing } from "@i18n/routing";
|
|
import { config as appConfig } from "@repo/config";
|
|
import { createPurchasesHelper } from "@repo/payments/lib/helper";
|
|
import {
|
|
getOrganizationsForSession,
|
|
getPurchasesForSession,
|
|
getSession,
|
|
} from "@shared/lib/middleware-helpers";
|
|
import createMiddleware from "next-intl/middleware";
|
|
import { type NextRequest, NextResponse } from "next/server";
|
|
import { withQuery } from "ufo";
|
|
|
|
const intlMiddleware = createMiddleware(routing);
|
|
|
|
export default async function middleware(req: NextRequest) {
|
|
const { pathname, origin } = req.nextUrl;
|
|
|
|
if (pathname.startsWith("/app")) {
|
|
const response = NextResponse.next();
|
|
|
|
if (!appConfig.ui.saas.enabled) {
|
|
return NextResponse.redirect(new URL("/", origin));
|
|
}
|
|
|
|
const session = await getSession(req);
|
|
let locale = req.cookies.get(appConfig.i18n.localeCookieName)?.value;
|
|
|
|
if (!session) {
|
|
return NextResponse.redirect(
|
|
new URL(
|
|
withQuery("/auth/login", {
|
|
redirectTo: pathname,
|
|
}),
|
|
origin,
|
|
),
|
|
);
|
|
}
|
|
|
|
if (
|
|
appConfig.users.enableOnboarding &&
|
|
!session.user.onboardingComplete &&
|
|
pathname !== "/app/onboarding"
|
|
) {
|
|
return NextResponse.redirect(
|
|
new URL(
|
|
withQuery("/app/onboarding", {
|
|
redirectTo: pathname,
|
|
}),
|
|
origin,
|
|
),
|
|
);
|
|
}
|
|
|
|
if (
|
|
!locale ||
|
|
(session.user.locale && locale !== session.user.locale)
|
|
) {
|
|
locale = session.user.locale ?? appConfig.i18n.defaultLocale;
|
|
response.cookies.set(appConfig.i18n.localeCookieName, locale);
|
|
}
|
|
|
|
if (
|
|
appConfig.organizations.enable &&
|
|
appConfig.organizations.requireOrganization &&
|
|
pathname === "/app"
|
|
) {
|
|
const organizations = await getOrganizationsForSession(req);
|
|
const organization =
|
|
organizations.find(
|
|
(org) => org.id === session?.session.activeOrganizationId,
|
|
) || organizations[0];
|
|
|
|
return NextResponse.redirect(
|
|
new URL(
|
|
organization
|
|
? `/app/${organization.slug}`
|
|
: "/app/new-organization",
|
|
origin,
|
|
),
|
|
);
|
|
}
|
|
|
|
const hasFreePlan = Object.values(appConfig.payments.plans).some(
|
|
(plan) => "isFree" in plan,
|
|
);
|
|
if (
|
|
((appConfig.organizations.enable &&
|
|
appConfig.organizations.enableBilling) ||
|
|
appConfig.users.enableBilling) &&
|
|
!hasFreePlan
|
|
) {
|
|
const organizationId = appConfig.organizations.enable
|
|
? session?.session.activeOrganizationId ||
|
|
(await getOrganizationsForSession(req))?.at(0)?.id
|
|
: undefined;
|
|
|
|
const purchases = await getPurchasesForSession(req, organizationId);
|
|
const { activePlan } = createPurchasesHelper(purchases);
|
|
|
|
const validPathsWithoutPlan = [
|
|
"/app/choose-plan",
|
|
"/app/onboarding",
|
|
"/app/new-organization",
|
|
"/app/organization-invitation/",
|
|
];
|
|
if (
|
|
!activePlan &&
|
|
!validPathsWithoutPlan.some((path) => pathname.startsWith(path))
|
|
) {
|
|
return NextResponse.redirect(
|
|
new URL("/app/choose-plan", origin),
|
|
);
|
|
}
|
|
}
|
|
|
|
return response;
|
|
}
|
|
|
|
if (pathname.startsWith("/auth")) {
|
|
if (!appConfig.ui.saas.enabled) {
|
|
return NextResponse.redirect(new URL("/", origin));
|
|
}
|
|
|
|
const session = await getSession(req);
|
|
|
|
if (session && pathname !== "/auth/reset-password") {
|
|
return NextResponse.redirect(new URL("/app", origin));
|
|
}
|
|
|
|
return NextResponse.next();
|
|
}
|
|
|
|
if (!appConfig.ui.marketing.enabled) {
|
|
return NextResponse.redirect(new URL("/app", origin));
|
|
}
|
|
|
|
return intlMiddleware(req);
|
|
}
|
|
|
|
export const config = {
|
|
matcher: [
|
|
"/((?!api|image-proxy|images|fonts|_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)",
|
|
],
|
|
};
|