added page template and basic registration

This commit is contained in:
Anton 2023-08-06 17:09:09 +02:00
parent b7d46473ce
commit 3c276c8fdf
11 changed files with 107 additions and 32 deletions

8
package-lock.json generated
View File

@ -10,7 +10,7 @@
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@heroicons/react": "^2.0.17", "@heroicons/react": "^2.0.17",
"leaflet": "^1.9.3", "leaflet": "^1.9.4",
"react-leaflet": "^4.2.1", "react-leaflet": "^4.2.1",
"react-leaflet-cluster": "^2.1.0", "react-leaflet-cluster": "^2.1.0",
"react-router-dom": "^6.11.2", "react-router-dom": "^6.11.2",
@ -2523,9 +2523,9 @@
} }
}, },
"node_modules/leaflet": { "node_modules/leaflet": {
"version": "1.9.3", "version": "1.9.4",
"resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.3.tgz", "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz",
"integrity": "sha512-iB2cR9vAkDOu5l3HAay2obcUHZ7xwUBBjph8+PGtmW/2lYhbLizWtG7nTeYht36WfOslixQF9D/uSIzhZgGMfQ==" "integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA=="
}, },
"node_modules/leaflet.markercluster": { "node_modules/leaflet.markercluster": {
"version": "1.5.3", "version": "1.5.3",

View File

@ -43,7 +43,7 @@
}, },
"dependencies": { "dependencies": {
"@heroicons/react": "^2.0.17", "@heroicons/react": "^2.0.17",
"leaflet": "^1.9.3", "leaflet": "^1.9.4",
"react-leaflet": "^4.2.1", "react-leaflet": "^4.2.1",
"react-leaflet-cluster": "^2.1.0", "react-leaflet-cluster": "^2.1.0",
"react-router-dom": "^6.11.2", "react-router-dom": "^6.11.2",

View File

@ -3,7 +3,7 @@ import NavBar from './NavBar'
import { BrowserRouter } from 'react-router-dom' import { BrowserRouter } from 'react-router-dom'
import { ToastContainer } from 'react-toastify' import { ToastContainer } from 'react-toastify'
export function AppShell({ name, useAuth, children }) { export function AppShell({ appName, useAuth, children }) {
return ( return (
<BrowserRouter> <BrowserRouter>
<ToastContainer position="top-right" <ToastContainer position="top-right"
@ -16,7 +16,7 @@ export function AppShell({ name, useAuth, children }) {
draggable draggable
pauseOnHover pauseOnHover
theme="light" /> theme="light" />
<NavBar name={name} useAuth={useAuth}></NavBar> <NavBar appName={appName} useAuth={useAuth}></NavBar>
<div id="app-content" className="tw-flex tw-!pl-[77px]"> <div id="app-content" className="tw-flex tw-!pl-[77px]">
{children} {children}
</div> </div>

View File

@ -5,12 +5,28 @@ import { toast } from "react-toastify";
import QuestionMarkIcon from '@heroicons/react/24/outline/QuestionMarkCircleIcon' import QuestionMarkIcon from '@heroicons/react/24/outline/QuestionMarkCircleIcon'
import * as React from "react"; import * as React from "react";
export default function NavBar({name, useAuth} : {name: string, useAuth : any}) { export default function NavBar({appName, useAuth} : {appName: string, useAuth : any}) {
const [email, setEmail] = useState<string>(""); const [email, setEmail] = useState<string>("");
const [userName, setUserName] = useState<string>("");
const [password, setPassword] = useState<string>(""); const [password, setPassword] = useState<string>("");
const { isAuthenticated, user, login, loading, logout, token } = useAuth(); const { isAuthenticated, user, login, register, loading, logout, token } = useAuth();
const onRegister = () => {
toast.promise(
register({ email: email, password: password}, userName),
{
success: {
render({data}){
return `Hi ${data?.first_name}`
},
// other options
icon: "✌️",
},
error: 'Error'
});
}
const onLogin = () => { const onLogin = () => {
toast.promise( toast.promise(
@ -39,7 +55,7 @@ export default function NavBar({name, useAuth} : {name: string, useAuth : any})
</button> </button>
<div className="tw-flex-1 tw-mr-2"> <div className="tw-flex-1 tw-mr-2">
<div className="tw-flex-1 tw-truncate tw-grid tw-grid-flow-col tw-max-w-52"> <div className="tw-flex-1 tw-truncate tw-grid tw-grid-flow-col tw-max-w-52">
<Link className="tw-btn tw-btn-ghost tw-px-2 tw-normal-case tw-text-xl tw-flex-1 tw-truncate" to={"/"}><p className="tw-truncate">{name}</p></Link> <Link className="tw-btn tw-btn-ghost tw-px-2 tw-normal-case tw-text-xl tw-flex-1 tw-truncate" to={"/"}><p className="tw-truncate">{appName}</p></Link>
<button className="tw-btn tw-px-2 tw-btn-ghost" onClick={() => window.my_modal_3.showModal()}><QuestionMarkIcon className="tw-h-5 tw-w-5"/></button> <button className="tw-btn tw-px-2 tw-btn-ghost" onClick={() => window.my_modal_3.showModal()}><QuestionMarkIcon className="tw-h-5 tw-w-5"/></button>
</div> </div>
@ -49,11 +65,11 @@ export default function NavBar({name, useAuth} : {name: string, useAuth : any})
{isAuthenticated && token ? {isAuthenticated && token ?
<div className="tw-flex-none"> <div className="tw-flex-none">
<div className="tw-avatar"> {user.avatar ? <div className="tw-avatar">
<div className="tw-w-10 tw-rounded-full"> <div className="tw-w-10 tw-rounded-full">
<img src={"https://map.api.free-planet-earth.org/assets/"+user?.avatar+"?access_token="+token} /> <img src={"https://map.api.free-planet-earth.org/assets/"+user?.avatar+"?access_token="+token} />
</div> </div>
</div> </div> : <></>}
<div className='tw-ml-2 tw-mr-2'>{user?.first_name}</div> <div className='tw-ml-2 tw-mr-2'>{user?.first_name}</div>
<div className="tw-dropdown tw-dropdown-end"> <div className="tw-dropdown tw-dropdown-end">
<label tabIndex={0} className="tw-btn tw-btn-ghost tw-btn-square"> <label tabIndex={0} className="tw-btn tw-btn-ghost tw-btn-square">
@ -68,16 +84,33 @@ export default function NavBar({name, useAuth} : {name: string, useAuth : any})
</div> </div>
</div> </div>
: :
<div className="tw-dropdown tw-dropdown-end tw-mr-2"> <div>
<label tabIndex={0} className="tw-btn tw-btn-ghost"> <div className="tw-dropdown tw-dropdown-end tw-mr-2">
Login <label tabIndex={0} className="tw-btn tw-btn-ghost">
</label> Login
<div tabIndex={0} className="tw-mt-3 tw-card tw-card-compact tw-dropdown-content tw-w-72 tw-bg-base-100 tw-shadow !tw-z-[1000]"> </label>
<div className="tw-card-body"> <div tabIndex={0} className="tw-mt-3 tw-card tw-card-compact tw-dropdown-content tw-w-72 tw-bg-base-100 tw-shadow !tw-z-[1000]">
<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-body">
<input type="password" placeholder="Password" onChange={e => setPassword(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" />
<div className="tw-card-actions"> <input type="password" placeholder="Password" onChange={e => setPassword(e.target.value)} className="tw-input tw-input-bordered tw-w-full tw-max-w-xs" />
<button className={loading ? 'tw-btn tw-loading tw-btn-disabled tw-btn-block tw-btn-primary' : 'tw-btn tw-btn-primary tw-btn-block'} onClick={() => onLogin()}>Login</button> <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>
</div>
<div className="tw-dropdown tw-dropdown-end tw-mr-2">
<label tabIndex={0} className="tw-btn tw-btn-ghost">
Sign Up
</label>
<div tabIndex={0} className="tw-mt-3 tw-card tw-card-compact tw-dropdown-content tw-w-72 tw-bg-base-100 tw-shadow !tw-z-[1000]">
<div className="tw-card-body">
<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>
</div> </div>
</div> </div>
</div> </div>

View File

@ -28,6 +28,7 @@ type AuthContextProps = {
isAuthenticated: Boolean, isAuthenticated: Boolean,
user: MyUserItem | null; user: MyUserItem | null;
login: (credentials: AuthCredentials) => Promise<MyUserItem | undefined>, login: (credentials: AuthCredentials) => Promise<MyUserItem | undefined>,
register: (credentials: AuthCredentials, userName: string) => Promise<MyUserItem | undefined>,
loading: Boolean, loading: Boolean,
logout: () => void, logout: () => void,
updateUser: (user: MyUserItem) => any, updateUser: (user: MyUserItem) => any,
@ -38,6 +39,7 @@ const AuthContext = createContext<AuthContextProps>({
isAuthenticated: false, isAuthenticated: false,
user: null, user: null,
login: () => Promise.reject(), login: () => Promise.reject(),
register: () => Promise.reject(),
loading: false, loading: false,
logout: () => { }, logout: () => { },
updateUser: () => Promise.reject(), updateUser: () => Promise.reject(),
@ -87,6 +89,18 @@ export const AuthProviderDirectus = ({ directus, children }: AuthProviderProps)
}; };
} }
const register = async (credentials: AuthCredentials, userName): Promise<MyUserItem | undefined> => {
setLoading(true);
try {
const res = await directus.users.createOne({email: credentials.email, password: credentials.password, first_name: userName});
return (await login(credentials));
} catch (error: any) {
setLoading(false);
console.log(error);
return error.response.data.error[0];
};
}
const logout = async () => { const logout = async () => {
@ -96,9 +110,10 @@ export const AuthProviderDirectus = ({ directus, children }: AuthProviderProps)
const updateUser = async (user: MyUserItem) => { const updateUser = async (user: MyUserItem) => {
setLoading(true); setLoading(true);
const { id, ...userRest } = user;
try { try {
const res = await directus.users.updateOne(user.id!, user) const res = await directus.users.updateOne(user.id!, userRest)
setUser(res as any); setUser(res as any);
setLoading(false); setLoading(false);
return res as any; return res as any;
@ -115,7 +130,7 @@ export const AuthProviderDirectus = ({ directus, children }: AuthProviderProps)
return ( return (
<AuthContext.Provider <AuthContext.Provider
value={{ isAuthenticated, user, login, loading, logout, updateUser, token }} value={{ isAuthenticated, user, login, register, loading, logout, updateUser, token }}
> >
{children} {children}
</AuthContext.Provider> </AuthContext.Provider>

View File

@ -39,7 +39,6 @@ function MapEventListener(props: MapEventListenerProps) {
// for refreshing map on resize (needs to be implemented) // for refreshing map on resize (needs to be implemented)
const mapDivRef = React.createRef(); const mapDivRef = React.createRef();
/** This is a description of the foo function. */
function UtopiaMap({ function UtopiaMap({
height = "500px", height = "500px",
width = "100%", width = "100%",

View File

@ -1,5 +1,5 @@
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import TitleCard from '../TitleCard' import {TitleCard} from '../Templates/TitleCard'
import InputText from '../Input/InputText' import InputText from '../Input/InputText'
import TextAreaInput from '../Input/TextAreaInput' import TextAreaInput from '../Input/TextAreaInput'
import { toast } from 'react-toastify'; import { toast } from 'react-toastify';

View File

@ -0,0 +1,27 @@
import { Link } from "react-router-dom"
import * as React from "react"
import {TitleCard} from "./TitleCard"
export function CardPage({title,children} : {
title: string,
children?: React.ReactNode,
}) {
return (
<main className="tw-flex-1 tw-overflow-y-auto tw-overflow-x-hidden tw-pt-2 tw-px-6 tw-bg-base-200 tw-min-w-80 tw-flex tw-justify-center" >
<div className='tw-w-full xl:tw-max-w-6xl'>
<div className="tw-text-sm tw-breadcrumbs">
<ul>
<li><Link to={'/'} >Home</Link></li>
<li>FAQ</li>
</ul>
</div>
<TitleCard title={title} topMargin="mt-2">
{children}
</TitleCard>
</div>
</main>
)
}

View File

@ -1,4 +1,4 @@
import Subtitle from "./Typography/Subtitle" import Subtitle from "../Typography/Subtitle"
import * as React from "react" import * as React from "react"
interface TitleCardProps { interface TitleCardProps {
@ -9,7 +9,7 @@ interface TitleCardProps {
TopSideButtons?: any TopSideButtons?: any
} }
function TitleCard({title, children, topMargin, TopSideButtons} : TitleCardProps){ export function TitleCard({title, children, topMargin, TopSideButtons} : TitleCardProps){
return( return(
<div className={"tw-card tw-w-full tw-p-6 tw-mb-16 tw-bg-base-100 tw-shadow-xl tw-h-fit " + (topMargin || "tw-mt-6")}> <div className={"tw-card tw-w-full tw-p-6 tw-mb-16 tw-bg-base-100 tw-shadow-xl tw-h-fit " + (topMargin || "tw-mt-6")}>
@ -33,6 +33,3 @@ interface TitleCardProps {
) )
} }
export default TitleCard

View File

@ -0,0 +1,2 @@
export {CardPage} from './CardPage'
export {TitleCard} from './TitleCard'

View File

@ -3,6 +3,8 @@ export {AppShell, Content, SideBar} from "./Components/AppShell"
export {AuthProviderDirectus, useAuthDirectus} from "./Components/Auth" export {AuthProviderDirectus, useAuthDirectus} from "./Components/Auth"
export {Settings} from './Components/Profile' export {Settings} from './Components/Profile'
export {Quests, Modal} from './Components/Gaming' export {Quests, Modal} from './Components/Gaming'
export {TitleCard, CardPage} from './Components/Templates'
import "./index.css" import "./index.css"
declare global { declare global {