Improve time selection with interactive popover and hour options
Replaces the simple click-to-cycle hour selection with a Popover component in `artifacts/cra-app/src/pages/timesheet-detail.tsx`, allowing users to select from a wider range of predefined hour options. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 55837015-10e9-4be9-b857-7f5e6be73772 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 96602b33-5bd8-4421-9962-7e11ed0421c8 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/1cc377db-7ea0-49f2-97ce-c3e87e0228cc/55837015-10e9-4be9-b857-7f5e6be73772/0xBkjKi Replit-Helium-Checkpoint-Created: true
This commit is contained in:
parent
147ae0f4c7
commit
7b2caa45fd
@ -1,4 +1,4 @@
|
||||
import { useState, useMemo, useEffect, useRef, useCallback } from "react";
|
||||
import { useState, useMemo, useEffect, useRef, useCallback, type ReactNode } from "react";
|
||||
import { useParams, Link } from "wouter";
|
||||
import {
|
||||
useGetTimesheet,
|
||||
@ -30,6 +30,7 @@ import {
|
||||
SelectValue
|
||||
} from "@/components/ui/select";
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog";
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
|
||||
import { useToast } from "@/hooks/use-toast";
|
||||
import { formatMonthYear, STATUS_LABELS, STATUS_COLORS, cn } from "@/lib/utils";
|
||||
import { getDaysInMonth, isWeekend, format } from "date-fns";
|
||||
@ -103,18 +104,11 @@ export default function TimesheetDetailPage() {
|
||||
};
|
||||
}, [timesheet]);
|
||||
|
||||
const handleCellClick = (lineId: number, dateStr: string) => {
|
||||
if (!isEditable) return;
|
||||
const HOUR_OPTIONS = [0, 0.5, 1, 2, 3, 4, 5, 6, 7, 7.7];
|
||||
|
||||
const handleSetHours = (lineId: number, dateStr: string, hours: number) => {
|
||||
const key = `${lineId}-${dateStr}`;
|
||||
const current = localEntries[key] || 0;
|
||||
|
||||
// Cycle: 0 -> 0.5 -> 1 -> 0
|
||||
let next = 0.5;
|
||||
if (current === 0.5) next = 1;
|
||||
if (current === 1) next = 0;
|
||||
|
||||
setLocalEntries(prev => ({ ...prev, [key]: next }));
|
||||
setLocalEntries(prev => ({ ...prev, [key]: hours }));
|
||||
setHasUnsavedChanges(true);
|
||||
};
|
||||
|
||||
@ -367,10 +361,15 @@ export default function TimesheetDetailPage() {
|
||||
const key = `${line.id}-${day.dateStr}`;
|
||||
const val = localEntries[key] || 0;
|
||||
|
||||
const cellContent = (
|
||||
<div className="flex items-center justify-center h-9 w-full text-xs">
|
||||
{val === 0 ? "" : val}
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<td
|
||||
key={day.dateStr}
|
||||
onClick={() => handleCellClick(line.id, day.dateStr)}
|
||||
className={cn(
|
||||
"p-0 text-center border-r transition-colors select-none",
|
||||
day.isWeekendDay ? "bg-muted/30" : "",
|
||||
@ -378,9 +377,33 @@ export default function TimesheetDetailPage() {
|
||||
val > 0 ? "bg-primary/5 text-primary font-semibold" : ""
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center justify-center h-9 w-full text-xs">
|
||||
{val === 0 ? "" : val}
|
||||
</div>
|
||||
{isEditable ? (
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
{cellContent}
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-1.5" side="bottom" align="center">
|
||||
<div className="grid grid-cols-5 gap-1">
|
||||
{HOUR_OPTIONS.map(h => (
|
||||
<button
|
||||
key={h}
|
||||
onClick={() => handleSetHours(line.id, day.dateStr, h)}
|
||||
className={cn(
|
||||
"px-2 py-1.5 rounded text-xs font-medium transition-colors",
|
||||
val === h
|
||||
? "bg-primary text-primary-foreground"
|
||||
: h === 0
|
||||
? "bg-muted/50 hover:bg-destructive/10 hover:text-destructive"
|
||||
: "bg-muted/50 hover:bg-primary/10"
|
||||
)}
|
||||
>
|
||||
{h === 0 ? "✕" : `${h}h`}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
) : cellContent}
|
||||
</td>
|
||||
);
|
||||
})}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user