Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
S
sweepstake
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Arjun Jhukal
sweepstake
Commits
aaff4469
Commit
aaff4469
authored
Oct 10, 2025
by
Arjun Jhukal
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
made anylytics dynamic
parent
7f758c97
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
229 additions
and
125 deletions
+229
-125
AdminAnalytics.tsx
src/app/(dashboard)/(admin)/AdminAnalytics.tsx
+177
-119
index.tsx
src/components/organism/Header/AdminHeader/index.tsx
+1
-2
index.tsx
...s/dashboard/adminDashboard/players/playerDetail/index.tsx
+0
-1
BannerSlider.tsx
.../pages/dashboard/adminDashboard/settings/BannerSlider.tsx
+0
-1
TransactionTable.tsx
...dashboard/adminDashboard/transaction/TransactionTable.tsx
+0
-1
index.tsx
src/components/pages/menus/index.tsx
+0
-1
store.ts
src/hooks/store.ts
+3
-0
dashboardApi.ts
src/services/dashboardApi.ts
+28
-0
dashboard.ts
src/types/dashboard.ts
+20
-0
No files found.
src/app/(dashboard)/(admin)/AdminAnalytics.tsx
View file @
aaff4469
import
{
IconButton
}
from
'@mui/material'
import
{
ArrowLeft
,
More
}
from
'@wandersonalwes/iconsax-react'
"use client"
;
import
{
useGetAnalyticsQuery
}
from
'@/services/dashboardApi'
;
import
{
AnalyticsProps
}
from
'@/types/dashboard'
;
import
{
formatDateTime
}
from
'@/utils/formatDateTime'
;
import
{
Box
,
ClickAwayListener
,
Fade
,
IconButton
,
List
,
ListItem
,
Paper
,
Popper
}
from
'@mui/material'
;
import
{
ArrowLeft
,
More
}
from
'@wandersonalwes/iconsax-react'
;
import
{
ApexOptions
}
from
'apexcharts'
;
import
React
from
'react'
import
React
,
{
useRef
,
useState
}
from
'react'
;
import
Chart
from
"react-apexcharts"
;
type
AnalyticsType
=
"today"
|
"this_week"
|
"this_month"
|
"this_year"
|
"all_time"
;
const
getColorByKey
=
(
key
:
string
,
isProfit
:
boolean
)
=>
{
const
palette
:
Record
<
string
,
string
>
=
{
total_deposits
:
"#22C55E"
,
total_withdraw
:
"#E14A5E"
,
total_transactions
:
"#3B82F6"
,
total_users
:
"#F59E0B"
,
};
return
isProfit
?
palette
[
key
]
||
"#6B7280"
:
"#EF4444"
;
};
// Skeleton loader
const
AnalyticsSkeleton
=
()
=>
(
<
div
className=
"col-span-1"
>
<
div
className=
"analytics__card p-4 rounded-[8px] border border-gray-100 shadow-sm animate-pulse"
>
<
div
className=
"flex justify-between items-center mb-3"
>
<
div
className=
"w-[80px] h-[10px] bg-gray-200 rounded"
></
div
>
<
div
className=
"w-[20px] h-[20px] bg-gray-200 rounded-full"
></
div
>
</
div
>
<
div
className=
"w-[120px] h-[10px] bg-gray-200 rounded mb-2"
></
div
>
<
div
className=
"flex justify-between items-end"
>
<
div
>
<
div
className=
"w-[60px] h-[16px] bg-gray-200 rounded mb-2"
></
div
>
<
div
className=
"w-[40px] h-[10px] bg-gray-200 rounded"
></
div
>
</
div
>
<
div
className=
"w-[140px] h-[80px] bg-gray-200 rounded"
></
div
>
</
div
>
</
div
>
</
div
>
);
export
default
function
AdminAnalytics
()
{
const
charts
=
[
{
title
:
'Total Revenue'
,
subtitle
:
'Jul 23 - Jul 30 (2025)'
,
value
:
'$2.689M'
,
change
:
16
,
isIncrease
:
true
,
chartOptions
:
{
chart
:
{
type
:
'area'
,
sparkline
:
{
enabled
:
true
}
},
stroke
:
{
curve
:
'smooth'
,
width
:
2
},
const
[
currentType
,
setCurrentType
]
=
useState
<
AnalyticsType
>
(
"this_week"
);
const
{
data
,
isLoading
}
=
useGetAnalyticsQuery
({
type
:
currentType
});
const
[
openIndex
,
setOpenIndex
]
=
useState
<
number
|
null
>
(
null
);
const
anchorRefs
=
useRef
<
(
HTMLButtonElement
|
null
)[]
>
([]);
const
handleToggle
=
(
index
:
number
)
=>
{
setOpenIndex
(
prev
=>
(
prev
===
index
?
null
:
index
));
};
const
handleClose
=
(
event
:
MouseEvent
|
TouchEvent
)
=>
{
if
(
anchorRefs
.
current
.
some
(
ref
=>
ref
?.
contains
(
event
.
target
as
Node
)))
return
;
setOpenIndex
(
null
);
};
const
handleSelect
=
(
type
:
AnalyticsType
)
=>
{
setCurrentType
(
type
);
setOpenIndex
(
null
);
};
if
(
isLoading
)
{
return
(
<
div
className=
"grid md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4 analytics__wrapper mb-5"
>
{
Array
.
from
({
length
:
4
}).
map
((
_
,
i
)
=>
(
<
AnalyticsSkeleton
key=
{
i
}
/>
))
}
</
div
>
);
}
if
(
!
data
?.
data
)
return
null
;
const
analyticsData
=
data
.
data
;
const
chartKeys
=
Object
.
keys
(
analyticsData
)
as
(
keyof
typeof
analyticsData
)[];
const
charts
=
chartKeys
.
map
((
key
)
=>
{
const
item
:
AnalyticsProps
=
analyticsData
[
key
];
const
color
=
getColorByKey
(
key
,
item
.
profit
);
const
chartOptions
:
ApexOptions
=
{
chart
:
{
type
:
"area"
,
sparkline
:
{
enabled
:
true
}
},
stroke
:
{
curve
:
"smooth"
,
width
:
2
},
fill
:
{
type
:
'gradient'
,
type
:
"gradient"
,
gradient
:
{
shade
:
'light'
,
type
:
'vertical'
,
shade
:
"light"
,
type
:
"vertical"
,
shadeIntensity
:
1
,
gradientToColors
:
[
'#E14A5E'
],
opacityFrom
:
1
,
opacityTo
:
0
,
stops
:
[
0
,
100
],
},
},
colors
:
[
'#E14A5E'
],
tooltip
:
{
enabled
:
true
},
}
as
ApexOptions
,
chartSeries
:
[{
name
:
'Revenue'
,
data
:
[
400
,
600
,
700
,
1200
,
1400
,
1800
,
2500
]
}],
},
{
title
:
'New Users'
,
subtitle
:
'Jul 23 - Jul 30 (2025)'
,
value
:
'3.2K'
,
change
:
8
,
isIncrease
:
true
,
chartOptions
:
{
chart
:
{
type
:
'area'
,
sparkline
:
{
enabled
:
true
}
},
stroke
:
{
curve
:
'straight'
,
width
:
2
},
fill
:
{
type
:
'gradient'
,
gradient
:
{
shade
:
'dark'
,
type
:
'vertical'
,
shadeIntensity
:
0.8
,
gradientToColors
:
[
'#22C55E'
],
gradientToColors
:
[
color
],
opacityFrom
:
0.8
,
opacityTo
:
0
,
stops
:
[
0
,
100
],
},
},
colors
:
[
'#22C55E'
],
tooltip
:
{
enabled
:
true
},
}
as
ApexOptions
,
chartSeries
:
[{
name
:
'Users'
,
data
:
[
200
,
400
,
600
,
700
,
900
,
1200
,
1500
]
}],
},
{
title
:
'Churn Rate'
,
subtitle
:
'Jul 23 - Jul 30 (2025)'
,
value
:
'5.4%'
,
change
:
-
4
,
isIncrease
:
false
,
chartOptions
:
{
chart
:
{
type
:
'area'
,
sparkline
:
{
enabled
:
true
}
},
stroke
:
{
curve
:
'smooth'
,
width
:
2
},
fill
:
{
type
:
'gradient'
,
gradient
:
{
shade
:
'light'
,
type
:
'vertical'
,
shadeIntensity
:
1
,
gradientToColors
:
[
'#F59E0B'
],
opacityFrom
:
1
,
opacityTo
:
0
,
stops
:
[
0
,
100
],
},
},
colors
:
[
'#F59E0B'
],
tooltip
:
{
enabled
:
true
},
}
as
ApexOptions
,
chartSeries
:
[{
name
:
'Churn'
,
data
:
[
8
,
7
,
6
,
5
,
5
,
4
,
3
]
}],
},
{
title
:
'Support Tickets'
,
subtitle
:
'Jul 23 - Jul 30 (2025)'
,
value
:
'1.2K'
,
change
:
-
12
,
isIncrease
:
false
,
chartOptions
:
{
chart
:
{
type
:
'area'
,
sparkline
:
{
enabled
:
true
}
},
stroke
:
{
curve
:
'stepline'
,
width
:
2
},
fill
:
{
type
:
'gradient'
,
gradient
:
{
shade
:
'dark'
,
type
:
'vertical'
,
shadeIntensity
:
0.8
,
gradientToColors
:
[
'#3B82F6'
],
opacityFrom
:
0.7
,
opacityTo
:
0
,
stops
:
[
0
,
100
],
},
},
colors
:
[
'#3B82F6'
],
colors
:
[
color
],
tooltip
:
{
enabled
:
true
},
}
as
ApexOptions
,
chartSeries
:
[{
name
:
'Tickets'
,
data
:
[
50
,
45
,
40
,
38
,
35
,
30
,
25
]
}],
},
};
const
chartSeries
=
[
{
name
:
item
.
name
,
data
:
item
.
breakdown
??
[
0
,
0
,
0
,
0
,
0
,
0
,
0
]
},
];
return
{
key
,
title
:
item
.
name
,
value
:
item
.
current
,
change
:
item
.
percent
,
isIncrease
:
item
.
profit
,
message
:
item
.
message
,
start_date
:
item
.
start_date
,
end_date
:
item
.
end_date
,
chartOptions
,
chartSeries
,
};
});
// const chartSeries = [
// {
// name: "Revenue",
// data: [400, 600, 700, 1200, 1400, 1800, 2500],
// },
// ];
return
(
<
div
className=
"grid md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4 analytics__wrapper mb-5"
>
{
charts
.
map
((
chart
,
index
)
=>
(
<
div
className=
"col-span-1"
key=
{
index
}
>
{
charts
.
map
((
chart
,
index
)
=>
{
const
{
date
:
startDate
}
=
formatDateTime
(
chart
.
start_date
);
const
{
date
}
=
formatDateTime
(
chart
.
end_date
);
const
open
=
openIndex
===
index
;
const
id
=
open
?
`analytics-action-${index}`
:
undefined
;
return
(
<
div
className=
"col-span-1"
key=
{
index
}
>
<
div
className=
"analytics__card p-4 rounded-[8px]"
>
<
div
className=
"card__title flex justify-between items-center mb-2"
>
<
div
className=
"title"
>
<
strong
className=
'text-[12px] leading-[120%] text-title font-[500] mb-1 block'
>
Total Revenue
</
strong
>
<
span
className=
"text-[10px] text-para-light leading-[120%] font-[500]"
>
Jul 23 - Jul 30 (2025)
</
span
>
<
strong
className=
'text-[12px] leading-[120%] text-title font-[500] mb-1 block'
>
{
chart
.
title
}
</
strong
>
<
span
className=
"text-[10px] text-para-light leading-[120%] font-[500]"
>
{
startDate
}
-
{
date
}
</
span
>
</
div
>
<
div
className=
"card__action"
>
<
IconButton
>
<
More
className=
'rotate-90'
variant=
'TwoTone'
/>
<
Box
>
<
IconButton
aria
-
describedby=
{
id
}
ref=
{
(
el
:
HTMLButtonElement
|
null
)
=>
{
anchorRefs
.
current
[
index
]
=
el
;
}
}
onClick=
{
()
=>
handleToggle
(
index
)
}
>
<
More
className=
"rotate-90"
variant=
"TwoTone"
/>
</
IconButton
>
</
div
>
<
Popper
open=
{
open
}
anchorEl=
{
anchorRefs
.
current
[
index
]
}
placement=
"bottom-end"
transition
style=
{
{
zIndex
:
1300
}
}
id=
{
id
}
>
{
({
TransitionProps
})
=>
(
<
Fade
{
...
TransitionProps
}
timeout=
{
200
}
>
<
Paper
elevation=
{
3
}
sx=
{
{
width
:
180
,
borderRadius
:
2
,
mt
:
1
,
}
}
>
<
ClickAwayListener
onClickAway=
{
handleClose
}
>
<
List
>
{
[
{
label
:
"Today"
,
value
:
"today"
},
{
label
:
"This Week"
,
value
:
"this_week"
},
{
label
:
"This Month"
,
value
:
"this_month"
},
{
label
:
"This Year"
,
value
:
"this_year"
},
{
label
:
"All Time"
,
value
:
"all_time"
},
].
map
((
item
)
=>
(
<
ListItem
key=
{
item
.
value
}
>
<
button
onClick=
{
()
=>
handleSelect
(
item
.
value
as
AnalyticsType
)
}
className=
{
`block w-full text-left py-2 px-4 hover:bg-[#FBF4FB] text-sm ${currentType === item.value ? "font-semibold text-primary" : ""}`
}
>
{
item
.
label
}
</
button
>
</
ListItem
>
))
}
</
List
>
</
ClickAwayListener
>
</
Paper
>
</
Fade
>
)
}
</
Popper
>
</
Box
>
</
div
>
<
div
className=
"card__content"
>
<
div
className=
"flex gap-2 items-end justify-between mb-2"
>
<
div
className=
"content flex gap-2 items-center"
>
<
strong
className=
'text-[16px] leading-[120%] font-[600] text-title'
>
$2.689M
</
strong
>
<
strong
className=
'text-[16px] leading-[120%] font-[600] text-title'
>
$
{
chart
.
value
}
</
strong
>
<
p
className=
{
`flex gap-1 items-center ${chart.isIncrease ? "increase" : "decrease"}`
}
>
<
span
className=
"arrow w-[18px] h-[18px] rounded-full flex justify-center items-center "
><
ArrowLeft
size=
{
12
}
/></
span
>
16%
</
p
>
<
span
className=
"arrow w-[18px] h-[18px] rounded-full flex justify-center items-center "
>
<
ArrowLeft
size=
{
12
}
/>
</
span
>
{
chart
.
change
}
%
</
p
>
</
div
>
<
div
className=
"relative aspect-[72/68] w-full max-w-[144px] h-[100px] text-right"
>
<
Chart
...
...
@@ -151,13 +209,13 @@ export default function AdminAnalytics() {
height=
"100%"
/>
</
div
>
</
div
>
<
p
className=
'text-[12px] font-[500] text-para-light'
>
compared to previous week
</
p
>
<
p
className=
'text-[12px] font-[500] text-para-light'
>
{
chart
.
message
}
</
p
>
</
div
>
</
div
>
</
div
>
))
}
);
})
}
</
div
>
)
)
;
}
src/components/organism/Header/AdminHeader/index.tsx
View file @
aaff4469
...
...
@@ -19,13 +19,12 @@ export default function AdminHeader() {
const
[
page
,
setPage
]
=
React
.
useState
(
1
);
const
[
pageSize
,
setPageSize
]
=
React
.
useState
(
10
);
const
{
data
}
=
useGetAllNotificationQuery
({
page
:
page
,
per_page
:
pageSize
});
console
.
log
(
data
);
return
(
<
Box
className=
'flex items-center gap-4 justify-between w-full'
>
<
AdminSearchBar
/>
<
div
className=
"right flex items-center gap-4"
>
<
CreatNewRecord
/>
<
NotificationPage
notifications=
{
data
?.
data
?.
data
||
[]
}
pagination=
{
data
?.
data
?.
pagination
}
/>
<
NotificationPage
notifications=
{
data
?.
data
?.
data
||
[]
}
pagination=
{
data
?.
data
?.
pagination
}
/>
<
Profile
/>
</
div
>
</
Box
>
...
...
src/components/pages/dashboard/adminDashboard/players/playerDetail/index.tsx
View file @
aaff4469
...
...
@@ -51,7 +51,6 @@ export default function PlayerDetailPage({ id }: { id: number }) {
const
{
date
}
=
formatDateTime
(
data
?.
data
?.
registered_date
as
string
);
console
.
log
(
"user balance"
,
userBalance
);
return
(
<>
<
section
className=
"player__detail__intro mb-12 lg:mb-16"
>
...
...
src/components/pages/dashboard/adminDashboard/settings/BannerSlider.tsx
View file @
aaff4469
...
...
@@ -35,7 +35,6 @@ export default function BannerSlider() {
const
{
data
,
isLoading
}
=
useGetAllBannerQuery
();
const
[
updateBanner
,
{
isLoading
:
updating
}]
=
useUpdateBannerMutation
();
console
.
log
(
"banner data"
,
data
);
const
formik
=
useFormik
({
initialValues
:
{
banners
:
data
?.
data
?.
length
...
...
src/components/pages/dashboard/adminDashboard/transaction/TransactionTable.tsx
View file @
aaff4469
...
...
@@ -34,7 +34,6 @@ export default function TransactionTable({ user_id, game_id, search }: { user_id
const
{
data
,
isLoading
:
loadingTransaction
}
=
useGetAllTransactionQuery
(
queryArgs
);
console
.
log
(
"all transaction"
,
data
);
const
tableData
=
useMemo
(()
=>
data
?.
data
?.
data
||
[],
[
data
]);
const
columns
=
useMemo
<
ColumnDef
<
SingleDepositProps
>
[]
>
(()
=>
[
...
...
src/components/pages/menus/index.tsx
View file @
aaff4469
...
...
@@ -17,7 +17,6 @@ export default function MenuPage() {
const
dispatch
=
useAppDispatch
();
const
[
selectedMenus
,
setSelectedMenus
]
=
React
.
useState
<
any
[]
>
([]);
console
.
log
(
"menus"
,
{
menus
,
selectedMenus
});
React
.
useEffect
(()
=>
{
...
...
src/hooks/store.ts
View file @
aaff4469
...
...
@@ -12,6 +12,7 @@ import { settingApi } from "@/services/settingApi";
import
{
pageApi
}
from
"@/services/pageApi"
;
import
{
notificationApi
}
from
"@/services/notificationApi"
;
import
{
menuApi
,
userMenuApi
}
from
"@/services/menuApi"
;
import
{
dashboardApi
}
from
"@/services/dashboardApi"
;
export
const
store
=
configureStore
({
reducer
:
{
...
...
@@ -29,6 +30,7 @@ export const store = configureStore({
[
notificationApi
.
reducerPath
]:
notificationApi
.
reducer
,
[
menuApi
.
reducerPath
]:
menuApi
.
reducer
,
[
userMenuApi
.
reducerPath
]:
userMenuApi
.
reducer
,
[
dashboardApi
.
reducerPath
]:
dashboardApi
.
reducer
,
},
middleware
:
(
getDefaultMiddleware
)
=>
getDefaultMiddleware
()
...
...
@@ -43,6 +45,7 @@ export const store = configureStore({
.
concat
(
notificationApi
.
middleware
)
.
concat
(
menuApi
.
middleware
)
.
concat
(
userMenuApi
.
middleware
)
.
concat
(
dashboardApi
.
middleware
)
})
export
type
RootState
=
ReturnType
<
typeof
store
.
getState
>
;
...
...
src/services/dashboardApi.ts
0 → 100644
View file @
aaff4469
import
{
createApi
}
from
"@reduxjs/toolkit/query/react"
;
import
{
baseQuery
}
from
"./baseQuery"
;
import
{
AnalyticsResponse
}
from
"@/types/dashboard"
;
export
const
dashboardApi
=
createApi
({
reducerPath
:
"dashboardApi"
,
baseQuery
:
baseQuery
,
tagTypes
:
[
"Analytics"
,
"Transactions"
],
endpoints
:
(
builder
)
=>
({
getAnalytics
:
builder
.
query
<
AnalyticsResponse
,
{
type
:
string
}
>
({
query
:
({
type
})
=>
({
url
:
`/api/admin/dashboard/overview?type=
${
type
}
`
,
method
:
"GET"
,
}),
providesTags
:
[
"Analytics"
],
}),
getAdminTransactions
:
builder
.
query
<
any
,
void
>
({
query
:
()
=>
({
url
:
`/api/admin/dashboard/deposits`
,
method
:
"GET"
,
}),
providesTags
:
[
"Transactions"
],
})
})
})
export
const
{
useGetAnalyticsQuery
,
useGetAdminTransactionsQuery
}
=
dashboardApi
;
\ No newline at end of file
src/types/dashboard.ts
0 → 100644
View file @
aaff4469
export
type
AnalyticsProps
=
{
name
:
string
,
start_date
:
string
,
end_date
:
string
,
current
:
number
,
previous
:
number
,
percent
:
number
,
profit
:
boolean
,
message
:
string
,
breakdown
:
number
[]
}
export
interface
AnalyticsResponse
{
data
:
{
total_deposits
:
AnalyticsProps
,
total_transactions
:
AnalyticsProps
,
total_users
:
AnalyticsProps
,
total_withdraw
:
AnalyticsProps
,
}
}
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment