Add comprehensive page management system to admin dashboard
Features added: - Database schema for pages and media files with content types (Rich Text, HTML, Markdown) - Admin API routes for full page CRUD operations - Image upload functionality with file management - Rich text editor using TinyMCE with image insertion - Admin interface for creating/editing pages with SEO options - Dynamic navigation and footer integration - Public page display routes with proper SEO metadata - Support for featured images and content excerpts Admin features: - Create/edit/delete pages with rich content editor - Upload and manage images through media library - Configure pages to appear in navigation or footer - Set page status (Draft, Published, Archived) - SEO title and description management - Real-time preview of content changes 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
167
components/layout/footer.tsx
Normal file
167
components/layout/footer.tsx
Normal file
@@ -0,0 +1,167 @@
|
||||
'use client'
|
||||
import { useState, useEffect } from 'react'
|
||||
import {
|
||||
Paper,
|
||||
Container,
|
||||
Box,
|
||||
Typography,
|
||||
Button,
|
||||
Divider,
|
||||
IconButton,
|
||||
Chip,
|
||||
} from '@mui/material'
|
||||
import {
|
||||
Facebook,
|
||||
Twitter,
|
||||
Instagram,
|
||||
YouTube,
|
||||
} from '@mui/icons-material'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import { useTranslations, useLocale } from 'next-intl'
|
||||
|
||||
interface DynamicPage {
|
||||
id: string
|
||||
title: string
|
||||
slug: string
|
||||
showInFooter: boolean
|
||||
footerOrder?: number
|
||||
}
|
||||
|
||||
export function Footer() {
|
||||
const [dynamicPages, setDynamicPages] = useState<DynamicPage[]>([])
|
||||
const router = useRouter()
|
||||
const t = useTranslations('home')
|
||||
const tSeo = useTranslations('seo')
|
||||
const locale = useLocale()
|
||||
|
||||
useEffect(() => {
|
||||
fetchDynamicPages()
|
||||
}, [])
|
||||
|
||||
const fetchDynamicPages = async () => {
|
||||
try {
|
||||
const response = await fetch('/api/pages?location=footer')
|
||||
if (response.ok) {
|
||||
const data = await response.json()
|
||||
setDynamicPages(data.data || [])
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch dynamic pages:', error)
|
||||
}
|
||||
}
|
||||
|
||||
const getCurrentYear = () => {
|
||||
return new Date().getFullYear()
|
||||
}
|
||||
|
||||
return (
|
||||
<Paper component="footer" sx={{ bgcolor: 'grey.900', color: 'white', py: 6 }}>
|
||||
<Container maxWidth="lg">
|
||||
<Box sx={{ display: 'flex', gap: 6, flexWrap: 'wrap', justifyContent: 'space-between', mb: 4 }}>
|
||||
{/* Brand */}
|
||||
<Box sx={{ flex: { xs: '1 1 100%', md: '1 1 auto' } }}>
|
||||
<Typography variant="h5" sx={{ mb: 2, fontWeight: 600 }}>
|
||||
{t('footer.brand')}
|
||||
</Typography>
|
||||
<Typography variant="body2" color="grey.400" sx={{ maxWidth: 300 }}>
|
||||
{tSeo('footer')}
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
{/* Quick Links */}
|
||||
<Box sx={{ flex: { xs: '1 1 50%', md: '1 1 auto' } }}>
|
||||
<Typography variant="h6" sx={{ mb: 2 }}>
|
||||
{t('footer.quickLinks.title')}
|
||||
</Typography>
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 1 }}>
|
||||
<Button color="inherit" sx={{ justifyContent: 'flex-start', p: 0 }}>
|
||||
{t('footer.quickLinks.about')}
|
||||
</Button>
|
||||
<Button color="inherit" sx={{ justifyContent: 'flex-start', p: 0 }}>
|
||||
{t('footer.quickLinks.blog')}
|
||||
</Button>
|
||||
<Button
|
||||
color="inherit"
|
||||
sx={{ justifyContent: 'flex-start', p: 0 }}
|
||||
onClick={() => router.push(`/${locale}/contact`)}
|
||||
>
|
||||
{t('footer.quickLinks.contact')}
|
||||
</Button>
|
||||
<Button color="inherit" sx={{ justifyContent: 'flex-start', p: 0 }}>
|
||||
{t('footer.quickLinks.support')}
|
||||
</Button>
|
||||
<Button color="inherit" sx={{ justifyContent: 'flex-start', p: 0 }}>
|
||||
{t('footer.quickLinks.api')}
|
||||
</Button>
|
||||
{dynamicPages.map((page) => (
|
||||
<Button
|
||||
key={page.id}
|
||||
color="inherit"
|
||||
sx={{ justifyContent: 'flex-start', p: 0 }}
|
||||
onClick={() => router.push(`/${locale}/pages/${page.slug}`)}
|
||||
>
|
||||
{page.title}
|
||||
</Button>
|
||||
))}
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Legal */}
|
||||
<Box sx={{ flex: { xs: '1 1 50%', md: '1 1 auto' } }}>
|
||||
<Typography variant="h6" sx={{ mb: 2 }}>
|
||||
{t('footer.legal.title')}
|
||||
</Typography>
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 1 }}>
|
||||
<Button color="inherit" sx={{ justifyContent: 'flex-start', p: 0 }}>
|
||||
{t('footer.legal.terms')}
|
||||
</Button>
|
||||
<Button color="inherit" sx={{ justifyContent: 'flex-start', p: 0 }}>
|
||||
{t('footer.legal.privacy')}
|
||||
</Button>
|
||||
<Button color="inherit" sx={{ justifyContent: 'flex-start', p: 0 }}>
|
||||
{t('footer.legal.cookies')}
|
||||
</Button>
|
||||
<Button color="inherit" sx={{ justifyContent: 'flex-start', p: 0 }}>
|
||||
{t('footer.legal.gdpr')}
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Social */}
|
||||
<Box sx={{ flex: { xs: '1 1 100%', md: '1 1 auto' } }}>
|
||||
<Typography variant="h6" sx={{ mb: 2 }}>
|
||||
{t('footer.social.title')}
|
||||
</Typography>
|
||||
<Box sx={{ display: 'flex', gap: 1 }}>
|
||||
<IconButton color="inherit" size="small">
|
||||
<Facebook />
|
||||
</IconButton>
|
||||
<IconButton color="inherit" size="small">
|
||||
<Twitter />
|
||||
</IconButton>
|
||||
<IconButton color="inherit" size="small">
|
||||
<Instagram />
|
||||
</IconButton>
|
||||
<IconButton color="inherit" size="small">
|
||||
<YouTube />
|
||||
</IconButton>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<Divider sx={{ bgcolor: 'grey.700', mb: 3 }} />
|
||||
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', flexWrap: 'wrap', gap: 2 }}>
|
||||
<Typography variant="body2" color="grey.400">
|
||||
© {getCurrentYear()} Biblical Guide - {locale === 'ro' ? 'Făcut cu ❤️ și 🙏' : 'Made with ❤️ and 🙏'}
|
||||
</Typography>
|
||||
<Box sx={{ display: 'flex', gap: 1, flexWrap: 'wrap' }}>
|
||||
<Chip label="🇷🇴 Română" size="small" variant="outlined" sx={{ color: 'white', borderColor: 'grey.600' }} />
|
||||
<Chip label="🇺🇸 English" size="small" variant="outlined" sx={{ color: 'white', borderColor: 'grey.600' }} />
|
||||
<Chip label="+20 more" size="small" variant="outlined" sx={{ color: 'white', borderColor: 'grey.600' }} />
|
||||
</Box>
|
||||
</Box>
|
||||
</Container>
|
||||
</Paper>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user