Commit 84e32cf0 by Arjun Jhukal

update the menu dynamic

parent aca945b6
"use client";
import MenuPage from '@/components/pages/menus'
import React from 'react'
export default function Menus() {
return (
<MenuPage />
)
}
......@@ -94,6 +94,26 @@ export default function AdminMenu({ open }: { open: boolean }) {
className={[
open ? "expanded" : "collapsed",
[
PATH.ADMIN.MENUS.ROOT,
].some(path => pathname.startsWith(path)) ? "active" : ""
].join(" ")}
onClick={() => { router.push(PATH.ADMIN.MENUS.ROOT) }}
>
<ListItemIcon className={open ? "expanded" : "collapsed"}>
<Paperclip2 />
</ListItemIcon>
<ListItemText
primary="Menus"
className={open ? "expanded" : "collapsed"}
/>
</ListItemButton>
</ListItem>
<ListItem>
<ListItemButton
className={[
open ? "expanded" : "collapsed",
[
PATH.ADMIN.PAGES.ROOT,
].some(path => pathname.startsWith(path)) ? "active" : ""
].join(" ")}
......
import React from "react";
import { List, ListItem, ListItemButton, ListItemIcon, ListItemText } from "@mui/material";
import { ReceiptEdit } from "@wandersonalwes/iconsax-react";
import { PATH } from "@/routes/PATH";
import { getAllMenus } from "@/serverApi/menu";
import { useGetAllUserMenuQuery } from "@/services/menuApi";
export default function PrimaryMenu() {
const {data}=useGetAllUserMenuQuery();
return (
<List>
{data ? data?.data?.map((menu: any) => (
<ListItem key={menu.slug}>
<ListItemButton component="a" href={menu.slug ? `/${menu.slug}` : "#"}>
<ListItemIcon>
<ReceiptEdit size={18} />
</ListItemIcon>
<ListItemText primary={menu.name} />
</ListItemButton>
</ListItem>
))
: (
<p></p>
)
}
</List>
);
}
......@@ -6,6 +6,7 @@ import { Home, MessageQuestion, ReceiptEdit, RecordCircle, StatusUp, UserEdit }
import Link from 'next/link';
import { usePathname, useRouter } from 'next/navigation';
import React from 'react'
import PrimaryMenu from './PrimaryMenu';
export default function UserMenu({ open }: { open: boolean }) {
const pathname = usePathname();
......@@ -83,7 +84,7 @@ export default function UserMenu({ open }: { open: boolean }) {
</ListItemButton>
</ListItem> */}
</List>
<List>
{/* <List>
<ListItem>
<ListItemButton
className={[
......@@ -185,27 +186,8 @@ export default function UserMenu({ open }: { open: boolean }) {
/>
</ListItemButton>
</ListItem>
{/* <ListItem>
<ListItemButton
className={[
open ? "expanded" : "collapsed",
[
PATH.USER.GENERAL_PAGES.PRIVACY_POLICY.ROOT
].some(path => pathname.startsWith(path)) ? "active" : ""
].join(" ")}
onClick={() => { router.push(PATH.ADMIN.GAMES.ROOT) }}
>
<ListItemIcon className={open ? "expanded" : "collapsed"}>
<MessageQuestion size={18} />
</ListItemIcon>
<ListItemText
primary="FAQs"
className={open ? "expanded" : "collapsed"}
/>
</ListItemButton>
</ListItem> */}
</List>
</List> */}
<PrimaryMenu />
</div>
<div className="support mt-4">
<Link href={"/support"} className="ss-btn support__btn flex items-center gap-2 w-full justify-start">
......
"use client";
import React from "react";
import { useGetAllPageQuery } from "@/services/pageApi";
import { motion, AnimatePresence } from "framer-motion";
import { CloseCircle } from "@wandersonalwes/iconsax-react";
import { Button } from "@mui/material";
import { useAppDispatch } from "@/hooks/hook";
import { showToast, ToastVariant } from "@/slice/toastSlice";
import { useCreateMenuMutation, useGetAllMenuQuery } from "@/services/menuApi";
export default function MenuPage() {
const { data, isLoading } = useGetAllPageQuery({ page: 1, per_page: 30 });
const [createMenu, { isLoading: updatingMenu }] = useCreateMenuMutation();
const { data: menus, isLoading: loadingMenu } = useGetAllMenuQuery();
const dispatch = useAppDispatch();
const [selectedMenus, setSelectedMenus] = React.useState<any[]>([]);
console.log("menus", { menus, selectedMenus });
React.useEffect(() => {
if (menus?.data) {
setSelectedMenus(menus.data);
}
}, [menus?.data]);
const handleAddMenu = (page: any) => {
if (selectedMenus.find((item) => item.id === page.id)) return;
setSelectedMenus((prev) => [...prev, page]);
};
const handleRemoveMenu = (id: number) => {
setSelectedMenus((prev) => prev.filter((item) => item.id !== id));
};
const handleMenuSave = async () => {
try {
const menuIds = selectedMenus.map((menu) => menu.id);
const response = await createMenu({ pages: menuIds }).unwrap();
dispatch(
showToast({
message: "Menu saved successfully!",
variant: ToastVariant.SUCCESS,
})
);
} catch (e: any) {
dispatch(
showToast({
message: e?.data?.message || "Something went wrong, try again later.",
variant: ToastVariant.ERROR,
})
);
}
};
if (isLoading) {
return <div className="text-center py-10">Loading pages...</div>;
}
const pages = data?.data?.data || [];
return (
<section className="grid lg:grid-cols-12 gap-8">
{/* LEFT SIDE - PAGES LIST */}
<div className="col-span-4 border border-gray-300 rounded-xl p-4">
<h2 className="text-lg font-semibold mb-3">All Pages</h2>
<div className="flex flex-col gap-2 max-h-[500px] overflow-y-auto">
{pages.map((page: any) => (
<button
key={page.id}
onClick={() => handleAddMenu(page)}
className="text-start px-2 py-1 rounded-lg border border-gray-300 hover:bg-gray-100 transition"
>
{page.name}
</button>
))}
</div>
</div>
{/* RIGHT SIDE - SELECTED MENU */}
<div className="col-span-8 border border-gray-300 rounded-xl p-4">
<h2 className="text-lg font-semibold mb-3">Selected Menu</h2>
{selectedMenus.length === 0 && (
<p className="text-gray-500 text-sm">No menu items added yet.</p>
)}
<div className="space-y-3">
<AnimatePresence>
{selectedMenus.map((menu) => (
<motion.div
key={menu.id}
layout
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: 10 }}
className="flex items-center justify-between px-4 py-2 border-gray-300 rounded-lg border w-full"
>
<span className="font-medium text-gray-800">{menu.name}</span>
<button
onClick={() => handleRemoveMenu(menu.id)}
className="text-gray-500 hover:text-red-600 transition max-w-fit"
>
<CloseCircle size={18} />
</button>
</motion.div>
))}
</AnimatePresence>
</div>
{selectedMenus.length > 0 && (
<div className="text-end mt-4">
<Button
variant="contained"
color="primary"
disabled={updatingMenu}
onClick={handleMenuSave}
>
{updatingMenu ? "Saving..." : "Save Menu"}
</Button>
</div>
)}
</div>
</section>
);
}
......@@ -11,6 +11,7 @@ import { userApi } from "@/services/userApi";
import { settingApi } from "@/services/settingApi";
import { pageApi } from "@/services/pageApi";
import { notificationApi } from "@/services/notificationApi";
import { menuApi, userMenuApi } from "@/services/menuApi";
export const store = configureStore({
reducer: {
......@@ -26,6 +27,8 @@ export const store = configureStore({
[settingApi.reducerPath]: settingApi.reducer,
[pageApi.reducerPath]: pageApi.reducer,
[notificationApi.reducerPath]: notificationApi.reducer,
[menuApi.reducerPath]: menuApi.reducer,
[userMenuApi.reducerPath]: userMenuApi.reducer,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware()
......@@ -38,7 +41,8 @@ export const store = configureStore({
.concat(settingApi.middleware)
.concat(pageApi.middleware)
.concat(notificationApi.middleware)
.concat(menuApi.middleware)
.concat(userMenuApi.middleware)
})
export type RootState = ReturnType<typeof store.getState>;
......
......@@ -55,7 +55,13 @@ export const PATH = {
ADD_NOTIFICATIONS: {
ROOT: "/notifications/add-notifications"
}
}
},
MENUS: {
ROOT: "/menus",
// ADD_NOTIFICATIONS: {
// ROOT: "/notifications/add-notifications"
// }
},
},
USER: {
GAMES: {
......
import { MenuResponse } from "@/types/menu";
import { serverBaseQuery } from "./serverBaseQuery";
export async function getAllMenus(): Promise<MenuResponse> {
return serverBaseQuery("/api/general/menus");
}
\ No newline at end of file
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
import { baseQuery } from "./baseQuery";
import { GlobalResponse } from "@/types/config";
import { MenuResponse } from "@/types/menu";
export const menuApi = createApi({
reducerPath: "menuApi",
baseQuery: baseQuery,
tagTypes: ['Menus'],
endpoints: (builder) => ({
createMenu: builder.mutation<GlobalResponse, { pages: string[] }>({
query: (body) => ({
url: "/api/admin/menu",
method: "POST",
body: body
}),
invalidatesTags: ["Menus"]
}),
getAllMenu: builder.query<MenuResponse, void>({
query: () => ({
url: "/api/admin/menu",
method: "GET"
})
, providesTags: ["Menus"]
}),
})
})
export const { useCreateMenuMutation, useGetAllMenuQuery } = menuApi;
const basePublicQuery = fetchBaseQuery({
baseUrl: process.env.NEXT_PUBLIC_BASE_URL,
});
export const userMenuApi = createApi({
reducerPath: "userMenuApi",
baseQuery: basePublicQuery,
tagTypes: ['Menus'],
endpoints: (builder) => ({
getAllUserMenu: builder.query<MenuResponse, void>({
query: () => ({
url: "api/general/menus",
method: "GET"
})
})
})
})
export const { useGetAllUserMenuQuery } = userMenuApi;
\ No newline at end of file
export interface MenuRequest {
pages: string[];
}
export interface MenuResponse {
data: {
id?: string;
name: string;
slug: string;
description: string;
}[];
}
\ 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