-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
[Feat] 과외방 목록
- Loading branch information
Showing
8 changed files
with
340 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,14 @@ | ||
import './App.css'; | ||
import { router } from './routes/Router'; | ||
import { RouterProvider } from 'react-router-dom'; | ||
import { RoomProvider } from './context/RoomContext'; | ||
|
||
function App() { | ||
return <RouterProvider router={router} />; | ||
return ( | ||
<RoomProvider> | ||
<RouterProvider router={router} /> | ||
</RoomProvider> | ||
); | ||
} | ||
|
||
export default App; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import { Permission } from '../context/RoomContext'; | ||
|
||
type TypeProps = { | ||
type: Permission; | ||
handleCheck: (id: number) => void; | ||
}; | ||
|
||
const PermissionToggle = ({ type, handleCheck }: TypeProps) => { | ||
return ( | ||
<div className="flex"> | ||
{type.title} | ||
<input | ||
id={`permission-${type.id}`} | ||
type="checkbox" | ||
checked={type.isChecked} | ||
className="hidden" | ||
onChange={() => handleCheck(type.id)} | ||
/> | ||
<label | ||
htmlFor={`permission-${type.id}`} | ||
className={`relative block w-10 h-6 bg-gray-100 rounded-lg cursor-pointer transition ${type.isChecked ? 'bg-green-400' : 'bg-gray-200'} | ||
before:content-[''] | ||
before:absolute before:top-0.5 before:left-0.5 | ||
before:w-5 before:h-5 before:bg-white before:rounded-full before:transition | ||
${type.isChecked ? 'before:translate-x-4' : ''}`} | ||
/> | ||
</div> | ||
); | ||
}; | ||
|
||
export default PermissionToggle; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import { MdDeleteOutline } from 'react-icons/md'; | ||
import { CiEdit } from 'react-icons/ci'; | ||
import { Room, useRoomContext } from '../context/RoomContext'; | ||
|
||
type RoomProps = { | ||
room: Room; | ||
}; | ||
|
||
const RoomInfo = ({ room }: RoomProps) => { | ||
const { onDelete } = useRoomContext(); | ||
|
||
const handleDelete = (id: number) => { | ||
onDelete(id); | ||
}; | ||
|
||
return ( | ||
<div className="flex items-center py-2.5 gap-4 px-4"> | ||
<div className="flex items-center p-1.5"> | ||
<img className="w-9 h-9" /> | ||
</div> | ||
<div className="flex flex-1 flex-col text-gray-900 cursor-pointer"> | ||
<h1 className="text-body1 font-bold leading-9">{room.roomName}</h1> | ||
<h3 className="text-body4 font-regular leading-6">학생이름</h3> | ||
</div> | ||
<div className="cursor-pointer"> | ||
<CiEdit size={20} /> | ||
</div> | ||
<div className="cursor-pointer" onClick={() => handleDelete(room.id)}> | ||
<MdDeleteOutline size={20} /> | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
export default RoomInfo; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import { Day } from '../context/RoomContext'; | ||
|
||
type DayProps = { | ||
day: Day; | ||
handleClick: (id: number) => void; | ||
}; | ||
|
||
const SelectDate = ({ day, handleClick }: DayProps) => { | ||
return ( | ||
<div> | ||
<button | ||
className={`px-4 text-white ${day.isClicked ? 'bg-black' : 'bg-gray-300'}`} | ||
onClick={() => handleClick(day.id)} | ||
> | ||
{day.date} | ||
</button> | ||
</div> | ||
); | ||
}; | ||
export default SelectDate; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
import { createContext, ReactNode, useContext, useState, useRef } from 'react'; | ||
|
||
export type Day = { | ||
id: number; | ||
date: string; | ||
isClicked: boolean; | ||
}; | ||
|
||
export type Permission = { | ||
id: number; | ||
type: string; | ||
title: string; | ||
isChecked: boolean; | ||
}; | ||
|
||
export type Room = { | ||
id: number; | ||
roomName: string; | ||
subject: string; | ||
days: string[]; | ||
pMaterials: boolean; | ||
pHomework: boolean; | ||
pStats: boolean; | ||
pCounseling: true; | ||
pPayment: true; | ||
sMaterials: true; | ||
sHomework: true; | ||
sStats: true; | ||
sCounseling: boolean; | ||
sPayment: boolean; | ||
}; | ||
|
||
type RoomContextType = { | ||
rooms: Room[]; | ||
onCreate: ( | ||
roomName: string, | ||
subject: string, | ||
days: string[], | ||
pMaterials: boolean, | ||
pHomework: boolean, | ||
pStats: boolean, | ||
sCounseling: boolean, | ||
sPayment: boolean, | ||
) => void; | ||
onDelete: (id: number) => void; | ||
}; | ||
|
||
const RoomContext = createContext<RoomContextType | undefined>(undefined); | ||
|
||
export const useRoomContext = () => { | ||
const context = useContext(RoomContext); | ||
if (!context) { | ||
throw new Error('context 오류 발생'); | ||
} | ||
return context; | ||
}; | ||
|
||
export const RoomProvider = ({ children }: { children: ReactNode }) => { | ||
const [rooms, setRooms] = useState<Room[]>([]); | ||
const idRef = useRef(0); | ||
|
||
const onCreate = ( | ||
roomName: string, | ||
subject: string, | ||
days: string[], | ||
pMaterials: boolean, | ||
pHomework: boolean, | ||
pStats: boolean, | ||
sCounseling: boolean, | ||
sPayment: boolean, | ||
) => { | ||
const newRoom: Room = { | ||
id: idRef.current++, | ||
roomName: roomName, | ||
subject: subject, | ||
days: days, | ||
pMaterials: pMaterials, | ||
pHomework: pHomework, | ||
pStats: pStats, | ||
pCounseling: true, | ||
pPayment: true, | ||
sMaterials: true, | ||
sHomework: true, | ||
sStats: true, | ||
sCounseling: sCounseling, | ||
sPayment: sPayment, | ||
}; | ||
setRooms([...rooms, newRoom]); | ||
}; | ||
|
||
const onDelete = (id: number) => { | ||
setRooms(rooms.filter((room) => room.id !== id)); | ||
}; | ||
|
||
return <RoomContext.Provider value={{ rooms, onCreate, onDelete }}>{children}</RoomContext.Provider>; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
import PermissionToggle from '../components/PermissionToggle'; | ||
import SelectDate from '../components/SelectDate'; | ||
import { useEffect, useState } from 'react'; | ||
import { useRoomContext } from '../context/RoomContext'; | ||
import { Day, Permission } from '../context/RoomContext'; | ||
import { useNavigate } from 'react-router-dom'; | ||
|
||
const CreateRoom = () => { | ||
const navigate = useNavigate(); | ||
const { onCreate, rooms } = useRoomContext(); | ||
const [roomName, setRoomName] = useState(''); | ||
const [subject, setSubject] = useState(''); | ||
const [dayList, setDayList] = useState<Day[]>([ | ||
{ id: 0, date: '월', isClicked: false }, | ||
{ id: 1, date: '화', isClicked: false }, | ||
{ id: 2, date: '수', isClicked: false }, | ||
{ id: 3, date: '목', isClicked: false }, | ||
{ id: 4, date: '금', isClicked: false }, | ||
{ id: 5, date: '토', isClicked: false }, | ||
{ id: 6, date: '일', isClicked: false }, | ||
]); | ||
const [days, setDays] = useState<string[]>([]); | ||
|
||
const [parentP, setparentP] = useState<Permission[]>([ | ||
{ id: 0, type: 'materials', title: '강의 자료함', isChecked: false }, | ||
{ id: 1, type: 'homework', title: '주차별 숙제', isChecked: false }, | ||
{ id: 2, type: 'stats', title: '성적 통계', isChecked: false }, | ||
{ id: 3, type: 'counseling', title: '상담 일지', isChecked: true }, | ||
{ id: 4, type: 'payment', title: '입금', isChecked: true }, | ||
]); | ||
const [studentP, setstudentP] = useState<Permission[]>([ | ||
{ id: 5, type: 'materials', title: '강의 자료함', isChecked: true }, | ||
{ id: 6, type: 'homework', title: '주차별 숙제', isChecked: true }, | ||
{ id: 7, type: 'stats', title: '성적 통계', isChecked: true }, | ||
{ id: 8, type: 'counseling', title: '상담 일지', isChecked: false }, | ||
{ id: 9, type: 'payment', title: '입금', isChecked: false }, | ||
]); | ||
|
||
const handleClick = (id: number) => { | ||
setDayList(dayList.map((day) => (id === day.id ? { ...day, isClicked: !day.isClicked } : day))); | ||
}; | ||
|
||
useEffect(() => { | ||
const selectedDays = dayList.filter((day) => day.isClicked).map((day) => day.date); | ||
setDays(selectedDays); | ||
}, [dayList]); | ||
|
||
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => { | ||
if (e.target.placeholder === '방이름') setRoomName(e.target.value); | ||
if (e.target.placeholder === '과목명') setSubject(e.target.value); | ||
}; | ||
|
||
const handleCheck = (id: number) => { | ||
if (id >= 3 && id <= 7) return; | ||
else if (id < 5) | ||
setparentP(parentP.map((type) => (id === type.id ? { ...type, isChecked: !type.isChecked } : type))); | ||
else if (id >= 5) | ||
setstudentP(studentP.map((type) => (id === type.id ? { ...type, isChecked: !type.isChecked } : type))); | ||
}; | ||
console.log(rooms); | ||
|
||
const handleCreate = ( | ||
roomName: string, | ||
subject: string, | ||
days: string[], | ||
pMaterials: boolean, | ||
pHomework: boolean, | ||
pStats: boolean, | ||
sCounseling: boolean, | ||
sPayment: boolean, | ||
) => { | ||
onCreate( | ||
roomName, | ||
subject, | ||
days, | ||
parentP[0].isChecked, | ||
parentP[1].isChecked, | ||
parentP[2].isChecked, | ||
studentP[3].isChecked, | ||
studentP[4].isChecked, | ||
); | ||
navigate('/user/roomlist'); | ||
}; | ||
return ( | ||
<div className="flex flex-col gap-16"> | ||
<input placeholder="방이름" onChange={handleChange} value={roomName} /> | ||
<input placeholder="과목명" onChange={handleChange} value={subject} /> | ||
<div className="flex gap-4 justify-center"> | ||
{dayList.map((day) => ( | ||
<SelectDate key={day.id} day={day} handleClick={handleClick} /> | ||
))} | ||
</div> | ||
<div className="flex justify-between"> | ||
<div className="flex flex-col"> | ||
<h1>학부모 권한설정</h1> | ||
{parentP.map((type) => ( | ||
<PermissionToggle key={type.id} type={type} handleCheck={handleCheck} /> | ||
))} | ||
</div> | ||
<div className="flex flex-col"> | ||
<h1>학생 권한설정</h1> | ||
{studentP.map((type) => ( | ||
<PermissionToggle key={type.id} type={type} handleCheck={handleCheck} /> | ||
))} | ||
</div> | ||
</div> | ||
|
||
<button | ||
onClick={() => | ||
handleCreate( | ||
roomName, | ||
subject, | ||
days, | ||
parentP[0].isChecked, | ||
parentP[1].isChecked, | ||
parentP[2].isChecked, | ||
studentP[3].isChecked, | ||
studentP[4].isChecked, | ||
) | ||
} | ||
className="text-white" | ||
> | ||
완료 | ||
</button> | ||
</div> | ||
); | ||
}; | ||
export default CreateRoom; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,26 @@ | ||
import { useNavigate } from 'react-router-dom'; | ||
import RoomInfo from '../components/RoomInfo'; | ||
import { useRoomContext } from '../context/RoomContext'; | ||
|
||
const RoomList = () => { | ||
return <div>RoomList</div>; | ||
const navigate = useNavigate(); | ||
const { rooms } = useRoomContext(); | ||
console.log(rooms); | ||
|
||
return ( | ||
<div className="flex flex-col"> | ||
<div> | ||
{rooms.map((room) => ( | ||
<RoomInfo key={room.id} room={room} /> | ||
))} | ||
</div> | ||
<div className="flex justify-end py-8"> | ||
<button onClick={() => navigate('createroom')} className="text-white px-4"> | ||
+ 과외방 개설 | ||
</button> | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
export default RoomList; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters