From c75567305a6c611d4a2a01266cca664f4266f6be Mon Sep 17 00:00:00 2001 From: Abul Hossain Date: Fri, 12 Aug 2022 23:41:11 +0600 Subject: [PATCH 1/3] feat: added shield for component --- components/ComponentShield.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 components/ComponentShield.js diff --git a/components/ComponentShield.js b/components/ComponentShield.js new file mode 100644 index 0000000..dc28209 --- /dev/null +++ b/components/ComponentShield.js @@ -0,0 +1,15 @@ +import React from 'react'; + +export function ComponentShield({ + RBAC, + showIf, + userRole, + children, + showForRole, + fallback = null, +}) { + if (RBAC) return <>{showForRole.includes(userRole) ? children : null}; + if (showIf) return <>{children}; + + return <>{fallback}; +} From 554c8cb8820833ff91b3ee48d65b3462c931e4e6 Mon Sep 17 00:00:00 2001 From: Abul Hossain Date: Sat, 13 Aug 2022 02:05:18 +0600 Subject: [PATCH 2/3] rename consts folder to constants --- constants/HTTP.js | 7 +++++++ modules/bookmark/bookmark.service.js | 2 +- pages/api/bookmarks/[id]/index.js | 2 +- pages/api/bookmarks/create.js | 2 +- 4 files changed, 10 insertions(+), 3 deletions(-) create mode 100644 constants/HTTP.js diff --git a/constants/HTTP.js b/constants/HTTP.js new file mode 100644 index 0000000..4361f40 --- /dev/null +++ b/constants/HTTP.js @@ -0,0 +1,7 @@ +export const httpMethodEnums = { + GET: 'GET', + PUT: 'PUT', + POST: 'POST', + PATCH: 'PATCH', + DELETE: 'DELETE', +}; diff --git a/modules/bookmark/bookmark.service.js b/modules/bookmark/bookmark.service.js index 271e325..3876a91 100644 --- a/modules/bookmark/bookmark.service.js +++ b/modules/bookmark/bookmark.service.js @@ -1,4 +1,4 @@ -import { httpMethodEnums } from '../../consts/HTTP'; +import { httpMethodEnums } from '../../constants/HTTP'; export const getBookmarkById = async ({ queryKey }) => { console.log({ queryKey }); diff --git a/pages/api/bookmarks/[id]/index.js b/pages/api/bookmarks/[id]/index.js index e2b670f..214bf2e 100644 --- a/pages/api/bookmarks/[id]/index.js +++ b/pages/api/bookmarks/[id]/index.js @@ -4,7 +4,7 @@ import { UpdateCommand, } from '@aws-sdk/lib-dynamodb'; -import { httpMethodEnums } from '../../../../consts/HTTP'; +import { httpMethodEnums } from '../../../../constants/HTTP'; import { ddbDocClient } from '../../../../libs/ddbDocClient'; const { TABLE_NAME } = process.env; diff --git a/pages/api/bookmarks/create.js b/pages/api/bookmarks/create.js index ef7a34d..4065021 100644 --- a/pages/api/bookmarks/create.js +++ b/pages/api/bookmarks/create.js @@ -1,7 +1,7 @@ import { nanoid } from 'nanoid'; import { PutCommand } from '@aws-sdk/lib-dynamodb'; -import { httpMethodEnums } from '../../../consts/HTTP'; +import { httpMethodEnums } from '../../../constants/HTTP'; import { ddbDocClient } from '../../../libs/ddbDocClient'; const { TABLE_NAME } = process.env; From 165526e41c321f53050a4725ca60ac8bda01fe15 Mon Sep 17 00:00:00 2001 From: Abul Hossain Date: Sat, 13 Aug 2022 02:05:53 +0600 Subject: [PATCH 3/3] feat: use auth hook and in auth pages --- components/NextShield.js | 2 +- consts/HTTP.js | 7 --- modules/auth/auth.query.js | 90 ++++++++++++++++++++++++++++++++- modules/auth/auth.service.js | 96 +++++++++++++++++++++++++++++++++++- pages/api/register.js | 4 +- pages/confirm.js | 27 +++++----- pages/login.js | 19 +++---- pages/register.js | 16 ++---- 8 files changed, 211 insertions(+), 50 deletions(-) delete mode 100644 consts/HTTP.js diff --git a/components/NextShield.js b/components/NextShield.js index 11892e0..01ba8d9 100644 --- a/components/NextShield.js +++ b/components/NextShield.js @@ -1,7 +1,7 @@ import React, { useEffect } from 'react'; -import { verifyPath, getAccessRoute } from '../libs/routes'; import { useGetUser } from '../modules/auth/auth.query'; +import { verifyPath, getAccessRoute } from '../libs/routes'; export function NextShield({ RBAC, diff --git a/consts/HTTP.js b/consts/HTTP.js deleted file mode 100644 index 4361f40..0000000 --- a/consts/HTTP.js +++ /dev/null @@ -1,7 +0,0 @@ -export const httpMethodEnums = { - GET: 'GET', - PUT: 'PUT', - POST: 'POST', - PATCH: 'PATCH', - DELETE: 'DELETE', -}; diff --git a/modules/auth/auth.query.js b/modules/auth/auth.query.js index 904d446..fd302ba 100644 --- a/modules/auth/auth.query.js +++ b/modules/auth/auth.query.js @@ -1,6 +1,92 @@ -import { useQuery } from 'react-query'; -import { getUser } from './auth.service'; +import { useRouter } from 'next/router'; +import { useMutation, useQuery } from 'react-query'; + +import { + login, + getUser, + confirm, + register, + resetPassword, + resetPasswordRequest, +} from './auth.service'; +import { setUsername } from '../../utils/storage'; export const useGetUser = (username) => { return useQuery(['getUser', username], getUser); }; + +export const useLogin = () => { + const router = useRouter(); + return useMutation(login, { + onSuccess: (_, { username }) => { + setUsername(username); + router.reload(); + }, + }); +}; + +export const useRegister = () => { + const router = useRouter(); + + return useMutation(register, { + onSuccess: (data, { username }) => { + if (!data.success) return; + setUsername(username); + router.push( + { + pathname: '/confirm', + query: { username }, + }, + '/confirm' + ); + }, + }); +}; + +export const useConfirm = () => { + const router = useRouter(); + + return useMutation(confirm, { + onSuccess: () => { + router.push( + { + pathname: '/login', + query: { confirmed: true }, + }, + '/login' + ); + }, + }); +}; + +export const useResetPassword = () => { + const router = useRouter(); + + return useMutation(resetPassword, { + onSuccess: () => { + router.push( + { + pathname: '/login', + query: { reset: true }, + }, + '/login' + ); + }, + }); +}; + +export const useResetPasswordRequest = () => { + const router = useRouter(); + + return useMutation(resetPasswordRequest, { + onSuccess: (data) => { + router.push( + { + pathname: '/password/reset', + query: { username: data.username }, + }, + '/password/reset' + ); + }, + }); +}; diff --git a/modules/auth/auth.service.js b/modules/auth/auth.service.js index cdd1453..6bda04a 100644 --- a/modules/auth/auth.service.js +++ b/modules/auth/auth.service.js @@ -1,5 +1,5 @@ -import { httpMethodEnums } from '../../consts/HTTP'; import { getUsername } from '../../utils/storage'; +import { httpMethodEnums } from '../../constants/HTTP'; export const getUser = async () => { const username = getUsername(); @@ -10,3 +10,97 @@ export const getUser = async () => { return res.json(); }; + +export const login = async (values) => { + try { + const res = await fetch('/api/login', { + method: httpMethodEnums.POST, + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(values), + }); + if (!res.ok) throw res; + return res.json(); + } catch (error) { + const { message } = await error.json(); + + throw new Error(message.split(`:`)[1]); + } +}; + +export const register = async (values) => { + try { + const res = await fetch('/api/register', { + method: httpMethodEnums.POST, + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(values), + }); + + if (!res.ok) throw res; + + return res.json(); + } catch (error) { + const { message } = await error.json(); + + throw new Error(message.split(`:`)[1]); + } +}; + +export const confirm = async (values) => { + try { + const res = await fetch('/api/confirm', { + method: httpMethodEnums.POST, + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(values), + }); + if (!res.ok) throw res; + } catch (error) { + const { message } = await error.json(); + + throw new Error(message.split(`:`)[1]); + } +}; + +export const resetPassword = async (values) => { + try { + const res = await fetch('/api/password/reset', { + method: httpMethodEnums.POST, + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(values), + }); + + if (!res.ok) throw res; + + return res.json(); + } catch (error) { + const { message } = await error.json(); + + throw new Error(message.split(`:`)[1]); + } +}; + +export const resetPasswordRequest = async (values) => { + try { + const res = await fetch('/api/password/reset_code', { + method: httpMethodEnums.POST, + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(values), + }); + if (!res.ok) throw res; + + return res.json(); + } catch (error) { + const { message } = await error.json(); + + throw new Error(message.split(`:`)[1]); + } +}; diff --git a/pages/api/register.js b/pages/api/register.js index bf115fe..56b512b 100644 --- a/pages/api/register.js +++ b/pages/api/register.js @@ -17,7 +17,9 @@ export default async function handler(req, res) { try { const response = await cognitoClient.send(signUpCommand); - return res.status(response['$metadata'].httpStatusCode).send(); + return res + .status(response['$metadata'].httpStatusCode) + .send({ success: true, message: 'User registered successfully' }); } catch (err) { console.log(err); return res diff --git a/pages/confirm.js b/pages/confirm.js index 94ef3cb..9357616 100644 --- a/pages/confirm.js +++ b/pages/confirm.js @@ -1,19 +1,17 @@ -import { useRouter } from 'next/router'; -import { Button, Col, Form, Input, Row } from 'antd'; +import { Button, Col, Form, Input, Row, Typography } from 'antd'; -import useRegister from '../hooks/useRegister'; -import { useState } from 'react'; +import { getUsername } from '../utils/storage'; +import { useConfirm } from '../modules/auth/auth.query'; -export default function Confirm() { - const router = useRouter(); - const { username = 'shipon2285@gmail.com' } = router.query; - const [loading, setLoading] = useState(); +const { Text } = Typography; - const { confirm } = useRegister(); +export default function Confirm() { + const { mutate, isLoading, error } = useConfirm(); const handleSubmit = async (values) => { - setLoading(true); - confirm({ ...values, username }, setLoading); + const username = getUsername(); + if (!username) return; + mutate({ ...values, username }); }; return ( @@ -28,13 +26,14 @@ export default function Confirm() { + {error?.message && {error.message}} diff --git a/pages/login.js b/pages/login.js index 94fc133..6965e4e 100644 --- a/pages/login.js +++ b/pages/login.js @@ -1,23 +1,16 @@ import { useRouter } from 'next/router'; -import { useState } from 'react'; import { Button, Col, Form, Input, Row, Typography } from 'antd'; -import useAuth from '../hooks/useAuth'; +import { useLogin } from '../modules/auth/auth.query'; const { Text } = Typography; export default function Login() { const router = useRouter(); - const [loading, setLoading] = useState(); - const { login } = useAuth(); + const { mutate, isLoading } = useLogin(); const { success } = router.query; - const handleSubmit = async (values) => { - setLoading(true); - await login({ ...values }, setLoading); - }; - return ( @@ -32,7 +25,7 @@ export default function Login() { )} -
+ @@ -41,11 +34,11 @@ export default function Login() { diff --git a/pages/register.js b/pages/register.js index 5b2b823..12dc0ce 100644 --- a/pages/register.js +++ b/pages/register.js @@ -1,17 +1,10 @@ -import { useState } from 'react'; import { Button, Col, Form, Input, Row, Typography } from 'antd'; - -import useRegister from '../hooks/useRegister'; +import { useRegister } from '../modules/auth/auth.query'; const { Text } = Typography; export default function Register() { - const { register } = useRegister(); - const [loading, setLoading] = useState(); - - const handleSubmit = (values) => { - register(values, setLoading); - }; + const { mutate, isLoading, error, data } = useRegister(); return ( @@ -20,7 +13,7 @@ export default function Register() { style={{ padding: '10px', }}> - + @@ -36,11 +29,12 @@ export default function Register() { size='large' type='primary' htmlType='submit' - loading={loading}> + loading={isLoading}> Submit Already have an account? Log in + {error?.message && {error.message}}