Add label functionality to tasks for better organization and tracking
Update TaskCard and TaskCreationModal components to support task labels, including UI elements for selection and display. Refactor schema imports to use '@shared/schema'. Replit-Commit-Author: Agent Replit-Commit-Session-Id: ceced2fc-aa46-458d-ba87-ddd4b7bb1518 Replit-Commit-Checkpoint-Type: intermediate_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/659922a9-0087-461c-90dd-6d9a58b81d4d/ceced2fc-aa46-458d-ba87-ddd4b7bb1518/vtpluZY
This commit is contained in:
+1
-1
@@ -14,7 +14,7 @@ import CalendarView from './components/CalendarView';
|
||||
import KanbanBoard from './components/KanbanBoard';
|
||||
import ProjectTemplate from './components/ProjectTemplate';
|
||||
import ThemeToggle from './components/ThemeToggle';
|
||||
import { Task } from './components/TaskCard';
|
||||
import { Task } from '@shared/schema';
|
||||
import { addDays, subDays } from 'date-fns';
|
||||
|
||||
// Mock data for prototype
|
||||
|
||||
@@ -19,12 +19,21 @@ export default function TaskCard({ task, onPlay, onPause, onEdit, onStatusChange
|
||||
const [isTimerRunning, setIsTimerRunning] = useState(task.isTracking);
|
||||
|
||||
// Fetch labels to get the label color
|
||||
const { data: labels = [] } = useQuery<Label[]>({
|
||||
const { data: labels = [], isLoading: labelsLoading, error: labelsError } = useQuery<Label[]>({
|
||||
queryKey: ['/api/labels'],
|
||||
staleTime: 5 * 60 * 1000, // 5 minutes cache
|
||||
refetchOnWindowFocus: false,
|
||||
});
|
||||
|
||||
// Find the label for this task
|
||||
const taskLabel = task.labelId ? labels.find(label => label.id === task.labelId) : null;
|
||||
const taskLabel = task.labelId && labels.length > 0 ? labels.find(label => label.id === task.labelId) : null;
|
||||
|
||||
// Debug logging - always log for tasks with labelId
|
||||
if (task.labelId) {
|
||||
console.log(`TaskCard Debug - Task: "${task.title}", LabelId: ${task.labelId}, Labels loading: ${labelsLoading}, Labels count: ${labels.length}, Labels error:`, labelsError);
|
||||
console.log(`TaskCard Debug - Available labels:`, labels.map(l => ({ id: l.id, name: l.name, color: l.color })));
|
||||
console.log(`TaskCard Debug - Found label:`, taskLabel);
|
||||
}
|
||||
|
||||
const handleToggleTimer = () => {
|
||||
if (isTimerRunning) {
|
||||
@@ -68,8 +77,12 @@ export default function TaskCard({ task, onPlay, onPause, onEdit, onStatusChange
|
||||
>
|
||||
{taskLabel && (
|
||||
<div
|
||||
className="absolute left-0 top-2 bottom-2 w-1 rounded-r-sm"
|
||||
style={{ backgroundColor: taskLabel.color }}
|
||||
className="absolute left-0 top-2 bottom-2 w-1 rounded-r-sm z-10"
|
||||
style={{
|
||||
backgroundColor: taskLabel.color,
|
||||
minWidth: '4px'
|
||||
}}
|
||||
data-testid={`accent-label-${task.id}`}
|
||||
/>
|
||||
)}
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
|
||||
@@ -6,8 +6,9 @@ import { Textarea } from '@/components/ui/textarea';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||
import { Calendar } from '@/components/ui/calendar';
|
||||
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
|
||||
import { CalendarIcon, Plus } from 'lucide-react';
|
||||
import { Task } from './TaskCard';
|
||||
import { CalendarIcon, Plus, Tag } from 'lucide-react';
|
||||
import { Task, Label } from '@shared/schema';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
interface TaskCreationModalProps {
|
||||
isOpen: boolean;
|
||||
@@ -20,8 +21,14 @@ export default function TaskCreationModal({ isOpen, onClose, onSave }: TaskCreat
|
||||
const [description, setDescription] = useState('');
|
||||
const [priority, setPriority] = useState<'low' | 'medium' | 'high'>('medium');
|
||||
const [dueDate, setDueDate] = useState<Date | undefined>();
|
||||
const [labelId, setLabelId] = useState<string | undefined>();
|
||||
const [isCalendarOpen, setIsCalendarOpen] = useState(false);
|
||||
|
||||
// Fetch labels
|
||||
const { data: labels = [] } = useQuery<Label[]>({
|
||||
queryKey: ['/api/labels'],
|
||||
});
|
||||
|
||||
const handleSave = () => {
|
||||
if (!title.trim()) return;
|
||||
|
||||
@@ -30,6 +37,7 @@ export default function TaskCreationModal({ isOpen, onClose, onSave }: TaskCreat
|
||||
description: description.trim() || undefined,
|
||||
priority,
|
||||
dueDate,
|
||||
labelId,
|
||||
status: 'todo',
|
||||
timeTracked: 0,
|
||||
isTracking: false
|
||||
@@ -43,6 +51,7 @@ export default function TaskCreationModal({ isOpen, onClose, onSave }: TaskCreat
|
||||
setDescription('');
|
||||
setPriority('medium');
|
||||
setDueDate(undefined);
|
||||
setLabelId(undefined);
|
||||
onClose();
|
||||
};
|
||||
|
||||
@@ -58,6 +67,7 @@ export default function TaskCreationModal({ isOpen, onClose, onSave }: TaskCreat
|
||||
setDescription('');
|
||||
setPriority('medium');
|
||||
setDueDate(undefined);
|
||||
setLabelId(undefined);
|
||||
onClose();
|
||||
};
|
||||
|
||||
@@ -109,6 +119,28 @@ export default function TaskCreationModal({ isOpen, onClose, onSave }: TaskCreat
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<div className="flex-1">
|
||||
<Select value={labelId || 'none'} onValueChange={(value) => setLabelId(value === 'none' ? undefined : value)}>
|
||||
<SelectTrigger data-testid="select-task-label">
|
||||
<SelectValue placeholder="Label" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="none">No Label</SelectItem>
|
||||
{labels.map((label) => (
|
||||
<SelectItem key={label.id} value={label.id}>
|
||||
<div className="flex items-center gap-2">
|
||||
<div
|
||||
className="w-3 h-3 rounded"
|
||||
style={{ backgroundColor: label.color }}
|
||||
/>
|
||||
{label.name}
|
||||
</div>
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<Popover open={isCalendarOpen} onOpenChange={setIsCalendarOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Badge } from '@/components/ui/badge';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||
import { Search, Filter, SortAsc, Calendar, ChevronLeft, ChevronRight } from 'lucide-react';
|
||||
import { Task } from './TaskCard';
|
||||
import { Task } from '@shared/schema';
|
||||
import TaskCard from './TaskCard';
|
||||
import TimeCompletionModal from './TimeCompletionModal';
|
||||
import { addDays, format, isSameDay, startOfToday } from 'date-fns';
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import TaskCard, { Task } from '../TaskCard';
|
||||
import TaskCard from '../TaskCard';
|
||||
import { Task } from '@shared/schema';
|
||||
|
||||
const mockTask: Task = {
|
||||
id: '1',
|
||||
|
||||
Reference in New Issue
Block a user