uchill/front_material/components/chat/NewChatModal.tsx

146 lines
4.5 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Модальное окно для создания нового чата
*/
'use client';
import React, { useState, useEffect } from 'react';
import {
Box,
Typography,
TextField,
List,
ListItemButton,
ListItemText,
Avatar,
Dialog,
DialogTitle,
DialogContent,
IconButton,
CircularProgress
} from '@mui/material';
import CloseRoundedIcon from '@mui/icons-material/CloseRounded';
import apiClient from '@/lib/api-client';
import { createChat } from '@/api/chat';
import { LoadingSpinner } from '../common/LoadingSpinner';
interface User {
id: number;
email: string;
first_name?: string;
last_name?: string;
avatar_url?: string | null;
role: string;
}
interface NewChatModalProps {
isOpen: boolean;
onClose: () => void;
onChatCreated: (chat: any) => void;
}
export function NewChatModal({ isOpen, onClose, onChatCreated }: NewChatModalProps) {
const [search, setSearch] = useState('');
const [users, setUsers] = useState<User[]>([]);
const [loading, setLoading] = useState(false);
const [creating, setCreating] = useState(false);
useEffect(() => {
if (isOpen) {
loadContacts();
}
}, [isOpen, search]);
const loadContacts = async () => {
setLoading(true);
try {
const response = await apiClient.get<any>(`/users/contacts/?search=${encodeURIComponent(search)}`);
setUsers(response.data.results || response.data || []);
} catch (error) {
console.error('Failed to load contacts:', error);
} finally {
setLoading(false);
}
};
const handleCreateChat = async (userId: number) => {
setCreating(userId as any);
try {
const response = await apiClient.post<any>('/chat/chats/create_direct/', { user_id: userId });
const chat = response.data.data || response.data;
onChatCreated(chat);
onClose();
} catch (error) {
console.error('Failed to create chat:', error);
} finally {
setCreating(false);
}
};
return (
<Dialog
open={isOpen}
onClose={onClose}
fullWidth
maxWidth="xs"
PaperProps={{
sx: {
borderRadius: '24px',
background: 'var(--md-sys-color-surface)',
boxShadow: '0 8px 32px rgba(0,0,0,0.12)',
}
}}
>
<DialogTitle sx={{ m: 0, p: 2, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<Typography variant="h6" component="span" sx={{ fontWeight: 700 }}>Новый чат</Typography>
<IconButton onClick={onClose} size="small">
<CloseRoundedIcon />
</IconButton>
</DialogTitle>
<DialogContent sx={{ p: 2, pt: 0 }}>
<TextField
fullWidth
placeholder="Поиск контактов..."
value={search}
onChange={(e) => setSearch(e.target.value)}
size="small"
sx={{ mb: 2 }}
/>
{loading && users.length === 0 ? (
<Box sx={{ display: 'flex', justifyContent: 'center', py: 4 }}>
<CircularProgress size={24} />
</Box>
) : users.length === 0 ? (
<Typography sx={{ textAlign: 'center', py: 4, color: 'text.secondary' }}>
Контакты не найдены
</Typography>
) : (
<List sx={{ pt: 0 }}>
{users.map((user) => (
<ListItemButton
key={user.id}
onClick={() => handleCreateChat(user.id)}
disabled={creating === (user.id as any)}
sx={{ borderRadius: '12px', mb: 0.5 }}
>
<Avatar
src={user.avatar_url || undefined}
sx={{ mr: 1.5, bgcolor: 'var(--md-sys-color-primary-container)', color: 'var(--md-sys-color-on-primary-container)' }}
>
{user.first_name?.[0] || user.email[0].toUpperCase()}
</Avatar>
<ListItemText
primary={`${user.first_name || ''} ${user.last_name || ''}`.trim() || user.email}
secondary={user.role === 'mentor' ? 'Ментор' : user.role === 'client' ? 'Студент' : 'Родитель'}
/>
{creating === (user.id as any) && <CircularProgress size={16} />}
</ListItemButton>
))}
</List>
)}
</DialogContent>
</Dialog>
);
}