From e4d9d50d2d999cf668a5c960d8108f0389cd8e53 Mon Sep 17 00:00:00 2001 From: kim Date: Mon, 15 Apr 2024 11:04:07 +0200 Subject: [PATCH 1/4] feat: change icons, add item handler --- package.json | 2 +- src/components/Map.stories.tsx | 60 +++++++++++++++++++ src/components/Map.tsx | 6 +- src/components/context/QueryClientContext.tsx | 19 +++++- .../icons/currentLocationMarker.svg | 17 ++++++ src/components/icons/icons.ts | 47 ++++++--------- src/components/icons/marker.svg | 17 ++++++ src/components/icons/pointer.svg | 17 ++++++ src/components/map/AddItemButton.tsx | 49 ++++----------- src/components/map/CurrentLocationMarker.tsx | 38 ++++-------- src/components/map/CurrentMarker.tsx | 4 +- src/components/map/InitialSetup.tsx | 21 +++++-- src/components/map/ItemsMarkers.tsx | 15 +---- src/components/map/MapContent.tsx | 6 +- src/components/map/MapEvents.tsx | 9 --- src/components/map/MarkerPopup.tsx | 16 +++-- src/langs/en.json | 3 +- src/location.svg | 20 ------- yarn.lock | 16 ++++- 19 files changed, 225 insertions(+), 157 deletions(-) create mode 100644 src/components/icons/currentLocationMarker.svg create mode 100644 src/components/icons/marker.svg create mode 100644 src/components/icons/pointer.svg delete mode 100644 src/location.svg diff --git a/package.json b/package.json index 4ce7e52..f94f501 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "dependencies": { "@emotion/react": "11.11.4", "@emotion/styled": "11.11.5", - "@graasp/sdk": "github:graasp/graasp-sdk#packed", + "@graasp/sdk": "4.7.1", "@graasp/translations": "1.23.0", "@graasp/ui": "4.9.3", "@mui/icons-material": "5.15.15", diff --git a/src/components/Map.stories.tsx b/src/components/Map.stories.tsx index f63ac56..7af600a 100644 --- a/src/components/Map.stories.tsx +++ b/src/components/Map.stories.tsx @@ -124,3 +124,63 @@ export const MapSignOutMobile = { ], // cannot play inside an iframe } satisfies Story; + +export const MapWithCurrentLocation = { + args: { + viewItem: () => ({}) as any, + currentMember: null, + currentPosition: { lat: 46.51, lng: 6.5 }, + useDeleteItemGeolocation: () => ({}) as any, + useItemsInMap: () => ({ data: [] }) as any, + useAddressFromGeolocation: () => ({ data: 'address' }) as any, + usePostItem: () => ({}) as any, + useRecycleItems: () => ({}) as any, + useSuggestionsForAddress: MOCK_USE_SUGGESTIONS as any, + }, + decorators: [ + (Story) => ( +
+ +
+ ), + ], + // cannot play inside an iframe +} satisfies Story; + +export const MapWithCurrentLocationAndItems = { + args: { + viewItem: () => ({}) as any, + currentMember: null, + currentPosition: { lat: 46.51, lng: 6.499 }, + useDeleteItemGeolocation: () => ({}) as any, + useItemsInMap: () => + ({ + data: [ + { + lat: 46.51, + lng: 6.5, + addressLabel: 'EPFL', + item, + }, + { + lat: 46.51, + lng: 6.4995, + addressLabel: 'EPFL', + item, + }, + ], + }) as any, + useAddressFromGeolocation: () => ({ data: 'address' }) as any, + usePostItem: () => ({}) as any, + useRecycleItems: () => ({}) as any, + useSuggestionsForAddress: MOCK_USE_SUGGESTIONS as any, + }, + decorators: [ + (Story) => ( +
+ +
+ ), + ], + // cannot play inside an iframe +} satisfies Story; diff --git a/src/components/Map.tsx b/src/components/Map.tsx index bd34152..87641f3 100644 --- a/src/components/Map.tsx +++ b/src/components/Map.tsx @@ -29,6 +29,8 @@ const Map = ({ usePostItem, viewItem, useDeleteItemGeolocation, + currentPosition, + handleAddOnClick, }: Props): JSX.Element => { const [showMap, setShowMap] = useState(false); @@ -43,11 +45,13 @@ const Map = ({ itemId={itemId} useSuggestionsForAddress={useSuggestionsForAddress} currentMember={currentMember} + currentPosition={currentPosition} useAddressFromGeolocation={useAddressFromGeolocation} useItemsInMap={useItemsInMap} useRecycleItems={useRecycleItems} usePostItem={usePostItem} viewItem={viewItem} + handleAddOnClick={handleAddOnClick} useDeleteItemGeolocation={useDeleteItemGeolocation} >
- {!showMap ? ( + {!showMap && !currentPosition ? ( ) : ( diff --git a/src/components/context/QueryClientContext.tsx b/src/components/context/QueryClientContext.tsx index 4bea3df..7816ee0 100644 --- a/src/components/context/QueryClientContext.tsx +++ b/src/components/context/QueryClientContext.tsx @@ -1,7 +1,11 @@ import { createContext, useContext, useMemo } from 'react'; import type { configureQueryClient } from '@graasp/query-client'; -import { CompleteMember, DiscriminatedItem } from '@graasp/sdk'; +import { + CompleteMember, + DiscriminatedItem, + ItemGeolocation, +} from '@graasp/sdk'; type QueryClientHooks = ReturnType['hooks']; type QueryClientMutations = ReturnType< @@ -11,6 +15,7 @@ type QueryClientMutations = ReturnType< export interface QueryClientContextInterface { itemId?: DiscriminatedItem['id']; currentMember?: CompleteMember | null; + currentPosition?: { lat: number; lng: number }; useAddressFromGeolocation: QueryClientHooks['useAddressFromGeolocation']; useItemsInMap: QueryClientHooks['useItemsInMap']; useRecycleItems: QueryClientMutations['useRecycleItems']; @@ -18,6 +23,12 @@ export interface QueryClientContextInterface { useDeleteItemGeolocation: QueryClientMutations['useDeleteItemGeolocation']; useSuggestionsForAddress: QueryClientHooks['useSuggestionsForAddress']; viewItem: (item: DiscriminatedItem) => void; + handleAddOnClick?: ({ + location, + }: { + location: Pick & + Partial>; + }) => void; } export const QueryClientContext = createContext({ @@ -45,6 +56,8 @@ export const QueryClientContextProvider = ({ useSuggestionsForAddress, viewItem, itemId, + currentPosition, + handleAddOnClick, }: QueryClientContextInterface & { children: JSX.Element }): JSX.Element => { const value = useMemo( () => ({ @@ -57,6 +70,8 @@ export const QueryClientContextProvider = ({ viewItem, itemId, useSuggestionsForAddress, + currentPosition, + handleAddOnClick, }), [ currentMember, @@ -68,6 +83,8 @@ export const QueryClientContextProvider = ({ useSuggestionsForAddress, viewItem, itemId, + currentPosition, + handleAddOnClick, ], ); diff --git a/src/components/icons/currentLocationMarker.svg b/src/components/icons/currentLocationMarker.svg new file mode 100644 index 0000000..3ffa983 --- /dev/null +++ b/src/components/icons/currentLocationMarker.svg @@ -0,0 +1,17 @@ + + + + + image/svg+xml + + + + + + + + + + + + \ No newline at end of file diff --git a/src/components/icons/icons.ts b/src/components/icons/icons.ts index d846984..3963baa 100644 --- a/src/components/icons/icons.ts +++ b/src/components/icons/icons.ts @@ -1,40 +1,31 @@ import L from 'leaflet'; import 'leaflet-easybutton'; -import markerPinPerson from '../../location.svg'; -import { MarkerParent } from '../../types'; +import currentMarker from './currentLocationMarker.svg'; +import markerIcon from './marker.svg'; +import pointerIcon from './pointer.svg'; -const iconPerson = new L.Icon({ - iconUrl: markerPinPerson, - iconSize: new L.Point(30, 30), - className: 'leaflet-div-icon', +const currentLocationMarker = new L.Icon({ + iconUrl: currentMarker, + iconSize: [30, 30], + iconAnchor: [15, 30], + popupAnchor: [0, -30], }); -export const greenIcon = new L.Icon({ - iconUrl: - 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-green.png', - shadowUrl: - 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/images/marker-shadow.png', - iconSize: [25, 41], - iconAnchor: [12, 41], - popupAnchor: [1, -34], +const marker = new L.Icon({ + iconUrl: markerIcon, + iconSize: [30, 30], + iconAnchor: [15, 30], + popupAnchor: [0, -30], shadowSize: [41, 41], }); -const redIcon = new L.Icon({ - iconUrl: - 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-2x-red.png', - shadowUrl: - 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/images/marker-shadow.png', - iconSize: [25, 41], - iconAnchor: [12, 41], - popupAnchor: [1, -34], +const pointer = new L.Icon({ + iconUrl: pointerIcon, + iconSize: [30, 30], + iconAnchor: [15, 30], + popupAnchor: [0, -30], shadowSize: [41, 41], }); -const iconsPerParent: { [key in MarkerParent]: L.Icon } = { - MyItems: redIcon, - Published: greenIcon, -}; - -export { iconPerson, iconsPerParent }; +export { currentLocationMarker, marker, pointer }; diff --git a/src/components/icons/marker.svg b/src/components/icons/marker.svg new file mode 100644 index 0000000..6878956 --- /dev/null +++ b/src/components/icons/marker.svg @@ -0,0 +1,17 @@ + + + + + image/svg+xml + + + + + + + + + + + + \ No newline at end of file diff --git a/src/components/icons/pointer.svg b/src/components/icons/pointer.svg new file mode 100644 index 0000000..d00610e --- /dev/null +++ b/src/components/icons/pointer.svg @@ -0,0 +1,17 @@ + + + + + image/svg+xml + + + + + + + + + + + + \ No newline at end of file diff --git a/src/components/map/AddItemButton.tsx b/src/components/map/AddItemButton.tsx index 54fda22..6bf4972 100644 --- a/src/components/map/AddItemButton.tsx +++ b/src/components/map/AddItemButton.tsx @@ -1,19 +1,7 @@ -import React, { useState } from 'react'; - import AddLocationAltIcon from '@mui/icons-material/AddLocationAlt'; -import { - Button, - CssBaseline, - Dialog, - DialogActions, - DialogContent, - DialogTitle, - IconButton, - TextField, - Tooltip, -} from '@mui/material'; +import { CssBaseline, IconButton, Tooltip } from '@mui/material'; -import { ItemGeolocation, ItemType } from '@graasp/sdk'; +import { ItemGeolocation } from '@graasp/sdk'; import { useQueryClientContext } from '../context/QueryClientContext'; @@ -21,36 +9,25 @@ type Props = { location: Pick & Partial>; }; -const AddItemButton = ({ location }: Props): JSX.Element => { - const { usePostItem, itemId: parentId } = useQueryClientContext(); - const { mutate: postItem } = usePostItem(); - const [open, setOpen] = useState(false); +const AddItemButton = ({ location }: Props): JSX.Element | null => { + const { handleAddOnClick } = useQueryClientContext(); - const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - const formData = new FormData(e.currentTarget); - const { name, description }: any = Object.fromEntries(formData); - if (location && name) { - await postItem({ - parentId, - name, - description, - type: ItemType.FOLDER, - geolocation: location, - }); - } - setOpen(false); - }; + // no handler does not show the add button + if (!handleAddOnClick) { + // eslint-disable-next-line no-console + console.debug('no add handler is defined'); + return null; + } return ( <> - setOpen(true)}> + handleAddOnClick({ location })}> - + {/* Add New Folder at Location
@@ -82,7 +59,7 @@ const AddItemButton = ({ location }: Props): JSX.Element => { -
+
*/} ); }; diff --git a/src/components/map/CurrentLocationMarker.tsx b/src/components/map/CurrentLocationMarker.tsx index 7328f1f..5a4adb8 100644 --- a/src/components/map/CurrentLocationMarker.tsx +++ b/src/components/map/CurrentLocationMarker.tsx @@ -1,40 +1,22 @@ -import { useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { Marker, Popup } from 'react-leaflet'; -import { iconPerson } from '../icons/icons'; +import { currentLocationMarker } from '../icons/icons'; -const CurrentLocationMarker = (): JSX.Element | null => { - const [position, setPosition] = useState<[number, number] | null>(null); - - const options = { - enableHighAccuracy: true, - timeout: 5000, - maximumAge: 0, - }; - - const success = (pos: { - coords: { latitude: number; longitude: number }; - }) => { - const crd = pos.coords; - setPosition([crd.latitude, crd.longitude]); - }; - - navigator.geolocation.getCurrentPosition( - success, - (err: { code: number; message: string }) => { - // eslint-disable-next-line no-console - console.warn(`ERROR(${err.code}): ${err.message}`); - }, - options, - ); +const CurrentLocationMarker = ({ + position, +}: { + position?: { lat: number; lng: number }; +}): JSX.Element | null => { + const { t } = useTranslation(); if (!position) { return null; } return ( - - Current location + + {t('Current location')} ); }; diff --git a/src/components/map/CurrentMarker.tsx b/src/components/map/CurrentMarker.tsx index 8c46d21..c804793 100644 --- a/src/components/map/CurrentMarker.tsx +++ b/src/components/map/CurrentMarker.tsx @@ -6,7 +6,7 @@ import { ItemGeolocation } from '@graasp/sdk'; import { LatLng } from 'leaflet'; import { useQueryClientContext } from '../context/QueryClientContext'; -import { greenIcon } from '../icons/icons'; +import { pointer } from '../icons/icons'; import CurrentMarkerPopupContent from './CurrentMarkerPopupContent'; const CurrentMarker = (): JSX.Element | null => { @@ -31,7 +31,7 @@ const CurrentMarker = (): JSX.Element | null => { return ( { setOpen(false); diff --git a/src/components/map/InitialSetup.tsx b/src/components/map/InitialSetup.tsx index fb81664..56e1125 100644 --- a/src/components/map/InitialSetup.tsx +++ b/src/components/map/InitialSetup.tsx @@ -10,7 +10,7 @@ const InitialSetup = ({ showMap: boolean; setShowMap: Dispatch; }): null => { - const { useItemsInMap, itemId } = useQueryClientContext(); + const { useItemsInMap, itemId, currentPosition } = useQueryClientContext(); const [isInitial, setIsInitial] = useState(true); const map = useMap(); @@ -23,11 +23,20 @@ const InitialSetup = ({ if (showMap || !isInitial) { return; } - - if (itemGeolocations && isInitial) { - const c = itemGeolocations.map((g) => [g.lat, g.lng]); - if (c.length) { - map.fitBounds(c as any); + if (isInitial) { + // center on all visible points + if (itemGeolocations?.length) { + const c = itemGeolocations.map((g) => [g.lat, g.lng]); + if (c.length) { + map.fitBounds(c as any); + } + setShowMap(true); + setIsInitial(false); + } + // center on current position of user + else if (currentPosition) { + map.setZoom(11); + map.flyTo([currentPosition.lat, currentPosition.lng] as any); setShowMap(true); setIsInitial(false); } diff --git a/src/components/map/ItemsMarkers.tsx b/src/components/map/ItemsMarkers.tsx index bd98fad..c165f47 100644 --- a/src/components/map/ItemsMarkers.tsx +++ b/src/components/map/ItemsMarkers.tsx @@ -4,7 +4,7 @@ import { FeatureGroup, Marker } from 'react-leaflet'; import { DiscriminatedItem } from '@graasp/sdk'; import { useQueryClientContext } from '../context/QueryClientContext'; -import { iconsPerParent } from '../icons/icons'; +import { marker } from '../icons/icons'; import MarkerPopup from './MarkerPopup'; const ItemsMarkers = ({ @@ -28,23 +28,12 @@ const ItemsMarkers = ({ keywords: tags, }); - // initial view - // useEffect(() => { - // if (itemId && itemGeolocations && groupRef) { - // const group = groupRef.current; // get native featureGroup instance - // if (group && group.getBounds().getNorthEast()) { - // map.fitBounds(group.getBounds()); - // } - // } - // // eslint-disable-next-line react-hooks/exhaustive-deps - // }, [itemGeolocations]); - return ( {itemGeolocations?.map((geoloc) => ( diff --git a/src/components/map/MapContent.tsx b/src/components/map/MapContent.tsx index bc10466..8fb98ba 100644 --- a/src/components/map/MapContent.tsx +++ b/src/components/map/MapContent.tsx @@ -8,7 +8,7 @@ import ItemsMarkers from './ItemsMarkers'; import MapEvents from './MapEvents'; const MapContent = (): JSX.Element => { - const { itemId } = useQueryClientContext(); + const { itemId, currentPosition } = useQueryClientContext(); const [bounds, setBounds] = useState<{ lat1: number; lat2: number; @@ -24,11 +24,9 @@ const MapContent = (): JSX.Element => { return ( <> - - - + ); diff --git a/src/components/map/MapEvents.tsx b/src/components/map/MapEvents.tsx index 03f6091..5396521 100644 --- a/src/components/map/MapEvents.tsx +++ b/src/components/map/MapEvents.tsx @@ -21,7 +21,6 @@ const MapEvents = ({ lng1: b.getSouthWest().lng, lng2: b.getNorthEast().lng, }); - // map.flyTo() }; useEffect(() => { @@ -42,14 +41,6 @@ const MapEvents = ({ }, }); - // const b = map.getBounds(); - // const bounds = { - // lat1: b.getSouthWest().lat, - // lat2: b.getNorthEast().lat, - // lng1: b.getSouthWest().lng, - // lng2: b.getNorthEast().lng, - // }; - return null; }; diff --git a/src/components/map/MarkerPopup.tsx b/src/components/map/MarkerPopup.tsx index 3721e2a..b66c976 100644 --- a/src/components/map/MarkerPopup.tsx +++ b/src/components/map/MarkerPopup.tsx @@ -42,12 +42,16 @@ const MarkerPopup = ({ - {PermissionLevelCompare.gte(item.permission, PermissionLevel.Admin) && ( - <> - - - - )} + {item?.permission && + PermissionLevelCompare.gte( + item.permission, + PermissionLevel.Admin, + ) && ( + <> + + + + )} ); diff --git a/src/langs/en.json b/src/langs/en.json index f51c2a4..86afdca 100644 --- a/src/langs/en.json +++ b/src/langs/en.json @@ -11,5 +11,6 @@ "Enter keywords here": "Enter keywords here", "filters": "filters", "Keywords": "Keywords", - "Filters": "Filters" + "Filters": "Filters", + "Current Location": "Current Location" } diff --git a/src/location.svg b/src/location.svg deleted file mode 100644 index b0204f3..0000000 --- a/src/location.svg +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 6786645..18eacfe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2374,7 +2374,7 @@ __metadata: "@emotion/react": "npm:11.11.4" "@emotion/styled": "npm:11.11.5" "@graasp/query-client": "npm:2.9.1" - "@graasp/sdk": "github:graasp/graasp-sdk#packed" + "@graasp/sdk": "npm:4.7.1" "@graasp/translations": "npm:1.23.0" "@graasp/ui": "npm:4.9.3" "@mui/icons-material": "npm:5.15.15" @@ -2503,6 +2503,20 @@ __metadata: languageName: node linkType: hard +"@graasp/sdk@npm:4.7.1": + version: 4.7.1 + resolution: "@graasp/sdk@npm:4.7.1" + dependencies: + "@faker-js/faker": "npm:8.4.1" + js-cookie: "npm:3.0.5" + validator: "npm:13.11.0" + peerDependencies: + date-fns: ^3 + uuid: ^9 + checksum: 10/182e2a33fbdf7ed2cac7fbdf5a01378a059415a753345cca501d2ddda4985b9448c81bb2931a7157dc34cd613412c5da42da38cb037e9a46438755707e4ea2aa + languageName: node + linkType: hard + "@graasp/translations@npm:1.23.0": version: 1.23.0 resolution: "@graasp/translations@npm:1.23.0" From 66355e215e8bd47e4671933d3f26d72bbcfbc163 Mon Sep 17 00:00:00 2001 From: kim Date: Mon, 15 Apr 2024 11:26:28 +0200 Subject: [PATCH 2/4] refactor: allow fallback add dialog --- src/components/Map.stories.tsx | 7 +- src/components/map/AddItemButton.tsx | 125 ++++++++++++++++++--------- src/langs/en.json | 5 +- 3 files changed, 92 insertions(+), 45 deletions(-) diff --git a/src/components/Map.stories.tsx b/src/components/Map.stories.tsx index 7af600a..48ba950 100644 --- a/src/components/Map.stories.tsx +++ b/src/components/Map.stories.tsx @@ -32,10 +32,15 @@ export const Map = { }, ], }) as any, - useAddressFromGeolocation: () => ({ data: 'address' }) as any, + useAddressFromGeolocation: () => + ({ data: { addressLabel: 'address', country: 'countryName' } }) as any, usePostItem: () => ({}) as any, useRecycleItems: () => ({}) as any, useSuggestionsForAddress: MOCK_USE_SUGGESTIONS as any, + handleAddOnClick({ location }) { + // eslint-disable-next-line no-alert + alert(JSON.stringify(location)); + }, }, decorators: [ (Story) => ( diff --git a/src/components/map/AddItemButton.tsx b/src/components/map/AddItemButton.tsx index 6bf4972..91d6220 100644 --- a/src/components/map/AddItemButton.tsx +++ b/src/components/map/AddItemButton.tsx @@ -1,7 +1,20 @@ +import { FormEvent, useState } from 'react'; +import { useTranslation } from 'react-i18next'; + import AddLocationAltIcon from '@mui/icons-material/AddLocationAlt'; -import { CssBaseline, IconButton, Tooltip } from '@mui/material'; +import { + Button, + CssBaseline, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + IconButton, + TextField, + Tooltip, +} from '@mui/material'; -import { ItemGeolocation } from '@graasp/sdk'; +import { ItemGeolocation, ItemType } from '@graasp/sdk'; import { useQueryClientContext } from '../context/QueryClientContext'; @@ -10,56 +23,82 @@ type Props = { Partial>; }; const AddItemButton = ({ location }: Props): JSX.Element | null => { - const { handleAddOnClick } = useQueryClientContext(); + const { + handleAddOnClick, + usePostItem, + itemId: parentId, + } = useQueryClientContext(); + const { mutate: postItem } = usePostItem(); + const { t } = useTranslation(); + const [open, setOpen] = useState(false); - // no handler does not show the add button - if (!handleAddOnClick) { - // eslint-disable-next-line no-console - console.debug('no add handler is defined'); - return null; - } + const handleSubmit = async (e: FormEvent) => { + e.preventDefault(); + const formData = new FormData(e.currentTarget); + const { name, description }: any = Object.fromEntries(formData); + if (location && name) { + await postItem({ + parentId, + name, + description, + type: ItemType.FOLDER, + geolocation: location, + }); + } + setOpen(false); + }; + const handleAddItem = () => { + if (handleAddOnClick) { + handleAddOnClick({ location }); + } else { + setOpen(true); + } + }; return ( <> - - handleAddOnClick({ location })}> + + - {/* - Add New Folder at Location -
- - - + {/* fallback form to add an item */} + {!handleAddOnClick && ( + + {t('Add a new folder at this location')} + + + + -

{location.addressLabel}

-
- - - - - -
*/} +

{location.addressLabel}

+
+ + + + + +
+ )} ); }; diff --git a/src/langs/en.json b/src/langs/en.json index 86afdca..302505a 100644 --- a/src/langs/en.json +++ b/src/langs/en.json @@ -12,5 +12,8 @@ "filters": "filters", "Keywords": "Keywords", "Filters": "Filters", - "Current Location": "Current Location" + "Current Location": "Current Location", + "Description (optional)": "Description (optional)", + "Name": "Name", + "Add a new folder at this location": "Add a new folder at this location" } From 39f471a1bd089b68906a6524c92faa437b11bfa1 Mon Sep 17 00:00:00 2001 From: kim Date: Mon, 15 Apr 2024 11:38:28 +0200 Subject: [PATCH 3/4] refactor: change current location text --- src/components/map/CurrentLocationMarker.tsx | 2 +- src/components/map/CurrentMarkerPopupContent.tsx | 5 ++++- src/langs/en.json | 5 +++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/components/map/CurrentLocationMarker.tsx b/src/components/map/CurrentLocationMarker.tsx index 5a4adb8..9a733a4 100644 --- a/src/components/map/CurrentLocationMarker.tsx +++ b/src/components/map/CurrentLocationMarker.tsx @@ -16,7 +16,7 @@ const CurrentLocationMarker = ({ return ( - {t('Current location')} + {t('My Location')} ); }; diff --git a/src/components/map/CurrentMarkerPopupContent.tsx b/src/components/map/CurrentMarkerPopupContent.tsx index df866a7..0764fc0 100644 --- a/src/components/map/CurrentMarkerPopupContent.tsx +++ b/src/components/map/CurrentMarkerPopupContent.tsx @@ -1,3 +1,5 @@ +import { useTranslation } from 'react-i18next'; + import { Skeleton } from '@mui/material'; import { ItemGeolocation } from '@graasp/sdk'; @@ -12,6 +14,7 @@ const CurrentMarkerPopupContent = ({ open: boolean; point: Pick; }): JSX.Element => { + const { t } = useTranslation(); const { useAddressFromGeolocation, currentMember } = useQueryClientContext(); const { data: address, isLoading } = useAddressFromGeolocation(point, { enabled: Boolean(currentMember) && open, @@ -26,7 +29,7 @@ const CurrentMarkerPopupContent = ({ return ; } - return 'This location does not match a specific address.'; + return t('This location does not match a specific address.'); }; return ( diff --git a/src/langs/en.json b/src/langs/en.json index 302505a..e39be40 100644 --- a/src/langs/en.json +++ b/src/langs/en.json @@ -12,8 +12,9 @@ "filters": "filters", "Keywords": "Keywords", "Filters": "Filters", - "Current Location": "Current Location", + "My Location": "My Location", "Description (optional)": "Description (optional)", "Name": "Name", - "Add a new folder at this location": "Add a new folder at this location" + "Add a new folder at this location": "Add a new folder at this location", + "This location does not match a specific address.": "This location does not match a specific address." } From 3ed03fd897ffe058b72519e307c235e4449f3b08 Mon Sep 17 00:00:00 2001 From: kim Date: Mon, 15 Apr 2024 14:05:19 +0200 Subject: [PATCH 4/4] refactor: include geoloc --- src/components/Map.stories.tsx | 64 ++--------------------------- src/components/Map.tsx | 50 ++++++++++++++++++++-- src/components/map/InitialSetup.tsx | 4 +- src/components/map/MapContent.tsx | 8 +++- 4 files changed, 59 insertions(+), 67 deletions(-) diff --git a/src/components/Map.stories.tsx b/src/components/Map.stories.tsx index 48ba950..fe6f11f 100644 --- a/src/components/Map.stories.tsx +++ b/src/components/Map.stories.tsx @@ -52,6 +52,8 @@ export const Map = { // cannot play inside an iframe } satisfies Story; +// it shows the country form if localisation is disabled +// it shows the current location otherwise export const MapSignedOut = { args: { itemId: 'd5a1c73d-cd4d-4f20-8a91-3c689ee87ea4', @@ -107,6 +109,8 @@ export const MapMobile = { // cannot play inside an iframe } satisfies Story; +// it shows the country form if localisation is disabled +// it shows the current location otherwise export const MapSignOutMobile = { parameters: { viewport: { defaultViewport: 'mobile1' } }, args: { @@ -129,63 +133,3 @@ export const MapSignOutMobile = { ], // cannot play inside an iframe } satisfies Story; - -export const MapWithCurrentLocation = { - args: { - viewItem: () => ({}) as any, - currentMember: null, - currentPosition: { lat: 46.51, lng: 6.5 }, - useDeleteItemGeolocation: () => ({}) as any, - useItemsInMap: () => ({ data: [] }) as any, - useAddressFromGeolocation: () => ({ data: 'address' }) as any, - usePostItem: () => ({}) as any, - useRecycleItems: () => ({}) as any, - useSuggestionsForAddress: MOCK_USE_SUGGESTIONS as any, - }, - decorators: [ - (Story) => ( -
- -
- ), - ], - // cannot play inside an iframe -} satisfies Story; - -export const MapWithCurrentLocationAndItems = { - args: { - viewItem: () => ({}) as any, - currentMember: null, - currentPosition: { lat: 46.51, lng: 6.499 }, - useDeleteItemGeolocation: () => ({}) as any, - useItemsInMap: () => - ({ - data: [ - { - lat: 46.51, - lng: 6.5, - addressLabel: 'EPFL', - item, - }, - { - lat: 46.51, - lng: 6.4995, - addressLabel: 'EPFL', - item, - }, - ], - }) as any, - useAddressFromGeolocation: () => ({ data: 'address' }) as any, - usePostItem: () => ({}) as any, - useRecycleItems: () => ({}) as any, - useSuggestionsForAddress: MOCK_USE_SUGGESTIONS as any, - }, - decorators: [ - (Story) => ( -
- -
- ), - ], - // cannot play inside an iframe -} satisfies Story; diff --git a/src/components/Map.tsx b/src/components/Map.tsx index 87641f3..800883c 100644 --- a/src/components/Map.tsx +++ b/src/components/Map.tsx @@ -1,6 +1,8 @@ import { useEffect, useState } from 'react'; import { MapContainer, TileLayer } from 'react-leaflet'; +import { Skeleton } from '@mui/material'; + import { DEFAULT_LANG } from '@graasp/translations'; import 'leaflet-easybutton/src/easy-button.css'; @@ -19,6 +21,12 @@ import MapContent from './map/MapContent'; type Props = QueryClientContextInterface; +const options = { + enableHighAccuracy: true, + timeout: 5000, + maximumAge: 0, +}; + const Map = ({ itemId, currentMember, @@ -29,10 +37,16 @@ const Map = ({ usePostItem, viewItem, useDeleteItemGeolocation, - currentPosition, handleAddOnClick, }: Props): JSX.Element => { const [showMap, setShowMap] = useState(false); + const [hasFetchedCurrentLocation, setHasFetchedCurrentLocation] = + useState(false); + + const [currentPosition, setCurrentPosition] = useState<{ + lat: number; + lng: number; + }>(); useEffect(() => { if (currentMember) { @@ -40,12 +54,36 @@ const Map = ({ } }, [currentMember]); + // get current location + useEffect(() => { + const success = (pos: { + coords: { latitude: number; longitude: number }; + }) => { + const crd = pos.coords; + setCurrentPosition({ lat: crd.latitude, lng: crd.longitude }); + setHasFetchedCurrentLocation(true); + }; + + navigator.geolocation.getCurrentPosition( + success, + (err: { code: number; message: string }) => { + // eslint-disable-next-line no-console + console.warn(`ERROR(${err.code}): ${err.message}`); + setHasFetchedCurrentLocation(true); + }, + options, + ); + }, []); + + if (!hasFetchedCurrentLocation) { + return ; + } + return ( {/* focus on initial geoloc if item id is defined, cannot use useffect because of map updates */} - + {!showMap && !currentPosition ? ( ) : ( - + )}
diff --git a/src/components/map/InitialSetup.tsx b/src/components/map/InitialSetup.tsx index 56e1125..de28496 100644 --- a/src/components/map/InitialSetup.tsx +++ b/src/components/map/InitialSetup.tsx @@ -6,11 +6,13 @@ import { useQueryClientContext } from '../context/QueryClientContext'; const InitialSetup = ({ showMap, setShowMap, + currentPosition, }: { showMap: boolean; setShowMap: Dispatch; + currentPosition?: { lat: number; lng: number }; }): null => { - const { useItemsInMap, itemId, currentPosition } = useQueryClientContext(); + const { useItemsInMap, itemId } = useQueryClientContext(); const [isInitial, setIsInitial] = useState(true); const map = useMap(); diff --git a/src/components/map/MapContent.tsx b/src/components/map/MapContent.tsx index 8fb98ba..dd60c93 100644 --- a/src/components/map/MapContent.tsx +++ b/src/components/map/MapContent.tsx @@ -7,8 +7,12 @@ import CurrentMarker from './CurrentMarker'; import ItemsMarkers from './ItemsMarkers'; import MapEvents from './MapEvents'; -const MapContent = (): JSX.Element => { - const { itemId, currentPosition } = useQueryClientContext(); +const MapContent = ({ + currentPosition, +}: { + currentPosition?: { lat: number; lng: number }; +}): JSX.Element => { + const { itemId } = useQueryClientContext(); const [bounds, setBounds] = useState<{ lat1: number; lat2: number;