쇼핑몰 구현 프로젝트

[쇼핑몰 구현 프로젝트] 05. 회원가입/로그인

binning 2024. 6. 23. 15:14

① Frontend

- Context를 이용하여 App.js에서 모든 Route에 로그인 관련 정보를 제공하고 LocalStorage에 저장

export const AuthContext = createContext({
  isLoggedIn: false,
  isAdmin: false,
  switchAdmin: () => {},
  login: () => {},
  logout: () => {}
});
  const getLoginData = () => {
    const data = JSON.parse(localStorage.getItem("login"));
    if(!data) return false;
    return data;
  };
  
  const getAdminData = () => {
    const data = JSON.parse(localStorage.getItem("admin"));
    if(!data) return false;
    return data;
  };
  
  const getUserId = () => {
    const data = JSON.parse(localStorage.getItem("userId"));
    if(!data) return "";
    return data;
  };
  
  const [isLoggedIn, setIsLoggedIn] = useState(getLoginData);
  const [isAdmin, setIsAdmin] = useState(getAdminData);
  const [userId, setUserId] = useState(getUserId);
  
  const login = useCallback((uid) => {
    setIsLoggedIn(true);
    setUserId(uid);
    window.location.href = "/";
  }, []);

  const logout = useCallback(() => {
    setIsLoggedIn(false);
    setIsAdmin(false);
    setUserId("");
    window.location.href = "/";
  }, []);
  
  const switchAdmin = useCallback(() => {
    setIsAdmin(true);
  }, []);
  
  useEffect(() => {
    localStorage.setItem("login", JSON.stringify(isLoggedIn));
  }, [isLoggedIn]);
  
  useEffect(() => {
    localStorage.setItem("admin", JSON.stringify(isAdmin));
  }, [isAdmin]);
  
  useEffect(() => {
    localStorage.setItem("userId", JSON.stringify(userId));
  }, [userId]);

 

② Backend

- Controller

const signup = async (req, res, next) => {
  const errors = validationResult(req);
  if (!errors.isEmpty()) {
    const error = new Error('Invalid inputs');
    error.code = 422;
    return next(error);
  }
  const { name, email, password, repeatpassword, address, phonenumber } = req.body;

  let existingUser
  try {
    existingUser = await User.findOne({ email: email })
  } catch (err) {
    const error = new Error('something went wrong');
    error.code = 500;
    return next(error);
  }
  
  if (existingUser) {
    const error = new Error('already existing email');
    error.code = 401;
    return next(error);
  }
  
  let hashedPassword;
  try {
    hashedPassword = await bcrypt.hash(password, 12);
  } catch(err) {
    const error = new Error('something went wrong');
    error.code = 500;
    return next(error);
  }
  
  const createdUser = new User({
    name,
    email,
    password: hashedPassword,
    address,
    phonenumber,
    admin: false,
    cart: [],
    review: []
  });

  try {
    await createdUser.save();
  } catch (err) {
    const error = new Error('something went wrong');
    error.code = 500;
    return next(error);
  }

  res.status(201).json({user: createdUser.toObject({ getters: true })});
};

const login = async (req, res, next) => {
  const { email, password } = req.body;

  let existingUser;

  try {
    existingUser = await User.findOne({ email: email })
  } catch (err) {
    const error = new Error('something went wrong');
    error.code = 500;
    return next(error);
  }

  if (!existingUser) {
    const error = new Error('can not find user');
    error.code = 404;
    return next(error);
  }

  let isValidPassword = false;
  try {
    isValidPassword = await bcrypt.compare(password, existingUser.password);
  } catch(err) {
    const error = new Error('something went wrong');
    error.code = 500;
    return next(error);
  }
  
  if(!isValidPassword) {
    const error = new Error('Invalid password');
    error.code = 401;
    return next(error);
  }
  
  res.status(200).json({user: existingUser.toObject({ getters: true })});
};