Core Features: - ✅ Authentication (login/register pages) - ✅ Main layout with sidebar - ✅ Channel list and navigation - ✅ Channel page with real-time messaging - ✅ Direct messages (DMs) page - ✅ Message components (list, input) - ✅ WebSocket integration for real-time updates - ✅ Typing indicators - ✅ Online status indicators - ✅ Stores (auth, channels, messages) - ✅ API client with JWT auth - ✅ Socket.IO client wrapper - ✅ Responsive UI with Tailwind Tech Stack: - Next.js 14 (App Router) - TypeScript - TailwindCSS - Socket.IO client - Zustand (state management) - Axios (HTTP client) - date-fns (date formatting) - lucide-react (icons) Build Status: ✅ Successfully compiles Production Ready: ✅ Optimized build generated
83 lines
2.3 KiB
TypeScript
83 lines
2.3 KiB
TypeScript
'use client';
|
|
|
|
import { useEffect } from 'react';
|
|
import { useRouter } from 'next/navigation';
|
|
import { useAuthStore } from '@/stores/useAuthStore';
|
|
import { useChannelStore } from '@/stores/useChannelStore';
|
|
import { useMessageStore } from '@/stores/useMessageStore';
|
|
import { wsClient } from '@/lib/socket';
|
|
import Sidebar from '@/components/sidebar/Sidebar';
|
|
|
|
export default function MainLayout({
|
|
children,
|
|
}: {
|
|
children: React.ReactNode;
|
|
}) {
|
|
const router = useRouter();
|
|
const { isAuthenticated, isLoading, loadUser, user } = useAuthStore();
|
|
const { loadChannels } = useChannelStore();
|
|
const { addMessage, addDirectMessage, setUserTyping, setUserStoppedTyping, loadConversations } = useMessageStore();
|
|
|
|
useEffect(() => {
|
|
loadUser();
|
|
}, [loadUser]);
|
|
|
|
useEffect(() => {
|
|
if (!isLoading && !isAuthenticated) {
|
|
router.push('/login');
|
|
}
|
|
}, [isAuthenticated, isLoading, router]);
|
|
|
|
useEffect(() => {
|
|
if (isAuthenticated) {
|
|
loadChannels();
|
|
loadConversations();
|
|
|
|
// Setup WebSocket event handlers
|
|
wsClient.updateHandlers({
|
|
onNewMessage: (message) => {
|
|
addMessage(message.channel_id, message);
|
|
},
|
|
onNewDM: (dm) => {
|
|
addDirectMessage(dm);
|
|
// Reload conversations to update unread count
|
|
loadConversations();
|
|
},
|
|
onUserTyping: (data) => {
|
|
if (data.user_id !== user?.id) {
|
|
setUserTyping(data.channel_id, data.user_id);
|
|
// Auto-clear typing after 3 seconds
|
|
setTimeout(() => {
|
|
setUserStoppedTyping(data.channel_id, data.user_id);
|
|
}, 3000);
|
|
}
|
|
},
|
|
onUserStoppedTyping: (data) => {
|
|
setUserStoppedTyping(data.channel_id, data.user_id);
|
|
},
|
|
});
|
|
}
|
|
}, [isAuthenticated, loadChannels, loadConversations, addMessage, addDirectMessage, setUserTyping, setUserStoppedTyping, user]);
|
|
|
|
if (isLoading) {
|
|
return (
|
|
<div className="min-h-screen flex items-center justify-center bg-gray-900">
|
|
<div className="text-white text-xl">Loading...</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
if (!isAuthenticated) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<div className="flex h-screen bg-gray-900 text-white overflow-hidden">
|
|
<Sidebar />
|
|
<main className="flex-1 flex flex-col overflow-hidden">
|
|
{children}
|
|
</main>
|
|
</div>
|
|
);
|
|
}
|