238 lines
5.9 KiB
TypeScript
238 lines
5.9 KiB
TypeScript
import { useState } from 'react';
|
||
import styled from 'styled-components';
|
||
import { declension } from '../../utils/declension';
|
||
import type { User } from '../../types/user';
|
||
import { PersonModal } from './PersonModal';
|
||
|
||
interface FamilySectionProps {
|
||
users: User[];
|
||
availableTags: string[];
|
||
onChange: (users: User[]) => void;
|
||
}
|
||
|
||
export function FamilySection({
|
||
users,
|
||
availableTags,
|
||
onChange,
|
||
}: FamilySectionProps) {
|
||
const [editingIndex, setEditingIndex] = useState<number | null>(null);
|
||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||
|
||
function handleDelete(index: number) {
|
||
onChange(users.filter((_, userIndex) => userIndex !== index));
|
||
}
|
||
|
||
function handleSave(user: User) {
|
||
if (editingIndex === null) {
|
||
onChange([...users, user]);
|
||
} else {
|
||
onChange(users.map((item, index) => index === editingIndex ? user : item));
|
||
}
|
||
|
||
setIsModalOpen(false);
|
||
setEditingIndex(null);
|
||
}
|
||
|
||
return (
|
||
<>
|
||
<FamilyList>
|
||
{users.map((user, index) => (
|
||
<FamilyMember
|
||
key={`${user.name}-${index}`}
|
||
type="button"
|
||
onClick={() => {
|
||
setEditingIndex(index);
|
||
setIsModalOpen(true);
|
||
}}
|
||
>
|
||
<Avatar>
|
||
<img src={getAvatarSrc(user)} alt="" />
|
||
</Avatar>
|
||
|
||
<Info>
|
||
<Name>{user.name}</Name>
|
||
<Age>
|
||
{user.age} {declension(user.age, ['год', 'года', 'лет'])}
|
||
<b> • </b>
|
||
<span>{user.gender === 'm' ? 'Мужской' : 'Женский'}</span>
|
||
</Age>
|
||
</Info>
|
||
|
||
<DeleteButton
|
||
type="button"
|
||
onClick={event => {
|
||
event.stopPropagation();
|
||
handleDelete(index);
|
||
}}
|
||
>
|
||
×
|
||
</DeleteButton>
|
||
</FamilyMember>
|
||
))}
|
||
</FamilyList>
|
||
|
||
<AddWrapper>
|
||
<AddButton
|
||
type="button"
|
||
onClick={() => {
|
||
setEditingIndex(null);
|
||
setIsModalOpen(true);
|
||
}}
|
||
>
|
||
Добавить человека <span>+</span>
|
||
</AddButton>
|
||
</AddWrapper>
|
||
|
||
<PersonModal
|
||
isOpen={isModalOpen}
|
||
user={editingIndex === null ? null : users[editingIndex]}
|
||
availableTags={availableTags}
|
||
onClose={() => {
|
||
setIsModalOpen(false);
|
||
setEditingIndex(null);
|
||
}}
|
||
onSave={handleSave}
|
||
/>
|
||
</>
|
||
);
|
||
}
|
||
|
||
function getAvatarSrc(user: User): string {
|
||
if (user.age < 16) {
|
||
return user.gender === 'f'
|
||
? '/images/broc-girl.png'
|
||
: '/images/broc-boy.png';
|
||
}
|
||
|
||
return user.gender === 'f'
|
||
? '/images/broc-woman.png'
|
||
: '/images/broc-man.png';
|
||
}
|
||
|
||
const FamilyList = styled.div`
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 12px;
|
||
`;
|
||
|
||
const FamilyMember = styled.button`
|
||
width: 100%;
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 12px 16px;
|
||
border: 1px solid ${({ theme }) => theme.colors.border};
|
||
border-radius: 12px;
|
||
background: #fff;
|
||
transition: 0.2s;
|
||
cursor: pointer;
|
||
text-align: left;
|
||
|
||
&:hover {
|
||
border-color: #c0c0c0;
|
||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.02);
|
||
}
|
||
|
||
&:nth-child(n+1) ${() => Avatar} {
|
||
background-color: #CEE0FF;
|
||
}
|
||
|
||
&:nth-child(2n+2) ${() => Avatar} {
|
||
background-color: #E6F696;
|
||
}
|
||
|
||
&:nth-child(3n+3) ${() => Avatar} {
|
||
background-color: #fff488;
|
||
}
|
||
|
||
&:nth-child(4n+4) ${() => Avatar} {
|
||
background-color: #ffd623;
|
||
}
|
||
`;
|
||
|
||
const Avatar = styled.div`
|
||
width: 46px;
|
||
height: 46px;
|
||
border-radius: 50%;
|
||
background: #f8f9fa;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin-right: 14px;
|
||
overflow: hidden;
|
||
|
||
img {
|
||
max-width: 100%;
|
||
}
|
||
`;
|
||
|
||
const Info = styled.div`
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
`;
|
||
|
||
const Name = styled.div`
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
color: ${({ theme }) => theme.colors.darkGreen};
|
||
`;
|
||
|
||
const Age = styled.div`
|
||
font-size: 16px;
|
||
font-weight: 350;
|
||
color: ${({ theme }) => theme.colors.gray};
|
||
`;
|
||
|
||
const DeleteButton = styled.button`
|
||
color: #d1d5db;
|
||
cursor: pointer;
|
||
font-size: 18px;
|
||
padding: 0 8px;
|
||
transition: 0.2s;
|
||
background: transparent;
|
||
border: 0;
|
||
|
||
&:hover {
|
||
color: #e53935;
|
||
}
|
||
`;
|
||
|
||
const AddWrapper = styled.div`
|
||
width: 100%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
`;
|
||
|
||
const AddButton = styled.button`
|
||
padding: 18px 23px;
|
||
border-radius: 12px;
|
||
height: 52px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin-top: 14px;
|
||
color: ${({ theme }) => theme.colors.green};
|
||
font-size: 15px;
|
||
font-weight: 350;
|
||
cursor: pointer;
|
||
transition: 0.2s;
|
||
background-color: transparent;
|
||
border: 0;
|
||
|
||
&:hover {
|
||
background-color: #F7FBF6;
|
||
}
|
||
|
||
&:active,
|
||
&:focus {
|
||
background-color: #EEF8EB;
|
||
outline: none;
|
||
}
|
||
|
||
span {
|
||
font-size: 20px;
|
||
margin-left: 8px;
|
||
font-weight: 300;
|
||
}
|
||
`; |