Миграции, сборка

This commit is contained in:
Халимов Рустам
2026-03-27 23:09:16 +03:00
parent 030ae1e4e4
commit ba5c5210d4
43 changed files with 406 additions and 194 deletions

View File

@@ -95,7 +95,14 @@ export interface Message {
isDeleted?: boolean;
quote?: string | null;
media?: MediaItem[];
sender: { id: string; username: string; displayName: string };
sender: {
id: string;
username: string;
userName?: string;
displayName: string;
avatar?: string | null;
avatarUrl?: string | null;
};
} | null;
forwardedFrom?: UserBasic | null;
media: MediaItem[];

View File

@@ -135,7 +135,7 @@ export default function SideMenu({ isOpen, onClose, onOpenProfile }: SideMenuPro
onClose();
};
const initials = (user?.displayName || user?.username || '??')
const initials = (user?.displayName || user?.userName || user?.username || '??')
.split(' ')
.map((w: string) => w[0])
.join('')
@@ -193,11 +193,11 @@ export default function SideMenu({ isOpen, onClose, onOpenProfile }: SideMenuPro
</div>
{/* Name & username */}
<h3 className="text-xl font-bold text-transparent bg-clip-text bg-gradient-to-b from-white to-white/70 tracking-tight leading-tight">
{user?.displayName || user?.username}
{user?.displayName || user?.userName || user?.username || ''}
</h3>
<div className="flex items-center gap-1.5 mt-1.5">
<AtSign size={12} className="text-knot-400" />
<span className="text-sm font-medium text-knot-100/70">{user?.username}</span>
<span className="text-sm font-medium text-knot-100/70">{user?.userName || user?.username || ''}</span>
</div>
</div>
{/* Bottom fade line */}
@@ -526,8 +526,8 @@ export default function SideMenu({ isOpen, onClose, onOpenProfile }: SideMenuPro
</div>
)}
<div className="flex-1 min-w-0">
<p className="text-sm font-medium text-white truncate">{u.displayName || u.username}</p>
<p className="text-xs text-zinc-500">@{u.username}</p>
<p className="text-sm font-medium text-white truncate">{u.displayName || u.userName || u.username || ''}</p>
<p className="text-xs text-zinc-500">@{u.userName || u.username || ''}</p>
</div>
<button
onClick={() => handleSendFriendRequest(u.id)}
@@ -561,8 +561,8 @@ export default function SideMenu({ isOpen, onClose, onOpenProfile }: SideMenuPro
</div>
)}
<div className="flex-1 min-w-0">
<p className="text-sm font-medium text-white truncate">{req.user.displayName || req.user.username}</p>
<p className="text-xs text-zinc-500">@{req.user.username}</p>
<p className="text-sm font-medium text-white truncate">{req.user.displayName || req.user.userName || req.user.username || ''}</p>
<p className="text-xs text-zinc-500">@{req.user.userName || req.user.username || ''}</p>
</div>
<div className="flex gap-1.5">
<button
@@ -610,9 +610,9 @@ export default function SideMenu({ isOpen, onClose, onOpenProfile }: SideMenuPro
)}
</div>
<div className="flex-1 min-w-0">
<p className="text-sm font-medium text-white truncate">{friend.displayName || friend.username}</p>
<p className="text-sm font-medium text-white truncate">{friend.displayName || friend.userName || friend.username || ''}</p>
<p className="text-xs text-zinc-500">
{friend.isOnline ? t('online') : `@${friend.username}`}
{friend.isOnline ? t('online') : `@${friend.userName || friend.username || ''}`}
</p>
</div>
<button

View File

@@ -74,7 +74,7 @@ export default function Sidebar() {
(m) =>
m.user.id !== user?.id &&
((m.user.username || m.user.userName || '').toLowerCase().includes(q) ||
m.user.displayName.toLowerCase().includes(q))
(m.user.displayName || '').toLowerCase().includes(q))
);
}).sort((a, b) => {
// 1. Favorites chat always on top
@@ -82,8 +82,8 @@ export default function Sidebar() {
if (b.type === 'favorites') return 1;
// 2. Pinned chats next
const aPinned = a.members.find(m => m.user.id === user?.id)?.isPinned;
const bPinned = b.members.find(m => m.user.id === user?.id)?.isPinned;
const aPinned = a.members.find(m => m.user.id === user?.id)?.isPinned ?? false;
const bPinned = b.members.find(m => m.user.id === user?.id)?.isPinned ?? false;
if (aPinned && !bPinned) return -1;
if (!aPinned && bPinned) return 1;
@@ -182,13 +182,13 @@ export default function Sidebar() {
<div className="w-[44px] h-[44px] rounded-full flex items-center justify-center overflow-hidden">
<Avatar
src={avatarUrl}
name={group.user.displayName || group.user.username}
name={group.user.displayName || group.user.userName || group.user.username || '?'}
size="md"
/>
</div>
</div>
<span className="text-[11px] text-zinc-400 truncate w-full text-center">
{isMine ? t('myStory') : (group.user.displayName || group.user.userName || group.user.username || '').split(' ')[0]}
{isMine ? t('myStory') : (group.user.displayName || group.user.userName || group.user.username || '?').split(' ')[0]}
</span>
</button>
);
@@ -218,7 +218,7 @@ export default function Sidebar() {
{showNewChat && <NewChatModal onClose={() => setShowNewChat(false)} />}
</AnimatePresence>
<AnimatePresence>
{showProfile && <UserProfile userId={user!.id} onClose={() => setShowProfile(false)} isSelf />}
{showProfile && user && <UserProfile userId={user.id} onClose={() => setShowProfile(false)} isSelf />}
</AnimatePresence>
<SideMenu
isOpen={showSideMenu}