Skip to content
Open
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
2,850 changes: 2,850 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
},
"dependencies": {
"react": "^19.1.0",
"react-dom": "^19.1.0"
"react-dom": "^19.1.0",
"react-router-dom": "^7.7.1"
},
"devDependencies": {
"@eslint/js": "^9.30.1",
Expand Down
43 changes: 41 additions & 2 deletions src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,44 @@
import Header from './component/Header.jsx'
import ProfileForm from './component/ProfileForm.jsx';
import ProfileList from './component/ProfileList.jsx';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { useState } from 'react';
import textList from './pages/Home.jsx';
import ProfileLayout from './pages/ProfileLayout.jsx';
import ProfileModify from './component/ProfileModify.jsx';
import './styles/component.css';
import './styles/Home.css';
import './styles/ProfileLayout.css';

function App() {
return <>당신은 할 수 있습니다.</>;
const [profileList, setProfileList] = useState([{
id: 1,
name: "신은총",
team: "PARADOX",
imgUrl: "/assets/PARADOX_default.png",
job: "Paradox-Intern",
tel: "010-1234-5678",
email: "paradox@gmail.com",
}]);

return (
<BrowserRouter>
<Header />
<Routes>
<Route path="/" element={
<div id="home">
<h1 >프로필 카드 리스트 만들기</h1>
<ul>{textList.map((text, index) => ( <li key={index}>{text}</li> ))} </ul>
</div>
} />
<Route path="/Profile" element={<ProfileLayout/>}>
<Route path="ProfileForm" element={<ProfileForm profileList={profileList} setProfileList={setProfileList} />} />
<Route path="ProfileList" element={<ProfileList profileList={profileList} setProfileList={setProfileList} />} />
<Route path="ProfileModify/:id" element={<ProfileModify profileList={profileList} setProfileList={setProfileList} />} />
</Route>
</Routes>
</BrowserRouter>
)
}

export default App;
export default App
Binary file added src/assets/PARADOX_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 added src/assets/PARADOX_reverse.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions src/component/Header.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Link } from 'react-router-dom';

export default function Header() {
return (
<div id="header">
<header>
<h1>Profile Card List</h1>
</header>
<nav>
<Link to="/">Home</Link>
<Link to="/Profile/ProfileList">Card List</Link>
<Link to="/Profile/ProfileForm">Make Card</Link>
</nav>
</div>
)
}
43 changes: 43 additions & 0 deletions src/component/ProfileCard.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import Reverse from '../assets/PARADOX_reverse.png';
import Default from '../assets/PARADOX_default.png';
import { useNavigate } from 'react-router-dom';

export default function ProfileCard({ profileList, setProfileList, profile, index }) {

const navigator = useNavigate();

const getProfileImg = (imgUrl) => {
if (imgUrl === '/assets/PARADOX_reverse.png') return Reverse;
return Default;
};

const delProfile = (index) => {
const temp = [...profileList].filter((_, i) => i !== index);
setProfileList(temp);
}

const editProfile = (index) => {
navigator(`/Profile/ProfileModify/${index}`);
}

return (
<div style={{ border: '3px solid black', borderRadius: '30px', padding: '25px', margin: '50px', backgroundColor: '#fffbde', fontSize: '35px'}}>
<div style={{display: 'flex', flexDirection: 'row'}}>
<div style={{marginRight: '20px'}}><img src={getProfileImg(profile.imgUrl)} alt={profile.name} /></div>
<div>
<p><b>Team. {profile.team}</b></p>
<p><b>{profile.job}</b></p>
<p><b>tel.</b> {profile.tel}</p>
<p><b>email.</b> {profile.email}</p>
</div>
</div>
<div style={{display: 'flex', flexDirection: 'row', justifyContent: 'space-between'}}>
<h2 style={{marginTop: 0}}>{profile.name}</h2>
<div style={{marginRight: '75px'}}>
<button style={{marginRight: '100px', scale: 2.5, backgroundColor: 'blue', borderRadius: '7px', border: '1px solid black'}} onClick={() => editProfile(index)}>수정</button>
<button style={{marginRight: '50px', scale: 2.5, backgroundColor: 'red', borderRadius: '7px', border: '1px solid black'}} onClick={() => delProfile(index)}>삭제</button>
</div>
</div>
</div>
);
}
70 changes: 70 additions & 0 deletions src/component/ProfileForm.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { useRef } from 'react';
import { useNavigate } from 'react-router-dom';

export default function ProfileForm({ profileList, setProfileList }) {
const formRef = useRef(null);
const name = useRef(null);
const team = useRef(null);
const job = useRef(null);
const tel = useRef(null);
const email = useRef(null);
const image1 = useRef(null);
const image2 = useRef(null);
const navigate = useNavigate();

const submitHandler = (event) => {
event.preventDefault();

if (!name.current.value) {
alert("이름을 입력해주세요.");
name.current.focus();
}else if (!team.current.value) {
alert("팀을 입력해주세요.");
team.current.focus();
}else if (!job.current.value) {
alert("직책을 입력해주세요.");
job.current.focus();
}else if (!tel.current.value) {
alert("전화번호를 입력해주세요.");
tel.current.focus();
}else if (!email.current.value) {
alert("이메일을 입력해주세요.");
email.current.focus();
}else if (!image1.current.checked && !image2.current.checked) {
alert("이미지를 선택해주세요.");
}else {
const formDataObject = {
name: name.current.value,
team: team.current.value,
job: job.current.value,
tel: tel.current.value,
email: email.current.value,
imgUrl: image1.current.checked ? "/assets/PARADOX_default.png" : "/assets/PARADOX_reverse.png"
};
setProfileList([
...profileList,
formDataObject,
]);
return navigate('/Profile/ProfileList');
}
};

return (
<form ref={formRef} onSubmit={submitHandler} id="profileForm">
<div className="form">
<h1>프로필 카드 만들기</h1>
<div className="create-div">
<h2>정보를 입력해주세요.</h2>
<p>Name <input type="text" placeholder="ex) 신은총" name="name" ref={name}></input></p>
<p>Team <input type="text" placeholder="ex) PARADOX" name="team" ref={team}></input></p>
<p>Job <input type="text" placeholder="ex) Full Stack Developer" name="job" ref={job}></input></p>
<p>Phone <input type="text" placeholder="ex) 010-1234-5678" name="tel" ref={tel}></input></p>
<p>Email <input type="text" placeholder="ex) example@example.com" name="email" ref={email}></input></p>
<p>Image <input type="radio" name="imgUrl" value="/assets/PARADOX_default.png" id="Default" ref={image1}></input><label htmlFor="Default">Default</label>
<input type="radio" name="imgUrl" value="/assets/PARADOX_reverse.png" id="Reverse" ref={image2}></input><label htmlFor="Reverse">Reverse</label></p>
<button type="submit" onClick={submitHandler}>등록하기</button>
</div>
</div>
</form>
);
}
13 changes: 13 additions & 0 deletions src/component/ProfileList.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import ProfileCard from "./ProfileCard";

export default function ProfileList({ profileList, setProfileList }) {

return (
<div>
<h1>프로필 카드 목록</h1>
{profileList.map((profile, index) => (
<ProfileCard key={index} profileList={profileList} setProfileList={setProfileList} profile={profile} index={index} />
))}
</div>
);
}
73 changes: 73 additions & 0 deletions src/component/ProfileModify.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { useParams, useNavigate } from 'react-router-dom';
import { useRef } from 'react';

export default function ProfileModify({ profileList, setProfileList }) {

const { id } = useParams();
const targetProfile = profileList[id];

const formRef = useRef(null);
const name = useRef(null);
const team = useRef(null);
const job = useRef(null);
const tel = useRef(null);
const email = useRef(null);
const image1 = useRef(null);
const image2 = useRef(null);
const navigate = useNavigate();

const submitHandler = (event) => {
event.preventDefault();

if (!name.current.value) {
alert("이름을 입력해주세요.");
name.current.focus();
}else if (!team.current.value) {
alert("팀을 입력해주세요.");
team.current.focus();
}else if (!job.current.value) {
alert("직책을 입력해주세요.");
job.current.focus();
}else if (!tel.current.value) {
alert("전화번호를 입력해주세요.");
tel.current.focus();
}else if (!email.current.value) {
alert("이메일을 입력해주세요.");
email.current.focus();
}else if (!image1.current.checked && !image2.current.checked) {
alert("이미지를 선택해주세요.");
}else {
const formDataObject = {
name: name.current.value,
team: team.current.value,
job: job.current.value,
tel: tel.current.value,
email: email.current.value,
imgUrl: image1.current.checked ? "/assets/PARADOX_default.png" : "/assets/PARADOX_reverse.png"
};
const temp = [...profileList];
temp[id] = formDataObject;
setProfileList(temp);
return navigate('/Profile/ProfileList');
}
};

return (
<form ref={formRef} onSubmit={submitHandler} id="profileForm">
<div className="form">
<h1>프로필 카드 만들기</h1>
<div className="create-div">
<h2>정보를 입력해주세요.</h2>
<p>Name <input type="text" placeholder="ex) 신은총" name="name" ref={name} defaultValue={targetProfile.name}></input></p>
<p>Team <input type="text" placeholder="ex) PARADOX" name="team" ref={team} defaultValue={targetProfile.team}></input></p>
<p>Job <input type="text" placeholder="ex) Full Stack Developer" name="job" ref={job} defaultValue={targetProfile.job}></input></p>
<p>Phone <input type="text" placeholder="ex) 010-1234-5678" name="tel" ref={tel} defaultValue={targetProfile.tel}></input></p>
<p>Email <input type="text" placeholder="ex) example@example.com" name="email" ref={email} defaultValue={targetProfile.email}></input></p>
<p>Image <input type="radio" name="imgUrl" value="/assets/PARADOX_default.png" id="Default" ref={image1} defaultChecked={targetProfile.imgUrl === "/assets/PARADOX_default.png"}></input><label htmlFor="Default">Default</label>
<input type="radio" name="imgUrl" value="/assets/PARADOX_reverse.png" id="Reverse" ref={image2} defaultChecked={targetProfile.imgUrl === "/assets/PARADOX_reverse.png"}></input><label htmlFor="Reverse">Reverse</label></p>
<button type="submit" onClick={submitHandler}>수정완료</button>
</div>
</div>
</form>
);
}
9 changes: 9 additions & 0 deletions src/data/cardData.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export const cardData = {
id: 1,
name: "류승찬",
team: "PARADOX",
imgUrl: "/assets/PARADOX_reverse.png",
job: "Chief Executive Officer (CEO)",
tel: "010-1234-5678",
email: "paradox@gmail.com",
};
7 changes: 7 additions & 0 deletions src/pages/Home.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const textList = [
"Home : 홈화면을 볼 수 있다.",
"Card List : 카드 리스트를 볼 수 있다.",
"Make Card : 카드를 만들 수 있다.",
];

export default textList;
9 changes: 9 additions & 0 deletions src/pages/ProfileLayout.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Outlet } from "react-router-dom";

export default function ProfileLayout() {
return (
<div id="profile-layout">
<Outlet/>
</div>
);
}
15 changes: 15 additions & 0 deletions src/styles/Home.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#home {
display: flex;
flex-direction: column;
align-items: center;
height: 100vh;
}

#home ul {
padding: 10px;
width: 97%;
}

html, body, #root {
height: 100%;
}
3 changes: 3 additions & 0 deletions src/styles/ProfileLayout.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#profile-layout {
height: 85%;
}
Loading