import Home from "./Pages/Home";
import Router from "./shared/Router";
const App = () => {
return <Router></Router>;
};
export default App;
import { BrowserRouter, Route, Routes } from "react-router-dom";
import Home from "../Pages/Home";
import Detail from "../Pages/Detail";
const Router = () => {
return (
<BrowserRouter>
<Routes>
{}
<Route path='/' element={<Home />} />
<Route path='/:id' element={<Detail />} />
</Routes>
</BrowserRouter>
);
};
export default Router;
import Layout from "../component/Layout";
import Header from "../component/Header";
import Form from "../component/Form";
import List from "../component/List";
const Home = () => {
return (
<Layout>
<Header></Header>
<Form></Form>
<List></List>
</Layout>
);
};
export default Home;
import styled from "styled-components";
import { useSelector, useDispatch } from "react-redux";
import { useParams, Link } from "react-router-dom";
import { getDetail } from "../redux/modules/todos";
const StDetailWrapDiv = styled.div`
border: 2px solid rgb(238, 238, 238);
width: 100%;
height: 100vh;
display: flex;
-webkit-box-align: center;
align-items: center;
-webkit-box-pack: center;
justify-content: center;
`;
const StDetailBorderDiv = styled.div`
width: 600px;
height: 400px;
border: 1px solid rgb(238, 238, 238);
display: flex;
flex-direction: column;
-webkit-box-pack: justify;
justify-content: space-between;
`;
const StDetailTitleDiv = styled.div`
display: flex;
height: 80px;
-webkit-box-pack: justify;
justify-content: space-between;
padding: 0px 24px;
-webkit-box-align: center;
align-items: center;
`;
const StBackButton = styled.button`
border: 1px solid rgb(221, 221, 221);
height: 40px;
width: 120px;
background-color: rgb(255, 255, 255);
border-radius: 12px;
cursor: pointer;
`;
const StDetailH1 = styled.h1`
padding: 0px 24px;
display: block;
font-size: 2em;
margin-block-start: 0.67em;
margin-block-end: 0.67em;
margin-inline-start: 0px;
margin-inline-end: 0px;
font-weight: bold;
`;
const StDetailMain = styled.main`
padding: 0px 24px;
display: block;
`;
const Detail = () => {
const selTodo = useSelector((state) => state.todos.todo);
console.log(selTodo);
const { id } = useParams();
const dispatch = useDispatch();
useEffect(() => {
dispatch(getDetail(Number(id)));
}, [dispatch, id]);
return (
<StDetailWrapDiv>
<StDetailBorderDiv>
<div>
<StDetailTitleDiv>
<div>ID : {selTodo.id}</div>
<Link to='/'>
<StBackButton>이전으로</StBackButton>
</Link>
</StDetailTitleDiv>
<StDetailH1>{selTodo.title}</StDetailH1>
<StDetailMain>{selTodo.content}</StDetailMain>
</div>
</StDetailBorderDiv>
</StDetailWrapDiv>
);
};
export default Detail;
import styled from "styled-components";
const Header = () => {
return <STTitle>투두리스트</STTitle>;
};
const STTitle = styled.h1`
text-align: center;
`;
export default Header;
import styled from "styled-components";
const Layout = ({ children }) => {
return <STLayout>{children}</STLayout>;
};
const STLayout = styled.div`
max-width: 1200px;
min-width: 800px;
margin: 0 auto;
`;
export default Layout;
import { useState, useSelector } from "react";
import { useDispatch } from "react-redux";
import { useEffect } from "react";
import styled from "styled-components";
import todos from "../redux/modules/todos";
import { addTodo } from "../redux/modules/todos";
const Form = () => {
const [todo, setTodo] = useState({
});
const dispatch = useDispatch();
const onChangeHandler = (e) => {
const { name, value } = e.target;
setTodo({
...todo,
id: Date.now(),
isDone: false,
[name]: value,
});
};
event.preventDefault();
if (
todo.title == undefined ||
todo.content == undefined ||
todo.content == "" ||
todo.title == ""
) {
alert("양식을 작성하여 제출하십시오.");
return;
}
dispatch(addTodo(todo));
setTodo({
id: "",
title: "",
content: "",
isDone: false,
});
};
return (
<STForm>
<STInputContainer>
<STInputLabel>제목</STInputLabel>
<STInput
type='text'
name='title'
value={todo.title}
onChange={onChangeHandler}
></STInput>
<STInputLabel>내용</STInputLabel>
<STInput
value={todo.content}
type='text'
name='content'
onChange={onChangeHandler}
></STInput>
</STInputContainer>
<STButton onClick={onSubmitHandler}>추가</STButton>
</STForm>
);
};
const STForm = styled.form`
background-color: rgb(238, 238, 238);
border-radius: 12px;
margin: 0px auto;
display: flex;
-webkit-box-align: center;
align-items: center;
-webkit-box-pack: justify;
justify-content: space-between;
padding: 30px;
gap: 20px;
display: flex;
align-items: center;
justify-content: center;
`;
const STInputContainer = styled.label`
display: flex;
-webkit-box-align: center;
align-items: center;
gap: 20px;
`;
const STInputLabel = styled.label`
font-size: 16px;
font-weight: 700;
`;
const STInput = styled.input`
height: 40px;
width: 240px;
border: none;
border-radius: 12px;
padding: 0px 12px;
`;
const STButton = styled.button`
border: none;
height: 40px;
cursor: pointer;
border-radius: 10px;
background-color: teal;
width: 140px;
color: rgb(255, 255, 255);
font-weight: 700;
`;
export default Form;
import styled from "styled-components";
import { useDispatch, useSelector } from "react-redux";
import todos from "../redux/modules/todos";
import { deleteTodo } from "../redux/modules/todos";
import { changeTodo } from "../redux/modules/todos";
import { eDiT } from "../redux/modules/todos";
import { Link } from "react-router-dom";
const List = () => {
const dispatch = useDispatch();
const [edit, setEdit] = useState({
title: "",
content: "",
});
useEffect(() => {
setOpenToggle(false);
}, [openToggle]);
const onDeleteHandler = (id) => {
dispatch(deleteTodo(id));
};
const onChangeHandler = (id) => {
dispatch(changeTodo(Number(id)));
};
const onEditHandler = (e) => {
setEdit({
...edit,
[e.target.name]: e.target.value,
});
};
const openEdit = (id) => {
});
const restTodo = todos.filter((item, i, arr) => {
});
console.log(restTodo);
newTodoList.isEdit = true;
restTodo.map((item, i, arr) => {
arr[i].isEdit = false;
});
setOpenToggle(!openToggle);
};
const submitEdit = (id) => {
});
newTodoList.isEdit = false;
newTodoList.title = edit.title;
newTodoList.content = edit.content;
console.log("이거", newTodoList);
dispatch(eDiT(newTodoList));
};
return (
<STList>
<STListLeft>
<div style={{ backgroundColor: "gray" }}>
<strong>In Progress</strong>
</div>
{todos.map((item) => {
if (item.isDone === false) {
return (
<STTodoItemContainer backgroundColor='white'>
<STTodoItem key={item.id}>
<div>
<Link
to={`/${item.id}`}
style={{ textDecoration: "none" }}
key={item.id}
>
{" "}
상세보기{" "}
</Link>
<h2>{item.title}</h2>
<p>{item.content}</p>
</div>
<STFooter>
<STButton
borderColor='red'
onClick={() => onDeleteHandler(item.id)}
>
삭제
</STButton>
<STButton
borderColor='green'
onClick={() => onChangeHandler(item.id)}
>
완료
</STButton>
</STFooter>
<button
onClick={() => {
openEdit(item.id);
}}
>
수정버튼
</button>
{}
{item.isEdit === true ? (
<STModifyContainer>
<button onClick={() => submitEdit(item.id)}>
수정완료
</button>
<STModifyitem
name='title'
placeholder='제목을 입력하세요'
onChange={onEditHandler}
></STModifyitem>
<STModifyitem
name='content'
placeholder='내용을 입력하세요'
onChange={onEditHandler}
></STModifyitem>
</STModifyContainer>
) : (
<div></div>
)}
</STTodoItem>
</STTodoItemContainer>
);
}
})}
</STListLeft>
<STListRight>
<div style={{ backgroundColor: "red" }}>
<strong>Done</strong>
</div>
{todos.map((item) => {
if (item.isDone === true) {
return (
<STTodoItemContainer backgroundColor='beige'>
<STTodoItem key={todos.id}>
<div>
<Link
to={`/${item.id}`}
style={{ textDecoration: "none" }}
key={item.id}
>
{" "}
상세보기{" "}
</Link>
{}
<h2>{item.title}</h2>
<p>{item.content}</p>
</div>
<STFooter>
<STButton
borderColor='red'
onClick={() => onDeleteHandler(item.id)}
>
삭제
</STButton>
<STButton
borderColor='blue'
onClick={() => onChangeHandler(item.id)}
>
취소
</STButton>
</STFooter>
</STTodoItem>
</STTodoItemContainer>
);
}
})}
</STListRight>
</STList>
);
};
const STModifyContainer = styled.div`
padding: 32px 0 32px 30px;
/* display: ${(props) => props.display}; */
`;
const STModifyitem = styled.input`
line-height: 27px;
float: left;
height: 27px;
padding: 0 0 0 7px;
vertical-align: top;
color: #333;
border: 1px solid #ccc;
opacity: 1;
`;
const StDetail = styled.a`
text-decoration: none;
`;
const STButton = styled.button`
border: 1px solid ${(props) => props.borderColor};
height: 40px;
width: 120px;
background-color: rgb(255, 255, 255);
border-radius: 12px;
cursor: pointer;
`;
const STFooter = styled.footer`
display: flex;
-webkit-box-pack: end;
justify-content: end;
padding: 12px;
gap: 12px;
`;
const STTodoItemContainer = styled.div`
background-color: ${(props) => props.backgroundColor};
display: flex;
flex-wrap: wrap;
gap: 12px; ;
`;
const STTodoItem = styled.div`
width: 220px;
border: 4px solid teal;
min-height: 100px;
border-radius: 12px;
padding: 12px 24px 24px;
margin: auto;
margin-top: 15px;
`;
const STList = styled.div`
width: 100%;
height: 1000px;
border: 1px solid #003458;
`;
const STListLeft = styled.div`
width: 50%;
height: 100%;
float: left;
box-sizing: border-box;
background: white;
text-align: center;
border-right: 2px solid black;
`;
const STListRight = styled.div`
width: 50%;
float: left;
box-sizing: border-box;
background: white;
text-align: center;
`;
export default List;
const initialState = {
todos: [
{
id: 0,
title: "React",
content: "리액트는 어려워",
isDone: false,
},
{
id: 1,
title: "Redux",
content: "리덕스는 더 어려워",
isDone: true,
},
],
todo: {
id: 1,
title: "Redux",
content: "리덕스는 더 어려워",
isDone: true,
},
};
export const addTodo = (payload) => {
};
export const deleteTodo = (payload) => {
};
export const changeTodo = (payload) => {
return { type: CHANGE_TODOLIST, id: payload };
};
export const getDetail = (id) => {
return {
type: GET_DETAIL,
id: id,
};
};
export const eDiT = (payload) => {
console.log("페이로드임", payload);
return {
type: EDIT,
id: payload.id,
title: payload.title,
content: payload.content,
isDone: payload.isDone,
};
};
const ADD_TODOLIST = "ADD_TODOLIST";
const DELETE_TODOLIST = "DELETE_TODOLIST";
const CHANGE_TODOLIST = "CHANGE_TODOLIST";
const GET_DETAIL = "GET_DETAIL";
const EDIT = "EDIT";
function todos(state = initialState, action) {
switch (action.type) {
case ADD_TODOLIST:
return {
...state,
todos: [...state.todos, { ...action.payload }],
};
case DELETE_TODOLIST:
return {
...state,
todos: state.todos.filter((todos) => todos.id !== parseInt(action.id)),
};
case CHANGE_TODOLIST:
state.todos.map((item, i, arr) => {
if (item.id === action.id) {
arr[i].isDone ? (arr[i].isDone = false) : (arr[i].isDone = true);
}
});
return {
...state,
todos: [...state.todos],
};
case GET_DETAIL:
const [selTodo] = state.todos.filter((item) => {
return item.id === action.id;
});
console.log("겟디테일", selTodo);
return { ...state, todo: selTodo };
case EDIT:
state.todos.map((item, i, arr) => {
if (item.id == action.id) {
arr[i].title = action.title;
arr[i].content = action.content;
}
});
return {
...state,
todos: [...state.todos],
};
default:// need this for default casereturn state;
}
}
export default todos;