mirror of
https://github.com/vercel/commerce.git
synced 2025-07-22 20:26:49 +00:00
✨ feat: logout
:%s
This commit is contained in:
@@ -1,13 +1,16 @@
|
||||
import React from 'react';
|
||||
import { Layout } from 'src/components/common';
|
||||
import { AccountPage } from 'src/components/modules/account';
|
||||
import React from 'react'
|
||||
import { Layout } from 'src/components/common'
|
||||
import useActiveCustomer from 'src/components/hooks/useActiveCustomer'
|
||||
import { AccountPage, AccountSignIn } from 'src/components/modules/account'
|
||||
|
||||
const Account = () => {
|
||||
return (
|
||||
<AccountPage/>
|
||||
);
|
||||
};
|
||||
const { customer } = useActiveCustomer()
|
||||
if (customer) {
|
||||
return <AccountPage />
|
||||
}
|
||||
return <AccountSignIn />
|
||||
}
|
||||
|
||||
Account.Layout = Layout
|
||||
|
||||
export default Account;
|
||||
export default Account
|
||||
|
@@ -6,26 +6,48 @@ import { ButtonCommon } from 'src/components/common'
|
||||
import InputSearch from 'src/components/common/InputSearch/InputSearch'
|
||||
import MenuDropdown from 'src/components/common/MenuDropdown/MenuDropdown'
|
||||
import { useCartDrawer } from 'src/components/contexts'
|
||||
import { IconBuy, IconFilter, IconHeart, IconHistory, IconUser } from 'src/components/icons'
|
||||
import { ACCOUNT_TAB, FILTER_PAGE, QUERY_KEY, ROUTE } from 'src/utils/constanst.utils'
|
||||
import {
|
||||
IconBuy,
|
||||
IconFilter,
|
||||
IconHeart,
|
||||
IconHistory,
|
||||
IconUser,
|
||||
} from 'src/components/icons'
|
||||
import {
|
||||
ACCOUNT_TAB,
|
||||
FILTER_PAGE,
|
||||
QUERY_KEY,
|
||||
ROUTE,
|
||||
} from 'src/utils/constanst.utils'
|
||||
import Logo from '../../../Logo/Logo'
|
||||
import s from './HeaderMenu.module.scss'
|
||||
import { useLogout } from '../../../../hooks/auth'
|
||||
interface Props {
|
||||
children?: any,
|
||||
isFull?: boolean,
|
||||
isStickyHeader?: boolean,
|
||||
visibleFilter?: boolean,
|
||||
openModalAuthen: () => void,
|
||||
openModalInfo: () => void,
|
||||
toggleFilter: () => void,
|
||||
children?: any
|
||||
isFull?: boolean
|
||||
isStickyHeader?: boolean
|
||||
visibleFilter?: boolean
|
||||
openModalAuthen: () => void
|
||||
openModalInfo: () => void
|
||||
toggleFilter: () => void
|
||||
}
|
||||
|
||||
|
||||
const HeaderMenu = memo(({ isFull, isStickyHeader, visibleFilter, openModalAuthen, openModalInfo, toggleFilter }: Props) => {
|
||||
const HeaderMenu = memo(
|
||||
({
|
||||
isFull,
|
||||
isStickyHeader,
|
||||
visibleFilter,
|
||||
openModalAuthen,
|
||||
openModalInfo,
|
||||
toggleFilter,
|
||||
}: Props) => {
|
||||
const router = useRouter()
|
||||
const { toggleCartDrawer } = useCartDrawer()
|
||||
|
||||
const optionMenu = useMemo(() => [
|
||||
const { logout } = useLogout()
|
||||
|
||||
const optionMenu = useMemo(
|
||||
() => [
|
||||
{
|
||||
onClick: openModalAuthen,
|
||||
name: 'Login (Demo)',
|
||||
@@ -53,32 +75,41 @@ const HeaderMenu = memo(({ isFull, isStickyHeader, visibleFilter, openModalAuthe
|
||||
{
|
||||
link: '/',
|
||||
name: 'Logout',
|
||||
onClick: logout,
|
||||
},
|
||||
|
||||
], [openModalAuthen])
|
||||
],
|
||||
[openModalAuthen, openModalInfo, logout]
|
||||
)
|
||||
return (
|
||||
<section className={classNames({
|
||||
<section
|
||||
className={classNames({
|
||||
[s.headerMenu]: true,
|
||||
[s.small]: isStickyHeader,
|
||||
[s.full]: isFull,
|
||||
})}>
|
||||
})}
|
||||
>
|
||||
<div className={s.left}>
|
||||
<div className={s.top}>
|
||||
<Logo />
|
||||
<div className={s.iconGroup}>
|
||||
{
|
||||
FILTER_PAGE.includes(router.pathname) && (
|
||||
{FILTER_PAGE.includes(router.pathname) && (
|
||||
<button className={s.iconFilter} onClick={toggleFilter}>
|
||||
<IconFilter />
|
||||
<div className={classNames({ [s.dot]: true, [s.isShow]: visibleFilter })}></div>
|
||||
<div
|
||||
className={classNames({
|
||||
[s.dot]: true,
|
||||
[s.isShow]: visibleFilter,
|
||||
})}
|
||||
></div>
|
||||
</button>
|
||||
)
|
||||
}
|
||||
<button className={`${s.iconCart} ${s.btnCart}`} onClick={toggleCartDrawer}>
|
||||
)}
|
||||
<button
|
||||
className={`${s.iconCart} ${s.btnCart}`}
|
||||
onClick={toggleCartDrawer}
|
||||
>
|
||||
<IconBuy />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div className={s.searchWrap}>
|
||||
<div className={s.inputSearch}>
|
||||
@@ -91,21 +122,27 @@ const HeaderMenu = memo(({ isFull, isStickyHeader, visibleFilter, openModalAuthe
|
||||
</div>
|
||||
<ul className={s.menu}>
|
||||
<li>
|
||||
<Link href={`${ROUTE.ACCOUNT}?${QUERY_KEY.TAB}=${ACCOUNT_TAB.ORDER}`}>
|
||||
<Link
|
||||
href={`${ROUTE.ACCOUNT}?${QUERY_KEY.TAB}=${ACCOUNT_TAB.ORDER}`}
|
||||
>
|
||||
<a>
|
||||
<IconHistory />
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href={`${ROUTE.ACCOUNT}?${QUERY_KEY.TAB}=${ACCOUNT_TAB.FAVOURITE}`}>
|
||||
<Link
|
||||
href={`${ROUTE.ACCOUNT}?${QUERY_KEY.TAB}=${ACCOUNT_TAB.FAVOURITE}`}
|
||||
>
|
||||
<a className={s.iconFavourite}>
|
||||
<IconHeart />
|
||||
</a>
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<MenuDropdown options={optionMenu} isHasArrow={false}><IconUser /></MenuDropdown>
|
||||
<MenuDropdown options={optionMenu} isHasArrow={false}>
|
||||
<IconUser />
|
||||
</MenuDropdown>
|
||||
</li>
|
||||
<li>
|
||||
<button className={s.btnCart} onClick={toggleCartDrawer}>
|
||||
@@ -115,6 +152,8 @@ const HeaderMenu = memo(({ isFull, isStickyHeader, visibleFilter, openModalAuthe
|
||||
</ul>
|
||||
</section>
|
||||
)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
HeaderMenu.displayName = 'HeaderMenu'
|
||||
export default HeaderMenu
|
||||
|
@@ -24,7 +24,7 @@ const MenuNavigationProductList = ({categories,brands,featured,visible,onClose}:
|
||||
setDataSort({...dataSort,...value});
|
||||
}
|
||||
function filter(){
|
||||
console.log(dataSort)
|
||||
// console.log(dataSort)
|
||||
}
|
||||
return(
|
||||
<>
|
||||
|
3
src/components/hooks/auth/index.ts
Normal file
3
src/components/hooks/auth/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export { default as useLogout } from './useLogout'
|
||||
|
||||
|
34
src/components/hooks/auth/useLogout.tsx
Normal file
34
src/components/hooks/auth/useLogout.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
import { LogoutMutation } from '@framework/schema'
|
||||
import { logoutMutation } from '@framework/utils/mutations/log-out-mutation'
|
||||
import { useState } from 'react'
|
||||
import { CommonError } from 'src/domains/interfaces/CommonError'
|
||||
import { LOCAL_STORAGE_KEY } from 'src/utils/constanst.utils'
|
||||
import rawFetcher from 'src/utils/rawFetcher'
|
||||
import useActiveCustomer from '../useActiveCustomer'
|
||||
|
||||
const useLogout = () => {
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [error, setError] = useState<CommonError | null>(null)
|
||||
const { mutate } = useActiveCustomer()
|
||||
|
||||
const logout = () => {
|
||||
setError(null)
|
||||
setLoading(true)
|
||||
rawFetcher<LogoutMutation>({
|
||||
query: logoutMutation,
|
||||
})
|
||||
.then(({ data }) => {
|
||||
if (!data.logout.success) {
|
||||
throw CommonError.create('Logout fail')
|
||||
}
|
||||
localStorage.setItem(LOCAL_STORAGE_KEY.TOKEN, '')
|
||||
mutate()
|
||||
})
|
||||
.catch(setError)
|
||||
.finally(() => setLoading(false))
|
||||
}
|
||||
|
||||
return { loading, logout, error }
|
||||
}
|
||||
|
||||
export default useLogout
|
@@ -4,6 +4,7 @@ import useActiveCustomer from './useActiveCustomer'
|
||||
import { CommonError } from 'src/domains/interfaces/CommonError'
|
||||
import rawFetcher from 'src/utils/rawFetcher'
|
||||
import { LoginMutation } from '@framework/schema'
|
||||
import { LOCAL_STORAGE_KEY } from 'src/utils/constanst.utils'
|
||||
|
||||
const query = gql`
|
||||
mutation login($username: String!, $password: String!) {
|
||||
@@ -42,9 +43,8 @@ const useLogin = () => {
|
||||
throw CommonError.create(data.login.message, data.login.errorCode)
|
||||
}
|
||||
const authToken = headers.get('vendure-auth-token')
|
||||
console.log("auth token: ", authToken)
|
||||
if (authToken != null) {
|
||||
localStorage.setItem('token', authToken)
|
||||
localStorage.setItem(LOCAL_STORAGE_KEY.TOKEN, authToken)
|
||||
return mutate()
|
||||
}
|
||||
})
|
||||
|
@@ -87,7 +87,7 @@ const AccountPage = ({ defaultActiveContent="orders" } : AccountPageProps) => {
|
||||
const query = router.query[QUERY_KEY.TAB] as string
|
||||
const index = getTabIndex(query)
|
||||
setActiveTab(index)
|
||||
}, [router.query[QUERY_KEY.TAB]])
|
||||
}, [router.query])
|
||||
|
||||
function showModal() {
|
||||
setModalVisible(true);
|
||||
|
@@ -12,8 +12,6 @@ interface EditInfoModalProps {
|
||||
const EditInfoModal = ({ accountInfo, visible = false, closeModal }: EditInfoModalProps) => {
|
||||
|
||||
function saveInfo() {
|
||||
console.log("saved !!!");
|
||||
|
||||
closeModal();
|
||||
}
|
||||
|
||||
|
@@ -16,7 +16,6 @@ const FormSubscribe = () => {
|
||||
e.preventDefault && e.preventDefault()
|
||||
value = inputElementRef.current?.getValue()?.toString() || ''
|
||||
}
|
||||
console.log("email here: ", value)
|
||||
}
|
||||
|
||||
return (
|
||||
|
@@ -38,6 +38,10 @@ export const ACCOUNT_TAB = {
|
||||
FAVOURITE: 'wishlist',
|
||||
}
|
||||
|
||||
export const LOCAL_STORAGE_KEY = {
|
||||
TOKEN: 'token'
|
||||
}
|
||||
|
||||
export const QUERY_KEY = {
|
||||
TAB: 'tab',
|
||||
CATEGORY: 'category',
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import { request } from 'graphql-request'
|
||||
import { RequestDocument, Variables } from 'graphql-request/dist/types'
|
||||
import { LOCAL_STORAGE_KEY } from './constanst.utils'
|
||||
|
||||
interface QueryOptions {
|
||||
query: RequestDocument
|
||||
@@ -10,11 +11,7 @@ interface QueryOptions {
|
||||
|
||||
const fetcher = async <T>(options: QueryOptions): Promise<T> => {
|
||||
const { query, variables } = options
|
||||
// console.log('query')
|
||||
// console.log(options)
|
||||
const token = localStorage.getItem('token')
|
||||
// console.log('token')
|
||||
// console.log(token)
|
||||
const token = localStorage.getItem(LOCAL_STORAGE_KEY.TOKEN)
|
||||
const res = await request<T>(
|
||||
process.env.NEXT_PUBLIC_VENDURE_SHOP_API_URL as string,
|
||||
query,
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import { rawRequest } from 'graphql-request'
|
||||
import { RequestDocument, Variables } from 'graphql-request/dist/types'
|
||||
import { LOCAL_STORAGE_KEY } from './constanst.utils'
|
||||
|
||||
interface QueryOptions {
|
||||
query: RequestDocument
|
||||
@@ -14,10 +15,12 @@ const rawFetcher = <T>({
|
||||
onLoad = () => true,
|
||||
}: QueryOptions): Promise<{ data: T; headers: any }> => {
|
||||
onLoad(true)
|
||||
const token = localStorage.getItem(LOCAL_STORAGE_KEY.TOKEN)
|
||||
return rawRequest<T>(
|
||||
process.env.NEXT_PUBLIC_VENDURE_SHOP_API_URL as string,
|
||||
query as string,
|
||||
variables
|
||||
variables,
|
||||
token ? { Authorization: 'Bearer ' + token } : {}
|
||||
)
|
||||
.then(({ data, headers }) => {
|
||||
return { data, headers }
|
||||
|
Reference in New Issue
Block a user