├── .gitignore ├── favicon.ico ├── src ├── index.css ├── index.js ├── Header.js ├── Utils.js ├── App.js ├── App.css ├── TaskCreator.js ├── TimeSlot.js ├── OtherTasks.js ├── logo.svg └── Day.js ├── package.json ├── LICENSE ├── README.md └── index.html /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitul45/ta-calendar/HEAD/favicon.ico -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | } 6 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | import './index.css'; 5 | 6 | ReactDOM.render( 7 | , 8 | document.getElementById('root') 9 | ); 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ta-calendar", 3 | "version": "0.0.1", 4 | "private": true, 5 | "devDependencies": { 6 | "react-scripts": "0.1.0" 7 | }, 8 | "dependencies": { 9 | "react": "^15.2.1", 10 | "react-dom": "^15.2.1" 11 | }, 12 | "scripts": { 13 | "start": "react-scripts start", 14 | "build": "react-scripts build", 15 | "eject": "react-scripts eject" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Header.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import logo from './logo.svg' 3 | 4 | var Header = React.createClass({ 5 | render() { 6 | return ( 7 |
8 | 9 |

ta – calendar

10 |
11 | ); 12 | } 13 | }) 14 | 15 | export default Header; 16 | -------------------------------------------------------------------------------- /src/Utils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Convert a number to human readable time. 3 | * 10.5 -> "10:30" 4 | * @param {Number} time 5 | * @returns {String} Human readable time 6 | */ 7 | function formatTime(time) { 8 | if (Number.isInteger(time)) 9 | return time + ":00"; 10 | else 11 | return ((time - 0.5) + ":30"); 12 | } 13 | 14 | const START_TIME = 9.5; 15 | const END_TIME = 18; 16 | const localStorageKey = 'calender_state'; 17 | const otherTaskStorageKey = 'other_tasks'; 18 | 19 | export default { 20 | formatTime, 21 | localStorageKey, 22 | otherTaskStorageKey, 23 | START_TIME, 24 | END_TIME 25 | } 26 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Base class 3 | */ 4 | import React from 'react'; 5 | import './App.css'; 6 | import Day from './Day'; 7 | import TaskCreator from './TaskCreator'; 8 | import Header from './Header'; 9 | import OtherTasks from './OtherTasks' 10 | 11 | var App = React.createClass({ 12 | 13 | addTask(name, duration, startTime) { 14 | this.refs.today.addTask(name, duration, startTime); 15 | }, 16 | 17 | render () { 18 | return ( 19 |
20 |
21 |
22 |
23 | 24 | 25 |
26 |
27 | 28 |
29 |
30 |
31 | ); 32 | } 33 | }) 34 | 35 | export default App; 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Mitul Shah 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | table, td, th { 2 | border: 1px solid #ddd; 3 | font-size: 14px; 4 | } 5 | 6 | table { 7 | border-collapse: collapse; 8 | text-align: center; 9 | width: 100%; 10 | margin-bottom: 20px; 11 | } 12 | 13 | th, td { 14 | padding: 15px; 15 | } 16 | 17 | th.time { 18 | width: 20%; 19 | } 20 | 21 | th.task { 22 | width: 80%; 23 | } 24 | 25 | .task-creator { 26 | display: flex; 27 | margin-bottom: 10px; 28 | } 29 | 30 | .task-creator__task-name { 31 | display: flex; 32 | flex-grow: 10; 33 | padding-right: 5px; 34 | } 35 | 36 | .task-creator__duration { 37 | display: flex; 38 | padding-right: 5px; 39 | } 40 | 41 | .task-creator__add-btn { 42 | display: flex; 43 | } 44 | 45 | .task-creator__start-time { 46 | flex-grow: 1; 47 | display: flex; 48 | padding-right: 5px; 49 | } 50 | 51 | .task-creator__task-name input { 52 | flex-grow: 1; 53 | } 54 | 55 | .task-creator__duration select { 56 | flex-grow: 1; 57 | } 58 | 59 | .task-creator__add-btn button { 60 | flex-grow: 1; 61 | } 62 | 63 | .task-creator__start-time select{ 64 | flex-grow: 1; 65 | } 66 | 67 | .time-slot__task { 68 | position: relative; 69 | text-align: left; 70 | } 71 | 72 | .time-slot__task:hover { 73 | cursor: pointer; 74 | } 75 | 76 | .time-slot__remove-btn { 77 | display: none; 78 | 79 | float: right; 80 | position: absolute; 81 | top: 15px; 82 | right: 15px; 83 | } 84 | 85 | .time-slot__task:hover .time-slot__remove-btn { 86 | display: block; 87 | } 88 | 89 | .time-slot__task--done { 90 | color: #CECECE; 91 | } 92 | 93 | .time-slot--active { 94 | background-color: aliceblue; 95 | } 96 | 97 | .header { 98 | margin-left: 5%; 99 | } 100 | 101 | .header__text { 102 | display: inline-block; 103 | height: 35px; 104 | vertical-align: super; 105 | } 106 | 107 | .header__logo { 108 | width: 35px; 109 | } 110 | 111 | .header__logo img { 112 | width: 35px; 113 | } 114 | 115 | .time-slot__task__name { 116 | padding-left: 15px; 117 | } 118 | 119 | .other-tasks__input { 120 | width: 100%; 121 | } 122 | 123 | .other-tasks__task-list { 124 | font-size: 14px; 125 | padding-left: 12px; 126 | } 127 | 128 | .other-tasks__task-list__item { 129 | margin: 5px; 130 | } 131 | 132 | .container { 133 | margin-left: 5%; 134 | margin-right: 5%; 135 | } 136 | 137 | .container--left { 138 | width: 70%; 139 | display: inline-block; 140 | } 141 | 142 | .container--right { 143 | width: 25%; 144 | float: right; 145 | } 146 | 147 | .time-slot__task__name--input { 148 | width: 80%; 149 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 📋 ta - calendar 2 | An app to plan your day, _every minute of your day_. Have you ever felt the day is about to be over and you haven't even started on the first thing to do? 3 | 4 | ## Motivation 5 | _"One of the most valuable skills in our economy is becoming increasingly rare."_ - [Cal Newport](http://calnewport.com/). 6 | 7 | [Deep work](https://www.goodreads.com/book/show/25744928-deep-work) is the ability to focus without distraction on a cognitively demanding task. It’s a skill that allows you to quickly master complicated information and produce better results in less time. Deep work will make you better at what you do and provide the sense of true fulfillment that comes from craftsmanship. It's like a superpower in our increasingly competitive twenty-first-century economy. 8 | 9 | One way to achieve deep work is to spend time only on things that matter. We spend much of our day on autopilot mode. To avoid this, we have to drain the shallows, we have to take control of our time, we have to _schedule every minute of the day_. We must prioritize ruthlessly, and strike out everything that isn't worth the time. 10 | 11 | This app helps you to achieve exactly that. It allows you to plan your day in intervals of 30 minutes. There is small to-do list widget on the right side which is to dump everything else that comes in-between. The idea is to focus only on one and one thing at a time - what are we doing today. 12 | 13 | ## Why not any other todo list? 14 | Most of the to-do lists help you list down things you want to do without considering the most important factor - how long will it take? And within a couple of days, that list becomes wishlist of things we want to achieve (sometime in future). ta - calendar helps by considering that task duration. Whenever you plan task you have to specify when you will do and how long it will take, this way your today's list does not become a dump of things to do. 15 | 16 | Of course, the idea is not to keep working for 9 hours a day deeply. But to keep track of your own time. You can (and should) always add entries like `Lunch`, `Foosball game`, etc to keep list concise. 17 | 18 | ## What does ta - calendar mean? 19 | It's just a word I came up with. Probably a mixture of `task list`, `todo list`, and `calendar`. 20 | 21 | ## Technology 22 | This app is built using [React](https://facebook.github.io/react/), and everything is stored in browser's `localStorage`. There is no server. The app, tasks, everything lives in your browser. So don't worry about privacy and other stuff. It uses GA to gather some fun stats. 23 | 24 | ## Check it out 25 | https://mitul45.github.io/ta-calendar/ 26 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ta – calendar 7 | 8 | 9 |
10 | 20 | 21 | 22 | 23 | 24 | 33 | 34 | -------------------------------------------------------------------------------- /src/TaskCreator.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Module for adding task, consisting input box for task name, 3 | * and two select fields for duration and start time. 4 | * 5 | * Calls parents addTask method on creation of task 6 | */ 7 | import React from 'react'; 8 | import Utils from './Utils' 9 | 10 | const START_TIME = Utils.START_TIME; 11 | const END_TIME = Utils.END_TIME; 12 | 13 | var TaskCreator = React.createClass({ 14 | 15 | getInitialState() { 16 | return { 17 | startTime: START_TIME, 18 | taskName: "", 19 | taskDuration: 0.5, 20 | } 21 | }, 22 | 23 | /** 24 | * Onclick handler for `Add` button 25 | */ 26 | addTask() { 27 | this.props.addTask(this.state.taskName, this.state.taskDuration, this.state.startTime); 28 | this.setState(this.getInitialState()); 29 | }, 30 | 31 | /** 32 | * Handlers for keeping internal state, and view in sync 33 | */ 34 | 35 | handleTaskNameChange(event) { 36 | this.setState({ 37 | taskName: event.target.value 38 | }) 39 | }, 40 | 41 | handleTaskDurationChange(event) { 42 | this.setState({ 43 | taskDuration: event.target.value 44 | }) 45 | }, 46 | 47 | handleStartTimeChange(event) { 48 | this.setState({ 49 | startTime: event.target.value 50 | }) 51 | }, 52 | 53 | render() { 54 | 55 | const startTimes = []; 56 | for (let i = START_TIME; i < END_TIME; i += 0.5) { 57 | startTimes.push(); 58 | } 59 | 60 | return ( 61 |
62 |
63 | 69 |
70 |
71 | 79 |
80 |
81 | 84 |
85 |
86 | 87 |
88 |
89 | ) 90 | } 91 | }) 92 | 93 | export default TaskCreator; 94 | -------------------------------------------------------------------------------- /src/TimeSlot.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Utils from './Utils'; 3 | import ReactDOM from 'react-dom'; 4 | 5 | var TimeSlot = React.createClass({ 6 | 7 | getInitialState() { 8 | return { 9 | taskName: this.props.timeSlot.taskName, 10 | editable: false, 11 | } 12 | }, 13 | 14 | /** 15 | * Format a slot object to human readable time. 16 | * @param {Object} slot 17 | * @returns {String} 18 | */ 19 | formatSlot(slot) { 20 | return Utils.formatTime(slot.startTime); 21 | }, 22 | 23 | deleteTask() { 24 | this.props.deleteTask(this.props.timeSlot); 25 | }, 26 | 27 | handleCheckboxChange(event) { 28 | this.props.completeTask(this.props.timeSlot, event.target.checked); 29 | }, 30 | 31 | /** 32 | * Mark this slot as editable, and show input field. 33 | */ 34 | handleDoubleClick() { 35 | this.setState({ 36 | editable: true, 37 | newTask: this.props.timeSlot.taskName, 38 | }) 39 | }, 40 | 41 | /** 42 | * Keep view and state in sync 43 | */ 44 | handleTextChange(event) { 45 | this.setState({ 46 | newTask: event.target.value, 47 | }) 48 | }, 49 | 50 | /** 51 | * Save task on enter and restore to previous on esc. 52 | */ 53 | handleKeyDown(event) { 54 | if (event.keyCode === 13 ) { 55 | this.createTask(this.state.newTask); 56 | } else if (event.keyCode === 27) { 57 | this.setState({ 58 | editable: false, 59 | }) 60 | } 61 | }, 62 | 63 | /** 64 | * create task in parent scope. 65 | * @param {any} taskName 66 | */ 67 | createTask(taskName) { 68 | this.props.createTask(this.props.timeSlot, taskName); 69 | this.setState({ 70 | editable: false, 71 | }) 72 | }, 73 | 74 | render() { 75 | return ( 76 | 77 | { this.formatSlot(this.props.timeSlot.slot) } 78 | 82 | 83 | { 84 | this.props.timeSlot.taskName 85 | ? 89 | : null 90 | } 91 | 92 | 93 | { this.state.editable 94 | ? 102 | : this.props.timeSlot.taskName 103 | } 104 | 105 | 106 | { this.props.timeSlot.taskName !== '' ? 107 | 108 | : null 109 | } 110 | 111 | 112 | ) 113 | } 114 | }) 115 | 116 | export default TimeSlot; 117 | -------------------------------------------------------------------------------- /src/OtherTasks.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Utils from './Utils' 3 | 4 | var OtherTasks = React.createClass({ 5 | 6 | getInitialState() { 7 | // if browser has some stored state, restore that 8 | let previousState = this.deserializeState(); 9 | if (previousState) { 10 | return previousState; 11 | } 12 | 13 | return { 14 | taskList: [ 15 | 'your upcoming tasks go here', 16 | 'try marking this one as done!' 17 | ], 18 | newTask: '', 19 | } 20 | }, 21 | 22 | /** 23 | * Set state in localStorage 24 | * @param {Object} state 25 | */ 26 | serializeState(state) { 27 | localStorage.setItem(Utils.otherTaskStorageKey, JSON.stringify(state)); 28 | }, 29 | 30 | /** 31 | * Get state from browser's local storage, if it exists 32 | */ 33 | deserializeState() { 34 | return JSON.parse(localStorage.getItem(Utils.otherTaskStorageKey)); 35 | }, 36 | 37 | /** 38 | * Add a task, and update localStorage. 39 | * @param {String} newTask 40 | */ 41 | createTask(newTask) { 42 | let taskList = this.state.taskList; 43 | taskList.push(newTask); 44 | const newState = { 45 | taskList: taskList, 46 | newTask: '', 47 | }; 48 | 49 | this.setState(newState); 50 | this.serializeState(newState); 51 | }, 52 | 53 | /** 54 | * Save task on enter and empty the input box on esc. 55 | * @param {any} event 56 | */ 57 | handleKeyDown(event) { 58 | if (event.keyCode === 13 ) { 59 | return this.createTask(this.state.newTask); 60 | } else if (event.keyCode === 27) { 61 | this.setState({ 62 | newTask: '', 63 | }) 64 | } 65 | }, 66 | 67 | /** 68 | * Keep state and view in sync 69 | */ 70 | handleChange(event) { 71 | this.setState({ 72 | newTask: event.target.value, 73 | }) 74 | }, 75 | 76 | /** 77 | * Remove item from tasklist, and update localStorage. 78 | * 79 | * @param {String} taskToRemove 80 | */ 81 | removeTask(taskToRemove) { 82 | let taskList = JSON.parse(JSON.stringify(this.state.taskList)); 83 | let newTaskList = taskList.filter(function(task) { 84 | return task !== taskToRemove; 85 | }) 86 | 87 | const newState = { 88 | taskList: newTaskList, 89 | }; 90 | 91 | this.setState(newState); 92 | this.serializeState(newState); 93 | }, 94 | 95 | render () { 96 | let tasks = []; 97 | const that = this; 98 | this.state.taskList.forEach(function(task) { 99 | tasks.push( 100 |
  • 101 | {task}  102 | ( that.removeTask(task)} 104 | >done) 105 |
  • 106 | ); 107 | }) 108 | 109 | return ( 110 |
    111 | 119 |
      120 | {tasks} 121 |
    122 |
    123 | ); 124 | } 125 | }) 126 | 127 | export default OtherTasks; 128 | -------------------------------------------------------------------------------- /src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 11 | 14 | 17 | 31 | 33 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /src/Day.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Module for displaying a day's tasks. 3 | */ 4 | import React from 'react'; 5 | import TimeSlot from './TimeSlot' 6 | import Utils from './Utils' 7 | 8 | const START_TIME = Utils.START_TIME; 9 | const END_TIME = Utils.END_TIME; 10 | 11 | var Day = React.createClass({ 12 | 13 | /** 14 | * @returns 15 | * { 16 | * timeSlots: { 17 | * 9.5: { 18 | * id: 0, 19 | * taskName: 'Get started', 20 | * slot: { 21 | * startTime: '9.5', 22 | * endTime: '10' 23 | * } 24 | * }, 25 | * active: false, 26 | * done: false, 27 | * ... 28 | * } 29 | * } 30 | */ 31 | getInitialState() { 32 | 33 | // if browser has some stored state, that's what we look for :D 34 | let previousState = this.deserializeState(); 35 | if (previousState) { 36 | return previousState; 37 | } 38 | 39 | // otherwise create empty day with no tasks. 40 | const timeSlots = []; 41 | let id = 0; 42 | 43 | // create half hours slots based on START_TIME and END_TIME 44 | for(let current = Utils.START_TIME; current < Utils.END_TIME; current += 0.5) { 45 | timeSlots.push({ 46 | id: id++, 47 | taskName: getDefaultTask(id), 48 | slot: { 49 | startTime: current, 50 | endTime: current + 0.5 51 | }, 52 | active: false, 53 | done: id === 3, 54 | }); 55 | } 56 | return { 57 | timeSlots, 58 | } 59 | 60 | function getDefaultTask(id) { 61 | switch(id) { 62 | case 1: return 'your today\'s tasks go here' 63 | case 2: return 'add task by double-clicking a section' 64 | case 3: return 'completed task looks like this' 65 | case 4: return 'remove a task by clicking \'Remove\' which appears on hover' 66 | case 5: return 'you can also add longer tasks using bar on top' 67 | case 6: return 'fork/star! if you like what you are seeing :)' 68 | default: return '' 69 | } 70 | } 71 | }, 72 | 73 | /** 74 | * Set state in localStorage 75 | * @param {Object} state 76 | */ 77 | serializeState(state) { 78 | localStorage.setItem(Utils.localStorageKey, JSON.stringify(state)); 79 | }, 80 | 81 | /** 82 | * Get state from browser's local storage, if it exists 83 | */ 84 | deserializeState() { 85 | return JSON.parse(localStorage.getItem(Utils.localStorageKey)); 86 | }, 87 | 88 | /** 89 | * Add a task - update the state accordingly 90 | * 91 | * @param {String} name 92 | * @param {any} duration 93 | * @param {any} startTime 94 | */ 95 | addTask(name, duration, startTime) { 96 | startTime = Number(startTime); 97 | duration = Number(duration); 98 | const endTime = startTime + duration; 99 | 100 | // #deepcopy 101 | let newSlots = JSON.parse(JSON.stringify(this.state.timeSlots)); 102 | 103 | newSlots.forEach(function (timeSlot) { 104 | if (timeSlot.slot.startTime >= startTime && timeSlot.slot.endTime <= endTime) { 105 | timeSlot.taskName = name; 106 | } 107 | }) 108 | 109 | const newState = { 110 | timeSlots: newSlots 111 | }; 112 | 113 | this.setState(newState); 114 | this.serializeState(newState); 115 | }, 116 | 117 | deleteTask(timeSlot) { 118 | // #deepcopy 119 | let newSlots = JSON.parse(JSON.stringify(this.state.timeSlots)); 120 | 121 | newSlots.forEach(function (slot) { 122 | if (slot.id === timeSlot.id) { 123 | slot.taskName = ""; 124 | slot.done = false; 125 | } 126 | }) 127 | 128 | const newState = { 129 | timeSlots: newSlots 130 | }; 131 | 132 | this.setState(newState); 133 | this.serializeState(newState); 134 | }, 135 | 136 | /** 137 | * Mark task as done. 138 | * @param {Object} timeSlot 139 | * @param {boolean} completeState 140 | */ 141 | completeTask(timeSlot, completeState) { 142 | // #deepcopy 143 | let newSlots = JSON.parse(JSON.stringify(this.state.timeSlots)); 144 | 145 | newSlots.forEach(function (slot) { 146 | if (slot.id === timeSlot.id) { 147 | slot.done = completeState; 148 | } 149 | }) 150 | 151 | const newState = { 152 | timeSlots: newSlots 153 | }; 154 | 155 | this.setState(newState); 156 | this.serializeState(newState); 157 | }, 158 | 159 | /** 160 | * Create task when some of it's child got updated through doubleclick event 161 | * @param {any} timeSlot 162 | * @param {string} taskName 163 | */ 164 | createTask(timeSlot, taskName) { 165 | // #deepcopy 166 | let newSlots = JSON.parse(JSON.stringify(this.state.timeSlots)); 167 | 168 | newSlots.forEach(function (slot) { 169 | if (slot.id === timeSlot.id) { 170 | slot.taskName = taskName; 171 | } 172 | }) 173 | 174 | const newState = { 175 | timeSlots: newSlots 176 | }; 177 | 178 | this.setState(newState); 179 | this.serializeState(newState); 180 | }, 181 | 182 | /** 183 | * Get current time in required format 184 | * 13:30 -> 13.5 185 | */ 186 | getCurrentTime() { 187 | const date = new Date(); 188 | return date.getHours() + (date.getMinutes() / 60); 189 | }, 190 | 191 | updateActiveSlot() { 192 | const current = this.getCurrentTime(); 193 | 194 | // #deepcopy 195 | let newSlots = JSON.parse(JSON.stringify(this.state.timeSlots)); 196 | newSlots.forEach(function (slot) { 197 | if (slot.slot.startTime <= current && current < slot.slot.endTime) { 198 | slot.active = true; 199 | } else { 200 | slot.active = false; 201 | } 202 | }) 203 | 204 | this.setState({ 205 | timeSlots: newSlots 206 | }); 207 | }, 208 | 209 | componentDidMount() { 210 | setInterval(this.updateActiveSlot, 1000); 211 | }, 212 | 213 | render() { 214 | 215 | let that = this; 216 | const slotRows = []; 217 | this.state.timeSlots.forEach(function (timeSlot) { 218 | slotRows.push( 219 | 226 | ) 227 | }) 228 | 229 | return ( 230 |
    231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | {slotRows} 240 | 241 |
    Time Task
    242 |
    243 | ) 244 | } 245 | }) 246 | 247 | export default Day; 248 | --------------------------------------------------------------------------------