react-native#RefreshControl TypeScript Examples

The following examples show how to use react-native#RefreshControl. 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: scrollable.tsx    From protect-scotland with Apache License 2.0 6 votes vote down vote up
Scrollable: FC<LayoutProps> = ({
  toast,
  backgroundColor,
  refresh,
  scrollViewRef,
  safeArea = true,
  children,
  contentContainerStyle,
  scrollableStyle = {},
  importantForAccessibility = 'auto'
}) => {
  const insets = useSafeAreaInsets();
  const refreshControl = refresh && <RefreshControl {...refresh} />;

  return (
    <Container style={[!!backgroundColor && {backgroundColor}]}>
      <ScrollView
        ref={scrollViewRef}
        keyboardShouldPersistTaps="always"
        style={scrollableStyle}
        importantForAccessibility={importantForAccessibility}
        contentContainerStyle={[
          styles.scrollView,
          {paddingBottom: (safeArea ? insets.bottom : 0) + SPACING_BOTTOM},
          contentContainerStyle
        ]}
        refreshControl={refreshControl}>
        {toast && (
          <>
            {toast}
            <Spacing s={8} />
          </>
        )}
        {children}
      </ScrollView>
    </Container>
  );
}
Example #2
Source File: News.tsx    From wuhan2020-frontend-react-native-app with MIT License 6 votes vote down vote up
function NewsScreen() {
  const { data, loading, fetchMore, refresh } = useContext(NewsDataContext);
  const [refreshing, setRefreshing] = useState(false);

  const onRefresh = useCallback(() => {
    setRefreshing(true);

    refresh();
    wait(2000).then(() => setRefreshing(false));
  }, [refreshing, refresh]);

  const news = uniqBy(data || [], 'sourceId');

  return (
    <StatusBarSafeLayout>
      <View style={styles.constainer}>
        <H1 title="新闻汇总" />
      </View>

      <ScrollView
        refreshControl={
          <RefreshControl
            tintColor="pink"
            refreshing={refreshing}
            onRefresh={onRefresh}
          />
        }
        onMomentumScrollEnd={fetchMore}>
        {news.map((entry: EntryPropsType) => (
          <Entry key={entry.sourceId} {...entry} />
        ))}
        {loading ? <ActivityIndicator size="large" color="red" /> : null}
      </ScrollView>
    </StatusBarSafeLayout>
  );
}
Example #3
Source File: Logistic.tsx    From wuhan2020-frontend-react-native-app with MIT License 6 votes vote down vote up
function LogisticLayout() {
  const [data, , loading, refresh] = useWuhan2020<LogisticalType>('logistical');
  const [refreshing, setRefreshing] = useState(false);

  const logistics: LogisticalType[] = data || [];

  function onRefresh() {
    setRefreshing(true);
    refresh();
    wait(2000).then(() => {
      setRefreshing(false);
    });
  }

  function renderItem({ item }: { item: LogisticalType }) {
    return <Logistic item={item} />;
  }

  return (
    <StatusBarSafeLayout>
      <FlatList
        refreshControl={
          <RefreshControl
            tintColor="red"
            refreshing={refreshing}
            onRefresh={onRefresh}
          />
        }
        keyExtractor={(item: LogisticalType) => String(item.id)}
        data={logistics}
        renderItem={renderItem}
        ListFooterComponent={loading ? <Loader /> : null}
      />
    </StatusBarSafeLayout>
  );
}
Example #4
Source File: PostList.tsx    From lexicon with MIT License 6 votes vote down vote up
PostList = forwardRef<Ref, Props>((props, ref) => {
  const { navigate } = useNavigation();
  const styles = useStyles();
  const { colors } = useTheme();

  const { onStartScroll, onStopScroll } = useUserEvent();

  const {
    data,
    showLabel,
    currentUser,
    hasFooter = true,
    numberOfLines = 0,
    showImageRow = false,
    style,
    prevScreen,
    onPressReply,
    refreshing,
    onRefresh,
    likedTopic,
    progressViewOffset = 0,
    ...otherProps
  } = props;

  const onPressAuthor = (username: string) => {
    navigate('UserInformation', { username });
  };

  const getItem = (data: Array<Post>, index: number) => data[index];

  const getItemCount = (data: Array<Post>) => data.length;

  const keyExtractor = ({ id, topicId }: Post) =>
    `post-${id === 0 ? topicId : id}`;

  const renderItem = ({ item }: { item: Post }) => (
    <PostItem
      data={item}
      postList={true}
      showLabel={showLabel}
      currentUser={currentUser}
      hasFooter={hasFooter}
      showImageRow={showImageRow}
      style={styles.item}
      numberOfLines={numberOfLines}
      prevScreen={prevScreen}
      onPressReply={onPressReply}
      onPressAuthor={onPressAuthor}
      likedTopic={likedTopic}
    />
  );

  return (
    <VirtualizedList
      ref={ref}
      data={data}
      refreshControl={
        <RefreshControl
          refreshing={refreshing}
          onRefresh={onRefresh}
          tintColor={colors.primary}
          progressViewOffset={progressViewOffset}
        />
      }
      onScrollBeginDrag={onStartScroll}
      onScrollEndDrag={onStopScroll}
      keyExtractor={keyExtractor}
      getItem={getItem}
      getItemCount={getItemCount}
      renderItem={renderItem}
      initialNumToRender={5}
      maxToRenderPerBatch={7}
      windowSize={10}
      style={[styles.container, style]}
      {...otherProps}
    />
  );
})
Example #5
Source File: devices.tsx    From iotc-cpm-sample with MIT License 6 votes vote down vote up
function DeviceList(props: {
  devices: IHealthDevice[];
  connect: (deviceId: string) => Promise<void>;
  refresh: () => void;
}) {
  const [refreshing, setRefreshing] = useState(false);
  const {devices, refresh, connect} = props;
  if (devices.length == 0) {
    return <NotFound retry={refresh} />;
  }
  return (
    <View style={{flex: 4}}>
      <Counter value={devices.length} />
      <ScrollView
        style={{flex: 1}}
        refreshControl={
          <RefreshControl
            refreshing={refreshing}
            onRefresh={() => {
              setRefreshing(true);
              refresh();
              // Hack! No need to restore refreshing state to false since
              // component will be unmounted by the end of the scan process
            }}
          />
        }>
        {devices.map(device => {
          return <Device key={device.id} device={device} connect={connect} />;
        })}
      </ScrollView>
    </View>
  );
}
Example #6
Source File: CloudSettings.tsx    From nyxo-app with GNU General Public License v3.0 5 votes vote down vote up
CloudSettings: FC<Props> = ({ route }) => {
  const dispatch = useAppDispatch()
  const { authenticated, loading } = useAppSelector(({ auth }) => auth)
  const linkingLoading = useAppSelector(({ linking }) => linking.loading)

  const linkCode = route?.params?.code

  const handleSignOut = () => {
    dispatch(logout())
  }

  const refresh = async () => {
    //FIXME
  }

  return (
    <SafeAreaView>
      <ScrollView
        refreshControl={
          <RefreshControl
            tintColor={colors.darkBlue}
            onRefresh={refresh}
            refreshing={linkingLoading === 'pending'}
          />
        }
        scrollEventThrottle={16}>
        <GoBackContainer>
          <GoBack route="Settings" />
          <Spacer />
        </GoBackContainer>

        <Container>
          <H2>NYXO_CLOUD.TITLE</H2>

          {!!authenticated && (
            <>
              <P>SCCloudInfo</P>
              <LinkModule linkCode={linkCode} />
              <PrimaryButton
                white
                title="Signout"
                onPress={handleSignOut}
                loading={loading === 'pending'}
              />
            </>
          )}
          {!authenticated && <SignupBottomButton />}
        </Container>
      </ScrollView>
      <CodeDisclaimer linkCode={linkCode} />
    </SafeAreaView>
  )
}
Example #7
Source File: MyLeave.tsx    From orangehrm-os-mobile with GNU General Public License v3.0 5 votes vote down vote up
render() {
    const {theme, leaveRequests} = this.props;
    return (
      <SafeAreaLayout>
        <FlatList
          data={leaveRequests}
          renderItem={({item}) => (
            <MyLeaveListItem
              leaveRequest={item}
              onPress={this.onPressLeave(item)}
            />
          )}
          keyExtractor={(item) => item.id}
          ItemSeparatorComponent={() => {
            return (
              <View style={{paddingHorizontal: theme.spacing}}>
                <Divider />
              </View>
            );
          }}
          ListFooterComponent={
            leaveRequests === undefined ||
            leaveRequests?.length === 0 ? null : (
              <View
                style={{
                  paddingHorizontal: theme.spacing,
                  paddingBottom: theme.spacing * 4,
                }}>
                <Divider />
              </View>
            )
          }
          refreshControl={
            <RefreshControl refreshing={false} onRefresh={this.onRefresh} />
          }
          contentContainerStyle={styles.contentContainer}
          ListEmptyComponent={
            leaveRequests !== undefined ? (
              <View style={styles.emptyContentView}>
                <Icon
                  name={'info-outline'}
                  type={'MaterialIcons'}
                  style={{
                    fontSize: theme.typography.largeIconSize,
                    paddingBottom: theme.spacing * 2,
                    marginTop: -theme.spacing * 2,
                  }}
                />
                <Text>{'No Leave Requests Found.'}</Text>
              </View>
            ) : null
          }
        />
      </SafeAreaLayout>
    );
  }
Example #8
Source File: LeaveList.tsx    From orangehrm-os-mobile with GNU General Public License v3.0 5 votes vote down vote up
render() {
    const {theme, leaveList} = this.props;
    return (
      <SafeAreaLayout>
        <FlatList
          data={leaveList}
          renderItem={({item}) => (
            <>
              <LeaveListItem
                leaveRequest={item}
                onPress={this.onPressLeave(item)}
              />
            </>
          )}
          keyExtractor={(item) => item.leaveRequestId}
          ItemSeparatorComponent={() => {
            return (
              <View style={{paddingHorizontal: theme.spacing}}>
                <Divider />
              </View>
            );
          }}
          ListFooterComponent={
            leaveList === undefined || leaveList?.length === 0 ? null : (
              <View
                style={{
                  paddingHorizontal: theme.spacing,
                  paddingBottom: theme.spacing * 4,
                }}>
                <Divider />
              </View>
            )
          }
          refreshControl={
            <RefreshControl refreshing={false} onRefresh={this.onRefresh} />
          }
          contentContainerStyle={styles.contentContainer}
          ListEmptyComponent={
            leaveList !== undefined ? (
              <View style={styles.emptyContentView}>
                <Icon
                  name={'info-outline'}
                  type={'MaterialIcons'}
                  style={{
                    fontSize: theme.typography.largeIconSize,
                    paddingBottom: theme.spacing * 2,
                    marginTop: -theme.spacing * 2,
                  }}
                />
                <Text>{'No Leave Requests Found.'}</Text>
              </View>
            ) : null
          }
        />
      </SafeAreaLayout>
    );
  }
Example #9
Source File: MainLayout.tsx    From orangehrm-os-mobile with GNU General Public License v3.0 5 votes vote down vote up
MainLayout = (props: React.PropsWithChildren<MainLayoutProps>) => {
  const {
    theme,
    children,
    refreshing,
    onRefresh,
    footer,
    header,
    scrollViewProps,
    statusBarBackgroundColor,
  } = props;

  return (
    <>
      <StatusBar
        barStyle="dark-content"
        backgroundColor={
          statusBarBackgroundColor
            ? statusBarBackgroundColor
            : theme.palette.statusBarSecondary
        }
      />
      <SafeAreaView
        style={[styles.safeArea, {backgroundColor: theme.palette.background}]}>
        {header === undefined ? null : header}
        <ScrollView
          contentInsetAdjustmentBehavior="automatic"
          contentContainerStyle={styles.scrollView}
          keyboardShouldPersistTaps="handled"
          refreshControl={
            onRefresh === undefined ? undefined : (
              <RefreshControl
                refreshing={refreshing === undefined ? false : refreshing}
                onRefresh={onRefresh}
              />
            )
          }
          {...scrollViewProps}>
          {children}
        </ScrollView>
        {footer === undefined ? null : footer}
      </SafeAreaView>
    </>
  );
}
Example #10
Source File: AttendanceList.tsx    From orangehrm-os-mobile with GNU General Public License v3.0 5 votes vote down vote up
render() {
    const {theme, employeeList, weekStartDay} = this.props;
    return (
      <SafeAreaLayout>
        <View
          style={{
            backgroundColor: theme.palette.backgroundSecondary,
            paddingBottom: theme.spacing * 2,
          }}>
          <DatePeriodComponent
            startDate={this.getWeekStartDate()}
            endDate={this.getWeekEndDate()}
            leftActive={true}
            rightActive={this.state.startDayIndex !== weekStartDay}
            onPressLeft={this.goLeft}
            onPressRight={this.goRight}
          />
        </View>
        <FlatList
          data={employeeList}
          renderItem={({item}) => (
            <>
              <AttendanceListItem
                employeeAttendance={item}
                onPress={this.onPressLeave(item)}
              />
            </>
          )}
          keyExtractor={(item) => item.employeeId}
          ItemSeparatorComponent={() => {
            return (
              <View style={{paddingHorizontal: theme.spacing}}>
                <Divider />
              </View>
            );
          }}
          ListFooterComponent={
            employeeList === undefined || employeeList?.length === 0 ? null : (
              <View
                style={{
                  paddingHorizontal: theme.spacing,
                  paddingBottom: theme.spacing * 4,
                }}>
                <Divider />
              </View>
            )
          }
          refreshControl={
            <RefreshControl refreshing={false} onRefresh={this.onRefresh} />
          }
          contentContainerStyle={styles.contentContainer}
          ListEmptyComponent={
            employeeList !== undefined ? (
              <View style={styles.emptyContentView}>
                <Icon
                  name={'info-outline'}
                  type={'MaterialIcons'}
                  style={{
                    fontSize: theme.typography.largeIconSize,
                    paddingBottom: theme.spacing * 2,
                    marginTop: -theme.spacing * 2,
                  }}
                />
                <Text>{'No Records Found.'}</Text>
              </View>
            ) : null
          }
        />
      </SafeAreaLayout>
    );
  }
Example #11
Source File: simpleRefreshListScreen.tsx    From THUInfo with MIT License 5 votes vote down vote up
export function simpleRefreshListScreen<T>(
	dataSource: (props: PropsWithChildren<any>) => Promise<T[]>,
	renderItem: (
		item: T,
		refresh: () => void,
		props: PropsWithChildren<any>,
		theme: Theme,
		index: number,
		total: number,
	) => ReactElement,
	keyExtractor: (item: T) => string,
	footer?: (theme: Theme) => ReactElement,
	header?: (theme: Theme) => ReactElement,
	empty?: (theme: Theme) => ReactElement,
	initialNumToRender?: number,
): FC {
	return (props) => {
		const [data, setData] = useState<T[]>([]);
		const [refreshing, setRefreshing] = useState(false);

		const themeName = useColorScheme();
		const theme = themes(themeName);

		const refresh = () => {
			setRefreshing(true);
			dataSource(props)
				.then(setData)
				.catch(() =>
					Snackbar.show({
						text: getStr("networkRetry"),
						duration: Snackbar.LENGTH_SHORT,
					}),
				)
				.then(() => setRefreshing(false));
		};
		// eslint-disable-next-line react-hooks/exhaustive-deps
		useEffect(refresh, []);

		return (
			<FlatList
				style={{flex: 1}}
				data={data}
				refreshControl={
					<RefreshControl
						refreshing={refreshing}
						onRefresh={refresh}
						colors={[theme.colors.accent]}
					/>
				}
				renderItem={({item, index}) =>
					renderItem(item, refresh, props, theme, index, data.length)
				}
				keyExtractor={keyExtractor}
				ListHeaderComponent={
					data.length === 0 ? null : header ? header(theme) : undefined
				}
				ListFooterComponent={footer ? footer(theme) : undefined}
				ListEmptyComponent={empty ? empty(theme) : undefined}
				initialNumToRender={initialNumToRender}
			/>
		);
	};
}
Example #12
Source File: ThreadList.tsx    From make-a-fortune with MIT License 5 votes vote down vote up
ThreadList: React.FC<{
  safeArea?: boolean;
}> = ({ safeArea }) => {
  const [refreshing, setRefreshing] = useState(false);

  const reloadLines = React.useCallback(() => {
    setRefreshing(true);

    wait(2000).then(() => {
      setRefreshing(false);
    });
  }, []);

  return (
    <>
      <Box safeAreaTop={safeArea} />
      <FlatList
        removeClippedSubviews
        refreshControl={
          <RefreshControl refreshing={refreshing} onRefresh={reloadLines} />
        }
        initialNumToRender={5}
        data={data}
        my={safeArea ? 12 : undefined}
        renderItem={({ item }) => (
          <VStack
            borderColor="gray.100"
            borderTopWidth={1}
            py={4}
            px={3}
            alignSelf="center"
            width={700}
            maxWidth="100%"
            key={item.id}
            space={1}
            bgColor="white"
          >
            <HStack space={2} alignItems="center">
              <Badge>#23333</Badge>
              <Badge>校园</Badge>
              <Box mx="auto" />
              <HStack space={1}>
                <Icon
                  as={<MaterialCommunityIcons name="comment-outline" />}
                  color="black"
                  size="xs"
                />
                <Text alignSelf="flex-end" fontSize="sm">
                  1
                </Text>
              </HStack>
            </HStack>
            <HStack space={1} alignItems="center">
              <Text>{item.title}</Text>
            </HStack>
            <Text>{item.content}</Text>
          </VStack>
        )}
        keyExtractor={item => item.id.toString()}
        // ListHeaderComponent={
        //   <Box alignSelf="center">
        //     <Button
        //       startIcon={
        //         <Icon as={MaterialCommunityIcons} name="refresh" size={5} />
        //       }
        //     >
        //       有新帖子
        //     </Button>
        //   </Box>
        // }
      />
      <Box safeAreaBottom={safeArea} />
    </>
  );
}
Example #13
Source File: ListView.tsx    From rn-clean-architecture-template with MIT License 5 votes vote down vote up
ListView: ListViewFC = (props) => {
  const {
    refreshing,
    ListFooterComponent,
    data,
    isLoadingMore,
    LoadingComponent,
  } = props;

  const refreshIndicatorVisible =
    refreshing === true && (data?.length ?? 0) > 0;

  const skeletonDisplayable =
    (refreshing && data?.length === 0) || isLoadingMore;

  const emptyItem = () => {
    if (refreshing) {
      return null;
    }
    return <EmptyListView {...props.emptyListViewProps} />;
  };

  const footer = () => {
    if (skeletonDisplayable) {
      if (LoadingComponent) {
        return LoadingComponent;
      }
      return (
        <>
          <SkeletonLoadingItem />
          <SkeletonLoadingItem />
          <SkeletonLoadingItem />
        </>
      );
    }
    return ListFooterComponent;
  };

  return (
    <View style={[styles.container]}>
      <FlatList
        {...props}
        ListEmptyComponent={emptyItem()}
        ListFooterComponent={footer()}
        refreshControl={
          <RefreshControl
            refreshing={refreshIndicatorVisible}
            onRefresh={props.onRefresh}
          />
        }
        style={styles.list}
      />
    </View>
  );
}
Example #14
Source File: ManageSubscription.tsx    From nyxo-app with GNU General Public License v3.0 5 votes vote down vote up
ManageSubscription: FC = () => {
  const loadingPurchase = useAppSelector((state) => state.subscription.loading)
  const dispatch = useAppDispatch()

  const [info, setEntitlements] = useState<
    PurchasesEntitlementInfos | undefined
  >()

  const handleRestorePurchase = async () => {
    await dispatch(restorePurchase())
  }

  const refetch = async () => {
    const { entitlements } = await Purchases.getPurchaserInfo()
    setEntitlements(entitlements)
  }

  useEffect(() => {
    const fetchData = async () => {
      const { entitlements } = await Purchases.getPurchaserInfo()
      setEntitlements(entitlements)
    }
    fetchData()
  }, [])

  const hasActiveSubscription = info?.active['Nyxo Coaching']?.isActive

  return (
    <SafeAreaView>
      <ScrollView
        refreshControl={
          <RefreshControl refreshing={loadingPurchase} onRefresh={refetch} />
        }>
        <GoBackContainer>
          <GoBack />
        </GoBackContainer>

        <Container>
          <H1>Manage Nyxo Subscription</H1>

          <ActiveSubscriptions />

          {!hasActiveSubscription && (
            <>
              <H2>RESTORE_PURCHASE</H2>
              <P>RESTORE_PURCHASE_BODY</P>
              <TextButton center onPress={handleRestorePurchase}>
                RESTORE_PURCHASE
              </TextButton>
            </>
          )}
        </Container>
      </ScrollView>
    </SafeAreaView>
  )
}
Example #15
Source File: Consultation.tsx    From wuhan2020-frontend-react-native-app with MIT License 5 votes vote down vote up
function ConsultationLayout() {
  const [data, , loading, refresh] = useWuhan2020<Clinic>('clinic');
  const [refreshing, setRefreshing] = useState(false);

  const clinics: Clinic[] = data || [];

  function onRefresh() {
    setRefreshing(true);
    refresh();
    wait(2000).then(() => {
      setRefreshing(false);
    });
  }

  function renderItem({ item }: { item: Clinic }) {
    return <Consultation item={item} />;
  }

  return (
    <StatusBarSafeLayout>
      <FlatList
        refreshControl={
          <RefreshControl
            tintColor="pink"
            refreshing={refreshing}
            onRefresh={onRefresh}
          />
        }
        keyExtractor={(item: Clinic) => String(item.id)}
        data={clinics}
        renderItem={renderItem}
        ListFooterComponent={
          loading ? (
            <View style={{ paddingTop: 20 }}>
              <Loader />
            </View>
          ) : null
        }
      />
    </StatusBarSafeLayout>
  );
}
Example #16
Source File: Donation.tsx    From wuhan2020-frontend-react-native-app with MIT License 5 votes vote down vote up
function DonationLayout() {
  const [data, , loading, refresh] = useWuhan2020<DonationType>('donation');
  const [refreshing, setRefreshing] = useState(false);

  const donations: DonationType[] = data || [];

  function onRefresh() {
    setRefreshing(true);
    refresh();
    wait(2000).then(() => {
      setRefreshing(false);
    });
  }

  function renderItem({ item }: { item: DonationType }) {
    return <Donation item={item} />;
  }

  return (
    <StatusBarSafeLayout>
      <FlatList
        refreshControl={
          <RefreshControl
            tintColor="pink"
            refreshing={refreshing}
            onRefresh={onRefresh}
          />
        }
        keyExtractor={(item: DonationType) => String(item.id)}
        data={donations}
        renderItem={renderItem}
        ListFooterComponent={
          loading ? (
            <View style={{ paddingTop: 20 }}>
              <Loader />
            </View>
          ) : null
        }
      />
    </StatusBarSafeLayout>
  );
}
Example #17
Source File: crHome.tsx    From THUInfo with MIT License 5 votes vote down vote up
CrHomeScreen = ({navigation}: {navigation: RootNav}) => {
	const [semesters, setSemesters] = useState<CrSemester[]>([]);
	const [refreshing, setRefreshing] = useState(false);

	const themeName = useColorScheme();
	const {colors} = themes(themeName);

	const refresh = () => {
		setRefreshing(true);
		helper
			.getCrAvailableSemesters()
			.then(setSemesters)
			.catch((e) => {
				if (e instanceof CrTimeoutError) {
					navigation.navigate("CrCaptcha");
				} else {
					Snackbar.show({
						text: getStr("networkRetry") + e?.message,
						duration: Snackbar.LENGTH_SHORT,
					});
				}
			})
			.then(() => setRefreshing(false));
	};
	// eslint-disable-next-line react-hooks/exhaustive-deps
	useEffect(refresh, []);

	return (
		<FlatList
			style={{flex: 1}}
			data={semesters}
			refreshControl={
				<RefreshControl
					refreshing={refreshing}
					onRefresh={refresh}
					colors={[colors.accent]}
				/>
			}
			renderItem={({item: {id, name}}) => (
				<TouchableOpacity
					onPress={() => navigation.navigate("CrCoursePlan", {semesterId: id})}
					style={{
						padding: 15,
						flexDirection: "row",
						justifyContent: "space-between",
					}}>
					<View style={{flex: 2, alignItems: "flex-start"}}>
						<Text style={{fontSize: 16, marginVertical: 2, color: colors.text}}>
							{name}
						</Text>
						<Text style={{color: "grey", marginVertical: 2}}>{id}</Text>
					</View>
				</TouchableOpacity>
			)}
			keyExtractor={({id}) => id}
		/>
	);
}
Example #18
Source File: Mobility.tsx    From wuhan2020-frontend-react-native-app with MIT License 5 votes vote down vote up
function MobilityScreen() {
  const { data, loading, refresh } = useContext(MobilityDataContext);
  const [refreshing, setRefreshing] = useState(false);

  function keyExtractor(item: EntryType) {
    return String(item.id);
  }

  function renderItem({ item }: { item: EntryType }) {
    return <Mobility item={item} />;
  }

  const onRefresh = useCallback(() => {
    setRefreshing(true);

    refresh();
    wait(2000).then(() => setRefreshing(false));
  }, [refreshing, refresh]);

  return (
    <StatusBarSafeLayout>
      <View>
        <SectionList
          keyExtractor={keyExtractor}
          refreshing={loading}
          refreshControl={
            <RefreshControl
              tintColor="pink"
              refreshing={refreshing}
              onRefresh={onRefresh}
            />
          }
          renderItem={renderItem}
          sections={toSection(data)}
          renderSectionHeader={({ section: { title } }) => (
            <View style={{ backgroundColor: '#eee' }}>
              <Text style={styles.subheader}>{title}</Text>
            </View>
          )}
          ListEmptyComponent={<ActivityIndicator size="large" color="red" />}
          ListHeaderComponent={
            <View style={styles.header}>
              <H1 title="确诊患者相同行程查询" />
            </View>
          }
        />
      </View>
    </StatusBarSafeLayout>
  );
}
Example #19
Source File: Hospital.tsx    From wuhan2020-frontend-react-native-app with MIT License 5 votes vote down vote up
function HospitalLayout() {
  const [data, , loading, refresh] = useWuhan2020<HospitalType>('hospital');
  const [refreshing, setRefreshing] = useState(false);

  const hospitals: HospitalType[] = data || [];

  function onRefresh() {
    setRefreshing(true);
    refresh();
    wait(2000).then(() => {
      setRefreshing(false);
    });
  }

  function renderItem({ item }: { item: HospitalType }) {
    return <Hospital item={item} />;
  }

  return (
    <StatusBarSafeLayout>
      <FlatList
        refreshControl={
          <RefreshControl
            tintColor="pink"
            refreshing={refreshing}
            onRefresh={onRefresh}
          />
        }
        keyExtractor={(item: HospitalType) => String(item.id)}
        data={hospitals}
        renderItem={renderItem}
        ListFooterComponent={
          loading ? (
            <View style={{ paddingTop: 20 }}>
              <Loader />
            </View>
          ) : null
        }
      />
    </StatusBarSafeLayout>
  );
}
Example #20
Source File: Hotel.tsx    From wuhan2020-frontend-react-native-app with MIT License 5 votes vote down vote up
function HotelLayout() {
  const [data, , loading, refresh] = useWuhan2020<TravelHotel>('travel_hotel');
  const [refreshing, setRefreshing] = useState(false);

  const hotels: HotelType[] = data || [];

  function onRefresh() {
    setRefreshing(true);
    refresh();
    wait(2000).then(() => {
      setRefreshing(false);
    });
  }

  function renderItem({ item }: { item: HotelType }) {
    return <Hotel item={item} />;
  }

  return (
    <StatusBarSafeLayout>
      <FlatList
        refreshControl={
          <RefreshControl
            tintColor="pink"
            refreshing={refreshing}
            onRefresh={onRefresh}
          />
        }
        keyExtractor={(item: HotelType) => String(item.id)}
        data={hotels}
        renderItem={renderItem}
        ListFooterComponent={
          loading ? (
            <View style={{ paddingTop: 20 }}>
              <Loader />
            </View>
          ) : null
        }
      />
    </StatusBarSafeLayout>
  );
}
Example #21
Source File: expenditure.tsx    From THUInfo with MIT License 5 votes vote down vote up
ExpenditureScreen = () => {
	const [[expenditures, income, outgo, remainder], setExpenditures] = useState<
		[Record[], number, number, number]
	>([[], 0, 0, 0]);

	const [beg, setBeg] = useState(dayjs().add(-1, "month").toDate());
	const [end, setEnd] = useState(dayjs().toDate());
	const [refreshing, setRefreshing] = useState(false);

	const themeName = useColorScheme();
	const theme = themes(themeName);

	const refresh = () => {
		setRefreshing(true);
		helper
			.getExpenditures(beg, end)
			.then(setExpenditures)
			.catch((e) => {
				Snackbar.show({
					text: getStr("networkRetry") + e?.message,
					duration: Snackbar.LENGTH_SHORT,
				});
			})
			.then(() => setRefreshing(false));
	};

	// eslint-disable-next-line react-hooks/exhaustive-deps
	useEffect(refresh, []);

	return (
		<View style={{padding: 10, flex: 1}}>
			<View style={{flexDirection: "row"}}>
				<Money title={getStr("income")} money={income} />
				<Money title={getStr("outgo")} money={outgo} />
				<Money title={getStr("remainder")} money={refreshing ? 0 : remainder} />
			</View>
			{!helper.mocked() && (
				<View style={styles.header}>
					<DatePickerTrigger
						date={beg}
						onChange={setBeg}
						disabled={refreshing}
						text={Platform.OS === "ios" ? getStr("begDate") : ""}
					/>
					<DatePickerTrigger
						date={end}
						onChange={setEnd}
						disabled={refreshing}
						text={Platform.OS === "ios" ? getStr("endDate") : ""}
					/>
					<Button
						title={getStr("query")}
						onPress={refresh}
						disabled={refreshing}
					/>
				</View>
			)}
			<View style={styles.container}>
				<FlatList
					data={expenditures}
					refreshControl={
						<RefreshControl
							refreshing={refreshing}
							onRefresh={refresh}
							colors={[theme.colors.accent]}
						/>
					}
					renderItem={({item}) => <ExpenditureCard record={item} />}
					keyExtractor={(item, index) => `${item.date}-${item.value}-${index}`}
				/>
			</View>
		</View>
	);
}
Example #22
Source File: dashboard.tsx    From protect-scotland with Apache License 2.0 4 votes vote down vote up
Dashboard: FC = () => {
  const {t} = useTranslation();
  const {
    initialised,
    enabled,
    status,
    contacts,
    getCloseContacts,
    permissions,
    readPermissions
  } = useExposure();
  const [appState] = useAppState();
  const {checked, paused} = useReminder();
  const navigation = useNavigation();
  const {onboarded, setContext, loadAppData} = useApplication();
  const {
    isolationDuration,
    isolationCompleteDuration,
    latestVersion: appLatestVersion
  } = useSettings();
  const [refreshing, setRefreshing] = useState(false);
  const {
    focusRef: tourFocus,
    focusA11yElement: focusTourElem
  } = useA11yElement();
  const {
    focusRef: dashboardFocus,
    focusA11yElement: focusDashboardElem
  } = useA11yElement();
  const isFocused = useIsFocused();
  const messageOpacity = useRef(new Animated.Value(0)).current;
  const contentOpacity = useRef(new Animated.Value(0)).current;
  const gridOpacity = useRef(new Animated.Value(0)).current;
  const exposureEnabled = useRef(enabled);
  const bluetoothDisabled = useRef(
    status.state === 'disabled' && status.type?.includes(StatusType.bluetooth)
  );
  const pushNotificationsDisabled = useRef(
    permissions.notifications.status === 'not_allowed'
  );

  const [state, setState] = useState<{
    stage: number;
    exposurePrompt: boolean;
    bluetoothPrompt: boolean;
    pushNotificationsPrompt: boolean;
    disabled: boolean;
    current: string;
    isolationMessage: string | null;
    isolationComplete: boolean;
    default: string;
    messages: string[];
  }>({
    stage: onboarded ? -1 : 0,
    exposurePrompt: false,
    bluetoothPrompt: false,
    pushNotificationsPrompt: false,
    disabled: false,
    current: t(
      getMessage({
        onboarded,
        enabled,
        status,
        messages: t('dashboard:tour', {returnObjects: true}),
        stage: onboarded ? -1 : 0,
        paused
      })
    ),
    isolationMessage: null,
    isolationComplete: false,
    messages: t('dashboard:tour', {returnObjects: true}),
    default: t('dashboard:message:standard')
  });

  const version = useVersion();

  const resetToNormal = () =>
    setState((s) => ({
      ...s,
      isolationComplete: false,
      isolationMessage: null
    }));

  const setExposed = () =>
    setState((s) => ({
      ...s,
      isolationComplete: false,
      isolationMessage: t('dashboard:exposed')
    }));

  const setIsolationComplete = () =>
    setState((s) => ({
      ...s,
      isolationComplete: true,
      isolationMessage: t('dashboard:isolationComplete')
    }));

  const processContactsForMessaging = async () => {
    let currentStatus = null;
    try {
      currentStatus = await SecureStore.getItemAsync('niexposuredate');
    } catch (err) {
      await SecureStore.deleteItemAsync('niexposuredate');
      console.log('processContactsForMessaging', err);
    }

    if (currentStatus) {
      const daysDiff = differenceInCalendarDays(
        new Date(),
        new Date(Number(currentStatus))
      );

      const withIsolation = isolationDuration + isolationCompleteDuration;

      if (daysDiff >= withIsolation) {
        await SecureStore.deleteItemAsync('niexposuredate');
        return resetToNormal();
      }

      if (daysDiff >= isolationDuration && daysDiff < withIsolation) {
        return setIsolationComplete();
      }

      if (contacts && contacts.length > 0) {
        return setExposed();
      }
    }

    return resetToNormal();
  };

  const checkLatestExposure = async () => {
    const latestExposure = getExposureDate(contacts);

    if (latestExposure) {
      await SecureStore.setItemAsync(
        'niexposuredate',
        String(latestExposure.getTime())
      );
    }

    processContactsForMessaging();
  };

  const onRefresh = () => {
    setRefreshing(true);
    loadAppData().then(() => setRefreshing(false));
  };

  useEffect(() => {
    onRefresh();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  useEffect(() => {
    getCloseContacts();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [status]);

  useEffect(() => {
    checkLatestExposure();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [contacts, status]);

  useFocusEffect(
    React.useCallback(() => {
      if (!isFocused || appState !== 'active') {
        return;
      }

      readPermissions();
    }, [isFocused, appState, readPermissions])
  );

  useEffect(() => {
    setState((s) => ({
      ...s,
      current: t(
        getMessage({
          onboarded,
          enabled,
          status,
          messages: state.messages,
          stage: state.stage,
          paused
        })
      )
    }));

    exposureEnabled.current = enabled;
    bluetoothDisabled.current =
      status.state === 'disabled' &&
      status.type?.includes(StatusType.bluetooth);
    pushNotificationsDisabled.current =
      permissions.notifications.status === 'not_allowed';

    if (!exposureEnabled.current && onboarded) {
      setTimeout(() => {
        if (!exposureEnabled.current) {
          setState((s) => ({
            ...s,
            exposurePrompt: true
          }));
        }
      }, PROMPT_OFFSET);
    } else if (bluetoothDisabled.current && onboarded) {
      setTimeout(() => {
        if (bluetoothDisabled.current) {
          setState((s) => ({
            ...s,
            bluetoothPrompt: true
          }));
        }
      }, PROMPT_OFFSET);
    } else if (pushNotificationsDisabled.current && onboarded) {
      setTimeout(() => {
        if (
          pushNotificationsDisabled.current &&
          exposureEnabled.current &&
          !bluetoothDisabled.current
        ) {
          setState((s) => ({
            ...s,
            pushNotificationsPrompt: true
          }));
        }
      }, PROMPT_OFFSET);
    } else if (onboarded && exposureEnabled.current) {
      setState((s) => ({
        ...s,
        exposurePrompt: false
      }));
    }

    setTimeout(() => checkLatestExposure(), 100);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [enabled, onboarded, status, permissions]);

  const animateTourIn = () => {
    setState((s) => ({...s, disabled: true}));
    Animated.parallel([
      Animated.timing(messageOpacity, {
        toValue: 1,
        duration: ANIMATION_DURATION,
        useNativeDriver: true
      }),
      Animated.timing(gridOpacity, {
        toValue: 1,
        duration: ANIMATION_DURATION,
        useNativeDriver: true
      })
    ]).start(() => {
      setState((s) => ({...s, disabled: false}));
    });
  };

  const animateTourOut = () => {
    setState((s) => ({...s, disabled: true}));
    Animated.parallel([
      Animated.timing(messageOpacity, {
        toValue: 0,
        duration: ANIMATION_DURATION,
        useNativeDriver: true
      }),
      Animated.timing(gridOpacity, {
        toValue: 0,
        duration: ANIMATION_DURATION,
        useNativeDriver: true
      })
    ]).start(() => {
      if (state.stage < state.messages.length - 1) {
        setState((s) => ({
          ...s,
          stage: state.stage + 1,
          current: getMessage({
            onboarded,
            enabled,
            status,
            messages: state.messages,
            stage: state.stage + 1
          })
        }));
        animateTourIn();
      } else {
        setState((s) => ({
          ...s,
          stage: -1,
          current: s.default
        }));
        setContext({onboarded: true});
        animateDashboard();
      }
    });
  };

  const animateDashboard = () => {
    setState((s) => ({...s, disabled: true}));
    Animated.parallel([
      Animated.timing(messageOpacity, {
        toValue: 1,
        duration: ANIMATION_DURATION,
        useNativeDriver: true
      }),
      Animated.timing(contentOpacity, {
        toValue: 1,
        duration: ANIMATION_DURATION,
        useNativeDriver: true
      }),
      Animated.timing(gridOpacity, {
        toValue: 1,
        duration: ANIMATION_DURATION,
        useNativeDriver: true
      })
    ]).start(() => {
      AsyncStorage.setItem('scot.onboarded', 'true');
      setState((s) => ({...s, disabled: false}));
    });
  };

  useEffect(() => {
    if (onboarded) {
      setTimeout(() => animateDashboard(), 200);
    } else {
      setTimeout(() => animateTourIn(), 200);
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  useEffect(() => {
    if (!state.disabled) {
      focusTourElem();
    }
  }, [focusTourElem, state.disabled]);

  useEffect(() => {
    if (onboarded && !state.disabled) {
      focusDashboardElem();
    }
  }, [focusDashboardElem, onboarded, state.disabled]);

  const handleTour = () => {
    animateTourOut();
  };

  if (!initialised || !checked) {
    return (
      <>
        <Container center="both">
          <ActivityIndicator color={colors.darkGrey} size="large" />
        </Container>
      </>
    );
  }

  return (
    <>
      <Header />
      <ScrollView
        refreshControl={
          <RefreshControl
            refreshing={onboarded && refreshing}
            onRefresh={onRefresh}
          />
        }>
        {onboarded &&
          appLatestVersion &&
          version &&
          appLatestVersion !== version?.display && (
            <View style={blockStyles.block}>
              <NewVersionCard />
              <Spacing s={16} />
            </View>
          )}
        <Spacing s={onboarded ? 15 : 65} />
        {!onboarded && state.stage > -1 && (
          <>
            <View style={styles.dots}>
              {[-1, 0, 1, 2].map((x) => (
                <Animated.View
                  key={`step-${x}`}
                  style={[
                    styles.dot,
                    {
                      backgroundColor:
                        state.stage > x
                          ? colors.primaryPurple
                          : colors.lighterPurple
                    }
                  ]}
                />
              ))}
            </View>
            <A11yView
              ref={tourFocus}
              accessible
              accessibilityHint={
                t('dashboard:tourA11y', {returnObjects: true})[state.stage]
              }
            />
            <Animated.View style={{opacity: messageOpacity}}>
              <TouchableWithoutFeedback onPress={() => handleTour()}>
                <Markdown markdownStyles={markDownStyles}>
                  {state.current}
                </Markdown>
              </TouchableWithoutFeedback>
              <Spacing s={30} />
              <ArrowLink
                onPress={() => {
                  if (!state.disabled) {
                    handleTour();
                  }
                }}
                accessibilityHint={t('dashboard:tourActionHint')}
                invert>
                <Text variant="h3" color="pink" style={styles.nextLink}>
                  {t('dashboard:tourAction')}
                </Text>
              </ArrowLink>
            </Animated.View>
          </>
        )}

        {onboarded && state.isolationMessage && (
          <>
            <Animated.View
              style={{
                opacity: messageOpacity
              }}>
              <View accessible ref={dashboardFocus}>
                <Markdown
                  markdownStyles={
                    state.isolationComplete
                      ? markDownStyles
                      : markDownStylesExposed
                  }>
                  {state.isolationMessage}
                </Markdown>
              </View>
              {!state.isolationComplete && (
                <>
                  <Spacing s={30} />
                  <ArrowLink
                    onPress={() =>
                      navigation.navigate(ScreenNames.closeContact)
                    }
                    accessibilityHint={t('dashboard:exposedAction')}
                    invert>
                    <Text variant="h3" color="pink" style={styles.nextLink}>
                      {t('dashboard:tourAction')}
                    </Text>
                  </ArrowLink>
                </>
              )}
              {state.isolationComplete && (
                <>
                  <Spacing s={20} />
                  <Text style={blockStyles.block} inline color="darkGrey">
                    {t('dashboard:isolationCompleteSupplemental')}
                  </Text>
                </>
              )}
            </Animated.View>
            <Spacing s={30} />
            <Animated.View
              style={[{opacity: contentOpacity}, blockStyles.block]}>
              <Message />
            </Animated.View>
          </>
        )}

        {onboarded && !state.isolationMessage && (
          <Animated.View style={{opacity: messageOpacity}}>
            <View accessible ref={dashboardFocus}>
              <Markdown markdownStyles={markDownStyles}>
                {state.current}
              </Markdown>
            </View>
            {state.stage === -1 && !paused && (
              <>
                <Spacing s={20} />
                <Text style={blockStyles.block} inline color="darkGrey">
                  {t(`dashboard:message:bluetooth:${Platform.OS}`)}
                </Text>
              </>
            )}
            {state.stage === -1 && paused && (
              <>
                <Spacing s={20} />
                <Text style={blockStyles.block} inline color="darkGrey">
                  {t('dashboard:message:pausedSupplemental')}
                </Text>
              </>
            )}
          </Animated.View>
        )}
        <Spacing s={30} />
        <Grid
          onboarded={onboarded}
          stage={state.stage}
          opacity={gridOpacity}
          onboardingCallback={() => handleTour()}
        />
        {state.isolationMessage && <Spacing s={34} />}
        {onboarded && !state.isolationMessage && (
          <>
            <Animated.View
              style={[{opacity: contentOpacity}, blockStyles.block]}>
              <Spacing s={30} />
              <Message />
              <Spacing s={16} />
              <Message
                image={RestrictionsImage}
                markdown={t('restrictions:message')}
                accessibilityLabel={t('restrictions:a11y:label')}
                accessibilityHint={t('restrictions:a11y:hint')}
                link={t('links:r')}
              />
              <Spacing s={45} />
            </Animated.View>
          </>
        )}
        {onboarded && (
          <Text variant="h4" color="primaryPurple" align="center">
            {t('dashboard:thanks')}
          </Text>
        )}
        <Spacing s={60} />
      </ScrollView>
      {checked && !paused && state.exposurePrompt && (
        <ExposureNotificationsModal
          isVisible={state.exposurePrompt}
          onBackdropPress={() =>
            setState((s) => ({...s, exposurePrompt: false}))
          }
          onClose={() => setState((s) => ({...s, exposurePrompt: false}))}
        />
      )}
      {checked && !paused && state.bluetoothPrompt && (
        <BluetoothNotificationsModal
          isVisible={state.bluetoothPrompt}
          onBackdropPress={() =>
            setState((s) => ({...s, bluetoothPrompt: false}))
          }
          onClose={() => setState((s) => ({...s, bluetoothPrompt: false}))}
        />
      )}
      {checked && !paused && state.pushNotificationsPrompt && (
        <PushNotificationsModal
          isVisible={state.pushNotificationsPrompt}
          onBackdropPress={() =>
            setState((s) => ({...s, pushNotificationsPrompt: false}))
          }
          onClose={() =>
            setState((s) => ({...s, pushNotificationsPrompt: false}))
          }
        />
      )}
    </>
  );
}
Example #23
Source File: PickEmployee.tsx    From orangehrm-os-mobile with GNU General Public License v3.0 4 votes vote down vote up
render() {
    const {theme, route, navigation, employees} = this.props;
    const {textValue, setTextValue, onRefresh} = route.params;

    let filteredData;
    if (textValue !== '') {
      const filterFn = this.filterFunction(textValue);
      filteredData = employees?.filter(filterFn);
    } else {
      filteredData = employees;
    }

    const paddingRight = theme.spacing * 6;

    return (
      <SafeAreaLayout>
        <View
          style={[
            styles.flex,
            {backgroundColor: theme.palette.backgroundSecondary},
          ]}>
          <View style={[styles.row, styles.inflex]}>
            <FlatButton
              text={'Employee'}
              icon={'account'}
              rightIcon={false}
              elevation
              onPress={this.onPressEmployeePicker}
            />
          </View>
          <View style={styles.inflex}>
            <PickEmployeeTextInput
              ref={(input) => {
                this.inputRef = input;
              }}
              autoFocus
              value={textValue}
              onChangeText={(text) => {
                navigation.setParams({textValue: text});
                setTextValue(text);
              }}
              style={[
                {
                  paddingRight,
                  paddingLeft: theme.spacing * 12,
                  backgroundColor: theme.palette.background,
                  ...Platform.select({
                    ios: {
                      paddingVertical: theme.spacing * 4,
                    },
                  }),
                },
                styles.textInputView,
              ]}
            />
          </View>
          <View style={[styles.row, styles.flex]}>
            {filteredData === undefined || filteredData.length === 0 ? (
              <View style={[styles.row, styles.flex, styles.center]}>
                <Text
                  style={{
                    padding: theme.spacing * 4,
                  }}>
                  {'No matching records found'}
                </Text>
              </View>
            ) : (
              <FlatList
                ItemSeparatorComponent={() => {
                  return <Divider />;
                }}
                ListHeaderComponent={<Divider />}
                ListFooterComponent={
                  <View
                    style={{
                      paddingBottom: theme.spacing * 2,
                    }}
                  />
                }
                data={filteredData}
                renderItem={({item}) => {
                  const fullName = getFirstAndLastNames(item);
                  return (
                    <TouchableOpacity onPress={this.pickEmployee(item)}>
                      <View
                        style={[
                          styles.row,
                          styles.flex,
                          {
                            paddingVertical: theme.spacing * 3,
                            paddingRight,
                            paddingLeft: theme.spacing * 4,
                            backgroundColor: theme.palette.background,
                          },
                        ]}>
                        <Avatar name={fullName} small />
                        <View
                          style={[
                            styles.row,
                            styles.flex,
                            styles.listItemView,
                            {
                              paddingTop: theme.spacing * 2,
                              paddingLeft: theme.spacing * 4,
                            },
                          ]}>
                          <Text style={styles.fullName}>{fullName}</Text>
                          <Text style={styles.employeeId}>
                            {item.employeeId}
                          </Text>
                        </View>
                      </View>
                    </TouchableOpacity>
                  );
                }}
                keyExtractor={(item) => item.empNumber}
                keyboardShouldPersistTaps="handled"
                refreshControl={
                  <RefreshControl refreshing={false} onRefresh={onRefresh} />
                }
              />
            )}
          </View>
        </View>
      </SafeAreaLayout>
    );
  }
Example #24
Source File: paginatedRefreshListScreen.tsx    From THUInfo with MIT License 4 votes vote down vote up
export function paginatedRefreshListScreen<T, R>(
	dataSource: (props: PropsWithChildren<R>, page: number) => Promise<T[]>,
	renderItem: (
		item: T,
		refresh: () => void,
		props: PropsWithChildren<R>,
		theme: Theme,
		index: number,
		total: number,
	) => ReactElement,
	keyExtractor: (item: T) => string,
	footer?: (theme: Theme) => ReactElement,
	header?: (theme: Theme, refresh: () => void) => ReactElement,
	empty?: (theme: Theme) => ReactElement,
	initialNumToRender?: number,
): FC<R> {
	return (props: PropsWithChildren<R>) => {
		const [data, setData] = useState<T[]>([]);
		const [page, setPage] = useState<number>(1);
		const [refreshing, setRefreshing] = useState(false);
		const [locked, setLocked] = useState(false);

		const themeName = useColorScheme();
		const theme = themes(themeName);

		const refresh = (force: boolean) => {
			if ((locked || refreshing) && !force) {
				return;
			}
			setRefreshing(true);
			setLocked(false);
			dataSource(props, force ? 1 : page + 1)
				.then((r) => {
					setData((prevData) => (force ? r : prevData.concat(r)));
					if (r.length === 0) {
						setLocked(true);
					}
				})
				.catch((e) => {
					console.error(e);
					Snackbar.show({
						text: `${getStr("networkRetry")}: ${e.message}`,
						duration: Snackbar.LENGTH_SHORT,
					});
				})
				.then(() => {
					setRefreshing(false);
					setPage((prevPage) => (force ? 1 : prevPage + 1));
				});
		};
		useEffect(() => {
			refresh(true);
			// eslint-disable-next-line react-hooks/exhaustive-deps
		}, []);

		return (
			<FlatList
				style={{flex: 1}}
				data={data}
				refreshControl={
					<RefreshControl
						refreshing={refreshing}
						onRefresh={() => refresh(true)}
						colors={[theme.colors.accent]}
					/>
				}
				renderItem={({item, index}) =>
					renderItem(
						item,
						() => {
							refresh(true);
						},
						props,
						theme,
						index,
						data.length,
					)
				}
				keyExtractor={keyExtractor}
				ListHeaderComponent={
					header
						? header(theme, () => {
								refresh(true); // eslint-disable-next-line no-mixed-spaces-and-tabs
						  })
						: undefined
				}
				ListFooterComponent={footer ? footer(theme) : undefined}
				ListEmptyComponent={empty ? empty(theme) : undefined}
				initialNumToRender={initialNumToRender}
				onEndReached={() => refresh(false)}
			/>
		);
	};
}
Example #25
Source File: AttendancePickEmployee.tsx    From orangehrm-os-mobile with GNU General Public License v3.0 4 votes vote down vote up
render() {
    const {theme, subordinates} = this.props;
    const {text} = this.state;

    let filteredData = subordinates;
    if (text !== '') {
      const filterFn = this.filterFunction(text);
      filteredData = subordinates?.filter(filterFn);
    } else {
      filteredData = subordinates;
    }

    const paddingRight = theme.spacing * 6;

    return (
      <SafeAreaLayout>
        <View
          style={[
            styles.flex,
            {backgroundColor: theme.palette.backgroundSecondary},
          ]}>
          <View style={styles.inflex}>
            <PickEmployeeTextInput
              autoFocus
              value={text}
              onChangeText={this.onChangeText}
              style={[
                {
                  paddingRight,
                  paddingLeft: theme.spacing * 12,
                  backgroundColor: theme.palette.background,
                  paddingVertical: theme.spacing * 4,
                },
                styles.textInputView,
              ]}
            />
          </View>
          <View style={[styles.row, styles.flex]}>
            {filteredData === undefined || filteredData.length === 0 ? (
              <View style={[styles.row, styles.flex, styles.center]}>
                <Text
                  style={{
                    padding: theme.spacing * 4,
                  }}>
                  {'No matching records found'}
                </Text>
              </View>
            ) : (
              <FlatList
                ItemSeparatorComponent={() => {
                  return <Divider />;
                }}
                ListHeaderComponent={<Divider />}
                ListFooterComponent={
                  <View
                    style={{
                      paddingBottom: theme.spacing * 2,
                    }}
                  />
                }
                data={filteredData}
                renderItem={({item}) => {
                  const fullName = getFirstAndLastNames(item);
                  return (
                    <TouchableOpacity onPress={this.pickEmployee(item)}>
                      <View
                        style={[
                          styles.row,
                          styles.flex,
                          {
                            paddingVertical: theme.spacing * 3,
                            paddingRight,
                            paddingLeft: theme.spacing * 4,
                            backgroundColor: theme.palette.background,
                          },
                        ]}>
                        <Avatar name={fullName} small />
                        <View
                          style={[
                            styles.row,
                            styles.flex,
                            styles.listItemView,
                            {
                              paddingTop: theme.spacing * 2,
                              paddingLeft: theme.spacing * 4,
                            },
                          ]}>
                          <Text style={styles.fullName}>{fullName}</Text>
                          <Text style={styles.employeeId}>
                            {item.employeeId}
                          </Text>
                        </View>
                      </View>
                    </TouchableOpacity>
                  );
                }}
                keyExtractor={(item) => item.empNumber}
                keyboardShouldPersistTaps="handled"
                refreshControl={
                  <RefreshControl
                    refreshing={false}
                    onRefresh={this.onRefresh}
                  />
                }
              />
            )}
          </View>
        </View>
      </SafeAreaLayout>
    );
  }
Example #26
Source File: ProductListScreen.tsx    From magento_react_native_graphql with MIT License 4 votes vote down vote up
ProductListScreen = ({
  navigation,
  route: {
    params: { categoryId },
  },
}: Props): React.ReactElement => {
  const { data, networkStatus, error, refresh, loadMore } = useCategoryProducts(
    {
      categoryId,
    },
  );
  const { isVisible, selectedIndex, setVisible, sortOptions } = useSort({
    onPress: refresh,
  });
  const { theme } = useContext(ThemeContext);

  useLayoutEffect(() => {
    navigation.setOptions({
      headerRight: () => (
        <CustomHeaderButtons>
          <CustomHeaderItem
            title={translate('common.sort')}
            iconName="sort"
            onPress={() => setVisible(true)}
          />
        </CustomHeaderButtons>
      ),
    });
  }, [navigation]);

  const onProductItemClicked = (index: number) => {
    if (data?.products?.items) {
      navigation.navigate(Routes.NAVIGATION_TO_PRODUCT_DETAILS_SCREEN, {
        name: data.products.items[index].name,
        sku: data.products.items[index].sku,
      });
    }
  };

  const renderItem = ({
    item,
    index,
  }: {
    item: ProductInListType;
    index: number;
  }) => {
    return (
      <ProductListItem
        item={item}
        index={index}
        onPress={onProductItemClicked}
      />
    );
  };

  const renderFooterComponent = () =>
    (networkStatus === NetworkStatus.fetchMore && (
      <View style={styles.footerContainer}>
        <Spinner />
      </View>
    )) || <></>;

  return (
    <GenericTemplate errorMessage={error?.message}>
      <FlatList
        numColumns={2}
        data={data?.products?.items ?? []}
        renderItem={renderItem}
        keyExtractor={item => `productListItem${item.sku}`}
        refreshControl={
          <RefreshControl
            refreshing={
              networkStatus === NetworkStatus.refetch ||
              networkStatus === NetworkStatus.loading
            }
            onRefresh={refresh}
          />
        }
        onEndReached={loadMore}
        ListFooterComponent={renderFooterComponent}
      />
      <BottomSheet isVisible={isVisible} containerStyle={styles.sortContainer}>
        {sortOptions.map((option, index) => (
          <ListItem
            key={option.title}
            containerStyle={[
              option.containerStyle,
              selectedIndex === index && {
                backgroundColor: theme.colors?.grey5,
              },
            ]}
            onPress={option.onPress}
          >
            <ListItem.Content>
              <ListItem.Title style={option.titleStyle}>
                {option.title}
              </ListItem.Title>
            </ListItem.Content>
          </ListItem>
        ))}
      </BottomSheet>
    </GenericTemplate>
  );
}
Example #27
Source File: HomeScreen.tsx    From Covid19 with MIT License 4 votes vote down vote up
HomeScreen = (props: any) => {
  const defaultState = useAppSelector((state) => state.root.default);
  const dispatch = useAppDispatch();
  const [refreshing, setRefresh] = useState<boolean>(false);

  const onRefresh = useCallback(async () => {
    setRefresh(true);
    const data = await getCovidData(props.country);
    dispatch(updateData(data));
    setRefresh(false);
  }, []);

  const results = defaultState.data;
  const country = defaultState.country;

  return (
    <SafeAreaView>
      <MotiView
        style={styles.topIconsContainer}
        from={{
          opacity: 0,
        }}
        animate={{
          opacity: 1,
        }}
        transition={{
          type: "timing",
          duration: 200,
          delay: 400,
        }}
      >
        <TouchableOpacity
          style={{
            backgroundColor: "white",
            borderRadius: 8,
            elevation: 8,
            marginRight: 6,
          }}
          onPress={() =>
            Linking.openURL("https://github.com/sarthakpranesh/Covid19")
          }
        >
          <Github
            style={{
              margin: 8,
            }}
            color="black"
          />
        </TouchableOpacity>
        {Object.keys(vaccineData).includes(country.toLowerCase()) ? (
          <TouchableOpacity
            style={{
              backgroundColor: "white",
              borderRadius: 8,
              elevation: 8,
              marginRight: 6,
            }}
            onPress={() => Linking.openURL(vaccineData[country.toLowerCase()])}
          >
            <Vaccine
              style={{
                margin: 8,
              }}
              color="black"
            />
          </TouchableOpacity>
        ) : null}
      </MotiView>
      <ScrollView
        style={Styles.scrollView}
        contentContainerStyle={Styles.scrollViewContentContainer}
        alwaysBounceVertical
        showsVerticalScrollIndicator={false}
        refreshControl={
          <RefreshControl refreshing={refreshing} onRefresh={onRefresh} />
        }
      >
        <View style={Styles.mainHeader}>
          <Image
            style={styles.mainHeaderImage}
            source={require("../../assets/ic1.png")}
          />
        </View>

        <MotiView
          from={{
            translateX: 50,
            opacity: 0,
          }}
          animate={{
            translateX: 0,
            opacity: 1,
          }}
          transition={{
            type: "timing",
            duration: 200,
          }}
        >
          <Country
            data={results?.global}
            countryName="World"
            containerStyle="#B1ECFF"
          />
        </MotiView>

        <MotiView
          from={{
            translateX: 50,
            opacity: 0,
          }}
          animate={{
            translateX: 0,
            opacity: 1,
          }}
          transition={{
            type: "timing",
            duration: 200,
            delay: 200,
          }}
        >
          <Country data={results?.country} countryName={country} />
        </MotiView>

        <MotiView
          from={{
            translateX: 50,
            opacity: 0,
          }}
          animate={{
            translateX: 0,
            opacity: 1,
          }}
          transition={{
            type: "timing",
            duration: 200,
            delay: 400,
          }}
        >
          <CandleCharts country={country} data={results?.timeline} />
        </MotiView>
      </ScrollView>
    </SafeAreaView>
  );
}
Example #28
Source File: quick-add-accounts-selector.tsx    From beancount-mobile with MIT License 4 votes vote down vote up
QuickAddAccountsSelector = connect(
  (state: { base: { userId: string } }) => ({
    userId: state.base.userId,
  })
)(function AssetsExpensesSelectorInner(props: Props): JSX.Element {
  const theme = useTheme().colorTheme;
  const styles = getStyles(theme);
  const { userId, onChange, navigation } = props;
  const [refreshing, setRefreshing] = useState(false);
  const {
    assetsOptionTabs,
    expensesOptionTabs,
    currencies,
    error,
    loading,
    refetch,
  } = useLedgerMeta(userId);
  const [selectedAssets, setSelectedAssets] = useState(
    assetsOptionTabs.length > 0 ? assetsOptionTabs[0].options[0] : ""
  );
  const [selectedExpenses, setSelectedExpenses] = useState(
    expensesOptionTabs.length > 0 ? expensesOptionTabs[0].options[0] : ""
  );

  useEffect(() => {
    const currency = currencies.length > 0 ? currencies[0] : "";
    if (onChange) {
      onChange({ asset: selectedAssets, expense: selectedExpenses, currency });
    }
  });

  const isLoading = loading || refreshing;

  if (loading) {
    return (
      <ScrollView
        style={styles.container}
        refreshControl={
          <RefreshControl
            refreshing={isLoading}
            onRefresh={async () => {
              try {
                setRefreshing(true);
                await refetch();
              } finally {
                setRefreshing(false);
              }
            }}
          />
        }
      >
        <LoadingList />
      </ScrollView>
    );
  }
  if (error) {
    return (
      <View style={[styles.container, styles.center]}>
        <Text
          onPress={async () => {
            await refetch();
          }}
        >
          {error.message}
        </Text>
      </View>
    );
  }

  return (
    <ScrollView
      style={styles.container}
      refreshControl={
        <RefreshControl
          refreshing={isLoading}
          onRefresh={async () => {
            try {
              setRefreshing(true);
              await refetch();
            } finally {
              setRefreshing(false);
            }
          }}
        />
      }
    >
      {isLoading ? (
        <LoadingList />
      ) : (
        <List>
          <ListItemStyled
            onPress={async () => {
              await analytics.track("tap_assets_picker", {
                originalOption: selectedAssets,
              });
              navigation.navigate("AccountPicker", {
                optionTabs: assetsOptionTabs,
                selectedItem: selectedAssets,
                onSelected: (item: string) => {
                  setSelectedAssets(item);
                },
              });
            }}
          >
            <Brief>{i18n.t("from").toUpperCase()}</Brief>
            <TextStyled>{selectedAssets}</TextStyled>
          </ListItemStyled>
          <ListItemStyled
            onPress={async () => {
              await analytics.track("tap_expenses_picker", {
                originalOption: selectedAssets,
              });
              navigation.navigate("AccountPicker", {
                optionTabs: expensesOptionTabs,
                selectedItem: selectedExpenses,
                onSelected: (item: string) => {
                  setSelectedExpenses(item);
                },
              });
            }}
          >
            <Brief>{i18n.t("to").toUpperCase()}</Brief>
            <TextStyled>{selectedExpenses}</TextStyled>
          </ListItemStyled>
        </List>
      )}
    </ScrollView>
  );
})
Example #29
Source File: Home.tsx    From wuhan2020-frontend-react-native-app with MIT License 4 votes vote down vote up
function Map() {
  const { data, refresh, timeout } = useContext(DataContext);
  const [selectedIndex, setIndex] = useState(0);
  const filter = filterList[selectedIndex];
  const [refreshing, setRefreshing] = useState(false);

  let mapData = data || [];

  const total = {
    confirmedCount: 0,
    curedCount: 0,
    deadCount: 0,
  };

  const webviewRef = useRef(null);

  useEffect(function() {
    if (webviewRef.current) {
      webviewRef.current.setOption({
        title: {
          text: `疫情地图${titleMap[filter]}`,
        },
        tooltip: {
          trigger: 'item',
          formatter: '{b}',
        },
        visualMap: {
          pieces: piecesMap[filter],
          showLabel: true,
          realtime: true,
          inRange: {
            color: ['yellow', 'red'],
          },
        },
        series: [
          {
            name: '中国',
            type: 'map',
            map: 'china',
            selectedMode: 'single', //multiple多选
            itemStyle: {
              normal: {
                label: {
                  show: false,
                  textStyle: {
                    color: '#231816',
                  },
                },
                areaStyle: { color: '#B1D0EC' },
                color: '#B1D0EC',
                borderColor: '#bbb',
              },
              emphasis: {
                label: {
                  show: false,
                  textStyle: {
                    color: '#fa4f04',
                  },
                },
              },
            },
            data: mapData,
          },
        ],
      });
    }
  });

  const onRefresh = useCallback(() => {
    setRefreshing(true);

    refresh();
    wait(2000).then(() => setRefreshing(false));
  }, [refreshing, refresh]);

  if (data) {
    let formatted = [];

    data.getAreaStat.forEach(entry => {
      total.confirmedCount = total.confirmedCount + entry.confirmedCount;
      total.curedCount = total.curedCount + entry.curedCount;
      total.deadCount = total.deadCount + entry.deadCount;

      formatted = formatted.concat([
        {
          name: entry.provinceShortName,
          value: entry[filter],
        },
      ]);
    });

    mapData = formatted;
  }

  const option = {
    title: {
      text: `疫情地图${titleMap[filter]}`,
    },
    tooltip: {
      trigger: 'item',
      formatter: '{b}',
    },
    visualMap: {
      pieces: piecesMap[filter],
      showLabel: true,
      realtime: true,
      inRange: {
        color: ['yellow', 'red'],
      },
    },
    series: [
      {
        name: '中国',
        type: 'map',
        map: 'china',
        selectedMode: 'single', //multiple多选
        itemStyle: {
          normal: {
            label: {
              show: false,
              textStyle: {
                color: '#231816',
              },
            },
            areaStyle: { color: '#B1D0EC' },
            color: '#B1D0EC',
            borderColor: '#bbb',
          },
          emphasis: {
            label: {
              show: false,
              textStyle: {
                color: '#fa4f04',
              },
            },
          },
        },
        data: mapData,
      },
    ],
  };

  if (timeout) {
    return (
      <SafeAreaView style={{ flex: 1 }}>
        <View
          style={{ justifyContent: 'center', alignItems: 'center', flex: 1 }}>
          <Text
            style={{
              color: colors.primary,
              fontSize: 18,
              paddingVertical: 20,
            }}>
            数据载入失败?
          </Text>
          <Button type="outline" onPress={refresh} title="点击重试" />
        </View>
      </SafeAreaView>
    );
  }

  return (
    <SafeAreaView style={{ flex: 1 }}>
      <ScrollView
        style={{
          flex: 1,
        }}
        refreshControl={
          <RefreshControl
            tintColor="pink"
            refreshing={refreshing}
            onRefresh={onRefresh}
          />
        }>
        <View style={{ backgroundColor: 'white' }}>
          {mapData.length ? (
            <View style={{ flex: 1 }}>
              <View style={{ height: 300 }}>
                <ECharts
                  ref={webviewRef}
                  option={option}
                  backgroundColor="#fcfcfc"
                />
              </View>
              <ButtonGroup
                selectedButtonStyle={styles.buttonGroup}
                onPress={setIndex}
                selectedIndex={selectedIndex}
                buttons={[
                  `确诊 (${total.confirmedCount})`,
                  `治愈 (${total.curedCount})`,
                  `致死 (${total.deadCount})`,
                ]}
                containerStyle={{ height: 50 }}
              />
              {data && data.getTimelineService && (
                <Timeline data={data.getTimelineService} />
              )}
              {data && data.getIndexRecommendList && (
                <RecommendationList data={data.getIndexRecommendList} />
              )}
            </View>
          ) : (
            <View style={{ flex: 1, width, height }}>
              <Loader
                size="large"
                color="red"
                style={{ marginTop: height / 3 }}
              />
            </View>
          )}
        </View>
      </ScrollView>
    </SafeAreaView>
  );
}