feat(contact): add contact form with admin panel and navbar dropdown

Database changes:
- Added ContactMessage model to Prisma schema
- Fields: userId, username, firstName, lastName, email, subject, message, status, ipAddress
- Status enum: new, read, resolved
- Relation to User model

Backend changes:
- Added POST /api/public/contact endpoint for form submissions
- Works for both authenticated and non-authenticated users
- Validation for email, subject (3-255 chars), message (10-5000 chars)
- Activity logging for submissions
- Added admin endpoints:
  - GET /api/admin/contact-messages - list with filtering by status
  - GET /api/admin/contact-messages/:id - view single message (auto-marks as read)
  - PATCH /api/admin/contact-messages/:id/status - update status
  - DELETE /api/admin/contact-messages/:id - delete message

Frontend changes:
- Created ContactPage at /contact route
- For non-logged-in users: firstName, lastName, email, subject, message fields
- For logged-in users: auto-fills username, shows only email, subject, message
- Character counter for message (max 5000)
- Success screen with auto-redirect to homepage
- Created ContactMessagesPage at /admin/contact-messages
- Two-column layout: message list + detail view
- Filter by status (all, new, read, resolved)
- View message details with sender info and IP address
- Update status and delete messages
- Added admin dropdown menu to Navbar
  - Desktop: dropdown with Activity Logs and Contact Messages
  - Mobile: expandable submenu
  - Click outside to close on desktop
  - ChevronDown icon rotates when open

Note: CAPTCHA integration planned for future enhancement
This commit is contained in:
Radosław Gierwiało
2025-12-05 17:15:25 +01:00
parent f90945aa47
commit 34f18b3b50
8 changed files with 997 additions and 16 deletions

View File

@@ -19,6 +19,8 @@ import HistoryPage from './pages/HistoryPage';
import ProfilePage from './pages/ProfilePage';
import PublicProfilePage from './pages/PublicProfilePage';
import ActivityLogsPage from './pages/admin/ActivityLogsPage';
import ContactMessagesPage from './pages/admin/ContactMessagesPage';
import ContactPage from './pages/ContactPage';
import NotFoundPage from './pages/NotFoundPage';
import VerificationBanner from './components/common/VerificationBanner';
import InstallPWA from './components/pwa/InstallPWA';
@@ -210,11 +212,22 @@ function App() {
</ProtectedRoute>
}
/>
<Route
path="/admin/contact-messages"
element={
<ProtectedRoute>
<ContactMessagesPage />
</ProtectedRoute>
}
/>
{/* Home Page */}
<Route path="/" element={<HomePage />} />
{/* Contact Page - Public route */}
<Route path="/contact" element={<ContactPage />} />
{/* Public Profile - /u/username format (no auth required) */}
<Route path="/u/:username" element={<PublicProfilePage />} />