First commit
This commit is contained in:
@@ -0,0 +1,171 @@
|
||||
// Next Imports
|
||||
import dynamic from 'next/dynamic'
|
||||
|
||||
// MUI Imports
|
||||
import Card from '@mui/material/Card'
|
||||
import CardHeader from '@mui/material/CardHeader'
|
||||
import CardContent from '@mui/material/CardContent'
|
||||
import Typography from '@mui/material/Typography'
|
||||
import LinearProgress from '@mui/material/LinearProgress'
|
||||
import Chip from '@mui/material/Chip'
|
||||
|
||||
// Third Party Imports
|
||||
import classnames from 'classnames'
|
||||
import type { ApexOptions } from 'apexcharts'
|
||||
|
||||
// Types Imports
|
||||
import type { ThemeColor } from '@core/types'
|
||||
|
||||
// Components Imports
|
||||
import OptionMenu from '@core/components/option-menu'
|
||||
import CustomAvatar from '@core/components/mui/Avatar'
|
||||
|
||||
// Styled Component Imports
|
||||
const AppReactApexCharts = dynamic(() => import('@/libs/styles/AppReactApexCharts'))
|
||||
|
||||
type DataType = {
|
||||
stats: string
|
||||
title: string
|
||||
progress: number
|
||||
avatarIcon: string
|
||||
avatarColor?: ThemeColor
|
||||
progressColor?: ThemeColor
|
||||
}
|
||||
|
||||
// Vars
|
||||
const series = [{ data: [37, 76, 65, 41, 99, 53, 70] }]
|
||||
|
||||
const data: DataType[] = [
|
||||
{
|
||||
title: 'Earnings',
|
||||
progress: 64,
|
||||
stats: '$545.69',
|
||||
progressColor: 'primary',
|
||||
avatarColor: 'primary',
|
||||
avatarIcon: 'tabler-currency-dollar'
|
||||
},
|
||||
{
|
||||
title: 'Profit',
|
||||
progress: 59,
|
||||
stats: '$256.34',
|
||||
progressColor: 'info',
|
||||
avatarColor: 'info',
|
||||
avatarIcon: 'tabler-chart-pie-2'
|
||||
},
|
||||
{
|
||||
title: 'Expense',
|
||||
progress: 22,
|
||||
stats: '$74.19',
|
||||
progressColor: 'error',
|
||||
avatarColor: 'error',
|
||||
avatarIcon: 'tabler-brand-paypal'
|
||||
}
|
||||
]
|
||||
|
||||
const EarningReports = () => {
|
||||
// Vars
|
||||
const primaryColorWithOpacity = 'var(--mui-palette-primary-lightOpacity)'
|
||||
|
||||
const options: ApexOptions = {
|
||||
chart: {
|
||||
parentHeightOffset: 0,
|
||||
toolbar: { show: false }
|
||||
},
|
||||
tooltip: { enabled: false },
|
||||
grid: {
|
||||
show: false,
|
||||
padding: {
|
||||
top: -31,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: -9
|
||||
}
|
||||
},
|
||||
plotOptions: {
|
||||
bar: {
|
||||
borderRadius: 4,
|
||||
distributed: true,
|
||||
columnWidth: '42%'
|
||||
}
|
||||
},
|
||||
legend: { show: false },
|
||||
dataLabels: { enabled: false },
|
||||
colors: [
|
||||
primaryColorWithOpacity,
|
||||
primaryColorWithOpacity,
|
||||
primaryColorWithOpacity,
|
||||
primaryColorWithOpacity,
|
||||
'var(--mui-palette-primary-main)',
|
||||
primaryColorWithOpacity,
|
||||
primaryColorWithOpacity
|
||||
],
|
||||
states: {
|
||||
hover: {
|
||||
filter: { type: 'none' }
|
||||
},
|
||||
active: {
|
||||
filter: { type: 'none' }
|
||||
}
|
||||
},
|
||||
xaxis: {
|
||||
categories: ['Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su'],
|
||||
axisTicks: { show: false },
|
||||
axisBorder: { show: false },
|
||||
labels: {
|
||||
style: {
|
||||
fontSize: '13px',
|
||||
colors: 'var(--mui-palette-text-disabled)'
|
||||
}
|
||||
}
|
||||
},
|
||||
yaxis: { show: false }
|
||||
}
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader
|
||||
title='Earning Reports'
|
||||
subheader='Weekly Earnings Overview'
|
||||
action={<OptionMenu options={['Last Week', 'Last Month', 'Last Year']} />}
|
||||
className='pbe-0'
|
||||
/>
|
||||
<CardContent className='flex flex-col gap-5 max-md:gap-5 max-[1015px]:gap-[62px] max-[1051px]:gap-10 max-[1200px]:gap-5 max-[1310px]:gap-10'>
|
||||
<div className='flex flex-col sm:flex-row items-center justify-between gap-8'>
|
||||
<div className='flex flex-col gap-3 is-full sm:is-[unset]'>
|
||||
<div className='flex items-center gap-2.5'>
|
||||
<Typography variant='h2'>$468</Typography>
|
||||
<Chip size='small' variant='tonal' color='success' label='+4.2%' />
|
||||
</div>
|
||||
<Typography variant='body2' className='text-balance'>
|
||||
You informed of this week compared to last week
|
||||
</Typography>
|
||||
</div>
|
||||
<AppReactApexCharts type='bar' height={163} width='100%' series={series} options={options} />
|
||||
</div>
|
||||
<div className='flex flex-col sm:flex-row gap-6 p-5 border rounded'>
|
||||
{data.map((item, index) => (
|
||||
<div key={index} className='flex flex-col gap-2 is-full'>
|
||||
<div className='flex items-center gap-2'>
|
||||
<CustomAvatar skin='light' variant='rounded' color={item.avatarColor} size={26}>
|
||||
<i className={classnames(item.avatarIcon, 'text-lg')} />
|
||||
</CustomAvatar>
|
||||
<Typography variant='h6' className='leading-6 font-normal'>
|
||||
{item.title}
|
||||
</Typography>
|
||||
</div>
|
||||
<Typography variant='h4'>{item.stats}</Typography>
|
||||
<LinearProgress
|
||||
value={item.progress}
|
||||
variant='determinate'
|
||||
color={item.progressColor}
|
||||
className='max-bs-1'
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
export default EarningReports
|
||||
@@ -0,0 +1,94 @@
|
||||
'use client'
|
||||
|
||||
// Next Imports
|
||||
import dynamic from 'next/dynamic'
|
||||
|
||||
// MUI Imports
|
||||
import Card from '@mui/material/Card'
|
||||
import Typography from '@mui/material/Typography'
|
||||
import CardContent from '@mui/material/CardContent'
|
||||
import CardHeader from '@mui/material/CardHeader'
|
||||
import { useTheme } from '@mui/material/styles'
|
||||
|
||||
// Third-party Imports
|
||||
import type { ApexOptions } from 'apexcharts'
|
||||
|
||||
// Styled Component Imports
|
||||
const AppReactApexCharts = dynamic(() => import('@/libs/styles/AppReactApexCharts'))
|
||||
|
||||
const series = [{ data: [40, 20, 65, 50] }]
|
||||
|
||||
const LineAreaDailySalesChart = () => {
|
||||
// Hook
|
||||
const theme = useTheme()
|
||||
|
||||
const options: ApexOptions = {
|
||||
chart: {
|
||||
parentHeightOffset: 0,
|
||||
toolbar: { show: false },
|
||||
sparkline: { enabled: true }
|
||||
},
|
||||
tooltip: { enabled: false },
|
||||
dataLabels: { enabled: false },
|
||||
stroke: {
|
||||
width: 2,
|
||||
curve: 'smooth'
|
||||
},
|
||||
grid: {
|
||||
show: false,
|
||||
padding: {
|
||||
bottom: 20
|
||||
}
|
||||
},
|
||||
fill: {
|
||||
type: 'gradient',
|
||||
gradient: {
|
||||
opacityTo: 0,
|
||||
opacityFrom: 1,
|
||||
shadeIntensity: 1,
|
||||
stops: [0, 100],
|
||||
colorStops: [
|
||||
[
|
||||
{
|
||||
offset: 0,
|
||||
opacity: 0.4,
|
||||
color: theme.palette.success.main
|
||||
},
|
||||
{
|
||||
opacity: 0,
|
||||
offset: 100,
|
||||
color: 'var(--mui-palette-background-paper)'
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
theme: {
|
||||
monochrome: {
|
||||
enabled: true,
|
||||
shadeTo: 'light',
|
||||
shadeIntensity: 1,
|
||||
color: theme.palette.success.main
|
||||
}
|
||||
},
|
||||
xaxis: {
|
||||
labels: { show: false },
|
||||
axisTicks: { show: false },
|
||||
axisBorder: { show: false }
|
||||
},
|
||||
yaxis: { show: false }
|
||||
}
|
||||
|
||||
return (
|
||||
<Card className='pbe-6'>
|
||||
<CardHeader title='Average Daily Sales' className='pbe-3' />
|
||||
<CardContent>
|
||||
<Typography>Total Sales This Month</Typography>
|
||||
<Typography variant='h4'>$28,450</Typography>
|
||||
</CardContent>
|
||||
<AppReactApexCharts type='area' height={88} width='100%' series={series} options={options} />
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
export default LineAreaDailySalesChart
|
||||
@@ -0,0 +1,108 @@
|
||||
// MUI Imports
|
||||
import Card from '@mui/material/Card'
|
||||
import CardHeader from '@mui/material/CardHeader'
|
||||
import CardContent from '@mui/material/CardContent'
|
||||
import Typography from '@mui/material/Typography'
|
||||
|
||||
// Third-party Imports
|
||||
import classnames from 'classnames'
|
||||
|
||||
import type { ThemeColor } from '@core/types'
|
||||
|
||||
// Components Imports
|
||||
import OptionMenu from '@core/components/option-menu'
|
||||
import CustomAvatar from '@core/components/mui/Avatar'
|
||||
|
||||
type DataType = {
|
||||
icon: string
|
||||
title: string
|
||||
amount: string
|
||||
avatarColor: ThemeColor
|
||||
trendNumber: string
|
||||
trend?: 'positive' | 'negative'
|
||||
}
|
||||
|
||||
// Vars
|
||||
const data: DataType[] = [
|
||||
{
|
||||
title: 'Emails',
|
||||
amount: '12,346',
|
||||
trendNumber: '0.3%',
|
||||
avatarColor: 'success',
|
||||
icon: 'tabler-mail'
|
||||
},
|
||||
{
|
||||
title: 'Opened',
|
||||
amount: '8,734',
|
||||
trendNumber: '2.1%',
|
||||
avatarColor: 'info',
|
||||
icon: 'tabler-link'
|
||||
},
|
||||
{
|
||||
title: 'Clicked',
|
||||
amount: '967',
|
||||
trendNumber: '1.4%',
|
||||
trend: 'negative',
|
||||
avatarColor: 'warning',
|
||||
icon: 'tabler-mouse'
|
||||
},
|
||||
{
|
||||
title: 'Subscribe',
|
||||
amount: '345',
|
||||
trendNumber: '8.5%',
|
||||
avatarColor: 'primary',
|
||||
icon: 'tabler-users'
|
||||
},
|
||||
{
|
||||
title: 'Complaints',
|
||||
amount: '10',
|
||||
trendNumber: '1.5%',
|
||||
trend: 'negative',
|
||||
avatarColor: 'secondary',
|
||||
icon: 'tabler-alert-triangle'
|
||||
},
|
||||
{
|
||||
title: 'Unsubscribe',
|
||||
amount: '86',
|
||||
trendNumber: '0.8%',
|
||||
avatarColor: 'error',
|
||||
icon: 'tabler-ban'
|
||||
}
|
||||
]
|
||||
|
||||
const MonthlyCampaignState = () => {
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader
|
||||
title='Monthly Campaign State'
|
||||
subheader='8.52k Social Visitors'
|
||||
action={<OptionMenu options={['Last Month', 'Last 6 Months', 'Last Year']} />}
|
||||
/>
|
||||
<CardContent className='flex flex-col gap-6 md:gap-[1.6875rem]'>
|
||||
{data.map((item, index) => (
|
||||
<div key={index} className='flex items-center gap-4'>
|
||||
<CustomAvatar skin='light' variant='rounded' color={item.avatarColor} size={34}>
|
||||
<i className={classnames(item.icon, 'text-[22px]')} />
|
||||
</CustomAvatar>
|
||||
<div className='flex flex-wrap justify-between items-center gap-x-4 gap-y-1 is-full'>
|
||||
<Typography className='font-medium' color='text.primary'>
|
||||
{item.title}
|
||||
</Typography>
|
||||
<div className='flex items-center gap-4'>
|
||||
<Typography>{item.amount}</Typography>
|
||||
<Typography
|
||||
className='flex justify-end is-11'
|
||||
color={`${item.trend === 'negative' ? 'error' : 'success'}.main`}
|
||||
>
|
||||
{item.trendNumber}
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
export default MonthlyCampaignState
|
||||
@@ -0,0 +1,295 @@
|
||||
'use client'
|
||||
|
||||
// React Imports
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
|
||||
// MUI Imports
|
||||
import AvatarGroup from '@mui/material/AvatarGroup'
|
||||
import Typography from '@mui/material/Typography'
|
||||
import LinearProgress from '@mui/material/LinearProgress'
|
||||
import Card from '@mui/material/Card'
|
||||
import Checkbox from '@mui/material/Checkbox'
|
||||
import CardHeader from '@mui/material/CardHeader'
|
||||
import TablePagination from '@mui/material/TablePagination'
|
||||
import type { TextFieldProps } from '@mui/material/TextField'
|
||||
|
||||
// Third-party Imports
|
||||
import classnames from 'classnames'
|
||||
import { rankItem } from '@tanstack/match-sorter-utils'
|
||||
import {
|
||||
createColumnHelper,
|
||||
flexRender,
|
||||
getCoreRowModel,
|
||||
useReactTable,
|
||||
getFilteredRowModel,
|
||||
getFacetedRowModel,
|
||||
getFacetedUniqueValues,
|
||||
getFacetedMinMaxValues,
|
||||
getPaginationRowModel,
|
||||
getSortedRowModel
|
||||
} from '@tanstack/react-table'
|
||||
import type { ColumnDef, FilterFn } from '@tanstack/react-table'
|
||||
import type { RankingInfo } from '@tanstack/match-sorter-utils'
|
||||
|
||||
// Type Imports
|
||||
import type { ProjectTableRowType } from '@/types/pages/profileTypes'
|
||||
|
||||
// Component Imports
|
||||
import OptionMenu from '@core/components/option-menu'
|
||||
import CustomAvatar from '@core/components/mui/Avatar'
|
||||
import CustomTextField from '@core/components/mui/TextField'
|
||||
import TablePaginationComponent from '@/components/TablePaginationComponent'
|
||||
|
||||
// Style Imports
|
||||
import tableStyles from '@core/styles/table.module.css'
|
||||
|
||||
declare module '@tanstack/table-core' {
|
||||
interface FilterFns {
|
||||
fuzzy: FilterFn<unknown>
|
||||
}
|
||||
interface FilterMeta {
|
||||
itemRank: RankingInfo
|
||||
}
|
||||
}
|
||||
|
||||
const fuzzyFilter: FilterFn<any> = (row, columnId, value, addMeta) => {
|
||||
// Rank the item
|
||||
const itemRank = rankItem(row.getValue(columnId), value)
|
||||
|
||||
// Store the itemRank info
|
||||
addMeta({
|
||||
itemRank
|
||||
})
|
||||
|
||||
// Return if the item should be filtered in/out
|
||||
return itemRank.passed
|
||||
}
|
||||
|
||||
const DebouncedInput = ({
|
||||
value: initialValue,
|
||||
onChange,
|
||||
debounce = 500,
|
||||
...props
|
||||
}: {
|
||||
value: string | number
|
||||
onChange: (value: string | number) => void
|
||||
debounce?: number
|
||||
} & Omit<TextFieldProps, 'onChange'>) => {
|
||||
// States
|
||||
const [value, setValue] = useState(initialValue)
|
||||
|
||||
useEffect(() => {
|
||||
setValue(initialValue)
|
||||
}, [initialValue])
|
||||
|
||||
useEffect(() => {
|
||||
const timeout = setTimeout(() => {
|
||||
onChange(value)
|
||||
}, debounce)
|
||||
|
||||
return () => clearTimeout(timeout)
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [value])
|
||||
|
||||
return <CustomTextField {...props} value={value} onChange={e => setValue(e.target.value)} />
|
||||
}
|
||||
|
||||
// Column Definitions
|
||||
const columnHelper = createColumnHelper<ProjectTableRowType>()
|
||||
|
||||
const ProjectTables = ({ projectTable }: { projectTable?: ProjectTableRowType[] }) => {
|
||||
// States
|
||||
const [rowSelection, setRowSelection] = useState({})
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const [data, setData] = useState<ProjectTableRowType[]>(projectTable || [])
|
||||
const [globalFilter, setGlobalFilter] = useState('')
|
||||
|
||||
// Update data when projectTable changes
|
||||
useEffect(() => {
|
||||
setData(projectTable || [])
|
||||
}, [projectTable])
|
||||
|
||||
// Hooks
|
||||
const columns = useMemo<ColumnDef<ProjectTableRowType, any>[]>(
|
||||
() => [
|
||||
{
|
||||
id: 'select',
|
||||
header: ({ table }) => (
|
||||
<Checkbox
|
||||
{...{
|
||||
checked: table.getIsAllRowsSelected(),
|
||||
indeterminate: table.getIsSomeRowsSelected(),
|
||||
onChange: table.getToggleAllRowsSelectedHandler()
|
||||
}}
|
||||
/>
|
||||
),
|
||||
cell: ({ row }) => (
|
||||
<Checkbox
|
||||
{...{
|
||||
checked: row.getIsSelected(),
|
||||
disabled: !row.getCanSelect(),
|
||||
indeterminate: row.getIsSomeSelected(),
|
||||
onChange: row.getToggleSelectedHandler()
|
||||
}}
|
||||
/>
|
||||
)
|
||||
},
|
||||
columnHelper.accessor('title', {
|
||||
header: 'پروژه',
|
||||
cell: ({ row }) => (
|
||||
<div className='flex items-center gap-3'>
|
||||
<CustomAvatar src={row.original.avatar} size={34} />
|
||||
<div className='flex flex-col'>
|
||||
<Typography className='font-medium' color='text.primary'>
|
||||
{row.original.title}
|
||||
</Typography>
|
||||
<Typography variant='body2'>{row.original.subtitle}</Typography>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}),
|
||||
columnHelper.accessor('leader', {
|
||||
header: 'Leader',
|
||||
cell: ({ row }) => <Typography color='text.primary'>{row.original.leader}</Typography>
|
||||
}),
|
||||
columnHelper.accessor('avatarGroup', {
|
||||
header: 'تیم',
|
||||
cell: ({ row }) => (
|
||||
<AvatarGroup max={4} className='flex items-center pull-up'>
|
||||
{(row.original.avatarGroup || []).map((avatar, index) => (
|
||||
<CustomAvatar key={index} src={avatar} size={26} />
|
||||
))}
|
||||
</AvatarGroup>
|
||||
),
|
||||
enableSorting: false
|
||||
}),
|
||||
columnHelper.accessor('status', {
|
||||
header: 'پیشرفت',
|
||||
cell: ({ row }) => (
|
||||
<div className='flex items-center gap-3'>
|
||||
<LinearProgress color='primary' value={row.original.status} variant='determinate' className='is-20' />
|
||||
<Typography color='text.primary'>{`${row.original.status}%`}</Typography>
|
||||
</div>
|
||||
)
|
||||
}),
|
||||
columnHelper.accessor('actions', {
|
||||
header: 'عملیات',
|
||||
cell: () => (
|
||||
<OptionMenu
|
||||
iconClassName='text-textSecondary'
|
||||
options={[
|
||||
'جزئیات',
|
||||
'Archive',
|
||||
{ divider: true },
|
||||
{ text: 'حذف', menuItemProps: { className: 'text-error' } }
|
||||
]}
|
||||
/>
|
||||
),
|
||||
enableSorting: false
|
||||
})
|
||||
],
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[]
|
||||
)
|
||||
|
||||
const table = useReactTable({
|
||||
data: data as ProjectTableRowType[],
|
||||
columns,
|
||||
filterFns: {
|
||||
fuzzy: fuzzyFilter
|
||||
},
|
||||
state: {
|
||||
rowSelection,
|
||||
globalFilter
|
||||
},
|
||||
initialState: {
|
||||
pagination: {
|
||||
pageSize: 5
|
||||
}
|
||||
},
|
||||
enableRowSelection: true, //enable row selection for all rows
|
||||
// enableRowSelection: row => row.original.age > 18, // or enable row selection conditionally per row
|
||||
globalFilterFn: fuzzyFilter,
|
||||
onRowSelectionChange: setRowSelection,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
onGlobalFilterChange: setGlobalFilter,
|
||||
getFilteredRowModel: getFilteredRowModel(),
|
||||
getSortedRowModel: getSortedRowModel(),
|
||||
getPaginationRowModel: getPaginationRowModel(),
|
||||
getFacetedRowModel: getFacetedRowModel(),
|
||||
getFacetedUniqueValues: getFacetedUniqueValues(),
|
||||
getFacetedMinMaxValues: getFacetedMinMaxValues()
|
||||
})
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader
|
||||
className='flex-wrap gap-x-4 gap-y-2'
|
||||
title='Project List'
|
||||
action={
|
||||
<DebouncedInput
|
||||
value={globalFilter ?? ''}
|
||||
onChange={value => setGlobalFilter(String(value))}
|
||||
placeholder='Search Project'
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<div className='overflow-x-auto'>
|
||||
<table className={tableStyles.table}>
|
||||
<thead>
|
||||
{table.getHeaderGroups().map(headerGroup => (
|
||||
<tr key={headerGroup.id}>
|
||||
{headerGroup.headers.map(header => (
|
||||
<th key={header.id}>
|
||||
{header.isPlaceholder ? null : (
|
||||
<div
|
||||
className={classnames({
|
||||
'flex items-center': header.column.getIsSorted(),
|
||||
'cursor-pointer select-none': header.column.getCanSort()
|
||||
})}
|
||||
onClick={header.column.getToggleSortingHandler()}
|
||||
>
|
||||
{flexRender(header.column.columnDef.header, header.getContext())}
|
||||
{{
|
||||
asc: <i className='tabler-chevron-up text-xl' />,
|
||||
desc: <i className='tabler-chevron-down text-xl' />
|
||||
}[header.column.getIsSorted() as 'asc' | 'desc'] ?? null}
|
||||
</div>
|
||||
)}
|
||||
</th>
|
||||
))}
|
||||
</tr>
|
||||
))}
|
||||
</thead>
|
||||
<tbody>
|
||||
{table
|
||||
.getRowModel()
|
||||
.rows.slice(0, table.getState().pagination.pageSize)
|
||||
.map(row => {
|
||||
return (
|
||||
<tr key={row.id} className={classnames({ selected: row.getIsSelected() })}>
|
||||
{row.getVisibleCells().map(cell => (
|
||||
<td key={cell.id}>{flexRender(cell.column.columnDef.cell, cell.getContext())}</td>
|
||||
))}
|
||||
</tr>
|
||||
)
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<TablePagination
|
||||
rowsPerPageOptions={[5, 7, 10]}
|
||||
component={() => <TablePaginationComponent table={table} />}
|
||||
count={table.getFilteredRowModel().rows.length}
|
||||
rowsPerPage={table.getState().pagination.pageSize}
|
||||
page={table.getState().pagination.pageIndex}
|
||||
onPageChange={(_, page) => {
|
||||
table.setPageIndex(page)
|
||||
}}
|
||||
/>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
export default ProjectTables
|
||||
@@ -0,0 +1,102 @@
|
||||
// MUI Imports
|
||||
import Card from '@mui/material/Card'
|
||||
import CardHeader from '@mui/material/CardHeader'
|
||||
import CardContent from '@mui/material/CardContent'
|
||||
import Typography from '@mui/material/Typography'
|
||||
|
||||
// Third-party Imports
|
||||
import classnames from 'classnames'
|
||||
|
||||
// Components Imports
|
||||
import OptionMenu from '@core/components/option-menu'
|
||||
|
||||
type DataType = {
|
||||
title: string
|
||||
imgSrc: string
|
||||
subtitle: string
|
||||
trendNumber: number
|
||||
trend?: 'positive' | 'negative'
|
||||
}
|
||||
|
||||
// Vars
|
||||
const data: DataType[] = [
|
||||
{
|
||||
title: '$8.45k',
|
||||
subtitle: 'United States',
|
||||
trendNumber: 25.8,
|
||||
imgSrc: '/images/cards/us.png'
|
||||
},
|
||||
{
|
||||
title: '$7.78k',
|
||||
subtitle: 'Brazil',
|
||||
trendNumber: 16.2,
|
||||
trend: 'negative',
|
||||
imgSrc: '/images/cards/brazil.png'
|
||||
},
|
||||
{
|
||||
title: '$6.48k',
|
||||
subtitle: 'India',
|
||||
trendNumber: 12.3,
|
||||
imgSrc: '/images/cards/india.png'
|
||||
},
|
||||
{
|
||||
title: '$5.12k',
|
||||
subtitle: 'Australia',
|
||||
trendNumber: 11.9,
|
||||
trend: 'negative',
|
||||
imgSrc: '/images/cards/australia.png'
|
||||
},
|
||||
{
|
||||
title: '$4.45k',
|
||||
subtitle: 'France',
|
||||
trendNumber: 16.2,
|
||||
imgSrc: '/images/cards/france.png'
|
||||
},
|
||||
{
|
||||
title: '$3.90k',
|
||||
subtitle: 'China',
|
||||
trendNumber: 14.8,
|
||||
imgSrc: '/images/cards/china.png'
|
||||
}
|
||||
]
|
||||
|
||||
const SalesByCountries = () => {
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader
|
||||
title='Sales by Countries'
|
||||
subheader='Monthly Sales Overview'
|
||||
action={<OptionMenu options={['Last Week', 'Last Month', 'Last Year']} />}
|
||||
/>
|
||||
<CardContent className='flex flex-col gap-[1.0875rem]'>
|
||||
{data.map((item, index) => (
|
||||
<div key={index} className='flex items-center gap-4'>
|
||||
<img src={item.imgSrc} alt={item.subtitle} width={34} />
|
||||
<div className='flex flex-wrap justify-between items-center gap-x-4 gap-y-1 is-full'>
|
||||
<div className='flex flex-col'>
|
||||
<Typography className='font-medium' color='text.primary'>
|
||||
{item.title}
|
||||
</Typography>
|
||||
<Typography variant='body2'>{item.subtitle}</Typography>
|
||||
</div>
|
||||
<div className='flex items-center gap-1'>
|
||||
<i
|
||||
className={classnames(
|
||||
item.trend === 'negative' ? 'tabler-chevron-down text-error' : 'tabler-chevron-up text-success',
|
||||
'text-xl'
|
||||
)}
|
||||
/>
|
||||
<Typography
|
||||
variant='h6'
|
||||
color={`${item.trend === 'negative' ? 'error' : 'success'}.main`}
|
||||
>{`${item.trendNumber}%`}</Typography>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
export default SalesByCountries
|
||||
@@ -0,0 +1,74 @@
|
||||
'use client'
|
||||
|
||||
// MUI Imports
|
||||
import Card from '@mui/material/Card'
|
||||
import Divider from '@mui/material/Divider'
|
||||
import Typography from '@mui/material/Typography'
|
||||
import CardContent from '@mui/material/CardContent'
|
||||
import MuiLinearProgress from '@mui/material/LinearProgress'
|
||||
import { styled } from '@mui/material/styles'
|
||||
|
||||
// Custom Components Imports
|
||||
import CustomAvatar from '@core/components/mui/Avatar'
|
||||
|
||||
const LinearProgress = styled(MuiLinearProgress)(() => ({
|
||||
'&.MuiLinearProgress-colorInfo': { backgroundColor: 'var(--mui-palette-primary-main)' },
|
||||
'& .MuiLinearProgress-bar': {
|
||||
borderTopRightRadius: 0,
|
||||
borderBottomRightRadius: 0
|
||||
}
|
||||
}))
|
||||
|
||||
const SalesOverview = () => {
|
||||
return (
|
||||
<Card>
|
||||
<CardContent>
|
||||
<div className='flex items-start justify-between gap-3'>
|
||||
<div>
|
||||
<Typography>Sales Overview</Typography>
|
||||
<Typography variant='h4'>$42.5k</Typography>
|
||||
</div>
|
||||
<Typography color='success.main' className='font-medium'>
|
||||
+18.2%
|
||||
</Typography>
|
||||
</div>
|
||||
<div className='flex items-center justify-between mlb-[1.4375rem]'>
|
||||
<div className='flex flex-col plb-2.25'>
|
||||
<div className='flex items-center mbe-2.5 gap-x-[6px]'>
|
||||
<CustomAvatar skin='light' color='info' variant='rounded' size={24}>
|
||||
<i className='tabler-shopping-cart text-lg' />
|
||||
</CustomAvatar>
|
||||
<Typography>Order</Typography>
|
||||
</div>
|
||||
<Typography variant='h5'>62.2%</Typography>
|
||||
<Typography variant='body2' color='text.disabled'>
|
||||
6,440
|
||||
</Typography>
|
||||
</div>
|
||||
<Divider flexItem orientation='vertical'>
|
||||
<CustomAvatar skin='light' size={24} className='text-xs text-textDisabled bg-actionHover'>
|
||||
VS
|
||||
</CustomAvatar>
|
||||
</Divider>
|
||||
<div className='flex items-end flex-col plb-2'>
|
||||
<div className='flex items-center mbe-2 gap-x-[6px]'>
|
||||
<Typography color='text.secondary' className='m'>
|
||||
Visits
|
||||
</Typography>
|
||||
<CustomAvatar skin='light' variant='rounded' color='primary' size={24}>
|
||||
<i className='tabler-link text-lg' />
|
||||
</CustomAvatar>
|
||||
</div>
|
||||
<Typography variant='h5'>25.5%</Typography>
|
||||
<Typography variant='body2' color='text.disabled'>
|
||||
12,749
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
<LinearProgress value={65} color='info' variant='determinate' className='bs-2.5' />
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
export default SalesOverview
|
||||
@@ -0,0 +1,109 @@
|
||||
// MUI Imports
|
||||
import Card from '@mui/material/Card'
|
||||
import CardHeader from '@mui/material/CardHeader'
|
||||
import CardContent from '@mui/material/CardContent'
|
||||
import Typography from '@mui/material/Typography'
|
||||
import Chip from '@mui/material/Chip'
|
||||
|
||||
// Third-party Imports
|
||||
import classnames from 'classnames'
|
||||
|
||||
// Components Imports
|
||||
import OptionMenu from '@core/components/option-menu'
|
||||
import CustomAvatar from '@core/components/mui/Avatar'
|
||||
|
||||
type DataType = {
|
||||
icon: string
|
||||
title: string
|
||||
amount: string
|
||||
subtitle: string
|
||||
trendNumber: number
|
||||
trend?: 'positive' | 'negative'
|
||||
}
|
||||
|
||||
// Vars
|
||||
const data: DataType[] = [
|
||||
{
|
||||
title: 'Direct Source',
|
||||
subtitle: 'Direct link click',
|
||||
amount: '1.2k',
|
||||
trendNumber: 4.2,
|
||||
icon: 'tabler-shadow'
|
||||
},
|
||||
{
|
||||
title: 'Social Networks',
|
||||
subtitle: 'Social Channels',
|
||||
amount: '31.5k',
|
||||
trendNumber: 8.2,
|
||||
icon: 'tabler-globe'
|
||||
},
|
||||
{
|
||||
title: 'Email Newsletter',
|
||||
subtitle: 'Mail Campaigns',
|
||||
amount: '893',
|
||||
trendNumber: 2.4,
|
||||
icon: 'tabler-mail'
|
||||
},
|
||||
{
|
||||
title: 'Referrals',
|
||||
subtitle: 'Impact Radius Visits',
|
||||
amount: '342',
|
||||
trendNumber: 0.4,
|
||||
trend: 'negative',
|
||||
icon: 'tabler-external-link'
|
||||
},
|
||||
{
|
||||
title: 'ADVT',
|
||||
subtitle: 'Google ADVT',
|
||||
amount: '2.15k',
|
||||
trendNumber: 9.1,
|
||||
icon: 'tabler-ad'
|
||||
},
|
||||
{
|
||||
title: 'Other',
|
||||
subtitle: 'Many Sources',
|
||||
amount: '12.5k',
|
||||
trendNumber: 6.2,
|
||||
icon: 'tabler-star'
|
||||
}
|
||||
]
|
||||
|
||||
const SourceVisits = () => {
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader
|
||||
title='Source Visits'
|
||||
subheader='38.4k Visitors'
|
||||
action={<OptionMenu options={['Last Week', 'Last Month', 'Last Year']} />}
|
||||
/>
|
||||
<CardContent className='flex flex-col gap-6 md:gap-[1.0875rem] lg:gap-[1.5875rem]'>
|
||||
{data.map((item, index) => (
|
||||
<div key={index} className='flex items-center gap-4'>
|
||||
<CustomAvatar skin='light' variant='rounded' size={34}>
|
||||
<i className={classnames(item.icon, 'text-[22px] text-textSecondary')} />
|
||||
</CustomAvatar>
|
||||
<div className='flex flex-wrap justify-between items-center gap-x-4 gap-y-1 is-full'>
|
||||
<div className='flex flex-col'>
|
||||
<Typography className='font-medium' color='text.primary'>
|
||||
{item.title}
|
||||
</Typography>
|
||||
<Typography variant='body2'>{item.subtitle}</Typography>
|
||||
</div>
|
||||
<div className='flex items-center gap-4'>
|
||||
<Typography>{item.amount}</Typography>
|
||||
<Chip
|
||||
variant='tonal'
|
||||
size='small'
|
||||
color={item.trend === 'negative' ? 'error' : 'success'}
|
||||
label={`${item.trend === 'negative' ? '-' : '+'}${item.trendNumber}%`}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
export default SourceVisits
|
||||
@@ -0,0 +1,215 @@
|
||||
'use client'
|
||||
|
||||
// Next Imports
|
||||
import dynamic from 'next/dynamic'
|
||||
|
||||
// MUI Imports
|
||||
import Card from '@mui/material/Card'
|
||||
import CardHeader from '@mui/material/CardHeader'
|
||||
import CardContent from '@mui/material/CardContent'
|
||||
import Typography from '@mui/material/Typography'
|
||||
import { useTheme } from '@mui/material/styles'
|
||||
|
||||
// Third Party Imports
|
||||
import classnames from 'classnames'
|
||||
import type { ApexOptions } from 'apexcharts'
|
||||
|
||||
// Types Imports
|
||||
import type { ThemeColor } from '@core/types'
|
||||
|
||||
// Components Imports
|
||||
import OptionMenu from '@core/components/option-menu'
|
||||
import CustomAvatar from '@core/components/mui/Avatar'
|
||||
|
||||
// Styled Component Imports
|
||||
const AppReactApexCharts = dynamic(() => import('@/libs/styles/AppReactApexCharts'))
|
||||
|
||||
type DataType = {
|
||||
title: string
|
||||
subtitle: string
|
||||
avatarIcon: string
|
||||
avatarColor?: ThemeColor
|
||||
}
|
||||
|
||||
// Vars
|
||||
const data: DataType[] = [
|
||||
{
|
||||
title: 'New Tickets',
|
||||
subtitle: '142',
|
||||
avatarColor: 'primary',
|
||||
avatarIcon: 'tabler-ticket'
|
||||
},
|
||||
{
|
||||
title: 'Open Tickets',
|
||||
subtitle: '28',
|
||||
avatarColor: 'info',
|
||||
avatarIcon: 'tabler-check'
|
||||
},
|
||||
{
|
||||
title: 'Response Time',
|
||||
subtitle: '1 Day',
|
||||
avatarColor: 'warning',
|
||||
avatarIcon: 'tabler-clock'
|
||||
}
|
||||
]
|
||||
|
||||
const SupportTracker = () => {
|
||||
// Hooks
|
||||
const theme = useTheme()
|
||||
|
||||
// Vars
|
||||
const disabledText = 'var(--mui-palette-text-disabled)'
|
||||
|
||||
const options: ApexOptions = {
|
||||
stroke: { dashArray: 10 },
|
||||
labels: ['Completed Task'],
|
||||
colors: ['var(--mui-palette-primary-main)'],
|
||||
states: {
|
||||
hover: {
|
||||
filter: { type: 'none' }
|
||||
},
|
||||
active: {
|
||||
filter: { type: 'none' }
|
||||
}
|
||||
},
|
||||
fill: {
|
||||
type: 'gradient',
|
||||
gradient: {
|
||||
shade: 'dark',
|
||||
opacityTo: 0.5,
|
||||
opacityFrom: 1,
|
||||
shadeIntensity: 0.5,
|
||||
stops: [30, 70, 100],
|
||||
inverseColors: false,
|
||||
gradientToColors: ['var(--mui-palette-primary-main)']
|
||||
}
|
||||
},
|
||||
plotOptions: {
|
||||
radialBar: {
|
||||
endAngle: 130,
|
||||
startAngle: -140,
|
||||
hollow: { size: '60%' },
|
||||
track: { background: 'transparent' },
|
||||
dataLabels: {
|
||||
name: {
|
||||
offsetY: -24,
|
||||
color: disabledText,
|
||||
fontFamily: theme.typography.fontFamily,
|
||||
fontSize: theme.typography.body2.fontSize as string
|
||||
},
|
||||
value: {
|
||||
offsetY: 8,
|
||||
fontWeight: 500,
|
||||
formatter: value => `${value}%`,
|
||||
color: 'var(--mui-palette-text-primary)',
|
||||
fontFamily: theme.typography.fontFamily,
|
||||
fontSize: theme.typography.h2.fontSize as string
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
padding: {
|
||||
top: -18,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 14
|
||||
}
|
||||
},
|
||||
responsive: [
|
||||
{
|
||||
breakpoint: 1380,
|
||||
options: {
|
||||
grid: {
|
||||
padding: {
|
||||
top: 8,
|
||||
left: 12
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
breakpoint: 1280,
|
||||
options: {
|
||||
chart: {
|
||||
height: 325
|
||||
},
|
||||
grid: {
|
||||
padding: {
|
||||
top: 12,
|
||||
left: 12
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
breakpoint: 1201,
|
||||
options: {
|
||||
chart: {
|
||||
height: 362
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
breakpoint: 1135,
|
||||
options: {
|
||||
chart: {
|
||||
height: 350
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
breakpoint: 980,
|
||||
options: {
|
||||
chart: {
|
||||
height: 300
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
breakpoint: 900,
|
||||
options: {
|
||||
chart: {
|
||||
height: 350
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader
|
||||
title='Support Tracker'
|
||||
subheader='Last 7 Days'
|
||||
action={<OptionMenu options={['Refresh', 'Edit', 'Share']} />}
|
||||
/>
|
||||
<CardContent className='flex flex-col sm:flex-row items-center justify-between gap-7'>
|
||||
<div className='flex flex-col gap-6 is-full sm:is-[unset]'>
|
||||
<div className='flex flex-col'>
|
||||
<Typography variant='h2'>164</Typography>
|
||||
<Typography>Total Tickets</Typography>
|
||||
</div>
|
||||
<div className='flex flex-col gap-4 is-full'>
|
||||
{data.map((item, index) => (
|
||||
<div key={index} className='flex items-center gap-4'>
|
||||
<CustomAvatar skin='light' variant='rounded' color={item.avatarColor} size={34}>
|
||||
<i className={classnames(item.avatarIcon, 'text-[22px]')} />
|
||||
</CustomAvatar>
|
||||
<div className='flex flex-col'>
|
||||
<Typography className='font-medium' color='text.primary'>
|
||||
{item.title}
|
||||
</Typography>
|
||||
<Typography variant='body2'>{item.subtitle}</Typography>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<AppReactApexCharts type='radialBar' height={350} width='100%' series={[85]} options={options} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
export default SupportTracker
|
||||
@@ -0,0 +1,225 @@
|
||||
'use client'
|
||||
|
||||
// Next Imports
|
||||
import dynamic from 'next/dynamic'
|
||||
|
||||
// MUI Imports
|
||||
import Card from '@mui/material/Card'
|
||||
import CardHeader from '@mui/material/CardHeader'
|
||||
import CardContent from '@mui/material/CardContent'
|
||||
import Typography from '@mui/material/Typography'
|
||||
import { useTheme } from '@mui/material/styles'
|
||||
|
||||
// Third Party Imports
|
||||
import classnames from 'classnames'
|
||||
import type { ApexOptions } from 'apexcharts'
|
||||
|
||||
// Types Imports
|
||||
import type { ThemeColor } from '@core/types'
|
||||
|
||||
// Components Imports
|
||||
import OptionMenu from '@core/components/option-menu'
|
||||
import CustomAvatar from '@core/components/mui/Avatar'
|
||||
|
||||
// Styled Component Imports
|
||||
const AppReactApexCharts = dynamic(() => import('@/libs/styles/AppReactApexCharts'))
|
||||
|
||||
type DataType = {
|
||||
title: string
|
||||
amount: number
|
||||
subtitle: string
|
||||
avatarIcon: string
|
||||
avatarColor: ThemeColor
|
||||
amountDiff?: 'positive' | 'negative'
|
||||
}
|
||||
|
||||
// Vars
|
||||
const series = [
|
||||
{ name: 'Earning', data: [15, 10, 20, 8, 12, 18, 12, 5] },
|
||||
{ name: 'Expense', data: [-7, -10, -7, -12, -6, -9, -5, -8] }
|
||||
]
|
||||
|
||||
const data: DataType[] = [
|
||||
{
|
||||
title: 'Total Revenue',
|
||||
subtitle: 'Client Payment',
|
||||
amount: 126,
|
||||
avatarColor: 'primary',
|
||||
avatarIcon: 'tabler-brand-paypal'
|
||||
},
|
||||
{
|
||||
title: 'Total Sales',
|
||||
subtitle: 'Refund',
|
||||
amount: 98,
|
||||
avatarColor: 'secondary',
|
||||
avatarIcon: 'tabler-currency-dollar'
|
||||
}
|
||||
]
|
||||
|
||||
const TotalEarning = () => {
|
||||
// Hooks
|
||||
const theme = useTheme()
|
||||
|
||||
// Vars
|
||||
const options: ApexOptions = {
|
||||
chart: {
|
||||
stacked: true,
|
||||
parentHeightOffset: 0,
|
||||
toolbar: { show: false },
|
||||
zoom: {
|
||||
enabled: false
|
||||
}
|
||||
},
|
||||
legend: { show: false },
|
||||
tooltip: { enabled: false },
|
||||
dataLabels: { enabled: false },
|
||||
stroke: {
|
||||
width: 5,
|
||||
colors: ['var(--mui-palette-background-paper)']
|
||||
},
|
||||
colors: ['var(--mui-palette-primary-main)', 'var(--mui-palette-secondary-main)'],
|
||||
states: {
|
||||
hover: {
|
||||
filter: { type: 'none' }
|
||||
},
|
||||
active: {
|
||||
filter: { type: 'none' }
|
||||
}
|
||||
},
|
||||
plotOptions: {
|
||||
bar: {
|
||||
borderRadius: 7,
|
||||
columnWidth: '40%',
|
||||
borderRadiusApplication: 'around',
|
||||
borderRadiusWhenStacked: 'all'
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
borderColor: 'var(--mui-palette-divider)',
|
||||
yaxis: {
|
||||
lines: { show: false }
|
||||
},
|
||||
padding: {
|
||||
top: -56,
|
||||
left: -13,
|
||||
right: 0,
|
||||
bottom: -15
|
||||
}
|
||||
},
|
||||
xaxis: {
|
||||
labels: { show: false },
|
||||
axisTicks: { show: false },
|
||||
crosshairs: { opacity: 0 },
|
||||
axisBorder: { show: false }
|
||||
},
|
||||
yaxis: {
|
||||
labels: { show: false }
|
||||
},
|
||||
responsive: [
|
||||
{
|
||||
breakpoint: theme.breakpoints.values.xl,
|
||||
options: {
|
||||
plotOptions: {
|
||||
bar: { columnWidth: '50%' }
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
breakpoint: 1380,
|
||||
options: {
|
||||
plotOptions: {
|
||||
bar: {
|
||||
borderRadius: 5,
|
||||
columnWidth: '55%'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
breakpoint: theme.breakpoints.values.lg,
|
||||
options: {
|
||||
plotOptions: {
|
||||
bar: {
|
||||
borderRadius: 7,
|
||||
columnWidth: '40%'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
breakpoint: theme.breakpoints.values.md,
|
||||
options: {
|
||||
plotOptions: {
|
||||
bar: { columnWidth: '25%', borderRadius: 6 }
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
breakpoint: 680,
|
||||
options: {
|
||||
plotOptions: {
|
||||
bar: { columnWidth: '28%' }
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
breakpoint: theme.breakpoints.values.sm,
|
||||
options: {
|
||||
plotOptions: {
|
||||
bar: { columnWidth: '38%' }
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
breakpoint: 450,
|
||||
options: {
|
||||
plotOptions: {
|
||||
bar: { columnWidth: '55%' }
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader
|
||||
title='Total Earning'
|
||||
action={<OptionMenu options={['Refresh', 'Share', 'Update']} />}
|
||||
subheader={
|
||||
<div className='flex items-center gap-2'>
|
||||
<Typography variant='h2'>87%</Typography>
|
||||
<div className='flex items-center gap-1'>
|
||||
<i className='tabler-chevron-up text-xl text-success' />
|
||||
<Typography color='success.main'>25.8%</Typography>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
<CardContent className='flex flex-col gap-4'>
|
||||
<AppReactApexCharts type='bar' height={189} width='100%' series={series} options={options} />
|
||||
{data.map((item, index) => (
|
||||
<div key={index} className='flex items-center gap-4'>
|
||||
<CustomAvatar skin='light' variant='rounded' color={item.avatarColor} size={38}>
|
||||
<i className={classnames(item.avatarIcon, 'text-[22px]')} />
|
||||
</CustomAvatar>
|
||||
<div className='flex justify-between items-center is-full'>
|
||||
<div className='flex flex-col'>
|
||||
<Typography className='font-medium' color='text.primary'>
|
||||
{item.title}
|
||||
</Typography>
|
||||
<Typography variant='body2'>{item.subtitle}</Typography>
|
||||
</div>
|
||||
<Typography
|
||||
className='font-medium'
|
||||
color={`${item.amountDiff === 'negative' ? 'error' : 'success'}.main`}
|
||||
>{`${item.amountDiff === 'negative' ? '-' : '+'}$${item.amount}`}</Typography>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
export default TotalEarning
|
||||
@@ -0,0 +1,226 @@
|
||||
'use client'
|
||||
|
||||
// React Imports
|
||||
import { useState } from 'react'
|
||||
|
||||
// MUI Imports
|
||||
import Badge from '@mui/material/Badge'
|
||||
import Card from '@mui/material/Card'
|
||||
import Grid from '@mui/material/Grid2'
|
||||
import Typography from '@mui/material/Typography'
|
||||
import { useTheme } from '@mui/material/styles'
|
||||
|
||||
// Third-party Components
|
||||
import classnames from 'classnames'
|
||||
import { useKeenSlider } from 'keen-slider/react'
|
||||
import type { KeenSliderPlugin } from 'keen-slider/react'
|
||||
|
||||
// Components Imports
|
||||
import CustomAvatar from '@core/components/mui/Avatar'
|
||||
|
||||
import AppKeenSlider from '@/libs/styles/AppKeenSlider'
|
||||
|
||||
type DataType = {
|
||||
img: string
|
||||
title: string
|
||||
details: { [key: string]: string }
|
||||
}
|
||||
|
||||
// Vars
|
||||
const data: DataType[] = [
|
||||
{
|
||||
title: 'Traffic',
|
||||
img: '/images/cards/graphic-illustration-1.png',
|
||||
details: {
|
||||
Sessions: '28%',
|
||||
'Page Views': '3.1k',
|
||||
Leads: '1.2k',
|
||||
Conversions: '12%'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Spending',
|
||||
img: '/images/cards/graphic-illustration-2.png',
|
||||
details: {
|
||||
Spend: '12h',
|
||||
Orders: '18',
|
||||
Order: '127',
|
||||
Items: '2.3k'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Revenue Sources',
|
||||
img: '/images/cards/graphic-illustration-3.png',
|
||||
details: {
|
||||
Direct: '268',
|
||||
Organic: '890',
|
||||
Referral: '62',
|
||||
Campaign: '1.2k'
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
const Slides = () => {
|
||||
return (
|
||||
<>
|
||||
{data.map((slide: DataType, index: number) => {
|
||||
return (
|
||||
<div key={index} className={classnames('keen-slider__slide p-6 pbe-3 is-full')}>
|
||||
<Typography variant='h5' className='mbe-0.5 text-[var(--mui-palette-common-white)]'>
|
||||
Website Analytics
|
||||
</Typography>
|
||||
<Typography variant='subtitle2' className='mbe-3 text-[var(--mui-palette-common-white)]'>
|
||||
Total 28.5% Conversion Rate
|
||||
</Typography>
|
||||
<Grid container spacing={4} className='relative'>
|
||||
<Grid size={{ xs: 12, sm: 8 }} className='order-2 sm:order-1'>
|
||||
<div className='flex flex-col gap-4 sm:plb-6'>
|
||||
<Typography className='font-medium text-[var(--mui-palette-common-white)]'>{slide.title}</Typography>
|
||||
<Grid container spacing={4}>
|
||||
{Object.keys(slide.details).map((key: string, index: number) => {
|
||||
return (
|
||||
<Grid key={index} size={{ xs: 6 }}>
|
||||
<div className='flex items-center gap-0.5'>
|
||||
<CustomAvatar
|
||||
color='primary'
|
||||
variant='rounded'
|
||||
className='font-medium mie-2 text-white bg-[var(--mui-palette-primary-dark)] bs-[30px] is-12'
|
||||
>
|
||||
{slide.details[key]}
|
||||
</CustomAvatar>
|
||||
<Typography noWrap className='text-[var(--mui-palette-common-white)]'>
|
||||
{key}
|
||||
</Typography>
|
||||
</div>
|
||||
</Grid>
|
||||
)
|
||||
})}
|
||||
</Grid>
|
||||
</div>
|
||||
</Grid>
|
||||
<Grid size={{ xs: 12, sm: 4 }} className='flex justify-center order-1 sm:order-2'>
|
||||
<img
|
||||
src={slide.img}
|
||||
height={150}
|
||||
className='max-bs-[150px] lg:bs-[120px] xl:bs-[150px] drop-shadow-[0_4px_60px_rgba(0,0,0,0.5)] sm:absolute bottom-3 end-0'
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const WebsiteAnalyticsSlider = () => {
|
||||
// States
|
||||
const [loaded, setLoaded] = useState<boolean>(false)
|
||||
const [currentSlide, setCurrentSlide] = useState<number>(0)
|
||||
|
||||
// Hooks
|
||||
const theme = useTheme()
|
||||
|
||||
const ResizePlugin: KeenSliderPlugin = slider => {
|
||||
const observer = new ResizeObserver(function () {
|
||||
slider.update()
|
||||
})
|
||||
|
||||
slider.on('created', () => {
|
||||
observer.observe(slider.container)
|
||||
})
|
||||
slider.on('destroyed', () => {
|
||||
observer.unobserve(slider.container)
|
||||
})
|
||||
}
|
||||
|
||||
const [sliderRef, instanceRef] = useKeenSlider<HTMLDivElement>(
|
||||
{
|
||||
loop: true,
|
||||
initial: 0,
|
||||
rtl: theme.direction === 'rtl',
|
||||
slideChanged(slider) {
|
||||
setCurrentSlide(slider.track.details.rel)
|
||||
},
|
||||
created() {
|
||||
setLoaded(true)
|
||||
}
|
||||
},
|
||||
[
|
||||
ResizePlugin,
|
||||
slider => {
|
||||
let mouseOver = false
|
||||
let timeout: number | ReturnType<typeof setTimeout>
|
||||
|
||||
const clearNextTimeout = () => {
|
||||
clearTimeout(timeout as number)
|
||||
}
|
||||
|
||||
const nextTimeout = () => {
|
||||
clearTimeout(timeout as number)
|
||||
if (mouseOver) return
|
||||
timeout = setTimeout(() => {
|
||||
slider.next()
|
||||
}, 2000)
|
||||
}
|
||||
|
||||
slider.on('created', () => {
|
||||
slider.container.addEventListener('mouseover', () => {
|
||||
mouseOver = true
|
||||
clearNextTimeout()
|
||||
})
|
||||
slider.container.addEventListener('mouseout', () => {
|
||||
mouseOver = false
|
||||
nextTimeout()
|
||||
})
|
||||
nextTimeout()
|
||||
})
|
||||
slider.on('dragStarted', clearNextTimeout)
|
||||
slider.on('animationEnded', nextTimeout)
|
||||
slider.on('updated', nextTimeout)
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
return (
|
||||
<AppKeenSlider>
|
||||
<Card className='bg-primary'>
|
||||
<div ref={sliderRef} className='keen-slider relative'>
|
||||
{loaded && instanceRef.current && (
|
||||
<div className='swiper-dots absolute top-1 inline-end-6'>
|
||||
{[...Array(instanceRef.current.track.details.slides.length).keys()].map(idx => {
|
||||
return (
|
||||
<Badge
|
||||
key={idx}
|
||||
variant='dot'
|
||||
component='div'
|
||||
className={classnames({
|
||||
active: currentSlide === idx
|
||||
})}
|
||||
onClick={() => {
|
||||
instanceRef.current?.moveToIdx(idx)
|
||||
}}
|
||||
sx={{
|
||||
'& .MuiBadge-dot': {
|
||||
width: '8px !important',
|
||||
height: '8px !important',
|
||||
backgroundColor: 'var(--mui-palette-common-white) !important',
|
||||
opacity: 0.4
|
||||
},
|
||||
'&.active .MuiBadge-dot': {
|
||||
opacity: 1
|
||||
}
|
||||
}}
|
||||
></Badge>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
<Slides />
|
||||
</div>
|
||||
</Card>
|
||||
</AppKeenSlider>
|
||||
)
|
||||
}
|
||||
|
||||
export default WebsiteAnalyticsSlider
|
||||
Reference in New Issue
Block a user