vibe themes
All checks were successful
platform/bro-js/journal.pl/pipeline/head This commit looks good
All checks were successful
platform/bro-js/journal.pl/pipeline/head This commit looks good
This commit is contained in:
175
src/user-card/user-card.tsx
Normal file
175
src/user-card/user-card.tsx
Normal file
@@ -0,0 +1,175 @@
|
||||
import React from 'react';
|
||||
import { Box, useColorMode, Text } from '@chakra-ui/react';
|
||||
import { useThemeManager } from '../../hooks/useThemeManager';
|
||||
|
||||
interface UserCardProps {
|
||||
user: {
|
||||
id: string;
|
||||
name: string;
|
||||
photo?: string;
|
||||
role?: string;
|
||||
status?: 'online' | 'offline' | 'away';
|
||||
attendance?: number;
|
||||
};
|
||||
onClick?: () => void;
|
||||
showStatus?: boolean;
|
||||
showAttendance?: boolean;
|
||||
}
|
||||
|
||||
export const UserCard: React.FC<UserCardProps> = ({
|
||||
user,
|
||||
onClick,
|
||||
showStatus = false,
|
||||
showAttendance = false
|
||||
}) => {
|
||||
const { isLightVariant } = useThemeManager();
|
||||
|
||||
// Функция для определения цвета статуса онлайн
|
||||
const getStatusColor = (status: string) => {
|
||||
switch (status) {
|
||||
case 'online':
|
||||
return 'green.500';
|
||||
case 'away':
|
||||
return 'yellow.500';
|
||||
default:
|
||||
return 'gray.400';
|
||||
}
|
||||
};
|
||||
|
||||
// Функция для рендера индикатора посещаемости
|
||||
const renderAttendanceIndicator = (attendance: number) => {
|
||||
let color;
|
||||
let text;
|
||||
|
||||
if (attendance >= 90) {
|
||||
color = 'green.500';
|
||||
text = '✓✓✓';
|
||||
} else if (attendance >= 70) {
|
||||
color = 'green.400';
|
||||
text = '✓✓';
|
||||
} else if (attendance >= 50) {
|
||||
color = 'yellow.500';
|
||||
text = '✓';
|
||||
} else if (attendance >= 30) {
|
||||
color = 'orange.500';
|
||||
text = '⚠';
|
||||
} else {
|
||||
color = 'red.500';
|
||||
text = '✗';
|
||||
}
|
||||
|
||||
return (
|
||||
<Text
|
||||
fontSize="xs"
|
||||
color={color}
|
||||
position="absolute"
|
||||
bottom="8px"
|
||||
right="8px"
|
||||
>
|
||||
{text}
|
||||
</Text>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Box
|
||||
position="relative"
|
||||
borderRadius="md"
|
||||
overflow="hidden"
|
||||
boxShadow="sm"
|
||||
transition="transform 0.2s, box-shadow 0.2s"
|
||||
_hover={onClick ? {
|
||||
transform: 'translateY(-2px)',
|
||||
boxShadow: 'md',
|
||||
cursor: 'pointer'
|
||||
} : {}}
|
||||
onClick={onClick}
|
||||
bg={isLightVariant ? 'white' : 'gray.700'}
|
||||
p={3}
|
||||
>
|
||||
<Box
|
||||
position="relative"
|
||||
borderRadius="full"
|
||||
width="60px"
|
||||
height="60px"
|
||||
overflow="hidden"
|
||||
margin="0 auto 8px"
|
||||
>
|
||||
{user.photo ? (
|
||||
<Box
|
||||
as="img"
|
||||
src={user.photo}
|
||||
alt={user.name}
|
||||
width="100%"
|
||||
height="100%"
|
||||
objectFit="cover"
|
||||
/>
|
||||
) : (
|
||||
<Box
|
||||
width="100%"
|
||||
height="100%"
|
||||
bg="gray.300"
|
||||
display="flex"
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
fontSize="xl"
|
||||
fontWeight="bold"
|
||||
color="gray.600"
|
||||
>
|
||||
{user.name.charAt(0).toUpperCase()}
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{showStatus && user.status && (
|
||||
<Box
|
||||
position="absolute"
|
||||
bottom="2px"
|
||||
right="2px"
|
||||
width="12px"
|
||||
height="12px"
|
||||
borderRadius="full"
|
||||
bg={getStatusColor(user.status)}
|
||||
border="2px solid"
|
||||
borderColor={isLightVariant ? 'white' : 'gray.700'}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
<Text
|
||||
textAlign="center"
|
||||
fontWeight="medium"
|
||||
fontSize="sm"
|
||||
noOfLines={1}
|
||||
title={user.name}
|
||||
>
|
||||
{user.name}
|
||||
</Text>
|
||||
|
||||
{user.role && (
|
||||
<Text
|
||||
textAlign="center"
|
||||
fontSize="xs"
|
||||
color={isLightVariant ? 'gray.500' : 'gray.300'}
|
||||
noOfLines={1}
|
||||
>
|
||||
{user.role}
|
||||
</Text>
|
||||
)}
|
||||
|
||||
{showAttendance && typeof user.attendance === 'number' && renderAttendanceIndicator(user.attendance)}
|
||||
|
||||
{/* Дополнительные декоративные элементы в зависимости от темы */}
|
||||
<Box
|
||||
position="absolute"
|
||||
top={0}
|
||||
left={0}
|
||||
right={0}
|
||||
height="5px"
|
||||
background={isLightVariant ? 'rgba(255, 255, 255, 0.8)' : 'rgba(0, 0, 0, 0.6)'}
|
||||
borderTopLeftRadius="md"
|
||||
borderTopRightRadius="md"
|
||||
zIndex={1}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user