diff --git a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/users/page-client.tsx b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/users/page-client.tsx index 45f0e5233..094428379 100644 --- a/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/users/page-client.tsx +++ b/packages/stack-server/src/app/(main)/(protected)/projects/[projectId]/users/page-client.tsx @@ -1,24 +1,108 @@ "use client"; - +import React from "react"; +import * as yup from "yup"; import { useAdminApp } from "../use-admin-app"; import { PageLayout } from "../page-layout"; import { Alert } from "@/components/ui/alert"; import { StyledLink } from "@/components/link"; import { UserTable } from "@/components/data-table/user-table"; +import { Button } from "@/components/ui/button" +import { SmartFormDialog } from "@/components/form-dialog"; +import { ActionDialog } from "@/components/action-dialog"; +import Typography from "@/components/ui/typography"; + +type CreateDialogProps = { + open: boolean; + onOpenChange: (open: boolean) => void; + setShowNotifyPasswordDialog: React.Dispatch>; + setcurrentUserPassword: React.Dispatch>; + +}; export default function PageClient() { const stackAdminApp = useAdminApp(); const allUsers = stackAdminApp.useServerUsers(); + const [addUserOpen, setAddUserOpen] = React.useState(false); + const [showNotifyPasswordDialog, setShowNotifyPasswordDialog] = React.useState(false); + const [currentUserPassword, setcurrentUserPassword] = React.useState(""); + + + const handlePasswordNotificationClose = async () => { + setShowNotifyPasswordDialog(false); + }; return ( - + setAddUserOpen(true)}> + Create users + + }> {allUsers.length > 0 ? null : ( Congratulations on starting your project! Check the documentation to add your first users. )} + + +
+ + Please change your password soon to ensure account security. + + + Your Current Password: {currentUserPassword} + +
+
); } + +function CreateDialog({ open, onOpenChange, setShowNotifyPasswordDialog,setcurrentUserPassword }: CreateDialogProps) { + const stackAdminApp = useAdminApp(); + + const formSchema = yup.object({ + email: yup.string().required().label("Email"), + }); + + const handleCreateUser = async (values: { email: string }) => { + const res= await stackAdminApp.createUserWithCredential({ + email: values.email, + }); + console.log(res) + if(res){ + + setcurrentUserPassword(res) + setShowNotifyPasswordDialog(true); + } + + }; + + return ( + + ); +} \ No newline at end of file diff --git a/packages/stack-shared/src/interface/clientInterface.ts b/packages/stack-shared/src/interface/clientInterface.ts index 587f391c2..1c9b4791d 100644 --- a/packages/stack-shared/src/interface/clientInterface.ts +++ b/packages/stack-shared/src/interface/clientInterface.ts @@ -640,36 +640,44 @@ export class StackClientInterface { async signUpWithCredential( email: string, - password: string, + password: string | null, emailVerificationRedirectUrl: string, - tokenStore: TokenStore, + tokenStore: TokenStore | null, ): Promise { + const requestBody = { + email, + password, + emailVerificationRedirectUrl, + }; + + const headers = { + "Content-Type": "application/json", + }; + + const requestOptions = { + headers, + method: "POST", + body: JSON.stringify(requestBody), + }; + const res = await this.sendClientRequestAndCatchKnownError( "/auth/signup", - { - headers: { - "Content-Type": "application/json" - }, - method: "POST", - body: JSON.stringify({ - email, - password, - emailVerificationRedirectUrl, - }), - }, + requestOptions, tokenStore, [KnownErrors.UserEmailAlreadyExists, KnownErrors.PasswordRequirementsNotMet] ); - + if (res.status === "error") { return res.error; } - - const result = await res.data.json(); - tokenStore.set({ - accessToken: result.accessToken, - refreshToken: result.refreshToken, - }); + + if (tokenStore) { + const result = await res.data.json(); + tokenStore.set({ + accessToken: result.accessToken, + refreshToken: result.refreshToken, + }); + } } async signInWithMagicLink(code: string, tokenStore: TokenStore): Promise { diff --git a/packages/stack/src/lib/stack-app.ts b/packages/stack/src/lib/stack-app.ts index b4611dcd9..d4879c757 100644 --- a/packages/stack/src/lib/stack-app.ts +++ b/packages/stack/src/lib/stack-app.ts @@ -21,6 +21,7 @@ import { EmailTemplateType, ServerPermissionDefinitionCustomizableJson, ServerPe import { EmailTemplateCrud, ListEmailTemplatesCrud } from "@stackframe/stack-shared/dist/interface/crud/email-templates"; import { scrambleDuringCompileTime } from "@stackframe/stack-shared/dist/utils/compile-time"; import { isReactServer } from "@stackframe/stack-sc"; +import { generateSecureRandomString } from "@stackframe/stack-shared/dist/utils/crypto"; import * as cookie from "cookie"; // NextNavigation.useRouter does not exist in react-server environments and some bundler try to be helpful and throw a warning. Ignore the warning. @@ -778,6 +779,23 @@ class _StackClientAppImpl { + const emailVerificationRedirectUrl = constructRedirectUrl(this.urls.emailVerification); + const password =generateSecureRandomString() + const errorCode = await this._interface.signUpWithCredential( + options.email, + password, + emailVerificationRedirectUrl, + null, + ); + if (!errorCode) { + return password + } + return errorCode; + } async signUpWithCredential(options: { email: string, @@ -1759,6 +1777,7 @@ export type StackClientApp, signInWithCredential(options: { email: string, password: string }): Promise, + createUserWithCredential(options: { email: string }): Promise, signUpWithCredential(options: { email: string, password: string }): Promise, callOAuthCallback(): Promise, sendForgotPasswordEmail(email: string): Promise,