ewhk9887/korean_code_reviews_from_github huggingface dataset:
@@ -0,0 +1,79 @@
+import React, { useState } from "react";
+import { useNavigate } from 'react-router-dom';
+import "../../../style/reset.scss";
+import "../../../style/common.scss";
+import "../../../style/variables.scss"
+import "./Login.scss";
+
+
+const Login = () => {
+  
+    const [userInfo, setUserInfo] = useState({
+      userId:"아이디",
+      userPw:"패스워드",
+    });
+  const navigate = useNavigate();
+  const goToMain = () => {
+    fetch("http://10.58.52.144:3000/users/signup", {
+      method: "POST",
+      headers: {
+        "Content-Type": "application/json",
+      },
+      body: JSON.stringify({
+        email: userInfo.userId,
+        password: userInfo.userPw,
+      }),
+    })
+    .then((response) => response.json())
+    .then((result) => {
+      if(result.accessToken) {
+        localStorage.setItem("token", result.accessToken);
+        navigate("/jinheekim-main");
+      }
+      if(result.message === "invalid password") {
+        alert ("비밀번호 틀렸음");
+      };
+      if(result.message === "specified user does not exist") {
+        alert ("아이디 틀렸음");
+      }
+    })
+    
+  }
+
+  const handleInput = (event) => {
+    const {value, id} = event.target;
+    setUserInfo({...userInfo, [id]:value});
+  };
+
+  const isValue = userInfo.userId.includes('@') && userInfo.userPw.length >= 5;
+
+  return (
+    <div className="login">
+      <div className="box">
+        <h1>Westagram</h1>
+        <div className="inputTxt">
+          <input
+            id="userId"
+            onChange={handleInput}
+            type="text"
+            className="id"
+            placeholder="전화번호, 사용자 이름 또는 이메일"
+            />
+          <input
+            id="userPw"
+            onChange={handleInput}
+            type="password"
+            className="pw"
+            placeholder="비밀번호"
+            />
+          <button type="button" onClick={goToMain} className={isValue ? "abled-button" : 'disabled-button'} disabled={!isValue}>로그인</button>
+          <div className="findPw">
+            <a href="#">비밀번호를 잊으셨나요?</a>
+          </div>
+        </div>                                                                                                                                      
+      </div>
+    </div>
+  );
+};
+
+export default Login;
\ No newline at end of file

리뷰: 👍 좋습니다! 계속해서 이렇게 세션내용 바로바로 적용해주면서 본인의 지식으로 가져가주시면 좋겠습니다!
@@ -0,0 +1,79 @@
+import React, { useState } from "react";
+import { useNavigate } from 'react-router-dom';
+import "../../../style/reset.scss";
+import "../../../style/common.scss";
+import "../../../style/variables.scss"
+import "./Login.scss";
+
+
+const Login = () => {
+  
+    const [userInfo, setUserInfo] = useState({
+      userId:"아이디",
+      userPw:"패스워드",
+    });
+  const navigate = useNavigate();
+  const goToMain = () => {
+    fetch("http://10.58.52.144:3000/users/signup", {
+      method: "POST",
+      headers: {
+        "Content-Type": "application/json",
+      },
+      body: JSON.stringify({
+        email: userInfo.userId,
+        password: userInfo.userPw,
+      }),
+    })
+    .then((response) => response.json())
+    .then((result) => {
+      if(result.accessToken) {
+        localStorage.setItem("token", result.accessToken);
+        navigate("/jinheekim-main");
+      }
+      if(result.message === "invalid password") {
+        alert ("비밀번호 틀렸음");
+      };
+      if(result.message === "specified user does not exist") {
+        alert ("아이디 틀렸음");
+      }
+    })
+    
+  }
+
+  const handleInput = (event) => {
+    const {value, id} = event.target;
+    setUserInfo({...userInfo, [id]:value});
+  };
+
+  const isValue = userInfo.userId.includes('@') && userInfo.userPw.length >= 5;
+
+  return (
+    <div className="login">
+      <div className="box">
+        <h1>Westagram</h1>
+        <div className="inputTxt">
+          <input
+            id="userId"
+            onChange={handleInput}
+            type="text"
+            className="id"
+            placeholder="전화번호, 사용자 이름 또는 이메일"
+            />
+          <input
+            id="userPw"
+            onChange={handleInput}
+            type="password"
+            className="pw"
+            placeholder="비밀번호"
+            />
+          <button type="button" onClick={goToMain} className={isValue ? "abled-button" : 'disabled-button'} disabled={!isValue}>로그인</button>
+          <div className="findPw">
+            <a href="#">비밀번호를 잊으셨나요?</a>
+          </div>
+        </div>                                                                                                                                      
+      </div>
+    </div>
+  );
+};
+
+export default Login;
\ No newline at end of file

리뷰: 코드에 주석이 많습니다!
추후에 다시 학습할 용도로 남겨놓은 주석이라면, 해당내용은 따로 블로그나 개인 메모에 작성을 해 주시고, 코드를 github을 통해 올려주실때는 불필요한 코드를 최대한 줄여주세요!
@@ -0,0 +1,79 @@
+import React, { useState } from "react";
+import { useNavigate } from 'react-router-dom';
+import "../../../style/reset.scss";
+import "../../../style/common.scss";
+import "../../../style/variables.scss"
+import "./Login.scss";
+
+
+const Login = () => {
+  
+    const [userInfo, setUserInfo] = useState({
+      userId:"아이디",
+      userPw:"패스워드",
+    });
+  const navigate = useNavigate();
+  const goToMain = () => {
+    fetch("http://10.58.52.144:3000/users/signup", {
+      method: "POST",
+      headers: {
+        "Content-Type": "application/json",
+      },
+      body: JSON.stringify({
+        email: userInfo.userId,
+        password: userInfo.userPw,
+      }),
+    })
+    .then((response) => response.json())
+    .then((result) => {
+      if(result.accessToken) {
+        localStorage.setItem("token", result.accessToken);
+        navigate("/jinheekim-main");
+      }
+      if(result.message === "invalid password") {
+        alert ("비밀번호 틀렸음");
+      };
+      if(result.message === "specified user does not exist") {
+        alert ("아이디 틀렸음");
+      }
+    })
+    
+  }
+
+  const handleInput = (event) => {
+    const {value, id} = event.target;
+    setUserInfo({...userInfo, [id]:value});
+  };
+
+  const isValue = userInfo.userId.includes('@') && userInfo.userPw.length >= 5;
+
+  return (
+    <div className="login">
+      <div className="box">
+        <h1>Westagram</h1>
+        <div className="inputTxt">
+          <input
+            id="userId"
+            onChange={handleInput}
+            type="text"
+            className="id"
+            placeholder="전화번호, 사용자 이름 또는 이메일"
+            />
+          <input
+            id="userPw"
+            onChange={handleInput}
+            type="password"
+            className="pw"
+            placeholder="비밀번호"
+            />
+          <button type="button" onClick={goToMain} className={isValue ? "abled-button" : 'disabled-button'} disabled={!isValue}>로그인</button>
+          <div className="findPw">
+            <a href="#">비밀번호를 잊으셨나요?</a>
+          </div>
+        </div>                                                                                                                                      
+      </div>
+    </div>
+  );
+};
+
+export default Login;
\ No newline at end of file

리뷰: ```suggestion
        <div className="inputTxt">
```
위 코드 처럼 js의 기본 컨벤션은 `camelCase`입니다! className을 작성할 때에도 신경써주셔야합니다!
@@ -0,0 +1,79 @@
+import React, { useState } from "react";
+import { useNavigate } from 'react-router-dom';
+import "../../../style/reset.scss";
+import "../../../style/common.scss";
+import "../../../style/variables.scss"
+import "./Login.scss";
+
+
+const Login = () => {
+  
+    const [userInfo, setUserInfo] = useState({
+      userId:"아이디",
+      userPw:"패스워드",
+    });
+  const navigate = useNavigate();
+  const goToMain = () => {
+    fetch("http://10.58.52.144:3000/users/signup", {
+      method: "POST",
+      headers: {
+        "Content-Type": "application/json",
+      },
+      body: JSON.stringify({
+        email: userInfo.userId,
+        password: userInfo.userPw,
+      }),
+    })
+    .then((response) => response.json())
+    .then((result) => {
+      if(result.accessToken) {
+        localStorage.setItem("token", result.accessToken);
+        navigate("/jinheekim-main");
+      }
+      if(result.message === "invalid password") {
+        alert ("비밀번호 틀렸음");
+      };
+      if(result.message === "specified user does not exist") {
+        alert ("아이디 틀렸음");
+      }
+    })
+    
+  }
+
+  const handleInput = (event) => {
+    const {value, id} = event.target;
+    setUserInfo({...userInfo, [id]:value});
+  };
+
+  const isValue = userInfo.userId.includes('@') && userInfo.userPw.length >= 5;
+
+  return (
+    <div className="login">
+      <div className="box">
+        <h1>Westagram</h1>
+        <div className="inputTxt">
+          <input
+            id="userId"
+            onChange={handleInput}
+            type="text"
+            className="id"
+            placeholder="전화번호, 사용자 이름 또는 이메일"
+            />
+          <input
+            id="userPw"
+            onChange={handleInput}
+            type="password"
+            className="pw"
+            placeholder="비밀번호"
+            />
+          <button type="button" onClick={goToMain} className={isValue ? "abled-button" : 'disabled-button'} disabled={!isValue}>로그인</button>
+          <div className="findPw">
+            <a href="#">비밀번호를 잊으셨나요?</a>
+          </div>
+        </div>                                                                                                                                      
+      </div>
+    </div>
+  );
+};
+
+export default Login;
\ No newline at end of file

리뷰: 해당 scss파일들은 Index.js에서 import 해와서 전역으로 적용시키는게 좋습니다.
@@ -0,0 +1,87 @@
+@import '../../../style/variables.scss';
+@import '../../../style/reset.scss';
+
+
+body {
+  font-size: 14px;
+}
+input {
+  outline: none;
+}
+
+.login {
+  width: 100%;
+  height: 100vh;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  flex-direction: column;
+  .box {
+    width: 400px;
+    padding: 40px 0 20px;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    flex-direction: column;
+    border: 1px solid rgb(219, 219, 219);
+
+    h1 {
+      font-size:40px;
+      font-family: 'Lobster';
+    }
+
+    .inputTxt {
+      width: 300px;
+  
+      input {
+        display: block;
+        width: 100%;
+        margin: 5px 0;
+        padding: 10px 0 10px 5px;
+        background-color: $grey-color-bg;
+        border-radius: 3px;
+        border: 1px solid $grey-color-border;
+  
+        &::placeholder{
+          font-size: 12px;
+        }
+      }
+    }
+  }
+}
+  
+@mixin button-style {
+    margin-top: 20px;
+    display: inline-block;
+    width: 100%;
+    text-align: center;
+    text-decoration-line: none;
+    padding: 8px 0;
+    border-radius: 8px;
+    border: 0px;
+    font-weight: bold;
+    color: #fff;
+    cursor: pointer;
+  }
+
+.abled-button {
+  @include button-style;
+  background-color: $point-color-blue;
+}
+
+.disabled-button {
+  @include button-style;
+  background-color: #666;
+}
+
+
+.findPw {
+  text-align: center;
+  margin: 60px 0;
+
+  a {
+    font-size: 9px;
+    color: rgb(0, 55, 107);
+    text-decoration: none;
+  }
+}
\ No newline at end of file

리뷰: 마찬가지 입니다! font같은 속성들도 common.scss에 작성해서 전역으로 관리할 수 있겠습니다!
@@ -0,0 +1,87 @@
+@import '../../../style/variables.scss';
+@import '../../../style/reset.scss';
+
+
+body {
+  font-size: 14px;
+}
+input {
+  outline: none;
+}
+
+.login {
+  width: 100%;
+  height: 100vh;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  flex-direction: column;
+  .box {
+    width: 400px;
+    padding: 40px 0 20px;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    flex-direction: column;
+    border: 1px solid rgb(219, 219, 219);
+
+    h1 {
+      font-size:40px;
+      font-family: 'Lobster';
+    }
+
+    .inputTxt {
+      width: 300px;
+  
+      input {
+        display: block;
+        width: 100%;
+        margin: 5px 0;
+        padding: 10px 0 10px 5px;
+        background-color: $grey-color-bg;
+        border-radius: 3px;
+        border: 1px solid $grey-color-border;
+  
+        &::placeholder{
+          font-size: 12px;
+        }
+      }
+    }
+  }
+}
+  
+@mixin button-style {
+    margin-top: 20px;
+    display: inline-block;
+    width: 100%;
+    text-align: center;
+    text-decoration-line: none;
+    padding: 8px 0;
+    border-radius: 8px;
+    border: 0px;
+    font-weight: bold;
+    color: #fff;
+    cursor: pointer;
+  }
+
+.abled-button {
+  @include button-style;
+  background-color: $point-color-blue;
+}
+
+.disabled-button {
+  @include button-style;
+  background-color: #666;
+}
+
+
+.findPw {
+  text-align: center;
+  margin: 60px 0;
+
+  a {
+    font-size: 9px;
+    color: rgb(0, 55, 107);
+    text-decoration: none;
+  }
+}
\ No newline at end of file

리뷰: variables.scss파일에 있으면 될 변수들이네요!
@@ -0,0 +1,71 @@
+package com.selab.todo.entity;
+
+import com.selab.todo.common.BaseEntity;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import org.springframework.data.annotation.CreatedDate;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import java.time.DayOfWeek;
+import java.time.LocalDateTime;
+import java.time.Month;
+import java.time.Year;
+
+@Entity(name = "diary")
+@Getter
+@Table(name = "diary")
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+public class Diary extends BaseEntity {
+    @Id
+    @Column(name = "id")
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Long id;
+
+    @Column(name = "title")
+    private String title;
+
+    @Column(name = "content")
+    private String content;
+
+    @Column(name = "createdAt")
+    @CreatedDate
+    private LocalDateTime createdAt;
+
+    @Column(name = "year")
+    private Year year;
+
+    @Column(name = "month")
+    private Month month;
+
+    @Column(name = "day")
+    private DayOfWeek day;
+
+    @Column(name = "feel")
+    private String feel;
+
+
+    public Diary(String title, String content, String feel, Year year, Month month, DayOfWeek day) {
+        this.title = title;
+        this.content = content;
+        this.feel = feel;
+        this.year = year;
+        this.month = month;
+        this.day = day;
+    }
+
+    public void update(String title, String content, String feel) {
+        this.title = title;
+        this.content = content;
+        this.feel = feel;
+    }
+
+    public void feelingUpdate(String feel){
+        this.feel = feel;
+    }
+}
\ No newline at end of file

리뷰: enumrated 추가해야 될 것 같은데요?
@@ -0,0 +1,71 @@
+package com.selab.todo.entity;
+
+import com.selab.todo.common.BaseEntity;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import org.springframework.data.annotation.CreatedDate;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import java.time.DayOfWeek;
+import java.time.LocalDateTime;
+import java.time.Month;
+import java.time.Year;
+
+@Entity(name = "diary")
+@Getter
+@Table(name = "diary")
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+public class Diary extends BaseEntity {
+    @Id
+    @Column(name = "id")
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Long id;
+
+    @Column(name = "title")
+    private String title;
+
+    @Column(name = "content")
+    private String content;
+
+    @Column(name = "createdAt")
+    @CreatedDate
+    private LocalDateTime createdAt;
+
+    @Column(name = "year")
+    private Year year;
+
+    @Column(name = "month")
+    private Month month;
+
+    @Column(name = "day")
+    private DayOfWeek day;
+
+    @Column(name = "feel")
+    private String feel;
+
+
+    public Diary(String title, String content, String feel, Year year, Month month, DayOfWeek day) {
+        this.title = title;
+        this.content = content;
+        this.feel = feel;
+        this.year = year;
+        this.month = month;
+        this.day = day;
+    }
+
+    public void update(String title, String content, String feel) {
+        this.title = title;
+        this.content = content;
+        this.feel = feel;
+    }
+
+    public void feelingUpdate(String feel){
+        this.feel = feel;
+    }
+}
\ No newline at end of file

리뷰: LocalDateTime 혹은 ZoneDateTime과 같은 시간을 다루는 객체 사용을 하지 않은 이유가 무엇일까요?
@@ -0,0 +1,23 @@
+package com.selab.todo.entity;
+
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+import javax.persistence.*;
+
+@Entity(name = "feeling")
+@Getter
+@Table(name = "feeling")
+@NoArgsConstructor(access = AccessLevel.PROTECTED)
+@AllArgsConstructor
+public class Feeling {
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    @Column(name = "id")
+    private Long id;
+
+    @Column(name = "feel")
+    private String feel;
+}

리뷰: 해당 클래스의 역할은 무엇일까요?
id, baseentity 정도는 추가해도 될 것 같아요
@@ -0,0 +1,42 @@
+package racingcar.domain;
+
+import racingcar.exception.CarNameLengthException;
+
+public class Car {
+
+    private static final int CAR_NAME_LENGTH = 5;
+    private static final int MOVABLE_MIN_NUMBER = 4;
+    private final String name;
+    private int position = 0;
+
+    public Car(String name) {
+        validate(name);
+        this.name = name;
+    }
+
+    private void validate(String name) {
+        validateLength(name);
+    }
+
+    private void validateLength(String name) {
+        if (name.length() > CAR_NAME_LENGTH) {
+            throw new CarNameLengthException();
+        }
+    }
+
+    public void move(CarMoveNumberGenerator carMoveNumberGenerator) {
+        final int number = carMoveNumberGenerator.generate();
+
+        if (number >= MOVABLE_MIN_NUMBER) {
+            position++;
+        }
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public int getPosition() {
+        return position;
+    }
+}

리뷰: 컨벤션에 따라서 상수와 인스턴스 변수를 새 줄로 구분해주시는 게 좋을 것 같습니다!!
@@ -0,0 +1,71 @@
+package racingcar.domain;
+
+import racingcar.exception.CarsDuplicatedNameException;
+import racingcar.exception.CarsMaxScoreBlankException;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+public class Cars {
+
+    private static final String DELIMITER = ",";
+    private static final String DUPLICATED_DELIMITER_REGEX = ",+";
+    private final List<Car> cars;
+
+    private Cars(List<Car> cars) {
+        this.cars = Collections.unmodifiableList(cars);
+    }
+
+    public static Cars createCarNameByWord(String input) {
+        List<Car> cars = new ArrayList<>();
+        String[] words = divideWord(input);
+        validate(words);
+
+        for (String carName : words) {
+            cars.add(new Car(carName));
+        }
+        return new Cars(cars);
+    }
+
+    private static void validate(String[] words) {
+        validateDuplicatedWord(words);
+    }
+
+    private static void validateDuplicatedWord(String[] words) {
+        Set<String> uniqueWord = new HashSet<>();
+        for (String word : words) {
+            if (!uniqueWord.add(word)) {
+                throw new CarsDuplicatedNameException();
+            }
+        }
+    }
+
+    private static String[] divideWord(String word) {
+        return word.replaceAll(DUPLICATED_DELIMITER_REGEX, DELIMITER).split(DELIMITER);
+    }
+
+    public void move(CarMoveNumberGenerator carMoveNumberGenerator) {
+        for (Car car : cars) {
+            car.move(carMoveNumberGenerator);
+        }
+    }
+
+    public Winner findWinner() {
+        int maxScore = findMaxScore();
+        return new Winner(cars.stream()
+                .filter(car -> (car.getPosition() == maxScore))
+                .map(Car::getName)
+                .collect(Collectors.toList()));
+    }
+
+    private int findMaxScore() {
+        return cars.stream()
+                .max(Comparator.comparingInt(Car::getPosition))
+                .map(Car::getPosition)
+                .orElseThrow(CarsMaxScoreBlankException::new);
+    }
+
+    public List<Car> getCars() {
+        return cars;
+    }
+}

리뷰: 불변 객체를 만들 때 생성자 단계에서는 방어적 복사를 고려해주시면 더 좋을 것 같아요!!

- [방어적 복사와 Unmodifiable Collections](https://tecoble.techcourse.co.kr/post/2021-04-26-defensive-copy-vs-unmodifiable/)
@@ -0,0 +1,16 @@
+package racingcar.domain;
+
+import java.util.List;
+
+public class Winner {
+
+    private final List<String> winner;
+
+    public Winner(List<String> winner) {
+        this.winner = winner;
+    }
+
+    public List<String> getWinner() {
+        return winner;
+    }
+}

리뷰: 리스트의 네이밍은 복수형이 더 적절하다고 생각합니다!
`Winner` 클래스 자체도 승리자들의 이름을 담고있는 일급 컬렉션이기 때문에 `Winners` 라는 네이밍을 더 추천드립니다!
@@ -0,0 +1,54 @@
+package racingcar.view;
+
+import racingcar.domain.Car;
+import racingcar.domain.Cars;
+import racingcar.domain.Winner;
+
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public class OutputView {
+
+    private static final String MESSAGE_INPUT_CAR_NAME = "경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)";
+    private static final String MESSAGE_INPUT_TRY = "시도할 회수는 몇회인가요?";
+    private static final String MESSAGE_RESULT = "실행 결과";
+    private static final String MOVE_MARK = "-";
+    private static final String JOIN_NAME_AND_POSITION = " : ";
+    private static final String WINNER_DELIMITER = ",";
+    private static final String MESSAGE_WINNER_PREFIX = "최종 우승자 : ";
+    private static final String MESSAGE_WINNER_SUFFIX = "";
+
+    public void printInputCarName() {
+        System.out.println(MESSAGE_INPUT_CAR_NAME);
+    }
+
+    public void printExceptionMessage(IllegalArgumentException exceptionMessage) {
+        System.out.println(exceptionMessage.getMessage());
+    }
+
+    public void printInputTry() {
+        System.out.println(MESSAGE_INPUT_TRY);
+    }
+
+    public void printBlank() {
+        System.out.println();
+    }
+
+    public void printResult(Cars cars) {
+        System.out.println(MESSAGE_RESULT);
+        for(Car car : cars.getCars()){
+            System.out.println(car.getName() + JOIN_NAME_AND_POSITION + convertMoveMark(car.getPosition()));
+        }
+        printBlank();
+    }
+
+    private String convertMoveMark(int position) {
+        return Stream.generate(() -> MOVE_MARK).limit(position).collect(Collectors.joining());
+    }
+
+    public void printWinner(Winner winner) {
+        String message = winner.getWinner().stream()
+                .collect(Collectors.joining(WINNER_DELIMITER, MESSAGE_WINNER_PREFIX, MESSAGE_WINNER_SUFFIX));
+        System.out.println(message);
+    }
+}

리뷰: String에서 제공하는 `repeat()` 메서드를 활용해보시는 것도 추천드립니다!