Add core components for task management and navigation
This commit introduces the foundational UI components and logic for the task management application, including task creation, calendar views, Kanban boards, and navigation elements. Replit-Commit-Author: Agent Replit-Commit-Session-Id: ceced2fc-aa46-458d-ba87-ddd4b7bb1518 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/659922a9-0087-461c-90dd-6d9a58b81d4d/ceced2fc-aa46-458d-ba87-ddd4b7bb1518/yy9YLEW
This commit is contained in:
@@ -0,0 +1,152 @@
|
||||
import { useState } from 'react';
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
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';
|
||||
|
||||
interface TaskCreationModalProps {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
onSave: (task: Partial<Task>) => void;
|
||||
}
|
||||
|
||||
export default function TaskCreationModal({ isOpen, onClose, onSave }: TaskCreationModalProps) {
|
||||
const [title, setTitle] = useState('');
|
||||
const [description, setDescription] = useState('');
|
||||
const [priority, setPriority] = useState<'low' | 'medium' | 'high'>('medium');
|
||||
const [dueDate, setDueDate] = useState<Date | undefined>();
|
||||
const [isCalendarOpen, setIsCalendarOpen] = useState(false);
|
||||
|
||||
const handleSave = () => {
|
||||
if (!title.trim()) return;
|
||||
|
||||
const newTask: Partial<Task> = {
|
||||
title: title.trim(),
|
||||
description: description.trim() || undefined,
|
||||
priority,
|
||||
dueDate,
|
||||
status: 'todo',
|
||||
timeTracked: 0,
|
||||
isTracking: false
|
||||
};
|
||||
|
||||
onSave(newTask);
|
||||
console.log('New task created:', newTask);
|
||||
|
||||
// Reset form
|
||||
setTitle('');
|
||||
setDescription('');
|
||||
setPriority('medium');
|
||||
setDueDate(undefined);
|
||||
onClose();
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setTitle('');
|
||||
setDescription('');
|
||||
setPriority('medium');
|
||||
setDueDate(undefined);
|
||||
onClose();
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog open={isOpen} onOpenChange={handleClose}>
|
||||
<DialogContent className="sm:max-w-md mx-4">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="flex items-center gap-2">
|
||||
<Plus className="w-4 h-4" />
|
||||
New Task
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<Input
|
||||
placeholder="What needs to be done?"
|
||||
value={title}
|
||||
onChange={(e) => setTitle(e.target.value)}
|
||||
className="text-base"
|
||||
data-testid="input-task-title"
|
||||
autoFocus
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Textarea
|
||||
placeholder="Add a description (optional)"
|
||||
value={description}
|
||||
onChange={(e) => setDescription(e.target.value)}
|
||||
className="resize-none text-sm"
|
||||
rows={3}
|
||||
data-testid="input-task-description"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-3">
|
||||
<div className="flex-1">
|
||||
<Select value={priority} onValueChange={(value: 'low' | 'medium' | 'high') => setPriority(value)}>
|
||||
<SelectTrigger data-testid="select-task-priority">
|
||||
<SelectValue placeholder="Priority" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="low">Low</SelectItem>
|
||||
<SelectItem value="medium">Medium</SelectItem>
|
||||
<SelectItem value="high">High</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<Popover open={isCalendarOpen} onOpenChange={setIsCalendarOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
className="flex items-center gap-2"
|
||||
data-testid="button-due-date"
|
||||
>
|
||||
<CalendarIcon className="w-4 h-4" />
|
||||
{dueDate ? dueDate.toLocaleDateString() : 'Due date'}
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0" align="end">
|
||||
<Calendar
|
||||
mode="single"
|
||||
selected={dueDate}
|
||||
onSelect={(date) => {
|
||||
setDueDate(date);
|
||||
setIsCalendarOpen(false);
|
||||
}}
|
||||
disabled={(date) => date < new Date()}
|
||||
initialFocus
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-3 pt-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={handleClose}
|
||||
className="flex-1"
|
||||
data-testid="button-cancel"
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
onClick={handleSave}
|
||||
disabled={!title.trim()}
|
||||
className="flex-1"
|
||||
data-testid="button-save-task"
|
||||
>
|
||||
Create Task
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user