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'
export default async function UserAccountUpdate(props: { params: Promise<{ id: string }> }) {
const { id } = await props.params;
return (
<AddPlayerForm />
<EditUserProfile id={id} />
)
}
import EditUserWallet from '@/components/pages/dashboard/userDashboard/account/profile/editUserWallet'
import { Button, InputLabel, OutlinedInput } from '@mui/material'
import { InfoCircle, WalletCheck } from '@wandersonalwes/iconsax-react'
import React from 'react'
export default function UserWallet() {
return (
<form action="#" className="wallet-form">
<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>
<EditUserWallet />
)
}
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 AddPlayerForm from '@/components/pages/dashboard/adminDashboard/players/addPlayerForm'
import AddPlayerPage from '@/components/pages/dashboard/adminDashboard/players/addPlayerForm'
import React from 'react'
export default function AddPlayer() {
......@@ -8,7 +8,7 @@ export default function AddPlayer() {
<PageHeader
title='Add Player'
/>
<AddPlayerForm />
<AddPlayerPage />
</>
)
}
"use client";
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 React from 'react'
......@@ -11,7 +11,7 @@ export default function SinglePlayer() {
return (
<>
<PageHeader />
<AddPlayerForm id={id} />
<AddPlayerPage id={id} />
</>
)
}
......@@ -165,7 +165,7 @@
}
.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: "";
transform-origin: bottom right;
......
"use client";
import { InputLabel, Tooltip } from "@mui/material";
import { InputLabel, OutlinedInput } from "@mui/material";
import { CloseCircle } from "@wandersonalwes/iconsax-react";
import React from "react";
......@@ -15,7 +15,7 @@ interface InputFileProps {
error?: string | boolean;
touched?: boolean;
multiple?: boolean;
serverFile?: string | string[] | null
serverFile?: string | string[] | null;
onRemoveServerFile?: (fileUrl?: string) => void;
}
......@@ -31,7 +31,7 @@ export default function InputFile({
touched,
multiple = false,
serverFile,
onRemoveServerFile
onRemoveServerFile,
}: InputFileProps) {
const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const files = e.target.files;
......@@ -49,54 +49,65 @@ export default function InputFile({
onChange(updatedFiles.length > 0 ? updatedFiles : null);
};
const fileChosen =
(Array.isArray(value) && value.length > 0) || value || serverFile;
return (
<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>}
</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">
<span className="bg-[#D8D8DD] text-title px-2 py-[2px] text-sm ">
Choose File
</span>
<span className="truncate text-gray-500">
{/* {Array.isArray(value)
? value.map((f) => f.name).join(", ") || "No file chosen"
: value?.name || "No file chosen"} */}
{
Array.isArray(value) && value.length || value ? "Update File" : "No file chosen"
<OutlinedInput
fullWidth
id={name}
name={name}
type="text"
readOnly
value={
Array.isArray(value)
? value.map((f) => f.name).join(", ") || ""
: 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
type="file"
id={`${name}-file`}
name={name}
accept={accept}
hidden
multiple={multiple}
onChange={(e) => {
handleFileChange(e)
e.target.value = '';
handleFileChange(e);
e.target.value = "";
}}
onBlur={onBlur}
/>
</label>
{/* Preview thumbnails */}
<div className="flex gap-3 flex-wrap mt-2">
{value && (
<>
{Array.isArray(value) ? (
{value &&
(Array.isArray(value) ? (
value.map((f) => (
<div
key={f.name}
className="relative w-[80px] h-[80px] rounded-lg overflow-hidden border border-gray-200"
>
{f instanceof File && (
<img
src={URL.createObjectURL(f)}
alt={f.name}
className="w-full h-full object-cover"
/>
)}
<CloseCircle
size={16}
className="absolute top-1 right-1 cursor-pointer text-white hover:text-red-500"
......@@ -105,7 +116,6 @@ export default function InputFile({
</div>
))
) : (
value instanceof File && (
<div
key={value.name}
className="relative w-[80px] h-[80px] rounded-lg overflow-hidden border border-gray-200"
......@@ -121,28 +131,23 @@ export default function InputFile({
onClick={() => onChange(null)}
/>
</div>
)
)}
</>
)}
{serverFile && (
<>
{Array.isArray(serverFile) ? (
))}
{/* Server File preview */}
{serverFile &&
(Array.isArray(serverFile) ? (
serverFile.map((f) => (
<div
key={f}
className="relative w-[80px] h-[80px] rounded-lg overflow-hidden border border-gray-200"
>
<img
src={f}
alt={f}
className="w-full h-full object-cover"
/>
<img src={f} alt={f} className="w-full h-full object-cover" />
<CloseCircle
size={16}
className="absolute top-1 right-1 cursor-pointer text-white hover:text-red-500"
onClick={() => onRemoveServerFile && onRemoveServerFile(f)}
onClick={() =>
onRemoveServerFile && onRemoveServerFile(f)
}
/>
</div>
))
......@@ -159,39 +164,14 @@ export default function InputFile({
<CloseCircle
size={16}
className="absolute top-1 right-1 cursor-pointer text-white hover:text-red-500"
onClick={() => onRemoveServerFile && onRemoveServerFile(serverFile)}
onClick={() =>
onRemoveServerFile && onRemoveServerFile(serverFile)
}
/>
</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 && (
<span className="text-red-500 text-xs mt-1">{error}</span>
)}
......
"use client";
import { useAppSelector } from '@/hooks/hook';
import EditIcon from '@/icons/EditIcon'
import { formatDateTime } from '@/utils/formatDateTime';
import Image from 'next/image'
import React from 'react'
export default function UserProfileCard() {
const user = useAppSelector(state => state.auth.user);
const { date } = formatDateTime(user?.registered_date as string);
return (
<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)"
}}>
<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]">
<EditIcon />
</div>
</div>
<h1 className="text-24 lg:text-[32px] text-white my-1">RamboXOX</h1>
<p className="text-white text-[11px] lg:text-[14px]">Joined: 04-09-2025</p>
<h1 className="text-24 lg:text-[32px] text-white my-1">{user?.name}</h1>
<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="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'
import CoinCard from '@/components/molecules/CoinCard'
import GoldCoinIcon from '@/icons/GoldCoinIcon'
import SilverCoinIcon from '@/icons/SilverCoinIcon'
import UserCoinCard from './UserCoinCard'
export default function UserHeader() {
return (
<Box className='flex items-center gap-4 justify-between w-full'>
<AdminSearchBar />
<div className="right flex items-center gap-4">
<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">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 >
<UserCoinCard />
<Profile />
</div>
</Box>
......
import { PATH } from '@/routes/PATH';
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 React from 'react'
......@@ -77,6 +77,26 @@ export default function AdminMenu({ open }: { open: boolean }) {
className={[
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,
].some(path => pathname.startsWith(path)) ? "active" : ""
].join(" ")}
......@@ -92,7 +112,7 @@ export default function AdminMenu({ open }: { open: boolean }) {
/>
</ListItemButton>
</ListItem>
<ListItem>
{/* <ListItem>
<ListItemButton
className={[
open ? "expanded" : "collapsed",
......@@ -111,7 +131,7 @@ export default function AdminMenu({ open }: { open: boolean }) {
className={open ? "expanded" : "collapsed"}
/>
</ListItemButton>
</ListItem>
</ListItem> */}
</List>
)
}
......@@ -16,7 +16,7 @@ export default function CustomTable<TData>({ table, loading = false,
const rowCount = table.getRowModel().rows.length;
const columnCount = table.getAllLeafColumns().length;
const user = useAppSelector((state) => state.auth.user)
if (user?.role.toUpperCase() === "USER") {
if (user?.role && user?.role.toUpperCase() === "USER") {
return (
<table className="min-w-full text-left">
<thead>
......
......@@ -11,7 +11,7 @@ import { useRouter } from 'next/navigation';
import { useAppDispatch } from '@/hooks/hook';
import { useLoginMutation } from '@/services/authApi';
import { showToast, ToastVariant } from '@/slice/toastSlice';
import { setTokens } from '@/slice/authSlice';
import { clearTokens, setTokens } from '@/slice/authSlice';
import PasswordField from '@/components/molecules/PasswordField';
const validationSchema = Yup.object().shape({
......@@ -57,6 +57,9 @@ export default function LoginPage() {
}),
);
dispatch(
clearTokens()
)
dispatch(
setTokens({
access_token: response.data.access_token,
// 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>
)
}
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 />
)
}
import React from 'react'
export default function UniqueSelling() {
return (
<div>UniqueSelling</div>
)
}
......@@ -4,6 +4,7 @@ import PageHeader from '@/components/molecules/PageHeader'
import React, { useState } from 'react'
import SiteSetting from './SiteSetting'
import AdminProfile from './AdminProfile'
import BannerSlider from './BannerSlider';
export default function SettingPage() {
// Track the active tab index
......@@ -12,6 +13,7 @@ export default function SettingPage() {
const tabs = [
{ title: "Site Settings", content: <SiteSetting /> },
{ title: "My Profile", content: <AdminProfile /> },
{ title: "Banner Slider", content: <BannerSlider /> },
];
return (
......@@ -20,17 +22,17 @@ export default function SettingPage() {
<section className="site__setting__tab">
{/* 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) => (
<li key={index}>
<button
<span
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' : ''}`}
>
{tab.title}
</button>
</span>
</li>
))}
</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"
import { useAppDispatch } from '@/hooks/hook'
import { useAppDispatch, useAppSelector } from '@/hooks/hook'
import { useAddUserWalletMutation } from '@/services/userApi'
import { showToast, ToastVariant } from '@/slice/toastSlice'
import { Button, OutlinedInput } from '@mui/material'
......@@ -14,11 +14,11 @@ const validationSchema = yup.object({
})
export default function ConnectWalletForm() {
const dispatch = useAppDispatch();
const user = useAppSelector((state) => state.auth.user);
const [connectWallet, { isLoading }] = useAddUserWalletMutation();
const formik = useFormik({
initialValues: {
wallet_address: "",
wallet_address: user?.wallet_address || "",
},
enableReinitialize: true,
validationSchema,
......
......@@ -8,6 +8,7 @@ import { playerApi } from "@/services/playerApi";
import { providerApi } from "@/services/providerApi";
import { transactionApi } from "@/services/transaction";
import { userApi } from "@/services/userApi";
import { settingApi } from "@/services/settingApi";
export const store = configureStore({
reducer: {
......@@ -20,6 +21,7 @@ export const store = configureStore({
[playerApi.reducerPath]: playerApi.reducer,
[transactionApi.reducerPath]: transactionApi.reducer,
[userApi.reducerPath]: userApi.reducer,
[settingApi.reducerPath]: settingApi.reducer,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware()
......@@ -29,6 +31,7 @@ export const store = configureStore({
.concat(providerApi.middleware)
.concat(transactionApi.middleware)
.concat(userApi.middleware)
.concat(settingApi.middleware)
})
......
......@@ -37,6 +37,12 @@ export const PATH = {
},
SETTINGS: {
ROOT: "/settings"
},
PAGES: {
ROOT: "/pages",
ADD_PAGE: {
ROOT: "/pages/add-page"
}
}
},
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 { baseQuery } from "./baseQuery";
import { SinlgePlayerResponseProps, WalletProps } from "@/types/player";
import { UserBalance, UserBalanceResponse } from "@/types/user";
export const userApi = createApi({
reducerPath: "userApi",
baseQuery: baseQuery,
tagTypes: ['user'],
tagTypes: ['user', 'wallet'],
endpoints: (builder) => ({
addUserWallet: builder.mutation<SinlgePlayerResponseProps, WalletProps>({
query: (body) => ({
url: "/api/connect-wallet",
method: "POST",
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;
\ No newline at end of file
export const { useAddUserWalletMutation, useUpdateUserProfileMutation, useGetUserBalanceQuery } = userApi;
\ No newline at end of file
import { RoleProps, User } from "@/types/auth";
import { PlayerProps } from "@/types/player";
import { createSlice } from "@reduxjs/toolkit";
import Cookies from "js-cookie";
type Data = {
access_token: string,
user: User | null,
user: PlayerProps | null,
}
const isBrowser = typeof window !== "undefined";
......
......@@ -13,10 +13,16 @@ export interface CommonPlayerProps {
phone?: string;
password: string;
password_confirmation: string;
role?: string;
}
export interface PlayerProps extends CommonPlayerProps {
id?: string;
profile_image: File | null;
profile_image_file?: string;
registered_date?: string | Date;
current_credit?: string,
total_withdrawl?: string,
total_deposited?: string
}
export const initialPlayerValues: PlayerProps = {
......@@ -52,8 +58,8 @@ export interface PlayerListResponse {
}
export interface SinlgePlayerResponseProps {
data: PlayerItem;
message: string;
status: string;
message?: string;
status?: string;
}
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