react-native#ListRenderItem TypeScript Examples

The following examples show how to use react-native#ListRenderItem. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: App.tsx    From react-native-ios-context-menu with MIT License 6 votes vote down vote up
export function HomeScreen(props) {
  const renderItem: ListRenderItem<ExampleListItem>  = ({ item })  => (
    React.createElement(item.component, {
      index: item.id,
      style: styles.exampleListItem
    })
  );

  return (
    <SafeAreaView>
      {false && (
        <TouchableOpacity
          onPress={() => {
            props.navigation.navigate('Test');
          }}
        >
          <Text>
            Push
          </Text>
        </TouchableOpacity>
      )}
      <FlatList
        contentContainerStyle={styles.scrollContentContainer}
        data={EXAMPLE_ITEMS}
        renderItem={renderItem}
        keyExtractor={(item) => `item-${item.id}`}
      />
    </SafeAreaView>
  );
}
Example #2
Source File: CardRowColorPicker.tsx    From react-native-ios-context-menu with MIT License 6 votes vote down vote up
_listRenderItem: ListRenderItem<string> = ({item}) => {
    const props = this.props;
    const state = this.state;

    const isSelected = (item === state.selectedItem);

    return(
      <TouchableOpacity 
        style={[
          styles.listItem, 
          isSelected && styles.listItemSelected,
          { backgroundColor: item }
        ]}
        onPress={() => {
          // clear if already selected
          const selectedItem = isSelected? undefined : item;

          this.setState({selectedItem});
          props.onSelectItem?.(selectedItem);
        }}
      />
    );
  };
Example #3
Source File: WeekCarousel.tsx    From nyxo-app with GNU General Public License v3.0 6 votes vote down vote up
WeekCarousel: FC<Props> = ({
  ListHeaderComponent,
  refreshControl,
  coaching
}) => {
  const { data, error } = useWeeks()

  const renderWeekCard: ListRenderItem<WeekCollectionItem> = ({ item }) => {
    return (
      <WeekCard
        key={item.slug}
        week={item}
        cardMargin={cardMargin}
        cardWidth={cardWidth}
        coaching={coaching}
      />
    )
  }

  return (
    <FlatList
      ListHeaderComponent={ListHeaderComponent}
      refreshControl={refreshControl}
      keyExtractor={(item) => item.slug}
      showsHorizontalScrollIndicator={false}
      snapToAlignment="center"
      data={data?.coachingWeekCollection?.items}
      renderItem={renderWeekCard}
    />
  )
}
Example #4
Source File: ExampleHabitSection.tsx    From nyxo-app with GNU General Public License v3.0 6 votes vote down vote up
ExampleHabitSection: FC<Props> = ({ habits }) => {
  if (!habits) return null

  const contentOffsets = habits.map(
    (_, index) => (EXAMPLE_HABIT_WIDTH + EXAMPLE_HABIT_MARGIN_LEFT) * index
  )
  const renderHabit: ListRenderItem<HabitCollectionItem> = ({
    item: habit
  }) => (
    <ExampleHabit
      key={`${habit?.title}`}
      title={habit?.title}
      period={habit?.period}
      description={habit?.description?.json}
    />
  )

  return (
    <>
      <H3>EXAMPLE_HABITS</H3>
      <TextSmall>TRY_THIS_HABIT</TextSmall>
      <List
        keyExtractor={keyExtractor}
        centerContent
        horizontal
        data={habits}
        renderItem={renderHabit}
        snapToOffsets={contentOffsets}
        decelerationRate="fast"
      />
    </>
  )
}
Example #5
Source File: PickerView.tsx    From BitcoinWalletMobile with MIT License 5 votes vote down vote up
PickerView: React.FC<Props> = (props) => {

    const languages = ["English", "Español", "Catalan", "Français", "Italiano", "Português Brasil", "日本語", "简体中文"]
    const currencies = [
        "USD",
        "AUD",
        "BRL",
        "CAD",
        "CHF",
        "CLP",
        "CNY",
        "DKK",
        "EUR",
        "GBP",
        "HKD",
        "INR",
        "ISK",
        "JPY",
        "KRW",
        "NZD",
        "PLN",
        "RUB",
        "SEK",
        "SGD",
        "THB",
        "TRY",
        "TWD",
    ]

    const getCurrentLanguage = (state: WalletState) => state.language
    const getCurrentCurrency = (state: WalletState) => state.currency

    const selectedLanguage = useSelector(getCurrentLanguage)
    const selectedCurrency = useSelector(getCurrentCurrency)

    const dispatch = useDispatch()

    const selectItem = (item: string) => {
        if (props.route.params.type == "Choose Currency") {
            dispatch(setCurrency(item))
        }
        else {
            dispatch(setLanguage(getLanguageShortCode(item)))
        }

        props.navigation.goBack()
    }

    const renderItem: ListRenderItem<string> = ({ item }) => (
        <TouchableOpacity onPress={() => { selectItem(item) }}>
            <View style={(props.route.params.type == "Choose Currency" ? (selectedCurrency == item ? styles.trSelected : styles.tr) : (selectedLanguage == getLanguageShortCode(item) ? styles.trSelected : styles.tr))}>
                <Text style={(props.route.params.type == "Choose Currency" ? (selectedCurrency == item ? styles.selectedRowText : styles.rowText) : (selectedLanguage == getLanguageShortCode(item) ? styles.selectedRowText : styles.rowText))}>{item}</Text>
                {props.route.params.type == "Choose Currency" && selectedCurrency == item &&
                    <Image style={styles.icon} source={require("../../assets/images/tick.png")} />
                }
                {props.route.params.type == "Choose Language" && selectedLanguage == getLanguageShortCode(item) &&
                    <Image style={styles.icon} source={require("../../assets/images/tick.png")} />
                }
            </View>
        </TouchableOpacity>
    )


    return (
        <View style={styles.container}>
            <Header screen={props.route.params.type == "Choose Language" ? getTranslated(selectedLanguage).choose_language : getTranslated(selectedLanguage).currency} action={() => { props.navigation.goBack() }} />
            <Screen>
                <View style={styles.container}>
                    <FlatList
                        data={props.route.params.type == "Choose Language" ? languages : currencies}
                        renderItem={renderItem}
                        showsVerticalScrollIndicator={false}
                        keyExtractor={(item) => item}
                    />
                </View>
            </Screen>
        </View>
    )
}
Example #6
Source File: Lessons.tsx    From nyxo-app with GNU General Public License v3.0 5 votes vote down vote up
LessonList: FC<Props> = ({
  locked,
  header,
  footer,
  onScroll,
  slug,
  refreshControl,
  ...rest
}) => {
  const { data } = useGetActiveCoaching()
  const { data: weekData } = useWeek(slug ?? 'introduction')
  const week = getWeek(weekData)

  const withData = week?.lessonsCollection.items.map((lesson) => ({
    ...lesson,
    completed: !!data?.lessons?.find((lssn) => lesson.slug === lssn)
  }))

  const groupedLessons = groupBy(withData, (lesson) => lesson.section?.title)
  const sectionData = withData?.map((item) => ({
    title: item.section?.title,
    description: item.section?.description,
    order: item.section?.order
  }))

  const sections = Object.entries(groupedLessons).map((group) => ({
    header: { ...sectionData?.find((item) => item.title === group[0]) },
    data: group[1]
  }))

  const renderCard: ListRenderItem<LessonCollectionItem> = ({ item }) => (
    <LessonListItem key={item?.slug} locked={locked} lesson={item} />
  )

  const renderSectionHeader: RenderSectionHeader = ({ section }) => (
    <SectionHeader
      key={`${section.header.title}`}
      description={section.header.description?.json}
      title={`${section.header.title}`}
    />
  )

  return (
    <StyledSectionList
      scrollEventThrottle={16}
      onScroll={onScroll}
      refreshControl={refreshControl}
      ListHeaderComponent={header}
      stickySectionHeadersEnabled={false}
      ListFooterComponent={
        <>
          {footer}
          <Spacer />
        </>
      }
      keyExtractor={keyExtractor}
      sections={sections}
      renderSectionHeader={renderSectionHeader}
      renderItem={renderCard}
      {...rest}
    />
  )
}
Example #7
Source File: CoachingSettings.tsx    From nyxo-app with GNU General Public License v3.0 5 votes vote down vote up
CoachingSettings: FC = () => {
  const {
    data: months,
    isLoading,
    refetch: refetchCoaching
  } = useListCoaching()
  const {
    data: activeMonth,
    refetch: refetchActiveMonth
  } = useGetActiveCoaching()

  const renderItem: ListRenderItem<CoachingPeriod> = ({ item }) => (
    <CoachingMonthCard key={`${item?.id}`} month={item} />
  )

  const data = months?.filter((m) => m?.id !== activeMonth?.id)

  const refresh = () => {
    refetchCoaching()
    refetchActiveMonth()
  }

  return (
    <SafeAreaView>
      <FlatList
        refreshControl={
          <ThemedRefreshControl refreshing={isLoading} onRefresh={refresh} />
        }
        ListHeaderComponent={() => (
          <>
            <GoBackContainer>
              <GoBack route={'Settings'} />
            </GoBackContainer>
            <Container>
              <H2>COACHING.SETTINGS.TITLE</H2>
              <H4>COACHING.SETTINGS.ACTIVE</H4>
            </Container>

            {activeMonth ? (
              <CoachingMonthCard actionsEnabled={false} month={activeMonth} />
            ) : null}
            <Container>
              <H4>COACHING.SETTINGS.ALL</H4>
            </Container>
          </>
        )}
        data={data}
        renderItem={renderItem}
      />
    </SafeAreaView>
  )
}
Example #8
Source File: Playlists.tsx    From jellyfin-audio-player with MIT License 5 votes vote down vote up
Playlists: React.FC = () => {
    // Retrieve data from store
    const { entities, ids } = useTypedSelector((state) => state.music.playlists);
    const isLoading = useTypedSelector((state) => state.music.playlists.isLoading);
    const lastRefreshed = useTypedSelector((state) => state.music.playlists.lastRefreshed);
    
    // Initialise helpers
    const dispatch = useAppDispatch();
    const navigation = useNavigation<MusicNavigationProp>();
    const getImage = useGetImage();
    const listRef = useRef<FlatList<EntityId>>(null);

    const getItemLayout = useCallback((data: EntityId[] | null | undefined, index: number): { offset: number, length: number, index: number } => {
        const length = 220;
        const offset = length * index;
        return { index, length, offset };
    }, []);

    // Set callbacks
    const retrieveData = useCallback(() => dispatch(fetchAllPlaylists()), [dispatch]);
    const selectAlbum = useCallback((id: string) => {
        navigation.navigate('Playlist', { id });
    }, [navigation]);
    const generateItem: ListRenderItem<EntityId> = useCallback(({ item, index }) => {
        if (index % 2 === 1) {
            return <View key={item} />;
        }

        const nextItemId = ids[index + 1];
        const nextItem = entities[nextItemId];

        return (
            <View style={{ flexDirection: 'row', marginLeft: 10, marginRight: 10 }} key={item}>
                <GeneratedPlaylistItem
                    id={item}
                    imageUrl={getImage(item as string)}
                    name={entities[item]?.Name || ''}
                    onPress={selectAlbum}
                />
                {nextItem && 
                    <GeneratedPlaylistItem
                        id={nextItemId}
                        imageUrl={getImage(nextItemId as string)}
                        name={nextItem.Name || ''}
                        onPress={selectAlbum}
                    />
                }
            </View>
        );
    }, [entities, getImage, selectAlbum, ids]);

    // Retrieve data on mount
    useEffect(() => { 
        // GUARD: Only refresh this API call every set amounts of days
        if (!lastRefreshed || differenceInDays(lastRefreshed, new Date()) > PLAYLIST_CACHE_AMOUNT_OF_DAYS) {
            retrieveData(); 
        }
    });
    
    return (
        <FlatList
            data={ids} 
            refreshing={isLoading}
            onRefresh={retrieveData}
            getItemLayout={getItemLayout}
            ref={listRef}
            keyExtractor={(item, index) => `${item}_${index}`}
            renderItem={generateItem}
        />
    );
}
Example #9
Source File: Overview.tsx    From BitcoinWalletMobile with MIT License 4 votes vote down vote up
Overview: React.FC<Props> = (props) => {

    const dispatch = useDispatch()

    var opacityRef = useRef(new Animated.Value(0)).current

    const mounted = useRef(true)
    const opacity = opacityRef.interpolate({ inputRange: [80, 150], outputRange: [0, 1] })

    const [isRefreshing, setIsRefreshing] = useState(false)

    const isSyncingSelector = (state: WalletState) => state.isSyncing
    const isSyncing = useSelector(isSyncingSelector)

    const transactionsSelector = (state: WalletState) => state.transactions
    const transactions = useSelector(transactionsSelector)

    const multiDeviceSupportSelector = (state: WalletState) => state.multiDeviceSupport
    const multiDeviceSupport = useSelector(multiDeviceSupportSelector)

    const isRestoringSelector = (state: WalletState) => state.isRestoring
    const isWalletRestoring = useSelector(isRestoringSelector)

    const isNewWalletSelector = (state: WalletState) => state.newlyCreated
    const isNewWallet = useSelector(isNewWalletSelector)

    const balanceSelector = (state: WalletState) => state.balance
    const balance = useSelector(balanceSelector)

    const currencySelector = (state: WalletState) => state.currency
    const currency = useSelector(currencySelector)

    let canGetRates = true

    const rateSelector = (state: WalletState) => {
        if (state.fiatRates[currency] != undefined) {
            return state.fiatRates[currency].last
        }
        else {
            canGetRates = false
            return 0
        }
    }

    const rate = useSelector(rateSelector)

    const langSelector = (state: WalletState) => state.language
    const language = useSelector(langSelector)

    const pushSend = () => {
        props.navigation.dangerouslyGetParent()?.navigate('Send')
    }

    const pushReceive = () => {
        props.navigation.navigate('Receive')
    }

    const btcToFiat = () => {
        let fiat = new BigNumber(balance).multipliedBy(rate).toFixed(2)

        if (isNaN(parseFloat(fiat))) {
            fiat = "0";
        }

        if (!canGetRates) {
            return "N/A"
        }

        return new Intl.NumberFormat(language, { style: 'currency', currency: currency }).format(parseFloat(fiat));
    }


    const syncWallet = async (smallSync = true) => {
        await wallet.synchronize(smallSync)
    }

    useEffect(() => {

        // Refresh every 10 minutes with a mini-sync
        const interval = setInterval(() => {
            syncWallet(!multiDeviceSupport)
        }, 600000);

    }, [])

    const renderItem: ListRenderItem<Transaction> = ({ item }) => (
        <TransactionView transaction={item} />
    );

    const insets = useSafeAreaInsets()

    return (
        <View style={styles.container}>
            <View style={styles.headerContainer}>
                <View style={{ marginTop: insets.top, height: 56 }}>
                    <View style={styles.textContain}>
                        <Text style={styles.headerText}>{getTranslated(language).overview}</Text>
                        <Animated.View style={{ opacity: opacity }}>
                            <View style={styles.btcBalanceRow}>
                                <Text style={styles.totalBalance}>{getTranslated(language).total_balance}:</Text>
                                <Text style={styles.btcBalance}>{balance.toString()}</Text>
                                <Text style={styles.currencyText}>BTC</Text>
                            </View>
                            <View style={styles.fiatBalanceRow}>
                                <Text style={styles.fiatBalance}>{btcToFiat()}</Text>
                                <Text style={styles.currencyText}>{currency}</Text>
                            </View>
                        </Animated.View>
                    </View>
                </View>
            </View>
            <Screen>
                <View style={styles.listContainer}>
                    <Animated.FlatList
                        data={transactions}
                        ListHeaderComponent={<BalanceCard numOfTransaction={transactions.length} isRefreshing={isSyncing} receiveAction={pushReceive} sendAction={pushSend} refreshAction={() => syncWallet(!multiDeviceSupport)} />}
                        renderItem={renderItem}
                        showsVerticalScrollIndicator={false}
                        keyExtractor={item => item.hash}
                        onScroll={Animated.event([{ nativeEvent: { contentOffset: { y: opacityRef } } }], { useNativeDriver: true })} />

                    {transactions.length == 0 &&
                        <View style={styles.noTransactions}>
                            <Text style={styles.noTransactionsText}>{getTranslated(language).no_transactions}</Text>
                        </View>
                    }
                </View>
            </Screen>
        </View>
    );
}
Example #10
Source File: Settings.tsx    From BitcoinWalletMobile with MIT License 4 votes vote down vote up
Settings: React.FC<Props> = (props) => {


    const [recoveryWordsModalVisible, setrecoveryWordsModalVisible] = useState(false)
    const [exitModalVisible, setExitModalVisible] = useState(false)

    const languageSelector = (state: WalletState) => state.language
    const language = useSelector(languageSelector)

    const currencySelector = (state: WalletState) => state.currency
    const currency = useSelector(currencySelector)

    const data = [getTranslated(language).currency, getTranslated(language).language, getTranslated(language).seed_phrase, "Support multiple devices", getTranslated(language).exit_wallet]

    const clearAndDelete = async () => {
        setExitModalVisible(false)
        store.dispatch(clearWallet())
    }


    const showRecoveryWordsModal = () => {
        setrecoveryWordsModalVisible(true)
    }

    const hideRecoveryWordsModal = () => {
        setrecoveryWordsModalVisible(false)
    }

    const showExitModal = () => {
        setExitModalVisible(true)
    }

    const hideExitModal = () => {
        setExitModalVisible(false)
    }

    const pushCurrency = () => {
        // @ts-ignore
        props.navigation.navigate('PickerView', { type: "Choose Currency" })
    }

    const pushLanguage = () => {
        // @ts-ignore
        props.navigation.navigate('PickerView', { type: "Choose Language" })
    }

    interface ChildProps {
        item: string
    }

    const conditonalView: React.FC<ChildProps> = ({ item }) => {
        if (item == getTranslated(language).currency) {
            return <View style={{ marginTop: 20 }}><SettingsItem label={getTranslated(language).currency} subLabel={currency} onClick={pushCurrency} /></View>
        }

        if (item == getTranslated(language).seed_phrase) {
            return <View style={{ marginTop: 50 }}><SettingsItem label={getTranslated(language).seed_phrase} subLabel="" onClick={showRecoveryWordsModal} /></View>
        }

        if (item == getTranslated(language).exit_wallet) {
            return <View style={{ marginTop: 50 }}><SettingsItem label={getTranslated(language).exit_wallet} subLabel="" onClick={showExitModal} /></View>
        }

        if (item == "Support multiple devices") {
            return <SettingsItem label="Support multiple devices" subLabel="" onClick={() => { }} />
        }

        else {
            return <SettingsItem label={getTranslated(language).language} subLabel={getLanguageBigName(language)} onClick={pushLanguage} />
        }
    }

    const renderItem: ListRenderItem<string> = ({ item }) => (
        conditonalView({ item: item })
    )

    return (
        <View style={styles.container}>
            <Header screen={getTranslated(language).settings} />
            <Screen>
                <View style={styles.content}>
                    <FlatList data={data}
                        renderItem={renderItem}
                        keyExtractor={item => item} />
                    <RecoveryWordsModal isVisible={recoveryWordsModalVisible} hideModal={hideRecoveryWordsModal} />
                    <ExitWalletModal isVisible={exitModalVisible} hideModal={hideExitModal} deleteCallback={clearAndDelete} />
                </View>
            </Screen>
        </View>
    );
}
Example #11
Source File: Onboarding.tsx    From mobile with Apache License 2.0 4 votes vote down vote up
OnboardingScreen = () => {
  const navigation = useNavigation();
  const {width: viewportWidth} = useWindowDimensions();
  const carouselRef = useRef<Carousel<OnboardingKey>>(null);
  const [currentStep, setCurrentStep] = useState(0);
  const i18n = useI18n();
  const {setOnboarded, setOnboardedDatetime} = useStorage();
  const startExposureNotificationService = useStartExposureNotificationService();
  const isStart = currentStep === 0;
  const isEnd = currentStep === onboardingData.length - 1;
  const {isScreenReaderEnabled} = useAccessibilityService();
  const currentStepForRenderItem = isScreenReaderEnabled ? currentStep : -1;

  const renderItem: ListRenderItem<OnboardingKey> = useCallback(
    ({item, index}) => {
      return (
        <View style={styles.flex} accessibilityElementsHidden={index !== currentStepForRenderItem}>
          <OnboardingContent key={item} item={item} isActive={index === currentStepForRenderItem} />
        </View>
      );
    },
    [currentStepForRenderItem],
  );

  const onSnapToNewPage = useCallback(
    async (index: number) => {
      // we want the EN permission dialogue to appear on the last step.
      if (index === onboardingData.length - 1) {
        try {
          await startExposureNotificationService();
        } catch (error) {
          if (error.message === 'API_NOT_CONNECTED') {
            navigation.reset({
              index: 0,
              routes: [{name: 'ErrorScreen'}],
            });
          }
        }
      }
    },
    [navigation, startExposureNotificationService],
  );

  const nextItem = useCallback(async () => {
    if (isEnd) {
      await setOnboarded(true);
      await setOnboardedDatetime(getCurrentDate());
      navigation.reset({
        index: 0,
        routes: [{name: 'Home'}],
      });
      return;
    }
    carouselRef.current?.snapToNext();
  }, [isEnd, navigation, setOnboarded, setOnboardedDatetime]);

  const prevItem = useCallback(() => {
    carouselRef.current?.snapToPrev();
  }, []);

  const onSnapToItem = useCallback(
    (newIndex: number) => {
      setCurrentStep(newIndex);
      onSnapToNewPage(newIndex);
    },
    [onSnapToNewPage],
  );

  return (
    <Box backgroundColor="overlayBackground" flex={1}>
      <SafeAreaView style={styles.flex}>
        <View style={styles.flex}>
          <Carousel
            ref={carouselRef}
            data={onboardingData}
            renderItem={renderItem}
            sliderWidth={viewportWidth}
            itemWidth={viewportWidth}
            onSnapToItem={onSnapToItem}
            importantForAccessibility="no"
            accessible={false}
            initialNumToRender={1}
          />
        </View>
        <Box flexDirection="row" borderTopWidth={2} borderTopColor="gray5">
          <Box flex={0} style={{...styles.offset1}}>
            {!isStart && (
              <Button text={i18n.translate(`Onboarding.ActionBack`)} variant="navigation" onPress={prevItem} />
            )}
          </Box>

          <Box flex={2} justifyContent="center" style={{...styles.offset2}}>
            <ProgressCircles numberOfSteps={onboardingData.length} activeStep={currentStep + 1} marginBottom="none" />
          </Box>

          <Box flex={0} style={{...styles.offset3}}>
            <Button
              color="bodyTextWhite"
              testID="onboardingNextButton"
              text={i18n.translate(`Onboarding.Action${isEnd ? 'End' : 'Next'}`)}
              variant="navigation"
              onPress={nextItem}
            />
          </Box>
        </Box>
      </SafeAreaView>
    </Box>
  );
}
Example #12
Source File: Tutorial.tsx    From mobile with Apache License 2.0 4 votes vote down vote up
TutorialScreen = () => {
  const navigation = useNavigation();
  const {width: viewportWidth} = useWindowDimensions();
  const carouselRef = useRef<Carousel<TutorialKey>>(null);
  const [currentStep, setCurrentStep] = useState(0);
  const i18n = useI18n();
  const close = useCallback(() => navigation.goBack(), [navigation]);

  const isStart = currentStep === 0;
  const isEnd = currentStep === tutorialData.length - 1;

  const {isScreenReaderEnabled} = useAccessibilityService();
  const currentStepForRenderItem = isScreenReaderEnabled ? currentStep : -1;

  const renderItem: ListRenderItem<TutorialKey> = useCallback(
    ({item, index}) => {
      return (
        <View style={styles.flex} accessibilityElementsHidden={index !== currentStepForRenderItem}>
          <TutorialContent key={item} item={item} isActive={index === currentStepForRenderItem} />
        </View>
      );
    },
    [currentStepForRenderItem],
  );

  const nextItem = useCallback(() => {
    if (isEnd) {
      close();
      return;
    }
    carouselRef.current?.snapToNext();
  }, [close, isEnd]);

  const prevItem = useCallback(() => {
    carouselRef.current?.snapToPrev();
  }, []);

  const onSnapToItem = useCallback((newIndex: number) => {
    setCurrentStep(newIndex);
  }, []);

  return (
    <Box backgroundColor="overlayBackground" flex={1}>
      <SafeAreaView style={styles.flex}>
        <Toolbar
          title=""
          navIcon="icon-back-arrow"
          navText={i18n.translate('Tutorial.Close')}
          navLabel={i18n.translate('Tutorial.Close')}
          onIconClicked={close}
        />
        <View style={styles.flex}>
          <Carousel
            ref={carouselRef}
            data={tutorialData}
            renderItem={renderItem}
            sliderWidth={viewportWidth}
            itemWidth={viewportWidth}
            onSnapToItem={onSnapToItem}
            importantForAccessibility="no"
            accessible={false}
            removeClippedSubviews={false}
          />
        </View>
        <Box flexDirection="row" borderTopWidth={2} borderTopColor="gray5">
          <Box flex={0} style={{...styles.offset1}}>
            {!isStart && (
              <Button text={i18n.translate(`Tutorial.ActionBack`)} variant="navigation" onPress={prevItem} />
            )}
          </Box>

          <Box flex={2} justifyContent="center" style={{...styles.offset2}}>
            <ProgressCircles numberOfSteps={tutorialData.length} activeStep={currentStep + 1} marginBottom="none" />
          </Box>

          <Box flex={0} style={{...styles.offset3}}>
            <Button
              testID="howItWorksNextButton"
              text={i18n.translate(`Tutorial.Action${isEnd ? 'End' : 'Next'}`)}
              variant="navigation"
              onPress={nextItem}
            />
          </Box>
        </Box>
      </SafeAreaView>
    </Box>
  );
}
Example #13
Source File: DayStrip.tsx    From nyxo-app with GNU General Public License v3.0 4 votes vote down vote up
CalendarStrip: FC = () => {
  const { selectDate, selectedDate } = useCalendar()
  const flatListRef = useRef<FlatList>(null)
  const [init, setInit] = useState(true)
  const dispatch = useAppDispatch()
  const startDate = new Date()

  const days = Array.from(Array(365 * 3)).map((_, index) =>
    startOfDay(sub(startDate, { days: index }))
  )

  const toggleCalendar = () => {
    dispatch(toggleCalendarModal(true))
  }

  const renderItem: ListRenderItem<Date> = ({ item, index }) => (
    <PressableContainer key={item.toISOString()} onPress={toggleCalendar}>
      <Day isFirst={index === 0}>
        <DateContainer isFirst={index === 0}>
          {localizedFormat(item, 'EEE d. LLL')}
        </DateContainer>
      </Day>
    </PressableContainer>
  )

  const handleViewableItemsChanged = ({
    viewableItems
  }: {
    viewableItems: Array<ViewToken>
  }) => {
    if (viewableItems.length === 1) {
      const date = viewableItems[0].item
      selectDate(date)
    }
  }

  const handleViewableItemsChangedRef = useRef(handleViewableItemsChanged)

  const viewabilityConfig = {
    itemVisiblePercentThreshold: 85,
    minimumViewTime: 750
  }

  const keyExtractor = (item: Date) => item.toISOString()

  const scrollToItem = (index: number) => {
    return flatListRef?.current?.scrollToIndex({
      index,
      animated: true,
      viewPosition: 0.5
    })
  }

  useEffect(() => {
    if (!init) {
      const index = days.findIndex((date) =>
        isSameDay(date, new Date(selectedDate))
      )
      if (index >= 0) {
        scrollToItem(index)
      }
    } else {
      setInit(false)
    }
  }, [days, init, selectedDate])

  const getItemLayout = (_: unknown, index: number) => {
    if (index === 0) {
      return {
        index,
        length: FIRST_DAY_WIDTH,
        offset: 0
      }
    }
    return {
      index,
      length: DAY_WIDTH,
      offset: FIRST_DAY_WIDTH + DAY_WIDTH * index - DAY_WIDTH
    }
  }

  const snapOffsets = days.map((_, index) => {
    if (index === 0) {
      return DAY_WIDTH
    }
    return DAY_WIDTH * (index + 1)
  })

  return (
    <Container>
      <FlatList
        ref={flatListRef}
        showsHorizontalScrollIndicator={false}
        inverted
        snapToStart
        horizontal
        getItemLayout={getItemLayout}
        keyExtractor={keyExtractor}
        viewabilityConfig={viewabilityConfig}
        onViewableItemsChanged={handleViewableItemsChangedRef.current}
        decelerationRate="fast"
        snapToOffsets={snapOffsets}
        data={days}
        renderItem={renderItem}
      />
      <Gradient pointerEvents="box-none" />
    </Container>
  )
}
Example #14
Source File: settings.tsx    From nyxo-app with GNU General Public License v3.0 4 votes vote down vote up
SettingsScreen: FC<Props> = ({ navigation }) => {
  const theme = useAppSelector((state) => state.theme.theme)

  const rateApp = () => {
    // FIXME
    Rate.rate(options, () => undefined)
  }

  const displayTheme = (t: string) => (t === 'dark' ? 'Light' : 'Dark')

  const settings = [
    {
      text: 'Select Tracking Source',
      icon: 'smartWatchCircleGraph',
      action: () => navigation.navigate('Sources')
    },
    {
      text: 'Coaching settings',
      icon: 'schoolPhysicalBold',
      action: () => navigation.navigate('Coaching')
    },

    {
      text: 'Manage Nyxo Subscription',
      icon: 'receipt',
      action: () => navigation.navigate('Subscription')
    },
    {
      text: 'Sync to backend',
      icon: 'syncCloud',
      action: () => navigation.navigate('Cloud', { code: '' })
    },
    {
      text: 'Switch mode',
      icon: 'astronomyMoon',
      theme: displayTheme(theme),
      action: () => navigation.push('Theme')
    },
    {
      text: 'RATE_APP',
      icon: 'star',
      action: rateApp
    },
    {
      text: 'ONBOARDING.TITLE',
      icon: 'compass',
      action: () => navigation.push('Onboarding')
    }
  ]

  const socialActions = [
    {
      text: 'Send feedback',
      icon: 'envelope',
      action: () => Linking.openURL('mailto:[email protected]')
    },
    {
      text: 'Visit site',
      icon: 'browserDotCom',
      action: () => Linking.openURL('https://nyxo.app/')
    },
    {
      text: 'Follow us on Facebook',
      icon: 'facebook',
      action: () =>
        Linking.openURL('https://www.facebook.com/Nyxo-467927177117033/')
    },

    {
      text: 'Follow us on Twitter',
      icon: 'twitter',
      action: () => Linking.openURL('https://twitter.com/hellonyxo')
    },

    {
      text: 'Follow us on Instagram',
      icon: 'instagram',
      action: () => Linking.openURL('https://www.instagram.com/hellonyxo/')
    },
    {
      text: 'Terms of Service',
      icon: 'handshake',
      action: () => Linking.openURL(CONFIG.TERMS_LINK)
    },
    {
      text: 'Privacy Policy',
      icon: 'lockCircle',
      action: () => Linking.openURL(CONFIG.PRIVACY_LINK)
    }
  ]

  const renderItem: ListRenderItem<SettingItem> = ({ item }) => {
    if (!item) return null
    return (
      <SettingRow onPress={item.action} badge={item.badge} icon={item.icon}>
        <Title>{`${item.text}`}</Title>
      </SettingRow>
    )
  }

  const renderSectionHeader = ({
    section
  }: {
    section: SectionListData<SettingItem, { title: string }>
  }) => {
    if (section.title === 'Settings') return null
    return <SectionHeader>{section.title}</SectionHeader>
  }

  const sections = [
    {
      title: 'Settings',
      data: settings
    },
    {
      title: 'Support',
      data: socialActions
    }
  ]

  return (
    <SafeAreaView>
      <SectionList
        ListHeaderComponent={<PageTitle>Settings</PageTitle>}
        sections={sections}
        renderSectionHeader={renderSectionHeader}
        keyExtractor={keyExtractor}
        renderItem={renderItem}
        ListFooterComponent={<VersionInformation />}
      />
    </SafeAreaView>
  )
}