diff --git a/frontend/src/apis/gets.ts b/frontend/src/apis/gets.ts index 8b146f408..d880f17ce 100644 --- a/frontend/src/apis/gets.ts +++ b/frontend/src/apis/gets.ts @@ -1,4 +1,3 @@ -// ./src/apis/gets.ts import { MoimInfo, Participation } from '@_types/index'; import ApiClient from './apiClient'; import { @@ -9,6 +8,7 @@ import { GetZzimMine, } from './responseTypes'; import { checkStatus } from './apiconfig'; +import { Filter } from '@_components/MyMoimListFilters/MyMoimListFilters'; export const getMoims = async (): Promise => { const response = await ApiClient.getWithAuth('moim'); @@ -18,6 +18,24 @@ export const getMoims = async (): Promise => { return json.data.moims; }; +export const getMyMoims = async ( + filter: Filter['api'], +): Promise => { + const response = await ApiClient.getWithAuth(`moim/mine?filter=${filter}`); + checkStatus(response); + + const json: GetMoims = await response.json(); + return json.data.moims; +}; + +export const getMyZzimMoims = async (): Promise => { + const response = await ApiClient.getWithAuth('moim/zzim'); + checkStatus(response); + + const json: GetMoims = await response.json(); + return json.data.moims; +}; + export const getMoim = async (moimId: number): Promise => { const response = await ApiClient.getWithAuth(`moim/${moimId}`); checkStatus(response); diff --git a/frontend/src/components/HomeMainContent/HomeMainContent.tsx b/frontend/src/components/HomeMainContent/HomeMainContent.tsx new file mode 100644 index 000000000..dc44f8ddd --- /dev/null +++ b/frontend/src/components/HomeMainContent/HomeMainContent.tsx @@ -0,0 +1,22 @@ +import MoimList from '@_components/MoimList/MoimList'; +import { MainPageTab } from '@_components/MoimTabBar/MoimTabBar'; +import MyMoimList from '@_components/MyMoim/MyMoim'; +import MyZzimMoimList from '@_components/MyZzimMoimList/MyZzimMoimList'; + +interface MoimMainContentProps { + currentTab: MainPageTab; +} + +export default function HomeMainContent(props: MoimMainContentProps) { + const { currentTab } = props; + + if (currentTab === '모임목록') { + return ; + } + if (currentTab === '나의모임') { + return ; + } + if (currentTab === '찜한모임') { + return ; + } +} diff --git a/frontend/src/components/Icons/ChattingIcon.tsx b/frontend/src/components/Icons/ChattingIcon.tsx new file mode 100644 index 000000000..caf838027 --- /dev/null +++ b/frontend/src/components/Icons/ChattingIcon.tsx @@ -0,0 +1,28 @@ +import { useTheme } from '@emotion/react'; + +interface ChattingIconProps { + isActive: boolean; +} + +export default function ChattingIcon(props: ChattingIconProps) { + const { isActive } = props; + + const theme = useTheme(); + + return ( + + + + ); +} diff --git a/frontend/src/components/Icons/HomeIcon.tsx b/frontend/src/components/Icons/HomeIcon.tsx new file mode 100644 index 000000000..9db8c1016 --- /dev/null +++ b/frontend/src/components/Icons/HomeIcon.tsx @@ -0,0 +1,28 @@ +import { useTheme } from '@emotion/react'; + +interface HomeIconProps { + isActive: boolean; +} + +export default function HomeIcon(props: HomeIconProps) { + const { isActive } = props; + + const theme = useTheme(); + + return ( + + + + ); +} diff --git a/frontend/src/components/Icons/MyPageIcon.tsx b/frontend/src/components/Icons/MyPageIcon.tsx new file mode 100644 index 000000000..89fc5a328 --- /dev/null +++ b/frontend/src/components/Icons/MyPageIcon.tsx @@ -0,0 +1,28 @@ +import { useTheme } from '@emotion/react'; + +interface MyPageIconProps { + isActive: boolean; +} + +export default function MyPageIcon(props: MyPageIconProps) { + const { isActive } = props; + + const theme = useTheme(); + + return ( + + + + ); +} diff --git a/frontend/src/components/Icons/PleaseIcon.tsx b/frontend/src/components/Icons/PleaseIcon.tsx new file mode 100644 index 000000000..897b2447e --- /dev/null +++ b/frontend/src/components/Icons/PleaseIcon.tsx @@ -0,0 +1,34 @@ +import { useTheme } from '@emotion/react'; + +interface PleaseIconProps { + isActive: boolean; +} + +export default function PleaseIcon(props: PleaseIconProps) { + const { isActive } = props; + + const theme = useTheme(); + + return ( + + + + + ); +} diff --git a/frontend/src/components/MoimCard/MoimCard.stories.tsx b/frontend/src/components/MoimCard/MoimCard.stories.tsx index 99dc1d6ca..4142f95d6 100644 --- a/frontend/src/components/MoimCard/MoimCard.stories.tsx +++ b/frontend/src/components/MoimCard/MoimCard.stories.tsx @@ -22,51 +22,30 @@ export const Default: Story = { isZzimed: true, moimId: 1, authorNickname: '김코딩', - status: 'MOIMING', - comments: [], participants: [ { - nickname: '치코', - profile: '', + nickname: '김코딩', + profile: 'https://avatars.githubusercontent.com/u/78939596?v=4', role: 'moimer', }, { - nickname: '치코', - profile: '', + nickname: '김디자인', + profile: 'https://avatars.githubusercontent.com/u/78939596?v=4', role: 'moimee', }, + ], + description: '코딩하면서 놀아요', + status: 'MOIMING', + comments: [ { - nickname: '치코', - profile: '', - role: 'moimer', - }, - { - nickname: '치코', - profile: '', - role: 'moimer', - }, - { - nickname: '치코', - profile: '', - role: 'moimer', - }, - { - nickname: '치코', - profile: '', - role: 'moimer', - }, - { - nickname: '치코', - profile: '', - role: 'moimer', - }, - { - nickname: '치코', - profile: '', - role: 'moimer', + commentId: 1, + nickname: '김코딩', + content: '안녕하세요', + dateTime: '2021-10-30 19:00', + profile: 'https://avatars.githubusercontent.com/u/78939596?v=4', + child: [], }, ], - description: '코딩하면서 놀아요', }, }, render: (args) => , diff --git a/frontend/src/components/MoimCard/MoimCard.style.ts b/frontend/src/components/MoimCard/MoimCard.style.ts index 80ce6e734..b66458b24 100644 --- a/frontend/src/components/MoimCard/MoimCard.style.ts +++ b/frontend/src/components/MoimCard/MoimCard.style.ts @@ -27,6 +27,12 @@ export const cardTitle = (props: { theme: Theme }) => { `; }; +export const heartButton = css` + padding: 0; + background: none; + border: 0; +`; + export const subjectBox = css` display: flex; gap: 0.8rem; diff --git a/frontend/src/components/MoimCard/MoimCard.tsx b/frontend/src/components/MoimCard/MoimCard.tsx index 11ead6865..7322e0f56 100644 --- a/frontend/src/components/MoimCard/MoimCard.tsx +++ b/frontend/src/components/MoimCard/MoimCard.tsx @@ -5,6 +5,7 @@ import { formatHhmmToKorean, formatYyyymmddToKorean } from '@_utils/formatters'; import { MoimInfo } from '@_types/index'; import { useTheme } from '@emotion/react'; import HeartIcon from '@_components/Icons/HeartIcon'; +import useChangeZzim from '@_hooks/mutaions/useChangeZzim'; interface MoimCardProps extends HTMLProps { moimInfo: MoimInfo; @@ -12,17 +13,36 @@ interface MoimCardProps extends HTMLProps { export default function MoimCard(props: MoimCardProps) { const { - moimInfo: { title, date, time, place, maxPeople, currentPeople, isZzimed }, + moimInfo: { + moimId, + title, + date, + time, + place, + maxPeople, + currentPeople, + isZzimed, + }, ...args } = props; const theme = useTheme(); + const { mutate: changeZzim } = useChangeZzim(); + + const handleHeartButtonClick = (e: React.MouseEvent) => { + e.stopPropagation(); + console.log(1); + changeZzim(moimId); + }; + return (

{title}

- +
diff --git a/frontend/src/components/MoimCardList/MoimCardList.stories.tsx b/frontend/src/components/MoimCardList/MoimCardList.stories.tsx index 717973c72..38880b352 100644 --- a/frontend/src/components/MoimCardList/MoimCardList.stories.tsx +++ b/frontend/src/components/MoimCardList/MoimCardList.stories.tsx @@ -35,47 +35,28 @@ export const Default: Story = { authorNickname: '김코딩', participants: [ { - nickname: '치코', - profile: '', + nickname: '김코딩', + profile: 'https://avatars.githubusercontent.com/u/78939596?v=4', role: 'moimer', }, { - nickname: '치코', - profile: '', + nickname: '김디자인', + profile: 'https://avatars.githubusercontent.com/u/78939596?v=4', role: 'moimee', }, + ], + description: '코딩하면서 놀아요', + status: 'MOIMING', + comments: [ { - nickname: '치코', - profile: '', - role: 'moimer', - }, - { - nickname: '치코', - profile: '', - role: 'moimer', - }, - { - nickname: '치코', - profile: '', - role: 'moimer', - }, - { - nickname: '치코', - profile: '', - role: 'moimer', - }, - { - nickname: '치코', - profile: '', - role: 'moimer', - }, - { - nickname: '치코', - profile: '', - role: 'moimer', + commentId: 1, + nickname: '김코딩', + content: '안녕하세요', + dateTime: '2021-10-30 19:00', + profile: 'https://avatars.githubusercontent.com/u/78939596?v=4', + child: [], }, ], - description: '코딩하면서 놀아요', }, { title: '볼 함 차보까?', @@ -84,54 +65,33 @@ export const Default: Story = { place: '서울 마포구 독막로 96 1층', maxPeople: 5, currentPeople: 3, - status: 'MOIMING', - comments: [], isZzimed: false, moimId: 1, authorNickname: '김코딩', participants: [ { - nickname: '치코', - profile: '', + nickname: '김코딩', + profile: 'https://avatars.githubusercontent.com/u/78939596?v=4', role: 'moimer', }, { - nickname: '치코', - profile: '', + nickname: '김디자인', + profile: 'https://avatars.githubusercontent.com/u/78939596?v=4', role: 'moimee', }, + ], + description: '코딩하면서 놀아요', + status: 'MOIMING', + comments: [ { - nickname: '치코', - profile: '', - role: 'moimer', - }, - { - nickname: '치코', - profile: '', - role: 'moimer', - }, - { - nickname: '치코', - profile: '', - role: 'moimer', - }, - { - nickname: '치코', - profile: '', - role: 'moimer', - }, - { - nickname: '치코', - profile: '', - role: 'moimer', - }, - { - nickname: '치코', - profile: '', - role: 'moimer', + commentId: 1, + nickname: '김코딩', + content: '안녕하세요', + dateTime: '2021-10-30 19:00', + profile: 'https://avatars.githubusercontent.com/u/78939596?v=4', + child: [], }, ], - description: '코딩하면서 놀아요', }, { title: '볼 함 차보까?', @@ -140,54 +100,34 @@ export const Default: Story = { place: '서울 마포구 독막로 96 1층', maxPeople: 5, currentPeople: 3, - status: 'MOIMING', - comments: [], isZzimed: true, moimId: 1, authorNickname: '김코딩', participants: [ { - nickname: '치코', - profile: '', + nickname: '김코딩', + profile: 'https://avatars.githubusercontent.com/u/78939596?v=4', role: 'moimer', }, { - nickname: '치코', - profile: '', + nickname: '김디자인', + profile: 'https://avatars.githubusercontent.com/u/78939596?v=4', role: 'moimee', }, + + ], + description: '코딩하면서 놀아요', + status: 'MOIMING', + comments: [ { - nickname: '치코', - profile: '', - role: 'moimer', - }, - { - nickname: '치코', - profile: '', - role: 'moimer', - }, - { - nickname: '치코', - profile: '', - role: 'moimer', - }, - { - nickname: '치코', - profile: '', - role: 'moimer', - }, - { - nickname: '치코', - profile: '', - role: 'moimer', - }, - { - nickname: '치코', - profile: '', - role: 'moimer', + commentId: 1, + nickname: '김코딩', + content: '안녕하세요', + dateTime: '2021-10-30 19:00', + profile: 'https://avatars.githubusercontent.com/u/78939596?v=4', + child: [], }, ], - description: '코딩하면서 놀아요', }, ], }, diff --git a/frontend/src/components/MoimList/MoimList.tsx b/frontend/src/components/MoimList/MoimList.tsx new file mode 100644 index 000000000..6d2491efd --- /dev/null +++ b/frontend/src/components/MoimList/MoimList.tsx @@ -0,0 +1,12 @@ +import MoimCardList from '@_components/MoimCardList/MoimCardList'; +import useMoims from '@_hooks/queries/useMoims'; + +export default function MoimList() { + const { moims, isLoading } = useMoims(); + + if (isLoading) { + return
로딩중...
; + } + + return moims && ; +} diff --git a/frontend/src/components/MoimTabBar/MoimTabBar.stories.tsx b/frontend/src/components/MoimTabBar/MoimTabBar.stories.tsx index f3570dafa..686433ea8 100644 --- a/frontend/src/components/MoimTabBar/MoimTabBar.stories.tsx +++ b/frontend/src/components/MoimTabBar/MoimTabBar.stories.tsx @@ -12,8 +12,7 @@ type Story = StoryObj; export const Default: Story = { args: { - tabs: ['Tab1', 'Tab2', 'Tab3'], - currentTab: 'Tab1', + currentTab: '모임목록', onTabClick: (tab: string) => console.log(tab), }, render: (args) => , diff --git a/frontend/src/components/MoimTabBar/MoimTabBar.tsx b/frontend/src/components/MoimTabBar/MoimTabBar.tsx index 57165e5e6..95534661e 100644 --- a/frontend/src/components/MoimTabBar/MoimTabBar.tsx +++ b/frontend/src/components/MoimTabBar/MoimTabBar.tsx @@ -1,14 +1,17 @@ import { useTheme } from '@emotion/react'; import * as S from './MoimTabBar.style'; +export type MainPageTab = '모임목록' | '나의모임' | '찜한모임'; + +const tabs: MainPageTab[] = ['모임목록', '나의모임', '찜한모임']; + interface MoimTabBarProps { - tabs: string[]; - currentTab: string; - onTabClick: (tab: string) => void; + currentTab: MainPageTab; + onTabClick: (tab: MainPageTab) => void; } export default function MoimTabBar(props: MoimTabBarProps) { - const { tabs, currentTab, onTabClick } = props; + const { currentTab, onTabClick } = props; const theme = useTheme(); diff --git a/frontend/src/components/MyMoim/MyMoim.tsx b/frontend/src/components/MyMoim/MyMoim.tsx new file mode 100644 index 000000000..3739a5e8c --- /dev/null +++ b/frontend/src/components/MyMoim/MyMoim.tsx @@ -0,0 +1,30 @@ +import MoimCardList from '@_components/MoimCardList/MoimCardList'; +import MyMoimListFilters, { + Filter, +} from '@_components/MyMoimListFilters/MyMoimListFilters'; +import useMyMoims from '@_hooks/queries/useMyMoims'; +import { Fragment, useState } from 'react'; + +export default function MyMoimList() { + const [selectedFilter, setSelectedFilter] = useState('all'); + + const { myMoims, isLoading } = useMyMoims(selectedFilter); + + const handleFilterSelect = (filter: Filter['api']) => { + setSelectedFilter(filter); + }; + + if (isLoading) { + return
로딩중...
; + } + + return ( + + + {myMoims && } + + ); +} diff --git a/frontend/src/components/MyMoimListFilters/MyMoimListFilters.stories.tsx b/frontend/src/components/MyMoimListFilters/MyMoimListFilters.stories.tsx index a19c46d7e..975ffc3cc 100644 --- a/frontend/src/components/MyMoimListFilters/MyMoimListFilters.stories.tsx +++ b/frontend/src/components/MyMoimListFilters/MyMoimListFilters.stories.tsx @@ -11,5 +11,9 @@ export default meta; type Story = StoryObj; export const Default: Story = { + args: { + selectedFilter: 'all', + handleFilterSelect: () => {}, + }, render: (args) => , }; diff --git a/frontend/src/components/MyMoimListFilters/MyMoimListFilters.tsx b/frontend/src/components/MyMoimListFilters/MyMoimListFilters.tsx index 38a151ae6..7e0709231 100644 --- a/frontend/src/components/MyMoimListFilters/MyMoimListFilters.tsx +++ b/frontend/src/components/MyMoimListFilters/MyMoimListFilters.tsx @@ -1,20 +1,42 @@ import MyMoimListFilterTag from '@_components/MyMoimListFilterTag/MyMoimListFilterTag'; -import { useState } from 'react'; import * as S from './MyMoimListFilters.style'; -const filters = ['모든 모임', '다가오는 모임', '지난 모임']; +export type Filter = + | { + ui: '모든 모임'; + api: 'all'; + } + | { + ui: '다가오는 모임'; + api: 'upcoming'; + } + | { + ui: '지난 모임'; + api: 'past'; + }; -export default function MyMoimListFilters() { - const [selectedFilter, setSelectedFilter] = useState(filters[0]); +const filters: Filter[] = [ + { ui: '모든 모임', api: 'all' }, + { ui: '다가오는 모임', api: 'upcoming' }, + { ui: '지난 모임', api: 'past' }, +]; + +interface MyMoimListFiltersProps { + selectedFilter: Filter['api']; + handleFilterSelect: (filter: Filter['api']) => void; +} + +export default function MyMoimListFilters(props: MyMoimListFiltersProps) { + const { selectedFilter, handleFilterSelect } = props; return (
- {filters.map((filter) => ( + {filters.map(({ ui, api }) => ( setSelectedFilter(filter)} + key={ui} + label={ui} + isSelected={selectedFilter === api} + onClick={() => handleFilterSelect(api)} /> ))}
diff --git a/frontend/src/components/MyZzimMoimList/MyZzimMoimList.tsx b/frontend/src/components/MyZzimMoimList/MyZzimMoimList.tsx new file mode 100644 index 000000000..573d1ab1a --- /dev/null +++ b/frontend/src/components/MyZzimMoimList/MyZzimMoimList.tsx @@ -0,0 +1,12 @@ +import MoimCardList from '@_components/MoimCardList/MoimCardList'; +import useMyZzimMoims from '@_hooks/queries/useMyZzimMoim'; + +export default function MyZzimMoimList() { + const { myZzimMoims, isLoading } = useMyZzimMoims(); + + if (isLoading) { + return
로딩중...
; + } + + return myZzimMoims && ; +} diff --git a/frontend/src/components/NavigationBar/NavigationBar.stories.tsx b/frontend/src/components/NavigationBar/NavigationBar.stories.tsx new file mode 100644 index 000000000..447ae7e46 --- /dev/null +++ b/frontend/src/components/NavigationBar/NavigationBar.stories.tsx @@ -0,0 +1,15 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import NavigationBar from './NavigationBar'; + +const meta = { + component: NavigationBar, + title: 'Components/NavigationBar', +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = { + render: (args) => , +}; diff --git a/frontend/src/components/NavigationBar/NavigationBar.style.ts b/frontend/src/components/NavigationBar/NavigationBar.style.ts new file mode 100644 index 000000000..4e5f0cd27 --- /dev/null +++ b/frontend/src/components/NavigationBar/NavigationBar.style.ts @@ -0,0 +1,22 @@ +import { DISPLAY_MAX_WIDTH } from '@_constants/styles'; +import { css, Theme } from '@emotion/react'; + +export const navigationBarContainer = (props: { theme: Theme }) => { + const { theme } = props; + + return css` + display: flex; + justify-content: space-between; + + width: 100%; + max-width: ${DISPLAY_MAX_WIDTH}; + height: 100%; + + background-color: ${theme.colorPalette.white[100]}; + box-shadow: 0 -2px 10px rgb(0 0 0 / 10%); + `; +}; +export const navigationBarList = css` + display: flex; + width: 100%; +`; diff --git a/frontend/src/components/NavigationBar/NavigationBar.tsx b/frontend/src/components/NavigationBar/NavigationBar.tsx new file mode 100644 index 000000000..87788ff51 --- /dev/null +++ b/frontend/src/components/NavigationBar/NavigationBar.tsx @@ -0,0 +1,47 @@ +import * as S from './NavigationBar.style'; +import { useState } from 'react'; +import NavigationBarItem from '@_components/NavigationBarItem/NavigationBarItem'; +import { useTheme } from '@emotion/react'; +import { useLocation, useNavigate } from 'react-router-dom'; +import ROUTES from '@_constants/routes'; + +export type Tab = '홈' | '채팅' | '해주세요' | '마이페이지'; + +const tabRoutes: Record = { + 홈: ROUTES.main, + 채팅: ROUTES.chat, + 해주세요: ROUTES.please, + 마이페이지: ROUTES.myPage, +}; + +export default function NavigationBar() { + const theme = useTheme(); + const navigate = useNavigate(); + const location = useLocation(); + + const [currentTab, setCurrentTab] = useState( + Object.keys(tabRoutes).find( + (key) => tabRoutes[key as Tab] === location.pathname, + ) as Tab, + ); + + const handleTabClick = (tab: Tab) => { + setCurrentTab(tab); + navigate(tabRoutes[tab]); + }; + + return ( + + ); +} diff --git a/frontend/src/components/NavigationBarItem/NavigationBarItem.style.ts b/frontend/src/components/NavigationBarItem/NavigationBarItem.style.ts new file mode 100644 index 000000000..15d5ec79c --- /dev/null +++ b/frontend/src/components/NavigationBarItem/NavigationBarItem.style.ts @@ -0,0 +1,22 @@ +import { css, Theme } from '@emotion/react'; + +export const navigationBarItem = (props: { + theme: Theme; + isActive: boolean; +}) => { + const { theme, isActive } = props; + + return css` + ${theme.typography.c2} + display: flex; + flex: 1; + flex-direction: column; + gap: 4px; + align-items: center; + justify-content: center; + + color: ${isActive + ? theme.colorPalette.grey[500] + : theme.colorPalette.grey[300]}; + `; +}; diff --git a/frontend/src/components/NavigationBarItem/NavigationBarItem.tsx b/frontend/src/components/NavigationBarItem/NavigationBarItem.tsx new file mode 100644 index 000000000..b3236cae1 --- /dev/null +++ b/frontend/src/components/NavigationBarItem/NavigationBarItem.tsx @@ -0,0 +1,40 @@ +import ChattingIcon from '@_components/Icons/ChattingIcon'; +import HomeIcon from '@_components/Icons/HomeIcon'; +import MyPageIcon from '@_components/Icons/MyPageIcon'; +import PleaseIcon from '@_components/Icons/PleaseIcon'; +import { useTheme } from '@emotion/react'; +import * as S from './NavigationBarItem.style'; +import { Tab } from '@_components/NavigationBar/NavigationBar'; + +interface NavigationBarItemProps { + tab: Tab; + isActive: boolean; + onClick: (tab: Tab) => void; +} + +export default function NavigationBarItem(props: NavigationBarItemProps) { + const { tab, isActive, onClick } = props; + + const theme = useTheme(); + + const tabIcon = + tab === '홈' ? ( + + ) : tab === '채팅' ? ( + + ) : tab === '해주세요' ? ( + + ) : ( + + ); + + return ( +
  • onClick(tab)} + > + {tabIcon} + {tab} +
  • + ); +} diff --git a/frontend/src/constants/queryKeys.ts b/frontend/src/constants/queryKeys.ts index b26573309..76a7ace45 100644 --- a/frontend/src/constants/queryKeys.ts +++ b/frontend/src/constants/queryKeys.ts @@ -1,5 +1,7 @@ const QUERY_KEYS = { moims: 'moims', + myMoims: 'myMoims', + myZzimMoims: 'myZzimMoims', moim: 'moim', userKey: 'userKey', chamyoMine: 'chamyoMine', diff --git a/frontend/src/constants/routes.ts b/frontend/src/constants/routes.ts index 4e8f2196d..71907d368 100644 --- a/frontend/src/constants/routes.ts +++ b/frontend/src/constants/routes.ts @@ -1,3 +1,20 @@ +/** + * TODO: 라우터 경로 도메인별로 재정의 +const ROUTES = { + main: '/', + moim: '/moim', + moimCreation: '/moim-create', + moimDetail: '/moim/:moimId', + moimParticipationComplete: '/moim/:moimId/participation-complete', + moimModify: '/moim/:moimId/modify', + + chatting: '/chatting', + chattingRoom: '/chatting/:moimId', + + login: '/login', +}; + */ + const ROUTES = { main: '/', addMoim: '/add-moim', @@ -7,6 +24,8 @@ const ROUTES = { modify: '/modify/:moimId', chat: '/chat', chattingRoom: '/chatting-room/:moimId', + please: '/please', + myPage: '/my-page', }; export default ROUTES; diff --git a/frontend/src/constants/styles.ts b/frontend/src/constants/styles.ts index 2f31b4c0d..50c0a25f1 100644 --- a/frontend/src/constants/styles.ts +++ b/frontend/src/constants/styles.ts @@ -1 +1,2 @@ export const DISPLAY_MAX_WIDTH = '60rem'; +export const NAVIGATION_BAR_HEIGHT = '9rem'; diff --git a/frontend/src/hooks/mutaions/useChangeZzim.ts b/frontend/src/hooks/mutaions/useChangeZzim.ts index 4970d32e8..9d0b310cd 100644 --- a/frontend/src/hooks/mutaions/useChangeZzim.ts +++ b/frontend/src/hooks/mutaions/useChangeZzim.ts @@ -12,6 +12,15 @@ export default function useChangeZzim() { queryClient.invalidateQueries({ queryKey: [QUERY_KEYS.ZzimMine, moimId], }); + queryClient.invalidateQueries({ + queryKey: [QUERY_KEYS.moims], + }); + queryClient.invalidateQueries({ + queryKey: [QUERY_KEYS.myMoims], + }); + queryClient.invalidateQueries({ + queryKey: [QUERY_KEYS.myZzimMoims], + }); }, }); } diff --git a/frontend/src/hooks/queries/useMyMoims.ts b/frontend/src/hooks/queries/useMyMoims.ts new file mode 100644 index 000000000..99be967b9 --- /dev/null +++ b/frontend/src/hooks/queries/useMyMoims.ts @@ -0,0 +1,13 @@ +import { getMyMoims } from '@_apis/gets'; +import { Filter } from '@_components/MyMoimListFilters/MyMoimListFilters'; +import QUERY_KEYS from '@_constants/queryKeys'; +import { useQuery } from '@tanstack/react-query'; + +export default function useMyMoims(selectedFilter: Filter['api']) { + const { data: myMoims, isLoading } = useQuery({ + queryKey: [QUERY_KEYS.myMoims, selectedFilter], + queryFn: () => getMyMoims(selectedFilter), + }); + + return { myMoims, isLoading }; +} diff --git a/frontend/src/hooks/queries/useMyZzimMoim.ts b/frontend/src/hooks/queries/useMyZzimMoim.ts new file mode 100644 index 000000000..10c88d5b7 --- /dev/null +++ b/frontend/src/hooks/queries/useMyZzimMoim.ts @@ -0,0 +1,12 @@ +import { getMyZzimMoims } from '@_apis/gets'; +import QUERY_KEYS from '@_constants/queryKeys'; +import { useQuery } from '@tanstack/react-query'; + +export default function useMyZzimMoims() { + const { data: myZzimMoims, isLoading } = useQuery({ + queryKey: [QUERY_KEYS.myZzimMoims], + queryFn: getMyZzimMoims, + }); + + return { myZzimMoims, isLoading }; +} diff --git a/frontend/src/layouts/HomeLayout.tsx/HomeFixedButtonWrapper/HomeFixedButtonWrapper.style.ts b/frontend/src/layouts/HomeLayout.tsx/HomeFixedButtonWrapper/HomeFixedButtonWrapper.style.ts index b3ad279ca..60b1230b2 100644 --- a/frontend/src/layouts/HomeLayout.tsx/HomeFixedButtonWrapper/HomeFixedButtonWrapper.style.ts +++ b/frontend/src/layouts/HomeLayout.tsx/HomeFixedButtonWrapper/HomeFixedButtonWrapper.style.ts @@ -1,14 +1,15 @@ -import { DISPLAY_MAX_WIDTH } from '@_constants/styles'; +import { DISPLAY_MAX_WIDTH, NAVIGATION_BAR_HEIGHT } from '@_constants/styles'; import { css } from '@emotion/react'; export const fixedWrapperStyle = css` position: fixed; - bottom: 26px; + bottom: 18px; display: flex; justify-content: right; width: 100%; max-width: ${DISPLAY_MAX_WIDTH}; + margin-bottom: ${NAVIGATION_BAR_HEIGHT}; padding-right: 4rem; `; diff --git a/frontend/src/layouts/HomeLayout.tsx/HomeLayout.style.ts b/frontend/src/layouts/HomeLayout.tsx/HomeLayout.style.ts new file mode 100644 index 000000000..ac325f83b --- /dev/null +++ b/frontend/src/layouts/HomeLayout.tsx/HomeLayout.style.ts @@ -0,0 +1,11 @@ +import { NAVIGATION_BAR_HEIGHT } from '@_constants/styles'; +import { css } from '@emotion/react'; + +export const containerStyle = css` + display: flex; + flex-direction: column; + gap: 1rem; + + margin-bottom: ${NAVIGATION_BAR_HEIGHT}; + padding-bottom: 2rem; +`; diff --git a/frontend/src/layouts/HomeLayout.tsx/HomeLayout.tsx b/frontend/src/layouts/HomeLayout.tsx/HomeLayout.tsx index f31f84a07..4b36b6a8b 100644 --- a/frontend/src/layouts/HomeLayout.tsx/HomeLayout.tsx +++ b/frontend/src/layouts/HomeLayout.tsx/HomeLayout.tsx @@ -1,4 +1,4 @@ -import * as S from './MoimList.style'; +import * as S from './HomeLayout.style'; import HomeFixedButtonWrapper from './HomeFixedButtonWrapper/HomeFixedButtonWrapper'; import HomeHeader from './HomeHeader/HomeHeader'; diff --git a/frontend/src/layouts/HomeLayout.tsx/MoimList.style.ts b/frontend/src/layouts/HomeLayout.tsx/MoimList.style.ts deleted file mode 100644 index e654ae305..000000000 --- a/frontend/src/layouts/HomeLayout.tsx/MoimList.style.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { css } from '@emotion/react'; - -export const containerStyle = css` - display: flex; - flex-direction: column; - gap: 10px; -`; diff --git a/frontend/src/layouts/components/NavigationBarWrapper/NavigationBarWrapper.style.ts b/frontend/src/layouts/components/NavigationBarWrapper/NavigationBarWrapper.style.ts new file mode 100644 index 000000000..fc279b701 --- /dev/null +++ b/frontend/src/layouts/components/NavigationBarWrapper/NavigationBarWrapper.style.ts @@ -0,0 +1,9 @@ +import { NAVIGATION_BAR_HEIGHT } from '@_constants/styles'; +import { css } from '@emotion/react'; + +export const navigationBarWrapper = css` + position: fixed; + bottom: 0; + width: 100%; + height: ${NAVIGATION_BAR_HEIGHT}; +`; diff --git a/frontend/src/layouts/components/NavigationBarWrapper/NavigationBarWrapper.tsx b/frontend/src/layouts/components/NavigationBarWrapper/NavigationBarWrapper.tsx new file mode 100644 index 000000000..d9438a295 --- /dev/null +++ b/frontend/src/layouts/components/NavigationBarWrapper/NavigationBarWrapper.tsx @@ -0,0 +1,8 @@ +import { PropsWithChildren } from 'react'; +import * as S from './NavigationBarWrapper.style'; + +export default function NavigationBarWrapper(props: PropsWithChildren) { + const { children } = props; + + return
    {children}
    ; +} diff --git a/frontend/src/pages/ChatPage/ChatPage.tsx b/frontend/src/pages/ChatPage/ChatPage.tsx index 47289b5b8..1b281d02c 100644 --- a/frontend/src/pages/ChatPage/ChatPage.tsx +++ b/frontend/src/pages/ChatPage/ChatPage.tsx @@ -1,6 +1,9 @@ import ChattingPreview from '@_components/ChattingPreview/ChattingPreview'; +import NavigationBar from '@_components/NavigationBar/NavigationBar'; import ChattingPreviewLayout from '@_layouts/ChattingPreviewLayout/ChattingPreviewLayout'; +import NavigationBarWrapper from '@_layouts/components/NavigationBarWrapper/NavigationBarWrapper'; import { useTheme } from '@emotion/react'; +import { Fragment } from 'react'; export default function ChatPage() { const theme = useTheme(); @@ -12,17 +15,22 @@ export default function ChatPage() { }); return ( - - - -

    채팅

    -
    -
    - - {dummy.map((dum, id) => ( - - ))} - -
    + + + + +

    채팅

    +
    +
    + + {dummy.map((dum, id) => ( + + ))} + +
    + + + +
    ); } diff --git a/frontend/src/pages/MainPage/MainPage.tsx b/frontend/src/pages/MainPage/MainPage.tsx index d36ea1ac1..833982628 100644 --- a/frontend/src/pages/MainPage/MainPage.tsx +++ b/frontend/src/pages/MainPage/MainPage.tsx @@ -1,52 +1,51 @@ import Button from '@_components/Button/Button'; import HomeLayout from '@_layouts/HomeLayout.tsx/HomeLayout'; import ROUTES from '@_constants/routes'; -import useMoims from '@_hooks/queries/useMoims'; import { useNavigate } from 'react-router-dom'; import PlusIcon from '@_components/Icons/PlusIcon'; -import MoimTabBar from '@_components/MoimTabBar/MoimTabBar'; -import MoimCardList from '@_components/MoimCardList/MoimCardList'; -import { useState } from 'react'; -import MyMoimListFilters from '@_components/MyMoimListFilters/MyMoimListFilters'; +import { Fragment, useState } from 'react'; +import NavigationBarWrapper from '@_layouts/components/NavigationBarWrapper/NavigationBarWrapper'; +import NavigationBar from '@_components/NavigationBar/NavigationBar'; -const tabs = ['모임목록', '나의모임', '찜한모임']; +import MoimTabBar, { MainPageTab } from '@_components/MoimTabBar/MoimTabBar'; +import HomeMainContent from '@_components/HomeMainContent/HomeMainContent'; export default function MainPage() { const navigate = useNavigate(); - const { moims } = useMoims(); - const [currentTab, setCurrentTab] = useState(tabs[0]); + const [currentTab, setCurrentTab] = useState('모임목록'); - const handleTabClick = (tab: string) => { + const handleTabClick = (tab: MainPageTab) => { setCurrentTab(tab); }; return ( - - 우아한테크코스 - - - - - - - {currentTab === '나의모임' && } - {moims && } - - - - - - + + + 우아한테크코스 + + + + + + + + + + + + + + + + + + ); }