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
49 changes: 49 additions & 0 deletions public/icons/zip/123.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions public/icons/zip/22.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions src/api/booksnap.api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,18 @@ export const pickBook = async (bookId: string) => {
}
};

// 책 담기
export const deleteBook = async (bookId: string) => {
try {
const response = await instance.delete(`api/pick-book`, { data: { bookId: bookId } });
if (response.status == 200) {
return { success: true, message: '책 담기가 취소되었습니다!' };
}
} catch (error: any) {
console.log(error);
}
};

// 서점 검색
export const searchBookstore = async (query: string | null) => {
try {
Expand Down
2 changes: 2 additions & 0 deletions src/api/instance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ instance.interceptors.response.use(
if (accessToken && refreshToken) {
localStorage.setItem('accessToken', accessToken);
localStorage.setItem('refreshToken', refreshToken);
}
if (nickname) {
localStorage.setItem('nickname', nickname);
}
return response;
Expand Down
12 changes: 12 additions & 0 deletions src/api/login.api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,15 @@ export const getTempPw = async (email: string) => {
console.log(err);
}
};

// 로그아웃
export const logOut = async (refreshToken: string) => {
try {
const response = await instance.post('auth/logout', { refreshToken: refreshToken });
if (response.status === 200) {
return response.data;
}
} catch (err) {
console.log(err);
}
};
12 changes: 12 additions & 0 deletions src/api/mypage.api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import instance from './instance';

export const getMyBook = async () => {
try {
const response = await instance.get('/api/pick-book');
if (response.status == 200) {
return response.data;
}
} catch (err) {
console.log(err);
}
};
12 changes: 12 additions & 0 deletions src/api/zip.api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,15 @@ export const getTrendZip = async () => {
console.log(err);
}
};

// 해시태그 검색
export const getHashTag = async () => {
try {
const response = await instance.get('/api/bookstores/hashtag');
if (response.status === 200) {
return response.data;
}
} catch (err) {
console.log(err);
}
};
5 changes: 3 additions & 2 deletions src/components/Booksnap/BookInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ import { BookDetailInfo } from '../../model/booksnap.model';
import image from '../../../public/icons/book-snap/image.png';
interface BookInfoProps {
bookInfo: BookDetailInfo;
onClick: React.MouseEventHandler<HTMLDivElement>;

onClick?: React.MouseEventHandler<HTMLDivElement>;
}

const BookInfo = ({ bookInfo, onClick }: BookInfoProps) => {
const author = bookInfo.authors.join(', ');
return (
<div className="flex flex-col gap-4" onClick={onClick}>
<div className="flex flex-col items-center gap-4" onClick={onClick}>
<img
src={bookInfo.bookImageUrl == '' ? image : bookInfo.bookImageUrl}
className="w-20"
Expand Down
3 changes: 2 additions & 1 deletion src/components/Booksnap/WriteButton.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { HiPencil } from 'react-icons/hi2';
import { useNavigate } from 'react-router-dom';
import { protectedNavigate } from '../../utils/ProtectedNavigate';

const WriteButton = () => {
const nav = useNavigate();
Expand All @@ -9,7 +10,7 @@ const WriteButton = () => {
<div
className="absolute right-[14px] flex items-center gap-1 rounded-full bg-[#C0E0D8] p-4"
style={{ boxShadow: '0px 4px 4px 0px rgba(0, 0, 0, 0.25)' }}
onClick={() => nav('create/1')}
onClick={() => protectedNavigate(nav, 'create/1')}
>
<HiPencil className="h-7 w-7 fill-[#191919]" />
</div>
Expand Down
12 changes: 10 additions & 2 deletions src/components/Common/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,26 +31,34 @@ const Header = ({ title }: HeaderProps) => {
'/booksnap/create/2',
'/booksnap/create/indi/2',
'/booksnap/create/book',
'/mypage/book',
];
const showBackButton = showBackButtonPaths.includes(location.pathname);

const showCloseButtonPaths = ['/bookie', '/booksnap/create/indi/1', '/booksnap/create/1'];
const showCloseButton = showCloseButtonPaths.includes(location.pathname);

// 마이페이지만 헤더 글씨, 아이콘 흰색
const myPage = location.pathname.startsWith('/mypage');

return (
<div className="fixed left-0 right-0 top-0 m-auto w-full max-w-[500px]">
<div className={`flex items-center bg-bg px-2 py-3`}>
{showBackButton && (
<div className="flex cursor-pointer items-center justify-center p-2.5" onClick={handleGoBack}>
<FaAngleLeft size={24} className="fill-mint" />
<FaAngleLeft size={24} className={`${myPage ? 'fill-white' : 'fill-mint'}`} />
</div>
)}
{showCloseButton && (
<div className="flex cursor-pointer items-center justify-center p-2.5" onClick={handleClose}>
<IoCloseOutline size={30} className="stroke-mint" />
</div>
)}
<div className="text-mint flex-1 text-center text-[20px] font-medium tracking-[-0.8px]">{title}</div>
<div
className={`flex-1 text-center text-[20px] font-medium tracking-[-0.8px] ${myPage ? 'text-white' : 'text-mint'}`}
>
{title}
</div>
{showBackButton || showCloseButton ? <div className="w-11" /> : ''}
</div>
</div>
Expand Down
5 changes: 3 additions & 2 deletions src/components/Common/MenuBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const MenuBar = () => {
const nav = useNavigate();
const location = useLocation();
const [currentMenu, setCurrentMenu] = useState<string>('home');
const isLogin = localStorage.getItem('accessToken');

useEffect(() => {
const pathname = location.pathname;
Expand Down Expand Up @@ -48,8 +49,8 @@ const MenuBar = () => {
active: <SmartToyIcon sx={{ fontSize: 30, fill: '#E27451' }} />,
},
{
menu: 'My page',
name: 'mypage',
menu: isLogin ? 'My Page' : 'Login',
name: isLogin ? 'mypage' : 'login',
inactive: <Person2Icon sx={{ fontSize: 30, fill: '#9DB2CE' }} />,
active: <Person2Icon sx={{ fontSize: 30, fill: '#E27451' }} />,
},
Expand Down
17 changes: 14 additions & 3 deletions src/components/Home/BookReview.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
import { useEffect, useState } from 'react';
import { getReview } from '../../api/booksnap.api';
import ReviewBox from './ReviewBox';
import { BooksnapPreview } from '../../model/booksnap.model';

const BookReview = () => {
const [reviews, setReview] = useState<BooksnapPreview[]>([]);

useEffect(() => {
getReview('trend', 1).then((data) => {
setReview(data.data.booksnapPreview.slice(0, 3)); // 배열의 첫 3개만 저장
});
}, []);

return (
<div className="flex flex-col gap-5 p-5">
<div className="flex flex-col gap-[5px]">
Expand All @@ -11,9 +22,9 @@ const BookReview = () => {
{/* 가로 스크롤 가능한 영역 */}
<div className="mx-[-32px] overflow-x-auto px-[32px] scrollbar-hide">
<div className="flex gap-[10px] after:w-[20px] after:flex-shrink-0 after:content-['']">
<ReviewBox />
<ReviewBox />
<ReviewBox />
{reviews.map((review, index) => (
<ReviewBox reviews={review} key={index} />
))}
</div>
</div>
</div>
Expand Down
8 changes: 7 additions & 1 deletion src/components/Home/BookieBox.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import MenuBookIcon from '@mui/icons-material/MenuBook';
import Bookie from '../../../public/icons/home/bookie.png';
import { protectedNavigate } from '../../utils/ProtectedNavigate';
import { useNavigate } from 'react-router-dom';

const BookieBox = () => {
const nav = useNavigate();
return (
<div className="flex w-full flex-col gap-[5px] rounded-[20px] bg-green px-[10px] pt-[15px]">
<div
className="flex w-full flex-col gap-[5px] rounded-[20px] bg-green px-[10px] pt-[15px]"
onClick={() => protectedNavigate(nav, '/bookie')}
>
<MenuBookIcon sx={{ fontSize: 24, fill: '#E8EBC8' }} />
<h3 className="text-[14px] font-medium leading-[22px] text-white">도서 추천 메이트</h3>
<div>
Expand Down
2 changes: 1 addition & 1 deletion src/components/Home/MadeBy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const MadeBy = () => {
</div>
<div className="flex flex-col items-end p-[10px] text-body3 text-white">
<p>@yongaricode</p>
<p className="text-pink">용가리 먹방 시작~</p>
<p className="text-pink">용가리가 코드를 짠다~</p>
</div>
<div className="flex flex-col items-end p-[10px] text-body3 text-white">
<p>@hyuna</p>
Expand Down
11 changes: 7 additions & 4 deletions src/components/Home/PopularBox.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import MenuBookIcon from '@mui/icons-material/MenuBook';
import Bookie from '../../../public/icons/home/bookie.png';
import { useNavigate } from 'react-router-dom';
import Marker from '../../../public/icons/zip/markerHome.svg?react';

const PopularBox = () => {
const nav = useNavigate();
return (
<div className="flex w-full flex-col justify-center gap-[10px] rounded-[20px] bg-orange px-[10px] pt-[15px]">
<div
className="flex w-full flex-col justify-center gap-[10px] rounded-[20px] bg-orange px-[10px] pt-[15px]"
onClick={() => nav('/zip?search=우주소년')}
>
<Marker />
<h3 className="text-[14px] font-medium leading-[22px] text-white">ZIPZIP이들이 PICK한</h3>
<div className="w-[75%] border-y-[2px] border-solid py-[10px] text-[16px] font-bold leading-5 text-white">
이달의 인기 서점 <br />
“고요서사”
"우주소년"
</div>
</div>
);
Expand Down
6 changes: 4 additions & 2 deletions src/components/Home/Ranking.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { useEffect, useState } from 'react';
import { getTrendZip } from '../../api/zip.api';
import { useNavigate } from 'react-router-dom';

const Ranking = () => {
const nav = useNavigate();
const [bookstores, setBookstores] = useState([
'게으른 정원',
'고요서사',
Expand Down Expand Up @@ -30,7 +32,7 @@ const Ranking = () => {
{/* 왼쪽 열 */}
<div className="flex flex-col gap-4">
{left.map((bookstore, i) => (
<p key={i}>
<p key={i} onClick={() => nav(`/zip?search=${bookstore}`)}>
{i + 1}. {bookstore}
</p>
))}
Expand All @@ -39,7 +41,7 @@ const Ranking = () => {
{/* 오른쪽 열 */}
<div className="flex flex-col gap-4">
{right.map((bookstore, i) => (
<p key={i}>
<p key={i} onClick={() => nav(`/zip?search=${bookstore}`)}>
{i + 6}. {bookstore}
</p> // 6부터 시작
))}
Expand Down
3 changes: 3 additions & 0 deletions src/components/Home/RegionBox.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import LocationSearchingIcon from '@mui/icons-material/LocationSearching';
import { useNavigate } from 'react-router-dom';

interface RegionBoxProps {
text: string;
}

const RegionBox = ({ text }: RegionBoxProps) => {
const nav = useNavigate();
return (
<div
className={`p-[10px] ${text == '내 위치' ? 'bg-orange text-white' : 'bg-green text-[#544F4F]'} flex aspect-square flex-col gap-[15px] rounded-[10px]`}
onClick={() => nav(`/zip?search=${text}`)}
>
<LocationSearchingIcon />
<p>{text}</p>
Expand Down
6 changes: 5 additions & 1 deletion src/components/Home/ReportBookstore.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import sunglass from '../../../public/icons/home/sunglass.png';
import hand from '../../../public/icons/home/hand.png';
import toast from 'react-hot-toast';

const ReportBookstore = () => {
return (
<div className="bg-mint flex w-full items-center justify-center gap-[10px] rounded-[20px] px-[10px] py-[15px] text-body4">
<div
className="flex w-full items-center justify-center gap-[10px] rounded-[20px] bg-mint px-[10px] py-[15px] text-body4"
onClick={() => toast.error('아직 준비중인 서비스입니다')}
>
<div>
<p className="font-medium"> To. zipzip이들 </p>
<p>
Expand Down
13 changes: 9 additions & 4 deletions src/components/Home/ReportStore.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
import Vector from '../../../public/icons/home/Vector.svg?react';

const ReportStore = () => {
interface ReportStore {
onClick: () => void;
}

const ReportStore = ({ onClick }: ReportStore) => {
const name = localStorage.getItem('nickname');
return (
<div className="flex flex-col py-[10px]">
<div className="flex flex-col py-[10px]" onClick={onClick}>
<div className="flex flex-col gap-[5px] p-[10px]">
<div className="text-body1 font-bold">
<span className="text-green">서점ZIP에 없는 독립서점</span>
<span className="text-white">을</span>
<p className="text-white">제보해주세요!</p>
</div>
<p className="text-white">독서광시온님의 제보가 서점ZIP을 살려요!</p>
<p className="text-white">{name}님의 제보가 서점ZIP을 살려요!</p>
</div>
<div className="bg-mint flex w-full items-center justify-center gap-[20px] rounded-[20px] px-[10px] py-[15px] text-body4">
<div className="flex w-full items-center justify-center gap-[20px] rounded-[20px] bg-mint px-[10px] py-[15px] text-body4">
<p className="text-[14px] font-medium text-[#302D2D]">
더 나은 서점ZIP 서비스를 위해 <br /> 독립 서점 제보하러 가기
</p>
Expand Down
18 changes: 12 additions & 6 deletions src/components/Home/ReviewBox.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
const ReviewBox = () => {
import { BooksnapPreview } from '../../model/booksnap.model';

interface ReviewBoxProps {
reviews: BooksnapPreview;
}

const ReviewBox = ({ reviews }: ReviewBoxProps) => {
return (
<div className="w-[165px] flex-shrink-0 overflow-hidden rounded-[20px] bg-bg_2 text-white shadow-md">
{/* 상단 텍스트 */}
<div className="px-4 pt-4 text-[16px]">독서왕용가리</div>
<div className="px-4 pt-4 text-[16px]">{reviews.userName}</div>

{/* 배경 이미지 영역 */}
<div className="relative mt-2 h-[190px] w-full overflow-hidden rounded-b-[20px]">
{/* 흐릿한 배경 이미지 */}
<div
className="absolute inset-0 bg-cover bg-center blur-sm"
style={{
backgroundImage: `url(https://search1.kakaocdn.net/thumb/R120x174.q85/?fname=http%3A%2F%2Ft1.daumcdn.net%2Flbook%2Fimage%2F1558147%3Ftimestamp%3D20221210154041)`,
backgroundImage: `url(${reviews.bookInfo.bookImageUrl})`,
}}
/>

Expand All @@ -21,12 +27,12 @@ const ReviewBox = () => {
<div className="relative z-10 flex h-full flex-col justify-end p-4">
<p className="break-keep text-[18px] font-bold">
“ <br />
사이키쿠스오가 될래...
{reviews.review.length > 15 ? `${reviews.review.slice(0, 15)}...` : reviews.review}
<br />”
</p>
<div className="text-green-200 mt-2 flex items-center justify-between text-[12px]">
<span>수레바퀴 아래서</span>
<span>★ 4</span>
<span>{reviews.bookInfo.title}</span>
<span>★ {reviews.rating}</span>
</div>
</div>
</div>
Expand Down
3 changes: 2 additions & 1 deletion src/components/Modal/AddBookstoreModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@ const AddBookstoreModal = ({ setModalOpen, name }: ModalProps) => {
const [closeTime, setCloseTime] = useState('');
const [feature, setFeature] = useState('');
const [detail, setDetail] = useState('');
const nickname = localStorage.getItem('nickname');

return (
<div className="flex w-[320px] flex-col items-center justify-center gap-6 rounded-2xl bg-white p-4">
<div className="flex w-full flex-col">
<p className="text-[18px] font-semibold">독립서점 제보하기</p>
<p className="text-[14px] text-gray_2">용가리님만 알고있는 독립서점을 제보해주세요!</p>
<p className="text-[14px] text-gray_2">{nickname}님만 알고있는 독립서점을 제보해주세요!</p>
</div>
<LabeledInput
label="서점 이름"
Expand Down
Loading