Skip to content

Commit 0d3dead

Browse files
fix(HeaderComponent): Ensure genres and tags are checked for array type before accessing length
refactor(ComicDetails): Simplify tab change handling and improve header rendering logic
1 parent 73bda4a commit 0d3dead

2 files changed

Lines changed: 127 additions & 152 deletions

File tree

src/Screens/Comic/Details/Components/HeaderComponent.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,9 @@ const HeaderComponent = memo(
4949
parts.push(ComicDetail.releaseDate);
5050
}
5151

52-
if (ComicDetail?.genres?.length > 0) {
52+
if (Array.isArray(ComicDetail?.genres) && ComicDetail.genres.length > 0) {
5353
parts.push(ComicDetail.genres.slice(0, 2).join(', '));
54-
} else if (ComicDetail?.tags?.length > 0) {
54+
} else if (Array.isArray(ComicDetail?.tags) && ComicDetail.tags.length > 0) {
5555
parts.push(ComicDetail.tags.slice(0, 2).join(', '));
5656
}
5757

@@ -166,7 +166,7 @@ const HeaderComponent = memo(
166166
<Text style={styles.metaText}>{formatMetaInfo()}</Text>
167167

168168
{/* Genre Tags */}
169-
{ComicDetail?.genres?.length > 0 && (
169+
{Array.isArray(ComicDetail?.genres) && ComicDetail.genres.length > 0 && (
170170
<View style={styles.genreContainer}>
171171
{ComicDetail.genres.slice(0, 3).map((genre, idx) => (
172172
<View key={idx} style={styles.genrePill}>

src/Screens/Comic/Details/index.js

Lines changed: 124 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -292,12 +292,6 @@ export function ComicDetails({route, navigation}) {
292292
}
293293
}, []);
294294

295-
const handleSortToggle = useCallback(() => {
296-
crashlytics().log('Comic Details Sort Clicked');
297-
analytics().logEvent('Comic_Details_Sort_Clicked');
298-
setSort(prev => !prev);
299-
}, []);
300-
301295
useEffect(() => {
302296
(async () => {
303297
if (!hasRewardAdsShown) {
@@ -342,164 +336,142 @@ export function ComicDetails({route, navigation}) {
342336
}
343337
}, [PageLink, dispatch, forIosLoading, isIosOverrideActive, reportError]);
344338

345-
const renderComicHeader = () => (
346-
<HeaderComponent
347-
link={PageLink}
348-
image={route?.params?.image}
349-
title={route?.params?.title}
350-
tabBar={tabBar}
351-
onTabBar={index => {
352-
crashlytics().log('Comic Details Tab Clicked');
353-
analytics().logEvent('Comic_Details_Tab_Clicked', {
354-
TabName: tabBar[index].name?.toString(),
355-
});
356-
tabBar.map(tab => (tab.active = false));
357-
tabBar[index].active = true;
358-
setTabBar([...tabBar]);
359-
}}
360-
sort={sort}
361-
setSORT={() => {
362-
crashlytics().log('Comic Details Sort Clicked');
363-
analytics().logEvent('Comic_Details_Sort_Clicked');
364-
setSort(!sort);
365-
}}
366-
notificationBell={notificationBell}
367-
onRequestLoginPrompt={handleRequestLoginPrompt}
368-
/>
369-
);
339+
const handleTabChange = useCallback(index => {
340+
crashlytics().log('Comic Details Tab Clicked');
341+
analytics().logEvent('Comic_Details_Tab_Clicked', {
342+
TabName: tabBar[index]?.name?.toString(),
343+
});
344+
setTabBar(prev =>
345+
prev.map((tab, tabIndex) => ({
346+
...tab,
347+
active: tabIndex === index,
348+
})),
349+
);
350+
}, [tabBar]);
370351

371-
if (error) return <Error error={error} />;
352+
const handleSortToggle = useCallback(() => {
353+
crashlytics().log('Comic Details Sort Clicked');
354+
analytics().logEvent('Comic_Details_Sort_Clicked');
355+
setSort(prev => !prev);
356+
}, []);
372357

373-
if (!isChapterTab && !isRecentTab) {
374-
return (
375-
<>
376-
<CommunityTab
377-
comicLink={PageLink}
378-
navigation={navigation}
379-
headerComponent={renderComicHeader()}
380-
/>
381-
<LoginPrompt
382-
visible={showLoginPrompt}
383-
loading={authLoading}
384-
onClose={handleCloseLoginPrompt}
385-
onGoogleSignIn={handleGoogleSignIn}
386-
onAppleSignIn={handleAppleSignIn}
387-
/>
388-
</>
389-
);
390-
}
358+
if (error) return <Error error={error} />;
391359

392360
return (
393-
<>
394-
<LoadingModal loading={loading} />
395-
<FlatList
396-
ListHeaderComponent={
361+
<View style={styles.container}>
362+
{/* Header - always rendered at the top level */}
363+
<HeaderComponent
364+
link={PageLink}
365+
image={route?.params?.image}
366+
title={route?.params?.title}
367+
tabBar={tabBar}
368+
onTabBar={handleTabChange}
369+
sort={sort}
370+
setSORT={handleSortToggle}
371+
notificationBell={notificationBell}
372+
onRequestLoginPrompt={handleRequestLoginPrompt}
373+
/>
374+
375+
{/* Tab Content - only switches the content below header */}
376+
<View style={styles.contentContainer}>
377+
{!isChapterTab && !isRecentTab ? (
378+
<CommunityTab
379+
comicLink={PageLink}
380+
navigation={navigation}
381+
headerComponent={null}
382+
/>
383+
) : (
397384
<>
398-
<HeaderComponent
399-
link={PageLink}
400-
image={route?.params?.image}
401-
title={route?.params?.title}
402-
tabBar={tabBar}
403-
onTabBar={index => {
404-
crashlytics().log('Comic Details Tab Clicked');
405-
analytics().logEvent('Comic_Details_Tab_Clicked', {
406-
TabName: tabBar[index].name?.toString(),
407-
});
408-
setTabBar(prev =>
409-
prev.map((tab, tabIndex) => ({
410-
...tab,
411-
active: tabIndex === index,
412-
})),
413-
);
414-
}}
415-
notificationBell={notificationBell}
416-
onRequestLoginPrompt={handleRequestLoginPrompt}
417-
/>
418-
{shouldShowSearch ? (
419-
<View style={styles.searchContainer}>
420-
<View style={styles.searchInputWrapper}>
421-
<Ionicons
422-
name="search"
423-
size={18}
424-
color="rgba(255,255,255,0.6)"
425-
style={styles.searchIcon}
385+
<LoadingModal loading={loading} />
386+
<FlatList
387+
ListHeaderComponent={
388+
shouldShowSearch ? (
389+
<View style={styles.searchContainer}>
390+
<View style={styles.searchInputWrapper}>
391+
<Ionicons
392+
name="search"
393+
size={18}
394+
color="rgba(255,255,255,0.6)"
395+
style={styles.searchIcon}
396+
/>
397+
<TextInput
398+
style={styles.searchInput}
399+
placeholder={
400+
isRecentTab ? 'Search recent reads' : 'Search chapters'
401+
}
402+
placeholderTextColor="rgba(255,255,255,0.6)"
403+
value={searchQuery}
404+
onChangeText={text => setSearchQuery(text)}
405+
autoCorrect={false}
406+
autoCapitalize="none"
407+
keyboardAppearance="dark"
408+
/>
409+
</View>
410+
{isChapterTab ? (
411+
<TouchableOpacity
412+
style={styles.sortButton}
413+
onPress={handleSortToggle}
414+
activeOpacity={0.7}>
415+
<FontAwesome5
416+
name={sort ? 'sort-numeric-up' : 'sort-numeric-down-alt'}
417+
size={16}
418+
color="#fff"
419+
/>
420+
</TouchableOpacity>
421+
) : null}
422+
</View>
423+
) : null
424+
}
425+
data={listData}
426+
style={styles.container}
427+
renderItem={({item, index}) => (
428+
<ChapterCard
429+
item={item}
430+
index={index}
431+
isBookmark={false}
432+
detailPageLink={PageLink}
433+
isFirst={index === 0}
434+
/>
435+
)}
436+
keyExtractor={(item, index) =>
437+
item?.link ? `${item.link}-${index}` : `ad-${index}`
438+
}
439+
showsVerticalScrollIndicator={false}
440+
ListFooterComponent={
441+
isChapterTab ? (
442+
<PaginationFooter
443+
pagination={ComicDetail?.pagination}
444+
pageLink={PageLink}
445+
route={route}
446+
navigation={navigation}
426447
/>
427-
<TextInput
428-
style={styles.searchInput}
429-
placeholder={
430-
isRecentTab ? 'Search recent reads' : 'Search chapters'
431-
}
432-
placeholderTextColor="rgba(255,255,255,0.6)"
433-
value={searchQuery}
434-
onChangeText={text => setSearchQuery(text)}
435-
autoCorrect={false}
436-
autoCapitalize="none"
437-
keyboardAppearance="dark"
438-
/>
439-
</View>
440-
{isChapterTab ? (
441-
<TouchableOpacity
442-
style={styles.sortButton}
443-
onPress={handleSortToggle}
444-
activeOpacity={0.7}>
445-
<FontAwesome5
446-
name={sort ? 'sort-numeric-up' : 'sort-numeric-down-alt'}
447-
size={16}
448-
color="#fff"
449-
/>
450-
</TouchableOpacity>
451-
) : null}
452-
</View>
453-
) : null}
448+
) : null
449+
}
450+
keyboardShouldPersistTaps="handled"
451+
/>
452+
{/* Continue Reading FAB - only show on Chapters tab when there's reading history */}
453+
{isChapterTab && lastReadChapter && (
454+
<ContinueReadingFAB
455+
visible={true}
456+
chapterTitle={lastReadChapter.title}
457+
progress={lastReadChapter.progress}
458+
currentPage={lastReadChapter.currentPage}
459+
totalPages={lastReadChapter.totalPages}
460+
onPress={handleContinueReading}
461+
/>
462+
)}
454463
</>
455-
}
456-
data={listData}
457-
style={styles.container}
458-
renderItem={({item, index}) => (
459-
<ChapterCard
460-
item={item}
461-
index={index}
462-
isBookmark={false}
463-
detailPageLink={PageLink}
464-
isFirst={index === 0}
465-
/>
466464
)}
467-
keyExtractor={(item, index) =>
468-
item?.link ? `${item.link}-${index}` : `ad-${index}`
469-
}
470-
showsVerticalScrollIndicator={false}
471-
ListFooterComponent={
472-
isChapterTab ? (
473-
<PaginationFooter
474-
pagination={ComicDetail?.pagination}
475-
pageLink={PageLink}
476-
route={route}
477-
navigation={navigation}
478-
/>
479-
) : null
480-
}
481-
keyboardShouldPersistTaps="handled"
482-
/>
465+
</View>
466+
483467
<LoginPrompt
484468
visible={showLoginPrompt}
485469
loading={authLoading}
486470
onClose={handleCloseLoginPrompt}
487471
onGoogleSignIn={handleGoogleSignIn}
488472
onAppleSignIn={handleAppleSignIn}
489473
/>
490-
491-
{/* Continue Reading FAB - only show on Chapters tab when there's reading history */}
492-
{isChapterTab && lastReadChapter && (
493-
<ContinueReadingFAB
494-
visible={true}
495-
chapterTitle={lastReadChapter.title}
496-
progress={lastReadChapter.progress}
497-
currentPage={lastReadChapter.currentPage}
498-
totalPages={lastReadChapter.totalPages}
499-
onPress={handleContinueReading}
500-
/>
501-
)}
502-
</>
474+
</View>
503475
);
504476
}
505477

@@ -508,6 +480,9 @@ const styles = StyleSheet.create({
508480
flex: 1,
509481
backgroundColor: '#14142a',
510482
},
483+
contentContainer: {
484+
flex: 1,
485+
},
511486
searchContainer: {
512487
paddingHorizontal: 16,
513488
marginBottom: 16,

0 commit comments

Comments
 (0)