Skip to content

Commit 25cc464

Browse files
committed
feat(site/experimental): add an organization switcher to the user menu
1 parent a8a0be9 commit 25cc464

File tree

4 files changed

+53
-2
lines changed

4 files changed

+53
-2
lines changed

site/src/api/queries/users.ts

+7
Original file line numberDiff line numberDiff line change
@@ -249,3 +249,10 @@ export const updateAppearanceSettings = (
249249
},
250250
};
251251
};
252+
253+
export const myOrganizations = () => {
254+
return {
255+
queryKey: ["organizations", "me"],
256+
queryFn: () => API.getOrganizations(),
257+
};
258+
};

site/src/contexts/auth/RequireAuth.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export const RequireAuth: FC = () => {
6767
};
6868

6969
type RequireKeys<T, R extends keyof T> = Omit<T, R> & {
70-
[K in keyof Pick<T, R>]: NonNullable<T[K]>;
70+
[K in keyof Pick<T, R>]-?: NonNullable<T[K]>;
7171
};
7272

7373
// We can do some TS magic here but I would rather to be explicit on what

site/src/modules/dashboard/Navbar/UserDropdown/UserDropdown.tsx

+4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { css, type Interpolation, type Theme, useTheme } from "@emotion/react";
22
import Badge from "@mui/material/Badge";
33
import type { FC } from "react";
4+
import { useQuery } from "react-query";
45
import type * as TypesGen from "api/typesGenerated";
56
import { DropdownArrow } from "components/DropdownArrow/DropdownArrow";
67
import {
@@ -11,6 +12,7 @@ import {
1112
import { UserAvatar } from "components/UserAvatar/UserAvatar";
1213
import { BUTTON_SM_HEIGHT, navHeight } from "theme/constants";
1314
import { UserDropdownContent } from "./UserDropdownContent";
15+
import { myOrganizations } from "api/queries/users";
1416

1517
export interface UserDropdownProps {
1618
user: TypesGen.User;
@@ -26,6 +28,7 @@ export const UserDropdown: FC<UserDropdownProps> = ({
2628
onSignOut,
2729
}) => {
2830
const theme = useTheme();
31+
const organizationsQuery = useQuery(myOrganizations());
2932

3033
return (
3134
<Popover>
@@ -63,6 +66,7 @@ export const UserDropdown: FC<UserDropdownProps> = ({
6366
user={user}
6467
buildInfo={buildInfo}
6568
supportLinks={supportLinks}
69+
organizations={organizationsQuery.data}
6670
onSignOut={onSignOut}
6771
/>
6872
</PopoverContent>

site/src/modules/dashboard/Navbar/UserDropdown/UserDropdownContent.tsx

+41-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { CopyButton } from "components/CopyButton/CopyButton";
2020
import { ExternalImage } from "components/ExternalImage/ExternalImage";
2121
import { usePopover } from "components/Popover/Popover";
2222
import { Stack } from "components/Stack/Stack";
23+
import { useDashboard } from "modules/dashboard/useDashboard";
2324

2425
export const Language = {
2526
accountLabel: "Account",
@@ -84,18 +85,21 @@ const styles = {
8485

8586
export interface UserDropdownContentProps {
8687
user: TypesGen.User;
88+
organizations?: TypesGen.Organization[];
8789
buildInfo?: TypesGen.BuildInfoResponse;
8890
supportLinks?: readonly TypesGen.LinkConfig[];
8991
onSignOut: () => void;
9092
}
9193

9294
export const UserDropdownContent: FC<UserDropdownContentProps> = ({
93-
buildInfo,
9495
user,
96+
organizations,
97+
buildInfo,
9598
supportLinks,
9699
onSignOut,
97100
}) => {
98101
const popover = usePopover();
102+
const { organizationId, setOrganizationId } = useDashboard();
99103

100104
const onPopoverClose = () => {
101105
popover.setIsOpen(false);
@@ -128,6 +132,42 @@ export const UserDropdownContent: FC<UserDropdownContentProps> = ({
128132

129133
<Divider css={{ marginBottom: 8 }} />
130134

135+
{organizations && (
136+
<div>
137+
<div
138+
css={{
139+
padding: "8px 20px 6px",
140+
textTransform: "uppercase",
141+
letterSpacing: 1.1,
142+
lineHeight: 1.1,
143+
fontSize: "0.8em",
144+
}}
145+
>
146+
My teams
147+
</div>
148+
{organizations.map((org) => (
149+
<MenuItem
150+
key={org.id}
151+
css={styles.menuItem}
152+
onClick={() => {
153+
setOrganizationId(org.id);
154+
popover.setIsOpen(false);
155+
}}
156+
>
157+
{/* <LogoutIcon css={styles.menuItemIcon} /> */}
158+
<Stack direction="row" spacing={1} css={styles.menuItemText}>
159+
{org.name}
160+
{organizationId == org.id && (
161+
<span css={{ fontSize: 12, color: "gray" }}>Current</span>
162+
)}
163+
</Stack>
164+
</MenuItem>
165+
))}
166+
</div>
167+
)}
168+
169+
<Divider css={{ marginBottom: 8 }} />
170+
131171
<Link to="/settings/account" css={styles.link}>
132172
<MenuItem css={styles.menuItem} onClick={onPopoverClose}>
133173
<AccountIcon css={styles.menuItemIcon} />

0 commit comments

Comments
 (0)