core v1
This commit is contained in:
50
management/src/components/StudentAvatar.tsx
Normal file
50
management/src/components/StudentAvatar.tsx
Normal file
@@ -0,0 +1,50 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
function normalizeAvatarUrl(raw?: string | null): string {
|
||||
const trimmed = raw?.trim() || '';
|
||||
if (!trimmed) return '';
|
||||
if (trimmed.startsWith('//')) return `https:${trimmed}`;
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
interface StudentAvatarProps {
|
||||
fullName: string;
|
||||
avatar?: string | null;
|
||||
isOnline?: boolean;
|
||||
size?: number;
|
||||
}
|
||||
|
||||
export const StudentAvatar: React.FC<StudentAvatarProps> = ({
|
||||
fullName,
|
||||
avatar,
|
||||
isOnline = false,
|
||||
size = 48,
|
||||
}) => {
|
||||
const [imgFailed, setImgFailed] = useState(false);
|
||||
const avatarUrl = normalizeAvatarUrl(avatar);
|
||||
const initial = fullName ? fullName.trim().charAt(0).toUpperCase() : 'S';
|
||||
const showImage = !!avatarUrl && !imgFailed;
|
||||
|
||||
useEffect(() => {
|
||||
setImgFailed(false);
|
||||
}, [avatarUrl]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`student-workspace-avatar ${isOnline ? 'online' : ''} ${showImage ? 'has-image' : ''}`}
|
||||
style={{ width: size, height: size, fontSize: size * 0.38 }}
|
||||
>
|
||||
{showImage ? (
|
||||
<img
|
||||
src={avatarUrl}
|
||||
alt={fullName}
|
||||
className="student-avatar-img"
|
||||
referrerPolicy="no-referrer"
|
||||
onError={() => setImgFailed(true)}
|
||||
/>
|
||||
) : (
|
||||
initial
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user