Skip to content

Commit

Permalink
Persist form values for login
Browse files Browse the repository at this point in the history
  • Loading branch information
leerob committed Dec 15, 2024
1 parent 06b7fab commit d2d1a38
Show file tree
Hide file tree
Showing 4 changed files with 373 additions and 326 deletions.
75 changes: 49 additions & 26 deletions app/(login)/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ async function logActivity(
teamId: number | null | undefined,
userId: number,
type: ActivityType,
ipAddress?: string
ipAddress?: string,
) {
if (teamId === null || teamId === undefined) {
return;
Expand Down Expand Up @@ -64,18 +64,26 @@ export const signIn = validatedAction(signInSchema, async (data, formData) => {
.limit(1);

if (userWithTeam.length === 0) {
return { error: 'Invalid email or password. Please try again.' };
return {
error: 'Invalid email or password. Please try again.',
email,
password,
};
}

const { user: foundUser, team: foundTeam } = userWithTeam[0];

const isPasswordValid = await comparePasswords(
password,
foundUser.passwordHash
foundUser.passwordHash,
);

if (!isPasswordValid) {
return { error: 'Invalid email or password. Please try again.' };
return {
error: 'Invalid email or password. Please try again.',
email,
password,
};
}

await Promise.all([
Expand Down Expand Up @@ -108,7 +116,11 @@ export const signUp = validatedAction(signUpSchema, async (data, formData) => {
.limit(1);

if (existingUser.length > 0) {
return { error: 'Failed to create user. Please try again.' };
return {
error: 'Failed to create user. Please try again.',
email,
password,
};
}

const passwordHash = await hashPassword(password);
Expand All @@ -122,7 +134,11 @@ export const signUp = validatedAction(signUpSchema, async (data, formData) => {
const [createdUser] = await db.insert(users).values(newUser).returning();

if (!createdUser) {
return { error: 'Failed to create user. Please try again.' };
return {
error: 'Failed to create user. Please try again.',
email,
password,
};
}

let teamId: number;
Expand All @@ -138,8 +154,8 @@ export const signUp = validatedAction(signUpSchema, async (data, formData) => {
and(
eq(invitations.id, parseInt(inviteId)),
eq(invitations.email, email),
eq(invitations.status, 'pending')
)
eq(invitations.status, 'pending'),
),
)
.limit(1);

Expand All @@ -160,7 +176,7 @@ export const signUp = validatedAction(signUpSchema, async (data, formData) => {
.where(eq(teams.id, teamId))
.limit(1);
} else {
return { error: 'Invalid or expired invitation.' };
return { error: 'Invalid or expired invitation.', email, password };
}
} else {
// Create a new team if there's no invitation
Expand All @@ -171,7 +187,11 @@ export const signUp = validatedAction(signUpSchema, async (data, formData) => {
[createdTeam] = await db.insert(teams).values(newTeam).returning();

if (!createdTeam) {
return { error: 'Failed to create team. Please try again.' };
return {
error: 'Failed to create team. Please try again.',
email,
password,
};
}

teamId = createdTeam.id;
Expand Down Expand Up @@ -226,7 +246,7 @@ export const updatePassword = validatedActionWithUser(

const isPasswordValid = await comparePasswords(
currentPassword,
user.passwordHash
user.passwordHash,
);

if (!isPasswordValid) {
Expand All @@ -251,7 +271,7 @@ export const updatePassword = validatedActionWithUser(
]);

return { success: 'Password updated successfully.' };
}
},
);

const deleteAccountSchema = z.object({
Expand All @@ -273,7 +293,7 @@ export const deleteAccount = validatedActionWithUser(
await logActivity(
userWithTeam?.teamId,
user.id,
ActivityType.DELETE_ACCOUNT
ActivityType.DELETE_ACCOUNT,
);

// Soft delete
Expand All @@ -291,14 +311,14 @@ export const deleteAccount = validatedActionWithUser(
.where(
and(
eq(teamMembers.userId, user.id),
eq(teamMembers.teamId, userWithTeam.teamId)
)
eq(teamMembers.teamId, userWithTeam.teamId),
),
);
}

(await cookies()).delete('session');
redirect('/sign-in');
}
},
);

const updateAccountSchema = z.object({
Expand All @@ -318,7 +338,7 @@ export const updateAccount = validatedActionWithUser(
]);

return { success: 'Account updated successfully.' };
}
},
);

const removeTeamMemberSchema = z.object({
Expand All @@ -340,18 +360,18 @@ export const removeTeamMember = validatedActionWithUser(
.where(
and(
eq(teamMembers.id, memberId),
eq(teamMembers.teamId, userWithTeam.teamId)
)
eq(teamMembers.teamId, userWithTeam.teamId),
),
);

await logActivity(
userWithTeam.teamId,
user.id,
ActivityType.REMOVE_TEAM_MEMBER
ActivityType.REMOVE_TEAM_MEMBER,
);

return { success: 'Team member removed successfully' };
}
},
);

const inviteTeamMemberSchema = z.object({
Expand All @@ -374,7 +394,10 @@ export const inviteTeamMember = validatedActionWithUser(
.from(users)
.leftJoin(teamMembers, eq(users.id, teamMembers.userId))
.where(
and(eq(users.email, email), eq(teamMembers.teamId, userWithTeam.teamId))
and(
eq(users.email, email),
eq(teamMembers.teamId, userWithTeam.teamId),
),
)
.limit(1);

Expand All @@ -390,8 +413,8 @@ export const inviteTeamMember = validatedActionWithUser(
and(
eq(invitations.email, email),
eq(invitations.teamId, userWithTeam.teamId),
eq(invitations.status, 'pending')
)
eq(invitations.status, 'pending'),
),
)
.limit(1);

Expand All @@ -411,12 +434,12 @@ export const inviteTeamMember = validatedActionWithUser(
await logActivity(
userWithTeam.teamId,
user.id,
ActivityType.INVITE_TEAM_MEMBER
ActivityType.INVITE_TEAM_MEMBER,
);

// TODO: Send invitation email and include ?inviteId={id} to sign-up URL
// await sendInvitationEmail(email, userWithTeam.team.name, role)

return { success: 'Invitation sent successfully' };
}
},
);
4 changes: 3 additions & 1 deletion app/(login)/login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export function Login({ mode = 'signin' }: { mode?: 'signin' | 'signup' }) {
const inviteId = searchParams.get('inviteId');
const [state, formAction, pending] = useActionState<ActionState, FormData>(
mode === 'signin' ? signIn : signUp,
{ error: '' }
{ error: '' },
);

return (
Expand Down Expand Up @@ -51,6 +51,7 @@ export function Login({ mode = 'signin' }: { mode?: 'signin' | 'signup' }) {
name="email"
type="email"
autoComplete="email"
defaultValue={state.email}
required
maxLength={50}
className="appearance-none rounded-full relative block w-full px-3 py-2 border border-gray-300 placeholder-gray-500 text-gray-900 focus:outline-none focus:ring-orange-500 focus:border-orange-500 focus:z-10 sm:text-sm"
Expand All @@ -74,6 +75,7 @@ export function Login({ mode = 'signin' }: { mode?: 'signin' | 'signup' }) {
autoComplete={
mode === 'signin' ? 'current-password' : 'new-password'
}
defaultValue={state.password}
required
minLength={8}
maxLength={100}
Expand Down
24 changes: 12 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,28 @@
"db:studio": "drizzle-kit studio"
},
"dependencies": {
"@radix-ui/react-avatar": "^1.1.1",
"@radix-ui/react-dropdown-menu": "^2.1.2",
"@radix-ui/react-avatar": "^1.1.2",
"@radix-ui/react-dropdown-menu": "^2.1.3",
"@radix-ui/react-icons": "^1.3.2",
"@radix-ui/react-label": "^2.1.0",
"@radix-ui/react-radio-group": "^1.2.1",
"@radix-ui/react-scroll-area": "^1.2.1",
"@radix-ui/react-separator": "^1.1.0",
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-label": "^2.1.1",
"@radix-ui/react-radio-group": "^1.2.2",
"@radix-ui/react-scroll-area": "^1.2.2",
"@radix-ui/react-separator": "^1.1.1",
"@radix-ui/react-slot": "^1.1.1",
"@types/bcryptjs": "^2.4.6",
"@types/node": "^22.10.1",
"@types/node": "^22.10.2",
"@types/react": "19.0.1",
"@types/react-dom": "19.0.2",
"autoprefixer": "^10.4.20",
"bcryptjs": "^2.4.3",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"dotenv": "^16.4.7",
"drizzle-kit": "^0.30.0",
"drizzle-orm": "^0.38.0",
"drizzle-kit": "^0.30.1",
"drizzle-orm": "^0.38.2",
"jose": "^5.9.6",
"lucide-react": "^0.468.0",
"next": "15.0.4-canary.48",
"next": "15.1.1-canary.5",
"postcss": "^8.4.49",
"postgres": "^3.4.5",
"react": "19.0.0",
Expand All @@ -44,6 +44,6 @@
"tailwindcss-animate": "^1.0.7",
"tailwindcss-react-aria-components": "1.2.0",
"typescript": "^5.7.2",
"zod": "^3.23.8"
"zod": "^3.24.1"
}
}
Loading

0 comments on commit d2d1a38

Please sign in to comment.