how to use logout button without authProvider - reactjs

hi react admin community,
I want to use logout button with custom component and router. I have checked documentation but not found any solution.
please suggest to me how I can use it.
below I added my code.
Adminroot Component
This is Admin Component.
import React from 'react';
import { Admin, Resource } from 'react-admin';
import jsonServerProvider from 'ra-data-json-server';
import { UserList } from "../users/users";
import Dashboard from './dashboard';
import MyLogoutButton from '../auth/logout';
const authProvider = {
logout: params => Promise.resolve(),
};
function Adminroot(props) {
const dataProvider = jsonServerProvider('http://jsonplaceholder.typicode.com');
return (
<div>
<Admin logoutButton={MyLogoutButton} loginPage={false} dashboard={Dashboard} dataProvider={dataProvider}>
<Resource name="users" list={UserList} />
</Admin>
</div>
);
}
export default Adminroot;
MyLogoutButton Component
This component contains default code which provides react-admin for logout.
Now, when clicks on Logout button. by default redirects to /login Url.
There renders a Logout component (below written the logout component code) that contains logout logic and redirect to /signin but it shows blank page until I refresh the page.
import React, { forwardRef } from 'react';
import { useLogout } from 'react-admin';
import MenuItem from '#material-ui/core/MenuItem';
import ExitIcon from '#material-ui/icons/PowerSettingsNew';
const MyLogoutButton = forwardRef((props, ref) => {
const logout = useLogout();
const handleClick = () => logout();
return (
<MenuItem
onClick={handleClick}
ref={ref}
>
<ExitIcon /> Logout
</MenuItem>
);
});
export default MyLogoutButton;
Logout Component
import React , { useContext } from 'react';
import { AppContext } from '../../AppContext';
import { Redirect } from 'react-router-dom';
function Logout(props){
const {handleSignOut} = useContext(AppContext);
handleSignOut();
return props.history.push('/signin');
}
export default Logout;

Related

Closing Overlay In React

I tried to debug my code but I lost right now.
Basicly I created State that open Login window and overlay that are Portals, when someone click the login button. its works fine but my problem is that I want when someone click on the overlay that the login window and the overlay will close.
I can't achieve that unfortunately.
Thanks For Advance !
Here is the code :
App.js
import { useState } from "react";
import Home from "./components/Elements/Home";
import Footer from "./components/UI/Footer";
import NaviBar from "./components/UI/NaviBar";
import "./App.css";
import Auth from "./components/Auth/Auth";
function App(props) {
const [openWindow, setOpenWindow] = useState(false);
const clickImport = (data) => {
setOpenWindow(true);
};
const closeHandler = () => {
setOpenWindow(false);
};
return (
<>
<NaviBar dataClick={clickImport} />
{openWindow && <Auth dataClickClose={closeHandler} />}
<Home />
<Footer />
</>
);
}
export default App;
Auth.js
import { useState } from "react";
import ReactDOM from "react-dom";
import classes from "./Auth.module.css";
import Login from "./Login";
import Overlay from "./Overlay";
const Auth = (props) => {
return (
<>
{ReactDOM.createPortal(<Login />, document.getElementById("auth"))}
{ReactDOM.createPortal(
<Overlay onClick={props.dataClickClose} />,
document.getElementById("blur")
)}
</>
);
};
export default Auth;
Basicly I created State that open Login window and overlay that are Portals, when someone click the login button. its works fine but my problem is that I want when someone click on the overlay that the login window and the overlay will close.
Solved It.
I forgot to update the Overlay component.
here is my fix:
import classes from "./Overlay.module.css";
const Overlay = (props) => {
return <div className={classes.bgContainer} onClick={props.closeClick}></div>;
};
export default Overlay;

Why is my useContext not working in my app and my browser remains loading?

Im trying to use useContext hook to pass variables and functions through different components without lifting them to the main App.js component. I was trying to do this and it seemed to compile correctly but when i go to my browser my app is stucked in a blank page and remains loading.
LoginContext.js: In this component i store the user data in an object using the useState hook and i use jwt_decode to decode the use token and get all the data i need to store.
import React, { createContext, useState } from "react";
import jwt_decode from 'jwt-decode';
const LoginContext = createContext();
export function LoginProvider({children}) {
const [user, setUser] = useState({})
function handleCallbackResponse(response){
var userData = jwt_decode(response.credential); //Token with the login user Data
setUser(userData); //Store user Data
/* console.log(userData) */
document.getElementById('signInDiv').hidden = true;
}
function handleSignOut(event) {
setUser({}) //Empy the user Data
document.getElementById('signInDiv').hidden = false;
}
return(
<LoginProvider value={{user, handleCallbackResponse, handleSignOut}}>{children}</LoginProvider>
);
}
export default LoginContext
The i have my Login.js which uses LoginContext: Here i use the user to show the different data of the logged in use and the handleCallbackResponse to do my Login.
import React, { useContext, useEffect } from 'react'
import LoginContext from '../LoginContext';
const Login = () => {
const {user, handleCallbackResponse, handleSignOut} = useContext(LoginContext)
useEffect(()=>{
/*global google*/
google.accounts.id.initialize({
client_id:"My client ID",
callback: handleCallbackResponse
})
google.accounts.id.prompt();
google.accounts.id.renderButton(
document.getElementById('signInDiv'),
{theme: 'outline', size: 'medium'}
)
}, []);
return (
<div>
<div id="signInDiv"></div>
{
//If user objetc is not empty show sign out button
Object.keys(user).length !== 0 &&
<button onClick={(e)=>handleSignOut(e)}>Sign Out</button>
}
{user &&
<div>
<img src={user.picture} alt="" />
<h3>{user.name}</h3>
</div>
}
</div>
)
}
export default Login
App.js:
import './App.css';
import Login from './atoms/Login';
import { BrowserRouter , Routes, Route } from 'react-router-dom';
import Dashboard from './pages/Dashboard';
import { LoginProvider } from './LoginContext';
import PrivateRoutes from './utils/PrivateRoutes';
function App() {
return (
<LoginProvider>
<BrowserRouter>
<Routes>
{/* <Route element={<PrivateRoutes/>}>
</Route> */}
<Route exact path="/dashboard" element={<Dashboard/>}/>
<Route path="/" element={<Login/>} />
</Routes>
</BrowserRouter>
</LoginProvider>
);
}
export default App;
For some reason my application runs with no error but in the browser it remains loading with a blank page and im not able to inspect the page.
Instead of:
<LoginProvider value={{user, handleCallbackResponse, handleSignOut}}>{children}</LoginProvider>
);
Replace with
<LoginContext.Provider value={{user, handleCallbackResponse, handleSignOut}}>{children}</LoginContext.Provider>

How to get route params in React functional component

I want to print url params(:uname ,:unumber) through Profile functional component. Here is my code.
My route in App.js
<Route path="/profile/:uname-:unumber" component={Profile} >
<Profile />
</Route>
I'm clicking profile url from Dashboard.js; this is my link
<Link to={{
pathname: `/profile/${userDetail.name}-${userDetail.u_number}`,
}} >view profile</Link>
on click on this link it is generating a url for eg: 'http://localhost:3000/profile-mynamehere-747484' and it is redirecting to profile component. But how to print to access the uname and unumber in profile component. I tried like this but not works
import React, {useState, useEffect, Component } from "react";
import axios from "axios";
import { useHistory,useParams } from "react-router-dom";
import Header from "../Header";
import {
BrowserRouter as Router,
Route,
Link,
Redirect,
withRouter
} from "react-router-dom";
const Profile = ({uname, unumber}) => {
console.log(uname); // here I want to print mynamehere from url, but not prints name
console.log(unumber);// here I want to print 747484 from url, but not prints unumber
return (
<div>
</div>
);
};
export default Profile;
use UseParams like this in profile component
const { uname,unumber } = useParams();
In Profile you should useParams to get pass the uname & unumber:
import { useHistory,useParams } from "react-router-dom";
const Profile = () => {
const {uname, unumber} = useParams()
console.log(uname);
console.log(unumber);
return (
<div>
</div>
);
};
In your profile component do the following:
import React, {useState, useEffect, Component } from "react";
import axios from "axios";
import { useHistory,useParams } from "react-router-dom";
import Header from "../Header";
const Profile = () => {
const {uname, unumber} = useParams()
console.log(uname-unumber)
return (
<div>
</div>
);
};
export default Profile;

How to provide context from contextApi for a specific set of routes in nextjs and preserve state with routing through linking?

I am using contextApi with nextjs and I'm having some trouble when providing a context just for certain routes. I am able to make the context available for just a few routes, but when I transition from one to the other through linking, I end up losing the state of my application.
I have three files inside my pages folder:
index.tsx,
Dashboard/index.tsx and
SignIn/index.tsx.
If I import the provider inside the files Dashboard/index.tsx and SignIn/index.tsx and go from one page to the other by pressing a Link component from next/link, the whole state is set back to the initial state.
The content of the Dashboard/index.tsx file
import React from 'react';
import Dashboard from '../../app/views/Dashboard';
import { AuthProvider } from '../../contexts/auth';
const Index: React.FC = () => (
<AuthProvider>
<Dashboard />
</AuthProvider>
);
export default Index;
This is the contend of the SignIn/index.tsx file:
import React from 'react';
import SignIn from '../../app/views/SignIn';
import { AuthProvider } from '../../contexts/auth';
const Index: React.FC = () => (
<AuthProvider>
<SignIn />
</AuthProvider>
);
export default Index;
The views folder is where I create the components that will be rendered.
The content of the file views/SignIn/index.tsx is:
import React, { useContext } from 'react';
import Link from 'next/link';
import { AuthContext } from '../../../contexts/auth';
const SignIn: React.FC = () => {
const { signed, signIn } = useContext(AuthContext);
async function handleSignIn() {
signIn();
}
return (
<div>
<Link href="Dashboard">Go back to Dashboard</Link>
<button onClick={handleSignIn}>Click me</button>
</div>
);
};
export default SignIn;
And the content of the file views/Dashboard/index.tsx is:
import React, { useContext } from 'react';
import Link from 'next/link';
import { AuthContext } from '../../../contexts/auth';
const Dashboard: React.FC = () => {
const { signed, signIn } = useContext(AuthContext);
async function handleSignIn() {
signIn();
}
return (
<div>
<Link href="SignIn">Go back to sign in page</Link>
<button onClick={handleSignIn}>Click me</button>
</div>
);
};
export default Dashboard;
I am able to access the context inside both /Dashboard and /SignIn, but when I press the link, the state comes back to the initial one. I figured out that the whole provider is rerenderized and therefore the new state becomes the initial state, but I wasn't able to go around this issue in a "best practices manner".
If I put the provider inside _app.tsx, I can maintain the state when transitioning between pages, but I end up providing this state to the / route as well, which I am trying to avoid.
I was able to go around this by doing the following, but it really does not seem to be the best solution for me.
I removed the Providers from Pages/SignIn/index.tsx and Pages/Dashboard/index.tsx and used the following snippet for the _app.tsx file:
import React from 'react';
import { AppProps } from 'next/app';
import { useRouter } from 'next/router';
import { AuthProvider } from '../contexts/auth';
const App: React.FC<AppProps> = ({ Component, pageProps }) => {
const router = useRouter();
const AuthProviderRoutes = ['/SignIn', '/Dashboard'];
return (
<>
{AuthProviderRoutes.includes(router.pathname) ? (
<AuthProvider>
<Component {...pageProps} />
</AuthProvider>
) : <Component {...pageProps} />}
</>
);
};
export default App;
Does anyone have a better solution?

React exporting withRouter and withStyles error

I am using react along with redux and material-ui to make a component. I am attempting to write an export statement export default connect()(withRouter(FirstPage))(withStyles(styles)(FirstPage))
However, this doesn't seem to work I get an error that says
TypeError: Cannot set property 'props' of undefined
this.props = props;
This error is referencing one of my node_modules.
Here is my full code:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import {withRouter} from 'react-router-dom'
import { withStyles } from '#material-ui/core/styles';
import Card from '#material-ui/core/Card';
import CardActions from '#material-ui/core/CardActions';
import CardContent from '#material-ui/core/CardContent';
import Button from '#material-ui/core/Button';
const styles = theme =>({
root: {
maxWidth: 345,
},
})
class FirstPage extends Component {
state = {
feeling: ''
}
//This function will dispatch the users response to index.js
//The dispatch type here is 'SET_FEELING'
submitData=(event) => {
event.preventDefault();
this.props.dispatch({type: 'SET_FEELING', payload: this.state})
this.changeLocation();
}
//This function will update the local state with the users response
handleChange= (event) => {
this.setState({
feeling: event.target.value
})
}
//This function will change the current url when a button is clicked
changeLocation= ()=> {
this.props.history.push('/secondPage')
}
render(){
const { classes } = this.props;
return(
<div>
<Card >
<CardContent className={classes.root}>
<form>
<input onChange={this.handleChange} placeholder='How are you feeling' value={this.state.feeling} />
</form>
</CardContent>
<CardActions>
<Button onClick={this.submitData}>Submit</Button>
</CardActions>
</Card>
</div>
)
}
}
//this export connects the component to the reduxStore as well as allowing us to use the history props
export default connect()(withRouter(FirstPage))(withStyles(styles)(FirstPage))
I believe the following code should work:
export default withRouter(connect()(withStyles(styles)(FirstPage)))
Instead of
export default connect()(withRouter(FirstPage))(withStyles(styles)(FirstPage))
First of all, connect() returns a function that only accepts an argument. Second, connect() should be wrapped inside withRouter(). This problem is stated in the github docs of React Router.
without using react-redux :
export default (withStyles(styles), withRouter)(FirstPage);

Resources