Skip to content

Commit

Permalink
Merge pull request #322 from Injaeeee/Next-정인재-Sprint11
Browse files Browse the repository at this point in the history
[정인재] Sprint11
  • Loading branch information
jyh0521 authored Aug 26, 2024
2 parents 7e58628 + ccc8f8b commit f850267
Show file tree
Hide file tree
Showing 29 changed files with 950 additions and 41 deletions.
7 changes: 4 additions & 3 deletions components/bestboarditemlist.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import favorite from "@/images/favorite.png";
import { BoardItemProps, BoardItemListProps } from "@/interfaces/boardItem";
import Link from "next/link";
import { FormatDate } from "@/pages/util/formatDate";
import defaultImage from "@/images/img_default.png";

export default function BestBoardItemList({ boards }: BoardItemListProps) {
return (
Expand All @@ -24,12 +25,12 @@ function BestBoardItem({ board }: BoardItemProps) {
<BoardWrapper>
<TitleWrapper>
<BoardTitle>{board.title}</BoardTitle>
{/* <Image
src={board.image}
<Image
src={board.image || defaultImage}
alt="BestBoardImage"
width={72}
height={72}
/> */}
/>
</TitleWrapper>
<WriterWrapper>
<WriterLeftElement>
Expand Down
3 changes: 2 additions & 1 deletion components/boarditemlist.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Image from "next/image";
import { BoardItemProps, BoardItemListProps } from "@/interfaces/boardItem";
import Link from "next/link";
import { FormatDate } from "@/pages/util/formatDate";
import defaultImage from "@/images/img_default.png";

export default function BoardItemList({ boards }: BoardItemListProps) {
return (
Expand All @@ -22,7 +23,7 @@ function BoardItem({ board }: BoardItemProps) {
<TitleWrapper>
<BoardTitle>{board.title}</BoardTitle>
<Image
src={board.image}
src={board.image || defaultImage}
alt="BestBoardImage"
width={72}
height={72}
Expand Down
10 changes: 6 additions & 4 deletions components/fileinput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ import styled from "styled-components";
import Image from "next/image";
import plusIcon from "@/images/ic_plus.svg";
import { FileInputType } from "@/interfaces/article";
import { postImage } from "@/pages/util/api";

function FileInput({ value, onChange }: FileInputType) {
function FileInput({ value, fileChange, previewChange }: FileInputType) {
const inputRef = useRef<HTMLInputElement | null>(null);
const [preview, setPreview] = useState<string | null>(null);

const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
const nextValue = e.target.files ? e.target.files[0] : null;
onChange(nextValue);
fileChange(nextValue);
};

const handleClearClick = () => {
Expand All @@ -22,7 +23,7 @@ function FileInput({ value, onChange }: FileInputType) {
inputNode.value = "";

setPreview(null);
onChange(null);
fileChange(null);
};

useEffect(() => {
Expand All @@ -31,7 +32,8 @@ function FileInput({ value, onChange }: FileInputType) {
const nextpreview = URL.createObjectURL(value);

setPreview(nextpreview);
console.log(nextpreview);
previewChange(nextpreview);
// console.log(nextpreview);

// 메모리 누수를 방지하기 위해 URL 객체를 해제
return () => {
Expand Down
6 changes: 5 additions & 1 deletion components/primarybutton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ export default function PrimaryButton({
disabled: disabled = false,
onClick,
}: ButtonProps) {
return <Button disabled={disabled}>{children}</Button>;
return (
<Button disabled={disabled} onClick={onClick}>
{children}
</Button>
);
}

const Button = styled.button<{ disabled: boolean }>`
Expand Down
45 changes: 45 additions & 0 deletions components/primaryinput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { ChangeEventHandler, FocusEventHandler } from "react";
import styled from "styled-components";

interface InputType {
id: string;
name: string;
type: string;
placeholder: string;
onChange?: ChangeEventHandler<HTMLInputElement>;
onBlur?: FocusEventHandler<HTMLInputElement>;
hasError?: boolean;
}

export default function PrimaryInput({
id,
name,
type,
placeholder,
onChange,
onBlur,
hasError,
}: InputType) {
return (
<Input
id={id}
name={name}
type={type}
placeholder={placeholder}
onChange={onChange}
onBlur={onBlur}
hasError={hasError}
/>
);
}

const Input = styled.input<{ hasError?: boolean }>`
width: 100%;
border-radius: 12px;
padding: 16px 24px;
background-color: #f3f4f6;
color: #9ca3af;
font-size: 16px;
font-weight: 400;
border: ${({ hasError }) => (hasError ? "1px solid red" : "none")};
`;
66 changes: 62 additions & 4 deletions components/topbar.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,48 @@
import PrimaryButton from "./primarybutton";
import pandaLogo from "@/images/logo.png";
import mobilePandaLogo from "@/images/mobilelogo.png";
import userIcon from "@/images/user.png";
import Link from "next/link";
import Image from "next/image";
import styled from "styled-components";
import { isLoggedIn } from "@/pages/util/api";
import { useEffect, useState } from "react";
import PrimaryButton from "./primarybutton";

export default function Topbar() {
const [isLogin, setIsLogin] = useState(false);
const [isOpen, setIsOpen] = useState(false);

useEffect(() => {
if (isLoggedIn() == true) {
setIsLogin(true);
} else {
setIsLogin(false);
}
}, [isLogin]);

const handleLogClick = () => {
setIsOpen((prev) => !prev);
};

const handleLogoutClick = () => {
setIsLogin(false);
localStorage.removeItem("access_token");
localStorage.removeItem("refresh_token");
window.location.href = "/login"; // 로그아웃 후 리다이렉션
};

return (
<TopbarHeader>
<LeftElement>
<Link href="/">
<LogoWrapper>
<Image src={pandaLogo} alt="Panda Logo" className="desktop" />
<Image
src={pandaLogo}
alt="Panda Logo"
className="desktop"
width={153}
height={51}
/>
<Image
src={mobilePandaLogo}
alt="Mobile Panda Logo"
Expand All @@ -29,8 +59,18 @@ export default function Topbar() {
</Link>
</ButtonWrapper>
</LeftElement>
<Image src={userIcon} alt="userIcon" />
{/* <PrimaryButton>로그인</PrimaryButton> */}
{isLogin ? (
<LogOutWrapper onClick={handleLogClick}>
<Image src={userIcon} alt="userIcon" />
{isOpen && (
<LogOutButton onClick={handleLogoutClick}>로그아웃</LogOutButton>
)}
</LogOutWrapper>
) : (
<Link href="/login">
<PrimaryButton>로그인</PrimaryButton>
</Link>
)}
</TopbarHeader>
);
}
Expand Down Expand Up @@ -99,3 +139,21 @@ const LogoWrapper = styled.div`
}
}
`;

const LogOutWrapper = styled.div`
position: relative;
`;

const LogOutButton = styled.button`
position: absolute;
width: 139px;
height: 51px;
border: solid 1px #d1d5db;
border-radius: 8px;
padding: 16px 0;
margin-top: 50px;
margin-left: -130px;
font-size: 16px;
font-weight: 400;
background-color: #ffffff;
`;
Binary file added images/Img_home_01.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/Img_home_02.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/Img_home_03.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/Img_home_top.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions images/ic_eyeclose.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions images/ic_eyeopen.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/ic_google.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/ic_kakao.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/img_default.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified images/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/logo2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 3 additions & 2 deletions interfaces/article.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
export interface articleType {
title: string;
content: string;
image: string;
image: string | null;
}

export interface FileInputType {
value: File | null;
onChange: (file: File | null) => void;
fileChange: (file: File | null) => void;
previewChange: (preview: string | null) => void;
}
6 changes: 6 additions & 0 deletions interfaces/user.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export interface UserInfo {
email: string;
nickname?: string;
password: string;
passwordConfirmation?: string;
}
47 changes: 46 additions & 1 deletion lib/axios.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,52 @@
import axios from "axios";
import axios, { AxiosError } from "axios";

const instance = axios.create({
baseURL: " https://panda-market-api.vercel.app/",
});

// 요청 인터셉터
instance.interceptors.request.use(
(config) => {
// 요청이 가기 전에 할 작업
// 예: 인증 토큰 추가
const token = localStorage.getItem("access_token");
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => {
// 요청 에러 처리
return Promise.reject(error);
}
);

// 응답 인터셉터
instance.interceptors.response.use(
(response) => {
// 응답 데이터 처리
return response;
},
(error: AxiosError) => {
// 응답 에러 처리
if (axios.isAxiosError(error)) {
if (error.response) {
// 서버 응답이 있는 경우
console.error("서버 에러:", error.response.data);
alert("유효하지 않은 아이디 입니다.");
} else if (error.request) {
// 요청이 보내졌으나 응답이 없는 경우
console.error("요청 에러:", error.request);
} else {
// 에러를 발생시킨 요청 구성 문제
console.error("에러 구성:", error.message);
}
} else {
// Axios가 아닌 다른 에러
console.error("기타 에러:", error);
}
return Promise.reject(error);
}
);

export default instance;
9 changes: 8 additions & 1 deletion next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ const nextConfig = {
protocol: 'https',
hostname: 'sprint-fe-project.s3.ap-northeast-2.amazonaws.com',
},
{
protocol: 'http',
hostname: 'via.placeholder.com',
},
{
protocol: 'https',
hostname: 'flexible.img.hani.co.kr',
},
],
},
reactStrictMode: true,
Expand All @@ -22,7 +30,6 @@ const nextConfig = {
]
},


}

module.exports = nextConfig
11 changes: 9 additions & 2 deletions pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,22 @@ import type { AppProps } from "next/app";
import GlobalStyle from "@/styles/globalstyle";
import Topbar from "@/components/topbar";
import Head from "next/head";
import { useRouter } from "next/router";

export default function App({ Component, pageProps }: AppProps) {
const router = useRouter();

const isLoginPage =
router.pathname === "/login" || router.pathname === "/signup";

const isLandingPage = router.pathname === "/";
return (
<>
<Head>
<title>판다마켓</title>
</Head>
<GlobalStyle />
<Topbar />
<GlobalStyle isLoginPage={isLoginPage} isLandingPage={isLandingPage} />
{!isLoginPage && <Topbar />}
<Component {...pageProps} />
</>
);
Expand Down
Loading

0 comments on commit f850267

Please sign in to comment.