Repository: Gerald-27119/Merkury
Pull request #102: fix/MER-242
Author: login: Mredosz
Created: 2025-04-26T11:38:13Z | Merged: 2025-05-13T18:30:57Z

This pull request introduces several significant changes to the `venus` project, focusing on enhancing the sidebar's functionality, improving code modularity, and adding utility hooks. The updates include modularizing the sidebar components, adding reusable hooks, and removing unused or redundant code.

### Sidebar Refactoring and Enhancements:
* The `Sidebar` component has been restructured to use modular components such as `SidebarList`, `SidebarSection`, `SidebarToggleButton`, and `Tooltip`. This improves readability and maintainability. [[1]](diffhunk://#diff-940539102dd775cc947ca3014232e20b582dd12c84aac4bbb88547678fee47efL1-R54) [[2]](diffhunk://#diff-6896d24f08ed59f7aaa8ea89ef9b12ac4cf7c65714ab9b3c08ee1016db59fa6dR1-R32) [[3]](diffhunk://#diff-e0078c002b3488c0154c945926818b66e0ae589b3e1aeb41282414e204406813R1-R23) [[4]](diffhunk://#diff-7452aa58572c7676974b08ceaf1475b274b92462e926667c7febee832397e9f9R1-R24) [[5]](diffhunk://#diff-02e89813a618f0c7b643c26cbc76045de36a76f32acc11416f3a9b197fc2a309R1-R26)
* Introduced new components like `SidebarIcon`, `SidebarLabel`, and `SidebarItem` variants (`SidebarItemSubmenu`, `SidebarItemAction`, `SidebarItemLink`) to handle specific sidebar functionalities. [[1]](diffhunk://#diff-6896d24f08ed59f7aaa8ea89ef9b12ac4cf7c65714ab9b3c08ee1016db59fa6dR1-R32) [[2]](diffhunk://#diff-90a404ab0440210316e0b9333f90520630c18915433b88abb085710f43cf8719R1-R52) [[3]](diffhunk://#diff-051ef3e29be961c172d18af37a21405bfcba557bb8b2026f51e8daaad894f925R1-R68)
* Removed hardcoded sidebar links and replaced them with dynamically generated links using utility functions (`getOptionsLinks`, `staticLinks`, etc.).

### Hook Additions:
* Added `useBoolean`, `useToggle`, and `useToggleState` hooks to simplify state management for boolean values and toggling logic. [[1]](diffhunk://#diff-98d6181806f983071def834e93daf0cc08c91bbaf312119f740d502d2db5fc1dR1-R11) [[2]](diffhunk://#diff-cce60c1ae6a65c21ffabac775c7cf1fe0ae8b47167477ef63a2e78de9ce55610R1-R11) [[3]](diffhunk://#diff-bfd40a3b89d4045ec31c319d9ede9bd519530ca78a3834d19a33f7e52e1bb7eeR1-R11)
* Introduced the `useDarkMode` hook to manage and persist the dark mode state, including updating the DOM and localStorage.

### Code Cleanup:
* Removed the `SignOutButton` component and its associated logic, as it is no longer in use.
* Eliminated unused imports and redundant code from the `Sidebar` and `Layout` components. [[1]](diffhunk://#diff-940539102dd775cc947ca3014232e20b582dd12c84aac4bbb88547678fee47efL1-R54) [[2]](diffhunk://#diff-82e35592ca46356a12d98649b6d11df954bd601be4198b509d5dc8e286e3db0cL4-L42)

### Dependency Updates:
* Added the `motion` library to `package.json` for animations, which is now used in components like `SidebarLabel`.


Diff:
diff --git a/venus/package.json b/venus/package.json
index a5a0b0ade..3e35ffd04 100644
--- a/venus/package.json
+++ b/venus/package.json
@@ -21,6 +21,7 @@
     "axios": "^1.7.3",
     "dotenv": "^16.4.7",
     "maplibre-gl": "^5.4.0",
+    "motion": "^12.10.4",
     "openmeteo": "^1.1.4",
     "react": "^18.3.1",
     "react-dom": "^18.3.1",
diff --git a/venus/src/components/sign-out-button/SignOutButton.jsx b/venus/src/components/sign-out-button/SignOutButton.jsx
deleted file mode 100644
index 1f474a0a4..000000000
--- a/venus/src/components/sign-out-button/SignOutButton.jsx
+++ /dev/null
@@ -1,40 +0,0 @@
-import { logout } from "../../http/account.js";
-import { useDispatch } from "react-redux";
-import { accountAction } from "../../redux/account.jsx";
-import { notificationAction } from "../../redux/notification.jsx";
-import { useNavigate } from "react-router-dom";
-
-export default function SignOutButton() {
-  const dispatch = useDispatch();
-  const navigate = useNavigate();
-
-  const handleSignOut = async () => {
-    try {
-      await logout();
-      dispatch(
-        notificationAction.setSuccess({
-          message: "You have been successfully logged out",
-        }),
-      );
-      dispatch(accountAction.signOut());
-    } catch (error) {
-      dispatch(
-        notificationAction.setError({
-          message: error?.message || "Logout failed!",
-        }),
-      );
-    }
-    navigate("/");
-  };
-
-  return (
-    <button
-      className={
-        "justify-center rounded-sm bg-linear-to-r from-purple-500 to-teal-500 px-1.5 text-center align-middle leading-normal text-fuchsia-50 transition-all delay-200 duration-600 ease-in-out hover:from-teal-600 hover:to-purple-600"
-      }
-      onClick={handleSignOut}
-    >
-      Sign out
-    </button>
-  );
-}
diff --git a/venus/src/hooks/useBoolean.tsx b/venus/src/hooks/useBoolean.tsx
new file mode 100644
index 000000000..cbb7f61ff
--- /dev/null
+++ b/venus/src/hooks/useBoolean.tsx
@@ -0,0 +1,11 @@
+import { useCallback, useState } from "react";
+
+export function useBoolean(initialValue = false) {
+  const [value, setValue] = useState(initialValue);
+
+  const setTrue = useCallback(() => setValue(true), []);
+  const setFalse = useCallback(() => setValue(false), []);
+  const toggle = useCallback(() => setValue((prev) => !prev), []);
+
+  return [value, setTrue, setFalse, toggle] as const;
+}
diff --git a/venus/src/hooks/useDarkMode.tsx b/venus/src/hooks/useDarkMode.tsx
new file mode 100644
index 000000000..c1c973dc3
--- /dev/null
+++ b/venus/src/hooks/useDarkMode.tsx
@@ -0,0 +1,24 @@
+import { useState, useEffect } from "react";
+
+export function useDarkMode() {
+  const [isDark, setIsDark] = useState(
+    () => localStorage.getItem("theme") === "dark",
+  );
+
+  useEffect(() => {
+    const html = document.documentElement;
+    if (isDark) {
+      html.classList.add("dark");
+      localStorage.setItem("theme", "dark");
+    } else {
+      html.classList.remove("dark");
+      localStorage.setItem("theme", "light");
+    }
+  }, [isDark]);
+
+  const toggleDarkMode = () => {
+    setIsDark((prev) => !prev);
+  };
+
+  return [isDark, toggleDarkMode] as const;
+}
diff --git a/venus/src/hooks/useToggleState.tsx b/venus/src/hooks/useToggleState.tsx
new file mode 100644
index 000000000..faff152dc
--- /dev/null
+++ b/venus/src/hooks/useToggleState.tsx
@@ -0,0 +1,11 @@
+import { useCallback, useState } from "react";
+
+export function useToggleState(initialState = false) {
+  const [state, setState] = useState(initialState);
+
+  const toggle = useCallback(() => {
+    setState((prevState) => !prevState);
+  }, []);
+
+  return [state, setState, toggle] as const;
+}
diff --git a/venus/src/layout/Layout.jsx b/venus/src/layout/Layout.jsx
index ee605a480..887ecbbdb 100644
--- a/venus/src/layout/Layout.jsx
+++ b/venus/src/layout/Layout.jsx
@@ -1,13 +1,15 @@
 import { Outlet, useLocation } from "react-router-dom";
 import Notification from "../components/notification/Notification.jsx";
 import Sidebar from "./sidebar/Sidebar.tsx";
-import { useEffect, useState } from "react";
+import { useEffect } from "react";
 import MobileBar from "./mobile-bar/MobileBar";
+import { useToggleState } from "../hooks/useToggleState";
 
 export default function Layout() {
   const location = useLocation();
   const isMapPage = location.pathname === "/map";
-  const [isSidebarOpen, setIsSidebarOpen] = useState(false);
+  const [isSidebarOpen, setIsSidebarOpen, toggleSidebar] =
+    useToggleState(false);
 
   useEffect(() => {
     if (location.pathname.includes("account") && window.innerWidth >= 1280) {
@@ -15,30 +17,14 @@ export default function Layout() {
     }
   }, [location]);
 
-  const toggleSideBar = () => {
-    setIsSidebarOpen((prevState) => !prevState);
-  };
-
-  const closeSideBar = () => {
-    if (window.innerWidth < 1280) {
-      setIsSidebarOpen(false);
-    }
-  };
-
   return (
-    <>
-      <div className={`${isMapPage ? "relative" : "flex"} lg:h-screen`}>
-        <Sidebar
-          isSidebarOpen={isSidebarOpen}
-          onToggle={toggleSideBar}
-          onClose={closeSideBar}
-        />
-        <main className="relative flex w-full flex-col items-center justify-center">
-          <MobileBar onToggle={toggleSideBar} />
-          <Notification title="test" message="message" />
-          <Outlet />
-        </main>
-      </div>
-    </>
+    <div className={`${isMapPage ? "relative" : "flex"} lg:h-screen`}>
+      <Sidebar isSidebarOpen={isSidebarOpen} onToggle={toggleSidebar} />
+      <main className="relative flex w-full flex-col items-center justify-center">
+        <MobileBar onToggle={toggleSidebar} />
+        <Notification title="test" message="message" />
+        <Outlet />
+      </main>
+    </div>
   );
 }
diff --git a/venus/src/layout/sidebar/Sidebar.tsx b/venus/src/layout/sidebar/Sidebar.tsx
index 1bf6d9baf..f9c7ce14a 100644
--- a/venus/src/layout/sidebar/Sidebar.tsx
+++ b/venus/src/layout/sidebar/Sidebar.tsx
@@ -1,203 +1,50 @@
-import { FaRegBell, FaRegHeart, FaRegUser } from "react-icons/fa";
-import { useState } from "react";
-import { LuMoon, LuSun } from "react-icons/lu";
-import { IoMenu } from "react-icons/io5";
-import {
-  MdOutlineForum,
-  MdOutlinePhotoLibrary,
-  MdOutlineVideoLibrary,
-} from "react-icons/md";
-import { FaRegMap } from "react-icons/fa6";
-import { BiComment, BiHome, BiMessageRounded } from "react-icons/bi";
-import { FiUsers } from "react-icons/fi";
-import { TbMapPin, TbMapPinPlus } from "react-icons/tb";
-import { BsGear } from "react-icons/bs";
-import SidebarItem from "./components/SidebarItem";
 import useSelectorTyped from "../../hooks/useSelectorTyped";
 import { useLocation } from "react-router-dom";
-
-const iconSize = 35;
-
-const links = [
-  { to: "/", icon: <BiHome size={iconSize} aria-label="home" />, name: "home" },
-  {
-    to: "/map",
-    icon: <FaRegMap size={iconSize} aria-label="map" />,
-    name: "map",
-  },
-  {
-    to: "/forum",
-    icon: <MdOutlineForum size={iconSize} aria-label="forum" />,
-    name: "forum",
-  },
-  {
-    to: "/chat",
-    icon: <BiMessageRounded size={iconSize} aria-label="chat" />,
-    name: "chat",
-  },
-  {
-    to: "/spots-list",
-    icon: <FaRegHeart size={iconSize} aria-label="spotsList" />,
-    name: "favorites spots",
-  },
-];
-
-const accountLinks = [
-  {
-    to: "/account/profile",
-    icon: <FaRegUser size={iconSize} aria-label="profile" />,
-    name: "profile",
-  },
-  {
-    to: "/account/spots-list",
-    icon: <TbMapPin size={iconSize} aria-label="accountSpotsList" />,
-    name: "spots list",
-  },
-  {
-    to: "/account/photos-list",
-    icon: <MdOutlinePhotoLibrary size={iconSize} aria-label="photosList" />,
-    name: "photos list",
-  },
-  {
-    to: "/account/movies-list",
-    icon: <MdOutlineVideoLibrary size={iconSize} aria-label="moviesList" />,
-    name: "movies list",
-  },
-  {
-    to: "/account/friends",
-    icon: <FiUsers size={iconSize} aria-label="friends" />,
-    name: "friends",
-  },
-  {
-    to: "/account/add-spot",
-    icon: <TbMapPinPlus size={iconSize} aria-label="addSpot" />,
-    name: "add spot",
-  },
-  {
-    to: "/account/comments",
-    icon: <BiComment size={iconSize} aria-label="comments" />,
-    name: "comments",
-  },
-  {
-    to: "/account/settings",
-    icon: <BsGear size={iconSize} aria-label="settings" />,
-    name: "settings",
-  },
-];
+import SidebarList from "./components/SidebarList";
+import { useDarkMode } from "../../hooks/useDarkMode";
+import SidebarSection from "./components/SidebarSection";
+import SidebarToggleButton from "./components/SidebarToggleButton";
+import {
+  getOptionsLinks,
+  staticLinks,
+  userLoggedLinks,
+} from "../../utils/sidebar/sidebarLinks";
 
 interface SidebarProps {
   isSidebarOpen: boolean;
   onToggle: () => void;
-  onClose: () => void;
 }
 
-export default function Sidebar({
-  isSidebarOpen,
-  onToggle,
-  onClose,
-}: SidebarProps) {
-  const [isDark, setIsDark] = useState(
-    localStorage.getItem("theme") === "dark",
-  );
-
+export default function Sidebar({ isSidebarOpen, onToggle }: SidebarProps) {
+  const [isDark, toggleDarkMode] = useDarkMode();
   const isLogged = useSelectorTyped((state) => state.account.isLogged);
   const location = useLocation();
   const isAccountPage = location.pathname.includes("/account");
   const isChatPage = location.pathname.includes("/chat");
 
-  const optionsLinks = [
-    {
-      icon: <FaRegBell size={iconSize} aria-label="notification" />,
-      name: "notification",
-    },
-    {
-      to: isLogged ? "/account/profile" : "/login",
-      icon: <FaRegUser size={iconSize} aria-label="account" />,
-      name: isLogged ? "account" : "login",
-    },
-    isDark
-      ? {
-          icon: <LuSun size={iconSize} aria-label="changeMode" />,
-          name: "light mode",
-        }
-      : {
-          icon: <LuMoon size={iconSize} aria-label="changeMode" />,
-          name: "dark mode",
-        },
-  ];
+  const allLinks = isLogged
+    ? [...staticLinks, ...userLoggedLinks]
+    : [...staticLinks];
 
-  const toggleDarkMode = () => {
-    const html = document.documentElement;
-    if (html.classList.contains("dark")) {
-      html.classList.remove("dark");
-      localStorage.setItem("theme", "light");
-      setIsDark(false);
-    } else {
-      html.classList.add("dark");
-      localStorage.setItem("theme", "dark");
-      setIsDark(true);
-    }
-  };
+  const optionsLinks = getOptionsLinks(isLogged, isDark);
 
   return (
     <aside
-      className={`bg-violetDark text-darkText fixed top-0 left-0 z-50 flex h-full shrink-0 flex-col justify-between overflow-hidden p-2 transition-all duration-300 ${isAccountPage || isChatPage ? "xl:static" : "absolute"} ${isSidebarOpen ? "w-full translate-x-0 xl:w-[220px]" : "w-0 -translate-x-full p-0 lg:w-[70px] xl:translate-x-0"}`}
+      className={`bg-violetDark text-darkText fixed top-0 left-0 z-50 flex h-full shrink-0 flex-col justify-between py-2 transition-all duration-300 ${isAccountPage || isChatPage ? "xl:static" : "absolute"} ${isSidebarOpen ? "w-full translate-x-0 xl:w-[220px]" : "w-[220px] -translate-x-full p-0 xl:w-[70px] xl:translate-x-0"}`}
     >
       <div className="flex flex-col space-y-10">
-        <div className="bg-violetDark flex items-center justify-between">
-          <button
-            type="button"
-            className="ml-2 w-fit cursor-pointer"
-            onClick={onToggle}
-          >
-            <IoMenu size={40} />
-          </button>
-          <span className="text-darkText mr-2 font-semibold xl:hidden">
-            Merkury
-          </span>
-        </div>
-        <nav className="flex flex-col space-y-1">
-          {links.map(({ to, icon, name }) => (
-            <SidebarItem
-              key={name}
-              to={to}
-              icon={icon}
-              name={name}
-              isSidebarOpen={isSidebarOpen}
-              onLinkClick={onClose}
-            />
-          ))}
-          <hr className="border-violetLight w-full" />
-        </nav>
-      </div>
-      <div className="flex flex-col space-y-3">
-        {location.pathname.includes("account") &&
-          accountLinks.map(({ to, icon, name }) => (
-            <SidebarItem
-              key={name}
-              to={to}
-              icon={icon}
-              name={name}
-              isSidebarOpen={isSidebarOpen}
-              isMiddlePart={true}
-              onLinkClick={onClose}
-            />
-          ))}
-      </div>
-      <div className="flex flex-col space-y-3">
-        <hr className="border-violetLight w-full" />
-        {optionsLinks.map(({ to, icon, name }) => (
-          <SidebarItem
-            key={name}
-            to={to}
-            icon={icon}
-            name={name}
-            isSidebarOpen={isSidebarOpen}
-            onChangeTheme={toggleDarkMode}
-            onLinkClick={onClose}
-          />
-        ))}
+        <SidebarToggleButton onToggle={onToggle} />
+        <SidebarSection showBottomHr={true}>
+          <SidebarList links={allLinks} isSidebarOpen={isSidebarOpen} />
+        </SidebarSection>
       </div>
+      <SidebarSection showTopHr={true}>
+        <SidebarList
+          links={optionsLinks}
+          isSidebarOpen={isSidebarOpen}
+          onChangeTheme={toggleDarkMode}
+        />
+      </SidebarSection>
     </aside>
   );
 }
diff --git a/venus/src/layout/sidebar/components/SidebarIcon.tsx b/venus/src/layout/sidebar/components/SidebarIcon.tsx
new file mode 100644
index 000000000..bd8a95cec
--- /dev/null
+++ b/venus/src/layout/sidebar/components/SidebarIcon.tsx
@@ -0,0 +1,32 @@
+import { BaseLink } from "../../../model/interface/sidebar/link";
+import {
+  isSidebarAction,
+  isSidebarLink,
+  isSidebarSubmenu,
+} from "../../../utils/sidebar/functions";
+import { NavLink } from "react-router-dom";
+
+interface SidebarIconProps {
+  link: BaseLink;
+  isSidebarOpen: boolean;
+}
+
+export default function SidebarIcon({ link, isSidebarOpen }: SidebarIconProps) {
+  if (isSidebarSubmenu(link) && !isSidebarOpen) {
+    return (
+      <NavLink
+        to={link.to}
+        className="flex h-10 w-10 items-center justify-center"
+      >
+        <span className="z-50 flex h-full w-full items-center justify-center">
+          {link.icon}
+        </span>
+      </NavLink>
+    );
+  }
+
+  if (isSidebarLink(link) || isSidebarAction(link)) {
+    return link.icon;
+  }
+  return null;
+}
diff --git a/venus/src/layout/sidebar/components/SidebarItem.tsx b/venus/src/layout/sidebar/components/SidebarItem.tsx
deleted file mode 100644
index 334285fd2..000000000
--- a/venus/src/layout/sidebar/components/SidebarItem.tsx
+++ /dev/null
@@ -1,62 +0,0 @@
-import { NavLink } from "react-router-dom";
-import { ReactElement } from "react";
-import { GoDotFill } from "react-icons/go";
-
-interface SidebarItemProps {
-  to?: string;
-  icon: ReactElement;
-  name: string;
-  isSidebarOpen: boolean;
-  onChangeTheme?: () => void;
-  isMiddlePart?: boolean;
-  onLinkClick: () => void;
-}
-
-export default function SidebarItem({
-  to,
-  icon,
-  name,
-  isSidebarOpen,
-  onChangeTheme,
-  isMiddlePart,
-  onLinkClick,
-}: SidebarItemProps) {
-  const content = (isActive: boolean): ReactElement => (
-    <>
-      <div className="flex h-10 w-10 shrink-0 items-center justify-center">
-        {icon}
-      </div>
-      <p
-        className={`flex min-w-[10rem] items-center text-start text-base font-semibold capitalize transition-opacity duration-300 ${!isSidebarOpen ? "pointer-events-none opacity-0" : "opacity-100"}`}
-      >
-        {name}
-        {!isMiddlePart && isActive && <GoDotFill className="ml-2" />}
-      </p>
-    </>
-  );
-
-  if (!to) {
-    return (
-      <button
-        type="button"
-        onClick={name !== "notification" ? onChangeTheme : undefined}
-        className="flex w-full cursor-pointer items-center space-x-4 rounded-md p-2 transition-all"
-      >
-        {content(false)}
-      </button>
-    );
-  }
-
-  return (
-    <NavLink
-      to={to}
-      end
-      className={({ isActive }) =>
-        `flex w-full items-center space-x-4 rounded-md p-2 transition-all ${isMiddlePart && "hover:bg-violetLight"} ${isActive && isMiddlePart && "bg-violetLight"}`
-      }
-      onClick={onLinkClick}
-    >
-      {({ isActive }) => content(isActive)}
-    </NavLink>
-  );
-}
diff --git a/venus/src/layout/sidebar/components/SidebarLabel.tsx b/venus/src/layout/sidebar/components/SidebarLabel.tsx
new file mode 100644
index 000000000..f9f1acf75
--- /dev/null
+++ b/venus/src/layout/sidebar/components/SidebarLabel.tsx
@@ -0,0 +1,52 @@
+import { AnimatePresence, motion } from "motion/react";
+import { IoIosArrowDown, IoIosArrowUp } from "react-icons/io";
+import { GoDotFill } from "react-icons/go";
+import { BaseLink } from "../../../model/interface/sidebar/link";
+import { isSidebarSubmenu } from "../../../utils/sidebar/functions";
+
+interface SidebarLabelProps {
+  link: BaseLink;
+  isOpen?: boolean;
+  isChildren?: boolean;
+  isActive: boolean;
+  isDot?: boolean;
+  isSidebarOpen: boolean;
+}
+
+export default function SidebarLabel({
+  link,
+  isOpen,
+  isChildren,
+  isActive,
+  isDot,
+  isSidebarOpen,
+}: SidebarLabelProps) {
+  return (
+    <AnimatePresence initial={false}>
+      {isSidebarOpen && (
+        <div className="relative overflow-hidden">
+          <motion.p
+            key="sidebar-label"
+            initial={{ opacity: 0, x: -8 }}
+            animate={{ opacity: 1, x: 0 }}
+            exit={{ opacity: 0, x: -8 }}
+            transition={{ duration: 0.2 }}
+            className={`ml-2 flex min-w-[10rem] items-center text-start font-semibold capitalize`}
+          >
+            {link.name}
+            {isSidebarSubmenu(link) &&
+              link.children?.length > 0 &&
+              (isOpen ? (
+                <IoIosArrowUp className="ml-2" />
+              ) : (
+                <IoIosArrowDown className="ml-2" />
+              ))}
+            {!isChildren && (isActive || isDot) && (
+              <GoDotFill className="ml-2" />
+            )}
+          </motion.p>
+        </div>
+      )}
+    </AnimatePresence>
+  );
+}
diff --git a/venus/src/layout/sidebar/components/SidebarList.tsx b/venus/src/layout/sidebar/components/SidebarList.tsx
new file mode 100644
index 000000000..4069f7bd3
--- /dev/null
+++ b/venus/src/layout/sidebar/components/SidebarList.tsx
@@ -0,0 +1,14 @@
+import SidebarItem from "./sidebar-item/SidebarItem";
+import { BaseLink } from "../../../model/interface/sidebar/link";
+
+interface SidebarListProps {
+  links: BaseLink[];
+  isSidebarOpen: boolean;
+  onChangeTheme?: () => void;
+}
+
+export default function SidebarList(props: SidebarListProps) {
+  return props.links.map((link, index) => (
+    <SidebarItem key={link.name} link={link} {...props} index={index} />
+  ));
+}
diff --git a/venus/src/layout/sidebar/components/SidebarSection.tsx b/venus/src/layout/sidebar/components/SidebarSection.tsx
new file mode 100644
index 000000000..b70c326fe
--- /dev/null
+++ b/venus/src/layout/sidebar/components/SidebarSection.tsx
@@ -0,0 +1,23 @@
+import { ReactElement } from "react";
+
+interface SidebarSectionProps {
+  children: ReactElement;
+  showTopHr?: boolean;
+  showBottomHr?: boolean;
+}
+
+const hrClasses = "border-violetLight mx-2 mt-1";
+
+export default function SidebarSection({
+  children,
+  showTopHr,
+  showBottomHr,
+}: SidebarSectionProps) {
+  return (
+    <nav className="flex flex-col space-y-1">
+      {showTopHr && <hr className={hrClasses} />}
+      {children}
+      {showBottomHr && <hr className={hrClasses} />}
+    </nav>
+  );
+}
diff --git a/venus/src/layout/sidebar/components/SidebarToggleButton.tsx b/venus/src/layout/sidebar/components/SidebarToggleButton.tsx
new file mode 100644
index 000000000..581175c0a
--- /dev/null
+++ b/venus/src/layout/sidebar/components/SidebarToggleButton.tsx
@@ -0,0 +1,24 @@
+import { IoMenu } from "react-icons/io5";
+
+interface SidebarToggleButtonProps {
+  onToggle: () => void;
+}
+
+export default function SidebarToggleButton({
+  onToggle,
+}: SidebarToggleButtonProps) {
+  return (
+    <div className="bg-violetDark mx-2 flex items-center justify-between">
+      <button
+        type="button"
+        className="ml-2 w-fit cursor-pointer"
+        onClick={onToggle}
+      >
+        <IoMenu size={40} />
+      </button>
+      <span className="text-darkText mr-2 font-semibold xl:hidden">
+        Merkury
+      </span>
+    </div>
+  );
+}
diff --git a/venus/src/layout/sidebar/components/Tooltip.tsx b/venus/src/layout/sidebar/components/Tooltip.tsx
new file mode 100644
index 000000000..09c73b457
--- /dev/null
+++ b/venus/src/layout/sidebar/components/Tooltip.tsx
@@ -0,0 +1,28 @@
+import { NavLink } from "react-router-dom";
+import { SidebarSubmenuLink } from "../../../model/interface/sidebar/link";
+
+interface TooltipProps {
+  links: SidebarSubmenuLink[];
+  name: string;
+}
+
+export default function Tooltip({ links, name }: TooltipProps) {
+  return (
+    <div className="bg-violetLight text-darkText absolute top-0 left-full z-50 ml-3.5 rounded-r-md pt-2 text-start text-base font-semibold whitespace-nowrap capitalize">
+      <p
+        className={`${links?.length ? "cursor-auto" : "cursor-pointer"} px-3 pb-2`}
+      >
+        {name}
+      </p>
+      {links?.map((link) => (
+        <NavLink
+          key={link.name}
+          to={link.to}
+          className="hover:bg-violetDark block px-3 pb-1 font-normal text-gray-300 last:rounded-br-md"
+        >
+          {link.name}
+        </NavLink>
+      ))}
+    </div>
+  );
+}
diff --git a/venus/src/layout/sidebar/components/sidebar-item/SidebarItem.tsx b/venus/src/layout/sidebar/components/sidebar-item/SidebarItem.tsx
new file mode 100644
index 000000000..ba90b1164
--- /dev/null
+++ b/venus/src/layout/sidebar/components/sidebar-item/SidebarItem.tsx
@@ -0,0 +1,62 @@
+import {
+  BaseLink,
+  SidebarAction,
+  SidebarLink,
+  SidebarSubmenu,
+} from "../../../../model/interface/sidebar/link";
+import SidebarItemSubmenu from "./SidebarItemSubmenu";
+import SidebarItemAction from "./SidebarItemAction";
+import SidebarItemLink from "./SidebarItemLink";
+import { useBoolean } from "../../../../hooks/useBoolean";
+
+interface SidebarItemProps {
+  link: BaseLink;
+  isSidebarOpen: boolean;
+  onChangeTheme?: () => void;
+  index: number;
+}
+
+export default function SidebarItem({
+  link,
+  isSidebarOpen,
+  onChangeTheme,
+  index,
+}: SidebarItemProps) {
+  const [isTooltipShown, showTooltip, hideTooltip] = useBoolean(false);
+
+  switch (link.type) {
+    case "submenu":
+      return (
+        <SidebarItemSubmenu
+          isSidebarOpen={isSidebarOpen}
+          link={link as SidebarSubmenu}
+          index={index}
+          showTooltip={showTooltip}
+          hideTooltip={hideTooltip}
+          isTooltipShown={isTooltipShown}
+        />
+      );
+    case "action":
+      return (
+        <SidebarItemAction
+          link={link as SidebarAction}
+          isSidebarOpen={isSidebarOpen}
+          onChangeTheme={onChangeTheme!}
+          showTooltip={showTooltip}
+          hideTooltip={hideTooltip}
+          isTooltipShown={isTooltipShown}
+        />
+      );
+    case "link":
+    default:
+      return (
+        <SidebarItemLink
+          link={link as SidebarLink}
+          isSidebarOpen={isSidebarOpen}
+          showTooltip={showTooltip}
+          hideTooltip={hideTooltip}
+          isTooltipShown={isTooltipShown}
+        />
+      );
+  }
+}
diff --git a/venus/src/layout/sidebar/components/sidebar-item/SidebarItemAction.tsx b/venus/src/layout/sidebar/components/sidebar-item/SidebarItemAction.tsx
new file mode 100644
index 000000000..6bb26039a
--- /dev/null
+++ b/venus/src/layout/sidebar/components/sidebar-item/SidebarItemAction.tsx
@@ -0,0 +1,76 @@
+import { logout } from "../../../../http/account";
+import { notificationAction } from "../../../../redux/notification";
+import { accountAction } from "../../../../redux/account";
+import { SidebarAction } from "../../../../model/interface/sidebar/link";
+import SidebarItemContent from "./SidebarItemContent";
+import useDispatchTyped from "../../../../hooks/useDispatchTyped";
+import { useNavigate } from "react-router-dom";
+
+interface SidebarItemActionProps {
+  link: SidebarAction;
+  isSidebarOpen: boolean;
+  showTooltip: () => void;
+  hideTooltip: () => void;
+  onChangeTheme: () => void;
+  isTooltipShown: boolean;
+}
+
+export default function SidebarItemAction({
+  link,
+  showTooltip,
+  hideTooltip,
+  onChangeTheme,
+  isSidebarOpen,
+  isTooltipShown,
+}: SidebarItemActionProps) {
+  const dispatch = useDispatchTyped();
+  const navigate = useNavigate();
+
+  const handleSignOut = async () => {
+    try {
+      await logout();
+      dispatch(
+        notificationAction.setSuccess({
+          message: "You have been successfully logged out",
+        }),
+      );
+      dispatch(accountAction.signOut());
+    } catch (error: any) {
+      dispatch(
+        notificationAction.setError({
+          message: error?.message || "Logout failed!",
+        }),
+      );
+    }
+    navigate("/");
+  };
+
+  let clickHandler: (() => void) | undefined;
+  switch (link.actionType) {
+    case "login":
+      clickHandler = handleSignOut;
+      break;
+    case "changeMode":
+      clickHandler = onChangeTheme;
+      break;
+    default:
+      clickHandler = () => {};
+  }
+
+  return (
+    <button
+      type="button"
+      onClick={clickHandler}
+      onMouseEnter={showTooltip}
+      onMouseLeave={hideTooltip}
+      className={`mx-2 flex cursor-pointer items-center space-x-3 rounded-md pl-2 ${!isSidebarOpen && "hover:bg-violetLight mr-0 rounded-r-none transition-none"}`}
+    >
+      <SidebarItemContent
+        isSidebarOpen={isSidebarOpen}
+        isActive={false}
+        link={link}
+        isTooltipShown={isTooltipShown}
+      />
+    </button>
+  );
+}
diff --git a/venus/src/layout/sidebar/components/sidebar-item/SidebarItemContent.tsx b/venus/src/layout/sidebar/components/sidebar-item/SidebarItemContent.tsx
new file mode 100644
index 000000000..4482f4f4a
--- /dev/null
+++ b/venus/src/layout/sidebar/components/sidebar-item/SidebarItemContent.tsx
@@ -0,0 +1,50 @@
+import { BaseLink } from "../../../../model/interface/sidebar/link";
+import Tooltip from "../Tooltip";
+import SidebarIcon from "../SidebarIcon";
+import SidebarLabel from "../SidebarLabel";
+import { isSidebarSubmenu } from "../../../../utils/sidebar/functions";
+
+interface SidebarItemContentProps {
+  link: BaseLink;
+  isSidebarOpen: boolean;
+  isActive: boolean;
+  isChildren?: boolean;
+  isDot?: boolean;
+  isTooltipShown: boolean;
+  isOpen?: boolean;
+}
+
+export default function SidebarItemContent({
+  link,
+  isChildren,
+  isSidebarOpen,
+  isOpen,
+  isTooltipShown,
+  isDot,
+  isActive,
+}: SidebarItemContentProps) {
+  return (
+    <div className="flex items-center transition-all">
+      <div
+        className={`relative flex shrink-0 items-center justify-center text-3xl ${isChildren ? "h-10 w-5" : "h-10 w-10"}`}
+      >
+        <SidebarIcon link={link} isSidebarOpen={isSidebarOpen} />
+        {!isSidebarOpen && isTooltipShown && (
+          <Tooltip
+            name={link.name}
+            links={isSidebarSubmenu(link) ? link.children : []}
+          />
+        )}
+      </div>
+
+      <SidebarLabel
+        link={link}
+        isOpen={isOpen}
+        isChildren={isChildren}
+        isActive={isActive}
+        isDot={isDot}
+        isSidebarOpen={isSidebarOpen}
+      />
+    </div>
+  );
+}
diff --git a/venus/src/layout/sidebar/components/sidebar-item/SidebarItemLink.tsx b/venus/src/layout/sidebar/components/sidebar-item/SidebarItemLink.tsx
new file mode 100644
index 000000000..50de237c0
--- /dev/null
+++ b/venus/src/layout/sidebar/components/sidebar-item/SidebarItemLink.tsx
@@ -0,0 +1,38 @@
+import { NavLink } from "react-router-dom";
+import SidebarItemContent from "./SidebarItemContent";
+import { SidebarLink } from "../../../../model/interface/sidebar/link";
+
+interface SidebarItemLinkProps {
+  link: SidebarLink;
+  isSidebarOpen: boolean;
+  showTooltip: () => void;
+  hideTooltip: () => void;
+  isTooltipShown: boolean;
+}
+
+export default function SidebarItemLink({
+  link,
+  showTooltip,
+  hideTooltip,
+  isSidebarOpen,
+  isTooltipShown,
+}: SidebarItemLinkProps) {
+  return (
+    <NavLink
+      to={link.to}
+      end
+      onMouseEnter={showTooltip}
+      onMouseLeave={hideTooltip}
+      className={`mx-2 flex items-center space-x-3 rounded-md pl-2 transition-all ${!isSidebarOpen && "hover:bg-violetLight mr-0 rounded-r-none transition-none"}`}
+    >
+      {({ isActive }) => (
+        <SidebarItemContent
+          isSidebarOpen={isSidebarOpen}
+          isActive={isActive}
+          link={link}
+          isTooltipShown={isTooltipShown}
+        />
+      )}
+    </NavLink>
+  );
+}
diff --git a/venus/src/layout/sidebar/components/sidebar-item/SidebarItemSubmenu.tsx b/venus/src/layout/sidebar/components/sidebar-item/SidebarItemSubmenu.tsx
new file mode 100644
index 000000000..907bb7d3c
--- /dev/null
+++ b/venus/src/layout/sidebar/components/sidebar-item/SidebarItemSubmenu.tsx
@@ -0,0 +1,96 @@
+import SidebarItemSubmenuLink from "./SidebarItemSubmenuLink";
+import React, { useEffect, useState } from "react";
+import { useToggleState } from "../../../../hooks/useToggleState";
+import SidebarItemContent from "./SidebarItemContent";
+import { SidebarSubmenu } from "../../../../model/interface/sidebar/link";
+import { motion, AnimatePresence } from "motion/react";
+import { useLocation } from "react-router-dom";
+
+interface SidebarItemSubmenuProps {
+  link: SidebarSubmenu;
+  isSidebarOpen: boolean;
+  index: number;
+  showTooltip: () => void;
+  hideTooltip: () => void;
+  isTooltipShown: boolean;
+}
+
+export default function SidebarItemSubmenu({
+  index,
+  isSidebarOpen,
+  link,
+  showTooltip,
+  hideTooltip,
+  isTooltipShown,
+}: SidebarItemSubmenuProps) {
+  const [isSubmenuOpen, setIsSubmenuOpen, toggleSubmenu] =
+    useToggleState(false);
+  const [openedSubmenuName, setOpenedSubmenuName] = useState<string | null>();
+  const [isDot, setIsDot] = useState(false);
+  const location = useLocation();
+
+  useEffect(() => {
+    if (openedSubmenuName !== link.name && isSubmenuOpen) {
+      toggleSubmenu();
+    }
+  }, [openedSubmenuName]);
+
+  useEffect(() => {
+    const hasActiveChild =
+      link.children?.some((child) => child.to === location.pathname) ?? false;
+
+    setIsDot(hasActiveChild);
+
+    if (hasActiveChild) {
+      setOpenedSubmenuName(link.name);
+      setIsSubmenuOpen(true);
+    } else if (openedSubmenuName === link.name) {
+      setOpenedSubmenuName(null);
+      setIsSubmenuOpen(false);
+    }
+  }, [location.pathname]);
+
+  const handleOpenSubmenu = () => {
+    setOpenedSubmenuName(isSubmenuOpen ? null : link.name);
+    toggleSubmenu();
+  };
+
+  return (
+    <div
+      className={`mx-2 transition-all duration-500 ${index === 0 && "mt-2"} ${!isSidebarOpen && "mr-0"}`}
+    >
+      <button
+        type="button"
+        onClick={handleOpenSubmenu}
+        onMouseEnter={showTooltip}
+        onMouseLeave={hideTooltip}
+        className={`flex w-full cursor-pointer items-center space-x-3 rounded-md pl-2 ${!isSidebarOpen && "hover:bg-violetLight rounded-r-none"}`}
+      >
+        <SidebarItemContent
+          isSidebarOpen={isSidebarOpen}
+          isActive={false}
+          link={link}
+          isDot={isDot}
+          isOpen={isSubmenuOpen}
+          isTooltipShown={isTooltipShown}
+        />
+      </button>
+      <AnimatePresence initial={false}>
+        {isSubmenuOpen && isSidebarOpen && (
+          <motion.div
+            key="submenu"
+            initial={{ opacity: 0, height: 0, x: -8 }}
+            animate={{ opacity: 1, height: "auto", x: 0 }}
+            exit={{ opacity: 0, height: 0, x: -8 }}
+            transition={{ duration: 0.3 }}
+            className="space-y-1 overflow-hidden"
+          >
+            {link.children?.map((link) => (
+              <SidebarItemSubmenuLink key={link.name} link={link} />
+            ))}
+          </motion.div>
+        )}
+      </AnimatePresence>
+    </div>
+  );
+}
diff --git a/venus/src/layout/sidebar/components/sidebar-item/SidebarItemSubmenuLink.tsx b/venus/src/layout/sidebar/components/sidebar-item/SidebarItemSubmenuLink.tsx
new file mode 100644
index 000000000..279eef7b9
--- /dev/null
+++ b/venus/src/layout/sidebar/components/sidebar-item/SidebarItemSubmenuLink.tsx
@@ -0,0 +1,24 @@
+import { NavLink } from "react-router-dom";
+import { SidebarSubmenuLink } from "../../../../model/interface/sidebar/link";
+
+interface SidebarItemSubmenuProps {
+  link: SidebarSubmenuLink;
+}
+
+export default function SidebarItemSubmenuLink({
+  link,
+}: SidebarItemSubmenuProps) {
+  return (
+    <NavLink
+      to={link.to}
+      end
+      className={({ isActive }) =>
+        `hover:bg-violetLight mx-2 flex items-center space-x-1 rounded-md text-gray-300 ${isActive && "bg-violetLight"}`
+      }
+    >
+      <p className="ml-12 min-w-[10rem] py-1.5 text-start font-semibold capitalize">
+        {link.name}
+      </p>
+    </NavLink>
+  );
+}
diff --git a/venus/src/model/interface/sidebar/link.ts b/venus/src/model/interface/sidebar/link.ts
new file mode 100644
index 000000000..2c5db3b8c
--- /dev/null
+++ b/venus/src/model/interface/sidebar/link.ts
@@ -0,0 +1,34 @@
+import { ReactElement } from "react";
+
+type LinkType = "link" | "submenu" | "action";
+
+export interface BaseLink {
+  name: string;
+  type: LinkType;
+}
+
+export interface SidebarLink extends BaseLink {
+  type: "link";
+  to: string;
+  icon: ReactElement;
+}
+
+export interface SidebarSubmenuLink extends BaseLink {
+  type: "link";
+  to: string;
+}
+
+export interface SidebarSubmenu extends BaseLink {
+  type: "submenu";
+  to: string;
+  icon: ReactElement;
+  children: SidebarSubmenuLink[];
+}
+
+export interface SidebarAction extends BaseLink {
+  type: "action";
+  actionType: string;
+  icon: ReactElement;
+}
+
+export type SidebarItemType = SidebarLink | SidebarSubmenu | SidebarAction;
diff --git a/venus/src/test/unit/Sidebar.test.jsx b/venus/src/test/unit/Sidebar.test.jsx
index 0d0acf3f7..92ace1405 100644
--- a/venus/src/test/unit/Sidebar.test.jsx
+++ b/venus/src/test/unit/Sidebar.test.jsx
@@ -8,7 +8,7 @@ import Sidebar from "../../layout/sidebar/Sidebar.tsx";
 
 const queryClient = new QueryClient();
 
-const renderSidebar = (preloadedState, pathname) => {
+const renderSidebar = (preloadedState, pathname, isSidebarOpen = false) => {
   const store = configureStore({
     reducer: {
       account: accountSlice.reducer,
@@ -20,7 +20,7 @@ const renderSidebar = (preloadedState, pathname) => {
     <Provider store={store}>
       <MemoryRouter initialEntries={[pathname]}>
         <QueryClientProvider client={queryClient}>
-          <Sidebar />
+          <Sidebar isSidebarOpen={isSidebarOpen} onToggle={() => {}} />
         </QueryClientProvider>
       </MemoryRouter>
     </Provider>,
@@ -47,7 +47,7 @@ describe("Sidebar component unit tests", () => {
         expect(link).toBeInTheDocument();
       });
 
-      test("should render MapPage link", () => {
+      test("should render Map link", () => {
         const links = screen.getAllByRole("link");
         const link = links.find((link) => link.getAttribute("href") === "/map");
         expect(link).toBeInTheDocument();
@@ -69,14 +69,6 @@ describe("Sidebar component unit tests", () => {
         expect(link).toBeInTheDocument();
       });
 
-      test("should render Spots List link", () => {
-        const links = screen.getAllByRole("link");
-        const link = links.find(
-          (link) => link.getAttribute("href") === "/spots-list",
-        );
-        expect(link).toBeInTheDocument();
-      });
-
       test("should render Login link", () => {
         const links = screen.getAllByRole("link");
         const link = links.find(
@@ -107,18 +99,13 @@ describe("Sidebar component unit tests", () => {
         expect(icon).toBeInTheDocument();
       });
 
-      test("should render Spots List icon", () => {
-        const icon = screen.getByLabelText("spotsList");
-        expect(icon).toBeInTheDocument();
-      });
-
       test("should render Notification icon", () => {
         const icon = screen.getByLabelText("notification");
         expect(icon).toBeInTheDocument();
       });
 
-      test("should render Account icon", () => {
-        const icon = screen.getByLabelText("account");
+      test("should render Login icon", () => {
+        const icon = screen.getByLabelText("login");
         expect(icon).toBeInTheDocument();
       });
 
@@ -149,6 +136,14 @@ describe("Sidebar component unit tests", () => {
         );
         expect(link).toBeInTheDocument();
       });
+
+      test("should render Favorite spots link", () => {
+        const links = screen.getAllByRole("link");
+        const link = links.find(
+          (link) => link.getAttribute("href") === "/spots-list",
+        );
+        expect(link).toBeInTheDocument();
+      });
     });
   });
 
@@ -161,6 +156,7 @@ describe("Sidebar component unit tests", () => {
           },
         },
         "/",
+        true,
       );
     });
 
@@ -185,11 +181,6 @@ describe("Sidebar component unit tests", () => {
         expect(text).toBeInTheDocument();
       });
 
-      test("should render Favorites spots Text", () => {
-        const text = screen.getByText("favorites spots");
-        expect(text).toBeInTheDocument();
-      });
-
       test("should render Notification Text", () => {
         const text = screen.getByText("notification");
         expect(text).toBeInTheDocument();
@@ -202,130 +193,6 @@ describe("Sidebar component unit tests", () => {
     });
   });
 
-  describe("When sidebar is close and user is logged on account page", () => {
-    beforeEach(() => {
-      renderSidebar(
-        {
-          account: {
-            isLogged: true,
-          },
-        },
-        "/account/profile",
-      );
-    });
-
-    describe("Check is links render", () => {
-      test("should render Profile Link", () => {
-        const links = screen.getAllByRole("link");
-        const link = links.find(
-          (link) => link.getAttribute("href") === "/account/profile",
-        );
-        expect(link).toBeInTheDocument();
-      });
-
-      test("should render Spots List Link", () => {
-        Object.assign(window, { innerWidth: 1920 });
-        window.dispatchEvent(new Event("resize"));
-        const links = screen.getAllByRole("link");
-        const link = links.find(
-          (link) => link.getAttribute("href") === "/account/spots-list",
-        );
-        expect(link).toBeInTheDocument();
-      });
-
-      test("should render Photos list Link", () => {
-        const links = screen.getAllByRole("link");
-        const link = links.find(
-          (link) => link.getAttribute("href") === "/account/photos-list",
-        );
-        expect(link).toBeInTheDocument();
-      });
-
-      test("should render Movies list Link", () => {
-        const links = screen.getAllByRole("link");
-        const link = links.find(
-          (link) => link.getAttribute("href") === "/account/movies-list",
-        );
-        expect(link).toBeInTheDocument();
-      });
-
-      test("should render friends Link", () => {
-        const links = screen.getAllByRole("link");
-        const link = links.find(
-          (link) => link.getAttribute("href") === "/account/friends",
-        );
-        expect(link).toBeInTheDocument();
-      });
-
-      test("should render Add spot Link", () => {
-        const links = screen.getAllByRole("link");
-        const link = links.find(
-          (link) => link.getAttribute("href") === "/account/add-spot",
-        );
-        expect(link).toBeInTheDocument();
-      });
-
-      test("should render Comments Link", () => {
-        const links = screen.getAllByRole("link");
-        const link = links.find(
-          (link) => link.getAttribute("href") === "/account/comments",
-        );
-        expect(link).toBeInTheDocument();
-      });
-
-      test("should render Settings Link", () => {
-        screen.debug();
-        const links = screen.getAllByRole("link");
-        const link = links.find(
-          (link) => link.getAttribute("href") === "/account/settings",
-        );
-        expect(link).toBeInTheDocument();
-      });
-    });
-
-    describe("Check is icons render", () => {
-      test("should render Profile icon", () => {
-        const icon = screen.getByLabelText("profile");
-        expect(icon).toBeInTheDocument();
-      });
-
-      test("should render Spots list icon", () => {
-        const icon = screen.getByLabelText("accountSpotsList");
-        expect(icon).toBeInTheDocument();
-      });
-
-      test("should render Photos List icon", () => {
-        const icon = screen.getByLabelText("photosList");
-        expect(icon).toBeInTheDocument();
-      });
-
-      test("should render Movies List icon", () => {
-        const icon = screen.getByLabelText("moviesList");
-        expect(icon).toBeInTheDocument();
-      });
-
-      test("should render Friends icon", () => {
-        const icon = screen.getByLabelText("friends");
-        expect(icon).toBeInTheDocument();
-      });
-
-      test("should render Add Spot icon", () => {
-        const icon = screen.getByLabelText("addSpot");
-        expect(icon).toBeInTheDocument();
-      });
-
-      test("should render Comments icon", () => {
-        const icon = screen.getByLabelText("comments");
-        expect(icon).toBeInTheDocument();
-      });
-
-      test("should render settings icon", () => {
-        const icon = screen.getByLabelText("settings");
-        expect(icon).toBeInTheDocument();
-      });
-    });
-  });
-
   describe("When sidebar is open and user is logged on account page", () => {
     beforeEach(() => {
       renderSidebar(
@@ -335,6 +202,7 @@ describe("Sidebar component unit tests", () => {
           },
         },
         "/account/profile",
+        true,
       );
     });
 
@@ -344,18 +212,18 @@ describe("Sidebar component unit tests", () => {
         expect(text).toBeInTheDocument();
       });
 
-      test("should render Spots List Text", () => {
-        const text = screen.getByText("spots list");
+      test("should render Spots Text", () => {
+        const text = screen.getByText("spots");
         expect(text).toBeInTheDocument();
       });
 
-      test("should render Photos list Text", () => {
-        const text = screen.getByText("photos list");
+      test("should render Photos Text", () => {
+        const text = screen.getByText("photos");
         expect(text).toBeInTheDocument();
       });
 
-      test("should render Movies list Text", () => {
-        const text = screen.getByText("movies list");
+      test("should render Movies Text", () => {
+        const text = screen.getByText("movies");
         expect(text).toBeInTheDocument();
       });
 
diff --git a/venus/src/utils/sidebar/functions.ts b/venus/src/utils/sidebar/functions.ts
new file mode 100644
index 000000000..b0571954a
--- /dev/null
+++ b/venus/src/utils/sidebar/functions.ts
@@ -0,0 +1,23 @@
+import {
+  BaseLink,
+  SidebarAction,
+  SidebarLink,
+  SidebarSubmenu,
+} from "../../model/interface/sidebar/link";
+
+export function isSidebarSubmenu(link: BaseLink): link is SidebarSubmenu {
+  return (
+    "children" in link &&
+    Array.isArray(link.children) &&
+    "to" in link &&
+    typeof link.to === "string"
+  );
+}
+
+export function isSidebarAction(link: BaseLink): link is SidebarAction {
+  return "actionType" in link && typeof link.actionType === "string";
+}
+
+export function isSidebarLink(link: BaseLink): link is SidebarLink {
+  return "to" in link && typeof link.to === "string";
+}
diff --git a/venus/src/utils/sidebar/sidebarLinks.tsx b/venus/src/utils/sidebar/sidebarLinks.tsx
new file mode 100644
index 000000000..87e9f91b6
--- /dev/null
+++ b/venus/src/utils/sidebar/sidebarLinks.tsx
@@ -0,0 +1,131 @@
+import { SidebarItemType } from "../../model/interface/sidebar/link";
+import { BiHome, BiMessageRounded } from "react-icons/bi";
+import { FaRegMap } from "react-icons/fa6";
+import { MdOutlineForum } from "react-icons/md";
+import { FaRegBell, FaRegHeart, FaRegUser } from "react-icons/fa";
+import { TbLogin2, TbLogout2 } from "react-icons/tb";
+import { LuMoon, LuSun } from "react-icons/lu";
+
+export const staticLinks: SidebarItemType[] = [
+  {
+    to: "/",
+    icon: <BiHome aria-label="home" />,
+    name: "home",
+    type: "link",
+  },
+  {
+    to: "/map",
+    icon: <FaRegMap aria-label="map" />,
+    name: "map",
+    type: "link",
+  },
+  {
+    to: "/forum",
+    icon: <MdOutlineForum aria-label="forum" />,
+    name: "forum",
+    type: "link",
+  },
+  {
+    to: "/chat",
+    icon: <BiMessageRounded aria-label="chat" />,
+    name: "chat",
+    type: "link",
+  },
+];
+
+export const userLoggedLinks: SidebarItemType[] = [
+  {
+    to: "/spots-list",
+    icon: <FaRegHeart aria-label="spotsList" />,
+    name: "favorites spots",
+    type: "link",
+  },
+  {
+    icon: <FaRegUser aria-label="account" />,
+    name: "account",
+    type: "submenu",
+    to: "/account/profile",
+    children: [
+      {
+        to: "/account/profile",
+        name: "profile",
+        type: "link",
+      },
+      {
+        to: "/spots",
+        name: "spots",
+        type: "link",
+      },
+      {
+        to: "/account/photos",
+        name: "photos",
+        type: "link",
+      },
+      {
+        to: "/account/movies",
+        name: "movies",
+        type: "link",
+      },
+      {
+        to: "/account/friends",
+        name: "friends",
+        type: "link",
+      },
+      {
+        to: "/account/add-spot",
+        name: "add spot",
+        type: "link",
+      },
+      {
+        to: "/account/comments",
+        name: "comments",
+        type: "link",
+      },
+      {
+        to: "/account/settings",
+        name: "settings",
+        type: "link",
+      },
+    ],
+  },
+];
+
+export const getOptionsLinks = (
+  isLogged: boolean,
+  isDark: boolean,
+): SidebarItemType[] => {
+  return [
+    {
+      icon: <FaRegBell aria-label="notification" />,
+      name: "notification",
+      actionType: "notification",
+      type: "action",
+    },
+    isLogged
+      ? {
+          icon: <TbLogout2 aria-label="login" />,
+          name: "sign out",
+          actionType: "login",
+          type: "action",
+        }
+      : {
+          icon: <TbLogin2 aria-label="login" />,
+          to: "/login",
+          name: "login",
+          type: "link",
+        },
+    isDark
+      ? {
+          icon: <LuSun aria-label="changeMode" />,
+          name: "light mode",
+          actionType: "changeMode",
+          type: "action",
+        }
+      : {
+          icon: <LuMoon aria-label="changeMode" />,
+          name: "dark mode",
+          actionType: "changeMode",
+          type: "action",
+        },
+  ];
+};


Reviews:
user: login: copilot-pull-request-reviewer[bot]
body: ## Pull Request Overview

This pull request refactors the Sidebar component to simplify its structure and improve maintainability by consolidating the sign-out logic into the SidebarItem component, reorganizing sidebar links into categorized arrays, and updating the tests to align with the new design.  
- Moved sign-out functionality from a dedicated SignOutButton into SidebarItem.  
- Organized sidebar links into static, userLogged, and options arrays for clearer logic and dynamic rendering.  
- Added support for nested child links in SidebarItem and updated tests to reflect new textual labels.

### Reviewed Changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

| File                                                         | Description                                                                  |
| ------------------------------------------------------------ | ---------------------------------------------------------------------------- |
| venus/src/test/unit/Sidebar.test.jsx                         | Removed obsolete tests and updated labels to reflect the new naming changes. |
| venus/src/layout/sidebar/components/SidebarItem.tsx          | Consolidated sign-out logic, added nested link support, and refined component props. |
| venus/src/layout/sidebar/Sidebar.jsx                         | Reorganized links into separate arrays and updated rendering logic.          |
| venus/src/components/sign-out-button/SignOutButton.jsx       | Removed as its functionality is now included in SidebarItem.                 |


<details>
<summary>Comments suppressed due to low confidence (2)</summary>

**venus/src/layout/sidebar/Sidebar.jsx:115**
* Consider adding an explicit property (e.g., 'action' or 'isButton') to indicate when a SidebarItem should render as a button versus a link. Relying on falsy 'to' values may reduce clarity and could lead to confusion when maintaining the code.
```
to: !isLogged && "/login",
```
**venus/src/layout/sidebar/components/SidebarItem.tsx:89**
* Using the 'name' property to differentiate behavior (e.g., sign-out logic) could be fragile, especially in localized contexts. Consider adding a dedicated prop (like 'actionType') to clearly indicate the intended functionality.
```
if (name === "sign out") {
```
</details>


state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-26T11:39:54Z
user: login: stanoz
body: Gdy sidebar jest zwinięty i najadę na ikonkę od account to nie widać dostępnych opcji.

![obraz](https://github.com/user-attachments/assets/b3f42199-7d93-4427-80f7-b329c94badfe)

state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-26T12:45:02Z
user: login: copilot-pull-request-reviewer[bot]
body: ## Pull Request Overview

This pull request refactors and modularizes the sidebar component of the venus application while introducing several custom hooks for state management and theme toggling. Key changes include the extraction of sidebar subcomponents (e.g., SidebarItemSubmenu, SidebarItemLink, SidebarItemAction) for improved maintainability, the integration of custom hooks (useToggleState, useDarkMode, etc.) to streamline state logic, and an overall code cleanup that removes redundant components such as SignOutButton.

### Reviewed Changes

Copilot reviewed 25 out of 25 changed files in this pull request and generated no comments.

<details>
<summary>Show a summary per file</summary>

| File | Description |
| ---- | ----------- |
| venus/src/layout/sidebar/components/sidebar-item/SidebarItemSubmenu.tsx | New submenu component using AnimatePresence and motion for animations. |
| venus/src/layout/sidebar/components/sidebar-item/SidebarItemLink.tsx | Implements sidebar links with tooltip support via NavLink. |
| venus/src/layout/sidebar/components/sidebar-item/SidebarItemContent.tsx | Consolidates rendering of icons, labels, and tooltips for sidebar items. |
| venus/src/layout/sidebar/components/sidebar-item/SidebarItemAction.tsx | Handles actions such as logout and theme toggling. |
| venus/src/layout/sidebar/components/SidebarItem.tsx | Routes the sidebar items to their respective subcomponents based on type. |
| venus/src/layout/sidebar/components/Tooltip.tsx | Provides a tooltip for sidebar items with submenu links. |
| venus/src/layout/sidebar/components/SidebarToggleButton.tsx | Offers a toggle button for the sidebar, especially on smaller screens. |
| venus/src/layout/sidebar/components/SidebarSection.tsx | Wraps sidebar item groups and conditionally displays horizontal rules. |
| venus/src/layout/sidebar/components/SidebarList.tsx | Renders a list of sidebar items using SidebarItem. |
| venus/src/layout/sidebar/components/SidebarLabel.tsx | Displays animated labels with conditional icons based on state. |
| venus/src/layout/sidebar/components/SidebarIcon.tsx | Manages icon rendering based on item type and sidebar state. |
| venus/src/layout/sidebar/Sidebar.tsx | Main sidebar component refactored for modular layout and integration with hooks. |
| venus/src/layout/Layout.jsx | Updated layout with integrated sidebar and mobile bar using toggle hooks. |
| venus/src/hooks/* | Custom hooks (useToggleState, useToggle, useDarkMode, useBoolean) introduced for cleaner state management. |
| venus/package.json | Added the motion dependency for animations. |
</details>



<details>
<summary>Comments suppressed due to low confidence (1)</summary>

**venus/src/layout/sidebar/components/sidebar-item/SidebarItemSubmenu.tsx:40**
* The code references 'location.pathname' without importing or defining 'location'. Consider importing the 'useLocation' hook from 'react-router-dom' or using 'window.location' instead.
```
link.children?.some((child) => child.to === location.pathname) ?? false;
```
</details>


state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-09T11:52:33Z
user: login: stanoz
body: Czym różni się `useToggle` od `useToggleState`? I jak odpaliłem to w intelliju to pokazuje mi, że `useToggle` nie jest używany
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-10T12:39:44Z
user: login: stanoz
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-10T13:18:25Z
user: login: Mredosz
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-10T13:18:53Z
user: login: stanoz
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-10T13:20:52Z
user: login: Mredosz
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-10T13:46:46Z
user: login: stanoz
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-10T13:47:55Z
user: login: Mredosz
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-10T13:59:44Z
user: login: stanoz
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-11T08:09:39Z
user: login: stanoz
body: Brak innych uwag
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-11T08:10:38Z
user: login: Gerald-27119
body: git
state: COMMENTED
author_association: OWNER
submitted_at: 2025-05-13T18:30:33Z
user: login: Gerald-27119
state: APPROVED
author_association: OWNER
submitted_at: 2025-05-13T18:30:51Z

Review comments:
diff_hunk: @@ -0,0 +1,97 @@
+import SidebarItemSubmenuLink from "./SidebarItemSubmenuLink";
+import React, { useEffect, useState } from "react";
+import { useToggleState } from "../../../../hooks/useToggleState";
+import SidebarItemContent from "./SidebarItemContent";
+import { SidebarSubmenu } from "../../../../model/interface/sidebar/link";
+import { motion, AnimatePresence } from "motion/react";
+import { useLocation } from "react-router-dom";
+
+interface SidebarItemSubmenuProps {
+  link: SidebarSubmenu;
+  isSidebarOpen: boolean;
+  index: number;
+  showTooltip: () => void;
+  hideTooltip: () => void;
+  isTooltipShown: boolean;
+}
+
+export default function SidebarItemSubmenu({
+  index,
+  isSidebarOpen,
+  link,
+  showTooltip,
+  hideTooltip,
+  isTooltipShown,
+}: SidebarItemSubmenuProps) {
+  const [isOpen, setIsOpenSubmenu, toggleSubmenu] = useToggleState(false);
+  const [openSubmenu, setOpenSubmenu] = useState<string | null>();
path: venus/src/layout/sidebar/components/sidebar-item/SidebarItemSubmenu.tsx
user: login: stanoz
body: Proponuję zmianę nazw, bo obecne sugerują, że są to wartości `true`, `false`
created_at: 2025-05-10T13:18:25Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,97 @@
+import SidebarItemSubmenuLink from "./SidebarItemSubmenuLink";
+import React, { useEffect, useState } from "react";
+import { useToggleState } from "../../../../hooks/useToggleState";
+import SidebarItemContent from "./SidebarItemContent";
+import { SidebarSubmenu } from "../../../../model/interface/sidebar/link";
+import { motion, AnimatePresence } from "motion/react";
+import { useLocation } from "react-router-dom";
+
+interface SidebarItemSubmenuProps {
+  link: SidebarSubmenu;
+  isSidebarOpen: boolean;
+  index: number;
+  showTooltip: () => void;
+  hideTooltip: () => void;
+  isTooltipShown: boolean;
+}
+
+export default function SidebarItemSubmenu({
+  index,
+  isSidebarOpen,
+  link,
+  showTooltip,
+  hideTooltip,
+  isTooltipShown,
+}: SidebarItemSubmenuProps) {
+  const [isOpen, setIsOpenSubmenu, toggleSubmenu] = useToggleState(false);
+  const [openSubmenu, setOpenSubmenu] = useState<string | null>();
path: venus/src/layout/sidebar/components/sidebar-item/SidebarItemSubmenu.tsx
user: login: Mredosz
body: Które nazwy?
created_at: 2025-05-10T13:18:53Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,97 @@
+import SidebarItemSubmenuLink from "./SidebarItemSubmenuLink";
+import React, { useEffect, useState } from "react";
+import { useToggleState } from "../../../../hooks/useToggleState";
+import SidebarItemContent from "./SidebarItemContent";
+import { SidebarSubmenu } from "../../../../model/interface/sidebar/link";
+import { motion, AnimatePresence } from "motion/react";
+import { useLocation } from "react-router-dom";
+
+interface SidebarItemSubmenuProps {
+  link: SidebarSubmenu;
+  isSidebarOpen: boolean;
+  index: number;
+  showTooltip: () => void;
+  hideTooltip: () => void;
+  isTooltipShown: boolean;
+}
+
+export default function SidebarItemSubmenu({
+  index,
+  isSidebarOpen,
+  link,
+  showTooltip,
+  hideTooltip,
+  isTooltipShown,
+}: SidebarItemSubmenuProps) {
+  const [isOpen, setIsOpenSubmenu, toggleSubmenu] = useToggleState(false);
+  const [openSubmenu, setOpenSubmenu] = useState<string | null>();
+  const [isDot, setIsDot] = useState(false);
+  const location = useLocation();
+
+  useEffect(() => {
+    if (openSubmenu !== link.name && isOpen) {
+      toggleSubmenu();
+    }
+  }, [openSubmenu]);
+
+  useEffect(() => {
+    const hasActiveChild =
+      link.children?.some((child) => child.to === location.pathname) ?? false;
+
+    setIsDot(hasActiveChild);
+
+    if (hasActiveChild) {
+      setOpenSubmenu(link.name);
+      setIsOpenSubmenu(true);
+    } else if (openSubmenu === link.name) {
+      setOpenSubmenu(null);
+      setIsOpenSubmenu(false);
+    }
+  }, [location.pathname]);
+
+  const handleOpenSubmenu = () => {
+    if (setOpenSubmenu) {
path: venus/src/layout/sidebar/components/sidebar-item/SidebarItemSubmenu.tsx
user: login: stanoz
body: Dlaczego w tym ifie w warunku jest funkcja?
created_at: 2025-05-10T13:20:52Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,97 @@
+import SidebarItemSubmenuLink from "./SidebarItemSubmenuLink";
+import React, { useEffect, useState } from "react";
+import { useToggleState } from "../../../../hooks/useToggleState";
+import SidebarItemContent from "./SidebarItemContent";
+import { SidebarSubmenu } from "../../../../model/interface/sidebar/link";
+import { motion, AnimatePresence } from "motion/react";
+import { useLocation } from "react-router-dom";
+
+interface SidebarItemSubmenuProps {
+  link: SidebarSubmenu;
+  isSidebarOpen: boolean;
+  index: number;
+  showTooltip: () => void;
+  hideTooltip: () => void;
+  isTooltipShown: boolean;
+}
+
+export default function SidebarItemSubmenu({
+  index,
+  isSidebarOpen,
+  link,
+  showTooltip,
+  hideTooltip,
+  isTooltipShown,
+}: SidebarItemSubmenuProps) {
+  const [isOpen, setIsOpenSubmenu, toggleSubmenu] = useToggleState(false);
+  const [openSubmenu, setOpenSubmenu] = useState<string | null>();
+  const [isDot, setIsDot] = useState(false);
+  const location = useLocation();
+
+  useEffect(() => {
+    if (openSubmenu !== link.name && isOpen) {
+      toggleSubmenu();
+    }
+  }, [openSubmenu]);
+
+  useEffect(() => {
+    const hasActiveChild =
+      link.children?.some((child) => child.to === location.pathname) ?? false;
+
+    setIsDot(hasActiveChild);
+
+    if (hasActiveChild) {
+      setOpenSubmenu(link.name);
+      setIsOpenSubmenu(true);
+    } else if (openSubmenu === link.name) {
+      setOpenSubmenu(null);
+      setIsOpenSubmenu(false);
+    }
+  }, [location.pathname]);
+
+  const handleOpenSubmenu = () => {
+    if (setOpenSubmenu) {
path: venus/src/layout/sidebar/components/sidebar-item/SidebarItemSubmenu.tsx
user: login: Mredosz
body: Wcześniej ta funkcja była przesyłana w propach w niektórych przypadkach, zapomniałem usunąć. Już usunięte
created_at: 2025-05-10T13:46:45Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,97 @@
+import SidebarItemSubmenuLink from "./SidebarItemSubmenuLink";
+import React, { useEffect, useState } from "react";
+import { useToggleState } from "../../../../hooks/useToggleState";
+import SidebarItemContent from "./SidebarItemContent";
+import { SidebarSubmenu } from "../../../../model/interface/sidebar/link";
+import { motion, AnimatePresence } from "motion/react";
+import { useLocation } from "react-router-dom";
+
+interface SidebarItemSubmenuProps {
+  link: SidebarSubmenu;
+  isSidebarOpen: boolean;
+  index: number;
+  showTooltip: () => void;
+  hideTooltip: () => void;
+  isTooltipShown: boolean;
+}
+
+export default function SidebarItemSubmenu({
+  index,
+  isSidebarOpen,
+  link,
+  showTooltip,
+  hideTooltip,
+  isTooltipShown,
+}: SidebarItemSubmenuProps) {
+  const [isOpen, setIsOpenSubmenu, toggleSubmenu] = useToggleState(false);
+  const [openSubmenu, setOpenSubmenu] = useState<string | null>();
path: venus/src/layout/sidebar/components/sidebar-item/SidebarItemSubmenu.tsx
user: login: stanoz
body: `openSubmenu` i `setOpenSubmenu`
created_at: 2025-05-10T13:47:55Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,97 @@
+import SidebarItemSubmenuLink from "./SidebarItemSubmenuLink";
+import React, { useEffect, useState } from "react";
+import { useToggleState } from "../../../../hooks/useToggleState";
+import SidebarItemContent from "./SidebarItemContent";
+import { SidebarSubmenu } from "../../../../model/interface/sidebar/link";
+import { motion, AnimatePresence } from "motion/react";
+import { useLocation } from "react-router-dom";
+
+interface SidebarItemSubmenuProps {
+  link: SidebarSubmenu;
+  isSidebarOpen: boolean;
+  index: number;
+  showTooltip: () => void;
+  hideTooltip: () => void;
+  isTooltipShown: boolean;
+}
+
+export default function SidebarItemSubmenu({
+  index,
+  isSidebarOpen,
+  link,
+  showTooltip,
+  hideTooltip,
+  isTooltipShown,
+}: SidebarItemSubmenuProps) {
+  const [isOpen, setIsOpenSubmenu, toggleSubmenu] = useToggleState(false);
+  const [openSubmenu, setOpenSubmenu] = useState<string | null>();
path: venus/src/layout/sidebar/components/sidebar-item/SidebarItemSubmenu.tsx
user: login: Mredosz
body: Według mnie nie jakby nazwa była `isOpenSubmenu i setIsOpenSubmenu` to wtedy by to wskazywało na boolean. A masz jakieś propozycje na zmianę nazwy?
created_at: 2025-05-10T13:59:44Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,97 @@
+import SidebarItemSubmenuLink from "./SidebarItemSubmenuLink";
+import React, { useEffect, useState } from "react";
+import { useToggleState } from "../../../../hooks/useToggleState";
+import SidebarItemContent from "./SidebarItemContent";
+import { SidebarSubmenu } from "../../../../model/interface/sidebar/link";
+import { motion, AnimatePresence } from "motion/react";
+import { useLocation } from "react-router-dom";
+
+interface SidebarItemSubmenuProps {
+  link: SidebarSubmenu;
+  isSidebarOpen: boolean;
+  index: number;
+  showTooltip: () => void;
+  hideTooltip: () => void;
+  isTooltipShown: boolean;
+}
+
+export default function SidebarItemSubmenu({
+  index,
+  isSidebarOpen,
+  link,
+  showTooltip,
+  hideTooltip,
+  isTooltipShown,
+}: SidebarItemSubmenuProps) {
+  const [isOpen, setIsOpenSubmenu, toggleSubmenu] = useToggleState(false);
+  const [openSubmenu, setOpenSubmenu] = useState<string | null>();
path: venus/src/layout/sidebar/components/sidebar-item/SidebarItemSubmenu.tsx
user: login: stanoz
body: Obgadane na dsc
created_at: 2025-05-11T08:09:39Z
author_association: COLLABORATOR

PR comments:
user: login: Mredosz
created_at: 2025-04-26T13:06:28Z
body: > Gdy sidebar jest zwinięty i najadę na ikonkę od account to nie widać dostępnych opcji.
> 
> ![obraz](https://github.com/user-attachments/assets/b3f42199-7d93-4427-80f7-b329c94badfe)
> 

To myślałem nad tym i tu wsm pytanie do wszystkich @KacperBadek @Gerald-27119 @stanoz . Zrobić tak że pokazują się same ikony zaraz pod tamtą? Czy macie jakąś inną propozycję? 
author_association: COLLABORATOR
user: login: stanoz
created_at: 2025-04-26T13:31:52Z
body: > > Gdy sidebar jest zwinięty i najadę na ikonkę od account to nie widać dostępnych opcji.
> > ![obraz](https://private-user-images.githubusercontent.com/114993612/437710520-b3f42199-7d93-4427-80f7-b329c94badfe.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NDU2NzQ0ODcsIm5iZiI6MTc0NTY3NDE4NywicGF0aCI6Ii8xMTQ5OTM2MTIvNDM3NzEwNTIwLWIzZjQyMTk5LTdkOTMtNDQyNy04MGY3LWIzMjljOTRiYWRmZS5wbmc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBVkNPRFlMU0E1M1BRSzRaQSUyRjIwMjUwNDI2JTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDI1MDQyNlQxMzI5NDdaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT1iNDc0NDMyMTRlNGZlYjdhNGQxOTc3ZGRhZDkzMGZkYzVhNDgyOTUyNDQwNDRhZjVlOGViODA5MTFiMzM5YjM2JlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCJ9.GqCF8qyHbVzcTVkdstCjqM6CP5LMtG_68RrV5XbZlVE)
> 
> To myślałem nad tym i tu wsm pytanie do wszystkich @KacperBadek @Gerald-27119 @stanoz . Zrobić tak że pokazują się same ikony zaraz podeślę tamtą? Czy macie jakąś inną propozycję?

Ja bym zrobił, że będą wyświetlać się same ikonki, może z lekkim wcięciem
author_association: COLLABORATOR
user: login: Gerald-27119
created_at: 2025-04-26T18:59:56Z
body: ![image](https://github.com/user-attachments/assets/277d1e01-8400-4bb8-9683-86127b2c2c6d)
Na innym PR usuwamy ten Footer co nie?

author_association: OWNER
user: login: Gerald-27119
created_at: 2025-04-26T19:01:18Z
body: > > > Gdy sidebar jest zwinięty i najadę na ikonkę od account to nie widać dostępnych opcji.
> > > ![obraz](https://private-user-images.githubusercontent.com/114993612/437710520-b3f42199-7d93-4427-80f7-b329c94badfe.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NDU2NzQ0ODcsIm5iZiI6MTc0NTY3NDE4NywicGF0aCI6Ii8xMTQ5OTM2MTIvNDM3NzEwNTIwLWIzZjQyMTk5LTdkOTMtNDQyNy04MGY3LWIzMjljOTRiYWRmZS5wbmc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBVkNPRFlMU0E1M1BRSzRaQSUyRjIwMjUwNDI2JTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDI1MDQyNlQxMzI5NDdaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT1iNDc0NDMyMTRlNGZlYjdhNGQxOTc3ZGRhZDkzMGZkYzVhNDgyOTUyNDQwNDRhZjVlOGViODA5MTFiMzM5YjM2JlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCJ9.GqCF8qyHbVzcTVkdstCjqM6CP5LMtG_68RrV5XbZlVE)
> > 
> > 
> > To myślałem nad tym i tu wsm pytanie do wszystkich @KacperBadek @Gerald-27119 @stanoz . Zrobić tak że pokazują się same ikony zaraz podeślę tamtą? Czy macie jakąś inną propozycję?
> 
> Ja bym zrobił, że będą wyświetlać się same ikonki, może z lekkim wcięciem

Nie rozumiem o czym mówicie. W jakim przypadku?
author_association: OWNER
user: login: KacperBadek
created_at: 2025-04-26T19:18:10Z
body: > > > > Gdy sidebar jest zwinięty i najadę na ikonkę od account to nie widać dostępnych opcji.
> > > > ![obraz](https://private-user-images.githubusercontent.com/114993612/437710520-b3f42199-7d93-4427-80f7-b329c94badfe.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NDU2NzQ0ODcsIm5iZiI6MTc0NTY3NDE4NywicGF0aCI6Ii8xMTQ5OTM2MTIvNDM3NzEwNTIwLWIzZjQyMTk5LTdkOTMtNDQyNy04MGY3LWIzMjljOTRiYWRmZS5wbmc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBVkNPRFlMU0E1M1BRSzRaQSUyRjIwMjUwNDI2JTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDI1MDQyNlQxMzI5NDdaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT1iNDc0NDMyMTRlNGZlYjdhNGQxOTc3ZGRhZDkzMGZkYzVhNDgyOTUyNDQwNDRhZjVlOGViODA5MTFiMzM5YjM2JlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCJ9.GqCF8qyHbVzcTVkdstCjqM6CP5LMtG_68RrV5XbZlVE)
> > > 
> > > 
> > > To myślałem nad tym i tu wsm pytanie do wszystkich @KacperBadek @Gerald-27119 @stanoz . Zrobić tak że pokazują się same ikony zaraz podeślę tamtą? Czy macie jakąś inną propozycję?
> > 
> > 
> > Ja bym zrobił, że będą wyświetlać się same ikonki, może z lekkim wcięciem
> 
> Nie rozumiem o czym mówicie. W jakim przypadku?

Wogóle chcemy żeby to na hoverze sie rozwijało czy, lepiej po kliknięciu? A odpowiadając na pytanie, to albo tak jak Stachu mówi, albo niech to się tylko rozwija w dół jak jest już hamburger kliknięty (menu wyszło na prawo)
author_association: COLLABORATOR
user: login: Mredosz
created_at: 2025-04-26T19:31:31Z
body: > ![image](https://private-user-images.githubusercontent.com/114993042/437769580-277d1e01-8400-4bb8-9683-86127b2c2c6d.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NDU2OTYxMDksIm5iZiI6MTc0NTY5NTgwOSwicGF0aCI6Ii8xMTQ5OTMwNDIvNDM3NzY5NTgwLTI3N2QxZTAxLTg0MDAtNGJiOC05NjgzLTg2MTI3YjJjMmM2ZC5wbmc_WC1BbXotQWxnb3JpdGhtPUFXUzQtSE1BQy1TSEEyNTYmWC1BbXotQ3JlZGVudGlhbD1BS0lBVkNPRFlMU0E1M1BRSzRaQSUyRjIwMjUwNDI2JTJGdXMtZWFzdC0xJTJGczMlMkZhd3M0X3JlcXVlc3QmWC1BbXotRGF0ZT0yMDI1MDQyNlQxOTMwMDlaJlgtQW16LUV4cGlyZXM9MzAwJlgtQW16LVNpZ25hdHVyZT1hZGJlNzIwNzY2NzA2ZDBkM2UwMGRiMDMyNjZlODkxYjg3NWYyMWM0OTNlYTg5NGRhM2M2NTlmMDZmNmQ2YmI2JlgtQW16LVNpZ25lZEhlYWRlcnM9aG9zdCJ9.2__IIf-OsZXH_Q37M8z3jx_n9zy9mtHGYiqQEu6ym_Y) Na innym PR usuwamy ten Footer co nie?

Tak
author_association: COLLABORATOR
user: login: Gerald-27119
created_at: 2025-04-27T10:55:43Z
body: brak uwag
author_association: OWNER
user: login: KacperBadek
created_at: 2025-04-28T12:53:53Z
body: Brak uwag
author_association: COLLABORATOR
user: login: Mredosz
created_at: 2025-05-10T13:20:29Z
body: > Czym różni się `useToggle` od `useToggleState`? I jak odpaliłem to w intelliju to pokazuje mi, że `useToggle` nie jest używany

`useToggleState` zwraca dodatkowo funkcję set zrobiłem dwa osobne potem okazało się że w tym branchu jednak nie potrzebuję `useToggle` jak chcesz mogę go usunąć ale pewnie komuś się kiedyś przyda. A zrobiłem dwa ponieważ w React nie można sobie wybrać które właściwości, pola (nie pamiętam dokładnej nazwy na to) to nie możesz sobie wybrać że chcesz np wyciągnąć pierwszy i trzeci. A nie powinno się tak robić że używa się tylko części z tych właściwości z hooka. Mam nadzieję że wytłumaczyłe jak nie to możemy się na dc zgadać to wytłumaczę to lepiej bo trudno mi to inaczej opisć.
author_association: COLLABORATOR
user: login: KacperBadek
created_at: 2025-05-11T19:57:56Z
body: ![obraz](https://github.com/user-attachments/assets/ca29096f-dfab-4f12-a6a1-d648e69e4a19)
Nie lepiej by było gdyby te opcje się podświetlały na hoverze? Zmiana tła albo jaśniejszy/ciemniejszy text-color.
author_association: COLLABORATOR
user: login: KacperBadek
created_at: 2025-05-11T20:02:47Z
body: Brak innych uwag.
author_association: COLLABORATOR
user: login: Mredosz
created_at: 2025-05-12T13:39:56Z
body: > ![obraz](https://private-user-images.githubusercontent.com/40339146/442532238-ca29096f-dfab-4f12-a6a1-d648e69e4a19.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NDcwNTcwMDQsIm5iZiI6MTc0NzA1NjcwNCwicGF0aCI6Ii80MDMzOTE0Ni80NDI1MzIyMzgtY2EyOTA5NmYtZGZhYi00ZjEyLWE2YTEtZDY0OGU2OWU0YTE5LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTA1MTIlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwNTEyVDEzMzE0NFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTljODBmYjJjYjIyYWQyNDE5Yjk2MzgzYjBlZGRkOGNhNTBhYjJjMmQyYzViYWYyMzFiYzY0ZjljY2NjMjQxNzAmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.wU0eEdRgUqUpNrSUT7p-q05FggLOQm6IZVRbo2uRvOY) Nie lepiej by było gdyby te opcje się podświetlały na hoverze? Zmiana tła albo jaśniejszy/ciemniejszy text-color.

Dodałem hover zobacz czy coś takiego może być
author_association: COLLABORATOR