Skip to content

Commit 67fc8db

Browse files
committed
added edit functionality
1 parent 61d417d commit 67fc8db

12 files changed

Lines changed: 328 additions & 41 deletions

File tree

public/locales/de/translation.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,6 @@
1818
"completedBadge": "abgeschlossen",
1919
"pendingBadge": "ausstehend",
2020
"searchPlaceholder": "tippen, um todos zu suchen ...",
21-
"createNewTodo": "Neues Todo erstellen"
21+
"createNewTodo": "Neues Todo erstellen",
22+
"noTodosFound": "Es gibt keine Todos"
2223
}

public/locales/en/translation.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,6 @@
1818
"completedBadge": "completed",
1919
"pendingBadge": "pending",
2020
"searchPlaceholder": "type to search todos ...",
21-
"createNewTodo": "Create new todo"
21+
"createNewTodo": "Create new todo",
22+
"noTodosFound": "There are no todos"
2223
}

src/lib/todo.schema.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { z } from 'zod';
2+
3+
const todoSchema = z.object({
4+
title: z
5+
.string()
6+
.nonempty({ message: 'This is required' })
7+
.min(4, { message: 'At least 4 characters are needed' }),
8+
description: z.string().nonempty({ message: 'This is required' }),
9+
deadline: z.coerce.date().refine(
10+
(date) => {
11+
const today = new Date();
12+
today.setHours(0, 0, 0, 0);
13+
return date >= today;
14+
},
15+
{ message: 'Deadline cannot be in the past' },
16+
),
17+
priority: z.string().nonempty(),
18+
});
19+
20+
export { todoSchema };

src/routeTree.gen.ts

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import { Route as rootRoute } from './routes/__root'
1414
import { Route as IndexImport } from './routes/index'
1515
import { Route as TodosNewImport } from './routes/todos/new'
16+
import { Route as TodosTodoIdEditImport } from './routes/todos/$todoId/edit'
1617

1718
// Create/Update Routes
1819

@@ -28,6 +29,12 @@ const TodosNewRoute = TodosNewImport.update({
2829
getParentRoute: () => rootRoute,
2930
} as any)
3031

32+
const TodosTodoIdEditRoute = TodosTodoIdEditImport.update({
33+
id: '/todos/$todoId/edit',
34+
path: '/todos/$todoId/edit',
35+
getParentRoute: () => rootRoute,
36+
} as any)
37+
3138
// Populate the FileRoutesByPath interface
3239

3340
declare module '@tanstack/react-router' {
@@ -46,6 +53,13 @@ declare module '@tanstack/react-router' {
4653
preLoaderRoute: typeof TodosNewImport
4754
parentRoute: typeof rootRoute
4855
}
56+
'/todos/$todoId/edit': {
57+
id: '/todos/$todoId/edit'
58+
path: '/todos/$todoId/edit'
59+
fullPath: '/todos/$todoId/edit'
60+
preLoaderRoute: typeof TodosTodoIdEditImport
61+
parentRoute: typeof rootRoute
62+
}
4963
}
5064
}
5165

@@ -54,36 +68,41 @@ declare module '@tanstack/react-router' {
5468
export interface FileRoutesByFullPath {
5569
'/': typeof IndexRoute
5670
'/todos/new': typeof TodosNewRoute
71+
'/todos/$todoId/edit': typeof TodosTodoIdEditRoute
5772
}
5873

5974
export interface FileRoutesByTo {
6075
'/': typeof IndexRoute
6176
'/todos/new': typeof TodosNewRoute
77+
'/todos/$todoId/edit': typeof TodosTodoIdEditRoute
6278
}
6379

6480
export interface FileRoutesById {
6581
__root__: typeof rootRoute
6682
'/': typeof IndexRoute
6783
'/todos/new': typeof TodosNewRoute
84+
'/todos/$todoId/edit': typeof TodosTodoIdEditRoute
6885
}
6986

7087
export interface FileRouteTypes {
7188
fileRoutesByFullPath: FileRoutesByFullPath
72-
fullPaths: '/' | '/todos/new'
89+
fullPaths: '/' | '/todos/new' | '/todos/$todoId/edit'
7390
fileRoutesByTo: FileRoutesByTo
74-
to: '/' | '/todos/new'
75-
id: '__root__' | '/' | '/todos/new'
91+
to: '/' | '/todos/new' | '/todos/$todoId/edit'
92+
id: '__root__' | '/' | '/todos/new' | '/todos/$todoId/edit'
7693
fileRoutesById: FileRoutesById
7794
}
7895

7996
export interface RootRouteChildren {
8097
IndexRoute: typeof IndexRoute
8198
TodosNewRoute: typeof TodosNewRoute
99+
TodosTodoIdEditRoute: typeof TodosTodoIdEditRoute
82100
}
83101

84102
const rootRouteChildren: RootRouteChildren = {
85103
IndexRoute: IndexRoute,
86104
TodosNewRoute: TodosNewRoute,
105+
TodosTodoIdEditRoute: TodosTodoIdEditRoute,
87106
}
88107

89108
export const routeTree = rootRoute
@@ -97,14 +116,18 @@ export const routeTree = rootRoute
97116
"filePath": "__root.tsx",
98117
"children": [
99118
"/",
100-
"/todos/new"
119+
"/todos/new",
120+
"/todos/$todoId/edit"
101121
]
102122
},
103123
"/": {
104124
"filePath": "index.tsx"
105125
},
106126
"/todos/new": {
107127
"filePath": "todos/new.tsx"
128+
},
129+
"/todos/$todoId/edit": {
130+
"filePath": "todos/$todoId/edit.tsx"
108131
}
109132
}
110133
}

src/routes/__root.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { Outlet, createRootRoute } from '@tanstack/react-router'
2-
import { TanStackRouterDevtools } from '@tanstack/react-router-devtools'
1+
import { Outlet, createRootRoute } from '@tanstack/react-router';
2+
import { TanStackRouterDevtools } from '@tanstack/react-router-devtools';
33

44
export const Route = createRootRoute({
55
component: () => (
@@ -8,4 +8,4 @@ export const Route = createRootRoute({
88
<TanStackRouterDevtools />
99
</>
1010
),
11-
})
11+
});

src/routes/index.tsx

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
ButtonLink,
55
CheckIcon,
66
ClockIcon,
7+
EmptyTodoList,
78
Header,
89
SearchBar,
910
TodoCard,
@@ -17,6 +18,7 @@ export const Route = createFileRoute('/')({
1718
});
1819

1920
function App() {
21+
const navigate = Route.useNavigate();
2022
const [searchQuery, setSearchQuery] = useState('');
2123
const todos = useTodoStore((state) => state.todos);
2224
const deleteTodos = useTodoStore((state) => state.delete);
@@ -27,6 +29,10 @@ function App() {
2729
setSearchQuery(e.target.value);
2830
};
2931

32+
const onEdit = (todoId: string) => {
33+
navigate({ to: '/todos/$todoId/edit', params: { todoId } });
34+
};
35+
3036
const lowerSearchQuery = searchQuery.toLowerCase();
3137
const filteredTodos = useMemo(() => {
3238
return todos.filter(
@@ -36,6 +42,17 @@ function App() {
3642
);
3743
}, [todos, lowerSearchQuery]);
3844

45+
const todoCards = filteredTodos.map((todo) => {
46+
return (
47+
<TodoCard
48+
key={todo.id}
49+
todo={todo}
50+
onDelete={deleteTodos}
51+
onEdit={onEdit}
52+
/>
53+
);
54+
});
55+
3956
return (
4057
<div className="min-h-screen bg-gray-50 pt-16 space-y-8">
4158
<div className="container mx-auto px-4 py-8">
@@ -74,16 +91,16 @@ function App() {
7491
</Badge>
7592
</div>
7693
</div>
77-
<div
78-
data-testid="todos"
79-
className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 pt-8"
80-
>
81-
{filteredTodos.map((todo) => {
82-
return (
83-
<TodoCard key={todo.id} todo={todo} onDelete={deleteTodos} />
84-
);
85-
})}
86-
</div>
94+
{filteredTodos.length === 0 ? (
95+
<EmptyTodoList />
96+
) : (
97+
<div
98+
data-testid="todos"
99+
className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 pt-8"
100+
>
101+
{todoCards}
102+
</div>
103+
)}
87104
</div>
88105
</div>
89106
);

0 commit comments

Comments
 (0)