rss-backends-actions.ts 7.23 KB
Newer Older
1
import {produce} from 'immer';
2 3
import {Container} from 'aurelia-framework';
import * as LogManager from 'aurelia-logging';
4
import {Store} from 'aurelia-store';
5
import * as constants from '../constants';
6
import {Article} from '../models/Article';
7
import {Category} from '../models/Category';
8
import {Counter} from '../models/Counter';
9 10 11
import {Backend} from '../services/backend';
import {TestBackend} from '../services/backends/test';
import {TTRss} from '../services/backends/ttrss';
12
import {doRouterNavigation} from './actions';
13 14 15 16
import {Auth, SelectableBackend, State} from './state';

const logger = LogManager.getLogger('aurss:store:actions:rss');

17 18 19
export const selectBackend = produce((state: State, selectedBackend: SelectableBackend) => {
    state.selectedBackend = selectedBackend;
});
20

21 22 23 24 25 26
/**
 * This action is meant to be called when the authenticate method of the backend succeeds.
 * @param state
 * @param authInfos
 */

27
export function authenticateSucceeded(state: State, authInfos: Auth) {
28 29
    const newState = Object.assign({}, state);
    newState.authentication = authInfos;
30 31 32
    return doRouterNavigation(
        newState, 'display-articles-from-category', { categoryId: constants.DEFAULT_CATEGORY},
    );
33
}
34

35 36 37 38
/**
 * This action is meant to be called when the isLoggedIn method of the backend returns true.
 * @param state
 */
39 40 41
export const isLoggedIn = produce((state: State) => {
    state.authentication.isLoggedIn = true;
});
42

43 44
export const fetchArticles = produce((state: State, categoryId: string) => {
    state.rss.isFetching = true;
45

46
    getBackend(state.selectedBackend).getArticles(categoryId);
47
});
48

49 50 51 52
export const receivedArticles = produce((state: State, articles: Article[]) => {
    state.rss.isFetching = false;
    state.rss.displayedArticles = articles;
});
53

54 55 56 57 58
export function fetchCategories(state: State) {
    getBackend(state.selectedBackend).getCategories();
    return state;
}

59 60 61
export const receivedCategories = produce((state: State, categories: Category[]) => {
    state.rss.categories = categories;
});
62

63 64 65 66 67
export function fetchCounters(state: State) {
    getBackend(state.selectedBackend).getCounters();
    return state;
}

68
export const receivedCounters = produce((state: State, counters: Counter[]) => {
69 70 71 72 73
    const categoryIdToCounters = counters.reduce((acc, counter) => {
        acc[counter.categoryId] = counter.unreadCount;
        return acc;
    }, {});

74
    state.rss.categories = state.rss.categories.map((category) => ({
75 76 77
        ...category,
        unreadCount: categoryIdToCounters[category.id],
    }));
78
});
79

80 81 82 83 84 85
/**
 * Do a request to the backend to mark an article as read.
 * @param state
 * @param article
 * @param discard: If this is true, the article will be added to articlesToDiscards.
 */
86
export const markAsRead = produce((state: State, article: Article, { discard = false } = {}) => {
87
    getBackend(state.selectedBackend).markAsRead(article);
88

89
    if (!discard) {
90
        return;
91
    }
92 93 94

    state.rss.articlesToDiscards.push(article);
});
95

96
export function markAsUnread(state: State, article: Article) {
97
    getBackend(state.selectedBackend).markAsUnread(article);
98 99 100
    return state;
}

101
export function markAsFavorite(state: State, article: Article) {
102
    getBackend(state.selectedBackend).markAsFavorite(article);
103
    return state;
104 105 106
}

export function unmarkAsFavorite(state: State, article: Article) {
107
    getBackend(state.selectedBackend).unmarkAsFavorite(article);
108 109 110
    return state;
}

111
export const markedAsRead = produce((state: State, article: Article) => {
112
    fetchCounters(state);
113

114
    if (state.rss.articlesToDiscards.includes(article)) {
115 116
        removeArticle(state.rss.displayedArticles, article);
        return;
117 118
    }

119 120 121
    const articleToUpdate = findArticleInArray(state.rss.displayedArticles, article);
    if (articleToUpdate) {
        articleToUpdate.isRead = true;
122
    }
123
});
124

125 126 127 128 129
function removeArticle(articles: Article[], article: Article) {
    const articleToRemove = findArticleInArray(articles, article);
    if (articleToRemove) {
        const indexToRemove = articles.indexOf(articleToRemove);
        articles.splice(indexToRemove, 1);
130
    }
131
}
132

133 134
function findArticleInArray(articles: Article[], article: Article): Article | undefined {
    return articles.find(elt => elt.id === article.id);
135 136
}

137
export const markedAsUnread = produce((state: State, article: Article) => {
138
    fetchCounters(state);
139

140 141 142 143 144
    const articleToUpdate = findArticleInArray(state.rss.displayedArticles, article);
    if (articleToUpdate) {
        articleToUpdate.isRead = false;
    }
});
145

146 147 148 149 150 151 152 153 154 155 156 157 158
export const markedAsFavorite = produce((state: State, article: Article) => {
    const articleToUpdate = findArticleInArray(state.rss.displayedArticles, article);
    if (articleToUpdate) {
        articleToUpdate.isFavorite = true;
    }
});

export const unmarkedAsFavorite = produce((state: State, article: Article) => {
    const articleToUpdate = findArticleInArray(state.rss.displayedArticles, article);
    if (articleToUpdate) {
        articleToUpdate.isFavorite = false;
    }
});
159

160
export function openArticle(state: State, article: Article) {
161 162 163 164
    const tab = window.open(article.link, '_blank');
    if (tab) {
        tab.focus();
    }
165 166 167 168

    return state;
}

169 170 171 172 173 174 175 176 177 178
export function getBackend(selectedBackend: SelectableBackend): Backend {
    switch (selectedBackend) {
        case SelectableBackend.ttrss:
            return Container.instance.get(TTRss) as Backend;
        case SelectableBackend.test:
            return Container.instance.get(TestBackend) as Backend;
        default:
            logger.error('An unsupported backend was requested, return the default test backend');
            return Container.instance.get(TestBackend) as Backend;
    }
179
}
180 181 182

// This must be exported because to tests some component that uses dispatchify,
// these actions must be registered.
183
export function registerRssBackendsActions(store: Store<State>) {
184
    store.registerAction(
185
        'selectBackend',
186 187
        selectBackend,
    );
188
    store.registerAction(
189
        'authenticateSucceeded',
190 191
        authenticateSucceeded,
    );
192
    store.registerAction(
193
        'isLoggedIn',
194 195
        isLoggedIn,
    );
196
    store.registerAction(
197
        'markAsRead',
198 199 200
        markAsRead,
    );
    store.registerAction(
201
        'markAsUnread',
202 203 204
        markAsUnread,
    );
    store.registerAction(
205
        'markedAsRead',
206 207
        markedAsRead,
    );
208
    store.registerAction(
209
        'markAsFavorite',
210 211 212
        markAsFavorite,
    );
    store.registerAction(
213
        'unmarkAsFavorite',
214 215
        unmarkAsFavorite,
    );
216
    store.registerAction(
217
        'markedAsUnread',
218 219
        markedAsUnread,
    );
220
    store.registerAction(
221
        'markedAsFavorite',
222 223 224
        markedAsFavorite,
    );
    store.registerAction(
225
        'unmarkedAsFavorite',
226 227
        unmarkedAsFavorite,
    );
228
    store.registerAction(
229
        'openArticle',
230 231
        openArticle,
    );
232
    store.registerAction(
233
        'fetchArticles',
234
        fetchArticles,
235
    );
236
    store.registerAction(
237
        'receivedArticles',
238
        receivedArticles,
239
    );
240
    store.registerAction(
241
        'fetchCategories',
242 243 244
        fetchCategories,
    );
    store.registerAction(
245
        'receivedCategories',
246 247
        receivedCategories,
    );
248
    store.registerAction(
249
        'fetchCounters',
250 251 252
        fetchCounters,
    );
    store.registerAction(
253
        'receivedCounters',
254 255
        receivedCounters,
    );
256
}