diff --git a/apps/console/src/app.tsx b/apps/console/src/app.tsx
index 6f5852c6..4614cc0b 100644
--- a/apps/console/src/app.tsx
+++ b/apps/console/src/app.tsx
@@ -38,6 +38,7 @@ import { Suspense } from "react";
import { FullScreenLoader } from "./components/common/FullScreenLoader";
import { OrgPage } from "./pages/projects/OrgPage";
import { useCurrentOrganization } from "./lib/hooks/useCurrentOrganization";
+import { WaitlistWrapper } from "~/pages/WaitlistWrapper";
initSuperTokens();
@@ -101,7 +102,9 @@ export function App() {
path="/onboarding"
element={
-
+
+
+
}
/>
@@ -112,7 +115,9 @@ export function App() {
element={
}>
-
+
+
+
}
@@ -131,7 +136,9 @@ export function App() {
-
+
+
+
diff --git a/apps/console/src/components/layout/OrgSubHeader.tsx b/apps/console/src/components/layout/OrgSubHeader.tsx
index f664280e..1f34f7d4 100644
--- a/apps/console/src/components/layout/OrgSubHeader.tsx
+++ b/apps/console/src/components/layout/OrgSubHeader.tsx
@@ -8,9 +8,9 @@ const isActive = (href: string) => {
export const OrgSubHeader = () => {
const navigate = useNavigate();
- const { organization } = useCurrentOrganization();
+ const { organization, waitlisted } = useCurrentOrganization();
- if (!organization) {
+ if (!organization || waitlisted) {
return;
}
diff --git a/apps/console/src/graphql/definitions/queries/organizations.tsx b/apps/console/src/graphql/definitions/queries/organizations.tsx
index b099650b..520d645e 100644
--- a/apps/console/src/graphql/definitions/queries/organizations.tsx
+++ b/apps/console/src/graphql/definitions/queries/organizations.tsx
@@ -18,6 +18,7 @@ export const GET_ORGANIZATION = graphql(/* GraphQL */ `
organization(data: $data) {
id
name
+ waitlisted
members @include(if: $includeMembers) {
id
role
diff --git a/apps/console/src/lib/hooks/useCurrentOrganization.tsx b/apps/console/src/lib/hooks/useCurrentOrganization.tsx
index 7a3502b1..8d03f965 100644
--- a/apps/console/src/lib/hooks/useCurrentOrganization.tsx
+++ b/apps/console/src/lib/hooks/useCurrentOrganization.tsx
@@ -59,5 +59,6 @@ export const useCurrentOrganization = ({
error,
currentOrgId,
selectOrg,
+ waitlisted: data?.organization?.waitlisted,
};
};
diff --git a/apps/console/src/lib/hooks/useWaitlist.ts b/apps/console/src/lib/hooks/useWaitlist.ts
new file mode 100644
index 00000000..adccc66e
--- /dev/null
+++ b/apps/console/src/lib/hooks/useWaitlist.ts
@@ -0,0 +1,14 @@
+import { useMemo } from "react";
+import { useCurrentOrganization } from "./useCurrentOrganization";
+
+export const useWaitlist = () => {
+ const { isSuccess, currentOrgId, waitlisted } = useCurrentOrganization();
+
+ const shouldRenderWaitlistNotice = useMemo(() => {
+ return isSuccess && currentOrgId && waitlisted;
+ }, [isSuccess, currentOrgId, waitlisted]);
+
+ return {
+ shouldRenderWaitlistNotice,
+ };
+};
diff --git a/apps/console/src/pages/WaitlistWrapper.tsx b/apps/console/src/pages/WaitlistWrapper.tsx
new file mode 100644
index 00000000..6cd9e91c
--- /dev/null
+++ b/apps/console/src/pages/WaitlistWrapper.tsx
@@ -0,0 +1,36 @@
+import { useGetCurrentUser } from "~/graphql/hooks/queries";
+import { useWaitlist } from "~/lib/hooks/useWaitlist";
+
+export const WaitlistWrapper = ({ children }) => {
+ const { shouldRenderWaitlistNotice } = useWaitlist();
+ const { data: currentUserData } = useGetCurrentUser();
+
+ if (shouldRenderWaitlistNotice) {
+ return (
+
+
+ You're on the waitlist!
+
+
+
Thank you for signing up for Pezzo Cloud.
+
+ You will receive an invitation at{" "}
+ {currentUserData.me.email}{" "}
+ soon.
+
+
+ Need access sooner? Email us at{" "}
+
+ hello@pezzo.ai
+
+
+
+
+ );
+ } else {
+ return children;
+ }
+};
diff --git a/apps/server/prisma/migrations/20240105073154_add_organization_waitlisted_and_default_to_false/migration.sql b/apps/server/prisma/migrations/20240105073154_add_organization_waitlisted_and_default_to_false/migration.sql
new file mode 100644
index 00000000..92c6c8e9
--- /dev/null
+++ b/apps/server/prisma/migrations/20240105073154_add_organization_waitlisted_and_default_to_false/migration.sql
@@ -0,0 +1,2 @@
+-- AlterTable
+ALTER TABLE "Organization" ADD COLUMN "waitlisted" BOOLEAN NOT NULL DEFAULT false;
diff --git a/apps/server/prisma/schema.prisma b/apps/server/prisma/schema.prisma
index 26efa639..36e5f0eb 100644
--- a/apps/server/prisma/schema.prisma
+++ b/apps/server/prisma/schema.prisma
@@ -83,6 +83,7 @@ model Organization {
apiKeys ApiKey[]
providerApiKeys ProviderApiKey[]
invitations Invitation[]
+ waitlisted Boolean @default(false)
}
model OrganizationMember {
diff --git a/apps/server/src/app/config/common-config-schema.ts b/apps/server/src/app/config/common-config-schema.ts
index e223e179..3f695f95 100644
--- a/apps/server/src/app/config/common-config-schema.ts
+++ b/apps/server/src/app/config/common-config-schema.ts
@@ -22,6 +22,7 @@ const commonConfigSchema = {
KMS_KEY_ARN: Joi.string().default(
"arn:aws:kms:us-east-1:111122223333:key/demo-master-key"
),
+ WAITLIST_ENABLED: Joi.boolean().default(false),
};
const cloudConfigSchema = {
diff --git a/apps/server/src/app/identity/organizations.service.ts b/apps/server/src/app/identity/organizations.service.ts
index 1bf30634..4edb874c 100644
--- a/apps/server/src/app/identity/organizations.service.ts
+++ b/apps/server/src/app/identity/organizations.service.ts
@@ -1,10 +1,14 @@
import { Injectable } from "@nestjs/common";
import { PrismaService } from "../prisma.service";
import { OrgRole } from "@prisma/client";
+import { ConfigService } from "@nestjs/config";
@Injectable()
export class OrganizationsService {
- constructor(private readonly prisma: PrismaService) {}
+ constructor(
+ private readonly prisma: PrismaService,
+ private config: ConfigService
+ ) {}
async getById(id: string) {
return await this.prisma.organization.findUnique({ where: { id } });
@@ -108,9 +112,12 @@ export class OrganizationsService {
}
async createOrg(name: string, creatorUserId: string) {
+ const waitlisted = this.config.get("WAITLIST_ENABLED");
+
return await this.prisma.organization.create({
data: {
name,
+ waitlisted,
members: {
create: {
userId: creatorUserId,
diff --git a/apps/server/src/app/identity/users.service.ts b/apps/server/src/app/identity/users.service.ts
index b4bd0bfb..f4e759dc 100644
--- a/apps/server/src/app/identity/users.service.ts
+++ b/apps/server/src/app/identity/users.service.ts
@@ -6,6 +6,7 @@ import { ExtendedUser } from "./models/extended-user.model";
import UserMetadata from "supertokens-node/recipe/usermetadata";
import { SupertokensMetadata } from "../auth/auth.types";
import { randomBytes } from "crypto";
+import { ConfigService } from "@nestjs/config";
export type UserWithOrgMemberships = User & {
orgMemberships: OrganizationMember[];
@@ -13,7 +14,10 @@ export type UserWithOrgMemberships = User & {
@Injectable()
export class UsersService {
- constructor(private readonly prisma: PrismaService) {}
+ constructor(
+ private readonly prisma: PrismaService,
+ private config: ConfigService
+ ) {}
async createUser(
userCreateRequest: UserCreateRequest
@@ -28,9 +32,12 @@ export class UsersService {
},
});
+ const waitlisted = this.config.get("WAITLIST_ENABLED");
+
const organization = await this.prisma.organization.create({
data: {
name: `${userCreateRequest.name}'s Organization`,
+ waitlisted,
members: {
create: {
userId: userCreateRequest.id,