-
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.
Merge pull request #35 from GDSC-Hongik/feature/my-study-layout
[Feature] 나의 스터디 페이지 UI 구축
- Loading branch information
Showing
25 changed files
with
1,017 additions
and
17 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
97 changes: 97 additions & 0 deletions
97
apps/client/app/(afterLogin)/my-study/_components/AssignmentStatusBox.tsx
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,97 @@ | ||
import { css } from "@styled-system/css"; | ||
import { Flex } from "@styled-system/jsx"; | ||
import { Text } from "@wow-class/ui"; | ||
import { parseISODate } from "@wow-class/utils"; | ||
import { assignmentSubmissionStatusMap } from "constants/assignmentSubmissionStatusMap"; | ||
import type { AssignmentSubmissionStatusType } from "types/entities/myStudy"; | ||
import Box from "wowds-ui/Box"; | ||
import Button from "wowds-ui/Button"; | ||
import Tag from "wowds-ui/Tag"; | ||
|
||
interface AssignmentStatusBoxProps { | ||
week: number; | ||
name: string; | ||
assignmentSubmissionStatus: AssignmentSubmissionStatusType; | ||
deadline: string; | ||
} | ||
|
||
const AssignmentStatusBox = ({ | ||
week, | ||
name, | ||
assignmentSubmissionStatus, | ||
deadline, | ||
}: AssignmentStatusBoxProps) => { | ||
const { year, month, day, hours, minutes } = parseISODate(deadline); | ||
|
||
const attendanceDeadline = `${year}년 ${month}월 ${day}일 ${hours}:${minutes}까지`; | ||
const { | ||
label: assignmentSubmissionStatusLabel, | ||
color: assignmentSubmissionStatusColor, | ||
} = assignmentSubmissionStatusMap[assignmentSubmissionStatus]; | ||
|
||
return ( | ||
<Box | ||
style={dailyTaskBoxStyle} | ||
text={ | ||
<Flex | ||
className={dailyTaskBoxContentContainerStyle} | ||
direction="column" | ||
justifyContent="space-between" | ||
> | ||
<Flex direction="column" gap="16px"> | ||
<Text as="div" color="primary" typo="label2"> | ||
과제 | ||
</Text> | ||
<Flex direction="column" gap="4px"> | ||
<Flex gap="8px"> | ||
<Text as="h2" typo="h2"> | ||
{week}주차 과제 | ||
</Text> | ||
<Tag color={assignmentSubmissionStatusColor} variant="solid2"> | ||
{assignmentSubmissionStatusLabel} | ||
</Tag> | ||
</Flex> | ||
<Text as="div" className={assignmentNameStyle} typo="body1"> | ||
{name} | ||
</Text> | ||
<Text as="div" color="sub" typo="body1"> | ||
{attendanceDeadline} | ||
</Text> | ||
</Flex> | ||
</Flex> | ||
<Button | ||
disabled={assignmentSubmissionStatus !== "SUCCESS"} | ||
size="lg" | ||
style={assignmentButtonStyle} | ||
> | ||
나의 과제 바로가기 | ||
</Button> | ||
</Flex> | ||
} | ||
/> | ||
); | ||
}; | ||
|
||
export default AssignmentStatusBox; | ||
|
||
const dailyTaskBoxStyle = { | ||
maxWidth: "376px", | ||
minWidth: "376px", | ||
paddingBottom: "20px", | ||
height: "229px", | ||
}; | ||
|
||
const dailyTaskBoxContentContainerStyle = css({ | ||
height: "185px", | ||
minWidth: "328px !important", | ||
}); | ||
|
||
const assignmentButtonStyle = { | ||
minWidth: "328px", | ||
}; | ||
|
||
const assignmentNameStyle = css({ | ||
whiteSpace: "nowrap", | ||
overflow: "hidden", | ||
textOverflow: "ellipsis", | ||
}); |
90 changes: 90 additions & 0 deletions
90
apps/client/app/(afterLogin)/my-study/_components/AttendanceStatusBox.tsx
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,90 @@ | ||
import { css } from "@styled-system/css"; | ||
import { Flex } from "@styled-system/jsx"; | ||
import { Text } from "@wow-class/ui"; | ||
import { parseISODate } from "@wow-class/utils"; | ||
import { attendanceStatusMap } from "constants/attendanceStatusMap"; | ||
import type { AttendanceStatusType } from "types/entities/myStudy"; | ||
import Box from "wowds-ui/Box"; | ||
import Button from "wowds-ui/Button"; | ||
import Tag from "wowds-ui/Tag"; | ||
|
||
interface AttendanceStatusBoxProps { | ||
week: number; | ||
attendanceStatus: AttendanceStatusType; | ||
period: { | ||
start: string; | ||
end: string; | ||
}; | ||
} | ||
|
||
const AttendanceStatusBox = ({ | ||
week, | ||
attendanceStatus, | ||
period, | ||
}: AttendanceStatusBoxProps) => { | ||
const { | ||
year: startYear, | ||
month: startMonth, | ||
day: startDay, | ||
hours: startHour, | ||
minutes: startMinute, | ||
} = parseISODate(period.start); | ||
const { hours: endHour, minutes: endMinute } = parseISODate(period.end); | ||
|
||
const attendancePeriod = `${startYear}년 ${startMonth}월 ${startDay}일 ${startHour}:${startMinute} - ${endHour}:${endMinute}까지`; | ||
const { label: attendanceStatusLabel, color: attendanceStatusColor } = | ||
attendanceStatusMap[attendanceStatus]; | ||
|
||
return ( | ||
<Box | ||
style={dailyTaskBoxStyle} | ||
text={ | ||
<Flex | ||
className={dailyTaskBoxContentContainerStyle} | ||
direction="column" | ||
justifyContent="space-between" | ||
> | ||
<Flex direction="column" gap="16px"> | ||
<Text as="div" color="primary" typo="label2"> | ||
출석 | ||
</Text> | ||
<Flex direction="column" gap="4px"> | ||
<Flex gap="8px"> | ||
<Text as="h2" typo="h2"> | ||
{week}주차 출석체크 | ||
</Text> | ||
<Tag color={attendanceStatusColor} variant="solid2"> | ||
{attendanceStatusLabel} | ||
</Tag> | ||
</Flex> | ||
<Text as="div" color="error" typo="body1"> | ||
{attendancePeriod} | ||
</Text> | ||
</Flex> | ||
</Flex> | ||
<Button size="lg" style={attendanceButtonStyle}> | ||
출석 체크하기 | ||
</Button> | ||
</Flex> | ||
} | ||
/> | ||
); | ||
}; | ||
|
||
export default AttendanceStatusBox; | ||
|
||
const dailyTaskBoxStyle = { | ||
maxWidth: "376px", | ||
minWidth: "376px", | ||
paddingBottom: "20px", | ||
height: "229px", | ||
}; | ||
|
||
const dailyTaskBoxContentContainerStyle = css({ | ||
height: "185px", | ||
minWidth: "328px !important", | ||
}); | ||
|
||
const attendanceButtonStyle = { | ||
minWidth: "328px", | ||
}; |
80 changes: 80 additions & 0 deletions
80
apps/client/app/(afterLogin)/my-study/_components/DailyTaskCarousel.tsx
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,80 @@ | ||
"use client"; | ||
|
||
import { css } from "@styled-system/css"; | ||
import { Flex } from "@styled-system/jsx"; | ||
import useHorizontalScroll from "hooks/useHorizontalScroll"; | ||
import Image from "next/image"; | ||
import { type PropsWithChildren, useEffect, useState } from "react"; | ||
|
||
const DailyTaskCarousel = ({ children }: PropsWithChildren) => { | ||
const [showRightButton, setShowRightButton] = useState(false); | ||
|
||
const itemWidth = 386; | ||
|
||
const { containerRef, handleScroll } = useHorizontalScroll(); | ||
|
||
useEffect(() => { | ||
if (containerRef.current) { | ||
const containerWidth = containerRef.current.offsetWidth; | ||
const totalChildrenWidth = Array.from(containerRef.current.children) | ||
.map((child) => (child as HTMLElement).offsetWidth) | ||
.reduce((acc, width) => acc + width, 0); | ||
|
||
if (totalChildrenWidth > containerWidth) { | ||
setShowRightButton(true); | ||
} | ||
} | ||
}, [containerRef]); | ||
|
||
const handleClickScrollRightButton = () => { | ||
if (containerRef.current) { | ||
const currentScrollPosition = containerRef.current.scrollLeft; | ||
const newScrollPosition = currentScrollPosition + itemWidth; | ||
|
||
handleScroll(newScrollPosition); | ||
} | ||
}; | ||
|
||
return ( | ||
<> | ||
<Flex | ||
aria-live="polite" | ||
className={dailyTaskBoxContainerStyle} | ||
gap="lg" | ||
ref={containerRef} | ||
> | ||
{children} | ||
</Flex> | ||
{showRightButton && ( | ||
<button | ||
aria-label="scroll-right-button" | ||
className={scrollRightButtonStyle} | ||
tabIndex={0} | ||
onClick={handleClickScrollRightButton} | ||
> | ||
<Image | ||
alt="scroll-right-button" | ||
height={52} | ||
src="/images/arrow-button.svg" | ||
width={52} | ||
/> | ||
</button> | ||
)} | ||
</> | ||
); | ||
}; | ||
|
||
export default DailyTaskCarousel; | ||
|
||
const dailyTaskBoxContainerStyle = css({ | ||
overflowX: "auto", | ||
scrollBehavior: "smooth", | ||
scrollbarWidth: "none", | ||
}); | ||
|
||
const scrollRightButtonStyle = css({ | ||
position: "absolute", | ||
top: "110px", | ||
right: "101px", | ||
cursor: "pointer", | ||
}); |
40 changes: 40 additions & 0 deletions
40
apps/client/app/(afterLogin)/my-study/_components/DailyTasks.tsx
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,40 @@ | ||
import { Flex } from "@styled-system/jsx"; | ||
import { Text } from "@wow-class/ui"; | ||
import { dailyTaskMockData } from "constants/mockData"; | ||
|
||
import { AttendanceStatusBox, DailyTaskCarousel } from "."; | ||
import AssignmentStatusBox from "./AssignmentStatusBox"; | ||
|
||
const DailyTasks = () => { | ||
return ( | ||
<section aria-label="daily-tasks"> | ||
<Flex direction="column" gap="xl" position="relative"> | ||
<Text typo="h2">오늘의 할 일</Text> | ||
<DailyTaskCarousel> | ||
{dailyTaskMockData.map((dailyTask, index) => { | ||
return dailyTask.type === "ATTENDANCE" ? ( | ||
<AttendanceStatusBox | ||
attendanceStatus={dailyTask.attendanceStatus} | ||
key={index} | ||
period={dailyTask.period} | ||
week={dailyTask.week} | ||
/> | ||
) : ( | ||
<AssignmentStatusBox | ||
deadline={dailyTask.deadline} | ||
key={index} | ||
name={dailyTask.name} | ||
week={dailyTask.week} | ||
assignmentSubmissionStatus={ | ||
dailyTask.assignmentSubmissionStatus | ||
} | ||
/> | ||
); | ||
})} | ||
</DailyTaskCarousel> | ||
</Flex> | ||
</section> | ||
); | ||
}; | ||
|
||
export default DailyTasks; |
Oops, something went wrong.