Skip to content

Commit

Permalink
Merge pull request #208 from googleinterns/save-trips
Browse files Browse the repository at this point in the history
Save/Share trips
  • Loading branch information
Cindyzhang977 authored Aug 7, 2020
2 parents 89890d8 + d236f59 commit 0370023
Show file tree
Hide file tree
Showing 17 changed files with 264 additions and 148 deletions.
2 changes: 1 addition & 1 deletion frontend/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ function Authenticator({ children, onChange, setTripIds }) {
readUser(userEmail).then((userData) => {
// Empty list representation in datastore
if (userData.tripIds !== 'null') {
setTripIds(userData.tripIds);
setTripIds(JSON.parse(userData.tripIds));
}
});
}
Expand Down
34 changes: 22 additions & 12 deletions frontend/src/ExploreView.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ function Explore() {
'trip' in query
? JSON.parse(decodeURIComponent(query.trip))
: {
centerLocation: {},
centerLat: 0,
centerLng: 0,
attractions: [],
searchText,
tripId: null,
Expand Down Expand Up @@ -75,6 +76,10 @@ function Explore() {
}
}, [loadMore, getNextPage]);

useEffect(() => {
setTripObject({ ...tripObject, attractions: selectedAttractions });
}, [selectedAttractions]);

/**
* Get the photo url of each attraction object
* @param {object[]} attractions array of objects from Places Request
Expand All @@ -88,16 +93,24 @@ function Explore() {
const name = attraction.name;
const photoUrl = attraction.photos[0].getUrl();
const latLng = attraction.geometry.location;
const isSelected = selectedAttractions.some(
(newAttraction) => newAttraction.photoUrl === attraction.photos[0].getUrl()
);
let isSelected;
if (tripObject.tripId) {
isSelected = selectedAttractions.some(
(newAttraction) => newAttraction.name === attraction.name
);
} else {
isSelected = selectedAttractions.some(
(newAttraction) =>
newAttraction.photoUrl === attraction.photos[0].getUrl()
);
}
const newAttraction = createAttraction(name, latLng, photoUrl, isSelected);
newAllAttractions.push(newAttraction);
}
}
return newAllAttractions;
},
[selectedAttractions]
[selectedAttractions, tripObject]
);

const handleNearbySearch = useCallback(
Expand Down Expand Up @@ -125,10 +138,8 @@ function Explore() {
const coordinates = textSearchResults.current[0].geometry.location;
setTripObject({
...tripObject,
centerLocation: {
lat: coordinates.lat(),
lng: coordinates.lng(),
},
centerLat: coordinates.lat(),
centerLng: coordinates.lng(),
});
placesService.current.nearbySearch(
{
Expand Down Expand Up @@ -261,7 +272,7 @@ function Explore() {
onReady={onMapReady}
attractions={selectedAttractions}
mode="pins"
centerLocation={tripObject.centerLocation}
centerLocation={{ lat: tripObject.centerLat, lng: tripObject.centerLng }}
key={selectedAttractions}
/>
</div>
Expand All @@ -278,7 +289,7 @@ function Explore() {
*/
function toggleSelection(targetAttraction) {
const targetAttrIndexInSelected = selectedAttractions.findIndex(
(attraction) => attraction.photoUrl === targetAttraction.photoUrl
(attraction) => attraction.name === targetAttraction.name
);

targetAttraction.selected = !targetAttraction.selected;
Expand All @@ -304,7 +315,6 @@ function Explore() {
function createAttraction(name, latLng, photoUrl, selected) {
return {
name,
description: 'Insert description here.',
lat: latLng.lat(),
lng: latLng.lng(),
photoUrl,
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/ExploreView.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
.attractionNameOverlay {
color: white;
display: none;
font-size: 2.5vmin;
font-size: 18px;
font-weight: 500;
text-align: left;
}
Expand Down
83 changes: 28 additions & 55 deletions frontend/src/RouteView.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
import React, { useState, useEffect, useRef } from 'react';
import React, { useState, useEffect } from 'react';
import { useLocation, useHistory } from 'react-router-dom';
import Button from 'react-bootstrap/Button';
import Container from 'react-bootstrap/Container';
import Row from 'react-bootstrap/Row';
import Col from 'react-bootstrap/Col';
import Modal from 'react-bootstrap/Modal';
import styles from './RouteView.module.css';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faClone } from '@fortawesome/free-solid-svg-icons';
import { getQueryParameters, handleRouting } from './routingUtils.js';
import { createTrip, updateTrip } from './tripUtils.js';

Expand All @@ -17,6 +13,7 @@ import OptimizeButton from './route/OptimizeButton.js';
import SaveShareButtons from './route/SaveShareButtons.js';
import TripName from './trip-name/TripName.js';
import BackButton from './navbar/BackButton.js';
import ShareTripModal from './share-trip/ShareTripModal.js';

/**
* Render the route page with list of locations in order and directions on a map between the locations.
Expand All @@ -28,14 +25,12 @@ function RouteView({ loggedIn, userEmail }) {
const [optimizedOrder, setOptimizedOrder] = useState(null);
const [showShareModal, setShowShareModal] = useState(false);

const textAreaRef = useRef(null);
const handleShareClose = () => setShowShareModal(false);
const handleShareShow = () => setShowShareModal(true);

const urlParameters = useLocation();
const query = getQueryParameters(urlParameters.search);
const history = useHistory();
const tripObject = JSON.parse(decodeURIComponent(query.trip));
const [tripObject, setTripObject] = useState(
JSON.parse(decodeURIComponent(query.trip))
);
const [attractions, setAttractions] = useState(tripObject.attractions);

useEffect(() => {
Expand All @@ -56,18 +51,19 @@ function RouteView({ loggedIn, userEmail }) {
}
setIsOptimized(true);
setIsOptimizing(false);
setIsSaved(false);
}

function save() {
setIsSaved(true);
// save to back end database
tripObject.isOptimized = isOptimized;
console.log(tripObject);
if (!tripObject.id) {
createTrip(userEmail, tripObject).then((tripId) => console.log(tripId));
if (!tripObject.tripId) {
createTrip(userEmail, tripObject)
.then((res) => res.json())
.then((json) => setTripObject({ ...tripObject, tripId: json.tripId }));
} else {
updateTrip(tripObject.id, tripObject);
updateTrip(tripObject.tripId, tripObject);
}
setIsSaved(true);
}

function onManualPlaceChange(newAttractions) {
Expand All @@ -77,57 +73,31 @@ function RouteView({ loggedIn, userEmail }) {
handleRouting(history, 'route', tripObject, newAttractions);
}

function copyToClipboard(e) {
textAreaRef.current.select();
document.execCommand('copy');
}

return (
<>
<Modal show={showShareModal} onHide={handleShareClose}>
<Modal.Header closeButton>
<Modal.Title>Share Trip</Modal.Title>
</Modal.Header>
<Modal.Body>
<Container>
<Row className={styles.copyContainer}>
<div className={styles.modalText}>Copy link to share trip.</div>
<input
ref={textAreaRef}
value={window.location.href}
className={styles.copyText}
/>
<FontAwesomeIcon
icon={faClone}
onClick={copyToClipboard}
className={styles.copyBtn}
/>
</Row>
<Row className={styles.modalBtnContainer}>
<Button
variant="primary"
onClick={handleShareClose}
className={styles.modalBtn}
>
Close
</Button>
</Row>
</Container>
</Modal.Body>
</Modal>
<ShareTripModal
showShareModal={showShareModal}
setShowShareModal={setShowShareModal}
tripName={tripObject.tripName}
url={window.location.href}
/>
<BackButton
className={styles.editBtnContainer}
onClick={() => handleRouting(history, 'explore', tripObject, attractions)}
text="Edit Attractions"
/>
{loggedIn && (
<SaveShareButtons isSaved={isSaved} save={save} share={handleShareShow} />
<SaveShareButtons
isSaved={isSaved}
save={save}
share={() => setShowShareModal(true)}
/>
)}
<div className={styles.container}>
<Row className={styles.row}>
<Col sm={4}>
<Row className={styles.row}>
<TripName />
<TripName tripObject={tripObject} setTripObject={setTripObject} />
</Row>
<Row className={styles.routeListContainer}>
<Route places={attractions} onManualPlaceChange={onManualPlaceChange} />
Expand All @@ -150,7 +120,10 @@ function RouteView({ loggedIn, userEmail }) {
<Map
mode="directions"
attractions={attractions}
centerLocation={tripObject.centerLocation}
centerLocation={{
lat: tripObject.centerLat,
lng: tripObject.centerLng,
}}
/>
</div>
</Col>
Expand Down
41 changes: 0 additions & 41 deletions frontend/src/RouteView.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -6,53 +6,12 @@
padding-left: 15px;
}

.copyContainer {
margin: 15px 0;
}

.copyText {
background-color: #f0f0f0;
border: none;
border-radius: 5px;
padding: 6px;
width: 90%;
}

.copyText:focus {
outline: none;
}

.copyBtn {
font-size: 1.2rem;
margin: 7px 10px;
opacity: 0.6;
}

.copyBtn:hover {
cursor: pointer;
opacity: 0.8;
}

.editBtnContainer {
left: 28px;
position: absolute;
top: 20px;
}

.modalBtn {
margin: 5px 30px;
padding: 5px;
width: 70px;
}

.modalBtnContainer {
justify-content: flex-end;
}

.modalText {
margin-bottom: 10px;
}

.container {
margin: auto;
max-width: 2000px;
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/SearchView.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import styles from './SearchView.module.css';
function SearchView({ loggedIn, tripIds }) {
const savedTrips = loggedIn ? (
tripIds.length > 0 ? (
<SavedTrips trips={tripIds} />
<SavedTrips tripIds={tripIds} />
) : (
<div className={styles.noTrips}>No saved trips found.</div>
)
Expand Down
3 changes: 1 addition & 2 deletions frontend/src/route/LocationCard.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,10 @@ import { Draggable } from 'react-beautiful-dnd';
/**
* Return a card component representing a place the user has selected.
* @param {string} location the name of the place selected
* @param {string} description a description of @param location
* @param {string} image image source of @param location
* @param {number} index index of location in route list
*/
function LocationCard({ location, description, image, index }) {
function LocationCard({ location, image, index }) {
// ref: https://egghead.io/lessons/react-reorder-a-list-with-react-beautiful-dnd
return (
<Draggable draggableId={`draggable-${index}`} index={index}>
Expand Down
1 change: 0 additions & 1 deletion frontend/src/route/Route.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ function Route({ places, onManualPlaceChange }) {
{places.map((place, index) => (
<LocationCard
location={place.name}
description={place.description}
image={place.photoUrl}
index={index}
key={index}
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/routingUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export const getQueryParameters = (query) => {
* @param {object} attractions list of selected attractions
*/
export const handleRouting = (history, page, tripObject, attractions) => {
tripObject.attractions = attractions;
const url = '?trip=' + encodeURIComponent(JSON.stringify(tripObject));
history.push(`/${page}${url}`);
const tripWithAttractions = { ...tripObject, attractions };
const encodedTrip = encodeURIComponent(JSON.stringify(tripWithAttractions));
history.push(`/${page}?trip=${encodedTrip}`);
};
Loading

0 comments on commit 0370023

Please sign in to comment.