feat: hide statistics, work time, expenses and finances from regular users
This commit is contained in:
@@ -15,10 +15,11 @@ import {
|
|||||||
IconSun,
|
IconSun,
|
||||||
} from "@tabler/icons-react";
|
} from "@tabler/icons-react";
|
||||||
import classes from "./Navbar.module.css";
|
import classes from "./Navbar.module.css";
|
||||||
import { useAppDispatch } from "../../redux/store.ts";
|
import { RootState, useAppDispatch } from "../../redux/store.ts";
|
||||||
import { logout } from "../../features/authSlice.ts";
|
import { logout } from "../../features/authSlice.ts";
|
||||||
import { useNavigate, useRouterState } from "@tanstack/react-router";
|
import { useNavigate, useRouterState } from "@tanstack/react-router";
|
||||||
import { setHideNavbar } from "../../features/uiSlice.ts";
|
import { setHideNavbar } from "../../features/uiSlice.ts";
|
||||||
|
import { useSelector } from "react-redux";
|
||||||
|
|
||||||
interface NavbarLinkProps {
|
interface NavbarLinkProps {
|
||||||
icon: typeof IconHome2;
|
icon: typeof IconHome2;
|
||||||
@@ -93,17 +94,21 @@ const mockdata = [
|
|||||||
label: "Маркетплейсы",
|
label: "Маркетплейсы",
|
||||||
href: "/marketplaces",
|
href: "/marketplaces",
|
||||||
},
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const adminMockdata = [
|
||||||
{
|
{
|
||||||
icon: IconChartDots,
|
icon: IconChartDots,
|
||||||
label: "Статистика",
|
label: "Статистика",
|
||||||
href: "/statistics",
|
href: "/statistics",
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export function Navbar() {
|
export function Navbar() {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const router = useRouterState();
|
const router = useRouterState();
|
||||||
|
const role = useSelector((state: RootState) => state.auth.role);
|
||||||
const { colorScheme, toggleColorScheme } = useMantineColorScheme({
|
const { colorScheme, toggleColorScheme } = useMantineColorScheme({
|
||||||
keepTransitions: true,
|
keepTransitions: true,
|
||||||
});
|
});
|
||||||
@@ -114,9 +119,17 @@ export function Navbar() {
|
|||||||
const onNavlinkClick = (props: NavbarLinkProps) => {
|
const onNavlinkClick = (props: NavbarLinkProps) => {
|
||||||
navigate({ to: props.href });
|
navigate({ to: props.href });
|
||||||
};
|
};
|
||||||
const links = mockdata.map((link, index) => (
|
|
||||||
<NavbarLink
|
|
||||||
|
|
||||||
|
const getLinksData = () => {
|
||||||
|
let data = mockdata;
|
||||||
|
if (role === "admin") {
|
||||||
|
data = data.concat(adminMockdata);
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
const links = getLinksData().map((link, index) => (
|
||||||
|
<NavbarLink
|
||||||
{...link}
|
{...link}
|
||||||
index={index}
|
index={index}
|
||||||
key={link.label}
|
key={link.label}
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||||
import { jwtDecode, JwtPayload } from "jwt-decode";
|
import { jwtDecode, JwtPayload as JwtPayloadBase } from "jwt-decode";
|
||||||
|
|
||||||
interface AuthState {
|
interface AuthState {
|
||||||
isAuthorized: boolean;
|
isAuthorized: boolean;
|
||||||
accessToken: string;
|
accessToken: string;
|
||||||
isGuest: boolean;
|
isGuest: boolean;
|
||||||
|
role: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialState = (): AuthState => {
|
const initialState = (): AuthState => {
|
||||||
@@ -16,20 +17,26 @@ const initialState = (): AuthState => {
|
|||||||
accessToken: "",
|
accessToken: "",
|
||||||
isAuthorized: false,
|
isAuthorized: false,
|
||||||
isGuest: false,
|
isGuest: false,
|
||||||
|
role: "user",
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
interface JwtPayload extends JwtPayloadBase {
|
||||||
|
role: string;
|
||||||
|
}
|
||||||
|
|
||||||
const authSlice = createSlice({
|
const authSlice = createSlice({
|
||||||
name: "auth",
|
name: "auth",
|
||||||
initialState,
|
initialState,
|
||||||
reducers: {
|
reducers: {
|
||||||
login: (state, action: PayloadAction<{ accessToken: string }>) => {
|
login: (state, action: PayloadAction<{ accessToken: string }>) => {
|
||||||
try {
|
try {
|
||||||
const { sub } = jwtDecode<JwtPayload>(
|
const { sub, role } = jwtDecode<JwtPayload>(
|
||||||
action.payload.accessToken
|
action.payload.accessToken,
|
||||||
);
|
);
|
||||||
state.accessToken = action.payload.accessToken;
|
state.accessToken = action.payload.accessToken;
|
||||||
state.isAuthorized = true;
|
state.isAuthorized = true;
|
||||||
|
state.role = role;
|
||||||
if (sub === "guest") state.isGuest = true;
|
if (sub === "guest") state.isGuest = true;
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
const url = window.location.href;
|
const url = window.location.href;
|
||||||
|
|||||||
@@ -3,8 +3,10 @@ import { Tabs } from "@mantine/core";
|
|||||||
import PageBlock from "../../components/PageBlock/PageBlock.tsx";
|
import PageBlock from "../../components/PageBlock/PageBlock.tsx";
|
||||||
import {
|
import {
|
||||||
IconBriefcase,
|
IconBriefcase,
|
||||||
IconCalendarUser, IconCoins,
|
IconCalendarUser,
|
||||||
IconCurrencyDollar, IconQrcode,
|
IconCoins,
|
||||||
|
IconCurrencyDollar,
|
||||||
|
IconQrcode,
|
||||||
IconUser,
|
IconUser,
|
||||||
} from "@tabler/icons-react";
|
} from "@tabler/icons-react";
|
||||||
import RolesAndPositionsTab from "./tabs/RolesAndPositions/RolesAndPositionsTab.tsx";
|
import RolesAndPositionsTab from "./tabs/RolesAndPositions/RolesAndPositionsTab.tsx";
|
||||||
@@ -14,8 +16,13 @@ import FinancesTab from "./tabs/Finances/FinancesTab.tsx";
|
|||||||
import WorkTimeTable from "./tabs/WorkTimeTable/ui/WorkTimeTable.tsx";
|
import WorkTimeTable from "./tabs/WorkTimeTable/ui/WorkTimeTable.tsx";
|
||||||
import { WorkShiftsTab } from "./tabs/WorkShifts/WorkShiftsTab.tsx";
|
import { WorkShiftsTab } from "./tabs/WorkShifts/WorkShiftsTab.tsx";
|
||||||
import { ExpensesTab } from "./tabs/Expenses/ExpensesTab.tsx";
|
import { ExpensesTab } from "./tabs/Expenses/ExpensesTab.tsx";
|
||||||
|
import { useSelector } from "react-redux";
|
||||||
|
import { RootState } from "../../redux/store.ts";
|
||||||
|
|
||||||
const AdminPage = () => {
|
const AdminPage = () => {
|
||||||
|
const userRole = useSelector((state: RootState) => state.auth.role);
|
||||||
|
const isAdmin = userRole === "admin";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles["container"]}>
|
<div className={styles["container"]}>
|
||||||
<PageBlock fullHeight>
|
<PageBlock fullHeight>
|
||||||
@@ -29,31 +36,37 @@ const AdminPage = () => {
|
|||||||
leftSection={<IconUser />}>
|
leftSection={<IconUser />}>
|
||||||
Пользователи
|
Пользователи
|
||||||
</Tabs.Tab>
|
</Tabs.Tab>
|
||||||
<Tabs.Tab
|
{isAdmin && (
|
||||||
value={"finances"}
|
<Tabs.Tab
|
||||||
leftSection={<IconCurrencyDollar />}>
|
value={"finances"}
|
||||||
Финансы
|
leftSection={<IconCurrencyDollar />}>
|
||||||
</Tabs.Tab>
|
Финансы
|
||||||
|
</Tabs.Tab>
|
||||||
|
)}
|
||||||
<Tabs.Tab
|
<Tabs.Tab
|
||||||
value={"rolesAndPositions"}
|
value={"rolesAndPositions"}
|
||||||
leftSection={<IconBriefcase />}>
|
leftSection={<IconBriefcase />}>
|
||||||
Должности
|
Должности
|
||||||
</Tabs.Tab>
|
</Tabs.Tab>
|
||||||
<Tabs.Tab
|
{isAdmin && (
|
||||||
value={"workTimeTable"}
|
<Tabs.Tab
|
||||||
leftSection={<IconCalendarUser />}>
|
value={"workTimeTable"}
|
||||||
Рабочее время
|
leftSection={<IconCalendarUser />}>
|
||||||
</Tabs.Tab>
|
Рабочее время
|
||||||
|
</Tabs.Tab>
|
||||||
|
)}
|
||||||
<Tabs.Tab
|
<Tabs.Tab
|
||||||
value={"workShifts"}
|
value={"workShifts"}
|
||||||
leftSection={<IconQrcode />}>
|
leftSection={<IconQrcode />}>
|
||||||
Смены
|
Смены
|
||||||
</Tabs.Tab>
|
</Tabs.Tab>
|
||||||
<Tabs.Tab
|
{isAdmin && (
|
||||||
value={"expenses"}
|
<Tabs.Tab
|
||||||
leftSection={<IconCoins />}>
|
value={"expenses"}
|
||||||
Расходы
|
leftSection={<IconCoins />}>
|
||||||
</Tabs.Tab>
|
Расходы
|
||||||
|
</Tabs.Tab>
|
||||||
|
)}
|
||||||
</Tabs.List>
|
</Tabs.List>
|
||||||
<Tabs.Panel value={"users"}>
|
<Tabs.Panel value={"users"}>
|
||||||
<motion.div
|
<motion.div
|
||||||
|
|||||||
@@ -1,8 +1,17 @@
|
|||||||
import { StatisticsTab } from "../components/StatisticsTabSegmentedControl/StatisticsTabSegmentedControl.tsx";
|
import { StatisticsTab } from "../components/StatisticsTabSegmentedControl/StatisticsTabSegmentedControl.tsx";
|
||||||
import styles from "./StatisticsPage.module.css";
|
import styles from "./StatisticsPage.module.css";
|
||||||
import { ProfitTab } from "../tabs/ProfitTab/ProfitTab.tsx";
|
import { ProfitTab } from "../tabs/ProfitTab/ProfitTab.tsx";
|
||||||
|
import { useSelector } from "react-redux";
|
||||||
|
import { RootState } from "../../../redux/store.ts";
|
||||||
|
import { Navigate } from "@tanstack/react-router";
|
||||||
|
|
||||||
export const StatisticsPage = () => {
|
export const StatisticsPage = () => {
|
||||||
|
const userRole = useSelector((state: RootState) => state.auth.role);
|
||||||
|
|
||||||
|
if (userRole !== "admin") {
|
||||||
|
return <Navigate to={"/leads"} />;
|
||||||
|
}
|
||||||
|
|
||||||
const serviceType = StatisticsTab.PROFIT;
|
const serviceType = StatisticsTab.PROFIT;
|
||||||
|
|
||||||
const getBody = () => {
|
const getBody = () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user