├── backend ├── todo │ ├── __init__.py │ ├── migrations │ │ ├── __init__.py │ │ ├── 0002_todo_done.py │ │ └── 0001_initial.py │ ├── tests.py │ ├── admin.py │ ├── apps.py │ ├── urls.py │ ├── models.py │ └── views.py ├── todo_backend │ ├── __init__.py │ ├── wsgi.py │ ├── urls.py │ └── settings.py ├── db.sqlite3 ├── manage.py └── .gitignore ├── public ├── favicon.ico ├── logo192.png ├── logo512.png ├── manifest.json └── index.html └── src ├── components ├── TodoDetail │ ├── TodoDetail.css │ └── TodoDetail.js └── Todo │ ├── Todo.js │ └── Todo.css ├── App.test.js ├── containers └── TodoList │ ├── TodoList.css │ ├── NewTodo │ ├── NewTodo.css │ └── NewTodo.js │ └── TodoList.js ├── index.css ├── index.js ├── App.css ├── App.js ├── logo.svg └── serviceWorker.js /backend/todo/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/todo_backend/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/todo/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/todo/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /backend/todo/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /backend/db.sqlite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djvonny/swpp-redux-tutorial/HEAD/backend/db.sqlite3 -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djvonny/swpp-redux-tutorial/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djvonny/swpp-redux-tutorial/HEAD/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djvonny/swpp-redux-tutorial/HEAD/public/logo512.png -------------------------------------------------------------------------------- /backend/todo/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class TodoConfig(AppConfig): 5 | name = 'todo' 6 | -------------------------------------------------------------------------------- /backend/todo/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | 3 | from . import views 4 | 5 | urlpatterns = [ 6 | path('', views.index), 7 | path('/', views.index), 8 | ] 9 | -------------------------------------------------------------------------------- /backend/todo/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | class Todo(models.Model): 4 | title = models.CharField(max_length=120) 5 | content = models.TextField() 6 | done = models.BooleanField(default=False) 7 | -------------------------------------------------------------------------------- /src/components/TodoDetail/TodoDetail.css: -------------------------------------------------------------------------------- 1 | .TodoDetail .row { 2 | display: flex; 3 | padding: 20px; 4 | height: 30px; 5 | text-align: left; 6 | } 7 | 8 | .TodoDetail .left { 9 | font-weight: bold; 10 | flex: 25% 11 | } 12 | 13 | .TodoDetail .right { 14 | flex: 75%; 15 | } -------------------------------------------------------------------------------- /src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | ReactDOM.unmountComponentAtNode(div); 9 | }); 10 | -------------------------------------------------------------------------------- /src/containers/TodoList/TodoList.css: -------------------------------------------------------------------------------- 1 | .TodoList { 2 | background: white; 3 | width: 512px; 4 | box-shadow: 0 3px 9px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23); /* 그림자 */ 5 | margin: auto; 6 | margin-top: 4rem; 7 | } 8 | 9 | .TodoList .title { 10 | padding: 2rem; 11 | font-size: 2.5rem; 12 | text-align: center; 13 | font-weight: 500; 14 | background: orange; 15 | color: black; 16 | } -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", 4 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /src/components/Todo/Todo.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import './Todo.css'; 4 | 5 | const Todo = (props) => { 6 | return ( 7 |
8 |
11 | {props.title} 12 |
13 | {props.done &&
} 14 |
15 | ); 16 | }; 17 | 18 | export default Todo; -------------------------------------------------------------------------------- /backend/todo/migrations/0002_todo_done.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.4 on 2019-09-24 14:43 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('todo', '0001_initial'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='todo', 15 | name='done', 16 | field=models.BooleanField(default=False), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /backend/todo_backend/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for todo_backend project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/2.2/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'todo_backend.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import * as serviceWorker from './serviceWorker'; 6 | 7 | ReactDOM.render(, document.getElementById('root')); 8 | 9 | // If you want your app to work offline and load faster, you can change 10 | // unregister() to register() below. Note this comes with some pitfalls. 11 | // Learn more about service workers: https://bit.ly/CRA-PWA 12 | serviceWorker.unregister(); 13 | -------------------------------------------------------------------------------- /src/components/Todo/Todo.css: -------------------------------------------------------------------------------- 1 | .Todo { 2 | border-top: 1px solid #f1f3f5; 3 | padding: 1rem; 4 | display: flex; 5 | align-items: center; 6 | transition: all 0.15s; 7 | } 8 | 9 | .Todo .text { 10 | flex: 1; 11 | text-align: left; 12 | word-break: break-all; 13 | cursor: pointer; 14 | } 15 | 16 | .Todo .text:hover { 17 | color: orange; 18 | } 19 | 20 | .Todo .done { 21 | text-decoration: line-through; 22 | color: #adb5bd; 23 | } 24 | 25 | .Todo .done-mark { 26 | font-size: 1.5rem; 27 | line-height: 1rem; 28 | margin-left: 1rem; 29 | color: orange; 30 | font-weight: 800; 31 | } -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | animation: App-logo-spin infinite 20s linear; 7 | height: 40vmin; 8 | pointer-events: none; 9 | } 10 | 11 | .App-header { 12 | background-color: #282c34; 13 | min-height: 100vh; 14 | display: flex; 15 | flex-direction: column; 16 | align-items: center; 17 | justify-content: center; 18 | font-size: calc(10px + 2vmin); 19 | color: white; 20 | } 21 | 22 | .App-link { 23 | color: #61dafb; 24 | } 25 | 26 | @keyframes App-logo-spin { 27 | from { 28 | transform: rotate(0deg); 29 | } 30 | to { 31 | transform: rotate(360deg); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /backend/todo/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.2.5 on 2019-09-08 06:26 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | initial = True 9 | 10 | dependencies = [ 11 | ] 12 | 13 | operations = [ 14 | migrations.CreateModel( 15 | name='Todo', 16 | fields=[ 17 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 18 | ('title', models.CharField(max_length=120)), 19 | ('content', models.TextField()), 20 | ], 21 | ), 22 | ] 23 | -------------------------------------------------------------------------------- /backend/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'todo_backend.settings') 9 | try: 10 | from django.core.management import execute_from_command_line 11 | except ImportError as exc: 12 | raise ImportError( 13 | "Couldn't import Django. Are you sure it's installed and " 14 | "available on your PYTHONPATH environment variable? Did you " 15 | "forget to activate a virtual environment?" 16 | ) from exc 17 | execute_from_command_line(sys.argv) 18 | 19 | 20 | if __name__ == '__main__': 21 | main() 22 | -------------------------------------------------------------------------------- /src/components/TodoDetail/TodoDetail.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import './TodoDetail.css'; 4 | 5 | class TodoDetail extends React.Component { 6 | render() { 7 | if (this.props.match) { 8 | console.log(this.props.match.params.id); 9 | } 10 | return ( 11 | < div className="TodoDetail" > 12 |
13 |
14 | Name: 15 |
16 |
17 | {this.props.title} 18 |
19 |
20 | 21 |
22 |
23 | Content: 24 |
25 |
26 | {this.props.content} 27 |
28 |
29 | 30 | ); 31 | } 32 | }; 33 | 34 | export default TodoDetail; -------------------------------------------------------------------------------- /src/containers/TodoList/NewTodo/NewTodo.css: -------------------------------------------------------------------------------- 1 | .NewTodo { 2 | width: 80%; 3 | margin: 20px auto; 4 | border: 1px solid #eee; 5 | box-shadow: 0 2px 3px #ccc; 6 | text-align: center; 7 | } 8 | 9 | .NewTodo label { 10 | display: block; 11 | margin: 10px auto; 12 | text-align: center; 13 | font-weight: bold; 14 | } 15 | 16 | .NewTodo input, 17 | .NewTodo textarea { 18 | display: block; 19 | width: 80%; 20 | box-sizing: border-box; 21 | border: 1px solid black; 22 | outline: none; 23 | font: inherit; 24 | margin: auto; 25 | } 26 | 27 | .NewTodo button { 28 | margin: 5px 0; 29 | padding: 10px; 30 | font: inherit; 31 | border: 1px solid #fa923f; 32 | background-color: transparent; 33 | color: #fa923f; 34 | cursor: pointer; 35 | } 36 | 37 | .NewTodo button:hover, 38 | .NewTodo button:active { 39 | color: white; 40 | background-color: #fa923f; 41 | } -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import './App.css'; 3 | 4 | import TodoList from './containers/TodoList/TodoList'; 5 | import TodoDetail from './components/TodoDetail/TodoDetail'; 6 | import NewTodo from './containers/TodoList/NewTodo/NewTodo'; 7 | 8 | import { BrowserRouter, Route, Redirect, Switch } from 'react-router-dom'; 9 | 10 | function App() { 11 | return ( 12 | 13 |
14 | 15 | } /> 16 | 17 | 18 | 19 |

Not Found

} /> 20 |
21 |
22 |
23 | ); 24 | } 25 | 26 | export default App; 27 | -------------------------------------------------------------------------------- /backend/todo_backend/urls.py: -------------------------------------------------------------------------------- 1 | """todo_backend URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/2.2/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: path('', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.urls import include, path 14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 15 | """ 16 | from django.contrib import admin 17 | from django.urls import include, path 18 | 19 | urlpatterns = [ 20 | path('api/todo/', include('todo.urls')), 21 | path('admin/', admin.site.urls), 22 | ] 23 | -------------------------------------------------------------------------------- /src/containers/TodoList/NewTodo/NewTodo.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | import { Redirect } from 'react-router-dom'; 4 | 5 | import './NewTodo.css'; 6 | 7 | class NewTodo extends Component { 8 | state = { 9 | title: '', 10 | content: '', 11 | submitted: false, 12 | } 13 | 14 | postTodoHandler = () => { 15 | const data = { title: this.state.title, content: this.state.content }; 16 | alert('Submitted\n' + data.title + '\n' + data.content); 17 | this.setState({ submitted: true }); 18 | } 19 | 20 | render() { 21 | let redirect = null; 22 | if (this.state.submitted) { 23 | redirect = 24 | } 25 | return ( 26 |
27 | {redirect} 28 |

Add a Todo

29 | 30 | this.setState({ title: event.target.value })} /> 32 | 33 |