Skip to content

Commit

Permalink
Show location on map when editing a review
Browse files Browse the repository at this point in the history
* Rename id to locationId and reviewId
* Toast errors when getting review/location fails
* Pull locationId through redux into MapPage and show the marker (#386)
  The side pane and map components are only loosely coupled and make use of global state through redux.
  Extend this design instead of storing review id in the URL like the previous attempt.
  • Loading branch information
wbazant authored Jun 4, 2024
1 parent f94656d commit 049739b
Show file tree
Hide file tree
Showing 14 changed files with 180 additions and 124 deletions.
6 changes: 3 additions & 3 deletions src/components/desktop/NavBack.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ const NavBack = ({ isEntry }) => {
const { state } = useLocation()
const { t } = useTranslation()
// Restrict to integer :id to avoid match to e.g. /locations/new
const match = useRouteMatch('/locations/:id(\\d+)')
const entryId = match?.params.id
const match = useRouteMatch('/locations/:locationId(\\d+)')
const entryId = match?.params.locationId

const isEditingEntry = useRouteMatch('/locations/:id/edit')
const isEditingEntry = useRouteMatch('/locations/:locationId/edit')

const handleBackButtonClick = () => {
// Default to going back to the map. This occurs when the user opens /locations/:id directly
Expand Down
9 changes: 5 additions & 4 deletions src/components/desktop/SidePaneSwitch.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Redirect, Route, Switch } from 'react-router-dom'

import EntryWrapper from '../entry/EntryWrapper'
import { EditLocationPage, EditReviewPage } from '../form/EditableForm'
import { EditLocationPage } from '../form/EditLocation'
import { EditReviewPage } from '../form/EditReview'
import { LocationForm } from '../form/LocationForm'
import SettingsPage from '../settings/SettingsPage'
import MainPane from './MainPane'
Expand All @@ -15,10 +16,10 @@ const SidePaneSwitch = () => (
<Route>
<NavPane>
<Switch>
<Route path="/locations/:id/edit">
<Route path="/locations/:locationId/edit">
<EditLocationPage />
</Route>
<Route path="/reviews/:id/edit">
<Route path="/reviews/:reviewId/edit">
<EditReviewPage />
</Route>
<Route path="/locations/new">
Expand All @@ -27,7 +28,7 @@ const SidePaneSwitch = () => (
<Route path="/settings">
<SettingsPage desktop />
</Route>
<Route path={['/locations/:id', '/locations/:id']}>
<Route path="/locations/:locationId">
<EntryWrapper desktop />
</Route>
<Route>
Expand Down
8 changes: 4 additions & 4 deletions src/components/entry/EntryWrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,28 +19,28 @@ const EntryWrapper = ({ desktop }) => {
const [isLoading, setIsLoading] = useState(true)
const [isLightboxOpen, setIsLightboxOpen] = useState(false)
const [lightboxIndex, setLightboxIndex] = useState([0, 0])
const { id } = useParams()
const { locationId } = useParams()

useEffect(() => {
async function fetchEntryData() {
setIsLoading(true)

try {
const locationData = await getLocationById(id, 'reviews')
const locationData = await getLocationById(locationId, 'reviews')

dispatch(updateEntryLocation(locationData))
setReviews(locationData.reviews)
setIsLoading(false)
} catch {
toast.error(`Entry #${id} not found`, {
toast.error(`Location #${locationId} not found`, {
autoClose: 5000,
})
setIsError(true)
}
}

fetchEntryData()
}, [id, dispatch])
}, [locationId, dispatch])

const addSubmittedReview = (submittedReview) => {
setReviews((reviews) => [...reviews, submittedReview])
Expand Down
4 changes: 2 additions & 2 deletions src/components/entry/ReviewButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import Button from '../ui/Button'

export const ReviewButton = (props) => {
const history = useAppHistory()
const { id } = useParams()
const { locationId } = useParams()
const isDesktop = useIsDesktop()

return (
Expand All @@ -18,7 +18,7 @@ export const ReviewButton = (props) => {
window.location.hash = ''
window.location.hash = 'review'
} else {
history.push(`/locations/${id}/review`)
history.push(`/locations/${locationId}/review`)
}
}}
{...props}
Expand Down
51 changes: 51 additions & 0 deletions src/components/form/EditLocation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { useEffect, useState } from 'react'
import { useParams } from 'react-router-dom'
import { toast } from 'react-toastify'

import { getLocationById } from '../../utils/api'
import { useAppHistory } from '../../utils/useAppHistory'
import { Page } from '../entry/Entry'
import { LocationForm, locationToForm } from './LocationForm'

export const EditLocationForm = (props) => {
const { locationId } = useParams()
const history = useAppHistory()
const [location, setLocation] = useState(null)

useEffect(() => {
const loadFormData = async () => {
try {
const location = await getLocationById(locationId)
setLocation(location)
} catch (error) {
toast.error(`Location #${locationId} not found`)
}
}

loadFormData()
}, [locationId])

const handleSubmit = () => {
if (location) {
history.push(`/locations/${location.id}`)
}
}

return (
location && (
<LocationForm
initialValues={locationToForm(location)}
editingId={locationId}
onSubmit={handleSubmit}
{...props}
/>
)
)
}

export const EditLocationPage = () => (
<Page>
<h3 style={{ marginLeft: 10 }}>Editing Location</h3>
<EditLocationForm />
</Page>
)
61 changes: 61 additions & 0 deletions src/components/form/EditReview.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { useEffect, useState } from 'react'
import { useDispatch } from 'react-redux'
import { useParams } from 'react-router-dom'
import { toast } from 'react-toastify'

import { rememberLocationIdForReviewId } from '../../redux/miscSlice'
import { getReviewById } from '../../utils/api'
import { useAppHistory } from '../../utils/useAppHistory'
import { Page } from '../entry/Entry'
import { ReviewForm, reviewToForm } from './ReviewForm'

export const EditReviewForm = (props) => {
const { reviewId } = useParams()
const history = useAppHistory()
const dispatch = useDispatch()
const [review, setReview] = useState(null)

useEffect(() => {
const loadFormData = async () => {
try {
const review = await getReviewById(reviewId)
dispatch(
rememberLocationIdForReviewId({
reviewId,
locationId: review.location_id,
}),
)
setReview(review)
} catch (error) {
toast.error(`Review #${reviewId} not found`)
}
}

loadFormData()
}, [reviewId, dispatch])

const afterSubmit = () => {
if (review) {
history.push(`/locations/${review.location_id}`)
}
}
return (
review && (
<ReviewForm
initialValues={{ review: reviewToForm(review) }}
editingId={reviewId}
onSubmit={afterSubmit}
{...props}
/>
)
)
}

export const EditReviewPage = () => (
<Page>
<div style={{ paddingLeft: 10, paddingRight: 10 }}>
<h3>Editing My Review</h3>
<EditReviewForm />
</div>
</Page>
)
78 changes: 0 additions & 78 deletions src/components/form/EditableForm.js

This file was deleted.

6 changes: 3 additions & 3 deletions src/components/form/LocationNav.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const LocationNav = () => {

return (
<Switch>
<Route path="/reviews/:id/edit">
<Route path="/reviews/:reviewId/edit">
{() => (
<TopBarNav
onBack={(event) => {
Expand All @@ -27,7 +27,7 @@ const LocationNav = () => {
/>
)}
</Route>
<Route path="/locations/:id/review">
<Route path="/locations/:locationId/review">
{() => (
<TopBarNav
onBack={(event) => {
Expand All @@ -38,7 +38,7 @@ const LocationNav = () => {
/>
)}
</Route>
<Route path="/locations/:id/edit">
<Route path="/locations/:locationId/edit">
{() => (
<TopBarNav
onBack={(event) => {
Expand Down
2 changes: 1 addition & 1 deletion src/components/form/ReviewForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ export const ReviewForm = ({
initialValues = INITIAL_REVIEW_VALUES,
editingId = null,
}) => {
const { id: locationId } = useParams()
const { locationId } = useParams()
const isLoggedIn = useSelector((state) => !!state.auth.user)

const handleSubmit = async (
Expand Down
1 change: 0 additions & 1 deletion src/components/map/Location.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ const Label = styled.div`

const Location = memo(({ label, selected, ...props }) => (
<>
{/* "selected" will be used in a future PR which will put a pin on the location when it's clicked */}
{selected && <MapPin />}
<LocationButton {...props} />
<Label>{label}</Label>
Expand Down
30 changes: 21 additions & 9 deletions src/components/map/MapPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,27 @@ const BottomLeftLoadingIndicator = styled(LoadingIndicator)`

const MapPage = ({ isDesktop }) => {
const history = useAppHistory()
const match = useRouteMatch({
path: ['/locations/:entryId/:nextSegment', '/locations/:entryId'],
const locationRouteMatch = useRouteMatch({
path: ['/locations/:locationId/:nextSegment', '/locations/:locationId'],
})

const isAddingLocation = match?.params.entryId === 'new'
const entryId = match?.params.entryId && parseInt(match.params.entryId)
// distinguish viewing a location from having it displayed during e.g. editing or review
const isViewingLocation =
entryId && match.params.nextSegment?.indexOf('@') === 0
const reviewRouteMatch = useRouteMatch({
path: '/reviews/:reviewId/edit',
})
const locationIdsByReviewId = useSelector(
(state) => state.misc.locationIdsByReviewId,
)
let locationId, isAddingLocation, isViewingLocation
if (locationRouteMatch) {
locationId = parseInt(locationRouteMatch.params.locationId)
isAddingLocation = locationRouteMatch.params.locationId === 'new'
isViewingLocation =
locationRouteMatch.params.nextSegment?.indexOf('@') === 0
} else if (reviewRouteMatch) {
const reviewId = parseInt(reviewRouteMatch.params.reviewId)
locationId = locationIdsByReviewId[reviewId]
isAddingLocation = false
isViewingLocation = true
}

const { getCommonName } = useTypesById()
const dispatch = useDispatch()
Expand Down Expand Up @@ -106,7 +118,7 @@ const MapPage = ({ isDesktop }) => {
typeName: getCommonName(location.type_ids[0]),
}))
}
activeLocationId={entryId || hoveredLocationId}
activeLocationId={locationId || hoveredLocationId}
onViewChange={(newView) => {
dispatch(viewChangeAndFetch(newView))
}}
Expand Down
Loading

0 comments on commit 049739b

Please sign in to comment.