-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #48 from JECT-Study/feature/artwork-detail
[TASK-84, TASK-85] feat, style: 상세 페이지 우측 버튼 그룹 및 관련 모달 컴포넌트 구현
- Loading branch information
Showing
28 changed files
with
826 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import { isAxiosError } from 'axios'; | ||
|
||
import { ARTWORK } from '@/constants/API'; | ||
import { | ||
COMMON_ERROR_MESSAGE, | ||
LIKE_ERROR_MESSAGE, | ||
} from '@/constants/errorMessage'; | ||
import { ErrorResponseType } from '@/types/errorResponse'; | ||
|
||
import { authorizedClient } from '..'; | ||
|
||
const deleteArtworkLike = async (postId: number) => { | ||
try { | ||
const response = await authorizedClient.delete(ARTWORK.artworkLike(postId)); | ||
|
||
if (response.status === 204) { | ||
return true; | ||
} else { | ||
throw new Error('좋아요 취소 요청 실패'); | ||
} | ||
} catch (error) { | ||
if (isAxiosError<ErrorResponseType<null>>(error) && error.response) { | ||
const { code } = error; | ||
|
||
if (code) { | ||
console.error(LIKE_ERROR_MESSAGE[code]); | ||
throw new Error(LIKE_ERROR_MESSAGE[code]); | ||
} else { | ||
console.error(COMMON_ERROR_MESSAGE.UNKNOWN_ERROR); | ||
throw new Error(COMMON_ERROR_MESSAGE.UNKNOWN_ERROR); | ||
} | ||
} else { | ||
console.error(COMMON_ERROR_MESSAGE.NETWORK_ERROR); | ||
throw new Error(COMMON_ERROR_MESSAGE.NETWORK_ERROR); | ||
} | ||
} | ||
}; | ||
|
||
export default deleteArtworkLike; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { isAxiosError } from 'axios'; | ||
|
||
import { ARTWORK } from '@/constants/API'; | ||
import { | ||
COMMON_ERROR_MESSAGE, | ||
LIKE_ERROR_MESSAGE, | ||
} from '@/constants/errorMessage'; | ||
import { ErrorResponseType } from '@/types/errorResponse'; | ||
|
||
import { authorizedClient } from '..'; | ||
|
||
const postArtworkLike = async (postId: number) => { | ||
try { | ||
const response = await authorizedClient.post<null>( | ||
ARTWORK.artworkLike(postId), | ||
); | ||
|
||
if (response.status === 204) { | ||
return true; | ||
} else { | ||
throw new Error('좋아요 요청 실패'); | ||
} | ||
} catch (error) { | ||
if (isAxiosError<ErrorResponseType<null>>(error) && error.response) { | ||
const { code } = error; | ||
|
||
if (code) { | ||
console.error(LIKE_ERROR_MESSAGE[code]); | ||
throw new Error(LIKE_ERROR_MESSAGE[code]); | ||
} else { | ||
console.error(COMMON_ERROR_MESSAGE.UNKNOWN_ERROR); | ||
throw new Error(COMMON_ERROR_MESSAGE.UNKNOWN_ERROR); | ||
} | ||
} else { | ||
console.error(COMMON_ERROR_MESSAGE.NETWORK_ERROR); | ||
throw new Error(COMMON_ERROR_MESSAGE.NETWORK_ERROR); | ||
} | ||
} | ||
}; | ||
|
||
export default postArtworkLike; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { COLLECTION } from '@/constants/API'; | ||
import { CollectionType } from '@/types/collection'; | ||
|
||
import { authorizedClient } from '..'; | ||
|
||
const getAllCollectionList = async () => { | ||
try { | ||
const { data } = await authorizedClient.get<{ | ||
collections: CollectionType[]; | ||
}>(COLLECTION.allCollectionsList); | ||
|
||
return data; | ||
} catch (error) {} | ||
}; | ||
|
||
export default getAllCollectionList; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import { isAxiosError } from 'axios'; | ||
|
||
import { COLLECTION } from '@/constants/API'; | ||
import { | ||
COLLECTION_ADD_ARTWORK_ERROR_MESSAGE, | ||
COMMON_ERROR_MESSAGE, | ||
} from '@/constants/errorMessage'; | ||
import { ErrorResponseType } from '@/types/errorResponse'; | ||
|
||
import { authorizedClient } from '..'; | ||
|
||
interface PostCollectionAddArtworkProps { | ||
collectionId: number; | ||
postId: number; | ||
} | ||
|
||
const postCollectionAddArtwork = async ({ | ||
collectionId, | ||
postId, | ||
}: PostCollectionAddArtworkProps) => { | ||
try { | ||
const response = await authorizedClient.post<null>( | ||
COLLECTION.collectionAddArtwork(collectionId, postId), | ||
); | ||
|
||
if (response.status === 201) { | ||
return true; | ||
} else { | ||
throw new Error('컬랙션 내 작품 추가 요청 실패'); | ||
} | ||
} catch (error) { | ||
if (isAxiosError<ErrorResponseType<null>>(error) && error.response) { | ||
const { code } = error; | ||
|
||
if (code) { | ||
console.error(COLLECTION_ADD_ARTWORK_ERROR_MESSAGE[code]); | ||
throw new Error(COLLECTION_ADD_ARTWORK_ERROR_MESSAGE[code]); | ||
} else { | ||
console.error(COMMON_ERROR_MESSAGE.UNKNOWN_ERROR); | ||
throw new Error(COMMON_ERROR_MESSAGE.UNKNOWN_ERROR); | ||
} | ||
} else { | ||
console.error(COMMON_ERROR_MESSAGE.NETWORK_ERROR); | ||
throw new Error(COMMON_ERROR_MESSAGE.NETWORK_ERROR); | ||
} | ||
} | ||
}; | ||
|
||
export default postCollectionAddArtwork; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { COLLECTION } from '@/constants/API'; | ||
|
||
import { authorizedClient } from '..'; | ||
|
||
export interface PostCreateColleactionProps { | ||
name: string; | ||
isPrivate: boolean; | ||
} | ||
|
||
const postCreateCollection = async ({ | ||
name, | ||
isPrivate, | ||
}: PostCreateColleactionProps) => { | ||
const response = await authorizedClient.post(COLLECTION.collection, { | ||
name, | ||
status: isPrivate ? 'PRIVATE' : 'PUBLIC', | ||
}); | ||
|
||
return response.status === 201; | ||
}; | ||
|
||
export default postCreateCollection; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
'use client'; | ||
|
||
import { useEffect, useState } from 'react'; | ||
import { useStore } from 'zustand'; | ||
|
||
import Icon from '@/components/Icon/Icon'; | ||
import CollectionModal from '@/components/Modal/CollectionModal'; | ||
import useToggleLike from '@/hooks/serverStateHooks/useToggleLike'; | ||
import modalStore from '@/stores/modalStore'; | ||
import { ArtworkPostSocialInfoType } from '@/types'; | ||
|
||
import ShareModal from '../Modal/ShareModal'; | ||
|
||
interface ButtonGroupProps { | ||
socialInfo: ArtworkPostSocialInfoType; | ||
} | ||
|
||
const ButtonGroup = ({ | ||
socialInfo: { | ||
postId, | ||
nickname, | ||
title, | ||
likeCount: initialLikeCount, | ||
isLiked: initialIsLiked, | ||
}, | ||
}: ButtonGroupProps) => { | ||
const { openModal } = useStore(modalStore); | ||
const [blockButton, setBlockButton] = useState(false); | ||
|
||
const { | ||
mutate: toggleLike, | ||
setLikeStatus, | ||
isLiked, | ||
likeCount, | ||
} = useToggleLike({ | ||
isLiked: initialIsLiked, | ||
likeCount: initialLikeCount, | ||
}); | ||
|
||
const openCollectionModal = () => { | ||
openModal({ | ||
modalSize: 'lg', | ||
contents: <CollectionModal />, | ||
}); | ||
}; | ||
|
||
const openShareModal = () => { | ||
openModal({ | ||
modalSize: 'md', | ||
contents: <ShareModal nickname={nickname} title={title} />, | ||
}); | ||
}; | ||
|
||
const handleClickLikeToggle = () => { | ||
setBlockButton(true); | ||
toggleLike(postId); | ||
setBlockButton(false); | ||
}; | ||
|
||
useEffect(() => { | ||
setLikeStatus({ | ||
isLiked: initialIsLiked, | ||
likeCount: initialLikeCount, | ||
}); | ||
}, [initialLikeCount, initialIsLiked]); | ||
|
||
return ( | ||
<div className='tablet:absolute top-0 left-full tablet:w-[77px] w-content tablet:h-full tablet:ml-[30px] button-s text-center'> | ||
<div className='sticky flex tablet:flex-col gap-[40px] top-[100px]'> | ||
<div className='flex flex-col items-center gap-[10px]'> | ||
<button | ||
className='flex flex-col justify-center items-center tablet:gap-[3px] tablet:w-full w-[57px] rounded-full bg-gray-800 aspect-square active:bg-[#3E3B43]' | ||
onClick={handleClickLikeToggle} | ||
disabled={blockButton} | ||
> | ||
<Icon | ||
name={isLiked ? 'HeartFilled' : 'Heart'} | ||
size='l' | ||
className={isLiked ? 'text-[#FF4548]' : 'text-white'} | ||
/> | ||
<p>{likeCount}</p> | ||
</button> | ||
<p>좋아요</p> | ||
</div> | ||
<div className='flex flex-col items-center gap-[10px]'> | ||
<button | ||
className='flex flex-col justify-center items-center tablet:gap-[3px] tablet:w-full w-[57px] rounded-full bg-gray-800 aspect-square active:bg-[#3E3B43]' | ||
onClick={openShareModal} | ||
> | ||
<Icon name='AlternateShare' size='l' /> | ||
</button> | ||
<p>공유하기</p> | ||
</div> | ||
<div className='flex flex-col items-center gap-[10px]'> | ||
<button | ||
className='flex flex-col justify-center items-center tablet:gap-[3px] tablet:w-full w-[57px] rounded-full bg-gray-800 aspect-square active:bg-[#3E3B43]' | ||
onClick={openCollectionModal} | ||
> | ||
<Icon name='Bookmark' size='l' /> | ||
</button> | ||
<p>저장하기</p> | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
export default ButtonGroup; |
Oops, something went wrong.