- Complete React + TypeScript application with Vite - Dashboard with charts and metrics visualization - Kanban board with drag-and-drop functionality - Product backlog management with user stories - Sprint planning and tracking features - Comprehensive UI component library (shadcn/ui) - Tailwind CSS styling with dark mode support - Context-based state management - Mock data for immediate testing and demonstration
251 lines
6.6 KiB
TypeScript
251 lines
6.6 KiB
TypeScript
import React, { createContext, useContext, useState, ReactNode } from 'react';
|
|
import { Task, UserStory, Sprint } from '../types';
|
|
|
|
interface AppContextType {
|
|
tasks: Task[];
|
|
userStories: UserStory[];
|
|
sprints: Sprint[];
|
|
activeSprint: Sprint | null;
|
|
addTask: (task: Omit<Task, 'id' | 'createdAt' | 'updatedAt' | 'comments'>) => void;
|
|
updateTask: (id: string, updates: Partial<Task>) => void;
|
|
deleteTask: (id: string) => void;
|
|
addComment: (taskId: string, comment: string, author: string) => void;
|
|
addUserStory: (story: Omit<UserStory, 'id'>) => void;
|
|
updateUserStory: (id: string, updates: Partial<UserStory>) => void;
|
|
reorderUserStories: (stories: UserStory[]) => void;
|
|
addSprint: (sprint: Omit<Sprint, 'id'>) => void;
|
|
updateSprint: (id: string, updates: Partial<Sprint>) => void;
|
|
closeSprint: (id: string) => void;
|
|
setActiveSprint: (sprint: Sprint) => void;
|
|
}
|
|
|
|
const AppContext = createContext<AppContextType | undefined>(undefined);
|
|
|
|
export const useApp = () => {
|
|
const context = useContext(AppContext);
|
|
if (!context) {
|
|
throw new Error('useApp must be used within AppProvider');
|
|
}
|
|
return context;
|
|
};
|
|
|
|
const mockUserStories: UserStory[] = [
|
|
{
|
|
id: 'us-1',
|
|
title: 'User Authentication',
|
|
description: 'As a user, I want to log in securely',
|
|
storyPoints: 5,
|
|
businessValue: 8,
|
|
acceptanceCriteria: 'User can login with email and password',
|
|
status: 'in-sprint',
|
|
priority: 1,
|
|
sprintId: 'sprint-1'
|
|
},
|
|
{
|
|
id: 'us-2',
|
|
title: 'Dashboard View',
|
|
description: 'As a user, I want to see my dashboard',
|
|
storyPoints: 8,
|
|
businessValue: 9,
|
|
acceptanceCriteria: 'Dashboard shows key metrics and recent activity',
|
|
status: 'in-sprint',
|
|
priority: 2,
|
|
sprintId: 'sprint-1'
|
|
},
|
|
{
|
|
id: 'us-3',
|
|
title: 'Data Export',
|
|
description: 'As a user, I want to export my data',
|
|
storyPoints: 3,
|
|
businessValue: 5,
|
|
acceptanceCriteria: 'User can export data in CSV format',
|
|
status: 'sprint-ready',
|
|
priority: 3
|
|
}
|
|
];
|
|
|
|
const mockSprint: Sprint = {
|
|
id: 'sprint-1',
|
|
name: 'Sprint 1',
|
|
goal: 'Deliver core authentication and dashboard features',
|
|
startDate: new Date('2025-10-13'),
|
|
endDate: new Date('2025-10-27'),
|
|
capacity: 40,
|
|
status: 'active',
|
|
userStories: ['us-1', 'us-2']
|
|
};
|
|
|
|
const mockTasks: Task[] = [
|
|
{
|
|
id: 'task-1',
|
|
title: 'Design login form',
|
|
description: 'Create mockups for the login interface',
|
|
timeComplexity: '4 hours',
|
|
status: 'done',
|
|
userStoryId: 'us-1',
|
|
comments: [
|
|
{
|
|
id: 'c-1',
|
|
text: 'Mockups look great!',
|
|
author: 'Jane Smith',
|
|
timestamp: new Date('2025-10-14')
|
|
}
|
|
],
|
|
createdAt: new Date('2025-10-13'),
|
|
updatedAt: new Date('2025-10-14')
|
|
},
|
|
{
|
|
id: 'task-2',
|
|
title: 'Implement authentication API',
|
|
description: 'Set up backend authentication endpoints',
|
|
timeComplexity: '8 hours',
|
|
status: 'in-progress',
|
|
userStoryId: 'us-1',
|
|
comments: [],
|
|
createdAt: new Date('2025-10-13'),
|
|
updatedAt: new Date('2025-10-15')
|
|
},
|
|
{
|
|
id: 'task-3',
|
|
title: 'Create dashboard layout',
|
|
description: 'Build responsive dashboard layout',
|
|
timeComplexity: '6 hours',
|
|
status: 'todo',
|
|
userStoryId: 'us-2',
|
|
comments: [],
|
|
createdAt: new Date('2025-10-13'),
|
|
updatedAt: new Date('2025-10-13')
|
|
}
|
|
];
|
|
|
|
export const AppProvider = ({ children }: { children: ReactNode }) => {
|
|
const [tasks, setTasks] = useState<Task[]>(mockTasks);
|
|
const [userStories, setUserStories] = useState<UserStory[]>(mockUserStories);
|
|
const [sprints, setSprints] = useState<Sprint[]>([mockSprint]);
|
|
const [activeSprint, setActiveSprintState] = useState<Sprint | null>(mockSprint);
|
|
|
|
const addTask = (taskData: Omit<Task, 'id' | 'createdAt' | 'updatedAt' | 'comments'>) => {
|
|
const newTask: Task = {
|
|
...taskData,
|
|
id: `task-${Date.now()}`,
|
|
comments: [],
|
|
createdAt: new Date(),
|
|
updatedAt: new Date()
|
|
};
|
|
setTasks([...tasks, newTask]);
|
|
};
|
|
|
|
const updateTask = (id: string, updates: Partial<Task>) => {
|
|
setTasks(tasks.map(task =>
|
|
task.id === id ? { ...task, ...updates, updatedAt: new Date() } : task
|
|
));
|
|
};
|
|
|
|
const deleteTask = (id: string) => {
|
|
setTasks(tasks.filter(task => task.id !== id));
|
|
};
|
|
|
|
const addComment = (taskId: string, text: string, author: string) => {
|
|
setTasks(tasks.map(task => {
|
|
if (task.id === taskId) {
|
|
return {
|
|
...task,
|
|
comments: [
|
|
...task.comments,
|
|
{
|
|
id: `c-${Date.now()}`,
|
|
text,
|
|
author,
|
|
timestamp: new Date()
|
|
}
|
|
],
|
|
updatedAt: new Date()
|
|
};
|
|
}
|
|
return task;
|
|
}));
|
|
};
|
|
|
|
const addUserStory = (storyData: Omit<UserStory, 'id'>) => {
|
|
const newStory: UserStory = {
|
|
...storyData,
|
|
id: `us-${Date.now()}`
|
|
};
|
|
setUserStories([...userStories, newStory]);
|
|
};
|
|
|
|
const updateUserStory = (id: string, updates: Partial<UserStory>) => {
|
|
setUserStories(userStories.map(story =>
|
|
story.id === id ? { ...story, ...updates } : story
|
|
));
|
|
};
|
|
|
|
const reorderUserStories = (stories: UserStory[]) => {
|
|
setUserStories(stories);
|
|
};
|
|
|
|
const addSprint = (sprintData: Omit<Sprint, 'id'>) => {
|
|
const newSprint: Sprint = {
|
|
...sprintData,
|
|
id: `sprint-${Date.now()}`
|
|
};
|
|
setSprints([...sprints, newSprint]);
|
|
};
|
|
|
|
const updateSprint = (id: string, updates: Partial<Sprint>) => {
|
|
setSprints(sprints.map(sprint =>
|
|
sprint.id === id ? { ...sprint, ...updates } : sprint
|
|
));
|
|
if (activeSprint?.id === id) {
|
|
setActiveSprintState(prev => prev ? { ...prev, ...updates } : null);
|
|
}
|
|
};
|
|
|
|
const closeSprint = (id: string) => {
|
|
// Move unfinished items back to backlog
|
|
const sprint = sprints.find(s => s.id === id);
|
|
if (sprint) {
|
|
setUserStories(userStories.map(story => {
|
|
if (story.sprintId === id) {
|
|
return { ...story, status: 'backlog', sprintId: undefined };
|
|
}
|
|
return story;
|
|
}));
|
|
|
|
setSprints(sprints.map(s =>
|
|
s.id === id ? { ...s, status: 'closed' as const } : s
|
|
));
|
|
|
|
if (activeSprint?.id === id) {
|
|
setActiveSprintState(null);
|
|
}
|
|
}
|
|
};
|
|
|
|
const setActiveSprint = (sprint: Sprint) => {
|
|
setActiveSprintState(sprint);
|
|
};
|
|
|
|
return (
|
|
<AppContext.Provider value={{
|
|
tasks,
|
|
userStories,
|
|
sprints,
|
|
activeSprint,
|
|
addTask,
|
|
updateTask,
|
|
deleteTask,
|
|
addComment,
|
|
addUserStory,
|
|
updateUserStory,
|
|
reorderUserStories,
|
|
addSprint,
|
|
updateSprint,
|
|
closeSprint,
|
|
setActiveSprint
|
|
}}>
|
|
{children}
|
|
</AppContext.Provider>
|
|
);
|
|
};
|