Архитектура

This commit is contained in:
Халимов Рустам
2026-03-21 02:19:38 +03:00
parent f3e0941647
commit 5da1a2f45d
44 changed files with 826 additions and 380 deletions
@@ -127,9 +127,23 @@ export default function UserProfile({ userId, chatId, onClose, onGoToMessage, is
createdAt: msg.createdAt
})));
const isMediaGif = (m: any) => {
if (m.type === 'gif') return true;
if (m.url?.toLowerCase().includes('klipy') || m.url?.toLowerCase().endsWith('.gif')) return true;
if (m.filename?.toLowerCase().includes('gif')) return true;
if (m.type === 'image' && m.url?.toLowerCase().endsWith('.mp4')) return true;
return false;
};
const pureMedia = allMedia.filter(m => !isMediaGif(m));
const combinedGifsSet = new Map();
allGifs.forEach(m => combinedGifsSet.set(m.id, m));
allMedia.filter(isMediaGif).forEach(m => combinedGifsSet.set(m.id, m));
const pureGifs = Array.from(combinedGifsSet.values());
const sortedStories = [...userStories].sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
const sortedMedia = [...allMedia].sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
const sortedGifs = [...allGifs].sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
const sortedMedia = [...pureMedia].sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
const sortedGifs = [...pureGifs].sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
const sortedFiles = [...sharedFiles].sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
const sortedLinks = [...sharedLinks].sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
@@ -355,8 +369,9 @@ export default function UserProfile({ userId, chatId, onClose, onGoToMessage, is
const tabsConfig = [
{ key: 'publications' as const, label: t('publicationsTab') || 'Публикации', icon: Play, count: sortedStories.length },
...(chatId ? [
...(chatId && !isSelf ? [
{ key: 'media' as const, label: t('mediaTab'), icon: ImageIcon, count: sortedMedia.length },
{ key: 'gifs' as const, label: 'GIF', icon: Play, count: sortedGifs.length },
{ key: 'files' as const, label: t('filesTab'), icon: FileText, count: sortedFiles.flatMap(msg => msg.media || []).length },
{ key: 'links' as const, label: t('linksTab'), icon: LinkIcon, count: sortedLinks.flatMap(msg => msg.links || []).length },
] : []),
@@ -831,6 +846,34 @@ export default function UserProfile({ userId, chatId, onClose, onGoToMessage, is
<p className="text-xs text-zinc-600 italic">{t('sharedPhotos') as string}</p>
</div>
)
) : activeTab === 'gifs' ? (
sortedGifs.length > 0 ? (
renderGrouped(sortedGifs as any[], (m, idx) => (
<div
key={m.id}
className="relative aspect-square bg-zinc-900 overflow-hidden group cursor-pointer"
>
<video
src={getMediaUrl(m.url)}
autoPlay
loop
muted
playsInline
className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-200"
/>
<button
onClick={(e) => { e.stopPropagation(); onGoToMessage?.(m.messageId); }}
className="absolute bottom-2 right-2 px-2 py-1 rounded-md bg-black/60 backdrop-blur-sm flex items-center justify-center text-white text-[10px] font-medium opacity-0 group-hover:opacity-100 transition-opacity hover:bg-black/80 shadow-md"
>
{t('showInChat')}
</button>
</div>
), "grid grid-cols-3 gap-0.5 px-1")
) : (
<div className="flex items-center justify-center py-8">
<p className="text-xs text-zinc-600 italic">GIF не найдены</p>
</div>
)
) : activeTab === 'files' ? (
sortedFiles.length > 0 ? (
renderGrouped(sortedFiles, (msg, idx) => (