updaste dashboard
This commit is contained in:
60
src/App.tsx
60
src/App.tsx
@@ -1,44 +1,24 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { Route, BrowserRouter as Router, Routes, Navigate } from "react-router-dom";
|
||||
import DefaultLayout from "./Layouts/DefaultLayout";
|
||||
import Login from "./Pages/Login";
|
||||
import { RouteLink } from "./Routes/Routes";
|
||||
import Cookies from "js-cookie";
|
||||
import { useContext } from 'react';
|
||||
import { Route, BrowserRouter as Router, Routes } from "react-router-dom";
|
||||
import GlobalStateContext from './Contexts/GlobalStateContext';
|
||||
import DefaultLayout from './Layouts/DefaultLayout';
|
||||
import Login from './Pages/Login';
|
||||
import { RouteLink } from './Routes/Routes';
|
||||
|
||||
function App() {
|
||||
const [token, setToken] = useState<string | null>(null);
|
||||
function App() {
|
||||
const context = useContext(GlobalStateContext);
|
||||
if (!context) throw new Error('App must be used within a GlobalStateProvider');
|
||||
const { isAuthenticate } = context;
|
||||
|
||||
useEffect(() => {
|
||||
const savedToken = Cookies.get("token");
|
||||
console.log("Token from Cookies:", savedToken);
|
||||
setToken(savedToken || null);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Router>
|
||||
<Routes>
|
||||
<Route path="/login" element={<Login />} />
|
||||
<Route
|
||||
path="/*"
|
||||
element={
|
||||
token ? (
|
||||
<DefaultLayout>
|
||||
<Routes>
|
||||
{RouteLink.map(({ path, Component }, index) => (
|
||||
<Route key={index} path={path} element={<Component />} />
|
||||
))}
|
||||
<Route path="/" element={<Navigate to="/dashboard" />} />
|
||||
</Routes>
|
||||
</DefaultLayout>
|
||||
) : (
|
||||
<Navigate to="/login" replace />
|
||||
)
|
||||
}
|
||||
/>
|
||||
<Route path="*" element={<Navigate to={token ? "/dashboard" : "/login"} replace />} />
|
||||
</Routes>
|
||||
</Router>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Router>
|
||||
<Routes>
|
||||
<Route path="/login" element={<Login />} />
|
||||
<Route path="/*" element={localStorage.getItem("token")? (<DefaultLayout><Routes>{RouteLink.map(({ path, Component }, index) => (<Route key={index} path={path} element={<Component />} />))}</Routes></DefaultLayout>) : (<Login />)} />
|
||||
<Route path="*" element={<Login />} />
|
||||
</Routes>
|
||||
</Router>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
|
||||
@@ -6,8 +6,12 @@ import { nav } from "../Routes/Nav";
|
||||
import logo from '../assets/logo.svg';
|
||||
import { AccordionItem, AccordionItemContent, AccordionItemTrigger, AccordionRoot } from "../components/ui/accordion";
|
||||
import { Avatar } from "../components/ui/avatar";
|
||||
import { LuLogOut } from "react-icons/lu";
|
||||
import { logout, setToken } from "../Redux/Service/authSlice";
|
||||
import { useDispatch } from "react-redux";
|
||||
|
||||
const DefaultLayout: FC<{ children: React.ReactNode }> = ({ children }) => {
|
||||
const dispatch = useDispatch()
|
||||
const navigate = useNavigate()
|
||||
const location = useLocation()
|
||||
|
||||
@@ -15,25 +19,31 @@ const DefaultLayout: FC<{ children: React.ReactNode }> = ({ children }) => {
|
||||
|
||||
|
||||
return (
|
||||
<HStack position={'relative'} bg="#F2F2F2" backgroundPosition="center" backgroundRepeat="repeat" backgroundSize="cover" gap={0} w="100%" h="100vh" p={0}>
|
||||
<HStack overflow={'hidden'} position={'relative'} bg="#F2F2F2" backgroundPosition="center" backgroundRepeat="repeat" backgroundSize="cover" gap={0} w="100%" h="100vh" p={0}>
|
||||
|
||||
<VStack zIndex={1} gap={0} rounded={'lg'} h="100%" w="16%" overflow={'scroll'} >
|
||||
<VStack zIndex={1} gap={0} rounded={'lg'} h="100%" w="16%" overflow={'auto'} >
|
||||
<HStack w={'100%'} p={3} h={'8%'} justifyContent={'center'}>
|
||||
<Image w={55} src={logo} />
|
||||
</HStack>
|
||||
<VStack w={'100%'} p={4} pt={0}>
|
||||
<VStack w={'100%'} p={4} pt={0}>
|
||||
{nav?.map(({ title, path, Icon, type, children }, index) => type === 'single' ?
|
||||
<NavLink className="link" key={index} to={path} style={{ cursor: 'pointer', borderRadius: '8px', padding: '6px', width: '100%', display: 'flex', alignItems: 'center', gap: 6, border: '1px solid #ffffff', backgroundColor:'#fff', color:'#000', boxShadow:'rgba(99, 99, 99, 0.2) 0px 2px 8px 0px'}} ><Icon style={{ fontSize: '20px' }} /> <Text fontSize={'xs'} w={'100%'}>{title}</Text></NavLink> :
|
||||
<AccordionRoot bg={'#fff'} rounded={'lg'} collapsible>
|
||||
<AccordionItem boxShadow={'rgba(99, 99, 99, 0.2) 0px 2px 8px 0px'} borderBottom={'none'} p={0} key={index} value={title}>
|
||||
<AccordionItem rounded={'lg'} bg={'#fff'} boxShadow={'rgba(99, 99, 99, 0.2) 0px 2px 8px 0px'} borderBottom={'none'} p={0} key={index} value={title}>
|
||||
<AccordionItemTrigger className="Oxygen" color={'#fff'} onClick={() => navigate(path)} gap={0} style={{ cursor: 'pointer', borderRadius: '8px', padding: '5px', width: '100%', display: 'flex', alignItems: 'center', border: '1px solid #ffffff', backgroundColor:'#fff',color:'#000', fontSize: '14px', }}> <Text fontSize={'xs'} gap={1} display={'flex'} alignItems={'center'} ><Icon style={{ fontSize: '20px' }} />{title}</Text></AccordionItemTrigger>
|
||||
{children?.map(({ title, path, Icon }, index) => <AccordionItemContent className={`linkChild Oxygen ${location?.pathname === path && 'activeChild'}`} key={index} onClick={()=>navigate(path)} style={{ marginTop: 6, cursor: 'pointer', borderRadius: '8px', padding: '6px', width: '100%', display: 'flex', alignItems: 'center', gap: 6, border: '1px solid #ffffff', backgroundColor:'#fff',color:'#919198' }} ><Icon style={{ fontSize: '20px' }} /> <Text fontSize={'xs'} w={'100%'}>{title}</Text></AccordionItemContent>)}
|
||||
</AccordionItem>
|
||||
</AccordionRoot>)}
|
||||
</VStack>
|
||||
|
||||
<VStack w={'100%'} p={3} pt={0}>
|
||||
<HStack onClick={()=>{dispatch(logout()), navigate('/login')}} className="link" style={{ cursor: 'pointer', borderRadius: '8px', padding: '6px', width: '100%', display: 'flex', alignItems: 'center', gap: 6, border: '1px solid #ffffff', backgroundColor:'#fff', color:'#000', boxShadow:'rgba(99, 99, 99, 0.2) 0px 2px 8px 0px'}} ><LuLogOut style={{ fontSize: '20px' }} /> <Text fontSize={'xs'} w={'100%'}>Logout</Text></HStack>
|
||||
</VStack>
|
||||
</VStack>
|
||||
<VStack gap={0} h="100%" w="85%" >
|
||||
<HStack h={'8%'} w={'100%'} justifyContent={'flex-end'} pe={3} gap={6}>
|
||||
|
||||
|
||||
<VStack gap={0} h="100%" w="85%" >
|
||||
<HStack h={'12%'} w={'100%'} justifyContent={'flex-end'} pe={3} gap={6}>
|
||||
<NavLink to={'/manage-notification'}><RiNotificationLine color="#013e3e" cursor={'pointer'} style={{ fontSize: '22px' }} /></NavLink>
|
||||
<HStack cursor={'pointer'} onClick={() => navigate('/profile')} >
|
||||
<Avatar size={'sm'} src="https://i.pinimg.com/736x/d6/cd/0f/d6cd0ffd4634b0763d3958a7325ce26e.jpg" />
|
||||
|
||||
@@ -67,8 +67,8 @@ const Dashboard = () => {
|
||||
|
||||
return (
|
||||
<MainFrame>
|
||||
<Box display={"flex"} p={"20px"} gap={5}>
|
||||
<Box w={"30%"} boxShadow={"rgba(99, 99, 99, 0.2) 0px 2px 8px 0px"}>
|
||||
<Box display={"flex"} p={"20px"} pt={'8px'} gap={5}>
|
||||
<Box rounded={'lg'} w={"30%"} boxShadow={"rgba(99, 99, 99, 0.2) 0px 2px 8px 0px"}>
|
||||
<Heading fontSize={"sm"} p={2}>
|
||||
Total Users
|
||||
</Heading>
|
||||
@@ -117,6 +117,7 @@ const Dashboard = () => {
|
||||
<Box
|
||||
p={"20px"}
|
||||
w={"50%"}
|
||||
rounded={'lg'}
|
||||
boxShadow={"rgba(99, 99, 99, 0.2) 0px 2px 8px 0px"}
|
||||
>
|
||||
<HStack alignItems={"center"} mb={4}>
|
||||
@@ -140,13 +141,14 @@ const Dashboard = () => {
|
||||
w={"20%"}
|
||||
boxShadow={"rgba(99, 99, 99, 0.2) 0px 2px 8px 0px"}
|
||||
p={'10px'}
|
||||
rounded={'lg'}
|
||||
>
|
||||
<Text fontSize={"sm"} fontWeight={500} pt={3}>Number Of Groups created</Text>
|
||||
<CircularApp />
|
||||
</Box>
|
||||
</Box>
|
||||
<Box p={"20px"} display={"flex"} gap={5}>
|
||||
<Box w={"50%"} bg={"#f2f2f2"} h={400} p={"10px"} overflow={'scroll'}>
|
||||
<Box p={"20px"} pt={0} display={"flex"} gap={5}>
|
||||
<Box w={"50%"} rounded={'lg'} bg={"#f2f2f2"} h={400} p={"10px"} overflow={'auto'}>
|
||||
<HStack justifyContent={"space-between"} mb={5}>
|
||||
<Text fontSize={"xs"} fontWeight={500}>Faqs</Text>
|
||||
<Button
|
||||
@@ -180,7 +182,7 @@ const Dashboard = () => {
|
||||
))}
|
||||
</AccordionRoot>
|
||||
</Box>
|
||||
<Box w={"50%"} bg={"#f2f2f2"} h={400} overflow={'scroll'}>
|
||||
<Box w={"50%"} rounded={'lg'} bg={"#f2f2f2"} h={400} overflow={'auto'}>
|
||||
<AgencyName />
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
@@ -2,9 +2,18 @@ import { Box, HStack, Text } from "@chakra-ui/react";
|
||||
import MainFrame from "../../../components/MainFrame"
|
||||
import { p } from "framer-motion/client";
|
||||
import AboutUsAddModel from "../../ManageCMS/AboutUs/AboutUsAddModel";
|
||||
import { useGetAboutUsQuery } from "../../../Redux/Service/manage.aboutus.service";
|
||||
|
||||
|
||||
const AboutUs = () => {
|
||||
|
||||
const {
|
||||
data
|
||||
} = useGetAboutUsQuery()
|
||||
|
||||
console.log('====================================');
|
||||
console.log(data);
|
||||
console.log('====================================');
|
||||
return (
|
||||
|
||||
<MainFrame>
|
||||
|
||||
@@ -15,7 +15,7 @@ const baseQuery = fetchBaseQuery({
|
||||
|
||||
if (token) {
|
||||
headers.set("Authorization", `Basic ${basicAuth}`);
|
||||
headers.set("access-token", `Bearer ${token}`);
|
||||
headers.set("access-token", `${token}`);
|
||||
|
||||
}
|
||||
headers.set("Content-Type", "application/json");
|
||||
@@ -23,6 +23,7 @@ const baseQuery = fetchBaseQuery({
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
// ✅ Handle 401 Errors (Auto Logout)
|
||||
export const baseQueryWithReauth: BaseQueryFn<
|
||||
string | FetchArgs,
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
type AuthState = {
|
||||
token: string | null;
|
||||
};
|
||||
|
||||
const initialState: AuthState = {
|
||||
token: Cookies.get("token") || null, // Load token from cookies
|
||||
token: localStorage.getItem("token") || null, // ✅ Ensures token is either a string or null
|
||||
};
|
||||
|
||||
const authSlice = createSlice({
|
||||
@@ -15,11 +14,11 @@ const authSlice = createSlice({
|
||||
reducers: {
|
||||
setToken: (state, action: PayloadAction<string>) => {
|
||||
state.token = action.payload;
|
||||
Cookies.set("token", action.payload, { expires: 7, secure: true, sameSite: "Strict" }); // Store in cookies for 7 days
|
||||
localStorage.setItem("token", action.payload); // ✅ Store token in localStorage
|
||||
},
|
||||
logout: (state) => {
|
||||
state.token = null;
|
||||
Cookies.remove("token");
|
||||
localStorage.removeItem("token"); // ✅ Remove token from localStorage on logout
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,26 +1,85 @@
|
||||
import { createApi } from "@reduxjs/toolkit/query";
|
||||
import { createApi } from "@reduxjs/toolkit/query/react";
|
||||
import { baseQueryWithReauth } from "./apiSlice";
|
||||
|
||||
export const aboutUs = createApi({
|
||||
reducerPath: "aboutUs",
|
||||
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
|
||||
endpoints: (builder) => ({
|
||||
|
||||
|
||||
|
||||
getPosts: builder.query<Post[], void>({ query: () => "/posts" }),
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
reducerPath: "aboutUs",
|
||||
baseQuery: baseQueryWithReauth, // Use enhanced baseQuery with error handling
|
||||
endpoints: (builder) => ({
|
||||
|
||||
|
||||
|
||||
// 🔹 GET: Fetch all posts
|
||||
getAboutUs: builder.query<AboutUs[], void>({
|
||||
query: () => "/about-us",
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// 🔹 GET: Fetch a single post by ID
|
||||
getPostById: builder.query<Post, number>({
|
||||
query: (id) => `/posts/${id}`,
|
||||
}),
|
||||
|
||||
// 🔹 POST: Create a new post
|
||||
createPost: builder.mutation<Post, Partial<Post>>({
|
||||
query: (newPost) => ({
|
||||
url: "/posts",
|
||||
method: "POST",
|
||||
body: newPost,
|
||||
}),
|
||||
}),
|
||||
|
||||
// 🔹 PUT: Update an existing post
|
||||
updatePost: builder.mutation<Post, { id: number; updatedData: Partial<Post> }>({
|
||||
query: ({ id, updatedData }) => ({
|
||||
url: `/posts/${id}`,
|
||||
method: "PUT",
|
||||
body: updatedData,
|
||||
}),
|
||||
}),
|
||||
|
||||
// 🔹 DELETE: Remove a post by ID
|
||||
deletePost: builder.mutation<{ success: boolean }, number>({
|
||||
query: (id) => ({
|
||||
url: `/posts/${id}`,
|
||||
method: "DELETE",
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
export const {
|
||||
useGetAboutUsQuery,
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
export const { } = aboutUs;
|
||||
|
||||
export type Post = {
|
||||
id: number;
|
||||
title: string;
|
||||
body: string;
|
||||
};
|
||||
useGetPostByIdQuery,
|
||||
useCreatePostMutation,
|
||||
useUpdatePostMutation,
|
||||
useDeletePostMutation
|
||||
} = aboutUs;
|
||||
|
||||
// Define Post type
|
||||
export type Post = {
|
||||
id: number;
|
||||
title: string;
|
||||
body: string;
|
||||
};
|
||||
|
||||
|
||||
export type AboutUs = {
|
||||
id: number;
|
||||
language_master_xid: number;
|
||||
content: string;
|
||||
is_active: boolean;
|
||||
};
|
||||
|
||||
@@ -13,13 +13,13 @@ interface MainFrameProps {
|
||||
|
||||
const MainFrame: FC<MainFrameProps> = ({ children }) => {
|
||||
return (
|
||||
<MotionVStack {...OPACITY_ON_LOAD} w="100%" h="90%" p={0} pb={0}>
|
||||
<MotionVStack rounded="lg" overflowY={'auto'} overflowX={'hidden'} {...OPACITY_ON_LOAD} w="100%" minH="93%" p={0} pb={2}>
|
||||
<Box
|
||||
w="100%"
|
||||
h="100%"
|
||||
// h="100%"
|
||||
bg="#ffffff"
|
||||
overflow={'scroll'}
|
||||
// rounded="md"
|
||||
// overflow={'scroll'}
|
||||
rounded="lg"
|
||||
boxShadow={'rgba(99, 99, 99, 0.2) 0px 2px 8px 0px'}
|
||||
pt={3}
|
||||
>
|
||||
|
||||
@@ -156,12 +156,31 @@ body {
|
||||
/* Border around the thumb */
|
||||
}
|
||||
|
||||
/* Style the scrollbar thumb on hover */
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background-color: #555;
|
||||
/* Darker gray when hovered */
|
||||
/* Scrollbar width */
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Scrollbar track */
|
||||
::-webkit-scrollbar-track {
|
||||
background: transparent; /* No visible track */
|
||||
}
|
||||
|
||||
/* Scrollbar thumb (the draggable part) */
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: rgba(0, 0, 0, 0.3); /* Light black (30% opacity) */
|
||||
border-radius: 10px; /* Rounded edges */
|
||||
transition: background 0.3s;
|
||||
}
|
||||
|
||||
/* On hover, make it darker */
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
|
||||
input:focus-visible {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user