Create rudimentary catalogue
This commit is contained in:
@ -2,11 +2,22 @@ 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 { useQuery, useMutation, useQueryClient, queryOptions } from "@tanstack/react-query";
|
||||
import axios from "axios";
|
||||
import Contacts from './Contacts';
|
||||
import { Button } from './ui/Button';
|
||||
|
||||
import { Button, buttonVariants } from './ui/Button';
|
||||
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog"
|
||||
|
||||
|
||||
//Todo: Move types to own file
|
||||
interface User {
|
||||
@ -21,11 +32,24 @@ interface Node {
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface Media {
|
||||
id: string;
|
||||
alt?: string;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
url?: string;
|
||||
filename?: string;
|
||||
mimeType?: string;
|
||||
filesize?: number;
|
||||
width?: number;
|
||||
height?: number;
|
||||
}
|
||||
|
||||
interface Product extends Node {
|
||||
id: string;
|
||||
name: string;
|
||||
weight?: number;
|
||||
picture: string;
|
||||
picture: Media;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
};
|
||||
@ -209,11 +233,20 @@ export const KiosMap = () => {
|
||||
setSelectedNode({ id: nodeId, type: typeParam })
|
||||
console.log("set id:", nodeId)
|
||||
}
|
||||
|
||||
|
||||
//params: dispatch: Dispatch, courier: User
|
||||
const handleAcceptRoute = () => {
|
||||
|
||||
}
|
||||
|
||||
const handleOpenCatalogue = () => {
|
||||
}
|
||||
|
||||
//params
|
||||
const handleRequestProduct = () => {
|
||||
|
||||
}
|
||||
|
||||
const blackDotIcon = L.divIcon({
|
||||
className: 'bg-gray-950 rounded-full',
|
||||
iconSize: [20, 20],
|
||||
@ -235,35 +268,76 @@ export const KiosMap = () => {
|
||||
|
||||
return (
|
||||
<div className='w-full flex justify-center align-middle'>
|
||||
|
||||
{
|
||||
selectedNode.type !== 'none' && (
|
||||
<div className='absolute bg-white border-gray-950 border-2 z-[999] left-10 top-1/4 p-4'>
|
||||
<div className='absolute bg-white border-gray-950 border-2 z-[998] left-10 top-1/4 p-4'>
|
||||
<div className='flex gap-8 flex-col'>
|
||||
{selectedMaker !== undefined && (
|
||||
<div>
|
||||
<Contacts
|
||||
name={selectedMaker.name}
|
||||
email={selectedMaker.email}
|
||||
phoneNumber={selectedMaker.phoneNumber}
|
||||
role={'maker'}
|
||||
<div className='flex gap-4 flex-col'>
|
||||
<Contacts
|
||||
name={selectedMaker.name}
|
||||
email={selectedMaker.email}
|
||||
phoneNumber={selectedMaker.phoneNumber}
|
||||
role={'maker'}
|
||||
/>
|
||||
<Button
|
||||
variant="kios"
|
||||
onClick={() => handleOpenCatalogue()}
|
||||
>See catalogue</Button>
|
||||
{(selectedMaker.stock !== undefined && selectedMaker.stock.length > 0) &&
|
||||
<Dialog>
|
||||
<DialogTrigger
|
||||
className={buttonVariants({ variant: "kios" })}
|
||||
>
|
||||
See catalogue
|
||||
</DialogTrigger>
|
||||
|
||||
<DialogContent className='lg:max-w-screen-lg overflow-y-scroll max-h-screen'>
|
||||
<DialogHeader>
|
||||
<DialogTitle className="text-4xl underline underline-offset-2">{selectedMaker.name}'s stock</DialogTitle>
|
||||
<DialogDescription>
|
||||
<ul className='flex flex-col gap-4'>
|
||||
{selectedMaker.stock.map((product, i) => {
|
||||
return (
|
||||
<li className="flex flex-row gap-4">
|
||||
{product.picture.url &&
|
||||
<img
|
||||
width={160}
|
||||
src={product.picture.url}
|
||||
alt={product.picture.alt || ''}/>
|
||||
}
|
||||
<div className="flex flex-col gap-4 pb-4">
|
||||
<h3 className='text-4xl text-black py-2'>
|
||||
{product.name}
|
||||
</h3>
|
||||
<Button
|
||||
variant={'kios'}
|
||||
className='w-full'
|
||||
onClick={() => handleRequestProduct()}
|
||||
>
|
||||
Request product
|
||||
</Button>
|
||||
</div>
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
</ul>
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{selectedRetailer !== undefined && (
|
||||
<Contacts
|
||||
name={selectedRetailer.name}
|
||||
email={selectedRetailer.email}
|
||||
phoneNumber={selectedRetailer.phoneNumber}
|
||||
role={'retailer'}
|
||||
/>
|
||||
<>
|
||||
<Contacts
|
||||
name={selectedRetailer.name}
|
||||
email={selectedRetailer.email}
|
||||
phoneNumber={selectedRetailer.phoneNumber}
|
||||
role={'retailer'}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
//Todo: Display products
|
||||
{selectedDispatch !== undefined && (
|
||||
<div className='flex flex-col gap-4'>
|
||||
<Contacts
|
||||
@ -291,12 +365,12 @@ export const KiosMap = () => {
|
||||
) :
|
||||
<div>
|
||||
<h2 className='text-xl font-bold underline-offset-2 underline py-2'>No courier!</h2>
|
||||
<Button
|
||||
<Button
|
||||
variant={"kios"}
|
||||
onClick={() => handleAcceptRoute()}
|
||||
>
|
||||
Accept route as courier
|
||||
</Button>
|
||||
>
|
||||
Accept route as courier
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
@ -9,7 +9,7 @@ const buttonVariants = cva(
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
kios: "border-2 border-gray-950 py-2 px-4 w-full hover:bg-gray-950 transition-all hover:text-white hover:font-bold rounded-none",
|
||||
kios: "text-black border-2 border-gray-950 py-2 px-4 w-full hover:bg-gray-950 transition-all hover:text-white hover:font-bold rounded-none",
|
||||
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
||||
destructive:
|
||||
"bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
||||
|
120
astro/src/components/ui/dialog.tsx
Normal file
120
astro/src/components/ui/dialog.tsx
Normal file
@ -0,0 +1,120 @@
|
||||
import * as React from "react"
|
||||
import * as DialogPrimitive from "@radix-ui/react-dialog"
|
||||
import { X } from "lucide-react"
|
||||
|
||||
import { cn } from "@/utils"
|
||||
|
||||
const Dialog = DialogPrimitive.Root
|
||||
|
||||
const DialogTrigger = DialogPrimitive.Trigger
|
||||
|
||||
const DialogPortal = DialogPrimitive.Portal
|
||||
|
||||
const DialogClose = DialogPrimitive.Close
|
||||
|
||||
const DialogOverlay = React.forwardRef<
|
||||
React.ElementRef<typeof DialogPrimitive.Overlay>,
|
||||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DialogPrimitive.Overlay
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"fixed inset-0 z-[999] bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName
|
||||
|
||||
const DialogContent = React.forwardRef<
|
||||
React.ElementRef<typeof DialogPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<DialogPortal>
|
||||
<DialogOverlay />
|
||||
<DialogPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"fixed left-[50%] top-[50%] z-[999] w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%]",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<DialogPrimitive.Close className="absolute right-4 top-4 opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
|
||||
<X className="h-4 w-4" />
|
||||
<span className="sr-only">Close</span>
|
||||
</DialogPrimitive.Close>
|
||||
</DialogPrimitive.Content>
|
||||
</DialogPortal>
|
||||
))
|
||||
DialogContent.displayName = DialogPrimitive.Content.displayName
|
||||
|
||||
const DialogHeader = ({
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div
|
||||
className={cn(
|
||||
"flex flex-col space-y-1.5 text-center sm:text-left",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
DialogHeader.displayName = "DialogHeader"
|
||||
|
||||
const DialogFooter = ({
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div
|
||||
className={cn(
|
||||
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
DialogFooter.displayName = "DialogFooter"
|
||||
|
||||
const DialogTitle = React.forwardRef<
|
||||
React.ElementRef<typeof DialogPrimitive.Title>,
|
||||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DialogPrimitive.Title
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"text-lg font-semibold leading-none tracking-tight",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DialogTitle.displayName = DialogPrimitive.Title.displayName
|
||||
|
||||
const DialogDescription = React.forwardRef<
|
||||
React.ElementRef<typeof DialogPrimitive.Description>,
|
||||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DialogPrimitive.Description
|
||||
ref={ref}
|
||||
className={cn("text-sm text-muted-foreground", className)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
DialogDescription.displayName = DialogPrimitive.Description.displayName
|
||||
|
||||
export {
|
||||
Dialog,
|
||||
DialogPortal,
|
||||
DialogOverlay,
|
||||
DialogClose,
|
||||
DialogTrigger,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogFooter,
|
||||
DialogTitle,
|
||||
DialogDescription,
|
||||
}
|
@ -22,6 +22,8 @@ export interface User {
|
||||
id: string;
|
||||
name: string;
|
||||
phoneNumber?: number;
|
||||
adminOfMakers?: string[] | Maker[];
|
||||
adminOfRetailers?: string[] | Retailer[];
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
email: string;
|
||||
@ -33,6 +35,28 @@ export interface User {
|
||||
lockUntil?: string;
|
||||
password?: string;
|
||||
}
|
||||
export interface Maker {
|
||||
id: string;
|
||||
name: string;
|
||||
phoneNumber?: string;
|
||||
email?: string;
|
||||
/**
|
||||
* @minItems 2
|
||||
* @maxItems 2
|
||||
*/
|
||||
location: [number, number];
|
||||
stock?: string[] | Product[];
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
export interface Product {
|
||||
id: string;
|
||||
name: string;
|
||||
picture: string | Media;
|
||||
weight?: number;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
export interface Media {
|
||||
id: string;
|
||||
alt?: string;
|
||||
@ -45,6 +69,20 @@ export interface Media {
|
||||
width?: number;
|
||||
height?: number;
|
||||
}
|
||||
export interface Retailer {
|
||||
id: string;
|
||||
name: string;
|
||||
phoneNumber?: string;
|
||||
email?: string;
|
||||
/**
|
||||
* @minItems 2
|
||||
* @maxItems 2
|
||||
*/
|
||||
location: [number, number];
|
||||
stock?: string[] | Product[];
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
export interface Courier {
|
||||
id: string;
|
||||
updatedAt: string;
|
||||
@ -61,39 +99,3 @@ export interface Dispatch {
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
export interface Product {
|
||||
id: string;
|
||||
name: string;
|
||||
picture: string | Media;
|
||||
weight?: number;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
export interface Maker {
|
||||
id: string;
|
||||
name: string;
|
||||
phoneNumber?: string;
|
||||
email?: string;
|
||||
/**
|
||||
* @minItems 2
|
||||
* @maxItems 2
|
||||
*/
|
||||
location: [number, number];
|
||||
stock?: string[] | Product[];
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
export interface Retailer {
|
||||
id: string;
|
||||
name: string;
|
||||
phoneNumber?: string;
|
||||
email?: string;
|
||||
/**
|
||||
* @minItems 2
|
||||
* @maxItems 2
|
||||
*/
|
||||
location: [number, number];
|
||||
stock?: string[] | Product[];
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
|
Reference in New Issue
Block a user