From 129fb06ee58c7c0d0c2463edb4dcdf1581265259 Mon Sep 17 00:00:00 2001 From: "SeungJu, Lee" <84257439+SeungJL@users.noreply.github.com> Date: Thu, 29 Aug 2024 15:10:13 +0900 Subject: [PATCH 01/11] add and refactor homeRecommendation Section (#217) --- .../cards/RecommendationBannerCard.tsx | 43 +++++++++++++++++++ constants/contents/HomeRecommendationTab.ts | 24 +++++++++++ pageTemplates/home/HomeRankingSection.tsx | 29 +++---------- pageTemplates/home/HomeTab.tsx | 10 ++--- pages/home/index.tsx | 4 +- 5 files changed, 79 insertions(+), 31 deletions(-) create mode 100644 components/organisms/cards/RecommendationBannerCard.tsx create mode 100644 constants/contents/HomeRecommendationTab.ts diff --git a/components/organisms/cards/RecommendationBannerCard.tsx b/components/organisms/cards/RecommendationBannerCard.tsx new file mode 100644 index 000000000..fd8936aab --- /dev/null +++ b/components/organisms/cards/RecommendationBannerCard.tsx @@ -0,0 +1,43 @@ +import { AspectRatio, Box, Button, Flex } from "@chakra-ui/react"; +import Image from "next/image"; +import Link from "next/link"; + +export interface RecommendationBannerCardProps { + title: string; + text: string; + bannerImage: string; + buttonProps: { + link: string; + text: string; + }; +} + +function RecommendationBannerCard({ + title, + text, + bannerImage, + buttonProps, +}: RecommendationBannerCardProps) { + return ( + + + {title} + + + + {title} + + + {text} + + + + + + + + + ); +} + +export default RecommendationBannerCard; diff --git a/constants/contents/HomeRecommendationTab.ts b/constants/contents/HomeRecommendationTab.ts new file mode 100644 index 000000000..98ff2ef58 --- /dev/null +++ b/constants/contents/HomeRecommendationTab.ts @@ -0,0 +1,24 @@ +import { RecommendationBannerCardProps } from "../../components/organisms/cards/RecommendationBannerCard"; + +export const HOME_RECOMMENDATION_TAB_CONTENTS: RecommendationBannerCardProps[] = [ + { + title: "동아리 점수 랭킹 페이지", + text: "동아리 활동을 통해 얻은 점수를 확인하고 자신의 랭킹과 활동 기록을 한눈에 볼 수 있는 공간입니다. 다양한 활동을 통해 점수를 획득하고, 본인의 순위를 확인해 보세요!", + bannerImage: + "https://studyabout.s3.ap-northeast-2.amazonaws.com/%EB%B0%B0%EB%84%88/%EB%9E%AD%ED%82%B9+%EB%B0%B0%EB%84%88.png", + buttonProps: { + link: "/statistics", + text: "랭킹 페이지로 이동하기", + }, + }, + { + title: "ABOUT 디스코드 채널", + text: "온라인에서도 활발하게 스터디를 진행하고 있습니다! 다양한 컨셉의 스터디 채널이 있으니, 디스코드 서버에 방문하고 같이 공부해요!", + bannerImage: + "https://studyabout.s3.ap-northeast-2.amazonaws.com/%EB%B0%B0%EB%84%88/%EB%94%94%EC%8A%A4%EC%BD%94%EB%93%9C+%EB%B0%B0%EB%84%88.jpg", + buttonProps: { + link: "https://discord.gg/dDu2kg2uez", + text: "디스코드 서버로 이동하기", + }, + }, +]; diff --git a/pageTemplates/home/HomeRankingSection.tsx b/pageTemplates/home/HomeRankingSection.tsx index 9aacc6889..351edc77e 100644 --- a/pageTemplates/home/HomeRankingSection.tsx +++ b/pageTemplates/home/HomeRankingSection.tsx @@ -1,31 +1,12 @@ -import { AspectRatio, Box, Button, Flex } from "@chakra-ui/react"; -import Image from "next/image"; -import Link from "next/link"; +import RecommendationBannerCard from "../../components/organisms/cards/RecommendationBannerCard"; +import { HOME_RECOMMENDATION_TAB_CONTENTS } from "../../constants/contents/HomeRecommendationTab"; function HomeRankingSection() { return ( <> - - rankingBanner - - - - 동아리 점수 랭킹 페이지 - - - 동아리 활동을 통해 얻은 점수를 확인하고 자신의 랭킹과 활동 기록을 한눈에 볼 수 있는 - 공간입니다. 다양한 활동을 통해 점수를 획득하고, 본인의 순위를 확인해 보세요! - - - - - - - + {HOME_RECOMMENDATION_TAB_CONTENTS.map((content) => ( + + ))} ); } diff --git a/pageTemplates/home/HomeTab.tsx b/pageTemplates/home/HomeTab.tsx index 27ce4b98b..bfa4e6362 100644 --- a/pageTemplates/home/HomeTab.tsx +++ b/pageTemplates/home/HomeTab.tsx @@ -12,7 +12,7 @@ import { LocationEn } from "../../types/services/locationTypes"; import { convertLocationLangTo } from "../../utils/convertUtils/convertDatas"; import { getUrlWithLocationAndDate } from "../../utils/convertUtils/convertTypes"; -export type HomeTab = "스터디" | "번개" | "캘린더" | "랭킹"; +export type HomeTab = "스터디" | "번개" | "캘린더" | "추천"; interface HomeTabProps { tab: HomeTab; @@ -34,7 +34,7 @@ function HomeTab({ tab: category, setTab: setCategory }: HomeTabProps) { study: "스터디", gather: "번개", club: "캘린더", - temp: "랭킹", + temp: "추천", }; useEffect(() => { @@ -63,7 +63,7 @@ function HomeTab({ tab: category, setTab: setCategory }: HomeTabProps) { `/home?tab=gather&location=${locationParam || convertLocationLangTo(session?.user.location || "suw", "en")}`, ); } - if (tab === "랭킹") { + if (tab === "추천") { router.replace(`/home?tab=temp`); } if (tab === "캘린더") { @@ -95,8 +95,8 @@ function HomeTab({ tab: category, setTab: setCategory }: HomeTabProps) { flex: 1, }, { - text: "랭킹", - func: () => handleTabMove("랭킹"), + text: "추천", + func: () => handleTabMove("추천"), flex: 1, }, ]; diff --git a/pages/home/index.tsx b/pages/home/index.tsx index 1f38c7e4a..09c55ad0b 100644 --- a/pages/home/index.tsx +++ b/pages/home/index.tsx @@ -20,14 +20,14 @@ function Home() { <> - {tab !== "랭킹" && } + {tab !== "추천" && } {tab === "스터디" ? ( ) : tab === "번개" ? ( ) : tab === "캘린더" ? ( - ) : tab === "랭킹" ? ( + ) : tab === "추천" ? ( ) : null} From a355fee7c3b77b7f8a7c39bb785c426a9e9f314e Mon Sep 17 00:00:00 2001 From: LSJ Date: Mon, 2 Sep 2024 12:23:38 +0900 Subject: [PATCH 02/11] feat: calendar --- components/atoms/ColorLabel.tsx | 24 ++ components/atoms/LocationSelector.tsx | 4 +- components/atoms/MonthNav.tsx | 42 +-- components/atoms/PointCircle.tsx | 5 +- components/atoms/PointCircleText.tsx | 22 -- components/molecules/PointCircleTextRow.tsx | 21 -- components/molecules/groups/ButtonGroups.tsx | 58 ++-- components/molecules/rows/ColorLabelRow.tsx | 21 ++ components/organisms/Calendar.tsx | 200 ++++++++++++ .../calendarSchedule.ts} | 168 +++++++--- constants/contentsText/accordionContents.ts | 2 +- constants/location.ts | 27 +- .../studyConstants/studyLocationConstants.ts | 1 - modals/InviteUserModal.tsx | 4 +- pageTemplates/gather/GatherLocationFilter.tsx | 6 +- pageTemplates/home/HomeCalendarSection.tsx | 50 +++ pageTemplates/home/HomeClubSection.tsx | 272 ---------------- pageTemplates/home/HomeRankingSection.tsx | 2 +- pageTemplates/home/HomeReviewSection.tsx | 2 +- pageTemplates/home/study/HomeStudyChart.tsx | 13 +- pageTemplates/home/study/HomeStudyCol.tsx | 4 +- .../study/studyController/StudyController.tsx | 4 +- pageTemplates/record/RecordCalendar.tsx | 154 +++++---- .../record/RecordCalendarSetting.tsx | 17 +- .../record/RecordLocationCategory.tsx | 87 ++--- pageTemplates/record/RecordOverview.tsx | 1 - pageTemplates/record/RecordSkeleton.tsx | 300 ------------------ .../record/detail/RecordDetailStudyBlock.tsx | 6 +- .../register/location/LocationMember.tsx | 4 +- .../SecretSquare/SecretSquareCategories.tsx | 8 +- pageTemplates/square/SquareLoungeSection.tsx | 30 +- pages/calendar/index.tsx | 11 +- pages/eventCalendar.tsx | 278 ---------------- pages/home/index.tsx | 4 +- pages/review/index.tsx | 6 +- pages/study/writing/place.tsx | 14 +- 36 files changed, 695 insertions(+), 1177 deletions(-) create mode 100644 components/atoms/ColorLabel.tsx delete mode 100644 components/atoms/PointCircleText.tsx delete mode 100644 components/molecules/PointCircleTextRow.tsx create mode 100644 components/molecules/rows/ColorLabelRow.tsx create mode 100644 components/organisms/Calendar.tsx rename constants/{settingValue/eventContents.ts => contents/calendarSchedule.ts} (59%) create mode 100644 pageTemplates/home/HomeCalendarSection.tsx delete mode 100644 pageTemplates/home/HomeClubSection.tsx delete mode 100644 pageTemplates/record/RecordSkeleton.tsx delete mode 100644 pages/eventCalendar.tsx diff --git a/components/atoms/ColorLabel.tsx b/components/atoms/ColorLabel.tsx new file mode 100644 index 000000000..aed3712e5 --- /dev/null +++ b/components/atoms/ColorLabel.tsx @@ -0,0 +1,24 @@ +import { Box, Flex } from "@chakra-ui/react"; + +import { CustomColor } from "../../types/globals/interaction"; +import PointCircle from "./PointCircle"; + +export interface ColorLabelProps { + color?: CustomColor; + colorText?: string; + //이후 colorText를 color로 변경 + text: string; +} + +function ColorLabel({ text, color, colorText }: ColorLabelProps) { + return ( + + + + {text} + + + ); +} + +export default ColorLabel; diff --git a/components/atoms/LocationSelector.tsx b/components/atoms/LocationSelector.tsx index eec5cf27e..19525d2ba 100644 --- a/components/atoms/LocationSelector.tsx +++ b/components/atoms/LocationSelector.tsx @@ -1,7 +1,7 @@ import { Select } from "@chakra-ui/react"; import { ChangeEvent, useEffect, useRef, useState } from "react"; -import { LOCATION_CONVERT } from "../../constants/location"; +import { LOCATION_TO_FULLNAME } from "../../constants/location"; import { DispatchType } from "../../types/hooks/reactTypes"; import { ActiveLocation } from "../../types/services/locationTypes"; import { isLocationType } from "../../utils/validationUtils"; @@ -57,7 +57,7 @@ export default function LocationSelector({ > {options.map((option, idx) => ( ))} diff --git a/components/atoms/MonthNav.tsx b/components/atoms/MonthNav.tsx index e63628145..f23a4dac0 100644 --- a/components/atoms/MonthNav.tsx +++ b/components/atoms/MonthNav.tsx @@ -1,42 +1,30 @@ +import { Box, Flex } from "@chakra-ui/react"; import { Dayjs } from "dayjs"; -import styled from "styled-components"; import { DispatchType } from "../../types/hooks/reactTypes"; -interface IMonthNav { - month: number; - setNavMonth: DispatchType; +interface MonthNavProps { + monthNum: number; + changeMonth: DispatchType; } -function MonthNav({ month, setNavMonth }: IMonthNav) { - const onClick = (dir: "left" | "right") => { - if (dir === "left") setNavMonth((old) => old.subtract(1, "month")); - else setNavMonth((old) => old.add(1, "month")); +function MonthNav({ monthNum, changeMonth }: MonthNavProps) { + const handleMonthChange = (dir: "left" | "right") => { + if (dir === "left") changeMonth((old) => old.subtract(1, "month")); + else changeMonth((old) => old.add(1, "month")); }; return ( - - onClick("left")}> + + handleMonthChange("left")}> - - {month + 1}월 - onClick("right")}> + + {monthNum + 1}월 + handleMonthChange("right")}> - - + + ); } -const Layout = styled.div` - display: flex; - align-items: center; - - font-size: 20px; - font-weight: 700; -`; - -const IconWrapper = styled.button` - padding: 0 var(--gap-1); -`; - export default MonthNav; diff --git a/components/atoms/PointCircle.tsx b/components/atoms/PointCircle.tsx index d17ee17e9..edde14d02 100644 --- a/components/atoms/PointCircle.tsx +++ b/components/atoms/PointCircle.tsx @@ -4,12 +4,13 @@ import { CustomColor } from "../../types/globals/interaction"; interface PointCircleProps { color?: CustomColor; + colorText?: string; } -function PointCircle({ color = "mint" }: PointCircleProps) { +function PointCircle({ color = "mint", colorText }: PointCircleProps) { return ( - + ); } diff --git a/components/atoms/PointCircleText.tsx b/components/atoms/PointCircleText.tsx deleted file mode 100644 index 974448313..000000000 --- a/components/atoms/PointCircleText.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { Box, Flex } from "@chakra-ui/react"; - -import { CustomColor } from "../../types/globals/interaction"; -import PointCircle from "./PointCircle"; - -export interface PointCircleTextProps { - color?: CustomColor; - text: string; -} - -function PointCircleText({ text, color }: PointCircleTextProps) { - return ( - - - - {text} - - - ); -} - -export default PointCircleText; diff --git a/components/molecules/PointCircleTextRow.tsx b/components/molecules/PointCircleTextRow.tsx deleted file mode 100644 index 3c3316b61..000000000 --- a/components/molecules/PointCircleTextRow.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { Box, Flex } from "@chakra-ui/react"; - -import PointCircleText, { PointCircleTextProps } from "../atoms/PointCircleText"; - -interface PointCircleTextRowProps { - props: PointCircleTextProps[]; -} - -function PointCircleTextRow({ props }: PointCircleTextRowProps) { - return ( - - {props.map((prop, idx) => ( - - - - ))} - - ); -} - -export default PointCircleTextRow; diff --git a/components/molecules/groups/ButtonGroups.tsx b/components/molecules/groups/ButtonGroups.tsx index c7a24658a..b2fc08987 100644 --- a/components/molecules/groups/ButtonGroups.tsx +++ b/components/molecules/groups/ButtonGroups.tsx @@ -1,44 +1,64 @@ import { Button, Flex } from "@chakra-ui/react"; import styled from "styled-components"; -export interface IButtonOptions { +export interface ButtonOptionsProps { text: string; func: () => void; + color?: string; } export interface IButtonGroups { - buttonItems: IButtonOptions[]; + buttonOptionsArr: ButtonOptionsProps[]; currentValue: string; size?: "sm" | "md"; isWrap?: boolean; isEllipse?: boolean; + type?: "block" | "text"; } export default function ButtonGroups({ - buttonItems, + buttonOptionsArr, currentValue, size, isWrap = false, isEllipse = false, + type = "block", }: IButtonGroups) { + console.log(buttonOptionsArr, currentValue); return ( - {buttonItems.map((buttonData, idx) => ( - - + {buttonOptionsArr.map((buttonOptions, idx) => ( + + {type === "block" ? ( + + ) : ( + + )} ))} diff --git a/components/molecules/rows/ColorLabelRow.tsx b/components/molecules/rows/ColorLabelRow.tsx new file mode 100644 index 000000000..6d830b787 --- /dev/null +++ b/components/molecules/rows/ColorLabelRow.tsx @@ -0,0 +1,21 @@ +import { Box, Flex } from "@chakra-ui/react"; + +import ColorLabel, { ColorLabelProps } from "../../atoms/ColorLabel"; + +interface ColorLabelRowProps { + props: ColorLabelProps[]; +} + +function ColorLabelRow({ props }: ColorLabelRowProps) { + return ( + + {props.map((prop, idx) => ( + + + + ))} + + ); +} + +export default ColorLabelRow; diff --git a/components/organisms/Calendar.tsx b/components/organisms/Calendar.tsx new file mode 100644 index 000000000..38d8353b0 --- /dev/null +++ b/components/organisms/Calendar.tsx @@ -0,0 +1,200 @@ +import { Box, Flex, Grid } from "@chakra-ui/react"; +import dayjs, { Dayjs } from "dayjs"; +import styled from "styled-components"; + +import { COLOR_TABLE } from "../../constants/colorConstants"; +import { CalendarContentProps } from "../../constants/contents/calendarSchedule"; +import { DAYS_OF_WEEK } from "../../constants/util/util"; + +interface CalendarProps { + monthFirstDate: Dayjs; + calendarContents: CalendarContentProps[]; +} + +export interface CalendarScheduleProps { + content: string; + color: string; + isFirst: boolean; + isLast: boolean; + blockIdx: number; +} + +export interface DaySchedules { + first: string | null; + second: string | null; + third: string | null; +} + +const DAY_BLOCK_WIDTH = 50; + +const CALENDAR_DAY_COLOR = { + sun: "var(--color-red)", + sat: "var(--color-blue)", +}; + +const SCHEDULE_TYPE_TO_COLOR = { + main: COLOR_TABLE[0], + schedule: COLOR_TABLE[5], + event: COLOR_TABLE[3], +}; + +const generateCalendarDates = (monthFirstDate: Dayjs) => { + const daysInMonth = monthFirstDate.daysInMonth(); + const frontBlankDate = monthFirstDate.day(); + const totalDate = daysInMonth + frontBlankDate; + const rowsInMonth = totalDate <= 35 ? 5 : 6; + return Array.from({ length: 7 * rowsInMonth }, (_, idx) => + idx < frontBlankDate || idx >= totalDate ? null : idx - frontBlankDate + 1, + ); +}; + +function Calendar({ monthFirstDate, calendarContents }: CalendarProps) { + const calendarDates = generateCalendarDates(monthFirstDate); + let endingSchedules = []; + + const daySchedules: DaySchedules = { + first: null, + second: null, + third: null, + }; + + const getDaySchedules = (date: number): CalendarScheduleProps[] => { + return calendarContents.reduce((acc: CalendarScheduleProps[], schedule) => { + const isFirstDay = date === schedule.start; + const isEndDay = date === schedule.end; + if (schedule.start <= date && date <= schedule.end) { + acc.push({ + content: schedule.content, + color: SCHEDULE_TYPE_TO_COLOR[schedule.type], + isFirst: isFirstDay, + isLast: isEndDay, + blockIdx: schedule?.blockIdx, + }); + if (isFirstDay) fillSchedule(schedule.content); + if (isEndDay) endingSchedules.push(schedule.content); + } + return acc; + }, []); + }; + + const deleteSchedule = (content: string) => { + for (const key in daySchedules) { + if (daySchedules[key] === content) daySchedules[key] = null; + } + }; + + const fillSchedule = (content: string) => { + const availableKey = Object.keys(daySchedules).find((key) => !daySchedules[key]); + if (availableKey) daySchedules[availableKey] = content; + }; + + return ( + + + {DAYS_OF_WEEK.map((day) => ( + + {day} + + ))} + + + {calendarDates?.map((item, idx) => { + const day = idx % 7 === 0 ? "sun" : idx % 7 === 6 ? "sat" : null; + const isToday = monthFirstDate.date(item).isSame(dayjs(), "day"); + const contentArr = getDaySchedules(item); + const dateInfo = Object.values(daySchedules).map((title) => + contentArr?.find((c) => c.content === title), + ); + + endingSchedules.forEach((item) => deleteSchedule(item)); + endingSchedules = []; + + return ( + + + {!isToday ? ( + item + ) : ( + + {item} + + )} + + <> + {dateInfo.map((item, idx2) => { + return ( + + {item?.isFirst ? item?.content : "\u00A0"} + + ); + })} + + + ); + })} + + + ); +} + +const EventBlock = styled.div<{ + color: string; + isFirst: boolean; + isLast: boolean; +}>` + font-size: 10px; + margin-bottom: 2px; + font-weight: 400; + white-space: nowrap; + color: white; + background-color: ${(props) => props.color}; + position: relative; + z-index: ${(props) => (props.isFirst ? 4 : 0)}; + padding-left: ${(props) => (props.isFirst ? "var(--gap-1)" : 0)}; + padding-right: ${(props) => (props.isLast ? "var(--gap-1)" : 0)}; +`; + +export default Calendar; diff --git a/constants/settingValue/eventContents.ts b/constants/contents/calendarSchedule.ts similarity index 59% rename from constants/settingValue/eventContents.ts rename to constants/contents/calendarSchedule.ts index 6ec359373..9ce228b28 100644 --- a/constants/settingValue/eventContents.ts +++ b/constants/contents/calendarSchedule.ts @@ -1,42 +1,40 @@ -import { TABLE_COLORS } from "../styles"; - -type Content = { +export interface CalendarContentProps { content: string; start: number; end: number; - color: string; - text: string; + type: "event" | "schedule" | "main"; + text?: string; blockIdx?: number; -}; +} -export const EVENT_CONTENT_2023: Record = { +export const EVENT_CONTENT_2023: Record = { 10: [ { content: "[10월] 에타 홍보 이벤트 추첨", start: 22, end: 24, - color: TABLE_COLORS[2], + type: "event", text: "에타에 동아리 홍보글을 올려주시면 100 포인트와 추첨을 통해 치킨 기프티콘을 드려요!", }, { content: "[시험기간] 랜덤선물 이벤트", start: 16, end: 22, - color: TABLE_COLORS[0], + type: "event", text: "항상 돌아오는 시험기간 파이팅 이벤트... 매일 단톡방에서 랜덤한 선착순 선물을 뿌립니다!", }, { content: "[시험기간] 스터디 투표 2배 이벤트 ", start: 16, end: 22, - color: TABLE_COLORS[3], + type: "event", text: "시험 기간에 스터디에 투표하면 점수를 2배로 받아요!", }, { content: "[오프라인] 번개 이벤트", start: 29, end: 31, - color: TABLE_COLORS[6], + type: "event", text: "진행 예정", }, ], @@ -45,21 +43,21 @@ export const EVENT_CONTENT_2023: Record = { content: "수원/안양 정기모임", start: 17, end: 18, - color: TABLE_COLORS[2], + type: "schedule", text: "정기모임", }, { content: "양천/강남", start: 18, end: 18, - color: TABLE_COLORS[0], + type: "schedule", text: "정기모임", }, { content: "정기 모임", start: 19, end: 19, - color: TABLE_COLORS[0], + type: "schedule", text: "정기모임", blockIdx: 1, }, @@ -67,7 +65,7 @@ export const EVENT_CONTENT_2023: Record = { content: "11월 홍보 이벤트 당첨자 선별", start: 26, end: 30, - color: TABLE_COLORS[3], + type: "event", text: "11월 홍보 이벤트 당첨자 선별", }, ], @@ -76,61 +74,61 @@ export const EVENT_CONTENT_2023: Record = { content: "시험 기간 이벤트", start: 4, end: 8, - color: TABLE_COLORS[0], + type: "event", text: "이벤트", }, { content: "홍보 이벤트 추첨", start: 22, end: 24, - color: TABLE_COLORS[1], + type: "event", text: "이벤트", }, { content: "수원/강남 펭귄 핫팩", start: 17, end: 31, - color: TABLE_COLORS[2], + type: "event", text: "이벤트", }, ], }; -export const EVENT_CONTENT_2024: Record = { +export const EVENT_CONTENT_2024: Record = { 6: [ { content: "시험기간 응원 선물 이벤트", start: 10, end: 14, - color: "var(--color-blue)", + type: "event", text: "시험기간 응원 기념으로 매일 단톡방에서 기프티콘을 뿌립니다!", }, { content: "동아리 1차 용인 MT", start: 25, end: 26, - color: "var(--color-mint)", + type: "schedule", text: "", }, { content: "모임 활성화 이벤트", start: 19, end: 20, - color: "var(--color-blue)", + type: "event", text: "이제 종강하고 동아리 내에서 본격적으로 다양한 모임을 진행해보려고 하는데요! 모임을 개최하고 진행해주시는 분께는 매번 5000원의 지원금을 드립니다!", }, { content: "소모임 개설 기간", start: 24, end: 30, - color: "var(--color-orange)", + type: "main", text: "방학동안 스터디 뿐만 아니라 다양한 장르의 그룹을 활성화 해보려고 해요! 토익, 자격증 등의 스터디 뿐만 아니라 카페 탐방, 영화 관람, 보드게임, 러닝, 취미 활동 등 모든 모임 개설이 가능합니다. 모임장에게는 2만원씩 지원 혜택이 있습니다.", }, { content: "홍보 이벤트", start: 24, end: 30, - color: "var(--color-blue)", + type: "event", text: "에타 홍보에 참여하고 상품 받아가세요! 총 10만원 쏩니다!", }, ], @@ -139,84 +137,170 @@ export const EVENT_CONTENT_2024: Record = { content: "동아리 2차 대성리 MT", start: 3, end: 4, - color: "var(--color-mint)", + type: "schedule", text: "", }, { content: "소모임 편성", start: 6, end: 7, - color: "var(--color-orange)", + type: "main", text: "", }, { content: "모임 활성화 이벤트", start: 8, end: 9, - color: "var(--color-blue)", + type: "event", text: "", }, { content: "알고리즘 공모전", start: 11, end: 12, - color: "var(--color-blue)", + type: "event", text: "", }, { content: "정기모임 진행 주간", - start: 19, + start: 18, end: 21, - color: "var(--color-mint)", + type: "schedule", text: "", }, { content: "라운지 및 피드, 채팅, 인스타 기능 출시", - start: 29, + start: 28, end: 31, - color: "var(--color-mint)", + type: "main", text: "", }, ], 8: [ { - content: "조모임 진행 기간", + content: "월간 체크", + start: 1, + end: 1, + type: "main", + text: "", + }, + { + content: "조모임 진행 주간", start: 8, end: 11, - color: "var(--color-orange)", + type: "schedule", text: "", }, { content: "커뮤니티 출시", start: 5, end: 6, - color: "var(--color-mint)", + type: "main", text: "", }, { - content: "지역별 정기모임 기간", - start: 15, - end: 18, - color: "var(--color-orange)", + content: "에브리타임 홍보 이벤트 시작 ~ ", + start: 13, + end: 15, + type: "event", + text: "", + }, + { + content: "지역 정기모임 주간", + start: 14, + end: 17, + type: "schedule", + text: "", + }, + + { + content: "온라인 스터디 오픈", + start: 20, + end: 22, + type: "main", text: "", }, { content: "추억의 뽑기 이벤트", start: 22, end: 23, - color: "var(--color-blue)", + type: "event", text: "", }, { content: "동아리 정비 기간", start: 26, end: 30, - color: "var(--color-mint)", + type: "schedule", + text: "", + }, + { + content: "한줄 카피라이팅 이벤트", + start: 28, + end: 30, + type: "event", + text: "", + }, + ], + 9: [ + { + content: "동아리 리뉴얼 ~ ", + start: 2, + end: 4, + type: "main", + text: "에브리타임에 홍보하면 매주 2분께 올리브영 기프티콘을 드려요!", + }, + { + content: "에타 홍보 이벤트 ~ ", + start: 3, + end: 5, + type: "event", + text: "에브리타임에 홍보하면 매주 2분께 올리브영 기프티콘을 드려요!", + }, + { + content: "디스코드 오픈 이벤트 ~ ", + start: 10, + end: 12, + type: "event", + text: "동아리 스터디 디스코드 채널이 생겼습니다! 같이 공부하고 이벤트 상품 받아가세요!", + }, + { + content: "열공 스터디 이벤트 ~ ", + start: 9, + end: 11, + type: "event", + text: "동아리 스터디 디스코드 채널이 생겼습니다! 같이 공부하고 이벤트 상품 받아가세요!", + }, + { + content: "유령인원 정리 기간", + start: 16, + end: 17, + type: "main", + text: "", + }, + { + content: "동아리 전체 정기모임", + start: 13, + end: 14, + type: "main", + text: "", + }, + { + content: "지역 정기모임 주간", + start: 19, + end: 22, + type: "schedule", + text: "", + }, + { + content: "ABOUT 빙고판 이벤트", + start: 17, + end: 28, + type: "event", text: "", }, ], - 9: [], 10: [], 11: [], 12: [], diff --git a/constants/contentsText/accordionContents.ts b/constants/contentsText/accordionContents.ts index 0a486fc73..88baeeef8 100644 --- a/constants/contentsText/accordionContents.ts +++ b/constants/contentsText/accordionContents.ts @@ -1,5 +1,5 @@ import { IAccordionContent } from "../../components/molecules/Accordion"; -import { EVENT_ALWAYS, EVENT_CONTENT_2024 } from "../../constants/settingValue/eventContents"; +import { EVENT_ALWAYS, EVENT_CONTENT_2024 } from "../contents/calendarSchedule"; //회원가입 질문 컨텐츠 export const ACCORDION_CONTENT_FEE: IAccordionContent[] = [ diff --git a/constants/location.ts b/constants/location.ts index 6e40f0d35..b8a30ba04 100644 --- a/constants/location.ts +++ b/constants/location.ts @@ -2,11 +2,12 @@ import { ActiveLocation, InactiveLocation, Location, - LocationEn, + LocationEn } from "../types/services/locationTypes"; -import { TABLE_COLORS } from "./styles"; +import { COLOR_TABLE } from "./colorConstants"; + +export const LOCATION_OPEN: ActiveLocation[] = ["수원", "양천", "강남", "동대문", "인천", "안양"]; -export const LOCATION_OPEN: ActiveLocation[] = ["수원", "양천", "안양", "강남", "동대문", "인천"]; export const LOCATION_RECRUITING: InactiveLocation[] = [ "마포", "성남", @@ -23,7 +24,7 @@ export const LOCATION_RECRUITING: InactiveLocation[] = [ export const LOCATION_ALL = [...LOCATION_OPEN, ...LOCATION_RECRUITING]; -export const LOCATION_CONVERT: Record = { +export const LOCATION_TO_FULLNAME: Record = { 수원: "수원시", 양천: "양천구 · 영등포구", 안양: "안양 인근 지역", @@ -76,15 +77,6 @@ export const LOCATION_MEMBER_CNT: { 시흥: { member: 7, new: 2 }, }; -export const LOCATION_TABLE_COLOR: Record = { - 수원: TABLE_COLORS[0], - 양천: TABLE_COLORS[3], - 안양: TABLE_COLORS[2], - 강남: TABLE_COLORS[1], - 인천: TABLE_COLORS[4], - 동대문: TABLE_COLORS[5], -}; - export const krToEnMapping: Record = { 수원: "suw", 강남: "gan", @@ -124,3 +116,12 @@ export const enToKrMapping: Record = { buc: "부천", sih: "시흥", }; + +export const LOCATION_TO_COLOR: Record = { + 수원: COLOR_TABLE[0], + 양천: COLOR_TABLE[1], + 강남: COLOR_TABLE[3], + 동대문: COLOR_TABLE[4], + 인천: COLOR_TABLE[2], + 안양: COLOR_TABLE[5], +}; diff --git a/constants/serviceConstants/studyConstants/studyLocationConstants.ts b/constants/serviceConstants/studyConstants/studyLocationConstants.ts index 68645e127..c8b78f57d 100644 --- a/constants/serviceConstants/studyConstants/studyLocationConstants.ts +++ b/constants/serviceConstants/studyConstants/studyLocationConstants.ts @@ -208,7 +208,6 @@ export const PLACE_TO_LOCATION = createPlaceToLocationMap(LOCATION_TO_PLACE); function createPlaceToLocationMap(obj: LocationToPlace) { const placeToLocationMap: { [key: string]: ActiveLocation } = {}; - Object.entries(obj).forEach(([location, ids]) => { ids.forEach((id) => { placeToLocationMap[id] = location as ActiveLocation; diff --git a/modals/InviteUserModal.tsx b/modals/InviteUserModal.tsx index 739ef7b14..95b97b96b 100644 --- a/modals/InviteUserModal.tsx +++ b/modals/InviteUserModal.tsx @@ -61,7 +61,7 @@ export default function InviteUserModal({ setIsModal }: IInviteUserModal) { }, }; - const buttonItems = [ + const buttonOptionsArr = [ { text: "수원", func: () => setLocation("수원"), @@ -90,7 +90,7 @@ export default function InviteUserModal({ setIsModal }: IInviteUserModal) { return ( - + onClickButton("전체"), @@ -64,7 +64,7 @@ export default function GatherLocationFilter() { return ( { + buttonOptionsArr={buttonOptionsArr.sort((x, y) => { if (x.text === "전체") return -1; if (y.text === "전체") return 1; if (x.text === defaultLocation) return -1; diff --git a/pageTemplates/home/HomeCalendarSection.tsx b/pageTemplates/home/HomeCalendarSection.tsx new file mode 100644 index 000000000..d12547e84 --- /dev/null +++ b/pageTemplates/home/HomeCalendarSection.tsx @@ -0,0 +1,50 @@ +import { Box, Flex } from "@chakra-ui/react"; +import dayjs from "dayjs"; +import { useState } from "react"; + +import { ColorLabelProps } from "../../components/atoms/ColorLabel"; +import MonthNav from "../../components/atoms/MonthNav"; +import Accordion from "../../components/molecules/Accordion"; +import ColorLabelRow from "../../components/molecules/rows/ColorLabelRow"; +import Calendar from "../../components/organisms/Calendar"; +import { COLOR_TABLE } from "../../constants/colorConstants"; +import { EVENT_CONTENT_2024 } from "../../constants/contents/calendarSchedule"; +import { ACCORDION_CONTENT_EVENT } from "../../constants/contentsText/accordionContents"; + +const SCHEDULE_CATEGORIES: ColorLabelProps[] = [ + { + text: "공식 행사", + colorText: COLOR_TABLE[0], + }, + { + text: "이벤트", + colorText: COLOR_TABLE[3], + }, + { + text: "일정", + colorText: COLOR_TABLE[5], + }, +]; + +function HomeCalendarSection() { + const [monthFirstDate, setMonthFirstDate] = useState(dayjs().startOf("month")); + const monthNum = monthFirstDate.month(); + + const calendarContents = + monthFirstDate.year() === 2024 ? EVENT_CONTENT_2024[monthFirstDate.month() + 1] : null; + return ( + <> + + + + + + + 일정 상세정보 + + + + ); +} + +export default HomeCalendarSection; diff --git a/pageTemplates/home/HomeClubSection.tsx b/pageTemplates/home/HomeClubSection.tsx deleted file mode 100644 index 8206ded7b..000000000 --- a/pageTemplates/home/HomeClubSection.tsx +++ /dev/null @@ -1,272 +0,0 @@ -import { Box, Flex } from "@chakra-ui/react"; -import dayjs from "dayjs"; -import { Fragment, useState } from "react"; -import styled from "styled-components"; - -import MonthNav from "../../components/atoms/MonthNav"; -import { PointCircleTextProps } from "../../components/atoms/PointCircleText"; -import Accordion from "../../components/molecules/Accordion"; -import PointCircleTextRow from "../../components/molecules/PointCircleTextRow"; -import { ACCORDION_CONTENT_EVENT } from "../../constants/contentsText/accordionContents"; -import { EVENT_CONTENT_2024 } from "../../constants/settingValue/eventContents"; -import { DAYS_OF_WEEK } from "../../constants/util/util"; -const DAYS_TITLE = ["포인트 2배", null, null, null, null, null, "점수 2배"]; - -interface IEventContent { - content: string; - color: string; - isFirst: boolean; - isLast: boolean; - blockIdx?: number; -} - -function HomeClubSection() { - const [navMonth, setNavMonth] = useState(dayjs().startOf("month")); - - const getFilledDates = (navMonth: dayjs.Dayjs) => { - const daysInMonth = navMonth.daysInMonth(); - const frontBlankDate = navMonth.day(); - const totalDate = daysInMonth + frontBlankDate; - const rowsInMonth = totalDate <= 35 ? 5 : 6; - return Array.from({ length: 7 * rowsInMonth }, (_, idx) => - idx < frontBlankDate || idx >= totalDate ? null : idx - frontBlankDate + 1, - ); - }; - - const filledDates = getFilledDates(navMonth); - - const eventBlocks: { [key: string]: string } = { - first: null, - second: null, - third: null, - }; - - let endBlocks = []; - - const filledContents = (date: number) => { - const eventArr = navMonth.year() === 2024 ? EVENT_CONTENT_2024[navMonth.month() + 1] : null; - - if (!eventArr) return; - return eventArr.reduce((acc: IEventContent[], event) => { - const isFirstDay = date === event.start; - const isEndDay = date === event.end; - if (event.start <= date && date <= event.end) { - acc.push({ - content: event.content, - color: event.color, - isFirst: isFirstDay, - isLast: isEndDay, - blockIdx: event?.blockIdx, - }); - if (isFirstDay) fillEventDate(event.content); - if (isEndDay) endBlocks.push(event.content); - } - return acc; - }, []); - }; - - const fillEventDate = (content: string) => { - const availableKey = Object.keys(eventBlocks).find((key) => !eventBlocks[key]); - if (availableKey) eventBlocks[availableKey] = content; - }; - - const deleteEventDate = (content: string) => { - for (const key in eventBlocks) { - if (eventBlocks[key] === content) eventBlocks[key] = null; - } - }; - - const textRowObj: PointCircleTextProps[] = [ - { - text: "공식 행사", - color: "mint", - }, - { - text: "이벤트", - color: "blue", - }, - { - text: "일정", - color: "orange", - }, - ]; - - return ( - <> - - - - - - - {DAYS_TITLE.map((day, idx) => ( -
{day}
- ))} -
- - {DAYS_OF_WEEK.map((day) => ( -
{day}
- ))} -
- - {filledDates?.map((item, idx) => { - const day = idx % 7 === 0 ? "sun" : idx % 7 === 6 ? "sat" : null; - const isToday = navMonth.date(item).isSame(dayjs(), "day"); - - const contentArr = filledContents(item); - const dateInfo = Object.values(eventBlocks).map((title) => - contentArr?.find((c) => c.content === title), - ); - - endBlocks.forEach((item) => deleteEventDate(item)); - endBlocks = []; - - return ( - - - {!isToday ? item : {item}} - - - {dateInfo.map((item, idx2) => { - return ( - - {item?.blockIdx !== undefined && ( - -   - - )} - - {item?.isFirst ? item?.content : "\u00A0"} - - - ); - })} - - - ); - })} - -
- - 이벤트 상세정보 - - - - ); -} - -const Calendar = styled.div` - width: 364px; - margin: 0 auto; - display: flex; - flex-direction: column; -`; - -const WeekTitleHeader = styled.div` - display: flex; - justify-content: space-between; - font-size: 10px; - color: var(--color-mint); - - margin-bottom: var(--gap-1); - font-weight: 600; - > div { - flex: 1; - text-align: center; - } -`; - -const DayOfWeek = styled.div` - display: flex; - justify-content: space-between; - background-color: var(--gray-200); - padding: var(--gap-1) 0; - font-size: 12px; - > div { - flex: 1; - text-align: center; - } - > div:first-child { - color: var(--color-red); - } - > div:last-child { - color: #6bafff; - } -`; - -const CalendarDates = styled.div` - display: grid; - background-color: white; - grid-template-columns: repeat(7, 1fr); - border: var(--border); - border-radius: var(--rounded); - > div:first-child { - color: var(--color-red); - } -`; - -const DateBlock = styled.div` - width: 52px; - padding-top: var(--gap-1); - font-size: 12px; - font-weight: 600; - text-align: center; - flex: 1; - border-top: var(--border); -`; - -const Date = styled.div<{ day: "sun" | "sat"; isToday: boolean }>` - position: relative; - height: 18px; - margin-bottom: var(--gap-1); - color: ${(props) => - props.isToday - ? "white" - : props.day === "sun" - ? "var(--color-red)" - : props.day === "sat" - ? "var(--color-blue)" - : null}; -`; - -const DateContent = styled.div``; - -const EventBlock = styled.div<{ - color: string; - isFirst: boolean; - isLast: boolean; -}>` - font-size: 10px; - margin-bottom: 2px; - font-weight: 400; - white-space: nowrap; - color: white; - background-color: ${(props) => props.color}; - position: relative; - - z-index: ${(props) => (props.isFirst ? 4 : 0)}; - padding-left: ${(props) => (props.isFirst ? "var(--gap-1)" : 0)}; - padding-right: ${(props) => (props.isLast ? "var(--gap-1)" : 0)}; -`; - -const TodayCircle = styled.div` - position: absolute; - top: 50%; - left: 50%; - width: 18px; - height: 18px; - border-radius: 50%; - transform: translate(-50%, -50%); - background-color: var(--gray-800); - color: white; -`; - -export default HomeClubSection; diff --git a/pageTemplates/home/HomeRankingSection.tsx b/pageTemplates/home/HomeRankingSection.tsx index 351edc77e..7f42d2d77 100644 --- a/pageTemplates/home/HomeRankingSection.tsx +++ b/pageTemplates/home/HomeRankingSection.tsx @@ -1,5 +1,5 @@ import RecommendationBannerCard from "../../components/organisms/cards/RecommendationBannerCard"; -import { HOME_RECOMMENDATION_TAB_CONTENTS } from "../../constants/contents/HomeRecommendationTab"; +import { HOME_RECOMMENDATION_TAB_CONTENTS } from "../../constants/contents/homeRecommendationTab"; function HomeRankingSection() { return ( diff --git a/pageTemplates/home/HomeReviewSection.tsx b/pageTemplates/home/HomeReviewSection.tsx index 00025e037..e52454a15 100644 --- a/pageTemplates/home/HomeReviewSection.tsx +++ b/pageTemplates/home/HomeReviewSection.tsx @@ -24,7 +24,7 @@ export default function HomeReviewSection() { } + rightComponent={} /> {imageArr && } diff --git a/pageTemplates/home/study/HomeStudyChart.tsx b/pageTemplates/home/study/HomeStudyChart.tsx index e321becac..f5768632d 100644 --- a/pageTemplates/home/study/HomeStudyChart.tsx +++ b/pageTemplates/home/study/HomeStudyChart.tsx @@ -1,11 +1,11 @@ import { Box } from "@chakra-ui/react"; import dayjs from "dayjs"; import dynamic from "next/dynamic"; -import { useRouter } from "next/navigation"; import HighlightedTextButton from "../../../components/atoms/buttons/HighlightedTextButton"; import SectionBar from "../../../components/molecules/bars/SectionBar"; import { ChartStudyOptions } from "../../../components/organisms/chart/ChartOptions"; +import { useToast } from "../../../hooks/custom/CustomToast"; import { VoteCntProps } from "../../../types/models/studyTypes/studyRecords"; interface HomeStudyChartProps { @@ -13,7 +13,8 @@ interface HomeStudyChartProps { } function HomeStudyChart({ voteCntArr }: HomeStudyChartProps) { - const router = useRouter(); + // const router = useRouter(); + const toast = useToast(); const ApexCharts = dynamic(() => import("react-apexcharts"), { ssr: false }); const filtered: VoteCntProps[] = voteCntArr?.reduce((acc, cur) => { @@ -35,13 +36,15 @@ function HomeStudyChart({ voteCntArr }: HomeStudyChartProps) { xArr.push(dayjs(obj.date).date() + ""); }); + const onClick = () => { + toast("warning", "24년 9월 5일 오픈"); + }; + return ( <> router.push("/calendar")} /> - } + rightComponent={} /> - - - - {filterData?.map((item, idx) => { - const arrivedInfo = item?.arrivedInfoList; +function RecordCalendar({ filterData, monthFirstDate }: IRecordCalendar) { + console.log(2, filterData); + const calendarContents: CalendarContentProps[] = filterData.flatMap((data) => { + const arrivedInfo = data?.arrivedInfoList; + const date = data?.date; + const dayjsDate = date && dayjsToStr(monthFirstDate.date(date)); + let openLocation = null; + for (const key in LOCATION_OPEN_DATE) { + if (LOCATION_OPEN_DATE[key] === dayjsDate) openLocation = key; + } + const openStudyLocation: Set<{ + location: string; + cnt: number; + }> = new Set(); + arrivedInfo?.forEach((place) => { + openStudyLocation.add({ + location: PLACE_TO_LOCATION[place.placeId], + cnt: place.arrivedInfo.length, + }); + }); + console.log(24, arrivedInfo, openLocation, openStudyLocation); + let tempCnt = 0; - const date = item?.date; - const dayjsDate = date && dayjsToStr(navMonth.date(date)); - let openLocation = null; - for (const key in LOCATION_OPEN_DATE) { - if (LOCATION_OPEN_DATE[key] === dayjsDate) openLocation = key; - } - const openStudyLocation: Set<{ - location: string; - cnt: number; - }> = new Set(); - arrivedInfo?.forEach((place) => { - openStudyLocation.add({ - location: PLACE_TO_LOCATION[place.placeId], - cnt: place.arrivedInfo.length, - }); - }); - let tempCnt = 0; - return ( - - {!openLocation ? ( - {date} - ) : ( - {date} - )} - {Array.from(openStudyLocation).map((location, idx) => { - if (idx > 2 || location.cnt < 2) return null; - tempCnt++; - return ( - - {tempCnt < 4 || openStudyLocation.size <= 3 ? ( - "Open" - ) : ( - - )} - - ); - })} - - ); - })} - - + const resData = Array.from(openStudyLocation) + .map((location, idx) => { + if (idx > 2 || location.cnt < 2) return null; + tempCnt++; + return { + content: "오픈", + start: date, + end: date, + type: "main" as "main" | "event" | "schedule", + blockIdx: tempCnt - 1, + }; + }) + .filter((place) => place !== null); + return resData; + // { + // Array.from(openStudyLocation).map((location, idx) => { + // if (idx > 2 || location.cnt < 2) return null; + // tempCnt++; + // return ( + // + // {tempCnt < 4 || openStudyLocation.size <= 3 ? ( + // "스터디 오픈" + // ) : ( + // + // )} + // + // ); + // }); + // } + }); + console.log(calendarContents); + return ( + + + + // + // + // + // {filterData?.map((data, idx) => { + // + // return ( + // + // {!openLocation ? ( + // {date} + // ) : ( + // {date} + // )} + // {Array.from(openStudyLocation).map((location, idx) => { + // if (idx > 2 || location.cnt < 2) return null; + // tempCnt++; + // return ( + // + // {tempCnt < 4 || openStudyLocation.size <= 3 ? ( + // "스터디 오픈" + // ) : ( + // + // )} + // + // ); + // })} + // + // ); + // })} + // + // ); } function DayOfWeek() { @@ -104,7 +150,7 @@ const LocationOpen = styled.div<{ location: Location }>` display: flex; justify-content: center; align-items: center; - border: ${(props) => `2px solid ${LOCATION_TABLE_COLOR[props.location]}`}; + border: ${(props) => `2px solid ${LOCATION_TO_COLOR[props.location]}`}; width: 24px; height: 24px; border-radius: 50%; @@ -112,7 +158,7 @@ const LocationOpen = styled.div<{ location: Location }>` const Open = styled.div<{ location: Location }>` font-size: 10px; - color: ${(props) => LOCATION_TABLE_COLOR[props.location] || "var(--gray-500)"}; + color: ${(props) => LOCATION_TO_COLOR[props.location]}; `; const DayLine = styled.div` diff --git a/pageTemplates/record/RecordCalendarSetting.tsx b/pageTemplates/record/RecordCalendarSetting.tsx index 4c9a8c189..0c10caa35 100644 --- a/pageTemplates/record/RecordCalendarSetting.tsx +++ b/pageTemplates/record/RecordCalendarSetting.tsx @@ -1,6 +1,7 @@ import dayjs, { Dayjs } from "dayjs"; import { useEffect } from "react"; +import { ALL_스터디인증 } from "../../constants/serviceConstants/studyConstants/studyPlaceConstants"; import { useErrorToast } from "../../hooks/custom/CustomToast"; import { useStudyAttendRecordQuery } from "../../hooks/study/queries"; import { DispatchBoolean, DispatchType } from "../../types/hooks/reactTypes"; @@ -40,11 +41,17 @@ function RecordCalendarSetting({ ? null : { date: idx - frontBlankDate + 1, arrivedInfoList: [] }, ); - studyRecords.forEach((item) => { - const filledIdx = dayjs(item.date).date() + frontBlankDate - 1; - const data = filledDates[filledIdx]; - if (data) data.arrivedInfoList = item.arrivedInfoList; - }); + + studyRecords + .map((study) => ({ + arrivedInfoList: study.arrivedInfoList.filter((item) => item.placeId !== ALL_스터디인증), + date: study.date, + })) + .forEach((item) => { + const filledIdx = dayjs(item.date).date() + frontBlankDate - 1; + const data = filledDates[filledIdx]; + if (data) data.arrivedInfoList = item.arrivedInfoList; + }); setArrivedCalendar(filledDates); // eslint-disable-next-line react-hooks/exhaustive-deps }, [isLoading, navMonth, studyRecords]); diff --git a/pageTemplates/record/RecordLocationCategory.tsx b/pageTemplates/record/RecordLocationCategory.tsx index ebc25eb9e..93f17287d 100644 --- a/pageTemplates/record/RecordLocationCategory.tsx +++ b/pageTemplates/record/RecordLocationCategory.tsx @@ -1,11 +1,12 @@ +import { Box } from "@chakra-ui/react"; import { useEffect, useState } from "react"; -import styled from "styled-components"; -import { LOCATION_CONVERT, LOCATION_OPEN, LOCATION_TABLE_COLOR } from "../../constants/location"; +import ButtonGroups from "../../components/molecules/groups/ButtonGroups"; +import { LOCATION_OPEN, LOCATION_TO_COLOR, LOCATION_TO_FULLNAME } from "../../constants/location"; import { PLACE_TO_LOCATION } from "../../constants/serviceConstants/studyConstants/studyLocationConstants"; import { DispatchType } from "../../types/hooks/reactTypes"; import { IArrivedData } from "../../types/models/studyTypes/studyRecords"; -import { Location, LocationFilterType } from "../../types/services/locationTypes"; +import { ActiveLocationAll } from "../../types/services/locationTypes"; interface IRecordLocationCategory { initialData: IArrivedData[]; @@ -13,12 +14,7 @@ interface IRecordLocationCategory { } function RecordLocationCategory({ initialData, setFilterData }: IRecordLocationCategory) { - const [category, setCategory] = useState("전체"); - - const onClickBadge = (value: Location) => { - if (value === category) setCategory("전체"); - else setCategory(value); - }; + const [category, setCategory] = useState("전체"); useEffect(() => { if (!initialData) return; @@ -35,58 +31,31 @@ function RecordLocationCategory({ initialData, setFilterData }: IRecordLocationC } }, [category, initialData, setFilterData]); + const buttonOptionsArr = (["전체", ...LOCATION_OPEN] as ActiveLocationAll[]).map((location) => ({ + text: LOCATION_TO_FULLNAME[location] || "전체", + func: () => { + if (location === category) setCategory("전체"); + else setCategory(location); + }, + color: LOCATION_TO_COLOR[location], + })); + return ( - - - {LOCATION_OPEN.map((location) => ( - - ))} - - + + + ); } -const Layout = styled.div` - padding: 0 var(--gap-4); - height: 36px; - display: flex; - align-items: center; - justify-content: space-between; - background-color: var(--gray-200); - border-top: 1px solid var(--gray-300); - border-bottom: 1px solid var(--gray-300); - > div { - display: flex; - align-items: center; - } - > span:last-child { - font-size: 10px; - color: var(--gray-600); - } -`; - -const SpaceBadge = styled.section` - display: flex; - align-items: center; -`; - -const Button = styled.button<{ - location: Location; - category: LocationFilterType; -}>` - margin-right: var(--gap-3); - font-weight: 600; - color: ${(props) => LOCATION_TABLE_COLOR[props.location]}; - font-size: ${(props) => (props.category === props.location ? "14px" : "12px")}; - opacity: ${(props) => - props.category !== "전체" && props.category !== props.location ? "0.7" : "1"}; -`; - export default RecordLocationCategory; diff --git a/pageTemplates/record/RecordOverview.tsx b/pageTemplates/record/RecordOverview.tsx index 238200092..ca529a676 100644 --- a/pageTemplates/record/RecordOverview.tsx +++ b/pageTemplates/record/RecordOverview.tsx @@ -107,7 +107,6 @@ const MyRecordItem = styled.div` flex-direction: column; justify-content: space-around; height: 100%; - > div { display: flex; align-items: center; diff --git a/pageTemplates/record/RecordSkeleton.tsx b/pageTemplates/record/RecordSkeleton.tsx deleted file mode 100644 index cec0e61e6..000000000 --- a/pageTemplates/record/RecordSkeleton.tsx +++ /dev/null @@ -1,300 +0,0 @@ -import dayjs from "dayjs"; -import styled from "styled-components"; - -import Skeleton from "../../components/atoms/skeleton/Skeleton"; -import { LOCATION_CONVERT, LOCATION_OPEN, LOCATION_TABLE_COLOR } from "../../constants/location"; -import { Location } from "../../types/services/locationTypes"; - -interface IRecordSkeleton { - isCalendar: boolean; -} - -function RecordSkeleton({ isCalendar }: IRecordSkeleton) { - const blankDate = Array.from( - { - length: dayjs().date(1).day(), - }, - (_, i) => i + 1, - ); - - const totalDate = Array.from( - { - length: dayjs().daysInMonth(), - }, - (_, i) => i + 1, - ); - return ( - - - - -
- 스터디 오픈 - - temp - -
-
- 참여한 인원 - - temp - -
-
- -
- 내 참여 횟수 - - temp - -
-
- 내 최근 참여 - - temp - -
-
-
-
- - - {LOCATION_OPEN.map((location) => ( - - {LOCATION_CONVERT[location]} - - ))} - - - {isCalendar ? ( - - - - {blankDate?.map((item) => )} - - {totalDate?.map((item, idx) => ( - - {item} - - Open - - - ))} - - - ) : ( - - {new Array(6).fill(0).map((_, idx) => ( - - - temp - - - {new Array(2).fill(0).map((_, idx2) => ( - - - - tempte - - - temp - - - - {new Array(3).fill(0).map((who, idx3) => ( - - temp - - ))} - - - ))} - - - ))} - - )} -
- ); -} -function DayOfWeek() { - return ( - - - - - - - - - - ); -} - -const Layout = styled.div``; - -/** overview */ -const RecordOverview = styled.div` - padding: var(--gap-3) var(--gap-4); - display: flex; - justify-content: space-between; - align-items: center; - height: 80px; -`; - -const MyRecord = styled.div` - display: flex; - height: 100%; - > div:first-child { - width: 125px; - } - > div:last-child { - width: 140px; - } -`; - -const MyRecordItem = styled.div` - display: flex; - flex-direction: column; - justify-content: space-around; - height: 100%; - - > div { - display: flex; - align-items: center; - } -`; -const ContentName = styled.span` - margin-right: var(--gap-2); - color: var(--gray-600); - font-size: 13px; -`; - -const ContentValue = styled.span` - font-weight: 700; - font-size: 14px; - color: var(--gray-700); -`; -const SpaceBadge = styled.section` - display: flex; - align-items: center; -`; - -const Button2 = styled.button<{ - location: Location; -}>` - margin-right: var(--gap-3); - font-weight: 600; - color: ${(props) => LOCATION_TABLE_COLOR[props.location]}; - font-size: 12px; -`; - -/** category */ -const Category = styled.div` - padding: 0 var(--gap-4); - height: 36px; - display: flex; - align-items: center; - justify-content: space-between; - background-color: var(--gray-200); - border-top: 1px solid var(--gray-300); - border-bottom: 1px solid var(--gray-300); - > div { - display: flex; - align-items: center; - } - > span:last-child { - font-size: 10px; - color: var(--gray-600); - } -`; - -/** calendar */ - -const Calendar = styled.div``; - -const CallenderDays = styled.div` - display: grid; - grid-auto-rows: 72px; - grid-template-columns: repeat(7, 1fr); - margin: 0 var(--gap-1); - font-size: 14px; -`; -const DayItem = styled.div` - flex: 1; - display: flex; - flex-direction: column; - align-items: center; - border: 1px solid var(--gray-200); -`; - -const DayItemDate = styled.span<{ isToday: boolean }>` - color: ${(props) => (props.isToday ? "var(--color-mint)" : null)}; - font-weight: ${(props) => (props.isToday ? "600" : null)}; - font-size: ${(props) => (props.isToday ? "15px" : null)}; -`; - -const Open = styled.div` - font-size: 10px; -`; - -const DayLine = styled.div` - margin: var(--gap-2) 24px; - display: flex; - justify-content: space-between; - color: var(--gray-600); - font-size: 12px; -`; - -/** detail */ - -export const Detail = styled.div` - display: flex; - flex-direction: column; -`; -const Block = styled.div` - border-top: 4px solid var(--gray-200); - padding: var(--gap-3) var(--gap-4); - padding-bottom: 0; -`; -const Date = styled.div` - margin-bottom: var(--gap-3); - font-size: 13px; - color: var(--gray-700); -`; -const StudyInfo = styled.div` - font-size: 12px; - color: var(--gray-700); -`; -const PlaceInfo = styled.div` - margin-bottom: var(--gap-3); -`; - -const PlaceName = styled.div` - display: flex; - align-items: center; - color: var(--gray-700); - font-size: 14px; - > span:first-child { - font-weight: 600; - margin-right: var(--gap-1); - } -`; -const OpenLocation = styled.span` - font-size: 11px; -`; - -const MemberWrapper = styled.div` - margin-top: var(--gap-3); - - display: grid; - grid-template-columns: repeat(auto-fill, minmax(20%, auto)); - align-items: center; - line-height: 2; -`; - -const Member = styled.span` - margin-right: var(--gap-1); - color: var(--gray-600); -`; -export default RecordSkeleton; diff --git a/pageTemplates/record/detail/RecordDetailStudyBlock.tsx b/pageTemplates/record/detail/RecordDetailStudyBlock.tsx index ab569113e..29522d8e2 100644 --- a/pageTemplates/record/detail/RecordDetailStudyBlock.tsx +++ b/pageTemplates/record/detail/RecordDetailStudyBlock.tsx @@ -1,7 +1,7 @@ import { Fragment } from "react"; import styled from "styled-components"; -import { LOCATION_TABLE_COLOR } from "../../../constants/location"; +import { LOCATION_TO_COLOR } from "../../../constants/location"; import { PLACE_TO_NAME } from "../../../constants/serviceConstants/studyConstants/studyCafeNameConstants"; import { PLACE_TO_LOCATION } from "../../../constants/serviceConstants/studyConstants/studyLocationConstants"; import { Location } from "../../../types/services/locationTypes"; @@ -59,7 +59,7 @@ const PlaceInfo = styled.div<{ location: Location }>` width: 148px; flex-shrink: 0; margin-bottom: var(--gap-4); - border: ${(props) => `1px solid ${LOCATION_TABLE_COLOR[props.location]}`}; + border: ${(props) => `1px solid ${LOCATION_TO_COLOR[props.location]}`}; border-radius: var(--rounded-lg); padding: var(--gap-2); @@ -79,7 +79,7 @@ const PlaceName = styled.div` const OpenLocation = styled.span<{ location: Location }>` font-size: 11px; - color: ${(props) => LOCATION_TABLE_COLOR[props.location]}; + color: ${(props) => LOCATION_TO_COLOR[props.location]}; `; const MemberWrapper = styled.div` diff --git a/pageTemplates/register/location/LocationMember.tsx b/pageTemplates/register/location/LocationMember.tsx index 90ba38724..d1e82cfe0 100644 --- a/pageTemplates/register/location/LocationMember.tsx +++ b/pageTemplates/register/location/LocationMember.tsx @@ -1,12 +1,12 @@ import styled from "styled-components"; -import { LOCATION_CONVERT, LOCATION_MEMBER_CNT } from "../../../constants/location"; +import { LOCATION_MEMBER_CNT, LOCATION_TO_FULLNAME } from "../../../constants/location"; import { Location } from "../../../types/services/locationTypes"; function LocationMember({ location }: { location: Location }) { return ( - {LOCATION_CONVERT[location]} + {LOCATION_TO_FULLNAME[location]} {LOCATION_MEMBER_CNT[location].new} diff --git a/pageTemplates/square/SecretSquare/SecretSquareCategories.tsx b/pageTemplates/square/SecretSquare/SecretSquareCategories.tsx index 57648b426..70face7c4 100644 --- a/pageTemplates/square/SecretSquare/SecretSquareCategories.tsx +++ b/pageTemplates/square/SecretSquare/SecretSquareCategories.tsx @@ -1,7 +1,9 @@ import { Box } from "@chakra-ui/react"; import { Dispatch, SetStateAction } from "react"; -import ButtonGroups, { IButtonOptions } from "../../../components/molecules/groups/ButtonGroups"; +import ButtonGroups, { + ButtonOptionsProps, +} from "../../../components/molecules/groups/ButtonGroups"; import { type SecretSquareCategoryWithAll } from "../../../types/models/square"; const SECRET_SQUARE_CATEGORY: SecretSquareCategoryWithAll[] = [ @@ -21,7 +23,7 @@ function SecretSquareCategories({ category: selectedCategory, setCategory, }: SecretSquareCategoryProps) { - const buttonItems: IButtonOptions[] = SECRET_SQUARE_CATEGORY.map((category) => ({ + const buttonOptionsArr: ButtonOptionsProps[] = SECRET_SQUARE_CATEGORY.map((category) => ({ text: `#${category}`, func: () => setCategory(category), })); @@ -29,7 +31,7 @@ function SecretSquareCategories({ return ( { - return { - text: `${textObj[category]}`, - func: () => { - newSearchParams.set("category", category); - router.replace(`/square?${newSearchParams}`); - setCategory(category); - }, - }; - }, - ); - - + const buttonOptionsArr: ButtonOptionsProps[] = ( + ["all", "gather", "group"] as (FeedType | "all")[] + ).map((category) => { + return { + text: `${textObj[category]}`, + func: () => { + newSearchParams.set("category", category); + router.replace(`/square?${newSearchParams}`); + setCategory(category); + }, + }; + }); return ( - - + + - {!isLoading ? ( + {!isLoading && ( <> {isCalendar ? ( - + ) : ( )} - ) : ( - )}
diff --git a/pages/eventCalendar.tsx b/pages/eventCalendar.tsx deleted file mode 100644 index 156ae2c8e..000000000 --- a/pages/eventCalendar.tsx +++ /dev/null @@ -1,278 +0,0 @@ -import { Box, Flex } from "@chakra-ui/react"; -import dayjs from "dayjs"; -import { Fragment, useState } from "react"; -import styled from "styled-components"; - -import MonthNav from "../components/atoms/MonthNav"; -import { PointCircleTextProps } from "../components/atoms/PointCircleText"; -import Header from "../components/layouts/Header"; -import Slide from "../components/layouts/PageSlide"; -import Accordion from "../components/molecules/Accordion"; -import PointCircleTextRow from "../components/molecules/PointCircleTextRow"; -import { ACCORDION_CONTENT_EVENT } from "../constants/contentsText/accordionContents"; -import { EVENT_CONTENT_2024 } from "../constants/settingValue/eventContents"; -import { DAYS_OF_WEEK } from "../constants/util/util"; -const DAYS_TITLE = ["포인트 2배", null, null, null, null, null, "점수 2배"]; - -interface IEventContent { - content: string; - color: string; - isFirst: boolean; - isLast: boolean; - blockIdx?: number; -} - -function EventCalendar() { - const [navMonth, setNavMonth] = useState(dayjs().startOf("month")); - - const getFilledDates = (navMonth: dayjs.Dayjs) => { - const daysInMonth = navMonth.daysInMonth(); - const frontBlankDate = navMonth.day(); - const totalDate = daysInMonth + frontBlankDate; - const rowsInMonth = totalDate <= 35 ? 5 : 6; - return Array.from({ length: 7 * rowsInMonth }, (_, idx) => - idx < frontBlankDate || idx >= totalDate ? null : idx - frontBlankDate + 1, - ); - }; - - const filledDates = getFilledDates(navMonth); - - const eventBlocks: { [key: string]: string } = { - first: null, - second: null, - third: null, - }; - - let endBlocks = []; - - const filledContents = (date: number) => { - const eventArr = navMonth.year() === 2024 ? EVENT_CONTENT_2024[navMonth.month() + 1] : null; - - if (!eventArr) return; - return eventArr.reduce((acc: IEventContent[], event) => { - const isFirstDay = date === event.start; - const isEndDay = date === event.end; - if (event.start <= date && date <= event.end) { - acc.push({ - content: event.content, - color: event.color, - isFirst: isFirstDay, - isLast: isEndDay, - blockIdx: event?.blockIdx, - }); - if (isFirstDay) fillEventDate(event.content); - if (isEndDay) endBlocks.push(event.content); - } - return acc; - }, []); - }; - - const fillEventDate = (content: string) => { - const availableKey = Object.keys(eventBlocks).find((key) => !eventBlocks[key]); - if (availableKey) eventBlocks[availableKey] = content; - }; - - const deleteEventDate = (content: string) => { - for (const key in eventBlocks) { - if (eventBlocks[key] === content) eventBlocks[key] = null; - } - }; - - const textRowObj: PointCircleTextProps[] = [ - { - text: "공식 행사", - color: "mint", - }, - { - text: "이벤트", - color: "blue", - }, - { - text: "일정", - color: "orange", - }, - ]; - - return ( - <> -
- - - - - - - - {DAYS_TITLE.map((day, idx) => ( -
{day}
- ))} -
- - {DAYS_OF_WEEK.map((day) => ( -
{day}
- ))} -
- - {filledDates?.map((item, idx) => { - const day = idx % 7 === 0 ? "sun" : idx % 7 === 6 ? "sat" : null; - const isToday = navMonth.date(item).isSame(dayjs(), "day"); - - const contentArr = filledContents(item); - const dateInfo = Object.values(eventBlocks).map((title) => - contentArr?.find((c) => c.content === title), - ); - - endBlocks.forEach((item) => deleteEventDate(item)); - endBlocks = []; - - return ( - - - {!isToday ? item : {item}} - - - {dateInfo.map((item, idx2) => { - return ( - - {item?.blockIdx !== undefined && ( - -   - - )} - - {item?.isFirst ? item?.content : "\u00A0"} - - - ); - })} - - - ); - })} - -
- - 이벤트 상세정보 - - -
- - ); -} - -const Calendar = styled.div` - width: 364px; - margin: 0 auto; - display: flex; - flex-direction: column; -`; - -const WeekTitleHeader = styled.div` - display: flex; - justify-content: space-between; - font-size: 10px; - color: var(--color-mint); - - margin-bottom: var(--gap-1); - font-weight: 600; - > div { - flex: 1; - text-align: center; - } -`; - -const DayOfWeek = styled.div` - display: flex; - justify-content: space-between; - background-color: var(--gray-200); - padding: var(--gap-1) 0; - font-size: 12px; - > div { - flex: 1; - text-align: center; - } - > div:first-child { - color: var(--color-red); - } - > div:last-child { - color: #6bafff; - } -`; - -const CalendarDates = styled.div` - display: grid; - background-color: white; - grid-template-columns: repeat(7, 1fr); - border: var(--border); - border-radius: var(--rounded); - > div:first-child { - color: var(--color-red); - } -`; - -const DateBlock = styled.div<{ isToday: boolean }>` - width: 52px; - padding-top: var(--gap-1); - font-size: 12px; - font-weight: 600; - text-align: center; - flex: 1; - border-top: var(--border); - background-color: ${(props) => (props.isToday ? "var(--gray-200)" : null)}; -`; - -const Date = styled.div<{ day: "sun" | "sat"; isToday: boolean }>` - position: relative; - height: 18px; - margin-bottom: var(--gap-1); - color: ${(props) => - props.isToday - ? "white" - : props.day === "sun" - ? "var(--color-red)" - : props.day === "sat" - ? "var(--color-blue)" - : null}; -`; - -const DateContent = styled.div``; - -const EventBlock = styled.div<{ - color: string; - isFirst: boolean; - isLast: boolean; -}>` - font-size: 10px; - margin-bottom: 2px; - font-weight: 400; - white-space: nowrap; - color: white; - background-color: ${(props) => props.color}; - position: relative; - - z-index: ${(props) => (props.isFirst ? 4 : 0)}; - padding-left: ${(props) => (props.isFirst ? "var(--gap-1)" : 0)}; - padding-right: ${(props) => (props.isLast ? "var(--gap-1)" : 0)}; -`; - -const TodayCircle = styled.div` - position: absolute; - top: 50%; - left: 50%; - width: 18px; - height: 18px; - border-radius: 50%; - transform: translate(-50%, -50%); - background-color: var(--gray-800); - color: white; -`; - -export default EventCalendar; diff --git a/pages/home/index.tsx b/pages/home/index.tsx index 09c55ad0b..d55eaf779 100644 --- a/pages/home/index.tsx +++ b/pages/home/index.tsx @@ -2,7 +2,7 @@ import { Box } from "@chakra-ui/react"; import { useState } from "react"; import Slide from "../../components/layouts/PageSlide"; -import HomeClubSection from "../../pageTemplates/home/HomeClubSection"; +import HomeCalendarSection from "../../pageTemplates/home/HomeCalendarSection"; import HomeGatherSection from "../../pageTemplates/home/HomeGatherSection"; import HomeHeader from "../../pageTemplates/home/homeHeader/HomeHeader"; import HomeInitialSetting from "../../pageTemplates/home/HomeInitialSetting"; @@ -26,7 +26,7 @@ function Home() { ) : tab === "번개" ? ( ) : tab === "캘린더" ? ( - + ) : tab === "추천" ? ( ) : null} diff --git a/pages/review/index.tsx b/pages/review/index.tsx index 086fc1c85..21a77f2ae 100644 --- a/pages/review/index.tsx +++ b/pages/review/index.tsx @@ -10,7 +10,7 @@ import KakaoShareBtn from "../../components/atoms/Icons/KakaoShareBtn"; import { MainLoading } from "../../components/atoms/loaders/MainLoading"; import Header from "../../components/layouts/Header"; import Slide from "../../components/layouts/PageSlide"; -import ButtonGroups, { IButtonOptions } from "../../components/molecules/groups/ButtonGroups"; +import ButtonGroups, { ButtonOptionsProps } from "../../components/molecules/groups/ButtonGroups"; import { LOCATION_OPEN } from "../../constants/location"; import { WEB_URL } from "../../constants/system"; import { useErrorToast } from "../../hooks/custom/CustomToast"; @@ -109,7 +109,7 @@ function Review() { setVisibleCnt((old) => old + 8); }; - const buttonArr: IButtonOptions[] = ["전체", ...LOCATION_OPEN].map((location) => ({ + const buttonArr: ButtonOptionsProps[] = ["전체", ...LOCATION_OPEN].map((location) => ({ text: location, func: () => location === "전체" @@ -136,7 +136,7 @@ function Review() { <> diff --git a/pages/study/writing/place.tsx b/pages/study/writing/place.tsx index 94e1cdcee..593d2439d 100644 --- a/pages/study/writing/place.tsx +++ b/pages/study/writing/place.tsx @@ -7,10 +7,12 @@ import styled from "styled-components"; import BottomNav from "../../../components/layouts/BottomNav"; import Header from "../../../components/layouts/Header"; import Slide from "../../../components/layouts/PageSlide"; -import ButtonGroups, { IButtonOptions } from "../../../components/molecules/groups/ButtonGroups"; +import ButtonGroups, { + ButtonOptionsProps, +} from "../../../components/molecules/groups/ButtonGroups"; import ProgressStatus from "../../../components/molecules/ProgressStatus"; import SearchLocation from "../../../components/organisms/SearchLocation"; -import { LOCATION_CONVERT, LOCATION_OPEN } from "../../../constants/location"; +import { LOCATION_OPEN, LOCATION_TO_FULLNAME } from "../../../constants/location"; import { useFailToast } from "../../../hooks/custom/CustomToast"; import RegisterLayout from "../../../pageTemplates/register/RegisterLayout"; import RegisterOverview from "../../../pageTemplates/register/RegisterOverview"; @@ -60,8 +62,8 @@ function WritingStudyPlace() { router.push(`/study/writing/content`); }; - const buttonItems: IButtonOptions[] = LOCATION_OPEN.map((locationInfo) => ({ - text: LOCATION_CONVERT[locationInfo], + const buttonOptionsArr: ButtonOptionsProps[] = LOCATION_OPEN.map((locationInfo) => ({ + text: LOCATION_TO_FULLNAME[locationInfo], func: () => setLocation(locationInfo), })); @@ -77,8 +79,8 @@ function WritingStudyPlace() { From 9852ced3696c41127566475c7e10401b4cfce39c Mon Sep 17 00:00:00 2001 From: "SeungJu, Lee" <84257439+SeungJL@users.noreply.github.com> Date: Mon, 2 Sep 2024 12:24:24 +0900 Subject: [PATCH 03/11] feat: calendar (#218) --- components/atoms/ColorLabel.tsx | 24 ++ components/atoms/LocationSelector.tsx | 4 +- components/atoms/MonthNav.tsx | 42 +-- components/atoms/PointCircle.tsx | 5 +- components/atoms/PointCircleText.tsx | 22 -- components/molecules/PointCircleTextRow.tsx | 21 -- components/molecules/groups/ButtonGroups.tsx | 58 ++-- components/molecules/rows/ColorLabelRow.tsx | 21 ++ components/organisms/Calendar.tsx | 200 ++++++++++++ .../calendarSchedule.ts} | 168 +++++++--- constants/contentsText/accordionContents.ts | 2 +- constants/location.ts | 27 +- .../studyConstants/studyLocationConstants.ts | 1 - modals/InviteUserModal.tsx | 4 +- pageTemplates/gather/GatherLocationFilter.tsx | 6 +- pageTemplates/home/HomeCalendarSection.tsx | 50 +++ pageTemplates/home/HomeClubSection.tsx | 272 ---------------- pageTemplates/home/HomeRankingSection.tsx | 2 +- pageTemplates/home/HomeReviewSection.tsx | 2 +- pageTemplates/home/study/HomeStudyChart.tsx | 13 +- pageTemplates/home/study/HomeStudyCol.tsx | 4 +- .../study/studyController/StudyController.tsx | 4 +- pageTemplates/record/RecordCalendar.tsx | 154 +++++---- .../record/RecordCalendarSetting.tsx | 17 +- .../record/RecordLocationCategory.tsx | 87 ++--- pageTemplates/record/RecordOverview.tsx | 1 - pageTemplates/record/RecordSkeleton.tsx | 300 ------------------ .../record/detail/RecordDetailStudyBlock.tsx | 6 +- .../register/location/LocationMember.tsx | 4 +- .../SecretSquare/SecretSquareCategories.tsx | 8 +- pageTemplates/square/SquareLoungeSection.tsx | 30 +- pages/calendar/index.tsx | 11 +- pages/eventCalendar.tsx | 278 ---------------- pages/home/index.tsx | 4 +- pages/review/index.tsx | 6 +- pages/study/writing/place.tsx | 14 +- 36 files changed, 695 insertions(+), 1177 deletions(-) create mode 100644 components/atoms/ColorLabel.tsx delete mode 100644 components/atoms/PointCircleText.tsx delete mode 100644 components/molecules/PointCircleTextRow.tsx create mode 100644 components/molecules/rows/ColorLabelRow.tsx create mode 100644 components/organisms/Calendar.tsx rename constants/{settingValue/eventContents.ts => contents/calendarSchedule.ts} (59%) create mode 100644 pageTemplates/home/HomeCalendarSection.tsx delete mode 100644 pageTemplates/home/HomeClubSection.tsx delete mode 100644 pageTemplates/record/RecordSkeleton.tsx delete mode 100644 pages/eventCalendar.tsx diff --git a/components/atoms/ColorLabel.tsx b/components/atoms/ColorLabel.tsx new file mode 100644 index 000000000..aed3712e5 --- /dev/null +++ b/components/atoms/ColorLabel.tsx @@ -0,0 +1,24 @@ +import { Box, Flex } from "@chakra-ui/react"; + +import { CustomColor } from "../../types/globals/interaction"; +import PointCircle from "./PointCircle"; + +export interface ColorLabelProps { + color?: CustomColor; + colorText?: string; + //이후 colorText를 color로 변경 + text: string; +} + +function ColorLabel({ text, color, colorText }: ColorLabelProps) { + return ( + + + + {text} + + + ); +} + +export default ColorLabel; diff --git a/components/atoms/LocationSelector.tsx b/components/atoms/LocationSelector.tsx index eec5cf27e..19525d2ba 100644 --- a/components/atoms/LocationSelector.tsx +++ b/components/atoms/LocationSelector.tsx @@ -1,7 +1,7 @@ import { Select } from "@chakra-ui/react"; import { ChangeEvent, useEffect, useRef, useState } from "react"; -import { LOCATION_CONVERT } from "../../constants/location"; +import { LOCATION_TO_FULLNAME } from "../../constants/location"; import { DispatchType } from "../../types/hooks/reactTypes"; import { ActiveLocation } from "../../types/services/locationTypes"; import { isLocationType } from "../../utils/validationUtils"; @@ -57,7 +57,7 @@ export default function LocationSelector({ > {options.map((option, idx) => ( ))} diff --git a/components/atoms/MonthNav.tsx b/components/atoms/MonthNav.tsx index e63628145..f23a4dac0 100644 --- a/components/atoms/MonthNav.tsx +++ b/components/atoms/MonthNav.tsx @@ -1,42 +1,30 @@ +import { Box, Flex } from "@chakra-ui/react"; import { Dayjs } from "dayjs"; -import styled from "styled-components"; import { DispatchType } from "../../types/hooks/reactTypes"; -interface IMonthNav { - month: number; - setNavMonth: DispatchType; +interface MonthNavProps { + monthNum: number; + changeMonth: DispatchType; } -function MonthNav({ month, setNavMonth }: IMonthNav) { - const onClick = (dir: "left" | "right") => { - if (dir === "left") setNavMonth((old) => old.subtract(1, "month")); - else setNavMonth((old) => old.add(1, "month")); +function MonthNav({ monthNum, changeMonth }: MonthNavProps) { + const handleMonthChange = (dir: "left" | "right") => { + if (dir === "left") changeMonth((old) => old.subtract(1, "month")); + else changeMonth((old) => old.add(1, "month")); }; return ( - - onClick("left")}> + + handleMonthChange("left")}> - - {month + 1}월 - onClick("right")}> + + {monthNum + 1}월 + handleMonthChange("right")}> - - + + ); } -const Layout = styled.div` - display: flex; - align-items: center; - - font-size: 20px; - font-weight: 700; -`; - -const IconWrapper = styled.button` - padding: 0 var(--gap-1); -`; - export default MonthNav; diff --git a/components/atoms/PointCircle.tsx b/components/atoms/PointCircle.tsx index d17ee17e9..edde14d02 100644 --- a/components/atoms/PointCircle.tsx +++ b/components/atoms/PointCircle.tsx @@ -4,12 +4,13 @@ import { CustomColor } from "../../types/globals/interaction"; interface PointCircleProps { color?: CustomColor; + colorText?: string; } -function PointCircle({ color = "mint" }: PointCircleProps) { +function PointCircle({ color = "mint", colorText }: PointCircleProps) { return ( - + ); } diff --git a/components/atoms/PointCircleText.tsx b/components/atoms/PointCircleText.tsx deleted file mode 100644 index 974448313..000000000 --- a/components/atoms/PointCircleText.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { Box, Flex } from "@chakra-ui/react"; - -import { CustomColor } from "../../types/globals/interaction"; -import PointCircle from "./PointCircle"; - -export interface PointCircleTextProps { - color?: CustomColor; - text: string; -} - -function PointCircleText({ text, color }: PointCircleTextProps) { - return ( - - - - {text} - - - ); -} - -export default PointCircleText; diff --git a/components/molecules/PointCircleTextRow.tsx b/components/molecules/PointCircleTextRow.tsx deleted file mode 100644 index 3c3316b61..000000000 --- a/components/molecules/PointCircleTextRow.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { Box, Flex } from "@chakra-ui/react"; - -import PointCircleText, { PointCircleTextProps } from "../atoms/PointCircleText"; - -interface PointCircleTextRowProps { - props: PointCircleTextProps[]; -} - -function PointCircleTextRow({ props }: PointCircleTextRowProps) { - return ( - - {props.map((prop, idx) => ( - - - - ))} - - ); -} - -export default PointCircleTextRow; diff --git a/components/molecules/groups/ButtonGroups.tsx b/components/molecules/groups/ButtonGroups.tsx index c7a24658a..b2fc08987 100644 --- a/components/molecules/groups/ButtonGroups.tsx +++ b/components/molecules/groups/ButtonGroups.tsx @@ -1,44 +1,64 @@ import { Button, Flex } from "@chakra-ui/react"; import styled from "styled-components"; -export interface IButtonOptions { +export interface ButtonOptionsProps { text: string; func: () => void; + color?: string; } export interface IButtonGroups { - buttonItems: IButtonOptions[]; + buttonOptionsArr: ButtonOptionsProps[]; currentValue: string; size?: "sm" | "md"; isWrap?: boolean; isEllipse?: boolean; + type?: "block" | "text"; } export default function ButtonGroups({ - buttonItems, + buttonOptionsArr, currentValue, size, isWrap = false, isEllipse = false, + type = "block", }: IButtonGroups) { + console.log(buttonOptionsArr, currentValue); return ( - {buttonItems.map((buttonData, idx) => ( - - + {buttonOptionsArr.map((buttonOptions, idx) => ( + + {type === "block" ? ( + + ) : ( + + )} ))} diff --git a/components/molecules/rows/ColorLabelRow.tsx b/components/molecules/rows/ColorLabelRow.tsx new file mode 100644 index 000000000..6d830b787 --- /dev/null +++ b/components/molecules/rows/ColorLabelRow.tsx @@ -0,0 +1,21 @@ +import { Box, Flex } from "@chakra-ui/react"; + +import ColorLabel, { ColorLabelProps } from "../../atoms/ColorLabel"; + +interface ColorLabelRowProps { + props: ColorLabelProps[]; +} + +function ColorLabelRow({ props }: ColorLabelRowProps) { + return ( + + {props.map((prop, idx) => ( + + + + ))} + + ); +} + +export default ColorLabelRow; diff --git a/components/organisms/Calendar.tsx b/components/organisms/Calendar.tsx new file mode 100644 index 000000000..38d8353b0 --- /dev/null +++ b/components/organisms/Calendar.tsx @@ -0,0 +1,200 @@ +import { Box, Flex, Grid } from "@chakra-ui/react"; +import dayjs, { Dayjs } from "dayjs"; +import styled from "styled-components"; + +import { COLOR_TABLE } from "../../constants/colorConstants"; +import { CalendarContentProps } from "../../constants/contents/calendarSchedule"; +import { DAYS_OF_WEEK } from "../../constants/util/util"; + +interface CalendarProps { + monthFirstDate: Dayjs; + calendarContents: CalendarContentProps[]; +} + +export interface CalendarScheduleProps { + content: string; + color: string; + isFirst: boolean; + isLast: boolean; + blockIdx: number; +} + +export interface DaySchedules { + first: string | null; + second: string | null; + third: string | null; +} + +const DAY_BLOCK_WIDTH = 50; + +const CALENDAR_DAY_COLOR = { + sun: "var(--color-red)", + sat: "var(--color-blue)", +}; + +const SCHEDULE_TYPE_TO_COLOR = { + main: COLOR_TABLE[0], + schedule: COLOR_TABLE[5], + event: COLOR_TABLE[3], +}; + +const generateCalendarDates = (monthFirstDate: Dayjs) => { + const daysInMonth = monthFirstDate.daysInMonth(); + const frontBlankDate = monthFirstDate.day(); + const totalDate = daysInMonth + frontBlankDate; + const rowsInMonth = totalDate <= 35 ? 5 : 6; + return Array.from({ length: 7 * rowsInMonth }, (_, idx) => + idx < frontBlankDate || idx >= totalDate ? null : idx - frontBlankDate + 1, + ); +}; + +function Calendar({ monthFirstDate, calendarContents }: CalendarProps) { + const calendarDates = generateCalendarDates(monthFirstDate); + let endingSchedules = []; + + const daySchedules: DaySchedules = { + first: null, + second: null, + third: null, + }; + + const getDaySchedules = (date: number): CalendarScheduleProps[] => { + return calendarContents.reduce((acc: CalendarScheduleProps[], schedule) => { + const isFirstDay = date === schedule.start; + const isEndDay = date === schedule.end; + if (schedule.start <= date && date <= schedule.end) { + acc.push({ + content: schedule.content, + color: SCHEDULE_TYPE_TO_COLOR[schedule.type], + isFirst: isFirstDay, + isLast: isEndDay, + blockIdx: schedule?.blockIdx, + }); + if (isFirstDay) fillSchedule(schedule.content); + if (isEndDay) endingSchedules.push(schedule.content); + } + return acc; + }, []); + }; + + const deleteSchedule = (content: string) => { + for (const key in daySchedules) { + if (daySchedules[key] === content) daySchedules[key] = null; + } + }; + + const fillSchedule = (content: string) => { + const availableKey = Object.keys(daySchedules).find((key) => !daySchedules[key]); + if (availableKey) daySchedules[availableKey] = content; + }; + + return ( + + + {DAYS_OF_WEEK.map((day) => ( + + {day} + + ))} + + + {calendarDates?.map((item, idx) => { + const day = idx % 7 === 0 ? "sun" : idx % 7 === 6 ? "sat" : null; + const isToday = monthFirstDate.date(item).isSame(dayjs(), "day"); + const contentArr = getDaySchedules(item); + const dateInfo = Object.values(daySchedules).map((title) => + contentArr?.find((c) => c.content === title), + ); + + endingSchedules.forEach((item) => deleteSchedule(item)); + endingSchedules = []; + + return ( + + + {!isToday ? ( + item + ) : ( + + {item} + + )} + + <> + {dateInfo.map((item, idx2) => { + return ( + + {item?.isFirst ? item?.content : "\u00A0"} + + ); + })} + + + ); + })} + + + ); +} + +const EventBlock = styled.div<{ + color: string; + isFirst: boolean; + isLast: boolean; +}>` + font-size: 10px; + margin-bottom: 2px; + font-weight: 400; + white-space: nowrap; + color: white; + background-color: ${(props) => props.color}; + position: relative; + z-index: ${(props) => (props.isFirst ? 4 : 0)}; + padding-left: ${(props) => (props.isFirst ? "var(--gap-1)" : 0)}; + padding-right: ${(props) => (props.isLast ? "var(--gap-1)" : 0)}; +`; + +export default Calendar; diff --git a/constants/settingValue/eventContents.ts b/constants/contents/calendarSchedule.ts similarity index 59% rename from constants/settingValue/eventContents.ts rename to constants/contents/calendarSchedule.ts index 6ec359373..9ce228b28 100644 --- a/constants/settingValue/eventContents.ts +++ b/constants/contents/calendarSchedule.ts @@ -1,42 +1,40 @@ -import { TABLE_COLORS } from "../styles"; - -type Content = { +export interface CalendarContentProps { content: string; start: number; end: number; - color: string; - text: string; + type: "event" | "schedule" | "main"; + text?: string; blockIdx?: number; -}; +} -export const EVENT_CONTENT_2023: Record = { +export const EVENT_CONTENT_2023: Record = { 10: [ { content: "[10월] 에타 홍보 이벤트 추첨", start: 22, end: 24, - color: TABLE_COLORS[2], + type: "event", text: "에타에 동아리 홍보글을 올려주시면 100 포인트와 추첨을 통해 치킨 기프티콘을 드려요!", }, { content: "[시험기간] 랜덤선물 이벤트", start: 16, end: 22, - color: TABLE_COLORS[0], + type: "event", text: "항상 돌아오는 시험기간 파이팅 이벤트... 매일 단톡방에서 랜덤한 선착순 선물을 뿌립니다!", }, { content: "[시험기간] 스터디 투표 2배 이벤트 ", start: 16, end: 22, - color: TABLE_COLORS[3], + type: "event", text: "시험 기간에 스터디에 투표하면 점수를 2배로 받아요!", }, { content: "[오프라인] 번개 이벤트", start: 29, end: 31, - color: TABLE_COLORS[6], + type: "event", text: "진행 예정", }, ], @@ -45,21 +43,21 @@ export const EVENT_CONTENT_2023: Record = { content: "수원/안양 정기모임", start: 17, end: 18, - color: TABLE_COLORS[2], + type: "schedule", text: "정기모임", }, { content: "양천/강남", start: 18, end: 18, - color: TABLE_COLORS[0], + type: "schedule", text: "정기모임", }, { content: "정기 모임", start: 19, end: 19, - color: TABLE_COLORS[0], + type: "schedule", text: "정기모임", blockIdx: 1, }, @@ -67,7 +65,7 @@ export const EVENT_CONTENT_2023: Record = { content: "11월 홍보 이벤트 당첨자 선별", start: 26, end: 30, - color: TABLE_COLORS[3], + type: "event", text: "11월 홍보 이벤트 당첨자 선별", }, ], @@ -76,61 +74,61 @@ export const EVENT_CONTENT_2023: Record = { content: "시험 기간 이벤트", start: 4, end: 8, - color: TABLE_COLORS[0], + type: "event", text: "이벤트", }, { content: "홍보 이벤트 추첨", start: 22, end: 24, - color: TABLE_COLORS[1], + type: "event", text: "이벤트", }, { content: "수원/강남 펭귄 핫팩", start: 17, end: 31, - color: TABLE_COLORS[2], + type: "event", text: "이벤트", }, ], }; -export const EVENT_CONTENT_2024: Record = { +export const EVENT_CONTENT_2024: Record = { 6: [ { content: "시험기간 응원 선물 이벤트", start: 10, end: 14, - color: "var(--color-blue)", + type: "event", text: "시험기간 응원 기념으로 매일 단톡방에서 기프티콘을 뿌립니다!", }, { content: "동아리 1차 용인 MT", start: 25, end: 26, - color: "var(--color-mint)", + type: "schedule", text: "", }, { content: "모임 활성화 이벤트", start: 19, end: 20, - color: "var(--color-blue)", + type: "event", text: "이제 종강하고 동아리 내에서 본격적으로 다양한 모임을 진행해보려고 하는데요! 모임을 개최하고 진행해주시는 분께는 매번 5000원의 지원금을 드립니다!", }, { content: "소모임 개설 기간", start: 24, end: 30, - color: "var(--color-orange)", + type: "main", text: "방학동안 스터디 뿐만 아니라 다양한 장르의 그룹을 활성화 해보려고 해요! 토익, 자격증 등의 스터디 뿐만 아니라 카페 탐방, 영화 관람, 보드게임, 러닝, 취미 활동 등 모든 모임 개설이 가능합니다. 모임장에게는 2만원씩 지원 혜택이 있습니다.", }, { content: "홍보 이벤트", start: 24, end: 30, - color: "var(--color-blue)", + type: "event", text: "에타 홍보에 참여하고 상품 받아가세요! 총 10만원 쏩니다!", }, ], @@ -139,84 +137,170 @@ export const EVENT_CONTENT_2024: Record = { content: "동아리 2차 대성리 MT", start: 3, end: 4, - color: "var(--color-mint)", + type: "schedule", text: "", }, { content: "소모임 편성", start: 6, end: 7, - color: "var(--color-orange)", + type: "main", text: "", }, { content: "모임 활성화 이벤트", start: 8, end: 9, - color: "var(--color-blue)", + type: "event", text: "", }, { content: "알고리즘 공모전", start: 11, end: 12, - color: "var(--color-blue)", + type: "event", text: "", }, { content: "정기모임 진행 주간", - start: 19, + start: 18, end: 21, - color: "var(--color-mint)", + type: "schedule", text: "", }, { content: "라운지 및 피드, 채팅, 인스타 기능 출시", - start: 29, + start: 28, end: 31, - color: "var(--color-mint)", + type: "main", text: "", }, ], 8: [ { - content: "조모임 진행 기간", + content: "월간 체크", + start: 1, + end: 1, + type: "main", + text: "", + }, + { + content: "조모임 진행 주간", start: 8, end: 11, - color: "var(--color-orange)", + type: "schedule", text: "", }, { content: "커뮤니티 출시", start: 5, end: 6, - color: "var(--color-mint)", + type: "main", text: "", }, { - content: "지역별 정기모임 기간", - start: 15, - end: 18, - color: "var(--color-orange)", + content: "에브리타임 홍보 이벤트 시작 ~ ", + start: 13, + end: 15, + type: "event", + text: "", + }, + { + content: "지역 정기모임 주간", + start: 14, + end: 17, + type: "schedule", + text: "", + }, + + { + content: "온라인 스터디 오픈", + start: 20, + end: 22, + type: "main", text: "", }, { content: "추억의 뽑기 이벤트", start: 22, end: 23, - color: "var(--color-blue)", + type: "event", text: "", }, { content: "동아리 정비 기간", start: 26, end: 30, - color: "var(--color-mint)", + type: "schedule", + text: "", + }, + { + content: "한줄 카피라이팅 이벤트", + start: 28, + end: 30, + type: "event", + text: "", + }, + ], + 9: [ + { + content: "동아리 리뉴얼 ~ ", + start: 2, + end: 4, + type: "main", + text: "에브리타임에 홍보하면 매주 2분께 올리브영 기프티콘을 드려요!", + }, + { + content: "에타 홍보 이벤트 ~ ", + start: 3, + end: 5, + type: "event", + text: "에브리타임에 홍보하면 매주 2분께 올리브영 기프티콘을 드려요!", + }, + { + content: "디스코드 오픈 이벤트 ~ ", + start: 10, + end: 12, + type: "event", + text: "동아리 스터디 디스코드 채널이 생겼습니다! 같이 공부하고 이벤트 상품 받아가세요!", + }, + { + content: "열공 스터디 이벤트 ~ ", + start: 9, + end: 11, + type: "event", + text: "동아리 스터디 디스코드 채널이 생겼습니다! 같이 공부하고 이벤트 상품 받아가세요!", + }, + { + content: "유령인원 정리 기간", + start: 16, + end: 17, + type: "main", + text: "", + }, + { + content: "동아리 전체 정기모임", + start: 13, + end: 14, + type: "main", + text: "", + }, + { + content: "지역 정기모임 주간", + start: 19, + end: 22, + type: "schedule", + text: "", + }, + { + content: "ABOUT 빙고판 이벤트", + start: 17, + end: 28, + type: "event", text: "", }, ], - 9: [], 10: [], 11: [], 12: [], diff --git a/constants/contentsText/accordionContents.ts b/constants/contentsText/accordionContents.ts index 0a486fc73..88baeeef8 100644 --- a/constants/contentsText/accordionContents.ts +++ b/constants/contentsText/accordionContents.ts @@ -1,5 +1,5 @@ import { IAccordionContent } from "../../components/molecules/Accordion"; -import { EVENT_ALWAYS, EVENT_CONTENT_2024 } from "../../constants/settingValue/eventContents"; +import { EVENT_ALWAYS, EVENT_CONTENT_2024 } from "../contents/calendarSchedule"; //회원가입 질문 컨텐츠 export const ACCORDION_CONTENT_FEE: IAccordionContent[] = [ diff --git a/constants/location.ts b/constants/location.ts index 6e40f0d35..b8a30ba04 100644 --- a/constants/location.ts +++ b/constants/location.ts @@ -2,11 +2,12 @@ import { ActiveLocation, InactiveLocation, Location, - LocationEn, + LocationEn } from "../types/services/locationTypes"; -import { TABLE_COLORS } from "./styles"; +import { COLOR_TABLE } from "./colorConstants"; + +export const LOCATION_OPEN: ActiveLocation[] = ["수원", "양천", "강남", "동대문", "인천", "안양"]; -export const LOCATION_OPEN: ActiveLocation[] = ["수원", "양천", "안양", "강남", "동대문", "인천"]; export const LOCATION_RECRUITING: InactiveLocation[] = [ "마포", "성남", @@ -23,7 +24,7 @@ export const LOCATION_RECRUITING: InactiveLocation[] = [ export const LOCATION_ALL = [...LOCATION_OPEN, ...LOCATION_RECRUITING]; -export const LOCATION_CONVERT: Record = { +export const LOCATION_TO_FULLNAME: Record = { 수원: "수원시", 양천: "양천구 · 영등포구", 안양: "안양 인근 지역", @@ -76,15 +77,6 @@ export const LOCATION_MEMBER_CNT: { 시흥: { member: 7, new: 2 }, }; -export const LOCATION_TABLE_COLOR: Record = { - 수원: TABLE_COLORS[0], - 양천: TABLE_COLORS[3], - 안양: TABLE_COLORS[2], - 강남: TABLE_COLORS[1], - 인천: TABLE_COLORS[4], - 동대문: TABLE_COLORS[5], -}; - export const krToEnMapping: Record = { 수원: "suw", 강남: "gan", @@ -124,3 +116,12 @@ export const enToKrMapping: Record = { buc: "부천", sih: "시흥", }; + +export const LOCATION_TO_COLOR: Record = { + 수원: COLOR_TABLE[0], + 양천: COLOR_TABLE[1], + 강남: COLOR_TABLE[3], + 동대문: COLOR_TABLE[4], + 인천: COLOR_TABLE[2], + 안양: COLOR_TABLE[5], +}; diff --git a/constants/serviceConstants/studyConstants/studyLocationConstants.ts b/constants/serviceConstants/studyConstants/studyLocationConstants.ts index 68645e127..c8b78f57d 100644 --- a/constants/serviceConstants/studyConstants/studyLocationConstants.ts +++ b/constants/serviceConstants/studyConstants/studyLocationConstants.ts @@ -208,7 +208,6 @@ export const PLACE_TO_LOCATION = createPlaceToLocationMap(LOCATION_TO_PLACE); function createPlaceToLocationMap(obj: LocationToPlace) { const placeToLocationMap: { [key: string]: ActiveLocation } = {}; - Object.entries(obj).forEach(([location, ids]) => { ids.forEach((id) => { placeToLocationMap[id] = location as ActiveLocation; diff --git a/modals/InviteUserModal.tsx b/modals/InviteUserModal.tsx index 739ef7b14..95b97b96b 100644 --- a/modals/InviteUserModal.tsx +++ b/modals/InviteUserModal.tsx @@ -61,7 +61,7 @@ export default function InviteUserModal({ setIsModal }: IInviteUserModal) { }, }; - const buttonItems = [ + const buttonOptionsArr = [ { text: "수원", func: () => setLocation("수원"), @@ -90,7 +90,7 @@ export default function InviteUserModal({ setIsModal }: IInviteUserModal) { return ( - + onClickButton("전체"), @@ -64,7 +64,7 @@ export default function GatherLocationFilter() { return ( { + buttonOptionsArr={buttonOptionsArr.sort((x, y) => { if (x.text === "전체") return -1; if (y.text === "전체") return 1; if (x.text === defaultLocation) return -1; diff --git a/pageTemplates/home/HomeCalendarSection.tsx b/pageTemplates/home/HomeCalendarSection.tsx new file mode 100644 index 000000000..d12547e84 --- /dev/null +++ b/pageTemplates/home/HomeCalendarSection.tsx @@ -0,0 +1,50 @@ +import { Box, Flex } from "@chakra-ui/react"; +import dayjs from "dayjs"; +import { useState } from "react"; + +import { ColorLabelProps } from "../../components/atoms/ColorLabel"; +import MonthNav from "../../components/atoms/MonthNav"; +import Accordion from "../../components/molecules/Accordion"; +import ColorLabelRow from "../../components/molecules/rows/ColorLabelRow"; +import Calendar from "../../components/organisms/Calendar"; +import { COLOR_TABLE } from "../../constants/colorConstants"; +import { EVENT_CONTENT_2024 } from "../../constants/contents/calendarSchedule"; +import { ACCORDION_CONTENT_EVENT } from "../../constants/contentsText/accordionContents"; + +const SCHEDULE_CATEGORIES: ColorLabelProps[] = [ + { + text: "공식 행사", + colorText: COLOR_TABLE[0], + }, + { + text: "이벤트", + colorText: COLOR_TABLE[3], + }, + { + text: "일정", + colorText: COLOR_TABLE[5], + }, +]; + +function HomeCalendarSection() { + const [monthFirstDate, setMonthFirstDate] = useState(dayjs().startOf("month")); + const monthNum = monthFirstDate.month(); + + const calendarContents = + monthFirstDate.year() === 2024 ? EVENT_CONTENT_2024[monthFirstDate.month() + 1] : null; + return ( + <> + + + + + + + 일정 상세정보 + + + + ); +} + +export default HomeCalendarSection; diff --git a/pageTemplates/home/HomeClubSection.tsx b/pageTemplates/home/HomeClubSection.tsx deleted file mode 100644 index 8206ded7b..000000000 --- a/pageTemplates/home/HomeClubSection.tsx +++ /dev/null @@ -1,272 +0,0 @@ -import { Box, Flex } from "@chakra-ui/react"; -import dayjs from "dayjs"; -import { Fragment, useState } from "react"; -import styled from "styled-components"; - -import MonthNav from "../../components/atoms/MonthNav"; -import { PointCircleTextProps } from "../../components/atoms/PointCircleText"; -import Accordion from "../../components/molecules/Accordion"; -import PointCircleTextRow from "../../components/molecules/PointCircleTextRow"; -import { ACCORDION_CONTENT_EVENT } from "../../constants/contentsText/accordionContents"; -import { EVENT_CONTENT_2024 } from "../../constants/settingValue/eventContents"; -import { DAYS_OF_WEEK } from "../../constants/util/util"; -const DAYS_TITLE = ["포인트 2배", null, null, null, null, null, "점수 2배"]; - -interface IEventContent { - content: string; - color: string; - isFirst: boolean; - isLast: boolean; - blockIdx?: number; -} - -function HomeClubSection() { - const [navMonth, setNavMonth] = useState(dayjs().startOf("month")); - - const getFilledDates = (navMonth: dayjs.Dayjs) => { - const daysInMonth = navMonth.daysInMonth(); - const frontBlankDate = navMonth.day(); - const totalDate = daysInMonth + frontBlankDate; - const rowsInMonth = totalDate <= 35 ? 5 : 6; - return Array.from({ length: 7 * rowsInMonth }, (_, idx) => - idx < frontBlankDate || idx >= totalDate ? null : idx - frontBlankDate + 1, - ); - }; - - const filledDates = getFilledDates(navMonth); - - const eventBlocks: { [key: string]: string } = { - first: null, - second: null, - third: null, - }; - - let endBlocks = []; - - const filledContents = (date: number) => { - const eventArr = navMonth.year() === 2024 ? EVENT_CONTENT_2024[navMonth.month() + 1] : null; - - if (!eventArr) return; - return eventArr.reduce((acc: IEventContent[], event) => { - const isFirstDay = date === event.start; - const isEndDay = date === event.end; - if (event.start <= date && date <= event.end) { - acc.push({ - content: event.content, - color: event.color, - isFirst: isFirstDay, - isLast: isEndDay, - blockIdx: event?.blockIdx, - }); - if (isFirstDay) fillEventDate(event.content); - if (isEndDay) endBlocks.push(event.content); - } - return acc; - }, []); - }; - - const fillEventDate = (content: string) => { - const availableKey = Object.keys(eventBlocks).find((key) => !eventBlocks[key]); - if (availableKey) eventBlocks[availableKey] = content; - }; - - const deleteEventDate = (content: string) => { - for (const key in eventBlocks) { - if (eventBlocks[key] === content) eventBlocks[key] = null; - } - }; - - const textRowObj: PointCircleTextProps[] = [ - { - text: "공식 행사", - color: "mint", - }, - { - text: "이벤트", - color: "blue", - }, - { - text: "일정", - color: "orange", - }, - ]; - - return ( - <> - - - - - - - {DAYS_TITLE.map((day, idx) => ( -
{day}
- ))} -
- - {DAYS_OF_WEEK.map((day) => ( -
{day}
- ))} -
- - {filledDates?.map((item, idx) => { - const day = idx % 7 === 0 ? "sun" : idx % 7 === 6 ? "sat" : null; - const isToday = navMonth.date(item).isSame(dayjs(), "day"); - - const contentArr = filledContents(item); - const dateInfo = Object.values(eventBlocks).map((title) => - contentArr?.find((c) => c.content === title), - ); - - endBlocks.forEach((item) => deleteEventDate(item)); - endBlocks = []; - - return ( - - - {!isToday ? item : {item}} - - - {dateInfo.map((item, idx2) => { - return ( - - {item?.blockIdx !== undefined && ( - -   - - )} - - {item?.isFirst ? item?.content : "\u00A0"} - - - ); - })} - - - ); - })} - -
- - 이벤트 상세정보 - - - - ); -} - -const Calendar = styled.div` - width: 364px; - margin: 0 auto; - display: flex; - flex-direction: column; -`; - -const WeekTitleHeader = styled.div` - display: flex; - justify-content: space-between; - font-size: 10px; - color: var(--color-mint); - - margin-bottom: var(--gap-1); - font-weight: 600; - > div { - flex: 1; - text-align: center; - } -`; - -const DayOfWeek = styled.div` - display: flex; - justify-content: space-between; - background-color: var(--gray-200); - padding: var(--gap-1) 0; - font-size: 12px; - > div { - flex: 1; - text-align: center; - } - > div:first-child { - color: var(--color-red); - } - > div:last-child { - color: #6bafff; - } -`; - -const CalendarDates = styled.div` - display: grid; - background-color: white; - grid-template-columns: repeat(7, 1fr); - border: var(--border); - border-radius: var(--rounded); - > div:first-child { - color: var(--color-red); - } -`; - -const DateBlock = styled.div` - width: 52px; - padding-top: var(--gap-1); - font-size: 12px; - font-weight: 600; - text-align: center; - flex: 1; - border-top: var(--border); -`; - -const Date = styled.div<{ day: "sun" | "sat"; isToday: boolean }>` - position: relative; - height: 18px; - margin-bottom: var(--gap-1); - color: ${(props) => - props.isToday - ? "white" - : props.day === "sun" - ? "var(--color-red)" - : props.day === "sat" - ? "var(--color-blue)" - : null}; -`; - -const DateContent = styled.div``; - -const EventBlock = styled.div<{ - color: string; - isFirst: boolean; - isLast: boolean; -}>` - font-size: 10px; - margin-bottom: 2px; - font-weight: 400; - white-space: nowrap; - color: white; - background-color: ${(props) => props.color}; - position: relative; - - z-index: ${(props) => (props.isFirst ? 4 : 0)}; - padding-left: ${(props) => (props.isFirst ? "var(--gap-1)" : 0)}; - padding-right: ${(props) => (props.isLast ? "var(--gap-1)" : 0)}; -`; - -const TodayCircle = styled.div` - position: absolute; - top: 50%; - left: 50%; - width: 18px; - height: 18px; - border-radius: 50%; - transform: translate(-50%, -50%); - background-color: var(--gray-800); - color: white; -`; - -export default HomeClubSection; diff --git a/pageTemplates/home/HomeRankingSection.tsx b/pageTemplates/home/HomeRankingSection.tsx index 351edc77e..7f42d2d77 100644 --- a/pageTemplates/home/HomeRankingSection.tsx +++ b/pageTemplates/home/HomeRankingSection.tsx @@ -1,5 +1,5 @@ import RecommendationBannerCard from "../../components/organisms/cards/RecommendationBannerCard"; -import { HOME_RECOMMENDATION_TAB_CONTENTS } from "../../constants/contents/HomeRecommendationTab"; +import { HOME_RECOMMENDATION_TAB_CONTENTS } from "../../constants/contents/homeRecommendationTab"; function HomeRankingSection() { return ( diff --git a/pageTemplates/home/HomeReviewSection.tsx b/pageTemplates/home/HomeReviewSection.tsx index 00025e037..e52454a15 100644 --- a/pageTemplates/home/HomeReviewSection.tsx +++ b/pageTemplates/home/HomeReviewSection.tsx @@ -24,7 +24,7 @@ export default function HomeReviewSection() { } + rightComponent={} /> {imageArr && } diff --git a/pageTemplates/home/study/HomeStudyChart.tsx b/pageTemplates/home/study/HomeStudyChart.tsx index e321becac..f5768632d 100644 --- a/pageTemplates/home/study/HomeStudyChart.tsx +++ b/pageTemplates/home/study/HomeStudyChart.tsx @@ -1,11 +1,11 @@ import { Box } from "@chakra-ui/react"; import dayjs from "dayjs"; import dynamic from "next/dynamic"; -import { useRouter } from "next/navigation"; import HighlightedTextButton from "../../../components/atoms/buttons/HighlightedTextButton"; import SectionBar from "../../../components/molecules/bars/SectionBar"; import { ChartStudyOptions } from "../../../components/organisms/chart/ChartOptions"; +import { useToast } from "../../../hooks/custom/CustomToast"; import { VoteCntProps } from "../../../types/models/studyTypes/studyRecords"; interface HomeStudyChartProps { @@ -13,7 +13,8 @@ interface HomeStudyChartProps { } function HomeStudyChart({ voteCntArr }: HomeStudyChartProps) { - const router = useRouter(); + // const router = useRouter(); + const toast = useToast(); const ApexCharts = dynamic(() => import("react-apexcharts"), { ssr: false }); const filtered: VoteCntProps[] = voteCntArr?.reduce((acc, cur) => { @@ -35,13 +36,15 @@ function HomeStudyChart({ voteCntArr }: HomeStudyChartProps) { xArr.push(dayjs(obj.date).date() + ""); }); + const onClick = () => { + toast("warning", "24년 9월 5일 오픈"); + }; + return ( <> router.push("/calendar")} /> - } + rightComponent={} /> - - - - {filterData?.map((item, idx) => { - const arrivedInfo = item?.arrivedInfoList; +function RecordCalendar({ filterData, monthFirstDate }: IRecordCalendar) { + console.log(2, filterData); + const calendarContents: CalendarContentProps[] = filterData.flatMap((data) => { + const arrivedInfo = data?.arrivedInfoList; + const date = data?.date; + const dayjsDate = date && dayjsToStr(monthFirstDate.date(date)); + let openLocation = null; + for (const key in LOCATION_OPEN_DATE) { + if (LOCATION_OPEN_DATE[key] === dayjsDate) openLocation = key; + } + const openStudyLocation: Set<{ + location: string; + cnt: number; + }> = new Set(); + arrivedInfo?.forEach((place) => { + openStudyLocation.add({ + location: PLACE_TO_LOCATION[place.placeId], + cnt: place.arrivedInfo.length, + }); + }); + console.log(24, arrivedInfo, openLocation, openStudyLocation); + let tempCnt = 0; - const date = item?.date; - const dayjsDate = date && dayjsToStr(navMonth.date(date)); - let openLocation = null; - for (const key in LOCATION_OPEN_DATE) { - if (LOCATION_OPEN_DATE[key] === dayjsDate) openLocation = key; - } - const openStudyLocation: Set<{ - location: string; - cnt: number; - }> = new Set(); - arrivedInfo?.forEach((place) => { - openStudyLocation.add({ - location: PLACE_TO_LOCATION[place.placeId], - cnt: place.arrivedInfo.length, - }); - }); - let tempCnt = 0; - return ( - - {!openLocation ? ( - {date} - ) : ( - {date} - )} - {Array.from(openStudyLocation).map((location, idx) => { - if (idx > 2 || location.cnt < 2) return null; - tempCnt++; - return ( - - {tempCnt < 4 || openStudyLocation.size <= 3 ? ( - "Open" - ) : ( - - )} - - ); - })} - - ); - })} - - + const resData = Array.from(openStudyLocation) + .map((location, idx) => { + if (idx > 2 || location.cnt < 2) return null; + tempCnt++; + return { + content: "오픈", + start: date, + end: date, + type: "main" as "main" | "event" | "schedule", + blockIdx: tempCnt - 1, + }; + }) + .filter((place) => place !== null); + return resData; + // { + // Array.from(openStudyLocation).map((location, idx) => { + // if (idx > 2 || location.cnt < 2) return null; + // tempCnt++; + // return ( + // + // {tempCnt < 4 || openStudyLocation.size <= 3 ? ( + // "스터디 오픈" + // ) : ( + // + // )} + // + // ); + // }); + // } + }); + console.log(calendarContents); + return ( + + + + // + // + // + // {filterData?.map((data, idx) => { + // + // return ( + // + // {!openLocation ? ( + // {date} + // ) : ( + // {date} + // )} + // {Array.from(openStudyLocation).map((location, idx) => { + // if (idx > 2 || location.cnt < 2) return null; + // tempCnt++; + // return ( + // + // {tempCnt < 4 || openStudyLocation.size <= 3 ? ( + // "스터디 오픈" + // ) : ( + // + // )} + // + // ); + // })} + // + // ); + // })} + // + // ); } function DayOfWeek() { @@ -104,7 +150,7 @@ const LocationOpen = styled.div<{ location: Location }>` display: flex; justify-content: center; align-items: center; - border: ${(props) => `2px solid ${LOCATION_TABLE_COLOR[props.location]}`}; + border: ${(props) => `2px solid ${LOCATION_TO_COLOR[props.location]}`}; width: 24px; height: 24px; border-radius: 50%; @@ -112,7 +158,7 @@ const LocationOpen = styled.div<{ location: Location }>` const Open = styled.div<{ location: Location }>` font-size: 10px; - color: ${(props) => LOCATION_TABLE_COLOR[props.location] || "var(--gray-500)"}; + color: ${(props) => LOCATION_TO_COLOR[props.location]}; `; const DayLine = styled.div` diff --git a/pageTemplates/record/RecordCalendarSetting.tsx b/pageTemplates/record/RecordCalendarSetting.tsx index 4c9a8c189..0c10caa35 100644 --- a/pageTemplates/record/RecordCalendarSetting.tsx +++ b/pageTemplates/record/RecordCalendarSetting.tsx @@ -1,6 +1,7 @@ import dayjs, { Dayjs } from "dayjs"; import { useEffect } from "react"; +import { ALL_스터디인증 } from "../../constants/serviceConstants/studyConstants/studyPlaceConstants"; import { useErrorToast } from "../../hooks/custom/CustomToast"; import { useStudyAttendRecordQuery } from "../../hooks/study/queries"; import { DispatchBoolean, DispatchType } from "../../types/hooks/reactTypes"; @@ -40,11 +41,17 @@ function RecordCalendarSetting({ ? null : { date: idx - frontBlankDate + 1, arrivedInfoList: [] }, ); - studyRecords.forEach((item) => { - const filledIdx = dayjs(item.date).date() + frontBlankDate - 1; - const data = filledDates[filledIdx]; - if (data) data.arrivedInfoList = item.arrivedInfoList; - }); + + studyRecords + .map((study) => ({ + arrivedInfoList: study.arrivedInfoList.filter((item) => item.placeId !== ALL_스터디인증), + date: study.date, + })) + .forEach((item) => { + const filledIdx = dayjs(item.date).date() + frontBlankDate - 1; + const data = filledDates[filledIdx]; + if (data) data.arrivedInfoList = item.arrivedInfoList; + }); setArrivedCalendar(filledDates); // eslint-disable-next-line react-hooks/exhaustive-deps }, [isLoading, navMonth, studyRecords]); diff --git a/pageTemplates/record/RecordLocationCategory.tsx b/pageTemplates/record/RecordLocationCategory.tsx index ebc25eb9e..93f17287d 100644 --- a/pageTemplates/record/RecordLocationCategory.tsx +++ b/pageTemplates/record/RecordLocationCategory.tsx @@ -1,11 +1,12 @@ +import { Box } from "@chakra-ui/react"; import { useEffect, useState } from "react"; -import styled from "styled-components"; -import { LOCATION_CONVERT, LOCATION_OPEN, LOCATION_TABLE_COLOR } from "../../constants/location"; +import ButtonGroups from "../../components/molecules/groups/ButtonGroups"; +import { LOCATION_OPEN, LOCATION_TO_COLOR, LOCATION_TO_FULLNAME } from "../../constants/location"; import { PLACE_TO_LOCATION } from "../../constants/serviceConstants/studyConstants/studyLocationConstants"; import { DispatchType } from "../../types/hooks/reactTypes"; import { IArrivedData } from "../../types/models/studyTypes/studyRecords"; -import { Location, LocationFilterType } from "../../types/services/locationTypes"; +import { ActiveLocationAll } from "../../types/services/locationTypes"; interface IRecordLocationCategory { initialData: IArrivedData[]; @@ -13,12 +14,7 @@ interface IRecordLocationCategory { } function RecordLocationCategory({ initialData, setFilterData }: IRecordLocationCategory) { - const [category, setCategory] = useState("전체"); - - const onClickBadge = (value: Location) => { - if (value === category) setCategory("전체"); - else setCategory(value); - }; + const [category, setCategory] = useState("전체"); useEffect(() => { if (!initialData) return; @@ -35,58 +31,31 @@ function RecordLocationCategory({ initialData, setFilterData }: IRecordLocationC } }, [category, initialData, setFilterData]); + const buttonOptionsArr = (["전체", ...LOCATION_OPEN] as ActiveLocationAll[]).map((location) => ({ + text: LOCATION_TO_FULLNAME[location] || "전체", + func: () => { + if (location === category) setCategory("전체"); + else setCategory(location); + }, + color: LOCATION_TO_COLOR[location], + })); + return ( - - - {LOCATION_OPEN.map((location) => ( - - ))} - - + + + ); } -const Layout = styled.div` - padding: 0 var(--gap-4); - height: 36px; - display: flex; - align-items: center; - justify-content: space-between; - background-color: var(--gray-200); - border-top: 1px solid var(--gray-300); - border-bottom: 1px solid var(--gray-300); - > div { - display: flex; - align-items: center; - } - > span:last-child { - font-size: 10px; - color: var(--gray-600); - } -`; - -const SpaceBadge = styled.section` - display: flex; - align-items: center; -`; - -const Button = styled.button<{ - location: Location; - category: LocationFilterType; -}>` - margin-right: var(--gap-3); - font-weight: 600; - color: ${(props) => LOCATION_TABLE_COLOR[props.location]}; - font-size: ${(props) => (props.category === props.location ? "14px" : "12px")}; - opacity: ${(props) => - props.category !== "전체" && props.category !== props.location ? "0.7" : "1"}; -`; - export default RecordLocationCategory; diff --git a/pageTemplates/record/RecordOverview.tsx b/pageTemplates/record/RecordOverview.tsx index 238200092..ca529a676 100644 --- a/pageTemplates/record/RecordOverview.tsx +++ b/pageTemplates/record/RecordOverview.tsx @@ -107,7 +107,6 @@ const MyRecordItem = styled.div` flex-direction: column; justify-content: space-around; height: 100%; - > div { display: flex; align-items: center; diff --git a/pageTemplates/record/RecordSkeleton.tsx b/pageTemplates/record/RecordSkeleton.tsx deleted file mode 100644 index cec0e61e6..000000000 --- a/pageTemplates/record/RecordSkeleton.tsx +++ /dev/null @@ -1,300 +0,0 @@ -import dayjs from "dayjs"; -import styled from "styled-components"; - -import Skeleton from "../../components/atoms/skeleton/Skeleton"; -import { LOCATION_CONVERT, LOCATION_OPEN, LOCATION_TABLE_COLOR } from "../../constants/location"; -import { Location } from "../../types/services/locationTypes"; - -interface IRecordSkeleton { - isCalendar: boolean; -} - -function RecordSkeleton({ isCalendar }: IRecordSkeleton) { - const blankDate = Array.from( - { - length: dayjs().date(1).day(), - }, - (_, i) => i + 1, - ); - - const totalDate = Array.from( - { - length: dayjs().daysInMonth(), - }, - (_, i) => i + 1, - ); - return ( - - - - -
- 스터디 오픈 - - temp - -
-
- 참여한 인원 - - temp - -
-
- -
- 내 참여 횟수 - - temp - -
-
- 내 최근 참여 - - temp - -
-
-
-
- - - {LOCATION_OPEN.map((location) => ( - - {LOCATION_CONVERT[location]} - - ))} - - - {isCalendar ? ( - - - - {blankDate?.map((item) => )} - - {totalDate?.map((item, idx) => ( - - {item} - - Open - - - ))} - - - ) : ( - - {new Array(6).fill(0).map((_, idx) => ( - - - temp - - - {new Array(2).fill(0).map((_, idx2) => ( - - - - tempte - - - temp - - - - {new Array(3).fill(0).map((who, idx3) => ( - - temp - - ))} - - - ))} - - - ))} - - )} -
- ); -} -function DayOfWeek() { - return ( - - - - - - - - - - ); -} - -const Layout = styled.div``; - -/** overview */ -const RecordOverview = styled.div` - padding: var(--gap-3) var(--gap-4); - display: flex; - justify-content: space-between; - align-items: center; - height: 80px; -`; - -const MyRecord = styled.div` - display: flex; - height: 100%; - > div:first-child { - width: 125px; - } - > div:last-child { - width: 140px; - } -`; - -const MyRecordItem = styled.div` - display: flex; - flex-direction: column; - justify-content: space-around; - height: 100%; - - > div { - display: flex; - align-items: center; - } -`; -const ContentName = styled.span` - margin-right: var(--gap-2); - color: var(--gray-600); - font-size: 13px; -`; - -const ContentValue = styled.span` - font-weight: 700; - font-size: 14px; - color: var(--gray-700); -`; -const SpaceBadge = styled.section` - display: flex; - align-items: center; -`; - -const Button2 = styled.button<{ - location: Location; -}>` - margin-right: var(--gap-3); - font-weight: 600; - color: ${(props) => LOCATION_TABLE_COLOR[props.location]}; - font-size: 12px; -`; - -/** category */ -const Category = styled.div` - padding: 0 var(--gap-4); - height: 36px; - display: flex; - align-items: center; - justify-content: space-between; - background-color: var(--gray-200); - border-top: 1px solid var(--gray-300); - border-bottom: 1px solid var(--gray-300); - > div { - display: flex; - align-items: center; - } - > span:last-child { - font-size: 10px; - color: var(--gray-600); - } -`; - -/** calendar */ - -const Calendar = styled.div``; - -const CallenderDays = styled.div` - display: grid; - grid-auto-rows: 72px; - grid-template-columns: repeat(7, 1fr); - margin: 0 var(--gap-1); - font-size: 14px; -`; -const DayItem = styled.div` - flex: 1; - display: flex; - flex-direction: column; - align-items: center; - border: 1px solid var(--gray-200); -`; - -const DayItemDate = styled.span<{ isToday: boolean }>` - color: ${(props) => (props.isToday ? "var(--color-mint)" : null)}; - font-weight: ${(props) => (props.isToday ? "600" : null)}; - font-size: ${(props) => (props.isToday ? "15px" : null)}; -`; - -const Open = styled.div` - font-size: 10px; -`; - -const DayLine = styled.div` - margin: var(--gap-2) 24px; - display: flex; - justify-content: space-between; - color: var(--gray-600); - font-size: 12px; -`; - -/** detail */ - -export const Detail = styled.div` - display: flex; - flex-direction: column; -`; -const Block = styled.div` - border-top: 4px solid var(--gray-200); - padding: var(--gap-3) var(--gap-4); - padding-bottom: 0; -`; -const Date = styled.div` - margin-bottom: var(--gap-3); - font-size: 13px; - color: var(--gray-700); -`; -const StudyInfo = styled.div` - font-size: 12px; - color: var(--gray-700); -`; -const PlaceInfo = styled.div` - margin-bottom: var(--gap-3); -`; - -const PlaceName = styled.div` - display: flex; - align-items: center; - color: var(--gray-700); - font-size: 14px; - > span:first-child { - font-weight: 600; - margin-right: var(--gap-1); - } -`; -const OpenLocation = styled.span` - font-size: 11px; -`; - -const MemberWrapper = styled.div` - margin-top: var(--gap-3); - - display: grid; - grid-template-columns: repeat(auto-fill, minmax(20%, auto)); - align-items: center; - line-height: 2; -`; - -const Member = styled.span` - margin-right: var(--gap-1); - color: var(--gray-600); -`; -export default RecordSkeleton; diff --git a/pageTemplates/record/detail/RecordDetailStudyBlock.tsx b/pageTemplates/record/detail/RecordDetailStudyBlock.tsx index ab569113e..29522d8e2 100644 --- a/pageTemplates/record/detail/RecordDetailStudyBlock.tsx +++ b/pageTemplates/record/detail/RecordDetailStudyBlock.tsx @@ -1,7 +1,7 @@ import { Fragment } from "react"; import styled from "styled-components"; -import { LOCATION_TABLE_COLOR } from "../../../constants/location"; +import { LOCATION_TO_COLOR } from "../../../constants/location"; import { PLACE_TO_NAME } from "../../../constants/serviceConstants/studyConstants/studyCafeNameConstants"; import { PLACE_TO_LOCATION } from "../../../constants/serviceConstants/studyConstants/studyLocationConstants"; import { Location } from "../../../types/services/locationTypes"; @@ -59,7 +59,7 @@ const PlaceInfo = styled.div<{ location: Location }>` width: 148px; flex-shrink: 0; margin-bottom: var(--gap-4); - border: ${(props) => `1px solid ${LOCATION_TABLE_COLOR[props.location]}`}; + border: ${(props) => `1px solid ${LOCATION_TO_COLOR[props.location]}`}; border-radius: var(--rounded-lg); padding: var(--gap-2); @@ -79,7 +79,7 @@ const PlaceName = styled.div` const OpenLocation = styled.span<{ location: Location }>` font-size: 11px; - color: ${(props) => LOCATION_TABLE_COLOR[props.location]}; + color: ${(props) => LOCATION_TO_COLOR[props.location]}; `; const MemberWrapper = styled.div` diff --git a/pageTemplates/register/location/LocationMember.tsx b/pageTemplates/register/location/LocationMember.tsx index 90ba38724..d1e82cfe0 100644 --- a/pageTemplates/register/location/LocationMember.tsx +++ b/pageTemplates/register/location/LocationMember.tsx @@ -1,12 +1,12 @@ import styled from "styled-components"; -import { LOCATION_CONVERT, LOCATION_MEMBER_CNT } from "../../../constants/location"; +import { LOCATION_MEMBER_CNT, LOCATION_TO_FULLNAME } from "../../../constants/location"; import { Location } from "../../../types/services/locationTypes"; function LocationMember({ location }: { location: Location }) { return ( - {LOCATION_CONVERT[location]} + {LOCATION_TO_FULLNAME[location]} {LOCATION_MEMBER_CNT[location].new} diff --git a/pageTemplates/square/SecretSquare/SecretSquareCategories.tsx b/pageTemplates/square/SecretSquare/SecretSquareCategories.tsx index 57648b426..70face7c4 100644 --- a/pageTemplates/square/SecretSquare/SecretSquareCategories.tsx +++ b/pageTemplates/square/SecretSquare/SecretSquareCategories.tsx @@ -1,7 +1,9 @@ import { Box } from "@chakra-ui/react"; import { Dispatch, SetStateAction } from "react"; -import ButtonGroups, { IButtonOptions } from "../../../components/molecules/groups/ButtonGroups"; +import ButtonGroups, { + ButtonOptionsProps, +} from "../../../components/molecules/groups/ButtonGroups"; import { type SecretSquareCategoryWithAll } from "../../../types/models/square"; const SECRET_SQUARE_CATEGORY: SecretSquareCategoryWithAll[] = [ @@ -21,7 +23,7 @@ function SecretSquareCategories({ category: selectedCategory, setCategory, }: SecretSquareCategoryProps) { - const buttonItems: IButtonOptions[] = SECRET_SQUARE_CATEGORY.map((category) => ({ + const buttonOptionsArr: ButtonOptionsProps[] = SECRET_SQUARE_CATEGORY.map((category) => ({ text: `#${category}`, func: () => setCategory(category), })); @@ -29,7 +31,7 @@ function SecretSquareCategories({ return ( { - return { - text: `${textObj[category]}`, - func: () => { - newSearchParams.set("category", category); - router.replace(`/square?${newSearchParams}`); - setCategory(category); - }, - }; - }, - ); - - + const buttonOptionsArr: ButtonOptionsProps[] = ( + ["all", "gather", "group"] as (FeedType | "all")[] + ).map((category) => { + return { + text: `${textObj[category]}`, + func: () => { + newSearchParams.set("category", category); + router.replace(`/square?${newSearchParams}`); + setCategory(category); + }, + }; + }); return ( - - + + - {!isLoading ? ( + {!isLoading && ( <> {isCalendar ? ( - + ) : ( )} - ) : ( - )} diff --git a/pages/eventCalendar.tsx b/pages/eventCalendar.tsx deleted file mode 100644 index 156ae2c8e..000000000 --- a/pages/eventCalendar.tsx +++ /dev/null @@ -1,278 +0,0 @@ -import { Box, Flex } from "@chakra-ui/react"; -import dayjs from "dayjs"; -import { Fragment, useState } from "react"; -import styled from "styled-components"; - -import MonthNav from "../components/atoms/MonthNav"; -import { PointCircleTextProps } from "../components/atoms/PointCircleText"; -import Header from "../components/layouts/Header"; -import Slide from "../components/layouts/PageSlide"; -import Accordion from "../components/molecules/Accordion"; -import PointCircleTextRow from "../components/molecules/PointCircleTextRow"; -import { ACCORDION_CONTENT_EVENT } from "../constants/contentsText/accordionContents"; -import { EVENT_CONTENT_2024 } from "../constants/settingValue/eventContents"; -import { DAYS_OF_WEEK } from "../constants/util/util"; -const DAYS_TITLE = ["포인트 2배", null, null, null, null, null, "점수 2배"]; - -interface IEventContent { - content: string; - color: string; - isFirst: boolean; - isLast: boolean; - blockIdx?: number; -} - -function EventCalendar() { - const [navMonth, setNavMonth] = useState(dayjs().startOf("month")); - - const getFilledDates = (navMonth: dayjs.Dayjs) => { - const daysInMonth = navMonth.daysInMonth(); - const frontBlankDate = navMonth.day(); - const totalDate = daysInMonth + frontBlankDate; - const rowsInMonth = totalDate <= 35 ? 5 : 6; - return Array.from({ length: 7 * rowsInMonth }, (_, idx) => - idx < frontBlankDate || idx >= totalDate ? null : idx - frontBlankDate + 1, - ); - }; - - const filledDates = getFilledDates(navMonth); - - const eventBlocks: { [key: string]: string } = { - first: null, - second: null, - third: null, - }; - - let endBlocks = []; - - const filledContents = (date: number) => { - const eventArr = navMonth.year() === 2024 ? EVENT_CONTENT_2024[navMonth.month() + 1] : null; - - if (!eventArr) return; - return eventArr.reduce((acc: IEventContent[], event) => { - const isFirstDay = date === event.start; - const isEndDay = date === event.end; - if (event.start <= date && date <= event.end) { - acc.push({ - content: event.content, - color: event.color, - isFirst: isFirstDay, - isLast: isEndDay, - blockIdx: event?.blockIdx, - }); - if (isFirstDay) fillEventDate(event.content); - if (isEndDay) endBlocks.push(event.content); - } - return acc; - }, []); - }; - - const fillEventDate = (content: string) => { - const availableKey = Object.keys(eventBlocks).find((key) => !eventBlocks[key]); - if (availableKey) eventBlocks[availableKey] = content; - }; - - const deleteEventDate = (content: string) => { - for (const key in eventBlocks) { - if (eventBlocks[key] === content) eventBlocks[key] = null; - } - }; - - const textRowObj: PointCircleTextProps[] = [ - { - text: "공식 행사", - color: "mint", - }, - { - text: "이벤트", - color: "blue", - }, - { - text: "일정", - color: "orange", - }, - ]; - - return ( - <> -
- - - - - - - - {DAYS_TITLE.map((day, idx) => ( -
{day}
- ))} -
- - {DAYS_OF_WEEK.map((day) => ( -
{day}
- ))} -
- - {filledDates?.map((item, idx) => { - const day = idx % 7 === 0 ? "sun" : idx % 7 === 6 ? "sat" : null; - const isToday = navMonth.date(item).isSame(dayjs(), "day"); - - const contentArr = filledContents(item); - const dateInfo = Object.values(eventBlocks).map((title) => - contentArr?.find((c) => c.content === title), - ); - - endBlocks.forEach((item) => deleteEventDate(item)); - endBlocks = []; - - return ( - - - {!isToday ? item : {item}} - - - {dateInfo.map((item, idx2) => { - return ( - - {item?.blockIdx !== undefined && ( - -   - - )} - - {item?.isFirst ? item?.content : "\u00A0"} - - - ); - })} - - - ); - })} - -
- - 이벤트 상세정보 - - -
- - ); -} - -const Calendar = styled.div` - width: 364px; - margin: 0 auto; - display: flex; - flex-direction: column; -`; - -const WeekTitleHeader = styled.div` - display: flex; - justify-content: space-between; - font-size: 10px; - color: var(--color-mint); - - margin-bottom: var(--gap-1); - font-weight: 600; - > div { - flex: 1; - text-align: center; - } -`; - -const DayOfWeek = styled.div` - display: flex; - justify-content: space-between; - background-color: var(--gray-200); - padding: var(--gap-1) 0; - font-size: 12px; - > div { - flex: 1; - text-align: center; - } - > div:first-child { - color: var(--color-red); - } - > div:last-child { - color: #6bafff; - } -`; - -const CalendarDates = styled.div` - display: grid; - background-color: white; - grid-template-columns: repeat(7, 1fr); - border: var(--border); - border-radius: var(--rounded); - > div:first-child { - color: var(--color-red); - } -`; - -const DateBlock = styled.div<{ isToday: boolean }>` - width: 52px; - padding-top: var(--gap-1); - font-size: 12px; - font-weight: 600; - text-align: center; - flex: 1; - border-top: var(--border); - background-color: ${(props) => (props.isToday ? "var(--gray-200)" : null)}; -`; - -const Date = styled.div<{ day: "sun" | "sat"; isToday: boolean }>` - position: relative; - height: 18px; - margin-bottom: var(--gap-1); - color: ${(props) => - props.isToday - ? "white" - : props.day === "sun" - ? "var(--color-red)" - : props.day === "sat" - ? "var(--color-blue)" - : null}; -`; - -const DateContent = styled.div``; - -const EventBlock = styled.div<{ - color: string; - isFirst: boolean; - isLast: boolean; -}>` - font-size: 10px; - margin-bottom: 2px; - font-weight: 400; - white-space: nowrap; - color: white; - background-color: ${(props) => props.color}; - position: relative; - - z-index: ${(props) => (props.isFirst ? 4 : 0)}; - padding-left: ${(props) => (props.isFirst ? "var(--gap-1)" : 0)}; - padding-right: ${(props) => (props.isLast ? "var(--gap-1)" : 0)}; -`; - -const TodayCircle = styled.div` - position: absolute; - top: 50%; - left: 50%; - width: 18px; - height: 18px; - border-radius: 50%; - transform: translate(-50%, -50%); - background-color: var(--gray-800); - color: white; -`; - -export default EventCalendar; diff --git a/pages/home/index.tsx b/pages/home/index.tsx index 09c55ad0b..d55eaf779 100644 --- a/pages/home/index.tsx +++ b/pages/home/index.tsx @@ -2,7 +2,7 @@ import { Box } from "@chakra-ui/react"; import { useState } from "react"; import Slide from "../../components/layouts/PageSlide"; -import HomeClubSection from "../../pageTemplates/home/HomeClubSection"; +import HomeCalendarSection from "../../pageTemplates/home/HomeCalendarSection"; import HomeGatherSection from "../../pageTemplates/home/HomeGatherSection"; import HomeHeader from "../../pageTemplates/home/homeHeader/HomeHeader"; import HomeInitialSetting from "../../pageTemplates/home/HomeInitialSetting"; @@ -26,7 +26,7 @@ function Home() { ) : tab === "번개" ? ( ) : tab === "캘린더" ? ( - + ) : tab === "추천" ? ( ) : null} diff --git a/pages/review/index.tsx b/pages/review/index.tsx index 086fc1c85..21a77f2ae 100644 --- a/pages/review/index.tsx +++ b/pages/review/index.tsx @@ -10,7 +10,7 @@ import KakaoShareBtn from "../../components/atoms/Icons/KakaoShareBtn"; import { MainLoading } from "../../components/atoms/loaders/MainLoading"; import Header from "../../components/layouts/Header"; import Slide from "../../components/layouts/PageSlide"; -import ButtonGroups, { IButtonOptions } from "../../components/molecules/groups/ButtonGroups"; +import ButtonGroups, { ButtonOptionsProps } from "../../components/molecules/groups/ButtonGroups"; import { LOCATION_OPEN } from "../../constants/location"; import { WEB_URL } from "../../constants/system"; import { useErrorToast } from "../../hooks/custom/CustomToast"; @@ -109,7 +109,7 @@ function Review() { setVisibleCnt((old) => old + 8); }; - const buttonArr: IButtonOptions[] = ["전체", ...LOCATION_OPEN].map((location) => ({ + const buttonArr: ButtonOptionsProps[] = ["전체", ...LOCATION_OPEN].map((location) => ({ text: location, func: () => location === "전체" @@ -136,7 +136,7 @@ function Review() { <> diff --git a/pages/study/writing/place.tsx b/pages/study/writing/place.tsx index 94e1cdcee..593d2439d 100644 --- a/pages/study/writing/place.tsx +++ b/pages/study/writing/place.tsx @@ -7,10 +7,12 @@ import styled from "styled-components"; import BottomNav from "../../../components/layouts/BottomNav"; import Header from "../../../components/layouts/Header"; import Slide from "../../../components/layouts/PageSlide"; -import ButtonGroups, { IButtonOptions } from "../../../components/molecules/groups/ButtonGroups"; +import ButtonGroups, { + ButtonOptionsProps, +} from "../../../components/molecules/groups/ButtonGroups"; import ProgressStatus from "../../../components/molecules/ProgressStatus"; import SearchLocation from "../../../components/organisms/SearchLocation"; -import { LOCATION_CONVERT, LOCATION_OPEN } from "../../../constants/location"; +import { LOCATION_OPEN, LOCATION_TO_FULLNAME } from "../../../constants/location"; import { useFailToast } from "../../../hooks/custom/CustomToast"; import RegisterLayout from "../../../pageTemplates/register/RegisterLayout"; import RegisterOverview from "../../../pageTemplates/register/RegisterOverview"; @@ -60,8 +62,8 @@ function WritingStudyPlace() { router.push(`/study/writing/content`); }; - const buttonItems: IButtonOptions[] = LOCATION_OPEN.map((locationInfo) => ({ - text: LOCATION_CONVERT[locationInfo], + const buttonOptionsArr: ButtonOptionsProps[] = LOCATION_OPEN.map((locationInfo) => ({ + text: LOCATION_TO_FULLNAME[locationInfo], func: () => setLocation(locationInfo), })); @@ -77,8 +79,8 @@ function WritingStudyPlace() { From 2bc77cad42ed2c8a63c3da429af0f39b76f6a204 Mon Sep 17 00:00:00 2001 From: LSJ Date: Mon, 2 Sep 2024 12:52:00 +0900 Subject: [PATCH 04/11] . --- constants/contents/calendarSchedule.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/constants/contents/calendarSchedule.ts b/constants/contents/calendarSchedule.ts index 9ce228b28..5895d50bf 100644 --- a/constants/contents/calendarSchedule.ts +++ b/constants/contents/calendarSchedule.ts @@ -296,7 +296,7 @@ export const EVENT_CONTENT_2024: Record = { { content: "ABOUT 빙고판 이벤트", start: 17, - end: 28, + end: 18, type: "event", text: "", }, From ce4ddbe6059b859aa569eb46524b29c98cb421b6 Mon Sep 17 00:00:00 2001 From: LSJ Date: Mon, 2 Sep 2024 12:56:39 +0900 Subject: [PATCH 05/11] . --- .../{HomeRecommendationTab.ts => homeRecommendationTab2.ts} | 0 pageTemplates/home/HomeRankingSection.tsx | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename constants/contents/{HomeRecommendationTab.ts => homeRecommendationTab2.ts} (100%) diff --git a/constants/contents/HomeRecommendationTab.ts b/constants/contents/homeRecommendationTab2.ts similarity index 100% rename from constants/contents/HomeRecommendationTab.ts rename to constants/contents/homeRecommendationTab2.ts diff --git a/pageTemplates/home/HomeRankingSection.tsx b/pageTemplates/home/HomeRankingSection.tsx index 7f42d2d77..43ffac53e 100644 --- a/pageTemplates/home/HomeRankingSection.tsx +++ b/pageTemplates/home/HomeRankingSection.tsx @@ -1,5 +1,5 @@ import RecommendationBannerCard from "../../components/organisms/cards/RecommendationBannerCard"; -import { HOME_RECOMMENDATION_TAB_CONTENTS } from "../../constants/contents/homeRecommendationTab"; +import { HOME_RECOMMENDATION_TAB_CONTENTS } from "../../constants/contents/homeRecommendationTab2"; function HomeRankingSection() { return ( From ec648ddb8b204282b6ab4ca52273ddadaa936e4d Mon Sep 17 00:00:00 2001 From: LSJ Date: Tue, 3 Sep 2024 11:00:55 +0900 Subject: [PATCH 06/11] chore: docs --- constants/contentsText/Private.tsx | 4 +++- .../aboutHeader/promotionModal/PromotionModalOverview.tsx | 3 +-- pageTemplates/home/HomeCalendarSection.tsx | 1 + pageTemplates/promotion/PromotionContent.tsx | 8 ++++---- pageTemplates/promotion/PromotionTitle.tsx | 4 ++-- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/constants/contentsText/Private.tsx b/constants/contentsText/Private.tsx index d00f88a2a..5b32df201 100644 --- a/constants/contentsText/Private.tsx +++ b/constants/contentsText/Private.tsx @@ -20,4 +20,6 @@ const P = styled.p` export const OPEN_KAKAO_LINK = "https://open.kakao.com/o/sjDgVzmf"; -export const PROMOTION_TEXT = `✨대학생들의 소모임 플랫폼 ABOUT✨\n\n스터디, 소모임, 취미 모임, 정보 공유 등 다양한 활동을 즐기고 싶다면 ABOUT에서 함께해요! 저희는 대학생 동아리이자 소모임 플랫폼으로, 같은 지역의 친구들과 스터디를 하거나, 관심사나 취미를 교류하고 친목을 다질 수 있는 모임입니다. ABOUT과 함께 즐겁고 의미있는 대학생활을 만들어보세요!\n\n📚스터디\n✔ 매일 자율적으로 참여하는 카공 스터디\n✔ 각 잡고 진행하는 정기스터디\n✔ 그 외 온라인 스터인 (캠 스터디, 공부 인증 등)\n\n🙌🏻소모임\n✔ 영어 회화, 자격증 시험, 프로그래밍 등의 공부 소모임\n✔ 운동 인증, 투두메이트, 습관 만들기 등의 자기계발 소모임\n✔ 보드게임, 전시회, 방탈출, 게임, 출사 등의 취미 소모임\n\n🎉친목 활동\n✔ 누구나 자유롭게 올리고 참여하는 번개 모임\n✔ 파티룸, OT, MT, 정기모임 등의 동아리 행사\n✔ 또래 친구들과 조별로 진행하는 조모임\n\n🙆가입 조건\n만 19~26세의 대학생(졸업생)\n\n공부할 땐 열심히 공부하고, 놀 땐 더 열심히 놀 사람\n근처에 사는 친구들과 스터디나 관심사를 공유하고 싶은 사람\n친목뿐만 아니라 더 의미있는 대학 생활을 보내고 싶은 사람\n\n모두 환영합니다🤗\n\n✅회비\n가입비: 2000원 \n보증금: 3000원 (탈퇴시 환급)\n\n🚨이성/종교 목적 등 불온한 목적의 가입을 엄격히 금지합니다. 또한 타인에게 불편함을 주는 인원들은 파악 즉시 추방됩니다.\n\n🐶 가입 신청 or 동아리 구경 🐶\nhttp://study-about.club\n\n🐶 문의사항 🐶\nhttps://open.kakao.com/o/sjDgVzmf`; +export const PROMOTION_TITLE = `✨동아리 하나로 스터디부터 취미, 소모임, 번개까지⁉️ 수도권 대학생 연합 동아리 ABOUT에서 하고 싶은 거 다 하자‼️`; + +export const PROMOTION_TEXT = `공부, 취미, 친구 모두 다 챙기면서 의미있는 대학생활을 보내고 싶다면, 저희 동아리에서 함께해요!\n\n🔥 동아리 소개 🔥\nABOUT은 대학생을 위한 스터디 동아리입니다! 현재 총 400명 이상의 회원이 지역별로 활동하고 있기 때문에 근처에 사는 또래 친구들과 스터디와 다양한 활동이 가능합니다. 2022년 개설 이후로 2000명 이상의 회원이 참여했고, 1000회 이상의 카공 스터디가 열렸으며, 200회 이상의 번개 모임과 40여개의 취미/관심사 소모임이 지금까지 활발히 운영되고 있습니다!\n\n💘공부는 해야 하는데 집에서 뒹굴거리고 있는 당신! 스터디를 할까 해도 날짜, 장소, 시간을 계획하기 어려워 포기하진 않았나요?\n\n💘익명의 누군가와 스터디를 하는 게 부담감이 느껴지진 않았나요?\n\n💘운영 관리가 되지 않아 당일 파토가 나고, 유령 모임이 되어버리진 않았나요?\n\n💘친구도 사귀고 다양한 활동도 하고 싶은데, 무작정 술 먹고 노는 것보단 공부도 하고 의미있는 대학생활을 보내고 싶진 않나요?\n\n가입만 하세요! 공부부터 취미, 친구 사귀기까지 이 모든 걸 책임져 드리겠습니다😎\n\n📚 스터디 활동\n1. 카공 스터디\n동네 친구들과 함께 공부할 수 있는 카공 스터디입니다. 언제든 원하는 날짜와 장소로 참여할 수 있어요!\n\n2. 정기 스터디\n시험기간에는 각 잡고 하루 종일 공부하는 스터디가 열립니다. 열심히 공부하는 친구들과 함께라면 밤샘도 두렵지 않아...💫\n\n3. 온라인 스터디(캠 스터디, 공부 인증)\n오프라인 스터디가 어려운 날에는 온라인 스터디에서 같이 공부해요!\n\n🙌🏻 다양한 소모임\n동아리 내에서 같은 관심사나 목적을 가진 친구들끼리 그룹을 만들어 원하는 공부나 취미 활동을 함께 진행할 수 있습니다.\n\n1. 공부 소모임:\n영어 회화, 자격증 준비, 프로그래밍 같은 학습 중심 소모임\n\n2. 자기계발 소모임:\n운동 인증, 습관 만들기 등 자기 성장에 집중할 수 있는 소모임\n\n3. 취미 소모임\n보드게임, 전시회 관람, 방탈출 등 취미를 공유할 수 있는 소모임\n\n😆 즐거운 친목 활동\n1. 자유롭게 열리는 번개 모임\n내 마음대로 여는 번개 모임! 시간과 조건을 설정해 원하는 친구들과 만날 수 있습니다. 부담 없이 참여해보세요.\n\n2. 파티룸, OT, MT 등 다양한 행사\n운영진이 다 준비할게요! 그냥 와서 놀기만 하세요. 나이, 성별, 지역 등을 고려한 사전 조편성으로 어색하지 않게 즐길 수 있어요!\n\n3. 또래 친구들과 함께하는 조모임\n같은 지역 또래 친구들과 조를 매칭해 만나는 모임입니다. 처음이라고 걱정하지 마세요! 새로운 친구들과 금방 친해질 수 있어요.\n\n📝 가입 조건\n만 19~26세의 대학생(졸업생 포함)\n✔ 근처에 사는 친구들과 스터디나 관심사를 공유하고 싶은 사람\n✔ 친목뿐만 아니라 더 의미 있는 대학생활을 원하는 사람\n✔ 하고 싶은 건 많은데 동아리 여러 개 들어가고 싶진 않은 사람\n✔ 파토 안 나고 잘 만나는 동아리에서 활동하고 싶은 사람\n\n모두 환영합니다🤗\n\n🚨 주의 사항\n이성/종교 목적 등 불온한 가입은 엄격히 금지되며, 타인에게 불편을 주는 인원은 즉시 추방됩니다.\n\n🎯 지금 바로 가입하고 스터디 시작하기!\n\n👇 가입 신청 및 동아리 구경 👇\nhttp://study-about.club\n\n 🐾 궁금한 점이 있다면? 바로 문의해주세요~\nhttps://open.kakao.com/o/sjDgVzmf`; diff --git a/modals/aboutHeader/promotionModal/PromotionModalOverview.tsx b/modals/aboutHeader/promotionModal/PromotionModalOverview.tsx index db647f6b1..4ecb93433 100644 --- a/modals/aboutHeader/promotionModal/PromotionModalOverview.tsx +++ b/modals/aboutHeader/promotionModal/PromotionModalOverview.tsx @@ -10,8 +10,7 @@ function PromotionModalOverview() { - 에브리타임에 홍보글을 작성해주시면 200 Point와 매주 추첨을 통해 치킨 기프티콘 - 을 드려요! + (한정)에브리타임에 홍보글을 작성해주시면 매주 두분께 올리브영 기프티콘을 드려요! ); diff --git a/pageTemplates/home/HomeCalendarSection.tsx b/pageTemplates/home/HomeCalendarSection.tsx index d12547e84..62fce4a87 100644 --- a/pageTemplates/home/HomeCalendarSection.tsx +++ b/pageTemplates/home/HomeCalendarSection.tsx @@ -36,6 +36,7 @@ function HomeCalendarSection() { <> + diff --git a/pageTemplates/promotion/PromotionContent.tsx b/pageTemplates/promotion/PromotionContent.tsx index 3e1ec09ee..1ce976996 100644 --- a/pageTemplates/promotion/PromotionContent.tsx +++ b/pageTemplates/promotion/PromotionContent.tsx @@ -4,7 +4,7 @@ import { useState } from "react"; import styled from "styled-components"; import { CopyBtn } from "../../components/atoms/Icons/CopyIcon"; -import { PROMOTION_TEXT } from "../../constants/contentsText/Private"; +import { PROMOTION_TEXT, PROMOTION_TITLE } from "../../constants/contentsText/Private"; function PromotionContent() { const [isText, setIsText] = useState(true); @@ -34,18 +34,18 @@ function PromotionContent() { 이미지 - {isText && } + {isText && } {isText ? ( <> - ✨대학생들의 소모임 플랫폼 ABOUT✨ + {PROMOTION_TITLE}
{PROMOTION_TEXT}
) : ( promotionImage
- 에브리타임에 홍보글을 작성해주시면 2000원(200 pt)와 추첨을 통해 !!매 주!!{" "} - BBQ 황금 올리브 치킨 세트를 드립니다! + (한정 이벤트) 에브리타임 동아리 게시판에 홍보 글을 올려주시면 매주 두분께{" "} + 올리브영 10,000원 기프티콘을 드려요!
[학교 당 3일에 1번만 참여 가능]
From 049370e0106d24f56f42a2450e877cc5a87af587 Mon Sep 17 00:00:00 2001 From: LSJ Date: Tue, 3 Sep 2024 11:12:29 +0900 Subject: [PATCH 07/11] remove temp like popup --- .../setting/userSetting/userSettingPopUp.tsx | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/pageTemplates/setting/userSetting/userSettingPopUp.tsx b/pageTemplates/setting/userSetting/userSettingPopUp.tsx index 8e1949309..613618025 100644 --- a/pageTemplates/setting/userSetting/userSettingPopUp.tsx +++ b/pageTemplates/setting/userSetting/userSettingPopUp.tsx @@ -5,7 +5,6 @@ import { useEffect, useState } from "react"; import { ALPHABET_POP_UP, ATTEND_POP_UP, - ENTHUSIASTIC_POP_UP, FAQ_POP_UP, GATHER_JOIN_MEMBERS, INSTAGRAM_POP_UP, @@ -24,7 +23,6 @@ import InstaPopUp from "../../../modals/pop-up/InstaPopUp"; import LastWeekAttendPopUp from "../../../modals/pop-up/LastWeekAttendPopUp"; import ManagerPopUp from "../../../modals/pop-up/ManagerPopUp"; import SuggestPopUp from "../../../modals/pop-up/SuggestPopUp"; -import RecentJoinUserPopUp from "../../../modals/RecentJoinUserPopUp"; import { IUser, IUserSummary } from "../../../types/models/userTypes/userInfoTypes"; import { checkAndSetLocalStorage } from "../../../utils/storageUtils"; @@ -60,7 +58,7 @@ export default function UserSettingPopUp({ cnt, userInfo }: UserSettingPopUpProp const { data: session } = useSession(); const [modalTypes, setModalTypes] = useState([]); - const [recentMembers, setRecentMembers] = useState(); + // const [recentMembers, setRecentMembers] = useState(); const { data: gatherData } = useGatherQuery(); @@ -109,9 +107,9 @@ export default function UserSettingPopUp({ cnt, userInfo }: UserSettingPopUpProp localStorage.setItem(GATHER_JOIN_MEMBERS, JSON.stringify(temp)); localStorage.setItem(STUDY_ATTEND_MEMBERS, JSON.stringify(filtered)); - const gatherMembers = filteredGather.flatMap((obj) => obj.participants.map((who) => who.user)); + // const gatherMembers = filteredGather.flatMap((obj) => obj.participants.map((who) => who.user)); - setRecentMembers([...gatherMembers, ...(firstData ? firstData.members : [])]); + // setRecentMembers([...gatherMembers, ...(firstData ? firstData.members : [])]); }, [gatherData]); useEffect(() => { @@ -124,10 +122,10 @@ export default function UserSettingPopUp({ cnt, userInfo }: UserSettingPopUpProp setModalTypes((old) => [...old, "lastWeekAttend"]); if (++popUpCnt === 2) return; } - if (!checkAndSetLocalStorage(ENTHUSIASTIC_POP_UP, 27)) { - setModalTypes((old) => [...old, "enthusiastic"]); - if (++popUpCnt === 2) return; - } + // if (!checkAndSetLocalStorage(ENTHUSIASTIC_POP_UP, 27)) { + // setModalTypes((old) => [...old, "enthusiastic"]); + // if (++popUpCnt === 2) return; + // } if (!checkAndSetLocalStorage(FAQ_POP_UP, 21)) { setModalTypes((old) => [...old, "faq"]); if (++popUpCnt === 2) return; @@ -158,12 +156,12 @@ export default function UserSettingPopUp({ cnt, userInfo }: UserSettingPopUpProp return ( <> - {recentMembers?.length ? ( + {/* {recentMembers?.length ? ( who.uid !== session?.user.uid)} setIsModal={() => setRecentMembers(null)} /> - ) : null} + ) : null} */} {Object.entries(MODAL_COMPONENTS).map(([key, Component]) => { const type = key as UserPopUp; From d855a3a8a7eb854b58d6abef4387164c0123343c Mon Sep 17 00:00:00 2001 From: LSJ Date: Tue, 3 Sep 2024 11:13:58 +0900 Subject: [PATCH 08/11] . --- constants/contents/calendarSchedule.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/constants/contents/calendarSchedule.ts b/constants/contents/calendarSchedule.ts index 5895d50bf..0ec4e6421 100644 --- a/constants/contents/calendarSchedule.ts +++ b/constants/contents/calendarSchedule.ts @@ -293,6 +293,13 @@ export const EVENT_CONTENT_2024: Record = { type: "schedule", text: "", }, + { + content: "지역 정기 스터디 주간", + start: 26, + end: 29, + type: "schedule", + text: "", + }, { content: "ABOUT 빙고판 이벤트", start: 17, From 0b68cb5f9d85ea88969f7f41930254e98d4de65d Mon Sep 17 00:00:00 2001 From: "SeungJu, Lee" <84257439+SeungJL@users.noreply.github.com> Date: Tue, 3 Sep 2024 12:47:08 +0900 Subject: [PATCH 09/11] perf: study-calendar (#219) --- components/molecules/groups/ButtonGroups.tsx | 1 - components/organisms/Calendar.tsx | 13 +++++++++---- constants/contents/calendarSchedule.ts | 12 ++++++++++-- modals/pop-up/LastWeekAttendPopUp.tsx | 2 +- pageTemplates/home/HomeCalendarSection.tsx | 1 - pageTemplates/home/study/HomeStudyChart.tsx | 9 +-------- pageTemplates/record/RecordCalendar.tsx | 12 ++++++------ pageTemplates/record/RecordLocationCategory.tsx | 6 ++++-- pages/calendar/index.tsx | 2 +- pages/gather/writing/condition.tsx | 2 +- pages/profile/[uid].tsx | 2 +- pages/square/secret/[id].tsx | 2 +- pages/vote.tsx | 2 +- 13 files changed, 36 insertions(+), 30 deletions(-) diff --git a/components/molecules/groups/ButtonGroups.tsx b/components/molecules/groups/ButtonGroups.tsx index b2fc08987..e87e014df 100644 --- a/components/molecules/groups/ButtonGroups.tsx +++ b/components/molecules/groups/ButtonGroups.tsx @@ -24,7 +24,6 @@ export default function ButtonGroups({ isEllipse = false, type = "block", }: IButtonGroups) { - console.log(buttonOptionsArr, currentValue); return ( {buttonOptionsArr.map((buttonOptions, idx) => ( diff --git a/components/organisms/Calendar.tsx b/components/organisms/Calendar.tsx index 38d8353b0..318c84787 100644 --- a/components/organisms/Calendar.tsx +++ b/components/organisms/Calendar.tsx @@ -63,9 +63,10 @@ function Calendar({ monthFirstDate, calendarContents }: CalendarProps) { const isFirstDay = date === schedule.start; const isEndDay = date === schedule.end; if (schedule.start <= date && date <= schedule.end) { + acc.push({ content: schedule.content, - color: SCHEDULE_TYPE_TO_COLOR[schedule.type], + color: schedule?.color || SCHEDULE_TYPE_TO_COLOR[schedule.type], isFirst: isFirstDay, isLast: isEndDay, blockIdx: schedule?.blockIdx, @@ -118,9 +119,11 @@ function Calendar({ monthFirstDate, calendarContents }: CalendarProps) { const day = idx % 7 === 0 ? "sun" : idx % 7 === 6 ? "sat" : null; const isToday = monthFirstDate.date(item).isSame(dayjs(), "day"); const contentArr = getDaySchedules(item); - const dateInfo = Object.values(daySchedules).map((title) => - contentArr?.find((c) => c.content === title), - ); + + const dateInfo = Object.values(daySchedules).map((title, index) => { + const matchedContents = contentArr.filter((c) => c.content === title); + return matchedContents[index]; // 순서를 고려하여 index에 해당하는 요소를 선택 + }); endingSchedules.forEach((item) => deleteSchedule(item)); endingSchedules = []; @@ -160,6 +163,7 @@ function Calendar({ monthFirstDate, calendarContents }: CalendarProps) { <> {dateInfo.map((item, idx2) => { + return ( (props.isFirst ? 4 : 0)}; padding-left: ${(props) => (props.isFirst ? "var(--gap-1)" : 0)}; padding-right: ${(props) => (props.isLast ? "var(--gap-1)" : 0)}; + text-align: ${(props) => props.isFirst && props.isLast && "center"}; `; export default Calendar; diff --git a/constants/contents/calendarSchedule.ts b/constants/contents/calendarSchedule.ts index 0ec4e6421..bd76ef0aa 100644 --- a/constants/contents/calendarSchedule.ts +++ b/constants/contents/calendarSchedule.ts @@ -2,9 +2,10 @@ export interface CalendarContentProps { content: string; start: number; end: number; - type: "event" | "schedule" | "main"; + type?: "event" | "schedule" | "main"; text?: string; blockIdx?: number; + color?: string; } export const EVENT_CONTENT_2023: Record = { @@ -294,12 +295,19 @@ export const EVENT_CONTENT_2024: Record = { text: "", }, { - content: "지역 정기 스터디 주간", + content: "조모임 진행 주간", start: 26, end: 29, type: "schedule", text: "", }, + { + content: "시험대비 스터디 집중 ~ ", + start: 29, + end: 30, + type: "main", + text: "", + }, { content: "ABOUT 빙고판 이벤트", start: 17, diff --git a/modals/pop-up/LastWeekAttendPopUp.tsx b/modals/pop-up/LastWeekAttendPopUp.tsx index 48ac55f38..bbda03a8b 100644 --- a/modals/pop-up/LastWeekAttendPopUp.tsx +++ b/modals/pop-up/LastWeekAttendPopUp.tsx @@ -41,7 +41,7 @@ function LastWeekAttendPopUp({ setIsModal }: IModal) { ); const totalScore = scoreObj?.study + scoreObj?.gather; - console.log(2, filteredData, scoreObj); + const footerOptions: IFooterOptions = { main: {}, sub: { diff --git a/pageTemplates/home/HomeCalendarSection.tsx b/pageTemplates/home/HomeCalendarSection.tsx index 62fce4a87..d12547e84 100644 --- a/pageTemplates/home/HomeCalendarSection.tsx +++ b/pageTemplates/home/HomeCalendarSection.tsx @@ -36,7 +36,6 @@ function HomeCalendarSection() { <> - diff --git a/pageTemplates/home/study/HomeStudyChart.tsx b/pageTemplates/home/study/HomeStudyChart.tsx index f5768632d..c841a4f9e 100644 --- a/pageTemplates/home/study/HomeStudyChart.tsx +++ b/pageTemplates/home/study/HomeStudyChart.tsx @@ -5,7 +5,6 @@ import dynamic from "next/dynamic"; import HighlightedTextButton from "../../../components/atoms/buttons/HighlightedTextButton"; import SectionBar from "../../../components/molecules/bars/SectionBar"; import { ChartStudyOptions } from "../../../components/organisms/chart/ChartOptions"; -import { useToast } from "../../../hooks/custom/CustomToast"; import { VoteCntProps } from "../../../types/models/studyTypes/studyRecords"; interface HomeStudyChartProps { @@ -13,8 +12,6 @@ interface HomeStudyChartProps { } function HomeStudyChart({ voteCntArr }: HomeStudyChartProps) { - // const router = useRouter(); - const toast = useToast(); const ApexCharts = dynamic(() => import("react-apexcharts"), { ssr: false }); const filtered: VoteCntProps[] = voteCntArr?.reduce((acc, cur) => { @@ -36,15 +33,11 @@ function HomeStudyChart({ voteCntArr }: HomeStudyChartProps) { xArr.push(dayjs(obj.date).date() + ""); }); - const onClick = () => { - toast("warning", "24년 9월 5일 오픈"); - }; - return ( <> } + rightComponent={} /> { const arrivedInfo = data?.arrivedInfoList; const date = data?.date; @@ -36,18 +35,19 @@ function RecordCalendar({ filterData, monthFirstDate }: IRecordCalendar) { cnt: place.arrivedInfo.length, }); }); - console.log(24, arrivedInfo, openLocation, openStudyLocation); - let tempCnt = 0; + let tempCnt = 0; + const resData = Array.from(openStudyLocation) .map((location, idx) => { if (idx > 2 || location.cnt < 2) return null; tempCnt++; + return { - content: "오픈", + content: "스터디", start: date, end: date, - type: "main" as "main" | "event" | "schedule", + color: LOCATION_TO_COLOR[location.location], blockIdx: tempCnt - 1, }; }) @@ -69,7 +69,7 @@ function RecordCalendar({ filterData, monthFirstDate }: IRecordCalendar) { // }); // } }); - console.log(calendarContents); + return ( { const filteredArrived = item?.arrivedInfoList.filter( - (place) => PLACE_TO_LOCATION[place?.placeId] === category, + (place) => + place?.placeId !== ALL_스터디인증 && PLACE_TO_LOCATION[place?.placeId] === category, ); if (!filteredArrived) return; return { ...item, arrivedInfoList: filteredArrived }; @@ -50,7 +52,7 @@ function RecordLocationCategory({ initialData, setFilterData }: IRecordLocationC > diff --git a/pages/calendar/index.tsx b/pages/calendar/index.tsx index d096d12ce..07e237a5b 100644 --- a/pages/calendar/index.tsx +++ b/pages/calendar/index.tsx @@ -36,7 +36,7 @@ function Record() { setFilterData(arrivedCalendar); setIsLoading(false); }, [arrivedCalendar]); - + return ( <>
diff --git a/pages/gather/writing/condition.tsx b/pages/gather/writing/condition.tsx index c6a5865d1..beedcfd7c 100644 --- a/pages/gather/writing/condition.tsx +++ b/pages/gather/writing/condition.tsx @@ -82,7 +82,7 @@ function WritingCondition() { const toggleSwitch = (e: ChangeEvent, type: GatherConditionType) => { const isChecked = e.target.checked; - console.log(type); + if (type === "location" && isChecked) { setLocation(session?.user.location); } diff --git a/pages/profile/[uid].tsx b/pages/profile/[uid].tsx index a5b30dba9..4a1f8a4f8 100644 --- a/pages/profile/[uid].tsx +++ b/pages/profile/[uid].tsx @@ -39,7 +39,7 @@ function ProfilePage() { enabled: !!uid, }); - console.log(uid, user); + useEffect(() => { if (user) setTransferUserName(user.name); diff --git a/pages/square/secret/[id].tsx b/pages/square/secret/[id].tsx index 8af366769..6293c806e 100644 --- a/pages/square/secret/[id].tsx +++ b/pages/square/secret/[id].tsx @@ -132,7 +132,7 @@ function SecretSquareDetailPage() { }, ); }; - console.log(squareDetail); + return ( <>
diff --git a/pages/vote.tsx b/pages/vote.tsx index bcc2d733b..5796f9ae4 100644 --- a/pages/vote.tsx +++ b/pages/vote.tsx @@ -43,7 +43,7 @@ export default function StudyVoteMap() { enabled: !!location && !!date, }); - console.log(2, studyVoteData); + //메인 스터디 장소가 선택되면 3km 거리 이하의 장소들이 2지망으로 자동 선택 useEffect(() => { From 3f2d5f849e63eb727c0d1e611cdfd01f973d955b Mon Sep 17 00:00:00 2001 From: LSJ Date: Tue, 3 Sep 2024 13:51:01 +0900 Subject: [PATCH 10/11] docs --- pages/_document.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pages/_document.tsx b/pages/_document.tsx index 077bc1ff7..238386178 100644 --- a/pages/_document.tsx +++ b/pages/_document.tsx @@ -52,9 +52,9 @@ export default class MyDocument extends Document { /> - + - + From df0152c6b9f98e289a3d7b6b82b0f4b1a6882c95 Mon Sep 17 00:00:00 2001 From: LSJ Date: Tue, 3 Sep 2024 20:26:42 +0900 Subject: [PATCH 11/11] chore --- components/atoms/buttons/RowTextBlockButton.tsx | 1 + constants/settingValue/dateSettingValue.ts | 2 +- modals/promotion/PromotionAllCoolTimeModal.tsx | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/components/atoms/buttons/RowTextBlockButton.tsx b/components/atoms/buttons/RowTextBlockButton.tsx index ddc872e45..9b251b5d4 100644 --- a/components/atoms/buttons/RowTextBlockButton.tsx +++ b/components/atoms/buttons/RowTextBlockButton.tsx @@ -10,6 +10,7 @@ function RowTextBlockButton({ text, onClick }: RowTextBlockButtonProps) { } const Button = styled.button` + width: 100%; padding: 16px; text-align: start; border-bottom: var(--border); diff --git a/constants/settingValue/dateSettingValue.ts b/constants/settingValue/dateSettingValue.ts index 9cd05cab3..dbc699b34 100644 --- a/constants/settingValue/dateSettingValue.ts +++ b/constants/settingValue/dateSettingValue.ts @@ -1 +1 @@ -export const PROMOTION_WIN_DATE = "2024-08-13"; +export const PROMOTION_WIN_DATE = "2024-09-03"; diff --git a/modals/promotion/PromotionAllCoolTimeModal.tsx b/modals/promotion/PromotionAllCoolTimeModal.tsx index a48d2b470..f1b1d70dd 100644 --- a/modals/promotion/PromotionAllCoolTimeModal.tsx +++ b/modals/promotion/PromotionAllCoolTimeModal.tsx @@ -21,6 +21,7 @@ function PromotionAllCoolTimeModal({ promotionData, setIsModal }: IPromotionAllC item.uid !== "2636066822" && item.uid !== "3224546232", ).length; + const footerOptions: IFooterOptions = { children: (