diff options
Diffstat (limited to 'front/index.jsx')
-rw-r--r-- | front/index.jsx | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/front/index.jsx b/front/index.jsx new file mode 100644 index 0000000..85b1977 --- /dev/null +++ b/front/index.jsx @@ -0,0 +1,172 @@ +import "preact/debug"; +import { get, post } from 'axios'; +import { Component, render, Fragment, h } from 'preact'; +import strftime from 'strftime'; +import { ConfigView, Config } from './config.jsx' +/** @jsx h */ +/** @jsxFrag Fragment */ + +/* naive. assumes: + year = 365 days, + day = 24 hrs, + hr = 60 mins, + min = 60 secs +*/ +function format_relative_naive(date) { + const sec = 1000; + const min = 60 * sec; + const hr = 60 * min; + const day = 24 * hr; + let now = new Date(); + let ms_diff = date - now; + if (Math.abs(ms_diff) < 2 * min) { + return `${Math.round(ms_diff / sec)}s`; + } else if (Math.abs(ms_diff) < 2 * hr) { + return `${Math.round(ms_diff / min)}m`; + } else if (Math.abs(ms_diff) < 2 * day) { + return `${Math.round(ms_diff / hr)}h`; + } else { + return `${Math.round(ms_diff / day)}d`; + } +} + + +class TodoList extends Component { + constructor() { + super(); + this.state = { todos: [] }; + } + + componentWillMount() { + get("/todos").then(resp => { + let todos = resp.data.todos; + todos.sort((todo1, todo2) => { return todo1.expires - todo2.expires; }) + this.setState({ todos: resp.data.todos }) + }) + } + + render({ config }, { todos }) { + let { datefmt, timezoneOffset } = config; + return <table class="table table-hover"> + <thead> + <tr> + <td></td> + <td>what</td> + <td>when</td> + <td>left</td> + </tr> + </thead> + <tbody> + {todos.map(todo => { + return <TodoRow + dateFormatter={date => strftime("%H:%M", date)} + done={todo.done} + desc={todo.desc} + display_date={new Date(todo.expires)} + key={`todo-${todo.id}`} + id={todo.id} + /> + })} + </tbody> + </table>; + } +} + +class TodoRow extends Component { + constructor(props) { + super(props); + this.state = { id: props.id } + } + + deleteTodo(event) { + post("/delete-todo", { id: this.state.id }) + .then(resp => { + console.log(resp); + window.location.reload(); + }); + } + + render({ dateFormatter, done, desc, display_date, key }, { }) { + let status = done ? + <span class="i">DONE</span> + : <span class="d"> TODO</span> + return <tr key={key}> + <td><i class="twa twa-heart"></i> {status}</td> + <td>{desc}</td> + <td>{dateFormatter(display_date)}</td> + <td style={{textAlign: "right"}}>{format_relative_naive(display_date)}</td> + <td><a class="a-button" onClick={this.deleteTodo.bind(this)}><i class="twa twa-cross-mark"></i></a></td> + </tr> + } +} + +class PostForm extends Component { + constructor({ notify_list, config }) { + super(); + this.state = { + notify_list: notify_list, + desc: "", + date: config.getDefaultDate() }; + } + postTodo(event) { + if (this.state.desc.length == 0) { + return; + } + post( + "/new-todo", { + desc: this.state.desc, + expires: new Date(this.state.date).getTime(), + done: false + } + ) + .then((resp) => { + console.log(resp.data); + window.location.reload(); + }).catch((err) => { + console.log("err: "); + console.log(err); + }); + } + + render(props, state) { + let isEmpty = state.desc.length == 0; + const noop = _ => {}; + let aClasslist = `a-button ${isEmpty ? "a-button-disabled" : ""}` + return <> + <input + class="input-todo" + type="text" + onInput={e => this.setState({ desc: e.target.value })} + /> + <input + class="input-todo" + type="text" + onInput={e => this.setState({ date: e.target.value })} + value={this.state.date} + /> + <a class={aClasslist} onClick={isEmpty ? noop : this.postTodo.bind(this)}>post</a> + </> + } +} + +class App extends Component { + constructor() { + super(); + this.state = { config: new Config() }; + } + + changeConfig(newConfig) { + this.setState({ config: newConfig }); + } + + render({}, { config }) { + return <div> + <PostForm config={config} /> + <p style={{display: "inline"}}> | </p> + <ConfigView config={config} onChangeConfig={this.changeConfig} /> + <TodoList config={config} /> + </div> + } +} + +render(<App />, document.getElementById("root")); |