how to compare hour in react native? - react-native

I trying to compare an hour in react native, pasting some parameters; like a : current time, begin time an end time to open a mode screen, below is the follow code:
import React, { Component } from 'react';
import moment from "moment";
import SplashScreen from './Components/SplashScreen.js';
import Intro from './Components/Menu.js';
import Intro2 from './Components/Menu2.js';
export default class Index extends Component {
state = {
ready: false,
};
componentDidMount() {
var that = this;
setTimeout(() => {
this.setState({ ready: true });
}, 3500);
var currentD = new Date();
var startIntroHourD = new Date();
startIntroHourD.setHours(13,30,0); // 5.30 pm
var endIntroHourD = new Date();
endIntroHourD.setHours(5,30,0); // 5.30 am
}
render() {
if (this.state.currentD >= this.state.startIntroHourD && this.state.currentD <this.state.endIntroHourD ){
if (this.state.ready === false) {
return <SplashScreen />;
}
return <Intro/>;
}else{
if (this.state.ready === false) {
return <SplashScreen />;
}
return <Intro2/>;
}
}
}
But this parameters are not working, someone can help me to put the correct follow format time?

Related

Audio and Video not working offline when using useNetInfo from netinfo

I've been battling a bug in my code for the last 4 days and would appreciate some pointers to get me going in the right directions. Component is working fine as long as there is internet connection, but if there is no internet connection, audios and videos are not playing, only thumbnail present.
I'm using netInfo's NetInfo.fetch() to check for connection. If there is connection, I'm refetching data to check for any updates to student assignments.
I'm using expo-av for playing audio/video files (v10.2.1). I'm also using useQuery hook from react-query to fetch data about audio and video files (like url etc.) My video player component is something like this:
Video Player:
import React, {
forwardRef,
ForwardRefRenderFunction,
useCallback,
useImperativeHandle,
useRef
} from 'react';
import { Platform } from 'react-native';
import Orientation from 'react-native-orientation-locker';
import { Audio, Video, VideoFullscreenUpdateEvent, VideoProps } from 'expo-av';
const Player: ForwardRefRenderFunction<
Video | undefined,
VideoProps
> = (props, ref) => {
const innerRef = useRef<Video>(null);
const orientation = useCallback<
(event: VideoFullscreenUpdateEvent) => void
>(
(event) => {
if (Platform.OS === 'android') {
if (
event.fullscreenUpdate === Video.FULLSCREEN_UPDATE_PLAYER_DID_PRESENT
) {
Orientation.unlockAllOrientations();
} else if (
event.fullscreenUpdate === Video.FULLSCREEN_UPDATE_PLAYER_DID_DISMISS
) {
Orientation.lockToPortrait();
}
}
props.onFullscreenUpdate?.(event);
},
[props]
);
useImperativeHandle(ref, () => {
if (innerRef.current) {
return innerRef.current;
}
return undefined;
});
return (
<Video
resizeMode="contain"
useNativeControls
ref={innerRef}
onLoad={loading}
{...props}
onFullscreenUpdate={orientation}
/>
);
};
export const VideoPlayer = forwardRef(Player);
Custom Hook:
For async state management, I'm using a custom react-query hook, that looks something like this (non-relevant imports and code removed):
import { useFocusEffect } from '#react-navigation/core';
import { useCallback } from 'react';
import NetInfo from '#react-native-community/netinfo';
export const useStudentAssignment = (
assignmentId: Assignment['id']
): UseQueryResult<Assignment, Error> => {
const listKey = studentAssignmentKeys.list({ assignedToIdEq: studentData?.id });
const queryClient = useQueryClient();
const data = useQuery<Assignment, Error>(
studentAssignmentKeys.detail(assignmentId),
async () => {
const { data: assignment } = await SystemAPI.fetchAssignment(assignmentId);
return Assignment.deserialize({
...assignment,
});
},
{
staleTime: 1000 * 60 * 30,
initialData: () => {
const cache= queryClient.getQueryData<Assignment[]>(listKey);
return cache?.find((assignment) => assignment.id === assignmentId);
},
initialDataUpdatedAt: queryClient.getQueryState(listKey)?.dataUpdatedAt,
}
);
useFocusEffect(
useCallback(() => {
NetInfo.fetch().then((state) => {
if (state.isConnected) {
data.refetch();
}
});
}, [data])
);
return data;
};
Component:
import React, { FC, useCallback, useEffect, useMemo, useRef } from 'react';
import { SafeAreaView } from 'react-native-safe-area-context';
import { StackScreenProps } from '#react-navigation/stack';
import { ROUTES } from 'enums/SMSRoutes';
import { StoreType } from 'enums/SMSStoreType';
import { useStudentAssignment } from 'hooks/Assignments/useStudentAssignment';
import { RootStackParamList } from 'navigators';
import { AssignmentViewer } from 'screens/AssignmentViewer';
type NavProps = StackScreenProps<
RootStackParamList,
ROUTES.ASSIGNMENT_VIEW
>;
export const AssignmentView: FC<NavProps> = ({
navigation,
route: {
params: { assignmentId }
}
}) => {
const assignmentQuery = useStudentAssignment(assignmentId);
const assignmentTracker = useStore(StoreType.AssignmentTracker);
const isDoneRef = useRef<boolean>(false);
const questions = assignmentQuery.data?.questions || [];
const activeQuestion = useMemo(() => {
return questions.filter((question) => question.active);
}, [questions]);
const onDone = useCallback(() => {
isDoneRef.current = true;
navigation.push(ROUTES.ASSIGNMENT_COMPLETED);
}, [navigation]);
useEffect(() => {
assignmentTracker.start(assignmentId);
return () => {
assignmentTracker.finish(isDoneRef.current);
};
}, []);
return (
<SafeAreaView>
<AssignmentViewer
questions={activeQuestion}
onDone={onDone}
isLoading={assignmentQuery.isLoading}
/>
</SafeAreaView>
);
};
What I'm trying to do here is that if internet connection is connected and the user navigates to the current view (which is used to view assignments), I'd like to refetch the data. Per the requirements, I can't use the staleTime property or any other interval based refetching.
Component is working fine if I don't refetch, or if internet connection is present. If connection isn't there, it doesn't play the cache'd audio/video.
If I take out the check for internet connection (remove netInfo), component display videos both offline and online. However, refetching fails due to no connectivity.
What should I change to make sure that data is refetched when connected and videos are played even if not connected to Internet?

Problem while using Expo-av Library, App crashes while changing the songs

I am running my application on an android device. So I am using Context API, the song is in context, whenever a user clicks on a song it is updated in context and every component gets it and then useEffect of PlayerWidget gets triggered and that time my app is crashing. At the Start of the app, the song is null.
import React, { useEffect, useState, useContext } from "react";
import { View, Text, Image, TouchableOpacity } from "react-native";
import tailwind from "tailwind-rn";
import { AntDesign, FontAwesome, Foundation } from "#expo/vector-icons";
import { Audio } from "expo-av";
import { Sound } from "expo-av/build/Audio/Sound";
import { AppContext } from "../AppContext";
function PlayerWidget() {
const { song } = useContext(AppContext);
useEffect(() => {
if (song) {
console.log("player", song);
console.log("a");
playCurrentSong();
}
}, [song]);
//const navigation = useNavigation();
const [sound, setSound] = (useState < Sound) | (null > null);
const [isPlaying, setIsPlaying] = useState < boolean > false;
const [duration, setDuration] = (useState < number) | (null > null);
const [position, setPosition] = (useState < number) | (null > null);
/* useEffect(() => {
playCurrentSong();
}, []);
*/
const playBackStatusUpdate = (status: any) => {
setPosition(status.positionMillis);
setDuration(status.durationMillis);
};
const playCurrentSong = async () => {
if (!song) return;
if (sound) {
console.log(sound);
await sound.unloadAsync();
}
const { sound: newSound } = await Audio.Sound.createAsync(
{ uri: song.songUri },
{ shouldPlay: isPlaying },
playBackStatusUpdate
);
setSound(newSound);
setIsPlaying(true);
};
const onPlayPausePress = async () => {
if (!sound) {
return;
}
console.log(sound);
if (isPlaying) {
await sound.pauseAsync();
setIsPlaying(false);
} else {
await sound.playAsync();
setIsPlaying(true);
}
};
if (song === null) {
return null;
}
}
export default PlayerWidget;
Can you tell me what I am doing wrong?

react native setInterval cannot read property apply

I am new in react native I am trying to render the count of unread notification for that I called my API in HOC it is working fine for initial few seconds but after that, I started to get the below error
func.apply is not a function
below is my code
import React, { Component } from "react";
import PropTypes from "prop-types";
import { Modal, View } from "react-native";
import { themes } from "./constants";
import { AsyncStorage } from "react-native";
export default (OriginalComponent, animationType) =>
class extends Component {
static propTypes = {
handleFail: PropTypes.func,
theme: PropTypes.string,
visible: PropTypes.bool
};
state = {
modalVisible: true
};
static getDerivedStateFromProps({ visible }) {
if (typeof visible === "undefined") {
setInterval(
AsyncStorage.getItem("loginJWT").then(result => {
if (result !== null) {
result = JSON.parse(result);
fetch(serverUrl + "/api/getUnreadNotificationsCount", {
method: "GET",
headers: {
Authorization: "Bearer " + result.data.jwt
}
})
.then(e => e.json())
.then(function(response) {
if (response.status === "1") {
if (response.msg > 0) {
AsyncStorage.setItem(
"unreadNotification",
JSON.stringify(response.msg)
);
} else {
AsyncStorage.setItem("unreadNotification", 0);
}
}
})
.catch(error => {
alert(error);
// console.error(error, "ERRRRRORRR");
});
} else {
AsyncStorage.setItem("unreadNotification", 0);
}
}),
5000
);
return null;
}
return { modalVisible: visible };
}
handleOpenModal = () => {
this.setState({ modalVisible: true });
};
handleCloseModal = () => {
const { handleFail } = this.props;
this.setState({ modalVisible: false }, handleFail);
};
render() {
const { modalVisible } = this.state;
const { theme } = this.props;
return (
<View>
<Modal
animationType={animationType ? animationType : "fade"}
transparent={true}
visible={modalVisible}
onRequestClose={this.handleCloseModal}
>
<View style={themes[theme] ? themes[theme] : themes.transparent}>
<OriginalComponent
handleCloseModal={this.handleCloseModal}
{...this.props}
/>
</View>
</Modal>
</View>
);
}
};
I have not used getDerivedStateFromProps but, according to the docs, it is called on initial component mount and before each render update.
Thus your code is creating a new interval timer on each update without clearing any of the earlier timers, which could be causing a race condition of some sort.
You may want to consider using the simpler alternatives listed in the docs, or at a minimum, insure that you cancel an interval before creating a new one.

ReactNative and NativeBase Radio

I've tried to change the radio value in ReactNative App with NativeBase template. I want to get or set value from the radio after click it, exactly checked or not. But couldn't find a way to get or set value to it. Even the radio button never changed on the screen after click. The codes are like as below:
import React, { Component } from 'react';
import { TouchableOpacity, Image, View } from 'react-native';
import { connect } from 'react-redux';
import { actions } from 'react-native-navigation-redux-helpers';
import {
Container,
Header,
Title,
Content,
Text,
Button,
Icon,
InputGroup,
Input,
List,
ListItem,
Radio, } from 'native-base';
import { openDrawer } from '../../actions/drawer';
import { Col, Row, Grid } from 'react-native-easy-grid';
import styles from './styles';
import dimension from './global';
import Swiper from 'react-native-swiper';
const imgBoy = require('../../../images/icon_boy.png');
const imgGirl = require('../../../images/icon_girl.png');
const {
popRoute,
} = actions;
class SessionPage extends Component {
static propTypes = {
name: React.PropTypes.string,
index: React.PropTypes.number,
list: React.PropTypes.arrayOf(React.PropTypes.string),
openDrawer: React.PropTypes.func,
popRoute: React.PropTypes.func,
navigation: React.PropTypes.shape({
key: React.PropTypes.string,
}),
}
popRoute() {
this.props.popRoute(this.props.navigation.key);
}
constructor(props) {
super(props);
// console.log(this.props.navigation);
this.state = {
sliderCount : parseInt(this.props.navigation.behavior.length / 5) + 1,
sliderArray : [],
selected : false,
}
this.getSliderArray();
console.log(this.state);
}
getSliderArray() {
for (var i = 0; i < this.state.sliderCount; i++) {
var childArray = [];
for (var j = i * 5; j < 5 * (i + 1); j++) {
if (this.props.navigation.behavior[j] != null){
var unit = this.props.navigation.behavior[j];
unit.selected = true;
childArray.push(unit);
}
}
this.state.sliderArray.push({
index : i,
behaviors : childArray
})
}
}
selectRadio(i, j){
this.state.sliderArray[i].behaviors[j].selected = true;
}
render() {
const { props: { name, index, list } } = this;
return (
<Container style={styles.container}>
<Swiper style={styles.wrapper}
height={dimension.Height - 400}
width={dimension.Width - 40}
showsButtons={false}
showsPagination={true}>
{this.state.sliderArray.map((item, i) =>
<View style={styles.slide1} key={i}>
{item.behaviors.map((subitem, j) =>
<ListItem key={i + "-" + j} style={styles.cardradio}>
<Radio selected={this.state.sliderArray[i].behaviors[j].selected} onPress={() => this.selectRadio(i, j)} />
<Text>{subitem.behaviorName}</Text>
</ListItem>
)}
</View>
)}
</Swiper>
</Content>
</Container>
);
}
}
function bindAction(dispatch) {
return {
openDrawer: () => dispatch(openDrawer()),
popRoute: key => dispatch(popRoute(key)),
};
}
const mapStateToProps = state => ({
navigation: state.cardNavigation,
name: state.user.name,
index: state.list.selectedIndex,
list: state.list.list,
});
export default connect(mapStateToProps, bindAction)(SessionPage);
selectRadio(i, j){
this.state.sliderArray[i].behaviors[j].selected = true; <== This is the problem
}
When you call this.state = something after the component has mounted, it doesn't trigger update method of component life cycle. Hence view will not be updated.
You should be using this.setState() to update your views
this.setState({
slider = something
})
For more info, refer docs
this.setState() is an async method. After you make changes in getSliderArray(), it may not be reflected in immediate console.log
this.getSliderArray();
console.log(this.state);
You can pass callback to this.setState() to perform any action only after state is changed
this.setState({
// new values
}, function() {
// Will be called only after switching to new state
})

How to detect first launch in react-native

What is a good way to detect the first and initial launch of an react-native app, in order to show an on-boarding/introductory screen ?
Your logic should follow this:
class MyStartingComponent extends React.Component {
constructor(){
super();
this.state = {firstLaunch: null};
}
componentDidMount(){
AsyncStorage.getItem("alreadyLaunched").then(value => {
if(value === null){
AsyncStorage.setItem('alreadyLaunched', 'true'); // No need to wait for `setItem` to finish, although you might want to handle errors
this.setState({firstLaunch: true});
}
else{
this.setState({firstLaunch: false});
}}) // Add some error handling, also you can simply do this.setState({fistLaunch: value === null})
}
render(){
if(this.state.firstLaunch === null){
return null; // This is the 'tricky' part: The query to AsyncStorage is not finished, but we have to present something to the user. Null will just render nothing, so you can also put a placeholder of some sort, but effectively the interval between the first mount and AsyncStorage retrieving your data won't be noticeable to the user.
}else if(this.state.firstLaunch === 'true'){
return <FirstLaunchComponent/>
}else{
return <NotFirstLaunchComponent/>
}
}
Hope it helps.
I made some adjustments to martinarroyo's suggestion. AsyncStorage.setItem should set a string value and not a bool.
import { AsyncStorage } from 'react-native';
const HAS_LAUNCHED = 'hasLaunched';
function setAppLaunched() {
AsyncStorage.setItem(HAS_LAUNCHED, 'true');
}
export default async function checkIfFirstLaunch() {
try {
const hasLaunched = await AsyncStorage.getItem(HAS_LAUNCHED);
if (hasLaunched === null) {
setAppLaunched();
return true;
}
return false;
} catch (error) {
return false;
}
}
This function can then be imported wherever you need it. Note that you should render null (or something else clever) while waiting for the async function to check AsyncStorage.
import React from 'react';
import { Text } from 'react-native';
import checkIfFirstLaunch from './utils/checkIfFirstLaunch';
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
isFirstLaunch: false,
hasCheckedAsyncStorage: false,
};
}
async componentWillMount() {
const isFirstLaunch = await checkIfFirstLaunch();
this.setState({ isFirstLaunch, hasCheckedAsyncStorage: true });
}
render() {
const { hasCheckedAsyncStorage, isFirstLaunch } = this.state;
if (!hasCheckedAsyncStorage) {
return null;
}
return isFirstLaunch ?
<Text>This is the first launch</Text> :
<Text>Has launched before</Text>
;
}
}
In 2022: Note that AsyncStorage from react-native is already deprecated.
Use react-native-async-storage/async-storage instead.
Custom hook:
import React, { useState } from "react";
import AsyncStorage from "#react-native-async-storage/async-storage";
async function checkIfFirstLaunch() {
try {
const hasFirstLaunched = await AsyncStorage.getItem("#usesr_onboarded");
if (hasFirstLaunched === null) {
return true;
}
return false;
} catch (error) {
return false;
}
}
const useGetOnboardingStatus = () => {
const [isFirstLaunch, setIsFirstLaunch] = useState(false);
const [isFirstLaunchIsLoading, setIsFirstLaunchIsLoading] = useState(true);
React.useEffect(async () => {
const firstLaunch = await checkIfFirstLaunch();
setIsFirstLaunch(firstLaunch);
setIsFirstLaunchIsLoading(false);
}, []);
return {
isFirstLaunch: isFirstLaunch,
isLoading: isFirstLaunchIsLoading,
};
};
export default useGetOnboardingStatus;
Usage:
import useGetOnboardingStatus from "../../utils/useGetOnboardingStatus";
const { isFirstLaunch, isLoading: onboardingIsLoading } =
useGetOnboardingStatus();
As Eirik Fosse mentioned: You can use onboardingIsLoading to return null while waiting for the response.