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
bd1b5dd7
Commit
bd1b5dd7
authored
Oct 17, 2025
by
Arjun Jhukal
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
updated the chagne password functionality at logged in user profile
parent
bca8509d
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
202 additions
and
341 deletions
+202
-341
AccountTab.tsx
...p/(dashboard)/(user)/(privateUser)/account/AccountTab.tsx
+5
-1
ResetPasswordForm.tsx
...components/pages/auth/resetPassword/ResetPasswordForm.tsx
+136
-0
index.tsx
src/components/pages/auth/resetPassword/index.tsx
+7
-129
Activities.tsx
...pages/dashboard/adminDashboard/activityLog/Activities.tsx
+27
-197
index.tsx
...ents/pages/dashboard/adminDashboard/activityLog/index.tsx
+2
-2
ReduxHydrator.tsx
src/routes/ReduxHydrator.tsx
+4
-4
ServerPrivate.tsx
src/routes/ServerPrivate.tsx
+3
-3
notificationApi.tsx
src/services/notificationApi.tsx
+5
-4
notification.ts
src/types/notification.ts
+13
-1
No files found.
src/app/(dashboard)/(user)/(privateUser)/account/AccountTab.tsx
View file @
bd1b5dd7
...
...
@@ -2,6 +2,7 @@ import GlassWrapper from '@/components/molecules/GlassWrapper';
import
TabController
from
'@/components/molecules/TabController'
;
import
UserProfileCard
from
"@/components/organism/Cards/UserProfileCard"
;
import
ResetPasswordForm
from
'@/components/pages/auth/resetPassword/ResetPasswordForm'
;
import
EditUserProfile
from
'@/components/pages/dashboard/userDashboard/account/profile/editProfile'
;
import
EditUserWallet
from
'@/components/pages/dashboard/userDashboard/account/profile/editUserWallet'
;
import
{
useAppSelector
}
from
'@/hooks/hook'
;
...
...
@@ -14,11 +15,14 @@ export default function AccountTab() {
const
{
data
,
isLoading
}
=
useGetUserGameBalanceQuery
();
const
[
currentActiveTab
,
setCurrentActiveTab
]
=
React
.
useState
<
profileTabProps
>
(
"account_detail"
);
const
handleTabChange
=
(
tab
:
string
)
=>
{
setCurrentActiveTab
(
tab
as
profileTabProps
);
};
const
user
=
useAppSelector
((
state
)
=>
state
.
auth
.
user
);
console
.
log
(
user
);
const
renderTabContent
=
()
=>
{
switch
(
currentActiveTab
)
{
case
"account_detail"
:
...
...
@@ -27,7 +31,7 @@ export default function AccountTab() {
return
<
EditUserWallet
/>;
case
"change_password"
:
return
(<
div
className=
"px-8 lg:pt-8 pb-8"
>
<
h2
>
Change Password
</
h2
>
<
ResetPasswordForm
email=
{
user
?.
email
}
/
>
</
div
>);
default
:
return
null
;
...
...
src/components/pages/auth/resetPassword/ResetPasswordForm.tsx
0 → 100644
View file @
bd1b5dd7
import
PasswordField
from
'@/components/molecules/PasswordField'
import
{
useAppDispatch
}
from
'@/hooks/hook'
import
{
PATH
}
from
'@/routes/PATH'
import
{
useResetPasswordMutation
}
from
'@/services/authApi'
import
{
clearTokens
}
from
'@/slice/authSlice'
import
{
showToast
,
ToastVariant
}
from
'@/slice/toastSlice'
import
{
Box
,
InputLabel
,
OutlinedInput
}
from
'@mui/material'
import
{
ArrowLeft
}
from
'@wandersonalwes/iconsax-react'
import
{
useFormik
}
from
'formik'
import
Link
from
'next/link'
import
{
useRouter
}
from
'next/navigation'
import
React
from
'react'
import
*
as
Yup
from
'yup'
;
const
validationSchema
=
Yup
.
object
().
shape
({
emailAddress
:
Yup
.
string
()
.
email
(
'Must be a valid email'
)
.
max
(
255
)
.
required
(
'Email is required'
),
password
:
Yup
.
string
()
.
required
(
'Password is required'
)
.
test
(
'no-leading-trailing-whitespace'
,
'Password cannot start or end with spaces'
,
(
value
)
=>
value
===
value
?.
trim
()
)
.
max
(
16
,
'Password must be less than 10 characters'
),
confirmPassword
:
Yup
.
string
()
.
oneOf
([
Yup
.
ref
(
'password'
)],
'Passwords must match'
)
.
required
(
'Confirm Password is required'
),
})
export
default
function
ResetPasswordForm
({
email
}:
{
email
?:
string
})
{
const
router
=
useRouter
();
const
dispatch
=
useAppDispatch
();
const
initialValues
=
{
emailAddress
:
email
||
""
,
password
:
""
,
confirmPassword
:
""
,
}
const
[
resetPassword
,
{
isLoading
}]
=
useResetPasswordMutation
();
const
{
handleSubmit
,
handleBlur
,
handleChange
,
errors
,
dirty
,
values
,
touched
}
=
useFormik
(
{
initialValues
,
validationSchema
,
onSubmit
:
async
(
values
)
=>
{
try
{
const
response
=
await
resetPassword
({
email
:
values
.
emailAddress
,
password
:
values
.
password
,
password_confirmation
:
values
.
confirmPassword
,
}).
unwrap
();
dispatch
(
showToast
({
message
:
response
?.
message
||
"New password is updated"
,
variant
:
ToastVariant
.
SUCCESS
,
autoTime
:
true
,
}),
);
dispatch
(
clearTokens
());
router
.
replace
(
PATH
.
AUTH
.
LOGIN
.
ROOT
);
}
catch
(
e
:
any
)
{
console
.
log
(
"Error"
,
e
);
dispatch
(
showToast
({
message
:
e
?.
data
?.
message
||
"Unable to reset password. Try again later"
,
variant
:
ToastVariant
.
ERROR
,
autoTime
:
true
,
}),
);
}
}
}
)
return
(
<
form
action=
""
onSubmit=
{
handleSubmit
}
>
<
div
className=
"grid md:grid-cols-2 gap-x-3 gap-y-5"
>
{
!
email
?
<
div
className=
"col-span-2"
>
<
div
className=
"input_field"
>
<
InputLabel
htmlFor=
"emailAddress"
>
Email Address*
</
InputLabel
>
<
OutlinedInput
name=
'emailAddress'
id=
'emailAddress'
placeholder=
'example@example.com'
value=
{
values
.
emailAddress
}
onChange=
{
handleChange
}
onBlur=
{
handleBlur
}
error=
{
Boolean
(
touched
.
emailAddress
&&
errors
.
emailAddress
)
}
/>
{
touched
.
emailAddress
&&
errors
.
emailAddress
?
<
span
className=
"error "
>
{
errors
.
emailAddress
}
</
span
>
:
null
}
</
div
>
</
div
>
:
""
}
<
div
className=
"col-span-2"
>
<
div
className=
"input_field"
>
<
PasswordField
name=
"password"
label=
"Password*"
placeholder=
"XXXXXXX"
value=
{
values
.
password
}
onChange=
{
handleChange
}
onBlur=
{
handleBlur
}
error=
{
touched
.
password
?
errors
.
password
:
undefined
}
/>
</
div
>
</
div
>
<
div
className=
"col-span-2"
>
<
div
className=
"input_field"
>
<
PasswordField
name=
"confirmPassword"
label=
"Confirm Password*"
placeholder=
"XXXXXXX"
value=
{
values
.
confirmPassword
}
onChange=
{
handleChange
}
onBlur=
{
handleBlur
}
error=
{
touched
.
confirmPassword
?
errors
.
confirmPassword
:
undefined
}
/>
</
div
>
</
div
>
</
div
>
<
div
className=
"action__group text-center flex flex-col gap-4 mt-8"
>
<
button
className=
'ss-btn bg-primary-grad'
disabled=
{
!
dirty
}
>
{
isLoading
?
"Changing Password"
:
"Reset Password"
}
</
button
>
<
Link
href=
{
PATH
.
DASHBOARD
.
ROOT
}
className=
'ss-btn bg-secondary-grad'
>
Login
</
Link
>
</
div
>
</
form
>
)
}
src/components/pages/auth/resetPassword/index.tsx
View file @
bd1b5dd7
"use client"
;
import
React
,
{
useEffect
,
useState
}
from
'react'
import
React
from
'react'
import
AuthMessageBlock
from
'../authMessageBlock'
import
{
Box
,
InputLabel
,
OutlinedInput
}
from
'@mui/material'
import
PasswordField
from
'@/components/molecules/PasswordField'
import
{
ArrowLeft
}
from
'@wandersonalwes/iconsax-react'
import
Link
from
'next/link'
import
{
PATH
}
from
'@/routes/PATH'
import
*
as
Yup
from
'yup'
;
import
{
useFormik
}
from
'formik'
;
import
{
useAppDispatch
}
from
'@/hooks/hook'
import
{
showToast
,
ToastVariant
}
from
'@/slice/toastSlice'
;
import
{
useResetPasswordMutation
}
from
'@/services/authApi'
;
import
{
useRouter
,
useSearchParams
}
from
'next/navigation'
;
import
ResetPasswordForm
from
'./ResetPasswordForm'
;
import
{
Box
}
from
'@mui/material'
;
import
Link
from
'next/link'
;
import
{
ArrowLeft
}
from
'@wandersonalwes/iconsax-react'
;
import
{
PATH
}
from
'@/routes/PATH'
;
const
validationSchema
=
Yup
.
object
().
shape
({
emailAddress
:
Yup
.
string
()
.
email
(
'Must be a valid email'
)
.
max
(
255
)
.
required
(
'Email is required'
),
password
:
Yup
.
string
()
.
required
(
'Password is required'
)
.
test
(
'no-leading-trailing-whitespace'
,
'Password cannot start or end with spaces'
,
(
value
)
=>
value
===
value
?.
trim
()
)
.
max
(
16
,
'Password must be less than 10 characters'
),
confirmPassword
:
Yup
.
string
()
.
oneOf
([
Yup
.
ref
(
'password'
)],
'Passwords must match'
)
.
required
(
'Confirm Password is required'
),
})
export
default
function
ResetPasswordPage
()
{
const
router
=
useRouter
();
const
dispatch
=
useAppDispatch
();
const
initialValues
=
{
emailAddress
:
""
,
password
:
""
,
confirmPassword
:
""
,
}
const
[
resetPassword
,
{
isLoading
}]
=
useResetPasswordMutation
();
const
{
handleSubmit
,
handleBlur
,
handleChange
,
errors
,
dirty
,
values
,
touched
}
=
useFormik
(
{
initialValues
,
validationSchema
,
onSubmit
:
async
(
values
)
=>
{
try
{
const
response
=
await
resetPassword
({
email
:
values
.
emailAddress
,
password
:
values
.
password
,
password_confirmation
:
values
.
confirmPassword
,
}).
unwrap
();
dispatch
(
showToast
({
message
:
response
?.
message
||
"New password is updated"
,
variant
:
ToastVariant
.
SUCCESS
,
autoTime
:
true
,
}),
);
router
.
replace
(
PATH
.
AUTH
.
LOGIN
.
ROOT
);
}
catch
(
e
:
any
)
{
console
.
log
(
"Error"
,
e
);
dispatch
(
showToast
({
message
:
e
?.
data
?.
message
||
"Unable to reset password. Try again later"
,
variant
:
ToastVariant
.
ERROR
,
autoTime
:
true
,
}),
);
}
}
}
)
return
(
<>
<
AuthMessageBlock
...
...
@@ -95,61 +27,7 @@ export default function ResetPasswordPage() {
<
Link
href=
{
PATH
.
DASHBOARD
.
ROOT
}
className=
'text-[12px] leading-[120%] font-bold lg:text-[16px] hover:text-primary flex gap-2 items-center'
><
ArrowLeft
/>
Back to Dashboard
</
Link
>
<
h1
className=
"text-[24px] leading-[120%] font-bold lg:text-[48px]"
>
Forgot Password
</
h1
>
</
div
>
<
form
action=
""
onSubmit=
{
handleSubmit
}
>
<
div
className=
"grid md:grid-cols-2 gap-x-3 gap-y-5"
>
<
div
className=
"col-span-2"
>
<
div
className=
"input_field"
>
<
InputLabel
htmlFor=
"emailAddress"
>
Email Address*
</
InputLabel
>
<
OutlinedInput
name=
'emailAddress'
id=
'emailAddress'
placeholder=
'example@example.com'
value=
{
values
.
emailAddress
}
onChange=
{
handleChange
}
onBlur=
{
handleBlur
}
error=
{
Boolean
(
touched
.
emailAddress
&&
errors
.
emailAddress
)
}
/>
{
touched
.
emailAddress
&&
errors
.
emailAddress
?
<
span
className=
"error "
>
{
errors
.
emailAddress
}
</
span
>
:
null
}
</
div
>
</
div
>
<
div
className=
"col-span-2"
>
<
div
className=
"input_field"
>
<
PasswordField
name=
"password"
label=
"Password*"
placeholder=
"XXXXXXX"
value=
{
values
.
password
}
onChange=
{
handleChange
}
onBlur=
{
handleBlur
}
error=
{
touched
.
password
?
errors
.
password
:
undefined
}
/>
</
div
>
</
div
>
<
div
className=
"col-span-2"
>
<
div
className=
"input_field"
>
<
PasswordField
name=
"confirmPassword"
label=
"Confirm Password*"
placeholder=
"XXXXXXX"
value=
{
values
.
confirmPassword
}
onChange=
{
handleChange
}
onBlur=
{
handleBlur
}
error=
{
touched
.
confirmPassword
?
errors
.
confirmPassword
:
undefined
}
/>
</
div
>
</
div
>
</
div
>
<
div
className=
"action__group text-center flex flex-col gap-4 mt-8"
>
<
button
className=
'ss-btn bg-primary-grad'
disabled=
{
!
dirty
}
>
{
isLoading
?
"Changing Password"
:
"Reset Password"
}
</
button
>
<
Link
href=
{
PATH
.
DASHBOARD
.
ROOT
}
className=
'ss-btn bg-secondary-grad'
>
Login
</
Link
>
</
div
>
</
form
>
<
ResetPasswordForm
/>
</
Box
>
</>
)
...
...
src/components/pages/dashboard/adminDashboard/activityLog/Activities.tsx
View file @
bd1b5dd7
...
...
@@ -7,22 +7,14 @@ import { useReactTable, getCoreRowModel, getPaginationRowModel, getSortedRowMode
import
{
Pagination
,
Box
}
from
'@mui/material'
;
import
{
TransactionStatusProps
}
from
'../transaction/TransactionTable'
;
import
{
StatusOptions
}
from
'@/types/config'
;
import
{
useGetAllActivityQuery
}
from
'@/services/notificationApi'
;
import
{
ActivityProps
}
from
'@/types/notification'
;
interface
Activity
{
id
:
number
;
type
:
string
;
user
:
string
;
userId
:
string
;
action
:
string
;
details
:
string
;
timestamp
:
string
;
status
:
string
;
icon
:
React
.
ReactNode
;
}
export
default
function
Activities
()
{
const
activityTypes
=
[
{
value
:
'
all
'
,
label
:
'All Activities'
},
{
value
:
''
,
label
:
'All Activities'
},
{
value
:
'registration'
,
label
:
'Registration'
},
{
value
:
'login'
,
label
:
'Login/Logout'
},
{
value
:
'deposit'
,
label
:
'Deposits'
},
...
...
@@ -33,140 +25,6 @@ export default function Activities() {
{
value
:
'bonus'
,
label
:
'Bonuses'
}
];
const
activities
:
Activity
[]
=
[
{
id
:
1
,
type
:
'registration'
,
user
:
'john_doe'
,
userId
:
'USR001'
,
action
:
'New user registered'
,
details
:
'Account created successfully'
,
timestamp
:
'2025-10-16 14:30:25'
,
status
:
'success'
,
icon
:
<
User
/>
},
{
id
:
2
,
type
:
'deposit'
,
user
:
'sarah_smith'
,
userId
:
'USR042'
,
action
:
'Cash deposit'
,
details
:
'Amount: $500.00 via Credit Card'
,
timestamp
:
'2025-10-16 14:25:10'
,
status
:
'success'
,
icon
:
<
User
/>
},
{
id
:
3
,
type
:
'withdrawal'
,
user
:
'mike_wilson'
,
userId
:
'USR078'
,
action
:
'Withdrawal request'
,
details
:
'Amount: $250.00 to Bank Account'
,
timestamp
:
'2025-10-16 14:20:45'
,
status
:
'pending'
,
icon
:
<
User
/>
},
{
id
:
4
,
type
:
'password_update'
,
user
:
'emma_brown'
,
userId
:
'USR023'
,
action
:
'Password changed'
,
details
:
'Security credentials updated'
,
timestamp
:
'2025-10-16 14:15:30'
,
status
:
'success'
,
icon
:
<
Lock
/>
},
{
id
:
5
,
type
:
'login'
,
user
:
'david_lee'
,
userId
:
'USR056'
,
action
:
'User login'
,
details
:
'IP: 192.168.1.100, Location: New York, USA'
,
timestamp
:
'2025-10-16 14:10:15'
,
status
:
'success'
,
icon
:
<
User
/>
},
{
id
:
6
,
type
:
'game_play'
,
user
:
'lisa_garcia'
,
userId
:
'USR089'
,
action
:
'Game played'
,
details
:
'Super Stakes Poker - Bet: $50, Won: $125'
,
timestamp
:
'2025-10-16 14:05:00'
,
status
:
'success'
,
icon
:
<
User
/>
},
{
id
:
7
,
type
:
'withdrawal'
,
user
:
'alex_martinez'
,
userId
:
'USR034'
,
action
:
'Withdrawal failed'
,
details
:
'Amount: $1000.00 - Insufficient funds'
,
timestamp
:
'2025-10-16 14:00:45'
,
status
:
'failed'
,
icon
:
<
User
/>
},
{
id
:
8
,
type
:
'profile_update'
,
user
:
'rachel_white'
,
userId
:
'USR067'
,
action
:
'Profile updated'
,
details
:
'Changed email and phone number'
,
timestamp
:
'2025-10-16 13:55:30'
,
status
:
'success'
,
icon
:
<
User
/>
},
{
id
:
9
,
type
:
'bonus'
,
user
:
'chris_taylor'
,
userId
:
'USR045'
,
action
:
'Bonus claimed'
,
details
:
'Welcome Bonus: $100 credited'
,
timestamp
:
'2025-10-16 13:50:15'
,
status
:
'success'
,
icon
:
<
User
/>
},
{
id
:
10
,
type
:
'logout'
,
user
:
'olivia_anderson'
,
userId
:
'USR091'
,
action
:
'User logout'
,
details
:
'Session ended normally'
,
timestamp
:
'2025-10-16 13:45:00'
,
status
:
'success'
,
icon
:
<
User
/>
},
{
id
:
11
,
type
:
'deposit'
,
user
:
'james_thomas'
,
userId
:
'USR012'
,
action
:
'Cash deposit'
,
details
:
'Amount: $1,200.00 via Bank Transfer'
,
timestamp
:
'2025-10-16 13:40:45'
,
status
:
'success'
,
icon
:
<
User
/>
},
{
id
:
12
,
type
:
'password_update'
,
user
:
'sophia_jackson'
,
userId
:
'USR073'
,
action
:
'Password reset'
,
details
:
'Reset via email verification'
,
timestamp
:
'2025-10-16 13:35:30'
,
status
:
'success'
,
icon
:
<
Lock
/>
}
];
const
[
search
,
setSearch
]
=
React
.
useState
(
""
);
const
[
page
,
setPage
]
=
React
.
useState
(
1
);
...
...
@@ -175,22 +33,21 @@ export default function Activities() {
const
[
activityType
,
setActivityType
]
=
React
.
useState
(
"all"
);
const
[
sorting
,
setSorting
]
=
React
.
useState
<
any
>
([]);
const
queryArgs
=
useMemo
(
()
=>
({
page
,
per_page
:
pageSize
,
search
:
search
||
""
,
activity_type
:
activityType
,
status
}),
[
page
,
pageSize
,
search
,
status
]
);
const
filteredData
=
useMemo
(()
=>
{
return
activities
.
filter
(
activity
=>
{
const
matchesSearch
=
search
===
""
||
activity
.
user
.
toLowerCase
().
includes
(
search
.
toLowerCase
())
||
activity
.
userId
.
toLowerCase
().
includes
(
search
.
toLowerCase
())
||
activity
.
action
.
toLowerCase
().
includes
(
search
.
toLowerCase
())
||
activity
.
details
.
toLowerCase
().
includes
(
search
.
toLowerCase
());
const
matchesType
=
activityType
===
"all"
||
activity
.
type
===
activityType
;
return
matchesSearch
&&
matchesType
;
});
},
[
search
,
activityType
]);
const
{
data
,
isLoading
}
=
useGetAllActivityQuery
(
queryArgs
)
const
columns
=
useMemo
<
ColumnDef
<
Activity
>
[]
>
(()
=>
[
const
columns
=
useMemo
<
ColumnDef
<
Activity
Props
>
[]
>
(()
=>
[
{
accessorKey
:
"id"
,
header
:
({
column
})
=>
{
...
...
@@ -216,23 +73,16 @@ export default function Activities() {
accessorKey
:
"user"
,
header
:
"User"
,
cell
:
({
row
})
=>
{
const
{
user
,
userId
}
=
row
.
original
;
const
initials
=
user
.
split
(
'_'
).
map
(
n
=>
n
[
0
]).
join
(
''
).
toUpperCase
();
const
{
username
,
email
}
=
row
.
original
return
(
<
Box
className=
"flex justify-start items-center gap-2"
>
<
small
className=
"text-[10px] w-[24px] h-[24px] flex items-center justify-center uppercase rounded-[4px] bg-[#1EB41B]/10 font-[500] text-[#1EB41B]"
>
{
initials
}
</
small
>
<
div
className=
"name-detail"
>
<
strong
className=
"text-primary block text-[12px] leading-[120%] font-[500] capitalize"
>
{
user
.
replace
(
'_'
,
' '
)
}
{
username
}
</
strong
>
<
small
className=
"text-[10px] text-para-light font-[500]"
>
{
userId
}
{
email
}
</
small
>
</
div
>
</
Box
>
);
},
},
...
...
@@ -253,18 +103,11 @@ export default function Activities() {
},
},
{
accessorKey
:
"action"
,
header
:
"Action"
,
cell
:
({
row
})
=>
(
<
span
className=
"text-[12px] font-[500]"
>
{
row
.
original
.
action
}
</
span
>
),
},
{
accessorKey
:
"details"
,
header
:
"Details"
,
cell
:
({
row
})
=>
(
<
span
className=
"text-[11px] text-para-light max-w-[250px] block truncate"
>
{
row
.
original
.
details
}
{
row
.
original
.
log
}
</
span
>
),
},
...
...
@@ -300,7 +143,7 @@ export default function Activities() {
],
[]);
const
table
=
useReactTable
({
data
:
filteredData
,
data
:
data
?.
data
?.
data
||
[]
,
columns
,
state
:
{
sorting
},
onSortingChange
:
setSorting
,
...
...
@@ -309,8 +152,6 @@ export default function Activities() {
getSortedRowModel
:
getSortedRowModel
(),
});
const
totalPages
=
Math
.
ceil
(
filteredData
.
length
/
pageSize
);
return
(
<
div
className=
"border-gray border-solid border-[1px] rounded-[8px] lg:rounded-[16px]"
>
...
...
@@ -332,15 +173,12 @@ export default function Activities() {
/>
<
div
className=
"flex flex-col md:flex-row justify-between items-start md:items-center mt-4 px-8 py-6 gap-4"
>
<
div
className=
"flex items-center gap-2"
>
<
span
className=
"text-[12px] font-[500]"
>
Rows
per page:
</
span
>
<
div
>
<
span
>
Row
per page:
</
span
>
<
select
value=
{
pageSize
}
onChange=
{
(
e
)
=>
{
setPageSize
(
Number
(
e
.
target
.
value
));
setPage
(
1
);
}
}
className=
"border border-gray-300 rounded p-1 text-[12px]"
onChange=
{
(
e
)
=>
setPageSize
(
Number
(
e
.
target
.
value
))
}
className=
"ml-2 border border-gray-300 rounded p-1"
>
{
[
5
,
10
,
15
,
20
].
map
((
size
)
=>
(
<
option
key=
{
size
}
value=
{
size
}
>
...
...
@@ -348,18 +186,10 @@ export default function Activities() {
</
option
>
))
}
</
select
>
{
/* <span className="text-[12px] text-para-light ml-4">
Showing {filteredData.length > 0 ? ((page - 1) * pageSize) + 1 : 0} to {Math.min(page * pageSize, filteredData.length)} of {filteredData.length} activities
</span> */
}
</
div
>
<
Pagination
count=
{
totalPages
||
1
}
<
Pagination
count=
{
data
?.
data
?.
pagination
?.
total_pages
||
1
}
page=
{
page
}
onChange=
{
(
_
,
value
)
=>
setPage
(
value
)
}
variant=
"outlined"
shape=
"rounded"
sx=
{
{
gap
:
"8px"
}
}
/>
onChange=
{
(
_
,
value
)
=>
setPage
(
value
)
}
variant=
"outlined"
shape=
"rounded"
sx=
{
{
gap
:
"8px"
}
}
/>
</
div
>
</
div
>
);
...
...
src/components/pages/dashboard/adminDashboard/activityLog/index.tsx
View file @
bd1b5dd7
...
...
@@ -7,11 +7,11 @@ export default function ActivityLogPage() {
return
(
<
section
className=
"activity__log__root"
>
<
PageHeader
title=
'Activity Log'
/>
<
div
className=
"grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 xl:grid-cols-4 gap-4 mb-8"
>
{
/*
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 xl:grid-cols-4 gap-4 mb-8">
{Array.from({ length: 4 }).map((_, index) => (
<ActivityAnalyticCard key={index.toString()} />
))}
</
div
>
</div>
*/
}
<
div
className=
"section-title mb-4"
>
<
h2
className=
"text-[20px] leading-[140%] font-[600]"
>
All Activities
...
...
src/routes/ReduxHydrator.tsx
View file @
bd1b5dd7
...
...
@@ -4,12 +4,12 @@ import { useEffect } from "react";
import
{
useAppDispatch
}
from
"@/hooks/hook"
;
import
{
setTokens
}
from
"@/slice/authSlice"
;
export
default
function
ReduxHydrator
({
token
,
user
}:
{
token
:
string
;
user
:
any
})
{
export
default
function
ReduxHydrator
({
token
}:
{
token
:
string
;
})
{
const
dispatch
=
useAppDispatch
();
useEffect
(()
=>
{
dispatch
(
setTokens
({
access_token
:
token
,
user
}));
},
[
dispatch
,
token
,
user
]);
//
useEffect(() => {
//
dispatch(setTokens({ access_token: token, user }));
//
}, [dispatch, token, user]);
return
null
;
}
src/routes/ServerPrivate.tsx
View file @
bd1b5dd7
...
...
@@ -24,13 +24,13 @@ export default async function ServerPrivate({ children }: { children: React.Reac
redirect
(
"/"
);
}
// Optionally, you could fetch user data from your API here if you don't store it in JWT
const
user
=
payload
;
// Or fetch user profile based on token
// const user = payload;
return
(
<>
{
/* ✅ Hydrate Redux store on client */
}
<
ReduxHydrator
token=
{
access_token
}
user=
{
user
}
/>
<
ReduxHydrator
token=
{
access_token
}
/>
{
children
}
</>
);
...
...
src/services/notificationApi.tsx
View file @
bd1b5dd7
import
{
createApi
}
from
"@reduxjs/toolkit/query/react"
;
import
{
baseQuery
}
from
"./baseQuery"
;
import
{
NotificationResponse
}
from
"@/types/notification"
;
import
{
ActivityResponse
,
NotificationResponse
}
from
"@/types/notification"
;
import
{
GlobalResponse
,
QueryParams
}
from
"@/types/config"
;
export
const
notificationApi
=
createApi
({
...
...
@@ -36,13 +36,14 @@ export const notificationApi = createApi({
}),
invalidatesTags
:
[
"Notification"
]
}),
getAllActivity
:
builder
.
query
<
NotificationResponse
,
{
activity_type
:
string
}
&
QueryParams
>
({
query
:
({
search
,
page
,
per_page
,
activity_type
})
=>
{
getAllActivity
:
builder
.
query
<
ActivityResponse
,
{
activity_type
:
string
,
status
?
:
string
}
&
QueryParams
>
({
query
:
({
search
,
page
,
per_page
,
activity_type
,
status
})
=>
{
const
params
=
new
URLSearchParams
();
if
(
search
)
params
.
append
(
'search'
,
search
);
if
(
page
)
params
.
append
(
'page'
,
page
.
toString
());
if
(
per_page
)
params
.
append
(
'page_size'
,
per_page
.
toString
());
if
(
per_page
)
params
.
append
(
'activity_type'
,
activity_type
.
toString
());
if
(
activity_type
)
params
.
append
(
'activity_type'
,
activity_type
.
toString
());
if
(
status
)
params
.
append
(
'status'
,
status
.
toString
());
const
queryString
=
params
.
toString
();
return
{
url
:
`/api/admin/activity
${
queryString
?
`?
${
queryString
}
`
:
''
}
`
,
...
...
src/types/notification.ts
View file @
bd1b5dd7
...
...
@@ -20,7 +20,18 @@ export interface ActivityResponse {
success
:
boolean
;
message
:
string
;
data
:
{
data
:
{}
[];
data
:
ActivityProps
[];
pagination
:
Pagination
;
}
}
export
interface
ActivityProps
{
id
:
number
,
username
:
string
,
email
:
string
,
status
:
string
,
log
:
string
type
:
string
,
timestamp
:
string
;
}
\ 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