Skip to content

Commit

Permalink
init commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Péter Hauszknecht committed Jul 12, 2017
0 parents commit a0ebaf0
Show file tree
Hide file tree
Showing 13 changed files with 391 additions and 0 deletions.
8 changes: 8 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"plugins": [
"transform-react-jsx",
"transform-object-rest-spread",
"transform-es2015-modules-commonjs",
"transform-class-properties"
]
}
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package-lock.json
node_modules
lib
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# repatch-example-electron-app

## Running the example

```
npm install
npm run build
npm start
```

## Autobuild

```
npm run build:w
```
17 changes: 17 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8">
<title>Hello World!</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>

<body>
<div id="app"></div>
</body>
<script>
require('./lib/index')
</script>

</html>
51 changes: 51 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{
"name": "repatch-example-electron-app",
"version": "0.0.1",
"description": "Todo electron app to representing repatch",
"main": "lib/main",
"scripts": {
"babel": "babel src -d lib",
"babel:w": "babel src -d lib -w",
"build": "rm -rf lib && npm run babel",
"build:w": "npm run babel:w",
"start": "electron lib/main",
"start-prod": "NODE_ENV=production npm start"
},
"authors": [
"Péter Hauszknecht <[email protected]> (https://github.com/jayhasyee)"
],
"keywords": [
"dispatch",
"redux",
"reducer",
"state",
"predictable",
"functional",
"immutable",
"flux"
],
"repository": {
"type": "git",
"url": "https://github.com/jaystack/repatch-example-electron-app.git"
},
"license": "MIT",
"bugs": {
"url": "https://github.com/jaystack/repatch-example-electron-app/issues"
},
"dependencies": {
"electron": "^1.7.4",
"prop-types": "^15.5.10",
"react": "^15.6.1",
"react-dom": "^15.6.1",
"react-redux": "^5.0.5",
"redux": "^3.7.1",
"repatch": "0.0.11"
},
"devDependencies": {
"babel-cli": "^6.24.1",
"babel-plugin-transform-class-properties": "^6.24.1",
"babel-plugin-transform-es2015-modules-commonjs": "^6.24.1",
"babel-plugin-transform-object-rest-spread": "^6.23.0",
"babel-plugin-transform-react-jsx": "^6.24.1"
}
}
59 changes: 59 additions & 0 deletions src/actions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
function call(method, path, query, body) {
return () => async (dispatch, getState, api) => {
try {
return await api[path][method.toLowerCase()](query, body)
} catch (error) {
dispatch(state => ({ ...state, error: error.message }))
} finally {
dispatch(state => ({ ...state, isFetching: false }))
}
}
}

export function fetchTodos() {
return () => async dispatch => {
dispatch(cancelRemovingTodo())
const todos = await dispatch(call('GET', '/todos'))
dispatch(state => ({ ...state, todos }))
}
}

export function addTodo() {
return () => async dispatch => {
dispatch(cancelRemovingTodo())
await dispatch(call('POST', '/todos'))
await dispatch(fetchTodos())
}
}

export function updateTodo(id, message) {
return () => async dispatch => {
dispatch(cancelRemovingTodo())
await dispatch(call('PUT', '/todos', { id }, { message }))
await dispatch(fetchTodos())
}
}

export function checkTodo(id) {
return () => async dispatch => {
dispatch(cancelRemovingTodo())
await dispatch(call('PATCH', '/todos', { id }))
await dispatch(fetchTodos())
}
}

export function removeTodo(removingTodoId) {
return state => ({ ...state, removingTodoId })
}

export function cancelRemovingTodo() {
return state => ({ ...state, removingTodoId: null })
}

export function confirmRemovingTodo() {
return () => async (dispatch, getState) => {
const id = getState().removingTodoId
await dispatch(call('DELETE', '/todos', { id }))
await dispatch(fetchTodos())
}
}
38 changes: 38 additions & 0 deletions src/api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
const todos = [
{
id: Math.random().toString(),
message: 'shopping',
checked: false
},
{
id: Math.random().toString(),
message: 'carwash',
checked: false
},
{
id: Math.random().toString(),
message: 'haircut',
checked: true
}
]

export default {
'/todos': {
get: async () => JSON.parse(JSON.stringify(todos)),
post: async () => {
todos.push({ id: Math.random().toString(), message: '', checked: false })
},
put: async ({ id }, { message }) => {
const todo = todos.find(todo => todo.id === id)
todo.message = message
},
patch: async ({ id }) => {
const todo = todos.find(todo => todo.id === id)
todo.checked = !todo.checked
},
delete: async ({ id }) => {
const todoIndex = todos.findIndex(todo => todo.id === id)
todos.splice(todoIndex, 1)
}
}
}
44 changes: 44 additions & 0 deletions src/components/App.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import * as React from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { fetchTodos, addTodo } from '../actions'
import Item from './Item'

class App extends React.PureComponent {
static propTypes = {
todos: PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.string,
message: PropTypes.string,
checked: PropTypes.bool
})
),
fetchTodos: PropTypes.func,
addTodo: PropTypes.func
}

componentDidMount() {
this.props.fetchTodos()
}

render() {
const { todos, addTodo } = this.props
return (
<div className="app">
{todos.map((todo, index) => <Item key={todo.id} todoIndex={index} />)}
<button onClick={() => addTodo()}>+</button>
</div>
)
}
}

const mapStateToProps = state => ({
todos: state.todos
})

const mapDispatchToProps = {
fetchTodos,
addTodo
}

export default connect(mapStateToProps, mapDispatchToProps)(App)
74 changes: 74 additions & 0 deletions src/components/Item.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import * as React from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import {
checkTodo,
updateTodo,
removeTodo,
cancelRemovingTodo,
confirmRemovingTodo
} from '../actions'

class Item extends React.PureComponent {
static propTypes = {
todoIndex: PropTypes.number,
todo: PropTypes.shape({
id: PropTypes.string,
message: PropTypes.string,
checked: PropTypes.bool
}),
isRemovingTodo: PropTypes.bool,
checkTodo: PropTypes.func,
updateTodo: PropTypes.func,
removeTodo: PropTypes.func,
cancelRemovingTodo: PropTypes.func,
confirmRemovingTodo: PropTypes.func
}

render() {
const {
todo: { id, message, checked },
isRemovingTodo,
checkTodo,
updateTodo,
removeTodo,
cancelRemovingTodo,
confirmRemovingTodo
} = this.props
return (
<div className="item">
<input
type="checkbox"
checked={checked}
onChange={() => checkTodo(id)}
/>
<input
type="text"
value={message}
onChange={evt => updateTodo(id, evt.target.value)}
/>
{isRemovingTodo
? <span>
<button onClick={() => confirmRemovingTodo()}>YES</button>
<button onClick={() => cancelRemovingTodo()}>NO</button>
</span>
: <button onClick={() => removeTodo(id)}>X</button>}
</div>
)
}
}

const mapStateToProps = (state, { todoIndex }) => ({
todo: state.todos[todoIndex],
isRemovingTodo: state.removingTodoId === state.todos[todoIndex].id
})

const mapDispatchToProps = {
checkTodo,
updateTodo,
removeTodo,
cancelRemovingTodo,
confirmRemovingTodo
}

export default connect(mapStateToProps, mapDispatchToProps)(Item)
12 changes: 12 additions & 0 deletions src/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import * as React from 'react'
import * as ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
import store from './store'
import App from './components/App'

ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('app')
)
57 changes: 57 additions & 0 deletions src/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { app, BrowserWindow } from 'electron'
import * as path from 'path'
import * as url from 'url'

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let win

function createWindow() {
// Create the browser window.
win = new BrowserWindow({ width: 800, height: 600 })

// and load the index.html of the app.
win.loadURL(
url.format({
pathname: path.join(__dirname, '../index.html'),
protocol: 'file:',
slashes: true
})
)

// Open the DevTools.
//win.webContents.openDevTools();

// Emitted when the window is closed.
win.on('closed', () => {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
win = null
})
}

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow)

// Quit when all windows are closed.
app.on('window-all-closed', () => {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
})

app.on('activate', () => {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (win === null) {
createWindow()
}
})

// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
Loading

0 comments on commit a0ebaf0

Please sign in to comment.