Skip to content

Commit

Permalink
Merge pull request YJU-OKURA#164 from dorimu0/feat/component
Browse files Browse the repository at this point in the history
出席簿と出席統計ページを追加
  • Loading branch information
Lainari authored Jun 19, 2024
2 parents e97da35 + 921ebc2 commit f929e46
Show file tree
Hide file tree
Showing 23 changed files with 677 additions and 23 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,10 @@
"@tanstack/react-query": "^5.17.10",
"@types/js-cookie": "^3.0.6",
"axios": "^1.6.5",
"date-fns": "^3.6.0",
"ion-sdk-js": "^1.8.2",
"js-cookie": "^3.0.5",
"moment": "^2.30.1",
"ion-sdk-js": "^1.8.2",
"next": "14.0.4",
"react": "^18",
"react-calendar": "^4.8.0",
Expand Down
1 change: 1 addition & 0 deletions public/images/navbar/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const test = {
user: '/images/navbar/user.png',
school: '/images/navbar/schoolMark.png',
};

export default test;
Binary file added public/images/navbar/schoolMark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions public/svgs/attendance/edit.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions public/svgs/attendance/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const icons = {
edit: '/svgs/attendance/edit.svg',
};

export default icons;
9 changes: 9 additions & 0 deletions src/api/attendance/getAttendance.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import req from '../apiUtils';

const getAttendance = async (csId: number) => {
const response = await req(`/at/attendance/${csId}`, 'get', 'gin');

return response;
};

export default getAttendance;
9 changes: 9 additions & 0 deletions src/api/attendance/getAttendances.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import req from '../apiUtils';

const getAttendances = async (cId: number) => {
const response = await req(`/at/${cId}`, 'get', 'gin');

return response;
};

export default getAttendances;
10 changes: 10 additions & 0 deletions src/api/attendance/postAttendance.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import {Attendance} from '@/src/interfaces/attendance';
import req from '../apiUtils';

const postAttendance = async (users: Attendance[]) => {
const response = await req('/at', 'post', 'gin', users);

return response;
};

export default postAttendance;
151 changes: 151 additions & 0 deletions src/app/classes/[cId]/[mId]/components/Attendance.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
import icons from '@/public/svgs/attendance';
import getAttendance from '@/src/api/attendance/getAttendance';
import postAttendance from '@/src/api/attendance/postAttendance';
import type {Attendance, AttendanceUser} from '@/src/interfaces/attendance';
import Image from 'next/image';
import {useEffect, useState} from 'react';

const Attendance = () => {
const [AttendanceUsers, setAttendanceUsers] = useState<AttendanceUser[]>([]);
const [isModify, setIsModify] = useState<boolean[]>([]);
const [selectedOption, setSelectedOption] = useState('');
const [isReload, setIsReload] = useState<boolean>(false);
console.log(isModify);

useEffect(() => {
getAttendance(10).then(res => {
console.log(res.data);
setAttendanceUsers(res.data);
setSelectedOption(res.data[0].IsAttendance);
setIsModify(new Array(res.data.length).fill(false));
});
}, [isReload]);

const handleClickModify = (
uid: number,
cid: number,
csid: number,
status: string
) => {
console.log(uid, cid, csid, status);
const user: Attendance[] = [
{
uid: uid,
cid: cid,
csid: csid,
status: status,
},
];

if (user)
postAttendance(user).then(res => {
setIsReload(!isReload);
console.log(res);
});
};

const handleSelectChange = (event: React.ChangeEvent<HTMLSelectElement>) => {
setSelectedOption(event.target.value);
};

const isModifyOpen = (index: number) => {
console.log(index);
setIsModify(prev => prev.map((open, i) => (i === index ? !open : open))); // クリックしたコメントの開閉状態を反転
};

return (
<div className="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 z-50">
<div
className=" bg-white rounded-lg w-[800px] h-[600px] py-[30px] box-border flex items-center"
id="modal-container"
>
<div className="w-full h-[500px]">
<div className="text-xl font-semibold text-center">Attendance</div>
<div className="text-lg font-semibold text-green-400 text-center">
출석률 : 100%
</div>
<div className="p-5 overflow-scroll">
{AttendanceUsers.map((user, index) => (
<div key={index}>
<div className="bg-gray-100 flex justify-between items-center p-3 rounded-lg mb-3 font-semibold text-lg">
<span className="flex justify-center items-center w-[450px]">
<span>{index + 1}.</span>
<div className="w-[35px] h-[35px] ml-3 rounded-full overflow-hidden">
<Image
src={user.ClassUser.User.Image}
width={35}
height={35}
alt="image"
/>{' '}
</div>
<span className="w-[350px] text-start px-5">
{user.ClassUser.Nickname}
</span>
</span>

<span className="w-[120px]">
{isModify[index] ? (
<div className="flex">
<select
name=""
id=""
onChange={handleSelectChange}
value={user.IsAttendance}
>
<option value="ATTENDANCE">출석</option>
<option value="TARDY">지각</option>
<option value="ABSENCE">결석</option>
</select>
<div>
<button
className="px-2"
onClick={() =>
handleClickModify(
user.UID,
user.CID,
user.CSID,
selectedOption
)
}
>
수정
</button>
</div>
</div>
) : (
<div className="flex items-center">
<div>
{user.IsAttendance === 'ATTENDANCE'
? '출석'
: user.IsAttendance === 'TARDY'
? '지각'
: '결석'}
</div>
<span
className="px-2"
onClick={() => {
isModifyOpen(index);
}}
>
<Image
src={icons.edit}
width={20}
height={20}
alt="icon"
className="opacity-60"
/>
</span>
</div>
)}
</span>
</div>
</div>
))}
</div>
</div>
</div>
</div>
);
};

export default Attendance;
118 changes: 118 additions & 0 deletions src/app/classes/[cId]/[mId]/components/AttendanceCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import getClassMember from '@/src/api/classUser/getClassMember';
import {useEffect, useState} from 'react';
import {ClassUser} from '@/src/interfaces/user';
import {Attendance} from '@/src/interfaces/attendance';
import postAttendance from '@/src/api/attendance/postAttendance';

const AttendanceCard = ({cid}: {cid: number; uid: number}) => {
const [users, setUsers] = useState<ClassUser[]>([]);
const [submitUsers, setSubmitUsers] = useState<Attendance[]>([]);
const [isOpen, setIsOpen] = useState<boolean>(false);

useEffect(() => {
getClassMember(cid).then(res => {
console.log(res);
setUsers(res);

// コンポーネントを結合した後、値を受け取って使用するように修正する必要があります。
const uids = res.map((user: ClassUser) => ({
uid: user.uid,
cid: cid,
csid: 10,
status: '',
}));
setSubmitUsers(uids);
});
}, []);

const handleClickStatus = (id: number, status: string) => {
const updatedUsers = submitUsers.map(user =>
user.uid === id ? {...user, status: status} : user
);
console.log(updatedUsers);
setSubmitUsers(updatedUsers);
};

const handleClickSave = () => {
postAttendance(submitUsers).then(() => {
console.log('save');
setIsOpen(false);
});
};

return (
<div>
<div>
<button
className="px-3 py-1 bg-blue-400 text-white rounded-lg"
onClick={() => {
setIsOpen(true);
}}
>
출석부
</button>
</div>
{isOpen ? (
<div className="fixed inset-0 z-20 flex items-center justify-center bg-black bg-opacity-50">
<div
className=" bg-white rounded-lg w-[500px] h-[630px] px-4 py-10 box-border"
id="modal-container"
>
<div className="text-center text-lg text-gray-500">출석부</div>
<div className="relative h-[calc(100%-28px)]">
{users.map((user, index) => (
<div
className="border-b-2 flex justify-between items-center p-2"
key={index}
>
<span className="w-[30px] text-center">{index + 1}.</span>
<div className="w-[200px] text-start">
<p className="text-clip overflow-hidden">{user.nickname}</p>
</div>
<div>
<button
className="px-3 hover:bg-gray-200 border-s-2"
onClick={() => handleClickStatus(user.uid, 'ATTENDANCE')}
>
출석
</button>
<button
className="px-2 hover:bg-gray-200 border-s-2"
onClick={() => handleClickStatus(user.uid, 'TARDY')}
>
지각
</button>
<button
className="px-2 hover:bg-gray-200 border-s-2"
onClick={() => handleClickStatus(user.uid, 'ABSENCE')}
>
결석
</button>
</div>
</div>
))}
<div className="absolute w-full bottom-0 pt-2 flex justify-center ">
<button
className="px-3 py-1 bg-red-400 text-white rounded-lg mr-4"
onClick={() => {
setIsOpen(false);
}}
>
닫기
</button>
<button
className="px-3 py-1 bg-blue-400 text-white rounded-lg"
onClick={handleClickSave}
>
저장
</button>
</div>
</div>
</div>
</div>
) : null}
</div>
);
};

export default AttendanceCard;
Loading

0 comments on commit f929e46

Please sign in to comment.