diff --git a/src/App.jsx b/src/App.jsx
index 6a93646..3a0b532 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -13,6 +13,8 @@ import LoadingModal from './components/Modal/LoadingModal';
import CreateObjectModal from './components/Modal/CreateObjectModal';
import SearchObjectModal from './components/Modal/SearchObjectModal';
import ControllerObjectModal from './components/Modal/ControllerObjectModal';
+import CreateProjectModal from './components/Modal/CreateProjectModal';
+import LoginModal from './components/Modal/LoginModal';
function App() {
return (
@@ -25,15 +27,17 @@ function App() {
+
+
- } />
+ } />
+ } />
} />
} />
} />
- } />
diff --git a/src/apis/Project/ProjectController.js b/src/apis/Project/ProjectController.js
new file mode 100644
index 0000000..ca1ff20
--- /dev/null
+++ b/src/apis/Project/ProjectController.js
@@ -0,0 +1,46 @@
+import basicApi from '..';
+
+export const getProjectList = async (memberId) => {
+ try {
+ const response = await basicApi.get(`api/project/${memberId}`);
+ return response.data;
+ } catch (error) {
+ console.error(error);
+ throw error;
+ }
+};
+
+export const postFile = async (file) => {
+ const formData = FormData();
+ formData.append('file', file);
+ try {
+ const response = await basicApi.post(`file`, formData, {
+ headers: {
+ 'Content-Type': 'multipart/form-data',
+ },
+ });
+ return response.data;
+ } catch (error) {
+ console.error(error);
+ throw error;
+ }
+};
+
+export const postProject = async (title, file) => {
+ try {
+ const data = {
+ name: title,
+ thumbnailUrl: file,
+ memberId: 8,
+ };
+ const response = await basicApi.post('api/project', data, {
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ });
+ return response.data;
+ } catch (error) {
+ console.error(error);
+ throw error;
+ }
+};
diff --git a/src/apis/User/LoginController.js b/src/apis/User/LoginController.js
index 36b2427..2e0c547 100644
--- a/src/apis/User/LoginController.js
+++ b/src/apis/User/LoginController.js
@@ -1,8 +1,19 @@
import basicApi from '../index';
-export const loginController = async () => {
+export const loginController = async (email, password) => {
try {
- const response = await basicApi.post('/posts');
+ const response = await basicApi.post(
+ 'api/login',
+ {
+ email,
+ password,
+ },
+ {
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ },
+ );
return response.data;
} catch (error) {
console.error('Error fetching posts:', error);
@@ -10,6 +21,16 @@ export const loginController = async () => {
}
};
+export const signUp = async () => {
+ try {
+ const response = await basicApi.get(`/api/sign-in`);
+ return response.data;
+ } catch (error) {
+ console.error(error);
+ throw error;
+ }
+};
+
export const userData = async () => {
try {
const response = await basicApi.get('/get');
diff --git a/src/assets/logo.svg b/src/assets/logo.svg
new file mode 100644
index 0000000..43e4bf4
--- /dev/null
+++ b/src/assets/logo.svg
@@ -0,0 +1,13 @@
+
diff --git a/src/components/LoginPage/LoginFormContainer.jsx b/src/components/LoginPage/LoginFormContainer.jsx
new file mode 100644
index 0000000..e48f8dd
--- /dev/null
+++ b/src/components/LoginPage/LoginFormContainer.jsx
@@ -0,0 +1,49 @@
+import styled from 'styled-components';
+import SubmitBtn from './atom/SubmitBtn';
+
+function LoginFormContainer({
+ email,
+ password,
+ setEmail,
+ setPassword,
+ LoginHandle,
+}) {
+ return (
+
+ setEmail(e.target.value)}
+ required
+ />
+ setPassword(e.target.value)}
+ required
+ />
+
+
+ );
+}
+
+export default LoginFormContainer;
+
+const Container = styled.form`
+ width: 308px;
+ height: 221px;
+ margin-top: 52px;
+ display: flex;
+ flex-direction: column;
+ gap: 32px;
+`;
+
+const InputBox = styled.input`
+ width: 308px;
+ height: 48px;
+ padding: 0 18px;
+ border: 1px solid #6b7684;
+ border-radius: 8px;
+`;
diff --git a/src/components/LoginPage/SocialLoginBtn.jsx b/src/components/LoginPage/SocialLoginBtn.jsx
deleted file mode 100644
index 69580d4..0000000
--- a/src/components/LoginPage/SocialLoginBtn.jsx
+++ /dev/null
@@ -1,42 +0,0 @@
-import styled from 'styled-components';
-import { ReactComponent as Kakao } from '../../assets/socialLogin/kakao.svg';
-import { ReactComponent as Naver } from '../../assets/socialLogin/naver.svg';
-
-function SocialLoginBtn({ type, onClick }) {
- return (
-
- {type === 'kakao' && (
-
-
- 카카오로 로그인하기
-
- )}
- {type === 'naver' && (
-
-
- 네이버로 로그인하기
-
- )}
-
- );
-}
-export default SocialLoginBtn;
-
-const SocialLoginBtnContainer = styled.div`
- width: 22.86458vw;
- height: 5vh;
- border: 1px solid;
- border-radius: 12px;
- display: flex;
- justify-content: center;
- align-items: center;
-`;
-const TextContainer = styled.div`
- display: flex;
- justify-content: center;
- align-items: center;
-`;
-const SocialLoginText = styled.span`
- margin-left: 0.6vw;
- font-size: 1.0416vw;
-`;
diff --git a/src/components/LoginPage/atom/SubmitBtn.jsx b/src/components/LoginPage/atom/SubmitBtn.jsx
new file mode 100644
index 0000000..95c2a1e
--- /dev/null
+++ b/src/components/LoginPage/atom/SubmitBtn.jsx
@@ -0,0 +1,23 @@
+import styled from 'styled-components';
+
+function SubmitBtn({ type, onClick }) {
+ return (
+
+ 로그인
+
+ );
+}
+
+export default SubmitBtn;
+
+const SubmitButton = styled.button`
+ width: 308px;
+ height: 48px;
+ background-color: #3182f6;
+ border: none;
+ border-radius: 8px;
+ color: white;
+ &:hover {
+ background-color: #1b64da;
+ }
+`;
diff --git a/src/components/Modal/CreateProjectModal.jsx b/src/components/Modal/CreateProjectModal.jsx
new file mode 100644
index 0000000..1549818
--- /dev/null
+++ b/src/components/Modal/CreateProjectModal.jsx
@@ -0,0 +1,97 @@
+import styled from 'styled-components';
+import { useRecoilState } from 'recoil';
+import { useState } from 'react';
+import CancelBtn from './atom/CancelBtn';
+import { CreateProjectModalState } from '../../store/modalState';
+import { postFile, postProject } from '../../apis/Project/ProjectController';
+
+function CreateProjectModal() {
+ const [modalValue, setModalValue] = useRecoilState(CreateProjectModalState);
+ const [title, setTitle] = useState('');
+ const [file, setFile] = useState(null);
+
+ if (!modalValue) {
+ return null;
+ }
+
+ const CancelHandler = () => {
+ setModalValue(false);
+ };
+
+ const handleSummit = async () => {
+ if (file) {
+ try {
+ const fileUrl = await postFile(file);
+ await postProject(title, fileUrl);
+ setTitle('');
+ setFile(null);
+ setModalValue(false);
+ } catch (error) {
+ console.error(error);
+ }
+ } else {
+ console.warn('No file selected');
+ }
+ };
+
+ return (
+
+
+
+
+
+ 프로젝트 만들기
+ setTitle(e.target.value)}
+ />
+ setFile(e.target.files[0])} // 파일 선택 처리
+ />
+
+
+
+ );
+}
+
+export default CreateProjectModal;
+
+const ModalBackdrop = styled.div`
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100vw;
+ height: 100vh;
+ background-color: rgba(0, 0, 0, 0.5);
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ z-index: 999;
+`;
+
+const ModalBox = styled.div`
+ position: absolute;
+ display: flex;
+ flex-direction: column;
+ width: 22.5vw;
+ height: 56.388888888888886vh;
+ background-color: #ffffff;
+ border-radius: 12px;
+ padding: 1.04vw;
+`;
+
+const CancelPostion = styled.div`
+ position: absolute;
+ top: 1vw;
+ right: 1vw;
+`;
+
+const MainTitle = styled.p`
+ font-size: 1.2vw;
+`;
diff --git a/src/components/Modal/LoginModal.jsx b/src/components/Modal/LoginModal.jsx
new file mode 100644
index 0000000..a24e2ef
--- /dev/null
+++ b/src/components/Modal/LoginModal.jsx
@@ -0,0 +1,101 @@
+import { useRecoilState } from 'recoil';
+import { useState } from 'react';
+import styled from 'styled-components';
+import CancelBtn from './atom/CancelBtn';
+import { LoginModalState } from '../../store/modalState';
+import { loginController } from '../../apis/User/LoginController';
+
+function LoginModal() {
+ const [modalValue, setModalValue] = useRecoilState(LoginModalState);
+ const [email, setEmail] = useState('');
+ const [password, setPassword] = useState('');
+ if (!modalValue) {
+ return null;
+ }
+ const CancelHandler = () => {
+ setModalValue(false);
+ };
+
+ const LoginHandle = async () => {
+ try {
+ await loginController(email, password);
+ setEmail('');
+ setPassword('');
+ } catch (error) {
+ error(error);
+ }
+ };
+ return (
+
+
+
+
+
+ 로그인
+ setEmail(e.target.value)}
+ />
+ setPassword(e.target.value)}
+ />
+
+ 생성
+
+
+
+ );
+}
+
+export default LoginModal;
+
+const ModalBackdrop = styled.div`
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100vw;
+ height: 100vh;
+ background-color: rgba(0, 0, 0, 0.5);
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ z-index: 999;
+`;
+
+const ModalBox = styled.div`
+ position: absolute;
+ display: flex;
+ align-items: center;
+ flex-direction: column;
+ width: 18.54vw;
+ height: 48.3vh;
+ background-color: #ffffff;
+ border-radius: 12px;
+ padding: 1.04vw;
+`;
+
+const CancelPostion = styled.div`
+ position: absolute;
+ top: 1vw;
+ right: 1vw;
+`;
+
+const MainTitle = styled.p`
+ font-size: 1.2vw;
+`;
+
+const LoginInput = styled.input`
+ width: 14.166666666666666vw;
+ height: 4.907407407407407vh;
+ padding: 0.6vw;
+`;
+
+const LoginBtn = styled.button`
+ width: 14.16vw;
+ height: 4.44vh;
+`;
diff --git a/src/components/myPage/SideMenu.jsx b/src/components/myPage/SideMenu.jsx
index cc6405a..3a78dde 100644
--- a/src/components/myPage/SideMenu.jsx
+++ b/src/components/myPage/SideMenu.jsx
@@ -1,15 +1,18 @@
import styled from 'styled-components';
import { useLocation } from 'react-router-dom';
+import { useSetRecoilState } from 'recoil';
import Logo from './atom/Logo';
import MenuBtn from './atom/MenuBtn';
import SearchProject from './atom/SearchProject';
+import { LoginModalState } from '../../store/modalState';
const types = ['About', 'OverView', 'Comments', 'Projects', 'Starred'];
function SideMenu() {
const location = useLocation();
+ const setLoginModal = useSetRecoilState(LoginModalState);
const shouldShow = [
- '/',
+ '/list',
'/Projects',
'/About',
'/OverView',
@@ -34,6 +37,9 @@ function SideMenu() {
))}
+
);
}
diff --git a/src/pages/ItemPage.jsx b/src/pages/ItemPage.jsx
index 1d9b9d7..4ed4ed9 100644
--- a/src/pages/ItemPage.jsx
+++ b/src/pages/ItemPage.jsx
@@ -1,6 +1,11 @@
+import { useEffect } from 'react';
import ProjectCard from '../components/ItemPage/ProjectCard';
+import { getProjectList } from '../apis/Project/ProjectController';
function ItemPage() {
+ useEffect(() => {
+ getProjectList(8);
+ }, []);
return (
{
- navigate(-1);
+ const nav = useNavigate();
+ const [email, setEmail] = useState('');
+ const [password, setPassword] = useState('');
+ const LoginHandle = () => {
+ loginController(email, password);
+ setEmail('');
+ setPassword('');
+ nav('/list');
};
- const NAVER = process.env.REACT_APP_NAVER;
- const KAKAO = process.env.REACT_APP_KAKAO;
-
- const routeToSocialLogin = (type) => {
- const url = type === 'naver' ? NAVER : KAKAO;
- window.location.href = url;
- };
-
return (
-
-
-
-
- MoreView
- routeToSocialLogin('kakao')}
- />
- 또는
- routeToSocialLogin('naver')}
+
+
+
-
+
);
}
+
export default LoginPage;
-const LoginContainer = styled.div`
- width: 28.645vw;
- height: 63.888vh;
- border: 1px solid;
- border-radius: 12px;
+const Container = styled.div`
+ width: 100vw;
+ height: 100vh;
display: flex;
- align-items: center;
flex-direction: column;
- margin: 3vw auto;
- position: relative;
-`;
-
-const LogoStyle = styled.h1`
- font-family: 'Anta', sans-serif;
- font-weight: 400;
- font-style: normal;
- font-size: 3.5vw;
- margin: 4.6vw 0 7vw 0;
-`;
-
-const Despite = styled.p`
- margin: 1vw 0 1vw 0;
- color: #b1acac;
-`;
-
-const BackPosition = styled.div`
- position: absolute;
- top: 1.5vw;
- left: 2vw;
+ align-items: center;
+ justify-content: center;
`;
diff --git a/src/store/modalState.js b/src/store/modalState.js
index 30e5f78..83d022f 100644
--- a/src/store/modalState.js
+++ b/src/store/modalState.js
@@ -19,3 +19,13 @@ export const ControllerModalState = atom({
key: 'ControllerModalState',
default: false,
});
+
+export const CreateProjectModalState = atom({
+ key: 'CreateProjectModalState',
+ default: false,
+});
+
+export const LoginModalState = atom({
+ key: 'LoginModalState',
+ default: false,
+});
diff --git a/src/store/userState.js b/src/store/userState.js
new file mode 100644
index 0000000..e69de29