v3
This commit is contained in:
parent
38bdf4c3c5
commit
0ad3ce27a4
@ -291,11 +291,20 @@ module.exports = class OrdersDBApi {
|
||||
const transaction = (options && options.transaction) || undefined;
|
||||
|
||||
let include = [
|
||||
|
||||
{
|
||||
model: db.order_items,
|
||||
as: 'order_items_order',
|
||||
include: [
|
||||
{
|
||||
model: db.products,
|
||||
as: 'product',
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
model: db.customers,
|
||||
as: 'customer',
|
||||
|
||||
required: false,
|
||||
where: filter.customer ? {
|
||||
[Op.or]: [
|
||||
{ id: { [Op.in]: filter.customer.split('|').map(term => Utils.uuid(term)) } },
|
||||
|
||||
84
frontend/src/components/LoginModal.tsx
Normal file
84
frontend/src/components/LoginModal.tsx
Normal file
@ -0,0 +1,84 @@
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import { Field, Form, Formik } from 'formik';
|
||||
import { useAppDispatch, useAppSelector } from '../stores/hooks';
|
||||
import { loginUser } from '../stores/authSlice';
|
||||
import CardBoxModal from './CardBoxModal';
|
||||
import FormField from './FormField';
|
||||
import BaseButton from './BaseButton';
|
||||
import BaseButtons from './BaseButtons';
|
||||
import { mdiEye, mdiEyeOff } from '@mdi/js';
|
||||
import BaseIcon from './BaseIcon';
|
||||
|
||||
type Props = {
|
||||
isActive: boolean;
|
||||
onClose: () => void;
|
||||
};
|
||||
|
||||
const LoginModal = ({ isActive, onClose }: Props) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { isFetching } = useAppSelector((state) => state.auth);
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
|
||||
const handleSubmit = (values) => {
|
||||
dispatch(loginUser(values))
|
||||
.unwrap()
|
||||
.then(() => {
|
||||
onClose();
|
||||
})
|
||||
.catch(() => {
|
||||
// error is handled by slice
|
||||
});
|
||||
};
|
||||
|
||||
const togglePasswordVisibility = () => {
|
||||
setShowPassword(!showPassword);
|
||||
};
|
||||
|
||||
return (
|
||||
<CardBoxModal
|
||||
title="Login"
|
||||
isActive={isActive}
|
||||
onClose={onClose}
|
||||
>
|
||||
<Formik
|
||||
initialValues={{ email: 'admin@flatlogic.com', password: 'eea84746' }}
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
<Form>
|
||||
<FormField label="Login" help="Please enter your login">
|
||||
<Field name="email" />
|
||||
</FormField>
|
||||
|
||||
<div className="relative">
|
||||
<FormField label="Password" help="Please enter your password">
|
||||
<Field name="password" type={showPassword ? 'text' : 'password'} />
|
||||
</FormField>
|
||||
<div
|
||||
className="absolute bottom-8 right-0 pr-3 flex items-center cursor-pointer"
|
||||
onClick={togglePasswordVisibility}
|
||||
>
|
||||
<BaseIcon
|
||||
className="text-gray-500 hover:text-gray-700"
|
||||
size={20}
|
||||
path={showPassword ? mdiEyeOff : mdiEye}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<BaseButtons>
|
||||
<BaseButton
|
||||
className="w-full"
|
||||
type="submit"
|
||||
label={isFetching ? 'Loading...' : 'Login'}
|
||||
color="info"
|
||||
disabled={isFetching}
|
||||
/>
|
||||
</BaseButtons>
|
||||
</Form>
|
||||
</Formik>
|
||||
</CardBoxModal>
|
||||
);
|
||||
};
|
||||
|
||||
export default LoginModal;
|
||||
@ -1,4 +1,4 @@
|
||||
import React, { ReactNode, useState, useEffect } from 'react'
|
||||
import React, { ReactNode, useState, useEffect, useContext } from 'react'
|
||||
import { mdiClose, mdiDotsVertical } from '@mdi/js'
|
||||
import { containerMaxW } from '../config'
|
||||
import BaseIcon from './BaseIcon'
|
||||
@ -6,6 +6,7 @@ import NavBarItemPlain from './NavBarItemPlain'
|
||||
import NavBarMenuList from './NavBarMenuList'
|
||||
import { MenuNavBarItem } from '../interfaces'
|
||||
import { useAppSelector } from '../stores/hooks';
|
||||
import { ModalContext } from '../context/ModalContext';
|
||||
|
||||
type Props = {
|
||||
menu: MenuNavBarItem[]
|
||||
@ -19,6 +20,7 @@ export default function NavBar({ menu, className = '', children }: Props) {
|
||||
const bgColor = useAppSelector((state) => state.style.bgLayoutColor);
|
||||
const { orders } = useAppSelector((state) => state.orders)
|
||||
const { currentUser } = useAppSelector((state) => state.auth)
|
||||
const { openLoginModal } = useContext(ModalContext);
|
||||
|
||||
const pendingOrder = orders.find(order => order.status === 'pending' && order.customer?.id === currentUser?.id);
|
||||
const cartItemsCount = pendingOrder?.order_items_order?.reduce((acc, item) => acc + item.quantity, 0) || 0;
|
||||
@ -38,6 +40,13 @@ export default function NavBar({ menu, className = '', children }: Props) {
|
||||
setIsMenuNavBarActive(!isMenuNavBarActive)
|
||||
}
|
||||
|
||||
const menuToShow = menu.filter((item) => {
|
||||
if (currentUser) {
|
||||
return !item.isLogin
|
||||
}
|
||||
return !item.isLogout && !item.isCurrentUser
|
||||
})
|
||||
|
||||
return (
|
||||
<nav
|
||||
className={`${className} top-0 inset-x-0 fixed ${bgColor} h-14 z-30 transition-position w-screen lg:w-auto dark:bg-dark-800`}
|
||||
@ -54,7 +63,7 @@ export default function NavBar({ menu, className = '', children }: Props) {
|
||||
isMenuNavBarActive ? 'block' : 'hidden'
|
||||
} flex items-center max-h-screen-menu overflow-y-auto lg:overflow-visible absolute w-screen top-14 left-0 ${bgColor} shadow-lg lg:w-auto lg:flex lg:static lg:shadow-none dark:bg-dark-800`}
|
||||
>
|
||||
<NavBarMenuList menu={menu} cartItemsCount={cartItemsCount} />
|
||||
<NavBarMenuList menu={menuToShow} cartItemsCount={cartItemsCount} openLoginModal={openLoginModal} />
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
@ -15,10 +15,11 @@ import ClickOutside from "./ClickOutside";
|
||||
|
||||
type Props = {
|
||||
item: MenuNavBarItem,
|
||||
cartItemsCount?: number
|
||||
cartItemsCount?: number,
|
||||
openLoginModal?: () => void
|
||||
}
|
||||
|
||||
export default function NavBarItem({ item, cartItemsCount }: Props) {
|
||||
export default function NavBarItem({ item, cartItemsCount, openLoginModal }: Props) {
|
||||
const router = useRouter();
|
||||
const dispatch = useAppDispatch();
|
||||
const excludedRef = useRef(null);
|
||||
@ -59,9 +60,12 @@ export default function NavBarItem({ item, cartItemsCount }: Props) {
|
||||
dispatch(setDarkMode(null))
|
||||
}
|
||||
|
||||
if (item.isLogin) {
|
||||
openLoginModal();
|
||||
}
|
||||
|
||||
if(item.isLogout) {
|
||||
dispatch(logoutUser())
|
||||
router.push('/login')
|
||||
}
|
||||
}
|
||||
|
||||
@ -93,8 +97,13 @@ export default function NavBarItem({ item, cartItemsCount }: Props) {
|
||||
item.isDesktopNoLabel && item.icon ? 'lg:hidden' : ''
|
||||
}`}
|
||||
>
|
||||
{itemLabel} {item.label === 'Cart' && cartItemsCount > 0 && `(${cartItemsCount})`}
|
||||
{itemLabel}
|
||||
</span>
|
||||
{item.label === 'Cart' && cartItemsCount > 0 && (
|
||||
<div className="bg-red-500 text-white text-xs rounded-full h-5 w-5 flex items-center justify-center">
|
||||
{cartItemsCount}
|
||||
</div>
|
||||
)}
|
||||
{item.isCurrentUser && <UserAvatarCurrentUser className="w-6 h-6 mr-3 inline-flex" />}
|
||||
{item.menu && (
|
||||
<BaseIcon
|
||||
|
||||
@ -4,15 +4,16 @@ import NavBarItem from './NavBarItem'
|
||||
|
||||
type Props = {
|
||||
menu: MenuNavBarItem[],
|
||||
cartItemsCount?: number
|
||||
cartItemsCount?: number,
|
||||
openLoginModal?: () => void
|
||||
}
|
||||
|
||||
export default function NavBarMenuList({ menu, cartItemsCount }: Props) {
|
||||
export default function NavBarMenuList({ menu, cartItemsCount, openLoginModal }: Props) {
|
||||
return (
|
||||
<>
|
||||
{menu.map((item, index) => (
|
||||
<div key={index}>
|
||||
<NavBarItem item={item} cartItemsCount={cartItemsCount} />
|
||||
<NavBarItem item={item} cartItemsCount={cartItemsCount} openLoginModal={openLoginModal} />
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
|
||||
30
frontend/src/context/ModalContext.tsx
Normal file
30
frontend/src/context/ModalContext.tsx
Normal file
@ -0,0 +1,30 @@
|
||||
|
||||
import React, { createContext, useState, ReactNode } from 'react';
|
||||
|
||||
export const ModalContext = createContext({
|
||||
isLoginModalActive: false,
|
||||
openLoginModal: () => {},
|
||||
closeLoginModal: () => {},
|
||||
});
|
||||
|
||||
type Props = {
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
export const ModalProvider = ({ children }: Props) => {
|
||||
const [isLoginModalActive, setIsLoginModalActive] = useState(false);
|
||||
|
||||
const openLoginModal = () => {
|
||||
setIsLoginModalActive(true);
|
||||
};
|
||||
|
||||
const closeLoginModal = () => {
|
||||
setIsLoginModalActive(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<ModalContext.Provider value={{ isLoginModalActive, openLoginModal, closeLoginModal }}>
|
||||
{children}
|
||||
</ModalContext.Provider>
|
||||
);
|
||||
};
|
||||
27
frontend/src/layouts/LayoutShop.tsx
Normal file
27
frontend/src/layouts/LayoutShop.tsx
Normal file
@ -0,0 +1,27 @@
|
||||
|
||||
import React, { ReactNode, useContext } from 'react';
|
||||
import { useAppSelector } from '../stores/hooks';
|
||||
import NavBar from '../components/NavBar';
|
||||
import menuNavBar from '../menuNavBar';
|
||||
import LoginModal from '../components/LoginModal';
|
||||
import { ModalContext } from '../context/ModalContext';
|
||||
|
||||
type Props = {
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
export default function LayoutShop({ children }: Props) {
|
||||
const darkMode = useAppSelector((state) => state.style.darkMode);
|
||||
const bgColor = useAppSelector((state) => state.style.bgLayoutColor);
|
||||
const { isLoginModalActive, closeLoginModal } = useContext(ModalContext);
|
||||
|
||||
return (
|
||||
<div className={darkMode ? 'dark' : ''}>
|
||||
<div className={`${bgColor} dark:bg-slate-800 dark:text-slate-100 pt-14`}>
|
||||
<NavBar menu={menuNavBar} />
|
||||
{children}
|
||||
<LoginModal isActive={isLoginModalActive} onClose={closeLoginModal} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -10,7 +10,8 @@ import {
|
||||
mdiThemeLightDark,
|
||||
mdiGithub,
|
||||
mdiVuejs,
|
||||
mdiCart
|
||||
mdiCart,
|
||||
mdiLogin,
|
||||
} from '@mdi/js'
|
||||
import { MenuNavBarItem } from './interfaces'
|
||||
|
||||
@ -44,6 +45,11 @@ const menuNavBar: MenuNavBarItem[] = [
|
||||
isDesktopNoLabel: true,
|
||||
isToggleLightDark: true,
|
||||
},
|
||||
{
|
||||
icon: mdiLogin,
|
||||
label: 'Login',
|
||||
isLogin: true,
|
||||
},
|
||||
{
|
||||
icon: mdiLogout,
|
||||
label: 'Log out',
|
||||
|
||||
@ -16,6 +16,7 @@ import { appWithTranslation } from 'next-i18next';
|
||||
import '../i18n';
|
||||
import IntroGuide from '../components/IntroGuide';
|
||||
import { appSteps, loginSteps, usersSteps, rolesSteps } from '../stores/introSteps';
|
||||
import { ModalProvider } from '../context/ModalContext';
|
||||
|
||||
// Initialize axios
|
||||
axios.defaults.baseURL = process.env.NEXT_PUBLIC_BACK_API
|
||||
@ -158,42 +159,44 @@ function MyApp({ Component, pageProps }: AppPropsWithLayout) {
|
||||
|
||||
return (
|
||||
<Provider store={store}>
|
||||
{getLayout(
|
||||
<>
|
||||
<Head>
|
||||
<meta name="description" content={description} />
|
||||
<ModalProvider>
|
||||
{getLayout(
|
||||
<>
|
||||
<Head>
|
||||
<meta name="description" content={description} />
|
||||
|
||||
<meta property="og:url" content={url} />
|
||||
<meta property="og:site_name" content="https://flatlogic.com/" />
|
||||
<meta property="og:title" content={title} />
|
||||
<meta property="og:description" content={description} />
|
||||
<meta property="og:image" content={image} />
|
||||
<meta property="og:image:type" content="image/png" />
|
||||
<meta property="og:image:width" content={imageWidth} />
|
||||
<meta property="og:image:height" content={imageHeight} />
|
||||
<meta property="og:url" content={url} />
|
||||
<meta property="og:site_name" content="https://flatlogic.com/" />
|
||||
<meta property="og:title" content={title} />
|
||||
<meta property="og:description" content={description} />
|
||||
<meta property="og:image" content={image} />
|
||||
<meta property="og:image:type" content="image/png" />
|
||||
<meta property="og:image:width" content={imageWidth} />
|
||||
<meta property="og:image:height" content={imageHeight} />
|
||||
|
||||
<meta property="twitter:card" content="summary_large_image" />
|
||||
<meta property="twitter:title" content={title} />
|
||||
<meta property="twitter:description" content={description} />
|
||||
<meta property="twitter:image:src" content={image} />
|
||||
<meta property="twitter:image:width" content={imageWidth} />
|
||||
<meta property="twitter:image:height" content={imageHeight} />
|
||||
<meta property="twitter:card" content="summary_large_image" />
|
||||
<meta property="twitter:title" content={title} />
|
||||
<meta property="twitter:description" content={description} />
|
||||
<meta property="twitter:image:src" content={image} />
|
||||
<meta property="twitter:image:width" content={imageWidth} />
|
||||
<meta property="twitter:image:height" content={imageHeight} />
|
||||
|
||||
<link rel="icon" href="/favicon.svg" />
|
||||
</Head>
|
||||
<link rel="icon" href="/favicon.svg" />
|
||||
</Head>
|
||||
|
||||
<ErrorBoundary>
|
||||
<Component {...pageProps} />
|
||||
</ErrorBoundary>
|
||||
<IntroGuide
|
||||
steps={steps}
|
||||
stepsName={stepName}
|
||||
stepsEnabled={stepsEnabled}
|
||||
onExit={handleExit}
|
||||
/>
|
||||
{(process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'dev_stage') && <DevModeBadge />}
|
||||
</>
|
||||
)}
|
||||
<ErrorBoundary>
|
||||
<Component {...pageProps} />
|
||||
</ErrorBoundary>
|
||||
<IntroGuide
|
||||
steps={steps}
|
||||
stepsName={stepName}
|
||||
stepsEnabled={stepsEnabled}
|
||||
onExit={handleExit}
|
||||
/>
|
||||
{(process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'dev_stage') && <DevModeBadge />}
|
||||
</>
|
||||
)}
|
||||
</ModalProvider>
|
||||
</Provider>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,18 +1,16 @@
|
||||
|
||||
import React, { ReactElement, useEffect } from 'react';
|
||||
import Head from 'next/head'
|
||||
import {
|
||||
useAppDispatch,
|
||||
useAppSelector
|
||||
} from "../../stores/hooks";
|
||||
} from "../stores/hooks";
|
||||
import { useRouter } from "next/router";
|
||||
import { fetch as fetchOrders } from '../../stores/orders/ordersSlice'
|
||||
import LayoutAuthenticated from "../../layouts/Authenticated";
|
||||
import { getPageTitle } from "../../config";
|
||||
import SectionTitleLineWithButton from "../../components/SectionTitleLineWithButton";
|
||||
import SectionMain from "../../components/SectionMain";
|
||||
import CardBox from "../../components/CardBox";
|
||||
import BaseButton from "../../components/BaseButton";
|
||||
import { fetch as fetchOrders } from '../stores/orders/ordersSlice'
|
||||
import LayoutShop from "../layouts/LayoutShop";
|
||||
import { getPageTitle } from "../config";
|
||||
import SectionTitleLineWithButton from "../components/SectionTitleLineWithButton";
|
||||
import SectionMain from "../components/SectionMain";
|
||||
import BaseButton from "../components/BaseButton";
|
||||
import { mdiCart } from "@mdi/js";
|
||||
|
||||
const CartPage = () => {
|
||||
@ -21,11 +19,17 @@ const CartPage = () => {
|
||||
const { orders } = useAppSelector((state) => state.orders)
|
||||
const { currentUser } = useAppSelector((state) => state.auth)
|
||||
|
||||
const pendingOrder = orders.find(order => order.status === 'pending' && order.customer?.id === currentUser?.id);
|
||||
const pendingOrder =
|
||||
orders &&
|
||||
orders.find(
|
||||
(order) => order.status === 'Pending' && order.customer?.id === currentUser?.user.id,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(fetchOrders({ query: '?status=pending' }));
|
||||
}, [dispatch]);
|
||||
if (currentUser) {
|
||||
dispatch(fetchOrders({ query: '?status=Pending' }));
|
||||
}
|
||||
}, [dispatch, currentUser]);
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -35,14 +39,12 @@ const CartPage = () => {
|
||||
<SectionMain>
|
||||
<SectionTitleLineWithButton icon={mdiCart} title={'Shopping Cart'} main>
|
||||
</SectionTitleLineWithButton>
|
||||
<CardBox>
|
||||
<>
|
||||
<p className={'block font-bold mb-2'}>Order Items</p>
|
||||
<CardBox
|
||||
<div
|
||||
className='mb-6 border border-gray-300 rounded overflow-hidden'
|
||||
hasTable
|
||||
>
|
||||
<div className='overflow-x-auto'>
|
||||
<div className={'overflow-x-auto'}>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
@ -57,7 +59,7 @@ const CartPage = () => {
|
||||
pendingOrder.order_items_order.map((item: any) => (
|
||||
<tr key={item.id}>
|
||||
<td data-label="product_name">
|
||||
{item.product_name}
|
||||
{item.product.name}
|
||||
</td>
|
||||
<td data-label="quantity">
|
||||
{item.quantity}
|
||||
@ -74,14 +76,13 @@ const CartPage = () => {
|
||||
</table>
|
||||
</div>
|
||||
{!pendingOrder?.order_items_order?.length && <div className={'text-center py-4'}>Your cart is empty</div>}
|
||||
</CardBox>
|
||||
</div>
|
||||
</>
|
||||
<BaseButton
|
||||
color='info'
|
||||
label='Checkout'
|
||||
onClick={() => router.push('/checkout')}
|
||||
/>
|
||||
</CardBox>
|
||||
</SectionMain>
|
||||
</>
|
||||
);
|
||||
@ -89,11 +90,11 @@ const CartPage = () => {
|
||||
|
||||
CartPage.getLayout = function getLayout(page: ReactElement) {
|
||||
return (
|
||||
<LayoutAuthenticated
|
||||
<LayoutShop
|
||||
>
|
||||
{page}
|
||||
</LayoutAuthenticated>
|
||||
</LayoutShop>
|
||||
)
|
||||
}
|
||||
|
||||
export default CartPage;
|
||||
export default CartPage;
|
||||
@ -1,38 +1,41 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import React, { useEffect, useContext } from 'react';
|
||||
import { useAppDispatch, useAppSelector } from '../stores/hooks';
|
||||
import { fetch as fetchProducts } from '../stores/products/productsSlice';
|
||||
import LayoutGuest from '../layouts/Guest';
|
||||
import CardBox from '../components/CardBox';
|
||||
import { getPageTitle } from '../config';
|
||||
import Head from 'next/head';
|
||||
import SectionMain from '../components/SectionMain';
|
||||
import SectionTitleLineWithButton from '../components/SectionTitleLineWithButton';
|
||||
import { mdiStorefrontOutline } from '@mdi/js';
|
||||
import { create as createOrder } from '../stores/orders/ordersSlice';
|
||||
import { create as createOrder, fetch as fetchOrders } from '../stores/orders/ordersSlice';
|
||||
import { create as createOrderItem } from '../stores/order_items/order_itemsSlice';
|
||||
import { ModalContext } from '../context/ModalContext';
|
||||
import LayoutShop from '../layouts/LayoutShop';
|
||||
|
||||
const IndexPage = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { products, loading } = useAppSelector((state) => state.products);
|
||||
const { orders } = useAppSelector((state) => state.orders);
|
||||
const { currentUser } = useAppSelector((state) => state.auth);
|
||||
const { openLoginModal } = useContext(ModalContext);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(fetchProducts({}));
|
||||
dispatch(fetchOrders({}));
|
||||
}, [dispatch]);
|
||||
|
||||
const handleAddToCart = async (product) => {
|
||||
if (!currentUser) {
|
||||
alert('Please login to add items to your cart.');
|
||||
openLoginModal();
|
||||
return;
|
||||
}
|
||||
|
||||
let pendingOrder = orders.find(order => order.status === 'pending' && order.customer?.id === currentUser.id);
|
||||
let pendingOrder = orders.find(order => order.status === 'Pending' && order.customer?.id === currentUser.id);
|
||||
|
||||
if (!pendingOrder) {
|
||||
const orderData = {
|
||||
customer: currentUser.id,
|
||||
status: 'pending',
|
||||
status: 'Pending',
|
||||
};
|
||||
const newOrderAction = await dispatch(createOrder(orderData));
|
||||
if (newOrderAction.payload) {
|
||||
@ -52,17 +55,13 @@ const IndexPage = () => {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<LayoutGuest>
|
||||
<>
|
||||
<Head>
|
||||
<title>{getPageTitle('Shop')}</title>
|
||||
</Head>
|
||||
<SectionMain>
|
||||
<SectionTitleLineWithButton icon={mdiStorefrontOutline} title="Our Products" main>
|
||||
</SectionTitleLineWithButton>
|
||||
<SectionTitleLineWithButton icon={mdiStorefrontOutline} title="Our Products" main />
|
||||
|
||||
{loading && <div>Loading...</div>}
|
||||
|
||||
@ -89,8 +88,12 @@ const IndexPage = () => {
|
||||
</div>
|
||||
)}
|
||||
</SectionMain>
|
||||
</LayoutGuest>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
IndexPage.getLayout = function getLayout(page) {
|
||||
return <LayoutShop>{page}</LayoutShop>;
|
||||
};
|
||||
|
||||
export default IndexPage;
|
||||
@ -86,8 +86,10 @@ export const authSlice = createSlice({
|
||||
const token = action.payload;
|
||||
const user = jwt.decode(token);
|
||||
|
||||
state.isFetching = false;
|
||||
state.errorMessage = '';
|
||||
state.token = token;
|
||||
state.currentUser = user;
|
||||
localStorage.setItem('token', token);
|
||||
localStorage.setItem('user', JSON.stringify(user));
|
||||
axios.defaults.headers.common['Authorization'] = 'Bearer ' + token;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user