mirror of
https://github.com/utopia-os/utopia-ui.git
synced 2025-12-13 07:46:10 +00:00
password reset implemented
This commit is contained in:
parent
f5dd097228
commit
3be1718022
25
package-lock.json
generated
25
package-lock.json
generated
@ -10,6 +10,7 @@
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@heroicons/react": "^2.0.17",
|
||||
"@tanstack/react-query": "^5.17.8",
|
||||
"@types/offscreencanvas": "^2019.7.1",
|
||||
"leaflet": "^1.9.4",
|
||||
"prop-types": "^15.8.1",
|
||||
@ -256,6 +257,30 @@
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tanstack/query-core": {
|
||||
"version": "5.17.8",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.17.8.tgz",
|
||||
"integrity": "sha512-V4hQv4jmRwbji9wo3F6/JQEjbWLUlv2sE2K5R49girEyok71ksDnVHbQiAvp4+FbovMY8A3IbP3cH3jqAUe/BQ==",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/tannerlinsley"
|
||||
}
|
||||
},
|
||||
"node_modules/@tanstack/react-query": {
|
||||
"version": "5.17.8",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.17.8.tgz",
|
||||
"integrity": "sha512-J+QMBoQiAZglwVB/bEgmf9IczLPg0YwFaqmn4aTW72ZYkUYyBU9dj6OMQk3RzmD9RzUz2m7pPBCkcT0Z1i0acg==",
|
||||
"dependencies": {
|
||||
"@tanstack/query-core": "5.17.8"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/tannerlinsley"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@trysound/sax": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz",
|
||||
|
||||
@ -44,6 +44,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@heroicons/react": "^2.0.17",
|
||||
"@tanstack/react-query": "^5.17.8",
|
||||
"@types/offscreencanvas": "^2019.7.1",
|
||||
"leaflet": "^1.9.4",
|
||||
"prop-types": "^15.8.1",
|
||||
|
||||
@ -6,31 +6,37 @@ import { QuestsProvider } from '../Gaming/hooks/useQuests'
|
||||
import { AssetsProvider, useSetAssetApi } from './hooks/useAssets'
|
||||
import { SetAssetsApi } from './SetAssetsApi'
|
||||
import { AssetsApi } from '../../types'
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||
|
||||
export function AppShell({ appName, nameWidth, children, assetsApi } : {appName: string, nameWidth?: number, children: React.ReactNode, assetsApi: AssetsApi}) {
|
||||
export function AppShell({ appName, nameWidth, children, assetsApi }: { appName: string, nameWidth?: number, children: React.ReactNode, assetsApi: AssetsApi }) {
|
||||
|
||||
// Create a client
|
||||
const queryClient = new QueryClient()
|
||||
|
||||
|
||||
return (
|
||||
<BrowserRouter>
|
||||
<AssetsProvider>
|
||||
<SetAssetsApi assetsApi={assetsApi}></SetAssetsApi>
|
||||
<QuestsProvider initialOpen={true}>
|
||||
<ToastContainer position="top-right"
|
||||
autoClose={2000}
|
||||
hideProgressBar
|
||||
newestOnTop={false}
|
||||
closeOnClick
|
||||
rtl={false}
|
||||
pauseOnFocusLoss
|
||||
draggable
|
||||
pauseOnHover
|
||||
theme="light" />
|
||||
<NavBar appName={appName} nameWidth={nameWidth}></NavBar>
|
||||
<div id="app-content" className="tw-flex tw-!pl-[77px]">
|
||||
{children}
|
||||
</div>
|
||||
</QuestsProvider>
|
||||
</AssetsProvider>
|
||||
</BrowserRouter>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<BrowserRouter>
|
||||
<AssetsProvider>
|
||||
<SetAssetsApi assetsApi={assetsApi}></SetAssetsApi>
|
||||
<QuestsProvider initialOpen={true}>
|
||||
<ToastContainer position="top-right"
|
||||
autoClose={2000}
|
||||
hideProgressBar
|
||||
newestOnTop={false}
|
||||
closeOnClick
|
||||
rtl={false}
|
||||
pauseOnFocusLoss
|
||||
draggable
|
||||
pauseOnHover
|
||||
theme="light" />
|
||||
<NavBar appName={appName} nameWidth={nameWidth}></NavBar>
|
||||
<div id="app-content" className="tw-flex tw-!pl-[77px]">
|
||||
{children}
|
||||
</div>
|
||||
</QuestsProvider>
|
||||
</AssetsProvider>
|
||||
</BrowserRouter>
|
||||
</QueryClientProvider>
|
||||
)
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ type ContentProps = {
|
||||
|
||||
export function Content({children} : ContentProps) {
|
||||
return (
|
||||
<div className='tw-flex tw-flex-col tw-w-full tw-relative'>
|
||||
<div className='tw-flex tw-flex-col tw-w-full tw-bg-base-200 tw-relative'>
|
||||
{children}
|
||||
</div>
|
||||
|
||||
|
||||
@ -10,63 +10,11 @@ import DialogModal from "../Templates/DialogModal";
|
||||
|
||||
export default function NavBar({ appName, nameWidth = 200}: { appName: string, nameWidth?: number }) {
|
||||
|
||||
|
||||
const [signupOpen, setSignupOpen] = useState(false);
|
||||
const [loginOpen, setLoginOpen] = useState(false);
|
||||
|
||||
|
||||
const [email, setEmail] = useState<string>("");
|
||||
const [userName, setUserName] = useState<string>("");
|
||||
const [password, setPassword] = useState<string>("");
|
||||
|
||||
|
||||
const { isAuthenticated, user, login, register, loading, logout, token } = useAuth();
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
const onRegister = async () => {
|
||||
await toast.promise(
|
||||
register({ email: email, password: password }, userName),
|
||||
{
|
||||
success: {
|
||||
render({ data }) {
|
||||
navigate(`/`);
|
||||
return `Hi ${data?.first_name}`
|
||||
},
|
||||
// other options
|
||||
icon: "✌️",
|
||||
},
|
||||
error: {
|
||||
render( {data} ) {
|
||||
return `${data}`
|
||||
},
|
||||
},
|
||||
pending: 'creating new user ...'
|
||||
});
|
||||
setSignupOpen(false);
|
||||
}
|
||||
|
||||
const onLogin = async () => {
|
||||
await toast.promise(
|
||||
login({ email: email, password: password }),
|
||||
{
|
||||
success: {
|
||||
render({ data }) {
|
||||
navigate(`/`);
|
||||
return `Hi ${data?.first_name}`
|
||||
},
|
||||
// other options
|
||||
icon: "✌️",
|
||||
},
|
||||
error: {
|
||||
render( {data} ) {
|
||||
return `${data}`
|
||||
},
|
||||
},
|
||||
pending: 'logging in ...'
|
||||
});
|
||||
setLoginOpen(false);
|
||||
}
|
||||
|
||||
const { isAuthenticated, user, logout, token } = useAuth();
|
||||
|
||||
const onLogout = () => {
|
||||
toast.promise(
|
||||
@ -133,11 +81,11 @@ export default function NavBar({ appName, nameWidth = 200}: { appName: string, n
|
||||
<div>
|
||||
|
||||
<div className="tw-hidden md:tw-flex">
|
||||
<div onClick={() => setLoginOpen(true)} className="tw-btn tw-btn-ghost tw-mr-2">
|
||||
<div onClick={() => navigate("/login")} className="tw-btn tw-btn-ghost tw-mr-2">
|
||||
Login
|
||||
</div>
|
||||
|
||||
<div onClick={() => setSignupOpen(true)} className="tw-btn tw-btn-ghost tw-mr-2">
|
||||
<div onClick={() => navigate("/signup")} className="tw-btn tw-btn-ghost tw-mr-2">
|
||||
Sign Up
|
||||
</div>
|
||||
</div>
|
||||
@ -150,35 +98,15 @@ export default function NavBar({ appName, nameWidth = 200}: { appName: string, n
|
||||
|
||||
</label>
|
||||
<ul tabIndex={1} className="tw-menu tw-dropdown-content tw-mt-3 tw-p-2 tw-shadow tw-bg-base-100 tw-rounded-box tw-w-52 !tw-z-[10000]">
|
||||
<li><a onClick={() => {setLoginOpen(true)}}>Login</a></li>
|
||||
<li><a onClick={() => setSignupOpen(true)}>Sign Up</a></li>
|
||||
<li><a onClick={() => {() => navigate("/login")}}>Login</a></li>
|
||||
<li><a onClick={() => () => navigate("/signup")}>Sign Up</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<DialogModal
|
||||
title="Login"
|
||||
isOpened={loginOpen}
|
||||
onClose={() => setLoginOpen(false)}>
|
||||
<input type="email" placeholder="E-Mail" value={email} onChange={e => setEmail(e.target.value)} className="tw-input tw-input-bordered tw-w-full tw-max-w-xs" />
|
||||
<input type="password" placeholder="Password" onChange={e => setPassword(e.target.value)} className="tw-input tw-input-bordered tw-w-full tw-max-w-xs" />
|
||||
<div className="tw-card-actions">
|
||||
<button className={loading ? 'tw-btn tw-btn-disabled tw-btn-block tw-btn-primary' : 'tw-btn tw-btn-primary tw-btn-block'} onClick={() => onLogin()}>{loading ? <span className="tw-loading tw-loading-spinner"></span> : 'Login'}</button>
|
||||
</div>
|
||||
</DialogModal>
|
||||
<DialogModal
|
||||
title="Sign Up"
|
||||
isOpened={signupOpen}
|
||||
onClose={() => setSignupOpen(false)}>
|
||||
<input type="text" placeholder="Name" value={userName} onChange={e => setUserName(e.target.value)} className="tw-input tw-input-bordered tw-w-full tw-max-w-xs" />
|
||||
<input type="email" placeholder="E-Mail" value={email} onChange={e => setEmail(e.target.value)} className="tw-input tw-input-bordered tw-w-full tw-max-w-xs" />
|
||||
<input type="password" placeholder="Password" onChange={e => setPassword(e.target.value)} className="tw-input tw-input-bordered tw-w-full tw-max-w-xs" />
|
||||
<div className="tw-card-actions">
|
||||
<button className={loading ? 'tw-btn tw-btn-disabled tw-btn-block tw-btn-primary' : 'tw-btn tw-btn-primary tw-btn-block'} onClick={() => onRegister()}>{loading ? <span className="tw-loading tw-loading-spinner"></span> : 'Sign Up'}</button>
|
||||
</div>
|
||||
</DialogModal>
|
||||
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,66 +1,53 @@
|
||||
import {useState} from 'react'
|
||||
import {Link} from 'react-router-dom'
|
||||
import { useRef, useState } from 'react'
|
||||
import { Link, useNavigate } from 'react-router-dom'
|
||||
import ErrorText from '../Typography/ErrorText'
|
||||
import {TextInput} from '../Input/TextInput'
|
||||
import { TextInput } from '../Input/TextInput'
|
||||
import * as React from 'react'
|
||||
import { toast } from 'react-toastify'
|
||||
import { useAuth } from './useAuth'
|
||||
import { MapOverlayPage} from '../Templates'
|
||||
|
||||
export function LoginPage(){
|
||||
export function LoginPage() {
|
||||
|
||||
const INITIAL_LOGIN_OBJ = {
|
||||
password : "",
|
||||
emailId : ""
|
||||
const [email, setEmail] = useState<string>("");
|
||||
const [password, setPassword] = useState<string>("");
|
||||
|
||||
const { login, loading } = useAuth();
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
const onLogin = async () => {
|
||||
await toast.promise(
|
||||
login({ email: email, password: password }),
|
||||
{
|
||||
success: {
|
||||
render({ data }) {
|
||||
navigate(`/`);
|
||||
return `Hi ${data?.first_name}`
|
||||
},
|
||||
// other options
|
||||
icon: "✌️",
|
||||
},
|
||||
error: {
|
||||
render({ data }) {
|
||||
return `${data}`
|
||||
},
|
||||
},
|
||||
pending: 'logging in ...'
|
||||
});
|
||||
}
|
||||
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [errorMessage, setErrorMessage] = useState("")
|
||||
const [loginObj, setLoginObj] = useState(INITIAL_LOGIN_OBJ)
|
||||
|
||||
const submitForm = (e) =>{
|
||||
e.preventDefault()
|
||||
setErrorMessage("")
|
||||
|
||||
if(loginObj.emailId.trim() === "")return setErrorMessage("Email Id is required! (use any value)")
|
||||
if(loginObj.password.trim() === "")return setErrorMessage("Password is required! (use any value)")
|
||||
else{
|
||||
setLoading(true)
|
||||
// Call API to check user credentials and save token in localstorage
|
||||
localStorage.setItem("token", "DumyTokenHere")
|
||||
setLoading(false)
|
||||
window.location.href = '/app/welcome'
|
||||
}
|
||||
}
|
||||
|
||||
const updateFormValue = (val: string) => {
|
||||
console.log(val)
|
||||
}
|
||||
|
||||
return(
|
||||
<div className="tw-flex-1 tw-bg-base-200 tw-flex tw-items-center">
|
||||
<div className="tw-card tw-mx-auto tw-w-full tw-max-w-md tw-shadow-xl">
|
||||
<div className="tw-grid md:tw-grid-cols-1 tw-grid-cols-1 tw-bg-base-100 tw-rounded-xl">
|
||||
<div className='tw-py-10 tw-px-10'>
|
||||
<h2 className='tw-text-2xl tw-font-semibold tw-mb-2 tw-text-center'>Login</h2>
|
||||
<form onSubmit={(e) => submitForm(e)}>
|
||||
|
||||
<div className="tw-mb-4">
|
||||
|
||||
<TextInput type="email" defaultValue={loginObj.emailId} containerStyle="tw-mt-4" labelTitle="E-Mail" updateFormValue={(v) => updateFormValue(v)}/>
|
||||
|
||||
<TextInput defaultValue={loginObj.password} type="password" containerStyle="tw-mt-4" labelTitle="Password" updateFormValue={(v) => updateFormValue(v)}/>
|
||||
|
||||
return (
|
||||
<MapOverlayPage>
|
||||
<h2 className='tw-text-2xl tw-font-semibold tw-mb-2 tw-text-center'>Login</h2>
|
||||
<input type="email" placeholder="E-Mail" value={email} onChange={e => setEmail(e.target.value)} className="tw-input tw-input-bordered tw-w-full tw-max-w-xs" />
|
||||
<input type="password" placeholder="Password" onChange={e => setPassword(e.target.value)} className="tw-input tw-input-bordered tw-w-full tw-max-w-xs" />
|
||||
<div className='tw-text-right tw-text-primary'><Link to="/reset-password"><span className="tw-text-sm tw-inline-block hover:tw-text-primary hover:tw-underline hover:tw-cursor-pointer tw-transition tw-duration-200">Forgot Password?</span></Link>
|
||||
</div>
|
||||
|
||||
<div className='tw-text-right tw-text-primary'><Link to="/forgot-password"><span className="tw-text-sm tw-inline-block hover:tw-text-primary hover:tw-underline hover:tw-cursor-pointer tw-transition tw-duration-200">Forgot Password?</span></Link>
|
||||
</div>
|
||||
|
||||
<ErrorText styleClass="mt-8">{errorMessage}</ErrorText>
|
||||
<button type="submit" className={"tw-btn tw-mt-2 tw-w-full tw-btn-primary" + (loading ? " tw-loading" : "")}>Login</button>
|
||||
|
||||
<div className='tw-text-center tw-mt-4'>Don't have an account yet? <Link to="/signup"><span className=" tw-inline-block hover:tw-text-primary hover:tw-underline hover:tw-cursor-pointer tw-transition tw-duration-200">Sign Up</span></Link></div>
|
||||
</form>
|
||||
</div>
|
||||
<div className="tw-card-actions">
|
||||
<button className={loading ? 'tw-btn tw-btn-disabled tw-btn-block tw-btn-primary' : 'tw-btn tw-btn-primary tw-btn-block'} onClick={() => onLogin()}>{loading ? <span className="tw-loading tw-loading-spinner"></span> : 'Login'}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</MapOverlayPage>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
48
src/Components/Auth/RequestPasswordPage.tsx
Normal file
48
src/Components/Auth/RequestPasswordPage.tsx
Normal file
@ -0,0 +1,48 @@
|
||||
import { useState } from 'react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
|
||||
import * as React from 'react'
|
||||
import { toast } from 'react-toastify'
|
||||
import { useAuth } from './useAuth'
|
||||
import { MapOverlayPage} from '../Templates'
|
||||
|
||||
export function RequestPasswordPage({reset_url}) {
|
||||
|
||||
const [email, setEmail] = useState<string>("");
|
||||
|
||||
const { requestPasswordReset, loading } = useAuth();
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
const onReset = async () => {
|
||||
await toast.promise(
|
||||
requestPasswordReset( email, reset_url),
|
||||
{
|
||||
success: {
|
||||
render() {
|
||||
navigate(`/`);
|
||||
return `Check your mailbox`
|
||||
},
|
||||
// other options
|
||||
icon: "📬",
|
||||
},
|
||||
error: {
|
||||
render({ data }) {
|
||||
return `${data}`
|
||||
},
|
||||
},
|
||||
pending: 'sending email ...'
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<MapOverlayPage>
|
||||
<h2 className='tw-text-2xl tw-font-semibold tw-mb-2 tw-text-center'>Reset Password</h2>
|
||||
<input type="email" placeholder="E-Mail" value={email} onChange={e => setEmail(e.target.value)} className="tw-input tw-input-bordered tw-w-full tw-max-w-xs" />
|
||||
<div className="tw-card-actions tw-mt-4">
|
||||
<button className={loading ? 'tw-btn tw-btn-disabled tw-btn-block tw-btn-primary' : 'tw-btn tw-btn-primary tw-btn-block'} onClick={() => onReset()}>{loading ? <span className="tw-loading tw-loading-spinner"></span> : 'Send'}</button>
|
||||
</div>
|
||||
</MapOverlayPage>
|
||||
)
|
||||
}
|
||||
|
||||
50
src/Components/Auth/SetNewPasswordPage.tsx
Normal file
50
src/Components/Auth/SetNewPasswordPage.tsx
Normal file
@ -0,0 +1,50 @@
|
||||
import { useRef, useState } from 'react'
|
||||
import { Link, useNavigate } from 'react-router-dom'
|
||||
import ErrorText from '../Typography/ErrorText'
|
||||
import { TextInput } from '../Input/TextInput'
|
||||
import * as React from 'react'
|
||||
import { toast } from 'react-toastify'
|
||||
import { useAuth } from './useAuth'
|
||||
import { MapOverlayPage} from '../Templates'
|
||||
|
||||
export function SetNewPasswordPage() {
|
||||
|
||||
const [password, setPassword] = useState<string>("");
|
||||
|
||||
const { passwordReset, loading } = useAuth();
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
const onReset = async () => {
|
||||
const token = window.location.search.split("token=")[1];
|
||||
console.log(token);
|
||||
|
||||
await toast.promise(
|
||||
passwordReset(token, password),
|
||||
{
|
||||
success: {
|
||||
render() {
|
||||
navigate(`/`);
|
||||
return `New password set`
|
||||
},
|
||||
},
|
||||
error: {
|
||||
render({ data }) {
|
||||
return `${data}`
|
||||
},
|
||||
},
|
||||
pending: 'setting password ...'
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<MapOverlayPage>
|
||||
<h2 className='tw-text-2xl tw-font-semibold tw-mb-2 tw-text-center'>Set new Password</h2>
|
||||
<input type="password" placeholder="Password" onChange={e => setPassword(e.target.value)} className="tw-input tw-input-bordered tw-w-full tw-max-w-xs" />
|
||||
<div className="tw-card-actions tw-mt-4">
|
||||
<button className={loading ? 'tw-btn tw-btn-disabled tw-btn-block tw-btn-primary' : 'tw-btn tw-btn-primary tw-btn-block'} onClick={() => onReset()}>{loading ? <span className="tw-loading tw-loading-spinner"></span> : 'Set'}</button>
|
||||
</div>
|
||||
</MapOverlayPage>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,63 +1,55 @@
|
||||
import { useState } from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { useRef, useState } from 'react'
|
||||
import { Link, useNavigate } from 'react-router-dom'
|
||||
import ErrorText from '../Typography/ErrorText'
|
||||
import {TextInput} from '../Input/TextInput'
|
||||
import { TextInput } from '../Input/TextInput'
|
||||
import * as React from 'react'
|
||||
import { toast } from 'react-toastify'
|
||||
import { useAuth } from './useAuth'
|
||||
import { MapOverlayPage } from '../Templates'
|
||||
|
||||
export function SignupPage() {
|
||||
|
||||
const INITIAL_REGISTER_OBJ = {
|
||||
name : "",
|
||||
password : "",
|
||||
emailId : ""
|
||||
const [email, setEmail] = useState<string>("");
|
||||
const [userName, setUserName] = useState<string>("");
|
||||
|
||||
const [password, setPassword] = useState<string>("");
|
||||
|
||||
const { register, loading } = useAuth();
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
const onRegister = async () => {
|
||||
await toast.promise(
|
||||
register({ email: email, password: password }, userName),
|
||||
{
|
||||
success: {
|
||||
render({ data }) {
|
||||
navigate(`/`);
|
||||
return `Hi ${data?.first_name}`
|
||||
},
|
||||
// other options
|
||||
icon: "✌️",
|
||||
},
|
||||
error: {
|
||||
render({ data }) {
|
||||
return `${data}`
|
||||
},
|
||||
},
|
||||
pending: 'creating new user ...'
|
||||
});
|
||||
}
|
||||
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [errorMessage, setErrorMessage] = useState("")
|
||||
const [registerObj, setRegisterObj] = useState(INITIAL_REGISTER_OBJ)
|
||||
|
||||
const submitForm = (e) =>{
|
||||
e.preventDefault()
|
||||
setErrorMessage("")
|
||||
|
||||
if(registerObj.name.trim() === "")return setErrorMessage("Name is required! (use any value)")
|
||||
if(registerObj.emailId.trim() === "")return setErrorMessage("Email Id is required! (use any value)")
|
||||
if(registerObj.password.trim() === "")return setErrorMessage("Password is required! (use any value)")
|
||||
else{
|
||||
setLoading(true)
|
||||
// Call API to check user credentials and save token in localstorage
|
||||
localStorage.setItem("token", "DumyTokenHere")
|
||||
setLoading(false)
|
||||
window.location.href = '/app/welcome'
|
||||
}
|
||||
}
|
||||
|
||||
const updateFormValue = (val: string) => {
|
||||
console.log(val)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="tw-flex-1 tw-bg-base-200 tw-flex tw-items-center">
|
||||
<div className="tw-card tw-mx-auto tw-w-full tw-max-w-md tw-shadow-xl">
|
||||
<div className="tw-grid md:tw-grid-cols-1 tw-grid-cols-1 tw-bg-base-100 tw-rounded-xl">
|
||||
<div className='tw-py-10 tw-px-10'>
|
||||
<h2 className='tw-text-2xl tw-font-semibold tw-mb-2 tw-text-center'>Sign Up</h2>
|
||||
<form onSubmit={(e) => submitForm(e)}>
|
||||
|
||||
<div className="mb-4">
|
||||
<TextInput defaultValue={registerObj.name} containerStyle="tw-mt-4" labelTitle="Name" updateFormValue={updateFormValue} />
|
||||
<TextInput defaultValue={registerObj.emailId} containerStyle="tw-mt-4" labelTitle="E-Mail" updateFormValue={updateFormValue} />
|
||||
<TextInput defaultValue={registerObj.password} type="password" containerStyle="tw-mt-4" labelTitle="Password" updateFormValue={updateFormValue} />
|
||||
</div>
|
||||
|
||||
<ErrorText styleClass="tw-mt-8">{errorMessage}</ErrorText>
|
||||
<button type="submit" className={"tw-btn tw-mt-2 tw-w-full tw-btn-primary" + (loading ? " tw-loading" : "")}>Register</button>
|
||||
|
||||
<div className='tw-text-center tw-mt-4'>Already have an account? <Link to="/login"><span className=" tw-inline-block hover:tw-text-primary hover:tw-underline hover:tw-cursor-pointer tw-transition tw-duration-200">Login</span></Link></div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<MapOverlayPage>
|
||||
<h2 className='tw-text-2xl tw-font-semibold tw-mb-2 tw-text-center'>Sign Up</h2>
|
||||
<input type="text" placeholder="Name" value={userName} onChange={e => setUserName(e.target.value)} className="tw-input tw-input-bordered tw-w-full tw-max-w-xs" />
|
||||
<input type="email" placeholder="E-Mail" value={email} onChange={e => setEmail(e.target.value)} className="tw-input tw-input-bordered tw-w-full tw-max-w-xs" />
|
||||
<input type="password" placeholder="Password" onChange={e => setPassword(e.target.value)} className="tw-input tw-input-bordered tw-w-full tw-max-w-xs" />
|
||||
<div className="tw-card-actions tw-mt-4">
|
||||
<button className={loading ? 'tw-btn tw-btn-disabled tw-btn-block tw-btn-primary' : 'tw-btn tw-btn-primary tw-btn-block'} onClick={() => onRegister()}>{loading ? <span className="tw-loading tw-loading-spinner"></span> : 'Sign Up'}</button>
|
||||
</div>
|
||||
</div>
|
||||
</MapOverlayPage>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
export {AuthProvider, useAuth} from "./useAuth"
|
||||
export {LoginPage} from "./LoginPage"
|
||||
export {SignupPage} from "./SignupPage"
|
||||
export {SignupPage} from './SignupPage'
|
||||
export {RequestPasswordPage} from './RequestPasswordPage'
|
||||
export {SetNewPasswordPage} from './SetNewPasswordPage'
|
||||
@ -24,7 +24,9 @@ type AuthContextProps = {
|
||||
loading: Boolean,
|
||||
logout: () => Promise<any>,
|
||||
updateUser: (user: UserItem) => any,
|
||||
token: String | null
|
||||
token: String | null,
|
||||
requestPasswordReset: (email:string, reset_url: string) => Promise<any>,
|
||||
passwordReset: (token:string, new_password:string) => Promise<any>
|
||||
}
|
||||
|
||||
const AuthContext = createContext<AuthContextProps>({
|
||||
@ -35,7 +37,9 @@ const AuthContext = createContext<AuthContextProps>({
|
||||
loading: false,
|
||||
logout: () => Promise.reject(),
|
||||
updateUser: () => Promise.reject(),
|
||||
token: ""
|
||||
token: "",
|
||||
requestPasswordReset: () => Promise.reject(),
|
||||
passwordReset: () => Promise.reject()
|
||||
});
|
||||
|
||||
export const AuthProvider = ({ userApi, children }: AuthProviderProps) => {
|
||||
@ -118,10 +122,34 @@ export const AuthProvider = ({ userApi, children }: AuthProviderProps) => {
|
||||
};
|
||||
}
|
||||
|
||||
const requestPasswordReset = async (email: string, reset_url?: string): Promise<any> => {
|
||||
setLoading(true);
|
||||
try {
|
||||
await userApi.requestPasswordReset(email, reset_url);
|
||||
return setLoading(false);
|
||||
} catch (error: any) {
|
||||
setLoading(false);
|
||||
throw error;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
const passwordReset = async (token: string, new_password:string): Promise<any> => {
|
||||
setLoading(true);
|
||||
try {
|
||||
await userApi.passwordReset(token, new_password);
|
||||
return setLoading(false);
|
||||
} catch (error: any) {
|
||||
setLoading(false);
|
||||
throw error;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<AuthContext.Provider
|
||||
value={{ isAuthenticated, user, login, register, loading, logout, updateUser, token }}
|
||||
value={{ isAuthenticated, user, login, register, loading, logout, updateUser, token, requestPasswordReset, passwordReset }}
|
||||
>
|
||||
{children}
|
||||
</AuthContext.Provider>
|
||||
|
||||
@ -18,6 +18,7 @@ import { LeafletRefsProvider } from "./hooks/useLeafletRefs";
|
||||
import { LayerControl } from "./Subcomponents/LayerControl";
|
||||
import { QuestControl } from "./Subcomponents/QuestControl";
|
||||
import { Control } from "./Subcomponents/Control";
|
||||
import { Outlet } from "react-router-dom";
|
||||
|
||||
|
||||
export interface MapEventListenerProps {
|
||||
@ -71,6 +72,7 @@ function UtopiaMap({
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<LayersProvider initialLayers={[]}>
|
||||
<TagsProvider initialTags={[]}>
|
||||
<PermissionsProvider initialPermissions={[]}>
|
||||
@ -114,6 +116,8 @@ function UtopiaMap({
|
||||
</PermissionsProvider>
|
||||
</TagsProvider>
|
||||
</LayersProvider>
|
||||
<Outlet></Outlet>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@ import { HexColorPicker } from "react-colorful";
|
||||
import "./ColorPicker.css"
|
||||
import useClickOutside from "./useClickOutside";
|
||||
|
||||
export const ColorPicker = ({ color, onChange, className }) => {
|
||||
export const ColorPicker = ({ color = "#000", onChange, className }) => {
|
||||
const popover = useRef<HTMLDivElement>(null);
|
||||
const [isOpen, toggle] = useState(false);
|
||||
|
||||
|
||||
@ -158,8 +158,8 @@ export function ProfileSettings() {
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<main className="tw-flex-1 tw-overflow-y-auto tw-overflow-x-hidden tw-pt-8 tw-px-6 tw-bg-base-200 tw-min-w-80 tw-flex tw-justify-center" >
|
||||
<div className='tw-backdrop-contrast-50 tw-h-full tw-w-full'>
|
||||
<main className="tw-flex-1 tw-overflow-y-auto tw-overflow-x-hidden tw-pt-8 tw-px-6 tw-min-w-80 tw-flex tw-justify-center" >
|
||||
<div className='tw-w-full xl:tw-max-w-6xl'>
|
||||
<TitleCard title="Profile" topMargin="tw-mt-2" className='tw-mb-6'>
|
||||
<div className="tw-flex">
|
||||
@ -219,6 +219,6 @@ export function ProfileSettings() {
|
||||
renderCrop();
|
||||
}}>Select</button>
|
||||
</DialogModal>
|
||||
</>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
30
src/Components/Templates/MapOverlayPage.tsx
Normal file
30
src/Components/Templates/MapOverlayPage.tsx
Normal file
@ -0,0 +1,30 @@
|
||||
|
||||
import * as React from 'react'
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
export function MapOverlayPage({children} : {children: React.ReactNode}) {
|
||||
|
||||
|
||||
const closeScreen = () => {
|
||||
navigate(`/`);
|
||||
}
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
|
||||
return (
|
||||
<div className="tw-absolute tw-z-1000 tw-h-full tw-w-full tw-m-auto">
|
||||
|
||||
<div className='tw-backdrop-brightness-75 tw-h-full tw-w-full tw-grid tw-place-items-center tw-m-auto'
|
||||
>
|
||||
<div className='tw-card tw-shadow-xl tw-bg-base-100 tw-p-4 tw-max-w-xs tw-absolute tw-top-0 tw-bottom-0 tw-right-0 tw-left-0 tw-m-auto tw-h-fit '>
|
||||
<div className="tw-card-body tw-p-2">
|
||||
{children}
|
||||
<button className="tw-btn tw-btn-sm tw-btn-circle tw-btn-ghost tw-absolute tw-right-2 tw-top-2" onClick={() => closeScreen()}>✕</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,2 +1,3 @@
|
||||
export {CardPage} from './CardPage'
|
||||
export {TitleCard} from './TitleCard'
|
||||
export {MapOverlayPage} from './MapOverlayPage'
|
||||
@ -1,6 +1,6 @@
|
||||
export { UtopiaMap, Layer, Tags, Permissions, ItemForm, ItemView, PopupTextAreaInput, PopupStartEndInput, PopupTextInput, PopupButton, TextView, StartEndView } from './Components/Map';
|
||||
export {AppShell, Content, SideBar} from "./Components/AppShell"
|
||||
export {AuthProvider, useAuth, LoginPage, SignupPage} from "./Components/Auth"
|
||||
export {AuthProvider, useAuth, LoginPage, SignupPage, RequestPasswordPage, SetNewPasswordPage} from "./Components/Auth"
|
||||
export {UserSettings, ProfileSettings} from './Components/Profile'
|
||||
export {Quests, Modal} from './Components/Gaming'
|
||||
export {TitleCard, CardPage} from './Components/Templates'
|
||||
|
||||
@ -87,7 +87,9 @@ export interface UserApi {
|
||||
logout(): Promise<void>,
|
||||
getUser(): Promise<UserItem>,
|
||||
getToken(): Promise<any>,
|
||||
updateUser(user: UserItem): Promise<void>
|
||||
updateUser(user: UserItem): Promise<void>,
|
||||
requestPasswordReset(email:string, reset_url?:string),
|
||||
passwordReset(token:string,new_password:string)
|
||||
}
|
||||
|
||||
export type UserItem = {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user