feat: Initialize the Electron frontend with core UI components and integrate Convex backend services.

This commit is contained in:
Bryan1029384756
2026-02-10 18:29:42 -06:00
parent 34e9790db9
commit 17790afa9b
64 changed files with 149216 additions and 628 deletions

View File

@@ -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>
);
};