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..498594d67 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,110 @@ "use client"; - +import React, { useState } 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"; +import { runAsynchronously } from "@stackframe/stack-shared/dist/utils/promises"; +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. + + Congratulations on starting your project! Check the{" "} + + documentation + {" "} + to add your first users. )} + + runAsynchronously(handlePasswordNotificationClose())} + > +
+ + 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, + }); + if (typeof res === 'string') { + setCurrentUserPassword(res); + setShowNotifyPasswordDialog(true); + } else { + console.error('Unexpected response:', res); + } + + }; + + 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 85dab47b2..7db7fddcf 100644 --- a/packages/stack-shared/src/interface/clientInterface.ts +++ b/packages/stack-shared/src/interface/clientInterface.ts @@ -615,9 +615,9 @@ export class StackClientInterface { async signUpWithCredential( email: string, - password: string, + password: string | null, emailVerificationRedirectUrl: string, - session: InternalSession, + session: InternalSession | null, ): Promise { const res = await this.sendClientRequestAndCatchKnownError( "/auth/signup", diff --git a/packages/stack/src/lib/stack-app.ts b/packages/stack/src/lib/stack-app.ts index 1781675ee..8c97df850 100644 --- a/packages/stack/src/lib/stack-app.ts +++ b/packages/stack/src/lib/stack-app.ts @@ -25,6 +25,7 @@ import * as cookie from "cookie"; import { InternalSession } from "@stackframe/stack-shared/dist/sessions"; import { useTrigger } from "@stackframe/stack-shared/dist/hooks/use-trigger"; import { mergeScopeStrings } from "@stackframe/stack-shared/dist/utils/strings"; +import { generateSecureRandomString } from "@stackframe/stack-shared/dist/utils/crypto"; // NextNavigation.useRouter does not exist in react-server environments and some bundlers try to be helpful and throw a warning. Ignore the warning. @@ -1019,6 +1020,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, password: string, @@ -2087,6 +2105,7 @@ export type StackClientApp, signInWithCredential(options: { email: string, password: string }): Promise, signUpWithCredential(options: { email: string, password: string }): Promise, + createUserWithCredential(options: { email: string }): Promise, callOAuthCallback(): Promise, sendForgotPasswordEmail(email: string): Promise, sendMagicLinkEmail(email: string): Promise,