Fix some bugs

This commit is contained in:
Steve Kinney
2024-09-17 15:50:09 -06:00
parent 4971bda81b
commit e29c63f5cb
6 changed files with 105 additions and 64 deletions

View File

@@ -47,7 +47,13 @@ export const updateTask = (id, updates) => {
if (!task) return undefined; if (!task) return undefined;
Object.assign(task, updates, { lastModified: new Date() }); for (const key in updates) {
if (updates[key] !== undefined) {
task[key] = updates[key];
}
}
Object.assign(task, { lastModified: new Date() });
return task; return task;
}; };

View File

@@ -1,12 +1,12 @@
import { useState } from 'react'; import { useState } from 'react';
import { useTaskContext } from './task-context'; import { useTaskActions } from './task-context';
type CreateTaskProps = { type CreateTaskProps = {
onSubmit: (title: string) => void; onSubmit: (title: string) => void;
}; };
export const CreateTask = ({ onSubmit }: CreateTaskProps) => { export const CreateTask = ({ onSubmit }: CreateTaskProps) => {
const { addTask } = useTaskContext(); const { addTask } = useTaskActions();
const [title, setTitle] = useState(''); const [title, setTitle] = useState('');
return ( return (

View File

@@ -1,10 +1,10 @@
export const DateTime = ({ date, title }: { date: Date; title: string }) => { export const DateTime = ({ date, title }: { date: Date; title: string }) => {
return ( return (
<div className="flex gap-2 text-xs sm:flex-row"> <div className="flex gap-2 overflow-x-hidden text-xs sm:flex-row">
<h3 className="font-semibold sm:after:content-[':'] after:text-gray-900 text-primary-800"> <h3 className="font-semibold sm:after:content-[':'] after:text-gray-900 text-primary-800">
{title} {title}
</h3> </h3>
<p> <p className="whitespace-pre">
{date.toLocaleString(undefined, { {date.toLocaleString(undefined, {
dateStyle: 'short', dateStyle: 'short',
timeStyle: 'short', timeStyle: 'short',

View File

@@ -1,9 +1,11 @@
import { import {
createContext, createContext,
useReducer, useReducer,
useMemo,
useEffect, useEffect,
type ReactNode, type ReactNode,
useContext, useContext,
useCallback,
} from 'react'; } from 'react';
import { TasksActions, taskReducer, initialState } from './task-reducer'; import { TasksActions, taskReducer, initialState } from './task-reducer';
import type { Task } from '../types'; import type { Task } from '../types';
@@ -27,7 +29,7 @@ const TaskProvider = ({ children }: TaskProviderProps) => {
const [state, dispatch] = useReducer(taskReducer, initialState); const [state, dispatch] = useReducer(taskReducer, initialState);
// Fetch all tasks // Fetch all tasks
const fetchTasks = async () => { const fetchTasks = useCallback(async () => {
dispatch({ type: TasksActions.SET_LOADING }); dispatch({ type: TasksActions.SET_LOADING });
try { try {
const response = await fetch('/api/tasks'); const response = await fetch('/api/tasks');
@@ -39,10 +41,11 @@ const TaskProvider = ({ children }: TaskProviderProps) => {
payload: 'Failed to fetch tasks', payload: 'Failed to fetch tasks',
}); });
} }
}; }, [dispatch]);
// Add a new task // Add a new task
const addTask = async (title: string) => { const addTask = useCallback(
async (title: string) => {
dispatch({ type: TasksActions.SET_LOADING }); dispatch({ type: TasksActions.SET_LOADING });
try { try {
const response = await fetch('/api/tasks', { const response = await fetch('/api/tasks', {
@@ -53,12 +56,18 @@ const TaskProvider = ({ children }: TaskProviderProps) => {
const data = await response.json(); const data = await response.json();
dispatch({ type: TasksActions.ADD_TASK, payload: data }); dispatch({ type: TasksActions.ADD_TASK, payload: data });
} catch (error) { } catch (error) {
dispatch({ type: TasksActions.SET_ERROR, payload: 'Failed to add task' }); dispatch({
type: TasksActions.SET_ERROR,
payload: 'Failed to add task',
});
} }
}; },
[dispatch],
);
// Update a task // Update a task
const updateTask = async (id: string, updatedTask: Partial<Task>) => { const updateTask = useCallback(
async (id: string, updatedTask: Partial<Task>) => {
dispatch({ type: TasksActions.SET_LOADING }); dispatch({ type: TasksActions.SET_LOADING });
try { try {
@@ -82,10 +91,13 @@ const TaskProvider = ({ children }: TaskProviderProps) => {
payload: 'Failed to update task', payload: 'Failed to update task',
}); });
} }
}; },
[dispatch],
);
// Delete a task // Delete a task
const deleteTask = async (id: string) => { const deleteTask = useCallback(
async (id: string) => {
dispatch({ type: TasksActions.SET_LOADING }); dispatch({ type: TasksActions.SET_LOADING });
try { try {
await fetch(`/api/tasks/${id}`, { await fetch(`/api/tasks/${id}`, {
@@ -98,7 +110,9 @@ const TaskProvider = ({ children }: TaskProviderProps) => {
payload: 'Failed to delete task', payload: 'Failed to delete task',
}); });
} }
}; },
[dispatch],
);
useEffect(() => { useEffect(() => {
fetchTasks(); fetchTasks();
@@ -120,12 +134,33 @@ const TaskProvider = ({ children }: TaskProviderProps) => {
); );
}; };
const useTaskContext = () => { const useTaskState = () => {
const context = useContext(TaskContext); const context = useContext(TaskContext);
if (!context) { if (!context) {
throw new Error('useTaskContext must be used within a TaskProvider'); throw new Error('useTaskContext must be used within a TaskProvider');
} }
return context;
return context.tasks;
}; };
export { TaskContext, TaskProvider, useTaskContext }; export const useTaskActions = () => {
const context = useContext(TaskContext);
if (!context) {
throw new Error('useTaskContext must be used within a TaskProvider');
}
const actions = useMemo(
() => ({
addTask: context.addTask,
updateTask: context.updateTask,
deleteTask: context.deleteTask,
}),
[context.addTask, context.updateTask, context.deleteTask],
);
return actions;
};
export { TaskContext, TaskProvider, useTaskState };

View File

@@ -1,12 +1,12 @@
import { DateTime } from './date-time'; import { DateTime } from './date-time';
import { useTaskContext } from './task-context'; import { useTaskActions } from './task-context';
type TaskProps = { type TaskProps = {
task: import('../types').Task; task: import('../types').Task;
}; };
export const Task = ({ task }: TaskProps) => { export const Task = ({ task }: TaskProps) => {
const { updateTask, deleteTask } = useTaskContext(); const { updateTask, deleteTask } = useTaskActions();
return ( return (
<li className="block p-4 space-y-2 border-t-2 border-x-2 last:border-b-2"> <li className="block p-4 space-y-2 border-t-2 border-x-2 last:border-b-2">

View File

@@ -1,8 +1,8 @@
import { Task } from './task'; import { Task } from './task';
import { useTaskContext } from './task-context'; import { useTaskState } from './task-context';
export const Tasks = () => { export const Tasks = () => {
const { tasks } = useTaskContext(); const tasks = useTaskState();
return ( return (
<section> <section>