49de105862
- Better separation between main feature pages and manage pages - Toggle via keyboard shortcut Cmd/Ctrl + B or click collapse button - Collapsed state persisted to database (survives page refresh) - All menu items show tooltips when collapsed - Smooth animations using Framer Motion and CSS transitions - Impersonation-safe (preferences not modified when impersonating) https://github.com/user-attachments/assets/35827922-b80a-418e-8341-eb22c9bb5ed4 <!-- devin-review-badge-begin --> --- <a href="https://app.devin.ai/review/triggerdotdev/trigger.dev/pull/2939"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://static.devin.ai/assets/gh-open-in-devin-review-dark.svg?v=1"> <img src="https://static.devin.ai/assets/gh-open-in-devin-review-light.svg?v=1" alt="Open with Devin"> </picture> </a> <!-- devin-review-badge-end -->
39 lines
1.2 KiB
TypeScript
39 lines
1.2 KiB
TypeScript
import { type UIMatch } from "@remix-run/react";
|
|
import type { UserWithDashboardPreferences } from "~/models/user.server";
|
|
import { type loader } from "~/root";
|
|
import { useChanged } from "./useChanged";
|
|
import { useTypedMatchesData } from "./useTypedMatchData";
|
|
import { useIsImpersonating } from "./useOrganizations";
|
|
|
|
export type User = UserWithDashboardPreferences;
|
|
|
|
export function useOptionalUser(matches?: UIMatch[]): User | undefined {
|
|
const routeMatch = useTypedMatchesData<typeof loader>({
|
|
id: "root",
|
|
matches,
|
|
});
|
|
|
|
return routeMatch?.user ?? undefined;
|
|
}
|
|
|
|
export function useUser(matches?: UIMatch[]): User {
|
|
const maybeUser = useOptionalUser(matches);
|
|
if (!maybeUser) {
|
|
throw new Error(
|
|
"No user found in root loader, but user is required by useUser. If user is optional, try useOptionalUser instead."
|
|
);
|
|
}
|
|
return maybeUser;
|
|
}
|
|
|
|
export function useUserChanged(callback: (user: User | undefined) => void) {
|
|
useChanged(useOptionalUser, callback);
|
|
}
|
|
|
|
export function useHasAdminAccess(matches?: UIMatch[]): boolean {
|
|
const user = useOptionalUser(matches);
|
|
const isImpersonating = useIsImpersonating(matches);
|
|
|
|
return Boolean(user?.admin) || isImpersonating;
|
|
}
|