From b4a9765dafddd7a85812ecedd969c0d0a7d6e1a5 Mon Sep 17 00:00:00 2001 From: Jack Andrews Date: Sun, 3 Nov 2024 11:24:00 +0000 Subject: [PATCH] feat: initial flags work & sidebar improvemnts --- .../@/shadcn/components/app-sidebar.tsx | 4 +- apps/client/@/shadcn/components/nav-main.tsx | 65 ++++++++- apps/client/@/shadcn/ui/sidebar.tsx | 2 +- .../components/CreateTicketModal/index.tsx | 15 +- apps/client/layouts/newLayout.tsx | 29 ++-- apps/client/layouts/portalLayout.tsx | 128 +----------------- apps/client/layouts/settings.tsx | 77 ++++++----- apps/client/pages/_app.tsx | 6 +- apps/client/pages/settings/flags.tsx | 65 +++++++++ 9 files changed, 200 insertions(+), 191 deletions(-) create mode 100644 apps/client/pages/settings/flags.tsx diff --git a/apps/client/@/shadcn/components/app-sidebar.tsx b/apps/client/@/shadcn/components/app-sidebar.tsx index 9e2dd4577..4094c683e 100644 --- a/apps/client/@/shadcn/components/app-sidebar.tsx +++ b/apps/client/@/shadcn/components/app-sidebar.tsx @@ -51,7 +51,6 @@ export function AppSidebar({ ...props }: React.ComponentProps) { teams: [ { name: "Peppermint", - logo: GalleryVerticalEnd, plan: `version: ${process.env.NEXT_PUBLIC_CLIENT_VERSION}`, }, ], @@ -81,10 +80,12 @@ export function AppSidebar({ ...props }: React.ComponentProps) { { title: "Open", url: "/issues/open", + initial: "o", }, { title: "Closed", url: "/issues/closed", + initial: "f", }, ], }, @@ -93,6 +94,7 @@ export function AppSidebar({ ...props }: React.ComponentProps) { url: "/admin", icon: Settings, isActive: true, + initial: "a", }, ], }; diff --git a/apps/client/@/shadcn/components/nav-main.tsx b/apps/client/@/shadcn/components/nav-main.tsx index 810dd263b..fb44d3290 100644 --- a/apps/client/@/shadcn/components/nav-main.tsx +++ b/apps/client/@/shadcn/components/nav-main.tsx @@ -1,4 +1,5 @@ import { ChevronRight, type LucideIcon } from "lucide-react"; +import { useState, useEffect } from "react"; import { Collapsible, @@ -14,6 +15,7 @@ import { SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, + useSidebar, } from "@/shadcn/ui/sidebar"; import { useRouter } from "next/router"; @@ -25,13 +27,35 @@ export function NavMain({ url: string; icon?: LucideIcon; isActive?: boolean; + initial?: string; items?: { title: string; url: string; + initial?: string; }[]; }[]; }) { const router = useRouter(); + const sidebar = useSidebar(); + const [hideKeyboardShortcuts, setHideKeyboardShortcuts] = useState(false); + + useEffect(() => { + const loadFlags = () => { + const savedFlags = localStorage.getItem("featureFlags"); + if (savedFlags) { + const flags = JSON.parse(savedFlags); + const hideShortcuts = flags.find( + (f: any) => f.name === "Hide Keyboard Shortcuts" + )?.enabled; + setHideKeyboardShortcuts(hideShortcuts || false); + } + }; + + loadFlags(); + window.addEventListener("storage", loadFlags); + return () => window.removeEventListener("storage", loadFlags); + }, []); + return ( @@ -39,12 +63,23 @@ export function NavMain({ item.items ? ( router.push(item.url)} > - {item.icon && } - {item.title} +
+
+ {item.icon && } + + {item.title} + +
+ {!hideKeyboardShortcuts && ( + {item.initial} + )} +
{item.items?.map((subItem) => ( @@ -52,9 +87,14 @@ export function NavMain({ router.push(subItem.url)} - className="cursor-pointer" + className="cursor-pointer flex flex-row items-center justify-between w-full px-0 pl-2.5" > {subItem.title} + + {!hideKeyboardShortcuts && ( + {subItem.initial} + )} + ))} @@ -64,11 +104,22 @@ export function NavMain({ router.push(item.url)} > - {item.icon && } - {item.title} +
+
+ {item.icon && } + + {item.title} + +
+ {!hideKeyboardShortcuts && ( + {item.initial} + )} +
) diff --git a/apps/client/@/shadcn/ui/sidebar.tsx b/apps/client/@/shadcn/ui/sidebar.tsx index 99bdba71b..d5a588326 100644 --- a/apps/client/@/shadcn/ui/sidebar.tsx +++ b/apps/client/@/shadcn/ui/sidebar.tsx @@ -703,7 +703,7 @@ const SidebarMenuSub = React.forwardRef< ref={ref} data-sidebar="menu-sub" className={cn( - "mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l border-sidebar-border px-2.5 py-0.5", + "flex min-w-0 ml-3.5 translate-x-px flex-col gap-1 border-l border-sidebar-border pl-2.5 pr-0 py-0.5", "group-data-[collapsible=icon]:hidden", className )} diff --git a/apps/client/components/CreateTicketModal/index.tsx b/apps/client/components/CreateTicketModal/index.tsx index 62226784a..8e764f427 100644 --- a/apps/client/components/CreateTicketModal/index.tsx +++ b/apps/client/components/CreateTicketModal/index.tsx @@ -145,6 +145,9 @@ export default function CreateTicketModal({ keypress, setKeyPressDown }) { useEffect(() => checkPress(), [keypress]); + const showKeyboardShortcuts = + localStorage.getItem("hide-keyboard-shortcuts") === "true"; + return ( <> diff --git a/apps/client/layouts/newLayout.tsx b/apps/client/layouts/newLayout.tsx index e7099ced0..83e5a4c95 100644 --- a/apps/client/layouts/newLayout.tsx +++ b/apps/client/layouts/newLayout.tsx @@ -87,18 +87,18 @@ export default function NewLayout({ children }: any) { icon: FileText, current: location.pathname === "/documents" ? true : false, initial: "d", - internal: true + internal: true, }, ]; function handleKeyPress(event: any) { const pathname = location.pathname; - + // Check for Ctrl or Meta key to bypass the shortcut handler if (event.ctrlKey || event.metaKey) { return; // Don't override browser shortcuts } - + if ( document.activeElement!.tagName !== "INPUT" && document.activeElement!.tagName !== "TEXTAREA" && @@ -132,7 +132,6 @@ export default function NewLayout({ children }: any) { } } } - useEffect(() => { // attach the event listener @@ -345,7 +344,12 @@ export default function NewLayout({ children }: any) { setKeyPressDown={setKeyPressDown} /> {navigation.map((item: any) => ( -
  • +
  • - - {user.name}'s closed - -
    - - f + + {user.name}'s closed +
    + + f +
  • @@ -494,7 +498,6 @@ export default function NewLayout({ children }: any) { )} -
    diff --git a/apps/client/layouts/portalLayout.tsx b/apps/client/layouts/portalLayout.tsx index 865904ed7..85e99b492 100644 --- a/apps/client/layouts/portalLayout.tsx +++ b/apps/client/layouts/portalLayout.tsx @@ -28,8 +28,6 @@ export default function PortalLayout({ children }: any) { const { t, lang } = useTranslation("peppermint"); const [sidebarOpen, setSidebarOpen] = useState(false); - const [tab, setTab] = useState("unread"); - const [currentPath, setCurrentPath] = useState(); if (!user) { location.push("/auth/login"); @@ -72,15 +70,6 @@ export default function PortalLayout({ children }: any) { } } - // async function markasread(id) { - // await fetch(`/api/v1/user/notifcation/${id}`, { - // method: "GET", - // headers: { - // Authorization: `Bearer ${getCookie("session")}`, - // }, - // }).then((res) => res.json()); - // await fetchUserProfile(); - // } function handleKeyPress(event: any) { const pathname = location.pathname; @@ -373,107 +362,8 @@ export default function PortalLayout({ children }: any) {
    - {/* - - - {user.notifcations.filter( - (notification) => !notification.read - ).length > 0 && ( - - )} - - - -
    -
    - -
    -
    - {user !== undefined ? ( - tab === "unread" ? ( - user.notifcations - .filter((notification) => !notification.read) - .map((notification: any) => ( -
    -
    -

    - {notification.text} -

    - -
    -
    - )) - ) : ( - user.notifcations - .filter((notification) => notification.read) - .map((notification: any) => ( -
    -
    -

    - {notification.text} -

    -
    -
    - )) - ) - ) : ( - <> - )} -
    -
    -
    -
    - - - - */} - + + {/* Profile dropdown */} @@ -494,19 +384,7 @@ export default function PortalLayout({ children }: any) { leaveTo="transform opacity-0 scale-95" > - {/* - {({ active }) => ( - - {t("profile")} - - )} - */} + {({ active }) => (
    - + + ); } diff --git a/apps/client/pages/_app.tsx b/apps/client/pages/_app.tsx index 2b01576e2..f6e47a738 100644 --- a/apps/client/pages/_app.tsx +++ b/apps/client/pages/_app.tsx @@ -37,7 +37,7 @@ function Auth({ children }: any) { const { loading, user } = useUser(); React.useEffect(() => { - if (loading) return; // Do nothing while loading + if (loading) return; }, [user, loading]); if (user) { @@ -87,12 +87,12 @@ function MyApp({ Component, pageProps: { session, ...pageProps } }: any) { - + - + diff --git a/apps/client/pages/settings/flags.tsx b/apps/client/pages/settings/flags.tsx new file mode 100644 index 000000000..c244682b7 --- /dev/null +++ b/apps/client/pages/settings/flags.tsx @@ -0,0 +1,65 @@ +import { useRouter } from "next/router"; +import { useEffect, useState } from "react"; + +interface FeatureFlag { + name: string; + enabled: boolean; + description: string; +} + +const defaultFlags: FeatureFlag[] = [ + { + name: "Hide Keyboard Shortcuts", + enabled: false, + description: "Hide keyboard shortcuts", + }, +]; + +export default function FeatureFlags() { + const [flags, setFlags] = useState([]); + const router = useRouter(); + + useEffect(() => { + // Load flags from localStorage on component mount + const savedFlags = localStorage.getItem("featureFlags"); + if (savedFlags) { + setFlags(JSON.parse(savedFlags)); + } else { + setFlags(defaultFlags); + localStorage.setItem("featureFlags", JSON.stringify(defaultFlags)); + } + }, []); + + const toggleFlag = (flagName: string) => { + const updatedFlags = flags.map((flag) => + flag.name === flagName ? { ...flag, enabled: !flag.enabled } : flag + ); + setFlags(updatedFlags); + localStorage.setItem("featureFlags", JSON.stringify(updatedFlags)); + router.reload(); + }; + + return ( +
    +

    Feature Flags

    +
    + {flags.map((flag) => ( +
    +
    +
    {flag.name}
    +
    {flag.description}
    +
    +
    + +
    +
    + ))} +
    +
    + ); +}