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'; import Contacts from './Contacts'; import type { User, Node, Retailer, Maker, Product, Dispatch, DispatchStatus, CreateDispatch } from '../astroTypes'; import { useQuery, useMutation, useQueryClient, queryOptions } from "@tanstack/react-query"; import { useGetMakers, useGetDispatches, useGetRetailers, useGetUser, useGetMyself, API_URL, useGetMyRetailers, useCreateDispatch } from "../utils/hooks" import { Button, buttonVariants } from './ui/Button'; import { humanId, poolSize, minLength, maxLength } from 'human-id' import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger, } from "@/components/ui/dialog" import { LoginForm } from './LoginForm'; import { hasAuthCookie } from '@/utils/authUtils'; //Payload longitude and latitude are mislabeled/switched in payload const locationSwitcharoo = (location: number[]) => { if (location.length === 2) { const correctedLocation = [location[1], location[0]] return correctedLocation; } console.error("locationSwitcharoo: Location array malformed") return location } const dashArrays: Record = { requested: '20, 10', accepted: '0, 0', archived: '1, 5', } const dashColors: Record = { requested: '#000', accepted: '#000', archived: '#000', } const dashColorSelected: string = '#f87171' //same as tw red 400 const dashOpacities: Record = { requested: 0.7, accepted: 0.7, archived: 0.5 } interface NodeSelection { id: string, type: "maker" | "retailer" | "dispatch" | "none" } export const KiosMap = () => { const [authToken, setAuthToken] = useState('') const { data: makers, isLoading: isLoadingMakers } = useGetMakers(); const { data: retailers, isLoading: isLoadingRetailers } = useGetRetailers(); const { data: dispatches, isLoading: isLoadingDispatches } = useGetDispatches(); const { data: myself, isLoading: isLoadingMyself } = useGetMyself(authToken); const { data: myRetailers, isLoading: isLoadingMyRetailers } = useGetMyRetailers(myself); const createDispatchMutation = useCreateDispatch(); const [selectedNode, setSelectedNode] = useState({ id: "", type: "none" }) let selectedMaker: Maker | undefined = undefined; let selectedRetailer: Retailer | undefined = undefined; let selectedDispatch: Dispatch | undefined = undefined; if (selectedNode.type === "maker" && makers) { selectedMaker = makers.find(maker => maker.id === selectedNode.id && selectedNode.type === "maker"); } if (selectedNode.type === "retailer" && retailers) { selectedRetailer = retailers.find(retailer => retailer.id === selectedNode.id && selectedNode.type === "retailer"); } if (selectedNode.type === "dispatch" && dispatches) { selectedDispatch = dispatches.find(dispatch => dispatch.id === selectedNode.id && selectedNode.type === "dispatch"); } const handleSelectNode = (nodeId: string, typeParam: "maker" | "retailer" | "dispatch" | "none") => { setSelectedNode({ id: nodeId, type: typeParam }) } //params: dispatch: Dispatch, courier: User const handleAcceptRoute = () => { } const handleRequestDispatch = (products: Product[], retailer: Retailer, maker: Maker | undefined) => { if (maker === undefined) { console.error("Request dispatch error: Marker undefined") return } const dispatch: CreateDispatch = { code: humanId({ separator: '-', capitalize: false, }), products: products.map((product) => {return product.id}), maker: maker.id, retailer: retailer.id, timeSensitive: false, status: "requested", } createDispatchMutation.mutate(dispatch) } 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 [90, 180] // Northeast corner ); return (
{ (!hasAuthCookie() && !authToken) ? Login : myself &&

Logged in as: {myself?.name}

}
Login
{ selectedNode.type !== 'none' && (
{selectedMaker !== undefined && (
{(selectedMaker !== undefined && selectedMaker.stock !== undefined && selectedMaker.stock.length > 0) && See catalogue {selectedMaker.name}'s stock
    {selectedMaker.stock.map((product, i) => { return (
  • {product.picture.url && {product.picture.alt }

    {product.name}

    {product.weight &&

    Weight: {product.weight}

    } {myself ? (myRetailers !== undefined) &&
      {myRetailers.map((retailer, i) => { return (
    • ) })}
    : }
  • ) })}
}
)} {selectedRetailer !== undefined && ( <> )} {selectedDispatch !== undefined && (

Product{selectedDispatch.products.length > 1 && 's'}

{selectedDispatch.products.map((product, i) => { return (
{product.picture.alt}

{product.name}

) })}
{selectedDispatch.courier !== undefined ? ( ) :

No courier!

}
)}
) } handleSelectNode("", "none") }} attribution='© OpenStreetMap' /> {(makers && !isLoadingMakers) && {makers.map((maker: any, index: number) => ( handleSelectNode(maker.id, "maker") }} key={maker.id} position={[locationSwitcharoo(maker.location)[0], locationSwitcharoo(maker.location)[1]]} icon={selectedNode.id === maker.id ? selectedDotIcon : blackDotIcon} > {/* {maker.name} */} ))} } {(retailers && !isLoadingRetailers) && {retailers.map((retailer: any, index: number) => ( handleSelectNode(retailer.id, "retailer") }} key={retailer.id} position={[locationSwitcharoo(retailer.location)[0], locationSwitcharoo(retailer.location)[1]]} icon={selectedNode.id === retailer.id ? selectedDotIcon : blackDotIcon} > {/* {retailer.name} */} ))} } {(dispatches && !isLoadingDispatches) && {dispatches.map((dispatch: any, index: number) => { if (dispatch.maker && dispatch.retailer) { 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; const dashArray: string = dashArrays[status] const dashColor: string = dashColors[status] const dashOpacity: number = dashOpacities[status] return ( handleSelectNode(dispatch.id, "dispatch") }} key={dispatch.id} positions={[[start[0], start[1]], [end[0], end[1]]]} pathOptions={{ color: selectedNode.id === dispatch.id ? dashColorSelected : dashColor }} opacity={dashOpacity} dashArray={dashArray} /> ); } })} }
); };