diff --git a/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/users/page-client.tsx b/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/users/page-client.tsx index 0ea31b814e..c2f46cb409 100644 --- a/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/users/page-client.tsx +++ b/apps/dashboard/src/app/(main)/(protected)/projects/[projectId]/users/page-client.tsx @@ -1,18 +1,62 @@ "use client"; import { UserTable } from "@/components/data-table/user-table"; +import { FormDialog } from "@/components/form-dialog"; +import { InputField, SwitchField } from "@/components/form-fields"; import { StyledLink } from "@/components/link"; -import { Alert } from "@stackframe/stack-ui"; +import { Alert, Button } from "@stackframe/stack-ui"; +import * as yup from "yup"; import { PageLayout } from "../page-layout"; import { useAdminApp } from "../use-admin-app"; +function CreateDialog(props: { + open?: boolean, + onOpenChange?: (open: boolean) => void, + trigger?: React.ReactNode, +}) { + const adminApp = useAdminApp(); + const formSchema = yup.object({ + displayName: yup.string().optional(), + primaryEmail: yup.string().email().required(), + primaryEmailVerified: yup.boolean().optional(), + password: yup.string().required(), + }); + + return { + await adminApp.createUser(values); + }} + cancelButton + render={(form) => ( + <> + + +
+
+ +
+
+ +
+
+ + + + )} + />; +} + export default function PageClient() { const stackAdminApp = useAdminApp(); const allUsers = stackAdminApp.useUsers(); return ( - + Create User} />}> {allUsers.length > 0 ? null : ( Congratulations on starting your project! Check the documentation to add your first users. diff --git a/packages/stack-shared/src/interface/serverInterface.ts b/packages/stack-shared/src/interface/serverInterface.ts index 5fd86eb499..f20379d659 100644 --- a/packages/stack-shared/src/interface/serverInterface.ts +++ b/packages/stack-shared/src/interface/serverInterface.ts @@ -72,6 +72,21 @@ export class StackServerInterface extends StackClientInterface { } } + async createServerUser(data: UsersCrud['Server']['Create']): Promise { + const response = await this.sendServerRequest( + "/users", + { + method: "POST", + headers: { + "content-type": "application/json", + }, + body: JSON.stringify(data), + }, + null, + ); + return await response.json(); + } + async getServerUserByToken(session: InternalSession): Promise { const responseOrError = await this.sendServerRequestAndCatchKnownError( "/users/me", diff --git a/packages/stack/src/lib/stack-app.ts b/packages/stack/src/lib/stack-app.ts index aa71f6cae3..65bf9f5e4b 100644 --- a/packages/stack/src/lib/stack-app.ts +++ b/packages/stack/src/lib/stack-app.ts @@ -1568,6 +1568,12 @@ class _StackServerAppImpl { + const crud = await this._interface.createServerUser(serverUserCreateOptionsToCrud(options)); + await this._refreshUsers(); + return this._serverUserFromCrud(crud); + } + async getUser(options: GetUserOptions & { or: 'redirect' }): Promise>; async getUser(options: GetUserOptions & { or: 'throw' }): Promise>; @@ -2236,6 +2242,23 @@ function serverUserUpdateOptionsToCrud(options: ServerUserUpdateOptions): Curren } +type ServerUserCreateOptions = { + primaryEmail: string, + password: string, + displayName?: string, + primaryEmailVerified?: boolean, +} +function serverUserCreateOptionsToCrud(options: ServerUserCreateOptions): UsersCrud["Server"]["Create"] { + return { + primary_email: options.primaryEmail, + password: options.password, + primary_email_auth_enabled: true, + display_name: options.displayName, + primary_email_verified: options.primaryEmailVerified, + }; +} + + type _______________PROJECT_______________ = never; // this is a marker for VSCode's outline view export type Project = { @@ -2616,6 +2639,8 @@ export type StackServerApp | null>, + createUser(options: ServerUserCreateOptions): Promise, + useUser(options: GetUserOptions & { or: 'redirect' }): ProjectCurrentServerUser, useUser(options: GetUserOptions & { or: 'throw' }): ProjectCurrentServerUser, useUser(options?: GetUserOptions): ProjectCurrentServerUser | null,