First commit

This commit is contained in:
2026-02-19 01:15:36 +03:30
commit a898eccbff
1216 changed files with 189771 additions and 0 deletions
@@ -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