diff --git a/public/img/default-avatar.png b/public/img/default-avatar.png new file mode 100644 index 0000000..eafe9f4 Binary files /dev/null and b/public/img/default-avatar.png differ diff --git a/src/components/maps/main-map.tsx b/src/components/maps/main-map.tsx index 9ccbf2c..f4c7d39 100644 --- a/src/components/maps/main-map.tsx +++ b/src/components/maps/main-map.tsx @@ -5,6 +5,7 @@ import { MapContainer, Marker, Popup, TileLayer, Circle } from 'react-leaflet'; import { usePingSocket } from '@/lib/hooks/use-ping-socket'; import ChildModel from '@/lib/models/child'; import MapMarker from '@/components/maps/map-marker'; +import { getLatestPing } from '@/lib/utils'; type MainMapProps = { kids: ChildModel[]; @@ -33,19 +34,21 @@ const MainMap: React.FC = ({ kids }) => { <> {kids?.map((kid) => - kid.devices?.map((device) => - device.pings.map((ping) => ( + kid.devices?.map((device) => { + const latestPing = getLatestPing(device.pings); + return ( - ), - ), - ))} + latitude={latestPing.latitude} + longitude={latestPing.longitude} + timestamp={latestPing.timestamp} /> + ); + }, + ), + )} ; diff --git a/src/components/maps/map-marker.tsx b/src/components/maps/map-marker.tsx index ed048c1..f0c010a 100644 --- a/src/components/maps/map-marker.tsx +++ b/src/components/maps/map-marker.tsx @@ -1,13 +1,11 @@ import React from 'react'; import L from 'leaflet'; -import { Circle, Marker, Popup } from 'react-leaflet'; +import { Marker, Popup } from 'react-leaflet'; import { Card, CardContent, - CardDescription, CardFooter, CardHeader, - CardTitle, } from '@/components/ui/card'; import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; import { getInitials } from '@/lib/utils'; @@ -17,18 +15,17 @@ import { Icons } from '@/components/icons'; type MapMarkerProps = { childName: string; - avatar: string; + avatar: string | null deviceName: string; latitude: number; longitude: number; timestamp: Date; }; -const fillBlueOptions = { fillColor: 'blue' }; -const fillRedOptions = { fillColor: 'red' }; -const _getIcon = (icon: string) => { +const _getAvatarImage = (avatar: string | null) => avatar ?? '/img/default-avatar.png'; +const _getIcon = (icon: string | null) => { return L.icon({ - iconUrl: icon, + iconUrl: _getAvatarImage(icon), iconSize: [24, 24], }); }; @@ -40,27 +37,31 @@ const MapMarker: React.FC = ( > -
- - - {getInitials(childName)} - -
-
{childName}
-
on {deviceName}
+ +
+ + + {getInitials(childName)} + +
+
{childName}
+
on {deviceName}
+
-
-
- Last seen - {timestamp.toLocaleDateString() + ' ' + timestamp.toLocaleTimeString()} -
-
+ + +
+ Last seen - {timestamp.toLocaleDateString() + ' ' + timestamp.toLocaleTimeString()} +
+
+ -
+ {/**/} {/* */} diff --git a/src/lib/models/child.ts b/src/lib/models/child.ts index a40f00e..c591f19 100644 --- a/src/lib/models/child.ts +++ b/src/lib/models/child.ts @@ -3,7 +3,7 @@ import DeviceModel from './device'; export default interface ChildModel { id: string; name: string; - avatar: string; + avatar: string | null; devices: DeviceModel[]; // recentLocations: Location[]; } diff --git a/src/lib/utils.ts b/src/lib/utils.ts index c07671a..0d784ae 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -1,10 +1,12 @@ import { type ClassValue, clsx } from 'clsx'; import { twMerge } from 'tailwind-merge'; +import PingModel from '@/lib/models/ping'; export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); } -export const getInitials = (name: string) => { - return name?.match(/(\b\S)?/g).join(''); -}; +export const getInitials = (name: string) => name?.match(/(\b\S)?/g)?.join('') ?? ''; + +export const getLatestPing = (pings: PingModel[]): PingModel => + pings.reduce((ping, current) => (ping.timestamp > current.timestamp ? ping : current)); diff --git a/src/server/api/routers/child.ts b/src/server/api/routers/child.ts index 8a3ebbd..20b081b 100644 --- a/src/server/api/routers/child.ts +++ b/src/server/api/routers/child.ts @@ -1,14 +1,14 @@ -import { z } from "zod"; +import { z } from 'zod'; -import { createTRPCRouter, protectedProcedure } from "@/server/api/trpc"; -import { child } from "@/server/db/schema"; -import { eq } from "drizzle-orm"; +import { createTRPCRouter, protectedProcedure } from '@/server/api/trpc'; +import { child } from '@/server/db/schema'; +import { eq } from 'drizzle-orm'; export const childRouter = createTRPCRouter({ create: protectedProcedure .input(z.object({ name: z.string().min(1) })) .mutation(async ({ ctx, input }) => { - console.log("Child", "Create", ctx.session); + console.log('Child', 'Create', ctx.session); const c = { parentId: ctx.session.user.id, name: input.name,