diff --git a/frontend/src/components/Utils/filter-input.js b/frontend/src/components/Utils/filter-input.js
index e32419cd..be16a313 100644
--- a/frontend/src/components/Utils/filter-input.js
+++ b/frontend/src/components/Utils/filter-input.js
@@ -48,9 +48,9 @@ export function getCollaboratorUidArray(collaboratorEmailArr) {
* attacks. Thus, no sanitization is needed for text inputs besides providing a
* default value in a Trip field where applicable.
*
- * @param {Object} rawTripObj A JS Object containing the raw form data from the
+ * @param {!Object} rawTripObj A JS Object containing the raw form data from the
* add trip form.
- * @return {Object} Formatted/cleaned version of `rawTripObj` holding the data
+ * @return {!Object} Formatted/cleaned version of `rawTripObj` holding the data
* for the new Trip document that is to be created.
*/
export function formatTripData(rawTripObj) {
diff --git a/frontend/src/components/Utils/temp-auth-utils.js b/frontend/src/components/Utils/temp-auth-utils.js
index 787bfdc5..a9ba28e0 100644
--- a/frontend/src/components/Utils/temp-auth-utils.js
+++ b/frontend/src/components/Utils/temp-auth-utils.js
@@ -2,7 +2,7 @@
* @fileoverview This is a temporary file that is used to implement 'fake'
* versions of the Auth utility functions used in the ViewTrips components.
*
- * TODO(Issue 55): Remove this whole file function and replace any imports to
+ * TODO(Issue #55): Remove this whole file function and replace any imports to
* this file with Auth utils.
*/
@@ -10,7 +10,7 @@
/**
* Temporary hardcoded function that returns the current users email.
*
- * @return Hardcoded user email string.
+ * @return {string} Hardcoded user email string.
*/
export function getCurUserEmail() {
return 'matt.murdock';
@@ -19,7 +19,7 @@ export function getCurUserEmail() {
/**
* Temporary hardcoded function that returns the current users uid.
*
- * @return Hardcoded user uid string.
+ * @return {string} Hardcoded user uid string.
*/
export function getCurUserUid() {
return getUserUidFromUserEmail(getCurUserEmail());
diff --git a/frontend/src/components/Utils/time.js b/frontend/src/components/Utils/time.js
index fe354c26..6b71e246 100644
--- a/frontend/src/components/Utils/time.js
+++ b/frontend/src/components/Utils/time.js
@@ -61,7 +61,7 @@ export function timestampToFormatted(msTimestamp, timezone = "America/New_York")
/**
* Return a Firestore Timestamp corresponding to the date in `dateStr`.
*
- * @param {string} dateStr String containing a date in the form 'yyyy-mm-dd'.
+ * @param {string} dateStr String containing a date in the form 'YYYY-MM-DD'.
* @return {firebase.firestore.Timestamp} Firestore timestamp object created.
*/
export function getTimestampFromDateString(dateStr) {
@@ -73,3 +73,13 @@ export function getTimestampFromDateString(dateStr) {
const date = new Date(dateParts[0], dateParts[1] - 1, dateParts[2]);
return firebase.firestore.Timestamp.fromDate(date);
}
+
+/**
+ * Formats a Firestore timestamp into a date string in ISO format.
+ *
+ * @param {firebase.firestore.Timestamp} timestamp Firestore timestamp object.
+ * @return {string} ISO formatted date string: "YYYY-MM-DD or 2020-05-12".
+ */
+export function timestampToISOString(timestamp) {
+ return timestamp.toDate().toISOString().substring(0,10);
+}
diff --git a/frontend/src/components/ViewTrips/index.js b/frontend/src/components/ViewTrips/index.js
index 33f425ff..d12d0ef8 100644
--- a/frontend/src/components/ViewTrips/index.js
+++ b/frontend/src/components/ViewTrips/index.js
@@ -19,14 +19,7 @@ class ViewTrips extends React.Component {
refreshTripsContainer: false,
refreshSaveTripModal: false,
tripId: null,
- placeholderObj: {
- name: null,
- description: null,
- destination: null,
- startDate: null,
- endDate: null,
- collaborators: []
- }
+ defaultFormObj: null,
};
}
@@ -75,14 +68,7 @@ class ViewTrips extends React.Component {
showAddTripModal = () => {
this.setState({
tripId: null,
- placeholderObj: {
- name: 'Enter Trip Name',
- description: 'Enter Trip Description',
- destination: 'Enter Trip Destination',
- startDate: '',
- endDate: '',
- collaborators: ['person@email.xyz']
- }
+ defaultFormObj: null,
});
this.showSaveTripModal();
}
@@ -94,19 +80,11 @@ class ViewTrips extends React.Component {
* 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 = () => {
+ showEditTripModal = (tripId, tripData) => {
this.setState({
- tripId: null,
- placeholderObj: {
- name: null,
- description: null,
- destination: null,
- startDate: null,
- endDate: null,
- collaborators: []
- }
+ tripId: tripId,
+ defaultFormObj: tripData
});
this.showSaveTripModal();
}
@@ -121,7 +99,7 @@ class ViewTrips extends React.Component {
handleClose={this.hideSaveTripModal}
refreshTripsContainer={this.refreshTripsContainer}
tripId={this.state.tripId}
- placeholderObj={this.state.placeholderObj}
+ defaultFormObj={this.state.defaultFormObj}
key={this.state.refreshSaveTripModal}
/>
@@ -130,6 +108,7 @@ class ViewTrips extends React.Component {
diff --git a/frontend/src/components/ViewTrips/save-trip-form-elements.js b/frontend/src/components/ViewTrips/save-trip-form-elements.js
new file mode 100644
index 00000000..e327c91f
--- /dev/null
+++ b/frontend/src/components/ViewTrips/save-trip-form-elements.js
@@ -0,0 +1,143 @@
+import React from 'react';
+
+import { Form } from 'react-bootstrap';
+
+/**
+ * Returns a Form.Control element with input type 'text' and other props
+ * specified by the function parameters.
+ *
+ * @param {React.RefObject} ref Ref attached to the value inputted in the form.
+ * @param {string} placeholder Placeholder text value in the form input.
+ * @param {?string} defaultText Optional default text value in the form input.
+ * Null if no default text.
+ * @return {JSX.Element} The Form.Control element.
+ */
+function createTextFormControl(ref, placeholder, defaultText) {
+ return (
+
+ );
+}
+
+/**
+ * Returns a Form.Control element with input type 'date' and other props
+ * specified by the function parameters.
+ *
+ * @param {React.RefObject} ref Ref attached to the date inputted in the form.
+ * @param {?string} defaultDate Optional default ISO date string placed in the
+ * form input. Null if no default date.
+ * @return {JSX.Element} The Form.Control element.
+ */
+function createDateFormControl(ref, defaultDate) {
+ return (
+
+ );
+}
+
+/**
+ * Returns a Form.Control element with input type 'email' and other props
+ * specified by the function parameters.
+ *
+ * @param {React.RefObject} ref Ref attached to the value inputted in the form.
+ * @param {number} idx Index of the email Form.Control used for key prop.
+ * @param {string} placeholder Placeholder text value in the form input.
+ * @param {?Array} defaultEmailArr Array of the emails to be displayed
+ * in the default form fields. Null if no default emails.
+ * @return {JSX.Element} The Form.Control element.
+ */
+function createEmailFormControl(ref, idx, placeholder, defaultEmailArr) {
+ if (defaultEmailArr === null) {
+ return (
+
+ );
+ }
+ return (
+
+ );
+}
+
+/**
+ * Returns multiple Form.Control elements with input type 'email' and other
+ * props specified by the function parameters.
+ *
+ * One is added to the index of the emails show in order to display all
+ * collaborators except the current user.
+ *
+ * TODO(Issue #67): Email verification before submitting the form.
+ *
+ * TODO(Issue #72): More intuitive remove collaborator when !`isAddTripForm`.
+ *
+ * @param {!Array} refArr Array of refs attached to the
+ * emails inputted in the form.
+ * @param {boolean} isAddTripForm True if form is adding new trip, false if
+ * form is editting existing trip.
+ * @param {string} placeholder Placeholder text value in the form input.
+ * @param {?Array} defaultEmailArr Array of the emails to be displayed
+ * in the default form fields.
+ * @return {JSX.Element} The Form.Control elements.
+ */
+function createMultiFormControl(refArr, placeholder, defaultEmailArr) {
+ return (
+ <>
+ {refArr.map((ref, idx) =>
+ createEmailFormControl(ref, idx, placeholder, defaultEmailArr)
+ )}
+ >
+ );
+}
+
+/**
+ * Returns a Form.Group element with components specified by the input args.
+ *
+ * @param {string} controlId Prop that accessibly wires the nested label and
+ * input prop.
+ * @param {string} formLabel Label/title for the form input.
+ * @param {string} inputType Input type of the form.
+ * @param {!React.RefObject} ref Ref attached to the values inputted in the form.
+ * @param {string} placeholder Placeholder text value in the form input.
+ * @param {?string|?Array} defaultVal Default value in the form input.
+ * @return {JSX.Element} The Form.Group element.
+ */
+export function createFormGroup(controlId, formLabel, inputType,
+ ref, placeholder, defaultVal) {
+ let formControl;
+ switch(inputType) {
+ case 'text':
+ formControl = createTextFormControl(ref, placeholder, defaultVal);
+ break;
+ case 'date':
+ formControl = createDateFormControl(ref, defaultVal);
+ break;
+ case 'emails':
+ formControl = createMultiFormControl(ref, placeholder, defaultVal);
+ break;
+ default:
+ console.error('There should be no other input type')
+ }
+
+ return (
+
+ {formLabel}
+ {formControl}
+
+ )
+}
diff --git a/frontend/src/components/ViewTrips/save-trip-modal.js b/frontend/src/components/ViewTrips/save-trip-modal.js
index 769985d7..49a81324 100644
--- a/frontend/src/components/ViewTrips/save-trip-modal.js
+++ b/frontend/src/components/ViewTrips/save-trip-modal.js
@@ -3,127 +3,32 @@ import React from 'react';
import app from '../Firebase';
import { Button, Modal, Form } from 'react-bootstrap';
-import { COLLECTION_TRIPS } from '../../constants/database.js';
+import * as DB from '../../constants/database.js';
import { formatTripData } from '../Utils/filter-input.js';
+import { createFormGroup } from './save-trip-form-elements.js';
const db = app.firestore();
-/**
- * Returns a Form.Control element with input type 'text' and other fields
- * specified by the function parameters.
- *
- * @param {string} placeholder Text placehold in the form input
- * @param {React.RefObject} ref Ref attached to the value inputted in the form.
- * @return {JSX.Element} The Form.Control element.
- */
-function createTextFormControl(placeholder, ref) {
- return (
-
- );
-}
-
-/**
- * Returns a Form.Control element with input type 'date' and other fields
- * specified by the function parameters.
- *
- * @param {React.RefObject} refArr The list of refs attached to the emails
- * inputted in the form.
- * @return {JSX.Element} The Form.Control element.
- */
-function createDateFormControl(defaultValue, ref) {
- return (
-
- );
-}
-
-/**
- * Returns a Form.Control element with input type 'email' and other fields
- * specified by the function parameters.
- *
- * TODO(Issue #67): Email verification before submitting the form.
- *
- * @param {string} placeholder Text placehold in the form input
- * @param {React.RefObject} refArr The list of refs attached to the emails
- * inputted in the form.
- * @return {JSX.Element} The Form.Control element.
- */
-function createMultiFormControl(placeholder, refArr) {
- return (
- <>
- {refArr.map((ref, idx) => {
- return (
-
- );
- })}
- >
- );
-}
-
-/**
- * Returns a Form.Group element with components specified by the input args.
- *
- * @param {string} controlId Prop that accessibly wires the nested label and
- * input prop.
- * @param {string} formLabel Label/title for the form input.
- * @param {string} inputType Input type of the form.
- * @param {string} placeholder Text placeholder in the form input.
- * @param {React.RefObject} ref Ref attached to the values inputted in the form.
- * @param {string} subFormText Subtext instructions under a form input.
- * @return {JSX.Element} The Form.Group element.
- */
-function createFormGroup(controlId, formLabel, inputType, placeholder, ref) {
- let formControl;
- switch(inputType) {
- case 'text':
- formControl = createTextFormControl(placeholder, ref);
- break;
- case 'date':
- formControl = createDateFormControl(placeholder, ref);
- break;
- case 'emails':
- formControl = createMultiFormControl(placeholder, ref);
- break;
- default:
- console.error('There should be no other input type')
- }
-
- return (
-
- {formLabel}
- {formControl}
-
- )
-}
/**
* Component corresponding to the save trips modal.
*
- * This component "acts" as a parent of the (non-existent) AddTripModal and
+ * This component acts as a 'pseudo-parent' of the 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).
+ * the two fake components are dervied from the props `tripid` and
+ * `defaultFormObj` (see below). The primary difference between the add and
+ * edit trip modals is the former displays placeholder values in the empty form
+ * fields whereas the latter displays the current values of the trip in the
+ * respective form fields.
*
* @param {Object} props These are the props for this component:
- * - 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 saving (Remove when fix Issue #62).
+ * - show: Boolean that determines if the add trips modal should be displayed.
+ * - handleClose: Event handler responsible for closing the add trips modal.
+ * - refreshTripsContainer: Handler that refreshes the TripsContainer
+ * component upon trip creation (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
+ * - defaultFormObj: 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
@@ -144,11 +49,19 @@ class SaveTripModal extends React.Component {
this.isAddTripForm = this.props.tripId === null;
- // Create the number of collaborator input box refs as number of
- // collaborators specified in the placeholderObj
+ // For edit trips, create the number of collaborator input box refs as one
+ // less than the number of collaborators specified in prop `defaultFormObj`
+ // (do not include current user in list).
+ //
+ // TODO(Issue #71): Give user option to remove themself as a collaborator
+ // from current trip.
const collaboratorsRefArr = [];
- for (let i = 0; i < this.props.placeholderObj.collaborators.length; i++) {
- collaboratorsRefArr.push(React.createRef())
+ if (this.isAddTripForm) {
+ collaboratorsRefArr.push(React.createRef());
+ } else {
+ for (let i = 1; i < this.props.defaultFormObj.collaborators.length; i++) {
+ collaboratorsRefArr.push(React.createRef())
+ }
}
this.state = { collaboratorsRefArr: collaboratorsRefArr }
}
@@ -163,34 +76,34 @@ class SaveTripModal extends React.Component {
/**
* Creates a new Trip document in firestore with data in `tripData`.
*
- * @param {Object} tripData Data the new trip document will contain.
+ * @param {!Object} tripData Data the new trip document will contain.
*/
addNewTrip(tripData) {
- db.collection(COLLECTION_TRIPS)
+ db.collection(DB.COLLECTION_TRIPS)
.add(tripData)
.then(docRef => {
- console.log("Document written with ID: ", docRef.id);
+ console.log('Document written with ID: ', docRef.id);
})
.catch(error => {
- console.error("Error adding document: ", 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.
+ * @param {!string} tripId The document ID of the trip that is updated.
+ * @param {!Object} tripData Data the new trip document will contain.
*/
updateExistingTrip(tripId, tripData) {
- db.collection(COLLECTION_TRIPS)
+ db.collection(DB.COLLECTION_TRIPS)
.doc(tripId)
.set(tripData)
.then(() => {
- console.log("Document written with ID: ", tripId);
+ console.log('Document written with ID: ', tripId);
})
.catch(error => {
- console.error("Error adding document: ", error);
+ console.error('Error adding document: ', error);
});
}
@@ -238,6 +151,20 @@ class SaveTripModal extends React.Component {
return 'Edit Trip';
}
+ /** Returns the default form value for the trip field specified by `field`.
+ *
+ * @param {!string} field A trip document field
+ * (the constants in `database.js`).
+ * @return {?string} Default form value for edit trip modal or null for
+ * add trip modals.
+ */
+ getDefaultFormField = (field) => {
+ if (this.isAddTripForm) {
+ return null;
+ }
+ return this.props.defaultFormObj[field];
+ }
+
/** @inheritdoc */
render() {
return (
@@ -248,19 +175,54 @@ class SaveTripModal extends React.Component {