Source: screens/HomeScreen/HomeScreen.js

import React, {useCallback, useEffect, useState} from 'react';
import {RefreshControl, Alert, FlatList, ScrollView, ActivityIndicator, Text, View, SectionList} from 'react-native';
import {getGenres, genre2Labels, getBooksFromGenre, getReadingBooks, removeFromReading,addToPrefs } from '../../utils';
import BookModal from '../SelectScreen/BookModal';
import BookListItem from '../../common/BookListItem/BookListItem';
import styles from './styles';

/**
 * This is the React component which defines the UI for the Home screen in the app.
 *
 * @function HomeScreen
 * @param {Object} props - This is a dictionary of component properties.
 * @namespace
 */
export default function HomeScreen({extraData}) {
  const {name} = extraData?.user;
  const [hour, setHour ] = useState(0);
  const [ greeting, setGreeting ] = useState('Good Evening');
  const [recommendations, setRecommendations] = useState(undefined);
  const [loading, setLoading] = useState(true);
  const [reading, setReading] = useState(null);
  const [refreshing, setRefreshing] = useState(false);
  const [selectedBook, setSelectedBook] = useState(null);

  const getReading = async () => {
    const reading = await getReadingBooks();
    setLoading(false);
    if (reading)
      setReading(reading);
  }

  const getRecs = async () => {
    const genres = await getGenres();
    const recs = await genres.reduce(async (acc, genre) => {
      return [
        ...(await acc),
        { 
          title: genre2Labels[genre],
          data: (await getBooksFromGenre(genre, 2)),
        }
      ]
    }, []);
    setLoading(false);
    setRecommendations(recs);
  }

  // On the initial render, get the current time and list the user's recommended
  // books.
  useEffect(() => {
    setHour((new Date).getHours());

    getReading();
    getRecs();
  }, []);

  // Set the displayed greeting according to the time.
  useEffect(() => {
    if (17 <= hour || hour < 7) {
      setGreeting('Good Evening');
    } else if (7 <= hour && hour < 12) {
      setGreeting('Good Morning');
    } else {
      setGreeting('Good Afternoon');
    }
  }, [hour]);

  const showBookAlert = (book) => {
    Alert.alert(
      'Opinion',
      'Did you like this book?',
      [
        {
          text: 'I\'m not done yet',
          onPress: () => {}
        },
        {
          text: 'No',
          onPress: async () => {
            await removeFromReading(book);
            await getReading();
          },
          style: 'cancel'
        },
        {
          text: 'Yes',
          onPress: async () => {
            await addToPrefs(book);
            await removeFromReading(book);
            await getReading();
          }
        }
      ]
    );
  }

  const onRefresh = useCallback(async () => {
    setRefreshing(true);
    try {
      await getReading().catch((e) => {console.error(e)});
      await getRecs().catch((e) => {console.error(e)});
    } catch (e) {
      console.error(e);
    }
    setRefreshing(false);
  }, []);

  return (
    <ScrollView style={styles.container}
      refreshControl={
        <RefreshControl
          refreshing={refreshing}
          onRefresh={onRefresh}
        />
      }
    >
      {selectedBook !== null && 
        <BookModal
          showModal={selectedBook !== null}
          book={selectedBook}
          onDismiss={() => {setSelectedBook(null)}}
        />}
      <View style={styles.greetingContainer}>
        <Text style={styles.greeting}>{greeting},</Text> 
        <Text style={styles.name}>{name.split(' ')[0]} 👋 </Text>
      </View>
      {loading &&
          <ActivityIndicator style={{margin: 50, transform: [{scale: 2}]}} size='large' color='#ff0000' />}
      {reading?.length > 0 &&
          (<>
            <Text style={styles.header}>Currently Reading</Text>
            <FlatList
              scrollEnabled={false}
              data={reading}
              renderItem={({item}) => (
                <BookListItem
                  book={item}
                  style={{ marginHorizontal: 0 }}
                  onPress={() => {
                    showBookAlert(item)
                  }}
                />
              )}
              keyExtractor={(item, index) => index}
            />
          </>)}
      {recommendations &&
        <><Text style={styles.header}>Book Recommendations</Text>
          <SectionList
            scrollEnabled={false}
            sections={recommendations}
            renderItem={({item}) =>
                (<BookListItem book={item} style={{ marginHorizontal: 0 }} onPress={() => setSelectedBook(item)}/>)}
            renderSectionHeader={({section}) => (
              <Text style={styles.sectionHeader}>{section.title}</Text>
            )}
            keyExtractor={(item, index) => index}
          /></>}
    </ScrollView>
  );
}