Skip to content

Commit

Permalink
Merge pull request #35 from GDSC-Hongik/feature/my-study-layout
Browse files Browse the repository at this point in the history
[Feature] 나의 스터디 페이지 UI 구축
  • Loading branch information
ghdtjgus76 authored Aug 20, 2024
2 parents ded17a5 + 796c745 commit 7afab22
Show file tree
Hide file tree
Showing 25 changed files with 1,017 additions and 17 deletions.
2 changes: 1 addition & 1 deletion apps/client/app/(afterLogin)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const Layout = ({ children }: { children: React.ReactNode }) => {
return (
<>
<Navbar />
<styled.main paddingTop="3.375rem" paddingX="6.31rem" width="100vw">
<styled.main padding="54px 0 35px 101px" width="calc(100vw - 351px)">
{children}
</styled.main>
</>
Expand Down
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",
});
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",
};
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 apps/client/app/(afterLogin)/my-study/_components/DailyTasks.tsx
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;
Loading

0 comments on commit 7afab22

Please sign in to comment.