"use client"; import { useEffect, useState, useRef } from "react"; import { toast } from "@/components/ui/use-toast"; import { api } from "@/lib/trpc"; import { zodResolver } from "@hookform/resolvers/zod"; import { TRPCClientError } from "@trpc/client"; import { useForm } from "react-hook-form"; import { z } from "zod"; import { zMeasurementSchema, ZMetric } from "@lifetracker/shared/types/metrics"; import { ZHour } from "@lifetracker/shared/types/days"; import { Icon } from "@/components/ui/icon"; import { titleCase } from "title-case"; import { Dialog, DialogClose, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog"; import { X } from "lucide-react"; import { useDecrementCount, useIncrementCount, } from "@lifetracker/shared-react/hooks/measurements"; import { Separator } from "@radix-ui/react-dropdown-menu"; type CreateMeasurementSchema = z.infer; export default function HourMeasurementsDialog({ hour: initialHour, metrics, reload, children, }: { hour: ZHour, metrics: ZMetric[], reload: (newHour: ZHour) => void, children?: React.ReactNode; }) { const [hour, setHour] = useState(initialHour); const [isOpen, onOpenChange] = useState(false); const { mutate: increment } = useIncrementCount({ onSuccess: (res) => { const oldMeasurement = hour.measurements.find(m => m.metricId === res.metricId); const newHour = { ...hour, measurements: oldMeasurement ? hour.measurements.map(m => m.metricId === res.metricId ? res : m) : [...hour.measurements, res], }; setHour(newHour); reload(newHour); console.log("New hour's deets", newHour.measurements); toast({ description: "Measurement added!", }); }, onError: (error) => { toast({ description: error.message, }); }, }); const { mutate: decrement } = useDecrementCount({ onSuccess: (res, req) => { const oldMeasurementIndex = hour.measurements.findIndex(m => m.metricId === req.metricId); let newMeasurements; if (oldMeasurementIndex !== -1) { if (res === undefined) { // Remove the measurement if res is undefined newMeasurements = [ ...hour.measurements.slice(0, oldMeasurementIndex), ...hour.measurements.slice(oldMeasurementIndex + 1) ]; } else { // Update the measurement newMeasurements = [ ...hour.measurements.slice(0, oldMeasurementIndex), res, ...hour.measurements.slice(oldMeasurementIndex + 1) ]; } } else { // Add the new measurement newMeasurements = [...hour.measurements, res]; } const newHour = { ...hour, measurements: newMeasurements, }; setHour(newHour); reload(newHour); toast({ description: res === undefined ? "Measurement removed!" : "Measurement updated!", }); } }); let currentMeasurements = hour.measurements.map(measurement => measurement.metricName); // With useEffect, update currentMeasurements when hour changes useEffect(() => { currentMeasurements = hour.measurements.map(measurement => measurement.metricName); }, [hour]); return ( {children} Metrics for {hour.date} at {hour.datetime} {hour.measurements && hour.measurements.length > 0 ? (<>
Measurements
{hour.measurements.map(measurement => { const metric = metrics.find(m => m.id === measurement.metricId); return (
{metric.name}
{ decrement({ metricId: metric.id, hourId: hour.id, dayId: hour.dayId }); }} >
{measurement.value}
{ increment({ metricId: metric.id, hourId: hour.id, dayId: hour.dayId }); }}>
); })}
) : <> }
Add Measurement
{metrics.map(metric => ( // If metric.name is in currentMeasurements, don't show it currentMeasurements.includes(metric.name) ? null : ))}
// // Show a dropdown menu with an option for each metric. When the user selects a metric, increment the count for that metric in the hour. // // The dropdown should show the metric name and icon. // // Reset the dropdown to the default value after the user selects a metric. //