From c8eaf0fb54e0241928283ab944f4f0c6168e2982 Mon Sep 17 00:00:00 2001 From: grimsi <9295182+grimsi@users.noreply.github.com> Date: Fri, 27 Sep 2024 11:04:13 +0200 Subject: [PATCH] =?UTF-8?q?Implement=20=F0=9F=A5=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 56 ++++++++++++++++++++++++++ package.json | 6 ++- src/main/frontend/views/LoginView.tsx | 12 ++---- src/main/frontend/views/MainLayout.tsx | 51 +++++++++++++++++------ 4 files changed, 102 insertions(+), 23 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3be4431..440422c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,6 +44,7 @@ "moment-timezone": "^0.5.45", "next-themes": "^0.3.0", "react": "18.3.1", + "react-confetti-boom": "^1.0.0", "react-dom": "18.3.1", "react-router-dom": "6.26.1", "sonner": "^1.5.0", @@ -1959,6 +1960,25 @@ "node": ">=6.9.0" } }, + "node_modules/@emotion/is-prop-valid": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.7.3.tgz", + "integrity": "sha512-uxJqm/sqwXw3YPA5GXX365OBcJGFtxUVkB6WyezqFHlNe9jqUWH5ur2O2M8dGBz61kn1g3ZBlzUunFQXQIClhA==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@emotion/memoize": "0.7.1" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.1.tgz", + "integrity": "sha512-Qv4LTqO11jepd5Qmlp3M1YEjBumoTHcHFdgPTQ+sFlIL5myi/7xu/POwP7IRu6odBdmLXdtIs1D6TuW6kbwbbg==", + "license": "MIT", + "optional": true, + "peer": true + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", @@ -12213,6 +12233,19 @@ "node": ">=0.10.0" } }, + "node_modules/react-confetti-boom": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/react-confetti-boom/-/react-confetti-boom-1.0.0.tgz", + "integrity": "sha512-JPCs1tx36xduFdMORaRLLvFJABAQUgjEqKvqZiBZr8bUkHsCzbHeesnfQwZU1LExmGiYVFGIJS/tiR4OUTktww==", + "license": "MIT", + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, "node_modules/react-dom": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", @@ -16299,6 +16332,23 @@ "to-fast-properties": "^2.0.0" } }, + "@emotion/is-prop-valid": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.7.3.tgz", + "integrity": "sha512-uxJqm/sqwXw3YPA5GXX365OBcJGFtxUVkB6WyezqFHlNe9jqUWH5ur2O2M8dGBz61kn1g3ZBlzUunFQXQIClhA==", + "optional": true, + "peer": true, + "requires": { + "@emotion/memoize": "0.7.1" + } + }, + "@emotion/memoize": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.1.tgz", + "integrity": "sha512-Qv4LTqO11jepd5Qmlp3M1YEjBumoTHcHFdgPTQ+sFlIL5myi/7xu/POwP7IRu6odBdmLXdtIs1D6TuW6kbwbbg==", + "optional": true, + "peer": true + }, "@esbuild/aix-ppc64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", @@ -23397,6 +23447,12 @@ "loose-envify": "^1.1.0" } }, + "react-confetti-boom": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/react-confetti-boom/-/react-confetti-boom-1.0.0.tgz", + "integrity": "sha512-JPCs1tx36xduFdMORaRLLvFJABAQUgjEqKvqZiBZr8bUkHsCzbHeesnfQwZU1LExmGiYVFGIJS/tiR4OUTktww==", + "requires": {} + }, "react-dom": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", diff --git a/package.json b/package.json index 76c0825..0ddb4cb 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "moment-timezone": "^0.5.45", "next-themes": "^0.3.0", "react": "18.3.1", + "react-confetti-boom": "^1.0.0", "react-dom": "18.3.1", "react-router-dom": "6.26.1", "sonner": "^1.5.0", @@ -122,7 +123,8 @@ "@vaadin/vaadin-material-styles": "$@vaadin/vaadin-material-styles", "cron-validator": "$cron-validator", "moment": "$moment", - "moment-timezone": "$moment-timezone" + "moment-timezone": "$moment-timezone", + "react-confetti-boom": "$react-confetti-boom" }, "vaadin": { "dependencies": { @@ -181,6 +183,6 @@ "workbox-core": "7.1.0", "workbox-precaching": "7.1.0" }, - "hash": "9af3f915316df3b36e94b855108f7148a48217645c62f7b0e5a970f3030981b5" + "hash": "e5da4862f0edd6fde265ae72b8f5ec20ca6276687df8b437c1ebf9324053fb01" } } diff --git a/src/main/frontend/views/LoginView.tsx b/src/main/frontend/views/LoginView.tsx index 4258988..f7b372a 100644 --- a/src/main/frontend/views/LoginView.tsx +++ b/src/main/frontend/views/LoginView.tsx @@ -18,22 +18,18 @@ export default function LoginView() { const [url, setUrl] = useState(); const [signUpAllowed, setSignUpAllowed] = useState(false); - useEffect(() => { - RegistrationEndpoint.isSelfRegistrationAllowed().then(setSignUpAllowed); - }, []); - useEffect(() => { if (state.user) { const path = url ? new URL(url, document.baseURI).pathname : '/' navigate(path, {replace: true}); + } else { + RegistrationEndpoint.isSelfRegistrationAllowed().then(setSignUpAllowed); } }, [state.user]); async function tryLogin(values: any, formik: any) { - const {defaultUrl, error, redirectUrl} = await login(values.username, values.password); - if (!error) { - setUrl(redirectUrl ?? defaultUrl ?? '/'); - } else { + const {error} = await login(values.username, values.password); + if (error) { formik.setFieldError("username", " "); // Mark the field red, but don't show an error message formik.setFieldError("password", "Invalid username and/or password."); } diff --git a/src/main/frontend/views/MainLayout.tsx b/src/main/frontend/views/MainLayout.tsx index 64f2023..daf1173 100644 --- a/src/main/frontend/views/MainLayout.tsx +++ b/src/main/frontend/views/MainLayout.tsx @@ -1,24 +1,46 @@ import {useRouteMetadata} from 'Frontend/util/routing.js'; -import {useEffect} from 'react'; +import {useEffect, useState} from 'react'; import ProfileMenu from "Frontend/components/ProfileMenu"; import {Divider, Link, Navbar, NavbarBrand, NavbarContent, NavbarItem} from "@nextui-org/react"; import GameyfinLogo from "Frontend/components/theming/GameyfinLogo"; import * as PackageJson from "../../../../package.json"; import {Outlet, useNavigate} from "react-router-dom"; import {useAuth} from "Frontend/util/auth"; +import {Heart} from "@phosphor-icons/react"; +import Confetti, {ConfettiProps} from "react-confetti-boom"; export default function MainLayout() { const navigate = useNavigate(); const auth = useAuth(); const routeMetadata = useRouteMetadata(); + const [isExploding, setIsExploding] = useState(false); useEffect(() => { let newTitle = `Gameyfin - ${routeMetadata?.title}` ?? 'Gameyfin'; window.addEventListener('popstate', () => document.title = newTitle); }, []); + const confettiProps: ConfettiProps = { + mode: 'boom', + x: 0.5, + y: 1, + particleCount: 1000, + spreadDeg: 90, + launchSpeed: 4, + effectInterval: 10000 + } + + function easterEgg() { + if (isExploding) return; + setIsExploding(true); + if (confettiProps.mode === "boom") { + setTimeout(() => setIsExploding(false), confettiProps.effectInterval); + } + } + return (
+ {isExploding ? : <>}
navigate('/')}> @@ -44,17 +66,20 @@ export default function MainLayout() {
-
-

Gameyfin {PackageJson.version}

-

- © {(new Date()).getFullYear()}  - - Gameyfin contributors - -

-
+
+ +
); -} - -/**/ +} \ No newline at end of file