show storage
This commit is contained in:
@@ -13,6 +13,7 @@ import { IApiErrorRepsonse } from './types/error.types';
|
||||
import ToastContainer from './components/Toast';
|
||||
import { getRefreshToken, removeRefreshToken, removeToken, setRefreshToken, setToken } from './config/func';
|
||||
import { refreshToken } from './pages/auth/service/Service';
|
||||
import BuySpace from './shared/components/BuySpace'
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
@@ -102,6 +103,7 @@ const App: FC = () => {
|
||||
|
||||
<Main />
|
||||
<ToastContainer />
|
||||
<BuySpace />
|
||||
</QueryClientProvider>
|
||||
</I18nextProvider>
|
||||
</BrowserRouter>
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
import { FC, Fragment, ReactNode, useEffect } from 'react'
|
||||
import HeaderModal from './HeaderModal'
|
||||
|
||||
interface Props {
|
||||
open: boolean,
|
||||
close: () => void,
|
||||
children: ReactNode,
|
||||
isHeader?: boolean,
|
||||
title_header?: string,
|
||||
width?: number
|
||||
}
|
||||
|
||||
const DefaulModal: FC<Props> = (props: Props) => {
|
||||
|
||||
useEffect(() => {
|
||||
if (props.open) {
|
||||
document.body.style.overflow = 'hidden'
|
||||
} else {
|
||||
document.body.style.overflow = 'auto'
|
||||
}
|
||||
}, [props.open])
|
||||
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
{
|
||||
props.open && (
|
||||
<Fragment>
|
||||
<div style={{ maxWidth: props.width }} className='xl:justify-center xl:items-center items-end flex overflow-x-hidden overflow-y-auto fixed inset-0 z-[60] h-auto top-0 bottom-0 m-auto outline-none focus:outline-none xl:max-w-xl mx-auto'>
|
||||
<div className='relative xl:h-full max-h-[80%] bottom-0 left-0 flex xl:items-center sm:h-auto w-full xl:my-6 xl:p-2'>
|
||||
<div className='border-0 h-auto p-5 lg:min-w-full overflow-y-auto rounded-3xl rounded-b-none xl:rounded-b-3xl relative flex flex-col w-full modalGlass2 outline-none focus:outline-none'>
|
||||
|
||||
|
||||
{
|
||||
props.isHeader && props.title_header &&
|
||||
<div onClick={props.close} className='pb-6 border-b border-white border-opacity-20'>
|
||||
<div className='h-[5px] w-[200px] mx-auto bg-[#D1D3D7] rounded-full mb-4 xl:hidden'></div>
|
||||
<HeaderModal close={props.close} label={props.title_header} />
|
||||
</div>
|
||||
}
|
||||
|
||||
{props.children}
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div onClick={props.close} className='fixed size-full top-0 bottom-0 right-0 modalGlass inset-0 z-50 '></div>
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
|
||||
export default DefaulModal
|
||||
@@ -0,0 +1,21 @@
|
||||
import { CloseCircle } from 'iconsax-react'
|
||||
import { FC } from 'react'
|
||||
|
||||
|
||||
type Props = {
|
||||
label: string,
|
||||
close: () => void,
|
||||
}
|
||||
|
||||
const HeaderModal: FC<Props> = (props: Props) => {
|
||||
return (
|
||||
<div className='flex justify-between items-center'>
|
||||
<div className='text-sm'>{props.label}</div>
|
||||
<div className='size-7 rounded-full flex justify-center items-center'>
|
||||
<CloseCircle size={20} color='black' onClick={props.close} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default HeaderModal
|
||||
@@ -0,0 +1,17 @@
|
||||
import { FC } from 'react'
|
||||
|
||||
const ProgressBar: FC<{ percentage: number }> = ({ percentage }) => {
|
||||
return (
|
||||
<div className='w-full bg-gray-200 dltr overflow-hidden rounded-full h-2'>
|
||||
<div
|
||||
className={`h-2 rounded-full transition-all duration-300 ${percentage > 90 ? 'bg-red-500' :
|
||||
percentage > 70 ? 'bg-yellow-500' :
|
||||
'bg-green-500'
|
||||
}`}
|
||||
style={{ width: `${percentage}%` }}
|
||||
></div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default ProgressBar
|
||||
@@ -247,3 +247,23 @@ textarea::placeholder {
|
||||
.ql-snow .ql-picker:not(.ql-color-picker):not(.ql-icon-picker) svg {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.modalGlass {
|
||||
background: rgba(0, 0, 0, 0.436);
|
||||
background-blend-mode: multiply;
|
||||
|
||||
backdrop-filter: blur(7px);
|
||||
}
|
||||
.modalGlass2 {
|
||||
background: rgba(255, 255, 255, 0.502);
|
||||
background-blend-mode: multiply;
|
||||
|
||||
/* backdrop-filter: blur(5px); */
|
||||
}
|
||||
|
||||
.modalGlass3 {
|
||||
background: rgba(62, 61, 61, 0.2);
|
||||
background-blend-mode: multiply;
|
||||
|
||||
backdrop-filter: blur(44px);
|
||||
}
|
||||
|
||||
+6
-1
@@ -12,7 +12,12 @@
|
||||
"spam": "هرزنامه ها",
|
||||
"setting": "تنظیمات",
|
||||
"logout": "خروج",
|
||||
"admin_panel": "پنل مدیریت"
|
||||
"admin_panel": "پنل مدیریت",
|
||||
"storage": "ذخیرهسازی",
|
||||
"add_space": "اضافه کردن فضا"
|
||||
},
|
||||
"space": {
|
||||
"title": "خرید فضای ذخیره سازی"
|
||||
},
|
||||
"header": {
|
||||
"search": "جستجو"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { convertToGB } from '@/config/func'
|
||||
import { FC } from 'react'
|
||||
import { AddressData } from '../types/Types'
|
||||
import ProgressBar from '@/components/ProgressBar'
|
||||
|
||||
const ProgressBarEmail: FC<{ item: AddressData }> = ({ item }) => {
|
||||
const usedQuota = item.emailQuotaUsed || 0;
|
||||
@@ -17,15 +18,7 @@ const ProgressBarEmail: FC<{ item: AddressData }> = ({ item }) => {
|
||||
{percentage.toFixed(1)}%
|
||||
</span> */}
|
||||
</div>
|
||||
<div className='w-full bg-gray-200 dltr overflow-hidden rounded-full h-2'>
|
||||
<div
|
||||
className={`h-2 rounded-full transition-all duration-300 ${percentage > 90 ? 'bg-red-500' :
|
||||
percentage > 70 ? 'bg-yellow-500' :
|
||||
'bg-green-500'
|
||||
}`}
|
||||
style={{ width: `${percentage}%` }}
|
||||
></div>
|
||||
</div>
|
||||
<ProgressBar percentage={percentage} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -30,3 +30,10 @@ export const useVerifyDnsRecord = () => {
|
||||
queryFn: () => api.verifyDnsRecord(),
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetSpace = () => {
|
||||
return useQuery({
|
||||
queryKey: ["space"],
|
||||
queryFn: () => api.getSpace(),
|
||||
});
|
||||
};
|
||||
|
||||
@@ -20,3 +20,8 @@ export const verifyDnsRecord = async () => {
|
||||
const { data } = await axios.get(`/domains/verify-dns`);
|
||||
return data;
|
||||
};
|
||||
|
||||
export const getSpace = async () => {
|
||||
const { data } = await axios.get(`/business/quota`);
|
||||
return data;
|
||||
};
|
||||
|
||||
+2
-9
@@ -2,16 +2,9 @@ import { FC } from 'react'
|
||||
import SideBar from './SideBar'
|
||||
import AppRouter from '@/router/AppRouter'
|
||||
import Header from './Header'
|
||||
import Button from '@/components/Button'
|
||||
import { Add } from 'iconsax-react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useSharedStore } from './store/sharedStore'
|
||||
|
||||
const Main: FC = () => {
|
||||
|
||||
const { t } = useTranslation()
|
||||
const { setOpenSidebar, setOpenNewMessage } = useSharedStore()
|
||||
|
||||
return (
|
||||
<div className='p-2 md:p-4 overflow-hidden'>
|
||||
<SideBar />
|
||||
@@ -24,7 +17,7 @@ const Main: FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='flex fixed bottom-4 xl:hidden right-0 justify-center mt-10 md:mt-14 px-4'>
|
||||
{/* <div className='flex fixed bottom-4 xl:hidden right-0 justify-center mt-10 md:mt-14 px-4'>
|
||||
<Button
|
||||
className='bg-secondary font-normal text-primary w-fit px-4 md:px-6 text-sm'
|
||||
onClick={() => {
|
||||
@@ -37,7 +30,7 @@ const Main: FC = () => {
|
||||
<div>{t('sidebar.new_message')}</div>
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
</div> */}
|
||||
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -7,6 +7,7 @@ import { useSharedStore } from './store/sharedStore'
|
||||
import { clx } from '../helpers/utils'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Paths } from '@/utils/Paths'
|
||||
import Storage from './components/Storage'
|
||||
|
||||
const SideBar: FC = () => {
|
||||
|
||||
@@ -76,6 +77,7 @@ const SideBar: FC = () => {
|
||||
</div>
|
||||
|
||||
<div className='flex-1 flex flex-col justify-end mt-10 md:mt-14 pb-6 md:pb-8'>
|
||||
<Storage />
|
||||
<div className='text-xs text-[#8C90A3]'>
|
||||
<SideBarItem
|
||||
icon={<Logout variant={isActive('logout') ? 'Bold' : 'Outline'} color={isActive('logout') ? 'black' : '#8C90A3'} size={iconSizeSideBar} />}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import DefaulModal from '@/components/DefaulModal'
|
||||
import { useSharedStore } from '@/shared/store/sharedStore'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { FC } from 'react'
|
||||
|
||||
const BuySpace: FC = () => {
|
||||
|
||||
const { t } = useTranslation()
|
||||
const { openBuySpace, setOpenBuySpace } = useSharedStore()
|
||||
console.log(openBuySpace);
|
||||
|
||||
return (
|
||||
<DefaulModal
|
||||
open={openBuySpace}
|
||||
close={() => setOpenBuySpace(false)}
|
||||
isHeader={true}
|
||||
title_header={t('space.title')}
|
||||
>
|
||||
<div className='mt-5'>
|
||||
|
||||
</div>
|
||||
</DefaulModal >
|
||||
)
|
||||
}
|
||||
|
||||
export default BuySpace
|
||||
@@ -0,0 +1,52 @@
|
||||
import Button from '@/components/Button'
|
||||
import ProgressBar from '@/components/ProgressBar'
|
||||
import { useGetSpace } from '@/pages/setting/domain/hooks/useDomainData'
|
||||
import { useSharedStore } from '@/shared/store/sharedStore'
|
||||
import { Cloud } from 'iconsax-react'
|
||||
import { FC } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
const Storage: FC = () => {
|
||||
|
||||
const { t } = useTranslation()
|
||||
const { setOpenBuySpace } = useSharedStore()
|
||||
const { data } = useGetSpace()
|
||||
return (
|
||||
<div className='px-10 pb-5'>
|
||||
<div className='flex gap-2 items-center'>
|
||||
<Cloud size={20} color='#8C90A3' />
|
||||
<div className='text-xs text-description'>
|
||||
{t('sidebar.storage')}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='mt-5'>
|
||||
<ProgressBar
|
||||
percentage={
|
||||
data?.data?.quota?.totalInGB
|
||||
? Math.round(
|
||||
(data?.data?.quota?.usedInGB / data?.data?.quota?.totalInGB) * 100
|
||||
)
|
||||
: 0
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='mt-5 text-xs'>
|
||||
{data?.data?.quota?.usedInGB} گیگابایت از {data?.data?.quota?.totalInGB} گیگابایت استفاده شده است
|
||||
</div>
|
||||
|
||||
<div className='mt-5'>
|
||||
<Button
|
||||
variant='secondary'
|
||||
label={t('sidebar.add_space')}
|
||||
onClick={() => setOpenBuySpace(true)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Storage
|
||||
@@ -6,4 +6,6 @@ export const useSharedStore = create<SharedStoreType>((set) => ({
|
||||
setOpenSidebar: (value) => set({ openSidebar: value }),
|
||||
openNewMessage: false,
|
||||
setOpenNewMessage: (value) => set({ openNewMessage: value }),
|
||||
openBuySpace: false,
|
||||
setOpenBuySpace: (value) => set({ openBuySpace: value }),
|
||||
}));
|
||||
|
||||
@@ -3,4 +3,6 @@ export type SharedStoreType = {
|
||||
setOpenSidebar: (value: boolean) => void;
|
||||
openNewMessage: boolean;
|
||||
setOpenNewMessage: (value: boolean) => void;
|
||||
openBuySpace: boolean;
|
||||
setOpenBuySpace: (value: boolean) => void;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user