- added session sighting component
- add new session paused state and stop adding to session when true
This commit is contained in:
@@ -5,19 +5,26 @@ import type { ReducedSightingType } from "../../types/types";
|
|||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
import { faFloppyDisk, faPause, faPlay, faStop } from "@fortawesome/free-solid-svg-icons";
|
import { faFloppyDisk, faPause, faPlay, faStop } from "@fortawesome/free-solid-svg-icons";
|
||||||
|
import VehicleSessionItem from "../UI/VehicleSessionItem";
|
||||||
|
|
||||||
const SessionCard = () => {
|
const SessionCard = () => {
|
||||||
const { sessionStarted, setSessionStarted, sessionList } = useNPEDContext();
|
const { sessionStarted, setSessionStarted, sessionList, setSessionPaused, sessionPaused } = useNPEDContext();
|
||||||
|
|
||||||
const handleStartClick = () => {
|
const handleStartClick = () => {
|
||||||
setSessionStarted(!sessionStarted);
|
setSessionStarted(!sessionStarted);
|
||||||
toast(`${sessionStarted ? "Vehicle tracking session Ended" : "Vehicle tracking session Started"}`);
|
setSessionPaused(false);
|
||||||
|
toast(`${sessionStarted ? "Vehicle tracking session ended" : "Vehicle tracking session started"}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSaveCick = () => {
|
const handleSaveCick = () => {
|
||||||
console.log("clicked");
|
console.log("clicked");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handlepauseClick = () => {
|
||||||
|
setSessionPaused(!sessionPaused);
|
||||||
|
toast(`${sessionStarted ? "Vehicle tracking session paused" : "Vehicle tracking session resumed"}`);
|
||||||
|
};
|
||||||
|
|
||||||
const sightings = [...new Map(sessionList.map((vehicle) => [vehicle.vrm, vehicle]))];
|
const sightings = [...new Map(sessionList.map((vehicle) => [vehicle.vrm, vehicle]))];
|
||||||
|
|
||||||
const dedupedSightings = sightings.map((sighting) => sighting[1]);
|
const dedupedSightings = sightings.map((sighting) => sighting[1]);
|
||||||
@@ -75,45 +82,52 @@ const SessionCard = () => {
|
|||||||
{sessionStarted && (
|
{sessionStarted && (
|
||||||
<button
|
<button
|
||||||
className={`bg-gray-300 text-gray-800 px-4 py-2 rounded transition w-full lg:w-[50%]`}
|
className={`bg-gray-300 text-gray-800 px-4 py-2 rounded transition w-full lg:w-[50%]`}
|
||||||
onClick={handleSaveCick}
|
onClick={handlepauseClick}
|
||||||
>
|
>
|
||||||
<div className="flex flex-row gap-3 items-center justify-self-center">
|
<div className="flex flex-row gap-3 items-center justify-self-center">
|
||||||
<FontAwesomeIcon icon={faPause} />
|
<FontAwesomeIcon icon={sessionPaused ? faPlay : faPause} />
|
||||||
<p>Pause session</p>
|
<p>{sessionPaused ? "Resume session" : "Pause session"}</p>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul className="text-white space-y-2">
|
<ul className="text-white space-y-2">
|
||||||
<li className="rounded-xl border border-slate-800 bg-slate-800/60 p-3 shadow-sm flex flex-row justify-between">
|
<VehicleSessionItem
|
||||||
<p>Number of Vehicles sightings:</p>
|
sessionNumber={dedupedSightings.length}
|
||||||
<span className="font-bold text-green-600 text-xl">{dedupedSightings.length}</span>
|
textColour="text-green-400"
|
||||||
</li>
|
vehicleTag={"Number of Vehicles sightings:"}
|
||||||
<li className="rounded-xl border border-slate-800 bg-slate-800/60 p-3 shadow-sm flex flex-row justify-between">
|
/>
|
||||||
<p>Vehicles without Tax:</p>
|
<VehicleSessionItem
|
||||||
<span className="font-bold text-amber-600 text-xl">{vehicles.notTaxed.length}</span>
|
sessionNumber={vehicles.notTaxed.length}
|
||||||
</li>
|
textColour="text-amber-400"
|
||||||
<li className="rounded-xl border border-slate-800 bg-slate-800/60 p-3 shadow-sm flex flex-row justify-between">
|
vehicleTag={"Vehicles without Tax:"}
|
||||||
<p>Vehicles without MOT:</p>{" "}
|
/>
|
||||||
<span className="font-bold text-red-500 text-xl">{vehicles.notMOT.length}</span>
|
<VehicleSessionItem
|
||||||
</li>
|
sessionNumber={vehicles.notMOT.length}
|
||||||
<li className="rounded-xl border border-slate-800 bg-slate-800/60 p-3 shadow-sm flex flex-row justify-between">
|
textColour="text-red-500"
|
||||||
<p>Vehicles on Hotlists:</p>{" "}
|
vehicleTag={"Vehicles without MOT:"}
|
||||||
<span className="font-bold text-blue-500 text-xl">{vehicles.hotlistHit.length}</span>
|
/>
|
||||||
</li>
|
<VehicleSessionItem
|
||||||
<li className="rounded-xl border border-slate-800 bg-slate-800/60 p-3 shadow-sm flex flex-row justify-between">
|
sessionNumber={vehicles.hotlistHit.length}
|
||||||
<p>Vehicles with NPED Cat A:</p>
|
textColour="text-blue-400"
|
||||||
<span className="font-bold text-gray-300 text-xl">{vehicles.npedCatA.length}</span>
|
vehicleTag={"Vehicles on Hotlists:"}
|
||||||
</li>
|
/>
|
||||||
<li className="rounded-xl border border-slate-800 bg-slate-800/60 p-3 shadow-sm flex flex-row justify-between">
|
<VehicleSessionItem
|
||||||
<p>Vehicles with NPED Cat B:</p>{" "}
|
sessionNumber={vehicles.npedCatA.length}
|
||||||
<span className="font-bold text-gray-300 text-xl">{vehicles.npedCatB.length}</span>
|
textColour="text-gray-300"
|
||||||
</li>
|
vehicleTag={"Vehicles with NPED Cat A:"}
|
||||||
<li className="rounded-xl border border-slate-800 bg-slate-800/60 p-3 shadow-sm flex flex-row justify-between">
|
/>
|
||||||
Vehicles with NPED Cat C:{" "}
|
<VehicleSessionItem
|
||||||
<span className="font-bold text-gray-300 text-xl">{vehicles.npedCatC.length}</span>
|
sessionNumber={vehicles.npedCatB.length}
|
||||||
</li>
|
textColour="text-gray-300"
|
||||||
|
vehicleTag={"Vehicles with NPED Cat B:"}
|
||||||
|
/>
|
||||||
|
<VehicleSessionItem
|
||||||
|
sessionNumber={vehicles.npedCatC.length}
|
||||||
|
textColour="text-gray-300"
|
||||||
|
vehicleTag={"Vehicles with NPED Cat C:"}
|
||||||
|
/>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ export default function SightingHistoryWidget({ className, title }: SightingHist
|
|||||||
} = useSightingFeedContext();
|
} = useSightingFeedContext();
|
||||||
|
|
||||||
const { dispatch } = useAlertHitContext();
|
const { dispatch } = useAlertHitContext();
|
||||||
const { sessionStarted, setSessionList, sessionList } = useNPEDContext();
|
const { sessionStarted, setSessionList, sessionList, sessionPaused } = useNPEDContext();
|
||||||
|
|
||||||
const processedRefs = useRef<Set<number | string>>(new Set());
|
const processedRefs = useRef<Set<number | string>>(new Set());
|
||||||
|
|
||||||
@@ -88,6 +88,7 @@ export default function SightingHistoryWidget({ className, title }: SightingHist
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (sessionStarted) {
|
if (sessionStarted) {
|
||||||
if (!mostRecent) return;
|
if (!mostRecent) return;
|
||||||
|
if (sessionPaused) return;
|
||||||
const reducedMostRecent = reduceObject(mostRecent);
|
const reducedMostRecent = reduceObject(mostRecent);
|
||||||
setSessionList([...sessionList, reducedMostRecent]);
|
setSessionList([...sessionList, reducedMostRecent]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,14 @@
|
|||||||
import { Link } from "react-router";
|
import { Link } from "react-router";
|
||||||
import Logo from "/MAV.svg";
|
import Logo from "/MAV.svg";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
import {
|
import { faGear, faHome, faListCheck, faMaximize, faMinimize, faRotate } from "@fortawesome/free-solid-svg-icons";
|
||||||
faGear,
|
|
||||||
faHome,
|
|
||||||
faListCheck,
|
|
||||||
faMaximize,
|
|
||||||
faMinimize,
|
|
||||||
faRotate,
|
|
||||||
} from "@fortawesome/free-solid-svg-icons";
|
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import SoundBtn from "./SoundBtn";
|
import SoundBtn from "./SoundBtn";
|
||||||
import { useNPEDContext } from "../../context/NPEDUserContext";
|
import { useNPEDContext } from "../../context/NPEDUserContext";
|
||||||
|
|
||||||
export default function Header() {
|
export default function Header() {
|
||||||
const [isFullscreen, setIsFullscreen] = useState(false);
|
const [isFullscreen, setIsFullscreen] = useState(false);
|
||||||
const { sessionStarted } = useNPEDContext();
|
const { sessionStarted, sessionPaused } = useNPEDContext();
|
||||||
|
|
||||||
const toggleFullscreen = () => {
|
const toggleFullscreen = () => {
|
||||||
if (!document.fullscreenElement) {
|
if (!document.fullscreenElement) {
|
||||||
@@ -39,9 +32,13 @@ export default function Header() {
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col lg:flex-row items-center space-x-24 justify-items-center">
|
<div className="flex flex-col lg:flex-row items-center space-x-24 justify-items-center">
|
||||||
{sessionStarted && (
|
<div className="flex flex-row lg:flex-row space-x-2">
|
||||||
<div className="text-green-400 font-bold">Session Active</div>
|
{sessionStarted && sessionPaused ? (
|
||||||
|
<p className="text-gray-400 font-bold">Session Paused</p>
|
||||||
|
) : (
|
||||||
|
sessionStarted && <p className="text-green-400 font-bold">Session Active</p>
|
||||||
)}
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-row space-x-8">
|
<div className="flex flex-row space-x-8">
|
||||||
<Link to={"/"}>
|
<Link to={"/"}>
|
||||||
@@ -59,11 +56,7 @@ export default function Header() {
|
|||||||
</div>
|
</div>
|
||||||
<SoundBtn />
|
<SoundBtn />
|
||||||
<Link to={"/session-settings"}>
|
<Link to={"/session-settings"}>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon className="text-white" icon={faListCheck} size="2x" />
|
||||||
className="text-white"
|
|
||||||
icon={faListCheck}
|
|
||||||
size="2x"
|
|
||||||
/>
|
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
<Link to={"/system-settings"}>
|
<Link to={"/system-settings"}>
|
||||||
|
|||||||
18
src/components/UI/VehicleSessionItem.tsx
Normal file
18
src/components/UI/VehicleSessionItem.tsx
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import clsx from "clsx";
|
||||||
|
|
||||||
|
type VehicleSessionItemProps = {
|
||||||
|
sessionNumber: number;
|
||||||
|
textColour: string;
|
||||||
|
vehicleTag: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const VehicleSessionItem = ({ sessionNumber, textColour, vehicleTag }: VehicleSessionItemProps) => {
|
||||||
|
return (
|
||||||
|
<li className="rounded-xl border border-slate-800 bg-slate-800/60 p-3 shadow-sm flex flex-row justify-between items-center">
|
||||||
|
<p>{vehicleTag}</p>
|
||||||
|
<span className={`font-bold text-xl bg-slate-700 px-2 rounded-md ${clsx(textColour)}`}>{sessionNumber}</span>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default VehicleSessionItem;
|
||||||
@@ -5,17 +5,16 @@ type UserContextValue = {
|
|||||||
user: NPEDUser | null;
|
user: NPEDUser | null;
|
||||||
setUser: React.Dispatch<SetStateAction<NPEDUser | null>>;
|
setUser: React.Dispatch<SetStateAction<NPEDUser | null>>;
|
||||||
sessionStarted: boolean;
|
sessionStarted: boolean;
|
||||||
|
sessionPaused: boolean;
|
||||||
|
setSessionPaused: React.Dispatch<SetStateAction<boolean>>;
|
||||||
setSessionStarted: React.Dispatch<SetStateAction<boolean>>;
|
setSessionStarted: React.Dispatch<SetStateAction<boolean>>;
|
||||||
sessionList: ReducedSightingType[];
|
sessionList: ReducedSightingType[];
|
||||||
setSessionList: React.Dispatch<SetStateAction<ReducedSightingType[]>>;
|
setSessionList: React.Dispatch<SetStateAction<ReducedSightingType[]>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const NPEDUserContext = createContext<UserContextValue | undefined>(
|
export const NPEDUserContext = createContext<UserContextValue | undefined>(undefined);
|
||||||
undefined
|
|
||||||
);
|
|
||||||
export const useNPEDContext = () => {
|
export const useNPEDContext = () => {
|
||||||
const ctx = useContext(NPEDUserContext);
|
const ctx = useContext(NPEDUserContext);
|
||||||
if (!ctx)
|
if (!ctx) throw new Error("useNPEDContext must be used within <NPEDUserProvider>");
|
||||||
throw new Error("useNPEDContext must be used within <NPEDUserProvider>");
|
|
||||||
return ctx;
|
return ctx;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ export const NPEDUserProvider = ({ children }: NPEDUserProviderType) => {
|
|||||||
const [user, setUser] = useState<NPEDUser | null>(null);
|
const [user, setUser] = useState<NPEDUser | null>(null);
|
||||||
const [sessionStarted, setSessionStarted] = useState(false);
|
const [sessionStarted, setSessionStarted] = useState(false);
|
||||||
const [sessionList, setSessionList] = useState<ReducedSightingType[]>([]);
|
const [sessionList, setSessionList] = useState<ReducedSightingType[]>([]);
|
||||||
|
const [sessionPaused, setSessionPaused] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NPEDUserContext.Provider
|
<NPEDUserContext.Provider
|
||||||
@@ -20,6 +21,8 @@ export const NPEDUserProvider = ({ children }: NPEDUserProviderType) => {
|
|||||||
sessionStarted,
|
sessionStarted,
|
||||||
sessionList,
|
sessionList,
|
||||||
setSessionList,
|
setSessionList,
|
||||||
|
sessionPaused,
|
||||||
|
setSessionPaused,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
Reference in New Issue
Block a user