Clean up: Remove services files

This commit is contained in:
Samuel James 2026-09-05 15:29:04 +00:00
parent 603be6cbd8
commit 4375aedb34

View File

@ -1,259 +0,0 @@
import {
Task,
TaskDraft,
TASK_PRIORITIES,
TASK_STATUSES,
TITLE_MAX_LENGTH,
DESCRIPTION_MAX_LENGTH,
User,
} from '../types';
/**
* In-memory stand-in for the REST API described in
* architect/03-feasibility/frontend-handoff.md. Method names and payload shapes
* match the documented endpoints so the Backend phase can swap the bodies for
* fetch/axios calls without touching any component.
*
* GET /api/auth/me -> getCurrentUser()
* GET /api/users -> getUsers()
* GET /api/tasks -> getTasks()
* POST /api/tasks -> createTask(draft)
* PUT /api/tasks/:id -> updateTask(id, changes)
* DELETE /api/tasks/:id -> deleteTask(id)
*/
/** Error type carrying a message that is safe to show a user. */
export class ApiError extends Error {
status: number;
constructor(message: string, status = 400) {
super(message);
this.name = 'ApiError';
this.status = status;
}
}
const users: User[] = [
{ id: 1, username: 'sarah.chen', full_name: 'Sarah Chen' },
{ id: 2, username: 'alex.rivera', full_name: 'Alex Rivera' },
{ id: 3, username: 'david.kim', full_name: 'David Kim' },
{ id: 4, username: 'maria.garcia', full_name: 'Maria Garcia' },
{ id: 5, username: 'ben.carter', full_name: 'Ben Carter' },
];
/** Signed-in user. Real implementation reads this from GET /api/auth/me. */
const currentUser = users[0];
const isoDate = (dayOffset: number): string => {
const date = new Date();
date.setDate(date.getDate() + dayOffset);
return date.toISOString().slice(0, 10);
};
const timestamp = (dayOffset: number): string => {
const date = new Date();
date.setDate(date.getDate() + dayOffset);
return date.toISOString();
};
let tasks: Task[] = [
{
id: 1,
title: 'Website Redesign - Homepage Layout',
description: 'Finalize wireframes and mobile view',
assigned_to: users[1],
status: 'in_progress',
priority: 'high',
due_date: isoDate(5),
created_by: currentUser,
created_at: timestamp(-9),
updated_at: timestamp(-1),
},
{
id: 2,
title: 'Q4 Marketing Strategy',
description: 'Outline key campaigns and budget',
assigned_to: users[0],
status: 'open',
priority: 'medium',
due_date: isoDate(10),
created_by: users[2],
created_at: timestamp(-7),
updated_at: timestamp(-7),
},
{
id: 3,
title: 'API Integration Debugging',
description: 'Fixing errors in payment gateway',
assigned_to: users[2],
status: 'blocked',
priority: 'high',
due_date: isoDate(8),
created_by: currentUser,
created_at: timestamp(-6),
updated_at: timestamp(-2),
},
{
id: 4,
title: 'Partner Onboarding Playbook',
description: 'Document the hand-off steps for new partners',
assigned_to: users[2],
status: 'in_progress',
priority: 'high',
due_date: isoDate(-2),
created_by: users[3],
created_at: timestamp(-14),
updated_at: timestamp(-3),
},
{
id: 5,
title: 'API Integration Review',
description: 'Second pass over the payment gateway contract',
assigned_to: users[0],
status: 'open',
priority: 'low',
due_date: isoDate(6),
created_by: users[1],
created_at: timestamp(-4),
updated_at: timestamp(-4),
},
{
id: 6,
title: 'Mobile Nav Accessibility Audit',
description: 'Keyboard and screen reader pass on the mobile navigation',
assigned_to: users[3],
status: 'blocked',
priority: 'medium',
due_date: isoDate(12),
created_by: currentUser,
created_at: timestamp(-3),
updated_at: timestamp(-1),
},
];
const delay = (ms: number): Promise<void> =>
new Promise((resolve) => setTimeout(resolve, ms));
const clone = (task: Task): Task => ({ ...task });
const nextId = (): number =>
tasks.reduce((highest, task) => Math.max(highest, task.id), 0) + 1;
/**
* Validates a draft before it reaches the store. The UI validates too, but this
* is the trust boundary the real API will guard, so the rules live here as well.
*/
const validateDraft = (draft: Partial<TaskDraft>, requireAll: boolean): void => {
if (requireAll || draft.title !== undefined) {
const title = (draft.title ?? '').trim();
if (!title) {
throw new ApiError('A task title is required.');
}
if (title.length > TITLE_MAX_LENGTH) {
throw new ApiError(`Keep the title under ${TITLE_MAX_LENGTH} characters.`);
}
}
if (draft.description !== undefined && draft.description.length > DESCRIPTION_MAX_LENGTH) {
throw new ApiError(`Keep the description under ${DESCRIPTION_MAX_LENGTH} characters.`);
}
if (requireAll || draft.assignee_id !== undefined) {
const assignee = users.find((user) => user.id === draft.assignee_id);
if (!assignee) {
throw new ApiError('Assign this task to a current team member.');
}
}
if (draft.status !== undefined && !TASK_STATUSES.includes(draft.status)) {
throw new ApiError('Choose a valid status.');
}
if (draft.priority !== undefined && !TASK_PRIORITIES.includes(draft.priority)) {
throw new ApiError('Choose a valid priority.');
}
if (draft.due_date) {
if (Number.isNaN(Date.parse(draft.due_date))) {
throw new ApiError('Enter a due date in YYYY-MM-DD format.');
}
}
};
export const api = {
async getCurrentUser(): Promise<User> {
await delay(150);
return { ...currentUser };
},
async getUsers(): Promise<User[]> {
await delay(200);
return users.map((user) => ({ ...user }));
},
async getTasks(): Promise<Task[]> {
await delay(400);
return tasks.map(clone);
},
async createTask(draft: TaskDraft): Promise<Task> {
await delay(350);
validateDraft(draft, true);
const now = new Date().toISOString();
const task: Task = {
id: nextId(),
title: draft.title.trim(),
description: draft.description.trim(),
assigned_to: users.find((user) => user.id === draft.assignee_id),
status: draft.status,
priority: draft.priority,
due_date: draft.due_date || undefined,
created_by: { ...currentUser },
created_at: now,
updated_at: now,
};
tasks = [task, ...tasks];
return clone(task);
},
async updateTask(id: number, changes: Partial<TaskDraft>): Promise<Task> {
await delay(300);
const existing = tasks.find((task) => task.id === id);
if (!existing) {
throw new ApiError('That task no longer exists. Refresh to see the latest list.', 404);
}
validateDraft(changes, false);
const updated: Task = {
...existing,
title: changes.title !== undefined ? changes.title.trim() : existing.title,
description:
changes.description !== undefined ? changes.description.trim() : existing.description,
assigned_to:
changes.assignee_id !== undefined
? users.find((user) => user.id === changes.assignee_id)
: existing.assigned_to,
status: changes.status ?? existing.status,
priority: changes.priority ?? existing.priority,
due_date: changes.due_date !== undefined ? changes.due_date || undefined : existing.due_date,
updated_at: new Date().toISOString(),
};
tasks = tasks.map((task) => (task.id === id ? updated : task));
return clone(updated);
},
async deleteTask(id: number): Promise<void> {
await delay(250);
const exists = tasks.some((task) => task.id === id);
if (!exists) {
throw new ApiError('That task no longer exists. Refresh to see the latest list.', 404);
}
tasks = tasks.filter((task) => task.id !== id);
},
};
export type Api = typeof api;