File size: 2,917 Bytes
6a30288
 
 
 
 
 
 
 
 
 
 
f3845d0
6a30288
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f3845d0
 
 
 
 
6a30288
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f3845d0
6a30288
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f3845d0
6a30288
 
 
f3845d0
6a30288
 
 
 
 
 
 
 
 
 
 
f3845d0
6a30288
 
 
 
 
 
 
 
 
 
 
 
 
f3845d0
6a30288
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
"use server";

import { db } from "@/db/db";
import { users } from "@/db/schema";
import {
  createSession,
  destroySession,
  getCurrentUser,
  hashPassword,
  verifyPassword,
} from "@/lib/auth";
import { ensureDemoAccountSeed } from "@/lib/demo-auth-seed";
import { eq } from "drizzle-orm";
import { revalidatePath } from "next/cache";
import { z } from "zod";

const signInSchema = z.object({
  email: z.string().trim().email(),
  password: z.string().min(8),
});

const signUpSchema = z.object({
  name: z.string().trim().min(2).max(120),
  email: z.string().trim().email(),
  password: z.string().min(8).max(128),
});

export async function signIn(values: { email: string; password: string }) {
  try {
    const parsed = signInSchema.parse(values);
    const email = parsed.email.toLowerCase();
    const { password } = parsed;

    await ensureDemoAccountSeed(email);

    const [user] = await db.select().from(users).where(eq(users.email, email));

    if (!user || !verifyPassword(password, user.passwordHash)) {
      return {
        error: true,
        message: "Sign in failed",
        action: "Check your email and password, then try again.",
      };
    }

    await createSession(user.id);
    revalidatePath("/");

    return {
      error: false,
      message: "Signed in",
      action: "Welcome back to ShopSmart.",
    };
  } catch (error) {
    console.error("Sign in failed.", error);

    return {
      error: true,
      message: "Sign in failed",
      action: "Please use a valid email and password.",
    };
  }
}

export async function signUp(values: {
  name: string;
  email: string;
  password: string;
}) {
  try {
    const input = signUpSchema.parse(values);
    const email = input.email.toLowerCase();
    const [existingUser] = await db
      .select({ id: users.id })
      .from(users)
      .where(eq(users.email, email));

    if (existingUser) {
      return {
        error: true,
        message: "Account already exists",
        action: "Use a different email or sign in instead.",
      };
    }

    const result = await db.insert(users).values({
      name: input.name,
      email,
      passwordHash: hashPassword(input.password),
      createdAt: Math.floor(Date.now() / 1000),
    });

    await createSession(result[0].insertId);
    revalidatePath("/");

    return {
      error: false,
      message: "Account created",
      action: "You're ready to start shopping.",
    };
  } catch (error) {
    console.error("Sign up failed.", error);

    return {
      error: true,
      message: "Could not create account",
      action: "Please review your details and try again.",
    };
  }
}

export async function signOut() {
  await destroySession();
  revalidatePath("/");

  return {
    error: false,
    message: "Signed out",
    action: "See you again soon.",
  };
}

export async function getCurrentAccount() {
  return await getCurrentUser();
}