Skip to content
Snippets Groups Projects
Commit b15f63c4 authored by 조대희's avatar 조대희
Browse files

style: 스케줄 통합 및 더보기 버튼 추가 (#13)

parent 1f0133b6
Branches
No related tags found
1 merge request!21[#13] 스케줄 페이지 스타일 개선
Pipeline #10901 passed
......@@ -22,70 +22,74 @@ const generateTimeSlots = () => {
const days = ["", "", "", "", "", "", ""];
const dummySchedules = [
{
id: 1,
user_id: 1,
title: "알고리즘 스터디",
is_fixed: true,
time_indices: [36, 37, 38, 39],
createdAt: "2024-12-02T09:52:00.000Z",
updatedAt: "2024-12-02T09:52:00.000Z",
},
{
id: 5,
user_id: 1,
title: "웹시설 팀플",
is_fixed: true,
time_indices: [165, 166, 167, 255, 256, 257],
createdAt: "2024-12-02T09:54:53.000Z",
updatedAt: "2024-12-02T09:54:53.000Z",
},
{
id: 11,
user_id: 1,
title: "점심약속",
is_fixed: false,
time_indices: [240, 241, 242],
createdAt: "2024-12-02T09:54:53.000Z",
updatedAt: "2024-12-02T09:54:53.000Z",
},
{
id: 14,
user_id: 1,
title: "롤 5:5",
is_fixed: true,
time_indices: [302, 303, 304, 305, 306, 307],
createdAt: "2024-12-02T09:54:53.000Z",
updatedAt: "2024-12-02T09:54:53.000Z",
},
{
id: 20,
user_id: 1,
title: "토트넘 vs 첼시 경기",
is_fixed: true,
time_indices: [13, 14, 15, 16, 17, 18],
createdAt: "2024-12-02T09:54:53.000Z",
updatedAt: "2024-12-02T09:54:53.000Z",
}
];
// const dummySchedules = [
// {
// id: 1,
// user_id: 1,
// title: "알고리즘 스터디",
// is_fixed: true,
// time_indices: [36, 37, 38, 39],
// createdAt: "2024-12-02T09:52:00.000Z",
// updatedAt: "2024-12-02T09:52:00.000Z",
// },
// {
// id: 5,
// user_id: 1,
// title: "웹시설 팀플",
// is_fixed: true,
// time_indices: [165, 166, 167, 255, 256, 257],
// createdAt: "2024-12-02T09:54:53.000Z",
// updatedAt: "2024-12-02T09:54:53.000Z",
// },
// {
// id: 11,
// user_id: 1,
// title: "점심약속",
// is_fixed: false,
// time_indices: [240, 241, 242],
// createdAt: "2024-12-02T09:54:53.000Z",
// updatedAt: "2024-12-02T09:54:53.000Z",
// },
// {
// id: 14,
// user_id: 1,
// title: "롤 5:5",
// is_fixed: true,
// time_indices: [302, 303, 304, 305, 306, 307],
// createdAt: "2024-12-02T09:54:53.000Z",
// updatedAt: "2024-12-02T09:54:53.000Z",
// },
// {
// id: 20,
// user_id: 1,
// title: "토트넘 vs 첼시 경기",
// is_fixed: true,
// time_indices: [13, 14, 15, 16, 17, 18],
// createdAt: "2024-12-02T09:54:53.000Z",
// updatedAt: "2024-12-02T09:54:53.000Z",
// },
// {
// id: 26,
// user_id: 1,
// title: "아침 구보",
// is_fixed: true,
// time_indices: [34, 35, 130, 131, 226, 227, 322, 323, 418, 419, 514, 515, 610, 611],
// createdAt: "2024-12-02T09:54:53.000Z",
// updatedAt: "2024-12-02T09:54:53.000Z",
// },
// ];
const colorClasses = [
'bg-indigo-300',
'bg-purple-300',
'bg-pink-300',
'bg-blue-300',
'bg-green-300',
'bg-yellow-300',
'bg-red-300',
'bg-orange-300',
'bg-teal-300',
'bg-cyan-300',
'bg-rose-300',
'bg-violet-300',
'bg-fuchsia-300',
'bg-emerald-300',
'bg-lime-300'
'bg-indigo-300 hover:bg-indigo-400',
'bg-purple-300 hover:bg-purple-400',
'bg-pink-300 hover:bg-pink-400',
'bg-blue-300 hover:bg-blue-400',
'bg-green-300 hover:bg-green-400',
'bg-yellow-300 hover:bg-yellow-400',
'bg-red-300 hover:bg-red-400',
'bg-orange-300 hover:bg-orange-400',
'bg-teal-300 hover:bg-teal-400',
'bg-cyan-300 hover:bg-cyan-400',
];
const SchedulePage = () => {
const timeSlots = generateTimeSlots();
......@@ -97,13 +101,21 @@ const SchedulePage = () => {
const [newTitle, setNewTitle] = useState("");
const [isFixed, setIsFixed] = useState(true);
const [titleColorMap, setTitleColorMap] = useState(new Map());
const [showAllTimeSlot, setShowAllTimeSlot] = useState(false);
useEffect(() => {
// API
const initializeSchedules = async () => {
try {
const data = await fetchAllSchedules();
setSchedules(data);
// 스케줄 병합을 위해서 사용
const sortedSchedules = [...data].sort((a, b) => {
const aMin = Math.min(...a.time_indices);
const bMin = Math.min(...b.time_indices);
return aMin - bMin;
});
setSchedules(sortedSchedules);
} catch (error) {
console.error("Failed to load schedules", error);
}
......@@ -112,7 +124,7 @@ const SchedulePage = () => {
initializeSchedules();
// 임시 코드
setSchedules(dummySchedules);
// setSchedules(dummySchedules);
}, []);
useEffect(() => {
......@@ -278,13 +290,47 @@ const SchedulePage = () => {
const timeSlotIndex = timeIndex % 96;
const hour = Math.floor(timeSlotIndex / 4);
const minute = (timeSlotIndex % 4) * 15;
const day = days[dayIndex];
const time = `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`;
return `${day} ${time}`;
};
// 스케줄 통합해서 보여주기
const renderTimeSlot = (slotIndex, rowIndex, colIndex) => {
const schedule = schedules.find((s) => s.time_indices.includes(slotIndex));
const isSelected = selectedSlots.includes(slotIndex);
const isFirstSlot = schedule &&
!schedule.time_indices.includes(slotIndex - 1) &&
Math.floor((slotIndex - 1) / 96) === Math.floor(slotIndex / 96);
const isLastSlot = schedule &&
!schedule.time_indices.includes(slotIndex + 1) &&
Math.floor((slotIndex + 1) / 96) === Math.floor(slotIndex / 96);
return (
<div
key={slotIndex}
className={`p-2 border ${schedule
? `${getColorForTitle(schedule.title)} text-white
${!isFirstSlot && !isLastSlot ? 'border-t-0 border-b-0' : ''}
${!isFirstSlot ? 'border-t-0' : ''}
${!isLastSlot ? 'border-b-0' : ''}`
: isSelected
? "bg-primary-100 border-primary-300"
: "bg-grayscale-50"
} cursor-pointer`}
onClick={() => handleSlotClick(slotIndex)}
>
{isFirstSlot ? schedule?.title : ""}
</div>
);
};
const filterTimeSlots = (time) => {
const hour = parseInt(time.split(":")[0]);
return showAllTimeSlot || (hour >= 8 && hour <= 18);
};
return (
<div className="min-h-screen bg-grayscale-50">
......@@ -312,10 +358,22 @@ const SchedulePage = () => {
</label>
</div>
{/* 더보기 버튼 */}
<div className="flex justify-center mt-4">
<Label
theme="indigo"
size="lg"
className="cursor-pointer"
onClick={() => setShowAllTimeSlot(!showAllTimeSlot)}
>
{showAllTimeSlot ? "시간 접기" : "전체 시간 보기"}
</Label>
</div>
{/* Schedule Grid */}
<div className="p-4 pb-[210px]">
<div className="overflow-auto scrollbar-hide">
<div className="w-[100vw] tablet:w-[960px] grid grid-cols-[64px,repeat(7,1fr)] gap-2">
<div className="w-[100vw] tablet:w-[960px] grid grid-cols-[64px,repeat(7,1fr)] gap-0">
{/* Header */}
<div className="min-w-[54px] p-2 font-bold text-center bg-grayscale-200 select-none">
Time
......@@ -327,37 +385,21 @@ const SchedulePage = () => {
))}
{/* Time Slots */}
{timeSlots.map((time, rowIndex) => (
{timeSlots.map((time, rowIndex) => {
if (!filterTimeSlots(time)) return null;
return (
<React.Fragment key={rowIndex}>
{/* Time Column */}
<div className="min-w-[54px] p-2 font-bold text-center bg-grayscale-100 select-none">
{time}
</div>
{days.map((_, colIndex) => {
const slotIndex = colIndex * timeSlots.length + rowIndex;
const isSelected = selectedSlots.includes(slotIndex);
const schedule = schedules.find((s) =>
s.time_indices.includes(slotIndex)
);
return (
<div
key={slotIndex}
className={`p-2 border rounded ${
schedule
? `${getColorForTitle(schedule.title)} text-white`
: isSelected
? "bg-primary-100 border-primary-300"
: "bg-grayscale-50"
} cursor-pointer`}
onClick={() => handleSlotClick(slotIndex)}
>
{schedule ? schedule.title : ""}
</div>
);
return renderTimeSlot(slotIndex, rowIndex, colIndex);
})}
</React.Fragment>
))}
);
})}
</div>
</div>
</div>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment