feat: Implement core chat functionality, shared components, and initial multi-platform project structure.
All checks were successful
Build and Release / build-and-release (push) Successful in 15m0s
All checks were successful
Build and Release / build-and-release (push) Successful in 15m0s
This commit is contained in:
@@ -1,10 +1,14 @@
|
||||
import React from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
import { useQuery } from 'convex/react';
|
||||
import { api } from '../../../../convex/_generated/api';
|
||||
import { useOnlineUsers } from '../contexts/PresenceContext';
|
||||
import Tooltip from './Tooltip';
|
||||
|
||||
const ChatHeader = ({
|
||||
channelName,
|
||||
channelType,
|
||||
channelTopic,
|
||||
channelId,
|
||||
onToggleMembers,
|
||||
showMembers,
|
||||
onTogglePinned,
|
||||
@@ -13,6 +17,7 @@ const ChatHeader = ({
|
||||
onMobileBack,
|
||||
onStartCall,
|
||||
isDMCallActive,
|
||||
onOpenMembersScreen,
|
||||
// Search props
|
||||
searchQuery,
|
||||
onSearchQueryChange,
|
||||
@@ -25,6 +30,18 @@ const ChatHeader = ({
|
||||
const isDM = channelType === 'dm';
|
||||
const searchPlaceholder = isDM ? 'Search' : `Search ${serverName || 'Server'}`;
|
||||
|
||||
// Query members on mobile text channels only for online count
|
||||
const shouldQueryMembers = isMobile && !isDM && channelId;
|
||||
const members = useQuery(
|
||||
api.members.getChannelMembers,
|
||||
shouldQueryMembers ? { channelId } : "skip"
|
||||
) || [];
|
||||
const { resolveStatus } = useOnlineUsers();
|
||||
const onlineCount = useMemo(() => {
|
||||
if (!shouldQueryMembers) return 0;
|
||||
return members.filter(m => resolveStatus(m.status, m.id) !== 'offline').length;
|
||||
}, [members, resolveStatus, shouldQueryMembers]);
|
||||
|
||||
const handleSearchKeyDown = (e) => {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
@@ -45,15 +62,33 @@ const ChatHeader = ({
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor"><path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"/></svg>
|
||||
</button>
|
||||
)}
|
||||
<span className="chat-header-icon">{isDM ? '@' : '#'}</span>
|
||||
<span className="chat-header-name">{channelName}</span>
|
||||
{channelTopic && !isDM && !isMobile && (
|
||||
{isMobile && !isDM ? (
|
||||
<button className="mobile-channel-header-tap" onClick={onOpenMembersScreen}>
|
||||
<div className="mobile-channel-header-top">
|
||||
<span className="chat-header-icon">#</span>
|
||||
<span className="chat-header-name">{channelName}</span>
|
||||
<svg className="mobile-channel-chevron" width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M9.29 6.71a1 1 0 0 0 0 1.41L13.17 12l-3.88 3.88a1 1 0 1 0 1.42 1.41l4.59-4.59a1 1 0 0 0 0-1.41L10.71 6.7a1 1 0 0 0-1.42 0Z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div className="mobile-channel-header-bottom">
|
||||
<span className="mobile-online-dot" />
|
||||
<span className="mobile-online-count">{onlineCount ?? 0} Online</span>
|
||||
</div>
|
||||
</button>
|
||||
) : (
|
||||
<>
|
||||
<div className="chat-header-divider" />
|
||||
<span className="chat-header-topic" title={channelTopic}>{channelTopic}</span>
|
||||
<span className="chat-header-icon">{isDM ? '@' : '#'}</span>
|
||||
<span className="chat-header-name">{channelName}</span>
|
||||
{channelTopic && !isDM && !isMobile && (
|
||||
<>
|
||||
<div className="chat-header-divider" />
|
||||
<span className="chat-header-topic" title={channelTopic}>{channelTopic}</span>
|
||||
</>
|
||||
)}
|
||||
{isDM && <span className="chat-header-status-text"></span>}
|
||||
</>
|
||||
)}
|
||||
{isDM && <span className="chat-header-status-text"></span>}
|
||||
</div>
|
||||
<div className="chat-header-right">
|
||||
{!isDM && !isMobile && (
|
||||
|
||||
Reference in New Issue
Block a user