Skip to content

Instantly share code, notes, and snippets.

@kristian76
Last active November 22, 2016 17:16
Show Gist options
  • Save kristian76/a41bac0b5a03856337c793008ab55753 to your computer and use it in GitHub Desktop.
Save kristian76/a41bac0b5a03856337c793008ab55753 to your computer and use it in GitHub Desktop.
task board made with rect
/**
* index.js
*/
"use strict";
// Require app specific CSS
require('./app.css');
import React from 'react';
import ReactDOM from 'react-dom';
// Stores a userfriendly message
const TASK_STATUS = {
to_do: 'To Do',
in_progress: 'In Progress',
done: 'Done'
};
function futureDate() {
return (new Date()).getTime() + ((Math.random() * 30) * 25*60*60*1000);
}
class Task extends React.Component {
constructor(props) {
super(props);
this.state = {
name: '',
owner: '',
due: '',
status: ''
};
this.changeStatus = this.changeStatus.bind(this);
}
componentDidMount() {
// this.setState(this.props);
}
componentWillMount() {
this.setState(this.props.data);
}
changeStatus(e) {
e.preventDefault();
this.props.onUpdate(this.state);
}
render() {
let dueDate = new Date(this.state.due);
let local = {
day: 'numeric',
year: '2-digit',
month: 'short'
};
let taskStatusView = Object.keys(TASK_STATUS).map((key) => {
return <div className="mdl-cell mdl-cell--4-col" key={ key } onClick={ this.changeStatus }>
{ TASK_STATUS[key] }
</div>
});
return <div className="mdl-grid mdl-grid--no-spacing data-row">
<div className="mdl-cell mdl-cell--4-col">{ this.state.name }</div>
<div className="mdl-cell mdl-cell--2-col">
{ this.state.owner }
</div>
<div className="mdl-cell mdl-cell--2-col">{ dueDate.toLocaleString('da-DK', local) }</div>
<div className="mdl-cell mdl-cell--4-col mdl-grid mdl-grid--no-spacing">
{ taskStatusView }
</div>
</div>;
}
}
class Board extends React.Component {
constructor(props) {
super(props);
this.state = {
tasks: []
};
this.updateTask = this.updateTask.bind(this);
this.addTask = this.addTask.bind(this);
}
updateTask(payLoad) {
this.props.onTaskUpdate(payLoad);
}
addTask(e) {
e.preventDefault();
this.props.onTaskUpdate({
board: this.props.name
});
}
render() {
this.props.tasks.sort((a, b) => {
if (a.due < b.due) {
return -1;
}
if (a.due > b.due) {
return 1;
}
return 0;
});
let tasks = this.props.tasks.map((task, key) => {
let obj = task;
obj.board = this.props.name;;
return <Task data={ obj } key={key} onUpdate={ this.updateTask } />
});
return <div className="mdl-grid">
<div className="mdl-cell mdl-cell--12-col">
<div className="mdl-grid">
<div className="mdl-cell mdl-cell--4-col data-row-title">{ this.props.name }</div>
<div className="mdl-cell mdl-cell--2-col data-row-title">Owner</div>
<div className="mdl-cell mdl-cell--2-col data-row-title">Due</div>
<div className="mdl-cell mdl-cell--4-col data-row-title">Status</div>
</div>
<div className="mdl-grid">
<div className="mdl-cell mdl-cell--12-col">
{ tasks }
</div>
</div>
</div>
<div className="mdl-cell mdl-cell--2-col mdl-cell--10-offset">
<button type="button" className="mdl-button mdl-js-button mdl-button--raised mdl-button--colored"
onClick={ this.addTask }>Add Task</button>
</div>
</div>;
}
}
/**
* App
*/
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
visible: false,
dialog: {
data: {},
open: false
},
boarddialog: {
data: {},
open: false
}
};
this.handleTaskUpdate = this.handleTaskUpdate.bind(this);
this.addBoard = this.addBoard.bind(this);
}
componentDidMount() {
let stub = [
{
"name": "board 1",
"tasks": [
{
"name": "super",
"id": 1,
"owner": "superman",
"status": "in_progress",
"due": futureDate()
},
{
"name": "nice",
"id": 2,
"owner": "batman",
"status": "to_do",
"due": futureDate()
},
{
"name": "awesome",
"id": 3,
"owner": "cat woman",
"status": "done",
"due": futureDate()
},
{
"name": "sweet",
"id": 4,
"owner": "hulk",
"status": "to_do",
"due": futureDate()
},
]
},
{
"name": "board 2",
"tasks": [
{
"name": "super",
"id": 5,
"owner": "superman",
"status": "in_progress",
"due": futureDate()
},
{
"name": "nice",
"id": 6,
"owner": "batman",
"status": "to_do",
"due": futureDate()
},
{
"name": "awesome",
"id": 7,
"owner": "cat woman",
"status": "done",
"due": futureDate()
},
{
"name": "sweet",
"id": 8,
"owner": "hulk",
"status": "on_hold",
"due": futureDate()
},
]
},
];
this.setState({ data: stub });
}
handleTaskUpdate(payload) {
// Receive task data, set state and open dialog
this.setState({
dialog: {
open: true,
data: payload,
title: 'Update'
}
});
}
saveTask(data) {
console.log('saving task', data);
}
addBoard(e) {
e.preventDefault();
this.setState({
boarddialog: {
open: true,
data: {}
}
});
}
render() {
// console.log(this.state);
// Render all boards
let boards = this.state.data.map((board, id) => {
return <Board key={id} tasks={board.tasks} name={board.name} onTaskUpdate={ this.handleTaskUpdate } />
});
let boardNames = this.state.data.map((board, id) => {
return <button className="mdl-chip" key={ id }>
<span className="mdl-chip__text">
{ board.name }
</span>
<a href="#" className="mdl-chip__action">
<i className="material-icons">sort</i>
</a>
</button>;
});
return <div className="mdl-layout mdl-js-layout mdl-layout--fixed-header is-upgraded">
<header className="mdl-layout__header is-casting-shadow mdl-color--grey-100 mdl-color-text--grey-600">
<div className="mdl-layout__header-row">
<span className="mdl-layout-title">Title</span>
</div>
</header>
<div className="mdl-layout__drawer">
<header>
<button className="mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--icon"></button>
</header>
<nav className="mdl-navigation">
<a href="" className="mdl-navigation__link">Hello</a>
</nav>
</div>
<main className="mdl-layout__content">
<div className="mdl-grid">
<div className="mdl-cell mdl-cell--12-col">
<button className="mdl-button mdl-js-button mdl-button--raised mdl-button--colored" onClick={ this.addBoard.bind(this) }>Add Board</button>
</div>
</div>
<div className="mdl-grid">
<div className="mdl-cell mdl-cell--12-col">
{ boards }
</div>
</div>
</main>
<TaskDialog open={ this.state.dialog.open } data={ this.state.dialog.data } onSave={ this.saveTask.bind(this) } />
<BoardDialog open={ this.state.boarddialog.open } data={ this.state.boarddialog.data } />
</div>;
}
}
/**
* UI Components
*/
class UIComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
open: false,
data: null
};
}
_hideUI() {
this.setState({open: false});
}
componentWillReceiveProps(nextProps) {
if (this.state !== nextProps) {
this.setState(nextProps);
}
}
}
class BoardDialog extends UIComponent {
handleSave(e) {
}
handleCancel(e) {
this._hideUI();
}
render() {
return <dialog className="mdl-dialog" id="dialog" open={ this.state.open } ref={(dialog) => this.dialog = dialog}>
<h3 className="mdl-dialog__title">Task</h3>
<div className="mdl-dialog__content">
hello
</div>
<div className="mdl-dialog__actions">
<button type="button" className="mdl-button" onClick={ this.handleSave.bind(this) }>Save</button>
<button type="button" className="mdl-button" onClick={ this.handleCancel.bind(this) }>Cancel</button>
</div>
</dialog>;
}
}
class TaskDialog extends UIComponent {
handleSave(e) {
e.preventDefault();
this.props.onSave(this.state.data);
this._hideUI();
}
handleCancel(e) {
e.preventDefault();
this._hideUI();
}
changeDue(e) {
// FIXME handle date format
let data = this.state.data;
data.due = parseFloat(e.target.value);
this.setState({data: data});
}
changeName(e) {
let data = this.state.data;
data.name = e.target.value;
this.setState({data: data});
}
changeOwner(e) {
let data = this.state.data;
data.owner = e.target.value;
this.setState({data: data});
}
changeStatus(e) {
let data = this.state.data;
data.status = e.target.value;
this.setState({data: data});
}
render() {
// console.log(this.state);
let form = <form></form>;
if (this.state.data !== null) {
form = <form>
<div className="mdl-textfield mdl-js-textfield is-upgraded">
<input className="mdl-textfield__input" type="text"
value={ this.state.data.due } onChange={ this.changeDue.bind(this) } />
<label className="mdl-textfield__label">Due</label>
</div>
<div className="mdl-textfield mdl-js-textfield is-upgraded">
<input className="mdl-textfield__input" type="text"
value={ this.state.data.name } onChange={ this.changeName.bind(this) } />
<label className="mdl-textfield__label">Name</label>
</div>
<div className="mdl-textfield mdl-js-textfield is-upgraded">
<input className="mdl-textfield__input" type="text"
value={ this.state.data.owner } onChange={ this.changeOwner.bind(this) } />
<label className="mdl-textfield__label">Owner</label>
</div>
<div className="mdl-textfield mdl-js-textfield is-upgraded">
<input className="mdl-textfield__input" list="status"
value={ this.state.data.status } onChange={ this.changeStatus.bind(this) } />
<datalist id="status">
<option value="to_do"/>
<option value="in_progress"/>
<option value="on_hold"/>
<option value="done" />
</datalist>
</div>
</form>;
}
return <dialog className="mdl-dialog" id="dialog" open={ this.state.open } ref={(dialog) => this.dialog = dialog}>
<h3 className="mdl-dialog__title">Task</h3>
<div className="mdl-dialog__content">
{ form }
</div>
<div className="mdl-dialog__actions">
<button type="button" className="mdl-button" onClick={ this.handleSave.bind(this) }>Save</button>
<button type="button" className="mdl-button" onClick={ this.handleCancel.bind(this) }>Cancel</button>
</div>
</dialog>;
}
}
const ROOT = document.getElementById('appmount');
ROOT.setAttribute('class', 'mdl-layout__container');
ReactDOM.render(
<App />,
ROOT
);
{
"name": "plana",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node server.js"
},
"author": "",
"license": "ISC",
"dependencies": {
}
}
var path = require('path'),
webpack = require('webpack');
module.exports = {
devtool: 'source-map',
target: 'web',
node: {
fs: 'empty'
},
entry: {
dafuck: __dirname +'/dafuck/src/index.js'
},
output: {
path: __dirname, filename: '[name]/dist/js/bundle.js'
},
module: {
loaders: [
{
test: /.js?$/,
loader: 'babel-loader',
exclude: /node_modules/,
query: {
presets: ['es2015', 'react']
}
},
{
test: /\.json$/,
loader: 'json'
},
{
test: /\.css$/,
loader: 'style-loader!css-loader'
}
]
},
plugins: [
new webpack.DefinePlugin({ "global.GENTLY": false })
]
};
@kristian76
Copy link
Author

@kristian76
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment