diff --git a/package.json b/package.json
index 7eb0f0f..1fee002 100644
--- a/package.json
+++ b/package.json
@@ -40,6 +40,7 @@
"react-addons-transition-group": "^15.4.1",
"react-block-ui": "^0.2.2",
"react-bootstrap": "^0.30.7",
+ "react-date-picker": "^5.3.28",
"react-dom": "^15.3.2",
"react-fa": "^4.1.2",
"react-fontawesome": "^1.4.0",
diff --git a/src/api/Foogl.js b/src/api/Foogl.js
index 705e147..7f7f6e1 100644
--- a/src/api/Foogl.js
+++ b/src/api/Foogl.js
@@ -69,6 +69,37 @@ class FooglApi {
return error;
});
}
+
+ static updateTimeEntry(timeEntry) {
+ const body = JSON.stringify({
+ id: timeEntry.id,
+ title: timeEntry.title,
+ user_id: timeEntry.user_id,
+ project_id: timeEntry.project_id,
+ time_start: timeEntry.time_start,
+ time_end: timeEntry.time_end
+ })
+
+ return fetch(`${API_URL}/time_entries/${timeEntry.id}`, {
+ method: 'patch',
+ body
+ })
+ .then(response => {
+ return response.json();
+ })
+ .catch(error => {
+ return error;
+ });
+ }
+
+ static deleteTimeEntry(timeEntryId) {
+ return fetch(`${API_URL}/time_entries/${timeEntryId}`, { method: 'delete' })
+ .then(response => {
+ return response.json();
+ }).catch(error => {
+ return error;
+ });
+ }
}
export default FooglApi;
diff --git a/src/layout/utils.scss b/src/layout/utils.scss
index 1c91e00..ca614c2 100644
--- a/src/layout/utils.scss
+++ b/src/layout/utils.scss
@@ -25,3 +25,8 @@ a.nostyle:visited {
color: inherit;
cursor: auto;
}
+
+.hover-pointer {
+ cursor: pointer;
+ cursor: hand;
+}
diff --git a/src/pages/Dashboard/Components/TimeEntry/TimeEntry.js b/src/pages/Dashboard/Components/TimeEntry/TimeEntry.js
index 69c61e0..e8dbe26 100644
--- a/src/pages/Dashboard/Components/TimeEntry/TimeEntry.js
+++ b/src/pages/Dashboard/Components/TimeEntry/TimeEntry.js
@@ -1,30 +1,140 @@
-import React, { Component } from 'react';
+import React, { Component } from 'react'
+import { connect } from 'react-redux'
+import { Col, Popover, OverlayTrigger, FormGroup,
+ ControlLabel, Modal, Button } from 'react-bootstrap'
+import Icon from 'react-fa'
+import moment from 'moment'
+import { DateField, Calendar, TransitionView } from 'react-date-picker'
+import 'react-date-picker/index.css'
+
+import { deleteTimeEntry, updateTimeEntry } from '~/src/store/actions';
-import { connect } from 'react-redux';
-import {Col} from 'react-bootstrap';
import './TimeEntry.scss';
class TimeEntry extends Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ showModal: false
+ }
+ }
+
+ toggleShowModal() {
+ this.setState({ showModal: !this.state.showModal });
+ }
+
+ deleteTimeEntry() {
+ this.props.deleteTimeEntry(this.props.entry.id);
+ this.toggleShowModal();
+ }
+
+ onChange(dateString, attribute) {
+ let timeEntry = this.props.entry
+ timeEntry[attribute] = moment(dateString, 'DD-MM-YYYY HH:mm:ss').format()
+ this.props.updateTimeEntry(timeEntry)
+ }
+
render () {
+ const { showModal } = this.state;
+ const toggleShowModal = ::this.toggleShowModal
+ const deleteTimeEntry = ::this.deleteTimeEntry
+ // const onChange = (dateString, attribute) => {
+ // let timeEntry = this.props.entry
+ // timeEntry[attribute] = moment(dateString, 'DD-MM-YYYY HH:mm:ss').format()
+ // this.props.updateTimeEntry(timeEntry)
+ // }
+
+ const editPopover = (
+
+
+
+ );
+
+ const deleteModal = (
+
+
+
+ Delete Time Entry
+
+
+
+ Are you sure you want to delete this Time Entry?
+
+
+
+
+
+
+
+
+
+ );
+
return (
-
-
- {this.props.entry.title}
-
-
-
- {this.props.project.name}
-
-
-
- {this.props.entry.time_start}
-
-
-
- {this.props.entry.time_end}
-
-
+
+
+ {this.props.entry.title}
+
+
+
+ {this.props.project.name}
+
+
+
+ {this.props.entry.time_start}
+
+
+
+ {this.props.entry.time_end}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ { deleteModal }
+
);
}
};
@@ -37,4 +147,9 @@ const mapStateToProps = (state, ownProps) => {
};
}
-export default connect(mapStateToProps)(TimeEntry);
+const mapDispatchToProps = {
+ deleteTimeEntry,
+ updateTimeEntry
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(TimeEntry);
diff --git a/src/reducers/index.js b/src/reducers/index.js
index 176874a..28d5a0e 100644
--- a/src/reducers/index.js
+++ b/src/reducers/index.js
@@ -45,6 +45,37 @@ const ACTION_HANDLERS = {
};
},
+ 'ALTER_TIME_ENTRY': (state, action) => {
+ const timeEntry = action.timeEntry;
+ const timeEntryIndex = state.timeEntries.findIndex((elem) => (
+ elem.id == timeEntry.id
+ ));
+ const timeEntries = timeEntryIndex >= 0
+ ? state.timeEntries.slice(0).splice(timeEntryIndex + 1, 1, timeEntry)
+ : state.timeEntries
+
+ return {
+ ...state,
+ timeEntries
+ };
+ },
+
+ 'REMOVE_TIME_ENTRY': (state, action) => {
+ const timeEntryId = action.timeEntryId;
+ const timeEntryIndex = state.timeEntries
+ .findIndex(
+ (timeEntry) => timeEntry.id == timeEntryId
+ )
+ const timeEntries = timeEntryIndex >= 0
+ ? state.timeEntries.slice(0).splice(timeEntryIndex + 1, 1)
+ : state.timeEntries
+
+ return {
+ ...state,
+ timeEntries
+ };
+ },
+
'LOADING': (state, action) => {
const component = action.component
let newLoading = {}
diff --git a/src/store/actions.js b/src/store/actions.js
index a3059d9..c50c75a 100644
--- a/src/store/actions.js
+++ b/src/store/actions.js
@@ -71,22 +71,52 @@ export const loadTimeEntries = (userId) => {
}
}
-export const loadProjects = (userId) => {
+export const updateTimeEntry = (timeEntry) => {
return function(dispatch, getState) {
- dispatch(loading({ name: 'projectList' }))
+ dispatch(loading({ name: 'timeEntryList' }));
- return FooglApi.projects(userId)
+ return FooglApi.updateTimeEntry(timeEntry)
.then((response) => {
- dispatch(finishedLoading({ name: 'projectList' }))
- dispatch(setProjects(response.projects))
+ dispatch(alterTimeEntry(timeEntry))
+ dispatch(finishedLoading({ name: 'timeEntryList' }))
})
.catch((error) => {
- dispatch(finishedLoading({ name: 'projectList' }))
+ dispatch(finishedLoading({ name: 'timeEntryList' }))
dispatch(displayError(error))
});
}
}
+export const alterTimeEntry = (timeEntry) => {
+ return {
+ type: 'ALTER_TIME_ENTRY',
+ timeEntry
+ }
+}
+
+export const deleteTimeEntry = (timeEntryId) => {
+ return function(dispatch, getState) {
+ dispatch(loading({ name: 'timeEntryList' }));
+
+ return FooglApi.deleteTimeEntry(timeEntryId)
+ .then((response) => {
+ dispatch(removeTimeEntry(timeEntryId))
+ dispatch(finishedLoading({ name: 'timeEntryList' }))
+ })
+ .catch((error) => {
+ dispatch(finishedLoading({ name: 'timeEntryList' }))
+ dispatch(displayError(error))
+ });
+ }
+}
+
+export const removeTimeEntry = (timeEntryId) => {
+ return {
+ type: 'REMOVE_TIME_ENTRY',
+ timeEntryId
+ }
+}
+
// Login.
export const attemptLogin = (credentials) => {
return function(dispatch, getState) {
@@ -97,8 +127,8 @@ export const attemptLogin = (credentials) => {
dispatch(finishedLoading({ name: 'loginForm' }))
dispatch(setLoggedUser(response.user))
- dispatch(loadTimeEntries(response.user.id))
dispatch(loadProjects(response.user.id))
+ dispatch(loadTimeEntries(response.user.id))
browserHistory.push('/dashboard')
})
@@ -144,6 +174,22 @@ export const addProjectToStore = (project) => {
}
}
+export const loadProjects = (userId) => {
+ return function(dispatch, getState) {
+ dispatch(loading({ name: 'projectList' }))
+
+ return FooglApi.projects(userId)
+ .then((response) => {
+ dispatch(finishedLoading({ name: 'projectList' }))
+ dispatch(setProjects(response.projects))
+ })
+ .catch((error) => {
+ dispatch(finishedLoading({ name: 'projectList' }))
+ dispatch(displayError(error))
+ });
+ }
+}
+
export const setProjects = (projects) => {
return {
type: 'SET_PROJECTS',