179 lines
4.8 KiB
TypeScript
179 lines
4.8 KiB
TypeScript
import { Ionicons } from "@expo/vector-icons";
|
|
import { router, usePathname } from "expo-router";
|
|
import { Pressable, Text, View } from "react-native";
|
|
|
|
import { useAppSelector } from "@/store/hooks";
|
|
import { selectIsMobile } from "@/store/screen/screenSizeSlice";
|
|
import { IoniconsName } from "@/types/index";
|
|
import { useRoleAccess } from "@/hooks/useRoleAccess";
|
|
|
|
const HIDDEN_PATHS = ["/accounts/admins", "/accounts/todos"];
|
|
|
|
interface TabItem {
|
|
label: string;
|
|
route: string;
|
|
icon?: IoniconsName;
|
|
}
|
|
|
|
interface TabGroup {
|
|
basePath: string;
|
|
tabs: TabItem[];
|
|
}
|
|
|
|
export const ContentTabs = () => {
|
|
const pathname = usePathname();
|
|
const isMobile = useAppSelector(selectIsMobile);
|
|
const { isManager } = useRoleAccess();
|
|
|
|
// Hide top tabs when user lacks permission and is on restricted Accounts pages
|
|
if (!isManager && HIDDEN_PATHS.includes(pathname)) {
|
|
return null;
|
|
}
|
|
|
|
const tabGroups: TabGroup[] = [
|
|
{
|
|
basePath: "/",
|
|
tabs: [
|
|
{
|
|
label: "Dashboard",
|
|
route: "/user-dashboard/index",
|
|
icon: "home",
|
|
},
|
|
],
|
|
},
|
|
{
|
|
basePath: "/accounts",
|
|
tabs: [
|
|
{
|
|
label: "Users",
|
|
route: "/accounts/users",
|
|
icon: "person-outline",
|
|
},
|
|
...(isManager
|
|
? [
|
|
{
|
|
label: "Admins",
|
|
route: "/accounts/admins",
|
|
icon: "settings" as IoniconsName,
|
|
},
|
|
{
|
|
label: "Todos",
|
|
route: "/accounts/todos",
|
|
icon: "list" as IoniconsName,
|
|
},
|
|
]
|
|
: []),
|
|
],
|
|
},
|
|
{
|
|
basePath: "/logs",
|
|
tabs: [{ label: "System", route: "/logs/system", icon: "server" }],
|
|
},
|
|
{
|
|
basePath: "/reports",
|
|
tabs: [{ label: "Inbox", route: "/reports/inbox", icon: "mail" }],
|
|
},
|
|
{
|
|
basePath: "/data-protection",
|
|
tabs: [
|
|
{ label: "General", route: "/data-protection/general", icon: "cog" },
|
|
],
|
|
},
|
|
{
|
|
basePath: "/settings",
|
|
tabs: [{ label: "General", route: "/settings/general", icon: "cog" }],
|
|
},
|
|
];
|
|
|
|
let currentSection = "";
|
|
|
|
if (
|
|
pathname.includes("/dashboard") ||
|
|
pathname === "/(tabs)" ||
|
|
pathname === "/"
|
|
) {
|
|
currentSection = "/";
|
|
} else if (pathname.includes("/accounts")) {
|
|
currentSection = "/accounts";
|
|
} else if (pathname.includes("/settings")) {
|
|
currentSection = "/settings";
|
|
} else if (pathname.includes("/logs")) {
|
|
currentSection = "/logs";
|
|
} else if (pathname.includes("/reports")) {
|
|
currentSection = "/reports";
|
|
} else if (pathname.includes("/data-protection")) {
|
|
currentSection = "/data-protection";
|
|
}
|
|
|
|
const activeGroup = tabGroups.find(
|
|
(group) => group.basePath === currentSection
|
|
);
|
|
if (!activeGroup || activeGroup.tabs.length === 0) {
|
|
return null;
|
|
}
|
|
|
|
const isTabActive = (tabRoute: string) => {
|
|
if (tabRoute === "/user-dashboard/index") {
|
|
if (pathname === "/(tabs)" || pathname === "/") {
|
|
return true;
|
|
}
|
|
return pathname.includes("/user-dashboard");
|
|
}
|
|
|
|
const routeSegments = tabRoute.split("/");
|
|
const lastSegment = routeSegments[routeSegments.length - 1];
|
|
|
|
return pathname.includes(lastSegment);
|
|
};
|
|
|
|
return (
|
|
<View
|
|
className={`bg-primaryPurpleLight ${isMobile ? "px-1" : "px-2"} ${
|
|
isMobile ? "pt-2 pb-0" : "pt-3"
|
|
}`}
|
|
>
|
|
<View className={`flex-row ${isMobile ? "justify-start gap-3" : ""}`}>
|
|
{activeGroup.tabs.map((tab, index) => {
|
|
const active = isTabActive(tab.route);
|
|
return (
|
|
<Pressable
|
|
key={index}
|
|
onPress={() => router.push(tab.route as any)}
|
|
className={`relative mx-1 border-b-2 transition-colors duration-200
|
|
${active ? "border-white" : "border-transparent"}
|
|
${isMobile ? "px-1" : "px-4"}
|
|
`}
|
|
style={{ paddingBottom: isMobile ? 6 : 4 }}
|
|
>
|
|
{isMobile ? (
|
|
<View className="items-center">
|
|
<Ionicons
|
|
name={tab.icon as IoniconsName}
|
|
size={20}
|
|
color="white"
|
|
style={{ opacity: active ? 1 : 0.7 }}
|
|
/>
|
|
<Text
|
|
className="text-white text-[10px] mt-0.5"
|
|
style={{ opacity: active ? 1 : 0.7 }}
|
|
>
|
|
{tab.label}
|
|
</Text>
|
|
</View>
|
|
) : (
|
|
<Text
|
|
className={`text-base text-white transition-colors duration-200
|
|
${active ? "font-medium" : "font-normal"}
|
|
`}
|
|
>
|
|
{tab.label}
|
|
</Text>
|
|
)}
|
|
</Pressable>
|
|
);
|
|
})}
|
|
</View>
|
|
</View>
|
|
);
|
|
};
|