From 9ab363ca598cac7198b4dde4691af176f1baab29 Mon Sep 17 00:00:00 2001 From: Sewmina Date: Sun, 8 Jun 2025 22:04:00 +0530 Subject: [PATCH] ready --- Chat-admin-readme.md | 121 +++++++++ app/components/Modal.tsx | 43 ++++ app/components/Pagination.tsx | 28 ++- app/components/SearchInput.tsx | 4 +- app/components/ui/button.tsx | 34 +++ app/components/ui/card.tsx | 18 ++ app/components/ui/input.tsx | 22 ++ app/dashboard/chat/page.tsx | 160 ++++++++++++ app/dashboard/layout.tsx | 36 ++- app/dashboard/page.tsx | 436 +++++++++++++++++---------------- app/games/page.tsx | 243 ++++++++++++++++++ app/globals.css | 32 ++- app/lib/utils.ts | 6 + app/page.tsx | 1 - app/users/page.tsx | 205 ++++++++++++++++ app/utils/api.ts | 12 + package-lock.json | 202 ++++++++++++++- package.json | 12 +- tsconfig.json | 4 +- 19 files changed, 1377 insertions(+), 242 deletions(-) create mode 100644 Chat-admin-readme.md create mode 100644 app/components/Modal.tsx create mode 100644 app/components/ui/button.tsx create mode 100644 app/components/ui/card.tsx create mode 100644 app/components/ui/input.tsx create mode 100644 app/dashboard/chat/page.tsx create mode 100644 app/games/page.tsx create mode 100644 app/lib/utils.ts create mode 100644 app/users/page.tsx diff --git a/Chat-admin-readme.md b/Chat-admin-readme.md new file mode 100644 index 0000000..5f3584f --- /dev/null +++ b/Chat-admin-readme.md @@ -0,0 +1,121 @@ +# Duelfi Chat Server + +A real-time chat server built with Socket.IO and Express, supporting message creation, editing, and deletion. + +## Server Configuration + +- **Port**: 3040 +- **CORS Origins**: + - http://localhost:3000 + - http://localhost:3030 + - http://localhost:3031 + - https://dev.duelfi.io + - https://beta.duelfi.io + - https://duelfi.io + +## Message Structure + +```typescript +interface ChatMessage { + id: string; // Unique message identifier + user: string; // User identifier (DID format) + message: string; // Message content + timestamp: number; // Unix timestamp +} +``` + +## Socket Events + +### Client to Server + +1. **chat message** + - Purpose: Send a new message + - Payload: `ChatMessage` object + - Response: Broadcasts to all clients + +2. **edit message** + - Purpose: Edit an existing message + - Payload: `{ messageId: string, newMessage: string }` + - Response: Broadcasts 'message edited' on success + +3. **delete message** + - Purpose: Delete a message + - Payload: `messageId: string` + - Response: Broadcasts 'message deleted' on success + +### Server to Client + +1. **recent messages** + - Purpose: Initial message history + - Payload: `ChatMessage[]` + - Trigger: On connection + +2. **chat message** + - Purpose: New message notification + - Payload: `ChatMessage` object + - Trigger: When any client sends a message + +3. **message edited** + - Purpose: Message edit notification + - Payload: `{ messageId: string, newMessage: string }` + - Trigger: When a message is successfully edited + +4. **message deleted** + - Purpose: Message deletion notification + - Payload: `messageId: string` + - Trigger: When a message is successfully deleted + +## Message Storage + +- Messages are stored in `chat_history.json` +- Maximum of 100 messages are kept in memory +- File storage maintains message history +- All operations (create/edit/delete) are persisted to file + +## Error Handling + +- File operations are wrapped in try-catch blocks +- Failed operations return false +- Successful operations return true +- All errors are logged to console + +## Usage Example + +```typescript +// Connect to server +const socket = io('http://localhost:3040'); + +// Send message +socket.emit('chat message', { + id: Date.now().toString(), + user: 'did:privy:user123', + message: 'Hello world', + timestamp: Date.now() +}); + +// Edit message +socket.emit('edit message', { + messageId: 'message-id-here', + newMessage: 'Updated message' +}); + +// Delete message +socket.emit('delete message', 'message-id-here'); + +// Listen for events +socket.on('recent messages', (messages) => { + // Handle initial messages +}); + +socket.on('chat message', (message) => { + // Handle new message +}); + +socket.on('message edited', ({ messageId, newMessage }) => { + // Handle edited message +}); + +socket.on('message deleted', (messageId) => { + // Handle deleted message +}); +``` \ No newline at end of file diff --git a/app/components/Modal.tsx b/app/components/Modal.tsx new file mode 100644 index 0000000..d63d12a --- /dev/null +++ b/app/components/Modal.tsx @@ -0,0 +1,43 @@ +interface ModalProps { + isOpen: boolean; + onClose: () => void; + title: string; + children: React.ReactNode; +} + +export default function Modal({ isOpen, onClose, title, children }: ModalProps) { + if (!isOpen) return null; + + return ( +
+
+ {/* Background overlay */} +
+ + {/* Modal panel */} +
+
+
+

{title}

+ +
+
+ {children} +
+
+
+
+
+ ); +} \ No newline at end of file diff --git a/app/components/Pagination.tsx b/app/components/Pagination.tsx index f53b699..2593595 100644 --- a/app/components/Pagination.tsx +++ b/app/components/Pagination.tsx @@ -13,7 +13,7 @@ export default function Pagination({ totalItems, itemsPerPage, currentPage, onPa const pageNumbers = []; const maxVisiblePages = 5; let startPage = Math.max(1, currentPage - Math.floor(maxVisiblePages / 2)); - let endPage = Math.min(totalPages, startPage + maxVisiblePages - 1); + const endPage = Math.min(totalPages, startPage + maxVisiblePages - 1); if (endPage - startPage + 1 < maxVisiblePages) { startPage = Math.max(1, endPage - maxVisiblePages + 1); @@ -28,7 +28,7 @@ export default function Pagination({ totalItems, itemsPerPage, currentPage, onPa @@ -38,12 +38,14 @@ export default function Pagination({ totalItems, itemsPerPage, currentPage, onPa - {startPage > 2 && ...} + {startPage > 2 && ...} )} @@ -52,8 +54,10 @@ export default function Pagination({ totalItems, itemsPerPage, currentPage, onPa key={number} onClick={() => onPageChange(number)} className={`px-3 py-1 rounded-md ${ - currentPage === number ? 'bg-blue-500 text-white' : 'bg-gray-100 text-gray-700' - }`} + currentPage === number + ? 'bg-[var(--accent)] text-white' + : 'bg-[var(--card-bg)] text-[var(--text-primary)] hover:bg-[var(--card-border)]' + } transition-colors`} > {number} @@ -61,12 +65,14 @@ export default function Pagination({ totalItems, itemsPerPage, currentPage, onPa {endPage < totalPages && ( <> - {endPage < totalPages - 1 && ...} + {endPage < totalPages - 1 && ...} @@ -76,7 +82,7 @@ export default function Pagination({ totalItems, itemsPerPage, currentPage, onPa diff --git a/app/components/SearchInput.tsx b/app/components/SearchInput.tsx index a7995af..825c47f 100644 --- a/app/components/SearchInput.tsx +++ b/app/components/SearchInput.tsx @@ -8,13 +8,13 @@ export default function SearchInput({ placeholder, value, onChange }: SearchInpu return (
- +
onChange(e.target.value)} diff --git a/app/components/ui/button.tsx b/app/components/ui/button.tsx new file mode 100644 index 0000000..c8b2193 --- /dev/null +++ b/app/components/ui/button.tsx @@ -0,0 +1,34 @@ +import { ButtonHTMLAttributes, forwardRef } from 'react'; +import { cn } from '@/lib/utils'; + +interface ButtonProps extends ButtonHTMLAttributes { + variant?: 'default' | 'outline' | 'destructive'; + size?: 'default' | 'sm' | 'lg'; +} + +const Button = forwardRef( + ({ className, variant = 'default', size = 'default', ...props }, ref) => { + return ( + + +
+ ) : ( +
{message.message}
+ )} +
+ {editingMessage !== message.id && ( +
+ + +
+ )} + + + ))} + + + ); +} \ No newline at end of file diff --git a/app/dashboard/layout.tsx b/app/dashboard/layout.tsx index d422f16..33b9619 100644 --- a/app/dashboard/layout.tsx +++ b/app/dashboard/layout.tsx @@ -1,6 +1,7 @@ 'use client'; -import { useRouter } from 'next/navigation'; +import { useRouter, usePathname } from 'next/navigation'; +import Link from 'next/link'; import Cookies from 'js-cookie'; export default function DashboardLayout({ @@ -9,26 +10,51 @@ export default function DashboardLayout({ children: React.ReactNode; }) { const router = useRouter(); + const pathname = usePathname(); const handleLogout = () => { Cookies.remove('isAuthenticated', { path: '/' }); router.push('/login'); }; + const isActive = (path: string) => pathname === path; + return ( -
-