Tankernn 8 лет назад
Родитель
Сommit
ee0dcb3cdd
7 измененных файлов с 307 добавлено и 0 удалено
  1. 10 0
      .gitignore
  2. 17 0
      css/style.css
  3. 16 0
      index.html
  4. 163 0
      js/index.js
  5. 33 0
      package.json
  6. 46 0
      php/api.php
  7. 22 0
      webpack.config.js

+ 10 - 0
.gitignore

@@ -1,3 +1,13 @@
+# Compiled js
+bundle.js
+
+# Atom Remote-FTP
+.ftpconfig
+.ftpignore
+
+# DB settings
+php/db.php
+
 # Logs
 logs
 *.log

+ 17 - 0
css/style.css

@@ -0,0 +1,17 @@
+main {
+  width: 80%;
+  margin: auto;
+}
+
+div.item {
+  background-color: aliceblue;
+  border-radius: 0 10px 10px 0;
+  border-left: 10px solid blue;
+  padding: 10px;
+  margin-bottom: 10px;
+}
+
+form textarea {
+  width: 100%;
+  height: 100px;
+}

+ 16 - 0
index.html

@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <meta charset="utf-8" />
+    <title>Tankernn.eu TODO-list</title>
+    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
+    <link href="css/style.css" rel="Stylesheet" type="text/css"/>
+</head>
+
+<body>
+    <div id="content"></div>
+    <script type="text/javascript" src="bundle.js"></script>
+</body>
+
+</html>

+ 163 - 0
js/index.js

@@ -0,0 +1,163 @@
+var React = require('react');
+var ReactDOM = require('react-dom');
+var Remarkable = require('remarkable');
+var DatePicker = require('react-datepicker');
+require('react-datepicker/dist/react-datepicker.css');
+var Bootstrap = require('react-bootstrap');
+var moment = require('moment');
+var $ = require('jquery');
+
+var TodoForm = React.createClass({
+  getInitialState: function() {
+    return {title: '', text: '', deadline: moment(), priority: '1'};
+  },
+  handleTitleChange: function(e) {
+    this.setState({title: e.target.value});
+  },
+  handleDateChange: function(date) {
+    this.setState({deadline: date});
+  },
+  handlePriorityChange: function(e) {
+    this.setState({priority: e.target.value});
+  },
+  handleTextChange: function(e) {
+    this.setState({text: e.target.value});
+  },
+  handleSubmit: function(e) {
+    e.preventDefault();
+    var title = this.state.title.trim();
+    var text = this.state.text.trim();
+    var priority = this.state.priority;
+    var deadline = this.state.deadline._d.toLocaleDateString();
+    console.log(deadline);
+    if (!title || !text || !deadline) {
+      return;
+    }
+    this.props.onCommentSubmit({a: 'add', title: title, text: text, deadline: deadline, priority: priority});
+    this.setState({title: '', text: '', deadline: moment(), priority: '1'});
+  },
+  render: function() {
+    return (
+      <form className="form-inline" name="todoForm" onSubmit={this.handleSubmit}>
+        <input
+          className="form-control"
+          type="text"
+          placeholder="Title"
+          value={this.state.title}
+          onChange={this.handleTitleChange}
+        />
+        <select className="form-control" value={this.state.priority} onChange={this.handlePriorityChange}>
+          <option value="1">First priority</option>
+          <option value="2">Second priority</option>
+          <option value="3">Not very important</option>
+          <option value="4">Only if you are bored</option>
+        </select>
+        <DatePicker
+          placeholder="yyyy-mm-dd"
+          selected={this.state.deadline}
+          onChange={this.handleDateChange}
+        />
+        <br />
+        <textarea
+          className="form-control"
+          value={this.state.text}
+          onChange={this.handleTextChange}>
+        </textarea>
+        <br />
+        <input className="btn btn-primary" type="submit" value="Add" />
+      </form>
+    );
+  }
+});
+
+var LoginForm = React.createClass({
+  render: function() {
+    return (
+      <a href="http://tankernn.eu/login?redirect=http://todo.tankernn.eu">Log In</a>
+    );
+  }
+});
+
+var Item = React.createClass({
+  rawMarkup: function() {
+    var md = new Remarkable();
+    var rawMarkup = md.render(this.props.children.toString());
+    return { __html: rawMarkup };
+  },
+  render: function() {
+    var md = new Remarkable();
+    return (
+      <div className="item">
+        <h2>{this.props.title}</h2>
+        <span dangerouslySetInnerHTML={this.rawMarkup()} />
+      </div>
+    );
+  }
+});
+
+var TodoList = React.createClass({
+  render: function() {
+    console.log(this.props.list);
+    var itemList = this.props.list.map(function(item) {
+      return (
+        <Item priority={item.priority} title={item.title} key={item.id}>
+          {item.description}
+        </Item>
+      );
+    });
+    return (
+      <div className="list">
+        {itemList}
+      </div>
+    );
+  }
+});
+
+var App = React.createClass({
+  getInitialState: function() {
+    return {list: []};
+  },
+  componentDidMount: function() {
+    $.ajax({
+      url: this.props.url,
+      dataType: 'json',
+      type: 'GET',
+      success: function(data) {
+        this.setState({list: data.list});
+      }.bind(this),
+      error: function(xhr, status, err) {
+        console.error(this.props.url, status, err.toString());
+      }.bind(this)
+    });
+  },
+  handleCommentSubmit: function(comment) {
+    $.ajax({
+      url: this.props.url,
+      dataType: 'json',
+      cache: false,
+      type: 'POST',
+      data: comment,
+      success: function(data) {
+        if (data.result != 0) {
+          console.log("Error in API: " + data.result);
+        }
+        this.setState({list: data.list});
+      }.bind(this),
+      error: function(xhr, status, err) {
+        console.error(this.props.url, status, err.toString());
+      }.bind(this)
+    });
+  },
+  render: function() {
+    return (
+      <main>
+        <h1>Tankernn TODO list</h1>
+        <TodoForm onCommentSubmit={this.handleCommentSubmit} />
+        <TodoList list={this.state.list} />
+        <LoginForm />
+      </main>
+    );
+  }
+});
+
+ReactDOM.render(<App url="/php/api.php" />, document.getElementById('content'));

+ 33 - 0
package.json

@@ -0,0 +1,33 @@
+{
+  "name": "todo-app",
+  "version": "1.0.0",
+  "description": "A simple TODO-app.",
+  "main": "index.js",
+  "dependencies": {
+    "babel-preset-react": "^6.16.0",
+    "babelify": "^7.3.0",
+    "jquery": "^3.1.1",
+    "moment": "^2.15.1",
+    "react": "^15.3.2",
+    "react-bootstrap": "^0.30.6",
+    "react-datepicker": "^0.32.0",
+    "react-dom": "^15.3.2",
+    "remarkable": "^1.7.1",
+    "style-loader": "^0.13.1"
+  },
+  "devDependencies": {
+    "babel-core": "^6.4.5",
+    "babel-loader": "^6.2.1",
+    "babel-preset-es2015": "^6.3.13",
+    "babel-preset-react": "^6.3.13",
+    "css-loader": "^0.25.0",
+    "webpack": "^1.13.2"
+  },
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1",
+    "build": "browserify -t [ babelify --presets [ react ] ] -t browserify-css src/index.js -o build/app.js",
+    "start": "webpack-dev-server --progress --colors"
+  },
+  "author": "Tankernn",
+  "license": "ISC"
+}

+ 46 - 0
php/api.php

@@ -0,0 +1,46 @@
+<?php
+  session_name('default');
+  session_set_cookie_params(0, '/', '.tankernn.eu');
+  session_start();
+
+  // Database settings
+  require ("db.php");
+
+  $data = new StdClass();
+
+  if (!isset($_SESSION['userid'])) {
+    $data->result = 1;
+  } else {
+    $userid = $_SESSION['userid'];
+    if (!isset($_POST['a'])) {
+      $data->result = 2;
+    } else {
+      switch ($_POST['a']) {
+        case 'add':
+          $title = $_POST['title'];
+          $text = $_POST['text'];
+          $deadline = $_POST['deadline'];
+          $priority = $_POST['priority'];
+
+          $sql = "INSERT INTO Todo (userid, priority, deadline, title, description) VALUES ($userid, $priority, $deadline, '$title', '$text')";
+
+          $data->result = $conn->query($sql) ? 0 : $conn->error;
+
+          break;
+        case 'rm':
+          $id = $_GET['id'];
+
+          $sql = "DELETE FROM Todo WHERE id=$id";
+          break;
+      }
+    }
+    $sql = "SELECT * FROM Todo WHERE userid=$userid";
+    $query = $conn->query($sql);
+    $data->list = array();
+    while ($row = $query->fetch_array()) {
+      array_push($data->list, $row);
+    }
+  }
+
+  echo json_encode($data);
+?>

+ 22 - 0
webpack.config.js

@@ -0,0 +1,22 @@
+var path = require('path');
+var webpack = require('webpack');
+
+var BUILD_DIR = path.resolve(__dirname, 'build');
+
+module.exports = {
+  entry: './js/index.js',
+  output: { path: __dirname, filename: 'bundle.js' },
+  module: {
+    loaders: [
+      {
+        test: /.jsx?$/,
+        loader: 'babel-loader',
+        exclude: /node_modules/,
+        query: {
+          presets: ['es2015', 'react']
+        }
+      },
+      { test: /\.css$/, loader: "style-loader!css-loader?root=." },
+    ]
+  },
+};