feat: Phase 4-5 — demo mode, polish, deploy, and bug fixes
Add demo mode with mock data provider, Docker deployment, Playwright tests, PostHog analytics, error boundaries, and SEO metadata. Fix residences API response unwrapping, kanban drag-and-drop with optimistic updates, trailing slash proxy redirects, and column name mismatches with Go API. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+26
-14
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import * as tasksApi from '@/lib/api/tasks';
|
||||
import { useDataProvider } from '@/lib/demo/data-provider-context';
|
||||
import type { CreateTaskRequest, UpdateTaskRequest, CreateCompletionRequest } from '@/lib/api/tasks';
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -9,40 +9,45 @@ import type { CreateTaskRequest, UpdateTaskRequest, CreateCompletionRequest } fr
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export function useTasks() {
|
||||
const { tasks } = useDataProvider();
|
||||
return useQuery({
|
||||
queryKey: ['tasks'],
|
||||
queryFn: () => tasksApi.listTasks(),
|
||||
queryFn: () => tasks.list(),
|
||||
});
|
||||
}
|
||||
|
||||
export function useTasksByResidence(residenceId: number) {
|
||||
const { tasks } = useDataProvider();
|
||||
return useQuery({
|
||||
queryKey: ['tasks', 'by-residence', residenceId],
|
||||
queryFn: () => tasksApi.getTasksByResidence(residenceId),
|
||||
queryFn: () => tasks.getByResidence(residenceId),
|
||||
enabled: !!residenceId,
|
||||
});
|
||||
}
|
||||
|
||||
export function useTask(id: number) {
|
||||
const { tasks } = useDataProvider();
|
||||
return useQuery({
|
||||
queryKey: ['tasks', id],
|
||||
queryFn: () => tasksApi.getTask(id),
|
||||
queryFn: () => tasks.get(id),
|
||||
enabled: !!id,
|
||||
});
|
||||
}
|
||||
|
||||
export function useKanbanBoard(residenceId: number) {
|
||||
const { tasks } = useDataProvider();
|
||||
return useQuery({
|
||||
queryKey: ['tasks', 'kanban', residenceId],
|
||||
queryFn: () => tasksApi.getTasksByResidence(residenceId),
|
||||
queryFn: () => tasks.getByResidence(residenceId),
|
||||
enabled: !!residenceId,
|
||||
});
|
||||
}
|
||||
|
||||
export function useTaskCompletions(taskId: number) {
|
||||
const { tasks } = useDataProvider();
|
||||
return useQuery({
|
||||
queryKey: ['tasks', taskId, 'completions'],
|
||||
queryFn: () => tasksApi.getTaskCompletions(taskId),
|
||||
queryFn: () => tasks.getCompletions(taskId),
|
||||
enabled: !!taskId,
|
||||
});
|
||||
}
|
||||
@@ -53,8 +58,9 @@ export function useTaskCompletions(taskId: number) {
|
||||
|
||||
export function useCreateTask() {
|
||||
const queryClient = useQueryClient();
|
||||
const { tasks } = useDataProvider();
|
||||
return useMutation({
|
||||
mutationFn: (data: CreateTaskRequest) => tasksApi.createTask(data),
|
||||
mutationFn: (data: CreateTaskRequest) => tasks.create(data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['tasks'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['residences'] });
|
||||
@@ -64,8 +70,9 @@ export function useCreateTask() {
|
||||
|
||||
export function useUpdateTask(id: number) {
|
||||
const queryClient = useQueryClient();
|
||||
const { tasks } = useDataProvider();
|
||||
return useMutation({
|
||||
mutationFn: (data: UpdateTaskRequest) => tasksApi.updateTask(id, data),
|
||||
mutationFn: (data: UpdateTaskRequest) => tasks.update(id, data),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['tasks'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['tasks', id] });
|
||||
@@ -76,8 +83,9 @@ export function useUpdateTask(id: number) {
|
||||
|
||||
export function useDeleteTask() {
|
||||
const queryClient = useQueryClient();
|
||||
const { tasks } = useDataProvider();
|
||||
return useMutation({
|
||||
mutationFn: (id: number) => tasksApi.deleteTask(id),
|
||||
mutationFn: (id: number) => tasks.delete(id),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['tasks'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['residences'] });
|
||||
@@ -87,8 +95,9 @@ export function useDeleteTask() {
|
||||
|
||||
export function useMarkInProgress() {
|
||||
const queryClient = useQueryClient();
|
||||
const { tasks } = useDataProvider();
|
||||
return useMutation({
|
||||
mutationFn: (id: number) => tasksApi.markInProgress(id),
|
||||
mutationFn: (id: number) => tasks.markInProgress(id),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['tasks'] });
|
||||
},
|
||||
@@ -97,8 +106,9 @@ export function useMarkInProgress() {
|
||||
|
||||
export function useCancelTask() {
|
||||
const queryClient = useQueryClient();
|
||||
const { tasks } = useDataProvider();
|
||||
return useMutation({
|
||||
mutationFn: (id: number) => tasksApi.cancelTask(id),
|
||||
mutationFn: (id: number) => tasks.cancel(id),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['tasks'] });
|
||||
},
|
||||
@@ -107,8 +117,9 @@ export function useCancelTask() {
|
||||
|
||||
export function useArchiveTask() {
|
||||
const queryClient = useQueryClient();
|
||||
const { tasks } = useDataProvider();
|
||||
return useMutation({
|
||||
mutationFn: (id: number) => tasksApi.archiveTask(id),
|
||||
mutationFn: (id: number) => tasks.archive(id),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['tasks'] });
|
||||
},
|
||||
@@ -117,6 +128,7 @@ export function useArchiveTask() {
|
||||
|
||||
export function useCreateCompletion() {
|
||||
const queryClient = useQueryClient();
|
||||
const { tasks } = useDataProvider();
|
||||
return useMutation({
|
||||
mutationFn: ({
|
||||
data,
|
||||
@@ -126,7 +138,7 @@ export function useCreateCompletion() {
|
||||
images: File[];
|
||||
}) => {
|
||||
if (images.length > 0) {
|
||||
return tasksApi.createCompletionWithImages(
|
||||
return tasks.createCompletionWithImages(
|
||||
{
|
||||
task_id: data.task_id,
|
||||
notes: data.notes,
|
||||
@@ -136,7 +148,7 @@ export function useCreateCompletion() {
|
||||
images,
|
||||
);
|
||||
}
|
||||
return tasksApi.createCompletion(data);
|
||||
return tasks.createCompletion(data);
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['tasks'] });
|
||||
|
||||
Reference in New Issue
Block a user