fix: build errors and merging projects and homepage

This commit is contained in:
2026-08-30 21:38:59 +00:00
parent 97ff9852cd
commit c9a7294d13
71 changed files with 10942 additions and 5413 deletions

View File

@@ -0,0 +1,76 @@
import { z } from 'zod';
// ── Presigned upload ──────────────────────────────────────────────────────────
export const presignedUploadSchema = z.object({
mimeType: z.enum(['image/jpeg', 'image/png', 'image/webp', 'image/heic'])
});
// ── Register new animal (+ first sighting) ────────────────────────────────────
export const registerAnimalSchema = z.object({
// Animal identity
species: z.string().min(1).max(100),
breed: z.string().max(100).optional(),
animalName: z.string().max(100).optional(),
description: z.string().max(1000).optional(),
// AI suggestion to persist for admin review
aiBreedSuggestion: z.string().max(100).optional(),
aiBreedConfidence: z.number().min(0).max(1).optional(),
// First sighting details
reporterName: z.string().max(100).optional(),
seenAt: z.iso.datetime(),
lat: z.number().min(-90).max(90),
lng: z.number().min(-180).max(180),
// Device GPS — used server-side for 30km check, never stored
deviceLat: z.number().min(-90).max(90),
deviceLng: z.number().min(-180).max(180),
// Already-uploaded R2 keys (1–10 photos, browser uploaded directly)
photoKeys: z.array(z.string().min(1)).min(1).max(10)
});
export type RegisterAnimalInput = z.infer<typeof registerAnimalSchema>;
// ── Add sighting to existing animal ──────────────────────────────────────────
export const addSightingSchema = z.object({
animalId: z.string().uuid(),
reporterName: z.string().max(100).optional(),
seenAt: z.iso.datetime(),
lat: z.number().min(-90).max(90),
lng: z.number().min(-180).max(180),
deviceLat: z.number().min(-90).max(90),
deviceLng: z.number().min(-180).max(180),
photoKeys: z.array(z.string().min(1)).max(10).optional()
});
export type AddSightingInput = z.infer<typeof addSightingSchema>;
// ── Map viewport query ────────────────────────────────────────────────────────
export const mapQuerySchema = z.object({
minLat: z.coerce.number().min(-90).max(90),
minLng: z.coerce.number().min(-180).max(180),
maxLat: z.coerce.number().min(-90).max(90),
maxLng: z.coerce.number().min(-180).max(180),
// Optional filters
species: z.string().optional(),
breed: z.string().optional(),
name: z.string().optional(),
reporter: z.string().optional(),
fromDate: z.iso.datetime().optional(),
toDate: z.iso.datetime().optional()
});
export type MapQuery = z.infer<typeof mapQuerySchema>;
// ── Admin ─────────────────────────────────────────────────────────────────────
export const moderationActionSchema = z.object({
action: z.enum(['accept', 'deny'])
});