diff --git a/server/private/routers/approvals/listApprovals.ts b/server/private/routers/approvals/listApprovals.ts
index 6006e48b..76a895a6 100644
--- a/server/private/routers/approvals/listApprovals.ts
+++ b/server/private/routers/approvals/listApprovals.ts
@@ -80,7 +80,8 @@ async function queryApprovals(
user: {
name: users.name,
userId: users.userId,
- username: users.username
+ username: users.username,
+ email: users.email
}
})
.from(approvals)
diff --git a/src/app/[orgId]/settings/access/users/page.tsx b/src/app/[orgId]/settings/access/users/page.tsx
index 662ada60..c1036373 100644
--- a/src/app/[orgId]/settings/access/users/page.tsx
+++ b/src/app/[orgId]/settings/access/users/page.tsx
@@ -1,5 +1,6 @@
import { internal } from "@app/lib/api";
import { authCookieHeader } from "@app/lib/api/cookies";
+import { getUserDisplayName } from "@app/lib/getUserDisplayName";
import { ListUsersResponse } from "@server/routers/user";
import { AxiosResponse } from "axios";
import UsersTable, { UserRow } from "../../../../../components/UsersTable";
@@ -73,7 +74,11 @@ export default async function UsersPage(props: UsersPageProps) {
return {
id: user.id,
username: user.username,
- displayUsername: user.email || user.name || user.username,
+ displayUsername: getUserDisplayName({
+ email: user.email,
+ name: user.name,
+ username: user.username
+ }),
name: user.name,
email: user.email,
type: user.type,
diff --git a/src/app/[orgId]/settings/resources/proxy/[niceId]/authentication/page.tsx b/src/app/[orgId]/settings/resources/proxy/[niceId]/authentication/page.tsx
index b26d79a9..3dedea05 100644
--- a/src/app/[orgId]/settings/resources/proxy/[niceId]/authentication/page.tsx
+++ b/src/app/[orgId]/settings/resources/proxy/[niceId]/authentication/page.tsx
@@ -40,6 +40,7 @@ import { usePaidStatus } from "@app/hooks/usePaidStatus";
import { useResourceContext } from "@app/hooks/useResourceContext";
import { toast } from "@app/hooks/useToast";
import { createApiClient, formatAxiosError } from "@app/lib/api";
+import { getUserDisplayName } from "@app/lib/getUserDisplayName";
import { orgQueries, resourceQueries } from "@app/lib/queries";
import { zodResolver } from "@hookform/resolvers/zod";
import { build } from "@server/build";
@@ -154,7 +155,10 @@ export default function ResourceAuthenticationPage() {
const allUsers = useMemo(() => {
return orgUsers.map((user) => ({
id: user.id.toString(),
- text: `${user.email || user.username}${user.type !== UserType.Internal ? ` (${user.idpName})` : ""}`
+ text: `${getUserDisplayName({
+ email: user.email,
+ username: user.username
+ })}${user.type !== UserType.Internal ? ` (${user.idpName})` : ""}`
}));
}, [orgUsers]);
@@ -229,7 +233,10 @@ export default function ResourceAuthenticationPage() {
"users",
resourceUsers.map((i) => ({
id: i.userId.toString(),
- text: `${i.email || i.username}${i.type !== UserType.Internal ? ` (${i.idpName})` : ""}`
+ text: `${getUserDisplayName({
+ email: i.email,
+ username: i.username
+ })}${i.type !== UserType.Internal ? ` (${i.idpName})` : ""}`
}))
);
diff --git a/src/app/admin/users/[userId]/layout.tsx b/src/app/admin/users/[userId]/layout.tsx
index 0c8c50e6..e773a2ec 100644
--- a/src/app/admin/users/[userId]/layout.tsx
+++ b/src/app/admin/users/[userId]/layout.tsx
@@ -2,6 +2,7 @@ import { internal } from "@app/lib/api";
import { AxiosResponse } from "axios";
import { redirect } from "next/navigation";
import { authCookieHeader } from "@app/lib/api/cookies";
+import { getUserDisplayName } from "@app/lib/getUserDisplayName";
import { AdminGetUserResponse } from "@server/routers/user/adminGetUser";
import { HorizontalTabs } from "@app/components/HorizontalTabs";
import { cache } from "react";
@@ -44,7 +45,15 @@ export default async function UserLayoutProps(props: UserLayoutProps) {
return (
<>
{t("userQuestionRemove", {
- selectedUser:
- selected?.email ||
- selected?.name ||
- selected?.username
+ selectedUser: selected
+ ? getUserDisplayName({
+ email: selected.email,
+ name: selected.name,
+ username: selected.username
+ })
+ : ""
})}
- {user.email || user.name || user.username} + {getUserDisplayName({ user })}
{user.serverAdmin ? ( diff --git a/src/components/UserDevicesTable.tsx b/src/components/UserDevicesTable.tsx index 102014e3..11e5bead 100644 --- a/src/components/UserDevicesTable.tsx +++ b/src/components/UserDevicesTable.tsx @@ -12,6 +12,7 @@ import { import { useEnvContext } from "@app/hooks/useEnvContext"; import { toast } from "@app/hooks/useToast"; import { createApiClient, formatAxiosError } from "@app/lib/api"; +import { getUserDisplayName } from "@app/lib/getUserDisplayName"; import { ArrowRight, ArrowUpDown, @@ -344,7 +345,10 @@ export default function UserDevicesTable({ userClients }: ClientTableProps) { href={`/${r.orgId}/settings/access/users/${r.userId}`} > diff --git a/src/components/UsersTable.tsx b/src/components/UsersTable.tsx index e8729a9d..d6b6e610 100644 --- a/src/components/UsersTable.tsx +++ b/src/components/UsersTable.tsx @@ -19,6 +19,7 @@ import Link from "next/link"; import { useRouter } from "next/navigation"; import { formatAxiosError } from "@app/lib/api"; import { createApiClient } from "@app/lib/api"; +import { getUserDisplayName } from "@app/lib/getUserDisplayName"; import { useEnvContext } from "@app/hooks/useEnvContext"; import { useUserContext } from "@app/hooks/useUserContext"; import { useTranslations } from "next-intl"; @@ -271,10 +272,13 @@ export default function UsersTable({ users: u }: UsersTableProps) { buttonText={t("userRemoveOrgConfirm")} onConfirm={removeUser} string={ - selectedUser?.email || - selectedUser?.name || - selectedUser?.username || - "" + selectedUser + ? getUserDisplayName({ + email: selectedUser.email, + name: selectedUser.name, + username: selectedUser.username + }) + : "" } title={t("userRemoveOrg")} /> diff --git a/src/lib/getUserDisplayName.ts b/src/lib/getUserDisplayName.ts new file mode 100644 index 00000000..e95096c1 --- /dev/null +++ b/src/lib/getUserDisplayName.ts @@ -0,0 +1,36 @@ +import { GetUserResponse } from "@server/routers/user"; + +type UserDisplayNameInput = + | { + user: GetUserResponse; + } + | { + email?: string | null; + name?: string | null; + username?: string | null; + }; + +/** + * Gets the display name for a user. + * Priority: email > name > username + * + * @param input - Either a user object or individual email, name, username properties + * @returns The display name string + */ +export function getUserDisplayName(input: UserDisplayNameInput): string { + let email: string | null | undefined; + let name: string | null | undefined; + let username: string | null | undefined; + + if ("user" in input) { + email = input.user.email; + name = input.user.name; + username = input.user.username; + } else { + email = input.email; + name = input.name; + username = input.username; + } + + return email || name || username || ""; +} diff --git a/src/lib/queries.ts b/src/lib/queries.ts index de2dc64a..d016ec77 100644 --- a/src/lib/queries.ts +++ b/src/lib/queries.ts @@ -340,6 +340,7 @@ export type ApprovalItem = { name: string | null; userId: string; username: string; + email: string | null; }; };