@powerhousedao/academy 5.1.0-dev.0 → 5.1.0-dev.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +78 -0
- package/blog/BeyondCommunication-ABlueprintForDevelopment.md +2 -1
- package/blog/TheChallengeOfChange.md +1 -0
- package/docs/academy/01-GetStarted/00-ExploreDemoPackage.mdx +24 -27
- package/docs/academy/01-GetStarted/01-CreateNewPowerhouseProject.md +118 -9
- package/docs/academy/01-GetStarted/02-DefineToDoListDocumentModel.md +110 -28
- package/docs/academy/01-GetStarted/03-ImplementOperationReducers.md +191 -145
- package/docs/academy/01-GetStarted/04-WriteDocumentModelTests.md +378 -0
- package/docs/academy/01-GetStarted/05-BuildToDoListEditor.md +560 -0
- package/docs/academy/01-GetStarted/_04-BuildToDoListEditor +1 -1
- package/docs/academy/02-MasteryTrack/01-BuilderEnvironment/03-BuilderTools.md +2 -2
- package/docs/academy/{01-GetStarted → 02-MasteryTrack/01-BuilderEnvironment}/05-VetraStudio.md +48 -6
- package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/02-SpecifyTheStateSchema.md +75 -44
- package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/03-SpecifyDocumentOperations.md +28 -22
- package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/04-UseTheDocumentModelGenerator.md +28 -31
- package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/05-ImplementDocumentReducers.md +211 -206
- package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/06-ImplementDocumentModelTests.md +176 -62
- package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/07-ExampleToDoListRepository.md +21 -0
- package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/01-BuildingDocumentEditors.md +309 -319
- package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/06-DocumentTools/00-DocumentToolbar.mdx +4 -0
- package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/06-DocumentTools/01-OperationHistory.md +4 -0
- package/docs/academy/02-MasteryTrack/05-Launch/04-ConfigureEnvironment.md +1 -1
- package/docs/academy/03-ExampleUsecases/Chatroom/02-CreateNewPowerhouseProject.md +111 -35
- package/docs/academy/03-ExampleUsecases/Chatroom/03-DefineChatroomDocumentModel.md +255 -76
- package/docs/academy/03-ExampleUsecases/Chatroom/04-ImplementOperationReducers.md +281 -160
- package/docs/academy/03-ExampleUsecases/Chatroom/05-ImplementChatroomEditor.md +188 -35
- package/docs/academy/03-ExampleUsecases/Chatroom/06-LaunchALocalReactor.md +95 -7
- package/docs/academy/03-ExampleUsecases/Chatroom/_category_.json +1 -1
- package/docs/academy/03-ExampleUsecases/TodoList/00-GetTheStarterCode.md +24 -0
- package/docs/academy/03-ExampleUsecases/TodoList/01-GenerateTodoListDocumentModel.md +211 -0
- package/docs/academy/03-ExampleUsecases/TodoList/02-ImplementTodoListDocumentModelReducerOperationHandlers.md +171 -0
- package/docs/academy/03-ExampleUsecases/TodoList/03-AddTestsForTodoListActions.md +462 -0
- package/docs/academy/03-ExampleUsecases/TodoList/04-GenerateTodoListDocumentEditor.md +45 -0
- package/docs/academy/03-ExampleUsecases/TodoList/05-ImplementTodoListDocumentEditorUIComponents.md +422 -0
- package/docs/academy/03-ExampleUsecases/TodoList/06-GenerateTodoDriveExplorer.md +61 -0
- package/docs/academy/03-ExampleUsecases/TodoList/07-AddSharedComponentForShowingTodoListStats.md +384 -0
- package/docs/academy/03-ExampleUsecases/TodoList/_category_.json +8 -0
- package/docs/academy/03-ExampleUsecases/VetraPackageLibrary/VetraPackageLibrary.md +7 -0
- package/docs/academy/03-ExampleUsecases/VetraPackageLibrary/_category_.json +9 -0
- package/docs/academy/04-APIReferences/00-PowerhouseCLI.md +6 -2
- package/docs/academy/04-APIReferences/01-ReactHooks.md +2 -2
- package/docs/academy/04-APIReferences/06-VetraRemoteDrive.md +160 -0
- package/docs/academy/04-APIReferences/renown-sdk/00-Overview.md +316 -0
- package/docs/academy/04-APIReferences/renown-sdk/01-Authentication.md +672 -0
- package/docs/academy/04-APIReferences/renown-sdk/02-APIReference.md +957 -0
- package/docs/academy/04-APIReferences/renown-sdk/_category_.json +8 -0
- package/docs/academy/05-Architecture/00-PowerhouseArchitecture.md +7 -39
- package/docs/academy/06-ComponentLibrary/00-DocumentEngineering.md +72 -24
- package/docs/academy/08-Glossary.md +7 -0
- package/docs/academy/10-TodoListTutorial/02-ImplementTodoListDocumentModelReducerOperationHandlers.md +171 -0
- package/docs/academy/10-TodoListTutorial/03-AddTestsForTodoListActions.md +462 -0
- package/docs/academy/10-TodoListTutorial/05-ImplementTodoListDocumentEditorUIComponents.md +422 -0
- package/docs/academy/10-TodoListTutorial/07-AddSharedComponentForShowingTodoListStats.md +370 -0
- package/docusaurus.config.ts +28 -3
- package/package.json +1 -1
- package/sidebars.ts +49 -12
- package/src/css/custom.css +26 -18
- package/static/img/Vetra-logo-dark.svg +11 -0
- package/static/img/vetra-logo-light.svg +11 -0
- package/docs/academy/00-EthereumArgentinaHackathon.md +0 -207
- package/docs/academy/01-GetStarted/04-BuildToDoListEditor.md +0 -218
- package/docs/academy/01-GetStarted/06-ReactorMCP.md +0 -58
- package/docs/academy/05-Architecture/02-ReferencingMonorepoPackages +0 -65
- package/docs/academy/05-Architecture/04-MovingBeyondCRUD +0 -61
- /package/docs/academy/{01-GetStarted → 02-MasteryTrack/01-BuilderEnvironment}/images/Modules.png +0 -0
- /package/docs/academy/{01-GetStarted → 02-MasteryTrack/01-BuilderEnvironment}/images/VetraStudioDrive.png +0 -0
- /package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/06-DocumentTools/{02-RevisionHistoryTimeline → 02-RevisionHistoryTimeline/360/237/232/247"} +0 -0
- /package/docs/academy/05-Architecture/05-DocumentModelTheory/{01-WhatIsADocumentModel → 360/237/232/247 /01-WhatIsADocumentModel"} +0 -0
- /package/docs/academy/05-Architecture/05-DocumentModelTheory/{02-DAOandDocumentsModelsQ+A → 360/237/232/247 /02-DAOandDocumentsModelsQ+A"} +0 -0
- /package/docs/academy/05-Architecture/05-DocumentModelTheory/{02-domain-modeling → 360/237/232/247 /02-domain-modeling"} +0 -0
- /package/docs/academy/05-Architecture/05-DocumentModelTheory/{03-BenefitsOfDocumentModels → 360/237/232/247 /03-BenefitsOfDocumentModels"} +0 -0
- /package/docs/academy/05-Architecture/05-DocumentModelTheory/{04-UtilitiesAndTips → 360/237/232/247 /04-UtilitiesAndTips"} +0 -0
- /package/docs/academy/05-Architecture/05-DocumentModelTheory/{05-best-practices → 360/237/232/247 /05-best-practices"} +0 -0
- /package/docs/academy/05-Architecture/05-DocumentModelTheory/{_category_.json → 360/237/232/247 /_category_.json"} +0 -0
- /package/docs/academy/05-Architecture/05-DocumentModelTheory/{three-data-layers.png → 360/237/232/247 /three-data-layers.png"} +0 -0
|
@@ -1,6 +1,48 @@
|
|
|
1
|
-
# Implement the document model
|
|
1
|
+
# Implement the document model reducers
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
:::tip Tutorial Repository
|
|
4
|
+
📦 **Reference Code**: [step-3-implement-reducer-operation-handlers](https://github.com/powerhouse-inc/todo-tutorial/tree/step-3-implement-reducer-operation-handlers)
|
|
5
|
+
|
|
6
|
+
This step focuses on implementing the reducer logic for add, update, and delete operations.
|
|
7
|
+
:::
|
|
8
|
+
|
|
9
|
+
<details>
|
|
10
|
+
<summary>📖 How to use this tutorial</summary>
|
|
11
|
+
|
|
12
|
+
### Compare your reducer implementation
|
|
13
|
+
|
|
14
|
+
After implementing your reducers:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# Compare your reducers with the reference
|
|
18
|
+
git diff tutorial/step-3-implement-reducer-operation-handlers -- document-models/todo-list/src/reducers/
|
|
19
|
+
|
|
20
|
+
# View the reference reducer implementation
|
|
21
|
+
git show tutorial/step-3-implement-reducer-operation-handlers:document-models/todo-list/src/reducers/todos.ts
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Visual comparison with GitHub Desktop
|
|
25
|
+
|
|
26
|
+
After committing your work, compare visually:
|
|
27
|
+
1. **Branch** menu → **"Compare to Branch..."**
|
|
28
|
+
2. Select `tutorial/step-3-implement-reducer-operation-handlers`
|
|
29
|
+
3. Review differences in the visual interface
|
|
30
|
+
|
|
31
|
+
### If you get stuck
|
|
32
|
+
|
|
33
|
+
View or reset to a specific step:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# View the reducer code
|
|
37
|
+
git show tutorial/step-3-implement-reducer-operation-handlers:document-models/todo-list/src/reducers/todos.ts
|
|
38
|
+
|
|
39
|
+
# Reset to this step (WARNING: loses your changes)
|
|
40
|
+
git reset --hard tutorial/step-3-implement-reducer-operation-handlers
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
</details>
|
|
44
|
+
|
|
45
|
+
In this section, we will implement the operation reducers for the **To-do List** document model. For this, you need to export the document model specification from Connect and import it into your Powerhouse project directory.
|
|
4
46
|
|
|
5
47
|
To export the document model specification, follow the steps in the [Define ToDoList Document Model](/academy/GetStarted/DefineToDoListDocumentModel) section.
|
|
6
48
|
|
|
@@ -22,180 +64,184 @@ Either step will import the document model specification into your Powerhouse pr
|
|
|
22
64
|
|
|
23
65
|

|
|
24
66
|
|
|
25
|
-
##
|
|
67
|
+
## Generate the document model code
|
|
26
68
|
|
|
27
69
|
The next steps will take place in the VSCode editor. Make sure to have it open and the terminal window inside VSCode open as well.
|
|
28
70
|
|
|
29
|
-
To write the operation reducers of the **To-do List** document model, you need to generate the document model code from the document model specification file you have exported
|
|
71
|
+
To write the operation reducers of the **To-do List** document model, you need to generate the document model code from the document model specification file you have exported.
|
|
30
72
|
|
|
31
|
-
|
|
73
|
+
Run the following command in the terminal:
|
|
32
74
|
|
|
33
75
|
```bash
|
|
34
|
-
ph generate
|
|
76
|
+
ph generate TodoList.phd
|
|
35
77
|
```
|
|
36
78
|
|
|
37
|
-
|
|
79
|
+
## Explore the generated reducer file
|
|
80
|
+
|
|
81
|
+
Navigate to `/document-models/todo-list/src/reducers/todos.ts` and open it. You should see scaffolding code that needs to be filled for the three operations you specified:
|
|
38
82
|
|
|
39
|
-
|
|
83
|
+
```typescript
|
|
84
|
+
import type { TodoListTodosOperations } from "todo-tutorial/document-models/todo-list";
|
|
85
|
+
|
|
86
|
+
export const todoListTodosOperations: TodoListTodosOperations = {
|
|
87
|
+
addTodoItemOperation(state, action) {
|
|
88
|
+
// TODO: Implement "addTodoItemOperation" reducer
|
|
89
|
+
throw new Error('Reducer "addTodoItemOperation" not yet implemented');
|
|
90
|
+
},
|
|
91
|
+
updateTodoItemOperation(state, action) {
|
|
92
|
+
// TODO: Implement "updateTodoItemOperation" reducer
|
|
93
|
+
throw new Error('Reducer "updateTodoItemOperation" not yet implemented');
|
|
94
|
+
},
|
|
95
|
+
deleteTodoItemOperation(state, action) {
|
|
96
|
+
// TODO: Implement "deleteTodoItemOperation" reducer
|
|
97
|
+
throw new Error('Reducer "deleteTodoItemOperation" not yet implemented');
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
```
|
|
40
101
|
|
|
41
|
-
|
|
102
|
+
## Implement the operation reducers
|
|
42
103
|
|
|
43
|
-
|
|
104
|
+
Let's implement each reducer one by one.
|
|
44
105
|
|
|
45
|
-
|
|
46
|
-
|
|
106
|
+
### Step 1: Add the import
|
|
107
|
+
|
|
108
|
+
First, add the `generateId` import at the top of the file:
|
|
47
109
|
|
|
48
|
-
<details>
|
|
49
|
-
<summary>Operation Reducers</summary>
|
|
50
110
|
```typescript
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
//
|
|
63
|
-
state
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
//
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
// REMARKS: We only update fields that were included in the input
|
|
82
|
-
// This allows for partial updates (only update what was provided)
|
|
83
|
-
if (action.input.text) {
|
|
84
|
-
item.text = action.input.text;
|
|
85
|
-
}
|
|
86
|
-
if (typeof action.input.checked === 'boolean') {
|
|
87
|
-
item.checked = action.input.checked;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
},
|
|
91
|
-
|
|
92
|
-
// REMARKS: The deleteTodoItemOperation removes an item from the list.
|
|
93
|
-
// This showcases functional programming with array filters for immutable updates.
|
|
94
|
-
deleteTodoItemOperation(state, action, dispatch) {
|
|
95
|
-
// REMARKS: Create a new array containing only items that don't match the ID
|
|
96
|
-
// This is a common pattern for immutable array updates in JavaScript
|
|
97
|
-
state.items = state.items.filter(item => item.id !== action.input.id);
|
|
98
|
-
},
|
|
111
|
+
// added-line
|
|
112
|
+
import { generateId } from "document-model/core";
|
|
113
|
+
import type { TodoListTodosOperations } from "todo-tutorial/document-models/todo-list";
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Step 2: Implement addTodoItemOperation
|
|
117
|
+
|
|
118
|
+
Replace the boilerplate `addTodoItemOperation` with the actual implementation:
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
export const todoListTodosOperations: TodoListTodosOperations = {
|
|
122
|
+
// removed-start
|
|
123
|
+
addTodoItemOperation(state, action) {
|
|
124
|
+
// TODO: Implement "addTodoItemOperation" reducer
|
|
125
|
+
throw new Error('Reducer "addTodoItemOperation" not yet implemented');
|
|
126
|
+
},
|
|
127
|
+
// removed-end
|
|
128
|
+
// added-start
|
|
129
|
+
addTodoItemOperation(state, action) {
|
|
130
|
+
const id = generateId();
|
|
131
|
+
state.items.push({ ...action.input, id, checked: false });
|
|
132
|
+
},
|
|
133
|
+
// added-end
|
|
134
|
+
updateTodoItemOperation(state, action) {
|
|
135
|
+
// ...
|
|
136
|
+
},
|
|
137
|
+
deleteTodoItemOperation(state, action) {
|
|
138
|
+
// ...
|
|
139
|
+
},
|
|
99
140
|
};
|
|
141
|
+
```
|
|
100
142
|
|
|
101
|
-
|
|
102
|
-
|
|
143
|
+
**What's happening here:**
|
|
144
|
+
- We generate a unique ID using `generateId()` from `document-model/core`
|
|
145
|
+
- We push a new item to the `items` array with the input text, new ID, and `checked: false`
|
|
146
|
+
- Under the hood, Powerhouse uses Immer.js, so this "mutation" is actually immutable
|
|
147
|
+
|
|
148
|
+
### Step 3: Implement updateTodoItemOperation
|
|
149
|
+
|
|
150
|
+
Replace the boilerplate `updateTodoItemOperation`:
|
|
103
151
|
|
|
104
|
-
|
|
152
|
+
```typescript
|
|
153
|
+
// removed-start
|
|
154
|
+
updateTodoItemOperation(state, action) {
|
|
155
|
+
// TODO: Implement "updateTodoItemOperation" reducer
|
|
156
|
+
throw new Error('Reducer "updateTodoItemOperation" not yet implemented');
|
|
157
|
+
},
|
|
158
|
+
// removed-end
|
|
159
|
+
// added-start
|
|
160
|
+
updateTodoItemOperation(state, action) {
|
|
161
|
+
const item = state.items.find((item) => item.id === action.input.id);
|
|
162
|
+
if (!item) return;
|
|
163
|
+
item.text = action.input.text ?? item.text;
|
|
164
|
+
item.checked = action.input.checked ?? item.checked;
|
|
165
|
+
},
|
|
166
|
+
// added-end
|
|
167
|
+
```
|
|
105
168
|
|
|
106
|
-
|
|
169
|
+
**What's happening here:**
|
|
170
|
+
- We find the item by its ID
|
|
171
|
+
- We return early if the item is not found
|
|
172
|
+
- We use nullish coalescing (`??`) to only update fields that are provided
|
|
107
173
|
|
|
108
|
-
|
|
174
|
+
### Step 4: Implement deleteTodoItemOperation
|
|
109
175
|
|
|
110
|
-
|
|
176
|
+
Replace the boilerplate `deleteTodoItemOperation`:
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
// removed-start
|
|
180
|
+
deleteTodoItemOperation(state, action) {
|
|
181
|
+
// TODO: Implement "deleteTodoItemOperation" reducer
|
|
182
|
+
throw new Error('Reducer "deleteTodoItemOperation" not yet implemented');
|
|
183
|
+
},
|
|
184
|
+
// removed-end
|
|
185
|
+
// added-start
|
|
186
|
+
deleteTodoItemOperation(state, action) {
|
|
187
|
+
state.items = state.items.filter((item) => item.id !== action.input.id);
|
|
188
|
+
},
|
|
189
|
+
// added-end
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
**What's happening here:**
|
|
193
|
+
- We filter out the item with the matching ID
|
|
194
|
+
- This creates a new array without the deleted item
|
|
195
|
+
|
|
196
|
+
## Complete reducer file
|
|
197
|
+
|
|
198
|
+
Here's the complete implementation:
|
|
111
199
|
|
|
112
200
|
<details>
|
|
113
|
-
<summary>
|
|
201
|
+
<summary>Complete todos.ts</summary>
|
|
202
|
+
|
|
114
203
|
```typescript
|
|
115
|
-
import
|
|
116
|
-
import {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
// REMARKS: We apply the operation to get a new document state
|
|
137
|
-
// Note how we use the creators to generate the operation action
|
|
138
|
-
const updatedDocument = reducer(document, creators.addTodoItem(input));
|
|
139
|
-
|
|
140
|
-
// REMARKS: We verify that:
|
|
141
|
-
// 1. The operation was recorded in the document's operation history
|
|
142
|
-
// 2. The state was updated according to our reducer implementation
|
|
143
|
-
expect(updatedDocument.operations.global).toHaveLength(1);
|
|
144
|
-
expect(updatedDocument.operations.global[0].type).toBe('ADD_TODO_ITEM');
|
|
145
|
-
expect(updatedDocument.state.global.items).toHaveLength(1);
|
|
146
|
-
expect(updatedDocument.state.global.items[0].text).toBe('Buy milk');
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
it('should handle updateTodoItem operation', () => {
|
|
150
|
-
// REMARKS: For update, we first need to add an item, then update it
|
|
151
|
-
// This demonstrates the sequential application of operations
|
|
152
|
-
const addInput = { id: '1', text: 'Buy milk' };
|
|
153
|
-
const updateInput = { id: '1', text: 'Buy bread' };
|
|
154
|
-
|
|
155
|
-
// REMARKS: Operations are applied in sequence, building up document state
|
|
156
|
-
const createdDocument = reducer(document, creators.addTodoItem(addInput));
|
|
157
|
-
const updatedDocument = reducer(createdDocument, creators.updateTodoItem(updateInput));
|
|
158
|
-
|
|
159
|
-
// REMARKS: Now we have 2 operations in history, and the state reflects both
|
|
160
|
-
expect(updatedDocument.operations.global).toHaveLength(2);
|
|
161
|
-
expect(updatedDocument.state.global.items[0].text).toBe('Buy bread');
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
it('should handle deleteTodoItem operation', () => {
|
|
165
|
-
// REMARKS: Similar pattern - add an item, then delete it
|
|
166
|
-
const addInput = { id: '1', text: 'Buy milk' };
|
|
167
|
-
const deleteInput = { id: '1' };
|
|
168
|
-
|
|
169
|
-
const createdDocument = reducer(document, creators.addTodoItem(addInput));
|
|
170
|
-
const updatedDocument = reducer(createdDocument, creators.deleteTodoItem(deleteInput));
|
|
171
|
-
|
|
172
|
-
// REMARKS: After deletion, we still have 2 operations in history,
|
|
173
|
-
// but the items array is now empty again in the final state
|
|
174
|
-
expect(updatedDocument.operations.global).toHaveLength(2);
|
|
175
|
-
expect(updatedDocument.state.global.items).toHaveLength(0);
|
|
176
|
-
});
|
|
177
|
-
});
|
|
178
|
-
````
|
|
204
|
+
import { generateId } from "document-model/core";
|
|
205
|
+
import type { TodoListTodosOperations } from "todo-tutorial/document-models/todo-list";
|
|
206
|
+
|
|
207
|
+
export const todoListTodosOperations: TodoListTodosOperations = {
|
|
208
|
+
addTodoItemOperation(state, action) {
|
|
209
|
+
const id = generateId();
|
|
210
|
+
state.items.push({ ...action.input, id, checked: false });
|
|
211
|
+
},
|
|
212
|
+
|
|
213
|
+
updateTodoItemOperation(state, action) {
|
|
214
|
+
const item = state.items.find((item) => item.id === action.input.id);
|
|
215
|
+
if (!item) return;
|
|
216
|
+
item.text = action.input.text ?? item.text;
|
|
217
|
+
item.checked = action.input.checked ?? item.checked;
|
|
218
|
+
},
|
|
219
|
+
|
|
220
|
+
deleteTodoItemOperation(state, action) {
|
|
221
|
+
state.items = state.items.filter((item) => item.id !== action.input.id);
|
|
222
|
+
},
|
|
223
|
+
};
|
|
224
|
+
```
|
|
179
225
|
|
|
180
226
|
</details>
|
|
181
227
|
|
|
182
|
-
|
|
228
|
+
:::tip Check your work
|
|
229
|
+
|
|
230
|
+
To make sure everything works as expected:
|
|
183
231
|
|
|
184
232
|
```bash
|
|
185
|
-
|
|
186
|
-
|
|
233
|
+
# Check types compile correctly
|
|
234
|
+
pnpm tsc
|
|
187
235
|
|
|
188
|
-
|
|
236
|
+
# Check linting passes
|
|
237
|
+
pnpm lint
|
|
189
238
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
Tests 5 passed (5)
|
|
193
|
-
Start at 12:04:57
|
|
194
|
-
Duration 417ms (transform 79ms, setup 0ms, collect 174ms, tests 12ms, environment 0ms, prepare 158ms)
|
|
239
|
+
# Compare with reference implementation
|
|
240
|
+
git diff tutorial/step-3-implement-reducer-operation-handlers -- document-models/todo-list/src/reducers/
|
|
195
241
|
```
|
|
196
242
|
|
|
197
|
-
|
|
243
|
+
:::
|
|
198
244
|
|
|
199
|
-
## Up next:
|
|
245
|
+
## Up next: Writing tests
|
|
200
246
|
|
|
201
|
-
In the next chapter
|
|
247
|
+
In the next chapter, you'll write comprehensive tests to verify your reducer implementations work correctly.
|