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

Edit Trip Modal Infrastructure #70

Merged
merged 27 commits into from
Jul 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
fff10d3
Enfore consistent import statement groupings: React|other external li…
zghera Jul 15, 2020
eba6c71
Create infrastructure for add & edit trips with common 'save trip' pa…
zghera Jul 15, 2020
ee6d090
Discover how to set default value of date Form.Control.
zghera Jul 15, 2020
2e64ec6
Create and pass in placeholderObj as prop to SaveTripModal.
zghera Jul 15, 2020
8b86958
Rename date fields for placeholderObj.
zghera Jul 15, 2020
e18ae04
Integrated placeholderObj into current infrastructure.
zghera Jul 15, 2020
d896ff4
Fix collaborators field of placeholderObj to be an array.
zghera Jul 15, 2020
1328fd2
Update placeholderObj formatting.
zghera Jul 15, 2020
b46ec4f
Update modal components' documentation.
zghera Jul 15, 2020
0b47c68
Merge branch 'rename-add-trip-component' into edit-trip-modal-infra
zghera Jul 15, 2020
3684718
Refactor JSDoc for modals.
zghera Jul 15, 2020
62c2199
Update AddTripModal refrences to SaveTripModal or add/edit trip modal.
zghera Jul 15, 2020
025f1d6
Complete restructure of PR, see description.
zghera Jul 15, 2020
c54b527
Rename add-trip-modal.js to save-trip-modal.js.
zghera Jul 15, 2020
203628c
Added use of props title and tripId.
zghera Jul 15, 2020
a8db73c
Integrated tripId and added case for when trip is being editted/overw…
zghera Jul 15, 2020
9d97a4b
Add initial value for placeholderObj so SaveTripMoal compiles.
zghera Jul 15, 2020
3e6ff4d
Add documentation for event listeners in index.js.
zghera Jul 15, 2020
8c5d98a
Merge branch 'rename-add-trip-component' into edit-trip-modal-infra
zghera Jul 16, 2020
40fb73f
Update document writen/overwritten success console.logs.
zghera Jul 16, 2020
e30f294
Merge branch 'rename-add-trip-component' into edit-trip-modal-infra
zghera Jul 17, 2020
61d3dc7
Merge branch 'rename-add-trip-component' into edit-trip-modal-infra
zghera Jul 17, 2020
62a7baf
Move logic to grab title inside of save-trip-modal rather than pass i…
zghera Jul 17, 2020
6eda7ff
Merge branch 'rename-add-trip-component' into edit-trip-modal-infra
zghera Jul 17, 2020
26efe14
Fix spelling typo.
zghera Jul 17, 2020
eb42cc2
Merge branch 'rename-add-trip-component' into edit-trip-modal-infra
zghera Jul 17, 2020
a1090fc
Merge branch 'rename-add-trip-component' into edit-trip-modal-infra
zghera Jul 21, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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]']
zghera marked this conversation as resolved.
Show resolved Hide resolved
}
});
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
zghera marked this conversation as resolved.
Show resolved Hide resolved
* 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;