771 lines
27 KiB
TypeScript
771 lines
27 KiB
TypeScript
import { create } from 'zustand';
|
|
import { Project } from '../entities/Project';
|
|
import { Area } from '../entities/Area';
|
|
import { Note } from '../entities/Note';
|
|
import { Task } from '../entities/Task';
|
|
import { Tag } from '../entities/Tag';
|
|
import { InboxItem } from '../entities/InboxItem';
|
|
|
|
interface NotesStore {
|
|
notes: Note[];
|
|
isLoading: boolean;
|
|
isError: boolean;
|
|
hasLoaded: boolean;
|
|
setNotes: (notes: Note[]) => void;
|
|
setLoading: (isLoading: boolean) => void;
|
|
setError: (isError: boolean) => void;
|
|
loadNotes: () => Promise<void>;
|
|
}
|
|
|
|
interface AreasStore {
|
|
areas: Area[];
|
|
isLoading: boolean;
|
|
isError: boolean;
|
|
hasLoaded: boolean;
|
|
setAreas: (areas: Area[]) => void;
|
|
setLoading: (isLoading: boolean) => void;
|
|
setError: (isError: boolean) => void;
|
|
loadAreas: () => Promise<void>;
|
|
}
|
|
|
|
interface ProjectsStore {
|
|
projects: Project[];
|
|
currentProject: Project | null;
|
|
isLoading: boolean;
|
|
isError: boolean;
|
|
setProjects: (projects: Project[]) => void;
|
|
setCurrentProject: (project: Project | null) => void;
|
|
setLoading: (isLoading: boolean) => void;
|
|
setError: (isError: boolean) => void;
|
|
}
|
|
|
|
interface TagsStore {
|
|
tags: Tag[];
|
|
isLoading: boolean;
|
|
isError: boolean;
|
|
hasLoaded: boolean;
|
|
setTags: (tags: Tag[]) => void;
|
|
setLoading: (isLoading: boolean) => void;
|
|
setError: (isError: boolean) => void;
|
|
loadTags: (forceReload?: boolean) => Promise<void>;
|
|
getTags: () => Tag[];
|
|
refreshTags: () => Promise<void>;
|
|
addNewTags: (newTagNames: string[]) => void;
|
|
}
|
|
|
|
interface TasksStore {
|
|
tasks: Task[];
|
|
isLoading: boolean;
|
|
isError: boolean;
|
|
setTasks: (tasks: Task[]) => void;
|
|
setLoading: (isLoading: boolean) => void;
|
|
setError: (isError: boolean) => void;
|
|
loadTasks: (query?: string) => Promise<void>;
|
|
createTask: (taskData: Task) => Promise<Task>;
|
|
updateTask: (taskUid: string, taskData: Task) => Promise<Task>;
|
|
deleteTask: (taskUid: string) => Promise<void>;
|
|
toggleTaskCompletion: (taskUid: string) => Promise<Task>;
|
|
loadTaskById: (taskId: number) => Promise<Task>;
|
|
loadTaskByUid: (uid: string) => Promise<Task>;
|
|
loadSubtasks: (parentTaskUid: string) => Promise<Task[]>;
|
|
addTask: (task: Task) => void;
|
|
removeTask: (taskId: number) => void;
|
|
updateTaskInStore: (updatedTask: Task) => void;
|
|
}
|
|
|
|
interface InboxStore {
|
|
inboxItems: InboxItem[];
|
|
isLoading: boolean;
|
|
isError: boolean;
|
|
pagination: {
|
|
total: number;
|
|
limit: number;
|
|
offset: number;
|
|
hasMore: boolean;
|
|
};
|
|
setInboxItems: (inboxItems: InboxItem[]) => void;
|
|
appendInboxItems: (inboxItems: InboxItem[]) => void;
|
|
setPagination: (pagination: {
|
|
total: number;
|
|
limit: number;
|
|
offset: number;
|
|
hasMore: boolean;
|
|
}) => void;
|
|
addInboxItem: (inboxItem: InboxItem) => void;
|
|
updateInboxItem: (inboxItem: InboxItem) => void;
|
|
removeInboxItem: (id: number) => void;
|
|
removeInboxItemByUid: (uid: string) => void;
|
|
setLoading: (isLoading: boolean) => void;
|
|
setError: (isError: boolean) => void;
|
|
resetPagination: () => void;
|
|
}
|
|
|
|
interface HabitsStore {
|
|
habits: Task[];
|
|
isLoading: boolean;
|
|
isError: boolean;
|
|
setHabits: (habits: Task[]) => void;
|
|
setLoading: (isLoading: boolean) => void;
|
|
setError: (isError: boolean) => void;
|
|
loadHabits: () => Promise<void>;
|
|
logCompletion: (habitUid: string, completedAt?: Date) => Promise<void>;
|
|
removeTodayCompletion: (habitUid: string) => Promise<void>;
|
|
}
|
|
|
|
interface StoreState {
|
|
notesStore: NotesStore;
|
|
areasStore: AreasStore;
|
|
projectsStore: ProjectsStore;
|
|
tagsStore: TagsStore;
|
|
tasksStore: TasksStore;
|
|
inboxStore: InboxStore;
|
|
habitsStore: HabitsStore;
|
|
}
|
|
|
|
export const useStore = create<StoreState>((set: any) => ({
|
|
notesStore: {
|
|
notes: [],
|
|
isLoading: false,
|
|
isError: false,
|
|
hasLoaded: false,
|
|
setNotes: (notes) =>
|
|
set((state) => ({ notesStore: { ...state.notesStore, notes } })),
|
|
setLoading: (isLoading) =>
|
|
set((state) => ({
|
|
notesStore: { ...state.notesStore, isLoading },
|
|
})),
|
|
setError: (isError) =>
|
|
set((state) => ({ notesStore: { ...state.notesStore, isError } })),
|
|
loadNotes: async () => {
|
|
const state = useStore.getState();
|
|
if (state.notesStore.isLoading) return;
|
|
|
|
const { fetchNotes } = await import('../utils/notesService');
|
|
|
|
set((state) => ({
|
|
notesStore: {
|
|
...state.notesStore,
|
|
isLoading: true,
|
|
isError: false,
|
|
},
|
|
}));
|
|
|
|
try {
|
|
const notes = await fetchNotes();
|
|
set((state) => ({
|
|
notesStore: {
|
|
...state.notesStore,
|
|
notes,
|
|
isLoading: false,
|
|
hasLoaded: true,
|
|
},
|
|
}));
|
|
} catch (error) {
|
|
console.error('loadNotes: Failed to load notes:', error);
|
|
set((state) => ({
|
|
notesStore: {
|
|
...state.notesStore,
|
|
isError: true,
|
|
isLoading: false,
|
|
hasLoaded: true,
|
|
},
|
|
}));
|
|
}
|
|
},
|
|
},
|
|
areasStore: {
|
|
areas: [],
|
|
isLoading: false,
|
|
isError: false,
|
|
hasLoaded: false,
|
|
setAreas: (areas) =>
|
|
set((state) => ({ areasStore: { ...state.areasStore, areas } })),
|
|
setLoading: (isLoading) =>
|
|
set((state) => ({
|
|
areasStore: { ...state.areasStore, isLoading },
|
|
})),
|
|
setError: (isError) =>
|
|
set((state) => ({ areasStore: { ...state.areasStore, isError } })),
|
|
loadAreas: async () => {
|
|
const state = useStore.getState();
|
|
if (state.areasStore.isLoading) return;
|
|
|
|
const { fetchAreas } = await import('../utils/areasService');
|
|
|
|
set((state) => ({
|
|
areasStore: {
|
|
...state.areasStore,
|
|
isLoading: true,
|
|
isError: false,
|
|
},
|
|
}));
|
|
|
|
try {
|
|
const areas = await fetchAreas();
|
|
set((state) => ({
|
|
areasStore: {
|
|
...state.areasStore,
|
|
areas,
|
|
isLoading: false,
|
|
hasLoaded: true,
|
|
},
|
|
}));
|
|
} catch (error) {
|
|
console.error('loadAreas: Failed to load areas:', error);
|
|
set((state) => ({
|
|
areasStore: {
|
|
...state.areasStore,
|
|
isError: true,
|
|
isLoading: false,
|
|
hasLoaded: true,
|
|
},
|
|
}));
|
|
}
|
|
},
|
|
},
|
|
projectsStore: {
|
|
projects: [],
|
|
currentProject: null,
|
|
isLoading: false,
|
|
isError: false,
|
|
setProjects: (projects) =>
|
|
set((state) => ({
|
|
projectsStore: { ...state.projectsStore, projects },
|
|
})),
|
|
setCurrentProject: (currentProject) =>
|
|
set((state) => ({
|
|
projectsStore: { ...state.projectsStore, currentProject },
|
|
})),
|
|
setLoading: (isLoading) =>
|
|
set((state) => ({
|
|
projectsStore: { ...state.projectsStore, isLoading },
|
|
})),
|
|
setError: (isError) =>
|
|
set((state) => ({
|
|
projectsStore: { ...state.projectsStore, isError },
|
|
})),
|
|
},
|
|
tagsStore: {
|
|
tags: [],
|
|
isLoading: false,
|
|
isError: false,
|
|
hasLoaded: false,
|
|
setTags: (tags) =>
|
|
set((state) => ({ tagsStore: { ...state.tagsStore, tags } })),
|
|
setLoading: (isLoading) =>
|
|
set((state) => ({ tagsStore: { ...state.tagsStore, isLoading } })),
|
|
setError: (isError) =>
|
|
set((state) => ({ tagsStore: { ...state.tagsStore, isError } })),
|
|
loadTags: async (forceReload = false) => {
|
|
const state = useStore.getState();
|
|
if (state.tagsStore.isLoading) return;
|
|
|
|
// Skip loading if already loaded and not forcing reload
|
|
if (state.tagsStore.hasLoaded && !forceReload) return;
|
|
|
|
const { fetchTags } = await import('../utils/tagsService');
|
|
|
|
set((state) => ({
|
|
tagsStore: {
|
|
...state.tagsStore,
|
|
isLoading: true,
|
|
isError: false,
|
|
},
|
|
}));
|
|
|
|
try {
|
|
const tags = await fetchTags();
|
|
set((state) => ({
|
|
tagsStore: {
|
|
...state.tagsStore,
|
|
tags,
|
|
isLoading: false,
|
|
hasLoaded: true,
|
|
},
|
|
}));
|
|
} catch (error) {
|
|
console.error('loadTags: Failed to load tags:', error);
|
|
set((state) => ({
|
|
tagsStore: {
|
|
...state.tagsStore,
|
|
isError: true,
|
|
isLoading: false,
|
|
hasLoaded: true,
|
|
},
|
|
}));
|
|
}
|
|
},
|
|
getTags: (): Tag[] => {
|
|
const state: StoreState = useStore.getState();
|
|
// Auto-load tags if not loaded yet
|
|
if (!state.tagsStore.hasLoaded && !state.tagsStore.isLoading) {
|
|
state.tagsStore.loadTags();
|
|
}
|
|
return state.tagsStore.tags;
|
|
},
|
|
refreshTags: async () => {
|
|
const state = useStore.getState();
|
|
return state.tagsStore.loadTags(true);
|
|
},
|
|
addNewTags: (newTagNames: string[]) => {
|
|
const state = useStore.getState();
|
|
const existingTagNames = state.tagsStore.tags.map(
|
|
(tag: Tag) => tag.name
|
|
);
|
|
const tagsToAdd = newTagNames
|
|
.filter((name) => !existingTagNames.includes(name))
|
|
.map((name) => ({ name, id: Date.now() + Math.random() })); // Temporary ID
|
|
|
|
if (tagsToAdd.length > 0) {
|
|
set((state) => ({
|
|
tagsStore: {
|
|
...state.tagsStore,
|
|
tags: [...state.tagsStore.tags, ...tagsToAdd],
|
|
},
|
|
}));
|
|
}
|
|
},
|
|
},
|
|
tasksStore: {
|
|
tasks: [],
|
|
isLoading: false,
|
|
isError: false,
|
|
setTasks: (tasks) =>
|
|
set((state) => ({ tasksStore: { ...state.tasksStore, tasks } })),
|
|
setLoading: (isLoading) =>
|
|
set((state) => ({
|
|
tasksStore: { ...state.tasksStore, isLoading },
|
|
})),
|
|
setError: (isError) =>
|
|
set((state) => ({ tasksStore: { ...state.tasksStore, isError } })),
|
|
loadTasks: async (query = '') => {
|
|
const { fetchTasks } = await import('../utils/tasksService');
|
|
set((state) => ({
|
|
tasksStore: {
|
|
...state.tasksStore,
|
|
isLoading: true,
|
|
isError: false,
|
|
},
|
|
}));
|
|
try {
|
|
const { tasks } = await fetchTasks(query);
|
|
set((state) => ({
|
|
tasksStore: {
|
|
...state.tasksStore,
|
|
tasks,
|
|
isLoading: false,
|
|
},
|
|
}));
|
|
} catch (error) {
|
|
console.error('loadTasks: Failed to load tasks:', error);
|
|
set((state) => ({
|
|
tasksStore: {
|
|
...state.tasksStore,
|
|
isError: true,
|
|
isLoading: false,
|
|
},
|
|
}));
|
|
}
|
|
},
|
|
createTask: async (taskData) => {
|
|
const { createTask } = await import('../utils/tasksService');
|
|
try {
|
|
const newTask = await createTask(taskData);
|
|
set((state) => ({
|
|
tasksStore: {
|
|
...state.tasksStore,
|
|
tasks: [newTask, ...state.tasksStore.tasks],
|
|
},
|
|
}));
|
|
return newTask;
|
|
} catch (error) {
|
|
console.error('createTask: Failed to create task:', error);
|
|
set((state) => ({
|
|
tasksStore: { ...state.tasksStore, isError: true },
|
|
}));
|
|
throw error;
|
|
}
|
|
},
|
|
updateTask: async (taskUid, taskData) => {
|
|
const { updateTask } = await import('../utils/tasksService');
|
|
try {
|
|
const updatedTask = await updateTask(taskUid, taskData);
|
|
set((state) => ({
|
|
tasksStore: {
|
|
...state.tasksStore,
|
|
tasks: state.tasksStore.tasks.map((task) =>
|
|
task.uid === taskUid ? updatedTask : task
|
|
),
|
|
},
|
|
}));
|
|
return updatedTask;
|
|
} catch (error) {
|
|
console.error('updateTask: Failed to update task:', error);
|
|
set((state) => ({
|
|
tasksStore: { ...state.tasksStore, isError: true },
|
|
}));
|
|
throw error;
|
|
}
|
|
},
|
|
deleteTask: async (taskUid) => {
|
|
const { deleteTask } = await import('../utils/tasksService');
|
|
try {
|
|
await deleteTask(taskUid);
|
|
set((state) => ({
|
|
tasksStore: {
|
|
...state.tasksStore,
|
|
tasks: state.tasksStore.tasks.filter(
|
|
(task) => task.uid !== taskUid
|
|
),
|
|
},
|
|
}));
|
|
} catch (error) {
|
|
console.error('deleteTask: Failed to delete task:', error);
|
|
set((state) => ({
|
|
tasksStore: { ...state.tasksStore, isError: true },
|
|
}));
|
|
throw error;
|
|
}
|
|
},
|
|
toggleTaskCompletion: async (taskUid) => {
|
|
const { toggleTaskCompletion } = await import(
|
|
'../utils/tasksService'
|
|
);
|
|
try {
|
|
const updatedTask = await toggleTaskCompletion(taskUid);
|
|
set((state) => ({
|
|
tasksStore: {
|
|
...state.tasksStore,
|
|
tasks: state.tasksStore.tasks.map((task) =>
|
|
task.uid === taskUid ? updatedTask : task
|
|
),
|
|
},
|
|
}));
|
|
return updatedTask;
|
|
} catch (error) {
|
|
console.error(
|
|
'toggleTaskCompletion: Failed to toggle task completion:',
|
|
error
|
|
);
|
|
set((state) => ({
|
|
tasksStore: { ...state.tasksStore, isError: true },
|
|
}));
|
|
throw error;
|
|
}
|
|
},
|
|
loadTaskById: async (taskId) => {
|
|
const { fetchTaskById } = await import('../utils/tasksService');
|
|
try {
|
|
const task = await fetchTaskById(taskId);
|
|
set((state) => ({
|
|
tasksStore: {
|
|
...state.tasksStore,
|
|
tasks: state.tasksStore.tasks.some(
|
|
(t) => t.id === taskId
|
|
)
|
|
? state.tasksStore.tasks.map((t) =>
|
|
t.id === taskId ? task : t
|
|
)
|
|
: [task, ...state.tasksStore.tasks],
|
|
},
|
|
}));
|
|
return task;
|
|
} catch (error) {
|
|
console.error('loadTaskById: Failed to load task:', error);
|
|
set((state) => ({
|
|
tasksStore: { ...state.tasksStore, isError: true },
|
|
}));
|
|
throw error;
|
|
}
|
|
},
|
|
loadTaskByUid: async (uid) => {
|
|
const { fetchTaskByUid } = await import('../utils/tasksService');
|
|
try {
|
|
const task = await fetchTaskByUid(uid);
|
|
set((state) => ({
|
|
tasksStore: {
|
|
...state.tasksStore,
|
|
tasks: state.tasksStore.tasks.some((t) => t.uid === uid)
|
|
? state.tasksStore.tasks.map((t) =>
|
|
t.uid === uid ? task : t
|
|
)
|
|
: [task, ...state.tasksStore.tasks],
|
|
},
|
|
}));
|
|
return task;
|
|
} catch (error) {
|
|
console.error('loadTaskByUid: Failed to load task:', error);
|
|
set((state) => ({
|
|
tasksStore: { ...state.tasksStore, isError: true },
|
|
}));
|
|
throw error;
|
|
}
|
|
},
|
|
loadSubtasks: async (parentTaskUid) => {
|
|
const { fetchSubtasks } = await import('../utils/tasksService');
|
|
try {
|
|
const subtasks = await fetchSubtasks(parentTaskUid);
|
|
const parentTaskId =
|
|
subtasks.length > 0 ? subtasks[0].parent_task_id : null;
|
|
set((state) => ({
|
|
tasksStore: {
|
|
...state.tasksStore,
|
|
tasks: [
|
|
...state.tasksStore.tasks.filter(
|
|
(task) => task.parent_task_id !== parentTaskId
|
|
),
|
|
...subtasks,
|
|
],
|
|
},
|
|
}));
|
|
return subtasks;
|
|
} catch (error) {
|
|
console.error('loadSubtasks: Failed to load subtasks:', error);
|
|
set((state) => ({
|
|
tasksStore: { ...state.tasksStore, isError: true },
|
|
}));
|
|
throw error;
|
|
}
|
|
},
|
|
addTask: (task) =>
|
|
set((state) => ({
|
|
tasksStore: {
|
|
...state.tasksStore,
|
|
tasks: [task, ...state.tasksStore.tasks],
|
|
},
|
|
})),
|
|
removeTask: (taskId) =>
|
|
set((state) => ({
|
|
tasksStore: {
|
|
...state.tasksStore,
|
|
tasks: state.tasksStore.tasks.filter(
|
|
(task) => task.id !== taskId
|
|
),
|
|
},
|
|
})),
|
|
updateTaskInStore: (updatedTask) =>
|
|
set((state) => ({
|
|
tasksStore: {
|
|
...state.tasksStore,
|
|
tasks: state.tasksStore.tasks.map((task) =>
|
|
task.id === updatedTask.id
|
|
? {
|
|
...task,
|
|
...updatedTask,
|
|
subtasks:
|
|
updatedTask.subtasks ||
|
|
task.subtasks ||
|
|
[],
|
|
}
|
|
: task
|
|
),
|
|
},
|
|
})),
|
|
},
|
|
inboxStore: {
|
|
inboxItems: [],
|
|
isLoading: false,
|
|
isError: false,
|
|
pagination: {
|
|
total: 0,
|
|
limit: 20,
|
|
offset: 0,
|
|
hasMore: false,
|
|
},
|
|
setInboxItems: (inboxItems) =>
|
|
set((state) => ({
|
|
inboxStore: { ...state.inboxStore, inboxItems },
|
|
})),
|
|
appendInboxItems: (inboxItems) =>
|
|
set((state) => ({
|
|
inboxStore: {
|
|
...state.inboxStore,
|
|
inboxItems: [...state.inboxStore.inboxItems, ...inboxItems],
|
|
},
|
|
})),
|
|
setPagination: (pagination) =>
|
|
set((state) => ({
|
|
inboxStore: { ...state.inboxStore, pagination },
|
|
})),
|
|
addInboxItem: (inboxItem) =>
|
|
set((state) => ({
|
|
inboxStore: {
|
|
...state.inboxStore,
|
|
inboxItems: [inboxItem, ...state.inboxStore.inboxItems],
|
|
pagination: {
|
|
...state.inboxStore.pagination,
|
|
total: state.inboxStore.pagination.total + 1,
|
|
},
|
|
},
|
|
})),
|
|
updateInboxItem: (inboxItem) =>
|
|
set((state) => ({
|
|
inboxStore: {
|
|
...state.inboxStore,
|
|
inboxItems: state.inboxStore.inboxItems.map((item) =>
|
|
(inboxItem.uid && item.uid === inboxItem.uid) ||
|
|
(inboxItem.id && item.id === inboxItem.id)
|
|
? inboxItem
|
|
: item
|
|
),
|
|
},
|
|
})),
|
|
removeInboxItem: (id) =>
|
|
set((state) => ({
|
|
inboxStore: {
|
|
...state.inboxStore,
|
|
inboxItems: state.inboxStore.inboxItems.filter(
|
|
(item) => item.id !== id
|
|
),
|
|
pagination: {
|
|
...state.inboxStore.pagination,
|
|
total: Math.max(
|
|
0,
|
|
state.inboxStore.pagination.total - 1
|
|
),
|
|
},
|
|
},
|
|
})),
|
|
removeInboxItemByUid: (uid) =>
|
|
set((state) => ({
|
|
inboxStore: {
|
|
...state.inboxStore,
|
|
inboxItems: state.inboxStore.inboxItems.filter(
|
|
(item) => item.uid !== uid
|
|
),
|
|
pagination: {
|
|
...state.inboxStore.pagination,
|
|
total: Math.max(
|
|
0,
|
|
state.inboxStore.pagination.total - 1
|
|
),
|
|
},
|
|
},
|
|
})),
|
|
setLoading: (isLoading) =>
|
|
set((state) => ({
|
|
inboxStore: { ...state.inboxStore, isLoading },
|
|
})),
|
|
setError: (isError) =>
|
|
set((state) => ({
|
|
inboxStore: { ...state.inboxStore, isError },
|
|
})),
|
|
resetPagination: () =>
|
|
set((state) => ({
|
|
inboxStore: {
|
|
...state.inboxStore,
|
|
pagination: {
|
|
total: 0,
|
|
limit: 20,
|
|
offset: 0,
|
|
hasMore: false,
|
|
},
|
|
},
|
|
})),
|
|
},
|
|
habitsStore: {
|
|
habits: [],
|
|
isLoading: false,
|
|
isError: false,
|
|
setHabits: (habits) =>
|
|
set((state) => ({ habitsStore: { ...state.habitsStore, habits } })),
|
|
setLoading: (isLoading) =>
|
|
set((state) => ({
|
|
habitsStore: { ...state.habitsStore, isLoading },
|
|
})),
|
|
setError: (isError) =>
|
|
set((state) => ({
|
|
habitsStore: { ...state.habitsStore, isError },
|
|
})),
|
|
loadHabits: async () => {
|
|
const { fetchHabits } = await import('../utils/habitsService');
|
|
set((state) => ({
|
|
habitsStore: {
|
|
...state.habitsStore,
|
|
isLoading: true,
|
|
isError: false,
|
|
},
|
|
}));
|
|
try {
|
|
const habits = await fetchHabits();
|
|
set((state) => ({
|
|
habitsStore: {
|
|
...state.habitsStore,
|
|
habits,
|
|
isLoading: false,
|
|
},
|
|
}));
|
|
} catch (error) {
|
|
console.error('Failed to load habits:', error);
|
|
set((state) => ({
|
|
habitsStore: {
|
|
...state.habitsStore,
|
|
isError: true,
|
|
isLoading: false,
|
|
},
|
|
}));
|
|
}
|
|
},
|
|
logCompletion: async (habitUid, completedAt) => {
|
|
const { logHabitCompletion } = await import(
|
|
'../utils/habitsService'
|
|
);
|
|
try {
|
|
const updated = await logHabitCompletion(habitUid, completedAt);
|
|
set((state) => ({
|
|
habitsStore: {
|
|
...state.habitsStore,
|
|
habits: state.habitsStore.habits.map((h) =>
|
|
h.uid === habitUid ? { ...h, ...updated.task } : h
|
|
),
|
|
},
|
|
}));
|
|
} catch (error) {
|
|
console.error('Failed to log completion:', error);
|
|
throw error;
|
|
}
|
|
},
|
|
removeTodayCompletion: async (habitUid) => {
|
|
const { fetchHabitCompletions, deleteHabitCompletion } =
|
|
await import('../utils/habitsService');
|
|
try {
|
|
const startDate = new Date();
|
|
startDate.setHours(0, 0, 0, 0);
|
|
const endDate = new Date();
|
|
endDate.setHours(23, 59, 59, 999);
|
|
const completions = await fetchHabitCompletions(
|
|
habitUid,
|
|
startDate,
|
|
endDate
|
|
);
|
|
const today = new Date();
|
|
const targetCompletion = completions.find((completion) => {
|
|
const completionDate = new Date(completion.completed_at);
|
|
return (
|
|
completionDate.getFullYear() === today.getFullYear() &&
|
|
completionDate.getMonth() === today.getMonth() &&
|
|
completionDate.getDate() === today.getDate()
|
|
);
|
|
});
|
|
if (!targetCompletion) {
|
|
return;
|
|
}
|
|
const result = await deleteHabitCompletion(
|
|
habitUid,
|
|
targetCompletion.id
|
|
);
|
|
set((state) => ({
|
|
habitsStore: {
|
|
...state.habitsStore,
|
|
habits: state.habitsStore.habits.map((h) =>
|
|
h.uid === habitUid ? { ...h, ...result.task } : h
|
|
),
|
|
},
|
|
}));
|
|
} catch (error) {
|
|
console.error('Failed to remove habit completion:', error);
|
|
throw error;
|
|
}
|
|
},
|
|
},
|
|
}));
|