Архитектура
This commit is contained in:
@@ -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) => (
|
||||
|
||||
Reference in New Issue
Block a user