--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/client/src/actions/groupActions.js Tue Aug 01 12:20:14 2017 +0200
@@ -0,0 +1,17 @@
+import * as types from '../constants/actionTypes';
+
+
+export const groupCreateSuccess = (group) =>
+ ({ type: types.GROUP_CREATE_SUCCESS, group });
+
+export const groupCreateError = (error) =>
+ ({ type: types.GROUP_CREATE_ERROR, error });
+
+export const groupLoadSucess = (groups) =>
+ ({ type: types.GROUP_LOAD_SUCCESS, groups });
+
+export const groupLoadError = (error) =>
+ ({ type: types.GROUP_LOAD_ERROR, error });
+
+export const groupLoadAsync = () =>
+ ({ type: types.GROUP_LOAD_ASYNC });
--- a/client/src/actions/notesActions.js Mon Jul 31 23:18:38 2017 +0200
+++ b/client/src/actions/notesActions.js Tue Aug 01 12:20:14 2017 +0200
@@ -45,6 +45,10 @@
return { type: types.DO_DELETE_NOTE, noteId };
}
+export const doDeleteAllNote = () => {
+ return { type: types.DO_DELETE_ALL_NOTE };
+}
+
export const loadNote = (note) => {
return { type: types.LOAD_NOTE, note };
}
--- a/client/src/actions/sessionsActions.js Mon Jul 31 23:18:38 2017 +0200
+++ b/client/src/actions/sessionsActions.js Tue Aug 01 12:20:14 2017 +0200
@@ -39,6 +39,10 @@
return { type: types.DO_DELETE_SESSION, sessionId };
}
+export const doDeleteAllSession = () => (
+ { type: types.DO_DELETE_ALL_SESSION }
+)
+
export const loadSessions = () => {
return {
type: types.LOAD_SESSIONS
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/client/src/components/GroupForm.js Tue Aug 01 12:20:14 2017 +0200
@@ -0,0 +1,106 @@
+import React, { Component } from 'react';
+import { connect } from 'react-redux';
+import { bindActionCreators } from 'redux';
+import { FormGroup, FormControl, Button, InputGroup, HelpBlock, Glyphicon } from 'react-bootstrap';
+import * as authActions from '../actions/authActions';
+import * as sessionsActions from '../actions/sessionsActions';
+
+class GroupForm extends Component {
+
+ state = {
+ createGroup: false,
+ groupName: ''
+ }
+
+ toggleCreateGroup = (e) => {
+ e.preventDefault();
+ const { createGroup } = this.state;
+ this.setState({ createGroup: !createGroup });
+ }
+
+ onClickCreateGroup = (e) => {
+ e.preventDefault();
+ const groupName = this.state.groupName;
+ this.props.sessionsActions.createGroupAndUpdateSession(this.props.session, groupName);
+ this.setState({
+ createGroup: false,
+ groupName: ''
+ })
+ }
+
+ handleInputChange = (e) => {
+ const target = e.target;
+ const value = target.value;
+ const name = target.name;
+
+ this.setState({
+ [name]: value
+ });
+ }
+
+
+ render = () => {
+ const { createGroup } = this.props;
+ const hasErrors = true === createGroup.get('error') && createGroup.get('errorMessages').has('name');
+
+ let errors = [];
+ if (hasErrors) {
+ const errorMessages = createGroup.get('errorMessages').toArray();
+ errors = errorMessages.map((message, key) => {
+ return (
+ <HelpBlock key={ key }>{ message }</HelpBlock>
+ )
+ })
+ }
+
+ if (this.state.createGroup) {
+ return (
+ <FormGroup validationState={ hasErrors ? 'error' : null }>
+ <InputGroup>
+ <FormControl
+ type="text"
+ placeholder="Enter a name for your group"
+ onChange={this.handleInputChange}
+ name="groupName"
+ value={this.state.groupName} />
+ <InputGroup.Button>
+ <Button bsStyle="primary" onClick={ this.onClickCreateGroup }>Create</Button>
+ </InputGroup.Button>
+ </InputGroup>
+ { errors }
+ <hr />
+ <Button onClick={ this.toggleCreateGroup }>Cancel</Button>
+ </FormGroup>
+ )
+ }
+
+ if(this.props.online) {
+ return (
+ <FormGroup>
+ <Button className="pull-right" bsSize="small" onClick={ this.toggleCreateGroup }>
+ <Glyphicon glyph="plus" /> Create a new group
+ </Button>
+ </FormGroup>
+ )
+ }
+ return null;
+ }
+
+}
+
+function mapStateToProps(state, props) {
+
+ return {
+ createGroup: state.get('createGroup'),
+ online: state.getIn(['status', 'online']),
+ };
+}
+
+function mapDispatchToProps(dispatch) {
+ return {
+ sessionsActions: bindActionCreators(sessionsActions, dispatch),
+ authActions: bindActionCreators(authActions, dispatch),
+ }
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(GroupForm);
--- a/client/src/components/SessionForm.js Mon Jul 31 23:18:38 2017 +0200
+++ b/client/src/components/SessionForm.js Tue Aug 01 12:20:14 2017 +0200
@@ -1,7 +1,8 @@
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
-import { Panel, FormGroup, ControlLabel, FormControl, Button, InputGroup, HelpBlock, Glyphicon } from 'react-bootstrap';
+import { Panel, FormGroup, ControlLabel, FormControl } from 'react-bootstrap';
+import GroupForm from './GroupForm';
import '../App.css';
import * as sessionsActions from '../actions/sessionsActions';
import * as authActions from '../actions/authActions';
@@ -13,18 +14,6 @@
createGroup: false
}
- toggleCreateGroup = (e) => {
- e.preventDefault();
- const { createGroup } = this.state;
- this.setState({ createGroup: !createGroup });
- }
-
- onClickCreateGroup = (e) => {
- e.preventDefault();
- const groupName = this.groupName.value;
- this.props.sessionsActions.createGroupAndUpdateSession(this.props.currentSession, groupName);
- }
-
onChange = (e) => {
const { name, value } = e.target;
const changes = { [name]: value }
@@ -36,10 +25,9 @@
}, 750)
onGroupChange = (e) => {
- const groupId = parseInt(this.group.value, 10);
- const group = this.props.groups.find(group => group.id === groupId);
+ const groupName = e.target.value;
- this.props.sessionsActions.updateSession(this.props.currentSession, { group });
+ this.props.sessionsActions.updateSession(this.props.currentSession, { group: groupName });
}
componentWillUpdate = (nextProps, nextState) => {
@@ -48,48 +36,6 @@
}
}
- renderCreateGroup = () => {
- const { createGroup } = this.props;
- const hasErrors = true === createGroup.get('error') && createGroup.get('errorMessages').has('name');
-
- let errors = [];
- if (hasErrors) {
- const errorMessages = createGroup.get('errorMessages').toArray();
- errors = errorMessages.map((message, key) => {
- return (
- <HelpBlock key={ key }>{ message }</HelpBlock>
- )
- })
- }
-
- if (this.state.createGroup) {
- return (
- <FormGroup validationState={ hasErrors ? 'error' : null }>
- <InputGroup>
- <FormControl
- type="text"
- placeholder="Enter a name for your group"
- inputRef={ ref => { this.groupName = ref; } } />
- <InputGroup.Button>
- <Button bsStyle="primary" onClick={ this.onClickCreateGroup }>Create</Button>
- </InputGroup.Button>
- </InputGroup>
- { errors }
- <hr />
- <Button onClick={ this.toggleCreateGroup }>Cancel</Button>
- </FormGroup>
- )
- }
-
- return (
- <FormGroup>
- <Button className="pull-right" bsSize="small" onClick={ this.toggleCreateGroup }>
- <Glyphicon glyph="plus" /> Create a new group
- </Button>
- </FormGroup>
- )
- }
-
render() {
if (!this.props.currentSession) {
@@ -109,7 +55,6 @@
onChange={ this.onChange }
type="text"
placeholder="Enter a title"
- inputRef={ ref => { this.title = ref; } }
/>
</FormGroup>
<FormGroup>
@@ -120,7 +65,6 @@
defaultValue={ this.props.currentSession.description }
onChange={ this.onChange }
placeholder="Enter a description"
- inputRef={ ref => { this.description = ref; } }
/>
</FormGroup>
<FormGroup>
@@ -128,17 +72,15 @@
<FormControl
name="group"
componentClass="select"
- value={ this.props.group ? this.props.group.id : '' }
- onChange={ this.onGroupChange }
- inputRef={ ref => { this.group = ref; } }>
- <option />
+ value={ this.props.group ? this.props.group.get('name') : '' }
+ onChange={ this.onGroupChange }>
{ this.props.groups.map((group, key) =>
- <option key={ key } value={ group.id }>{ group.name }</option>
+ <option key={ key } value={ group.get('name') }>{ group.get('name') }</option>
) }
</FormControl>
</FormGroup>
<FormGroup>
- { this.renderCreateGroup() }
+ <GroupForm session={this.props.session} />
</FormGroup>
</form>
</Panel>
@@ -149,8 +91,8 @@
function mapStateToProps(state, props) {
let group;
- if (props.session && props.session.group) {
- group = state.groups.find(group => props.session.group.get('id') === group.id)
+ if (props.session && props.session.get('group')) {
+ group = state.get('groups').find(group => props.session.get('group') === group.get('name'))
}
return {
--- a/client/src/constants/actionTypes.js Mon Jul 31 23:18:38 2017 +0200
+++ b/client/src/constants/actionTypes.js Tue Aug 01 12:20:14 2017 +0200
@@ -3,6 +3,7 @@
export const ADD_NOTE = 'ADD_NOTE';
export const DELETE_NOTE = 'DELETE_NOTE';
export const DO_DELETE_NOTE = 'DO_DELETE_NOTE';
+export const DO_DELETE_ALL_NOTE = 'DO_DELETE_ALL_NOTE';
export const UPDATE_NOTE = 'UPDATE_NOTE';
export const RESET_ACTION_NOTE = 'RESET_ACTION_NOTE';
export const LOAD_NOTE = 'LOAD_NOTE';
@@ -11,6 +12,7 @@
export const UPDATE_SESSION = 'UPDATE_SESSION';
export const DELETE_SESSION = 'DELETE_SESSION';
export const DO_DELETE_SESSION = 'DO_DELETE_SESSION';
+export const DO_DELETE_ALL_SESSION = 'DO_DELETE_ALL_SESSION';
export const LOAD_SESSIONS = 'LOAD_SESSIONS';
export const LOAD_SESSION = 'LOAD_SESSION';
export const RESET_ACTION_SESSION = 'RESET_ACTION_SESSION';
--- a/client/src/reducers/authReducer.js Mon Jul 31 23:18:38 2017 +0200
+++ b/client/src/reducers/authReducer.js Tue Aug 01 12:20:14 2017 +0200
@@ -1,8 +1,10 @@
import Immutable from 'immutable';
import * as types from '../constants/actionTypes';
import UserRecord from '../store/userRecord';
+import GroupRecord from '../store/groupRecord';
import asyncRequest from '../constants/asyncRequest';
import uuidV4 from 'uuid/v4';
+import _ from 'lodash';
export const isAuthenticated = (state = false, action) => {
switch (action.type) {
@@ -103,9 +105,20 @@
export const groups = (state = Immutable.List([]), action) => {
switch (action.type) {
case types.GROUP_LOAD_SUCCESS:
- return Immutable.List(action.groups.results);
+ return Immutable.List(
+ action.groups.map((group) => GroupRecord({
+ ...(_.omit(group, 'is_personal')),
+ isPersonal: group['is_personal']
+ }))
+ );
case types.GROUP_CREATE_SUCCESS:
- return state.push(action.group);
+ return state.push(GroupRecord({
+ ...(_.omit(action.group, 'is_personal')),
+ isPersonal: action.group['is_personal']
+ }));
+ case types.AUTH_LOGOUT: {
+ return Immutable.List(); // empty note list on logout
+ }
default:
return state
}
--- a/client/src/reducers/notesReducer.js Mon Jul 31 23:18:38 2017 +0200
+++ b/client/src/reducers/notesReducer.js Tue Aug 01 12:20:14 2017 +0200
@@ -81,6 +81,9 @@
return state.push(noteRec);
}
}
+ case types.AUTH_LOGOUT: {
+ return Immutable.List(); // empty note list on logout
+ }
default:
return state;
}
--- a/client/src/reducers/sessionsReducer.js Mon Jul 31 23:18:38 2017 +0200
+++ b/client/src/reducers/sessionsReducer.js Tue Aug 01 12:20:14 2017 +0200
@@ -75,6 +75,9 @@
const session = state.get(index);
return state.set(index, session.merge({action: ActionEnum.NONE}));
}
+ case types.AUTH_LOGOUT: {
+ return Immutable.List(); // empty session list on logout
+ }
default:
return state;
}
--- a/client/src/sagas/SessionSyncronizer.js Mon Jul 31 23:18:38 2017 +0200
+++ b/client/src/sagas/SessionSyncronizer.js Tue Aug 01 12:20:14 2017 +0200
@@ -42,18 +42,20 @@
date: localObjInst.get('date'),
title: localObjInst.get('title'),
description: localObjInst.get('description'),
+ group: localObjInst.get('group'),
protocol: ''
};
}
getLocalRecord(remoteObj) {
- return new SessionRecord({
+ return SessionRecord({
_id: remoteObj.ext_id,
title: remoteObj.title,
description: remoteObj.description,
date: moment(remoteObj.date).toDate(),
action: ActionEnum.NONE,
- group: null
+ group: remoteObj.group,
+ protocol: remoteObj.protocol,
});
}
--- a/client/src/sagas/groupSaga.js Mon Jul 31 23:18:38 2017 +0200
+++ b/client/src/sagas/groupSaga.js Tue Aug 01 12:20:14 2017 +0200
@@ -1,5 +1,7 @@
import { put, take, all } from 'redux-saga/effects'
import * as types from '../constants/actionTypes';
+import { groupCreateSuccess, groupCreateError, groupLoadSucess, groupLoadError } from '../actions/groupActions';
+import { updateSession } from '../actions/sessionsActions';
function* watchCreateGroup(context) {
while (true) {
@@ -7,9 +9,9 @@
const client = context.client;
try {
const response = yield client.post('/api/auth/group/', group);
- yield put({ type: types.GROUP_CREATE_SUCCESS, group: response });
+ yield put(groupCreateSuccess(response));
} catch (e) {
- yield put({ type: types.GROUP_CREATE_ERROR, error: e });
+ yield put(groupCreateError(e));
}
}
}
@@ -22,21 +24,13 @@
const response = yield client.post('/api/auth/group/', group);
const actions = [
- {
- type: types.GROUP_CREATE_SUCCESS,
- group: response
- },
- {
- type: types.UPDATE_SESSION,
- session: session,
- values: { group: response },
- }
+ groupCreateSuccess(response),
+ updateSession(session, {group: response.name})
];
-
yield all(actions.map(action => put(action)));
} catch (e) {
- yield put({ type: types.GROUP_CREATE_ERROR, error: e });
+ yield put(groupCreateError(e));
}
}
}
@@ -47,9 +41,9 @@
yield take(types.GROUP_LOAD_ASYNC);
try {
const response = yield client.get('/api/auth/group/');
- yield put({ type: types.GROUP_LOAD_SUCCESS, groups: response });
+ yield put(groupLoadSucess(response.results));
} catch (e) {
- yield put({ type: types.GROUP_LOAD_ERROR, error: e });
+ yield put(groupLoadError(e));
}
}
}
--- a/client/src/sagas/syncSaga.js Mon Jul 31 23:18:38 2017 +0200
+++ b/client/src/sagas/syncSaga.js Tue Aug 01 12:20:14 2017 +0200
@@ -1,10 +1,11 @@
-import { put, take, all, select, spawn, race, call} from 'redux-saga/effects'
+import { put, take, all, select, spawn, race, call, fork} from 'redux-saga/effects'
import { delay } from 'redux-saga';
import * as types from '../constants/actionTypes';
import { getLastSync, getOnline } from './selectors';
import moment from 'moment';
import { startSynchronize, endSynchronize, updateLastSync } from '../actions/syncActions';
import { forceSync } from '../actions/networkActions';
+import { groupLoadAsync } from '../actions/groupActions';
import SessionSynchronizer from './SessionSyncronizer';
import NoteSynchronizer from './NoteSyncronizer';
import config from '../config';
@@ -39,10 +40,15 @@
}
+function* doLoadGroup() {
+ yield put(groupLoadAsync());
+}
+
function* watchDoSync(context) {
while (true) {
yield take(types.SYNC_DO_SYNC);
- yield spawn(doSync, context);
+ yield spawn(doSync, context); //we use spawn + take, because we do not want it to be interupted
+ yield fork(doLoadGroup);
yield take(types.SYNC_END_SYNC);
}
}
--- a/client/src/store/configureStore.js Mon Jul 31 23:18:38 2017 +0200
+++ b/client/src/store/configureStore.js Tue Aug 01 12:20:14 2017 +0200
@@ -13,6 +13,7 @@
import NoteRecord from './noteRecord';
import SessionRecord from './sessionRecord';
import UserRecord from './userRecord';
+import GroupRecord from './groupRecord';
import APIClient from '../api/APIClient';
import config from '../config';
import asyncRequest from '../constants/asyncRequest';
@@ -45,15 +46,15 @@
};
const immutableTransformConfig = {
- records: [NoteRecord, SessionRecord, UserRecord],
- whitelist: ['sessions', 'notes', 'authStatus']
+ records: [NoteRecord, SessionRecord, UserRecord, GroupRecord],
+ whitelist: ['sessions', 'notes', 'authStatus', 'groups']
}
const persistOptions = {
storage: localForage,
- records: [NoteRecord, SessionRecord, UserRecord],
+ records: [NoteRecord, SessionRecord, UserRecord, GroupRecord],
transforms: [immutableTransform(immutableTransformConfig)],
- whitelist: ['sessions', 'notes', 'autoSubmit', 'authStatus']
+ whitelist: ['sessions', 'notes', 'autoSubmit', 'authStatus', 'groups']
}
const apiClient = new APIClient(config.apiRootUrl);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/client/src/store/groupRecord.js Tue Aug 01 12:20:14 2017 +0200
@@ -0,0 +1,10 @@
+import Immutable from 'immutable';
+
+export default Immutable.Record({
+ name: '',
+
+ owner: '',
+ isPersonal: false,
+ description:''
+
+}, 'Group');
--- a/client/src/store/sessionRecord.js Mon Jul 31 23:18:38 2017 +0200
+++ b/client/src/store/sessionRecord.js Tue Aug 01 12:20:14 2017 +0200
@@ -10,6 +10,7 @@
date: '',
group: null,
+ protocol: '',
action: ActionEnum.NONE,
--- a/client/src/store/userRecord.js Mon Jul 31 23:18:38 2017 +0200
+++ b/client/src/store/userRecord.js Tue Aug 01 12:20:14 2017 +0200
@@ -6,6 +6,7 @@
email: '',
first_name: '',
- last_name: ''
+ last_name: '',
+ default_group: null,
}, 'User');
--- a/src/notes/api/views/core.py Mon Jul 31 23:18:38 2017 +0200
+++ b/src/notes/api/views/core.py Tue Aug 01 12:20:14 2017 +0200
@@ -29,6 +29,7 @@
serializers = {
'list': ListSessionSerializer,
'retrieve': DetailSessionSerializer,
+ 'update': CreateSessionSerializer,
'create': CreateSessionSerializer,
}
--- a/src/notes/api/views/sync.py Mon Jul 31 23:18:38 2017 +0200
+++ b/src/notes/api/views/sync.py Tue Aug 01 12:20:14 2017 +0200
@@ -36,7 +36,6 @@
Process log entries
'''
log_entries = self.__filter_object(model, user, modified_since, client_id)
- logger.debug("LOG ENTRies %r", list(log_entries))
res = {}
for log_entry in log_entries: