Skip to content

Commit

Permalink
feat: working live data
Browse files Browse the repository at this point in the history
  • Loading branch information
casperiv0 committed Jan 28, 2024
1 parent 53d67d7 commit 603ce7e
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 31 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import * as React from "react";
import type { CombinedEmsFdUnit, CombinedLeoUnit, EmsFdDeputy, Officer } from "@snailycad/types";
import { useActiveDeputies } from "hooks/realtime/useActiveDeputies";
import { useActiveOfficers } from "hooks/realtime/useActiveOfficers";
import { useTranslations } from "next-intl";
import { UnitItem } from "./unit-item";
import { ManageUnitModal } from "components/dispatch/active-units/modals/manage-unit-modal";
Expand All @@ -15,18 +13,16 @@ export function ActiveMapUnits() {
null | Officer | EmsFdDeputy | CombinedEmsFdUnit | CombinedLeoUnit
>(null);
const players = useMapPlayersStore((state) => state.players);
const { openUnits, setOpenUnits } = useDispatchMapState((state) => ({
const { openUnits, activeMapUnits, setOpenUnits } = useDispatchMapState((state) => ({
activeMapUnits: state.activeUnits,
openUnits: state.openUnits,
setOpenUnits: state.setOpenUnits,
}));
const t = useTranslations("Leo");

const { activeOfficers } = useActiveOfficers();
const { activeDeputies } = useActiveDeputies();
const units = createMapUnitsFromActiveUnits({
players: Array.from(players.values()),
activeOfficers,
activeDeputies,
activeUnits: activeMapUnits,
});

return (
Expand Down
49 changes: 42 additions & 7 deletions apps/client/src/hooks/realtime/use-map-players.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ import { makeSocketConnection } from "components/dispatch/map/modals/select-map-
import { ConnectionStatus } from "@snailycad/ui";
import { createWithEqualityFn } from "zustand/traditional";
import { shallow } from "zustand/shallow";
import { useMutation } from "@tanstack/react-query";
import type { EmsFdDeputy, Officer } from "@snailycad/types";
import { useListener } from "@casperiv/use-socket.io";
import { SocketEvents } from "@snailycad/config";

export const useMapPlayersStore = createWithEqualityFn<{
players: Map<string, MapPlayer | PlayerDataEventPayload>;
Expand All @@ -32,6 +36,7 @@ export function useMapPlayers() {
const { players, setPlayers } = useMapPlayersStore();

const currentMapServerURL = useDispatchMapState((state) => state.currentMapServerURL);
const setActiveMapUnits = useDispatchMapState((state) => state.setActiveMapUnits);
const modalState = useModal();
const { state, execute } = useFetch();
const { socket, setStatus, setSocket } = useSocketStore((state) => ({
Expand All @@ -40,11 +45,16 @@ export function useMapPlayers() {
setSocket: state.setSocket,
}));

const getCADUsers = React.useCallback(
async (options: {
const getCadUsersQuery = useMutation<
unknown,
Error,
{
map: Map<string, MapPlayer | PlayerDataEventPayload>;
fetchMore?: boolean;
}) => {
}
>({
mutationKey: ["get-cad-users", "live-map"],
mutationFn: async (options) => {
if (state === "loading") return;

const availablePlayersArray = Array.from(options.map.values());
Expand All @@ -65,23 +75,29 @@ export function useMapPlayers() {
});

const json = Array.isArray(rawJson) ? rawJson : [];
const units = new Map<string, EmsFdDeputy | Officer>();

for (const user of json) {
const player = availablePlayersArray.find(
(player) =>
player.discordId === user.discordId || player.convertedSteamId === user.steamId,
);

if (user.unit) {
units.set(user.unit.id, user.unit);
}

if (player) {
newPlayers.set(player.identifier, { ...player, ...user });
}
}

setActiveMapUnits(Array.from(units.values()));
}

setPlayers(options.map);
},
[state], // eslint-disable-line
);
});

const onPlayerData = React.useCallback(
async (data: PlayerDataEvent) => {
Expand Down Expand Up @@ -114,9 +130,12 @@ export function useMapPlayers() {
});
}

await getCADUsers({ map: newMap, fetchMore: data.payload.length !== players.size });
await getCadUsersQuery.mutateAsync({
map: newMap,
fetchMore: data.payload.length !== players.size,
});
},
[players, getCADUsers],
[players, getCadUsersQuery],
);

const onPlayerLeft = React.useCallback(
Expand Down Expand Up @@ -176,6 +195,22 @@ export function useMapPlayers() {
[currentMapServerURL], // eslint-disable-line react-hooks/exhaustive-deps
);

useListener(SocketEvents.UpdateOfficerStatus, () => {
getCadUsersQuery.mutate({
map: new Map(players),
// We have to fetch more to get the latest unit information
fetchMore: true,
});
});

useListener(SocketEvents.UpdateEmsFdStatus, () => {
getCadUsersQuery.mutate({
map: new Map(players),
// We have to fetch more to get the latest unit information
fetchMore: true,
});
});

const onConnect = React.useCallback(() => {
setStatus(ConnectionStatus.CONNECTED);
toastMessage({
Expand Down
31 changes: 14 additions & 17 deletions apps/client/src/lib/map/create-map-units-from-active-units.ts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,31 +10,26 @@ import type { MapPlayer, PlayerDataEventPayload } from "types/map";

interface ActiveUnitsOptions {
players: (MapPlayer | PlayerDataEventPayload)[];
activeOfficers: (Officer | CombinedLeoUnit)[];
activeDeputies: (EmsFdDeputy | CombinedEmsFdUnit)[];
activeUnits: (Officer | CombinedLeoUnit | EmsFdDeputy | CombinedEmsFdUnit)[];
}

export function createMapUnitsFromActiveUnits({
players,
activeOfficers,
activeDeputies,
}: ActiveUnitsOptions) {
const activeUnits: MapPlayer[] = [];
const _activeOfficers = activeOfficers;
const _activeDeputies = activeDeputies;
export function createMapUnitsFromActiveUnits({ players, activeUnits }: ActiveUnitsOptions) {
const transformedActiveUnits: MapPlayer[] = [];

for (const activeUnit of [..._activeOfficers, ..._activeDeputies]) {
for (const activeUnit of activeUnits) {
if (!activeUnit.status || activeUnit.status.shouldDo === ShouldDoType.SET_OFF_DUTY) continue;

if (isUnitCombined(activeUnit) || isUnitCombinedEmsFd(activeUnit)) {
const player = players.find((player) => findPlayerFromCombinedUnit(player, activeUnit));

if (!player || !("steamId" in player) || !("discordId" in player)) continue;

const existing = activeUnits.some((player) => findPlayerFromCombinedUnit(player, activeUnit));
const existing = transformedActiveUnits.some((player) =>
findPlayerFromCombinedUnit(player, activeUnit),
);

if (!existing) {
activeUnits.push({ ...player, unit: activeUnit });
transformedActiveUnits.push({ ...player, unit: activeUnit });
}

continue;
Expand All @@ -45,18 +40,20 @@ export function createMapUnitsFromActiveUnits({
const player = players.find((player) => findPlayerFromSingleUnit(player, activeUnit));
if (!player || !("steamId" in player) || !("discordId" in player)) continue;

const existing = activeUnits.some((player) => findPlayerFromSingleUnit(player, activeUnit));
const existing = transformedActiveUnits.some((player) =>
findPlayerFromSingleUnit(player, activeUnit),
);
if (!existing) {
activeUnits.push({ ...player, unit: activeUnit });
transformedActiveUnits.push({ ...player, unit: activeUnit });
}
}

return activeUnits;
return transformedActiveUnits;
}

export function findPlayerFromUnit(
player: MapPlayer | PlayerDataEventPayload,
activeUnit: Officer | EmsFdDeputy | CombinedLeoUnit | CombinedEmsFdUnit,
activeUnit: Officer | CombinedLeoUnit | EmsFdDeputy | CombinedEmsFdUnit,
) {
if (isUnitCombined(activeUnit) || isUnitCombinedEmsFd(activeUnit)) {
return findPlayerFromCombinedUnit(player, activeUnit);
Expand Down
9 changes: 9 additions & 0 deletions apps/client/src/state/mapState.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { CombinedEmsFdUnit, CombinedLeoUnit, EmsFdDeputy, Officer } from "@snailycad/types";
import { type ConnectionStatus } from "@snailycad/ui";
import { type Socket } from "socket.io-client";
import type { SmartMotorwaySignMarker, SmartSignMarker } from "types/map";
Expand All @@ -14,6 +15,9 @@ export enum MapItem {
}

interface DispatchMapState {
activeUnits: (EmsFdDeputy | Officer | CombinedLeoUnit | CombinedEmsFdUnit)[];
setActiveMapUnits(units: (EmsFdDeputy | Officer | CombinedLeoUnit | CombinedEmsFdUnit)[]): void;

smartSigns: SmartSignMarker[];
setSmartSigns(signs: SmartSignMarker[]): void;

Expand Down Expand Up @@ -49,6 +53,11 @@ interface MapStore {
export const useDispatchMapState = createWithEqualityFn<DispatchMapState>()(
persist(
(set) => ({
activeUnits: [],
setActiveMapUnits(activeUnits) {
set({ activeUnits });
},

openCalls: [],
setOpenCalls(calls) {
set({ openCalls: calls });
Expand Down

0 comments on commit 603ce7e

Please sign in to comment.