Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
aa3eab3
create card component
Apr 21, 2025
3db5f9f
update .gitignore
May 9, 2025
8690dff
출퇴근 버튼 생성, 9시 이후 지각표시, 출근시간 localStorage 저장 기능 추가가
May 9, 2025
2a305e6
3week base commit
May 24, 2025
ee34c61
3주차 베이스커밋
Jun 1, 2025
544d045
출퇴근 여부 및 지각 여부 App 컴포넌틍에서 관리하도록 변경
Jun 1, 2025
2e66cbc
출퇴근 여부 초기화로직 수정 및 대시보드 카드 백그라운드 컬러 출결 여부에 따라 변경되도록 설정
Jun 1, 2025
5971429
날씨 API 연동 및 화면출력력
Jun 3, 2025
6b1fc40
4week base commit
Jun 17, 2025
508e6df
연차 신청을 위한 시간대 선택, 연차 종류 구분 선택 라디오 버튼 추가
Jun 17, 2025
2a1c2ca
전체 레이아웃 변경을 위한 기초 작업 및 연차 신청 화면 연결
Jun 17, 2025
d78fb8c
디자인 통일을 위한 CSS 및 HTML 변경
Jun 19, 2025
bf40d4b
연차 신청 폼 작성
Jun 19, 2025
8a67ea2
메인 페이지 디자인 조정
Jun 22, 2025
0cbf44f
연차 신청 및 연차 차감 기능 구현
Jun 22, 2025
bec1943
useContext 사용하여 사용자 정보 전역관리 예정
Jul 1, 2025
05b3c74
App.jsx Context 사용하도록 변경
Jul 1, 2025
9f49af4
각 기능들 Context의 정보 사용할 수 있도록 상하위 컴포넌트 분리
Jul 1, 2025
680e426
분리된 컴포넌트 대응
Jul 1, 2025
309d696
잔여 연차 표시기능 추가
Jul 1, 2025
5b8d5d3
연차신청 메뉴 파일 디렉토리 변경
Jul 1, 2025
b51c918
디자인 변경
Jul 1, 2025
84364ce
날짜 포맷팅 오류 수정
Jul 1, 2025
00b1737
유저 정보 백엔드 서버에서 가져오도록 수정
Jul 3, 2025
e27a66c
유저 출결 정보 백엔드 API 에 저장하는 로직 추가
Jul 6, 2025
40c1ffe
유저 정보 로드 로직 수정
Jul 6, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions reactStudy1week/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
*.Zone.Identifier
2 changes: 2 additions & 0 deletions reactStudy1week/.gitignore:Zone.Identifier
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[ZoneTransfer]
ZoneId=3
12 changes: 12 additions & 0 deletions reactStudy1week/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# React + Vite

This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.

Currently, two official plugins are available:

- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) for Fast Refresh
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh

## Expanding the ESLint configuration

If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project.
2 changes: 2 additions & 0 deletions reactStudy1week/README.md:Zone.Identifier
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[ZoneTransfer]
ZoneId=3
33 changes: 33 additions & 0 deletions reactStudy1week/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'

export default [
{ ignores: ['dist'] },
{
files: ['**/*.{js,jsx}'],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
parserOptions: {
ecmaVersion: 'latest',
ecmaFeatures: { jsx: true },
sourceType: 'module',
},
},
plugins: {
'react-hooks': reactHooks,
'react-refresh': reactRefresh,
},
rules: {
...js.configs.recommended.rules,
...reactHooks.configs.recommended.rules,
'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }],
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
},
]
2 changes: 2 additions & 0 deletions reactStudy1week/eslint.config.js:Zone.Identifier
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[ZoneTransfer]
ZoneId=3
13 changes: 13 additions & 0 deletions reactStudy1week/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
2 changes: 2 additions & 0 deletions reactStudy1week/index.html:Zone.Identifier
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[ZoneTransfer]
ZoneId=3
33 changes: 33 additions & 0 deletions reactStudy1week/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"name": "react-study-first-week",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"lint": "eslint .",
"preview": "vite preview"
},
"dependencies": {
"@tailwindcss/postcss": "^4.1.4",
"@tailwindcss/vite": "^4.1.4",
"autoprefixer": "^10.4.21",
"postcss": "^8.5.3",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"tailwindcss": "^4.1.4"
},
"devDependencies": {
"@eslint/js": "^9.22.0",
"@types/react": "^19.0.10",
"@types/react-dom": "^19.0.4",
"@vitejs/plugin-react": "^4.3.4",
"eslint": "^9.22.0",
"eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-react-refresh": "^0.4.19",
"globals": "^16.0.0",
"vite": "^6.3.1"
},
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
}
2 changes: 2 additions & 0 deletions reactStudy1week/package.json:Zone.Identifier
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[ZoneTransfer]
ZoneId=3
1 change: 1 addition & 0 deletions reactStudy1week/public/vite.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions reactStudy1week/public/vite.svg:Zone.Identifier
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[ZoneTransfer]
ZoneId=3
48 changes: 48 additions & 0 deletions reactStudy1week/src/App.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@

@import 'tailwindcss';
/* @import 'tailwindcss/base';
@import 'tailwindcss/components';
@import 'tailwindcss/utilities'; */

/* #root {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
text-align: center;
}

.logo {
height: 6em;
padding: 1.5em;
will-change: filter;
transition: filter 300ms;
}
.logo:hover {
filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.react:hover {
filter: drop-shadow(0 0 2em #61dafbaa);
}

@keyframes logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}

@media (prefers-reduced-motion: no-preference) {
a:nth-of-type(2) .logo {
animation: logo-spin infinite 20s linear;
}
}

.card {
padding: 2em;
}

.read-the-docs {
color: #888;
} */
2 changes: 2 additions & 0 deletions reactStudy1week/src/App.css:Zone.Identifier
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[ZoneTransfer]
ZoneId=3
36 changes: 36 additions & 0 deletions reactStudy1week/src/App.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { useState } from 'react'
import './App.css'
import Card from './components/Card'

function App() {
const [count, setCount] = useState(0)
const memberInfoList = [
{
id: 1,
name: "박상길",
department: "인사팀",
joinDate: "2022-04-19"
},
{
id: 2,
name: "정진호",
department: "기획팀",
joinDate: "2012-02-20"
},
{
id:3,
name: "연민수",
department: "해외영업팀",
joinDate: "2010-01-11"
}
]
return (
<div>
{memberInfoList.map(memberInfo => {
return <Card memberInfo={memberInfo} key={memberInfo.id}></Card>
})}
</div>
)
}

export default App
2 changes: 2 additions & 0 deletions reactStudy1week/src/App.jsx:Zone.Identifier
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[ZoneTransfer]
ZoneId=3
1 change: 1 addition & 0 deletions reactStudy1week/src/assets/react.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions reactStudy1week/src/assets/react.svg:Zone.Identifier
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[ZoneTransfer]
ZoneId=3
96 changes: 96 additions & 0 deletions reactStudy1week/src/components/Card.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import React, { useState } from "react";

function Card(props) {
const [isWorking, setIsWorking] = useState(false)
const [isLate, setIsLate] = useState(false)
const memberInfo = props.memberInfo;
const nowDate = new Date();
const joinDate = new Date(memberInfo.joinDate);
const diffTime = nowDate.getTime() - joinDate.getTime();
const diffDays = diffTime / (1000 * 60 * 60 * 24)
const diffYears = Math.floor(diffDays / 365)
memberInfo.diffYears = diffYears;
if (memberInfo.department === "인사팀") {
memberInfo.backgroundColor = "bg-lime-200"
}
if (memberInfo.department === "기획팀") {
memberInfo.backgroundColor = "bg-sky-200"
}
if (memberInfo.department === "해외영업팀") {
memberInfo.backgroundColor = "bg-red-200"
}
// 출퇴근 상태 변경
function changeWorkingState(id) {
// isWorking == false -> 퇴근 상태
// isWorking == true -> 출근 상태
const currentHour = new Date();
setIsWorking(!isWorking);
localStorage.setItem(id, currentHour)

// 9시 이후 출근 시 지각 표시
if (!isWorking && currentHour.getHours() >= 9 && currentHour.getMinutes() >= 0) {
setIsLate(true);
}

if (isWorking) {
setIsLate(false)
}
}
// 출퇴근 시간 localStorage 저장
function getCheckedHour(id) {
return localStorage.getItem(id)
}
// Uncaught Error: Too many re-renders. React limits the number of renders to prevent an infinite loop.
// state를 변화시키는 함수가 무한루프에 빠지게 되면 발생하는 에러로 볼 수 있음
// state를 변화시키는 함수가 사용자 액션 시에만 동작하도록 해야함 -> 특히 이벤트 트리거에 연관된 함수
return (
<div className="max-w-sm w-full lg:max-w-full lg:flex pb-3">
<div className="h-48 lg:h-auto w-128 lg:w-128 flex-none bg-cover rounded-t lg:rounded-t-none lg:rounded-l text-center overflow-hidden">
</div>
<div className={memberInfo.backgroundColor + " lg:w-128 w-128 border-r border-b lg:border-l border-gray-400 lg:border-t lg:border-gray-400 rounded-xl lg:rounded-xl p-4 flex flex-col justify-between leading-normal"}>
<div className="mb-8">
{
Object.keys(memberInfo).map(key => {
let fieldName = ""
if (key === "name") {
fieldName = "이름"
}
if (key === "department") {
fieldName = "부서"
}
if (key === "joinDate") {
fieldName = "입사일"
}
if (key === "diffYears") {
fieldName = "년차"
}
return (
<div key={key + memberInfo.name}>
{
fieldName === '' ? <></> :
<p className="text-base text-black-600 flex items-center" >
{fieldName}: {memberInfo[key]}
</p>
}
</div>
)
})
}
<div>
<p className="text-base text-black-600 flex items-center">
{isWorking ? '출근 완료' : '퇴근 완료'} {isLate ? '지각입니다' : ''}
</p>
<p className="text-base text-black-600 flex items-center">
{isWorking ? '출근시간: ' : '퇴근시간: '} {getCheckedHour(memberInfo.id)}
</p>
</div>
<button onClick={() => changeWorkingState(memberInfo.id)} className="" >{isWorking ? '퇴근' : '출근'}</button>
</div>
</div>
<div className="h-48 lg:h-auto w-128 lg:w-128 flex-none bg-cover rounded-t lg:rounded-t-none lg:rounded-l text-center overflow-hidden">
</div>
</div>
)
}

export default Card;
2 changes: 2 additions & 0 deletions reactStudy1week/src/components/Card.jsx:Zone.Identifier
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[ZoneTransfer]
ZoneId=3
3 changes: 3 additions & 0 deletions reactStudy1week/src/components/WorkingCheckButtom.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
function WorkingCheckButton() {

}
Loading