From 4d926aa992aecd298f33fa2cf3305d429ae6005c Mon Sep 17 00:00:00 2001 From: hyunsunglimm Date: Tue, 30 Jan 2024 15:21:13 +0900 Subject: [PATCH 01/75] =?UTF-8?q?=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/Login.jsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pages/Login.jsx b/src/pages/Login.jsx index 25712ab..a3aa626 100644 --- a/src/pages/Login.jsx +++ b/src/pages/Login.jsx @@ -57,3 +57,5 @@ export default function Login() { ); } + +// 로그인 수정 From b54d860d0383884aa3e17cd9ac78e6b643f7f6af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=AF=BC=EC=9E=AC?= Date: Tue, 30 Jan 2024 15:37:42 +0900 Subject: [PATCH 02/75] mypagemj --- src/pages/MyPage.jsx | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/pages/MyPage.jsx b/src/pages/MyPage.jsx index a803b85..a190f2e 100644 --- a/src/pages/MyPage.jsx +++ b/src/pages/MyPage.jsx @@ -3,10 +3,20 @@ import { EmployeeContext } from "../context/EmployeeContext"; export default function MyPage() { const { loginUser } = useContext(EmployeeContext); + console.log(loginUser); return (
- +

MyPage

+
+ user +

{loginUser?.name}

+

{loginUser?.age}

+

{loginUser?.department}

+

{loginUser?.email}

+

{loginUser?.isworking ? "부재중" : "근무중"}

+
); } + From 93c4e9aae4272fefcb48ead5a1b3dc703d82662a Mon Sep 17 00:00:00 2001 From: Lee-donggeun Date: Tue, 30 Jan 2024 15:47:36 +0900 Subject: [PATCH 03/75] modalpage --- src/components/Modaltest.jsx | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/components/Modaltest.jsx diff --git a/src/components/Modaltest.jsx b/src/components/Modaltest.jsx new file mode 100644 index 0000000..e6646ab --- /dev/null +++ b/src/components/Modaltest.jsx @@ -0,0 +1,10 @@ +import React from 'react'; + +export default function Modaltest() { + return ( +
+ 모달 컴포넌트 연습 +
+ ); +} + From 1b5e49464ecadb0db55b0207d8f328a33b15684c Mon Sep 17 00:00:00 2001 From: Now-h <150241213+Now-h@users.noreply.github.com> Date: Tue, 30 Jan 2024 15:55:04 +0900 Subject: [PATCH 04/75] test --- src/components/Sidebar.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Sidebar.jsx b/src/components/Sidebar.jsx index 8a0592a..33b83a2 100644 --- a/src/components/Sidebar.jsx +++ b/src/components/Sidebar.jsx @@ -26,7 +26,7 @@ export default function Sidebar() {

페이지

  • - 직원 관리 + 직원 관
  • page2 From 2b3f6bc00c15705abbc7d2bed03616045d1446e6 Mon Sep 17 00:00:00 2001 From: hyunsunglimm Date: Tue, 30 Jan 2024 17:56:59 +0900 Subject: [PATCH 05/75] =?UTF-8?q?=ED=9A=8C=EC=9B=90=EA=B0=80=EC=9E=85=20?= =?UTF-8?q?=EC=9C=A0=ED=9A=A8=EC=84=B1=EA=B2=80=EC=A6=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .eslintrc.cjs | 23 +++--- src/App.jsx | 2 +- src/components/ImageUpload.jsx | 31 ++++++++ src/components/Input.jsx | 25 ++++++ src/pages/Login.jsx | 2 - src/pages/SignUp.jsx | 137 ++++++++++++++++++++------------- 6 files changed, 154 insertions(+), 66 deletions(-) create mode 100644 src/components/ImageUpload.jsx create mode 100644 src/components/Input.jsx diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 4dcb439..bb4f312 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -2,19 +2,20 @@ module.exports = { root: true, env: { browser: true, es2020: true }, extends: [ - 'eslint:recommended', - 'plugin:react/recommended', - 'plugin:react/jsx-runtime', - 'plugin:react-hooks/recommended', + "eslint:recommended", + "plugin:react/recommended", + "plugin:react/jsx-runtime", + "plugin:react-hooks/recommended", ], - ignorePatterns: ['dist', '.eslintrc.cjs'], - parserOptions: { ecmaVersion: 'latest', sourceType: 'module' }, - settings: { react: { version: '18.2' } }, - plugins: ['react-refresh'], + ignorePatterns: ["dist", ".eslintrc.cjs"], + parserOptions: { ecmaVersion: "latest", sourceType: "module" }, + settings: { react: { version: "18.2" } }, + plugins: ["react-refresh"], rules: { - 'react-refresh/only-export-components': [ - 'warn', + "react-refresh/only-export-components": [ + "warn", { allowConstantExport: true }, ], + "react/prop-types": "off", }, -} +}; diff --git a/src/App.jsx b/src/App.jsx index 994efa2..fef2715 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -42,7 +42,7 @@ function App() { ) .then((data) => setEmployees(data)) .catch(console.error); - }, []); + }, [employees]); return ( diff --git a/src/components/ImageUpload.jsx b/src/components/ImageUpload.jsx new file mode 100644 index 0000000..f5c76e1 --- /dev/null +++ b/src/components/ImageUpload.jsx @@ -0,0 +1,31 @@ +export default function ImageUpload({ message, handleChange, file }) { + return ( +
    +

    Image

    + + + {message && ( +

    + {message} +

    + )} +
    + ); +} diff --git a/src/components/Input.jsx b/src/components/Input.jsx new file mode 100644 index 0000000..e63d7a9 --- /dev/null +++ b/src/components/Input.jsx @@ -0,0 +1,25 @@ +import { forwardRef } from "react"; + +const Input = forwardRef(function Input( + { message, label, type = "text" }, + ref +) { + return ( +
    +

    {label}

    + + {message && ( +

    + {message} +

    + )} +
    + ); +}); + +export default Input; diff --git a/src/pages/Login.jsx b/src/pages/Login.jsx index a3aa626..25712ab 100644 --- a/src/pages/Login.jsx +++ b/src/pages/Login.jsx @@ -57,5 +57,3 @@ export default function Login() { ); } - -// 로그인 수정 diff --git a/src/pages/SignUp.jsx b/src/pages/SignUp.jsx index 0f20081..d896e32 100644 --- a/src/pages/SignUp.jsx +++ b/src/pages/SignUp.jsx @@ -1,4 +1,4 @@ -import { useRef, useState } from "react"; +import { useContext, useRef, useState } from "react"; import { getAuth, createUserWithEmailAndPassword, @@ -6,9 +6,18 @@ import { } from "firebase/auth"; import { useNavigate } from "react-router-dom"; import { addEmployee } from "../sanity/employee"; +import Input from "../components/Input"; +import ImageUpload from "../components/ImageUpload"; +import { EmployeeContext } from "../context/EmployeeContext"; export default function SignUp() { + const { employees } = useContext(EmployeeContext); const [file, setFile] = useState(); + const [errorMessage, setErrorMessage] = useState({ + imageMessage: "", + emailMessage: "", + passwordMessage: "", + }); const emailRef = useRef(); const passwordRef = useRef(); @@ -20,7 +29,9 @@ export default function SignUp() { const navigate = useNavigate(); - function signInHandler() { + function signInHandler(e) { + e.preventDefault(); + const auth = getAuth(); const email = emailRef.current.value; const password = passwordRef.current.value; @@ -30,6 +41,42 @@ export default function SignUp() { const startTime = startTimeRef.current.value; const endTime = endTimeRef.current.value; + if (!file) { + setErrorMessage((prev) => { + return { ...prev, imageMessage: "사진을 추가해주세요." }; + }); + return; + } + + if (employees.some((employee) => email === employee.email)) { + setErrorMessage((prev) => { + return { ...prev, emailMessage: "이미 존재하는 이메일입니다." }; + }); + return; + } + + if (password.length < 6) { + setErrorMessage((prev) => { + return { + ...prev, + passwordMessage: "비밀번호는 6자리 이상이어야 합니다.", + }; + }); + return; + } + + const specialCharacters = /[!@#$%^&*(),.?":{}|<>]/; + + if (specialCharacters.test(password)) { + setErrorMessage((prev) => { + return { + ...prev, + passwordMessage: "비밀번호에 특수문자를 포함할 수 없습니다.", + }; + }); + return; + } + const userData = { name, email, @@ -43,11 +90,13 @@ export default function SignUp() { .then(() => { addEmployee(userData); signOut(auth); // createUserWithEmailAndPassword함수가 동작하면 회원가입 후 자동으로 로그인함. 이를 막기위해 임시로 signOut함수사용 + navigate("/login"); }) .catch((error) => { console.log(error); + console.log(error.code); + console.log(error.message); }); - navigate("/login"); } const handleChange = (e) => { @@ -55,84 +104,68 @@ export default function SignUp() { const files = e.target.files; if (files && files[0]) { setFile(files[0]); + setErrorMessage((prev) => { + return { ...prev, imageMessage: "" }; + }); } }; - const labelStyle = "mb-2 text-gray-400"; - const inputStyle = "border-[1px] border-gray-200 w-full rounded-md py-1 px-2"; - return (

    직원 등록

    -
    +
    + + + + +
    -

    Image

    - -
    -
    -

    Password

    - -
    -
    -

    Name

    - -
    -
    -

    Age

    - -
    -
    -

    Department

    -
    -

    WorkingHours

    +

    WorkingHours

    - +
    - +
    -
    +
    ); From 4d358ef4d125c6dd90435dc8ad40154622b6f6c4 Mon Sep 17 00:00:00 2001 From: hyunsunglimm Date: Wed, 31 Jan 2024 17:14:51 +0900 Subject: [PATCH 06/75] =?UTF-8?q?=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EC=9C=A0?= =?UTF-8?q?=ED=9A=A8=EC=84=B1=20=EA=B2=80=EC=A6=9D=20&=20=EA=B7=BC?= =?UTF-8?q?=EB=AC=B4/=EB=B9=84=EA=B7=BC=EB=AC=B4=20=EC=A7=81=EC=9B=90=20?= =?UTF-8?q?=ED=95=84=ED=84=B0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 1 + src/App.jsx | 2 +- src/components/AbsenceEmployees.jsx | 56 +++++++++++++ src/components/EmployeeCard.jsx | 43 ++++++++++ src/components/Input.jsx | 2 +- src/components/Modal.jsx | 26 ++++++ src/components/WorkingEmployees.jsx | 21 +++++ src/pages/HomePage.jsx | 14 ++-- src/pages/Login.jsx | 67 +++++++++++----- src/pages/MyPage.jsx | 2 - src/pages/SignUp.jsx | 119 ++++++++++++++-------------- src/sanity/employee.js | 3 +- toy-project-1/schemas/employee.js | 5 ++ 13 files changed, 267 insertions(+), 94 deletions(-) create mode 100644 src/components/AbsenceEmployees.jsx create mode 100644 src/components/EmployeeCard.jsx create mode 100644 src/components/Modal.jsx create mode 100644 src/components/WorkingEmployees.jsx diff --git a/index.html b/index.html index 0644cfa..a27e136 100644 --- a/index.html +++ b/index.html @@ -10,6 +10,7 @@
    + diff --git a/src/App.jsx b/src/App.jsx index fef2715..994efa2 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -42,7 +42,7 @@ function App() { ) .then((data) => setEmployees(data)) .catch(console.error); - }, [employees]); + }, []); return ( diff --git a/src/components/AbsenceEmployees.jsx b/src/components/AbsenceEmployees.jsx new file mode 100644 index 0000000..489bfa0 --- /dev/null +++ b/src/components/AbsenceEmployees.jsx @@ -0,0 +1,56 @@ +import { useContext, useState } from "react"; +import { EmployeeContext } from "../context/EmployeeContext"; +import EmployeeCard from "./EmployeeCard"; + +export default function AbsenceEmployees() { + const [reason, setReason] = useState("전체"); + const { employees } = useContext(EmployeeContext); + const absenceEmployees = employees.filter( + (employee) => employee.isWorking === false + ); + + function getFilteredEmployees() { + switch (reason) { + case "전체": + return absenceEmployees; + + case "미기입": + return absenceEmployees.filter( + (employees) => !employees.reasonForAbsence + ); + + default: + return absenceEmployees.filter( + (employees) => employees.reasonForAbsence === reason + ); + } + } + + const filteredEmployees = getFilteredEmployees(); + + function handleChange(e) { + setReason(e.target.value); + } + + return ( +
    +

    + 부재중인 직원 중 부재 항목에 따른 카테고리 메뉴로 데이터 필터링 기능 + 구현 +

    +
    + +
    +
      + {filteredEmployees.map((employee) => ( + + ))} +
    +
    + ); +} diff --git a/src/components/EmployeeCard.jsx b/src/components/EmployeeCard.jsx new file mode 100644 index 0000000..86aa25f --- /dev/null +++ b/src/components/EmployeeCard.jsx @@ -0,0 +1,43 @@ +export default function EmployeeCard({ employee }) { + const { + name, + email, + age, + department, + image, + isWorking, + workingHours, + reasonForAbsence, + } = employee; + + const isReason = isWorking || reasonForAbsence; + + return ( +
  • + +
    +

    {name}

    +

    {email}

    +

    {age}

    +

    {department}

    +

    {workingHours}

    + {!isReason ? ( +

    + 부재 사유를 기입해주세요 ! +

    + ) : ( +

    + {reasonForAbsence} +

    + )} + +
    +
  • + ); +} diff --git a/src/components/Input.jsx b/src/components/Input.jsx index e63d7a9..9f18d69 100644 --- a/src/components/Input.jsx +++ b/src/components/Input.jsx @@ -1,7 +1,7 @@ import { forwardRef } from "react"; const Input = forwardRef(function Input( - { message, label, type = "text" }, + { message = "", label, type = "text" }, ref ) { return ( diff --git a/src/components/Modal.jsx b/src/components/Modal.jsx new file mode 100644 index 0000000..e702ae1 --- /dev/null +++ b/src/components/Modal.jsx @@ -0,0 +1,26 @@ +import { forwardRef, useImperativeHandle, useRef } from "react"; +import { createPortal } from "react-dom"; + +const Modal = forwardRef(function Modal({ children }, ref) { + const dialog = useRef(); + + useImperativeHandle(ref, () => { + return { + open() { + dialog.current.showModal(); + }, + }; + }); + + return createPortal( + + {children} + , + document.getElementById("modal-root") + ); +}); + +export default Modal; diff --git a/src/components/WorkingEmployees.jsx b/src/components/WorkingEmployees.jsx new file mode 100644 index 0000000..d4b5796 --- /dev/null +++ b/src/components/WorkingEmployees.jsx @@ -0,0 +1,21 @@ +import { useContext } from "react"; +import { EmployeeContext } from "../context/EmployeeContext"; +import EmployeeCard from "./EmployeeCard"; + +export default function WorkingEmployees() { + const { employees } = useContext(EmployeeContext); + const workingEmployees = employees.filter( + (employee) => employee.isWorking === true + ); + + return ( +
    +

    현재 근무중인 직원

    +
      + {workingEmployees.map((employee) => ( + + ))} +
    +
    + ); +} diff --git a/src/pages/HomePage.jsx b/src/pages/HomePage.jsx index c3b8bd4..6781470 100644 --- a/src/pages/HomePage.jsx +++ b/src/pages/HomePage.jsx @@ -1,16 +1,14 @@ +import AbsenceEmployees from "../components/AbsenceEmployees"; +import WorkingEmployees from "../components/WorkingEmployees"; + export default function HomePage() { return (
    -
    +
    기업 공지 모음 갤러리
    -
    - 근무중인 전 직원 조회 -
    -
    - 부재중인 직원 중 부재 항목에 따른 카테고리 메뉴로 데이터 필터링 기능 - 구현 -
    + +
    ); } diff --git a/src/pages/Login.jsx b/src/pages/Login.jsx index 25712ab..d46bdd8 100644 --- a/src/pages/Login.jsx +++ b/src/pages/Login.jsx @@ -1,46 +1,73 @@ -import { useRef } from "react"; +import { useContext, useRef, useState } from "react"; import { getAuth, signInWithEmailAndPassword } from "firebase/auth"; import { Link, useNavigate } from "react-router-dom"; +import Input from "../components/Input"; +import { EmployeeContext } from "../context/EmployeeContext"; export default function Login() { + const { employees } = useContext(EmployeeContext); + + const [errorMessage, setErrorMessage] = useState({ + emailMessage: "", + passwordMessage: "", + }); + const emailRef = useRef(); const passwordRef = useRef(); const navigate = useNavigate(); - function signInHandler() { + function signInHandler(e) { + e.preventDefault(); + const auth = getAuth(); - signInWithEmailAndPassword( - auth, - emailRef.current.value, - passwordRef.current.value - ) + + const email = emailRef.current.value; + const password = passwordRef.current.value; + + if (!employees.some((employee) => employee.email === email)) { + setErrorMessage((prev) => { + return { ...prev, emailMessage: "존재하는 직원 이메일이 아닙니다." }; + }); + return; + } + + signInWithEmailAndPassword(auth, email, password) .then(() => { navigate("/"); }) .catch((error) => { + setErrorMessage({ + emailMessage: "", + passwordMessage: "비밀번호가 틀립니다.", + }); console.log(error); }); } const contentHeight = `${window.innerHeight - 80}px`; - const inputStyle = "border-[1px] border-gray-200 w-full rounded-md py-1 px-2"; - return (
    -
    +

    Welcome to Intranet Five !

    -
    -

    email

    - -
    -
    -

    password

    - -
    + + -
    +
    ); } diff --git a/src/pages/MyPage.jsx b/src/pages/MyPage.jsx index a190f2e..d9b4e88 100644 --- a/src/pages/MyPage.jsx +++ b/src/pages/MyPage.jsx @@ -3,7 +3,6 @@ import { EmployeeContext } from "../context/EmployeeContext"; export default function MyPage() { const { loginUser } = useContext(EmployeeContext); - console.log(loginUser); return (
    @@ -19,4 +18,3 @@ export default function MyPage() {
    ); } - diff --git a/src/pages/SignUp.jsx b/src/pages/SignUp.jsx index d896e32..8d1adc4 100644 --- a/src/pages/SignUp.jsx +++ b/src/pages/SignUp.jsx @@ -1,9 +1,5 @@ import { useContext, useRef, useState } from "react"; -import { - getAuth, - createUserWithEmailAndPassword, - signOut, -} from "firebase/auth"; +import { getAuth, createUserWithEmailAndPassword } from "firebase/auth"; import { useNavigate } from "react-router-dom"; import { addEmployee } from "../sanity/employee"; import Input from "../components/Input"; @@ -89,8 +85,7 @@ export default function SignUp() { createUserWithEmailAndPassword(auth, email, password) .then(() => { addEmployee(userData); - signOut(auth); // createUserWithEmailAndPassword함수가 동작하면 회원가입 후 자동으로 로그인함. 이를 막기위해 임시로 signOut함수사용 - navigate("/login"); + navigate("/"); }) .catch((error) => { console.log(error); @@ -111,62 +106,64 @@ export default function SignUp() { }; return ( -
    -
    -

    직원 등록

    -
    - - - - - -
    -

    Department

    - -
    -
    -

    WorkingHours

    -
    -
    - - -
    -
    - - + <> +
    +
    +

    직원 등록

    + + + + + + +
    +

    Department

    + +
    +
    +

    WorkingHours

    +
    +
    + + +
    +
    + + +
    -
    - - + + +
    -
    + ); } diff --git a/src/sanity/employee.js b/src/sanity/employee.js index d51bb1c..53532d6 100644 --- a/src/sanity/employee.js +++ b/src/sanity/employee.js @@ -29,8 +29,9 @@ export async function addEmployee({ age, department, image: { asset: { _ref: result.document._id } }, - isWorking: false, + isWorking: true, workingHours, + reasonForAbsence: "", }); }); } diff --git a/toy-project-1/schemas/employee.js b/toy-project-1/schemas/employee.js index d7343fe..699ef3e 100644 --- a/toy-project-1/schemas/employee.js +++ b/toy-project-1/schemas/employee.js @@ -38,6 +38,11 @@ export default { name: 'workingHours', type: 'string', }, + { + title: 'ReasonForAbsence', + name: 'reasonForAbsence', + type: 'string', + }, ], preview: { select: {title: 'name', media: 'image'}, From cbf3b61dc45f092e16fbfc569be6230d1d09f8fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=AF=BC=EC=9E=AC?= Date: Wed, 31 Jan 2024 17:43:29 +0900 Subject: [PATCH 07/75] mypage styling --- src/pages/MyPage.jsx | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/pages/MyPage.jsx b/src/pages/MyPage.jsx index a190f2e..0076f7d 100644 --- a/src/pages/MyPage.jsx +++ b/src/pages/MyPage.jsx @@ -3,13 +3,21 @@ import { EmployeeContext } from "../context/EmployeeContext"; export default function MyPage() { const { loginUser } = useContext(EmployeeContext); - console.log(loginUser); + // console.log(loginUser); return ( -
    -

    MyPage

    -
    - user + +
    +
    +

    MyPage

    +
    +
    + user

    {loginUser?.name}

    {loginUser?.age}

    {loginUser?.department}

    From 9e6f3e86c13bd3ed680c6c9b7512a8f717e18eb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=AF=BC=EC=9E=AC?= Date: Wed, 31 Jan 2024 17:56:21 +0900 Subject: [PATCH 08/75] mypage styling --- src/pages/MyPage.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/MyPage.jsx b/src/pages/MyPage.jsx index 0076f7d..207d705 100644 --- a/src/pages/MyPage.jsx +++ b/src/pages/MyPage.jsx @@ -3,7 +3,7 @@ import { EmployeeContext } from "../context/EmployeeContext"; export default function MyPage() { const { loginUser } = useContext(EmployeeContext); - // console.log(loginUser); + return ( From 438ef298969a52e4191de4e9f61784d2a0618ce6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=AF=BC=EC=9E=AC?= Date: Wed, 31 Jan 2024 18:06:21 +0900 Subject: [PATCH 09/75] mypage styling --- src/pages/MyPage.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/MyPage.jsx b/src/pages/MyPage.jsx index 207d705..192d10d 100644 --- a/src/pages/MyPage.jsx +++ b/src/pages/MyPage.jsx @@ -5,6 +5,7 @@ export default function MyPage() { const { loginUser } = useContext(EmployeeContext); + return (
    From 1e3639a975770f66d571d825143a5e7894836e93 Mon Sep 17 00:00:00 2001 From: hyunsunglimm Date: Wed, 31 Jan 2024 19:21:09 +0900 Subject: [PATCH 10/75] =?UTF-8?q?=EA=B8=B0=EC=97=85=20=EA=B3=B5=EC=A7=80?= =?UTF-8?q?=20=EB=AA=A8=EC=9D=8C=20=EA=B0=A4=EB=9F=AC=EB=A6=AC=20=EC=8A=A4?= =?UTF-8?q?=ED=83=80=EC=9D=BC=EB=A7=81&=EB=8D=B0=EC=9D=B4=ED=84=B0=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/AbsenceEmployees.jsx | 2 +- src/components/NoticeCard.jsx | 16 ++++++++++++++ src/components/NoticeGallery.jsx | 34 +++++++++++++++++++++++++++++ src/components/WorkingEmployees.jsx | 2 +- src/pages/HomePage.jsx | 5 ++--- toy-project-1/schemas/index.js | 3 ++- toy-project-1/schemas/notice.js | 25 +++++++++++++++++++++ 7 files changed, 81 insertions(+), 6 deletions(-) create mode 100644 src/components/NoticeCard.jsx create mode 100644 src/components/NoticeGallery.jsx create mode 100644 toy-project-1/schemas/notice.js diff --git a/src/components/AbsenceEmployees.jsx b/src/components/AbsenceEmployees.jsx index 489bfa0..df25447 100644 --- a/src/components/AbsenceEmployees.jsx +++ b/src/components/AbsenceEmployees.jsx @@ -34,7 +34,7 @@ export default function AbsenceEmployees() { return (
    -

    +

    부재중인 직원 중 부재 항목에 따른 카테고리 메뉴로 데이터 필터링 기능 구현

    diff --git a/src/components/NoticeCard.jsx b/src/components/NoticeCard.jsx new file mode 100644 index 0000000..61928b0 --- /dev/null +++ b/src/components/NoticeCard.jsx @@ -0,0 +1,16 @@ +export default function NoticeCard({ notice }) { + const { title, thumbnail } = notice; + + return ( +
  • +
    + {`${title} +
    +

    {title}

    +
  • + ); +} diff --git a/src/components/NoticeGallery.jsx b/src/components/NoticeGallery.jsx new file mode 100644 index 0000000..be13e85 --- /dev/null +++ b/src/components/NoticeGallery.jsx @@ -0,0 +1,34 @@ +import { useEffect, useState } from "react"; +import client from "../sanity/client"; +import NoticeCard from "./NoticeCard"; + +export default function NoticeGallery() { + const [notices, setNotices] = useState([]); + console.log(notices[0]); + + useEffect(() => { + client + .fetch( + `*[_type == "notice"]{ + ..., + "id": _id, + "thumbnail": thumbnail.asset->url, + "createdAt": _createdAt, + "updatedAt": _updatedAt, + }` + ) + .then((data) => setNotices(data)) + .catch(console.error); + }, []); + + return ( +
    +

    기업 공지 모음 갤러리

    +
      + {notices.map((notice) => ( + + ))} +
    +
    + ); +} diff --git a/src/components/WorkingEmployees.jsx b/src/components/WorkingEmployees.jsx index d4b5796..c0aea2f 100644 --- a/src/components/WorkingEmployees.jsx +++ b/src/components/WorkingEmployees.jsx @@ -10,7 +10,7 @@ export default function WorkingEmployees() { return (
    -

    현재 근무중인 직원

    +

    현재 근무중인 직원

      {workingEmployees.map((employee) => ( diff --git a/src/pages/HomePage.jsx b/src/pages/HomePage.jsx index 6781470..337594b 100644 --- a/src/pages/HomePage.jsx +++ b/src/pages/HomePage.jsx @@ -1,12 +1,11 @@ import AbsenceEmployees from "../components/AbsenceEmployees"; +import NoticeGallery from "../components/NoticeGallery"; import WorkingEmployees from "../components/WorkingEmployees"; export default function HomePage() { return (
      -
      - 기업 공지 모음 갤러리 -
      +
      diff --git a/toy-project-1/schemas/index.js b/toy-project-1/schemas/index.js index bf5cfc4..66cfdf8 100644 --- a/toy-project-1/schemas/index.js +++ b/toy-project-1/schemas/index.js @@ -1,3 +1,4 @@ import employee from './employee' +import notice from './notice' -export const schemaTypes = [employee] +export const schemaTypes = [employee, notice] diff --git a/toy-project-1/schemas/notice.js b/toy-project-1/schemas/notice.js new file mode 100644 index 0000000..f6c5be5 --- /dev/null +++ b/toy-project-1/schemas/notice.js @@ -0,0 +1,25 @@ +export default { + title: 'Notice', + name: 'notice', + type: 'document', + fields: [ + { + title: 'Title', + name: 'title', + type: 'string', + }, + { + title: 'Description', + name: 'description', + type: 'text', + }, + { + title: 'Thumbnail', + name: 'thumbnail', + type: 'image', + }, + ], + preview: { + select: {title: 'title', media: 'thumbnail'}, + }, +} From 592aeea21efe92facca52a955c5d8a5fb74f66bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=AF=BC=EC=9E=AC?= Date: Thu, 1 Feb 2024 11:17:53 +0900 Subject: [PATCH 11/75] mypage style --- src/pages/MyPage.jsx | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/pages/MyPage.jsx b/src/pages/MyPage.jsx index 9b1b80b..ca51628 100644 --- a/src/pages/MyPage.jsx +++ b/src/pages/MyPage.jsx @@ -1,20 +1,24 @@ -import { useContext } from "react"; +import { useContext, useState } from "react"; import { EmployeeContext } from "../context/EmployeeContext"; export default function MyPage() { const { loginUser } = useContext(EmployeeContext); + const [isWorking, setIsWorking] = useState(loginUser?.isWorking || false); + const toggleStatus = () => { + setIsWorking(!isWorking); + }; - return ( -
      + style={{ + backgroundImage: `url(${loginUser?.image})`, + backgroundSize: "cover", + backgroundPosition: "center", + backgroundAttachment: "local", + backgroundRepeat: "no-repeat" + }}>

      MyPage

      @@ -23,7 +27,9 @@ export default function MyPage() {

      {loginUser?.age}

      {loginUser?.department}

      {loginUser?.email}

      -

      {loginUser?.isworking ? "부재중" : "근무중"}

      +
      ); From 647d5397d83d955843af4647ed1a9785a291e80e Mon Sep 17 00:00:00 2001 From: Lee-donggeun Date: Thu, 1 Feb 2024 11:48:41 +0900 Subject: [PATCH 12/75] =?UTF-8?q?=EB=AA=A8=EB=8B=AC=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 41 ++++++++++++++++++++++++++++++++--- package.json | 1 + src/components/Header.jsx | 2 ++ src/components/Modal.jsx | 42 ++++++++++++++++++++++++++++++++++++ src/components/Modaltest.jsx | 10 --------- 5 files changed, 83 insertions(+), 13 deletions(-) create mode 100644 src/components/Modal.jsx delete mode 100644 src/components/Modaltest.jsx diff --git a/package-lock.json b/package-lock.json index 2eb1c19..f948810 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "firebase": "^10.7.2", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-modal": "^3.16.1", "react-router-dom": "^6.21.3", "tailwindcss": "^3.4.1" }, @@ -2727,6 +2728,11 @@ "node": ">=12.0.0" } }, + "node_modules/exenv": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz", + "integrity": "sha512-Z+ktTxTwv9ILfgKCk32OX3n/doe+OcLTRtqK9pcL+JsP3J1/VW8Uvl4ZjLlKqeW4rzK4oesDOGMEMRIZqtP4Iw==" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -4415,7 +4421,6 @@ "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -4499,8 +4504,30 @@ "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" + }, + "node_modules/react-modal": { + "version": "3.16.1", + "resolved": "https://registry.npmjs.org/react-modal/-/react-modal-3.16.1.tgz", + "integrity": "sha512-VStHgI3BVcGo7OXczvnJN7yT2TWHJPDXZWyI/a0ssFNhGZWsPmB8cF0z33ewDXq4VfYMO1vXgiv/g8Nj9NDyWg==", + "dependencies": { + "exenv": "^1.2.0", + "prop-types": "^15.7.2", + "react-lifecycles-compat": "^3.0.0", + "warning": "^4.0.3" + }, + "engines": { + "node": ">=8" + }, + "peerDependencies": { + "react": "^0.14.0 || ^15.0.0 || ^16 || ^17 || ^18", + "react-dom": "^0.14.0 || ^15.0.0 || ^16 || ^17 || ^18" + } }, "node_modules/react-router": { "version": "6.21.3", @@ -5463,6 +5490,14 @@ } } }, + "node_modules/warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, "node_modules/websocket-driver": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", diff --git a/package.json b/package.json index f094a5e..197810e 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "firebase": "^10.7.2", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-modal": "^3.16.1", "react-router-dom": "^6.21.3", "tailwindcss": "^3.4.1" }, diff --git a/src/components/Header.jsx b/src/components/Header.jsx index 47e53d7..cdb44da 100644 --- a/src/components/Header.jsx +++ b/src/components/Header.jsx @@ -1,6 +1,7 @@ import { Link } from "react-router-dom"; import { useContext } from "react"; import { EmployeeContext } from "../context/EmployeeContext"; +import Modaltest from "./Modal"; export default function Header() { const { loginUser } = useContext(EmployeeContext); @@ -18,6 +19,7 @@ export default function Header() { ) : (

      현재 시간(컴포넌트화)

      +

      {loginUser?.name}

      +
      + +
      + {modalOpen && ( +
      { + if (e.target === modalBackground.current) { + setModalOpen(false); + } + }} + > +
      +

      리액트로 모달 구현하기

      + +
      +
      + )} + + ); +} \ No newline at end of file diff --git a/src/components/Modaltest.jsx b/src/components/Modaltest.jsx deleted file mode 100644 index e6646ab..0000000 --- a/src/components/Modaltest.jsx +++ /dev/null @@ -1,10 +0,0 @@ -import React from 'react'; - -export default function Modaltest() { - return ( -
      - 모달 컴포넌트 연습 -
      - ); -} - From b5022c3e93babaeb4e6cf6ef55455d812f504bdb Mon Sep 17 00:00:00 2001 From: Lee-donggeun Date: Thu, 1 Feb 2024 11:59:13 +0900 Subject: [PATCH 13/75] =?UTF-8?q?=ED=97=A4=EB=8D=94=20=EB=B6=80=EB=B6=84?= =?UTF-8?q?=20=ED=83=80=EC=9D=B4=EB=A8=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Header.jsx | 3 ++- src/components/Timer.jsx | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 src/components/Timer.jsx diff --git a/src/components/Header.jsx b/src/components/Header.jsx index cdb44da..e786714 100644 --- a/src/components/Header.jsx +++ b/src/components/Header.jsx @@ -2,6 +2,7 @@ import { Link } from "react-router-dom"; import { useContext } from "react"; import { EmployeeContext } from "../context/EmployeeContext"; import Modaltest from "./Modal"; +import Timer from "./Timer"; export default function Header() { const { loginUser } = useContext(EmployeeContext); @@ -18,7 +19,7 @@ export default function Header() { ) : (
      -

      현재 시간(컴포넌트화)

      +

      {loginUser?.name}

      diff --git a/src/components/Timer.jsx b/src/components/Timer.jsx new file mode 100644 index 0000000..b54168f --- /dev/null +++ b/src/components/Timer.jsx @@ -0,0 +1,25 @@ +import React, { useState, useEffect } from 'react'; + +export default function Timer () { + const [currentDateTime, setCurrentDateTime] = useState(new Date()); + + useEffect(() => { + // 1초마다 현재 날짜 및 시간을 업데이트 + const intervalId = setInterval(() => { + setCurrentDateTime(new Date()); + }, 1000); + + // 컴포넌트가 언마운트될 때 clearInterval을 통해 interval 정리 + return () => clearInterval(intervalId); + }, []); // 두 번째 매개변수에 빈 배열을 전달하여 최초 렌더링 시에만 useEffect가 실행되도록 함 + + const daysOfWeek = ['일', '월', '화', '수', '목', '금', '토']; + const dayOfWeek = daysOfWeek[currentDateTime.getDay()]; // 현재 날짜의 요일을 가져옴 + const formattedDateTime = currentDateTime.toLocaleString(); // 날짜 및 시간을 지역 시간 문자열로 변환 + + return ( +
      +

      현재 시간: {formattedDateTime} ({dayOfWeek})

      +
      + ); +}; \ No newline at end of file From c474e4d0352659838baa25fca47e4c9fb03d9f0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=AF=BC=EC=9E=AC?= Date: Thu, 1 Feb 2024 13:33:31 +0900 Subject: [PATCH 14/75] icon install --- package-lock.json | 9 +++++++++ package.json | 1 + src/pages/MyPage.jsx | 32 ++++++++++++++++++++++++-------- 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2eb1c19..57e764a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "firebase": "^10.7.2", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-icons": "^5.0.1", "react-router-dom": "^6.21.3", "tailwindcss": "^3.4.1" }, @@ -4496,6 +4497,14 @@ "react": "^18.2.0" } }, + "node_modules/react-icons": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.0.1.tgz", + "integrity": "sha512-WqLZJ4bLzlhmsvme6iFdgO8gfZP17rfjYEJ2m9RsZjZ+cc4k1hTzknEz63YS1MeT50kVzoa1Nz36f4BEx+Wigw==", + "peerDependencies": { + "react": "*" + } + }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", diff --git a/package.json b/package.json index f094a5e..9676af7 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "firebase": "^10.7.2", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-icons": "^5.0.1", "react-router-dom": "^6.21.3", "tailwindcss": "^3.4.1" }, diff --git a/src/pages/MyPage.jsx b/src/pages/MyPage.jsx index ca51628..3f9b7e4 100644 --- a/src/pages/MyPage.jsx +++ b/src/pages/MyPage.jsx @@ -1,5 +1,6 @@ import { useContext, useState } from "react"; import { EmployeeContext } from "../context/EmployeeContext"; +import { MdOutlineMail } from "react-icons/md"; export default function MyPage() { const { loginUser } = useContext(EmployeeContext); @@ -9,25 +10,40 @@ export default function MyPage() { setIsWorking(!isWorking); }; + const statusStyle = { + backgroundColor: isWorking ? "#FF0000" : "#00FF00", // 연두색 또는 빨간색 배경색을 선택 + color: "#FFFFFF", // 텍스트 색상을 흰색으로 설정 + }; + return (
      -
      + backgroundRepeat: "no-repeat", + }} + >

      MyPage

      - user + user

      {loginUser?.name}

      -

      {loginUser?.age}

      -

      {loginUser?.department}

      -

      {loginUser?.email}

      -
      From 5447cbaafcf5e2aad0c82eecf3ca9189c520ae03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=AF=BC=EC=9E=AC?= Date: Thu, 1 Feb 2024 14:18:27 +0900 Subject: [PATCH 15/75] =?UTF-8?q?=EB=B6=80=EC=9E=AC=EC=82=AC=EC=9C=A0?= =?UTF-8?q?=EA=B8=B0=EC=9E=AC=EC=8A=A4=ED=83=80=EC=9D=BC=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/MyPage.jsx | 59 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 46 insertions(+), 13 deletions(-) diff --git a/src/pages/MyPage.jsx b/src/pages/MyPage.jsx index 3f9b7e4..a537d72 100644 --- a/src/pages/MyPage.jsx +++ b/src/pages/MyPage.jsx @@ -1,18 +1,25 @@ import { useContext, useState } from "react"; import { EmployeeContext } from "../context/EmployeeContext"; import { MdOutlineMail } from "react-icons/md"; +import { MdOutlineWorkOutline } from "react-icons/md"; +import { FaGem } from "react-icons/fa"; export default function MyPage() { const { loginUser } = useContext(EmployeeContext); const [isWorking, setIsWorking] = useState(loginUser?.isWorking || false); + const [absenceReason, setAbsenceReason] = useState(""); // 부재 사유 추가 const toggleStatus = () => { setIsWorking(!isWorking); }; + const handleAbsenceReasonChange = (e) => { + setAbsenceReason(e.target.value); + }; + const statusStyle = { - backgroundColor: isWorking ? "#FF0000" : "#00FF00", // 연두색 또는 빨간색 배경색을 선택 - color: "#FFFFFF", // 텍스트 색상을 흰색으로 설정 + backgroundColor: isWorking ? "#FF0000" : "#00FF00", + color: "#FFFFFF", }; return ( @@ -35,18 +42,44 @@ export default function MyPage() { src={loginUser?.image} alt="user" /> -

      {loginUser?.name}

      -

      {loginUser?.age}

      -

      {loginUser?.department}

      -

      {loginUser?.email}

      - +

      {loginUser?.name}

      +

      + + {loginUser?.age} +

      +

      + + {loginUser?.department} +

      +

      + + {loginUser?.email} +

      +
      + + {isWorking ? "부재중" : "근무중"} + + +
      + {isWorking && ( +
      +