-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #70 from googleinterns/edit-trip-modal-infra
Edit Trip Modal Infrastructure
- Loading branch information
Showing
2 changed files
with
162 additions
and
44 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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'; | ||
|
||
|
||
|
@@ -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. | ||
* | ||
|
@@ -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}> | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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} | ||
/> | ||
); | ||
} | ||
|
@@ -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); | ||
|
@@ -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`. */ | ||
|
@@ -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, | ||
|
@@ -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); | ||
} | ||
|
||
} | ||
|
||
/** | ||
|
@@ -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> | ||
|
@@ -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> | ||
|
@@ -219,4 +280,4 @@ class AddTripModal extends React.Component { | |
} | ||
}; | ||
|
||
export default AddTripModal; | ||
export default SaveTripModal; |