platform/lms-adm-fe release promotion snapshot
This commit is contained in:
@@ -179,7 +179,7 @@ export function InstructorChatPanel({ session, open, initialThreadId = null, ini
|
||||
) : threads.length > 0 ? (
|
||||
<div className="space-y-2.5">
|
||||
{threads.map((thread) => (
|
||||
<ThreadCard key={thread.id} accessToken={session.accessToken} thread={thread} onOpen={() => handleOpenThread(thread.id)} />
|
||||
<ThreadCard key={thread.id} thread={thread} onOpen={() => handleOpenThread(thread.id)} />
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
@@ -192,7 +192,7 @@ export function InstructorChatPanel({ session, open, initialThreadId = null, ini
|
||||
);
|
||||
}
|
||||
|
||||
function ThreadCard({ accessToken, thread, onOpen }: { accessToken: string; thread: InstructorChatThread; onOpen: () => void }) {
|
||||
function ThreadCard({ thread, onOpen }: { thread: InstructorChatThread; onOpen: () => void }) {
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
@@ -201,7 +201,7 @@ function ThreadCard({ accessToken, thread, onOpen }: { accessToken: string; thre
|
||||
onClick={onOpen}
|
||||
>
|
||||
<div className="flex items-start gap-3">
|
||||
<StudentAvatar accessToken={accessToken} thread={thread} />
|
||||
<StudentAvatar thread={thread} />
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="flex items-center gap-2">
|
||||
<p className="truncate text-[14px] font-black text-[#111827]">{thread.studentName}</p>
|
||||
@@ -222,43 +222,17 @@ function ThreadCard({ accessToken, thread, onOpen }: { accessToken: string; thre
|
||||
);
|
||||
}
|
||||
|
||||
function StudentAvatar({ accessToken, thread }: { accessToken: string; thread: InstructorChatThread }) {
|
||||
const [avatarSource, setAvatarSource] = useState<string | null>(null);
|
||||
function StudentAvatar({ thread }: { thread: InstructorChatThread }) {
|
||||
const [avatarFailed, setAvatarFailed] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!thread.studentAvatarUrl) {
|
||||
setAvatarSource(null);
|
||||
return;
|
||||
}
|
||||
|
||||
let revoked = false;
|
||||
let objectUrl: string | null = null;
|
||||
|
||||
fetch(thread.studentAvatarUrl, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
},
|
||||
})
|
||||
.then((response) => (response.ok ? response.blob() : null))
|
||||
.then((blob) => {
|
||||
if (!blob || revoked) return;
|
||||
objectUrl = URL.createObjectURL(blob);
|
||||
setAvatarSource(objectUrl);
|
||||
})
|
||||
.catch(() => {
|
||||
if (!revoked) setAvatarSource(null);
|
||||
});
|
||||
|
||||
return () => {
|
||||
revoked = true;
|
||||
if (objectUrl) URL.revokeObjectURL(objectUrl);
|
||||
};
|
||||
}, [accessToken, thread.studentAvatarUrl]);
|
||||
setAvatarFailed(false);
|
||||
}, [thread.studentAvatarUrl]);
|
||||
|
||||
return (
|
||||
<span className="grid h-10 w-10 shrink-0 place-items-center overflow-hidden rounded-full bg-[#eef2ff] text-[#4f46e5] transition group-hover:bg-[#4f46e5] group-hover:text-white">
|
||||
{avatarSource ? (
|
||||
<img className="h-full w-full object-cover" src={avatarSource} alt="" />
|
||||
{thread.studentAvatarUrl && !avatarFailed ? (
|
||||
<img className="h-full w-full object-cover" src={thread.studentAvatarUrl} alt="" onError={() => setAvatarFailed(true)} />
|
||||
) : (
|
||||
<UserRound size={18} aria-hidden="true" />
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user