mirror of
https://github.com/fosrl/pangolin.git
synced 2026-01-28 22:00:51 +00:00
use display name function
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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})` : ""}`
|
||||
}))
|
||||
);
|
||||
|
||||
|
||||
@@ -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 (
|
||||
<>
|
||||
<SettingsSectionTitle
|
||||
title={`${user?.email || user?.name || user?.username}`}
|
||||
title={
|
||||
user
|
||||
? getUserDisplayName({
|
||||
email: user.email,
|
||||
name: user.name,
|
||||
username: user.username
|
||||
})
|
||||
: ""
|
||||
}
|
||||
description={t("userDescription2")}
|
||||
/>
|
||||
<HorizontalTabs items={navItems}>{children}</HorizontalTabs>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { verifySession } from "@app/lib/auth/verifySession";
|
||||
import { redirect } from "next/navigation";
|
||||
import DeviceLoginForm from "@/components/DeviceLoginForm";
|
||||
import { getUserDisplayName } from "@app/lib/getUserDisplayName";
|
||||
import { cache } from "react";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
@@ -24,7 +25,12 @@ export default async function DeviceLoginPage({ searchParams }: Props) {
|
||||
);
|
||||
}
|
||||
|
||||
const userName = user?.name || user?.username || "";
|
||||
const userName = user
|
||||
? getUserDisplayName({
|
||||
name: user.name,
|
||||
username: user.username
|
||||
})
|
||||
: "";
|
||||
|
||||
return (
|
||||
<DeviceLoginForm
|
||||
|
||||
@@ -11,6 +11,7 @@ import ConfirmDeleteDialog from "@app/components/ConfirmDeleteDialog";
|
||||
import { toast } from "@app/hooks/useToast";
|
||||
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 { useTranslations } from "next-intl";
|
||||
import {
|
||||
@@ -321,10 +322,13 @@ export default function UsersTable({ users }: Props) {
|
||||
<div className="space-y-2">
|
||||
<p>
|
||||
{t("userQuestionRemove", {
|
||||
selectedUser:
|
||||
selected?.email ||
|
||||
selected?.name ||
|
||||
selected?.username
|
||||
selectedUser: selected
|
||||
? getUserDisplayName({
|
||||
email: selected.email,
|
||||
name: selected.name,
|
||||
username: selected.username
|
||||
})
|
||||
: ""
|
||||
})}
|
||||
</p>
|
||||
|
||||
@@ -337,9 +341,11 @@ export default function UsersTable({ users }: Props) {
|
||||
}
|
||||
buttonText={t("userDeleteConfirm")}
|
||||
onConfirm={async () => deleteUser(selected!.id)}
|
||||
string={
|
||||
selected.email || selected.name || selected.username
|
||||
}
|
||||
string={getUserDisplayName({
|
||||
email: selected.email,
|
||||
name: selected.name,
|
||||
username: selected.username
|
||||
})}
|
||||
title={t("userDeleteServer")}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
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 { cn } from "@app/lib/cn";
|
||||
import {
|
||||
approvalFiltersSchema,
|
||||
@@ -185,7 +186,11 @@ function ApprovalRequest({ approval, orgId, onSuccess }: ApprovalRequestProps) {
|
||||
<LaptopMinimal className="size-4 text-muted-foreground flex-none relative top-2 sm:top-0" />
|
||||
<span>
|
||||
<span className="text-primary">
|
||||
{approval.user.username}
|
||||
{getUserDisplayName({
|
||||
email: approval.user.email,
|
||||
name: approval.user.name,
|
||||
username: approval.user.username
|
||||
})}
|
||||
</span>
|
||||
|
||||
{approval.type === "user_device" && (
|
||||
|
||||
@@ -46,6 +46,7 @@ import { Switch } from "@app/components/ui/switch";
|
||||
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 { cn } from "@app/lib/cn";
|
||||
import { orgQueries } from "@app/lib/queries";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
@@ -270,7 +271,10 @@ export default function CreateInternalResourceDialog({
|
||||
|
||||
const allUsers = usersResponse.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})` : ""}`
|
||||
}));
|
||||
|
||||
const allClients = clientsResponse
|
||||
|
||||
@@ -36,6 +36,7 @@ import {
|
||||
import { toast } from "@app/hooks/useToast";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { createApiClient, formatAxiosError } from "@app/lib/api";
|
||||
import { getUserDisplayName } from "@app/lib/getUserDisplayName";
|
||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||
import { Tag, TagInput } from "@app/components/tags/tag-input";
|
||||
import { UserType } from "@server/types/UserTypes";
|
||||
@@ -304,7 +305,10 @@ export default function EditInternalResourceDialog({
|
||||
|
||||
const allUsers = (usersQuery.data ?? []).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})` : ""}`
|
||||
}));
|
||||
|
||||
const machineClients = (clientsQuery.data ?? [])
|
||||
@@ -330,7 +334,10 @@ export default function EditInternalResourceDialog({
|
||||
|
||||
const formUsers = (resourceUsersQuery.data ?? []).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})` : ""}`
|
||||
}));
|
||||
|
||||
return {
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||
import { toast } from "@app/hooks/useToast";
|
||||
import { formatAxiosError } from "@app/lib/api";
|
||||
import { getUserDisplayName } from "@app/lib/getUserDisplayName";
|
||||
import { Laptop, LogOut, Moon, Sun, Smartphone } from "lucide-react";
|
||||
import { useTheme } from "next-themes";
|
||||
import { useRouter } from "next/navigation";
|
||||
@@ -49,9 +50,8 @@ export default function ProfileIcon() {
|
||||
const t = useTranslations();
|
||||
|
||||
function getInitials() {
|
||||
return (user.email || user.name || user.username)
|
||||
.substring(0, 1)
|
||||
.toUpperCase();
|
||||
const displayName = getUserDisplayName({ user });
|
||||
return displayName.substring(0, 1).toUpperCase();
|
||||
}
|
||||
|
||||
function handleThemeChange(theme: "light" | "dark" | "system") {
|
||||
@@ -109,7 +109,7 @@ export default function ProfileIcon() {
|
||||
{t("signingAs")}
|
||||
</p>
|
||||
<p className="text-xs leading-none text-muted-foreground">
|
||||
{user.email || user.name || user.username}
|
||||
{getUserDisplayName({ user })}
|
||||
</p>
|
||||
</div>
|
||||
{user.serverAdmin ? (
|
||||
|
||||
@@ -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}`}
|
||||
>
|
||||
<Button variant="outline">
|
||||
{r.userEmail || r.username || r.userId}
|
||||
{getUserDisplayName({
|
||||
email: r.userEmail,
|
||||
username: r.username
|
||||
}) || r.userId}
|
||||
<ArrowUpRight className="ml-2 h-4 w-4" />
|
||||
</Button>
|
||||
</Link>
|
||||
|
||||
@@ -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")}
|
||||
/>
|
||||
|
||||
36
src/lib/getUserDisplayName.ts
Normal file
36
src/lib/getUserDisplayName.ts
Normal file
@@ -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 || "";
|
||||
}
|
||||
@@ -340,6 +340,7 @@ export type ApprovalItem = {
|
||||
name: string | null;
|
||||
userId: string;
|
||||
username: string;
|
||||
email: string | null;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user