Skip to content

Commit

Permalink
Merge pull request #70 from googleinterns/edit-trip-modal-infra
Browse files Browse the repository at this point in the history
Edit Trip Modal Infrastructure
  • Loading branch information
zghera authored Jul 21, 2020
2 parents 34487f0 + a1090fc commit 79e9d30
Show file tree
Hide file tree
Showing 2 changed files with 162 additions and 44 deletions.
89 changes: 73 additions & 16 deletions frontend/src/components/ViewTrips/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import React from 'react';
import Button from 'react-bootstrap/Button';

import Header from '../Header/';
import AddTripModal from './add-trip-modal.js'
import SaveTripModal from './save-trip-modal.js'
import TripsContainer from './trips-container.js';


Expand All @@ -17,13 +17,22 @@ class ViewTrips extends React.Component {
super();
this.state = { showModal: false,
refreshTripsContainer: false,
refreshAddTripModal: false,
refreshSaveTripModal: false,
tripId: null,
placeholderObj: {
name: null,
description: null,
destination: null,
startDate: null,
endDate: null,
collaborators: []
}
};
}

/**
* Flips `refreshTripsContainer` property which causes that TripsContainer
* component to be reloaded.
* Handler that flips `refreshTripsContainer` property which causes that
* TripsContainer component to be reloaded.
*
* This allows a trip creator's view trips page to be updated in real time.
*
Expand All @@ -36,36 +45,84 @@ class ViewTrips extends React.Component {
}

/**
* Flips `refreshAddTripModal` property which causes that AddTripModal
* component to be reloaded.
* Handler that flips `refreshSaveTripModal` property which causes that
* save/edit trip component to be reloaded.
*
* This was done to prevent bugs where multiple component input fields would
* persist from one instance of the modal to the next when view trips page
* was not refreshed in between.
*/
refreshAddTripModal = () => {
this.setState({ refreshAddTripModal: !this.state.refreshAddTripModal });
refreshSaveTripModal = () => {
this.setState({ refreshSaveTripModal: !this.state.refreshSaveTripModal });
}

/** Property that refreshes and displays add trip page. */
showAddTripModal = () => {
this.refreshAddTripModal()
/** Handler that hides the add/edit trip page. */
hideSaveTripModal = () => { this.setState({ showModal: false }); }

/** Handler that refreshes and displays the add/edit trip page. */
showSaveTripModal = () => {
this.refreshSaveTripModal();
this.setState({ showModal: true });
}

/** Property that sets `showModal` to false --> hides add trip page. */
hideAddTripModal = () => { this.setState({ showModal: false }); }
/**
* Handler that displays the add trip page.
*
* Sets state for the states `tripId` and `placeholderObj` in order
* to ensure the modal has the visual characteristics of an "add trip" modal
* and creates a new Trip document in the database.
*/
showAddTripModal = () => {
this.setState({
tripId: null,
placeholderObj: {
name: 'Enter Trip Name',
description: 'Enter Trip Description',
destination: 'Enter Trip Destination',
startDate: '',
endDate: '',
collaborators: ['[email protected]']
}
});
this.showSaveTripModal();
}

/**
* Handler that displays the edit trip page.
*
* Sets state for the states `tripId` and `placeholderObj` in order
* to ensure the modal has the visual characteristics of an "edit trip" modal
* and overwrites and existing Trip document in the database.
*
* TODO(Issue #69): Get individual tripId and trip data for placeholderObj.
*/
showEditTripModal = () => {
this.setState({
tripId: null,
placeholderObj: {
name: null,
description: null,
destination: null,
startDate: null,
endDate: null,
collaborators: []
}
});
this.showSaveTripModal();
}

/** @inheritdoc */
render() {
return (
<div className="view-trips-page">
<Header />
<AddTripModal
<SaveTripModal
show={this.state.showModal}
handleClose={this.hideAddTripModal}
handleClose={this.hideSaveTripModal}
refreshTripsContainer={this.refreshTripsContainer}
key={this.state.refreshAddTripModal}
tripId={this.state.tripId}
placeholderObj={this.state.placeholderObj}
key={this.state.refreshSaveTripModal}
/>
<div className="manage-trips-bar">
<Button type='button' onClick={this.showAddTripModal}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,12 @@ function createTextFormControl(placeholder, ref) {
* inputted in the form.
* @return {JSX.Element} The Form.Control element.
*/
function createDateFormControl(ref) {
function createDateFormControl(defaultValue, ref) {
return (
<Form.Control
type="date"
ref={ref}
defaultValue={defaultValue}
/>
);
}
Expand Down Expand Up @@ -90,7 +91,7 @@ function createFormGroup(controlId, formLabel, inputType, placeholder, ref) {
formControl = createTextFormControl(placeholder, ref);
break;
case 'date':
formControl = createDateFormControl(ref);
formControl = createDateFormControl(placeholder, ref);
break;
case 'emails':
formControl = createMultiFormControl(placeholder, ref);
Expand All @@ -108,29 +109,48 @@ function createFormGroup(controlId, formLabel, inputType, placeholder, ref) {
}

/**
* Component corresponding to add trips modal.
* Component corresponding to the save trips modal.
*
* This component "acts" as a parent of the (non-existent) AddTripModal and
* EditTripModal components. The only differences in the implementation between
* the two fake components are dervied from the props `tripid` and
* `placeholderObj` (see below).
*
* @param {Object} props These are the props for this component:
* - show: Boolean that determines if the add trips modal should be displayed.
* - handleClose: The function that handles closing the add trips modal.
* - show: Boolean that determines if the save trips modal should be displayed.
* - handleClose: Handler that closes the save trips modal upon calling.
* - refreshTripsContainer: Function that handles refreshing the TripsContainer
* component upon trip creation (Remove when fix Issue #62).
* component upon trip saving (Remove when fix Issue #62).
* - tripId: For adding a new trip, this will be null. For editting an existing
* trip, this will the document id associated with the trip.
* - placeholderObj: Object containing the placeholder/default values for the
* form input text boxes.
* - key: Special React attribute that ensures a new AddTripModal instance is
* created whenever this key is updated
*
* @extends React.Component
*/
class AddTripModal extends React.Component {
class SaveTripModal extends React.Component {
/** @inheritdoc */
constructor(props) {
super(props);

// Create Refs to reference form input elements
this.nameRef = React.createRef();
this.descriptionRef = React.createRef();
this.destinationRef = React.createRef();
this.startDateRef = React.createRef();
this.endDateRef = React.createRef();
this.state = { collaboratorsRefArr: [React.createRef()] }

this.isAddTripForm = this.props.tripId === null;

// Create the number of collaborator input box refs as number of
// collaborators specified in the placeholderObj
const collaboratorsRefArr = [];
for (let i = 0; i < this.props.placeholderObj.collaborators.length; i++) {
collaboratorsRefArr.push(React.createRef())
}
this.state = { collaboratorsRefArr: collaboratorsRefArr }
}

/** Adds a new Ref element to the state variable `collaboratorsRefArr`. */
Expand All @@ -141,9 +161,43 @@ class AddTripModal extends React.Component {
}

/**
* Formats/cleans the form data and create a new Trip document in firestore.
* Creates a new Trip document in firestore with data in `tripData`.
*
* @param {Object} tripData Data the new trip document will contain.
*/
addNewTrip(tripData) {
db.collection(COLLECTION_TRIPS)
.add(tripData)
.then(docRef => {
console.log("Document written with ID: ", docRef.id);
})
.catch(error => {
console.error("Error adding document: ", error);
});
}

/**
* Updates an existing Trip document in firestore with data in `tripData`.
*
* @param {string} tripId The document ID of the trip that is updated.
* @param {Object} tripData Data the new trip document will contain.
*/
createTrip() {
updateExistingTrip(tripId, tripData) {
db.collection(COLLECTION_TRIPS)
.doc(tripId)
.set(tripData)
.then(() => {
console.log("Document written with ID: ", tripId);
})
.catch(error => {
console.error("Error adding document: ", error);
});
}

/**
* Formats/cleans the form data and saves the Trip document in firestore.
*/
saveTrip() {
const tripData = formatTripData(
{
name: this.nameRef.current.value,
Expand All @@ -156,14 +210,12 @@ class AddTripModal extends React.Component {
}
);

db.collection(COLLECTION_TRIPS)
.add(tripData)
.then(docRef => {
console.log("Document written with ID: ", docRef.id);
})
.catch(error => {
console.error("Error adding document: ", error);
});
if (this.isAddTripForm) {
this.addNewTrip(tripData);
} else {
this.updateExistingTrip(this.props.tripId, tripData);
}

}

/**
Expand All @@ -173,33 +225,42 @@ class AddTripModal extends React.Component {
* - Closing the modal.
*/
handleSubmitForm = () => {
this.createTrip();
this.saveTrip();
this.props.refreshTripsContainer();
this.props.handleClose();
}

/** Gets the Modal title based the type of modal (edit or add trip). */
getModalTitle = () => {
if (this.isAddTripForm) {
return 'Add New Trip';
}
return 'Edit Trip';
}

/** @inheritdoc */
render() {
return (
<Modal show={this.props.show} onHide={this.props.handleClose}>
<Modal.Header closeButton>
<Modal.Title>Add New Trip</Modal.Title>
<Modal.Title>{this.getModalTitle()}</Modal.Title>
</Modal.Header>

<Form>
<Modal.Body>
{createFormGroup('tripNameGroup', 'Trip Name', 'text',
'Enter Trip Name', this.nameRef)}
this.props.placeholderObj.name, this.nameRef)}
{createFormGroup('tripDescGroup', 'Trip Description', 'text',
'Enter Trip Description', this.descriptionRef)}
this.props.placeholderObj.description, this.descriptionRef)}
{createFormGroup('tripDestGroup', 'Trip Destination', 'text',
'Enter Trip Destination', this.destinationRef)}
this.props.placeholderObj.destination, this.destinationRef)}
{createFormGroup('tripStartDateGroup', 'Start Date', 'date',
'', this.startDateRef)}
this.props.placeholderObj.startDate, this.startDateRef)}
{createFormGroup('tripEndDateGroup', 'End Date', 'date',
'', this.endDateRef)}
this.props.placeholderObj.endDate, this.endDateRef)}
{createFormGroup('tripCollabsGroup', 'Trip Collaborators', 'emails',
'[email protected]', this.state.collaboratorsRefArr)}
this.props.placeholderObj.collaborators,
this.state.collaboratorsRefArr)}
<Button onClick={this.addCollaboratorRef}>
Add Another Collaborator
</Button>
Expand All @@ -210,7 +271,7 @@ class AddTripModal extends React.Component {
Cancel
</Button>
<Button variant='primary' onClick={this.handleSubmitForm}>
Add Trip
Save Trip
</Button>
</Modal.Footer>
</Form>
Expand All @@ -219,4 +280,4 @@ class AddTripModal extends React.Component {
}
};

export default AddTripModal;
export default SaveTripModal;

0 comments on commit 79e9d30

Please sign in to comment.