1- import { combine , createEvent , createStore , sample } from 'effector' ;
2- import { keyval , lazy , KeyvalWithState } from '@effector/model' ;
1+ import {
2+ combine ,
3+ createEvent ,
4+ createStore ,
5+ type EventCallable ,
6+ sample ,
7+ } from 'effector' ;
8+ import { KeyOrKeys , keyval , lazy , type Keyval } from '@effector/model' ;
39import { createAction } from 'effector-action' ;
410
511type InputTodo = {
@@ -49,9 +55,11 @@ export const todoList = keyval(() => {
4955 }
5056 } ) ;
5157
52- const childsList = keyval ( todoList ) as KeyvalWithState <
58+ const childsList = keyval ( todoList ) as Keyval <
5359 TodoInputShape ,
54- TodoShape
60+ TodoShape ,
61+ { removeCompleted : EventCallable < void > ; toggleAll : EventCallable < void > } ,
62+ any
5563 > ;
5664
5765 const $subtasksTotal = lazy ( ( ) => {
@@ -106,20 +114,14 @@ export const todoList = keyval(() => {
106114 target : $completed ,
107115 } ) ;
108116
109- const [ addSubtask ] = lazy ( [ 'event' ] , ( ) => [
110- createAction ( {
111- source : $todoDraft ,
112- target : { todoDraft : $todoDraft , add : childsList . edit . add } ,
113- fn ( target , todoDraft ) {
114- target . add ( {
115- id : createID ( ) ,
116- title : todoDraft ,
117- subtasks : [ ] ,
118- } ) ;
119- target . todoDraft . reinit ( ) ;
120- } ,
121- } ) ,
122- ] ) ;
117+ const [ addSubtask , removeCompleted , toggleAll ] = lazy (
118+ [ 'event' , 'event' , 'event' ] ,
119+ ( ) => [
120+ createAddTodo ( childsList ) ,
121+ createRemoveCompleted ( childsList ) ,
122+ createToggleAll ( childsList ) ,
123+ ] ,
124+ ) ;
123125
124126 return {
125127 key : 'id' ,
@@ -139,11 +141,86 @@ export const todoList = keyval(() => {
139141 editMode,
140142 toggleCompleted,
141143 addSubtask,
144+ removeCompleted,
145+ toggleAll,
142146 } ,
143147 optional : [ 'completed' , 'editing' , 'titleDraft' ] ,
144148 } ;
145149} ) ;
146150
151+ function createRemoveCompleted (
152+ todoList : Keyval <
153+ any ,
154+ TodoShape ,
155+ { removeCompleted : EventCallable < void > } ,
156+ any
157+ > ,
158+ ) {
159+ return createAction ( {
160+ source : todoList . $keys ,
161+ target : {
162+ removeCompletedNestedChilds : todoList . api . removeCompleted ,
163+ /** effector-action messing with function payloads so we need to wrap data to pass thru it */
164+ removeItems : todoList . edit . remove . prepend < {
165+ fn : ( entity : TodoShape ) => boolean ;
166+ } > ( ( { fn } ) => fn ) ,
167+ } ,
168+ fn ( target , childKeys ) {
169+ target . removeCompletedNestedChilds ( {
170+ key : childKeys ,
171+ data : Array . from ( childKeys , ( ) => undefined ) ,
172+ } ) ;
173+ target . removeItems ( {
174+ fn : ( { completed } ) => completed ,
175+ } ) ;
176+ } ,
177+ } ) ;
178+ }
179+
180+ function createToggleAll (
181+ todoList : Keyval < any , TodoShape , { toggleAll : EventCallable < void > } , any > ,
182+ ) {
183+ return createAction ( {
184+ source : todoList . $keys ,
185+ target : {
186+ toggleAllNestedChilds : todoList . api . toggleAll ,
187+ mapItems : todoList . edit . map ,
188+ } ,
189+ fn ( target , childKeys ) {
190+ target . toggleAllNestedChilds ( {
191+ key : childKeys ,
192+ data : Array . from ( childKeys , ( ) => undefined ) ,
193+ } ) ;
194+ target . mapItems ( {
195+ keys : childKeys ,
196+ map : ( { completed } ) => ( { completed : ! completed } ) ,
197+ } ) ;
198+ } ,
199+ } ) ;
200+ }
201+
202+ function createAddTodo ( todoList : Keyval < any , TodoShape , any , any > ) {
203+ return createAction ( {
204+ source : $todoDraft ,
205+ target : {
206+ add : todoList . edit . add ,
207+ todoDraft : $todoDraft ,
208+ } ,
209+ fn ( target , todoDraft ) {
210+ if ( ! todoDraft . trim ( ) ) return ;
211+ target . add ( {
212+ id : createID ( ) ,
213+ title : todoDraft . trim ( ) ,
214+ subtasks : [ ] ,
215+ } ) ;
216+ target . todoDraft . reinit ( ) ;
217+ } ,
218+ } ) ;
219+ }
220+
221+ export const removeCompleted = createRemoveCompleted ( todoList ) ;
222+ export const toggleAll = createToggleAll ( todoList ) ;
223+
147224export const $totalSize = combine ( todoList . $items , ( items ) => {
148225 return items . reduce ( ( acc , { subtasksTotal } ) => acc + 1 + subtasksTotal , 0 ) ;
149226} ) ;
@@ -156,22 +233,7 @@ function createID() {
156233 return `id-${ Math . random ( ) . toString ( 36 ) . slice ( 2 , 10 ) } ` ;
157234}
158235
159- export const addTodo = createAction ( {
160- source : $todoDraft ,
161- target : {
162- add : todoList . edit . add ,
163- todoDraft : $todoDraft ,
164- } ,
165- fn ( target , todoDraft ) {
166- if ( ! todoDraft . trim ( ) ) return ;
167- target . add ( {
168- id : createID ( ) ,
169- title : todoDraft . trim ( ) ,
170- subtasks : [ ] ,
171- } ) ;
172- target . todoDraft . reinit ( ) ;
173- } ,
174- } ) ;
236+ export const addTodo = createAddTodo ( todoList ) ;
175237
176238function addIds ( inputs : InputTodo [ ] ) : TodoInputShape [ ] {
177239 return inputs . map ( ( { title, subtasks = [ ] } ) => ( {
0 commit comments