index.js 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. var React = require('react');
  2. var ReactDOM = require('react-dom');
  3. var Remarkable = require('remarkable');
  4. var Button = require('react-bootstrap').Button;
  5. var ButtonToolbar = require('react-bootstrap').ButtonToolbar;
  6. var FormControl = require('react-bootstrap').FormControl;
  7. var FormGroup = require('react-bootstrap').FormGroup;
  8. var Panel = require('react-bootstrap').Panel;
  9. var Modal = require('react-bootstrap').Modal;
  10. var DatePicker = require('react-bootstrap-date-picker');
  11. var dateFormat = require('dateformat');
  12. var $ = require('jquery');
  13. const API_URL = "https://todo.tankernn.eu/php/api.php";
  14. const priorityNames = {1: "danger", 2: "warning", 3: "info", 4: "success"};
  15. function dateToString(date) {
  16. return dateFormat(date, "yyyy-mm-dd");
  17. }
  18. var TodoForm = React.createClass({
  19. getInitialState: function() {
  20. return {showModal: false, title: this.props.title, text: this.props.text, deadline: this.props.deadline, priority: this.props.priority};
  21. },
  22. getDefaultProps: function() {
  23. return {edit: false};
  24. },
  25. closeModal() {
  26. this.setState({ showModal: false });
  27. },
  28. openModal() {
  29. this.setState({ showModal: true });
  30. },
  31. handleTitleChange: function(e) {
  32. this.setState({title: e.target.value});
  33. },
  34. handleDateChange: function(dateString) {
  35. this.setState({deadline: dateString});
  36. console.log(dateToString(dateString));
  37. },
  38. handlePriorityChange: function(e) {
  39. this.setState({priority: e.target.value});
  40. },
  41. handleTextChange: function(e) {
  42. this.setState({text: e.target.value});
  43. },
  44. handleSubmit: function(e) {
  45. e.preventDefault();
  46. var title = this.state.title.trim();
  47. var text = this.state.text.trim();
  48. var priority = this.state.priority;
  49. var deadline = dateToString(this.state.deadline);
  50. console.log(deadline);
  51. if (!title || !text || !deadline) {
  52. return;
  53. }
  54. this.props.onCommentSubmit({a: (this.props.edit ? 'edit' : 'add'), id: -1, title: title, text: text, deadline: deadline, priority: priority});
  55. this.closeModal();
  56. if (!this.props.edit)
  57. this.setState(this.getInitialState());
  58. },
  59. render: function() {
  60. return (
  61. <div>
  62. <Button bsStyle="primary" onClick={this.openModal}>{this.props.edit ? "Edit" : "Add"}</Button>
  63. <Modal show={this.state.showModal} onHide={this.closeModal}>
  64. <form name="todoForm" onSubmit={this.handleSubmit}>
  65. <Modal.Header closeButton>
  66. <Modal.Title>TODO-Form</Modal.Title>
  67. </Modal.Header>
  68. <Modal.Body>
  69. <FormControl
  70. type="text"
  71. placeholder="Title"
  72. value={this.state.title}
  73. onChange={this.handleTitleChange}
  74. />
  75. <FormControl componentClass="select" value={this.state.priority} onChange={this.handlePriorityChange}>
  76. <option value={1}>First priority</option>
  77. <option value={2}>Second priority</option>
  78. <option value={3}>Not very important</option>
  79. <option value={4}>Only if you are bored</option>
  80. </FormControl>
  81. <DatePicker
  82. value={this.state.deadline}
  83. onChange={this.handleDateChange}
  84. />
  85. <br />
  86. <FormControl
  87. componentClass="textarea"
  88. value={this.state.text}
  89. onChange={this.handleTextChange} />
  90. </Modal.Body>
  91. <Modal.Footer>
  92. <ButtonToolbar>
  93. <Button bsStyle="primary" type="submit">Save</Button>
  94. <Button onClick={this.closeModal}>Cancel</Button>
  95. </ButtonToolbar>
  96. </Modal.Footer>
  97. </form>
  98. </Modal>
  99. </div>
  100. );
  101. }
  102. });
  103. var Item = React.createClass({
  104. rawMarkup: function() {
  105. var md = new Remarkable();
  106. var rawMarkup = md.render(this.props.children.toString());
  107. return { __html: rawMarkup };
  108. },
  109. handleEditSubmit: function(data) {
  110. data.a = 'edit';
  111. data.id = this.props.id;
  112. this.props.handleEditSubmit(data);
  113. },
  114. handleDeleteClick: function() {
  115. console.log("Deleting " + this.props.id);
  116. this.props.handleDeleteClick(this.props.id);
  117. },
  118. render: function() {
  119. var md = new Remarkable();
  120. var daysLeft = Math.ceil((new Date(this.props.deadline) - new Date()) / (1000 * 60 * 60 * 24));
  121. if (isNaN(daysLeft)) {
  122. daysLeft = "No deadline.";
  123. } else if (daysLeft > 1) {
  124. daysLeft += " days left.";
  125. } else if (daysLeft == 1) {
  126. daysLeft = "One day left.";
  127. } else if (daysLeft == 0) {
  128. daysLeft = "Deadline today!";
  129. } else {
  130. daysLeft = "Should have been done " + Math.abs(daysLeft) + " day(s) ago."
  131. }
  132. var deadline = new Date(this.props.deadline);
  133. if (isNaN(deadline))
  134. deadline = new Date();
  135. var todoForm = <TodoForm
  136. title={this.props.title}
  137. text={this.props.children.toString()}
  138. deadline={deadline.toISOString()}
  139. priority={this.props.priority}
  140. onCommentSubmit={this.handleEditSubmit}
  141. edit={true}
  142. />;
  143. return (
  144. <Panel
  145. header={<header><span className="deadline">{daysLeft}</span><h3>{this.props.title}</h3></header>}
  146. footer={
  147. <ButtonToolbar>
  148. {todoForm}
  149. <Button bsStyle="danger" onClick={this.handleDeleteClick}>Delete</Button>
  150. </ButtonToolbar>
  151. }
  152. bsStyle={priorityNames[this.props.priority]}
  153. >
  154. <span dangerouslySetInnerHTML={this.rawMarkup()} />
  155. </Panel>
  156. );
  157. }
  158. });
  159. var TodoList = React.createClass({
  160. render: function() {
  161. console.log(this.props.list);
  162. var onDeleteClick = this.props.onDeleteClick;
  163. var handleEditSubmit = this.props.handleEditSubmit;
  164. var itemList = this.props.list.map(function(item) {
  165. return (
  166. <Item handleDeleteClick={onDeleteClick} handleEditSubmit={handleEditSubmit} priority={item.priority} title={item.title} id={item.id} key={item.id} deadline={item.deadline}>
  167. {item.description}
  168. </Item>
  169. );
  170. });
  171. return (
  172. <div className="list">
  173. {itemList}
  174. </div>
  175. );
  176. }
  177. });
  178. var App = React.createClass({
  179. getInitialState: function() {
  180. return {list: [], result: 0};
  181. },
  182. updateList: function() {
  183. $.ajax({
  184. url: this.props.url,
  185. dataType: 'json',
  186. type: 'GET',
  187. success: function(data) {
  188. // Not logged in
  189. if (data.result == 1) {
  190. document.location.href = "https://tankernn.eu/login/";
  191. }
  192. // Success
  193. this.setState({list: data.list, result: data.result});
  194. }.bind(this),
  195. error: function(xhr, status, err) {
  196. console.error(this.props.url, status, err.toString());
  197. }.bind(this)
  198. });
  199. },
  200. componentDidMount: function() {
  201. this.updateList();
  202. },
  203. handleCommentSubmit: function(comment) {
  204. $.ajax({
  205. url: this.props.url,
  206. dataType: 'json',
  207. cache: false,
  208. type: 'POST',
  209. data: comment,
  210. success: function(data) {
  211. if (data.result != 0) {
  212. console.log("Error in API: " + data.result);
  213. }
  214. if (data.hasOwnProperty("message")) {
  215. console.log("API message: " + data.message);
  216. }
  217. this.setState({list: data.list, result: data.result});
  218. }.bind(this),
  219. error: function(xhr, status, err) {
  220. console.error(this.props.url, status, err.toString());
  221. this.setState({result: 1});
  222. }.bind(this)
  223. });
  224. },
  225. handleDelete: function(id) {
  226. $.ajax({
  227. url: this.props.url,
  228. dataType: 'json',
  229. cache: false,
  230. type: 'POST',
  231. data: {a: 'rm', id: id},
  232. success: function(data) {
  233. this.setState({list: data.list, result: data.result});
  234. }.bind(this),
  235. error: function(xhr, status, err) {
  236. console.error(this.props.url, status, err.toString());
  237. }.bind(this)
  238. });
  239. },
  240. render: function() {
  241. return (
  242. <main>
  243. <h1>Tankernn TODO list</h1>
  244. <TodoForm title={""} text={""} deadline={new Date().toISOString()} priority={1} onCommentSubmit={this.handleCommentSubmit} />
  245. <TodoList onDeleteClick={this.handleDelete} handleEditSubmit={this.handleCommentSubmit} list={this.state.list} />
  246. </main>
  247. );
  248. }
  249. });
  250. ReactDOM.render(<App url={API_URL} />, document.getElementById('content'));