Commit 6fb87a7a by Arjun Jhukal

updated the setting post request

parent 31b1d2ff
import AddPlayerForm from '@/components/pages/dashboard/adminDashboard/players/addPlayerForm' import AddPlayerPage from '@/components/pages/dashboard/adminDashboard/players/addPlayerForm';
import AddPlayerForm from '@/components/pages/dashboard/adminDashboard/players/addPlayerForm/AddPlayerForm';
import EditUserProfile from '@/components/pages/dashboard/userDashboard/account/profile/editProfile';
import React from 'react' import React from 'react'
export default async function UserAccountUpdate(props: { params: Promise<{ id: string }> }) { export default async function UserAccountUpdate(props: { params: Promise<{ id: string }> }) {
const { id } = await props.params; const { id } = await props.params;
return ( return (
<AddPlayerForm /> <EditUserProfile id={id} />
) )
} }
import EditUserWallet from '@/components/pages/dashboard/userDashboard/account/profile/editUserWallet'
import { Button, InputLabel, OutlinedInput } from '@mui/material' import { Button, InputLabel, OutlinedInput } from '@mui/material'
import { InfoCircle, WalletCheck } from '@wandersonalwes/iconsax-react' import { InfoCircle, WalletCheck } from '@wandersonalwes/iconsax-react'
import React from 'react' import React from 'react'
export default function UserWallet() { export default function UserWallet() {
return ( return (
<form action="#" className="wallet-form"> <EditUserWallet />
<InputLabel htmlFor="wallet_address">Wallet Address</InputLabel>
<OutlinedInput
name="wallet_address"
id="wallet_address"
value="17HzyHWNrdS7GpMArshSBLpJpcvrre93P6"
/>
<div className="info my-4">
<p className='flex items-center bg-[#EEFEC4] text-[#547D16] p-2 rounded-lg text-[10px] lg:text-[12px] gap-1 '><InfoCircle size={12} />You can only connect one wallet at a time. To update the wallet address,
change the wallet address and click update</p>
</div>
<Button variant='contained' color='secondary' sx={{
color: "#1E3634",
fontSize: "12px"
}} startIcon={<WalletCheck />}>Update</Button>
</form>
) )
} }
import React from 'react'
export default function GeneralPage() {
return (
<div>GeneralPage</div>
)
}
"use client";
import ReactQuillEditor from '@/components/molecules/ReactQuill'
import { Button, OutlinedInput } from '@mui/material'
import React, { useState } from 'react'
export default function AddGeneralPage() {
const [pageField, setPageField] = useState(1);
return (
<>
<OutlinedInput placeholder='Page Title' />
<OutlinedInput placeholder='Slug' />
{Array.from({ length: pageField }).map((i) => (
<div className="grid lg:grid-cols-12 gap-4">
<div className="col-span-3">
<OutlinedInput placeholder='Heading' />
</div>
<div className="col-span-9">
<ReactQuillEditor />
</div>
</div>
)
)}
<Button variant='contained' color='primary' onClick={() => {
setPageField(prev => prev + 1)
}}>Add More</Button>
</>
)
}
import PageHeader from '@/components/molecules/PageHeader'
import React from 'react'
export default function AllPages() {
return (
<>
<PageHeader title='All Pages' cta={{ label: "Add New Page", url: "/pages/add-page" }} />
</>
)
}
import PageHeader from '@/components/molecules/PageHeader' import PageHeader from '@/components/molecules/PageHeader'
import AddPlayerForm from '@/components/pages/dashboard/adminDashboard/players/addPlayerForm' import AddPlayerPage from '@/components/pages/dashboard/adminDashboard/players/addPlayerForm'
import React from 'react' import React from 'react'
export default function AddPlayer() { export default function AddPlayer() {
...@@ -8,7 +8,7 @@ export default function AddPlayer() { ...@@ -8,7 +8,7 @@ export default function AddPlayer() {
<PageHeader <PageHeader
title='Add Player' title='Add Player'
/> />
<AddPlayerForm /> <AddPlayerPage />
</> </>
) )
} }
"use client"; "use client";
import PageHeader from '@/components/molecules/PageHeader' import PageHeader from '@/components/molecules/PageHeader'
import AddPlayerForm from '@/components/pages/dashboard/adminDashboard/players/addPlayerForm'; import AddPlayerPage from '@/components/pages/dashboard/adminDashboard/players/addPlayerForm';
import { useParams } from 'next/navigation'; import { useParams } from 'next/navigation';
import React from 'react' import React from 'react'
...@@ -11,7 +11,7 @@ export default function SinglePlayer() { ...@@ -11,7 +11,7 @@ export default function SinglePlayer() {
return ( return (
<> <>
<PageHeader /> <PageHeader />
<AddPlayerForm id={id} /> <AddPlayerPage id={id} />
</> </>
) )
} }
...@@ -165,7 +165,7 @@ ...@@ -165,7 +165,7 @@
} }
.tab__link::after { .tab__link::after {
@apply absolute left-0 bottom-0 w-full h-[4px] bg-primary opacity-0 translate-x-0 transition-all; @apply absolute left-0 bottom-0 w-full h-[2px] bg-primary opacity-0 translate-x-0 transition-all;
content: ""; content: "";
transform-origin: bottom right; transform-origin: bottom right;
......
"use client"; "use client";
import { InputLabel, Tooltip } from "@mui/material"; import { InputLabel, OutlinedInput } from "@mui/material";
import { CloseCircle } from "@wandersonalwes/iconsax-react"; import { CloseCircle } from "@wandersonalwes/iconsax-react";
import React from "react"; import React from "react";
...@@ -15,7 +15,7 @@ interface InputFileProps { ...@@ -15,7 +15,7 @@ interface InputFileProps {
error?: string | boolean; error?: string | boolean;
touched?: boolean; touched?: boolean;
multiple?: boolean; multiple?: boolean;
serverFile?: string | string[] | null serverFile?: string | string[] | null;
onRemoveServerFile?: (fileUrl?: string) => void; onRemoveServerFile?: (fileUrl?: string) => void;
} }
...@@ -31,7 +31,7 @@ export default function InputFile({ ...@@ -31,7 +31,7 @@ export default function InputFile({
touched, touched,
multiple = false, multiple = false,
serverFile, serverFile,
onRemoveServerFile onRemoveServerFile,
}: InputFileProps) { }: InputFileProps) {
const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => { const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const files = e.target.files; const files = e.target.files;
...@@ -49,54 +49,65 @@ export default function InputFile({ ...@@ -49,54 +49,65 @@ export default function InputFile({
onChange(updatedFiles.length > 0 ? updatedFiles : null); onChange(updatedFiles.length > 0 ? updatedFiles : null);
}; };
const fileChosen =
(Array.isArray(value) && value.length > 0) || value || serverFile;
return ( return (
<div className="input__field"> <div className="input__field">
<InputLabel className="block text-sm font-semibold mb-2"> <InputLabel htmlFor={name} className="block text-sm font-semibold mb-2">
{label} {required && <span className="text-red-500">*</span>} {label} {required && <span className="text-red-500">*</span>}
</InputLabel> </InputLabel>
<label className="flex items-center justify-start border border-gray-300 gap-2 rounded-lg cursor-pointer hover:border-primary transition py-2 px-3"> <OutlinedInput
<span className="bg-[#D8D8DD] text-title px-2 py-[2px] text-sm "> fullWidth
Choose File id={name}
</span> name={name}
<span className="truncate text-gray-500"> type="text"
{/* {Array.isArray(value) readOnly
? value.map((f) => f.name).join(", ") || "No file chosen" value={
: value?.name || "No file chosen"} */} Array.isArray(value)
{ ? value.map((f) => f.name).join(", ") || ""
Array.isArray(value) && value.length || value ? "Update File" : "No file chosen" : value instanceof File
? value.name
: ""
} }
</span> placeholder="Choose file"
onClick={() => document.getElementById(`${name}-file`)?.click()}
error={Boolean(touched && error)}
sx={{
cursor: "pointer",
}}
/>
{/* Hidden file input */}
<input <input
type="file" type="file"
id={`${name}-file`}
name={name} name={name}
accept={accept} accept={accept}
hidden hidden
multiple={multiple} multiple={multiple}
onChange={(e) => { onChange={(e) => {
handleFileChange(e) handleFileChange(e);
e.target.value = ''; e.target.value = "";
}} }}
onBlur={onBlur} onBlur={onBlur}
/> />
</label>
{/* Preview thumbnails */}
<div className="flex gap-3 flex-wrap mt-2"> <div className="flex gap-3 flex-wrap mt-2">
{value && ( {value &&
<> (Array.isArray(value) ? (
{Array.isArray(value) ? (
value.map((f) => ( value.map((f) => (
<div <div
key={f.name} key={f.name}
className="relative w-[80px] h-[80px] rounded-lg overflow-hidden border border-gray-200" className="relative w-[80px] h-[80px] rounded-lg overflow-hidden border border-gray-200"
> >
{f instanceof File && (
<img <img
src={URL.createObjectURL(f)} src={URL.createObjectURL(f)}
alt={f.name} alt={f.name}
className="w-full h-full object-cover" className="w-full h-full object-cover"
/> />
)}
<CloseCircle <CloseCircle
size={16} size={16}
className="absolute top-1 right-1 cursor-pointer text-white hover:text-red-500" className="absolute top-1 right-1 cursor-pointer text-white hover:text-red-500"
...@@ -105,7 +116,6 @@ export default function InputFile({ ...@@ -105,7 +116,6 @@ export default function InputFile({
</div> </div>
)) ))
) : ( ) : (
value instanceof File && (
<div <div
key={value.name} key={value.name}
className="relative w-[80px] h-[80px] rounded-lg overflow-hidden border border-gray-200" className="relative w-[80px] h-[80px] rounded-lg overflow-hidden border border-gray-200"
...@@ -121,28 +131,23 @@ export default function InputFile({ ...@@ -121,28 +131,23 @@ export default function InputFile({
onClick={() => onChange(null)} onClick={() => onChange(null)}
/> />
</div> </div>
) ))}
)}
</> {/* Server File preview */}
)} {serverFile &&
{serverFile && ( (Array.isArray(serverFile) ? (
<>
{Array.isArray(serverFile) ? (
serverFile.map((f) => ( serverFile.map((f) => (
<div <div
key={f} key={f}
className="relative w-[80px] h-[80px] rounded-lg overflow-hidden border border-gray-200" className="relative w-[80px] h-[80px] rounded-lg overflow-hidden border border-gray-200"
> >
<img <img src={f} alt={f} className="w-full h-full object-cover" />
src={f}
alt={f}
className="w-full h-full object-cover"
/>
<CloseCircle <CloseCircle
size={16} size={16}
className="absolute top-1 right-1 cursor-pointer text-white hover:text-red-500" className="absolute top-1 right-1 cursor-pointer text-white hover:text-red-500"
onClick={() => onRemoveServerFile && onRemoveServerFile(f)} onClick={() =>
onRemoveServerFile && onRemoveServerFile(f)
}
/> />
</div> </div>
)) ))
...@@ -159,39 +164,14 @@ export default function InputFile({ ...@@ -159,39 +164,14 @@ export default function InputFile({
<CloseCircle <CloseCircle
size={16} size={16}
className="absolute top-1 right-1 cursor-pointer text-white hover:text-red-500" className="absolute top-1 right-1 cursor-pointer text-white hover:text-red-500"
onClick={() => onRemoveServerFile && onRemoveServerFile(serverFile)} onClick={() =>
onRemoveServerFile && onRemoveServerFile(serverFile)
}
/> />
</div> </div>
)} ))}
</>
)}
</div> </div>
{/* {
Array.isArray(serverFile) && serverFile.length > 0 ? (
serverFile.map((f) => (
<div
key={f}
className="flex items-center gap-2 rounded-[20px] py-[2px] px-3 bg-primary-light text-white"
>
<Tooltip title={f}>
<span className="text-[12px]">
{f.length > 5
? f.slice(0, 5) + "..."
: f}
</span>
</Tooltip>
</div>
))
) : (<span className="text-[12px]">
{serverFile && serverFile?.length > 5
? serverFile?.slice(0, 5) + "..."
: serverFile}
</span>)
} */}
{touched && error && ( {touched && error && (
<span className="text-red-500 text-xs mt-1">{error}</span> <span className="text-red-500 text-xs mt-1">{error}</span>
)} )}
......
"use client";
import { useAppSelector } from '@/hooks/hook';
import EditIcon from '@/icons/EditIcon' import EditIcon from '@/icons/EditIcon'
import { formatDateTime } from '@/utils/formatDateTime';
import Image from 'next/image' import Image from 'next/image'
import React from 'react' import React from 'react'
export default function UserProfileCard() { export default function UserProfileCard() {
const user = useAppSelector(state => state.auth.user);
const { date } = formatDateTime(user?.registered_date as string);
return ( return (
<div className="player__info text-center rounded-xl lg:rounded-3xl p-8 lg:py-10 lg:px-9" style={{ <div className="player__info text-center rounded-xl lg:rounded-3xl p-8 lg:py-10 lg:px-9" style={{
background: "linear-gradient(0deg, rgba(0, 0, 0, 0.20) 0%, rgba(0, 0, 0, 0.20) 100%), rgba(255, 255, 255, 0.10)" background: "linear-gradient(0deg, rgba(0, 0, 0, 0.20) 0%, rgba(0, 0, 0, 0.20) 100%), rgba(255, 255, 255, 0.10)"
}}> }}>
<div className="player__profile bg-primary-grad p-[1px] rounded-full max-w-fit mx-auto relative"> <div className="player__profile bg-primary-grad p-[1px] rounded-full max-w-fit mx-auto relative">
<Image src={"/assets/images/auth-image.png"} alt='' width={100} height={100} className=' aspect-square rounded-full border-[5px] border-solid border-white' /> <Image src={user?.profile_image_file || "/assets/images/auth-image.png"} alt='' width={100} height={100} className=' aspect-square rounded-full border-[5px] border-solid border-white' />
<div className="absolute left-[50%] translate-x-[-50%] bottom-[-10px]"> <div className="absolute left-[50%] translate-x-[-50%] bottom-[-10px]">
<EditIcon /> <EditIcon />
</div> </div>
</div> </div>
<h1 className="text-24 lg:text-[32px] text-white my-1">RamboXOX</h1> <h1 className="text-24 lg:text-[32px] text-white my-1">{user?.name}</h1>
<p className="text-white text-[11px] lg:text-[14px]">Joined: 04-09-2025</p> <p className="text-white text-[11px] lg:text-[14px]">Joined: {date}</p>
<div className="grid grid-cols-1 md:grid-cols-2 gap-2 mt-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-2 mt-4">
<div className="col-span-1 md:col-span-2 rounded-[14px] p-4 lg:py-6" style={{ background: "rgba(191, 26, 198, 0.10)" }}> <div className="col-span-1 md:col-span-2 rounded-[14px] p-4 lg:py-6" style={{ background: "rgba(191, 26, 198, 0.10)" }}>
......
import GoldCoinIcon from '@/icons/GoldCoinIcon'
import SilverCoinIcon from '@/icons/SilverCoinIcon'
import { useGetUserBalanceQuery } from '@/services/userApi'
import { Box } from '@mui/material'
import React from 'react'
export default function UserCoinCard() {
const { data, isLoading } = useGetUserBalanceQuery();
console.log(data);
return (
<>
<Box sx={{
background: "linear-gradient(to right,#FFA325,#693C00)",
padding: "1px",
borderRadius: "40px"
}}>
<Box sx={{
background: "#2D2D30",
borderRadius: "40px"
}} className="flex justify-start items-center gap-1 py-2 pl-4 pr-8">
<GoldCoinIcon />
<div className="coins">
<strong className="text-[12px] leading-4 font-[600] text-[#FBA027] block">{data?.data[0]?.value || 0}</strong>
<span className="text-[9px] mt-[-2px] block">Gold Coins</span>
</div>
</Box>
</Box>
<Box sx={{
background: "linear-gradient(to right,#69A29D,#93E0D9)",
padding: "1px",
borderRadius: "40px"
}}>
<Box sx={{
background: "#2D2D30",
borderRadius: "40px"
}} className="flex justify-start items-center gap-1 py-2 pl-4 pr-8">
<SilverCoinIcon />
<div className="coins">
<strong className="text-[12px] leading-4 font-[600] text-[#93E0D8] block">{data?.data[1]?.value || 0}</strong>
<span className="text-[9px] mt-[-2px] block">Gold Coins</span>
</div>
</Box>
</Box >
</>
)
}
...@@ -5,44 +5,14 @@ import AdminSearchBar from '../AdminHeader/AdminSearchBar' ...@@ -5,44 +5,14 @@ import AdminSearchBar from '../AdminHeader/AdminSearchBar'
import CoinCard from '@/components/molecules/CoinCard' import CoinCard from '@/components/molecules/CoinCard'
import GoldCoinIcon from '@/icons/GoldCoinIcon' import GoldCoinIcon from '@/icons/GoldCoinIcon'
import SilverCoinIcon from '@/icons/SilverCoinIcon' import SilverCoinIcon from '@/icons/SilverCoinIcon'
import UserCoinCard from './UserCoinCard'
export default function UserHeader() { export default function UserHeader() {
return ( return (
<Box className='flex items-center gap-4 justify-between w-full'> <Box className='flex items-center gap-4 justify-between w-full'>
<AdminSearchBar /> <AdminSearchBar />
<div className="right flex items-center gap-4"> <div className="right flex items-center gap-4">
<Box sx={{ <UserCoinCard />
background: "linear-gradient(to right,#FFA325,#693C00)",
padding: "1px",
borderRadius: "40px"
}}>
<Box sx={{
background: "#2D2D30",
borderRadius: "40px"
}} className="flex justify-start items-center gap-1 py-2 pl-4 pr-8">
<GoldCoinIcon />
<div className="coins">
<strong className="text-[12px] leading-4 font-[600] text-[#FBA027] block">20,000</strong>
<span className="text-[9px] mt-[-2px] block">Gold Coins</span>
</div>
</Box>
</Box>
<Box sx={{
background: "linear-gradient(to right,#69A29D,#93E0D9)",
padding: "1px",
borderRadius: "40px"
}}>
<Box sx={{
background: "#2D2D30",
borderRadius: "40px"
}} className="flex justify-start items-center gap-1 py-2 pl-4 pr-8">
<SilverCoinIcon />
<div className="coins">
<strong className="text-[12px] leading-4 font-[600] text-[#93E0D8] block">20,000</strong>
<span className="text-[9px] mt-[-2px] block">Gold Coins</span>
</div>
</Box>
</Box >
<Profile /> <Profile />
</div> </div>
</Box> </Box>
......
import { PATH } from '@/routes/PATH'; import { PATH } from '@/routes/PATH';
import { List, ListItem, ListItemButton, ListItemIcon, ListItemText } from '@mui/material' import { List, ListItem, ListItemButton, ListItemIcon, ListItemText } from '@mui/material'
import { Game, Setting, Setting2, StatusUp, UserSearch } from '@wandersonalwes/iconsax-react' import { Game, Paperclip2, Setting, Setting2, StatusUp, UserSearch } from '@wandersonalwes/iconsax-react'
import { usePathname, useRouter } from 'next/navigation' import { usePathname, useRouter } from 'next/navigation'
import React from 'react' import React from 'react'
...@@ -77,6 +77,26 @@ export default function AdminMenu({ open }: { open: boolean }) { ...@@ -77,6 +77,26 @@ export default function AdminMenu({ open }: { open: boolean }) {
className={[ className={[
open ? "expanded" : "collapsed", open ? "expanded" : "collapsed",
[ [
PATH.ADMIN.PAGES.ROOT,
].some(path => pathname.startsWith(path)) ? "active" : ""
].join(" ")}
onClick={() => { router.push(PATH.ADMIN.PAGES.ROOT) }}
>
<ListItemIcon className={open ? "expanded" : "collapsed"}>
<Paperclip2 />
</ListItemIcon>
<ListItemText
primary="Pages"
className={open ? "expanded" : "collapsed"}
/>
</ListItemButton>
</ListItem>
<ListItem>
<ListItemButton
className={[
open ? "expanded" : "collapsed",
[
PATH.ADMIN.SETTINGS.ROOT, PATH.ADMIN.SETTINGS.ROOT,
].some(path => pathname.startsWith(path)) ? "active" : "" ].some(path => pathname.startsWith(path)) ? "active" : ""
].join(" ")} ].join(" ")}
...@@ -92,7 +112,7 @@ export default function AdminMenu({ open }: { open: boolean }) { ...@@ -92,7 +112,7 @@ export default function AdminMenu({ open }: { open: boolean }) {
/> />
</ListItemButton> </ListItemButton>
</ListItem> </ListItem>
<ListItem> {/* <ListItem>
<ListItemButton <ListItemButton
className={[ className={[
open ? "expanded" : "collapsed", open ? "expanded" : "collapsed",
...@@ -111,7 +131,7 @@ export default function AdminMenu({ open }: { open: boolean }) { ...@@ -111,7 +131,7 @@ export default function AdminMenu({ open }: { open: boolean }) {
className={open ? "expanded" : "collapsed"} className={open ? "expanded" : "collapsed"}
/> />
</ListItemButton> </ListItemButton>
</ListItem> </ListItem> */}
</List> </List>
) )
} }
...@@ -16,7 +16,7 @@ export default function CustomTable<TData>({ table, loading = false, ...@@ -16,7 +16,7 @@ export default function CustomTable<TData>({ table, loading = false,
const rowCount = table.getRowModel().rows.length; const rowCount = table.getRowModel().rows.length;
const columnCount = table.getAllLeafColumns().length; const columnCount = table.getAllLeafColumns().length;
const user = useAppSelector((state) => state.auth.user) const user = useAppSelector((state) => state.auth.user)
if (user?.role.toUpperCase() === "USER") { if (user?.role && user?.role.toUpperCase() === "USER") {
return ( return (
<table className="min-w-full text-left"> <table className="min-w-full text-left">
<thead> <thead>
......
...@@ -11,7 +11,7 @@ import { useRouter } from 'next/navigation'; ...@@ -11,7 +11,7 @@ import { useRouter } from 'next/navigation';
import { useAppDispatch } from '@/hooks/hook'; import { useAppDispatch } from '@/hooks/hook';
import { useLoginMutation } from '@/services/authApi'; import { useLoginMutation } from '@/services/authApi';
import { showToast, ToastVariant } from '@/slice/toastSlice'; import { showToast, ToastVariant } from '@/slice/toastSlice';
import { setTokens } from '@/slice/authSlice'; import { clearTokens, setTokens } from '@/slice/authSlice';
import PasswordField from '@/components/molecules/PasswordField'; import PasswordField from '@/components/molecules/PasswordField';
const validationSchema = Yup.object().shape({ const validationSchema = Yup.object().shape({
...@@ -57,6 +57,9 @@ export default function LoginPage() { ...@@ -57,6 +57,9 @@ export default function LoginPage() {
}), }),
); );
dispatch( dispatch(
clearTokens()
)
dispatch(
setTokens({ setTokens({
access_token: response.data.access_token, access_token: response.data.access_token,
// refreshToken: response.data?.refresh, // refreshToken: response.data?.refresh,
......
import InputFile from '@/components/atom/InputFile'
import PasswordField from '@/components/molecules/PasswordField'
import { PATH } from '@/routes/PATH'
import { PlayerProps, SinlgePlayerResponseProps } from '@/types/player'
import { Button, InputLabel, OutlinedInput } from '@mui/material'
import { FormikProps } from 'formik'
import { useRouter } from 'next/navigation'
import React from 'react'
export default function AddPlayerForm({ formik, id, data }: { formik: FormikProps<PlayerProps>, id?: string, data?: SinlgePlayerResponseProps }) {
const router = useRouter();
return (
<form onSubmit={formik.handleSubmit}>
<div className="form__fields p-6 lg:p-10 flex flex-col gap-4 lg:gap-6 lg:grid grid-cols-2">
<div className="input__field">
<InputLabel htmlFor="name">Username<span className="text-red-500">*</span></InputLabel>
<OutlinedInput
fullWidth
id="name"
name="name"
type="name"
placeholder="Enter Username"
value={formik.values.name}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
<span className="error">
{formik.touched.name && formik.errors.name ? formik.errors.name : ""}
</span>
</div>
<div className="input__field">
<InputLabel htmlFor="email">Email<span className="text-red-500">*</span></InputLabel>
<OutlinedInput
fullWidth
id="email"
name="email"
type="email"
placeholder="Enter email address"
value={formik.values.email}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
<span className="error">
{formik.touched.email && formik.errors.email ? formik.errors.email : ""}
</span>
</div>
<div className="input__field">
<InputLabel htmlFor="first_name">First Name<span className="text-red-500">*</span></InputLabel>
<OutlinedInput
fullWidth
id="first_name"
name="first_name"
placeholder="Enter first name"
value={formik.values.first_name}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
<span className="error">
{formik.touched.first_name && formik.errors.first_name ? formik.errors.first_name : ""}
</span>
</div>
<div className="input__field">
<InputLabel htmlFor="last_name">Last Name<span className="text-red-500">*</span></InputLabel>
<OutlinedInput
fullWidth
id="last_name"
name="last_name"
placeholder="Enter last name"
value={formik.values.last_name}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
<span className="error">
{formik.touched.last_name && formik.errors.last_name ? formik.errors.last_name : ""}
</span>
</div>
<div className="input__field">
<InputLabel htmlFor="wallet_address">Wallet Address</InputLabel>
<OutlinedInput
fullWidth
id="wallet_address"
name="wallet_address"
placeholder="Enter wallet address"
value={formik.values.wallet_address}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
<span className="error">
{formik.touched.wallet_address && formik.errors.wallet_address ? formik.errors.wallet_address : ""}
</span>
</div>
<div className="input__field">
<InputLabel htmlFor="address">Address</InputLabel>
<OutlinedInput
fullWidth
id="address"
name="address"
placeholder="Enter address"
value={formik.values.address}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
<span className="error">
{formik.touched.address && formik.errors.address ? formik.errors.address : ""}
</span>
</div>
<div className="input__field">
<InputLabel htmlFor="city">City</InputLabel>
<OutlinedInput
fullWidth
id="city"
name="city"
placeholder="Enter city"
value={formik.values.city}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
<span className="error">
{formik.touched.city && formik.errors.city ? formik.errors.city : ""}
</span>
</div>
<div className="input__field">
<InputLabel htmlFor="phone">Phone</InputLabel>
<OutlinedInput
fullWidth
id="phone"
name="phone"
placeholder="Enter phone number"
value={formik.values.phone}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
<span className="error">
{formik.touched.phone && formik.errors.phone ? formik.errors.phone : ""}
</span>
</div>
<div className="input__field">
<PasswordField
name="password"
label="Password*"
placeholder="Enter password"
value={formik.values.password}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
error={formik.touched.password ? formik.errors.password : undefined}
/>
</div>
<div className="input__field">
<PasswordField
name="password_confirmation"
label="Confirm Password*"
placeholder="Confirm password"
value={formik.values.password_confirmation}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
error={formik.touched.password_confirmation ? formik.errors.password_confirmation : undefined}
/>
</div>
<div className="input__field">
<InputFile
name="profile_image"
label="Profile Image"
value={formik.values.profile_image || null}
onChange={(file: File | File[] | null) => formik.setFieldValue("profile_image", file)}
onBlur={() => formik.setFieldTouched("profile_image", true)}
serverFile={data?.data?.profile_image_file}
/>
<span className="error">
{formik.touched.profile_image && formik.errors.profile_image ? formik.errors.profile_image : ""}
</span>
</div>
</div>
<div className="text-end my-4 lg:my-8 max-w-fit ml-auto flex justify-end gap-4 px-10">
{/* {id ? <Button color='error' variant='contained' onClick={() => {
router.push(PATH.ADMIN.PLAYERS.ROOT)
}}>Cancel Player Edit</Button> : null} */}
<Button type="submit" variant="contained" color="primary" sx={{ color: "#fff" }} >
Confirm {id ? "Player Update" : "Player Addition"}
</Button>
</div>
</form>
)
}
...@@ -12,6 +12,7 @@ import { useFormik } from 'formik' ...@@ -12,6 +12,7 @@ import { useFormik } from 'formik'
import { useRouter } from 'next/navigation' import { useRouter } from 'next/navigation'
import React from 'react' import React from 'react'
import * as Yup from "yup"; import * as Yup from "yup";
import AddPlayerForm from './AddPlayerForm'
export const PlayerValidationSchema = (isEdit: boolean) => Yup.object().shape({ export const PlayerValidationSchema = (isEdit: boolean) => Yup.object().shape({
name: Yup.string().required("Username is required"), name: Yup.string().required("Username is required"),
...@@ -36,9 +37,8 @@ export const PlayerValidationSchema = (isEdit: boolean) => Yup.object().shape({ ...@@ -36,9 +37,8 @@ export const PlayerValidationSchema = (isEdit: boolean) => Yup.object().shape({
}), }),
// profile_image: Yup.mixed().required("Profile is required"), // profile_image: Yup.mixed().required("Profile is required"),
}); });
export default function AddPlayerForm({ id }: { id?: string }) { export default function AddPlayerPage({ id }: { id?: string }) {
console.log("user id", id)
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const router = useRouter(); const router = useRouter();
...@@ -58,7 +58,7 @@ export default function AddPlayerForm({ id }: { id?: string }) { ...@@ -58,7 +58,7 @@ export default function AddPlayerForm({ id }: { id?: string }) {
wallet_address: data?.data.wallet_address, wallet_address: data?.data.wallet_address,
address: data?.data.address, address: data?.data.address,
city: data?.data.city, city: data?.data.city,
phone: data?.data.phone, phone: data?.data.phone || "",
password: data?.data.password, password: data?.data.password,
password_confirmation: data?.data.password_confirmation, password_confirmation: data?.data.password_confirmation,
profile_image: null, profile_image: null,
...@@ -135,189 +135,12 @@ export default function AddPlayerForm({ id }: { id?: string }) { ...@@ -135,189 +135,12 @@ export default function AddPlayerForm({ id }: { id?: string }) {
} }
}) })
return ( return (
<form onSubmit={formik.handleSubmit}>
<div className="form__field__wrapper border-solid border-[1px] border-gray rounded-[16px] mb-6 "> <div className="form__field__wrapper border-solid border-[1px] border-gray rounded-[16px] mb-6 ">
<div className="form__title py-6 px-10 border-b-solid border-b-[1px] border-gray"> <div className="form__title py-6 px-10 border-b-solid border-b-[1px] border-gray">
<h2 className="text-[20px] leading-[140%] font-bold">Player Details</h2> <h2 className="text-[20px] leading-[140%] font-bold">Player Details</h2>
</div> </div>
<div className="form__fields p-6 lg:p-10 flex flex-col gap-4 lg:gap-6 lg:grid grid-cols-2">
<div className="input__field">
<InputLabel htmlFor="name">Username<span className="text-red-500">*</span></InputLabel>
<OutlinedInput
fullWidth
id="name"
name="name"
type="name"
placeholder="Enter Username"
value={formik.values.name}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
<span className="error">
{formik.touched.name && formik.errors.name ? formik.errors.name : ""}
</span>
</div>
<div className="input__field">
<InputLabel htmlFor="email">Email<span className="text-red-500">*</span></InputLabel>
<OutlinedInput
fullWidth
id="email"
name="email"
type="email"
placeholder="Enter email address"
value={formik.values.email}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
<span className="error">
{formik.touched.email && formik.errors.email ? formik.errors.email : ""}
</span>
</div>
<div className="input__field">
<InputLabel htmlFor="first_name">First Name<span className="text-red-500">*</span></InputLabel>
<OutlinedInput
fullWidth
id="first_name"
name="first_name"
placeholder="Enter first name"
value={formik.values.first_name}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
<span className="error">
{formik.touched.first_name && formik.errors.first_name ? formik.errors.first_name : ""}
</span>
</div>
<div className="input__field">
<InputLabel htmlFor="last_name">Last Name<span className="text-red-500">*</span></InputLabel>
<OutlinedInput
fullWidth
id="last_name"
name="last_name"
placeholder="Enter last name"
value={formik.values.last_name}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
<span className="error">
{formik.touched.last_name && formik.errors.last_name ? formik.errors.last_name : ""}
</span>
</div>
<div className="input__field">
<InputLabel htmlFor="wallet_address">Wallet Address</InputLabel>
<OutlinedInput
fullWidth
id="wallet_address"
name="wallet_address"
placeholder="Enter wallet address"
value={formik.values.wallet_address}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
<span className="error">
{formik.touched.wallet_address && formik.errors.wallet_address ? formik.errors.wallet_address : ""}
</span>
</div>
<div className="input__field">
<InputLabel htmlFor="address">Address</InputLabel>
<OutlinedInput
fullWidth
id="address"
name="address"
placeholder="Enter address"
value={formik.values.address}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
<span className="error">
{formik.touched.address && formik.errors.address ? formik.errors.address : ""}
</span>
</div>
<div className="input__field">
<InputLabel htmlFor="city">City</InputLabel>
<OutlinedInput
fullWidth
id="city"
name="city"
placeholder="Enter city"
value={formik.values.city}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
<span className="error">
{formik.touched.city && formik.errors.city ? formik.errors.city : ""}
</span>
</div>
<div className="input__field">
<InputLabel htmlFor="phone">Phone</InputLabel>
<OutlinedInput
fullWidth
id="phone"
name="phone"
placeholder="Enter phone number"
value={formik.values.phone}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
<span className="error">
{formik.touched.phone && formik.errors.phone ? formik.errors.phone : ""}
</span>
</div>
<div className="input__field"> <AddPlayerForm formik={formik} id={id} data={data} />
<PasswordField
name="password"
label="Password*"
placeholder="Enter password"
value={formik.values.password}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
error={formik.touched.password ? formik.errors.password : undefined}
/>
</div>
<div className="input__field">
<PasswordField
name="password_confirmation"
label="Confirm Password*"
placeholder="Confirm password"
value={formik.values.password_confirmation}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
error={formik.touched.password_confirmation ? formik.errors.password_confirmation : undefined}
/>
</div>
<div className="input__field">
<InputFile
name="profile_image"
label="Profile Image"
value={formik.values.profile_image || null}
onChange={(file: File | File[] | null) => formik.setFieldValue("profile_image", file)}
onBlur={() => formik.setFieldTouched("profile_image", true)}
serverFile={data?.data?.profile_image_file}
/>
<span className="error">
{formik.touched.profile_image && formik.errors.profile_image ? formik.errors.profile_image : ""}
</span>
</div>
</div>
</div>
<div className="text-end mt-8 lg:mt-12 max-w-fit ml-auto flex justify-end gap-4">
{id ? <Button color='error' variant='contained' onClick={() => {
router.push(PATH.ADMIN.PLAYERS.ROOT)
}}>Cancel Player Edit</Button> : null}
<Button type="submit" variant="contained" color="primary" sx={{ color: "#fff" }} >
Confirm {id ? "Player Update" : "Player Addition"}
</Button>
</div> </div>
</form>
) )
} }
import InputFile from '@/components/atom/InputFile'
import { Button, InputLabel, OutlinedInput } from '@mui/material'
import { useFormik } from 'formik';
import React from 'react'
import * as Yup from "yup";
export default function BannerSlider() {
const formik = useFormik({
initialValues: {
favicon: null as File | null,
logo: null as File | null,
websiteTitle: "",
banner: "",
subBanner: "",
gameProvider: "",
},
validationSchema: Yup.object({
favicon: Yup.mixed().required("Favicon is required"),
logo: Yup.mixed().required("Logo is required"),
websiteTitle: Yup.string().required("Website title is required"),
banner: Yup.string().required("Banner is required"),
gameProvider: Yup.string().required("Game provider is required"),
}),
onSubmit: (values) => {
},
});
return (
<div className="form__field__wrapper border-solid border-[1px] border-gray rounded-[16px] mb-6">
<div className="form__title py-6 px-10 border-b-solid border-b-[1px] border-gray">
<h2 className="text-[20px] leading-[140%] font-bold">Banner Slider</h2>
</div>
<div className="form__fields p-6 lg:p-10 grid gap-4 lg:gap-6 md:grid-cols-2">
{/* Name */}
<div className="input__field col-span-1 md:col-span-2">
<InputLabel htmlFor="name">Banner Title<span className="text-red-500">*</span></InputLabel>
<OutlinedInput
fullWidth
id="name"
name="name"
placeholder="Enter the name of the game"
value={formik.values.websiteTitle}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
<span className="error">
{formik.touched.websiteTitle && formik.errors.websiteTitle ? formik.errors.websiteTitle : ""}
</span>
</div>
{/* Name */}
<div className="input__field col-span-1 md:col-span-2">
<InputLabel htmlFor="name">Banner Description<span className="text-red-500">*</span></InputLabel>
<OutlinedInput
fullWidth
id="name"
name="name"
placeholder="Enter the name of the game"
value={formik.values.websiteTitle}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
<span className="error">
{formik.touched.websiteTitle && formik.errors.websiteTitle ? formik.errors.websiteTitle : ""}
</span>
</div>
{/* Name */}
<div className="input__field col-span-1 md:col-span-2">
<InputLabel htmlFor="name">Banner CTA Link<span className="text-red-500">*</span></InputLabel>
<OutlinedInput
fullWidth
id="name"
name="name"
placeholder="Enter the name of the game"
value={formik.values.websiteTitle}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
<span className="error">
{formik.touched.websiteTitle && formik.errors.websiteTitle ? formik.errors.websiteTitle : ""}
</span>
</div>
{/* Favicon */}
<div className="input__field col-span-1 md:col-span-2">
<InputFile
name="favicon"
label="Website Image"
value={formik.values.favicon || null}
onChange={(file: File | File[] | null) => formik.setFieldValue("favicon", file)}
onBlur={() => formik.setFieldTouched("favicon", true)}
// serverFile={serverFiles.favicon}
// onRemoveServerFile={() => handleServerFileRemoval("favicon")}
/>
<span className="error">
{formik.touched.favicon && formik.errors.favicon ? formik.errors.favicon : ""}
</span>
</div>
</div>
<div className="text-right px-10 mb-6 lg:mb-10 flex gap-2 justify-end">
<Button variant="contained" color="secondary">Add More Banner</Button>
<Button variant="contained" color="primary">Save Banner Setting</Button>
</div>
</div >
)
}
import React from 'react'
import BannerSlider from './BannerSlider'
export default function SalesBanner() {
return (
<BannerSlider />
)
}
...@@ -3,54 +3,120 @@ ...@@ -3,54 +3,120 @@
import React from "react"; import React from "react";
import { useFormik } from "formik"; import { useFormik } from "formik";
import * as Yup from "yup"; import * as Yup from "yup";
import { InputLabel, OutlinedInput, Button } from "@mui/material"; import { InputLabel, OutlinedInput, Button, IconButton } from "@mui/material";
import InputFile from "@/components/atom/InputFile"; import InputFile from "@/components/atom/InputFile";
import SelectField from "@/components/atom/SelectField"; import { CloseCircle } from "@wandersonalwes/iconsax-react";
import { useGetSettingsQuery, useUpdateSettingMutation } from "@/services/settingApi";
import { useAppDispatch } from "@/hooks/hook";
import { showToast, ToastVariant } from "@/slice/toastSlice";
export default function SiteSetting() { export default function SiteSetting() {
const dispatch = useAppDispatch();
const [updateSetting, { isLoading }] = useUpdateSettingMutation();
const { data } = useGetSettingsQuery();
console.log("settings", data);
const formik = useFormik({ const formik = useFormik({
initialValues: { initialValues: {
favicon: null as File | null, favicon: null,
logo: null as File | null, logo: null,
websiteTitle: "", site_name: "",
banner: "", unique_selling_points: [
subBanner: "", {
gameProvider: "", title: "",
description: "",
icon: null,
},
],
}, },
validationSchema: Yup.object({ validationSchema: Yup.object({
favicon: Yup.mixed().required("Favicon is required"), favicon: Yup.mixed().required("Favicon is required"),
logo: Yup.mixed().required("Logo is required"), logo: Yup.mixed().required("Logo is required"),
websiteTitle: Yup.string().required("Website title is required"), site_name: Yup.string().required("Website title is required"),
banner: Yup.string().required("Banner is required"), unique_selling_points: Yup.array().of(
gameProvider: Yup.string().required("Game provider is required"), Yup.object({
title: Yup.string().required("USP title is required"),
description: Yup.string().required("USP description is required"),
icon: Yup.mixed().required("USP icon is required"),
})
),
}), }),
onSubmit: (values) => { onSubmit: async (values) => {
const formData = new FormData();
if (values.favicon) formData.append("favicon", values.favicon);
if (values.logo) formData.append("logo", values.logo);
// Append text fields
formData.append("site_name", values.site_name);
// Append USP data
values.unique_selling_points.forEach((usp, index) => {
formData.append(`unique_selling_points[${index}][title]`, usp.title);
formData.append(`unique_selling_points[${index}][description]`, usp.description);
if (usp.icon) {
formData.append(`unique_selling_points[${index}][icon]`, usp.icon);
}
});
try {
const response = await updateSetting(formData).unwrap();
dispatch(
showToast({
message: response.message || "Setting Saved Successfully",
variant: ToastVariant.SUCCESS
})
)
}
catch (e: any) {
dispatch(
showToast({
message: e.message || "Something Went Wrong",
variant: ToastVariant.ERROR
})
)
}
}, },
}); });
const handleAddUSP = () => {
formik.setFieldValue("unique_selling_points", [
...formik.values.unique_selling_points,
{ title: "", description: "", icon: null },
]);
};
const handleRemoveUSP = (index: number) => {
const updated = [...formik.values.unique_selling_points];
updated.splice(index, 1);
formik.setFieldValue("unique_selling_points", updated);
};
return ( return (
<form onSubmit={formik.handleSubmit}> <form onSubmit={formik.handleSubmit}>
<div className="form__field__wrapper border-solid border-[1px] border-gray rounded-[16px] mb-6"> {/* Site Setting */}
<div className="form__title py-6 px-10 border-b-solid border-b-[1px] border-gray"> <div className="form__field__wrapper border border-gray rounded-[16px] mb-6">
<h2 className="text-[20px] leading-[140%] font-bold">Site Settings</h2> <div className="form__title py-6 px-10 border-b border-gray">
<h2 className="text-[20px] font-bold">Site Settings</h2>
</div> </div>
<div className="form__fields p-6 lg:p-10 grid gap-4 lg:gap-6 md:grid-cols-2"> <div className="form__fields p-6 lg:p-10 grid gap-4 lg:gap-6 md:grid-cols-2">
{/* Name */} {/* Website Title */}
<div className="input__field col-span-1 md:col-span-2"> <div className="input__field col-span-1 md:col-span-2">
<InputLabel htmlFor="name">Website Title<span className="text-red-500">*</span></InputLabel> <InputLabel>Website Title<span className="text-red-500">*</span></InputLabel>
<OutlinedInput <OutlinedInput
label="Website Title"
fullWidth fullWidth
id="name" name="site_name"
name="name" placeholder="Enter Website Title"
placeholder="Enter the name of the game" value={formik.values.site_name}
value={formik.values.websiteTitle}
onChange={formik.handleChange} onChange={formik.handleChange}
onBlur={formik.handleBlur} onBlur={formik.handleBlur}
/> />
<span className="error"> <span className="error">
{formik.touched.websiteTitle && formik.errors.websiteTitle ? formik.errors.websiteTitle : ""} {formik.touched.site_name && formik.errors.site_name
? formik.errors.site_name
: ""}
</span> </span>
</div> </div>
...@@ -62,8 +128,6 @@ export default function SiteSetting() { ...@@ -62,8 +128,6 @@ export default function SiteSetting() {
value={formik.values.favicon || null} value={formik.values.favicon || null}
onChange={(file: File | File[] | null) => formik.setFieldValue("favicon", file)} onChange={(file: File | File[] | null) => formik.setFieldValue("favicon", file)}
onBlur={() => formik.setFieldTouched("favicon", true)} onBlur={() => formik.setFieldTouched("favicon", true)}
// serverFile={serverFiles.favicon}
// onRemoveServerFile={() => handleServerFileRemoval("favicon")}
/> />
<span className="error"> <span className="error">
{formik.touched.favicon && formik.errors.favicon ? formik.errors.favicon : ""} {formik.touched.favicon && formik.errors.favicon ? formik.errors.favicon : ""}
...@@ -78,115 +142,104 @@ export default function SiteSetting() { ...@@ -78,115 +142,104 @@ export default function SiteSetting() {
value={formik.values.logo || null} value={formik.values.logo || null}
onChange={(file: File | File[] | null) => formik.setFieldValue("logo", file)} onChange={(file: File | File[] | null) => formik.setFieldValue("logo", file)}
onBlur={() => formik.setFieldTouched("logo", true)} onBlur={() => formik.setFieldTouched("logo", true)}
// serverFile={serverFiles.thumbnail}
// onRemoveServerFile={() => handleServerFileRemoval("thumbnail")}
/> />
<span className="error"> <span className="error">
{formik.touched.logo && formik.errors.logo ? formik.errors.logo : ""} {formik.touched.logo && formik.errors.logo ? formik.errors.logo : ""}
</span> </span>
</div> </div>
{/* Banner */}
<div className="input__field col-span-1 ">
<SelectField
name="banner"
label="Game banner"
value={formik.values.banner || ""}
onChange={(e) => formik.setFieldValue("banner", e.target.value)}
onBlur={() => formik.setFieldTouched("banner", true)}
required
options={[
{ value: "action", name: "Action" },
{ value: "adventure", name: "Adventure" },
{ value: "puzzle", name: "Puzzle" },
]}
/>
<span className="error">
{formik.touched.banner && formik.errors.banner ? formik.errors.banner : ""}
</span>
</div>
{/* Sub Banners */}
<div className="input__field col-span-1">
<SelectField
name="subBanner"
label="Sub Banners"
value={formik.values.subBanner || ""}
onChange={(e) => formik.setFieldValue("subBanner", e.target.value)}
onBlur={() => formik.setFieldTouched("subBanner", true)}
required
options={[
{ value: "action", name: "Action" },
{ value: "adventure", name: "Adventure" },
{ value: "puzzle", name: "Puzzle" },
]}
/>
<span className="error">
{formik.touched.subBanner && formik.errors.subBanner ? formik.errors.subBanner : ""}
</span>
</div> </div>
</div> </div>
</div>
<div className="form__field__wrapper border-solid border-[1px] border-gray rounded-[16px] mb-6"> {/* USP Section */}
<div className="form__title py-6 px-10 border-b-solid border-b-[1px] border-gray"> <div className="form__field__wrapper border border-gray rounded-[16px] mb-6">
<h2 className="text-[20px] leading-[140%] font-bold">Unique Selling Points</h2> <div className="form__title py-6 px-10 border-b border-gray">
<h2 className="text-[20px] font-bold">Unique Selling Points</h2>
</div> </div>
<div className="form__fields p-6 lg:p-10 grid gap-4 lg:gap-6 md:grid-cols-2 lg:grid-cols-3"> <div className="form__fields p-6 lg:p-10 space-y-6">
{/* Name */} {formik.values.unique_selling_points.map((usp, index) => (
<div className="input__field col-span-1 "> <div
<InputLabel htmlFor="name">USP Title<span className="text-red-500">*</span></InputLabel> key={index}
className="grid gap-4 lg:gap-6 md:grid-cols-2 lg:grid-cols-3 items-start relative border border-gray rounded-lg p-4"
>
{formik.values.unique_selling_points.length > 1 && (
<IconButton
onClick={() => handleRemoveUSP(index)}
className="!absolute !top-2 !right-2 !text-red-500 !justify-end !z-[9]"
>
<CloseCircle size={18} />
</IconButton>
)}
{/* USP Title */}
<div className="input__field">
<InputLabel>USP Title<span className="text-red-500">*</span></InputLabel>
<OutlinedInput <OutlinedInput
fullWidth fullWidth
id="name" name={`unique_selling_points[${index}].title`}
name="name" placeholder="Enter USP Title"
placeholder="Enter the title for USP" value={usp.title}
value={formik.values.websiteTitle}
onChange={formik.handleChange} onChange={formik.handleChange}
onBlur={formik.handleBlur} onBlur={formik.handleBlur}
/> />
<span className="error"> <span className="error">
{formik.touched.websiteTitle && formik.errors.websiteTitle ? formik.errors.websiteTitle : ""} {formik.touched.unique_selling_points?.[index]?.title &&
(formik.errors.unique_selling_points?.[index] as any)?.title
? (formik.errors.unique_selling_points?.[index] as any).title
: ""}
</span> </span>
</div> </div>
<div className="input__field col-span-1 "> {/* USP Description */}
<InputLabel htmlFor="name">USP Description<span className="text-red-500">*</span></InputLabel> <div className="input__field">
<InputLabel>USP Description<span className="text-red-500">*</span></InputLabel>
<OutlinedInput <OutlinedInput
fullWidth fullWidth
id="name" name={`unique_selling_points[${index}].description`}
name="name" placeholder="Enter USP Description"
placeholder="Enter the title for USP" value={usp.description}
value={formik.values.websiteTitle}
onChange={formik.handleChange} onChange={formik.handleChange}
onBlur={formik.handleBlur} onBlur={formik.handleBlur}
/> />
<span className="error"> <span className="error">
{formik.touched.websiteTitle && formik.errors.websiteTitle ? formik.errors.websiteTitle : ""} {formik.touched.unique_selling_points?.[index]?.description &&
(formik.errors.unique_selling_points?.[index] as any)?.description
? (formik.errors.unique_selling_points?.[index] as any).description
: ""}
</span> </span>
</div> </div>
<div className="input__field col-span-1 "> {/* USP Icon */}
<div className="input__field">
<InputFile <InputFile
name="favicon" name={`unique_selling_points[${index}].icon`}
label="USP Icon" label="USP Icon"
value={formik.values.favicon || null} value={usp.icon || null}
onChange={(file: File | File[] | null) => formik.setFieldValue("favicon", file)} onChange={(file: File | File[] | null) =>
onBlur={() => formik.setFieldTouched("favicon", true)} formik.setFieldValue(`unique_selling_points[${index}].icon`, file)
required }
// serverFile={serverFiles.favicon} onBlur={() => formik.setFieldTouched(`unique_selling_points[${index}].icon`, true)}
// onRemoveServerFile={() => handleServerFileRemoval("favicon")}
/> />
<span className="error"> <span className="error">
{formik.touched.favicon && formik.errors.favicon ? formik.errors.favicon : ""} {formik.touched.unique_selling_points?.[index]?.icon &&
(formik.errors.unique_selling_points?.[index] as any)?.icon
? (formik.errors.unique_selling_points?.[index] as any).icon
: ""}
</span> </span>
</div> </div>
</div>
))}
<Button variant="text" color="primary" onClick={handleAddUSP} className="!p-0">
+ Add More USP
</Button>
</div> </div>
</div> </div>
<div className="text-right"> <div className="text-right">
<Button variant="contained" color="primary">Save Setting</Button> <Button type="submit" variant="contained" color="primary">
Save Site Setting
</Button>
</div> </div>
</form> </form>
); );
......
import React from 'react'
export default function UniqueSelling() {
return (
<div>UniqueSelling</div>
)
}
...@@ -4,6 +4,7 @@ import PageHeader from '@/components/molecules/PageHeader' ...@@ -4,6 +4,7 @@ import PageHeader from '@/components/molecules/PageHeader'
import React, { useState } from 'react' import React, { useState } from 'react'
import SiteSetting from './SiteSetting' import SiteSetting from './SiteSetting'
import AdminProfile from './AdminProfile' import AdminProfile from './AdminProfile'
import BannerSlider from './BannerSlider';
export default function SettingPage() { export default function SettingPage() {
// Track the active tab index // Track the active tab index
...@@ -12,6 +13,7 @@ export default function SettingPage() { ...@@ -12,6 +13,7 @@ export default function SettingPage() {
const tabs = [ const tabs = [
{ title: "Site Settings", content: <SiteSetting /> }, { title: "Site Settings", content: <SiteSetting /> },
{ title: "My Profile", content: <AdminProfile /> }, { title: "My Profile", content: <AdminProfile /> },
{ title: "Banner Slider", content: <BannerSlider /> },
]; ];
return ( return (
...@@ -20,17 +22,17 @@ export default function SettingPage() { ...@@ -20,17 +22,17 @@ export default function SettingPage() {
<section className="site__setting__tab"> <section className="site__setting__tab">
{/* Tab Buttons */} {/* Tab Buttons */}
<ul className="tab__controller flex gap-4 lg:gap-12 border-b border-gray-300"> <ul className="tab__controller flex border-b border-gray-300">
{tabs.map((tab, index) => ( {tabs.map((tab, index) => (
<li key={index}> <li key={index}>
<button <span
onClick={() => setActiveTab(index)} onClick={() => setActiveTab(index)}
className={`tab__link font-semibold text-[1rem] cursor-pointer relative className={`tab__link font-[600] text-[1rem] cursor-pointer relative block py-3 px-4
${activeTab === index ? 'active' : ''}`} ${activeTab === index ? 'active' : ''}`}
> >
{tab.title} {tab.title}
</button> </span>
</li> </li>
))} ))}
</ul> </ul>
......
"use client";
import { PlayerValidationSchema } from '@/components/pages/dashboard/adminDashboard/players/addPlayerForm';
import AddPlayerForm from '@/components/pages/dashboard/adminDashboard/players/addPlayerForm/AddPlayerForm';
import { useAppDispatch, useAppSelector } from '@/hooks/hook';
import { useUpdateUserProfileMutation } from '@/services/userApi';
import { setTokens } from '@/slice/authSlice';
import { showToast, ToastVariant } from '@/slice/toastSlice';
import { initialPlayerValues, PlayerItem, SinlgePlayerResponseProps } from '@/types/player';
import { useFormik } from 'formik';
import { useRouter } from 'next/navigation';
import React from 'react'
export default function EditUserProfile({ id }: { id: string }) {
const dispatch = useAppDispatch();
const router = useRouter();
const [updateUserProfile, { isLoading }] = useUpdateUserProfileMutation();
const user = useAppSelector((state) => state.auth.user);
const access_token = useAppSelector((state) => state.auth.access_token);
console.log(access_token);
const formik = useFormik({
initialValues: user ? {
name: user.name,
email: user.email,
first_name: user.first_name,
last_name: user.last_name,
wallet_address: user.wallet_address,
address: user.address,
city: user.city,
phone: user.phone || "",
password: '',
password_confirmation: '',
profile_image: null,
} : initialPlayerValues,
validationSchema: PlayerValidationSchema(!!user?.id),
enableReinitialize: true,
onSubmit: async (values) => {
const formData = new FormData();
formData.append("name", values.name);
formData.append("email", values.email);
formData.append("first_name", values.first_name);
formData.append("last_name", values.last_name);
formData.append("password", values.password);
formData.append("password_confirmation", values.password_confirmation);
if (values.wallet_address) formData.append("wallet_address", values.wallet_address);
if (values.address) formData.append("address", values.address);
if (values.city) formData.append("city", values.city);
if (values.phone) formData.append("phone", values.phone);
if (values.profile_image) {
if (Array.isArray(values.profile_image)) {
values.profile_image.forEach((file) => formData.append("profile_image", file));
} else {
formData.append("profile_image", values.profile_image);
}
}
if (id && user) {
formData.append("profile_image_file", user.profile_image_file || "");
}
try {
const response = await updateUserProfile({ id: user?.id || "", body: formData });
dispatch(
showToast({
message: response?.data?.message || "Profile Updated Successfully",
variant: ToastVariant.SUCCESS
})
);
dispatch(
setTokens({
access_token: access_token,
user: response?.data?.data,
}),
);
}
catch (e: any) {
dispatch(
showToast({
message: e.error || e.data.message,
variant: ToastVariant.ERROR
})
)
}
}
})
const formattedData = user
? {
data: {
id: user.id || "",
name: user.name,
email: user.email,
first_name: user.first_name,
last_name: user.last_name,
wallet_address: user.wallet_address,
address: user.address,
city: user.city,
phone: user.phone || "",
password: "",
password_confirmation: "",
registered_date: user.registered_date || new Date().toISOString(),
current_credit: user.current_credit ?? undefined,
total_withdrawl: user.total_withdrawl ?? undefined,
total_deposited: user.total_deposited ?? undefined,
profile_image_file: user.profile_image_file ?? undefined,
} as PlayerItem,
}
: undefined;
return (
<AddPlayerForm
formik={formik}
data={formattedData}
id={id}
/>
)
}
"use client";
import { useAppDispatch, useAppSelector } from '@/hooks/hook';
import { useAddUserWalletMutation } from '@/services/userApi';
import { showToast, ToastVariant } from '@/slice/toastSlice';
import { Button, InputLabel, OutlinedInput } from '@mui/material'
import { InfoCircle, WalletCheck } from '@wandersonalwes/iconsax-react'
import { useFormik } from 'formik';
import React from 'react'
import * as yup from 'yup'
const validationSchema = yup.object({
wallet_address: yup.string().required("Wallet Address is Required")
})
export default function EditUserWallet() {
const dispatch = useAppDispatch();
const user = useAppSelector((state) => state.auth.user);
const [connectWallet, { isLoading }] = useAddUserWalletMutation();
const formik = useFormik({
initialValues: {
wallet_address: user?.wallet_address || "",
},
enableReinitialize: true,
validationSchema,
onSubmit: async (values) => {
try {
const response = await connectWallet(values).unwrap();
dispatch(
showToast({
message: response.message || "Unable to connect wallet. Try Again Later",
variant: ToastVariant.SUCCESS
})
)
}
catch (e: any) {
dispatch(
showToast({
message: e.message || "Unable to connect wallet. Try Again Later",
variant: ToastVariant.ERROR
})
)
}
}
})
return (
<form onSubmit={formik.handleSubmit} className="wallet-form">
<InputLabel htmlFor="wallet_address">Wallet Address</InputLabel>
<OutlinedInput
name='wallet_address'
id='wallet_address'
value={formik.values.wallet_address}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
placeholder='Enter your bitcoin address'
/>
<div className="info my-4">
<p className='flex items-center bg-[#EEFEC4] text-[#547D16] p-2 rounded-lg text-[10px] lg:text-[12px] gap-1 '><InfoCircle size={12} />You can only connect one wallet at a time. To update the wallet address,
change the wallet address and click update</p>
</div>
<Button type="submit" variant='contained' color='secondary' sx={{
color: "#1E3634",
fontSize: "12px"
}} startIcon={<WalletCheck />}>Update</Button>
</form>
)
}
"use client" "use client"
import { useAppDispatch } from '@/hooks/hook' import { useAppDispatch, useAppSelector } from '@/hooks/hook'
import { useAddUserWalletMutation } from '@/services/userApi' import { useAddUserWalletMutation } from '@/services/userApi'
import { showToast, ToastVariant } from '@/slice/toastSlice' import { showToast, ToastVariant } from '@/slice/toastSlice'
import { Button, OutlinedInput } from '@mui/material' import { Button, OutlinedInput } from '@mui/material'
...@@ -14,11 +14,11 @@ const validationSchema = yup.object({ ...@@ -14,11 +14,11 @@ const validationSchema = yup.object({
}) })
export default function ConnectWalletForm() { export default function ConnectWalletForm() {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const user = useAppSelector((state) => state.auth.user);
const [connectWallet, { isLoading }] = useAddUserWalletMutation(); const [connectWallet, { isLoading }] = useAddUserWalletMutation();
const formik = useFormik({ const formik = useFormik({
initialValues: { initialValues: {
wallet_address: "", wallet_address: user?.wallet_address || "",
}, },
enableReinitialize: true, enableReinitialize: true,
validationSchema, validationSchema,
......
...@@ -8,6 +8,7 @@ import { playerApi } from "@/services/playerApi"; ...@@ -8,6 +8,7 @@ import { playerApi } from "@/services/playerApi";
import { providerApi } from "@/services/providerApi"; import { providerApi } from "@/services/providerApi";
import { transactionApi } from "@/services/transaction"; import { transactionApi } from "@/services/transaction";
import { userApi } from "@/services/userApi"; import { userApi } from "@/services/userApi";
import { settingApi } from "@/services/settingApi";
export const store = configureStore({ export const store = configureStore({
reducer: { reducer: {
...@@ -20,6 +21,7 @@ export const store = configureStore({ ...@@ -20,6 +21,7 @@ export const store = configureStore({
[playerApi.reducerPath]: playerApi.reducer, [playerApi.reducerPath]: playerApi.reducer,
[transactionApi.reducerPath]: transactionApi.reducer, [transactionApi.reducerPath]: transactionApi.reducer,
[userApi.reducerPath]: userApi.reducer, [userApi.reducerPath]: userApi.reducer,
[settingApi.reducerPath]: settingApi.reducer,
}, },
middleware: (getDefaultMiddleware) => middleware: (getDefaultMiddleware) =>
getDefaultMiddleware() getDefaultMiddleware()
...@@ -29,6 +31,7 @@ export const store = configureStore({ ...@@ -29,6 +31,7 @@ export const store = configureStore({
.concat(providerApi.middleware) .concat(providerApi.middleware)
.concat(transactionApi.middleware) .concat(transactionApi.middleware)
.concat(userApi.middleware) .concat(userApi.middleware)
.concat(settingApi.middleware)
}) })
......
...@@ -37,6 +37,12 @@ export const PATH = { ...@@ -37,6 +37,12 @@ export const PATH = {
}, },
SETTINGS: { SETTINGS: {
ROOT: "/settings" ROOT: "/settings"
},
PAGES: {
ROOT: "/pages",
ADD_PAGE: {
ROOT: "/pages/add-page"
}
} }
}, },
USER: { USER: {
......
import { createApi } from "@reduxjs/toolkit/query/react";
import { baseQuery } from "./baseQuery";
import { GlobalResponse } from "@/types/config";
import { SiteSettingResponseProps } from "@/types/setting";
export const settingApi = createApi({
reducerPath: "settingApi",
baseQuery: baseQuery,
tagTypes: ['settings'],
endpoints: (builder) => ({
updateSetting: builder.mutation<GlobalResponse, FormData>({
query: (body) => ({
url: "/api/admin/settings",
method: "POST",
body: body,
}),
invalidatesTags: ['settings']
}),
getSettings: builder.query<SiteSettingResponseProps, void>({
query: () => ({
url: "/api/admin/settings",
method: "GET",
}),
providesTags: ['settings']
})
})
})
export const { useUpdateSettingMutation, useGetSettingsQuery } = settingApi;
\ No newline at end of file
import { createApi } from "@reduxjs/toolkit/query/react"; import { createApi } from "@reduxjs/toolkit/query/react";
import { baseQuery } from "./baseQuery"; import { baseQuery } from "./baseQuery";
import { SinlgePlayerResponseProps, WalletProps } from "@/types/player"; import { SinlgePlayerResponseProps, WalletProps } from "@/types/player";
import { UserBalance, UserBalanceResponse } from "@/types/user";
export const userApi = createApi({ export const userApi = createApi({
reducerPath: "userApi", reducerPath: "userApi",
baseQuery: baseQuery, baseQuery: baseQuery,
tagTypes: ['user'], tagTypes: ['user', 'wallet'],
endpoints: (builder) => ({ endpoints: (builder) => ({
addUserWallet: builder.mutation<SinlgePlayerResponseProps, WalletProps>({ addUserWallet: builder.mutation<SinlgePlayerResponseProps, WalletProps>({
query: (body) => ({ query: (body) => ({
url: "/api/connect-wallet", url: "/api/connect-wallet",
method: "POST", method: "POST",
body: body body: body
}),
invalidatesTags: ['wallet']
}),
updateUserProfile: builder.mutation<SinlgePlayerResponseProps, { id: string, body: FormData }>({
query: ({ id, body }) => ({
url: `/api/update/user-information/${id}`,
method: "POST",
body: body
}),
invalidatesTags: ['user', "wallet"]
}),
getUserBalance: builder.query<UserBalanceResponse, void>({
query: () => ({
url: "/api/get-balance",
method: "GET"
}) })
}) })
}) })
}) })
export const { useAddUserWalletMutation } = userApi; export const { useAddUserWalletMutation, useUpdateUserProfileMutation, useGetUserBalanceQuery } = userApi;
\ No newline at end of file \ No newline at end of file
import { RoleProps, User } from "@/types/auth"; import { RoleProps, User } from "@/types/auth";
import { PlayerProps } from "@/types/player";
import { createSlice } from "@reduxjs/toolkit"; import { createSlice } from "@reduxjs/toolkit";
import Cookies from "js-cookie"; import Cookies from "js-cookie";
type Data = { type Data = {
access_token: string, access_token: string,
user: User | null, user: PlayerProps | null,
} }
const isBrowser = typeof window !== "undefined"; const isBrowser = typeof window !== "undefined";
......
...@@ -13,10 +13,16 @@ export interface CommonPlayerProps { ...@@ -13,10 +13,16 @@ export interface CommonPlayerProps {
phone?: string; phone?: string;
password: string; password: string;
password_confirmation: string; password_confirmation: string;
role?: string;
} }
export interface PlayerProps extends CommonPlayerProps { export interface PlayerProps extends CommonPlayerProps {
id?: string;
profile_image: File | null; profile_image: File | null;
profile_image_file?: string; profile_image_file?: string;
registered_date?: string | Date;
current_credit?: string,
total_withdrawl?: string,
total_deposited?: string
} }
export const initialPlayerValues: PlayerProps = { export const initialPlayerValues: PlayerProps = {
...@@ -52,8 +58,8 @@ export interface PlayerListResponse { ...@@ -52,8 +58,8 @@ export interface PlayerListResponse {
} }
export interface SinlgePlayerResponseProps { export interface SinlgePlayerResponseProps {
data: PlayerItem; data: PlayerItem;
message: string; message?: string;
status: string; status?: string;
} }
export interface WalletProps { export interface WalletProps {
......
export interface SiteSettingRequestProps {
favicon: File | null;
favicon_url?: string;
logo: File | null;
logo_url?: string;
site_name: string;
unique_selling_points: UspProps[];
}
export interface SiteSettingResponseProps {
success: string;
message: string;
data: {
favIcon: string;
logo: string;
site_name: string;
unique_selling_points: {
title: string;
description: string;
icon: string;
}[]
}
}
export interface UspProps {
title: string;
description: string;
icon: File | null;
icon_url?: string;
}
export interface UserBalance {
type?: string;
value?: string;
providers: {
id: number;
name: string,
provider: string,
balance: 0
}[]
}
export interface UserBalanceResponse {
status?: string;
message?: string;
data: UserBalance[];
}
\ No newline at end of file
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