Skip to content

Commit

Permalink
Use LocationSearch API in Map form view (#64) (#65)
Browse files Browse the repository at this point in the history
* added search bar component in report form (#64)

* added search bar component in report form

* updated the location coordinates in search bar

* updated map co-ordinates with search

* remove console.logs from code

* updated the location on summary of report page

* separate namespace for useMainStore actions

* separate namespace for useFormStore

* normalization helper to round lat, lng

* remove duplicate initial state

* refactor to use store actions namespace

* setGeoData in locationsearch

* latLngToString helper

* fix drag to update location and update form location not main store

---------

Co-authored-by: Harsh <70363509+HarshMakadiya@users.noreply.github.com>
  • Loading branch information
toreylittlefield and HarshMakadiya committed Oct 7, 2023
1 parent 4058429 commit 0d445fe
Show file tree
Hide file tree
Showing 17 changed files with 162 additions and 123 deletions.
4 changes: 2 additions & 2 deletions packages/client/lib/components/BottomNav/BottomNav.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useState } from 'react';
import useFormStore from '../../../store/formStore.js';
import { useFormStoreActions } from '../../../store/formStore.js';
import { SVGIcon } from '../common/icons/SVGIcon.jsx';
import BottomNavItem from './BottomNavItem.jsx';

Expand Down Expand Up @@ -27,7 +27,7 @@ const RIGHT_NAV_ITEMS = BOTTOM_NAV_ITEMS.slice(2, 4);

const BottomNav = () => {
const [active, setActive] = useState(0);
const setShowForm = useFormStore((state) => state.setShowForm);
const { setShowForm } = useFormStoreActions();

const handleActive = (name) => {
setActive(name);
Expand Down
10 changes: 6 additions & 4 deletions packages/client/lib/components/LocationSearch.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { useRef, useState } from 'react';
import { useMainStoreActions } from '../../store/store';
import useOnClickOutside from '../hooks/useOnClickOutside';
import { SVGIcon } from './common/icons/SVGIcon';

Expand All @@ -22,12 +21,15 @@ const getSearchLocationData = async (searchText) => {
}
};

const LocationSearch = () => {
/**
* @property {({ lat, lng }) => void} setLocationData
* @returns {JSX.Element}
*/
const LocationSearch = ({ setLocationData }) => {
const [isOpen, setIsOpen] = useState(false);
const [value, setValue] = useState('');
const [results, setResults] = useState([]);
const searchRef = useRef(null);
const { setGeoData } = useMainStoreActions();

let debounceTimerRef = useRef(null);

Expand All @@ -52,7 +54,7 @@ const LocationSearch = () => {
console.log('Clicked on item:', name, lat, lng);
setValue(name);
setIsOpen(false);
setGeoData({ lat, lng });
setLocationData({ lat, lng });
};

const hideSearch = () => {
Expand Down
4 changes: 2 additions & 2 deletions packages/client/lib/components/Map.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
ZoomControl,
useMap,
} from 'react-leaflet';
import useFormStore from '../../store/formStore';
import { useFormStoreActions } from '../../store/formStore';
import useMainStore from '../../store/store';

/**
Expand All @@ -19,7 +19,7 @@ import useMainStore from '../../store/store';
*/
const SetViewOnUserLocation = () => {
const geoData = useMainStore((state) => state.geoData);
const setLocation = useFormStore((state) => state.setLocation);
const { setLocation } = useFormStoreActions();
const isMounted = useRef(false);
const map = useMap();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import useFormStore from '../../../../store/formStore';
import { useFormStore, useFormStoreActions } from '../../../../store/formStore';

const categoryOptions = [
'Lost/Missing Pet',
Expand All @@ -12,8 +12,8 @@ const categoryOptions = [

const CategoryView = () => {
const category = useFormStore((state) => state.category);
const setCategory = useFormStore((state) => state.setCategory);
const formErrorState = useFormStore((state) => state.error);
const { setCategory } = useFormStoreActions();

const handleChange = ({ target }) => {
setCategory(target.value);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
import useFormStore from '../../../../store/formStore';
import { latLngToString } from '@/lib/helpers/helpers';
import useMainStore from '@/store/store';
import { useFormStore, useFormStoreActions } from '../../../../store/formStore';
import { SVGIcon } from '../../common/icons/SVGIcon';

const LocationView = () => {
const { setStep } = useFormStoreActions();
const geoData = useMainStore((state) => state.geoData);
const location = useFormStore((state) => state.location);
const setLocation = useFormStore((state) => state.setLocation);
const setStep = useFormStore((state) => state.setStep);

const handleClick = () => {
setStep(5); // this is the step where the map is shown
};

// use the location from the form if it exists, otherwise use the geolocation data
const locationCoordinates = latLngToString(location ?? geoData);

return (
<div className="flex-1">
Expand All @@ -14,22 +23,19 @@ const LocationView = () => {
e.g. {'"'}Example Road, City{'"'} or {'"'}-8.54, 115.24{'"'}
</label>
<input
type="text"
id="location"
className="text-foreground border-border bg-background focus:ring-primary focus:border-primary block w-full rounded-lg border p-2 shadow-md"
disabled
onChange={(e) => setLocation(e.target.value)}
id="location"
name="location"
value={`${location.lat}, ${location.lng}`}
placeholder="Provide a location or coordinates"
className="text-foreground border-border bg-background focus:ring-primary focus:border-primary block w-full rounded-lg border p-2 shadow-md"
type="text"
value={locationCoordinates}
/>
<div className="mt-20 flex justify-center">
<button
onClick={(e) => {
e.preventDefault();
setStep(5);
}}
className="bg-primary text-background flex items-center rounded-xl px-3.5 py-2.5 font-bold"
onClick={handleClick}
type="button"
>
<SVGIcon
name="mapPinIcon"
Expand Down
21 changes: 10 additions & 11 deletions packages/client/lib/components/ReportForm/FormViews/PhotoView.jsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
//@ts-check
import Image from 'next/image';
import { useRef } from 'react';
import useFormStore from '../../../../store/formStore';
import { useFormStore, useFormStoreActions } from '../../../../store/formStore';
import { SVGIcon } from '../../common/icons/SVGIcon';

const PhotoView = () => {
const photos = useFormStore((state) => state.photos);
const setPhotos = useFormStore((state) => state.setPhotos);
const { setPhotos } = useFormStoreActions();
const inputRef = useRef(null);

const handleChange = (e) => {
const { files } = e.target;
// TODO: Add logic here to check for files type and size
if (photos.length > 0) {
if (files.length) {

if (files.length) {
// TODO: Add logic here to check for files type and size
if (photos.length > 0) {
setPhotos([...photos, ...Array.from(files)]);
}
} else {
if (files.length) {
} else {
setPhotos(Array.from(files));
}
}
Expand Down Expand Up @@ -54,10 +54,9 @@ const PhotoView = () => {
</p>
</div>
<button
onClick={(e) => {
e.preventDefault();
}}
// onClick={}
className="bg-primary hover:text-background/70 text-background flex items-center rounded-xl px-3.5 py-2.5 font-bold"
type="button"
>
<SVGIcon
className="text-background pr-1"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { latLngToString } from '@/lib/helpers/helpers';
import Image from 'next/image';
import useFormStore from '../../../../store/formStore';
import { useFormStore } from '../../../../store/formStore';

const SummaryView = () => {
const category = useFormStore((state) => state.category);
Expand All @@ -8,6 +9,8 @@ const SummaryView = () => {
const description = useFormStore((state) => state.description);
const location = useFormStore((state) => state.location);

const latLngString = latLngToString(location);

return (
<div className="flex-1">
<h2 className="mt-4 text-xl">Summary of report</h2>
Expand Down Expand Up @@ -62,7 +65,7 @@ const SummaryView = () => {
<h2 className="mt-4 text-xl">Location</h2>
<input
type="text"
value={`${location.lat}, ${location.lng}`}
value={latLngString}
placeholder="Provide a location or coordinates"
disabled
className="text-foreground border-border bg-background focus:ring-primary focus:border-primary block w-full rounded-lg border p-2 shadow-md"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import useFormStore from '../../../../store/formStore';
import { useFormStore, useFormStoreActions } from '../../../../store/formStore';

const TitleView = () => {
const title = useFormStore((state) => state.title);
const setTitle = useFormStore((state) => state.setTitle);
const description = useFormStore((state) => state.description);
const setDescription = useFormStore((state) => state.setDescription);
const formErrorState = useFormStore((state) => state.error);
const title = useFormStore((state) => state.title);

const { setDescription, setTitle } = useFormStoreActions();

const isTitleValid = () => {
if (!title && formErrorState) {
Expand Down
44 changes: 27 additions & 17 deletions packages/client/lib/components/ReportForm/FormViews/UpdateView.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import useMainStore from '@/store/store';
import { useEffect, useRef } from 'react';
import { MapContainer, Marker, TileLayer, useMap } from 'react-leaflet';
import useFormStore from '../../../../store/formStore';
import { useFormStore, useFormStoreActions } from '../../../../store/formStore';
import LocationSearch from '../../LocationSearch';
import { SVGIcon } from '../../common/icons/SVGIcon';

const SetMarkerLocation = ({ markerRef, setLocation }) => {
Expand All @@ -11,7 +13,8 @@ const SetMarkerLocation = ({ markerRef, setLocation }) => {

if (current) {
current.on('dragend', (e) => {
setLocation(e.target.getLatLng());
const { lat, lng } = e.target.getLatLng();
setLocation({ lat, lng });
});
}

Expand All @@ -25,40 +28,47 @@ const SetMarkerLocation = ({ markerRef, setLocation }) => {
return null;
};

const UpdateMapLocation = ({ location }) => {
const map = useMap();
map.setView(location, map.getZoom());
return null;
};

const UpdateView = () => {
const { setStep, setLocation } = useFormStoreActions();
const geoData = useMainStore((state) => state.geoData);
const location = useFormStore((state) => state.location);
const setLocation = useFormStore((state) => state.setLocation);
const setStep = useFormStore((state) => state.setStep);

// use the location from the form if it exists, otherwise use the geolocation data
const coordinatesLatLng = location ?? geoData;

const markerRef = useRef(null);

const handleConfirm = () => {
setStep(3);
};

return (
<div className="flex justify-center">
<div className="absolute top-10 z-[9999] w-11/12">
<input
type="text"
id="title"
name="title"
placeholder="Search"
className="text-foreground border-border bg-background focus:ring-primary focus:border-primary w-full rounded-lg border p-2 shadow-md"
/>
<LocationSearch setLocationData={setLocation} />
</div>
<MapContainer
center={location}
center={coordinatesLatLng}
zoom={13}
scrollWheelZoom={false}
className="min-h-screen w-full"
>
<TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" />
<SetMarkerLocation markerRef={markerRef} setLocation={setLocation} />;
<Marker position={location} ref={markerRef} draggable />
<Marker draggable position={coordinatesLatLng} ref={markerRef} />
<UpdateMapLocation location={coordinatesLatLng} />
</MapContainer>
<div className="absolute bottom-10 z-[9999]">
<button
onClick={(e) => {
e.preventDefault();
setStep(3);
}}
className="bg-positive hover:bg-positive text-background flex items-center rounded-xl px-3.5 py-2.5 font-bold"
onClick={handleConfirm}
type="button"
>
Confirm
<SVGIcon name="checkIcon" className="text-background pr-1" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import useFormStore from '../../../../store/formStore';
import { useFormStoreActions } from '../../../../store/formStore';
import { SVGIcon } from '../../common/icons/SVGIcon';

//TODO: is this component needed?
const ExitForm = () => {
const setShowForm = useFormStore((state) => state.setShowForm);
const { setShowForm } = useFormStoreActions();

const handleCancel = () => {
setShowForm(false);
};

return (
<button
onClick={(e) => {
e.preventDefault();
setShowForm(false);
}}
className="absolute right-2 top-2 z-[9999] flex"
onClick={handleCancel}
type="button"
>
{/* <XMarkIcon className="h-8 w-8 stroke-2 text-foreground" /> */}
<SVGIcon name="xMarkIcon" className="text-foreground" />
</button>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
import useFormStore from '../../../../store/formStore';
import { useFormStore, useFormStoreActions } from '../../../../store/formStore';
import { Button } from '../../common/Button';
import { SVGIcon } from '../../common/icons/SVGIcon';
import SubmitReportForm from './SubmitReportForm.jsx';

const FormButtons = () => {
const step = useFormStore((state) => state.step);
const setStep = useFormStore((state) => state.setStep);
const setError = useFormStore((state) => state.setError);

const resetForm = useFormStore((state) => state.resetForm);
const setShowForm = useFormStore((state) => state.setShowForm);
const { resetForm, setError, setShowForm, setStep } = useFormStoreActions();

const handleCancel = () => {
resetForm();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import useFormStore from '../../../../store/formStore';
import { useFormStoreActions } from '../../../../store/formStore';
import { useMainStoreActions } from '../../../../store/store';
import { Button } from '../../common/Button';

const SubmitReportForm = () => {
const { setMarkers } = useMainStoreActions();
const getFormData = useFormStore((state) => state.getFormData);
const resetForm = useFormStore((state) => state.resetForm);
const setShowForm = useFormStore((state) => state.setShowForm);
const { getFormData, resetForm, setShowForm } = useFormStoreActions();

const handleSubmit = (e) => {
e.preventDefault();
Expand All @@ -18,9 +16,9 @@ const SubmitReportForm = () => {

return (
<Button
buttonType="positive"
handleClick={handleSubmit}
iconName="checkIcon"
buttonType="positive"
type="submit"
>
Submit
Expand Down
2 changes: 1 addition & 1 deletion packages/client/lib/components/ReportForm/ReportForm.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import dynamic from 'next/dynamic';
import useFormStore from '../../../store/formStore';
import { useFormStore } from '../../../store/formStore';
import CategoryView from './FormViews/CategoryView';
import LocationView from './FormViews/LocationView';
import PhotoView from './FormViews/PhotoView';
Expand Down
Loading

0 comments on commit 0d445fe

Please sign in to comment.