Skip to content

Commit

Permalink
[frontend] Add online status to user avatar
Browse files Browse the repository at this point in the history
  • Loading branch information
usatie committed Jan 17, 2024
1 parent 4136ca2 commit 463a464
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 71 deletions.
11 changes: 2 additions & 9 deletions frontend/app/room/[id]/sidebar-item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import type {
RoomEntity,
UserOnRoomEntity,
} from "@/app/lib/dtos";
import { SmallAvatarSkeleton } from "@/app/ui/room/skeleton";
import { Avatar } from "@/app/ui/user/avatar";
import {
ContextMenu,
ContextMenuContent,
Expand All @@ -33,13 +33,6 @@ function truncateString(str: string | undefined, num: number): string {
return str.slice(0, num) + "...";
}

function Avatar({ avatarURL }: { avatarURL?: string }) {
if (!avatarURL) {
return <SmallAvatarSkeleton />;
}
return <img className="rounded-full w-6 h-6 object-cover" src={avatarURL} />;
}

export interface LeaveEvent {
userId: number;
roomId: number;
Expand Down Expand Up @@ -110,7 +103,7 @@ export default function SidebarItem({
{!isKicked && (
<ContextMenu>
<ContextMenuTrigger className="flex gap-2 items-center group hover:opacity-60">
<Avatar avatarURL={user.user.avatarURL} />
<Avatar avatarURL={user.user.avatarURL} size="small" />
<span className="text-muted-foreground text-sm whitespace-nowrap group-hover:text-primary">
{truncateString(user.user.name, 15)}
{room.accessLevel !== "DIRECT" && isUserOwner && " 👑"}
Expand Down
72 changes: 55 additions & 17 deletions frontend/app/ui/user/avatar.tsx
Original file line number Diff line number Diff line change
@@ -1,40 +1,78 @@
import { Skeleton } from "@/components/ui/skeleton";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
import Link from "next/link";

export type AvatarSize = "small" | "medium" | "large";

export function Avatar({
avatarURL,
size,
alt,
}: {
export interface Props {
avatarURL?: string;
size: AvatarSize;
href?: string;
alt?: string;
}) {
online?: boolean;
}

export function Avatar({ avatarURL, size, href, alt, online }: Props) {
let sizeClass = "";
let onlineStatusClass = online ? "bg-green-500 " : "bg-gray-500 ";
switch (size) {
case "small":
sizeClass = "h-6 w-6";
onlineStatusClass += "w-3 h-3 border-2";
break;
case "medium":
sizeClass = "h-10 w-10";
onlineStatusClass += "w-4 h-4 border-2";
break;
case "large":
sizeClass = "h-32 w-32";
sizeClass = "h-28 w-28";
onlineStatusClass += "w-8 h-8 border-4";
break;
default:
sizeClass = "h-10 w-10";
break;
throw new Error("Invalid size");
}
if (!avatarURL) {
return <Skeleton className={`flex-none rounded-full ${sizeClass}`} />;
} else {
return (
<img
className={`flex-none rounded-full object-cover ${sizeClass}`}
src={avatarURL}
alt={alt}
/>
);
}
const TooltipWrapper = ({ children }: { children: React.ReactNode }) =>
alt !== undefined ? (
<Tooltip>
<TooltipTrigger asChild>{children}</TooltipTrigger>
<TooltipContent>{alt}</TooltipContent>
</Tooltip>
) : (
children
);
const LinkWrapper = ({ children }: { children: React.ReactNode }) =>
href !== undefined ? <Link href={href}>{children}</Link> : children;
return (
<LinkWrapper>
<div className={`relative flex-none ${sizeClass}`}>
<TooltipProvider delayDuration={0}>
<TooltipWrapper>
<img
className={`rounded-full object-cover ${sizeClass}`}
src={avatarURL}
alt={alt}
/>
</TooltipWrapper>
<Tooltip>
<TooltipTrigger asChild>
<div
className={`absolute -bottom-[2px] -right-[2px] border-background rounded-full ${onlineStatusClass}`}
></div>
</TooltipTrigger>
<TooltipContent sideOffset={-2}>
{online ? "online" : "offline"}
</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
</LinkWrapper>
);
}
21 changes: 11 additions & 10 deletions frontend/app/ui/user/match-history.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { getMatchHistory } from "@/app/lib/actions";
import type { MatchDetailEntity } from "@/app/lib/dtos";
import Link from "next/link";
import { Avatar } from "./avatar";
import ProfileItem from "./profile-item";

Expand All @@ -17,17 +16,19 @@ function MatchDetailItem({
: "text-red-500"
: "";
return (
<Link href={`/user/${detail.user.id}`}>
<div className="flex flex-col gap-2">
<div className="flex gap-2 items-center">
<Avatar avatarURL={detail.user.avatarURL} size="medium" />
<div>{detail.user.name}</div>
<div className={`font-bold ${textColor}`}>
{detail.winLose} ({detail.score})
</div>
<div className="flex flex-col gap-2">
<div className="flex gap-2 items-center">
<Avatar
avatarURL={detail.user.avatarURL}
href={`/user/${detail.user.id}`}
size="medium"
/>
<div>{detail.user.name}</div>
<div className={`font-bold ${textColor}`}>
{detail.winLose} ({detail.score})
</div>
</div>
</Link>
</div>
);
}

Expand Down
11 changes: 8 additions & 3 deletions frontend/app/ui/user/user-list.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import type { PublicUserEntity } from "@/app/lib/dtos";
import { TooltipProvider } from "@/components/ui/tooltip";
import { AvatarSize } from "./avatar";
import UserTooltip from "./user-tool-tip";
import { Avatar, AvatarSize } from "./avatar";

export default function UserList({
users,
Expand All @@ -15,7 +14,13 @@ export default function UserList({
<div className="flex flex-wrap gap-2">
{users.length === 0 && <div>No users to display</div>}
{users.map((u) => (
<UserTooltip key={u.id} user={u} avatarSize={avatarSize} />
<Avatar
avatarURL={u.avatarURL}
size={avatarSize}
href={`/user/${u.id}`}
alt={u.name}
online={u.name === "Susami"}
/>
))}
</div>
</TooltipProvider>
Expand Down
32 changes: 0 additions & 32 deletions frontend/app/ui/user/user-tool-tip.tsx

This file was deleted.

0 comments on commit 463a464

Please sign in to comment.