Add comprehensive social media management system and improve admin pages
## Social Media Management System - Add SocialMediaLink database model with platform, URL, icon, and ordering - Create complete CRUD API endpoints for admin social media management - Implement admin social media management page with Material-UI DataGrid - Add "Social Media" menu item to admin navigation - Update footer to dynamically load and display enabled social media links - Support multiple platforms: Facebook, Twitter, Instagram, YouTube, LinkedIn, GitHub, TikTok - Include proper icon mapping and fallback handling ## Admin Pages Improvements - Replace broken TinyMCE editor with working WYSIWYG rich text editor - Create SimpleRichEditor component with toolbar for formatting - Fix admin authentication to use cookies instead of localStorage tokens - Update all admin API calls to use credentials: 'include' - Increase content editor height to 800px for better editing experience - Add Lexical editor component as alternative (not currently used) ## Footer Pages System - Create 8 comprehensive footer pages: About, Blog, Support, API Docs, Terms, Privacy, Cookies, GDPR - Implement dynamic footer link management with smart categorization - Separate Quick Links and Legal sections with automatic filtering - Remove duplicate hardcoded links and use database-driven system - All footer pages are fully written with professional content ## Database & Dependencies - Add uuid package for ID generation - Update Prisma schema with new SocialMediaLink model and relations - Seed default social media links for Facebook, Twitter, Instagram, YouTube - Add Lexical rich text editor packages (@lexical/react, etc.) ## Technical Improvements - Fix async params compatibility for Next.js 15 - Update MUI DataGrid deprecated props - Improve admin layout navigation structure - Add proper TypeScript interfaces for all new components - Implement proper error handling and user feedback 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -22,8 +22,8 @@ import {
|
||||
Grid,
|
||||
Paper
|
||||
} from '@mui/material';
|
||||
import { Editor } from '@tinymce/tinymce-react';
|
||||
import { ImageUpload } from './image-upload';
|
||||
import { SimpleRichEditor } from './simple-rich-editor';
|
||||
|
||||
interface Page {
|
||||
id?: string;
|
||||
@@ -128,16 +128,15 @@ export function PageEditor({ open, onClose, page, onSave }: PageEditorProps) {
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
const token = localStorage.getItem('authToken');
|
||||
const url = page ? `/api/admin/pages/${page.id}` : '/api/admin/pages';
|
||||
const method = page ? 'PUT' : 'POST';
|
||||
|
||||
const response = await fetch(url, {
|
||||
method,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${token}`
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(formData)
|
||||
});
|
||||
|
||||
@@ -174,54 +173,16 @@ export function PageEditor({ open, onClose, page, onSave }: PageEditorProps) {
|
||||
case 'RICH_TEXT':
|
||||
return (
|
||||
<Box sx={{ mt: 2 }}>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 1 }}>
|
||||
<Typography variant="subtitle2">Content</Typography>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 2 }}>
|
||||
<Typography variant="subtitle2">Rich Text Content</Typography>
|
||||
<Button size="small" onClick={() => setImageUploadOpen(true)}>
|
||||
Insert Image
|
||||
</Button>
|
||||
</Box>
|
||||
<Editor
|
||||
onInit={(evt, editor) => editorRef.current = { getEditor: () => editor }}
|
||||
<SimpleRichEditor
|
||||
value={formData.content}
|
||||
onEditorChange={(content) => setFormData(prev => ({ ...prev, content }))}
|
||||
init={{
|
||||
height: 400,
|
||||
menubar: true,
|
||||
plugins: [
|
||||
'advlist', 'autolink', 'lists', 'link', 'image', 'charmap', 'preview',
|
||||
'anchor', 'searchreplace', 'visualblocks', 'code', 'fullscreen',
|
||||
'insertdatetime', 'media', 'table', 'help', 'wordcount'
|
||||
],
|
||||
toolbar: 'undo redo | blocks | ' +
|
||||
'bold italic forecolor | alignleft aligncenter ' +
|
||||
'alignright alignjustify | bullist numlist outdent indent | ' +
|
||||
'removeformat | link image | code | help',
|
||||
content_style: 'body { font-family: Arial, Helvetica, sans-serif; font-size: 14px }',
|
||||
images_upload_handler: (blobInfo: any) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const formData = new FormData();
|
||||
formData.append('file', blobInfo.blob(), blobInfo.filename());
|
||||
|
||||
const token = localStorage.getItem('authToken');
|
||||
fetch('/api/admin/media', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${token}`
|
||||
},
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(result => {
|
||||
if (result.success) {
|
||||
resolve(result.data.url);
|
||||
} else {
|
||||
reject(result.error || 'Upload failed');
|
||||
}
|
||||
})
|
||||
.catch(error => reject(error));
|
||||
});
|
||||
}
|
||||
}}
|
||||
onChange={(content) => setFormData(prev => ({ ...prev, content }))}
|
||||
height={800}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
@@ -237,7 +198,7 @@ export function PageEditor({ open, onClose, page, onSave }: PageEditorProps) {
|
||||
</Box>
|
||||
<TextField
|
||||
multiline
|
||||
rows={20}
|
||||
rows={60}
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
value={formData.content}
|
||||
@@ -253,7 +214,7 @@ export function PageEditor({ open, onClose, page, onSave }: PageEditorProps) {
|
||||
<Typography variant="subtitle2" gutterBottom>Markdown Content</Typography>
|
||||
<TextField
|
||||
multiline
|
||||
rows={20}
|
||||
rows={60}
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
value={formData.content}
|
||||
|
||||
Reference in New Issue
Block a user