PageSourceSearch

https://csnovels.com/store/actions.js

js csnovels.com collected 2026-10-02 01:26:38 UTC 7,410 bytes, 327 lines download raw bytes

1/**
2 * Redux Action Creators
3 * Centralized actions for all state mutations
4 * PRODUCTION READY
5 */
6
7// ===== USER ACTIONS =====
8const userLoginStart = () => ({
9  type: "USER_LOGIN_START",
10});
11
12const userLoginSuccess = (userData, tier) => ({
13  type: "USER_LOGIN_SUCCESS",
14  payload: { data: userData, tier },
15});
16
17const userLoginFailure = (error) => ({
18  type: "USER_LOGIN_FAILURE",
19  payload: error,
20});
21
22const userLogout = () => ({
23  type: "USER_LOGOUT",
24});
25
26const userUpdate = (userData) => ({
27  type: "USER_UPDATE",
28  payload: userData,
29});
30
31// ===== BOOKS ACTIONS =====
32const fetchBooksStart = () => ({
33  type: "FETCH_BOOKS_START",
34});
35
36const fetchBooksSuccess = (books) => ({
37  type: "FETCH_BOOKS_SUCCESS",
38  payload: books,
39});
40
41const fetchBooksFailure = (error) => ({
42  type: "FETCH_BOOKS_FAILURE",
43  payload: error,
44});
45
46const filterBooks = (filteredBooks) => ({
47  type: "FILTER_BOOKS",
48  payload: filteredBooks,
49});
50
51const setCurrentBook = (book) => ({
52  type: "SET_CURRENT_BOOK",
53  payload: book,
54});
55
56// ===== CHAPTER ACTIONS =====
57const fetchChapterStart = () => ({
58  type: "FETCH_CHAPTER_START",
59});
60
61const fetchChapterSuccess = (chapter) => ({
62  type: "FETCH_CHAPTER_SUCCESS",
63  payload: chapter,
64});
65
66const fetchChapterFailure = (error) => ({
67  type: "FETCH_CHAPTER_FAILURE",
68  payload: error,
69});
70
71const cacheChapter = (chapterId, data) => ({
72  type: "CACHE_CHAPTER",
73  payload: { chapterId, data },
74});
75
76// ===== UI ACTIONS =====
77const toggleAds = (visibility) => ({
78  type: "TOGGLE_ADS",
79  payload: visibility,
80});
81
82const toggleInfiniteScroll = (enabled) => ({
83  type: "TOGGLE_INFINITE_SCROLL",
84  payload: enabled,
85});
86
87const addToast = (id, message, type = "info", duration = 3000) => ({
88  type: "ADD_TOAST",
89  payload: { id, message, type, duration },
90});
91
92const removeToast = (id) => ({
93  type: "REMOVE_TOAST",
94  payload: id,
95});
96
97const toggleSidebar = () => ({
98  type: "TOGGLE_SIDEBAR",
99});
100
101// ===== CACHE ACTIONS =====
102const updateCacheMetadata = (metadata) => ({
103  type: "UPDATE_CACHE_METADATA",
104  payload: metadata,
105});
106
107const clearCache = () => ({
108  type: "CLEAR_CACHE",
109});
110
111// ===== ASYNC THUNK-LIKE ACTIONS (Simplified) =====
112/**
113 * Login user with error handling and state management
114 */
115async function loginUser(email, password) {
116  try {
117    if (!appStore) {
118      throw new Error("Redux store not initialized");
119    }
120
121    appStore.dispatch(userLoginStart());
122
123    const response = await fetch("/signin", {
124      method: "POST",
125      headers: { "Content-Type": "application/json" },
126      body: JSON.stringify({ email, password }),
127    });
128
129    if (!response.ok) {
130      throw new Error(`Login failed: ${response.statusText}`);
131    }
132
133    const data = await response.json();
134    appStore.dispatch(userLoginSuccess(data.user, data.tier));
135    appStore.dispatch(
136      addToast(`toast-${Date.now()}`, "Logged in successfully", "success"),
137    );
138
139    if (typeof logger !== "undefined") {
140      logger.info("Auth", "User logged in successfully");
141    }
142
143    return data;
144  } catch (error) {
145    appStore.dispatch(userLoginFailure(error.message));
146    appStore.dispatch(addToast(`toast-${Date.now()}`, error.message, "error"));
147
148    if (typeof logger !== "undefined") {
149      logger.error("Auth", "Login failed", error);
150    }
151
152    throw error;
153  }
154}
155
156/**
157 * Load books with caching strategy
158 */
159async function loadBooks(forceRefresh = false) {
160  try {
161    if (!appStore) {
162      throw new Error("Redux store not initialized");
163    }
164
165    const state = appStore.getState();
166    const cacheAge = Date.now() - (state.books.lastFetchTime || 0);
167    const CACHE_TTL = 5 * 60 * 1000; // 5 minutes
168
169    // Use cache if valid
170    if (
171      !forceRefresh &&
172      cacheAge < CACHE_TTL &&
173      state.books.allBooks.length > 0
174    ) {
175      if (typeof logger !== "undefined") {
176        logger.debug("Books", "Using cached books");
177      }
178      return state.books.allBooks;
179    }
180
181    appStore.dispatch(fetchBooksStart());
182
183    const response = await fetch("/allbooks");
184    if (!response.ok) {
185      throw new Error(`Failed to fetch books: ${response.statusText}`);
186    }
187
188    const books = await response.json();
189    appStore.dispatch(fetchBooksSuccess(books));
190
191    if (typeof logger !== "undefined") {
192      logger.info("Books", `Loaded ${books.length} books`);
193    }
194
195    return books;
196  } catch (error) {
197    appStore.dispatch(fetchBooksFailure(error.message));
198    appStore.dispatch(
199      addToast(`toast-${Date.now()}`, "Failed to load books", "error"),
200    );
201
202    if (typeof logger !== "undefined") {
203      logger.error("Books", "Failed to load books", error);
204    }
205
206    throw error;
207  }
208}
209
210/**
211 * Load chapter with caching strategy
212 */
213async function loadChapter(slug, chapterNumber) {
214  try {
215    if (!appStore) {
216      throw new Error("Redux store not initialized");
217    }
218
219    const state = appStore.getState();
220
221    // Check if already cached
222    const cacheKey = `${slug}-${chapterNumber}`;
223    if (state.chapters.cache[cacheKey]) {
224      if (typeof logger !== "undefined") {
225        logger.debug("Chapter", `Using cached chapter: ${cacheKey}`);
226      }
227      appStore.dispatch(fetchChapterSuccess(state.chapters.cache[cacheKey]));
228      return state.chapters.cache[cacheKey];
229    }
230
231    appStore.dispatch(fetchChapterStart());
232
233    const response = await fetch(
234      `/getsinglechapter?slug=${slug}&chapter=${chapterNumber}`,
235    );
236    if (!response.ok) {
237      throw new Error(`Failed to fetch chapter: ${response.statusText}`);
238    }
239
240    const chapter = await response.json();
241    appStore.dispatch(cacheChapter(cacheKey, chapter));
242    appStore.dispatch(fetchChapterSuccess(chapter));
243
244    if (typeof logger !== "undefined") {
245      logger.info(
246        "Chapter",
247        `Loaded chapter: ${slug} - Chapter ${chapterNumber}`,
248      );
249    }
250
251    return chapter;
252  } catch (error) {
253    appStore.dispatch(fetchChapterFailure(error.message));
254    appStore.dispatch(
255      addToast(`toast-${Date.now()}`, "Failed to load chapter", "error"),
256    );
257
258    if (typeof logger !== "undefined") {
259      logger.error(
260        "Chapter",
261        `Failed to load chapter: ${slug}-${chapterNumber}`,
262        error,
263      );
264    }
265
266    throw error;
267  }
268}
269
270/**
271 * Logout user
272 */
273function logoutUser() {
274  try {
275    if (!appStore) {
276      throw new Error("Redux store not initialized");
277    }
278
279    appStore.dispatch(userLogout());
280    appStore.dispatch(clearCache());
281    localStorage.removeItem("user");
282    localStorage.removeItem("token");
283
284    appStore.dispatch(
285      addToast(`toast-${Date.now()}`, "Logged out successfully", "success"),
286    );
287
288    if (typeof logger !== "undefined") {
289      logger.info("Auth", "User logged out");
290    }
291  } catch (error) {
292    if (typeof logger !== "undefined") {
293      logger.error("Auth", "Logout failed", error);
294    }
295  }
296}
297
298// Export for use in other modules
299if (typeof module !== "undefined" && module.exports) {
300  module.exports = {
301    userLoginStart,
302    userLoginSuccess,
303    userLoginFailure,
304    userLogout,
305    userUpdate,
306    fetchBooksStart,
307    fetchBooksSuccess,
308    fetchBooksFailure,
309    filterBooks,
310    setCurrentBook,
311    fetchChapterStart,
312    fetchChapterSuccess,
313    fetchChapterFailure,
314    cacheChapter,
315    toggleAds,
316    toggleInfiniteScroll,
317    addToast,
318    removeToast,
319    toggleSidebar,
320    updateCacheMetadata,
321    clearCache,
322    loginUser,
323    loadBooks,
324    loadChapter,
325    logoutUser,
326  };
327}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.