Skip to content
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

Next 엄성민 - 스프린트 미션 8 #55

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
5e8f404
docs: update README.md
shyjnnn Oct 14, 2024
4874fef
feat: add: auto-labeling and assignee for PRs
shyjnnn Oct 14, 2024
f375c0d
Initial commit from Create Next App
eomsung Jan 10, 2025
f42d8be
wip
eomsung Jan 13, 2025
f580baf
readme update
eomsung Jan 13, 2025
9ed97eb
wip
eomsung Jan 13, 2025
a0def70
Merge branch 'main' of https://github.com/eomsung/4-sprint-mission-fe…
eomsung Jan 13, 2025
2afffe7
test
eomsung Jan 13, 2025
78a9246
tst
eomsung Jan 13, 2025
4620060
make freeBoard page
eomsung Jan 13, 2025
e96ead8
add articlepage, add comment function
eomsung Jan 13, 2025
c02cdf1
add button active
eomsung Jan 13, 2025
520590a
add create article
eomsung Jan 13, 2025
59529d3
add edit/delete function in artcle
eomsung Jan 14, 2025
a72aed8
add edit/delete comment function
eomsung Jan 14, 2025
3d4afc3
add responsive css
eomsung Jan 14, 2025
806ce0d
change baseURL
eomsung Jan 14, 2025
1770d3d
edit
eomsung Jan 14, 2025
4abfb8e
add cancel button in comment edit
eomsung Jan 14, 2025
12d7985
wip homepage
eomsung Jan 14, 2025
9c1afc7
change baseURL
eomsung Jan 14, 2025
d9b473f
feat: mainpage
eomsung Jan 15, 2025
98196eb
add loginpage ui
eomsung Jan 15, 2025
2ac74c5
refactoring : change the name freemarket to artocles
eomsung Jan 15, 2025
47a340b
refactor
eomsung Jan 15, 2025
ad6016a
refactor
eomsung Jan 15, 2025
d3aea30
add windowsize hook
eomsung Jan 15, 2025
f0d87b2
add windowsize hook
eomsung Jan 15, 2025
323c106
edit useDivicesize
eomsung Jan 15, 2025
f935598
edit baseurl
eomsung Jan 21, 2025
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
4 changes: 4 additions & 0 deletions .github/pull-request-template.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
### 기본

- [x]
<<<<<<< HEAD
- [테스트s]
=======
- []
>>>>>>> upstream/next-엄성민
- []

### 심화
Expand Down
41 changes: 41 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*

# env files (can opt-in for committing if needed)
.env*

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,11 @@ _위 이미지는 판다마켓의 대표 이미지입니다._ 📸
- **스프린트 미션 8부터** 시작하는 프론트엔드 내용을 포함하고 있어요.
- 만약 스프린트 미션 9부터 프론트엔드 코드를 React가 아닌 Next로 구현하고 싶다면 next 브랜치를 사용해요.

<<<<<<< HEAD
> _스프린트 미션 내 백엔드 요구사항은 [백엔드 레포지토리](https://github.com/codeit-sprint-fullstack/4-sprint-mission-be)의 브랜치에서 관리해주세요_
=======
> _스프린트 미션 내 백엔드 요구사항은 [백엔드 레포지토리](https://github.com/codeit-sprint-fullstack/2-Sprint-mission-Be)의 브랜치에서 관리해주세요_
>>>>>>> upstream/next-엄성민

---

Expand Down
101 changes: 101 additions & 0 deletions api/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import axios from "axios";

// const baseURL = "http://localhost:3100";
const baseURL = "https://four-sprint-mission-be-1.onrender.com";

const client = axios.create({
baseURL,
});

// 게시글 관련 api
const getArticles = async (keyword = "", order = "recent") => {
const options = {
params: {
keyword,
orderBy: order,
},
};
const url = `/article`;
const response = await client.get(url, options);
const data = response.data;
return data;
};

const getArticle = async (id) => {
const url = `/article/${id}`;
const response = await client.get(url);
const data = response.data;
return data;
};

const createArticle = async (newArticle) => {
const url = `/article`;
const response = await client.post(url, newArticle);
const data = response.data;
return data;
};

const deleteArticle = async (id) => {
const url = `/article/${id}`;
const response = await client.delete(url);
const data = response.data;
return data;
};

const patchArticle = async (id, article) => {
const url = `/article/${id}`;
const response = await client.patch(url, article);
const data = response.data;
return data;
};

const createComment = async (id, content) => {
const url = `/article/${id}/comment`;
const response = await client.post(url, { content });
const data = response.data;
return data;
};

const getComments = async (id) => {
const url = `article/${id}/comments`;
const response = await client.get(url);
const data = response.data;
return data;
};

const deleteComment = async (id) => {
const url = `article/${id}/comment`;
const response = await client.delete(url);
const data = response.data;
return data;
};

const patchComment = async (id, content) => {
const url = `article/${id}/comment`;
const response = await client.patch(url, { content });
const data = response.data;
return data;
};

// 상품 관련 api
const getProduct = async () => {
const url = "/products";
const response = await client.get(url);
const data = response.data;
return data;
};

const api = {
getArticles,
getArticle,
createArticle,
deleteArticle,
patchArticle,
createComment,
getComments,
deleteComment,
patchComment,
getProduct,
};

export default api;
24 changes: 24 additions & 0 deletions app/(auth)/_components/InputBox.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import clsx from "clsx";
import React from "react";

function InputBox({ userData, handleChange, name, placeholder, title }) {
return (
<div className="flex flex-col md:gap-4 gap-2">
<p className="font-bold md:text-[18px] text-[14px]">{title}</p>
<input
name={name}
className={clsx(
"md:w-[640px] md:h-p[56px] rounded-xl px-6 py-4 bg-[#F3F4F6] w-[343px] h-14 focus:outline-blue"
)}
placeholder={placeholder}
value={userData[name] || ""}
onChange={handleChange}
type={
name === "password" || name === "passwordCheck" ? "password" : "text"
}
/>
</div>
);
}

export default InputBox;
18 changes: 18 additions & 0 deletions app/(auth)/_components/SocialLogin.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from "react";
import Google from "@/assets/svg/ic_google.svg";
import Kakao from "@/assets/svg/ic_kakao.svg";
import Image from "next/image";

function SocialLogin() {
return (
<div className="w-full h-[74px] px-[23px] py-4 flex justify-between items-center rounded-lg bg-[#E6F2FF]">
<p className="font-medium"> 간편 로그인하기</p>
<div className="flex gap-4">
<Image src={Google.src} alt="googleicon" width={42} height={42} />
<Image src={Kakao.src} alt="kakaoicon" width={42} height={42} />
</div>
</div>
);
}

export default SocialLogin;
14 changes: 14 additions & 0 deletions app/(auth)/layout.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from "react";
import { basicFont } from "@/assets/fonts";

function layout({ children }) {
return (
<div
className={`min-w-max min-h-screen ${basicFont.className} text-[#1F2937] flex items-center`}
>
{children}
</div>
);
}

export default layout;
110 changes: 110 additions & 0 deletions app/(auth)/login/page.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
"use client";

import React, { useEffect, useState } from "react";
import Image from "next/image";
import Logo from "@/assets/svg/pandaLogo.svg";
import Link from "next/link";
import Button from "@/components/Button";
import InputBox from "../_components/InputBox";
import SocialLogin from "../_components/SocialLogin";

function loginPage() {
const [userData, setUserData] = useState({ email: "", password: "" });
// const [error, setError] = useState({ email: "", password: "" });

const [disabled, setDisabled] = useState(true);
const [isActive, setIsActive] = useState("inactive");

useEffect(() => {
if (userData.email === "" || userData.password === "") {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

disabled 상태만 button 컴포넌트로 넘겨도 될 것 같습니다

�해당 값으로 css 버튼 color 를 설정 해주는게 가능해 보여서 isActive 상태는 다른 페이지들에서도 관리 안하셔도 될 걸로 보여집니다!

아니라면 혹시라도 다른 의도가 있는지 궁금합니다

Copy link
Collaborator Author

@eomsung eomsung Jan 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

다른 의도가 있는건 아니였고 clsx 처음 써서 헷갈렸던거 같아요. 로그인이랑 회원가입은 미션9이기 때문에 미션을 진행하면서 수정해 보겠습니다!
->수정해보니까 disable은 원하지 않으면서 색깔만 항상 회색인 경우를 만들고 싶어서 그랬던거 같습니다.

//disable없애고 errorMsg 없으면 진행 있으면 강조
setDisabled(true);
setIsActive("inactive");
} else {
setDisabled(false);
setIsActive("active");
}
}, [userData]);

// const handleErrorMsg = (name, value) => {
// switch (name) {
// case "email":
// if (!value) return "이메일을 입력해주세요";
// return "";
// case "password":
// if (!value) return "비밀번호를 입력해주세요";
// }
// };

const handleSubmit = (e) => {
e.preventDefault();
console.log(userData);
};

const handleChange = (e) => {
const { name, value } = e.target;
setUserData((prev) => ({
...prev,
[name]: value,
}));
// const errorMsg = handleErrorMsg(name, value);
// setError((prev) => ({ ...prev, [name]: errorMsg }));
};

return (
<div className="md:w-[640px] flex flex-col md:gap-10 gap-6 m-auto w-[343px] ">
{/* 로고 */}
<div className="md:w-[369px] md:h-[132px] w-[198px] h-[66px] relative self-center">
<Link href="/">
<Image src={Logo.src} alt="logo" fill />
</Link>
</div>

<div className="flex flex-col gap-6">
<form className="flex flex-col gap-6" onSubmit={handleSubmit}>
{/* 입력 칸 */}
<div className="flex flex-col gap-2">
<InputBox
title="이메일"
name="email"
handleChange={handleChange}
userData={userData}
placeholder="이메일을 입력해주세요"
/>
{/* {error.email && <div className="text-red pl-4">{error.email}</div>} */}
</div>

<InputBox
title="비밀번호"
name="password"
handleChange={handleChange}
userData={userData}
placeholder="비밀번호를 입력해주세요"
/>

{/* 버튼 */}
<Button
className="w-full h-14 rounded-[40px] px-[124px] py-4"
isActive={isActive}
disabled={disabled}
>
로그인
</Button>
</form>

{/* 간편 로그인 */}
<SocialLogin />

{/* 회원가입 이동 */}
<div className="flex justify-center gap-1 font-medium">
<p>판다마켓이 처음이신가요?</p>{" "}
<Link href="/signup" className="text-blue">
회원가입
</Link>
</div>
</div>
</div>
);
}

export default loginPage;
Loading