Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inline edit controls - start editing and cancel editing #20029

Merged
merged 6 commits into from Jan 17, 2018

Conversation

caleybrock
Copy link
Contributor

@caleybrock caleybrock commented Jan 16, 2018

inlineedit

  • Edit button has an action that puts rows in editing state.
  • Password section has an editing state.
  • Cancel button stops editing.
  • Add redux tests for new actions and fix storybook

@Bjvanminnen
Copy link
Contributor

Is it weird that here we click the quick actions menu, select edit, and get an inline experience. But on the homepage, for the sections table, if we click on the quick actions menu, select "Edit section" we get a modal edit experience?

@@ -4,6 +4,8 @@ import PopUpMenu, {MenuBreak} from "@cdo/apps/lib/ui/PopUpMenu";
import color from "../../util/color";
import FontAwesome from '../FontAwesome';
import Button from '../Button';
import {startEditingStudent, cancelEditingStudent} from './manageStudentsRedux';
import { connect } from 'react-redux';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: would be good to be consistent on whether or not we have styles before/after braces in a single file

@@ -15,6 +17,17 @@ class ManageStudentActionsCell extends Component {
static propTypes = {
id: PropTypes.number.isRequired,
isEditing: PropTypes.bool,
//Provided by redux
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

supernit: throughout most of our code, we have a space after beginning a comment (though not actually true everywhere and it doesn't actually matter that much)

cancelEditingStudent(id) {
dispatch(cancelEditingStudent(id));
},
}))(ManageStudentActionsCell);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can actually just use a shortcut version of matchPropsToDispatch:

export default connect(state => {}, {startEditingStudent, cancelEditingStudent})(ManageStudentActionsCell)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is really good to know, although way less readable to me, so I'm going to leave it as is.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find it interesting to hear that you find the short form less readable (though I'm absolutely fine with you leaving this as is given that you think so).

@@ -1,6 +1,15 @@
import React from 'react';
import {UnconnectedManageStudentsTable} from './ManageStudentsTable';
import {SectionLoginType} from '@cdo/apps/util/sharedConstants';
import {combineReducers, createStore} from 'redux';
import manageStudents from './manageStudentsRedux';
import { Provider } from 'react-redux';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: similar comment about brace/space consistency

@@ -31,13 +35,33 @@ export default function manageStudents(state=initialState, action) {
studentData: action.studentData,
};
}
if (action.type === START_EDITING_STUDENT) {
let updatedStudentData = state.studentData;
updatedStudentData[action.studentId].isEditing = true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is mutating existing state (updatedStudentData is a reference to state.studentData, not a copy of it)

return {
...state,
studentData: updatedStudentData,
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a way to do this without mutating (that isn't super understandable) is

return {
  ...state,
  studentData: {
    ...state.studentData,
    [action.studentId]: {
      ...state.studentData[action.studentId],
      isEditing: true
    }
  }
};

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue for cancel

let studentDataArray = [];
for (var id in studentData) {
studentDataArray.push(studentData[id]);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this can just be Object.values(studentDataArray)?


// Converts key/value id/student pairs to an array of student objects for the
// component to display
// TODO: memoize this - sections could be a few thousand students
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should attach name to TODO

Copy link
Contributor

@Bjvanminnen Bjvanminnen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly nits, but will want to fix mutating state in the reducer.

@caleybrock
Copy link
Contributor Author

I asked the same question about the edit experience. Many of the fields in the sections table require explanatory text, where as the student table fields are self explanatory and require quick editing, often of many rows at a time. Making this table have a dialog would be a worse experience for teachers, and making the sections table inline would probably cause confusion.

@Bjvanminnen
Copy link
Contributor

I would agree that it makes sense for these tables to have different edit experiences. I wonder if they should also have different ways to begin the edit experience? Prob not a big deal either way.

@caleybrock
Copy link
Contributor Author

PTAL

isEditing: true
}
}
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: An alternative to this would be to use Immutable.js, which I think would allow you to do something like

return state.set(['studentData', action.studentId, isEditing'], true);

Doing some googling, I think you could also accomplish this with some lodashing, doing something like:

return _.set(_.clone(state), `studentData.${action.studentId}.isEditing`, true);

I haven't validated that this works, and am mostly just sharing as an FYI. The pattern currently used here is one we use elsewhere

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Turns out this was bad advice. Clone only makes a shallow copy, so this still ends up doing a mutation.

Consider the following code:

var foo = {
  parent: {
    x: 1,
    y: 2
  }
};

console.log(foo.parent.x); // prints 1

var foo2 = _.set(_.clone(foo), 'parent.x', 3);

console.log(foo.parent.x); // prints 3, foo and _.clone(foo) are both using the same parent object

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The following does appear to work, but I'm not sure I grok it well enough to recommend it's usage:

var foo2 = _.setWith(_.clone(foo), 'parent.x', 3, _.clone)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

alright, but it sounds like they way it is currently works.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep. Current approach is 👍

@caleybrock caleybrock merged commit a5351ef into staging Jan 17, 2018
@caleybrock caleybrock deleted the inline-edit-controls branch January 17, 2018 00:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants