Why does NetInfo not work for Web but works for Android (react-native-web)? - react-native-web

When using react-native-web NetInfo works fine for Android and iOS but is not working for web.
To confirm the code being run for web is the same as Android I console log in the componentDidMount and both Android and Web display the text. However the events dont seem to be working for the web version.
// src/App.js
import React from 'react';
import { Provider } from 'react-redux';
import store from './utilities/storage/store';
import EntryScreen from './screens/EntryScreen';
import Routing, { Router } from './utilities/routing/index';
import { NetInfo } from 'react-native';
const Route = Routing.Route;
class App extends React.Component {
componentDidMount() {
console.log('App mounted');
NetInfo.isConnected.addEventListener('connectionChange', this.handleConnectivityChange);
}
componentWillUnmount() {
NetInfo.isConnected.removeEventListener('connectionChange', this.handleConnectivityChange);
}
/**
* Listens for any internet connectivity changes.
* #param isConnected The internet connection status
*/
handleConnectivityChange = (isConnected) => {
console.log ('bam');
console.log ('Connected:', isConnected);
};
render() {
return (
<Provider store={store}>
<Router>
<Route path="/" component={EntryScreen} />
</Router>
</Provider>
);
}
}
export default App;
I would expect, based on the documentation that NetInfo works for web as well as Android. If it does not can someone provide a way to do this please.
"react": "^16.2.0",
"react-art": "^16.2.0",
"react-dom": "^16.2.0",
"react-native": "0.57.8",
"react-native-web": "0.9.13",

NetInfo on the web is missing some functionality compared to iOS and Android React Native. There is just not equivalent web APIs.
https://github.com/necolas/react-native-web/blob/master/README.md#modules

Related

Guidance on implementing Okta Redirect with Docusaurus

Having trobule implementing okta redirect with docusaurus using their documentation due to how docusaurus intiallly loads in routes. Can anyone provide any guidance on how to go about this?
https://github.com/okta/okta-react
Expected Behavior:
Initial path to load up redirects to okta and authenticates then returns back to webpage.
I ran into this same issue and saw your posting hoping for an answer. bummer. Then I dug around a little more. It's not fully implemented yet because I'm waiting on the okta creds from my administrators, but this got me to a permission denied screen (which is a good thing to me!)
Few things:
docusaurus currently uses react-router-dom v5. you need to specifically set that instead of defaulting to v6
src/pages/index.tsx (i'm using typescript) should allow you to setup a browserrouter there
react-router-dom package:
"react-router": "^5.3.3",
"react-router-config": "^5.1.1",
"react-router-dom": "^5.3.3"
src/pages/index.tsx - I updated the home component to have a DocusaurusHome component, then made Home hold the routing logic
import React from 'react';
import clsx from 'clsx';
import Link from '#docusaurus/Link';
import useDocusaurusContext from '#docusaurus/useDocusaurusContext';
import Layout from '#theme/Layout';
import HomepageFeatures from '#site/src/components/HomepageFeatures';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import styles from './index.module.css';
import { OktaAuth } from '#okta/okta-auth-js';
import { Security, LoginCallback } from '#okta/okta-react';
import { RequiredAuth } from '../components/RequiredAuth';
// file with client id
import clientId from '../Okta/OktaClientID';
// file with issuer url
import issuerUrl from '../Okta/OktaIssuerUrl';
const config = {
clientId: clientId,
issuer: issuerUrl,
redirectUri: `${location.protocol}//${location.host}/callback`,
scopes: ['openid', 'profile', 'email'],
pkce: true
};
const oktaAuth = new OktaAuth(config);
function HomepageHeader() {
const {siteConfig} = useDocusaurusContext();
return (
<header className={clsx('hero hero--primary', styles.heroBanner)}>
<div className="container">
<h1 className="hero__title">{siteConfig.title}</h1>
<p className="hero__subtitle">{siteConfig.tagline}</p>
<div className={styles.buttons}>
<Link
className="button button--secondary button--lg"
to="/docs/intro">
Docusaurus Tutorial - 5min ⏱️
</Link>
</div>
</div>
</header>
);
}
/**
* Actual Docusaurus Home component
*/
function DocusaurusHome(): JSX.Element {
const {siteConfig} = useDocusaurusContext();
return (<Layout
title={`Hello from ${siteConfig.title}`}
description="Description will go into a meta tag in <head />">
<HomepageHeader />
<main>
<HomepageFeatures />
</main>
</Layout>)
}
/**
* component for react-router-dom browserrouter and okta auth
*/
export default function Home(): JSX.Element {
const restore = async (_oktaAuth: OktaAuth, originalUri: string) => {
window.location.replace(originalUri);
};
return (
<BrowserRouter>
<Security oktaAuth={oktaAuth} restoreOriginalUri={restore}>
<Switch>
<Route path='/callback'>
<LoginCallback
errorComponent={(err) => {
// eslint-disable-next-line no-console
console.error(err);
setTimeout(() => {
localStorage.removeItem('okta-token-storage');
window.location.replace(`${location.protocol}//${location.host}/`);
}, 2000);
return null;
}}/>
</Route>
<Route path='/'>
<RequiredAuth />
</Route>
<Route path='*'>
<DocusaurusHome />
</Route>
</Switch>
</Security>
</BrowserRouter>);
}
The RequiredAuth component originally returned an react-router-dom Outlet, which doesn't exist in v5. I think that a Route should suffice in it's place
import React, { useEffect } from 'react';
import { useOktaAuth } from '#okta/okta-react';
import { toRelativeUrl } from '#okta/okta-auth-js';
import { Route } from 'react-router-dom';
export const RequiredAuth: React.FC = () => {
const { oktaAuth, authState } = useOktaAuth();
useEffect(() => {
if (!authState) {
return;
}
if (!authState?.isAuthenticated) {
const originalUri = toRelativeUrl(window.location.href, window.location.origin);
oktaAuth.setOriginalUri(originalUri);
oktaAuth.signInWithRedirect();
}
}, [oktaAuth, !!authState, authState?.isAuthenticated]);
if (!authState || !authState?.isAuthenticated) {
return <></>; // loading screen before okta login
}
return (<Route />);
};

Can't get Firebase emulators to work with AngularFire 7

Good talk yesterday at the Firebase Summit about emulators! I was able to get the Functions emulator to work with AngularFire 6. I can't get the Firestore emulator or the Functions emulator to work with AngularFire 7. Here's my app.module.ts:
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { AppComponent } from './app.component';
import { initializeApp,provideFirebaseApp } from '#angular/fire/app';
import { environment } from '../environments/environment';
import { provideFirestore,getFirestore } from '#angular/fire/firestore';
import { USE_EMULATOR as USE_FIRESTORE_EMULATOR } from '#angular/fire/compat/functions';
import { USE_EMULATOR as USE_FUNCTIONS_EMULATOR } from '#angular/fire/compat/functions';
import { FormsModule } from '#angular/forms';
#NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
FormsModule,
provideFirebaseApp(() => initializeApp(environment.firebase)),
provideFirestore(() => getFirestore()),
],
providers: [
{ provide: USE_FIRESTORE_EMULATOR, useValue: environment.useEmulators ? ['localhost', 8080] : undefined },
{ provide: USE_FUNCTIONS_EMULATOR, useValue: environment.useEmulators ? ['localhost', 5001] : undefined }
],
bootstrap: [AppComponent]
})
export class AppModule { }
There's a smell here. I'm initializing Firebase using AngularFire 7 but I'm importing the emulator from AngularFire 6.1.0. Firebase can be initialized with AngularFire 6 or AngularFire 7 but not both, i.e., you can't mix AngularFire 6 and 7.
How do I import the emulators without using AngularFire 6?
In environments.ts I made a property useEmulators:
export const environment = {
firebase: {
projectId: 'my-awesome-project',
appId: '1:234567890:web',
storageBucket: 'my-awesome-project.appspot.com',
apiKey: 'ABCdef',
authDomain: 'my-awesome-project.firebaseapp.com',
messagingSenderId: '0987654321',
},
production: false,
useEmulators: true
};
My Cloud Function runs great in the cloud but doesn't run in the emulators.
Each time I make a change in a Cloud Function, deploy the update to the cloud, wait a minute for the deploy to propagate, test my function, and wait for the logs to show up in the Firebase Console is ten minutes. I'm looking forward to using the emulators to speed up this development cycle.
Here's the rest of my code. I doubt there's anything wrong with these files.
The Cloud Function triggers from writing a message to Firestore, changes the message to uppercase, and writes the uppercase message to a new field in the document.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.uppercaseMe = functions.firestore.document('Triggers/{docId}').onCreate((snap, context) => {
var original = snap.data().message;
functions.logger.log('Uppercasing', context.params.docId, original);
var uppercase = original.toUpperCase();
return snap.ref.set({ uppercase }, { merge: true });
});
The HTML view has a form for submitting a message. It displays the data that was written to Firestore and then displays the results from the Cloud Function.
<form (ngSubmit)="triggerMe()">
<input type="text" [(ngModel)]="message" name="message" placeholder="Message" required>
<button type="submit" value="Submit">Submit</button>
</form>
<div>{{ data$ }}</div>
<div>{{ upperca$e }}</div>
The app.component.ts controller writes the message to Firestore, reads back the message from Firestore, then sets up a document listener to wait for the cloud function to write a new field to the document.
import { Component } from '#angular/core';
import { Firestore, doc, getDoc, collection, addDoc, onSnapshot } from '#angular/fire/firestore';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
data$: any;
docSnap: any;
message: string | null = null;
upperca$e: string | null = null;
unsubMessage$: any;
constructor(public firestore: Firestore) {}
async triggerMe() {
try {
// write to Firestore
const docRef = await addDoc(collection(this.firestore, 'Triggers'), {
message: this.message,
});
this.message = null; // clear form fields
// read from Firestore
this.docSnap = await getDoc(doc(this.firestore, 'Triggers', docRef.id));
this.data$ = this.docSnap.data().message;
// document listener
this.unsubMessage$ = onSnapshot(doc(this.firestore, 'Triggers', docRef.id), (snapshot: any) => {
this.upperca$e = snapshot.data().uppercase;
});
} catch (error) {
console.error(error);
}
}
}
Firebase emulators work independently of Angular or other apps! I reread the documentation and learned that you just spin up the emulators,
firebase emulators:start
open your browser to http://localhost:4000, and you can write data in Firestore and then see the results of your function appear in Firestore. You can also read the logs. This only works with triggerable functions, not with callable functions.
Amazing what you can learn by reading the documentation. :-)

Redux-persist doesn't persist the store when I'm on a different route

I'm trying to implement redux-persist with reduxjs/toolkit. I made it possible to persist the store on main page. However, when I route to MemeForm.jsx different paths in my app where I make another api call to fetch data from the server (which changes the redux-store since this api call adds another slice to the store) and refresh the page it gets crashed. (Edit: I get GET https://memegeneratorv2.netlify.app/217743513/fetch 404 error on netlify when I refresh the page.) It works perfectly in my local computer, though. I guess I couldn't implement redux-persist with reduxjs/toolkit correctly. I can't figure out this problem for a week. A little bit of help would be perfect.
Here is my github repo https://github.com/ahmettulutas/MemeGeneratorV2 and here is the netlify version of the app. https://memegeneratorv2.netlify.app
store.js
import { configureStore } from '#reduxjs/toolkit'
import loadMemesSlice from "./features/loadMemes/loadMemesSlice";
import fetchedMemeSlice from "./features/editMeme/memeFormSlice";
import { combineReducers } from '#reduxjs/toolkit';
import {
persistStore,
persistReducer,
FLUSH,
REHYDRATE,
PAUSE,
PERSIST,
PURGE,
REGISTER,
} from 'redux-persist'
import storage from 'redux-persist/lib/storage'
const persistConfig = { // configuration object for redux-persist
key: 'root',
storage, // define which storage to use
whitelist : ['fetchedMemeSlice','loadMemesSlice'],
}
const rootReducer = combineReducers({
loadMemesSlice: loadMemesSlice,
fetchedMemeSlice: fetchedMemeSlice,
})
const persistedReducer = persistReducer(persistConfig, rootReducer)
const store = configureStore({
reducer: persistedReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: {
ignoredActions: [FLUSH, PAUSE, PURGE, REHYDRATE, REGISTER, PERSIST],
},
}),
})
export const persistor = persistStore(store);
export default store;
app.js
import "./styles.css";
import Header from "./components/header";
import MemeComponent from "./features/editMeme/memeComponent";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import AllMemes from "./features/loadMemes/displayMemes";
import FetchedMeme from "./components/fetchedMeme";
import Footer from "./components/footer";
export default function App() {
return (
<Router>
<Header />
<div className="routes-section">
<Routes >
<Route path="/" exact element={<AllMemes/>}/>
<Route path="/:id" element={<MemeComponent />}></Route>
<Route path="/:id/:fetchedmeme" element={<FetchedMeme />}></Route>
</Routes>
</div>
<Footer />
</Router>
);
}
index.js
import { Provider } from "react-redux";
import ReactDOM from "react-dom";
import store from "./store";
import {persistor} from "./store";
import App from "./App";
import { PersistGate } from 'redux-persist/integration/react';
const rootElement = document.getElementById("root");
ReactDOM.render(
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<App />
</PersistGate>
</Provider>,
rootElement
)
Did you wrap the App Component to PersistGate Component in index.js?
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<App />
</PersistGate>
</Provider>
Please check if you added the reducer in the whitelist correctly.
whitelist : ['fetchedMemeSlice','loadMemesSlice']
I have just found the answer. Since netlify has it's own rules you need to handle some other configs when you use react-router-dom.
Check this link and do the required settings. https://github.com/vuejs/vuepress/issues/457#issuecomment-390206649
After that; add a netlify.toml file, which sets the redirect root when you refresh the page, to your project's root directory. You can directly copy and paste mine from my github repository https://github.com/ahmettulutas/MemeGeneratorV2 Finally, push your changes if you are using CI option from your github repo. Voila.

how can I sole resolve error for vue, that does not occurs locally?

In my app I use Login.vue and Logout.vue components, located in
/resources/js/components/auth
Locally the app runs fine on localhost.
Now I pushed to app to the remote repository, and the I get the following error after running:
npm run production
the error is:
ERROR Failed to compile with 1 errors 3:05:45 PM
error in ./resources/js/app.js
Module not found: Error: Can't resolve './components/auth/Login.vue' in '/var/www/ijsbrekerz/resources/js'
app.js looks like:
**
* First we will load all of this project's JavaScript dependencies which
* includes Vue and other libraries. It is a great starting point when
* building robust, powerful web applications using Vue and Laravel.
*/
require('./bootstrap');
import 'bootstrap';
import { createRouter, createWebHistory } from 'vue-router';
import routes from './routes.js';
import store from './store';
import vuex from 'vuex';
import { createApp } from 'vue';
import axios from 'axios';
import Master from'./components/layouts/Master.vue';
import ExampleComponent from'./components/ExampleComponent.vue';
import ManageCards from'./components/ManageCards.vue';
import Navibar from'./components/Navibar.vue';
import CreateSpeler from'./components/CreateSpeler.vue';
import CardsSpeler from'./components/CardsSpeler.vue';
import Home from'./components/Home.vue';
import ModalComponent from'./components/ModalComponent.vue';
import Game from'./components/Game.vue';
import GameAdmin from'./components/GameAdmin.vue';
import Login from'./components/auth/Login.vue';
import Logout from'./components/auth/Logout.vue';
import ImageUpload from'./components/ImageUpload.vue';
import Memory from'./components/Memory.vue';
// link naar uilteg opzetten routes..
const router = createRouter({
history: createWebHistory(),
routes: routes.routes,
});
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
// this route requires auth, check if logged in
// if not, redirect to login page.
if (!store.getters.loggedIn) {
next({
name: 'login',
})
}
} else if (to.matched.some(record => record.meta.requiresVisitor)) {
// this route requires auth, check if logged in
// if not, redirect to login page.
if (store.getters.loggedIn) {
next({
name: 'gameadmin',
})
}
} else if (to.matched.some(record => record.meta.requiresVisitor)) {
// this route requires auth, check if logged in
// if not, redirect to login page.
if (store.getters.loggedIn) {
next({
name: 'cards',
})
} else {
next()
}
} {
next() // make sure to always call next()!
}
})
const app = createApp({
components: {
ImageUpload,ExampleComponent,ManageCards,CardsSpeler,Memory,Home, Navibar, CreateSpeler, Game, ModalComponent, CardsSpeler, GameAdmin,Login,Logout// hier alle data en functies waar vue wat mee moet
}
});
app.use(router);
app.use(store);
app.use(vuex);
app.component('ModalComponent', ModalComponent);
app.component('CreateSpeler', CreateSpeler);
app.component('CardsSpeler', CardsSpeler);
app.component('ManageCards', ManageCards);
app.component('Navibar', Navibar);
app.component('Login', Login);
app.component('Logout', Logout);
app.component('Master', Master);
app.component('ImageUpload', ImageUpload);
app.component('Memory', Memory);
app.mount('#app');
///window.Vue = require('vue').default;
/**
* The following block of code may be used to automatically register your
* Vue components. It will recursively scan this directory for the Vue
* components and automatically register them with their "basename".
*
* Eg. ./components/ExampleComponent.vue -> <example-component></example-component>
*/
// const files = require.context('./', true, /\.vue$/i)
// files.keys().map(key => Vue.component(key.split('/').pop().split('.')[0], files(key).default))
// Vue.component('example-component', require('./components/ExampleComponent.vue').default);
/**
* Next, we will create a fresh Vue application instance and attach it to
* the page. Then, you may begin adding components to this application
* or customize the JavaScript scaffolding to fit your unique needs.
*/
//const app = new Vue({
// el: '#app',
//});
The directory structure of components is:
> app/resources/js/components/
>auth
>Login.vue
>Logout.vue
>layouts
>Master.vue
>CreateSpeler.vue
>ManageCards.vue
>etc
Can anyone understand why this is no problem locally, but on the remote server it generates the error?
I have installed vue#next, laravel-mix#next
First of all, I don't see where is the app.js is located in your directory structure but I am assuming that it is inside the app/resources/js directory.
Now if you are having errors at the server only but not in the local, I suggest the below possible solutions.
You might be running the project locally on a windows machine. In windows, the path doesn't strictly check. For example, auth/Login.vue and auth/login.vue will be treated as the same but in the Linux system, they are treated differently. Hence, check if the Login.vue is not actually login.vue.
Try to run production mode in the local machine and check if you get the same error or not. If you get an error there too, you might have a spelling mistake somewhere or the directory structure is wrong.

admin-on-rest custom routes redirecting to dashboard

I am trying to add a custom route to AOR that acts as a landing page for an email link. When I navigate to http://localhost:3000/random_page AOR changes the url to http://localhost:3000/random_page#/ and renders the Dashboard component instead of my RandomPage. I am probably missing something simple here but this is a barebones custom route example. Can anyone see what I am doing wrong?
import React from 'react'
import { Route } from 'react-router-dom'
import RandomPage from './RandomPage'
export default [
<Route exact path="/random_page" component={RandomPage} noLayout/>,
]
import React, { Component } from 'react';
import './App.css';
import { jsonServerRestClient, fetchUtils, Admin, Resource, Delete } from 'admin-on-rest';
import { LogList } from './components/LogList';
import { UserLogs } from './components/UserLogs';
import Dashboard from './components/Dashboard'
import authClient from './authClient'
import customRoutes from './customRoutes'
const httpClient = (url, options = {}) => {
if (!options.headers) {
options.headers = new Headers({ Accept: 'application/json' });
}
options.headers.set('X-AUTH-TOKEN', localStorage.getItem('token'));
return fetchUtils.fetchJson(url, options);
}
class App extends Component {
render() {
return (
<Admin
authClient={authClient}
title = "Logs"
restClient={jsonServerRestClient('http://localhost:3001/admin', httpClient)}
customRoutes={customRoutes}
dashboard={Dashboard}
>
<Resource name="users" list={UserList} show={UserLogs}/>
<Resource name="logs" list={LogList} remove={Delete} />
</Admin>
);
}
}
export default App;
I believe that you're looking for catchAll found under the <Admin> component in the docs. You can then parse out the information you need from the URL and handle accordingly.

Resources