Commit 0e1f8ba7 by Arjun Jhukal

updated the suspended user functionality

parent 557a3ffc
// components/Loading.tsx
"use client";
import React from "react";
import LotifyLoading from "@/components/atom/LotifyLoading";
import GlobalLoading from "@/components/organism/GlobalLoading";
export default function Loading() {
......
import { Switch } from '@mui/material'
import React from 'react'
export default function CustomSwitch({ isSuspended, onClick }: { isSuspended?: boolean; onClick?: () => void }) {
return (
<div className="flex items-center gap-2">
<Switch
checked={isSuspended}
sx={{
"& .MuiSwitch-switchBase.Mui-checked": {
color: "var(--primary)",
},
"& .MuiSwitch-switchBase.Mui-checked + .MuiSwitch-track": {
backgroundColor: "var(--primary)",
},
"& .MuiSwitch-track": {
backgroundColor: "var(--gray)",
},
}}
onClick={onClick}
/>
<span
className={`text-[12px] font-[500] ${isSuspended ? "text-[var(--para-light)]" : "text-[var(--primary)]"
}`}
>
{isSuspended ? "Activate" : "Suspend"}
</span>
</div>
)
}
......@@ -46,11 +46,11 @@ export default function PasswordField({
onMouseDown={handleMouseDownPassword}
edge="end"
color="secondary"
sx={{
padding: 0,
}}
// sx={{
// padding: 0,
// }}
>
{showPassword ? <Eye /> : <EyeSlash />}
{showPassword ? <Eye size={16} /> : <EyeSlash size={16} />}
</IconButton>
</InputAdornment >
}
......
......@@ -29,7 +29,7 @@ export default function TableHeader({
startAdornment={
<InputAdornment position="start">
<IconButton edge="start">
<SearchNormal size={32} />
<SearchNormal size={20} />
</IconButton>
</InputAdornment>
}
......@@ -55,7 +55,8 @@ export default function TableHeader({
borderRadius: "8px",
border: "1px solid var(--Gray, #E0E0E3)",
padding: "8px 16px",
color: "#0E0E11"
color: "#0E0E11",
maxWidth: "fit-content",
}}>Download CSV</Button>
</div>
);
......
......@@ -29,9 +29,9 @@ export default function ProfileBlock() {
const id = open ? 'profile-dropdown' : ""
const handleLogout = (e: React.MouseEvent) => {
router.replace(PATH.AUTH.LOGIN.ROOT);
e.preventDefault();
dispatch(clearTokens());
router.replace(PATH.AUTH.LOGIN.ROOT);
};
const menuItems = [
{
......@@ -162,7 +162,7 @@ export default function ProfileBlock() {
border: "1px solid rgba(255, 255, 255, 0.25)",
borderRadius: "8px",
boxShadow: `
0 8px 32px 0 rgba(0, 0, 0, 0.37),
0 8px 32px 0 #ddd,
inset 0 1px 0 0 rgba(255, 255, 255, 0.4),
0 0 20px rgba(255, 255, 255, 0.1)
`,
......
......@@ -122,7 +122,7 @@ export default function AdminMenu({ open }: { open: boolean }) {
border: "1px solid rgba(255, 255, 255, 0.25)",
borderRadius: "8px",
boxShadow: `
0 8px 32px 0 rgba(0, 0, 0, 0.37),
0 8px 32px 0 #ddd,
inset 0 1px 0 0 rgba(255, 255, 255, 0.4),
0 0 20px rgba(255, 255, 255, 0.1)
`,
......
"use client";
import CustomSwitch from '@/components/atom/Switch';
import ActionGroup from '@/components/molecules/Action';
import TabController from '@/components/molecules/TabController';
import TableHeader from '@/components/molecules/TableHeader'
import CustomTable from '@/components/organism/Table';
import { useAppDispatch } from '@/hooks/hook';
import { PATH } from '@/routes/PATH';
import { useDeletePlayerByIdMutation, useGetAllPlayerQuery } from '@/services/playerApi';
import { useDeletePlayerByIdMutation, useGetAllPlayerQuery, useSuspendPlayerByIdMutation } from '@/services/playerApi';
import { showToast, ToastVariant } from '@/slice/toastSlice';
import { PlayerItem, PlayerProps } from '@/types/player';
import { formatDateTime } from '@/utils/formatDateTime';
......@@ -22,16 +24,38 @@ export default function PlayerListing() {
const [sorting, setSorting] = useState<{ id: string; desc: boolean }[]>([]);
const [page, setPage] = useState(1);
const [pageSize, setPageSize] = useState(10);
const [currentTab, setCurrentTab] = React.useState("");
const { data, isLoading: loadingPlayer } = useGetAllPlayerQuery({
page,
per_page: pageSize,
search: search || ""
search: search || "",
status: currentTab || ""
});
const filteredData = useMemo(() => data?.data?.data || [], [data]);
const filteredData = useMemo(() => data?.data?.data || [], [data, currentTab, pageSize]);
const [deletePlayer, { isLoading: deletingPlayer }] = useDeletePlayerByIdMutation();
const [suspendPlayer, { isLoading: suspendingPlayer }] = useSuspendPlayerByIdMutation();
const handlePlayerSuspend = async (id: string) => {
try {
const response = await suspendPlayer({ id }).unwrap();
dispatch(
showToast({
message: response.message || "Player status updated successfully",
variant: ToastVariant.SUCCESS
})
)
}
catch (err: any) {
dispatch(
showToast({
message: err?.data?.message || "Failed to update player status",
variant: ToastVariant.ERROR
})
)
}
}
const columns = useMemo<ColumnDef<PlayerItem>[]>(() => [
{
id: 'select',
......@@ -88,6 +112,17 @@ export default function PlayerListing() {
)
},
{
accessorKey: "status",
header: "Account Status",
cell: ({ row }) => {
const isSuspended = row.original.is_suspended; // true or false
return (
<CustomSwitch isSuspended={isSuspended} onClick={() => handlePlayerSuspend(row.original.id)} />
);
},
},
{
accessorKey: 'registeredDate',
header: 'Registered Date',
cell: ({ row }) => {
......@@ -123,27 +158,65 @@ export default function PlayerListing() {
onView={`${PATH.ADMIN.PLAYERS.ROOT}/${row.original.id}`}
onEdit={`${PATH.ADMIN.PLAYERS.EDIT_PLAYER.ROOT}/${row.original.id}`}
onDelete={async () => {
const response = await deletePlayer({ id: row.original.id }).unwrap();
dispatch(
showToast({
message: response.message,
variant: ToastVariant.SUCCESS
})
)
try {
const response = await deletePlayer({ id: row.original.id }).unwrap();
dispatch(
showToast({
message: response.message || "Player deleted successfully",
variant: ToastVariant.SUCCESS
})
)
}
catch (err: any) {
dispatch(
showToast({
message: err?.data?.message || "Failed to delete player",
variant: ToastVariant.ERROR
})
)
}
}}
/>
),
},
], []);
// const table = useReactTable({
// data: data?.data?.data || [],
// columns,
// state: {
// sorting,
// },
// onSortingChange: setSorting,
// getCoreRowModel: getCoreRowModel(),
// getPaginationRowModel: getPaginationRowModel(),
// getSortedRowModel: getSortedRowModel(),
// })
const table = useReactTable({
data: filteredData || [],
data: data?.data?.data || [],
columns,
state: { sorting },
state: {
sorting,
pagination: {
pageIndex: page - 1,
pageSize: pageSize,
},
},
onSortingChange: setSorting,
onPaginationChange: (updater) => {
const newState = typeof updater === "function" ? updater({ pageIndex: page - 1, pageSize }) : updater;
setPage(newState.pageIndex + 1);
setPageSize(newState.pageSize);
},
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
})
getPaginationRowModel: getPaginationRowModel(),
});
const handleTabChange = (tab: string) => {
setCurrentTab(tab);
};
return (
<section className="player__listing_root">
......@@ -154,6 +227,11 @@ export default function PlayerListing() {
setSearch={setSearch}
onDownloadCSV={() => { }}
/>
<TabController
links={[{ label: "All", value: "" }, { label: "Subspended", value: "suspend" }]}
currentTab={currentTab}
onTabChange={handleTabChange}
/>
<CustomTable
table={table}
loading={loadingPlayer}
......
......@@ -42,8 +42,8 @@ export default function ExclusiveGameDetail({ game }: { game: SingleGameResponse
<Box sx={{
borderRadius: "16px"
}} className="flex justify-center items-center gap-2 py-4 px-6 bg-secondary-grad text-title">
<div className="coins">
}} className="flex justify-center items-center gap-2 py-4 px-6 bg-secondary-grad text-title ss-btn">
<div className="coins ">
<Link href={`/buy-coins/${game?.data?.id}`}>
<strong className="text-[16px] leading-4 font-[600] block mb-1">+ Deposit Coins</strong>
</Link>
......@@ -51,7 +51,7 @@ export default function ExclusiveGameDetail({ game }: { game: SingleGameResponse
</Box>
{game?.data?.provider == "goldcoincity" ? "" : <Box sx={{
borderRadius: "16px"
}} className="flex justify-center items-center gap-2 py-4 px-6 border border-secondary">
}} className="flex justify-center items-center gap-2 py-4 px-6 border border-secondary ss-btn">
<div className="coins">
<Link href={`/withdrawl`}>
<strong className="text-[16px] leading-4 font-[600] block mb-1 text-secondary">Withdraw Coins</strong>
......
// services/playerApi.ts
import { createApi } from "@reduxjs/toolkit/query/react";
import { baseQuery } from "./baseQuery";
import { PlayerListResponse, PlayerProps, SinlgePlayerResponseProps, } from "@/types/player";
import {
PlayerListResponse,
PlayerProps,
SinlgePlayerResponseProps,
} from "@/types/player";
import { GlobalResponse, QueryParams } from "@/types/config";
export const playerApi = createApi({
reducerPath: "playerApi",
baseQuery: baseQuery,
tagTypes: ["players"],
tagTypes: ["Players"],
endpoints: (builder) => ({
// CREATE PLAYER
createPlayer: builder.mutation<PlayerListResponse, FormData>({
query: (body) => ({
url: "/api/admin/add-user",
method: "POST",
body: body
body,
}),
invalidatesTags: ["players"]
invalidatesTags: [{ type: "Players", id: "LIST" }],
}),
getAllPlayer: builder.query<PlayerListResponse, QueryParams>({
query: ({ search, page, per_page }) => {
// GET ALL Players
getAllPlayer: builder.query<PlayerListResponse, QueryParams>({
query: ({ search, page, per_page, 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 (search) params.append("search", search);
if (page) params.append("page", page.toString());
if (per_page) params.append("page_size", per_page.toString());
if (status) params.append("status", status.toString());
const queryString = params.toString();
return {
url: `/api/admin/get-users${queryString ? `?${queryString}` : ''}`,
method: "GET"
}
url: `/api/admin/get-users${queryString ? `?${queryString}` : ""}`,
method: "GET",
};
},
providesTags: ['players']
providesTags: (result) =>
result?.data
? [
...result.data.data.map((player) => ({
type: "Players" as const,
id: player.id,
})),
{ type: "Players", id: "LIST" },
]
: [{ type: "Players", id: "LIST" }],
}),
// GET SINGLE PLAYER
getPlayerById: builder.query<SinlgePlayerResponseProps, { id: number }>({
query: ({ id }) => ({
url: `/api/admin/get-user/${id}`,
method: "GET"
method: "GET",
}),
providesTags: ['players']
providesTags: (result, error, { id }) => [{ type: "Players", id }],
}),
// GET PLAYER BALANCE BY ID
getPlayerBalanceById: builder.query<SinlgePlayerResponseProps, { id: string }>({
query: ({ id }) => ({
url: `/api/admin/get-balance/${id}`,
method: "GET"
method: "GET",
}),
providesTags: ['players']
providesTags: (result, error, { id }) => [{ type: "Players", id }],
}),
updatePlayerById: builder.mutation<SinlgePlayerResponseProps, { id: string, body: FormData }>({
// UPDATE PLAYER
updatePlayerById: builder.mutation<SinlgePlayerResponseProps, { id: string; body: FormData }>({
query: ({ id, body }) => ({
url: `/api/admin/update-user/${id}`,
method: "POST",
body: body
body,
}),
invalidatesTags: ["players"]
invalidatesTags: (result, error, { id }) => [{ type: "Players", id }],
}),
// DELETE PLAYER
deletePlayerById: builder.mutation<GlobalResponse, { id: string }>({
query: ({ id }) => ({
url: `/api/admin/user/${id}`,
method: "DELETE",
}),
invalidatesTags: ["players"]
invalidatesTags: (result, error, { id }) => [
{ type: "Players", id },
{ type: "Players", id: "LIST" },
],
}),
// SUSPEND PLAYER
suspendPlayerById: builder.mutation<GlobalResponse, { id: string }>({
query: ({ id }) => ({
url: `/api/admin/user/suspend/${id}`,
method: "POST",
}),
invalidatesTags: (result, error, { id }) => [
{ type: "Players", id },
{ type: "Players", id: "LIST" },
],
}),
})
})
}),
});
export const {
useCreatePlayerMutation,
useGetAllPlayerQuery,
useGetPlayerByIdQuery,
useGetPlayerBalanceByIdQuery, useUpdatePlayerByIdMutation,
useDeletePlayerByIdMutation
} = playerApi;
\ No newline at end of file
useGetPlayerBalanceByIdQuery,
useUpdatePlayerByIdMutation,
useDeletePlayerByIdMutation,
useSuspendPlayerByIdMutation,
} = playerApi;
......@@ -37,4 +37,5 @@ export interface QueryParams {
page?: number;
per_page?: number;
search?: string;
status?: string;
}
\ No newline at end of file
......@@ -47,6 +47,7 @@ export interface PlayerItem extends CommonPlayerProps {
total_withdrawl?: string,
total_deposited?: string
profile_image_file?: string;
is_suspended?: boolean;
}
export interface PlayerListResponse {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment