feat: Initialize the Electron frontend with core UI components and integrate Convex backend services.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import React, { useState, useEffect, useCallback } from 'react';
|
||||
import React, { useState, useEffect, useCallback, useRef } from 'react';
|
||||
import { useQuery, useConvex } from 'convex/react';
|
||||
import { api } from '../../../../convex/_generated/api';
|
||||
import Sidebar from '../components/Sidebar';
|
||||
@@ -6,6 +6,9 @@ import ChatArea from '../components/ChatArea';
|
||||
import VoiceStage from '../components/VoiceStage';
|
||||
import { useVoice } from '../contexts/VoiceContext';
|
||||
import FriendsView from '../components/FriendsView';
|
||||
import MembersList from '../components/MembersList';
|
||||
import ChatHeader from '../components/ChatHeader';
|
||||
import { useToasts } from '../components/Toast';
|
||||
|
||||
const Chat = () => {
|
||||
const [view, setView] = useState('server');
|
||||
@@ -14,8 +17,29 @@ const Chat = () => {
|
||||
const [userId, setUserId] = useState(null);
|
||||
const [channelKeys, setChannelKeys] = useState({});
|
||||
const [activeDMChannel, setActiveDMChannel] = useState(null);
|
||||
const [showMembers, setShowMembers] = useState(true);
|
||||
const [showPinned, setShowPinned] = useState(false);
|
||||
|
||||
const convex = useConvex();
|
||||
const { toasts, addToast, removeToast, ToastContainer } = useToasts();
|
||||
const prevDmChannelsRef = useRef(null);
|
||||
const { toggleMute } = useVoice();
|
||||
|
||||
// Keyboard shortcuts
|
||||
useEffect(() => {
|
||||
const handler = (e) => {
|
||||
if (e.ctrlKey && e.key === 'k') {
|
||||
e.preventDefault();
|
||||
// Quick switcher placeholder - could open a search modal
|
||||
}
|
||||
if (e.ctrlKey && e.shiftKey && e.key === 'M') {
|
||||
e.preventDefault();
|
||||
toggleMute();
|
||||
}
|
||||
};
|
||||
window.addEventListener('keydown', handler);
|
||||
return () => window.removeEventListener('keydown', handler);
|
||||
}, [toggleMute]);
|
||||
|
||||
const channels = useQuery(api.channels.list) || [];
|
||||
|
||||
@@ -113,20 +137,46 @@ const Chat = () => {
|
||||
}
|
||||
}, [convex]);
|
||||
|
||||
const handleSelectChannel = useCallback((channelId) => {
|
||||
setActiveChannel(channelId);
|
||||
setShowPinned(false);
|
||||
}, []);
|
||||
|
||||
const activeChannelObj = channels.find(c => c._id === activeChannel);
|
||||
const { room, voiceStates } = useVoice();
|
||||
|
||||
const isDMView = view === 'me' && activeDMChannel;
|
||||
const isServerTextChannel = view === 'server' && activeChannel && activeChannelObj?.type !== 'voice';
|
||||
const currentChannelId = isDMView ? activeDMChannel.channel_id : activeChannel;
|
||||
|
||||
function renderMainContent() {
|
||||
if (view === 'me') {
|
||||
if (activeDMChannel) {
|
||||
return (
|
||||
<ChatArea
|
||||
channelId={activeDMChannel.channel_id}
|
||||
channelName={activeDMChannel.other_username}
|
||||
channelKey={channelKeys[activeDMChannel.channel_id]}
|
||||
username={username}
|
||||
userId={userId}
|
||||
/>
|
||||
<div className="chat-container">
|
||||
<ChatHeader
|
||||
channelName={activeDMChannel.other_username}
|
||||
channelType="dm"
|
||||
onToggleMembers={() => {}}
|
||||
showMembers={false}
|
||||
onTogglePinned={() => setShowPinned(p => !p)}
|
||||
/>
|
||||
<div className="chat-content">
|
||||
<ChatArea
|
||||
channelId={activeDMChannel.channel_id}
|
||||
channelName={activeDMChannel.other_username}
|
||||
channelType="dm"
|
||||
channelKey={channelKeys[activeDMChannel.channel_id]}
|
||||
username={username}
|
||||
userId={userId}
|
||||
showMembers={false}
|
||||
onToggleMembers={() => {}}
|
||||
onOpenDM={openDM}
|
||||
showPinned={showPinned}
|
||||
onTogglePinned={() => setShowPinned(false)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return <FriendsView onOpenDM={openDM} />;
|
||||
@@ -137,13 +187,37 @@ const Chat = () => {
|
||||
return <VoiceStage room={room} channelId={activeChannel} voiceStates={voiceStates} channelName={activeChannelObj?.name} />;
|
||||
}
|
||||
return (
|
||||
<ChatArea
|
||||
channelId={activeChannel}
|
||||
channelName={activeChannelObj?.name || activeChannel}
|
||||
channelKey={channelKeys[activeChannel]}
|
||||
username={username}
|
||||
userId={userId}
|
||||
/>
|
||||
<div className="chat-container">
|
||||
<ChatHeader
|
||||
channelName={activeChannelObj?.name || activeChannel}
|
||||
channelType="text"
|
||||
channelTopic={activeChannelObj?.topic}
|
||||
onToggleMembers={() => setShowMembers(!showMembers)}
|
||||
showMembers={showMembers}
|
||||
onTogglePinned={() => setShowPinned(p => !p)}
|
||||
serverName="Secure Chat"
|
||||
/>
|
||||
<div className="chat-content">
|
||||
<ChatArea
|
||||
channelId={activeChannel}
|
||||
channelName={activeChannelObj?.name || activeChannel}
|
||||
channelType="text"
|
||||
channelKey={channelKeys[activeChannel]}
|
||||
username={username}
|
||||
userId={userId}
|
||||
showMembers={showMembers}
|
||||
onToggleMembers={() => setShowMembers(!showMembers)}
|
||||
onOpenDM={openDM}
|
||||
showPinned={showPinned}
|
||||
onTogglePinned={() => setShowPinned(false)}
|
||||
/>
|
||||
<MembersList
|
||||
channelId={activeChannel}
|
||||
visible={showMembers}
|
||||
onMemberClick={(member) => {}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -161,7 +235,7 @@ const Chat = () => {
|
||||
<Sidebar
|
||||
channels={channels}
|
||||
activeChannel={activeChannel}
|
||||
onSelectChannel={setActiveChannel}
|
||||
onSelectChannel={handleSelectChannel}
|
||||
username={username}
|
||||
channelKeys={channelKeys}
|
||||
view={view}
|
||||
@@ -170,8 +244,10 @@ const Chat = () => {
|
||||
activeDMChannel={activeDMChannel}
|
||||
setActiveDMChannel={setActiveDMChannel}
|
||||
dmChannels={dmChannels}
|
||||
userId={userId}
|
||||
/>
|
||||
{renderMainContent()}
|
||||
<ToastContainer />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user