diff options
-rw-r--r-- | components/toast.tsx | 77 | ||||
-rw-r--r-- | pages/_app.tsx | 5 | ||||
-rw-r--r-- | pages/user.tsx | 25 |
3 files changed, 71 insertions, 36 deletions
diff --git a/components/toast.tsx b/components/toast.tsx index 03a6255..5bfc0ae 100644 --- a/components/toast.tsx +++ b/components/toast.tsx @@ -1,10 +1,11 @@ -import { CSSProperties, ReactNode, Component } from "react"; +import { CSSProperties, ReactNode, useState, createContext } from "react"; import CloseIcon from '@material-ui/icons/Close'; -export function ToastArea(props: { +function ToastArea(props: { style?: CSSProperties children?: ReactNode + rerender?: boolean; }) { return <div id="ToastArea" style={{ position: "fixed", @@ -20,35 +21,32 @@ export function ToastArea(props: { }}>{props.children}</div> } -export class Toast extends Component<{ +function Toast(props: { text?: string icon?: ReactNode children?: ReactNode type?: "normal"|"confirmation"|"error" style?: CSSProperties -}> { - state = { render: true } +}) { + var [visible, setVisibility] = useState(true); - close = () => this.setState({ render: false }) + setTimeout(() => setVisibility(false), 10e3); - render () { - if (!this.state.render) return null; - return <div style={{ - padding: 0, - marginBottom: 12, - borderRadius: 8, - boxShadow: "0 8px 12px -4px #00000033", - color: - this.props.type === "confirmation" ? "var(--background)" : "var(--text)", - backgroundColor: - this.props.type === "normal" ? "var(--background)" : - this.props.type === "confirmation" ? "var(--disk-b)" : - this.props.type === "error" ? "var(--disk-a)" : "var(--background)", - ...this.props.style - }}> + return visible && <div style={{ + padding: 0, + marginBottom: 12, + borderRadius: 8, + boxShadow: "0 8px 12px -4px #00000033", + color: + props.type === "confirmation" ? "var(--background)" : "var(--text)", + backgroundColor: + props.type === "normal" ? "var(--background)" : + props.type === "confirmation" ? "var(--disk-b)" : + props.type === "error" ? "var(--disk-a)" : "var(--background)", + ...props.style + }}> { - this.props.children ? - this.props.children : + props.children || <div style={{ lineHeight: 0 }}> <div style={{ fontSize: 0, @@ -56,24 +54,45 @@ export class Toast extends Component<{ display: "inline-block", verticalAlign: "top", width: 32, height: 32 - }}>{this.props.icon}</div> + }}>{props.icon}</div> <h2 style={{ margin: "20px 0", display: "inline-block", width: "calc(100% - 128px)", verticalAlign: "top", - fontSize: 20 - }}>{this.props.text}</h2> + fontSize: 20, + userSelect: "none" + }}>{props.text}</h2> <div style={{ padding: 20, display: "inline-block", cursor: "pointer" - }} onClick={this.close}> + }} onClick={() => setVisibility(false)}> <CloseIcon/> </div> </div> } - </div> - } + </div> +} + +export var ToastContext = createContext<{ toast?: (message: string, + type: "confirmation"|"normal"|"error", + icon?: ReactNode ) => void }>({}); +var toasts: Array<JSX.Element> = []; + +export function ToastContextWrapper(props: { children?: ReactNode }) { + var [dummyState, rerender] = useState(false); + + return <ToastContext.Provider value={{ toast: (message: string, + type: "confirmation"|"normal"|"error", + icon?: ReactNode ) => { + toasts.push(<Toast type={type} text={message} icon={icon}/>); + rerender(!dummyState); + } }}> + { props.children } + <ToastArea rerender={dummyState}> + {toasts} + </ToastArea> + </ToastContext.Provider> } diff --git a/pages/_app.tsx b/pages/_app.tsx index 3c238b9..651d05d 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -1,5 +1,6 @@ import Head from 'next/head'; import { PreferencesContextWrapper } from '../components/preferencesContext'; +import { ToastContextWrapper } from '../components/toast'; import '../styles/global.css'; import '../styles/dark.css'; @@ -12,7 +13,9 @@ export default function VierOpEenRijWebsite({ Component, pageProps }) { <link rel="stylesheet" href="/font/stylesheet.css"/> </Head> <PreferencesContextWrapper> - <Component {...pageProps}/> + <ToastContextWrapper> + <Component {...pageProps}/> + </ToastContextWrapper> </PreferencesContextWrapper> </div> } diff --git a/pages/user.tsx b/pages/user.tsx index 71177d3..c7a78e6 100644 --- a/pages/user.tsx +++ b/pages/user.tsx @@ -1,4 +1,4 @@ -import { ReactNode, Children, useState, useEffect } from 'react'; +import { ReactNode, Children, useState, useEffect, useContext } from 'react'; import Icon from '@mdi/react'; import axios from 'axios'; @@ -8,6 +8,7 @@ import { Vierkant, IconLabelButton } from '../components/ui'; import { AccountAvatar } from '../components/account'; import { userInfo, userGames } from '../api/api'; import RecentGames from '../components/recentGames'; +import { ToastContext } from '../components/toast'; import PersonAddOutlinedIcon from '@material-ui/icons/PersonAddOutlined'; import AssignmentIndOutlinedIcon from '@material-ui/icons/AssignmentIndOutlined'; @@ -72,15 +73,19 @@ export default function AccountPage() { var [user, setUser] = useState<userInfo>(); var [ownPage, setOwnPage] = useState(false); var [gameInfo, setGameInfo] = useState<userGames>(); + var [loggedIn, setLoggedIn] = useState(false); var [editingStatus, setEditingStatus] = useState(false); + var { toast } = useContext(ToastContext); + useEffect(() => {(async() => { if (gotData) return; if (typeof window === "undefined") return; var id = new URLSearchParams(window.location.search).get("id"); var loggedIn = document.cookie.includes("token"); + setLoggedIn(loggedIn); if (id || loggedIn) { var self_id = ""; @@ -137,7 +142,7 @@ export default function AccountPage() { <p id="status" contentEditable={editingStatus ? "true" : "false"} style={{ marginTop: 6, transitionDuration: ".3s" - }}>{user?.status}</p> + }} suppressContentEditableWarning={true}>{user?.status}</p> </div> <div style={{ position: "absolute", @@ -145,7 +150,7 @@ export default function AccountPage() { height: "40px", bottom: 24, left: 24 + 12 + 128, right: 24 }}> - { + { loggedIn && <div> { ownPage ? <div> <IconLabelButton icon={<SettingsOutlinedIcon/>} href="/settings" text="Instellingen"/> @@ -170,10 +175,18 @@ export default function AccountPage() { } </div> : <div> - <IconLabelButton icon={<Icon size={1} path={mdiAccountCancelOutline}/>} text="Blokkeren"/> - <IconLabelButton icon={<PersonAddOutlinedIcon/>} text="Vriendschapsverzoek"/> + <IconLabelButton icon={<Icon size={1} path={mdiAccountCancelOutline}/>} text="Blokkeren" onclick={() => { + toast(`${user.username} geblokkeerd`, + "confirmation", + <Icon size={32 / 24} path={mdiAccountCancelOutline}/>) + }}/> + <IconLabelButton icon={<PersonAddOutlinedIcon/>} text="Vriendschapsverzoek" onclick={() => { + toast("Vriendschapsverzoek gestuurd", + "confirmation", + <PersonAddOutlinedIcon style={{ fontSize: 32 }}/>) + }}/> </div> - } + }</div>} </div> </Vierkant> <InfoSection> |