-
Notifications
You must be signed in to change notification settings - Fork 3
Feat/121/liked api #123
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
Feat/121/liked api #123
Changes from 12 commits
44d254e
77585af
0344be1
340752f
7a31287
c1fc0d7
1f75511
d3649f7
e075627
79d9191
ef72b00
84a8539
b243456
9e1b752
4317a4c
5bf99c2
e82ff4c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| import { fetchApi } from '@/src/utils/api'; | ||
| import { GatheringResponseType } from '@/src/types/gathering-data'; | ||
|
|
||
| // μ° λͺ©λ‘ μ‘°ν | ||
| export async function getLikedList(page: number): Promise<GatheringResponseType> { | ||
| const url = `/api/liked/memberLikes?page=${page}&size=6`; | ||
|
|
||
| const response = await fetchApi<{ data: GatheringResponseType }>(url, { | ||
| method: 'GET', | ||
| headers: { | ||
| 'Content-Type': 'application/json', | ||
| }, | ||
| }); | ||
| return response.data; | ||
| } | ||
|
|
||
| // μ° μΆκ°νκΈ° | ||
| export async function addLike(gatheringId: number): Promise<void> { | ||
| const url = `/api/liked/${gatheringId}`; | ||
|
|
||
| await fetchApi<void>(url, { | ||
| method: 'POST', | ||
| headers: { | ||
| 'Content-Type': 'application/json', | ||
| }, | ||
| }); | ||
| } | ||
|
|
||
| // μ° ν΄μ νκΈ° | ||
| export async function removeLike(gatheringId: number): Promise<void> { | ||
| const url = `/api/liked/${gatheringId}`; | ||
|
|
||
| await fetchApi<void>(url, { | ||
| method: 'DELETE', | ||
| headers: { | ||
| 'Content-Type': 'application/json', | ||
| }, | ||
| }); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| import { useQuery } from '@tanstack/react-query'; | ||
| import { getLikedList } from '@/src/_apis/liked/liked-apis'; | ||
|
|
||
| export function useGetLikedListQuery(page: number) { | ||
| return useQuery({ | ||
| queryKey: ['likedList', page], | ||
| queryFn: () => getLikedList(page), | ||
| }); | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,6 +1,12 @@ | ||||||||||||||||||||
| 'use client'; | ||||||||||||||||||||
|
|
||||||||||||||||||||
| import { useState } from 'react'; | ||||||||||||||||||||
| import { useRouter } from 'next/navigation'; | ||||||||||||||||||||
| import { addLike, removeLike } from '@/src/_apis/liked/liked-apis'; | ||||||||||||||||||||
| import { useGetGatheringListQuery } from '@/src/_queries/detail/gathering-list-queries'; | ||||||||||||||||||||
| import { ApiError } from '@/src/utils/api'; | ||||||||||||||||||||
| import ConfirmModal from '@/src/components/common/modal/confirm-modal'; | ||||||||||||||||||||
| import Toast from '@/src/components/common/toast'; | ||||||||||||||||||||
|
||||||||||||||||||||
| import GatheringCardCarousel from '@/src/components/gathering-list/gathering-card-carousel'; | ||||||||||||||||||||
|
|
||||||||||||||||||||
| interface GatheringListSectionProps { | ||||||||||||||||||||
|
|
@@ -9,12 +15,57 @@ interface GatheringListSectionProps { | |||||||||||||||||||
|
|
||||||||||||||||||||
| export default function GatheringListSection({ id }: GatheringListSectionProps) { | ||||||||||||||||||||
| const { data: gatheringList, isLoading, error } = useGetGatheringListQuery(id); | ||||||||||||||||||||
| const [showLoginModal, setShowLoginModal] = useState(false); | ||||||||||||||||||||
| const router = useRouter(); | ||||||||||||||||||||
|
|
||||||||||||||||||||
| if (isLoading) return <p>λ‘λ© μ€...</p>; | ||||||||||||||||||||
| const handleLike = async (gatheringId: number) => { | ||||||||||||||||||||
| try { | ||||||||||||||||||||
| await addLike(gatheringId); | ||||||||||||||||||||
| } catch (apiError) { | ||||||||||||||||||||
| if (apiError instanceof ApiError) { | ||||||||||||||||||||
| Toast({ message: `μ°νκΈ°μ μ€ν¨νμ΅λλ€: ${apiError.message}`, type: 'error' }); | ||||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
| }; | ||||||||||||||||||||
|
|
||||||||||||||||||||
| const handleUnlike = async (gatheringId: number) => { | ||||||||||||||||||||
| try { | ||||||||||||||||||||
| await removeLike(gatheringId); | ||||||||||||||||||||
| } catch (apiError) { | ||||||||||||||||||||
| if (apiError instanceof ApiError) { | ||||||||||||||||||||
| Toast({ message: `μ°νκΈ° ν΄μ μ μ€ν¨νμ΅λλ€: ${apiError.message}`, type: 'error' }); | ||||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
| }; | ||||||||||||||||||||
|
|
||||||||||||||||||||
| if (error) return <p>λ°μ΄ν°λ₯Ό λΆλ¬μ€λ λ° μ€ν¨νμ΅λλ€: {error.message}</p>; | ||||||||||||||||||||
| const handleLoginRedirect = () => { | ||||||||||||||||||||
| const currentPath = window.location.href; | ||||||||||||||||||||
| router.push(`/login?redirect=${encodeURIComponent(currentPath)}`); | ||||||||||||||||||||
| }; | ||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. URL μΈμ½λ© 보μ κ°νκ° νμν©λλ€ νμ¬ κ΅¬νμμλ λ€μκ³Ό κ°μ κ°μ μ μ μν©λλ€: const handleLoginRedirect = () => {
- const currentPath = window.location.href;
+ const currentPath = window.location.pathname + window.location.search;
+ const sanitizedPath = currentPath.replace(/[^\w\-\.\~\/\?\[\]\@\!\$\&\'\(\)\*\+\,\;\=]/g, '');
- router.push(`/login?redirect=${encodeURIComponent(currentPath)}`);
+ router.push(`/login?redirect=${encodeURIComponent(sanitizedPath)}`);
};π Committable suggestion
Suggested change
|
||||||||||||||||||||
|
|
||||||||||||||||||||
| // TODO: μΆν μλ¬, λ‘λ© μμ | ||||||||||||||||||||
| if (isLoading) return <p>λ‘λ© μ€...</p>; | ||||||||||||||||||||
| if (error) return <p>λ°μ΄ν°λ₯Ό λΆλ¬μ€λ λ° μ€ν¨νμ΅λλ€</p>; | ||||||||||||||||||||
|
Comment on lines
+46
to
+48
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π οΈ Refactor suggestion λ‘λ© λ° μλ¬ μν μ²λ¦¬λ₯Ό κ°μ ν΄μ£ΌμΈμ νμ¬ κ΅¬νμ κΈ°λ³Έμ μΈ ν μ€νΈλ§ νμνκ³ μμ΅λλ€. μ¬μ©μ κ²½νμ ν₯μμν€κΈ° μν΄ λ λμ UI μ»΄ν¬λνΈλ₯Ό μ¬μ©νλ κ²μ΄ μ’μ΅λλ€. λ€μκ³Ό κ°μ κ°μ μ¬νμ μ μν©λλ€:
if (isLoading) return <LoadingSpinner />;
if (error) return (
<ErrorState
message="λ°μ΄ν°λ₯Ό λΆλ¬μ€λ λ° μ€ν¨νμ΅λλ€"
onRetry={() => refetch()}
/>
);
if (!gatheringList || gatheringList.length === 0) return (
<EmptyState message="μμ§ λ±λ‘λ λͺ¨μμ΄ μμ΅λλ€" />
); |
||||||||||||||||||||
| if (!gatheringList || gatheringList.length === 0) return <p>λ°μ΄ν°κ° μμ΅λλ€.</p>; | ||||||||||||||||||||
|
|
||||||||||||||||||||
| return <GatheringCardCarousel gatheringData={gatheringList} crewId={id} />; | ||||||||||||||||||||
| return ( | ||||||||||||||||||||
| <> | ||||||||||||||||||||
| <GatheringCardCarousel | ||||||||||||||||||||
| gatheringData={gatheringList} | ||||||||||||||||||||
| crewId={id} | ||||||||||||||||||||
| onLike={handleLike} | ||||||||||||||||||||
| onUnlike={handleUnlike} | ||||||||||||||||||||
| onShowLoginModal={() => setShowLoginModal(true)} | ||||||||||||||||||||
| /> | ||||||||||||||||||||
| {showLoginModal && ( | ||||||||||||||||||||
| <ConfirmModal | ||||||||||||||||||||
| opened={showLoginModal} | ||||||||||||||||||||
| onClose={() => setShowLoginModal(false)} | ||||||||||||||||||||
| onConfirm={handleLoginRedirect} | ||||||||||||||||||||
| > | ||||||||||||||||||||
| λ‘κ·ΈμΈμ΄ νμν©λλ€! | ||||||||||||||||||||
| </ConfirmModal> | ||||||||||||||||||||
| )} | ||||||||||||||||||||
| </> | ||||||||||||||||||||
| ); | ||||||||||||||||||||
| } | ||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,10 +1,9 @@ | ||
| import GatheringList from '@/src/components/gathering-list/gathering-list'; | ||
| import { gatheringData } from '@/src/mock/gathering-data'; | ||
| import LikedList from '@/src/components/gathering-list/liked-list-container'; | ||
|
|
||
| export default function FavoritePage() { | ||
| return ( | ||
| <div className="mt-4 md:mt-10"> | ||
| <GatheringList gatheringData={gatheringData} /> | ||
| <LikedList /> | ||
| </div> | ||
| ); | ||
| } |
This file was deleted.
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -12,6 +12,8 @@ import GatheringCardPresenter from './presenter'; | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| interface GatheringCardContainerProps extends GatheringType { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className?: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| crewId: number; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onLike: (gatheringId: number) => Promise<void>; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onUnlike: (gatheringId: number) => Promise<void>; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export default function GatheringCard({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -25,9 +27,10 @@ export default function GatheringCard({ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| liked: initialIsLiked, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| crewId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onLike, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onUnlike, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }: GatheringCardContainerProps) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [opened, { open, close }] = useDisclosure(false); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // μμ μ°νκΈ° | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [isLiked, setIsLiked] = useState(initialIsLiked); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // λ μ§ λΉκ΅ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -42,9 +45,19 @@ export default function GatheringCard({ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // λ§κ° μκ° λ¬Έμμ΄ μμ± | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const deadlineMessage = `μ€λ ${gatheringDate.getHours()}μ λ§κ°`; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // μΆν μ°νκΈ° μ»΄ν¬λνΈ μμ±λλ©΄ μμ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const handleLikeToggle = () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setIsLiked((prev) => !prev); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // μ°νκΈ° μν μ λ°μ΄νΈ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const handleLikeToggle = async () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (isLiked) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await onUnlike(id); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setIsLiked(false); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await onLike(id); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setIsLiked(true); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Toast({ message: 'μ° μνλ₯Ό μ λ°μ΄νΈνλ λ° μ€ν¨νμ΅λλ€.', type: 'error' }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π οΈ Refactor suggestion μ’μμ ν κΈ νΈλ€λ¬μ κ°μ μ΄ νμν©λλ€. νμ¬ κ΅¬νμμ λ€μ μ¬νλ€μ κ°μ νλ©΄ μ’μ κ² κ°μ΅λλ€:
λ€μκ³Ό κ°μ΄ κ°μ ν΄λ³΄μΈμ: + const [isLoading, setIsLoading] = useState(false);
const handleLikeToggle = async () => {
+ if (isLoading) return;
+ setIsLoading(true);
try {
if (isLiked) {
await onUnlike(id);
- setIsLiked(false);
+ setIsLiked(prev => !prev);
} else {
await onLike(id);
- setIsLiked(true);
+ setIsLiked(prev => !prev);
}
} catch (error) {
+ // μλ μνλ‘ λ³΅κ΅¬
+ setIsLiked(prev => !prev);
+ if (error instanceof Error) {
+ Toast({ message: `μ’μμ μ
λ°μ΄νΈ μ€ν¨: ${error.message}`, type: 'error' });
+ } else {
Toast({ message: 'μ° μνλ₯Ό μ
λ°μ΄νΈνλ λ° μ€ν¨νμ΅λλ€.', type: 'error' });
+ }
} finally {
+ setIsLoading(false);
}
};π Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { data: gatheringData, error } = useGetGatheringDetailQuery(crewId, id); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -2,6 +2,7 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useEffect, useState } from 'react'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import Image from 'next/image'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useAuthStore } from '@/src/store/use-auth-store'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import GatheringCard from '@/src/components/common/gathering-card/container'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { GatheringType } from '@/src/types/gathering-data'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import IcoLeft from '@/public/assets/icons/ic-left.svg'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -10,16 +11,26 @@ import IcoRight from '@/public/assets/icons/ic-right.svg'; | |||||||||||||||||||||||||||||||||||||||||||||||||||||
| interface GatheringCardCarouselProps { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| gatheringData: GatheringType[]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| crewId: number; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onLike: (gatheringId: number) => Promise<void>; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onUnlike: (gatheringId: number) => Promise<void>; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onShowLoginModal: () => void; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export default function CustomGatheringCardCarousel({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| gatheringData, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| crewId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onLike, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onUnlike, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onShowLoginModal, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }: GatheringCardCarouselProps) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [currentIndex, setCurrentIndex] = useState(0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [slidesToShow, setSlidesToShow] = useState(1); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [slideSize, setSlideSize] = useState('w-full'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // λ‘κ·ΈμΈ μ¬λΆ νμΈ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const token = useAuthStore((state) => state.token); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const isLoggedIn = !!token; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const handleResize = () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const screenWidth = window.innerWidth; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -75,7 +86,25 @@ export default function CustomGatheringCardCarousel({ | |||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {gatheringData.map((card) => ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div key={card.id} className={`flex-shrink-0 ${slideSize} mb-5 lg:min-w-[362px]`}> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <GatheringCard crewId={crewId} {...card} className="w-full" /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <GatheringCard | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| crewId={crewId} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {...card} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| className="w-full" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onLike={() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (isLoggedIn) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return onLike(card.id); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onShowLoginModal(); // λ‘κ·ΈμΈμ΄ μ λμ΄ μμΌλ©΄ λͺ¨λ¬ νμ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return Promise.resolve(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onUnlike={() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (isLoggedIn) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return onUnlike(card.id); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onShowLoginModal(); // λ‘κ·ΈμΈμ΄ μ λμ΄ μμΌλ©΄ λͺ¨λ¬ νμ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return Promise.resolve(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π οΈ Refactor suggestion μ’μμ/μ’μμ μ·¨μ νΈλ€λ¬ μ€λ³΅ μ½λ κ°μ νμ onLikeμ onUnlike νΈλ€λ¬μ κ΅¬μ‘°κ° λ§€μ° μ μ¬νμ¬ μ€λ³΅ μ½λκ° λ°μνμ΅λλ€. λ€μκ³Ό κ°μ΄ κ³΅ν΅ λ‘μ§μ μΆμΆνμ¬ λ¦¬ν©ν λ§νλ κ²μ μΆμ²λ립λλ€: const createAuthenticatedHandler = (
handler: (id: number) => Promise<void>
) => (id: number) => {
if (isLoggedIn) {
return handler(id);
}
onShowLoginModal();
return Promise.resolve();
};
<GatheringCard
crewId={crewId}
{...card}
className="w-full"
onLike={createAuthenticatedHandler((id) => onLike(id))}
onUnlike={createAuthenticatedHandler((id) => onUnlike(id))}
/>μ΄λ κ² νλ©΄:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. μ’μμ/μ’μμ μ·¨μ νΈλ€λ¬μ κ°μ μ΄ νμν©λλ€. νμ¬ κ΅¬νμμ λ€μκ³Ό κ°μ λ¬Έμ μ λ€μ΄ λ°κ²¬λμμ΅λλ€:
λ€μκ³Ό κ°μ κ°μ λ ꡬνμ μ μν©λλ€: +const createAuthenticatedHandler = (
+ action: (id: number) => Promise<void>,
+ gatheringId: number,
+ showLoginModal: () => void,
+) => async () => {
+ if (!isLoggedIn) {
+ showLoginModal();
+ return;
+ }
+
+ try {
+ await action(gatheringId);
+ } catch (error) {
+ console.error('Failed to process action:', error);
+ // μλ¬ μ²λ¦¬ λ‘μ§ μΆκ° νμ
+ }
+};
<GatheringCard
crewId={crewId}
{...card}
className="w-full"
- onLike={() => {
- if (isLoggedIn) {
- return onLike(card.id);
- }
- onShowLoginModal();
- return Promise.resolve();
- }}
- onUnlike={() => {
- if (isLoggedIn) {
- return onUnlike(card.id);
- }
- onShowLoginModal();
- return Promise.resolve();
- }}
+ onLike={createAuthenticatedHandler(onLike, card.id, onShowLoginModal)}
+ onUnlike={createAuthenticatedHandler(onUnlike, card.id, onShowLoginModal)}
/>π Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ))} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π‘ Codebase verification
crewId μμ±μ΄ storiesμλ§ μΆκ°λμ΄ μκ³ μ€μ μ»΄ν¬λνΈμμλ μ¬μ©λμ§ μμ΅λλ€
κ²μ¦ κ²°κ³Ό:
crewId: 1μμ±μ΄ μΆκ°λμ΄ μμ΅λλ€GatheringDetailTypeνμ μ μ¬μ©νκ³ μμ§λ§,crewIdλ₯Ό μ€μ λ‘ μ¬μ©νλ λ‘μ§μ μμ΅λλ€π Analysis chain
crewId μμ±μ΄ μΌκ΄λκ² μΆκ°λμμ΅λλ€.
λͺ¨λ μ€ν 리μ
crewId: 1μ΄ μΆκ°λ κ²μ νμΈνμ΅λλ€. μ΄λ μ’μμ API μ°λμ μν λ³κ²½μ¬νκ³Ό μ λΆν©ν©λλ€.μ»΄ν¬λνΈμμ μ΄ μμ±μ΄ μ¬λ°λ₯΄κ² μ¬μ©λλμ§ νμΈνκΈ° μν΄ λ€μ μ€ν¬λ¦½νΈλ₯Ό μ€ννκ² μ΅λλ€:
Also applies to: 101-101, 144-144
π Scripts executed
The following scripts were executed for the analysis:
Script:
Length of output: 223
Script:
Length of output: 3064
Script:
Length of output: 3085