Clean up: Remove src files

This commit is contained in:
Samuel James 2026-09-05 15:28:05 +00:00
parent f6e4b1de7e
commit b32b3eaca1

View File

@ -1,202 +0,0 @@
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import AppShell from './components/common/AppShell';
import TaskForm from './components/TaskForm/TaskForm';
import TaskList, { FilterCounts } from './components/TaskList/TaskList';
import { api } from './services/api';
import { Task, TaskDraft, TaskFilter, TaskStatus, User } from './types';
import './App.css';
interface Notice {
kind: 'info' | 'error';
text: string;
}
const errorText = (error: unknown, fallback: string): string =>
error instanceof Error && error.message ? error.message : fallback;
function App() {
const [tasks, setTasks] = useState<Task[]>([]);
const [users, setUsers] = useState<User[]>([]);
const [currentUser, setCurrentUser] = useState<User | null>(null);
const [filter, setFilter] = useState<TaskFilter>('all');
const [loading, setLoading] = useState(true);
const [loadError, setLoadError] = useState<string | null>(null);
const [formOpen, setFormOpen] = useState(false);
const [editingTask, setEditingTask] = useState<Task | null>(null);
const [pendingTaskId, setPendingTaskId] = useState<number | null>(null);
const [notice, setNotice] = useState<Notice | null>(null);
/** Element that opened the dialog, so focus can go back where the user left it. */
const formTriggerRef = useRef<HTMLElement | null>(null);
const load = useCallback(async (): Promise<void> => {
setLoading(true);
setLoadError(null);
try {
const [me, teamMembers, taskList] = await Promise.all([
api.getCurrentUser(),
api.getUsers(),
api.getTasks(),
]);
setCurrentUser(me);
setUsers(teamMembers);
setTasks(taskList);
} catch (error) {
setLoadError(
errorText(error, 'TaskFlow could not reach the server. Check your connection and retry.')
);
} finally {
setLoading(false);
}
}, []);
useEffect(() => {
load();
}, [load]);
const counts: FilterCounts = useMemo(
() => ({
my: tasks.filter((task) => task.assigned_to?.id === currentUser?.id).length,
all: tasks.length,
blocked: tasks.filter((task) => task.status === 'blocked').length,
}),
[tasks, currentUser]
);
const visibleTasks = useMemo(() => {
if (filter === 'my') {
return tasks.filter((task) => task.assigned_to?.id === currentUser?.id);
}
if (filter === 'blocked') {
return tasks.filter((task) => task.status === 'blocked');
}
return tasks;
}, [tasks, filter, currentUser]);
const openForm = (task: Task | null): void => {
formTriggerRef.current = document.activeElement as HTMLElement | null;
setEditingTask(task);
setNotice(null);
setFormOpen(true);
};
const closeForm = (): void => {
setFormOpen(false);
setEditingTask(null);
formTriggerRef.current?.focus();
};
/** Rejects on failure so TaskForm can keep the user's input on screen. */
const saveTask = async (draft: TaskDraft): Promise<void> => {
if (editingTask) {
const updated = await api.updateTask(editingTask.id, draft);
setTasks((current) => current.map((task) => (task.id === updated.id ? updated : task)));
setNotice({ kind: 'info', text: `"${updated.title}" was updated.` });
} else {
const created = await api.createTask(draft);
setTasks((current) => [created, ...current]);
setNotice({ kind: 'info', text: `"${created.title}" was created.` });
}
closeForm();
};
const changeStatus = async (task: Task, status: TaskStatus): Promise<void> => {
setPendingTaskId(task.id);
setNotice(null);
try {
const updated = await api.updateTask(task.id, { status });
setTasks((current) => current.map((item) => (item.id === updated.id ? updated : item)));
setNotice({ kind: 'info', text: `"${updated.title}" is now ${status.replace('_', ' ')}.` });
} catch (error) {
setNotice({
kind: 'error',
text: errorText(error, `"${task.title}" could not be updated. It is unchanged, so try again.`),
});
} finally {
setPendingTaskId(null);
}
};
const deleteTask = async (task: Task): Promise<void> => {
// eslint-disable-next-line no-restricted-globals
const confirmed = window.confirm(`Delete "${task.title}"? This cannot be undone.`);
if (!confirmed) {
return;
}
setPendingTaskId(task.id);
setNotice(null);
try {
await api.deleteTask(task.id);
setTasks((current) => current.filter((item) => item.id !== task.id));
setNotice({ kind: 'info', text: `"${task.title}" was deleted.` });
} catch (error) {
setNotice({
kind: 'error',
text: errorText(error, `"${task.title}" could not be deleted. Nothing changed, so try again.`),
});
} finally {
setPendingTaskId(null);
}
};
if (loading) {
return (
<div className="app-loading" role="status">
<div className="loading-spinner" aria-hidden="true" />
<p>Loading your team's tasks...</p>
</div>
);
}
if (loadError || !currentUser) {
return (
<div className="app-error" role="alert">
<h1>We could not load your tasks</h1>
<p>{loadError ?? 'Your account details are unavailable right now.'}</p>
<button type="button" className="btn btn-primary retry-button" onClick={load}>
Try again
</button>
</div>
);
}
return (
<AppShell currentUser={currentUser} users={users}>
<div className="app-notice-region" aria-live="polite">
{notice && (
<div className={`app-notice ${notice.kind}`}>
<span>{notice.text}</span>
<button
type="button"
className="notice-dismiss"
onClick={() => setNotice(null)}
aria-label="Dismiss message"
>
<span aria-hidden="true">&#10005;</span>
</button>
</div>
)}
</div>
<TaskList
tasks={visibleTasks}
totalTaskCount={tasks.length}
counts={counts}
currentFilter={filter}
pendingTaskId={pendingTaskId}
onFilterChange={setFilter}
onCreateTask={() => openForm(null)}
onEditTask={openForm}
onDeleteTask={deleteTask}
onStatusChange={changeStatus}
/>
{formOpen && (
<TaskForm users={users} task={editingTask} onCancel={closeForm} onSubmit={saveTask} />
)}
</AppShell>
);
}
export default App;