Commit 0f9f3779 by Arjun Jhukal

updated the notification listing at admin side

parent 4d2d7d0f
......@@ -5,7 +5,7 @@ import React from 'react'
export default function DashboardProvider({ children }: { children: React.ReactNode }) {
const [search, setSearch] = React.useState("");
const user = useAppSelector(state => state.auth.user);
const user = useAppSelector(state => state?.auth.user);
if (user?.role && user.role.toUpperCase() === "ADMIN") {
return <>
<h1 className="text-[24px] leading-[120%] mb-6">Dashboard</h1>
......
......@@ -7,7 +7,6 @@ import React from 'react'
export default async function GeneralPage(props: { params: Promise<{ slug: string }> }) {
const { slug } = await props.params;
let pageData = null;
console.log(pageData);
try {
pageData = await getPageDetail(slug);
......
......@@ -5,12 +5,15 @@ import { getAllGames, getSubGames, getUsp } from "@/serverApi/game";
import { Tooltip } from "@mui/material";
import Image from "next/image";
import DashboardProvider from "./DashboardProvider";
import { getBanners, getSubBanners } from "@/serverApi/pages";
import Link from "next/link";
export default async function Home() {
let games = null;
let usps = null;
let subGames = null;
let banners = null;
let subBanners = null;
try {
games = await getAllGames();
} catch (err) {
......@@ -35,15 +38,25 @@ export default async function Home() {
console.log("❌ Failed to fetch games:", err);
return <p className="text-red-500">Failed to load games.</p>;
}
console.log({ subGames: subGames.data, usps })
try {
banners = await getBanners();
} catch (err) {
console.log("❌ Failed to fetch banner:", err);
return <p className="text-red-500">Failed to load banner.</p>;
}
try {
subBanners = await getSubBanners();
} catch (err) {
console.log("❌ Failed to fetch sub banner:", err);
return <p className="text-red-500">Failed to load sub banner.</p>;
}
// console.log({ subGames: subGames.data, usps })
return (
<DashboardProvider>
<>
<Dashboard />
<>
{banners?.data.length ?
<Dashboard slides={banners.data} /> : ""}
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4 2xl:grid-cols-5 mb-8">
{games?.data?.data.map((game) => (
......@@ -88,90 +101,123 @@ export default async function Home() {
))}
</div>
</section>
<div className="dashboard-card-wrapper grid grid-cols-2 gap-5 justify-center">
<div
className="dashboard-card1 flex px-10 gap-2 rounded-[24px]"
style={{
background: "rgba(255, 255, 255, 0.20)",
}}>
<div className="py-7 gap-6">
<h1
className="text-[40px] mb-[8px]"
style={{
color: "#FBD230",
lineHeight: "96%",
letterSpacing: "-0.682px",
}}>
Welcome BONUS!!
</h1>
<p
className="text-[13px] mb-[12px]"
style={{ lineHeight: "120%", color: "#FBD230" }}>
10$ on first play.
</p>
<a
href="#"
className="px-[18px] py-[11px] rounded-[28px]"
style={{
background:
"linear-gradient(270deg, #F9B901 0.09%, #D09F12 95.19%)",
}}>
Play Now
</a>
</div>
<div className="dashboard-card-img aspect-[245/245]">
<img
src="/assets/images/card1.png"
alt=""
// className="w-[245px] h-[245px]"
className="h-auto max-w-full "
style={{ width: "245px", height: "245px" }}
/>
</div>
</div>
<div
className="dashboard-card2 flex px-[45px] gap-2 rounded-[24px]"
style={{
background: "rgba(255, 255, 255, 0.10)",
}}>
<div className="py-[45px] gap-6">
<h1
className="text-[40px] mb-[10px]"
style={{
color: "#1AF7FE",
letterSpacing: "-0.682px",
lineHeight: "96%",
}}>
Easy.Set.Play
</h1>
<p
className="text-[13px] mb-[12px]"
style={{ color: "#E7BCFE", lineHeight: "120%" }}>
Join the Fun today.
</p>
<a
href="#"
className="px-[18px] py-[11px] rounded-[28px]"
style={{
background:
"linear-gradient(270deg, #D620D9 0.09%, #B40EF0 95.19%)",
}}>
Play Now
</a>
</div>
<div className="dashboard-card-img ">
<img
src="/assets/images/card2.png"
alt=""
// className="w-[245px] h-[245px]"
className="h-auto max-w-full "
style={{ width: "245px", height: "245px" }}
/>
</div>
</div>
</div>
{subBanners?.data.length ?
<div className="dashboard-card-wrapper grid grid-cols-2 gap-5 justify-center">
{subBanners?.data?.length > 0 &&
subBanners.data.map((subBanner, index) => (
<div
key={subBanner.name || index}
className="dashboard-card1 flex justify-between px-10 gap-2 rounded-[24px]"
style={{
background:
index % 2 === 0
? "rgba(255, 255, 255, 0.10)"
: "rgba(255, 255, 255, 0.20)",
}}
>
<div className="py-7 gap-6">
{/* ✅ Render title if available */}
{subBanner?.name && (
<h1
className="text-[40px] mb-[8px]"
style={{
color: "#FBD230",
lineHeight: "96%",
letterSpacing: "-0.682px",
}}
>
{subBanner.name}
</h1>
)}
{/* ✅ Render description if available */}
{subBanner?.description && (
<p
className="text-[13px] mb-[12px]"
style={{ lineHeight: "120%", color: "#FBD230" }}
>
{subBanner.description}
</p>
)}
{/* ✅ Render CTA button if link exists */}
{subBanner?.cta_link && (
<Link
href={subBanner.cta_link}
className="px-[18px] py-[11px] rounded-[28px] inline-block"
style={{
background:
index % 2 === 0
? "linear-gradient(270deg, #D620D9 0.09%, #B40EF0 95.19%)"
: "linear-gradient(270deg, #F9B901 0.09%, #D09F12 95.19%)",
}}
target="_blank"
>
Play Now
</Link>
)}
</div>
{/* ✅ Render image only if available */}
{subBanner?.image_url && (
<div className="dashboard-card-img aspect-[245/245]">
<Image
src={subBanner.image_url}
alt={subBanner.name || "Sub Banner"}
className="h-auto max-w-full"
width={245}
height={245}
/>
</div>
)}
</div>
))}
{/* <div
className="dashboard-card2 flex px-[45px] gap-2 rounded-[24px]"
style={{
background: "rgba(255, 255, 255, 0.10)",
}}>
<div className="py-[45px] gap-6">
<h1
className="text-[40px] mb-[10px]"
style={{
color: "#1AF7FE",
letterSpacing: "-0.682px",
lineHeight: "96%",
}}>
Easy.Set.Play
</h1>
<p
className="text-[13px] mb-[12px]"
style={{ color: "#E7BCFE", lineHeight: "120%" }}>
Join the Fun today.
</p>
<a
href="#"
className="px-[18px] py-[11px] rounded-[28px] inline-block"
style={{
background:
"linear-gradient(270deg, #D620D9 0.09%, #B40EF0 95.19%)",
}}>
Play Now
</a>
</div>
<div className="dashboard-card-img ">
<img
src="/assets/images/card2.png"
alt=""
// className="w-[245px] h-[245px]"
className="h-auto max-w-full "
style={{ width: "245px", height: "245px" }}
/>
</div>
</div> */}
</div> : null}
<UspSlider uspData={usps.data || []} />
</>
</>
</DashboardProvider>
);
}
......@@ -209,4 +209,8 @@
.lg-backdrop,
.lg-outer {
z-index: 9999;
}
.banner-desc span {
@apply text-[47px] leading-[50%] text-secondary font-[700];
}
\ No newline at end of file
......@@ -34,7 +34,6 @@ export default function SelectField({
touched,
}: SelectFieldProps) {
const theme = useThemeContext();
console.log("theme", theme);
return (
<div className="input__field">
<InputLabel className="block text-sm font-semibold mb-2">
......
......@@ -7,20 +7,25 @@ import NotificationPage from '../Notification';
import Profile from '../Profile';
import AdminSearchBar from './AdminSearchBar';
import CreatNewRecord from '../CreatNewRecord';
import { useGetAllNotificationQuery } from '@/services/notificationApi';
export default function AdminHeader() {
const [mounted, setMounted] = React.useState(false);
// const [mounted, setMounted] = React.useState(false);
React.useEffect(() => {
setMounted(true);
}, []);
// React.useEffect(() => {
// setMounted(true);
// }, []);
const [page, setPage] = React.useState(1);
const [pageSize, setPageSize] = React.useState(10);
const { data } = useGetAllNotificationQuery({ page: page, per_page: pageSize });
console.log(data);
return (
<Box className='flex items-center gap-4 justify-between w-full'>
<AdminSearchBar />
<div className="right flex items-center gap-4">
<CreatNewRecord />
<NotificationPage notifications={[]} />
<NotificationPage notifications={data?.data?.data || []} pagination={data?.data?.pagination}/>
<Profile />
</div>
</Box>
......
......@@ -15,16 +15,16 @@ import {
import Fade from '@mui/material/Fade'; // ✅ Import Fade
import { Notification } from '@wandersonalwes/iconsax-react';
import Link from 'next/link';
import { NotificationProps } from '@/types/notification';
import { Pagination } from '@/types/game';
type Notification = {
label: string;
description: string;
link?: string;
}
export default function NotificationPage({
notifications
notifications,
pagination
}: {
notifications: Notification[]
notifications: NotificationProps[]
pagination: Pagination | undefined
}) {
const anchorRef = useRef<HTMLButtonElement | null>(null);
const [open, setOpen] = useState(false);
......@@ -38,6 +38,7 @@ export default function NotificationPage({
const id = open ? 'popper' : undefined;
// const [readNotification,{isLoading}]
return (
<Box>
<IconButton
......@@ -79,18 +80,15 @@ export default function NotificationPage({
<Typography variant="h3" >
Notifications
</Typography>
<Link href={"#"} className='text-[12px] leading-[120%] hover:text-primary-dark font-medium'>View All</Link>
{pagination && pagination?.count > 2 ? <Link href={"#"} className='text-[12px] leading-[120%] hover:text-primary-dark font-medium'>View All</Link> : ""}
</div>
{
notifications.length ? (
<List className='max-h-[320px] overflow-auto px-1'>
{
notifications.map((notification) => (
<ListItem className='border-b-solid border-b-gray border-b-[1px] !pb-2 mb-2' key={notification.label}>
<Link href={""}>
<strong className="text-[12px] leading-[120%] font-[500] block mb-1">New User admin404 registerd</strong>
<p className='text-[10px] leading-[120%] text-para-light'>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Nihil, porro!</p>
</Link>
notifications.map((notification, index) => (
<ListItem className={`border-b-solid border-b-gray-100 border-b-[1px] rounded-sm !p-2 cursor-pointer ${notification.has_read ? "" : "bg-gray-100"} ${index > 0 ? "mb-2 " : ""}`} key={notification.id}>
<p className='text-[12px] lg:text-[14px] leading-[120%] text-title'>{notification.message}</p>
</ListItem>
))
}
......
......@@ -3,53 +3,100 @@
import React from "react";
import { useFormik } from "formik";
import * as Yup from "yup";
import { Button, InputLabel, OutlinedInput, IconButton } from "@mui/material";
import {
Button,
InputLabel,
OutlinedInput,
IconButton,
FormControlLabel,
Typography,
Switch,
} from "@mui/material";
import InputFile from "@/components/atom/InputFile";
import { CloseCircle } from "@wandersonalwes/iconsax-react";
import { useAppDispatch } from "@/hooks/hook";
import { showToast, ToastVariant } from "@/slice/toastSlice";
import { useGetAllBannerQuery, useUpdateBannerMutation } from "@/services/settingApi";
const validationSchema = Yup.object({
banners: Yup.array().of(
Yup.object({
name: Yup.string().required("Banner title is required"),
description: Yup.string().required("Banner description is required"),
cta_link: Yup.string().required("CTA link is required"),
// image: Yup.mixed().required("Banner image is required"),
type: Yup.boolean(),
})
),
});
export default function BannerSlider() {
const dispatch = useAppDispatch();
const { data, isLoading } = useGetAllBannerQuery();
const [updateBanner, { isLoading: updating }] = useUpdateBannerMutation();
console.log("banner data", data);
const formik = useFormik({
initialValues: {
banners: [
{
title: "",
description: "",
cta_link: "",
banners: data?.data?.length
? data.data.map((item: any) => ({
name: item.name || "",
description: item.description || "",
cta_link: item.cta_link || "",
image: null as File | null,
},
],
type: item.type || false,
image_url: item.image_url || "",
}))
: [
{
name: "",
description: "",
cta_link: "",
image: null as File | null,
type: false,
image_url: "",
},
],
},
validationSchema: Yup.object({
banners: Yup.array().of(
Yup.object({
title: Yup.string().required("Banner title is required"),
description: Yup.string().required("Banner description is required"),
cta_link: Yup.string().required("CTA link is required"),
image: Yup.mixed().required("Banner image is required"),
})
),
}),
onSubmit: (values) => {
validationSchema,
enableReinitialize: true,
onSubmit: async (values) => {
const formData = new FormData();
try {
values.banners.forEach((banner, index) => {
formData.append(`banners[${index}][name]`, banner.name);
formData.append(
`banners[${index}][description]`,
banner.description
);
formData.append(`banners[${index}][cta_link]`, banner.cta_link);
formData.append(
`banners[${index}][type]`,
banner.type ? "true" : "false"
);
if (banner.image) {
formData.append(`banners[${index}][image]`, banner.image);
} else if (banner.image_url) {
formData.append(`banners[${index}][image_url]`, banner.image_url);
}
});
const response = await updateBanner(formData).unwrap();
dispatch(
showToast({
message: "Banner created successfully",
variant: ToastVariant.ERROR
message: response?.message || "Banner created successfully",
variant: ToastVariant.SUCCESS,
})
)
}
catch (e: any) {
);
} catch (e: any) {
console.log(e);
dispatch(
showToast({
message: e.message || "Something went wrong",
variant: ToastVariant.ERROR
variant: ToastVariant.ERROR,
})
)
);
}
},
});
......@@ -62,6 +109,7 @@ export default function BannerSlider() {
description: "",
cta_link: "",
image: null,
isSubBanner: false,
},
]);
};
......@@ -75,9 +123,9 @@ export default function BannerSlider() {
return (
<form
onSubmit={formik.handleSubmit}
className="form__field__wrapper border-solid border-[1px] border-gray rounded-[16px] mb-6"
className="form__field__wrapper border 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 border-gray">
<h2 className="text-[20px] leading-[140%] font-bold">Banner Slider</h2>
</div>
......@@ -90,7 +138,7 @@ export default function BannerSlider() {
{formik.values.banners.length > 1 && (
<IconButton
onClick={() => handleRemoveBanner(index)}
className="!absolute !top-2 !right-2 !text-red-500 !justify-end !z-[9] max-w-fit"
className="!absolute !top-2 !right-2 !text-red-500 !z-[9] max-w-fit"
>
<CloseCircle size={18} />
</IconButton>
......@@ -103,16 +151,16 @@ export default function BannerSlider() {
</InputLabel>
<OutlinedInput
fullWidth
name={`banners[${index}].title`}
name={`banners[${index}].name`}
placeholder="Enter Banner Title"
value={banner.title}
value={banner.name}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
<span className="error">
{formik.touched.banners?.[index]?.title &&
(formik.errors.banners?.[index] as any)?.title
? (formik.errors.banners?.[index] as any).title
{formik.touched.banners?.[index]?.name &&
(formik.errors.banners?.[index] as any)?.name
? (formik.errors.banners?.[index] as any).name
: ""}
</span>
</div>
......@@ -171,6 +219,7 @@ export default function BannerSlider() {
onBlur={() =>
formik.setFieldTouched(`banners[${index}].image`, true)
}
serverFile={data?.data[index]?.image_url}
/>
<span className="error">
{formik.touched.banners?.[index]?.image &&
......@@ -179,6 +228,20 @@ export default function BannerSlider() {
: ""}
</span>
</div>
{/* ✅ Banner / Sub Banner Switch */}
<div className="input__field">
<FormControlLabel control={<Switch defaultChecked color="primary"
checked={banner.type}
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
formik.setFieldValue(
`banners[${index}].type`,
e.target.checked
)
}
name={`banners[${index}].type`}
/>} label="Mark Sub Banner" sx={{ color: "#000", fontSize: "12px" }} />
</div>
</div>
))}
......
......@@ -3,53 +3,87 @@
import Image from "next/image";
import { motion, AnimatePresence } from "framer-motion";
import { useState } from "react";
import { BannerProps } from "@/types/setting";
import { Button } from "@mui/material";
import { renderHTML } from "@/utils/RenderHTML";
const slides = [
{
id: 1,
image: "/assets/images/slider1.png",
},
// {
// id: 2,
// image: "/assets/images/slider2.jpg",
// },
// {
// id: 3,
// image: "/assets/images/slider1.png",
// },
];
export default function Dashboard() {
export default function Dashboard({ slides }: { slides: BannerProps[] }) {
const [current, setCurrent] = useState(0);
const handleDragEnd = (_: any, info: any) => {
const swipeThreshold = 100; // min distance to trigger slide change
if (info.offset.x < -swipeThreshold && current < slides.length - 1) {
setCurrent((prev) => prev + 1);
} else if (info.offset.x > swipeThreshold && current > 0) {
setCurrent((prev) => prev - 1);
}
};
return (
<div className="dashboard__root relative w-full mx-auto rounded-2xl mb-8">
<div className="relative h-[240px] w-full overflow-hidden rounded-[50px]">
<AnimatePresence mode="wait">
<motion.img
key={slides[current].id}
src={slides[current].image}
alt={`slide-${slides[current].id}`}
initial={{ opacity: 0, x: 100 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: -100 }}
transition={{ duration: 0.6 }}
className="absolute inset-0 w-full h-full object-cover rounded-2xl"
<div className="dashboard__root relative w-full mx-auto rounded-2xl mb-8">
<AnimatePresence mode="wait">
<motion.div
key={slides[current]?.name || current}
className="relative aspect-[1105/240] rounded-3xl overflow-hidden flex justify-center items-center text-center cursor-grab active:cursor-grabbing"
initial={{ opacity: 0, x: 100 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: -100 }}
transition={{ duration: 0.6 }}
drag="x"
dragConstraints={{ left: 0, right: 0 }}
onDragEnd={handleDragEnd}
>
<Image
src={slides[current].image_url || ""}
alt={slides[current].name}
fill
className="object-cover z-[-1]"
/>
</AnimatePresence>
</div>
<div className="content relative z-10 px-6">
<div className="content relative z-10 px-6 text-center">
{slides[current]?.name && (
<h1 className="text-[48px] leading-[50%] text-[#3A013F] mb-8">
{slides[current].name}
</h1>
)}
{slides[current]?.description && (
<p className="text-[#600167] text-[13px] leading-[120%] font-[700] mb-5 banner-desc">
{renderHTML(slides[current].description)}
</p>
)}
{slides[current]?.cta_link && (
<Button
variant="contained"
sx={{
borderRadius: 27,
background:
"linear-gradient(270deg, #F9B901 0.09%, #D09F12 95.19%)",
}}
onClick={() => window.open(slides[current].cta_link, "_blank")}
>
Play Now
</Button>
)}
</div>
</div>
</motion.div>
</AnimatePresence>
{/* Dots */}
<div className="absolute bottom-[-24px] left-1/2 -translate-x-1/2 flex gap-2">
<div className="justify-center flex gap-2 mt-4">
{slides.map((_, i) => (
<button
key={i}
onClick={() => setCurrent(i)}
className={`h-[8px] p-0 ${i === current ? "bg-white w-[24px]" : "bg-gray-400 w-[8px]"
className={`h-[8px] p-0 cursor-pointer ${i === current ? "bg-white w-[24px]" : "bg-gray-400 w-[8px]"
}`}
/>
))}
</div>
</div>
)
);
}
......@@ -7,7 +7,6 @@ import React from 'react'
export default function UserCoin({ slug }: { slug: string }) {
const { data } = useGetUserBalanceBySlugQuery({ slug });
console.log(data);
return (
<Box sx={{
background: "linear-gradient(0deg, rgba(234, 47, 231, 0.10) 0%, rgba(234, 47, 231, 0.10) 100%)",
......
......@@ -51,7 +51,6 @@ export default function WithdrawnHistoryPage() {
}
]
console.log(data);
const table = useReactTable({
data: data?.data?.data || [],
......
......@@ -10,6 +10,7 @@ import { transactionApi } from "@/services/transaction";
import { userApi } from "@/services/userApi";
import { settingApi } from "@/services/settingApi";
import { pageApi } from "@/services/pageApi";
import { notificationApi } from "@/services/notificationApi";
export const store = configureStore({
reducer: {
......@@ -24,6 +25,7 @@ export const store = configureStore({
[userApi.reducerPath]: userApi.reducer,
[settingApi.reducerPath]: settingApi.reducer,
[pageApi.reducerPath]: pageApi.reducer,
[notificationApi.reducerPath]: notificationApi.reducer,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware()
......@@ -35,6 +37,7 @@ export const store = configureStore({
.concat(userApi.middleware)
.concat(settingApi.middleware)
.concat(pageApi.middleware)
.concat(notificationApi.middleware)
})
......
import { PageRequestProps, PageResponseProps } from "@/types/page";
import { cookies } from "next/headers";
import { serverBaseQuery } from "./serverBaseQuery";
import { BannerResponseProps } from "@/types/setting";
export async function getPageDetail(slug: string): Promise<PageResponseProps | undefined> {
return serverBaseQuery(`/api/general/page/${slug}`);
}
export async function getBanners(): Promise<BannerResponseProps> {
return serverBaseQuery(`/api/general/home/banner`)
}
export async function getSubBanners(): Promise<BannerResponseProps> {
return serverBaseQuery(`/api/general/home/banner?type=true`)
}
\ No newline at end of file
import { createApi } from "@reduxjs/toolkit/query/react";
import { baseQuery } from "./baseQuery";
import { NotificationResponse } from "@/types/notification";
import { GlobalResponse, QueryParams } from "@/types/config";
export const notificationApi = createApi({
reducerPath: "notificationApi",
baseQuery: baseQuery,
tagTypes: ['Notification'],
endpoints: (builder) => ({
getAllNotification: builder.query<NotificationResponse, QueryParams>({
query: ({ search, page, per_page }) => {
const params = new URLSearchParams();
if (search) params.append('search', search);
if (page) params.append('page', page.toString());
if (per_page) params.append('page_size', per_page.toString());
const queryString = params.toString();
return {
url: `/api/admin/notifications${queryString ? `?${queryString}` : ''}`,
method: "GET"
}
},
providesTags: ["Notification"]
}),
readNotification: builder.mutation<GlobalResponse, { id: string }>({
query: ({ id }) => ({
url: `/api/admin/notification/${id}`,
method: "POST",
})
})
})
})
export const { useGetAllNotificationQuery } = notificationApi
\ No newline at end of file
import { createApi } from "@reduxjs/toolkit/query/react";
import { baseQuery } from "./baseQuery";
import { GlobalResponse } from "@/types/config";
import { SiteSettingResponseProps } from "@/types/setting";
import { BannerResponseProps, SiteSettingResponseProps } from "@/types/setting";
export const settingApi = createApi({
reducerPath: "settingApi",
baseQuery: baseQuery,
tagTypes: ['settings'],
tagTypes: ['settings', 'banners'],
endpoints: (builder) => ({
updateSetting: builder.mutation<GlobalResponse, FormData>({
query: (body) => ({
......@@ -22,8 +22,24 @@ export const settingApi = createApi({
method: "GET",
}),
providesTags: ['settings']
})
}),
updateBanner: builder.mutation<GlobalResponse, FormData>({
query: (body) => ({
url: "/api/admin/setting/banner",
method: "POST",
body: body,
}),
invalidatesTags: ['banners']
}),
getAllBanner: builder.query<BannerResponseProps, void>({
query: () => ({
url: "/api/admin/setting/banner",
method: "GET",
}),
providesTags: ['banners']
}),
})
})
export const { useUpdateSettingMutation, useGetSettingsQuery } = settingApi;
\ No newline at end of file
export const { useUpdateSettingMutation, useGetSettingsQuery, useUpdateBannerMutation, useGetAllBannerQuery } = settingApi;
\ No newline at end of file
import { Pagination } from "./game";
export interface NotificationProps {
id: string;
message: string,
has_read: boolean
}
export interface NotificationResponse {
success: boolean;
message: string;
data: {
data: NotificationProps[]
pagination: Pagination
}
}
\ No newline at end of file
......@@ -43,3 +43,17 @@ export interface UspProps {
icon_url?: string;
}
export interface BannerProps {
name: string;
description: string;
cta_link: string;
image?: File | null;
image_url?: string | null;
type: boolean /** TYPE TRUE REPRESENT SUB BANNER */
}
export interface BannerResponseProps {
message: string;
success: boolean;
data: BannerProps[];
}
\ 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