Files
grimlock/frontend/src/app/(main)/layout.tsx
JA 22fe893e65 Frontend: Complete Next.js implementation
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
2026-02-13 16:34:49 +00:00

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