Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions src/api/types/club.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CategoryType } from '@/features/Club/constants'
import { CategoryType } from '@/domain/Club/constants'
import { ClubInterface } from '@/types/club'

export interface ClubProfileProps {
Expand All @@ -20,7 +20,6 @@ export interface GetClubRequest {
export type GetClubResponse = ClubInterface[]

export interface PostClubLikeRequest {
queryParams: GetClubRequest
clubId: number
}

Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useQueryClient, useSuspenseQuery } from '@tanstack/react-query'

import { GetClubRequest, GetClubResponse } from '@/api/types/club'
import { CLUB_QUERY_KEY } from '@/features/Club/queries'
import { CLUB_QUERY_KEY } from '@/domain/Club/queries'
import { ClubSearchParams } from '@/types/club'
import { useAuth } from '@/util/auth/useAuth'
import { apiInterface } from '@/util/axios/custom-axios'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { useQueryClient } from '@tanstack/react-query'

import { useErrorHandledMutation } from '@/api/hooks/useErrorHandledMutation'
import { GetClubResponse, PostClubLikeRequest, PostClubLikeResponse } from '@/api/types/club'
import { CLUB_QUERY_KEY } from '@/features/Club/queries'
import { PostClubLikeRequest, PostClubLikeResponse } from '@/api/types/club'
import { CLUB_QUERY_KEY } from '@/domain/Club/queries'
import { apiInterface } from '@/util/axios/custom-axios'

const postClubLike = async ({ clubId }: PostClubLikeRequest) => {
Expand All @@ -14,15 +14,8 @@ export const usePostClubLike = () => {
const queryClient = useQueryClient()
return useErrorHandledMutation({
mutationFn: postClubLike,
onSuccess: (response, { queryParams }) => {
queryClient.setQueryData<GetClubResponse>(
CLUB_QUERY_KEY.clubSearchResults({ ...queryParams, keyword: queryParams.keyword }),
oldData => {
if (oldData !== undefined) {
return oldData.map(club => (club.clubId === response.clubId ? response : { ...club }))
}
},
)
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: CLUB_QUERY_KEY.base() })
},
})
}
15 changes: 15 additions & 0 deletions src/domain/Club/hooks/useReadClubDetail.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { useSuspenseQuery } from '@tanstack/react-query'

import { useAsyncRead } from '@/common/hooks/useAsyncRead'
import { CLUB_QUERY_KEY } from '@/domain/Club/queries'
import { kuKeyClient } from '@/packages/api'
import { useAuth } from '@/util/auth/useAuth'

export const useReadClubDetail = (clubId: number) => {
const isLogin = useAuth().authState ?? false
const read = useAsyncRead(kuKeyClient.api.ClubApi.clubClubIdGet)
return useSuspenseQuery({
queryKey: CLUB_QUERY_KEY.clubDetail(clubId, isLogin),
queryFn: () => read({ clubId, isLogin }),
})
}
7 changes: 7 additions & 0 deletions src/domain/Club/queries.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { GetClubRequest } from '@/api/types/club'

export const CLUB_QUERY_KEY = {
base: () => ['club'] as const,
clubSearchResults: (query: GetClubRequest) => [...CLUB_QUERY_KEY.base(), 'clubSearchResult', query] as const,
clubDetail: (clubID: number, isLogin: boolean) => [...CLUB_QUERY_KEY.base(), 'clubDetail', clubID, isLogin] as const,
}
4 changes: 2 additions & 2 deletions src/features/Club/components/CategoryDrawer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import { useEffect, useState } from 'react'

import * as s from './style.css'

import { CATEGORY_LIST, CategoryType } from '@/domain/Club/constants'
import { useGetCachedClubSearchResult } from '@/domain/Club/hooks/useGetClubSearch'
import CategoryChip from '@/features/Club/components/CategoryChip'
import { CATEGORY_LIST, CategoryType } from '@/features/Club/constants'
import { useGetCachedClubSearchResult } from '@/features/Club/hooks/useGetClubSearch'
import { ClubSearchParams } from '@/types/club'
import { useQueryParams } from '@/util/hooks/useQueryParams'

Expand Down
14 changes: 8 additions & 6 deletions src/features/Club/components/ClubCard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@ interface Props {
}
const ClubCard = ({ clubData, handleLikeClick }: Props) => {
return (
<Link className={s.Wrapper} to={`detail/${clubData.clubId}`} state={{ clubData }}>
{/* TODO: 안티패턴!!!!!! state 말고 해당 페이지 내에서 데이터 패칭하기 */}
<div className={s.ContentsWrapper}>
<div className={s.Wrapper}>
<Link className={s.ContentsWrapper} to={`detail/${clubData.clubId}`}>
<div className={s.ImageContainer}>
<img className={s.Image} src={clubData.imageUrl} alt={clubData.name} />
<Responsive
Expand Down Expand Up @@ -43,12 +42,15 @@ const ClubCard = ({ clubData, handleLikeClick }: Props) => {
<ClubSchedule recruitmentPeriod={clubData.recruitmentPeriod} regularMeeting={clubData.regularMeeting} />
<div className={s.Description}>{clubData.description}</div>
</div>
</div>
</Link>
<Responsive
mobile={
<button
className={s.MobileLikeButton({ myLikes: clubData.isLiked })}
onClick={() => handleLikeClick(clubData.clubId)}
onClick={event => {
event.stopPropagation()
handleLikeClick(clubData.clubId)
}}
>
<div className={s.HeartIcon({ myLikes: clubData.isLiked })}>
<HeartIcon />
Expand All @@ -57,7 +59,7 @@ const ClubCard = ({ clubData, handleLikeClick }: Props) => {
</button>
}
/>
</Link>
</div>
)
}
export default ClubCard
4 changes: 3 additions & 1 deletion src/features/Club/components/ClubCard/style.css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,10 @@ export const HeartIcon = recipe({
width: '1.18rem',
color: vars.color.black,
transition: 'color 0.25s ease',
marginLeft: '0.22rem',
},
f.smUp({
marginLeft: '0.22rem',
}),
f.smDown({
width: '1.03rem',
color: vars.color.darkGray2,
Expand Down
8 changes: 4 additions & 4 deletions src/features/Club/components/ClubList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import * as s from './style.css'

import { Responsive } from '@/common/Responsive'
import Toast from '@/components/ui/toast'
import { useGetClubSearch } from '@/domain/Club/hooks/useGetClubSearch'
import { usePostClubLike } from '@/domain/Club/hooks/usePostClubLike'
import ClubCard from '@/features/Club/components/ClubCard'
import { useGetClubSearch } from '@/features/Club/hooks/useGetClubSearch'
import { usePostClubLike } from '@/features/Club/hooks/usePostClubLike'
import { USER_AUTH_MESSAGE } from '@/lib/messages/common'
import { ClubSearchParams } from '@/types/club'
import { useAuth } from '@/util/auth/useAuth'
Expand All @@ -34,10 +34,10 @@ const ClubList = () => {

const handleLikeClick = useDeepCompareCallback(
(clubId: number) => {
if (isLogin) likeClub({ clubId, queryParams: requestQuery })
if (isLogin) likeClub({ clubId })
else toast.custom(() => <Toast message={USER_AUTH_MESSAGE.REQUIRE_LOGIN} type="error" />)
},
[likeClub, query, isLogin],
[likeClub, isLogin],
)

return (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as s from './style.css'

import CategoryChip from '@/features/Club/components/CategoryChip'
import { CATEGORY_LIST, CategoryType } from '@/features/Club/constants'
import { CATEGORY_LIST, CategoryType } from '@/domain/Club/constants'
import { ClubSearchParams } from '@/types/club'
import { useQueryParams } from '@/util/hooks/useQueryParams'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as s from './style.css'

import OptionIcon from '@/assets/icon/OptionIcon'
import CategoryDrawer from '@/features/Club/components/CategoryDrawer'
import { CATEGORY_LIST, CategoryType } from '@/features/Club/constants'
import { CATEGORY_LIST, CategoryType } from '@/domain/Club/constants'
import useDrawer from '@/util/hooks/useDrawer'

interface Props {
Expand Down
5 changes: 0 additions & 5 deletions src/features/Club/queries.ts

This file was deleted.

27 changes: 20 additions & 7 deletions src/features/ClubDetail/index.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,42 @@
import { LinkIcon } from 'lucide-react'
import { useLocation } from 'react-router-dom'
import { useParams } from 'react-router-dom'
import { toast } from 'sonner'

import * as s from './style.css'

import HeartIcon from '@/assets/icon/HeartIcon'
import Toast from '@/components/ui/toast'
import { usePostClubLike } from '@/domain/Club/hooks/usePostClubLike'
import { useReadClubDetail } from '@/domain/Club/hooks/useReadClubDetail'
import ContactButton from '@/features/Club/components/ClubCard/ContactButton'
import ClubSchedule from '@/features/ClubSchedule'
import { ClubInterface } from '@/types/club'
import { USER_AUTH_MESSAGE } from '@/lib/messages/common'
import { useAuth } from '@/util/auth/useAuth'
import { useDeepCompareCallback } from '@/util/hooks/useDeepCompare'

const ClubDetail = () => {
// const { clubId } = useParams()
// TODO: 추후에 단일 동아리 api 파서 옮기기
const { clubData } = useLocation().state as { clubData: ClubInterface }
const isLogin = useAuth().authState ?? false
const { clubId } = useParams()

const { data: clubData } = useReadClubDetail(Number(clubId))
const { mutate: likeClub } = usePostClubLike()

const handleLikeClick = useDeepCompareCallback(() => {
if (isLogin) likeClub({ clubId: Number(clubId) })
else toast.custom(() => <Toast message={USER_AUTH_MESSAGE.REQUIRE_LOGIN} type="error" />)
}, [likeClub, isLogin])

return (
<div className={s.Layout}>
<div className={s.Wrapper}>
<img className={s.Image} src={clubData.imageUrl} alt={clubData.name} />
<img className={s.Image} src={clubData.imageUrl[0]} alt={clubData.name} /> {/* TODO: IMG array로 만들기 */}
<div className={s.ContentsWrapper}>
<div className={s.ContentsHeader}>
<div className={s.TitleWrapper}>
<div className={s.Category}>{clubData.summary}</div>
<h1 className={s.Title}>{clubData.name}</h1>
</div>
<button className={s.LikeButton}>
<button className={s.LikeButton({ clicked: clubData.isLiked })} onClick={() => handleLikeClick()}>
<HeartIcon />
</button>
</div>
Expand Down
30 changes: 20 additions & 10 deletions src/features/ClubDetail/style.css.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { style } from '@vanilla-extract/css'
import { recipe } from '@vanilla-extract/recipes'

import { f } from '@/style'
import { vars } from '@/theme/theme.css'
Expand Down Expand Up @@ -74,16 +75,25 @@ export const Title = style([
f.smDown(vars.typography.mobile.display2SB),
])

export const LikeButton = style([
f.cursorPointer,
{ width: '2.4rem', color: vars.color.lightGray1 },
f.smUp({
marginRight: '1.42rem',
}),
f.smDown({
width: '1.66rem',
}),
])
export const LikeButton = recipe({
base: [
f.cursorPointer,
{ width: '2.4rem', color: vars.color.lightGray1, transition: 'color 0.256s' },
f.smUp({
marginRight: '1.42rem',
}),
f.smDown({
width: '1.66rem',
}),
],
variants: {
clicked: {
true: {
color: vars.color.red3,
},
},
},
})

export const Contents = style([
f.flex,
Expand Down
6 changes: 4 additions & 2 deletions src/features/HomeClubs/components/HotClubs/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { motion } from 'framer-motion'
import { useNavigate } from 'react-router-dom'

import * as s from '../Clubs/style.css'

import { useReadHotClubs } from '@/features/HomeClubs/hooks/useReadHotClubs'
import { Typography } from '@/ui/Typography'

const HotClubs = () => {
const { data: hotClubs } = useReadHotClubs()
const navigate = useNavigate()
const handleClick = (id: number) => navigate(`/club/detail/${id}`)

return (
<motion.div
Expand All @@ -18,7 +20,7 @@ const HotClubs = () => {
transition={{ duration: 0.2, ease: 'easeInOut' }}
>
{hotClubs.map(item => (
<button key={item.name} className={s.ItemBox}>
<button key={item.name} className={s.ItemBox} onClick={() => handleClick(item.clubId)}>
<img className={s.ItemImage} src={item.imageUrl} alt={item.name} />
<div className={s.Description}>
<div className={s.DescriptionText}>
Expand Down
7 changes: 6 additions & 1 deletion src/features/HomeClubs/components/RecommendedClubs/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { motion } from 'framer-motion'
import { useNavigate } from 'react-router-dom'

import * as s from '../Clubs/style.css'

Expand All @@ -7,6 +8,10 @@ import { Typography } from '@/ui/Typography'

const RecommendedClubs = () => {
const { data: recommendedClubs } = useReadRecommendedClubs()

const navigate = useNavigate()
const handleClick = (id: number) => navigate(`/club/detail/${id}`)

return (
<motion.div
key={'HOT'}
Expand All @@ -17,7 +22,7 @@ const RecommendedClubs = () => {
transition={{ duration: 0.2, ease: 'easeInOut' }}
>
{recommendedClubs.map(item => (
<button key={item.name} className={s.ItemBox}>
<button key={item.name} className={s.ItemBox} onClick={() => handleClick(item.clubId)}>
<img className={s.ItemImage} src={item.imageUrl} alt={item.name} />
<div className={s.Description}>
<div className={s.DescriptionText}>
Expand Down
2 changes: 1 addition & 1 deletion src/types/club.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CategoryType } from '@/features/Club/constants'
import { CategoryType } from '@/domain/Club/constants'

export interface ClubProfileProps {
img: string
Expand Down