// entry-service.ts
import {
Injectable,
Service,
Reducer,
ImmerReducer,
Effect,
EffectAction,
DefineAction
} from "service-x";
import { Entry, fetchEntries } from "./fetch-entries";
import { Observable, merge } from "rxjs";
import {
map,
distinctUntilChanged,
combineLatest,
switchMap,
debounceTime
} from "rxjs/operators";
interface State {
entries: Entry[];
keyword?: string;
}
@Injectable()
export class EntryService extends Service<State> {
defaultState: State = {
entries: []
};
// trigger loadEntries reload
@DefineAction()
reload$!: Observable<void>;
@ImmerReducer()
setKeyword(state: State, keyword: string) {
state.keyword = keyword;
}
@ImmerReducer()
setEntries(state: State, entries: Entry[]) {
state.entries = entries;
}
@Reducer()
reset(): State {
return this.defaultState;
}
@Effect()
loadEntries(
trigger$: Observable<void>,
state$: Observable<State>
): Observable<EffectAction> {
const keyword$ = state$.pipe(
map(state => state.keyword),
distinctUntilChanged(),
// debounce the input
debounceTime(500)
);
return merge(trigger$, this.reload$).pipe(
combineLatest(keyword$, (_, keyword) => keyword),
switchMap(keyword => fetchEntries(keyword)),
map(entries => this.actions().setEntries(entries))
);
}
}