174 lines
5.7 KiB
TypeScript
174 lines
5.7 KiB
TypeScript
import React, { useState } from 'react'
|
||
import { SortableMenuTree } from './SortableMenuTree'
|
||
import { MenuItem } from '@/@types/menu'
|
||
import { useMenuData } from '@/utils/hooks/useMenuData'
|
||
import {
|
||
FaRegBell,
|
||
FaSpinner,
|
||
FaBars,
|
||
FaRegSave
|
||
} from 'react-icons/fa';
|
||
import { Container } from '@/components/shared'
|
||
import { Helmet } from 'react-helmet'
|
||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||
|
||
export const MenuManager = () => {
|
||
const { menuItems, setMenuItems, loading, error, refetch, saveMenuData } = useMenuData()
|
||
const [isDesignMode, setIsDesignMode] = useState(true)
|
||
const [isSaving, setIsSaving] = useState(false)
|
||
const { translate } = useLocalization()
|
||
|
||
const [saveMessage, setSaveMessage] = useState<{
|
||
type: 'success' | 'error'
|
||
text: string
|
||
} | null>(null)
|
||
|
||
const handleMenuChange = (updatedItems: MenuItem[]) => {
|
||
setMenuItems(updatedItems)
|
||
}
|
||
|
||
const handleSave = async () => {
|
||
if (!isDesignMode) return
|
||
|
||
try {
|
||
setIsSaving(true)
|
||
setSaveMessage(null)
|
||
|
||
await saveMenuData(menuItems)
|
||
setSaveMessage({ type: 'success', text: 'Menu configuration saved successfully!' })
|
||
setTimeout(() => setSaveMessage(null), 3000)
|
||
setIsDesignMode(false)
|
||
} catch (err) {
|
||
setSaveMessage({
|
||
type: 'error',
|
||
text: err instanceof Error ? err.message : 'Failed to save menu configuration',
|
||
})
|
||
setTimeout(() => setSaveMessage(null), 5000)
|
||
} finally {
|
||
setIsSaving(false)
|
||
}
|
||
}
|
||
|
||
const handleToggleDesignMode = () => {
|
||
setIsDesignMode(!isDesignMode)
|
||
setSaveMessage(null)
|
||
}
|
||
|
||
if (loading) {
|
||
return (
|
||
<div className="min-h-screen bg-gray-50 flex items-center justify-center">
|
||
<div className="flex items-center gap-3 text-gray-600">
|
||
<FaSpinner className="animate-spin" />
|
||
<span className="text-lg">Loading menu configuration...</span>
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
if (error) {
|
||
return (
|
||
<div className="min-h-screen bg-gray-50 flex items-center justify-center">
|
||
<div className="bg-white p-8 rounded-lg shadow-md max-w-md w-full mx-4">
|
||
<div className="flex items-center gap-3 text-red-600 mb-4">
|
||
<FaRegBell size={24} />
|
||
<h2 className="text-lg font-semibold">Error Loading Menu</h2>
|
||
</div>
|
||
<p className="text-gray-600 mb-6">{error}</p>
|
||
<button
|
||
onClick={refetch}
|
||
className="w-full bg-blue-600 text-white py-2 px-4 rounded-lg hover:bg-blue-700 transition-colors"
|
||
>
|
||
Retry
|
||
</button>
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
return (
|
||
<Container>
|
||
<Helmet
|
||
titleTemplate="%s | Kurs Platform"
|
||
title={translate('::' + 'App.Menus.Manager')}
|
||
defaultTitle="Kurs Platform"
|
||
></Helmet>
|
||
|
||
<div className="bg-white rounded px-4 sm:px-4 lg:px-6 py-6">
|
||
<div className="flex items-center justify-between mb-6 flex-wrap gap-4">
|
||
{/* Sol kısım: Başlık */}
|
||
<div className="flex items-center gap-2">
|
||
<FaBars size={20} className="text-gray-600" />
|
||
<h2 className="text-lg font-semibold text-gray-900">Menu Manager</h2>
|
||
<span className="text-sm text-gray-500">({menuItems.length} root items)</span>
|
||
</div>
|
||
|
||
{/* Sağ kısım: Design Mode + Save butonu */}
|
||
<div className="flex items-center gap-4">
|
||
<div className="flex items-center gap-3">
|
||
<span
|
||
className={`text-sm font-medium ${isDesignMode ? 'text-blue-600' : 'text-gray-500'}`}
|
||
>
|
||
Design Mode
|
||
</span>
|
||
<button
|
||
onClick={handleToggleDesignMode}
|
||
className={`
|
||
relative inline-flex h-6 w-11 items-center rounded-full transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2
|
||
${isDesignMode ? 'bg-blue-600' : 'bg-gray-200'}
|
||
`}
|
||
>
|
||
<span
|
||
className={`
|
||
inline-block h-4 w-4 transform rounded-full bg-white transition-transform duration-200 ease-in-out
|
||
${isDesignMode ? 'translate-x-6' : 'translate-x-1'}
|
||
`}
|
||
/>
|
||
</button>
|
||
</div>
|
||
|
||
{
|
||
<button
|
||
onClick={handleSave}
|
||
disabled={!isDesignMode || isSaving}
|
||
className={`
|
||
flex items-center gap-2 px-4 py-2 rounded-lg transition-colors
|
||
${isDesignMode ? 'bg-green-600 hover:bg-green-700 text-white' : 'bg-gray-300 text-gray-500 cursor-not-allowed'}
|
||
${isSaving ? 'opacity-50' : ''}
|
||
`}
|
||
>
|
||
{isSaving ? (
|
||
<>
|
||
<FaSpinner size={16} className="animate-spin" />
|
||
Saving...
|
||
</>
|
||
) : (
|
||
<>
|
||
<FaRegSave size={16} />
|
||
Save Changes
|
||
</>
|
||
)}
|
||
</button>
|
||
}
|
||
</div>
|
||
</div>
|
||
|
||
{menuItems.length > 0 ? (
|
||
<SortableMenuTree
|
||
items={menuItems}
|
||
onItemsChange={handleMenuChange}
|
||
isDesignMode={isDesignMode}
|
||
refetch={refetch}
|
||
/>
|
||
) : (
|
||
<div className="text-center py-12 text-gray-500">
|
||
<FaBars size={24} className="mx-auto mb-4 text-gray-300" />
|
||
<p className="text-lg">No menu items found</p>
|
||
<p className="text-sm">Try refreshing the page or contact your administrator</p>
|
||
</div>
|
||
)}
|
||
</div>
|
||
</Container>
|
||
)
|
||
}
|
||
|
||
export default MenuManager
|