diff --git a/package-lock.json b/package-lock.json index b104eca95bbacd854d18049262156edb95846ae2..6baf32a4c008f549fb4f97d0aa011409a3faf911 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-hot-toast": "^2.4.1", + "react-icons": "^4.12.0", "react-router-dom": "^6.17.0" }, "devDependencies": { @@ -4720,6 +4721,14 @@ "react-dom": ">=16" } }, + "node_modules/react-icons": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.12.0.tgz", + "integrity": "sha512-IBaDuHiShdZqmfc/TwHu6+d6k2ltNCf3AszxNmjJc1KUfXdEeRJOKyNvLmAHaarhzGmTSVygNdyu8/opXv2gaw==", + "peerDependencies": { + "react": "*" + } + }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", diff --git a/package.json b/package.json index 1dabecaf574bc951e0d61c8f7d8d8fe23c5b6944..6595acb7e2887c8e060376b8e1bdc254c9dd6f84 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-hot-toast": "^2.4.1", + "react-icons": "^4.12.0", "react-router-dom": "^6.17.0" }, "devDependencies": { diff --git a/src/App.tsx b/src/App.tsx index 5fc4fdce7b59378cd45c974e35fc9701c0609a94..f56c46b3ecd4f11e6982d327210c1a7791de6325 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -5,7 +5,7 @@ import SidebarLayout from "./components/layouts/SidebarLayout"; import ProfileLayout from "./components/layouts/ProfileLayout"; import HomePage from "./pages/home"; import QueuePage from "./pages/queue"; -import ProfilePage from "./pages/profile"; +import NotFoundPage from "./pages/not-found"; import axios from "axios"; export default function App(): JSX.Element { @@ -51,15 +51,14 @@ export default function App(): JSX.Element { element: <QueuePage />, loader: userQueueLoader, }, - { - path: "/profile", - element: <ProfilePage />, - - }, ], }, ], }, + { + path: "*", + element: <NotFoundPage />, + }, ]); return <RouterProvider router={router} />; diff --git a/src/components/layouts/ProfileLayout.tsx b/src/components/layouts/ProfileLayout.tsx index dfe6e1ed2d830fe3de24251c97f18289145bcab3..6f8c24af38ea8c2ca1b948640e69509c302730c6 100644 --- a/src/components/layouts/ProfileLayout.tsx +++ b/src/components/layouts/ProfileLayout.tsx @@ -2,12 +2,16 @@ import { Outlet } from "react-router-dom"; // Asset imports import SampleImage1 from "../../assets/escape.jpg"; +import ProfilePage from "../../pages/profile"; +import { useState} from "react"; export default function ProfileLayout(): JSX.Element { + const [isOpen, setIsOpen] = useState(false); + return ( <> <aside className="w-full mt-4 px-6 flex flex-row-reverse items-center gap-8 xl:gap-12 xl:mt-6 xl:px-8"> - <div className="rounded-full border-BLACK border"> + <button className="rounded-full border-BLACK border" onClick={() => setIsOpen(!isOpen)}> <img className="rounded-full w-[50px] h-[50px] object-cover object-center xl:w-[75px] xl:h-[75px]" src={SampleImage1} @@ -15,11 +19,12 @@ export default function ProfileLayout(): JSX.Element { height={75} alt="" /> - </div> + </button> <div className="bg-YELLOW-5 py-1 px-4 rounded-3xl xl:py-2 xl:px-6 xl:rounded-[32px]"> <p className="h5 md:max-xl:text-[10px]">Premium User</p> </div> </aside> + {isOpen ? <ProfilePage setIsOpen={setIsOpen} /> : <></>} <Outlet /> </> diff --git a/src/hooks/useSession.ts b/src/hooks/useSession.ts index 3122bc08783279f5fc9b7517551a971844448795..a1609fac14af0edbdc96649d51a72d3a0e922a52 100644 --- a/src/hooks/useSession.ts +++ b/src/hooks/useSession.ts @@ -11,7 +11,8 @@ export default function useSession() { useEffect(() => { (async () => { - const token = localStorage.getItem("token") || queryToken; + try { + const token = localStorage.getItem("token") || queryToken; if (!token) { setLoading(false); @@ -28,11 +29,16 @@ export default function useSession() { } ); - if (res.data.message !== "error") { + console.log("halo"); + if (res.data.message !== "user not subscribed" || res.data.message !== "invalid token") { setSessionValid(true); } setLoading(false); + } catch (err) { + setSessionValid(false); + setLoading(false); + } })(); }); diff --git a/src/pages/not-found/index.tsx b/src/pages/not-found/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..415230e603a73313e20e9e3ea0316425edb057c1 --- /dev/null +++ b/src/pages/not-found/index.tsx @@ -0,0 +1,8 @@ + +const NotFoundPage = () => { + return ( + <div className="flex items-center justify-center text-7xl bg-white text-blue font-bold">NOT FOUND WKWKWKWKWK</div> + ) +} + +export default NotFoundPage \ No newline at end of file diff --git a/src/pages/profile/index.tsx b/src/pages/profile/index.tsx index 378d2ed796e70bc038f501d9714d59cd5351af3a..1add77475a3395b62cc84a17ada051cece07fd73 100644 --- a/src/pages/profile/index.tsx +++ b/src/pages/profile/index.tsx @@ -1,12 +1,17 @@ import axios from "axios"; -import { useEffect, useState} from "react"; -// import toast from 'react-hot-toast'; +import { useEffect, useState, useRef} from "react"; +import toast, {Toaster} from 'react-hot-toast'; +import { IoClose } from "react-icons/io5"; -export default function ProfilePage(): JSX.Element { +const ProfilePage = ({setIsOpen}:{setIsOpen: (bool: boolean)=>void}) => { +// const ProfilePage = () => { const [name, setName] = useState<string>(""); const [username, setUsername] = useState<string>(""); - + const [message, setMessage] = useState<string>(""); + //useref + const profileBox = useRef<HTMLDivElement>(null); + const background = useRef<HTMLDivElement>(null); useEffect (() => { (async () => { const res = await axios.get( @@ -19,61 +24,66 @@ export default function ProfilePage(): JSX.Element { ); const res2 = res.data; - setName(res2.name); setUsername(res2.username); })(); }, []); const onHandleSubmit = () => { + toast.promise(( (async () => { - console.log(`Bearer ${localStorage.getItem("token")}`); - await axios.put( - `${import.meta.env.VITE_REST_URL}/profile`, + const res = await axios.put( + `${import.meta.env.VITE_REST_URL}/profile`, { + name: name, + username: username, + }, { headers: { Authorization: `Bearer ${localStorage.getItem("token")}`, - }, - body: { - name: name, - username: username, } } - ) - console.log('gilsss'); + ) + console.log(res.status); + setMessage(res.data.message); })() - - // toast.promise(( - - // ),{ - // loading: 'Saving...', - // success: <b>Profile updated successfully!</b>, - // error: <b>Could not save.</b>, - // }); + ),{ + loading: 'Saving...', + success: <b>{message}</b>, + error: <b>{message}</b>, + }); + if (message == "Profile updated successfully!") { + setIsOpen(false); + } } - return ( - <section className="flex h-full w-screen bg-black bg-opacity-40 z-10 top-0 right-0 items-center justify-center fixed "> - <div className="flex flex-col items-center w-fit h-fit px-7 py-8 border-2 shadow-xl bg-YELLOW-4 opacity-100 gap-5 rounded-xl border-white"> - <div className="flex flex-row p-12 items-center gap-14"> - <img - className="w-[200px] h-[200px] object-cover object-center rounded-full" - src={import.meta.env.VITE_PHP_STORAGE_URL} - alt="image" - /> - <ul className="flex flex-col text-black font-semibold gap-3"> - <li className=""> - <div className="">Nama</div> - <input className="border-0 rounded-lg font-thin" type="text" defaultValue={name}/> - </li> - <li> - <div className="sh5" >Username</div> - <input className="border-0 rounded-lg font-thin" type="text" defaultValue={username}/> - </li> - </ul> - </div> - <button className="bg-white rounded-full px-8 py-4 font-semibold" onClick={onHandleSubmit} disabled={username ? false : ( username.length>50 ? true : false)}>Save</button> - </div> - </section> - ); -} \ No newline at end of file + return ( + <section ref={background} className="flex h-full w-screen bg-black bg-opacity-40 z-10 top-0 right-0 items-center justify-center fixed" > + <Toaster /> + <div ref={profileBox} className="flex flex-col items-center w-fit h-fit px-7 py-8 border-2 shadow-xl bg-YELLOW-4 opacity-100 gap-1 rounded-xl border-white z-20" > + <button className="flex self-end" onClick={() => setIsOpen(false)}> + <IoClose size="30px"/> + </button> + <div className="flex flex-row p-12 items-center gap-14"> + <img + className="w-[200px] h-[200px] object-cover object-center rounded-full outline outline-white" + src={import.meta.env.VITE_PHP_STORAGE_URL} + alt="image" + /> + <ul className="flex flex-col text-black font-semibold gap-5"> + <li className=""> + <div className="">Nama</div> + <input className="border-0 rounded-lg font-thin" type="text" defaultValue={name} onChange={(e) => setName(e.target.value)}/> + </li> + <li> + <div className="sh5" >Username</div> + <input className="border-0 rounded-lg font-thin" type="text" defaultValue={username} onChange={(e) => setUsername(e.target.value)}/> + </li> + </ul> + </div> + <button className="bg-white rounded-full px-8 py-4 font-semibold" onClick={onHandleSubmit} disabled={username ? false : (username.length>50 ? true : false)}>Save</button> + </div> + </section> + ); +} + +export default ProfilePage; \ No newline at end of file