Add default avatar and only show latest ping

This commit is contained in:
Fergal Moran
2024-01-05 21:00:28 +00:00
parent b048013ae1
commit f087366499
6 changed files with 46 additions and 40 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -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<MainMapProps> = ({ kids }) => {
<TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" />
<>
{kids?.map((kid) =>
kid.devices?.map((device) =>
device.pings.map((ping) => (
kid.devices?.map((device) => {
const latestPing = getLatestPing(device.pings);
return (
<MapMarker
key={ping.id}
key={latestPing.id}
childName={kid.name}
avatar={kid.avatar}
deviceName={device.deviceName}
latitude={ping.latitude}
longitude={ping.longitude}
timestamp={ping.timestamp} />
),
),
))}
latitude={latestPing.latitude}
longitude={latestPing.longitude}
timestamp={latestPing.timestamp} />
);
},
),
)}
</>
</MapContainer>
</div>;

View File

@@ -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<MapMarkerProps> = (
>
<Popup>
<Card className="w-full max-w-md p-6 grid gap-4">
<div className="flex items-center gap-4">
<Avatar className="h-16 w-16">
<AvatarImage src={avatar} alt={childName} />
<AvatarFallback>{getInitials(childName)}</AvatarFallback>
</Avatar>
<div className="grid gap-1">
<div className="text-lg font-bold">{childName}</div>
<div className="text-sm text-gray-500 dark:text-gray-400">on {deviceName}</div>
<CardHeader>
<div className="flex items-center gap-4">
<Avatar className="h-16 w-16">
<AvatarImage src={_getAvatarImage(avatar)} alt={childName} />
<AvatarFallback>{getInitials(childName)}</AvatarFallback>
</Avatar>
<div className="grid gap-1">
<div className="text-lg font-bold">{childName}</div>
<div className="text-sm text-gray-500 dark:text-gray-400">on {deviceName}</div>
</div>
</div>
</div>
<div className="text-sm text-gray-500 dark:text-gray-400">
Last seen - {timestamp.toLocaleDateString() + ' ' + timestamp.toLocaleTimeString()}
</div>
<div className="flex justify-end gap-4">
</CardHeader>
<CardContent>
<div className="text-sm text-gray-500 dark:text-gray-400">
Last seen - {timestamp.toLocaleDateString() + ' ' + timestamp.toLocaleTimeString()}
</div>
</CardContent>
<CardFooter className="flex justify-end gap-4">
<Link className="" href="#">
<Icons.message className="h-6 w-6" />
</Link>
<Link className="text-blue-700" href="#">
<Icons.call className="h-6 w-6" />
</Link>
</div>
</CardFooter>
</Card>
{/*<Card>*/}
{/* <CardHeader>*/}

View File

@@ -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[];
}

View File

@@ -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));

View File

@@ -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,