feat: build LogoutPage, improve LoginPage

This commit is contained in:
MTG2000
2022-06-01 21:20:28 +03:00
parent 3023d8e20b
commit d5be48f3be
6 changed files with 152 additions and 92 deletions

View File

@@ -6,7 +6,6 @@ import { Wallet_Service } from "./services";
import { Navigate, Route, Routes } from "react-router-dom";
import { useWrapperSetup } from "./utils/Wrapper";
import LoadingPage from "./Components/LoadingPage/LoadingPage";
import LoginPage from "./features/Auth/pages/LoginPage";
// Pages
const FeedPage = React.lazy(() => import("./features/Posts/pages/FeedPage/FeedPage"))
@@ -16,6 +15,8 @@ const PostDetailsPage = React.lazy(() => import("./features/Posts/pages/PostDeta
const CategoryPage = React.lazy(() => import("src/features/Projects/pages/CategoryPage/CategoryPage"))
const ExplorePage = React.lazy(() => import("src/features/Projects/pages/ExplorePage"))
const DonatePage = React.lazy(() => import("./features/Donations/pages/DonatePage/DonatePage"))
const LoginPage = React.lazy(() => import("./features/Auth/pages/LoginPage/LoginPage"))
const LogoutPage = React.lazy(() => import("./features/Auth/pages/LogoutPage/LogoutPage"))
function App() {
const { isWalletConnected } = useAppSelector(state => ({
@@ -58,6 +59,7 @@ function App() {
<Route path="/donate" element={<DonatePage />} />
<Route path="/login" element={<LoginPage />} />
<Route path="/logout" element={<LogoutPage />} />
<Route path="/" element={<Navigate to="/products" />} />
</Routes>

View File

@@ -15,6 +15,8 @@ import {
} from '@szhsin/react-menu';
import '@szhsin/react-menu/dist/index.css';
import { FiAward, FiChevronDown, FiFeather, FiLogIn, FiMic } from "react-icons/fi";
import { useMeQuery } from "src/graphql";
import Avatar from "src/features/Profiles/Components/Avatar/Avatar";
export default function NavDesktop() {
@@ -22,6 +24,8 @@ export default function NavDesktop() {
const communityRef = useRef(null);
const [communitymenuProps, toggleCommunityMenu] = useMenuState({ transition: true });
const meQuery = useMeQuery();
const { isWalletConnected } = useAppSelector((state) => ({
isWalletConnected: state.wallet.isConnected,
}));
@@ -157,13 +161,34 @@ export default function NavDesktop() {
: <Button className="ml-16 py-12 px-16 lg:px-20" onClick={onConnectWallet}><AiFillThunderbolt className='inline-block text-thunder transform scale-125' /> Connect Wallet </Button>
} */}
{currentSection === 'products' && <IconButton className='ml-16 self-center' onClick={openSearch}>
{currentSection === 'products' && <IconButton className='mr-16 self-center' onClick={openSearch}>
<BsSearch className='scale-125 text-gray-400' />
</IconButton>}
</motion.div>
<Link to='/login' className="ml-16 font-bold hover:text-primary-800 hover:underline">
Login <FiLogIn />
</Link>
{meQuery.data?.me ?
<Menu menuButton={<MenuButton ><Avatar src={meQuery.data.me.avatar} width={40} /> </MenuButton>}>
<MenuItem
className='!p-16 font-medium flex gap-16 hover:bg-gray-100 !rounded-12 opacity-60'
>
Profile (soon)
</MenuItem>
<MenuItem
href="/logout"
onClick={(e) => {
e.syntheticEvent.preventDefault();
navigate("/logout");
}}
className='!p-16 font-medium flex gap-16 hover:bg-gray-100 !rounded-12'
>
Logout
</MenuItem>
</Menu>
:
<Link to='/login' className="font-bold hover:text-primary-800 hover:underline">
Login <FiLogIn />
</Link>
}
<div className="relative h-24">
<motion.div
initial={{

View File

@@ -1,86 +0,0 @@
import { useEffect, useState } from "react"
import { BsFillLightningChargeFill } from "react-icons/bs";
import { Grid } from "react-loader-spinner";
import { useMeQuery } from "src/graphql"
export default function LoginPage() {
const [loadingLnurl, setLoadingLnurl] = useState(true)
const [lnurlAuth, setLnurlAuth] = useState("");
const [isLoggedIn, setIsLoggedIn] = useState(false);
const [isPollilng, setIsPollilng] = useState(false)
const meQuery = useMeQuery({
onCompleted: (data) => {
const stateChanged = Boolean(data.me) !== isLoggedIn;
if (stateChanged)
setIsPollilng(false);
setIsLoggedIn(Boolean(data.me));
}
})
useEffect(() => {
(async () => {
const res = await fetch(process.env.REACT_APP_AUTH_END_POINT! + '/login')
const data = await res.json()
setLoadingLnurl(false);
setLnurlAuth(data.encoded)
})()
}, [])
const { startPolling, stopPolling } = meQuery;
useEffect(() => {
if (isPollilng)
startPolling(1500);
else
stopPolling();
}, [isPollilng, startPolling, stopPolling])
const onLogin = () => {
setIsPollilng(true);
}
const logout = async () => {
await fetch(process.env.REACT_APP_AUTH_END_POINT! + '/logout', {
method: "GET",
'credentials': "include"
})
setIsPollilng(true);
}
return (
<div className="min-h-[80vh] flex flex-col justify-center items-center">
{loadingLnurl && <div className="flex flex-col gap-24 items-center">
<Grid color="var(--primary)" width="150" />
<p className="text-body3 font-bold">Fetching Lnurl-Auth...</p>
</div>}
{!loadingLnurl &&
(isLoggedIn ?
<div className="flex flex-col justify-center items-center">
<h3 className="text-body4">
Hello: <span className="font-bold">@{meQuery.data?.me?.name.slice(0, 10)}...</span>
</h3>
<img src={meQuery.data?.me?.avatar} className='w-80 h-80 object-cover' alt="" />
<button
onClick={logout}
className="text-black font-bolder bg-gray-200 rounded-12 px-16 py-12 mt-36 active:scale-90 transition-transform">
{isPollilng ? "Logging you out..." : "Logout"}
</button>
</div> :
<a
href={lnurlAuth}
onClick={onLogin}
className='text-black font-bolder bg-yellow-200 hover:bg-yellow-300 rounded-12 px-16 py-12 active:scale-90 transition-transform'>
Login with Lightning <BsFillLightningChargeFill className="scale-125" />
</a>
)}
</div>
)
}

View File

@@ -0,0 +1,86 @@
import { useEffect, useState } from "react"
import { BsFillLightningChargeFill } from "react-icons/bs";
import { Grid } from "react-loader-spinner";
import { useNavigate } from "react-router-dom";
import { useMeQuery } from "src/graphql"
export default function LoginPage() {
const [loadingLnurl, setLoadingLnurl] = useState(true)
const [lnurlAuth, setLnurlAuth] = useState("");
const [isLoggedIn, setIsLoggedIn] = useState(false);
const navigate = useNavigate()
const meQuery = useMeQuery({
onCompleted: (data) => {
if (data.me) {
setIsLoggedIn(true);
meQuery.stopPolling();
setTimeout(() => {
navigate('/')
}, 2000)
}
}
})
useEffect(() => {
(async () => {
const res = await fetch(process.env.REACT_APP_AUTH_END_POINT! + '/login')
const data = await res.json()
setLoadingLnurl(false);
setLnurlAuth(data.encoded)
})();
}, [])
const onLogin = () => {
meQuery.startPolling(1500)
}
return (
<div className="min-h-[80vh] page-container flex flex-col justify-center items-center">
{loadingLnurl && <div className="flex flex-col gap-24 items-center">
<Grid color="var(--primary)" width="150" />
<p className="text-body3 font-bold">Fetching Lnurl-Auth...</p>
</div>}
{!loadingLnurl &&
(isLoggedIn ?
<div className="flex flex-col justify-center items-center">
<h3 className="text-body4">
Hello: <span className="font-bold">@{meQuery.data?.me?.name.slice(0, 10)}...</span>
</h3>
<img src={meQuery.data?.me?.avatar} className='w-80 h-80 object-cover' alt="" />
</div> :
<div className="max-w-[326px] border-2 border-gray-200 rounded-16 p-16 flex flex-col gap-16 items-center" >
<p className="text-body1 font-bolder text-center">
Login
</p>
<p className="text-gray-600 text-body-4">
Zero credentials authentication.
<br />
All you need is a connected <a href='https://getalby.com'
target='_blank'
className="underline text-primary-500"
rel="noreferrer"
>WebLN wallet</a> that supports lnurl-auth, & you are good to go !!
</p>
<a
href={lnurlAuth}
onClick={onLogin}
className='block text-black font-bolder bg-yellow-200 hover:bg-yellow-300 rounded-12 px-16 py-12 active:scale-90 transition-transform'>
Login with Lightning <BsFillLightningChargeFill className="scale-125" />
</a>
</div>
)}
</div>
)
}

View File

@@ -0,0 +1,33 @@
import { useEffect, useState } from "react"
import { BsFillLightningChargeFill } from "react-icons/bs";
import { Grid, LineWave } from "react-loader-spinner";
import { useNavigate } from "react-router-dom";
export default function LoginPage() {
const navigate = useNavigate();
useEffect(() => {
fetch(process.env.REACT_APP_AUTH_END_POINT! + '/logout', {
method: "GET",
'credentials': "include"
})
.then(() => {
window.location.pathname = '/'
})
.catch(() => {
window.location.pathname = '/'
})
}, [navigate])
return (
<div className="min-h-[80vh] flex flex-col justify-center items-center">
<p className="text-body-2 text-gray-800">
Logging you out...
</p>
<LineWave color="var(--primary)" width="150" />
</div>
)
}

View File

@@ -7,7 +7,7 @@ interface Props {
export default function Avatar({ src, alt, width = 40 }: Props) {
return (
<img src={src} className='shrink-0 rounded-full shadow-inner object-contain border border-gray-100' style={{
<img src={src} className='shrink-0 rounded-full object-contain border-2 border-gray-100' style={{
width: width,
height: width,
}} alt={alt ?? "avatar"} />