Skip to content

Commit c6fa0ef

Browse files
committed
♻️ 💥 feat!: Added jotai atoms to manage localStorage and dropped useReducer hook, refactored all tab functionality
1 parent 5cce73e commit c6fa0ef

File tree

5 files changed

+104
-99
lines changed

5 files changed

+104
-99
lines changed

app/Components/TasksApp/TaskList.tsx

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ export default function TaskList({
4949
setTasks(methodsClone);
5050
}
5151

52+
console.log(tasks)
53+
5254
return (
5355
<ul
5456
ref={listRef}
@@ -116,7 +118,8 @@ function Task({
116118
audio.play();
117119
};
118120

119-
const [isEditing, setIsEditing] = useState(task.isNew);
121+
//A bit messy, but we avoid having a useless isNew value on the task
122+
const [isEditing, setIsEditing] = useState(isCurrentSecond(task.date));
120123
let taskContent;
121124
if (isEditing) {
122125
taskContent = (
@@ -198,3 +201,16 @@ function Task({
198201
</div>
199202
);
200203
}
204+
205+
206+
function isCurrentSecond(date: Date): boolean {
207+
const currentDate = new Date();
208+
return (
209+
date.getFullYear() === currentDate.getFullYear() &&
210+
date.getMonth() === currentDate.getMonth() &&
211+
date.getDate() === currentDate.getDate() &&
212+
date.getHours() === currentDate.getHours() &&
213+
date.getMinutes() === currentDate.getMinutes() &&
214+
date.getSeconds() === currentDate.getSeconds()
215+
);
216+
}
Lines changed: 32 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
11
"use client";
22

3-
import useLocalStorageReducer from "@/app/_lib/customHooks/useLocalStorageWithReducer";
3+
import { Task } from "@/app/_lib/_Tasks/TaskTypes";
44
import { useEffect } from "react";
55
import { v4 as uuid } from "uuid";
66
import AddTask from "./AddTask";
77
import TaskList from "./TaskList";
88

9-
export default function TaskPage() {
10-
//const [tasks, setTasks] = useLocalStorage("tasks", []);
11-
const [tasks, dispatch] = useLocalStorageReducer(
12-
tasksReducer,
13-
"tasks",
14-
initialTasks
15-
);
16-
9+
export default function TaskPage({
10+
tabtasks,
11+
updateTasks,
12+
}: {
13+
tabtasks: Array<Task>;
14+
updateTasks: (tasks: Task[]) => void;
15+
}) {
1716
useEffect(() => {
1817
const handleKeyDown = (event: KeyboardEvent) => {
1918
if (event.key === "Enter") {
@@ -29,93 +28,46 @@ export default function TaskPage() {
2928
}, []);
3029

3130
function handleAddTask(text: any) {
32-
dispatch({
33-
type: "added",
34-
id: uuid(),
35-
text: text,
36-
isNew: true,
37-
});
31+
updateTasks(
32+
[
33+
{
34+
id: uuid(),
35+
text: text,
36+
done: false,
37+
date: new Date(),
38+
},
39+
...tabtasks
40+
]
41+
);
3842
}
3943

4044
function handleChangeTask(task: any) {
41-
dispatch({
42-
type: "changed",
43-
task: task,
44-
});
45+
updateTasks(
46+
tabtasks.map((t: any) => {
47+
if (t.id === task.id) {
48+
return { ...task, isNew: false };
49+
} else {
50+
return t;
51+
}
52+
})
53+
);
4554
}
4655

4756
function handleDeleteTask(taskId: any) {
48-
dispatch({
49-
type: "deleted",
50-
id: taskId,
51-
});
57+
updateTasks(tabtasks.filter((t: any) => t.id !== taskId));
5258
}
5359

54-
//Mimics setState
55-
function handleStateTask(tasks: any) {
56-
dispatch({
57-
type: "state",
58-
tasks: tasks,
59-
});
60-
}
60+
console.log(tabtasks)
6161

6262
return (
6363
<>
6464
<AddTask onAddTask={handleAddTask} />
6565
<TaskList
66-
tasks={tasks}
67-
setTasks={handleStateTask}
66+
tasks={tabtasks}
67+
setTasks={updateTasks}
6868
onChangeTask={handleChangeTask}
6969
onDeleteTask={handleDeleteTask}
7070
/>
7171
</>
7272
);
7373
}
74-
75-
76-
77-
function tasksReducer(tasks: Array<any>, action: any) {
78-
switch (action.type) {
79-
case "added": {
80-
const newTasks = [
81-
{
82-
id: action.id,
83-
text: action.text,
84-
done: false,
85-
isNew: action.isNew,
86-
},
87-
...tasks,
88-
];
89-
return newTasks;
90-
}
91-
case "changed": {
92-
return tasks.map((t: any) => {
93-
if (t.id === action.task.id) {
94-
return { ...action.task, isNew: false };
95-
} else {
96-
return t;
97-
}
98-
});
99-
}
100-
case "deleted": {
101-
return tasks.filter((t: any) => t.id !== action.id);
102-
}
103-
case "state": {
104-
return [...action.tasks];
105-
}
106-
default: {
107-
throw Error("Unknown action: " + action.type);
108-
}
109-
}
110-
}
111-
112-
const initialTasks = [
113-
{ id: 2, text: "Drink matcha", done: false, isNew: false },
114-
{ id: 1, text: "Call grandma", done: false, isNew: false },
115-
{
116-
id: 0,
117-
text: "Contemplate the inevitable increase of entropy in the universe",
118-
done: true,
119-
isNew: false,
120-
},
121-
];
Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,56 @@
11
"use client";
22

3-
import useLocalStorage from "@/app/_lib/customHooks/useLocalStorageV2";
3+
import { Tab, Task } from "@/app/_lib/_Tasks/TaskTypes";
44
import { PlusIcon } from "@/app/_lib/icons/PlusIcon";
5-
import TaskPage from "./TaskPage";
6-
import { useEffect, useState } from "react";
75
import { useDragAndDrop } from "@formkit/drag-and-drop/react";
8-
import { animations } from "@formkit/drag-and-drop";
6+
import { useAtom } from "jotai";
7+
import { atomWithStorage } from "jotai/utils";
8+
import { useEffect, useState } from "react";
9+
import TaskPage from "./TaskPage";
910

10-
interface TabInfo {
11-
id: number;
12-
name: string;
13-
taskList: any;
14-
}
11+
const initialTasks: Task[] = [
12+
{ id: '2', text: "Drink matcha", done: false, date: new Date() },
13+
{ id: '1', text: "Call grandma", done: false, date: new Date() },
14+
{
15+
id: '0',
16+
text: "Contemplate the inevitable increase of entropy in the universe",
17+
done: true,
18+
date: new Date(),
19+
},
20+
];
1521

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

18-
export default function TasksTab() {
19-
const [tabs, setTabs] = useLocalStorage("tabs", initialTabs);
24+
const tabAtom = atomWithStorage("tabs", initialTabs);
25+
26+
export default function TaskApp() {
27+
const [tabs, setTabs] = useAtom(tabAtom);
2028

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

2331
function addNewTab() {
2432
const newTab = {
2533
id: tabs.length,
2634
name: `Tab ${tabs.length + 1}`,
27-
taskList: [],
35+
tasks: [],
2836
};
2937
setTabs([...tabs, newTab]);
3038
}
3139

40+
function updateTasks(tabName: string, tasks: Task[]) {
41+
const newTabs = tabs.map((tab) => {
42+
if (tab.name === tabName) {
43+
return { ...tab, tasks: tasks };
44+
}
45+
return tab;
46+
});
47+
48+
setTabs(newTabs);
49+
}
50+
51+
const activeTabTasks =
52+
tabs.find((tab) => tab.name === activeTab)?.tasks || [];
53+
3254
return (
3355
<>
3456
<main className="flex min-h-full flex-col items-center lg:pt-4 lg:m-16 lg:mt-0 md:p-0 pt-0">
@@ -40,7 +62,10 @@ export default function TasksTab() {
4062
updateTabs={setTabs}
4163
/>
4264
<div className="py-4 flex flex-col items-center w-full border border-t-0 border-base-300 rounded-br-box rounded-bl-box">
43-
<TaskPage />
65+
<TaskPage
66+
tabtasks={activeTabTasks}
67+
updateTasks={(tasks: Task[]) => updateTasks(activeTab, tasks)}
68+
/>
4469
</div>
4570
</main>
4671
</>
@@ -54,13 +79,13 @@ function TabsSelector({
5479
setActiveTab,
5580
updateTabs,
5681
}: {
57-
tabsState: Array<TabInfo>;
82+
tabsState: Array<Tab>;
5883
activeTab: string;
5984
addNewTab: () => void;
6085
setActiveTab: (tabName: string) => void;
61-
updateTabs: (tabs: Array<TabInfo>) => void;
86+
updateTabs: (tabs: Array<Tab>) => void;
6287
}) {
63-
const [parent, tabs, setTabs] = useDragAndDrop<HTMLUListElement, TabInfo>(
88+
const [parent, tabs, setTabs] = useDragAndDrop<HTMLUListElement, Tab>(
6489
tabsState,
6590
{
6691
//There is a bug with the animation because when the useEffect reAsigns the tabs the animation re-renders

app/_lib/_Tasks/TaskTypes.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
export interface Tab {
2+
id: number;
3+
name: string;
4+
tasks: Task[];
5+
}
6+
7+
export interface Task {
8+
id: string;
9+
text: string;
10+
done: boolean;
11+
date: Date;
12+
}

app/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { NextAuthProvider } from "./_lib/auth/AuthProvider";
66
//Using this just to be able to use localStorage is probably against the Geneva convention
77
//but if I spend any more hours trying to figure out how to use localStorage
88
//in Next.js with a useReducer hook I will kill myself
9-
const TaskAppNoSSR = dynamic(() => import("./Components/TasksApp/TasksTab"), {
9+
const TaskAppNoSSR = dynamic(() => import("./Components/TasksApp/_TaskApp"), {
1010
ssr: false,
1111
});
1212

0 commit comments

Comments
 (0)