sozsoft-platform/ui/src/views/menu/MenuManager.tsx

171 lines
5.8 KiB
TypeScript
Raw Normal View History

2026-02-24 20:44:16 +00:00
import React, { useState } from 'react'
import { SortableMenuTree } from './SortableMenuTree'
import { MenuItem } from '@/proxy/menus/menu'
import { useMenuData } from '@/utils/hooks/useMenuData'
2026-03-17 19:56:34 +00:00
import { FaRegBell, FaSpinner, FaBars, FaRegSave } from 'react-icons/fa'
2026-02-24 20:44:16 +00:00
import { Container } from '@/components/shared'
import { Helmet } from 'react-helmet'
import { useLocalization } from '@/utils/hooks/useLocalization'
2026-03-17 19:56:34 +00:00
import { APP_NAME } from '@/constants/app.constant'
2026-02-24 20:44:16 +00:00
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 | ${APP_NAME}`}
title={translate('::' + 'App.Menus.Manager')}
defaultTitle={APP_NAME}
></Helmet>
<div className="bg-white rounded px-2 sm:px-2 lg:px-3 py-3">
2026-03-17 19:56:34 +00:00
<div className="flex items-center justify-between mb-2 flex-wrap gap-4">
2026-02-24 20:44:16 +00:00
{/* Sol kısım: Başlık */}
<div className="flex items-center gap-2">
<FaBars size={20} className="text-gray-600" />
<h2 className="text-base 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={`
2026-05-03 12:24:46 +00:00
flex items-center gap-2 px-2 py-1 rounded-lg transition-colors
2026-02-24 20:44:16 +00:00
${isDesignMode ? 'bg-green-600 hover:bg-green-700 text-white' : 'bg-gray-300 text-gray-500 cursor-not-allowed'}
${isSaving ? 'opacity-50' : ''}
`}
>
{isSaving ? (
<>
2026-05-03 12:24:46 +00:00
<FaSpinner size={10} className="animate-spin" />
2026-02-24 20:44:16 +00:00
Saving...
</>
) : (
<>
2026-05-03 12:24:46 +00:00
<FaRegSave size={10} />
2026-02-24 20:44:16 +00:00
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