/ services / readChapterService.ts
readChapterService.ts
  1  import AsyncStorage from '@react-native-async-storage/async-storage';
  2  import { getMangaData, setMangaData } from './bookmarkService';
  3  import { MangaData } from '@/types';
  4  
  5  const LAST_READ_MANGA_KEY = 'last_read_manga';
  6  
  7  export interface LastReadManga {
  8    id: string;
  9    title: string;
 10    chapterNumber: string;
 11    timestamp: number;
 12  }
 13  
 14  export const getReadChapters = async (mangaId: string): Promise<string[]> => {
 15    try {
 16      const mangaData = await getMangaData(mangaId);
 17      return mangaData?.readChapters || [];
 18    } catch (error) {
 19      console.error('Error getting read chapters:', error);
 20      return [];
 21    }
 22  };
 23  
 24  export const getLastReadChapter = async (
 25    mangaId: string
 26  ): Promise<string | null> => {
 27    try {
 28      const mangaData = await getMangaData(mangaId);
 29      if (!mangaData?.readChapters || mangaData.readChapters.length === 0) {
 30        return 'Not started';
 31      }
 32  
 33      // Calculate the highest chapter number from readChapters array
 34      const highestChapter = Math.max(
 35        ...mangaData.readChapters.map((ch) => parseFloat(ch))
 36      ).toString();
 37  
 38      return `Chapter ${highestChapter}`;
 39    } catch (error) {
 40      console.error('Error getting last read chapter:', error);
 41      return null;
 42    }
 43  };
 44  
 45  export const markChapterAsRead = async (
 46    mangaId: string,
 47    chapterNumber: string,
 48    currentReadChapters: string[]
 49  ): Promise<string[]> => {
 50    try {
 51      const mangaData = await getMangaData(mangaId);
 52      if (mangaData) {
 53        const updatedReadChapters = Array.from(
 54          new Set([...currentReadChapters, chapterNumber])
 55        );
 56        const highestChapter = Math.max(
 57          ...updatedReadChapters.map((ch) => parseFloat(ch))
 58        ).toString();
 59        await setMangaData({
 60          ...mangaData,
 61          readChapters: updatedReadChapters,
 62          lastReadChapter: highestChapter,
 63          lastUpdated: Date.now(),
 64        });
 65  
 66        // Update last read manga info whenever a chapter is marked as read
 67        await setLastReadManga(mangaId, mangaData.title, chapterNumber);
 68  
 69        return updatedReadChapters;
 70      }
 71      return currentReadChapters;
 72    } catch (error) {
 73      console.error('Error marking chapter as read:', error);
 74      return currentReadChapters;
 75    }
 76  };
 77  export const markChapterAsUnread = async (
 78    mangaId: string,
 79    chapterNumber: string,
 80    currentReadChapters: string[]
 81  ): Promise<{
 82    updatedChapters: string[];
 83    newLastReadChapter: string | null;
 84  }> => {
 85    try {
 86      const mangaData = await getMangaData(mangaId);
 87      if (mangaData) {
 88        const updatedReadChapters = currentReadChapters.filter(
 89          (chapter) => chapter !== chapterNumber
 90        );
 91  
 92        // Determine the new last read chapter
 93        let newLastReadChapter: string | null = null;
 94        if (updatedReadChapters.length > 0) {
 95          newLastReadChapter = Math.max(
 96            ...updatedReadChapters.map((ch) => parseFloat(ch))
 97          ).toString();
 98        }
 99  
100        // Update manga data with new read chapters and last read chapter
101        await setMangaData({
102          ...mangaData,
103          readChapters: updatedReadChapters,
104          lastReadChapter: newLastReadChapter || '',
105          lastUpdated: Date.now(),
106        });
107  
108        // Update last read manga info if needed
109        const lastReadManga = await getLastReadManga();
110        if (
111          lastReadManga &&
112          lastReadManga.id === mangaId &&
113          lastReadManga.chapterNumber === chapterNumber
114        ) {
115          if (newLastReadChapter) {
116            await setLastReadManga(mangaId, mangaData.title, newLastReadChapter);
117          } else if (updatedReadChapters.length === 0) {
118            await setLastReadManga(mangaId, mangaData.title, 'not_started');
119          }
120        }
121  
122        return {
123          updatedChapters: updatedReadChapters,
124          newLastReadChapter,
125        };
126      }
127      return {
128        updatedChapters: currentReadChapters,
129        newLastReadChapter: null,
130      };
131    } catch (error) {
132      console.error('Error marking chapter as unread:', error);
133      return {
134        updatedChapters: currentReadChapters,
135        newLastReadChapter: null,
136      };
137    }
138  };
139  
140  export const setLastReadManga = async (
141    id: string,
142    title: string,
143    chapterNumber: string
144  ): Promise<void> => {
145    try {
146      const lastReadManga: LastReadManga = {
147        id,
148        title,
149        chapterNumber,
150        timestamp: Date.now(),
151      };
152  
153      console.log('Setting last read manga:', lastReadManga);
154      await AsyncStorage.setItem(
155        LAST_READ_MANGA_KEY,
156        JSON.stringify(lastReadManga)
157      );
158    } catch (error) {
159      console.error('Error setting last read manga:', error);
160    }
161  };
162  
163  export const getRecentlyReadManga = async (
164    limit: number = 6
165  ): Promise<MangaData[]> => {
166    try {
167      // Get all AsyncStorage keys
168      const allKeys = await AsyncStorage.getAllKeys();
169  
170      // Filter for manga data keys (manga_*)
171      const mangaKeys = allKeys.filter(
172        (key) => key.startsWith('manga_') && !key.includes('_read_chapters')
173      );
174  
175      const mangaDataArray = await Promise.all(
176        mangaKeys.map(async (key) => {
177          const data = await AsyncStorage.getItem(key);
178          return data ? (JSON.parse(data) as MangaData) : null;
179        })
180      );
181  
182      const validManga = mangaDataArray.filter(
183        (manga): manga is MangaData =>
184          manga !== null &&
185          manga.readChapters &&
186          manga.readChapters.length > 0 &&
187          !!manga.bannerImage
188      );
189  
190      // Sort by lastUpdated timestamp (descending)
191      validManga.sort((a, b) => (b.lastUpdated || 0) - (a.lastUpdated || 0));
192  
193      // Return the top {limit} items
194      return validManga.slice(0, limit);
195    } catch (error) {
196      console.error('Error fetching recently read manga:', error);
197      return [];
198    }
199  };
200  
201  export const getLastReadManga = async (): Promise<LastReadManga | null> => {
202    try {
203      const data = await AsyncStorage.getItem(LAST_READ_MANGA_KEY);
204      if (!data) return null;
205  
206      const parsedData = JSON.parse(data) as LastReadManga;
207      return parsedData;
208    } catch (error) {
209      console.error('Error getting last read manga:', error);
210      return null;
211    }
212  };