Skip to content

Commit

Permalink
Merge pull request #36 from googleinterns/view-trips-react-setup
Browse files Browse the repository at this point in the history
Initial Query Trips Implementation in ReactJS
  • Loading branch information
zghera authored Jul 15, 2020
2 parents 68e5d07 + 5118c4b commit bd9f702
Show file tree
Hide file tree
Showing 7 changed files with 168 additions and 11 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@
# Target folder is generated by maven when deploying the app so it
# does not make sense to include in the repo.
target/

# Don't include log files
*.log
2 changes: 1 addition & 1 deletion frontend/src/components/App/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class App extends React.Component {
<Route exact path={ROUTES.LANDING} component={LandingPage} />
<Route path={ROUTES.SIGN_IN} component={SignInPage} />
<Route path={ROUTES.VIEW_TRIPS} component={ViewTripsPage} />
<Route path={ROUTES.VIEW_ACTIVITIES} component={ViewActivitiesPage} />
<Route path={ROUTES.VIEW_ACTIVITIES + '/:tripId'} component={ViewActivitiesPage} />
</div>
</Router>
);
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/ViewActivities/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ class ViewActivities extends React.Component {
</div>
);
}
};
}

export default ViewActivities;
35 changes: 26 additions & 9 deletions frontend/src/components/ViewTrips/index.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,33 @@
import React from 'react';

import app from '../Firebase';
import TripsContainer from './trips-container.js'

const db = app.firestore();

/**
* Temporary hardcoded function that returns the current users email.
*
* The hardcoded string was created based on one of the manually created test
* Trip Documents. This function will be implemented in the user authentication
* JS module using Firebase's Authentication API.
*
* TODO(Issue 16): Remove this function once implemented in authentication
* module.
* @return Hardcoded user email string.
*/
function getUserEmail() {
return 'matt.murdock';
}

/**
* ViewTrips component.
* ViewTrips component that defines the page where a user can view and manage
* their current trips.
*/
class ViewTrips extends React.Component {
render() {
return (
<div>
<h1>View Trips</h1>
</div>
);
}
const ViewTrips = () => {
return (
<TripsContainer db={db} userEmail={getUserEmail()} />
);
};

export default ViewTrips;
28 changes: 28 additions & 0 deletions frontend/src/components/ViewTrips/trip.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from 'react';

/**
* Component corresponding to the container containing an individual trip.
*
* Trip object fields are cleaned and vetted with firestore security rules
* when trips are added and/or editted. Thus, no error checking is done here
* on the 'display' side.
*
* TODO(Issue 17): Feed all the Trip Doc data to the UI.
* Temporarily, only the title and associated document ID are included in a
* text element for each trip <div> element. This is done to simple test the
* query functionality.
*
* @param {Object} props These are the props for this component:
* - tripObj: JS object holding a Trip document fields and corresponding values.
* - tripId: Document ID for the current Trip document.
*/
const Trip = (props) => {
return (
<div>
<h2>{props.tripObj.name}</h2>
<p>Doc Id: {props.tripId}</p>
</div>
);
};

export default Trip;
93 changes: 93 additions & 0 deletions frontend/src/components/ViewTrips/trips-container.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import React from 'react';

import Trip from './trip.js';
import * as DATABASE from '../../constants/database.js';


/**
* Returns a promise of a query object containg the array of Trip Documents
* corresponding to the trips that the current user is a collaborator on.
*
* @param {firebase.firestore.Firestore} db The Firestore database instance.
* @param {string} userEmail The email corresponding to the current user
* logged in.
* @return {Promise<!firebase.firestore.QuerySnapshot>} Promise object
* containing the query results with zero or more Trip documents.
*/
function queryUserTrips(db, userEmail) {
return db.collection(DATABASE.COLLECTION_TRIPS)
.where(DATABASE.TRIPS_COLLABORATORS, 'array-contains', userEmail)
.get();
}

/**
* Grabs Trips query result from `queryUserTrips()` and returns an array of
* `<Trip>` elements as defined in `trip.js`.
*
* @param {Promise<!firebase.firestore.QuerySnapshot>} querySnapshot Promise
* object containing the query results with zero or more Trip documents.
* @return {Promise<!Array<Trip>>} Promise object containing an array
* of Trip React/HTML elements corresponding to the Trip documents included
* in `querySnapshot`.
*/
function serveTrips(querySnapshot) {
return new Promise(function(resolve) {
const tripsContainer = querySnapshot.docs.map(doc =>
( <Trip key={doc.id} tripObj={doc.data()} tripId={doc.id} /> ));
resolve(tripsContainer);
});
}

/**
* Returns a `<div>` element with the specified error message.
*
* @param {string} error Error message in `componentDidMount()` catch statement.
* @return {Promise<HTMLDivElement>} Promise object containing a `<div>` element
* with the error message `error` inside.
*/
function getErrorElement(error) {
return new Promise(function(resolve) {
console.log(`Error in Trips Container: ${error}`);
resolve(( <div><p>Error: Unable to load your trips.</p></div> ));
});
}

/**
* Component corresponding to the container containing a user's trips.
* props
*
* @param {Object} props These are the props for this component:
* - db: Firestore database instance.
* - userEmail: The current user's email.
* @extends React.Component
*/
class TripsContainer extends React.Component {
/** @inheritdoc */
constructor(props) {
super(props);
this.state = {trips: []};
}

/** @inheritdoc */
async componentDidMount() {
try {
const querySnapshot = await queryUserTrips(
this.props.db, this.props.userEmail);
let tripsContainer = await serveTrips(querySnapshot);
this.setState({ trips: tripsContainer });
}
catch (error) {
let errorElement = await getErrorElement(error);
this.setState({ trips: errorElement });
}
}

/** @inheritdoc */
render() {
return (
<div>{this.state.trips}</div>
);
}
}

export default TripsContainer;
16 changes: 16 additions & 0 deletions frontend/src/constants/database.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* This file specifies the database collection and field names.
*/
export const COLLECTION_TRIPS = 'trips';
export const TRIPS_NAME = 'name';
export const TRIPS_DESCRIPTION = 'description';
export const TRIPS_DESTINATION = 'destination';
export const TRIPS_COLLABORATORS = 'collaborators';
export const TRIPS_START_DATE = 'start_date';
export const TRIPS_END_DATE = 'end_date';

export const COLLECTION_ACTIVITIES = 'activities';
export const ACTIVITIES_START_TIME = 'start_time';
export const ACTIVITIES_END_TIME = 'end_time';
export const ACTIVITIES_TITLE = 'title';
export const ACTIVITIES_DESCRIPTION = 'description';

0 comments on commit bd9f702

Please sign in to comment.