feat(sidebar): regroup commerce nav and add XP mini toggle
Move Banking and Market out of Logistics into a commerce group beside Personal, and add a quick XP mini-mode toggle synced to the saved display preference via the layout-provided preferences prop. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
parent
906af4feb1
commit
38400366a1
2 changed files with 83 additions and 15 deletions
|
|
@ -124,6 +124,7 @@ export default async function RootLayout(props: { children: React.ReactNode }) {
|
|||
hasLogistics={isLogistics}
|
||||
showCallsign={user.preferences?.display?.showCallsign ?? false}
|
||||
canImpersonate={await isSuperuser(payload, user)}
|
||||
preferences={user.preferences}
|
||||
className="border-r"
|
||||
/>
|
||||
<SidebarInset>
|
||||
|
|
|
|||
|
|
@ -10,9 +10,13 @@ import {
|
|||
Search,
|
||||
Send,
|
||||
Shield,
|
||||
ShoppingBag,
|
||||
TrendingUp,
|
||||
UserCog,
|
||||
Users,
|
||||
Warehouse,
|
||||
Maximize,
|
||||
Minimize,
|
||||
} from "lucide-react";
|
||||
|
||||
import { NavCore } from "@/components/frontend/blocks/NavCore";
|
||||
|
|
@ -31,7 +35,9 @@ import Image from "next/image";
|
|||
import Link from "next/link";
|
||||
import XPDisplay from "@/components/frontend/blocks/XPDisplay";
|
||||
import type { ResolvedLevel } from "@/utils/xp/resolveLevel";
|
||||
import { Rank } from "@/payload-types";
|
||||
import { Rank, User } from "@/payload-types";
|
||||
import { Progress } from "@/components/ui/progress";
|
||||
import { updatePreferences } from "@/app/(frontend)/account/actions";
|
||||
|
||||
const data = {
|
||||
navMain: [
|
||||
|
|
@ -45,6 +51,8 @@ const data = {
|
|||
url: "/roster",
|
||||
icon: Users,
|
||||
},
|
||||
],
|
||||
navHelpdesk: [
|
||||
{
|
||||
title: "Helpdesk",
|
||||
url: "/helpdesk",
|
||||
|
|
@ -108,22 +116,19 @@ const data = {
|
|||
title: "Deployed Vehicles",
|
||||
url: "/logistics/game-vehicles",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
navCommerce: [
|
||||
{
|
||||
title: "Banking",
|
||||
url: "/logistics/banking",
|
||||
icon: TrendingUp,
|
||||
},
|
||||
{
|
||||
title: "Market",
|
||||
url: "/logistics/market",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
navSecondary: [
|
||||
{
|
||||
title: "Feedback",
|
||||
url: "https://onyxsimple.youtrack.cloud",
|
||||
icon: Send,
|
||||
icon: ShoppingBag,
|
||||
},
|
||||
],
|
||||
navPersonal: [
|
||||
|
|
@ -138,6 +143,13 @@ const data = {
|
|||
icon: UserCog,
|
||||
},
|
||||
],
|
||||
navSecondary: [
|
||||
{
|
||||
title: "Feedback",
|
||||
url: "https://onyxsimple.youtrack.cloud",
|
||||
icon: Send,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export function AppSidebar({
|
||||
|
|
@ -148,6 +160,7 @@ export function AppSidebar({
|
|||
hasLogistics = true,
|
||||
showCallsign = false,
|
||||
canImpersonate = false,
|
||||
preferences,
|
||||
...props
|
||||
}: {
|
||||
user: {
|
||||
|
|
@ -161,7 +174,36 @@ export function AppSidebar({
|
|||
hasLogistics?: boolean;
|
||||
showCallsign?: boolean;
|
||||
canImpersonate?: boolean;
|
||||
preferences?: NonNullable<User["preferences"]>;
|
||||
} & React.ComponentProps<typeof Sidebar>) {
|
||||
const [isMiniMode, setIsMiniMode] = React.useState<boolean>(
|
||||
preferences?.display?.xpDisplayMini ?? false
|
||||
);
|
||||
|
||||
// Re-sync when the saved preference changes (e.g. account page save + router.refresh()).
|
||||
const savedXpDisplayMini = preferences?.display?.xpDisplayMini ?? false;
|
||||
React.useEffect(() => {
|
||||
setIsMiniMode(savedXpDisplayMini);
|
||||
}, [savedXpDisplayMini]);
|
||||
|
||||
const handleToggleXPMode = React.useCallback(async () => {
|
||||
try {
|
||||
await updatePreferences({
|
||||
mutedAll: preferences?.notifications?.mutedAll ?? false,
|
||||
mutedTypes: preferences?.notifications?.mutedTypes ?? [],
|
||||
showCallsign: preferences?.display?.showCallsign ?? false,
|
||||
showVersionOverlay: preferences?.display?.showVersionOverlay ?? true,
|
||||
leadOrActual: preferences?.display?.leadOrActual ?? "lead",
|
||||
discordEnabled: preferences?.discord?.enabled ?? false,
|
||||
discordMutedTypes: preferences?.discord?.mutedTypes ?? [],
|
||||
xpDisplayMini: !isMiniMode,
|
||||
});
|
||||
setIsMiniMode(!isMiniMode);
|
||||
} catch (error) {
|
||||
console.error("Failed to update XP display preference:", error);
|
||||
}
|
||||
}, [isMiniMode, preferences]);
|
||||
|
||||
return (
|
||||
<Sidebar variant="inset" {...props}>
|
||||
<SidebarHeader>
|
||||
|
|
@ -208,6 +250,8 @@ export function AppSidebar({
|
|||
)}
|
||||
/>
|
||||
)}
|
||||
<NavCore label="Helpdesk" items={data.navHelpdesk} />
|
||||
<NavCore label="Commerce" items={data.navCommerce} />
|
||||
<NavCore label="Personal" items={data.navPersonal} />
|
||||
{/*<NavProjects projects={data.projects} />*/}
|
||||
</div>
|
||||
|
|
@ -226,9 +270,32 @@ export function AppSidebar({
|
|||
}
|
||||
className="mt-auto"
|
||||
/>
|
||||
<XPDisplay xpLevel={xpLevel} />
|
||||
</SidebarContent>
|
||||
<SidebarFooter>
|
||||
<div className="flex flex-col">
|
||||
<div className="flex items-center justify-between">
|
||||
{isMiniMode ? (
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="text-xs text-muted-foreground uppercase">
|
||||
{xpLevel.levelName}
|
||||
</div>
|
||||
<span className="text-xs font-bold">
|
||||
{xpLevel.xp.toLocaleString()}
|
||||
</span>
|
||||
<Progress value={xpLevel.progress} className="w-20 h-1" />
|
||||
</div>
|
||||
) : (
|
||||
<XPDisplay xpLevel={xpLevel} />
|
||||
)}
|
||||
<button
|
||||
onClick={handleToggleXPMode}
|
||||
className="p-1 rounded-md hover:bg-sidebar-accent hover:text-sidebar-accent-foreground transition-colors border border-transparent hover:border-sidebar-border"
|
||||
aria-label={isMiniMode ? "Expand XP Display" : "Minimize XP Display"}
|
||||
>
|
||||
{isMiniMode ? <Maximize size={16} /> : <Minimize size={16} />}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<NavUser
|
||||
user={{
|
||||
displayName: user?.displayName
|
||||
|
|
|
|||
Loading…
Reference in a new issue