Skip to content

Commit

Permalink
add task scheduling
Browse files Browse the repository at this point in the history
  • Loading branch information
birdup000 committed Dec 17, 2024
1 parent b96d924 commit 73e469d
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 21 deletions.
89 changes: 89 additions & 0 deletions app/components/ScheduledTasks.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import React, { useState } from 'react';
import { Task } from '../types/task';

interface ScheduledTasksProps {
tasks: Task[];
onTaskClick: (task: Task) => void;
onDeleteTask: (task: Task) => void;
}

// Ensure scheduledFor is treated as a Date when it exists
const ensureDateType = (date: Date | undefined): Date | undefined => {
if (!date) return undefined;
return date instanceof Date ? date : new Date(date);
};

const ScheduledTasks: React.FC<ScheduledTasksProps> = ({
tasks,
onTaskClick,
onDeleteTask,
}) => {
const [isOpen, setIsOpen] = useState(true);

const scheduledTasks = tasks.filter(task =>
task.status === 'todo' &&
task.scheduledFor &&
ensureDateType(task.scheduledFor)! > new Date()
);

if (scheduledTasks.length === 0) return null;

return (
<div className="mt-6 border-t border-[#444444] pt-4">
<div
className="flex items-center gap-2 mb-4 cursor-pointer hover:text-gray-300 transition-colors"
onClick={() => setIsOpen(!isOpen)}
>
<svg
xmlns="http://www.w3.org/2000/svg"
className={`h-4 w-4 transform transition-transform ${isOpen ? 'rotate-90' : ''}`}
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M9 5l7 7-7 7"
/>
</svg>
<h3 className="text-md font-medium text-gray-400">Scheduled Tasks</h3>
<span className="text-sm text-gray-500">
({scheduledTasks.length})
</span>
</div>
<div className={`transition-all duration-200 ${isOpen ? 'block' : 'hidden'}`}>
<div className="space-y-2">
{scheduledTasks.map((task) => (
<div
key={task.id}
className="px-4 py-3 bg-[#333333] rounded-lg cursor-pointer hover:bg-[#444444] transition-colors"
onClick={() => onTaskClick(task)}
>
<div className="flex justify-between items-start">
<div>
<h4 className="font-medium">{task.title}</h4>
<div className="text-sm text-gray-400 mt-1">
Scheduled for: {ensureDateType(task.scheduledFor)!.toLocaleString()}
</div>
</div>
<button
onClick={(e) => {
e.stopPropagation();
onDeleteTask(task);
}}
className="text-gray-400 hover:text-white transition-colors"
>
×
</button>
</div>
</div>
))}
</div>
</div>
</div>
);
};

export default ScheduledTasks;
14 changes: 14 additions & 0 deletions app/components/TaskForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const TaskForm: React.FC<TaskFormProps> = ({ onSubmit, onCancel, lists }) => {
const [description, setDescription] = useState('');
const [priority, setPriority] = useState<'low' | 'medium' | 'high'>('medium');
const [dueDate, setDueDate] = useState('');
const [scheduledFor, setScheduledFor] = useState('');
const [assignee, setAssignee] = useState('');
const [assignees, setAssignees] = useState<string[]>([]);
const [tag, setTag] = useState('');
Expand Down Expand Up @@ -50,6 +51,7 @@ const TaskForm: React.FC<TaskFormProps> = ({ onSubmit, onCancel, lists }) => {
priority,
status: 'todo',
dueDate: dueDate ? new Date(dueDate) : undefined,
scheduledFor: scheduledFor ? new Date(scheduledFor) : undefined,
assignees,
tags,
subtasks,
Expand Down Expand Up @@ -173,6 +175,18 @@ const TaskForm: React.FC<TaskFormProps> = ({ onSubmit, onCancel, lists }) => {
className="w-full px-3 py-2 bg-[#333333] rounded-md text-white focus:outline-none focus:ring-2 focus:ring-indigo-500"
/>
</div>

<div>
<label className="block text-sm font-medium text-gray-200 mb-1">
Schedule For
</label>
<input
type="datetime-local"
value={scheduledFor}
onChange={(e) => setScheduledFor(e.target.value)}
className="w-full px-3 py-2 bg-[#333333] rounded-md text-white focus:outline-none focus:ring-2 focus:ring-indigo-500"
/>
</div>
</div>
</fieldset>

Expand Down
50 changes: 29 additions & 21 deletions app/components/TaskList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import React from 'react';
import { Droppable } from '@hello-pangea/dnd';
import { Task } from '../types/task';
import { TaskCard } from './TaskCard';
import ScheduledTasks from './ScheduledTasks';

interface TaskListProps {
droppableId: string;
Expand All @@ -25,26 +26,33 @@ export const TaskList: React.FC<TaskListProps> = ({
listId
}) => {
return (
<Droppable droppableId={droppableId}>
{(provided) => (
<div
ref={provided.innerRef}
{...provided.droppableProps}
className="space-y-4"
>
{tasks.map((task, index) => (
<TaskCard
key={task.id}
task={task}
index={index}
onUpdateTask={onUpdateTask}
onClick={() => onTaskClick(task)}
onDelete={() => onDeleteTask(task)}
/>
))}
{provided.placeholder}
</div>
)}
</Droppable>
<div>
<Droppable droppableId={droppableId}>
{(provided) => (
<div
ref={provided.innerRef}
{...provided.droppableProps}
className="space-y-4"
>
{tasks.map((task, index) => (
<TaskCard
key={task.id}
task={task}
index={index}
onUpdateTask={onUpdateTask}
onClick={() => onTaskClick(task)}
onDelete={() => onDeleteTask(task)}
/>
))}
{provided.placeholder}
</div>
)}
</Droppable>
<ScheduledTasks
tasks={tasks}
onTaskClick={onTaskClick}
onDeleteTask={onDeleteTask}
/>
</div>
);
};
1 change: 1 addition & 0 deletions app/types/task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export interface Task {
priority: 'low' | 'medium' | 'high';
status: 'todo' | 'in-progress' | 'done';
dueDate?: Date;
scheduledFor?: Date;
assignees?: string[];
tags?: string[];
dependsOn?: string[];
Expand Down

0 comments on commit 73e469d

Please sign in to comment.