Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update tasks and project view #204

Merged
merged 1 commit into from
Dec 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions client/src/components/Modal Management/Layout/List.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const TaskList = ({
difficulty: 5,
importance: 5,
deadline: null,
collaborative: false,
urgent: false,
experience: 150
});
setQuickTaskInput('');
Expand Down Expand Up @@ -179,7 +179,7 @@ const TaskList = ({
<div className="inline-flex rounded-lg bg-gray-100 dark:bg-gray-700 p-0.5 sm:p-1">
<button
onClick={() => setActiveTab('tasks')}
className={`px-2 sm:px-4 py-1.5 sm:py-2 text-xs sm:text-sm rounded-md transition-all duration-200 ${
className={`px-3 sm:px-4 py-2 sm:py-2 text-sm sm:text-sm rounded-md transition-all duration-200 ${
activeTab === 'tasks'
? 'bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 shadow-sm'
: 'text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-200'
Expand All @@ -189,7 +189,7 @@ const TaskList = ({
</button>
<button
onClick={() => setActiveTab('projects')}
className={`px-2 sm:px-4 py-1.5 sm:py-2 text-xs sm:text-sm rounded-md transition-all duration-200 ${
className={`px-3 sm:px-4 py-2 sm:py-2 text-sm sm:text-sm rounded-md transition-all duration-200 ${
activeTab === 'projects'
? 'bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 shadow-sm'
: 'text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-200'
Expand All @@ -206,7 +206,7 @@ const TaskList = ({
onClick={() =>
setSortMethod(sortMethod === 'date' ? 'label' : 'date')
}
className="px-2 sm:px-4 py-1.5 sm:py-2 text-xs sm:text-sm rounded-md
className="px-3 sm:px-4 py-2 sm:py-2 text-sm sm:text-sm rounded-md
bg-gray-100 dark:bg-gray-700
text-gray-600 dark:text-gray-400
hover:text-gray-900 dark:hover:text-gray-200
Expand All @@ -223,7 +223,7 @@ const TaskList = ({
{/* Calendar/List View Toggle */}
<button
onClick={() => setIsCalendarView(!isCalendarView)}
className="px-2 sm:px-4 py-1.5 sm:py-2 text-xs sm:text-sm rounded-md
className="px-3 sm:px-4 py-2 sm:py-2 text-sm sm:text-sm rounded-md
bg-gray-100 dark:bg-gray-700
text-gray-600 dark:text-gray-400
hover:text-gray-900 dark:hover:text-gray-200
Expand Down
3 changes: 2 additions & 1 deletion client/src/components/Modal Management/Layout/View.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const View = ({ task, removeTask, completeTask, isCompleted, updateTask }) => {
deadline: task.deadline || '',
difficulty: task.difficulty,
importance: task.importance,
collaborative: task.collaborative,
urgent: task.urgent,
label: task.label || ''
});
const [showPomodoro, setShowPomodoro] = useState(false);
Expand Down Expand Up @@ -65,6 +65,7 @@ const View = ({ task, removeTask, completeTask, isCompleted, updateTask }) => {
<button
className="flex-shrink-0 w-8 h-8 flex items-center justify-center"
onClick={() => setShowDetails(!showDetails)}
aria-label="Toggle task details"
>
<svg
className="w-6 h-6 text-gray-400 transition-transform duration-300"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,19 @@ describe('Task Component Overdue Tests', () => {
/>
);

expect(screen.getByText('-10xp')).toBeInTheDocument();
// Click the expand button to show details
const expandButton = screen.getByRole('button', {
name: /toggle task details/i
});
fireEvent.click(expandButton);

// Now look for XP and penalty
expect(screen.getByText((content) => {
return content.includes('100') && content.includes('xp');
})).toBeInTheDocument();
expect(screen.getByText((content) => {
return content.includes('Due:') && content.includes('2024-01-13');
})).toBeInTheDocument();
});
});

Expand All @@ -151,7 +163,7 @@ describe('TaskView Integration Tests', () => {
difficulty: 50,
importance: 50,
experience: 100,
collaborative: false
urgent: false
};

const setup = (props = {}) => {
Expand All @@ -172,10 +184,8 @@ describe('TaskView Integration Tests', () => {
expect(screen.getByText('Test Task')).toBeInTheDocument();
});

test('shows description when details button is clicked', () => {
test('shows description when task has description', () => {
setup();
const detailsButton = screen.getByText('Details');
fireEvent.click(detailsButton);
expect(screen.getByText('Test description')).toBeInTheDocument();
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ const ProjectForm = ({ addTask }) => {
deadline: projectForm.deadline || null,
difficulty: 50,
importance: 50,
collaborative: false,
urgent: false,
experience: totalXP,
subtasks: subTasks
});
Expand Down
150 changes: 104 additions & 46 deletions client/src/components/Modal Management/Projects/ProjectView.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,59 +2,117 @@ import React from 'react';
import { formatDeadline, isOverdue, calculateOverduePenalty } from '../../../utils/tasks/tasksUtils';

const ProjectView = ({ task, isCompleted, handleSubtaskToggle }) => {
const completedSubtasks = task.subtasks.filter(subtask => subtask.completed).length;
const progress = (completedSubtasks / task.subtasks.length) * 100;

return (
<>
<div className="space-y-2">
{task.subtasks.map((subtask, index) => (
<div key={index} className="flex items-center gap-2">
{!isCompleted && (
<div className="relative">
<input
type="checkbox"
className="peer h-4 w-4 appearance-none rounded border border-gray-300
dark:border-gray-600 bg-white dark:bg-gray-700
checked:bg-blue-500 dark:checked:bg-blue-400
focus:outline-none focus:ring-2 focus:ring-blue-500/20
transition-all duration-200"
checked={subtask.completed || false}
onChange={() => handleSubtaskToggle(index)}
/>
<div className="absolute inset-0 pointer-events-none">
<div
className="absolute top-1/2 w-full border-t
border-white dark:border-gray-900
opacity-0 peer-checked:opacity-100
transition-opacity duration-200"
/>
</div>
</div>
)}
<span
className={`${subtask.completed || isCompleted ? 'line-through text-gray-400 dark:text-gray-500' : ''}
transition-all duration-200`}
>
{subtask.name}
<div className="space-y-4">
{/* Progress Bar and Share Button */}
<div className="flex items-center justify-between mb-2">
<div className="flex items-center gap-3">
<span className="text-gray-600 dark:text-gray-400 text-sm">Progress</span>
<div className="flex items-center gap-2">
<div className="w-32 h-2 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden">
<div
className="h-full bg-blue-500 dark:bg-blue-400 rounded-full transition-all duration-300"
style={{ width: `${progress}%` }}
/>
</div>
<span className="text-sm text-gray-600 dark:text-gray-400">
{completedSubtasks}/{task.subtasks.length}
</span>
</div>
))}
</div>
<button
onClick={() => {}} // Placeholder for future implementation
className="text-blue-500 hover:text-blue-600 dark:text-blue-400
dark:hover:text-blue-300 text-sm font-medium"
>
🤝 Share Project
</button>
</div>
{task.deadline && (
<p>Due date: {formatDeadline(task.deadline)}</p>

{/* Description Section */}
{task.desc && (
<div className="bg-gray-50/50 dark:bg-gray-800/30 rounded-lg p-4 mb-4">
<p className="text-sm text-gray-700 dark:text-gray-300 whitespace-pre-wrap leading-relaxed">
{task.desc}
</p>
</div>
)}
<p>
Total Experience: {task.experience}xp
{isCompleted && task.earlyBonus > 0 && (
<span className="text-green-600 dark:text-green-400">
{` + ${task.earlyBonus}xp early bonus!`}
</span>

{/* Subtasks List */}
<div className="border dark:border-gray-700 rounded-lg overflow-hidden">
<div className="divide-y divide-gray-200 dark:divide-gray-700">
{task.subtasks.map((subtask, index) => (
<div
key={index}
className={`p-3 transition-colors ${
subtask.completed
? 'bg-gray-50 dark:bg-gray-800/50'
: 'bg-white dark:bg-gray-800'
}`}
>
<div className="flex items-center gap-3">
{!isCompleted && (
<div className="relative">
<input
type="checkbox"
className="peer h-4 w-4 appearance-none rounded border border-gray-300
dark:border-gray-600 bg-white dark:bg-gray-700
checked:bg-blue-500 dark:checked:bg-blue-400
focus:outline-none focus:ring-2 focus:ring-blue-500/20
transition-all duration-200"
checked={subtask.completed || false}
onChange={() => handleSubtaskToggle(index)}
/>
<div className="absolute inset-0 pointer-events-none">
<div className="absolute top-1/2 w-full border-t border-white dark:border-gray-900
opacity-0 peer-checked:opacity-100 transition-opacity duration-200"/>
</div>
</div>
)}
<span className={`text-sm ${
subtask.completed || isCompleted
? 'text-gray-400 dark:text-gray-500 line-through'
: 'text-gray-900 dark:text-gray-100'
}`}>
{subtask.name}
</span>
</div>
</div>
))}
</div>
</div>

{/* Task Info Footer */}
<div className="flex flex-wrap gap-4 text-sm text-gray-600 dark:text-gray-400 pt-2">
{task.deadline && (
<div className="flex items-center gap-2">
<span>📅</span>
<span>
Due: {formatDeadline(task.deadline)}
{isOverdue(task.deadline) && !isCompleted && (
<span className="text-red-500 ml-1">
({calculateOverduePenalty(task.deadline)}xp)
</span>
)}
</span>
</div>
)}
{task.deadline && isOverdue(task.deadline) && (
<span className="text-red-500">
{` ${calculateOverduePenalty(task.deadline)}xp`}
<div className="flex items-center gap-2">
<span>⭐</span>
<span>
{task.experience}xp
{isCompleted && task.earlyBonus > 0 && (
<span className="text-green-600 dark:text-green-400">
{` + ${task.earlyBonus}xp early bonus!`}
</span>
)}
</span>
)}
</p>
</>
</div>
</div>
</div>
);
};

Expand Down
22 changes: 11 additions & 11 deletions client/src/components/Modal Management/Tasks/TaskForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const TaskForm = ({ addTask }) => {
difficulty: 50,
importance: 50,
deadline: '',
collaborative: false,
urgent: false,
label: ''
};

Expand All @@ -34,12 +34,12 @@ const TaskForm = ({ addTask }) => {
difficulty: formState.difficulty,
importance: formState.importance,
deadline: formState.deadline || null,
collaborative: formState.collaborative,
urgent: formState.urgent,
label: formState.label || null,
experience: calculateBaseXP(
formState.difficulty,
formState.importance,
formState.collaborative
formState.urgent
),
completion: false
};
Expand All @@ -64,8 +64,8 @@ const TaskForm = ({ addTask }) => {
setSelectedDeadline(null);
};

const toggleCollaborative = () => {
updateFormState('collaborative', !formState.collaborative);
const toggleUrgent = () => {
updateFormState('urgent', !formState.urgent);
};

const handleDeadlineClick = (days, buttonType) => {
Expand Down Expand Up @@ -260,19 +260,19 @@ const TaskForm = ({ addTask }) => {
<div className="flex items-center gap-4 pt-2">
<button
type="button"
onClick={toggleCollaborative}
onClick={toggleUrgent}
className={`flex-[1.2] px-3 py-2 rounded-lg border transition-all duration-200
${
formState.collaborative
? 'bg-blue-50 dark:bg-blue-500/10 border-blue-200 dark:border-blue-800'
formState.urgent
? 'bg-red-50 dark:bg-red-500/10 border-red-200 dark:border-red-800'
: 'bg-gray-50 dark:bg-gray-700/50 border-gray-200 dark:border-gray-600'
}`}
>
<div className="text-sm font-medium text-gray-800 dark:text-gray-200">
{formState.collaborative ? '👥 Team Task' : '👤 Solo Task'}
{formState.urgent ? '🚨 Urgent Task' : '⏱️ Regular Task'}
</div>
<div className="text-xs text-gray-500 dark:text-gray-400">
{formState.collaborative ? '+150 XP Bonus' : 'Base XP'}
{formState.urgent ? '+150 XP Bonus' : 'Base XP'}
</div>
</button>

Expand All @@ -284,7 +284,7 @@ const TaskForm = ({ addTask }) => {
{calculateBaseXP(
formState.difficulty,
formState.importance,
formState.collaborative
formState.urgent
)}
</div>
</div>
Expand Down
Loading
Loading