From ed420d5ff1f8b7c1380b95dd74c9ff097f982296 Mon Sep 17 00:00:00 2001 From: toqvist Date: Fri, 5 Apr 2024 15:03:18 +0200 Subject: [PATCH] Make map nodes selectable and stylish --- astro/src/components/KiosMap.tsx | 210 ++++++++++++++++------------ astro/src/types.ts | 2 +- payload/src/collections/Products.ts | 4 +- 3 files changed, 121 insertions(+), 95 deletions(-) diff --git a/astro/src/components/KiosMap.tsx b/astro/src/components/KiosMap.tsx index 48be123..047fffa 100644 --- a/astro/src/components/KiosMap.tsx +++ b/astro/src/components/KiosMap.tsx @@ -1,4 +1,4 @@ -import React, { useEffect } from 'react'; +import React, { useEffect, useState } from 'react'; import { MapContainer, TileLayer, Marker, CircleMarker, Popup, Polyline, LayerGroup, GeoJSON, } from 'react-leaflet'; import 'leaflet/dist/leaflet.css'; import L, { LatLngBounds } from 'leaflet'; @@ -7,30 +7,33 @@ import { useQuery, useMutation, useQueryClient, queryOptions } from "@tanstack/r import axios from "axios"; //Todo: Move types to own file -type User = { +interface User { name: string; id: string; email: string; phoneNumber: string; } -type Product = { +interface Node { + name: string; id: string; - title: string; +} + +interface Product extends Node { + id: string; + name: string; weight?: number; picture: string; createdAt: string; updatedAt: string; }; -// type Location = { +// interface Location = { // latitude: number; // longitude: number; // } -type Maker = { - id: string; - name: string; +interface Maker extends Node { email: string; phoneNumber?: string; location: [number, number]; @@ -39,9 +42,7 @@ type Maker = { updatedAt: string; }; -type Retailer = { - id: string; - name: string; +interface Retailer extends Node { email: string; phoneNumber?: string; location: [number, number]; @@ -53,7 +54,7 @@ type Retailer = { const DISPATCH_STATUS = ['requested', 'accepted', 'archived'] as const; type DispatchStatus = typeof DISPATCH_STATUS[number]; -type Dispatch = { +interface Dispatch { id: string; dispatchesCode?: string; //Human readable id createdAt: string; @@ -64,7 +65,7 @@ type Dispatch = { products: Product[]; courier?: User; - + timeSensitive: boolean; status: DispatchStatus; @@ -107,7 +108,7 @@ const getRetailers = async () => { console.log("Fetching url:", url) const response = await axios.get(url); - const retailers:Retailer[] = response.data.docs; + const retailers: Retailer[] = response.data.docs; console.log(`Fetch result from ${url}`, retailers) return retailers; @@ -126,8 +127,8 @@ const getDispatches = async () => { console.log("Fetching url:", url) const response = await axios.get(url); - const dispatches:Dispatch[] = response.data.docs; - + const dispatches: Dispatch[] = response.data.docs; + console.log(`Fetch result from ${url}`, dispatches) return dispatches; @@ -143,7 +144,7 @@ const useGetDispatches = () => { //Payload longitude and latitude are mislabeled in payload (lol) const locationSwitcharoo = (location: number[]) => { - if(location.length === 2) { + if (location.length === 2) { const correctedLocation = [location[1], location[0]] return correctedLocation; } @@ -160,29 +161,44 @@ const dashArrays: Record = { const dashColors: Record = { requested: '#000', - accepted: '#000', - archived: '#000', + accepted: '#000', + archived: '#000', } +const dashColorSelected: string = '#f87171' //same as tw red 400 + const dashOpacities: Record = { requested: 0.7, - accepted: 0.7, + accepted: 0.7, archived: 0.5 } - export const KiosMap = () => { const { data: makers, isLoading: isLoadingMakers } = useGetMakers(); const { data: retailers, isLoading: isLoadingRetailers } = useGetRetailers(); const { data: dispatches, isLoading: isLoadingDispatches } = useGetDispatches(); + const [selectedNodeId, setSelectedNodeId] = useState('') + + const handleSelectNode = (nodeId: string) => { + setSelectedNodeId(nodeId) + console.log("set id:", nodeId) + } + const blackDotIcon = L.divIcon({ className: 'bg-gray-950 rounded-full', iconSize: [20, 20], iconAnchor: [10, 10] }); - + + const selectedDotIcon = L.divIcon({ + className: 'bg-red-400 rounded-full ring-offset-2 ring-4 ring-red-400 ring-dashed', + iconSize: [20, 20], + iconAnchor: [10, 10] + }); + + const bounds = new LatLngBounds( [-90, -180], // Southwest corner @@ -191,84 +207,94 @@ export const KiosMap = () => { return (
- - - +
+
+
+ + - {(makers && !isLoadingMakers) && - - {makers.map((maker: any, index: number) => ( - - {maker.name} - - ))} - - } + {(makers && !isLoadingMakers) && + + {makers.map((maker: any, index: number) => ( + handleSelectNode(maker.id) + }} + key={maker.id} + position={[locationSwitcharoo(maker.location)[0], locationSwitcharoo(maker.location)[1]]} + icon={selectedNodeId === maker.id ? selectedDotIcon : blackDotIcon} + > + {/* {maker.name} */} + + ))} + + } - {(retailers && !isLoadingRetailers) && - - {retailers.map((retailer: any, index: number) => ( - - {retailer.name} - - ))} - - } + {(retailers && !isLoadingRetailers) && + + {retailers.map((retailer: any, index: number) => ( + handleSelectNode(retailer.id) + }} + key={retailer.id} + position={[locationSwitcharoo(retailer.location)[0], locationSwitcharoo(retailer.location)[1]]} + icon={selectedNodeId === retailer.id ? selectedDotIcon : blackDotIcon} + > + {/* {retailer.name} */} + + ))} + + } - {(dispatches && !isLoadingDispatches) && - - {dispatches.map((dispatch: any, index: number) => { + {(dispatches && !isLoadingDispatches) && + + {dispatches.map((dispatch: any, index: number) => { - if(dispatch.maker && dispatch.retailer) { + if (dispatch.maker && dispatch.retailer) { - const start = locationSwitcharoo(dispatch.maker.location); - const end = locationSwitcharoo(dispatch.retailer.location); - + const start = locationSwitcharoo(dispatch.maker.location); + const end = locationSwitcharoo(dispatch.retailer.location); - let productsString = ''; - dispatch.products.forEach((product: any, i: number) => { - productsString += product.productTitle + (i + 1 < dispatch.products.length ? ', ' : ''); - }); - //status type should already be inferred when list of dispatches is created, weird that is is required - const status: DispatchStatus = dispatch.status; + let productsString = ''; + dispatch.products.forEach((product: any, i: number) => { + productsString += product.productTitle + (i + 1 < dispatch.products.length ? ', ' : ''); + }); - const dashArray:string = dashArrays[status] - const dashColor:string = dashColors[status] - const dashOpacity:number = dashOpacities[status] - - return ( -
- -
- ); - } - })} -
- } -
+ //status type should already be inferred when list of dispatches is created, weird that is is required + const status: DispatchStatus = dispatch.status; + + const dashArray: string = dashArrays[status] + const dashColor: string = dashColors[status] + const dashOpacity: number = dashOpacities[status] + + return ( + handleSelectNode(dispatch.id) + }} + key={dispatch.id} + positions={[[start[0], start[1]], [end[0], end[1]]]} + pathOptions={{color: selectedNodeId === dispatch.id ? dashColorSelected : dashColor}} + opacity={dashOpacity} + dashArray={dashArray} /> + ); + } + })} + + } +
); }; diff --git a/astro/src/types.ts b/astro/src/types.ts index 96354f2..473133e 100755 --- a/astro/src/types.ts +++ b/astro/src/types.ts @@ -63,7 +63,7 @@ export interface Dispatch { } export interface Product { id: string; - title: string; + name: string; picture: string | Media; weight?: number; updatedAt: string; diff --git a/payload/src/collections/Products.ts b/payload/src/collections/Products.ts index e4d15cc..5640213 100644 --- a/payload/src/collections/Products.ts +++ b/payload/src/collections/Products.ts @@ -3,14 +3,14 @@ import { CollectionConfig } from 'payload/types'; const Products: CollectionConfig = { slug: 'products', admin: { - useAsTitle: 'title', + useAsTitle: 'name', }, access: { read: () => true, }, fields: [ { - name: 'title', + name: 'name', type: 'text', required: true, },