diff --git a/api/wishes/getPresignedURL.ts b/api/wishes/getPresignedURL.ts new file mode 100644 index 00000000..9ecce474 --- /dev/null +++ b/api/wishes/getPresignedURL.ts @@ -0,0 +1,17 @@ +import { client } from '../common/axios'; +import PATH from '../common/path'; + +export const getPresignedURL = async (fileName: string | undefined) => { + const accessToken = localStorage.getItem('accessToken'); + const data = await client.get( + `${PATH.API}/${PATH.V1}/${PATH.FILE}?${PATH.FILE_NAME}=${fileName}`, + { + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${accessToken}`, + }, + }, + ); + + return data; +}; diff --git a/api/wishes/uploadPresignedURL.ts b/api/wishes/uploadPresignedURL.ts new file mode 100644 index 00000000..7af5fff1 --- /dev/null +++ b/api/wishes/uploadPresignedURL.ts @@ -0,0 +1,13 @@ +import axios from 'axios'; + +export const uploadPresignedURL = async (signedURL: string, file: File | Blob | null) => { + console.log(decodeURIComponent(signedURL)); + const data = await axios.put(signedURL, file, { + headers: { + 'Content-Type': file?.type, + }, + }); + + console.log(data); + return data; +}; diff --git a/components/common/mainHeader.tsx b/components/common/mainHeader.tsx index 46620ebd..3613b52c 100644 --- a/components/common/mainHeader.tsx +++ b/components/common/mainHeader.tsx @@ -24,7 +24,7 @@ export default function MainHeader(props: MainHeaderProps) { const Styled = { Container: styled.div` display: flex; - margin: 2rem 0 0; + margin: 2rem 0 0rem; `, SideContainer: styled.div` diff --git a/components/common/progressBar.tsx b/components/common/progressBar.tsx index aa415e4e..ca830bfe 100644 --- a/components/common/progressBar.tsx +++ b/components/common/progressBar.tsx @@ -19,8 +19,8 @@ export default function ProgressBar(props: ProgressBarProps) { const Styled = { Container: styled.div<{ vertical: boolean }>` - width: 27rem; - height: 1rem; + width: 1rem; + height: 27rem; background-color: ${theme.colors.pastel_blue}; diff --git a/components/main/cake.tsx b/components/main/cake.tsx index 77b342b0..1fd98ca6 100644 --- a/components/main/cake.tsx +++ b/components/main/cake.tsx @@ -40,53 +40,49 @@ export default function Cake(props: CakeProps) { const CakeImg = () => (wishStatus === 'end' ? MainEndCakeImg : PillCakeImg); return ( - <> - - - - 말풍선 - - 케이크 - - - {wishStatus === 'while' || wishStatus === 'end' ? ( - - 모인 케이크 보러가기 {'>'} - - ) : ( - 모인 케이크 금액 - )} - - 총 {priceData}원 - - - {/* 수정 필요 */} - - {percent && } - - {percent}% - {percent && } - - - - - {(wishStatus === 'while' || wishStatus === 'end') && ( - - 펀딩 종료 후 3일내에 송금이 완료됩니다. -
- 계좌번호를 확인해주세요! -
- )} -
- + + + + 말풍선 + + 케이크 + + + {wishStatus === 'while' || wishStatus === 'end' ? ( + + 모인 케이크 보러가기 {'>'} + + ) : ( + 모인 케이크 금액 + )} + + 총 {priceData}원 + + + + {percent}% + + + + + + + + + {(wishStatus === 'while' || wishStatus === 'end') && ( + + 펀딩 종료 후 3일내에 송금이 완료됩니다. +
+ 계좌번호를 확인해주세요! +
+ )} +
); } const Styled = { Container: styled.div` margin: 9rem 0 0; - display: flex; - flex-direction: column; `, ImageContainer: styled.div` @@ -96,9 +92,6 @@ const Styled = { AboutButton: styled.button` width: 100%; - display: flex; - justify-content: center; - align-items: center; margin: 0 0 1rem; ${theme.fonts.headline24_100}; color: ${theme.colors.main_blue}; @@ -122,37 +115,70 @@ const Styled = { `, CenterContainer: styled.div` + width: 100%; display: flex; - justify-content: space-between; - align-items: flex-start; + justify-content: right; + align-items: center; + padding: 0 1rem 0 0; `, ContentContainer: styled.div` - width: 100%; + display: flex; + flex-direction: column; + justify-content: center; `, - // progress bar - BarContainer: styled.div``, - ProgressBox: styled.div` height: 27rem; display: flex; flex-direction: column; + justify-content: right; `, PercentWrapper: styled.div<{ percent: number }>` height: ${(props) => props.percent}%; - /* ${(props) => + ${(props) => props.percent > 3 && css` - margin-left: -1.7rem; - `} */ + margin-top: -2rem; + `} `, Percent: styled.div` ${theme.fonts.button16}; color: ${theme.colors.main_blue}; margin-top: auto; + margin-right: 0.5rem; + `, + + // Progressbar + BarContainer: styled.div` + width: 1rem; + height: 27rem; + + background-color: ${theme.colors.pastel_blue}; + + border-bottom-right-radius: 5rem; + border-bottom-left-radius: 5rem; + border-top-right-radius: 5rem; + border-top-left-radius: 5rem; + + -ms-transform: rotate(180deg); /* IE 9 */ + -webkit-transform: rotate(180deg); /* Chrome, Safari, Opera */ + transform: rotate(180deg); + `, + + Progress: styled.div<{ percent: number }>` + height: ${(props) => props.percent}%; + max-height: 100%; + width: 100%; + + background-color: ${theme.colors.main_blue}; + + border-bottom-right-radius: 5rem; + border-bottom-left-radius: 5rem; + border-top-right-radius: 5rem; + border-top-left-radius: 5rem; `, }; diff --git a/components/mypage/letters/[id].tsx b/components/mypage/letters/[id].tsx index b6169a48..d5d4db33 100644 --- a/components/mypage/letters/[id].tsx +++ b/components/mypage/letters/[id].tsx @@ -9,8 +9,6 @@ import { useEffect, useState } from 'react'; import { ArrowLeftIc, ArrowRightIc } from '@/public/assets/icons'; import { useRouter } from 'next/router'; import { useGetCakesLetters } from '@/hooks/queries/letters/useGetCakeLetters'; -import { useRecoilValue } from 'recoil'; -import { CakesCountData } from '@/recoil/cakesCountData'; import { CAKE_LIST } from '@/constant/cakeList'; export default function LettersContainer() { @@ -25,11 +23,11 @@ export default function LettersContainer() { setCakeId(router.query.cakeId); }, [router.isReady]); + // 케이크 정보, 개수 + const { cake } = router.query; const cakeData = CAKE_LIST.find((cake) => cake.cakeNumber === Number(cakeId)); - const selectedCake = useRecoilValue(CakesCountData).find( - (cake) => cake.cakeId === Number(cakeId), - ); + // 편지 const { lettersData, lettersSum } = useGetCakesLetters(wishId, cakeId); const handleNameBoxClick = (index: number) => { @@ -60,7 +58,7 @@ export default function LettersContainer() { fonts={theme.fonts.headline20} image={cakeData ? cakeData.smallImage : ''} cakeName={cakeData?.name} - cakeNum={selectedCake?.count} + cakeNum={Number(cake)} /> diff --git a/components/mypage/letters/lettersMain.tsx b/components/mypage/letters/lettersMain.tsx index 984c5b9d..b76aec8c 100644 --- a/components/mypage/letters/lettersMain.tsx +++ b/components/mypage/letters/lettersMain.tsx @@ -43,7 +43,16 @@ export default function LettersMainContainer() { const handleMoveToLetters = (cakeId: number) => { - router.push(`/mypage/letters/${wishId}/${cakeId}`); + const cake = CAKE_LIST.find(cake => cake.cakeNumber === cakeId); + + if (cake) { + router.push({ + pathname: `/mypage/letters/${wishId}/${cakeId}`, + query: { + cake: getCakeNum(cake.cakeNumber, cakesCount) + }, + }); + } }; const title = ( diff --git a/constant/path.ts b/constant/path.ts index 1ff7db1d..aad224fd 100644 --- a/constant/path.ts +++ b/constant/path.ts @@ -16,6 +16,8 @@ const PATH = { USER: 'user', ACCOUNT: 'account', PROGRESS: 'progress', + FILE: 'file', + FILE_NAME: 'fileName', PUBLIC: 'public', }; diff --git a/constant/queryKey.ts b/constant/queryKey.ts index 5413b26e..baf3f1ed 100644 --- a/constant/queryKey.ts +++ b/constant/queryKey.ts @@ -1,6 +1,4 @@ -import { QueryKeyType } from '@/types/queryKeyType'; - -export const QUERY_KEY: QueryKeyType = { +export const QUERY_KEY = { ITEM_DATA: 'itemData', WISHES_DATA: 'wishesData', PAYREADY: 'payReady', @@ -12,4 +10,5 @@ export const QUERY_KEY: QueryKeyType = { CAKE_LETTERS: 'cakeLetters', WISH_LINKS: 'wishLinks', ONE_WISH: 'oneWish', + PRE_SIGNED_URL: 'preSignedURL', }; diff --git a/hooks/queries/letters/useGetCakesCount.ts b/hooks/queries/letters/useGetCakesCount.ts index ae2b4b48..93f3735b 100644 --- a/hooks/queries/letters/useGetCakesCount.ts +++ b/hooks/queries/letters/useGetCakesCount.ts @@ -1,20 +1,20 @@ import { useQuery } from 'react-query'; import { QUERY_KEY } from '@/constant/queryKey'; import { getCakesCount } from '@/api/letters/getCakesCount'; -import { CakesCountData } from '@/recoil/cakesCountData'; -import { useSetRecoilState } from 'recoil'; +// import { CakesCountData } from '@/recoil/cakesCountData'; +// import { useSetRecoilState } from 'recoil'; import { useState } from 'react'; export function useGetCakesCount(wishId: string | string[] | undefined) { const [total, setTotal] = useState(0); - const setCakesCountData = useSetRecoilState(CakesCountData); + // const setCakesCountData = useSetRecoilState(CakesCountData); const { data: cakesCount } = useQuery( QUERY_KEY.CAKES_COUNT, async () => getCakesCount(wishId), { onSuccess: (data) => { - setCakesCountData(data); + // setCakesCountData(data); if (Array.isArray(data)) { const cakesTotal = calculateTotal(data.map((cake: { count: any; }) => cake.count)); setTotal(cakesTotal); diff --git a/hooks/wishes/useUploadItemInfo.ts b/hooks/wishes/useUploadItemInfo.ts new file mode 100644 index 00000000..c6d1e503 --- /dev/null +++ b/hooks/wishes/useUploadItemInfo.ts @@ -0,0 +1,44 @@ +import { getPresignedURL } from '@/api/wishes/getPresignedURL'; +import { uploadPresignedURL } from '@/api/wishes/uploadPresignedURL'; +import { QUERY_KEY } from '@/constant/queryKey'; +import { useEffect, useState } from 'react'; +import { useMutation, useQuery } from 'react-query'; + +export default function useUploadItemInfo() { + const [imageFile, setImageFile] = useState(null); + const [previewImage, setPreviewImage] = useState(''); + const [preSignedURL, setPreSignedURL] = useState(''); + + const { data } = useQuery(QUERY_KEY.PRE_SIGNED_URL, () => getPresignedURL(imageFile?.name), { + enabled: imageFile !== null && imageFile?.name !== '', + }); + + useEffect(() => { + if (data?.data?.success) { + mutate(); + } + }, [data]); + + const { mutate } = useMutation(() => uploadPresignedURL(data?.data?.data?.signedUrl, imageFile), { + onSuccess: () => { + // setPreSignedURL() + }, + }); + + console.log(data); + + function uploadImageFile(e: React.ChangeEvent) { + const imageFile = e.target.files && e.target.files[0]; + + if (imageFile) { + setImageFile(imageFile); + const reader = new FileReader(); + imageFile && reader.readAsDataURL(imageFile); + reader.onloadend = () => { + setPreviewImage(reader.result); + }; + } + } + + return { imageFile, previewImage, setPreviewImage, uploadImageFile }; +} diff --git a/hooks/wishes/useWisehsStep.tsx b/hooks/wishes/useWisehsStep.ts similarity index 100% rename from hooks/wishes/useWisehsStep.tsx rename to hooks/wishes/useWisehsStep.ts diff --git a/recoil/cakesCountData.ts b/recoil/cakesCountData.ts deleted file mode 100644 index 7c026b1d..00000000 --- a/recoil/cakesCountData.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { CakesCountType } from '@/types/letters/cakesCountType'; -import { atom } from 'recoil'; - -export const CakesCountData = atom({ - key: 'CakesCount', - default: - [ - { - cakeId: 0, - count: 0, - } - ], -}); diff --git a/types/letters/cakesCountType.ts b/types/letters/cakesCountType.ts deleted file mode 100644 index 5d0f30ac..00000000 --- a/types/letters/cakesCountType.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface CakesCountType { - cakeId: number; - count: number; -} - diff --git a/types/queryKeyType.ts b/types/queryKeyType.ts deleted file mode 100644 index 10270b02..00000000 --- a/types/queryKeyType.ts +++ /dev/null @@ -1,13 +0,0 @@ -export interface QueryKeyType { - ITEM_DATA: string; - WISHES_DATA: string; - PAYREADY: string; - PG_TOKEN: string; - USER: string; - ACCOUNT: string; - PROGRESS: string; - CAKES_COUNT: string; - CAKE_LETTERS: string; - WISH_LINKS: string; - ONE_WISH: string; -}