Files
vexplor_dev/frontend/components/messenger/UserAvatar.tsx
syc0123 403e5cae40 [RAPID] 메신저 기능 구현 및 UI/UX 개선
- 사용자 온라인 상태 표시 (온라인/자리비움/오프라인) 디스코드 스타일
- 채팅방별 알림 ON/OFF 토글 (Bell 아이콘, localStorage 저장)
- 파일 업로드 실시간 소켓 브로드캐스트 및 한글 파일명 깨짐 수정
- FAB 읽지않음 배지 버그 수정 (메신저 닫혀있을 때 markAsRead 차단)
- 타이핑 도트 애니메이션, 날짜 오늘/어제 표시
- 입력창 bordered box, DM 편집 버튼 숨김
- 메신저 설정 버튼 제거, 새 대화 시작하기 Empty state CTA
- useMessengerSocket 소켓 중복 생성 방지 (MessengerModal로 이동)

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>

[RAPID-micro] 추적 파일 정리 및 메신저 소소한 변경

- .omc/state/ 파일 git 추적 제거 (.gitignore 이미 설정됨)
- db/checkpoints/ gitignore 추가
- globals.css: 메신저 메시지 시간 폰트 스타일 추가
- useMessenger.ts: fileMimeType 필드 및 API_BASE_URL import 추가

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 12:20:43 +09:00

60 lines
1.5 KiB
TypeScript

"use client";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { cn } from "@/lib/utils";
export type UserStatus = "online" | "away" | "offline";
interface UserAvatarProps {
photo?: string | null;
name: string;
size?: "sm" | "md" | "lg";
status?: UserStatus;
/** @deprecated use status instead */
online?: boolean;
}
const sizeMap = {
sm: "h-7 w-7 text-xs",
md: "h-9 w-9 text-sm",
lg: "h-11 w-11 text-base",
};
const dotSizeMap = {
sm: "h-2.5 w-2.5",
md: "h-3 w-3",
lg: "h-3.5 w-3.5",
};
const statusColorMap: Record<UserStatus, string> = {
online: "bg-green-500",
away: "bg-yellow-400",
offline: "bg-gray-500",
};
export function UserAvatar({ photo, name, size = "md", status, online }: UserAvatarProps) {
// Resolve effective status (support legacy `online` prop)
const effectiveStatus: UserStatus | undefined =
status ?? (online === true ? "online" : online === false ? "offline" : undefined);
return (
<div className="relative inline-block shrink-0">
<Avatar className={cn(sizeMap[size])}>
{photo && <AvatarImage src={photo} alt={name} />}
<AvatarFallback className="bg-muted text-muted-foreground">
{name.charAt(0).toUpperCase()}
</AvatarFallback>
</Avatar>
{effectiveStatus !== undefined && (
<span
className={cn(
"absolute bottom-0 right-0 rounded-full border-2 border-background",
dotSizeMap[size],
statusColorMap[effectiveStatus]
)}
/>
)}
</div>
);
}