57 lines
2.1 KiB
TypeScript
Executable File
57 lines
2.1 KiB
TypeScript
Executable File
import React, { memo } from 'react';
|
|
import type { ResultDetail } from '../types';
|
|
import CheckIcon from './CheckIcon';
|
|
import XCircleIcon from './XCircleIcon';
|
|
|
|
interface UserResultItemProps {
|
|
detail: ResultDetail;
|
|
onErrorClick: (details: string) => void;
|
|
}
|
|
|
|
const UserResultItem: React.FC<UserResultItemProps> = ({ detail, onErrorClick }) => {
|
|
const isSuccess = detail.status === 'success';
|
|
const hasErrorDetails = !isSuccess && detail.errorDetails;
|
|
|
|
// Check if message contains "Đã có quyền" - should be yellow/warning
|
|
const isAlreadyHasPermission = isSuccess && detail.message?.includes('Đã có quyền');
|
|
|
|
// Determine status color: error=red, already has=yellow, success=green
|
|
const statusColor = !isSuccess
|
|
? 'text-rose-400'
|
|
: isAlreadyHasPermission
|
|
? 'text-amber-400'
|
|
: 'text-green-400';
|
|
const Icon = isSuccess ? CheckIcon : XCircleIcon;
|
|
|
|
const renderStatus = (className?: string) => {
|
|
const commonClasses = `flex items-center gap-2 ${statusColor}`;
|
|
if (hasErrorDetails) {
|
|
return (
|
|
<button
|
|
onClick={() => onErrorClick(detail.errorDetails!)}
|
|
className={`${commonClasses} hover:underline ${className || ''}`}
|
|
>
|
|
<Icon className="w-4 h-4 flex-shrink-0" />
|
|
<span className="text-xs">{detail.message}</span>
|
|
</button>
|
|
)
|
|
}
|
|
return (
|
|
<div className={`${commonClasses} ${className || ''}`}>
|
|
<Icon className="w-4 h-4 flex-shrink-0" />
|
|
<span className="text-xs">{detail.message}</span>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="grid grid-cols-1 sm:grid-cols-10 gap-x-4 gap-y-1 items-center p-2 rounded-md hover:bg-slate-700/30 font-mono text-sm">
|
|
<div className="truncate text-slate-300 sm:col-span-4" title={detail.username}>
|
|
{detail.username}
|
|
</div>
|
|
{renderStatus('sm:col-span-6')}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default memo(UserResultItem); |