Here is my code:, the auth webview open but then when i click allow with my account i can see in console i receive the access token but with an error, i would just like to receive the url in my AuthWebView.js then i can parse it:
Can't open url: epicture://status#access_token=94de672d6210f6ceecfe07efd5d62728c96b8e33&expires_in=315360000&token_type=bearer&refresh_token=cfb46e86a33f4a0cd92e1596335ac21393d13251&account_username=nmateotest&account_id=140192947
code:
import React, { Component } from "react";
import { WebView } from "react-native-webview";
import { Linking } from "react-native";
import { API_URL, API_CLIENT_ID } from "#env";
import APIToken from "./../api/APIToken";
export default class AuthWebView extends Component {
navigate = async (url) => {
if (url) {
console.log(url);
url = url.replace("#", "&");
let params = {};
const regex = /([^&=]+)=([^&]*)/g;
let m;
while ((m = regex.exec(url))) {
parameters[decodeURIComponent(m[1])] = decodeURIComponent(m[2]);
}
await APIToken.saveToken("BearerToken", parameters.access_token);
await APIToken.saveToken("username", parameters.account_username);
this.props.navigation.navigate("App");
}
};
componentDidMount() {
Linking.getInitialURL().then((url) => {
this.navigate(url);
});
}
render() {
return (
<WebView
source={{
uri:
API_URL +
"oauth2/authorize?client_id=" +
API_CLIENT_ID +
"&response_type=token",
}}
/>
);
}
Related
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?
I'm trying to use the expo-video-thumbnails package to generate a thumbnail from a video uri. The video uri is retrieved from async-storage. I get the following error
Argument of an incompatible class: class java.util.HashMap cannot be
passed as an argument to parameter expecting class java.lang.String.
If I use a static video uri, it works fine. I can't seem to get this to work with the value from AsyncStorage. Here's my code:
import React, { useState, useEffect } from 'react';
import { View, Image } from 'react-native';
import AsyncStorage from '#react-native-async-storage/async-storage';
import * as VideoThumbnails from 'expo-video-thumbnails';
export default function ThumbnailsScreen() {
// video uri
const [videoUri, setVideoUri] = React.useState({});
const getData = async () => {
try {
const value = await AsyncStorage.getItem('#lastRecordedVideo')
if(value !== null) {
setVideoUri(value)
}
} catch(e) {
console.log(e);
}
}
getData();
// thumbnails
const [image, setImage] = useState(null);
const generateThumbnail = async () => {
try {
const { uri } = await VideoThumbnails.getThumbnailAsync(
videoUri,
{
time: 1000,
}
);
setImage(uri);
} catch (e) {
console.warn(e);
}
};
useEffect(() => { generateThumbnail(); }, [])
return (
<View>
{image && <Image source={{ uri: image }} /> }
</View>
)
}
I have a simple react native application with a WebView component for displaying my website based on php. So it works. But, when I login and close the application (on IOS), the session state was loose and I need login again. I know that all webview data like cookies cleared when the application close. So I need AsyncStorage to save all cookies to application storage and get it when application open for passing to headers.
Here's my code:
import React, {Component} from 'react';
import AsyncStorage from '#react-native-community/async-storage';
import CookieManager from '#react-native-community/cookies';
import {SafeAreaView, StyleSheet, Alert} from 'react-native';
import {WebView} from 'react-native-webview';
let domain = "[https]://mysite.com";
export default class WebViewScreen extends Component {
constructor(props) {
super(props);
this.currentUrl = domain;
this.myWebView = React.createRef();
this.state = {
isReady: false,
cookiesString: '',
};
}
jsonCookiesToCookieString = (json) => {
let cookiesString = '';
for (let [key, value] of Object.entries(json)) {
cookiesString += `${key}=${value.value}; `;
}
return cookiesString;
};
UNSAFE_componentWillMount() {
this.provideMeSavedCookies()
.then(async (savedCookies) => {
let cookiesString = this.jsonCookiesToCookieString(savedCookies);
const PHPSESSID = await AsyncStorage.getItem('PHPSESSID');
if (PHPSESSID) {
cookiesString += `PHPSESSID=${PHPSESSID};`;
}
this.setState({cookiesString, isReady: true});
})
.catch((e) => {
this.setState({isReady: true});
});
}
onLoadEnd = (syntheticEvent) => {
let successUrl = `${domain}/dashboard.php`;
if (this.currentUrl === successUrl) {
CookieManager.getAll(true).then((res) => {
AsyncStorage.setItem('savedCookies', JSON.stringify(res));
if (res.PHPSESSID) {
AsyncStorage.setItem('PHPSESSID', res.PHPSESSID.value);
}
});
}
};
onNavigationStateChange = (navState) => {
this.currentUrl = navState.url;
};
provideMeSavedCookies = async () => {
try {
let value = await AsyncStorage.getItem('savedCookies');
if (value !== null) {
return Promise.resolve(JSON.parse(value));
}
} catch (error) {
return {}
}
};
render() {
const {cookiesString, isReady} = this.state;
if (!isReady) {
return null;
}
return (
<SafeAreaView>
<WebView
ref={this.myWebView}
source={{
uri: domain,
headers: {
Cookie: cookiesString,
},
}}
allowsBackForwardNavigationGestures
originWhitelist={['*']}
scalesPageToFit
useWebKit
onLoadEnd={this.onLoadEnd}
onNavigationStateChange={this.onNavigationStateChange}
sharedCookiesEnabled={true}
javaScriptEnabled={true}
domStorageEnabled={true}
/>
</SafeAreaView>
);
}
}
I missed all styles for most clearly and understanding code
So, I login and close the application. Then open again. It works only for one request, but not for multiple or when navigation. When I'm trying go to another page I loose my session and redirect to login page. If I change domain variable from mysite.com to mysite.com/my-profile where /my-profile page only for authorized users, it works too. My headers work only for first request page. How to fix it? How save the session after closing the app for each pages, not only for domain value?
I am trying to navigate back to the LogIn screen as soon as logout.js is hit.
At one point this seemed to work and then stopped and I can't work out why.
Here is my code:
import React, { Component } from 'react';
import { Text, View, Button } from 'react-native';
import * as SecureStore from 'expo-secure-store';
import { globalStyles } from '../styles/global';
export default class App extends Component {
componentDidMount() {
(async () => {
const token = await SecureStore.getItemAsync('token');
// Your fetch code
this.setState({loaded:false, error: null});
let url = 'https://www.example.com/api/auth/logout';
let h = new Headers();
h.append('Authorization', `Bearer ${token}`);
h.append('Content-Type', 'application/json');
h.append('X-Requested-With', 'XMLHttpRequest');
let req = new Request(url, {
headers: h,
method: 'GET'
});
fetch(req)
.then(response=>response.json())
//.then(this.showData)
.catch(this.badStuff)
})();
this.deleteToken()
}
badStuff = (err) => {
this.setState({loaded: true, error: err.message});
}
deleteToken() {
(async () => {
const token = await SecureStore.deleteItemAsync('token')
});
this.goToLogInScreen()
}
goToLogInScreen() {
this.props.navigation.navigate('LogIn')
}
render() {
return (
<View style={globalStyles.container}>
<Button
title="Go to Details"
onPress={() => this.props.navigation.navigate('LogIn')}
/>
</View>
);
}
}
I need the code to:
Send the command to the API to log out
Delete the token from SecureStore
Navigate to the LogIn screen (containing the log in form).
When I try to enter username and then go on next screen for live chating then I facing this error.
Here is code for ChatScreen.js file.
TypeError: undefined is not a function (near '..._fire.default.get...').
ChatScreen.js
import React,{Component} from "react";
import {Platform,KeyboardAvoidingView} from 'react-native';
import {GiftedChat}from 'react-native-gifted-chat-fix';
import{SafeAreaView}from 'react-native-safe-area-view';
import Video from 'react-native-video';
import Fire from '../fire';
export default class ChatScreen extends Component{
state={
messages:[]
}
get user(){
return{
_id:Fire.uid,
name:this.props.navigation.state.params.name
}
}
componentDidMount(){
Fire.get(message=>this.setState(previous=>({
messages:GiftedChat.append(previous.messages,message)
}))
);
}
componentWillUnmount(){
Fire.off()
}
render(){
const chat=<GiftedChat messages={this.state.messages} onSend={Fire.send} user={this.user}/>;
if(Platform.OS=='android'){
return(
<KeyboardAvoidingView style={{flex:1}}behavior="padding" keyboardVerticalOffset={30} enabled>
{chat}
</KeyboardAvoidingView>
);
}
return<SafeAreaView style={{flex:1}}>{chat}</SafeAreaView>;
}
}
Try changing the code in both files
At first in Fire.js
import firebase from 'firebase'; // 4.8.1
class Fire {
constructor() {
this.init();
this.observeAuth();
}
init = () => {
if (!firebase.apps.length) {
firebase.initializeApp({
apiKey:'AIzaSyAPfes9_2EwZESX1puYMUv29yunzK9Ve5U',
authDomain:'docman-31d96.firebaseapp.com',
databaseURL: "https://docman-31d96.firebaseio.com",
projectId: "docman-31d96",
storageBucket: "docman-31d96.appspot.com",
messagingSenderId: "649332068608",
appId:'1:649332068608:android:08c080ee6a4e521f5323e5'
});
}
};
observeAuth = () =>
firebase.auth().onAuthStateChanged(this.onAuthStateChanged);
onAuthStateChanged = user => {
if (!user) {
try {
firebase.auth().signInAnonymously();
} catch ({ message }) {
alert(message);
}
}
};
get uid() {
return (firebase.auth().currentUser || {}).uid;
}
get ref() {
return firebase.database().ref('messages');
}
parse = snapshot => {
const { timestamp: numberStamp, text, user } = snapshot.val();
const { key: _id } = snapshot;
const timestamp = new Date(numberStamp);
const message = {
_id,
timestamp,
text,
user,
};
return message;
};
on = callback =>
this.ref
.limitToLast(20)
.on('child_added', snapshot => callback(this.parse(snapshot)));
get timestamp() {
return firebase.database.ServerValue.TIMESTAMP;
}
// send the message to the Backend
send = messages => {
for (let i = 0; i < messages.length; i++) {
const { text, user } = messages[i];
const message = {
text,
user,
timestamp: this.timestamp,
};
this.append(message);
}
};
append = message => this.ref.push(message);
// close the connection to the Backend
off() {
this.ref.off();
}
}
Fire.shared = new Fire();
export default Fire;
and then in ChatScreen.js
import * as React from 'react';
import { Platform , KeyboardAvoidingView,SafeAreaView } from 'react-native';
// #flow
import { GiftedChat } from 'react-native-gifted-chat'; // 0.3.0
import Fire from '../fire';
type Props = {
name?: string,
};
class ChatScreen extends React.Component<Props> {
static navigationOptions = ({ navigation }) => ({
title: (navigation.state.params || {}).name || 'Chat!',
});
state = {
messages: [],
};
get user() {
return {
name: this.props.navigation.state.params.name,
_id: Fire.shared.uid,
};
}
render() {
const chat=<GiftedChat messages={this.state.messages} onSend={Fire.shared.send} user={this.user}/>;
if(Platform.OS=='android'){
return(
<KeyboardAvoidingView style={{flex:1}}behavior="padding" keyboardVerticalOffset={0} enabled>
{chat}
</KeyboardAvoidingView>
);
}
return<SafeAreaView style={{flex:1}}>{chat}</SafeAreaView>;
}
componentDidMount() {
Fire.shared.on(message =>
this.setState(previousState => ({
messages: GiftedChat.append(previousState.messages, message),
}))
);
}
componentWillUnmount() {
Fire.shared.off();
}
}
export default ChatScreen;
This helped for me It should work for you too
To see my chat app just visit https://snack.expo.io/#habibishaikh1/chatapp