Skip to content

Commit 0370023

Browse files
Merge pull request #208 from googleinterns/save-trips
Save/Share trips
2 parents 89890d8 + d236f59 commit 0370023

17 files changed

+264
-148
lines changed

frontend/src/App.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ function Authenticator({ children, onChange, setTripIds }) {
5656
readUser(userEmail).then((userData) => {
5757
// Empty list representation in datastore
5858
if (userData.tripIds !== 'null') {
59-
setTripIds(userData.tripIds);
59+
setTripIds(JSON.parse(userData.tripIds));
6060
}
6161
});
6262
}

frontend/src/ExploreView.js

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ function Explore() {
2828
'trip' in query
2929
? JSON.parse(decodeURIComponent(query.trip))
3030
: {
31-
centerLocation: {},
31+
centerLat: 0,
32+
centerLng: 0,
3233
attractions: [],
3334
searchText,
3435
tripId: null,
@@ -75,6 +76,10 @@ function Explore() {
7576
}
7677
}, [loadMore, getNextPage]);
7778

79+
useEffect(() => {
80+
setTripObject({ ...tripObject, attractions: selectedAttractions });
81+
}, [selectedAttractions]);
82+
7883
/**
7984
* Get the photo url of each attraction object
8085
* @param {object[]} attractions array of objects from Places Request
@@ -88,16 +93,24 @@ function Explore() {
8893
const name = attraction.name;
8994
const photoUrl = attraction.photos[0].getUrl();
9095
const latLng = attraction.geometry.location;
91-
const isSelected = selectedAttractions.some(
92-
(newAttraction) => newAttraction.photoUrl === attraction.photos[0].getUrl()
93-
);
96+
let isSelected;
97+
if (tripObject.tripId) {
98+
isSelected = selectedAttractions.some(
99+
(newAttraction) => newAttraction.name === attraction.name
100+
);
101+
} else {
102+
isSelected = selectedAttractions.some(
103+
(newAttraction) =>
104+
newAttraction.photoUrl === attraction.photos[0].getUrl()
105+
);
106+
}
94107
const newAttraction = createAttraction(name, latLng, photoUrl, isSelected);
95108
newAllAttractions.push(newAttraction);
96109
}
97110
}
98111
return newAllAttractions;
99112
},
100-
[selectedAttractions]
113+
[selectedAttractions, tripObject]
101114
);
102115

103116
const handleNearbySearch = useCallback(
@@ -125,10 +138,8 @@ function Explore() {
125138
const coordinates = textSearchResults.current[0].geometry.location;
126139
setTripObject({
127140
...tripObject,
128-
centerLocation: {
129-
lat: coordinates.lat(),
130-
lng: coordinates.lng(),
131-
},
141+
centerLat: coordinates.lat(),
142+
centerLng: coordinates.lng(),
132143
});
133144
placesService.current.nearbySearch(
134145
{
@@ -261,7 +272,7 @@ function Explore() {
261272
onReady={onMapReady}
262273
attractions={selectedAttractions}
263274
mode="pins"
264-
centerLocation={tripObject.centerLocation}
275+
centerLocation={{ lat: tripObject.centerLat, lng: tripObject.centerLng }}
265276
key={selectedAttractions}
266277
/>
267278
</div>
@@ -278,7 +289,7 @@ function Explore() {
278289
*/
279290
function toggleSelection(targetAttraction) {
280291
const targetAttrIndexInSelected = selectedAttractions.findIndex(
281-
(attraction) => attraction.photoUrl === targetAttraction.photoUrl
292+
(attraction) => attraction.name === targetAttraction.name
282293
);
283294

284295
targetAttraction.selected = !targetAttraction.selected;
@@ -304,7 +315,6 @@ function Explore() {
304315
function createAttraction(name, latLng, photoUrl, selected) {
305316
return {
306317
name,
307-
description: 'Insert description here.',
308318
lat: latLng.lat(),
309319
lng: latLng.lng(),
310320
photoUrl,

frontend/src/ExploreView.module.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@
6969
.attractionNameOverlay {
7070
color: white;
7171
display: none;
72-
font-size: 2.5vmin;
72+
font-size: 18px;
7373
font-weight: 500;
7474
text-align: left;
7575
}

frontend/src/RouteView.js

Lines changed: 28 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
1-
import React, { useState, useEffect, useRef } from 'react';
1+
import React, { useState, useEffect } from 'react';
22
import { useLocation, useHistory } from 'react-router-dom';
3-
import Button from 'react-bootstrap/Button';
43
import Container from 'react-bootstrap/Container';
54
import Row from 'react-bootstrap/Row';
65
import Col from 'react-bootstrap/Col';
7-
import Modal from 'react-bootstrap/Modal';
86
import styles from './RouteView.module.css';
9-
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
10-
import { faClone } from '@fortawesome/free-solid-svg-icons';
117
import { getQueryParameters, handleRouting } from './routingUtils.js';
128
import { createTrip, updateTrip } from './tripUtils.js';
139

@@ -17,6 +13,7 @@ import OptimizeButton from './route/OptimizeButton.js';
1713
import SaveShareButtons from './route/SaveShareButtons.js';
1814
import TripName from './trip-name/TripName.js';
1915
import BackButton from './navbar/BackButton.js';
16+
import ShareTripModal from './share-trip/ShareTripModal.js';
2017

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

31-
const textAreaRef = useRef(null);
32-
const handleShareClose = () => setShowShareModal(false);
33-
const handleShareShow = () => setShowShareModal(true);
34-
3528
const urlParameters = useLocation();
3629
const query = getQueryParameters(urlParameters.search);
3730
const history = useHistory();
38-
const tripObject = JSON.parse(decodeURIComponent(query.trip));
31+
const [tripObject, setTripObject] = useState(
32+
JSON.parse(decodeURIComponent(query.trip))
33+
);
3934
const [attractions, setAttractions] = useState(tripObject.attractions);
4035

4136
useEffect(() => {
@@ -56,18 +51,19 @@ function RouteView({ loggedIn, userEmail }) {
5651
}
5752
setIsOptimized(true);
5853
setIsOptimizing(false);
54+
setIsSaved(false);
5955
}
6056

6157
function save() {
62-
setIsSaved(true);
63-
// save to back end database
6458
tripObject.isOptimized = isOptimized;
65-
console.log(tripObject);
66-
if (!tripObject.id) {
67-
createTrip(userEmail, tripObject).then((tripId) => console.log(tripId));
59+
if (!tripObject.tripId) {
60+
createTrip(userEmail, tripObject)
61+
.then((res) => res.json())
62+
.then((json) => setTripObject({ ...tripObject, tripId: json.tripId }));
6863
} else {
69-
updateTrip(tripObject.id, tripObject);
64+
updateTrip(tripObject.tripId, tripObject);
7065
}
66+
setIsSaved(true);
7167
}
7268

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

80-
function copyToClipboard(e) {
81-
textAreaRef.current.select();
82-
document.execCommand('copy');
83-
}
84-
8576
return (
8677
<>
87-
<Modal show={showShareModal} onHide={handleShareClose}>
88-
<Modal.Header closeButton>
89-
<Modal.Title>Share Trip</Modal.Title>
90-
</Modal.Header>
91-
<Modal.Body>
92-
<Container>
93-
<Row className={styles.copyContainer}>
94-
<div className={styles.modalText}>Copy link to share trip.</div>
95-
<input
96-
ref={textAreaRef}
97-
value={window.location.href}
98-
className={styles.copyText}
99-
/>
100-
<FontAwesomeIcon
101-
icon={faClone}
102-
onClick={copyToClipboard}
103-
className={styles.copyBtn}
104-
/>
105-
</Row>
106-
<Row className={styles.modalBtnContainer}>
107-
<Button
108-
variant="primary"
109-
onClick={handleShareClose}
110-
className={styles.modalBtn}
111-
>
112-
Close
113-
</Button>
114-
</Row>
115-
</Container>
116-
</Modal.Body>
117-
</Modal>
78+
<ShareTripModal
79+
showShareModal={showShareModal}
80+
setShowShareModal={setShowShareModal}
81+
tripName={tripObject.tripName}
82+
url={window.location.href}
83+
/>
11884
<BackButton
11985
className={styles.editBtnContainer}
12086
onClick={() => handleRouting(history, 'explore', tripObject, attractions)}
12187
text="Edit Attractions"
12288
/>
12389
{loggedIn && (
124-
<SaveShareButtons isSaved={isSaved} save={save} share={handleShareShow} />
90+
<SaveShareButtons
91+
isSaved={isSaved}
92+
save={save}
93+
share={() => setShowShareModal(true)}
94+
/>
12595
)}
12696
<div className={styles.container}>
12797
<Row className={styles.row}>
12898
<Col sm={4}>
12999
<Row className={styles.row}>
130-
<TripName />
100+
<TripName tripObject={tripObject} setTripObject={setTripObject} />
131101
</Row>
132102
<Row className={styles.routeListContainer}>
133103
<Route places={attractions} onManualPlaceChange={onManualPlaceChange} />
@@ -150,7 +120,10 @@ function RouteView({ loggedIn, userEmail }) {
150120
<Map
151121
mode="directions"
152122
attractions={attractions}
153-
centerLocation={tripObject.centerLocation}
123+
centerLocation={{
124+
lat: tripObject.centerLat,
125+
lng: tripObject.centerLng,
126+
}}
154127
/>
155128
</div>
156129
</Col>

frontend/src/RouteView.module.css

Lines changed: 0 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -6,53 +6,12 @@
66
padding-left: 15px;
77
}
88

9-
.copyContainer {
10-
margin: 15px 0;
11-
}
12-
13-
.copyText {
14-
background-color: #f0f0f0;
15-
border: none;
16-
border-radius: 5px;
17-
padding: 6px;
18-
width: 90%;
19-
}
20-
21-
.copyText:focus {
22-
outline: none;
23-
}
24-
25-
.copyBtn {
26-
font-size: 1.2rem;
27-
margin: 7px 10px;
28-
opacity: 0.6;
29-
}
30-
31-
.copyBtn:hover {
32-
cursor: pointer;
33-
opacity: 0.8;
34-
}
35-
369
.editBtnContainer {
3710
left: 28px;
3811
position: absolute;
3912
top: 20px;
4013
}
4114

42-
.modalBtn {
43-
margin: 5px 30px;
44-
padding: 5px;
45-
width: 70px;
46-
}
47-
48-
.modalBtnContainer {
49-
justify-content: flex-end;
50-
}
51-
52-
.modalText {
53-
margin-bottom: 10px;
54-
}
55-
5615
.container {
5716
margin: auto;
5817
max-width: 2000px;

frontend/src/SearchView.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import styles from './SearchView.module.css';
1111
function SearchView({ loggedIn, tripIds }) {
1212
const savedTrips = loggedIn ? (
1313
tripIds.length > 0 ? (
14-
<SavedTrips trips={tripIds} />
14+
<SavedTrips tripIds={tripIds} />
1515
) : (
1616
<div className={styles.noTrips}>No saved trips found.</div>
1717
)

frontend/src/route/LocationCard.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,10 @@ import { Draggable } from 'react-beautiful-dnd';
1111
/**
1212
* Return a card component representing a place the user has selected.
1313
* @param {string} location the name of the place selected
14-
* @param {string} description a description of @param location
1514
* @param {string} image image source of @param location
1615
* @param {number} index index of location in route list
1716
*/
18-
function LocationCard({ location, description, image, index }) {
17+
function LocationCard({ location, image, index }) {
1918
// ref: https://egghead.io/lessons/react-reorder-a-list-with-react-beautiful-dnd
2019
return (
2120
<Draggable draggableId={`draggable-${index}`} index={index}>

frontend/src/route/Route.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ function Route({ places, onManualPlaceChange }) {
3737
{places.map((place, index) => (
3838
<LocationCard
3939
location={place.name}
40-
description={place.description}
4140
image={place.photoUrl}
4241
index={index}
4342
key={index}

frontend/src/routingUtils.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export const getQueryParameters = (query) => {
1616
* @param {object} attractions list of selected attractions
1717
*/
1818
export const handleRouting = (history, page, tripObject, attractions) => {
19-
tripObject.attractions = attractions;
20-
const url = '?trip=' + encodeURIComponent(JSON.stringify(tripObject));
21-
history.push(`/${page}${url}`);
19+
const tripWithAttractions = { ...tripObject, attractions };
20+
const encodedTrip = encodeURIComponent(JSON.stringify(tripWithAttractions));
21+
history.push(`/${page}?trip=${encodedTrip}`);
2222
};

0 commit comments

Comments
 (0)