@logickernel/frame 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +461 -0
- package/dist/adapters/nextjs.js +31 -0
- package/dist/adapters/nextjs.js.map +1 -0
- package/dist/adapters/nextjs.mjs +25 -0
- package/dist/adapters/nextjs.mjs.map +1 -0
- package/dist/components/AppSidebar.js +467 -0
- package/dist/components/AppSidebar.js.map +1 -0
- package/dist/components/AppSidebar.mjs +446 -0
- package/dist/components/AppSidebar.mjs.map +1 -0
- package/dist/components/NavMain.js +133 -0
- package/dist/components/NavMain.js.map +1 -0
- package/dist/components/NavMain.mjs +112 -0
- package/dist/components/NavMain.mjs.map +1 -0
- package/dist/components/NavUser.js +88 -0
- package/dist/components/NavUser.js.map +1 -0
- package/dist/components/NavUser.mjs +86 -0
- package/dist/components/NavUser.mjs.map +1 -0
- package/dist/components/TeamSwitcher.js +164 -0
- package/dist/components/TeamSwitcher.js.map +1 -0
- package/dist/components/TeamSwitcher.mjs +162 -0
- package/dist/components/TeamSwitcher.mjs.map +1 -0
- package/dist/hooks/useNavigation.d.mts +24 -0
- package/dist/hooks/useNavigation.d.ts +24 -0
- package/dist/hooks/useNavigation.js +59 -0
- package/dist/hooks/useNavigation.js.map +1 -0
- package/dist/hooks/useNavigation.mjs +57 -0
- package/dist/hooks/useNavigation.mjs.map +1 -0
- package/dist/index.d.mts +58 -0
- package/dist/index.d.ts +58 -0
- package/dist/index.js +495 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +465 -0
- package/dist/index.mjs.map +1 -0
- package/dist/types/index.d.mts +85 -0
- package/dist/types/index.d.ts +85 -0
- package/dist/types/index.js +4 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/index.mjs +3 -0
- package/dist/types/index.mjs.map +1 -0
- package/dist/types/ui-components.d.js +4 -0
- package/dist/types/ui-components.d.js.map +1 -0
- package/dist/types/ui-components.d.mjs +3 -0
- package/dist/types/ui-components.d.mjs.map +1 -0
- package/dist/utils/iconMapper.d.mts +16 -0
- package/dist/utils/iconMapper.d.ts +16 -0
- package/dist/utils/iconMapper.js +52 -0
- package/dist/utils/iconMapper.js.map +1 -0
- package/dist/utils/iconMapper.mjs +30 -0
- package/dist/utils/iconMapper.mjs.map +1 -0
- package/package.json +76 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var lucideReact = require('lucide-react');
|
|
4
|
+
var dropdownMenu = require('@/components/ui/dropdown-menu');
|
|
5
|
+
var sidebar = require('@/components/ui/sidebar');
|
|
6
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
7
|
+
|
|
8
|
+
function TeamSwitcher({
|
|
9
|
+
teams,
|
|
10
|
+
organizationId,
|
|
11
|
+
adapter
|
|
12
|
+
}) {
|
|
13
|
+
const { isMobile } = sidebar.useSidebar();
|
|
14
|
+
const pathname = adapter.usePathname();
|
|
15
|
+
const router = adapter.useRouter();
|
|
16
|
+
const pathSegments = pathname.split("/");
|
|
17
|
+
const isAppOrgRoute = pathname.startsWith("/app/") && pathSegments.length > 2 && pathSegments[2] !== "user";
|
|
18
|
+
const pathOrgId = isAppOrgRoute ? pathSegments[2] : null;
|
|
19
|
+
const currentOrgId = organizationId || (pathOrgId && teams.some((team) => team.id === pathOrgId) ? pathOrgId : null);
|
|
20
|
+
const activeTeam = currentOrgId ? teams.find((team) => team.id === currentOrgId) : null;
|
|
21
|
+
const handleTeamChange = (teamId) => {
|
|
22
|
+
router.push(`/app/${teamId}/home`);
|
|
23
|
+
if (router.refresh) {
|
|
24
|
+
router.refresh();
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
const teamsWithLogo = teams.map((org) => ({
|
|
28
|
+
id: org.id,
|
|
29
|
+
name: org.name,
|
|
30
|
+
logo: org.logo || lucideReact.GalleryVerticalEnd,
|
|
31
|
+
plan: org.plan || "Member"
|
|
32
|
+
}));
|
|
33
|
+
if (teamsWithLogo.length === 0) {
|
|
34
|
+
return /* @__PURE__ */ jsxRuntime.jsx(sidebar.SidebarMenu, { children: /* @__PURE__ */ jsxRuntime.jsx(sidebar.SidebarMenuItem, { children: /* @__PURE__ */ jsxRuntime.jsxs(sidebar.SidebarMenuButton, { size: "lg", className: "cursor-default", children: [
|
|
35
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-muted flex aspect-square size-8 items-center justify-center rounded-lg", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.GalleryVerticalEnd, { className: "size-4 text-muted-foreground" }) }),
|
|
36
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid flex-1 text-left text-sm leading-tight", children: [
|
|
37
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate font-medium text-muted-foreground", children: "No organizations" }),
|
|
38
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-xs text-muted-foreground", children: "Join or create one" })
|
|
39
|
+
] })
|
|
40
|
+
] }) }) });
|
|
41
|
+
}
|
|
42
|
+
if (!activeTeam) {
|
|
43
|
+
return /* @__PURE__ */ jsxRuntime.jsx(sidebar.SidebarMenu, { children: /* @__PURE__ */ jsxRuntime.jsx(sidebar.SidebarMenuItem, { children: /* @__PURE__ */ jsxRuntime.jsxs(dropdownMenu.DropdownMenu, { children: [
|
|
44
|
+
/* @__PURE__ */ jsxRuntime.jsx(dropdownMenu.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
45
|
+
sidebar.SidebarMenuButton,
|
|
46
|
+
{
|
|
47
|
+
size: "lg",
|
|
48
|
+
className: "data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground",
|
|
49
|
+
children: [
|
|
50
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-muted flex aspect-square size-8 items-center justify-center rounded-lg", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.GalleryVerticalEnd, { className: "size-4 text-muted-foreground" }) }),
|
|
51
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid flex-1 text-left text-sm leading-tight", children: [
|
|
52
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate font-medium", children: "Organizations" }),
|
|
53
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "truncate text-xs text-muted-foreground", children: [
|
|
54
|
+
teamsWithLogo.length,
|
|
55
|
+
" available"
|
|
56
|
+
] })
|
|
57
|
+
] }),
|
|
58
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronsUpDown, { className: "ml-auto" })
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
) }),
|
|
62
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
63
|
+
dropdownMenu.DropdownMenuContent,
|
|
64
|
+
{
|
|
65
|
+
className: "w-(--radix-dropdown-menu-trigger-width) min-w-56 rounded-lg",
|
|
66
|
+
align: "start",
|
|
67
|
+
side: isMobile ? "bottom" : "right",
|
|
68
|
+
sideOffset: 4,
|
|
69
|
+
children: [
|
|
70
|
+
/* @__PURE__ */ jsxRuntime.jsx(dropdownMenu.DropdownMenuLabel, { className: "text-muted-foreground text-xs", children: "Select an organization" }),
|
|
71
|
+
teamsWithLogo.map((team) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
72
|
+
dropdownMenu.DropdownMenuItem,
|
|
73
|
+
{
|
|
74
|
+
onClick: () => handleTeamChange(team.id),
|
|
75
|
+
className: "gap-2 p-2",
|
|
76
|
+
children: [
|
|
77
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex size-6 items-center justify-center rounded-md border", children: /* @__PURE__ */ jsxRuntime.jsx(team.logo, { className: "size-3.5 shrink-0" }) }),
|
|
78
|
+
team.name
|
|
79
|
+
]
|
|
80
|
+
},
|
|
81
|
+
team.id
|
|
82
|
+
)),
|
|
83
|
+
/* @__PURE__ */ jsxRuntime.jsx(dropdownMenu.DropdownMenuSeparator, {}),
|
|
84
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
85
|
+
dropdownMenu.DropdownMenuItem,
|
|
86
|
+
{
|
|
87
|
+
className: "gap-2 p-2",
|
|
88
|
+
onClick: () => router.push("/app/user/organizations"),
|
|
89
|
+
children: [
|
|
90
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex size-6 items-center justify-center rounded-md border bg-transparent", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.GalleryVerticalEnd, { className: "size-4" }) }),
|
|
91
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-muted-foreground font-medium", children: "Manage organizations" })
|
|
92
|
+
]
|
|
93
|
+
}
|
|
94
|
+
)
|
|
95
|
+
]
|
|
96
|
+
}
|
|
97
|
+
)
|
|
98
|
+
] }) }) });
|
|
99
|
+
}
|
|
100
|
+
const activeTeamWithLogo = teamsWithLogo.find(
|
|
101
|
+
(team) => team.id === currentOrgId
|
|
102
|
+
);
|
|
103
|
+
if (!activeTeamWithLogo) {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
return /* @__PURE__ */ jsxRuntime.jsx(sidebar.SidebarMenu, { children: /* @__PURE__ */ jsxRuntime.jsx(sidebar.SidebarMenuItem, { children: /* @__PURE__ */ jsxRuntime.jsxs(dropdownMenu.DropdownMenu, { children: [
|
|
107
|
+
/* @__PURE__ */ jsxRuntime.jsx(dropdownMenu.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
108
|
+
sidebar.SidebarMenuButton,
|
|
109
|
+
{
|
|
110
|
+
size: "lg",
|
|
111
|
+
className: "data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground",
|
|
112
|
+
children: [
|
|
113
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "bg-sidebar-primary text-sidebar-primary-foreground flex aspect-square size-8 items-center justify-center rounded-lg", children: /* @__PURE__ */ jsxRuntime.jsx(activeTeamWithLogo.logo, { className: "size-4" }) }),
|
|
114
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid flex-1 text-left text-sm leading-tight", children: [
|
|
115
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate font-medium", children: activeTeamWithLogo.name }),
|
|
116
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-xs", children: activeTeamWithLogo.plan })
|
|
117
|
+
] }),
|
|
118
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronsUpDown, { className: "ml-auto" })
|
|
119
|
+
]
|
|
120
|
+
}
|
|
121
|
+
) }),
|
|
122
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
123
|
+
dropdownMenu.DropdownMenuContent,
|
|
124
|
+
{
|
|
125
|
+
className: "w-(--radix-dropdown-menu-trigger-width) min-w-56 rounded-lg",
|
|
126
|
+
align: "start",
|
|
127
|
+
side: isMobile ? "bottom" : "right",
|
|
128
|
+
sideOffset: 4,
|
|
129
|
+
children: [
|
|
130
|
+
/* @__PURE__ */ jsxRuntime.jsx(dropdownMenu.DropdownMenuLabel, { className: "text-muted-foreground text-xs", children: "Organizations" }),
|
|
131
|
+
teamsWithLogo.map((team) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
132
|
+
dropdownMenu.DropdownMenuItem,
|
|
133
|
+
{
|
|
134
|
+
onClick: () => handleTeamChange(team.id),
|
|
135
|
+
className: "gap-2 p-2",
|
|
136
|
+
children: [
|
|
137
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex size-6 items-center justify-center rounded-md border", children: /* @__PURE__ */ jsxRuntime.jsx(team.logo, { className: "size-3.5 shrink-0" }) }),
|
|
138
|
+
team.name,
|
|
139
|
+
team.id === currentOrgId && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "ml-auto h-4 w-4" })
|
|
140
|
+
]
|
|
141
|
+
},
|
|
142
|
+
team.id
|
|
143
|
+
)),
|
|
144
|
+
/* @__PURE__ */ jsxRuntime.jsx(dropdownMenu.DropdownMenuSeparator, {}),
|
|
145
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
146
|
+
dropdownMenu.DropdownMenuItem,
|
|
147
|
+
{
|
|
148
|
+
className: "gap-2 p-2",
|
|
149
|
+
onClick: () => router.push("/app/user/organizations"),
|
|
150
|
+
children: [
|
|
151
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex size-6 items-center justify-center rounded-md border bg-transparent", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.GalleryVerticalEnd, { className: "size-4" }) }),
|
|
152
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-muted-foreground font-medium", children: "Manage organizations" })
|
|
153
|
+
]
|
|
154
|
+
}
|
|
155
|
+
)
|
|
156
|
+
]
|
|
157
|
+
}
|
|
158
|
+
)
|
|
159
|
+
] }) }) });
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
exports.TeamSwitcher = TeamSwitcher;
|
|
163
|
+
//# sourceMappingURL=TeamSwitcher.js.map
|
|
164
|
+
//# sourceMappingURL=TeamSwitcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/TeamSwitcher.tsx"],"names":["useSidebar","GalleryVerticalEnd","jsx","SidebarMenu","SidebarMenuItem","SidebarMenuButton","jsxs","DropdownMenu","DropdownMenuTrigger","ChevronsUpDown","DropdownMenuContent","DropdownMenuLabel","DropdownMenuItem","DropdownMenuSeparator","Check"],"mappings":"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","file":"TeamSwitcher.js","sourcesContent":["\"use client\"\n\nimport { Check, ChevronsUpDown, GalleryVerticalEnd } from \"lucide-react\"\nimport * as React from \"react\"\n\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from \"@/components/ui/dropdown-menu\"\nimport {\n SidebarMenu,\n SidebarMenuButton,\n SidebarMenuItem,\n useSidebar,\n} from \"@/components/ui/sidebar\"\nimport type { FrameworkAdapter, Organization } from \"../types\"\n\ninterface TeamSwitcherProps {\n teams: Organization[]\n organizationId?: string\n adapter: FrameworkAdapter\n}\n\nexport function TeamSwitcher({\n teams,\n organizationId,\n adapter,\n}: TeamSwitcherProps) {\n const { isMobile } = useSidebar()\n const pathname = adapter.usePathname()\n const router = adapter.useRouter()\n\n // Only extract org ID from /app/[org_id]/... paths, excluding /app/user/...\n const pathSegments = pathname.split(\"/\")\n const isAppOrgRoute =\n pathname.startsWith(\"/app/\") &&\n pathSegments.length > 2 &&\n pathSegments[2] !== \"user\"\n const pathOrgId = isAppOrgRoute ? pathSegments[2] : null\n\n // Determine current org: only from provided prop or valid path - don't auto-select\n const currentOrgId =\n organizationId ||\n (pathOrgId && teams.some((team) => team.id === pathOrgId)\n ? pathOrgId\n : null)\n\n // Find the active team based on current org ID\n const activeTeam = currentOrgId\n ? teams.find((team) => team.id === currentOrgId)\n : null\n\n const handleTeamChange = (teamId: string) => {\n // Navigate to the organization's home page\n router.push(`/app/${teamId}/home`)\n if (router.refresh) {\n router.refresh()\n }\n }\n\n // Transform organizations to teams format with default logo\n const teamsWithLogo = teams.map((org) => ({\n id: org.id,\n name: org.name,\n logo: org.logo || GalleryVerticalEnd,\n plan: org.plan || \"Member\",\n }))\n\n // No organizations state\n if (teamsWithLogo.length === 0) {\n return (\n <SidebarMenu>\n <SidebarMenuItem>\n <SidebarMenuButton size=\"lg\" className=\"cursor-default\">\n <div className=\"bg-muted flex aspect-square size-8 items-center justify-center rounded-lg\">\n <GalleryVerticalEnd className=\"size-4 text-muted-foreground\" />\n </div>\n <div className=\"grid flex-1 text-left text-sm leading-tight\">\n <span className=\"truncate font-medium text-muted-foreground\">\n No organizations\n </span>\n <span className=\"truncate text-xs text-muted-foreground\">\n Join or create one\n </span>\n </div>\n </SidebarMenuButton>\n </SidebarMenuItem>\n </SidebarMenu>\n )\n }\n\n // No org selected state - prompt user to select\n if (!activeTeam) {\n return (\n <SidebarMenu>\n <SidebarMenuItem>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <SidebarMenuButton\n size=\"lg\"\n className=\"data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground\"\n >\n <div className=\"bg-muted flex aspect-square size-8 items-center justify-center rounded-lg\">\n <GalleryVerticalEnd className=\"size-4 text-muted-foreground\" />\n </div>\n <div className=\"grid flex-1 text-left text-sm leading-tight\">\n <span className=\"truncate font-medium\">Organizations</span>\n <span className=\"truncate text-xs text-muted-foreground\">\n {teamsWithLogo.length} available\n </span>\n </div>\n <ChevronsUpDown className=\"ml-auto\" />\n </SidebarMenuButton>\n </DropdownMenuTrigger>\n <DropdownMenuContent\n className=\"w-(--radix-dropdown-menu-trigger-width) min-w-56 rounded-lg\"\n align=\"start\"\n side={isMobile ? \"bottom\" : \"right\"}\n sideOffset={4}\n >\n <DropdownMenuLabel className=\"text-muted-foreground text-xs\">\n Select an organization\n </DropdownMenuLabel>\n {teamsWithLogo.map((team) => (\n <DropdownMenuItem\n key={team.id}\n onClick={() => handleTeamChange(team.id)}\n className=\"gap-2 p-2\"\n >\n <div className=\"flex size-6 items-center justify-center rounded-md border\">\n <team.logo className=\"size-3.5 shrink-0\" />\n </div>\n {team.name}\n </DropdownMenuItem>\n ))}\n <DropdownMenuSeparator />\n <DropdownMenuItem\n className=\"gap-2 p-2\"\n onClick={() => router.push(\"/app/user/organizations\")}\n >\n <div className=\"flex size-6 items-center justify-center rounded-md border bg-transparent\">\n <GalleryVerticalEnd className=\"size-4\" />\n </div>\n <div className=\"text-muted-foreground font-medium\">\n Manage organizations\n </div>\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </SidebarMenuItem>\n </SidebarMenu>\n )\n }\n\n // Org selected state - show current org with switcher\n const activeTeamWithLogo = teamsWithLogo.find(\n (team) => team.id === currentOrgId\n )\n\n if (!activeTeamWithLogo) {\n return null\n }\n\n return (\n <SidebarMenu>\n <SidebarMenuItem>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <SidebarMenuButton\n size=\"lg\"\n className=\"data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground\"\n >\n <div className=\"bg-sidebar-primary text-sidebar-primary-foreground flex aspect-square size-8 items-center justify-center rounded-lg\">\n <activeTeamWithLogo.logo className=\"size-4\" />\n </div>\n <div className=\"grid flex-1 text-left text-sm leading-tight\">\n <span className=\"truncate font-medium\">\n {activeTeamWithLogo.name}\n </span>\n <span className=\"truncate text-xs\">{activeTeamWithLogo.plan}</span>\n </div>\n <ChevronsUpDown className=\"ml-auto\" />\n </SidebarMenuButton>\n </DropdownMenuTrigger>\n <DropdownMenuContent\n className=\"w-(--radix-dropdown-menu-trigger-width) min-w-56 rounded-lg\"\n align=\"start\"\n side={isMobile ? \"bottom\" : \"right\"}\n sideOffset={4}\n >\n <DropdownMenuLabel className=\"text-muted-foreground text-xs\">\n Organizations\n </DropdownMenuLabel>\n {teamsWithLogo.map((team) => (\n <DropdownMenuItem\n key={team.id}\n onClick={() => handleTeamChange(team.id)}\n className=\"gap-2 p-2\"\n >\n <div className=\"flex size-6 items-center justify-center rounded-md border\">\n <team.logo className=\"size-3.5 shrink-0\" />\n </div>\n {team.name}\n {team.id === currentOrgId && (\n <Check className=\"ml-auto h-4 w-4\" />\n )}\n </DropdownMenuItem>\n ))}\n <DropdownMenuSeparator />\n <DropdownMenuItem\n className=\"gap-2 p-2\"\n onClick={() => router.push(\"/app/user/organizations\")}\n >\n <div className=\"flex size-6 items-center justify-center rounded-md border bg-transparent\">\n <GalleryVerticalEnd className=\"size-4\" />\n </div>\n <div className=\"text-muted-foreground font-medium\">\n Manage organizations\n </div>\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </SidebarMenuItem>\n </SidebarMenu>\n )\n}\n\n"]}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { GalleryVerticalEnd, ChevronsUpDown, Check } from 'lucide-react';
|
|
2
|
+
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuLabel, DropdownMenuItem, DropdownMenuSeparator } from '@/components/ui/dropdown-menu';
|
|
3
|
+
import { useSidebar, SidebarMenu, SidebarMenuItem, SidebarMenuButton } from '@/components/ui/sidebar';
|
|
4
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
5
|
+
|
|
6
|
+
function TeamSwitcher({
|
|
7
|
+
teams,
|
|
8
|
+
organizationId,
|
|
9
|
+
adapter
|
|
10
|
+
}) {
|
|
11
|
+
const { isMobile } = useSidebar();
|
|
12
|
+
const pathname = adapter.usePathname();
|
|
13
|
+
const router = adapter.useRouter();
|
|
14
|
+
const pathSegments = pathname.split("/");
|
|
15
|
+
const isAppOrgRoute = pathname.startsWith("/app/") && pathSegments.length > 2 && pathSegments[2] !== "user";
|
|
16
|
+
const pathOrgId = isAppOrgRoute ? pathSegments[2] : null;
|
|
17
|
+
const currentOrgId = organizationId || (pathOrgId && teams.some((team) => team.id === pathOrgId) ? pathOrgId : null);
|
|
18
|
+
const activeTeam = currentOrgId ? teams.find((team) => team.id === currentOrgId) : null;
|
|
19
|
+
const handleTeamChange = (teamId) => {
|
|
20
|
+
router.push(`/app/${teamId}/home`);
|
|
21
|
+
if (router.refresh) {
|
|
22
|
+
router.refresh();
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
const teamsWithLogo = teams.map((org) => ({
|
|
26
|
+
id: org.id,
|
|
27
|
+
name: org.name,
|
|
28
|
+
logo: org.logo || GalleryVerticalEnd,
|
|
29
|
+
plan: org.plan || "Member"
|
|
30
|
+
}));
|
|
31
|
+
if (teamsWithLogo.length === 0) {
|
|
32
|
+
return /* @__PURE__ */ jsx(SidebarMenu, { children: /* @__PURE__ */ jsx(SidebarMenuItem, { children: /* @__PURE__ */ jsxs(SidebarMenuButton, { size: "lg", className: "cursor-default", children: [
|
|
33
|
+
/* @__PURE__ */ jsx("div", { className: "bg-muted flex aspect-square size-8 items-center justify-center rounded-lg", children: /* @__PURE__ */ jsx(GalleryVerticalEnd, { className: "size-4 text-muted-foreground" }) }),
|
|
34
|
+
/* @__PURE__ */ jsxs("div", { className: "grid flex-1 text-left text-sm leading-tight", children: [
|
|
35
|
+
/* @__PURE__ */ jsx("span", { className: "truncate font-medium text-muted-foreground", children: "No organizations" }),
|
|
36
|
+
/* @__PURE__ */ jsx("span", { className: "truncate text-xs text-muted-foreground", children: "Join or create one" })
|
|
37
|
+
] })
|
|
38
|
+
] }) }) });
|
|
39
|
+
}
|
|
40
|
+
if (!activeTeam) {
|
|
41
|
+
return /* @__PURE__ */ jsx(SidebarMenu, { children: /* @__PURE__ */ jsx(SidebarMenuItem, { children: /* @__PURE__ */ jsxs(DropdownMenu, { children: [
|
|
42
|
+
/* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
43
|
+
SidebarMenuButton,
|
|
44
|
+
{
|
|
45
|
+
size: "lg",
|
|
46
|
+
className: "data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground",
|
|
47
|
+
children: [
|
|
48
|
+
/* @__PURE__ */ jsx("div", { className: "bg-muted flex aspect-square size-8 items-center justify-center rounded-lg", children: /* @__PURE__ */ jsx(GalleryVerticalEnd, { className: "size-4 text-muted-foreground" }) }),
|
|
49
|
+
/* @__PURE__ */ jsxs("div", { className: "grid flex-1 text-left text-sm leading-tight", children: [
|
|
50
|
+
/* @__PURE__ */ jsx("span", { className: "truncate font-medium", children: "Organizations" }),
|
|
51
|
+
/* @__PURE__ */ jsxs("span", { className: "truncate text-xs text-muted-foreground", children: [
|
|
52
|
+
teamsWithLogo.length,
|
|
53
|
+
" available"
|
|
54
|
+
] })
|
|
55
|
+
] }),
|
|
56
|
+
/* @__PURE__ */ jsx(ChevronsUpDown, { className: "ml-auto" })
|
|
57
|
+
]
|
|
58
|
+
}
|
|
59
|
+
) }),
|
|
60
|
+
/* @__PURE__ */ jsxs(
|
|
61
|
+
DropdownMenuContent,
|
|
62
|
+
{
|
|
63
|
+
className: "w-(--radix-dropdown-menu-trigger-width) min-w-56 rounded-lg",
|
|
64
|
+
align: "start",
|
|
65
|
+
side: isMobile ? "bottom" : "right",
|
|
66
|
+
sideOffset: 4,
|
|
67
|
+
children: [
|
|
68
|
+
/* @__PURE__ */ jsx(DropdownMenuLabel, { className: "text-muted-foreground text-xs", children: "Select an organization" }),
|
|
69
|
+
teamsWithLogo.map((team) => /* @__PURE__ */ jsxs(
|
|
70
|
+
DropdownMenuItem,
|
|
71
|
+
{
|
|
72
|
+
onClick: () => handleTeamChange(team.id),
|
|
73
|
+
className: "gap-2 p-2",
|
|
74
|
+
children: [
|
|
75
|
+
/* @__PURE__ */ jsx("div", { className: "flex size-6 items-center justify-center rounded-md border", children: /* @__PURE__ */ jsx(team.logo, { className: "size-3.5 shrink-0" }) }),
|
|
76
|
+
team.name
|
|
77
|
+
]
|
|
78
|
+
},
|
|
79
|
+
team.id
|
|
80
|
+
)),
|
|
81
|
+
/* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
|
|
82
|
+
/* @__PURE__ */ jsxs(
|
|
83
|
+
DropdownMenuItem,
|
|
84
|
+
{
|
|
85
|
+
className: "gap-2 p-2",
|
|
86
|
+
onClick: () => router.push("/app/user/organizations"),
|
|
87
|
+
children: [
|
|
88
|
+
/* @__PURE__ */ jsx("div", { className: "flex size-6 items-center justify-center rounded-md border bg-transparent", children: /* @__PURE__ */ jsx(GalleryVerticalEnd, { className: "size-4" }) }),
|
|
89
|
+
/* @__PURE__ */ jsx("div", { className: "text-muted-foreground font-medium", children: "Manage organizations" })
|
|
90
|
+
]
|
|
91
|
+
}
|
|
92
|
+
)
|
|
93
|
+
]
|
|
94
|
+
}
|
|
95
|
+
)
|
|
96
|
+
] }) }) });
|
|
97
|
+
}
|
|
98
|
+
const activeTeamWithLogo = teamsWithLogo.find(
|
|
99
|
+
(team) => team.id === currentOrgId
|
|
100
|
+
);
|
|
101
|
+
if (!activeTeamWithLogo) {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
return /* @__PURE__ */ jsx(SidebarMenu, { children: /* @__PURE__ */ jsx(SidebarMenuItem, { children: /* @__PURE__ */ jsxs(DropdownMenu, { children: [
|
|
105
|
+
/* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
106
|
+
SidebarMenuButton,
|
|
107
|
+
{
|
|
108
|
+
size: "lg",
|
|
109
|
+
className: "data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground",
|
|
110
|
+
children: [
|
|
111
|
+
/* @__PURE__ */ jsx("div", { className: "bg-sidebar-primary text-sidebar-primary-foreground flex aspect-square size-8 items-center justify-center rounded-lg", children: /* @__PURE__ */ jsx(activeTeamWithLogo.logo, { className: "size-4" }) }),
|
|
112
|
+
/* @__PURE__ */ jsxs("div", { className: "grid flex-1 text-left text-sm leading-tight", children: [
|
|
113
|
+
/* @__PURE__ */ jsx("span", { className: "truncate font-medium", children: activeTeamWithLogo.name }),
|
|
114
|
+
/* @__PURE__ */ jsx("span", { className: "truncate text-xs", children: activeTeamWithLogo.plan })
|
|
115
|
+
] }),
|
|
116
|
+
/* @__PURE__ */ jsx(ChevronsUpDown, { className: "ml-auto" })
|
|
117
|
+
]
|
|
118
|
+
}
|
|
119
|
+
) }),
|
|
120
|
+
/* @__PURE__ */ jsxs(
|
|
121
|
+
DropdownMenuContent,
|
|
122
|
+
{
|
|
123
|
+
className: "w-(--radix-dropdown-menu-trigger-width) min-w-56 rounded-lg",
|
|
124
|
+
align: "start",
|
|
125
|
+
side: isMobile ? "bottom" : "right",
|
|
126
|
+
sideOffset: 4,
|
|
127
|
+
children: [
|
|
128
|
+
/* @__PURE__ */ jsx(DropdownMenuLabel, { className: "text-muted-foreground text-xs", children: "Organizations" }),
|
|
129
|
+
teamsWithLogo.map((team) => /* @__PURE__ */ jsxs(
|
|
130
|
+
DropdownMenuItem,
|
|
131
|
+
{
|
|
132
|
+
onClick: () => handleTeamChange(team.id),
|
|
133
|
+
className: "gap-2 p-2",
|
|
134
|
+
children: [
|
|
135
|
+
/* @__PURE__ */ jsx("div", { className: "flex size-6 items-center justify-center rounded-md border", children: /* @__PURE__ */ jsx(team.logo, { className: "size-3.5 shrink-0" }) }),
|
|
136
|
+
team.name,
|
|
137
|
+
team.id === currentOrgId && /* @__PURE__ */ jsx(Check, { className: "ml-auto h-4 w-4" })
|
|
138
|
+
]
|
|
139
|
+
},
|
|
140
|
+
team.id
|
|
141
|
+
)),
|
|
142
|
+
/* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
|
|
143
|
+
/* @__PURE__ */ jsxs(
|
|
144
|
+
DropdownMenuItem,
|
|
145
|
+
{
|
|
146
|
+
className: "gap-2 p-2",
|
|
147
|
+
onClick: () => router.push("/app/user/organizations"),
|
|
148
|
+
children: [
|
|
149
|
+
/* @__PURE__ */ jsx("div", { className: "flex size-6 items-center justify-center rounded-md border bg-transparent", children: /* @__PURE__ */ jsx(GalleryVerticalEnd, { className: "size-4" }) }),
|
|
150
|
+
/* @__PURE__ */ jsx("div", { className: "text-muted-foreground font-medium", children: "Manage organizations" })
|
|
151
|
+
]
|
|
152
|
+
}
|
|
153
|
+
)
|
|
154
|
+
]
|
|
155
|
+
}
|
|
156
|
+
)
|
|
157
|
+
] }) }) });
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export { TeamSwitcher };
|
|
161
|
+
//# sourceMappingURL=TeamSwitcher.mjs.map
|
|
162
|
+
//# sourceMappingURL=TeamSwitcher.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/TeamSwitcher.tsx"],"names":[],"mappings":"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","file":"TeamSwitcher.mjs","sourcesContent":["\"use client\"\n\nimport { Check, ChevronsUpDown, GalleryVerticalEnd } from \"lucide-react\"\nimport * as React from \"react\"\n\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from \"@/components/ui/dropdown-menu\"\nimport {\n SidebarMenu,\n SidebarMenuButton,\n SidebarMenuItem,\n useSidebar,\n} from \"@/components/ui/sidebar\"\nimport type { FrameworkAdapter, Organization } from \"../types\"\n\ninterface TeamSwitcherProps {\n teams: Organization[]\n organizationId?: string\n adapter: FrameworkAdapter\n}\n\nexport function TeamSwitcher({\n teams,\n organizationId,\n adapter,\n}: TeamSwitcherProps) {\n const { isMobile } = useSidebar()\n const pathname = adapter.usePathname()\n const router = adapter.useRouter()\n\n // Only extract org ID from /app/[org_id]/... paths, excluding /app/user/...\n const pathSegments = pathname.split(\"/\")\n const isAppOrgRoute =\n pathname.startsWith(\"/app/\") &&\n pathSegments.length > 2 &&\n pathSegments[2] !== \"user\"\n const pathOrgId = isAppOrgRoute ? pathSegments[2] : null\n\n // Determine current org: only from provided prop or valid path - don't auto-select\n const currentOrgId =\n organizationId ||\n (pathOrgId && teams.some((team) => team.id === pathOrgId)\n ? pathOrgId\n : null)\n\n // Find the active team based on current org ID\n const activeTeam = currentOrgId\n ? teams.find((team) => team.id === currentOrgId)\n : null\n\n const handleTeamChange = (teamId: string) => {\n // Navigate to the organization's home page\n router.push(`/app/${teamId}/home`)\n if (router.refresh) {\n router.refresh()\n }\n }\n\n // Transform organizations to teams format with default logo\n const teamsWithLogo = teams.map((org) => ({\n id: org.id,\n name: org.name,\n logo: org.logo || GalleryVerticalEnd,\n plan: org.plan || \"Member\",\n }))\n\n // No organizations state\n if (teamsWithLogo.length === 0) {\n return (\n <SidebarMenu>\n <SidebarMenuItem>\n <SidebarMenuButton size=\"lg\" className=\"cursor-default\">\n <div className=\"bg-muted flex aspect-square size-8 items-center justify-center rounded-lg\">\n <GalleryVerticalEnd className=\"size-4 text-muted-foreground\" />\n </div>\n <div className=\"grid flex-1 text-left text-sm leading-tight\">\n <span className=\"truncate font-medium text-muted-foreground\">\n No organizations\n </span>\n <span className=\"truncate text-xs text-muted-foreground\">\n Join or create one\n </span>\n </div>\n </SidebarMenuButton>\n </SidebarMenuItem>\n </SidebarMenu>\n )\n }\n\n // No org selected state - prompt user to select\n if (!activeTeam) {\n return (\n <SidebarMenu>\n <SidebarMenuItem>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <SidebarMenuButton\n size=\"lg\"\n className=\"data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground\"\n >\n <div className=\"bg-muted flex aspect-square size-8 items-center justify-center rounded-lg\">\n <GalleryVerticalEnd className=\"size-4 text-muted-foreground\" />\n </div>\n <div className=\"grid flex-1 text-left text-sm leading-tight\">\n <span className=\"truncate font-medium\">Organizations</span>\n <span className=\"truncate text-xs text-muted-foreground\">\n {teamsWithLogo.length} available\n </span>\n </div>\n <ChevronsUpDown className=\"ml-auto\" />\n </SidebarMenuButton>\n </DropdownMenuTrigger>\n <DropdownMenuContent\n className=\"w-(--radix-dropdown-menu-trigger-width) min-w-56 rounded-lg\"\n align=\"start\"\n side={isMobile ? \"bottom\" : \"right\"}\n sideOffset={4}\n >\n <DropdownMenuLabel className=\"text-muted-foreground text-xs\">\n Select an organization\n </DropdownMenuLabel>\n {teamsWithLogo.map((team) => (\n <DropdownMenuItem\n key={team.id}\n onClick={() => handleTeamChange(team.id)}\n className=\"gap-2 p-2\"\n >\n <div className=\"flex size-6 items-center justify-center rounded-md border\">\n <team.logo className=\"size-3.5 shrink-0\" />\n </div>\n {team.name}\n </DropdownMenuItem>\n ))}\n <DropdownMenuSeparator />\n <DropdownMenuItem\n className=\"gap-2 p-2\"\n onClick={() => router.push(\"/app/user/organizations\")}\n >\n <div className=\"flex size-6 items-center justify-center rounded-md border bg-transparent\">\n <GalleryVerticalEnd className=\"size-4\" />\n </div>\n <div className=\"text-muted-foreground font-medium\">\n Manage organizations\n </div>\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </SidebarMenuItem>\n </SidebarMenu>\n )\n }\n\n // Org selected state - show current org with switcher\n const activeTeamWithLogo = teamsWithLogo.find(\n (team) => team.id === currentOrgId\n )\n\n if (!activeTeamWithLogo) {\n return null\n }\n\n return (\n <SidebarMenu>\n <SidebarMenuItem>\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <SidebarMenuButton\n size=\"lg\"\n className=\"data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground\"\n >\n <div className=\"bg-sidebar-primary text-sidebar-primary-foreground flex aspect-square size-8 items-center justify-center rounded-lg\">\n <activeTeamWithLogo.logo className=\"size-4\" />\n </div>\n <div className=\"grid flex-1 text-left text-sm leading-tight\">\n <span className=\"truncate font-medium\">\n {activeTeamWithLogo.name}\n </span>\n <span className=\"truncate text-xs\">{activeTeamWithLogo.plan}</span>\n </div>\n <ChevronsUpDown className=\"ml-auto\" />\n </SidebarMenuButton>\n </DropdownMenuTrigger>\n <DropdownMenuContent\n className=\"w-(--radix-dropdown-menu-trigger-width) min-w-56 rounded-lg\"\n align=\"start\"\n side={isMobile ? \"bottom\" : \"right\"}\n sideOffset={4}\n >\n <DropdownMenuLabel className=\"text-muted-foreground text-xs\">\n Organizations\n </DropdownMenuLabel>\n {teamsWithLogo.map((team) => (\n <DropdownMenuItem\n key={team.id}\n onClick={() => handleTeamChange(team.id)}\n className=\"gap-2 p-2\"\n >\n <div className=\"flex size-6 items-center justify-center rounded-md border\">\n <team.logo className=\"size-3.5 shrink-0\" />\n </div>\n {team.name}\n {team.id === currentOrgId && (\n <Check className=\"ml-auto h-4 w-4\" />\n )}\n </DropdownMenuItem>\n ))}\n <DropdownMenuSeparator />\n <DropdownMenuItem\n className=\"gap-2 p-2\"\n onClick={() => router.push(\"/app/user/organizations\")}\n >\n <div className=\"flex size-6 items-center justify-center rounded-md border bg-transparent\">\n <GalleryVerticalEnd className=\"size-4\" />\n </div>\n <div className=\"text-muted-foreground font-medium\">\n Manage organizations\n </div>\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n </SidebarMenuItem>\n </SidebarMenu>\n )\n}\n\n"]}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { NavigationItem, Organization } from '../types/index.mjs';
|
|
2
|
+
import 'lucide-react';
|
|
3
|
+
import 'react';
|
|
4
|
+
|
|
5
|
+
interface UseNavigationOptions {
|
|
6
|
+
organizationId?: string;
|
|
7
|
+
apiBaseUrl?: string;
|
|
8
|
+
enabled?: boolean;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Hook to fetch navigation items and organizations from API
|
|
12
|
+
* Falls back to empty array if API is unavailable or disabled
|
|
13
|
+
*
|
|
14
|
+
* @param options - Configuration options
|
|
15
|
+
* @returns Navigation items, organizations, loading state, and error
|
|
16
|
+
*/
|
|
17
|
+
declare function useNavigation({ organizationId, apiBaseUrl, enabled, }?: UseNavigationOptions): {
|
|
18
|
+
items: NavigationItem[];
|
|
19
|
+
organizations: Organization[];
|
|
20
|
+
loading: boolean;
|
|
21
|
+
error: Error | null;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export { useNavigation };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { NavigationItem, Organization } from '../types/index.js';
|
|
2
|
+
import 'lucide-react';
|
|
3
|
+
import 'react';
|
|
4
|
+
|
|
5
|
+
interface UseNavigationOptions {
|
|
6
|
+
organizationId?: string;
|
|
7
|
+
apiBaseUrl?: string;
|
|
8
|
+
enabled?: boolean;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Hook to fetch navigation items and organizations from API
|
|
12
|
+
* Falls back to empty array if API is unavailable or disabled
|
|
13
|
+
*
|
|
14
|
+
* @param options - Configuration options
|
|
15
|
+
* @returns Navigation items, organizations, loading state, and error
|
|
16
|
+
*/
|
|
17
|
+
declare function useNavigation({ organizationId, apiBaseUrl, enabled, }?: UseNavigationOptions): {
|
|
18
|
+
items: NavigationItem[];
|
|
19
|
+
organizations: Organization[];
|
|
20
|
+
loading: boolean;
|
|
21
|
+
error: Error | null;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export { useNavigation };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var react = require('react');
|
|
4
|
+
|
|
5
|
+
function useNavigation({
|
|
6
|
+
organizationId,
|
|
7
|
+
apiBaseUrl = "/api",
|
|
8
|
+
enabled = true
|
|
9
|
+
} = {}) {
|
|
10
|
+
const [items, setItems] = react.useState([]);
|
|
11
|
+
const [organizations, setOrganizations] = react.useState([]);
|
|
12
|
+
const [loading, setLoading] = react.useState(false);
|
|
13
|
+
const [error, setError] = react.useState(null);
|
|
14
|
+
react.useEffect(() => {
|
|
15
|
+
if (!enabled || !organizationId) {
|
|
16
|
+
setItems([]);
|
|
17
|
+
setOrganizations([]);
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const fetchNavigation = async () => {
|
|
21
|
+
setLoading(true);
|
|
22
|
+
setError(null);
|
|
23
|
+
try {
|
|
24
|
+
const response = await fetch(
|
|
25
|
+
`${apiBaseUrl}/navigation/${organizationId}`,
|
|
26
|
+
{
|
|
27
|
+
credentials: "include"
|
|
28
|
+
// Include cookies for auth
|
|
29
|
+
}
|
|
30
|
+
);
|
|
31
|
+
if (!response.ok) {
|
|
32
|
+
if (response.status === 401) {
|
|
33
|
+
throw new Error("Unauthorized");
|
|
34
|
+
}
|
|
35
|
+
if (response.status === 404) {
|
|
36
|
+
throw new Error("Organization not found");
|
|
37
|
+
}
|
|
38
|
+
throw new Error(`Failed to fetch navigation: ${response.statusText}`);
|
|
39
|
+
}
|
|
40
|
+
const data = await response.json();
|
|
41
|
+
setItems(data.items || []);
|
|
42
|
+
setOrganizations(data.organizations || []);
|
|
43
|
+
} catch (err) {
|
|
44
|
+
const error2 = err instanceof Error ? err : new Error("Unknown error");
|
|
45
|
+
setError(error2);
|
|
46
|
+
setItems([]);
|
|
47
|
+
setOrganizations([]);
|
|
48
|
+
} finally {
|
|
49
|
+
setLoading(false);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
fetchNavigation();
|
|
53
|
+
}, [organizationId, apiBaseUrl, enabled]);
|
|
54
|
+
return { items, organizations, loading, error };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
exports.useNavigation = useNavigation;
|
|
58
|
+
//# sourceMappingURL=useNavigation.js.map
|
|
59
|
+
//# sourceMappingURL=useNavigation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/useNavigation.ts"],"names":["useState","useEffect","error"],"mappings":";;;;AAwBO,SAAS,aAAA,CAAc;AAAA,EAC5B,cAAA;AAAA,EACA,UAAA,GAAa,MAAA;AAAA,EACb,OAAA,GAAU;AACZ,CAAA,GAA0B,EAAC,EAAG;AAC5B,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIA,cAAA,CAA2B,EAAE,CAAA;AACvD,EAAA,MAAM,CAAC,aAAA,EAAe,gBAAgB,CAAA,GAAIA,cAAA,CAAyB,EAAE,CAAA;AACrE,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAIA,eAAS,KAAK,CAAA;AAC5C,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIA,eAAuB,IAAI,CAAA;AAErD,EAAAC,eAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,OAAA,IAAW,CAAC,cAAA,EAAgB;AAC/B,MAAA,QAAA,CAAS,EAAE,CAAA;AACX,MAAA,gBAAA,CAAiB,EAAE,CAAA;AACnB,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,kBAAkB,YAAY;AAClC,MAAA,UAAA,CAAW,IAAI,CAAA;AACf,MAAA,QAAA,CAAS,IAAI,CAAA;AAEb,MAAA,IAAI;AACF,QAAA,MAAM,WAAW,MAAM,KAAA;AAAA,UACrB,CAAA,EAAG,UAAU,CAAA,YAAA,EAAe,cAAc,CAAA,CAAA;AAAA,UAC1C;AAAA,YACE,WAAA,EAAa;AAAA;AAAA;AACf,SACF;AAEA,QAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,UAAA,IAAI,QAAA,CAAS,WAAW,GAAA,EAAK;AAC3B,YAAA,MAAM,IAAI,MAAM,cAAc,CAAA;AAAA,UAChC;AACA,UAAA,IAAI,QAAA,CAAS,WAAW,GAAA,EAAK;AAC3B,YAAA,MAAM,IAAI,MAAM,wBAAwB,CAAA;AAAA,UAC1C;AACA,UAAA,MAAM,IAAI,KAAA,CAAM,CAAA,4BAAA,EAA+B,QAAA,CAAS,UAAU,CAAA,CAAE,CAAA;AAAA,QACtE;AAEA,QAAA,MAAM,IAAA,GAA2B,MAAM,QAAA,CAAS,IAAA,EAAK;AACrD,QAAA,QAAA,CAAS,IAAA,CAAK,KAAA,IAAS,EAAE,CAAA;AACzB,QAAA,gBAAA,CAAiB,IAAA,CAAK,aAAA,IAAiB,EAAE,CAAA;AAAA,MAC3C,SAAS,GAAA,EAAK;AACZ,QAAA,MAAMC,SAAQ,GAAA,YAAe,KAAA,GAAQ,GAAA,GAAM,IAAI,MAAM,eAAe,CAAA;AACpE,QAAA,QAAA,CAASA,MAAK,CAAA;AACd,QAAA,QAAA,CAAS,EAAE,CAAA;AACX,QAAA,gBAAA,CAAiB,EAAE,CAAA;AAAA,MACrB,CAAA,SAAE;AACA,QAAA,UAAA,CAAW,KAAK,CAAA;AAAA,MAClB;AAAA,IACF,CAAA;AAEA,IAAA,eAAA,EAAgB;AAAA,EAClB,CAAA,EAAG,CAAC,cAAA,EAAgB,UAAA,EAAY,OAAO,CAAC,CAAA;AAExC,EAAA,OAAO,EAAE,KAAA,EAAO,aAAA,EAAe,OAAA,EAAS,KAAA,EAAM;AAChD","file":"useNavigation.js","sourcesContent":["\"use client\"\n\nimport { useEffect, useState } from \"react\"\nimport type { NavigationItem, Organization } from \"../types\"\n\ninterface UseNavigationOptions {\n organizationId?: string\n apiBaseUrl?: string\n enabled?: boolean\n}\n\ninterface NavigationResponse {\n items: NavigationItem[]\n organizationId: string\n organizations?: Organization[] // Add organizations to response\n}\n\n/**\n * Hook to fetch navigation items and organizations from API\n * Falls back to empty array if API is unavailable or disabled\n * \n * @param options - Configuration options\n * @returns Navigation items, organizations, loading state, and error\n */\nexport function useNavigation({\n organizationId,\n apiBaseUrl = \"/api\",\n enabled = true,\n}: UseNavigationOptions = {}) {\n const [items, setItems] = useState<NavigationItem[]>([])\n const [organizations, setOrganizations] = useState<Organization[]>([])\n const [loading, setLoading] = useState(false)\n const [error, setError] = useState<Error | null>(null)\n\n useEffect(() => {\n if (!enabled || !organizationId) {\n setItems([])\n setOrganizations([])\n return\n }\n\n const fetchNavigation = async () => {\n setLoading(true)\n setError(null)\n\n try {\n const response = await fetch(\n `${apiBaseUrl}/navigation/${organizationId}`,\n {\n credentials: \"include\", // Include cookies for auth\n }\n )\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Unauthorized\")\n }\n if (response.status === 404) {\n throw new Error(\"Organization not found\")\n }\n throw new Error(`Failed to fetch navigation: ${response.statusText}`)\n }\n\n const data: NavigationResponse = await response.json()\n setItems(data.items || [])\n setOrganizations(data.organizations || [])\n } catch (err) {\n const error = err instanceof Error ? err : new Error(\"Unknown error\")\n setError(error)\n setItems([]) // Fallback to empty array\n setOrganizations([]) // Fallback to empty array\n } finally {\n setLoading(false)\n }\n }\n\n fetchNavigation()\n }, [organizationId, apiBaseUrl, enabled])\n\n return { items, organizations, loading, error }\n}\n\n"]}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { useState, useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
function useNavigation({
|
|
4
|
+
organizationId,
|
|
5
|
+
apiBaseUrl = "/api",
|
|
6
|
+
enabled = true
|
|
7
|
+
} = {}) {
|
|
8
|
+
const [items, setItems] = useState([]);
|
|
9
|
+
const [organizations, setOrganizations] = useState([]);
|
|
10
|
+
const [loading, setLoading] = useState(false);
|
|
11
|
+
const [error, setError] = useState(null);
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
if (!enabled || !organizationId) {
|
|
14
|
+
setItems([]);
|
|
15
|
+
setOrganizations([]);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const fetchNavigation = async () => {
|
|
19
|
+
setLoading(true);
|
|
20
|
+
setError(null);
|
|
21
|
+
try {
|
|
22
|
+
const response = await fetch(
|
|
23
|
+
`${apiBaseUrl}/navigation/${organizationId}`,
|
|
24
|
+
{
|
|
25
|
+
credentials: "include"
|
|
26
|
+
// Include cookies for auth
|
|
27
|
+
}
|
|
28
|
+
);
|
|
29
|
+
if (!response.ok) {
|
|
30
|
+
if (response.status === 401) {
|
|
31
|
+
throw new Error("Unauthorized");
|
|
32
|
+
}
|
|
33
|
+
if (response.status === 404) {
|
|
34
|
+
throw new Error("Organization not found");
|
|
35
|
+
}
|
|
36
|
+
throw new Error(`Failed to fetch navigation: ${response.statusText}`);
|
|
37
|
+
}
|
|
38
|
+
const data = await response.json();
|
|
39
|
+
setItems(data.items || []);
|
|
40
|
+
setOrganizations(data.organizations || []);
|
|
41
|
+
} catch (err) {
|
|
42
|
+
const error2 = err instanceof Error ? err : new Error("Unknown error");
|
|
43
|
+
setError(error2);
|
|
44
|
+
setItems([]);
|
|
45
|
+
setOrganizations([]);
|
|
46
|
+
} finally {
|
|
47
|
+
setLoading(false);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
fetchNavigation();
|
|
51
|
+
}, [organizationId, apiBaseUrl, enabled]);
|
|
52
|
+
return { items, organizations, loading, error };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export { useNavigation };
|
|
56
|
+
//# sourceMappingURL=useNavigation.mjs.map
|
|
57
|
+
//# sourceMappingURL=useNavigation.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/useNavigation.ts"],"names":["error"],"mappings":";;AAwBO,SAAS,aAAA,CAAc;AAAA,EAC5B,cAAA;AAAA,EACA,UAAA,GAAa,MAAA;AAAA,EACb,OAAA,GAAU;AACZ,CAAA,GAA0B,EAAC,EAAG;AAC5B,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,QAAA,CAA2B,EAAE,CAAA;AACvD,EAAA,MAAM,CAAC,aAAA,EAAe,gBAAgB,CAAA,GAAI,QAAA,CAAyB,EAAE,CAAA;AACrE,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,SAAS,KAAK,CAAA;AAC5C,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,SAAuB,IAAI,CAAA;AAErD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,OAAA,IAAW,CAAC,cAAA,EAAgB;AAC/B,MAAA,QAAA,CAAS,EAAE,CAAA;AACX,MAAA,gBAAA,CAAiB,EAAE,CAAA;AACnB,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,kBAAkB,YAAY;AAClC,MAAA,UAAA,CAAW,IAAI,CAAA;AACf,MAAA,QAAA,CAAS,IAAI,CAAA;AAEb,MAAA,IAAI;AACF,QAAA,MAAM,WAAW,MAAM,KAAA;AAAA,UACrB,CAAA,EAAG,UAAU,CAAA,YAAA,EAAe,cAAc,CAAA,CAAA;AAAA,UAC1C;AAAA,YACE,WAAA,EAAa;AAAA;AAAA;AACf,SACF;AAEA,QAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,UAAA,IAAI,QAAA,CAAS,WAAW,GAAA,EAAK;AAC3B,YAAA,MAAM,IAAI,MAAM,cAAc,CAAA;AAAA,UAChC;AACA,UAAA,IAAI,QAAA,CAAS,WAAW,GAAA,EAAK;AAC3B,YAAA,MAAM,IAAI,MAAM,wBAAwB,CAAA;AAAA,UAC1C;AACA,UAAA,MAAM,IAAI,KAAA,CAAM,CAAA,4BAAA,EAA+B,QAAA,CAAS,UAAU,CAAA,CAAE,CAAA;AAAA,QACtE;AAEA,QAAA,MAAM,IAAA,GAA2B,MAAM,QAAA,CAAS,IAAA,EAAK;AACrD,QAAA,QAAA,CAAS,IAAA,CAAK,KAAA,IAAS,EAAE,CAAA;AACzB,QAAA,gBAAA,CAAiB,IAAA,CAAK,aAAA,IAAiB,EAAE,CAAA;AAAA,MAC3C,SAAS,GAAA,EAAK;AACZ,QAAA,MAAMA,SAAQ,GAAA,YAAe,KAAA,GAAQ,GAAA,GAAM,IAAI,MAAM,eAAe,CAAA;AACpE,QAAA,QAAA,CAASA,MAAK,CAAA;AACd,QAAA,QAAA,CAAS,EAAE,CAAA;AACX,QAAA,gBAAA,CAAiB,EAAE,CAAA;AAAA,MACrB,CAAA,SAAE;AACA,QAAA,UAAA,CAAW,KAAK,CAAA;AAAA,MAClB;AAAA,IACF,CAAA;AAEA,IAAA,eAAA,EAAgB;AAAA,EAClB,CAAA,EAAG,CAAC,cAAA,EAAgB,UAAA,EAAY,OAAO,CAAC,CAAA;AAExC,EAAA,OAAO,EAAE,KAAA,EAAO,aAAA,EAAe,OAAA,EAAS,KAAA,EAAM;AAChD","file":"useNavigation.mjs","sourcesContent":["\"use client\"\n\nimport { useEffect, useState } from \"react\"\nimport type { NavigationItem, Organization } from \"../types\"\n\ninterface UseNavigationOptions {\n organizationId?: string\n apiBaseUrl?: string\n enabled?: boolean\n}\n\ninterface NavigationResponse {\n items: NavigationItem[]\n organizationId: string\n organizations?: Organization[] // Add organizations to response\n}\n\n/**\n * Hook to fetch navigation items and organizations from API\n * Falls back to empty array if API is unavailable or disabled\n * \n * @param options - Configuration options\n * @returns Navigation items, organizations, loading state, and error\n */\nexport function useNavigation({\n organizationId,\n apiBaseUrl = \"/api\",\n enabled = true,\n}: UseNavigationOptions = {}) {\n const [items, setItems] = useState<NavigationItem[]>([])\n const [organizations, setOrganizations] = useState<Organization[]>([])\n const [loading, setLoading] = useState(false)\n const [error, setError] = useState<Error | null>(null)\n\n useEffect(() => {\n if (!enabled || !organizationId) {\n setItems([])\n setOrganizations([])\n return\n }\n\n const fetchNavigation = async () => {\n setLoading(true)\n setError(null)\n\n try {\n const response = await fetch(\n `${apiBaseUrl}/navigation/${organizationId}`,\n {\n credentials: \"include\", // Include cookies for auth\n }\n )\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new Error(\"Unauthorized\")\n }\n if (response.status === 404) {\n throw new Error(\"Organization not found\")\n }\n throw new Error(`Failed to fetch navigation: ${response.statusText}`)\n }\n\n const data: NavigationResponse = await response.json()\n setItems(data.items || [])\n setOrganizations(data.organizations || [])\n } catch (err) {\n const error = err instanceof Error ? err : new Error(\"Unknown error\")\n setError(error)\n setItems([]) // Fallback to empty array\n setOrganizations([]) // Fallback to empty array\n } finally {\n setLoading(false)\n }\n }\n\n fetchNavigation()\n }, [organizationId, apiBaseUrl, enabled])\n\n return { items, organizations, loading, error }\n}\n\n"]}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { User, FrameworkAdapter, SidebarData, NavigationItem, Organization } from './types/index.mjs';
|
|
4
|
+
export { LinkProps, NavigationConfig, Router } from './types/index.mjs';
|
|
5
|
+
import { Sidebar } from '@/components/ui/sidebar';
|
|
6
|
+
export { useNavigation } from './hooks/useNavigation.mjs';
|
|
7
|
+
export { getIconComponent } from './utils/iconMapper.mjs';
|
|
8
|
+
import 'lucide-react';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Props mode: Pass data (organizations + navigationItems)
|
|
12
|
+
* API mode: Omit data (fetched from API)
|
|
13
|
+
*/
|
|
14
|
+
interface AppSidebarProps extends React.ComponentProps<typeof Sidebar> {
|
|
15
|
+
user: User;
|
|
16
|
+
adapter: FrameworkAdapter;
|
|
17
|
+
/** Sidebar data containing organizations and navigation items (props mode) */
|
|
18
|
+
data?: SidebarData;
|
|
19
|
+
/** Current organization ID (optional, can be extracted from pathname) */
|
|
20
|
+
organizationId?: string;
|
|
21
|
+
/** Custom API base URL (API mode only, defaults to "/api") */
|
|
22
|
+
apiBaseUrl?: string;
|
|
23
|
+
}
|
|
24
|
+
declare function AppSidebar({ user, adapter, data, organizationId, apiBaseUrl, ...props }: AppSidebarProps): react_jsx_runtime.JSX.Element;
|
|
25
|
+
|
|
26
|
+
interface NavMainProps {
|
|
27
|
+
items: NavigationItem[];
|
|
28
|
+
adapter: FrameworkAdapter;
|
|
29
|
+
}
|
|
30
|
+
declare function NavMain({ items, adapter }: NavMainProps): react_jsx_runtime.JSX.Element;
|
|
31
|
+
|
|
32
|
+
interface NavUserProps {
|
|
33
|
+
user: User;
|
|
34
|
+
adapter: FrameworkAdapter;
|
|
35
|
+
}
|
|
36
|
+
declare function NavUser({ user, adapter }: NavUserProps): react_jsx_runtime.JSX.Element;
|
|
37
|
+
|
|
38
|
+
interface TeamSwitcherProps {
|
|
39
|
+
teams: Organization[];
|
|
40
|
+
organizationId?: string;
|
|
41
|
+
adapter: FrameworkAdapter;
|
|
42
|
+
}
|
|
43
|
+
declare function TeamSwitcher({ teams, organizationId, adapter, }: TeamSwitcherProps): react_jsx_runtime.JSX.Element | null;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Next.js adapter for @logickernel/frame
|
|
47
|
+
* Provides Next.js-specific implementations of FrameworkAdapter
|
|
48
|
+
*/
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Creates a Next.js adapter for the framework
|
|
52
|
+
* Use this when using @logickernel/frame in a Next.js application
|
|
53
|
+
*
|
|
54
|
+
* Note: This requires Next.js and next-auth to be installed
|
|
55
|
+
*/
|
|
56
|
+
declare function createNextJSAdapter(): FrameworkAdapter;
|
|
57
|
+
|
|
58
|
+
export { AppSidebar, FrameworkAdapter, NavMain, NavUser, NavigationItem, Organization, SidebarData, TeamSwitcher, User, createNextJSAdapter };
|