Feature batch: Projects, Recurrence, Group settings, Bug fixes

- Projects CRUD API + invite members
- Task recurrence (daily/weekly/monthly) with auto-creation
- Group time zones + GPS locations settings
- i18n fallback fix (no more undefined labels)
- UX: action buttons in one row
- Chat/Calendar: relative API URLs
- DB: task_assignments, projects tables, recurrence column

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-29 13:49:25 +00:00
parent fc39029ce3
commit b4b8439f80
14 changed files with 1173 additions and 136 deletions

View File

@@ -204,3 +204,44 @@ export function generateGoalPlan(token: string, id: string) {
export function getGoalReport(token: string, id: string) {
return apiFetch<{ data: GoalReport }>(`/api/v1/goals/${id}/report`, { token });
}
// Projects
export interface Project {
id: string;
owner_id: string | null;
name: string;
description: string;
color: string;
icon: string;
members: string[];
task_count?: number;
done_count?: number;
created_at: string;
updated_at: string;
}
export function getProjects(token: string, userId?: string) {
const qs = userId ? "?user_id=" + userId : "";
return apiFetch<{ data: Project[] }>("/api/v1/projects" + qs, { token });
}
export function getProject(token: string, id: string) {
return apiFetch<{ data: Project }>("/api/v1/projects/" + id, { token });
}
export function createProject(token: string, data: Partial<Project>) {
return apiFetch<{ data: Project }>("/api/v1/projects", { method: "POST", body: data, token });
}
export function updateProject(token: string, id: string, data: Partial<Project>) {
return apiFetch<{ data: Project }>("/api/v1/projects/" + id, { method: "PUT", body: data, token });
}
export function deleteProject(token: string, id: string) {
return apiFetch<void>("/api/v1/projects/" + id, { method: "DELETE", token });
}
export function inviteToProject(token: string, id: string, userId: string) {
return apiFetch<{ data: Project; status: string }>("/api/v1/projects/" + id + "/invite", { method: "POST", body: { user_id: userId }, token });
}