Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weโ€™ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

๐ŸŽ‰ ๊ฑฐ๋ž˜ ์ œ์•ˆ ๋กœ์ง ๊ตฌํ˜„ #67

Merged
merged 9 commits into from
Nov 13, 2023
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,32 @@ import { ItemSuggestion } from '@/types'
type SuggestListProps = {
suggestionData: ItemSuggestion[]
pokeAvailable: boolean
toCardId: number
}

/**
* TODO : ์Šคํฌ๋กค๋ฐ” ๋””์ž์ธ ์ˆ˜์ •
* TODO : ์‹ค์ œ API ์—ฐ๊ฒฐ(useMutation ์‚ฌ์šฉํ•ด์„œ)
*/
const SuggestList = ({ suggestionData, pokeAvailable }: SuggestListProps) => {
const SuggestList = ({
suggestionData,
pokeAvailable,
toCardId,
}: SuggestListProps) => {
console.log(suggestionData)
return (
<Tabs defaultValue="offer">
<Tabs defaultValue="OFFER">
<TabsList>
<TabsTrigger value="offer">์˜คํผํ•˜๊ธฐ</TabsTrigger>
<TabsTrigger value="poke">์ฐ”๋Ÿฌ๋ณด๊ธฐ</TabsTrigger>
<TabsTrigger value="OFFER">์˜คํผํ•˜๊ธฐ</TabsTrigger>
<TabsTrigger value="POKE">์ฐ”๋Ÿฌ๋ณด๊ธฐ</TabsTrigger>
</TabsList>
{['offer', 'poke'].map((type) => (
{['OFFER', 'POKE'].map((type) => (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

๋‹จ ๋‘๊ฐœ์˜ ๊ฐ’์„ ๋ Œ๋”๋ง ํ•˜๊ณ  ์žˆ๋Š”๋ฐ
๋‘๊ฐœ ์ •๋„๋ฉด ๊ทธ๋ƒฅ ํ’€์–ด์„œ ์จ๋„ ๋˜์ง€ ์•Š์„๊นŒ์š”? ์ด์œ ๊ฐ€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tab Content์˜ ๋‚ด์šฉ์ด ๋งŽ์•„์„œ ํ’€์–ด์„œ ์“ฐ์ง€ ์•Š๊ณ  map์œผ๋กœ ๋ฌถ์—ˆ์Šต๋‹ˆ๋‹ค!

<TabsContent
key={type}
value={type}
className=" data-[state=inactive]:hidden h-[402px] overflow-y-auto"
>
{!pokeAvailable && type === 'poke' ? (
{!pokeAvailable && type === 'POKE' ? (
<div className="flex flex-col justify-start items-center gap-4 p-8">
<Image
width={200}
Expand All @@ -49,6 +55,9 @@ const SuggestList = ({ suggestionData, pokeAvailable }: SuggestListProps) => {
itemName={v.itemName}
priceRange={v.priceRange}
suggestionType={v.suggestionType}
cardId={v.cardId}
toCardId={toCardId}
suggestionStatus={v.suggestionStatus}
/>
))
)}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
'use client'

import { useEffect, useState } from 'react'
import { useRouter } from 'next/navigation'
import { useState } from 'react'
import Button from '@/components/ui/Button'
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
} from '@/components/ui/Dialog'
import { handleApiError } from '@/lib/handleApiError'
import { getSuggestions } from '@/services/suggest/suggest'
import useSuggestionsQuery from '@/hooks/api/queries/useSuggestionsQuery'
import SuggestList from './SuggestList'
import TradeInfo from './TradeInfo'

Expand Down Expand Up @@ -49,7 +47,6 @@ const TradeSection = ({

const isLoggedIn = true
const isMyItem = currentUser.userId === authorId
const [suggestions, setSuggestions] = useState([])
const [open, setOpen] = useState(false)

const tradeInfo: TradeInfo[] = [
Expand All @@ -63,11 +60,10 @@ const TradeSection = ({
alert('์ œ์•ˆํ™•์ธ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•˜๊ธฐ')
} else {
setOpen(true)
const res = await getSuggestions(itemId)
setSuggestions(res.data.cardList)
}
}

const { data: suggestions } = useSuggestionsQuery(itemId)
juyeon-park marked this conversation as resolved.
Show resolved Hide resolved
return (
<section className="flex flex-col gap-2 w-full pt-4">
{tradeInfo.map((v, i) => (
Expand All @@ -90,6 +86,7 @@ const TradeSection = ({
<DialogTitle>์ œ์•ˆ ๊ฐ€๋Šฅํ•œ ๋‚ด ๋ฌผ๊ฑด ๋ณด๊ธฐ</DialogTitle>
</DialogHeader>
<SuggestList
toCardId={itemId}
pokeAvailable={pokeAvailable}
suggestionData={suggestions}
/>
Expand Down
31 changes: 0 additions & 31 deletions src/components/domain/card/suggest-card/SuggestCard.stories.tsx

This file was deleted.

32 changes: 30 additions & 2 deletions src/components/domain/card/suggest-card/SuggestCard.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
'use client'

import Button from '@/components/ui/Button'
import Card from '@/components/ui/Card'
import { CardFlex, CardImage, CardText } from '@/components/ui/Card/Card'
import { DEFAULT_ITEM_THUMBNAIL_IMG } from '@/constants/image'
import useSuggestMutation from '@/hooks/api/mutations/useSuggestMutation'

type SuggestCardProps = {
thumbNail?: string
cardTitle: string
itemName: string
priceRange: string
suggestionType: string
cardId: number
toCardId: number
suggestionStatus: string | null
}

const SuggestCard = ({
Expand All @@ -17,7 +23,20 @@ const SuggestCard = ({
itemName,
priceRange,
suggestionType,
cardId,
toCardId,
suggestionStatus,
}: SuggestCardProps) => {
const { mutate } = useSuggestMutation(toCardId, cardId)

const onClickSuggest = async (type: string) => {
mutate({
suggestionType: type,
fromCardId: cardId,
toCardId: toCardId,
})
}
console.log(suggestionStatus)
return (
<Card size="md">
<CardFlex
Expand All @@ -40,8 +59,17 @@ const SuggestCard = ({
<CardText type={'description'}>{itemName}</CardText>
<CardText type={'description'}>{priceRange}</CardText>
<div className="flex justify-end">
<Button variant={'gradation'} size={'sm'}>
{suggestionType === 'poke' ? '์ฐ”๋Ÿฌ๋ณด๊ธฐ' : '์˜คํผํ•˜๊ธฐ'}
<Button
variant={'gradation'}
size={'sm'}
onClick={() => onClickSuggest(suggestionType)}
disabled={suggestionStatus !== null}
>
{suggestionStatus === null
? suggestionType === 'POKE'
? '์ฐ”๋Ÿฌ๋ณด๊ธฐ'
: '์˜คํผํ•˜๊ธฐ'
: '์ œ์•ˆ๋จ'}
</Button>
</div>
</CardFlex>
Expand Down
3 changes: 2 additions & 1 deletion src/config/apiEndPoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ const ApiEndPoint = {
items: (cursorId: number) => `/items?cursorId=${cursorId}`,
myItems: (cursorId: number) => `/my-items?cursorId=${cursorId}`,
dibs: (itemId: number) => `/dib/${itemId}`,
suggestions: (itemId: string) => `/${itemId}/available-cards`,
suggestions: (itemId: number) => `/${itemId}/available-cards`,
suggestChecks: (cursorId: number) => `/suggest-checks?cursorId=${cursorId}`,
putUserProfile: () => '/users/profile-image',
putUserNickname: () => '/users/nickname',
postSuggestion: (suggestionType: string) => `/${suggestionType}`,
getMyDibs: (cursorId: number) => `/api/v1/dibs/?cursorId=${cursorId}`,
} as const

Expand Down
54 changes: 54 additions & 0 deletions src/hooks/api/mutations/useSuggestMutation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { useMutation, useQueryClient } from '@tanstack/react-query'
import { useRouter } from 'next/navigation'
import { toast } from '@/hooks/useToast'
import { handleApiError } from '@/lib/handleApiError'
import { postSuggestion } from '@/services/suggest/suggest'
import { ItemSuggestion } from '@/types'

const useSuggestMutation = (toCardId: number, fromCardId: number) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

useSuggestMutation ๊ฐ™์€ ๊ฒฝ์šฐ ๊ธฐ์กด ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธ ํ•˜๋Š”๊ฒƒ์œผ๋กœ ๋ณด์ด๋Š”๋ฐ
ํ•จ์ˆ˜๋ช…์„ useSuggestUpdateMutation์œผ๋กœ ํ•˜๋Š”๊ฒŒ ๋” ์ข‹์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค!

const queryClient = useQueryClient()
const router = useRouter()

const queryKey = [toCardId, 'suggestions']
return useMutation({
mutationFn: postSuggestion,
onMutate: async () => {
// ๋กค๋ฐฑ์„ ์œ„ํ•œ ์ด์ „ ๊ฐ’ ์ €์žฅ
const previousSuggestions = queryClient.getQueryData([
toCardId,
'suggestions',
]) as ItemSuggestion[]

await queryClient.cancelQueries({ queryKey })

const updateSuggestions = previousSuggestions

//๋‚™๊ด€์  ์—…๋ฐ์ดํŠธ
const indexToUpdate = previousSuggestions.findIndex(
(suggestion) => suggestion.cardId === fromCardId,
)
updateSuggestions[indexToUpdate].suggestionStatus = 'WAITING'
queryClient.setQueryData(queryKey, updateSuggestions)

return { previousSuggestions }
Comment on lines +27 to +33
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ํ˜น์‹œ UI๊ฐ€ ๋ฐ”๋€Œ์ง€ ์•Š๋Š” ์ด์Šˆ๊ฐ€ ํ•ด๊ฒฐ๋˜์…จ๋‚˜์š”?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

๋„ต!! ํ•ด๊ฒฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์›๋ณธ ๋ฐ์ดํ„ฐ๋ฅผ ๊นŠ์€ ๋ณต์‚ฌํ•˜์—ฌ ํ•ด๊ฒฐํ•˜์˜€์Šต๋‹ˆ๋‹ค.

},
onError: (error, _, context) => {
queryClient.setQueryData(queryKey, context?.previousSuggestions)
const { shouldRedirect } = handleApiError(error)
if (shouldRedirect) {
router.push(shouldRedirect)
} else {
console.log(shouldRedirect, error)
toast({
title: '์ œ์•ˆ์„ ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค',
duration: 2000,
})
}
},
onSettled: () => {
queryClient.invalidateQueries({ queryKey })
},
})
}

export default useSuggestMutation
11 changes: 11 additions & 0 deletions src/hooks/api/queries/useSuggestionsQuery.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { useQuery } from '@tanstack/react-query'
import { getSuggestions } from '@/services/suggest/suggest'

const useSuggestionsQuery = (itemId: number) => {
return useQuery({
queryKey: [itemId, 'suggestions'] as const,
queryFn: () => getSuggestions(itemId),
})
}

export default useSuggestionsQuery
2 changes: 1 addition & 1 deletion src/lib/msw/mocks/itemHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export const itemHandlers = [
cardTitle: '์•„์ดํฐ 16 ํŒ๋‹ˆ๋‹ค',
category: '์ „์ž๊ธฐ๊ธฐ',
itemName: '์•„์ดํฐ 16',
pokeAvailable: false,
pokeAvailable: true,
createdAt: '2023-10-23-20:08',
modifiedAt: '2023-10-24-20:08',
viewCount: 19,
Expand Down
57 changes: 51 additions & 6 deletions src/lib/msw/mocks/suggestHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const baseUrl = Environment.apiAddress()

export const suggestHandlers = [
rest.get(
`${baseUrl}${ApiEndPoint.suggestions('3')}`,
`${baseUrl}${ApiEndPoint.suggestions(3)}`,
async (_req, res, ctx) => {
return res(
ctx.status(200),
Expand All @@ -23,7 +23,8 @@ export const suggestHandlers = [
cardTitle: 'xxx',
itemName: '๋‹ค์ด์Šจ ์ฒญ์†Œ๊ธฐ',
priceRange: '10๋งŒ์›๋Œ€',
suggestionType: 'offer',
suggestionType: 'OFFER',
suggestionStatus: 'WAITING',
},
{
_id: 2,
Expand All @@ -32,7 +33,8 @@ export const suggestHandlers = [
cardTitle: 'xxx',
itemName: '์• ํ”Œ ์›Œ์น˜',
priceRange: '20๋งŒ์›๋Œ€',
suggestionType: 'poke',
suggestionType: 'POKE',
suggestionStatus: null,
},
{
_id: 3,
Expand All @@ -41,7 +43,8 @@ export const suggestHandlers = [
cardTitle: 'xxx',
itemName: '์—์–ดํŒŸ ํ”„๋กœ',
priceRange: '20๋งŒ์›๋Œ€',
suggestionType: 'poke',
suggestionType: 'POKE',
suggestionStatus: null,
},
{
_id: 4,
Expand All @@ -50,7 +53,8 @@ export const suggestHandlers = [
cardTitle: 'xxx',
itemName: '์—์–ดํŒŸ ํ”„๋กœ',
priceRange: '20๋งŒ์›๋Œ€',
suggestionType: 'poke',
suggestionType: 'POKE',
suggestionStatus: null,
},
{
_id: 5,
Expand All @@ -59,12 +63,53 @@ export const suggestHandlers = [
cardTitle: 'xxx',
itemName: '์—์–ดํŒŸ ํ”„๋กœ',
priceRange: '20๋งŒ์›๋Œ€',
suggestionType: 'poke',
suggestionType: 'POKE',
suggestionStatus: 'WAITING',
},
],
},
}),
)
},
),
rest.post(
`${baseUrl}${ApiEndPoint.postSuggestion('POKE')}`,
async (_req, res, ctx) => {
return res(
ctx.status(200),
ctx.json({
code: 'SUCCESS',
message: '์„ฑ๊ณตํ•˜์˜€์Šต๋‹ˆ๋‹ค.',
data: {
suggestionId: 1,
suggestionType: 'POKE',
fromCardId: 1,
toCardId: 3,
suggestionStatus: 'WAITING',
createdAt: '2023-11-09T14:59:51',
},
}),
)
},
),
rest.post(
`${baseUrl}${ApiEndPoint.postSuggestion('OFFER')}`,
async (_req, res, ctx) => {
return res(
ctx.status(200),
ctx.json({
code: 'SUCCESS',
message: '์„ฑ๊ณตํ•˜์˜€์Šต๋‹ˆ๋‹ค.',
data: {
suggestionId: 1,
suggestionType: 'OFFER',
fromCardId: 1,
toCardId: 3,
suggestionStatus: 'WAITING',
createdAt: '2023-11-09T14:59:51',
},
}),
)
},
),
]
Loading