Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rg/32 report incident form #35

Merged
merged 61 commits into from
May 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
888e76a
Initial commit
ranegray Mar 28, 2023
07bffbe
Setup beginning folder structure
ranegray Mar 28, 2023
3da895a
Integrated components into ReportForm for multi-step form
ranegray Mar 29, 2023
fd46302
Commented out Map and Nav in index, built ReportForm with conditional…
ranegray Mar 29, 2023
dd4e44c
Photo upload component design complete, needs slight tweaking
ranegray Mar 29, 2023
8f13e81
Finished first draft of SummaryView
ranegray Mar 29, 2023
2ec6384
Added file types and ability to use camera on mobile device in PhotoView
ranegray Mar 30, 2023
4888ed9
Added multiple file input and name attributes on SummaryView inputs
ranegray Mar 30, 2023
c84ab3f
Added jpeg file format
ranegray Mar 30, 2023
6ba7bc4
Added image thumbnails after selecting files
ranegray Mar 30, 2023
d2503bc
Tidied PhotoView component
ranegray Mar 30, 2023
4de533a
Styled thumbnails and began delete thumbnail functionality
ranegray Mar 30, 2023
beb656e
Added delete function to thumbnail photos
ranegray Mar 30, 2023
3b772aa
Removed stray useEffect in Report Form
ranegray Mar 30, 2023
0798ba0
Renamed initial state keys and form attributes
ranegray Mar 30, 2023
5b13ea0
Added useRef in photos for button embedded in label to activate file …
ranegray Mar 30, 2023
fd1cc35
Initialize zustand form store and refactored photo view to use zustan…
ranegray Mar 31, 2023
5cf2a97
Removed props from PhotoView prop in ReportForm
ranegray Mar 31, 2023
02cdb2c
Squashed bug for double triggering file input in PhotoView
ranegray Mar 31, 2023
e32eb4a
Refactored zustand actions and added global state and handlers to Sum…
ranegray Mar 31, 2023
2c087eb
Rough styling and state management for LocationView
ranegray Mar 31, 2023
89b3324
Added functionality to center Nav button and ability to go from map t…
ranegray Mar 31, 2023
be8b998
Added button to exit form at any step
ranegray Mar 31, 2023
c840848
Added watchLocation to geolocation and set location state to user loc…
ranegray Mar 31, 2023
c911e70
Refactored formStore, imports, and form navigation and added update l…
ranegray Mar 31, 2023
cd79ab8
Added functionality to update location on UpdateView
ranegray Apr 1, 2023
cdaed31
Added submit functionality, marker global store, and dynamic import o…
ranegray Apr 1, 2023
17475c7
Refactoring form to include incident page, big mess right now
ranegray Apr 6, 2023
ab89a3c
Added radio buttons to CategoryView
ranegray Apr 6, 2023
efb09a3
Updated formStore to reflect CategoryView form page
ranegray Apr 6, 2023
83e9766
Added onChange and checked statuses to radio buttons to persist throu…
ranegray Apr 6, 2023
eaad731
Styled Cancel button, renamed to match rest of buttons
ranegray Apr 6, 2023
0561217
Added Cancel functionality to Cancel button
ranegray Apr 6, 2023
1c97331
Styled buttons, added SummaryView, renamed TitleView
ranegray Apr 6, 2023
8e44e8a
Added SUmmaryView to flow of form, styled submit button
ranegray Apr 6, 2023
3fa02e3
Rough functionality of form addded
ranegray Apr 6, 2023
dbadfca
Added check at each step of form for required input
ranegray Apr 13, 2023
36e3bbb
Styled CategoryView and added PII warning text to each view
ranegray Apr 18, 2023
645f7ba
Styled FormButtons
ranegray Apr 18, 2023
66a1db7
Made form view styling uniform and tweaked to match Figma
ranegray Apr 18, 2023
aaa3d8f
Form validation in place for CategoryView
ranegray Apr 18, 2023
f5394ad
refactored useFormStore syntax and added ability to add photos one at…
ranegray Apr 30, 2023
bcf9b02
fixed bug when opening form before map was centered on user location
ranegray Apr 30, 2023
3db41f5
fixed showFormStore
ranegray May 5, 2023
a5e23af
starting on fixing bottomnav center button
ranegray May 15, 2023
9bcab41
consolidated map mounting useEffect and added comments
ranegray May 26, 2023
22bc75b
added back attribution to OpenStreetMaps
ranegray May 26, 2023
0dc0de1
added id keys to marker mapping and gave each marker unique id
ranegray May 26, 2023
57188e9
updated background and foreground to use utility classes and removed …
ranegray May 26, 2023
ad361a8
fixed faulty logic in setGeoData store
ranegray May 26, 2023
ef7a0b8
removed code from global.css
ranegray May 26, 2023
233ed0c
sorted formStore state A-Z
ranegray May 26, 2023
6f9ccbb
sorted formStore state A-Z
ranegray May 26, 2023
ba31c9e
removed state destructuring from index.tsx
ranegray May 26, 2023
c48968d
refactored show form conditional rendering
ranegray May 26, 2023
e6ac2e7
changed form imports to be relative
ranegray May 26, 2023
409dfa9
updated comment
ranegray May 26, 2023
bd8a45c
removed unnecessary logic
ranegray May 26, 2023
39f6f04
refactor ReportForm for readablitity and reusablity
ranegray May 26, 2023
7910afc
refactored BottomNav and centered middle button
ranegray May 26, 2023
8601c66
update package-lock.json
toreylittlefield May 27, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,545 changes: 991 additions & 554 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion packages/client/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
/coverage

# next.js
../.next/
./next


/out/

# production
Expand Down
56 changes: 0 additions & 56 deletions packages/client/lib/components/BottomNav.jsx

This file was deleted.

81 changes: 81 additions & 0 deletions packages/client/lib/components/BottomNav/BottomNav.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { useState } from 'react';
import BottomNavItem from './BottomNavItem.jsx';
import {
HomeIcon,
MagnifyingGlassIcon,
UserIcon,
PlusCircleIcon,
MapPinIcon,
} from '@heroicons/react/24/outline';
import useFormStore from '../../../store/formStore.js';

const BOTTOM_NAV_ITEMS = [
{
name: 'Home',
icon: <HomeIcon className="h-6 w-6 pointer-events-none" />,
},
{
name: 'Search',
icon: <MagnifyingGlassIcon className="h-6 w-6 pointer-events-none" />,
},
{
name: 'Layers',
icon: <MapPinIcon className="h-6 w-6 pointer-events-none" />,
},
{
name: 'Profile',
icon: <UserIcon className="h-6 w-6 pointer-events-none" />,
},
];

const LEFT_NAV_ITEMS = BOTTOM_NAV_ITEMS.slice(0, 2);
const RIGHT_NAV_ITEMS = BOTTOM_NAV_ITEMS.slice(2, 4);

const BottomNav = () => {
ranegray marked this conversation as resolved.
Show resolved Hide resolved
const [active, setActive] = useState(0);
const setShowForm = useFormStore((state) => state.setShowForm);

const handleActive = (name) => {
setActive(name);
};

const isActive = (name) => {
return active === name ? true : false;
};

return (
<div className="absolute bottom-0 z-[9999] w-full h-16 text-foreground/30 rounded-t-2xl p-1 grid grid-cols-5 justify-items-center items-center bg-white">
{LEFT_NAV_ITEMS.map((item) => (
<BottomNavItem
key={item.name}
setActive={() => handleActive(item.name)}
selected={isActive(item.name)}
name={item.name}
>
{item.icon}
</BottomNavItem>
))}
<div onClick={() => setShowForm(true)} className="relative">
<div className="absolute left-0 bottom-0 translate-y-1/3 -translate-x-1/2 rounded-full h-24 w-24 flex items-center justify-center bg-background">
<div className="rounded-full h-20 w-20 flex items-center justify-center bg-primary ">
<button className="rounded-full h-16 w-16 flex items-center justify-center bg-backgroundAlt">
<PlusCircleIcon className="h-6 w-6 text-primary" />
</button>
</div>
</div>
</div>
{RIGHT_NAV_ITEMS.map((item) => (
<BottomNavItem
key={item.name}
setActive={() => handleActive(item.name)}
selected={isActive(item.name)}
name={item.name}
>
{item.icon}
</BottomNavItem>
))}
</div>
);
};

export default BottomNav;
52 changes: 43 additions & 9 deletions packages/client/lib/components/Map.jsx
Original file line number Diff line number Diff line change
@@ -1,52 +1,86 @@
import { useEffect } from 'react';
import { useEffect, useRef } from 'react';
import useStore from '../../store/store';
import 'leaflet/dist/leaflet.css';
import { MapContainer, TileLayer, Marker, ZoomControl,useMap } from 'react-leaflet';
import {
MapContainer,
TileLayer,
Marker,
ZoomControl,
useMap,
} from 'react-leaflet';
import Leaflet from 'leaflet';
import useFormStore from '@/store/formStore';

const SetViewOnUserLocation = () => {
const setLocation = useFormStore((state) => state.setLocation);
const isMounted = useRef(false);
const map = useMap();

useEffect(() => {
(async function init() {
// TODO: delete override required on prototype required or not?
// delete Leaflet.Icon.Default.prototype._getIconUrl;

// Sets default icon path for leaflet icons/markers
Leaflet.Icon.Default.mergeOptions({
iconRetinaUrl: 'leaflet/images/marker-icon-2x.png',
iconUrl: 'leaflet/images/marker-icon.png',
shadowUrl: 'leaflet/images/marker-shadow.png',
});
})();

// Checks if map is currently mounted (prevents position error when form is opened)
isMounted.current = true;

return () => {
isMounted.current = false;
};
ranegray marked this conversation as resolved.
Show resolved Hide resolved
}, []);

useEffect(() => {
navigator.geolocation.getCurrentPosition(
(position) => {
map.setView(
{ lat: position.coords.latitude, lng: position.coords.longitude },
12
);
if (!map) return;
ranegray marked this conversation as resolved.
Show resolved Hide resolved

if (isMounted.current) {
ranegray marked this conversation as resolved.
Show resolved Hide resolved
map.setView(
{ lat: position.coords.latitude, lng: position.coords.longitude },
12
);
setLocation({
lat: position.coords.latitude,
lng: position.coords.longitude,
});
}
},
(error) => {
console.error(error);
},
{ enableHighAccuracy: true, timeout: 10000, maximumAge: Infinity }
);
}, [map]);
}, [map, setLocation]);

return null;
};

const Map = () => {
const geoData = useStore((state) => state.geoData);
const markers = useStore((state) => state.markers);

return (
<MapContainer center={geoData} zoom={12} zoomControl={false} className="min-h-screen w-full">
<MapContainer
center={geoData}
zoom={12}
zoomControl={false}
className="min-h-screen w-full"
>
<SetViewOnUserLocation />
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe in the future, we can move this out to it's own component

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like create a new file for it? Instead of colocating it with Map?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah I guess so but we can refactor later thanks!

<TileLayer
attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
ranegray marked this conversation as resolved.
Show resolved Hide resolved
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<Marker position={geoData} draggable />
{markers.length > 0 &&
markers.map((marker) => <Marker key={marker.id} position={marker.location} />)}
<ZoomControl position="topright" />
</MapContainer>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import useFormStore from '../../../../store/formStore';

const categoryOptions = [
'Lost/Missing Pet',
'Found Pet',
'Needs Medical Treatment',
'Gave/Received Medical Treatment',
'Gave Food',
'Poisoning',
'Other',
];

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

const handleChange = ({ target }) => {
setCategory(target.value);
};

const isFormValid = () => {
if(!category && formErrorState) {
return false;
}
return true;
};

return (
<div className="flex-1">
<h2 className="text-xl mt-4">Category of incident</h2>
<h3 className="text-lg">Please choose one category</h3>
{categoryOptions.map((option) => (
<div className="flex items-center" key={option}>
<input
onChange={handleChange}
checked={category === option}
type="radio"
name="category"
className="w-4 h-4"
id={option}
value={option}
required
/>
<label htmlFor={option} className="p-1">
{option}
</label>
</div>
))}
<p className={`text-xs text-negative ${isFormValid() ?'invisible' : 'visible'}`}>
Please provide a category
</p>
</div>
);
};

export default CategoryView;
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import useFormStore from '../../../../store/formStore';
import { MapPinIcon } from '@heroicons/react/24/outline';

const LocationView = () => {
const location = useFormStore((state) => state.location);
const setLocation = useFormStore((state) => state.setLocation);
const setStep = useFormStore((state) => state.setStep);

return (
<div className="flex-1">
<h2 className="text-xl mt-4">Pin map location</h2>
<div>
<label htmlFor="location" className="block mb-2 text-foreground">
e.g. "Example Road, City" or "-8.54, 115.24"
</label>
<input
type="text"
id="location"
disabled
onChange={(e) => setLocation(e.target.value)}
name="location"
value={`${location.lat}, ${location.lng}`}
placeholder="Provide a location or coordinates"
className="block w-full p-2 text-foreground border border-gray-300 rounded-lg bg-background focus:ring-primary focus:border-primary shadow-md"
/>
<div className="flex justify-center mt-20">
<button
onClick={(e) => {
e.preventDefault();
setStep(5);
}}
className="flex items-center bg-primary text-background font-bold py-2.5 px-3.5 rounded-xl"
>
<MapPinIcon className="w-7 h-7 pr-1 text-background" />
Update Location
</button>
</div>
</div>
</div>
);
};

export default LocationView;
Loading