Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test new hooks #675

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 29 additions & 47 deletions src/api.ts
Original file line number Diff line number Diff line change
@@ -1,80 +1,62 @@
import { openDB } from "idb";
import type { DBSchema, IDBPDatabase } from "idb";

Check warning on line 2 in src/api.ts

View workflow job for this annotation

GitHub Actions / lint

There should be at least one empty line between import groups
import type { Todo } from "./schema";

interface TodoDB extends DBSchema {
todos: {
key: string;

Check failure on line 7 in src/api.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected separator (;)
value: Todo;

Check failure on line 8 in src/api.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected separator (;)
};

Check failure on line 9 in src/api.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected separator (;)
}

let dbInstance: Promise<IDBPDatabase<TodoDB>> | null = null;
let dbInstancePromise!: Promise<IDBPDatabase<TodoDB>>;

async function initializeDB(): Promise<IDBPDatabase<TodoDB>> {
if (!dbInstance) {
dbInstance = openDB<TodoDB>("todosDB", 1, {
function initializeDB(): Promise<IDBPDatabase<TodoDB>> {
if (!dbInstancePromise) {
dbInstancePromise = openDB<TodoDB>("todosDB", 1, {
upgrade(db) {
if (!db.objectStoreNames.contains("todos")) {
db.createObjectStore("todos", { keyPath: "id" });
}
},
});
}
return dbInstance;
return dbInstancePromise;
}

async function safeExecute<T>(operationName: string, operationFn: () => Promise<T>): Promise<T> {
try {
return await operationFn();
} catch (error) {

Check failure on line 30 in src/api.ts

View workflow job for this annotation

GitHub Actions / lint

Closing curly brace appears on the same line as the subsequent block
console.error(`Error during ${operationName}:`, error);
throw new Error(`Failed to ${operationName}`);
}
}

export async function getTodos(): Promise<Todo[]> {
const db = await initializeDB();
return db.getAll("todos");
return safeExecute("getTodos", async () => {
const db = await initializeDB();
return db.getAll("todos");
});
}

export async function addTodo(todo: Todo): Promise<void> {
const db = await initializeDB();
await db.put("todos", todo);
return safeExecute("addTodo", async () => {
const db = await initializeDB();
await db.put("todos", todo);
});
}

export async function updateTodo(updatedTodo: Todo): Promise<void> {
const db = await initializeDB();
await db.put("todos", updatedTodo);
return safeExecute("updateTodo", async () => {
const db = await initializeDB();
await db.put("todos", updatedTodo);
});
}

export async function deleteTodo(todoId: string): Promise<void> {
const db = await initializeDB();
await db.delete("todos", todoId);
}

export async function getCompletedTodos(): Promise<string[]> {
const todos = await getTodos();
return todos.filter((todo) => todo.completed).map((todo) => todo.id);
}

export async function saveCompletedTodos(completedTodos: string[]): Promise<void> {
try {
return safeExecute("deleteTodo", async () => {
const db = await initializeDB();
const tx = db.transaction("todos", "readwrite");
const store = tx.objectStore("todos");

const updatePromises = completedTodos.map(async (id) => {
const todo = await store.get(id);
if (todo && !todo.completed) {
todo.completed = true;
await store.put(todo);
}
});

await Promise.all(updatePromises);
await tx.done;
} catch (error) {
console.error("Failed to save completed todos:", error);
}
await db.delete("todos", todoId);
});
}

export default {
getTodos,
addTodo,
updateTodo,
deleteTodo,
getCompletedTodos,
saveCompletedTodos,
};
58 changes: 30 additions & 28 deletions src/components/TodoList.tsx
Original file line number Diff line number Diff line change
@@ -1,49 +1,51 @@
import { useMemo } from "react";
import clsx from "clsx";

Check warning on line 2 in src/components/TodoList.tsx

View workflow job for this annotation

GitHub Actions / lint

There should be at least one empty line between import groups

Check warning on line 2 in src/components/TodoList.tsx

View workflow job for this annotation

GitHub Actions / lint

`clsx` import should occur before import of `react`
import type { FC } from "react";

import type { TodoListProps } from "../schema";

Check warning on line 3 in src/components/TodoList.tsx

View workflow job for this annotation

GitHub Actions / lint

There should be at least one empty line between import groups

import TodoItem from "./TodoItem";

const TodoList: FC<TodoListProps> = ({
const TodoList = ({

Check failure on line 6 in src/components/TodoList.tsx

View workflow job for this annotation

GitHub Actions / lint

Top-level functions should be declared with function keyword
todos,
error,
completedTodos,
handleDeleteClick,
handleToggleClick,
}) => {
const completedTodosSet = new Set(completedTodos);
}: TodoListProps) => {
const completedTodosSet = useMemo(
() => new Set(completedTodos),
[completedTodos]

Check failure on line 15 in src/components/TodoList.tsx

View workflow job for this annotation

GitHub Actions / lint

Missing trailing comma
);

const todoItems = todos.map((todo) => {
const isCompleted = completedTodosSet.has(todo.id);
return (
const content = useMemo(() => {
if (error) {
return (
<div className="py-4 text-center text-red-500 font-medium">
Oops! Something went wrong. Please try again later.
</div>
);
}

if (!todos.length) {
return (
<div className="py-4 text-center text-gray-500 font-medium">
No tasks available. Add a new one to get started!
</div>
);
}

return todos.map((todo) => (
<TodoItem
key={todo.id}
key={todo.text}
todo={todo}
isCompleted={isCompleted}
isCompleted={completedTodosSet.has(todo.id)}
onToggle={() => handleToggleClick(todo.id)}
onDelete={() => handleDeleteClick(todo.id)}
/>
);
});

if (error) {
return (
<div className="py-4 text-center text-red-500 font-medium">
Oops! Something went wrong. Please try again later.
</div>
);
}
));
}, [todos, error, completedTodosSet, handleToggleClick, handleDeleteClick]);

return (
<div className={clsx("overflow-auto h-full", "max-h-screen")}>
{todos.length
? todoItems
: (
<div className="py-4 text-center text-gray-500 font-medium">
No tasks available. Add a new one to get started!
</div>
)}
{content}
</div>
);
};
Expand Down
Loading
Loading