Skip to content

Commit

Permalink
♻️ 💥 feat!: Added jotai atoms to manage localStorage and dropped useR…
Browse files Browse the repository at this point in the history
…educer hook, refactored all tab functionality
  • Loading branch information
bytevictor committed Apr 11, 2024
1 parent 5cce73e commit c6fa0ef
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 99 deletions.
18 changes: 17 additions & 1 deletion app/Components/TasksApp/TaskList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ export default function TaskList({
setTasks(methodsClone);
}

console.log(tasks)

return (
<ul
ref={listRef}
Expand Down Expand Up @@ -116,7 +118,8 @@ function Task({
audio.play();
};

const [isEditing, setIsEditing] = useState(task.isNew);
//A bit messy, but we avoid having a useless isNew value on the task
const [isEditing, setIsEditing] = useState(isCurrentSecond(task.date));
let taskContent;
if (isEditing) {
taskContent = (
Expand Down Expand Up @@ -198,3 +201,16 @@ function Task({
</div>
);
}


function isCurrentSecond(date: Date): boolean {
const currentDate = new Date();
return (
date.getFullYear() === currentDate.getFullYear() &&
date.getMonth() === currentDate.getMonth() &&
date.getDate() === currentDate.getDate() &&
date.getHours() === currentDate.getHours() &&
date.getMinutes() === currentDate.getMinutes() &&
date.getSeconds() === currentDate.getSeconds()
);
}
112 changes: 32 additions & 80 deletions app/Components/TasksApp/TaskPage.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
"use client";

import useLocalStorageReducer from "@/app/_lib/customHooks/useLocalStorageWithReducer";
import { Task } from "@/app/_lib/_Tasks/TaskTypes";
import { useEffect } from "react";
import { v4 as uuid } from "uuid";
import AddTask from "./AddTask";
import TaskList from "./TaskList";

export default function TaskPage() {
//const [tasks, setTasks] = useLocalStorage("tasks", []);
const [tasks, dispatch] = useLocalStorageReducer(
tasksReducer,
"tasks",
initialTasks
);

export default function TaskPage({
tabtasks,
updateTasks,
}: {
tabtasks: Array<Task>;
updateTasks: (tasks: Task[]) => void;
}) {
useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => {
if (event.key === "Enter") {
Expand All @@ -29,93 +28,46 @@ export default function TaskPage() {
}, []);

function handleAddTask(text: any) {
dispatch({
type: "added",
id: uuid(),
text: text,
isNew: true,
});
updateTasks(
[
{
id: uuid(),
text: text,
done: false,
date: new Date(),
},
...tabtasks
]
);
}

function handleChangeTask(task: any) {
dispatch({
type: "changed",
task: task,
});
updateTasks(
tabtasks.map((t: any) => {
if (t.id === task.id) {
return { ...task, isNew: false };
} else {
return t;
}
})
);
}

function handleDeleteTask(taskId: any) {
dispatch({
type: "deleted",
id: taskId,
});
updateTasks(tabtasks.filter((t: any) => t.id !== taskId));
}

//Mimics setState
function handleStateTask(tasks: any) {
dispatch({
type: "state",
tasks: tasks,
});
}
console.log(tabtasks)

return (
<>
<AddTask onAddTask={handleAddTask} />
<TaskList
tasks={tasks}
setTasks={handleStateTask}
tasks={tabtasks}
setTasks={updateTasks}
onChangeTask={handleChangeTask}
onDeleteTask={handleDeleteTask}
/>
</>
);
}



function tasksReducer(tasks: Array<any>, action: any) {
switch (action.type) {
case "added": {
const newTasks = [
{
id: action.id,
text: action.text,
done: false,
isNew: action.isNew,
},
...tasks,
];
return newTasks;
}
case "changed": {
return tasks.map((t: any) => {
if (t.id === action.task.id) {
return { ...action.task, isNew: false };
} else {
return t;
}
});
}
case "deleted": {
return tasks.filter((t: any) => t.id !== action.id);
}
case "state": {
return [...action.tasks];
}
default: {
throw Error("Unknown action: " + action.type);
}
}
}

const initialTasks = [
{ id: 2, text: "Drink matcha", done: false, isNew: false },
{ id: 1, text: "Call grandma", done: false, isNew: false },
{
id: 0,
text: "Contemplate the inevitable increase of entropy in the universe",
done: true,
isNew: false,
},
];
Original file line number Diff line number Diff line change
@@ -1,34 +1,56 @@
"use client";

import useLocalStorage from "@/app/_lib/customHooks/useLocalStorageV2";
import { Tab, Task } from "@/app/_lib/_Tasks/TaskTypes";
import { PlusIcon } from "@/app/_lib/icons/PlusIcon";
import TaskPage from "./TaskPage";
import { useEffect, useState } from "react";
import { useDragAndDrop } from "@formkit/drag-and-drop/react";
import { animations } from "@formkit/drag-and-drop";
import { useAtom } from "jotai";
import { atomWithStorage } from "jotai/utils";
import { useEffect, useState } from "react";
import TaskPage from "./TaskPage";

interface TabInfo {
id: number;
name: string;
taskList: any;
}
const initialTasks: Task[] = [
{ id: '2', text: "Drink matcha", done: false, date: new Date() },
{ id: '1', text: "Call grandma", done: false, date: new Date() },
{
id: '0',
text: "Contemplate the inevitable increase of entropy in the universe",
done: true,
date: new Date(),
},
];

const initialTabs: Array<TabInfo> = [{ id: 0, name: "To-Do", taskList: [] }];
const initialTabs: Array<Tab> = [{ id: 0, name: "To-Do", tasks: initialTasks }];

export default function TasksTab() {
const [tabs, setTabs] = useLocalStorage("tabs", initialTabs);
const tabAtom = atomWithStorage("tabs", initialTabs);

export default function TaskApp() {
const [tabs, setTabs] = useAtom(tabAtom);

const [activeTab, setActiveTab] = useState(tabs[0].name);

function addNewTab() {
const newTab = {
id: tabs.length,
name: `Tab ${tabs.length + 1}`,
taskList: [],
tasks: [],
};
setTabs([...tabs, newTab]);
}

function updateTasks(tabName: string, tasks: Task[]) {
const newTabs = tabs.map((tab) => {
if (tab.name === tabName) {
return { ...tab, tasks: tasks };
}
return tab;
});

setTabs(newTabs);
}

const activeTabTasks =
tabs.find((tab) => tab.name === activeTab)?.tasks || [];

return (
<>
<main className="flex min-h-full flex-col items-center lg:pt-4 lg:m-16 lg:mt-0 md:p-0 pt-0">
Expand All @@ -40,7 +62,10 @@ export default function TasksTab() {
updateTabs={setTabs}
/>
<div className="py-4 flex flex-col items-center w-full border border-t-0 border-base-300 rounded-br-box rounded-bl-box">
<TaskPage />
<TaskPage
tabtasks={activeTabTasks}
updateTasks={(tasks: Task[]) => updateTasks(activeTab, tasks)}
/>
</div>
</main>
</>
Expand All @@ -54,13 +79,13 @@ function TabsSelector({
setActiveTab,
updateTabs,
}: {
tabsState: Array<TabInfo>;
tabsState: Array<Tab>;
activeTab: string;
addNewTab: () => void;
setActiveTab: (tabName: string) => void;
updateTabs: (tabs: Array<TabInfo>) => void;
updateTabs: (tabs: Array<Tab>) => void;
}) {
const [parent, tabs, setTabs] = useDragAndDrop<HTMLUListElement, TabInfo>(
const [parent, tabs, setTabs] = useDragAndDrop<HTMLUListElement, Tab>(
tabsState,
{
//There is a bug with the animation because when the useEffect reAsigns the tabs the animation re-renders
Expand Down
12 changes: 12 additions & 0 deletions app/_lib/_Tasks/TaskTypes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export interface Tab {
id: number;
name: string;
tasks: Task[];
}

export interface Task {
id: string;
text: string;
done: boolean;
date: Date;
}
2 changes: 1 addition & 1 deletion app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { NextAuthProvider } from "./_lib/auth/AuthProvider";
//Using this just to be able to use localStorage is probably against the Geneva convention
//but if I spend any more hours trying to figure out how to use localStorage
//in Next.js with a useReducer hook I will kill myself
const TaskAppNoSSR = dynamic(() => import("./Components/TasksApp/TasksTab"), {
const TaskAppNoSSR = dynamic(() => import("./Components/TasksApp/_TaskApp"), {
ssr: false,
});

Expand Down

0 comments on commit c6fa0ef

Please sign in to comment.