Skip to content

Commit 2d83f5d

Browse files
committed
Ahh, git
1 parent d777f9b commit 2d83f5d

25 files changed

+765
-123
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
server/gin-bin
2+
server/main

README.md

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
1-
# go-todo
1+
# go-react-todo
22

3-
Todo REST API written in Go, setup using docker & docker-compose.
3+
- Todo REST API in Go
4+
- React frontend client with Redux.
5+
- Setup with docker & docker-compose.
46

57
Database library for postgres is [Gorp](https://github.com/go-gorp/gorp),
68
livereloading goes to [codegangsta/Gin](https://github.com/codegangsta/gin),
79
HTTP framework used is [gin-gonic/gin](https://github.com/gin-gonic/gin).
810

11+
Docker-compose file contains the definition for three containers -
12+
database (postgres), backend (Go) and frontend (React).
13+
914
## Requirements
1015

1116
- docker
@@ -19,7 +24,14 @@ Find your docker-machine IP by running
1924

2025
$ docker-machine env default
2126

22-
Access the todo API via port 8080.
27+
Go todo API (backend) can be accessed at port 8080, webpack-dev-server
28+
(react frontend) at 9000.
29+
Requests from webpack-dev-server are proxied to the Go container by
30+
webpack conifig.
31+
32+
## Production setup:
33+
34+
- A story in the making
2335

2436
## API endpoints
2537

client/Dockerfile

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
FROM node:6.5.0-slim
2+
3+
RUN mkdir -p /usr/src/app
4+
WORKDIR /usr/src/app
5+
6+
COPY package.json /usr/src/app/
7+
ENV NODE_ENV development
8+
RUN npm install
9+
10+
#COPY . /usr/src/app
11+
#CMD [ "bash", "sleep 10m" ]

client/index.html

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<!doctype html>
2+
<html>
3+
<head>
4+
</head>
5+
<body lang="en">
6+
<div id="react-app"></div>
7+
<script src="/bundle.js" type="text/javascript"></script>
8+
</body></html>

client/package.json

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
{
2+
"name": "go-react-todo",
3+
"version": "1.0.0",
4+
"description": "Todo application using go & reactjs",
5+
"main": "index.js",
6+
"scripts": {
7+
"build": "NODE_ENV=production ./node_modules/webpack/bin/webpack.js",
8+
"start": "./node_modules/webpack-dev-server/bin/webpack-dev-server.js"
9+
},
10+
"keywords": [
11+
"go",
12+
"reactjs"
13+
],
14+
"author": "xTrinch",
15+
"license": "MIT",
16+
"dependencies": {
17+
"clean-webpack-plugin": "0.1.10",
18+
"copy-webpack-plugin": "3.0.1",
19+
"express": "4.14.0",
20+
"isomorphic-fetch": "^2.2.1",
21+
"jquery": "3.1.0",
22+
"react": "15.3.0",
23+
"react-dom": "15.3.0",
24+
"react-redux": "^4.4.5",
25+
"redux": "^3.6.0",
26+
"redux-thunk": "^2.1.0",
27+
"webpack": "1.13.1"
28+
},
29+
"devDependencies": {
30+
"babel-loader": "6.2.4",
31+
"babel-preset-es2015": "6.13.2",
32+
"babel-preset-react": "6.11.1",
33+
"css-loader": "0.23.1",
34+
"less": "2.7.1",
35+
"less-loader": "2.2.3",
36+
"style-loader": "0.13.1",
37+
"webpack-dev-server": "1.14.1"
38+
}
39+
}

client/src/actions/index.jsx

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import fetch from 'isomorphic-fetch';
2+
3+
let nextTodoId = 0
4+
export const addTodo = (text) => {
5+
return dispatch => {
6+
dispatch(sendTodo()),
7+
fetch(`/api/v1/todos/`, {
8+
method: 'POST',
9+
headers: {
10+
'Content-Type': 'application/json'
11+
},
12+
body: JSON.stringify({
13+
title: text
14+
})
15+
})
16+
.then(req => req.json())
17+
.then(json => dispatch(receiveTodo(json)));
18+
}
19+
}
20+
21+
export const sendTodo = () => {
22+
return {
23+
type: 'SEND_TODO'
24+
}
25+
}
26+
27+
export const receiveTodo = (json) => {
28+
return {
29+
type: 'RECEIVE_TODO',
30+
todo: json
31+
}
32+
}
33+
34+
export const deleteTodo = (id) => {
35+
return dispatch => {
36+
dispatch(sendTodo()),
37+
fetch(`/api/v1/todos/`+id, {
38+
method: 'DELETE'
39+
}).then(dispatch(receiveDeleteTodo(id)));
40+
}
41+
}
42+
43+
export const receiveDeleteTodo = (id) => {
44+
return {
45+
type: 'RECEIVE_DELETE_TODO',
46+
id: id
47+
}
48+
}
49+
50+
export const updateTodo = (todo) => {
51+
return dispatch => {
52+
dispatch(toggleTodo(todo)),
53+
fetch(`/api/v1/todos/`+todo.id, {
54+
method: 'PUT',
55+
headers: {
56+
'Content-Type': 'application/json'
57+
},
58+
body: JSON.stringify(todo)
59+
}).then(dispatch(receiveUpdateTodo(todo)));
60+
}
61+
}
62+
63+
export const receiveUpdateTodo = (todo) => {
64+
return {
65+
type: 'RECEIVE_UPDATE_TODO',
66+
todo: todo
67+
}
68+
}
69+
70+
export const clearTodo = () => {
71+
return {
72+
type: 'CLEAR_TODO'
73+
}
74+
}
75+
76+
export const requestTodos = () => {
77+
return {
78+
type: 'REQUEST_TODOS'
79+
}
80+
}
81+
82+
export const receiveTodos = (json) => {
83+
return {
84+
type: 'RECEIVE_TODOS',
85+
todos: json,
86+
updatedAt: Date.now()
87+
}
88+
}
89+
90+
export const getTodos = () => {
91+
return dispatch => {
92+
dispatch(requestTodos()),
93+
fetch(`/api/v1/todos/`)
94+
.then(req => req.json())
95+
.then(json => dispatch(receiveTodos(json)));
96+
}
97+
}
98+
99+
100+
export const setVisibilityFilter = (filter) => {
101+
return {
102+
type: 'SET_VISIBILITY_FILTER',
103+
filter
104+
}
105+
}
106+
107+
export const toggleTodo = (todo) => {
108+
return {
109+
type: 'TOGGLE_TODO',
110+
todo: todo
111+
}
112+
}

client/src/components/app.jsx

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import React from 'react'
2+
import Footer from './footer.jsx'
3+
import AddTodo from '../containers/addtodo.jsx'
4+
import VisibleTodoList from '../containers/visibletodolist.jsx'
5+
import { getTodos } from '../actions/index.jsx'
6+
import { connect } from 'react-redux'
7+
8+
class App extends React.Component {
9+
constructor(props) {
10+
super(props)
11+
//this.handlers = createHandlers(this.props.dispatch);
12+
// binders
13+
}
14+
15+
componentDidMount() {
16+
this.props.dispatch(getTodos())
17+
}
18+
19+
render() {
20+
return (
21+
<div>
22+
<AddTodo />
23+
<VisibleTodoList />
24+
<Footer />
25+
</div>
26+
);
27+
}
28+
}
29+
30+
export default connect()(App);

client/src/components/footer.jsx

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import React from 'react'
2+
import FilterLink from '../containers/filterlink.jsx'
3+
4+
const Footer = () => (
5+
<p>
6+
Show:
7+
{" "}
8+
<FilterLink filter="SHOW_ALL">
9+
All
10+
</FilterLink>
11+
{", "}
12+
<FilterLink filter="SHOW_ACTIVE">
13+
Active
14+
</FilterLink>
15+
{", "}
16+
<FilterLink filter="SHOW_COMPLETED">
17+
Completed
18+
</FilterLink>
19+
</p>
20+
)
21+
22+
export default Footer

client/src/components/link.jsx

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import React, { PropTypes } from 'react'
2+
3+
const Link = ({ active, children, onClick }) => {
4+
if (active) {
5+
return <span>{children}</span>
6+
}
7+
8+
return (
9+
<a href="#"
10+
onClick={e => {
11+
e.preventDefault()
12+
onClick()
13+
}}
14+
>
15+
{children}
16+
</a>
17+
)
18+
}
19+
20+
Link.propTypes = {
21+
active: PropTypes.bool.isRequired,
22+
children: PropTypes.node.isRequired,
23+
onClick: PropTypes.func.isRequired
24+
}
25+
26+
export default Link

client/src/components/todo.jsx

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import React, { PropTypes } from 'react'
2+
3+
const Todo = ({ onClick, deleteTodo, updateTodo, todo }) => (
4+
<li>
5+
<span
6+
style={{
7+
textDecoration: todo.completed? 'line-through': 'none'
8+
}}
9+
onClick={onClick}>{todo.title}</span>
10+
11+
<a href="#" style={{
12+
marginLeft: "10px",
13+
textDecoration: todo.completed? 'line-through': 'none'
14+
}}
15+
onClick={e => {
16+
e.preventDefault()
17+
todo.completed = !todo.completed
18+
updateTodo()
19+
}}>(complete)</a>
20+
21+
<a href="#" style={{
22+
marginLeft: "10px"
23+
}}
24+
onClick={e => {
25+
e.preventDefault()
26+
deleteTodo()
27+
}}>(delete)</a>
28+
</li>
29+
)
30+
31+
Todo.propTypes = {
32+
onClick: PropTypes.func.isRequired,
33+
deleteTodo: PropTypes.func.isRequired,
34+
updateTodo: PropTypes.func.isRequired,
35+
todo: PropTypes.object.isRequired
36+
}
37+
38+
export default Todo

0 commit comments

Comments
 (0)