mirror of
https://github.com/formbricks/formbricks.git
synced 2026-05-08 06:41:45 -05:00
chore: invite types (#4613)
Co-authored-by: pandeymangg <anshuman.pandey9999@gmail.com>
This commit is contained in:
@@ -1,35 +1,4 @@
|
||||
import { Button } from "@/modules/ui/components/button";
|
||||
import { Metadata } from "next";
|
||||
import { getTranslations } from "next-intl/server";
|
||||
import Link from "next/link";
|
||||
import { IntroPage, metadata } from "@/modules/setup/(fresh-instance)/intro/page";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Intro",
|
||||
description: "Open-source Experience Management. Free & open source.",
|
||||
};
|
||||
|
||||
const renderRichText = async (text: string) => {
|
||||
const t = await getTranslations();
|
||||
return <p>{t.rich(text, { b: (chunks) => <b>{chunks}</b> })}</p>;
|
||||
};
|
||||
|
||||
const Page = async () => {
|
||||
const t = await getTranslations();
|
||||
return (
|
||||
<div className="flex flex-col items-center">
|
||||
<h2 className="mb-6 text-xl font-medium">{t("setup.intro.welcome_to_formbricks")}</h2>
|
||||
<div className="mx-auto max-w-sm space-y-4 text-sm leading-6 text-slate-600">
|
||||
{renderRichText("setup.intro.paragraph_1")}
|
||||
{renderRichText("setup.intro.paragraph_2")}
|
||||
{renderRichText("setup.intro.paragraph_3")}
|
||||
</div>
|
||||
<Button className="mt-6" asChild>
|
||||
<Link href="/setup/signup">{t("setup.intro.get_started")}</Link>
|
||||
</Button>
|
||||
|
||||
<p className="pt-6 text-xs text-slate-400">{t("setup.intro.made_with_love_in_kiel")}</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Page;
|
||||
export { metadata };
|
||||
export default IntroPage;
|
||||
|
||||
@@ -1,16 +1,3 @@
|
||||
import { authOptions } from "@/modules/auth/lib/authOptions";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { notFound } from "next/navigation";
|
||||
import { getIsFreshInstance } from "@formbricks/lib/instance/service";
|
||||
|
||||
const FreshInstanceLayout = async ({ children }: { children: React.ReactNode }) => {
|
||||
const session = await getServerSession(authOptions);
|
||||
const isFreshInstance = await getIsFreshInstance();
|
||||
|
||||
if (session ?? !isFreshInstance) {
|
||||
return notFound();
|
||||
}
|
||||
return <>{children}</>;
|
||||
};
|
||||
import { FreshInstanceLayout } from "@/modules/setup/(fresh-instance)/layout";
|
||||
|
||||
export default FreshInstanceLayout;
|
||||
|
||||
@@ -1,57 +1,4 @@
|
||||
import { SignupForm } from "@/modules/auth/signup/components/signup-form";
|
||||
import { getIsSSOEnabled } from "@/modules/ee/license-check/lib/utils";
|
||||
import { Metadata } from "next";
|
||||
import { getTranslations } from "next-intl/server";
|
||||
import {
|
||||
AZURE_OAUTH_ENABLED,
|
||||
DEFAULT_ORGANIZATION_ID,
|
||||
DEFAULT_ORGANIZATION_ROLE,
|
||||
EMAIL_AUTH_ENABLED,
|
||||
EMAIL_VERIFICATION_DISABLED,
|
||||
GITHUB_OAUTH_ENABLED,
|
||||
GOOGLE_OAUTH_ENABLED,
|
||||
IS_TURNSTILE_CONFIGURED,
|
||||
OIDC_DISPLAY_NAME,
|
||||
OIDC_OAUTH_ENABLED,
|
||||
PRIVACY_URL,
|
||||
TERMS_URL,
|
||||
WEBAPP_URL,
|
||||
} from "@formbricks/lib/constants";
|
||||
import { findMatchingLocale } from "@formbricks/lib/utils/locale";
|
||||
import { SignupPage, metadata } from "@/modules/setup/(fresh-instance)/signup/page";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Sign up",
|
||||
description: "Open-source Experience Management. Free & open source.",
|
||||
};
|
||||
|
||||
const Page = async () => {
|
||||
const locale = await findMatchingLocale();
|
||||
const isSSOEnabled = await getIsSSOEnabled();
|
||||
const t = await getTranslations();
|
||||
return (
|
||||
<div className="flex flex-col items-center">
|
||||
<h2 className="mb-6 text-xl font-medium">{t("setup.signup.create_administrator")}</h2>
|
||||
<p className="text-sm text-slate-800">{t("setup.signup.this_user_has_all_the_power")}</p>
|
||||
<hr className="my-6 w-full border-slate-200" />
|
||||
<SignupForm
|
||||
webAppUrl={WEBAPP_URL}
|
||||
termsUrl={TERMS_URL}
|
||||
privacyUrl={PRIVACY_URL}
|
||||
emailVerificationDisabled={EMAIL_VERIFICATION_DISABLED}
|
||||
emailAuthEnabled={EMAIL_AUTH_ENABLED}
|
||||
googleOAuthEnabled={GOOGLE_OAUTH_ENABLED}
|
||||
githubOAuthEnabled={GITHUB_OAUTH_ENABLED}
|
||||
azureOAuthEnabled={AZURE_OAUTH_ENABLED}
|
||||
oidcOAuthEnabled={OIDC_OAUTH_ENABLED}
|
||||
oidcDisplayName={OIDC_DISPLAY_NAME}
|
||||
userLocale={locale}
|
||||
defaultOrganizationId={DEFAULT_ORGANIZATION_ID}
|
||||
defaultOrganizationRole={DEFAULT_ORGANIZATION_ROLE}
|
||||
isSSOEnabled={isSSOEnabled}
|
||||
isTurnstileConfigured={IS_TURNSTILE_CONFIGURED}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Page;
|
||||
export { metadata };
|
||||
export default SignupPage;
|
||||
|
||||
@@ -1,22 +1,3 @@
|
||||
import { FormbricksLogo } from "@/modules/ui/components/formbricks-logo";
|
||||
import { Toaster } from "react-hot-toast";
|
||||
|
||||
const SetupLayout = ({ children }: { children: React.ReactNode }) => {
|
||||
return (
|
||||
<>
|
||||
<Toaster />
|
||||
<div className="flex h-full w-full items-center justify-center bg-slate-50">
|
||||
<div
|
||||
style={{ scrollbarGutter: "stable both-edges" }}
|
||||
className="flex max-h-[90vh] w-[40rem] flex-col items-center space-y-4 overflow-auto rounded-lg border bg-white p-12 text-center shadow-md">
|
||||
<div className="h-20 w-20 rounded-lg bg-slate-900 p-2">
|
||||
<FormbricksLogo className="h-full w-full" />
|
||||
</div>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
import { SetupLayout } from "@/modules/setup/layout";
|
||||
|
||||
export default SetupLayout;
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
"use server";
|
||||
|
||||
import { authenticatedActionClient } from "@/lib/utils/action-client";
|
||||
import { checkAuthorizationUpdated } from "@/lib/utils/action-client-middleware";
|
||||
import { sendInviteMemberEmail } from "@/modules/email";
|
||||
import { z } from "zod";
|
||||
import { INVITE_DISABLED } from "@formbricks/lib/constants";
|
||||
import { inviteUser } from "@formbricks/lib/invite/service";
|
||||
import { ZId } from "@formbricks/types/common";
|
||||
import { AuthenticationError } from "@formbricks/types/errors";
|
||||
import { ZUserEmail, ZUserName } from "@formbricks/types/user";
|
||||
|
||||
const ZInviteOrganizationMemberAction = z.object({
|
||||
email: ZUserEmail,
|
||||
organizationId: ZId,
|
||||
name: ZUserName,
|
||||
});
|
||||
|
||||
export const inviteOrganizationMemberAction = authenticatedActionClient
|
||||
.schema(ZInviteOrganizationMemberAction)
|
||||
.action(async ({ ctx, parsedInput }) => {
|
||||
if (INVITE_DISABLED) {
|
||||
throw new AuthenticationError("Invite disabled");
|
||||
}
|
||||
|
||||
await checkAuthorizationUpdated({
|
||||
userId: ctx.user.id,
|
||||
organizationId: parsedInput.organizationId,
|
||||
access: [
|
||||
{
|
||||
type: "organization",
|
||||
roles: ["owner", "manager"],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const invite = await inviteUser({
|
||||
organizationId: parsedInput.organizationId,
|
||||
invitee: {
|
||||
email: parsedInput.email,
|
||||
name: parsedInput.name,
|
||||
role: "owner",
|
||||
teamIds: [],
|
||||
},
|
||||
currentUserId: ctx.user.id,
|
||||
});
|
||||
|
||||
await sendInviteMemberEmail(
|
||||
invite.id,
|
||||
parsedInput.email,
|
||||
ctx.user.name,
|
||||
"",
|
||||
false, // is onboarding invite
|
||||
undefined,
|
||||
ctx.user.locale
|
||||
);
|
||||
|
||||
return invite;
|
||||
});
|
||||
-154
@@ -1,154 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { inviteOrganizationMemberAction } from "@/app/setup/organization/[organizationId]/invite/actions";
|
||||
import { getFormattedErrorMessage } from "@/lib/utils/helper";
|
||||
import { Alert, AlertDescription, AlertTitle } from "@/modules/ui/components/alert";
|
||||
import { Button } from "@/modules/ui/components/button";
|
||||
import { FormControl, FormError, FormField, FormItem, FormProvider } from "@/modules/ui/components/form";
|
||||
import { Input } from "@/modules/ui/components/input";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { PlusIcon } from "lucide-react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { useRouter } from "next/navigation";
|
||||
import React, { useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { toast } from "react-hot-toast";
|
||||
import { TInviteMembersFormSchema, ZInviteMembersFormSchema } from "@formbricks/types/invites";
|
||||
|
||||
interface InviteMembersProps {
|
||||
IS_SMTP_CONFIGURED: boolean;
|
||||
organizationId: string;
|
||||
}
|
||||
|
||||
export const InviteMembers = ({ IS_SMTP_CONFIGURED, organizationId }: InviteMembersProps) => {
|
||||
const t = useTranslations();
|
||||
const [membersCount, setMembersCount] = useState(1);
|
||||
const router = useRouter();
|
||||
|
||||
const form = useForm<TInviteMembersFormSchema>({
|
||||
resolver: zodResolver(ZInviteMembersFormSchema),
|
||||
});
|
||||
|
||||
const { isSubmitting } = form.formState;
|
||||
|
||||
const inviteTeamMembers = async (data: TInviteMembersFormSchema) => {
|
||||
for (const member of Object.values(data)) {
|
||||
try {
|
||||
if (!member.email) continue;
|
||||
const inviteResponse = await inviteOrganizationMemberAction({
|
||||
email: member.email.toLowerCase(),
|
||||
name: member.name,
|
||||
organizationId,
|
||||
});
|
||||
if (inviteResponse?.data) {
|
||||
toast.success(`${t("setup.invite.invitation_sent_to")} ${member.email}!`);
|
||||
} else {
|
||||
const errorMessage = getFormattedErrorMessage(inviteResponse);
|
||||
toast.error(errorMessage);
|
||||
}
|
||||
} catch (error) {
|
||||
toast.error(`${t("setup.invite.failed_to_invite")} ${member.email}.`);
|
||||
}
|
||||
}
|
||||
|
||||
router.push("/");
|
||||
};
|
||||
|
||||
const handleSkip = () => {
|
||||
router.push("/");
|
||||
};
|
||||
|
||||
return (
|
||||
<FormProvider {...form}>
|
||||
{!IS_SMTP_CONFIGURED && (
|
||||
<Alert variant="warning">
|
||||
<AlertTitle>{t("setup.invite.smtp_not_configured")}</AlertTitle>
|
||||
<AlertDescription>{t("setup.invite.smtp_not_configured_description")}</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
void form.handleSubmit(inviteTeamMembers)(e);
|
||||
}}
|
||||
className="space-y-4">
|
||||
<div className="flex flex-col items-center space-y-4">
|
||||
<h2 className="text-2xl font-medium">{t("setup.invite.invite_your_organization_members")}</h2>
|
||||
<p>{t("setup.invite.life_s_no_fun_alone")}</p>
|
||||
|
||||
{Array.from({ length: membersCount }).map((_, index) => (
|
||||
<div key={`member-${index.toString()}`} className="space-y-2">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={`member-${index.toString()}.email`}
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<div>
|
||||
<div className="relative">
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={`user@example.com`}
|
||||
className="w-80"
|
||||
isInvalid={Boolean(error?.message)}
|
||||
/>
|
||||
</div>
|
||||
{error?.message && <FormError className="text-left">{error.message}</FormError>}
|
||||
</div>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={`member-${index.toString()}.name`}
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<div>
|
||||
<div className="relative">
|
||||
<Input
|
||||
{...field}
|
||||
placeholder={`Full Name (optional)`}
|
||||
className="w-80"
|
||||
isInvalid={Boolean(error?.message)}
|
||||
/>
|
||||
</div>
|
||||
{error?.message && <FormError className="text-left">{error.message}</FormError>}
|
||||
</div>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={() => {
|
||||
setMembersCount((count) => count + 1);
|
||||
}}
|
||||
type="button">
|
||||
<PlusIcon />
|
||||
{t("setup.invite.add_another_member")}
|
||||
</Button>
|
||||
|
||||
<hr className="my-6 w-full border-slate-200" />
|
||||
|
||||
<div className="space-y-2">
|
||||
<Button
|
||||
className="flex w-80 justify-center"
|
||||
type="submit"
|
||||
loading={isSubmitting}
|
||||
disabled={isSubmitting}>
|
||||
{t("setup.invite.continue")}
|
||||
</Button>
|
||||
<Button type="button" variant="ghost" className="flex w-80 justify-center" onClick={handleSkip}>
|
||||
{t("setup.invite.skip")}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</FormProvider>
|
||||
);
|
||||
};
|
||||
@@ -1,40 +1,4 @@
|
||||
import { InviteMembers } from "@/app/setup/organization/[organizationId]/invite/components/invite-members";
|
||||
import { authOptions } from "@/modules/auth/lib/authOptions";
|
||||
import { Metadata } from "next";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { getTranslations } from "next-intl/server";
|
||||
import { notFound } from "next/navigation";
|
||||
import { SMTP_HOST, SMTP_PASSWORD, SMTP_PORT, SMTP_USER } from "@formbricks/lib/constants";
|
||||
import { verifyUserRoleAccess } from "@formbricks/lib/organization/auth";
|
||||
import { AuthenticationError } from "@formbricks/types/errors";
|
||||
import { InvitePage, metadata } from "@/modules/setup/organization/[organizationId]/invite/page";
|
||||
|
||||
type Params = Promise<{
|
||||
organizationId: string;
|
||||
}>;
|
||||
export const metadata: Metadata = {
|
||||
title: "Invite",
|
||||
description: "Open-source Experience Management. Free & open source.",
|
||||
};
|
||||
|
||||
interface InvitePageProps {
|
||||
params: Params;
|
||||
}
|
||||
|
||||
const Page = async (props: InvitePageProps) => {
|
||||
const params = await props.params;
|
||||
const t = await getTranslations();
|
||||
const IS_SMTP_CONFIGURED = Boolean(SMTP_HOST && SMTP_PORT && SMTP_USER && SMTP_PASSWORD);
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session) throw new AuthenticationError(t("common.session_not_found"));
|
||||
|
||||
const { hasCreateOrUpdateMembersAccess } = await verifyUserRoleAccess(
|
||||
params.organizationId,
|
||||
session.user.id
|
||||
);
|
||||
|
||||
if (!hasCreateOrUpdateMembersAccess) return notFound();
|
||||
|
||||
return <InviteMembers IS_SMTP_CONFIGURED={IS_SMTP_CONFIGURED} organizationId={params.organizationId} />;
|
||||
};
|
||||
|
||||
export default Page;
|
||||
export { metadata };
|
||||
export default InvitePage;
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { createOrganizationAction } from "@/app/setup/organization/create/actions";
|
||||
import { Button } from "@/modules/ui/components/button";
|
||||
import { FormControl, FormError, FormField, FormItem, FormProvider } from "@/modules/ui/components/form";
|
||||
import { Input } from "@/modules/ui/components/input";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useState } from "react";
|
||||
import { SubmitHandler, useForm } from "react-hook-form";
|
||||
import { toast } from "react-hot-toast";
|
||||
import { z } from "zod";
|
||||
import { ZOrganization } from "@formbricks/types/organizations";
|
||||
|
||||
const ZCreateOrganizationFormSchema = ZOrganization.pick({ name: true });
|
||||
type TCreateOrganizationForm = z.infer<typeof ZCreateOrganizationFormSchema>;
|
||||
|
||||
export const CreateOrganization = () => {
|
||||
const t = useTranslations();
|
||||
const router = useRouter();
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
|
||||
const form = useForm<TCreateOrganizationForm>({
|
||||
defaultValues: {
|
||||
name: "",
|
||||
},
|
||||
mode: "onChange",
|
||||
resolver: zodResolver(ZCreateOrganizationFormSchema),
|
||||
});
|
||||
|
||||
const organizationName = form.watch("name");
|
||||
|
||||
const onSubmit: SubmitHandler<TCreateOrganizationForm> = async () => {
|
||||
try {
|
||||
setIsSubmitting(true);
|
||||
const createOrganizationResponse = await createOrganizationAction({ organizationName });
|
||||
if (createOrganizationResponse?.data) {
|
||||
router.push(`/setup/organization/${createOrganizationResponse.data.id}/invite`);
|
||||
}
|
||||
} catch (error) {
|
||||
toast.error("Some error occurred while creating organization");
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<FormProvider {...form}>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
void form.handleSubmit(onSubmit)(e);
|
||||
}}>
|
||||
<div className="flex flex-col items-center space-y-4">
|
||||
<h2 className="text-2xl font-medium">{t("setup.organization.create.title")}</h2>
|
||||
<p>{t("setup.organization.create.description")}</p>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="name"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
isInvalid={Boolean(form.formState.errors.name)}
|
||||
placeholder="e.g., Acme Inc"
|
||||
className="w-80"
|
||||
required
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
<FormError />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<Button
|
||||
type="submit"
|
||||
className="flex w-80 justify-center"
|
||||
loading={isSubmitting}
|
||||
disabled={isSubmitting || organizationName.trim() === ""}>
|
||||
{t("setup.organization.create.continue")}
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</FormProvider>
|
||||
);
|
||||
};
|
||||
@@ -1,43 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { formbricksLogout } from "@/app/lib/formbricks";
|
||||
import { DeleteAccountModal } from "@/modules/account/components/DeleteAccountModal";
|
||||
import { Alert, AlertDescription, AlertTitle } from "@/modules/ui/components/alert";
|
||||
import { Button } from "@/modules/ui/components/button";
|
||||
import { useTranslations } from "next-intl";
|
||||
import React, { useState } from "react";
|
||||
import { TUser } from "@formbricks/types/user";
|
||||
|
||||
interface RemovedFromOrganizationProps {
|
||||
isFormbricksCloud: boolean;
|
||||
user: TUser;
|
||||
}
|
||||
|
||||
export const RemovedFromOrganization = ({ user, isFormbricksCloud }: RemovedFromOrganizationProps) => {
|
||||
const t = useTranslations();
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<Alert variant="warning">
|
||||
<AlertTitle>{t("setup.organization.create.no_membership_found")}</AlertTitle>
|
||||
<AlertDescription>{t("setup.organization.create.no_membership_found_description")}</AlertDescription>
|
||||
</Alert>
|
||||
<hr className="my-4 border-slate-200" />
|
||||
<p className="text-sm">{t("setup.organization.create.delete_account_description")}</p>
|
||||
<DeleteAccountModal
|
||||
open={isModalOpen}
|
||||
setOpen={setIsModalOpen}
|
||||
user={user}
|
||||
isFormbricksCloud={isFormbricksCloud}
|
||||
formbricksLogout={formbricksLogout}
|
||||
organizationsWithSingleOwner={[]}
|
||||
/>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setIsModalOpen(true);
|
||||
}}>
|
||||
{t("setup.organization.create.delete_account")}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,47 +1,4 @@
|
||||
import { RemovedFromOrganization } from "@/app/setup/organization/create/components/removed-from-organization";
|
||||
import { authOptions } from "@/modules/auth/lib/authOptions";
|
||||
import { getIsMultiOrgEnabled } from "@/modules/ee/license-check/lib/utils";
|
||||
import { ClientLogout } from "@/modules/ui/components/client-logout";
|
||||
import { Metadata } from "next";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { getTranslations } from "next-intl/server";
|
||||
import { notFound } from "next/navigation";
|
||||
import { IS_FORMBRICKS_CLOUD } from "@formbricks/lib/constants";
|
||||
import { gethasNoOrganizations } from "@formbricks/lib/instance/service";
|
||||
import { getOrganizationsByUserId } from "@formbricks/lib/organization/service";
|
||||
import { getUser } from "@formbricks/lib/user/service";
|
||||
import { AuthenticationError } from "@formbricks/types/errors";
|
||||
import { CreateOrganization } from "./components/create-organization";
|
||||
import { CreateOrganizationPage, metadata } from "@/modules/setup/organization/create/page";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Create Organization",
|
||||
description: "Open-source Experience Management. Free & open source.",
|
||||
};
|
||||
|
||||
const Page = async () => {
|
||||
const t = await getTranslations();
|
||||
const session = await getServerSession(authOptions);
|
||||
|
||||
if (!session) throw new AuthenticationError(t("common.session_not_found"));
|
||||
|
||||
const user = await getUser(session.user.id);
|
||||
if (!user) {
|
||||
return <ClientLogout />;
|
||||
}
|
||||
|
||||
const hasNoOrganizations = await gethasNoOrganizations();
|
||||
const isMultiOrgEnabled = await getIsMultiOrgEnabled();
|
||||
const userOrganizations = await getOrganizationsByUserId(session.user.id);
|
||||
|
||||
if (hasNoOrganizations || isMultiOrgEnabled) {
|
||||
return <CreateOrganization />;
|
||||
}
|
||||
|
||||
if (userOrganizations.length === 0) {
|
||||
return <RemovedFromOrganization user={user} isFormbricksCloud={IS_FORMBRICKS_CLOUD} />;
|
||||
}
|
||||
|
||||
return notFound();
|
||||
};
|
||||
|
||||
export default Page;
|
||||
export { metadata };
|
||||
export default CreateOrganizationPage;
|
||||
|
||||
Reference in New Issue
Block a user