diff --git a/src/layout/Header/Dropdown.module.scss b/src/layout/Header/Dropdown.module.scss index c5f9255..3f81a3d 100644 --- a/src/layout/Header/Dropdown.module.scss +++ b/src/layout/Header/Dropdown.module.scss @@ -1,16 +1,21 @@ .container { position: absolute; - top: 100px; + display: flex; + top: 80px; right: 0; width: 100%; background-color: #f5f5f5; box-shadow: 0 5px 7px rgb(0 0 0 / 10%); z-index: 1000; - display: flex; flex-direction: column; } -.setting-item__link, +.setting-item__link { + padding: 10px; + text-align: left; + width: calc(100% - 20px); +} + .setting-item__button { padding: 10px; text-align: left; diff --git a/src/layout/Header/Header.module.scss b/src/layout/Header/Header.module.scss index 0e08415..4259fb8 100644 --- a/src/layout/Header/Header.module.scss +++ b/src/layout/Header/Header.module.scss @@ -35,6 +35,10 @@ margin-right: 24px; } +.menu-icon { + background: none; +} + .search, .menu { cursor: pointer; diff --git a/src/layout/Header/index.tsx b/src/layout/Header/index.tsx index a3668b5..1794fa8 100644 --- a/src/layout/Header/index.tsx +++ b/src/layout/Header/index.tsx @@ -3,7 +3,7 @@ import { useState } from 'react'; import { Link } from 'react-router-dom'; import Menu from 'assets/svg/auth/menu.svg?react'; -import SearchIcon from 'assets/svg/auth/search-icon.svg?react'; +// import SearchIcon from 'assets/svg/auth/search-icon.svg?react'; import Logo from 'assets/svg/common/koin-logo.svg?react'; import useMediaQuery from 'hooks/useMediaQuery'; import Setting1 from 'pages/Coop/components/Setting'; @@ -23,16 +23,17 @@ function Header() {
diff --git a/src/pages/Coop/components/Calendar/Calendar.module.scss b/src/pages/Coop/components/Calendar/Calendar.module.scss index e21851d..d9e31b4 100644 --- a/src/pages/Coop/components/Calendar/Calendar.module.scss +++ b/src/pages/Coop/components/Calendar/Calendar.module.scss @@ -134,13 +134,18 @@ } .title-wrapper-mobile { - width: calc(100% - 48px); + width: 100%; margin: 8px 24px; + + @include media.media-breakpoint-down(mobile) { + margin: 0; + } } .move-wrapper-mobile { display: flex; justify-content: space-between; + width: calc(100% - 48px); } .button-container-mobile { diff --git a/src/pages/Coop/components/Calendar/hooks/useCalendar.ts b/src/pages/Coop/components/Calendar/hooks/useCalendar.ts index d0ffa86..96032d1 100644 --- a/src/pages/Coop/components/Calendar/hooks/useCalendar.ts +++ b/src/pages/Coop/components/Calendar/hooks/useCalendar.ts @@ -59,7 +59,13 @@ function useCalendar() { return setMonth((p) => p + 1); }; + const goToday = () => { + setYear(today.getFullYear()); + setMonth(today.getMonth() + 1); + }; + return { + goToday, today, year, month, diff --git a/src/pages/Coop/components/Calendar/index.tsx b/src/pages/Coop/components/Calendar/index.tsx index 2678b0b..b800bc1 100644 --- a/src/pages/Coop/components/Calendar/index.tsx +++ b/src/pages/Coop/components/Calendar/index.tsx @@ -23,27 +23,16 @@ interface CalendarProps { } export default function Calendar({ selectedDate, setSelectedDate }: CalendarProps) { - const { dateList, isToday } = useCalendar(); + const { + dateList, + isToday, + prevMonth: prevCalendarMonth, + nextMonth: nextCalendarMonth, + goToday, + } = useCalendar(); const [dateListFormState, setdateListFormState] = useState<'week' | 'month'>('week'); const { isMobile } = useMediaQuery(); - const handlePrevNext = (direction: 'prev' | 'next') => { - let newDate; - if (dateListFormState === 'week') { - newDate = new Date(selectedDate); - newDate.setDate(newDate.getDate() + (direction === 'prev' ? -WEEK : WEEK)); // 주 단위 이동 - } else { - newDate = new Date(selectedDate); - newDate.setMonth(newDate.getMonth() + (direction === 'prev' ? -1 : 1)); // 월 단위 이동 - } - setSelectedDate(newDate); // 선택된 날짜 업데이트 - }; - - const handleTodayClick = () => { - const today = new Date(); - setSelectedDate(today); - }; - const getDateList = (form: 'week' | 'month') => { if (form === 'week') { const todayDateIndex = dateList.findIndex((date) => isSameDate(selectedDate, date)); @@ -59,6 +48,53 @@ export default function Calendar({ selectedDate, setSelectedDate }: CalendarProp return []; }; + const prevMonth = () => { + const prevMonthDate = new Date(selectedDate); + prevMonthDate.setMonth(selectedDate.getMonth() - 1); + prevCalendarMonth(); + setSelectedDate(prevMonthDate); + }; + + const nextMonth = () => { + const nextMonthDate = new Date(selectedDate); + nextMonthDate.setMonth(selectedDate.getMonth() + 1); + nextCalendarMonth(); + setSelectedDate(nextMonthDate); + }; + + const prevWeek = () => { + const prevWeekDate = new Date(selectedDate); + prevWeekDate.setDate(selectedDate.getDate() - WEEK); + + const todayDateIndex = dateList.findIndex((date) => isSameDate(selectedDate, date)); + const rowIndex = Math.floor(todayDateIndex / WEEK); + + if (rowIndex === 0) { + prevCalendarMonth(); + } + + setSelectedDate(prevWeekDate); + }; + + const nextWeek = () => { + const prevWeekDate = new Date(selectedDate); + prevWeekDate.setDate(selectedDate.getDate() + WEEK); + + const todayDateIndex = dateList.findIndex((date) => isSameDate(selectedDate, date)); + const rowIndex = Math.floor(todayDateIndex / WEEK); + + if (rowIndex === 5) { + nextCalendarMonth(); + } + setSelectedDate(prevWeekDate); + }; + + const handleTodayClick = () => { + const today = new Date(); + goToday(); + setSelectedDate(today); + }; + return (
{isMobile ? ( @@ -101,9 +137,9 @@ export default function Calendar({ selectedDate, setSelectedDate }: CalendarProp
handlePrevNext('prev')} - onNextClick={() => handlePrevNext('next')} - onTodayClick={() => handleTodayClick()} + onPrevClick={dateListFormState === 'week' ? prevWeek : prevMonth} + onNextClick={dateListFormState === 'week' ? nextWeek : nextMonth} + onTodayClick={handleTodayClick} />
@@ -144,9 +180,9 @@ export default function Calendar({ selectedDate, setSelectedDate }: CalendarProp
handlePrevNext('prev')} - onNextClick={() => handlePrevNext('next')} - onTodayClick={() => handleTodayClick()} + onPrevClick={dateListFormState === 'week' ? prevWeek : prevMonth} + onNextClick={dateListFormState === 'week' ? nextWeek : nextMonth} + onTodayClick={handleTodayClick} />
+ -
오늘 -
+ -
+
+
); diff --git a/src/pages/Coop/components/DiningBlocks/DiningBlocks.module.scss b/src/pages/Coop/components/DiningBlocks/DiningBlocks.module.scss index b862245..56ebe55 100644 --- a/src/pages/Coop/components/DiningBlocks/DiningBlocks.module.scss +++ b/src/pages/Coop/components/DiningBlocks/DiningBlocks.module.scss @@ -179,4 +179,5 @@ .diet-image { width: 100%; + -webkit-user-drag: none; } diff --git a/src/pages/Coop/components/DiningDownload/DiningDownload.module.scss b/src/pages/Coop/components/DiningDownload/DiningDownload.module.scss index 9c48c49..89a6b82 100644 --- a/src/pages/Coop/components/DiningDownload/DiningDownload.module.scss +++ b/src/pages/Coop/components/DiningDownload/DiningDownload.module.scss @@ -4,6 +4,7 @@ padding: 8px 12px; gap: 8px; border-radius: 8px; + align-items: center; &:hover { cursor: pointer; @@ -18,7 +19,6 @@ font-size: 14px; font-weight: 400; text-align: center; - padding: 2px 0 0 4px; } .exel-icon { diff --git a/src/pages/Coop/components/DiningDownload/index.tsx b/src/pages/Coop/components/DiningDownload/index.tsx index feb033a..942c433 100644 --- a/src/pages/Coop/components/DiningDownload/index.tsx +++ b/src/pages/Coop/components/DiningDownload/index.tsx @@ -18,7 +18,7 @@ export default function DiningDownload() { }; return ( -
+ <>
식단 파일 다운로드
- {isModalOpen && } - -
+ ); } diff --git a/src/pages/Coop/components/DiningTypeSelect/MobileDiningTypeSelect/MobileDiningTypeSelect.module.scss b/src/pages/Coop/components/DiningTypeSelect/MobileDiningTypeSelect/MobileDiningTypeSelect.module.scss new file mode 100644 index 0000000..ec80a79 --- /dev/null +++ b/src/pages/Coop/components/DiningTypeSelect/MobileDiningTypeSelect/MobileDiningTypeSelect.module.scss @@ -0,0 +1,73 @@ +.container { + display: flex; + align-items: center; + justify-content: space-between; + margin-left: 16px; +} + +.type-title { + color: #10477a; + font-size: 18px; + font-style: normal; + font-weight: 700; + line-height: 160%; /* 28.8px */ +} + +.dropdown { + position: relative; + + &__trigger { + display: flex; + align-items: center; + justify-content: center; + padding: 6px 16px; + border-radius: 8px; + background: none; + color: #000; + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: 160%; /* 25.6px */ + + &:active { + background: #eee; + } + } +} + +.arrow-icon { + transition: all 0.4s ease; + + &__transform { + transform: rotate(-180deg); + } +} + +.dropdown-list { + z-index: 5; + position: absolute; + bottom: -122px; + left: 0; + display: flex; + flex-direction: column; + width: 84px; + border-radius: 8px; + background: #fff; + box-shadow: 0 2px 20px 0 rgba(0 0 0 / 4%), 0 8px 32px 0 rgba(0 0 0 / 8%); +} + +.dropdown-item { + display: flex; + align-items: center; + color: #000; + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: 160%; /* 25.6px */ + padding: 6px 16px; + background: none; + + &--selected { + background: #f5f5f5; + } +} diff --git a/src/pages/Coop/components/DiningTypeSelect/MobileDiningTypeSelect/index.tsx b/src/pages/Coop/components/DiningTypeSelect/MobileDiningTypeSelect/index.tsx new file mode 100644 index 0000000..1c73249 --- /dev/null +++ b/src/pages/Coop/components/DiningTypeSelect/MobileDiningTypeSelect/index.tsx @@ -0,0 +1,59 @@ +import { useRef, useState } from 'react'; + +import ArrowDown from 'assets/svg/common/arrow-down.svg?react'; +import useOnClickOutside from 'hooks/useOnclickOutside'; +import { DiningType, DINING_TYPES, DINING_TYPE_MAP } from 'models/dinings'; +import cn from 'utils/className'; + +import styles from './MobileDiningTypeSelect.module.scss'; + +interface MobileDiningTypeSelectProps { + selectedDiningType: DiningType; + setSelectedDiningType: (diningType: DiningType) => void; +} + +export default function MobileDiningTypeSelect({ + selectedDiningType, setSelectedDiningType, +}: MobileDiningTypeSelectProps) { + const [typeOpen, setTypeOpen] = useState(false); + const ref = useRef(null); + + useOnClickOutside(ref, () => setTypeOpen(false)); + + return ( +
+
{`${DINING_TYPE_MAP[selectedDiningType]} 식단`}
+
+ + {typeOpen && ( +
+ {DINING_TYPES.map((type: DiningType) => ( + + ))} +
+ )} +
+
+ ); +} diff --git a/src/pages/Coop/components/DownloadModal/index.tsx b/src/pages/Coop/components/DownloadModal/index.tsx index e286d6f..ff162fc 100644 --- a/src/pages/Coop/components/DownloadModal/index.tsx +++ b/src/pages/Coop/components/DownloadModal/index.tsx @@ -124,6 +124,7 @@ export default function DownloadModal({ closeModal }: DownloadModalProps) { } const downloadUrl = URL.createObjectURL(response.data); + const link = document.createElement('a'); link.href = downloadUrl; link.download = filename; @@ -131,7 +132,7 @@ export default function DownloadModal({ closeModal }: DownloadModalProps) { link.click(); document.body.removeChild(link); URL.revokeObjectURL(downloadUrl); - } catch (error) { + } catch (error: any) { showToast('파일 다운로드에 실패했습니다. 다시 시도해 주세요.'); } }; @@ -211,19 +212,17 @@ export default function DownloadModal({ closeModal }: DownloadModalProps) { -
다운로드
{errorCode && } -
+ diff --git a/src/pages/Coop/components/Setting/Setting.module.scss b/src/pages/Coop/components/Setting/Setting.module.scss index 5ae1f76..f15308b 100644 --- a/src/pages/Coop/components/Setting/Setting.module.scss +++ b/src/pages/Coop/components/Setting/Setting.module.scss @@ -2,7 +2,7 @@ display: flex; align-items: center; gap: 40px; - padding-right: 24px; + margin-right: 24px; } .setting-item__link, diff --git a/src/pages/Coop/index.tsx b/src/pages/Coop/index.tsx index 28e87bc..db32bc4 100644 --- a/src/pages/Coop/index.tsx +++ b/src/pages/Coop/index.tsx @@ -8,6 +8,7 @@ import DiningDownload from 'pages/Coop/components/DiningDownload'; import DiningTypeSelect from 'pages/Coop/components/DiningTypeSelect'; import { getDiningTypeOnTime } from 'utils/operate'; +import MobileDiningTypeSelect from './components/DiningTypeSelect/MobileDiningTypeSelect'; import styles from './Coop.module.scss'; import type { DiningType } from 'models/dinings'; @@ -28,12 +29,19 @@ export default function Coop() { )} -
- -
+ ) : ( +
+ +
+ )} }>