diff --git a/.env b/.env deleted file mode 100644 index 572274e..0000000 --- a/.env +++ /dev/null @@ -1 +0,0 @@ -NEXT_PUBLIC_NETWORK=testnet \ No newline at end of file diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..4d3c330 --- /dev/null +++ b/.env.example @@ -0,0 +1,2 @@ +NEXT_PUBLIC_NETWORK=NETWORK +NEXT_PUBLIC_AUTH_URL=AUTH_ENDPOINT \ No newline at end of file diff --git a/components/profile/menu-list.tsx b/components/profile/menu-list.tsx index 7798888..b4b2d2d 100644 --- a/components/profile/menu-list.tsx +++ b/components/profile/menu-list.tsx @@ -3,6 +3,9 @@ import { Div } from '@stylin.js/elements'; import { not } from 'ramda'; import { FC, useState } from 'react'; +import { MEMEZ_FUN_TOKEN_AUTH } from '@/constants'; +import { useCookie } from '@/hooks/use-cookie'; + import { DocIDSVG, ExplorerSVG, @@ -20,9 +23,22 @@ import RPCCollapseMenuInfo from './rpc-collapse-info'; const MenuList: FC = () => { const [isActiveNSFE, setIsActiveNSFE] = useState(false); const [isRPCMenuOpen, setIsRPCMenuOpen] = useState(false); + const { mutate: disconnectWallet } = useDisconnectWallet(); + const { cookie: bearerToken } = useCookie(MEMEZ_FUN_TOKEN_AUTH); const [isAccountMenuOpen, setIsAccountMenuOpen] = useState(false); const [isExplorerMenuOpen, setIsExplorerMenuOpen] = useState(false); - const { mutate: disconnectWallet } = useDisconnectWallet(); + + const handleDisconnectWallet = () => { + fetch(`${process.env.NEXT_PUBLIC_AUTH_URL}/sign-out`, { + method: 'DELETE', + mode: 'cors', + headers: { + Authorization: `Bearer ${bearerToken}`, + }, + }).then((res) => { + res.ok && disconnectWallet(); + }); + }; return (
@@ -58,7 +74,7 @@ const MenuList: FC = () => { Icon={LogoutSVG} title="Disconnect" color="#E85965" - onClick={() => disconnectWallet()} + onClick={handleDisconnectWallet} />
); diff --git a/constants/index.ts b/constants/index.ts index dadc0b8..4b589b5 100644 --- a/constants/index.ts +++ b/constants/index.ts @@ -3,3 +3,5 @@ export * from './math'; export * from './network'; export * from './routes'; export const DROPDOWN_DATA = ['Days', 'Weeks', 'Months']; + +export const MEMEZ_FUN_TOKEN_AUTH = 'MEMEZ_FUN_TOKEN_AUTH'; diff --git a/hooks/use-cookie/index.ts b/hooks/use-cookie/index.ts new file mode 100644 index 0000000..186f97a --- /dev/null +++ b/hooks/use-cookie/index.ts @@ -0,0 +1,34 @@ +import { useState } from 'react'; +const setCookie = (name: string, value: string, days: number) => { + const expires = new Date(); + expires.setTime(expires.getTime() + days * 24 * 60 * 60 * 1000); + document.cookie = `${name}=${value}; expires=${expires.toUTCString()}; path=/`; +}; + +const getCookie = (name: string): string | null => { + const value = `; ${document.cookie}`; + const parts = value.split(`; ${name}=`); + if (parts.length === 2) return parts.pop()?.split(';').shift() || null; + return null; +}; + +const deleteCookie = (name: string) => { + document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/`; +}; +export const useCookie = (name: string) => { + const [cookie, setCookieState] = useState(() => + getCookie(name) + ); + + const set = (value: string, days: number = 365) => { + setCookie(name, value, days); + setCookieState(value); + }; + + const remove = () => { + deleteCookie(name); + setCookieState(null); + }; + + return { cookie, set, remove } as const; +}; diff --git a/pages/_document.tsx b/pages/_document.tsx index 9a68613..1bbfe76 100644 --- a/pages/_document.tsx +++ b/pages/_document.tsx @@ -2,7 +2,12 @@ import { Head, Html, Main, NextScript } from 'next/document'; const Document = () => ( - + + +
diff --git a/views/sign-in/index.tsx b/views/sign-in/index.tsx index 80fc16f..7b2a4c6 100644 --- a/views/sign-in/index.tsx +++ b/views/sign-in/index.tsx @@ -43,8 +43,10 @@ const SignIn: FC = () => {

- - +
+ + +
{ - const { setValue, trigger } = useFormContext(); const { dialog, handleClose } = useDialog(); const handleOpenConnectModal = useConnectModal(); + const { mutate: disconnectWallet } = useDisconnectWallet(); + const { set: setCookie } = useCookie(MEMEZ_FUN_TOKEN_AUTH); + const { getValues, handleSubmit } = useFormContext(); + const { push } = useRouter(); - const handleCreateProfile = () => { - return new Promise((resolve, reject) => { - setTimeout(() => { - const isSuccess = Math.random() > 0.5; - if (isSuccess) { - setValue('success', true); - resolve('success'); - return; - } - reject('Error'); - }, 1000); - }); - }; + const scheduleTimeToDisconnect = () => { + const oneHour = 60 * 60 * 1000; + const disconnectTimer = setTimeout(() => { + disconnectWallet(); + push(RoutesEnum.SignIn); + }, oneHour); - const handleSignIn = async () => { - let fieldsToValidate: (keyof SignInFormProps)[] = []; + return disconnectTimer; + }; - fieldsToValidate = ['username', 'password']; - const isValid = await trigger(fieldsToValidate); + const onSignIn = async () => { + const { username, password } = getValues(); + const body = JSON.stringify({ + username, + password, + }); + return await fetch(`${process.env.NEXT_PUBLIC_AUTH_URL}/sign-in`, { + method: 'POST', + mode: 'cors', + headers: { + 'Content-Type': 'application/json', + }, + body, + }).then(async (res) => { + const response = await res.json(); + scheduleTimeToDisconnect(); + if (!res.ok) { + throw new Error(`${response.error}: ${response.message}`); + } + setCookie(response.accessToken); + return; + }); + }; - if (isValid) { - await dialog.promise(handleCreateProfile(), { - success: () => ({ - title: 'Sign-in successful', - button: ( - - ), - ghostButton: ( - - ), - message: 'Now connect your wallet do see all the function', - }), - loading: () => ({ - Icon: , - title: 'Signing...', - message: 'Please wait...', - }), - error: (e) => ({ - title: 'Oops! You can not sign in!', - button: { label: 'Try again', onClick: handleClose }, - message: ( - e.message || - 'Make sure you fill every field correctly and try again.' - ).replace('Invariant failed: ', ''), - ghostButton: { - label: 'Do not want to try again!', - onClick: handleClose, - }, - }), - }); - } - if (!isValid) return; + const handleSignIn = () => { + dialog.promise(onSignIn(), { + success: () => ({ + title: 'Sign-in successful', + button: ( + + ), + ghostButton: ( + + ), + message: 'Now connect your wallet do see all the function', + }), + loading: () => ({ + Icon: , + title: 'Signing...', + message: 'Please wait...', + }), + error: (e) => ({ + title: 'Oops! You can not sign in!', + button: { label: 'Try again', onClick: handleClose }, + message: ( + e.message || 'Make sure you fill every field correctly and try again.' + ).replace('Invariant failed: ', ''), + ghostButton: { + label: 'Do not want to try again!', + onClick: handleClose, + }, + }), + }); }; return ( -
+