menumanager çağırınca abpconfig tekrar çağrılsın menü düzenlensin

This commit is contained in:
Sedat ÖZTÜRK 2025-06-26 17:59:53 +03:00
parent b2dc2251d8
commit 35e4957cc3
9 changed files with 129 additions and 58 deletions

View file

@ -9,6 +9,7 @@ using Microsoft.Extensions.Logging;
using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services; using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain.Repositories;
using static Kurs.Platform.Data.Seeds.SeedConsts;
namespace Kurs.Platform.Menus; namespace Kurs.Platform.Menus;
@ -28,6 +29,10 @@ public class MenuAppService : CrudAppService<
{ {
_menuRepository = menuRepository; _menuRepository = menuRepository;
_repositoryKey = languageKeyRepository; _repositoryKey = languageKeyRepository;
CreatePolicyName = $"{AppCodes.Menus.Menu}.Create";
UpdatePolicyName = $"{AppCodes.Menus.Menu}.Update";
DeletePolicyName = $"{AppCodes.Menus.Menu}.Delete";
} }
public override async Task<PagedResultDto<MenuDto>> GetListAsync(PagedAndSortedResultRequestDto input) public override async Task<PagedResultDto<MenuDto>> GetListAsync(PagedAndSortedResultRequestDto input)
@ -81,6 +86,8 @@ public class MenuAppService : CrudAppService<
public override async Task<MenuDto> CreateAsync(MenuDto input) public override async Task<MenuDto> CreateAsync(MenuDto input)
{ {
await CheckCreatePolicyAsync();
var keyExists = await _repositoryKey.AnyAsync( var keyExists = await _repositoryKey.AnyAsync(
a => a.Key == input.DisplayName && a => a.Key == input.DisplayName &&
a.ResourceName == PlatformConsts.AppName); a.ResourceName == PlatformConsts.AppName);
@ -98,6 +105,8 @@ public class MenuAppService : CrudAppService<
public override async Task<MenuDto> UpdateAsync(Guid id, MenuDto input) public override async Task<MenuDto> UpdateAsync(Guid id, MenuDto input)
{ {
await CheckUpdatePolicyAsync();
var key = await _repositoryKey.FirstOrDefaultAsync( var key = await _repositoryKey.FirstOrDefaultAsync(
a => a.Key == input.DisplayName && a => a.Key == input.DisplayName &&
a.ResourceName == PlatformConsts.AppName); a.ResourceName == PlatformConsts.AppName);
@ -115,8 +124,44 @@ public class MenuAppService : CrudAppService<
return await base.UpdateAsync(id, input); return await base.UpdateAsync(id, input);
} }
public async Task<List<MenuDto>> UpdateAllAsync(List<MenuDto> inputs)
{
await CheckUpdatePolicyAsync();
var result = new List<MenuDto>();
foreach (var input in inputs)
{
if (input.Id == Guid.Empty)
{
throw new ArgumentException("MenuDto içinde geçerli bir Id bulunmalıdır.");
}
var key = await _repositoryKey.FirstOrDefaultAsync(
a => a.Key == input.DisplayName &&
a.ResourceName == PlatformConsts.AppName);
if (key is null)
{
await _repositoryKey.InsertAsync(new LanguageKey
{
Key = input.DisplayName,
ResourceName = PlatformConsts.AppName
});
}
var updated = await base.UpdateAsync(input.Id, input);
result.Add(updated);
}
return result;
}
public override async Task DeleteAsync(Guid id) public override async Task DeleteAsync(Guid id)
{ {
await CheckDeletePolicyAsync();
var menu = await _menuRepository.GetAsync(id); var menu = await _menuRepository.GetAsync(id);
if (menu != null) if (menu != null)
{ {

View file

@ -82,7 +82,7 @@ define(['./workbox-54d0af47'], (function (workbox) { 'use strict';
"revision": "3ca0b8505b4bec776b69afdba2768812" "revision": "3ca0b8505b4bec776b69afdba2768812"
}, { }, {
"url": "index.html", "url": "index.html",
"revision": "0.scg6n9r90k8" "revision": "0.hld5cocdcl"
}], {}); }], {});
workbox.cleanupOutdatedCaches(); workbox.cleanupOutdatedCaches();
workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), { workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), {

View file

@ -27,14 +27,17 @@ const HorizontalMenuContent = ({ manuVariant }: HorizontalMenuContentProps) => {
{navigationConfig.map((nav) => { {navigationConfig.map((nav) => {
if (nav.type === NAV_ITEM_TYPE_TITLE || nav.type === NAV_ITEM_TYPE_COLLAPSE) { if (nav.type === NAV_ITEM_TYPE_TITLE || nav.type === NAV_ITEM_TYPE_COLLAPSE) {
return ( return (
<PermissionCheck key={nav.key} permissions={nav.authority}> <PermissionCheck
key={nav.key || `nav-${nav.path || Math.random()}`}
permissions={nav.authority}
>
<Dropdown <Dropdown
trigger="hover" trigger="hover"
renderTitle={<HorizontalMenuItem manuVariant={manuVariant} nav={nav} />} renderTitle={<HorizontalMenuItem manuVariant={manuVariant} nav={nav} />}
> >
{nav.subMenu.map((secondarySubNav) => ( {nav.subMenu.map((secondarySubNav) => (
<PermissionCheck <PermissionCheck
key={secondarySubNav.key} key={secondarySubNav.key || `sec-${secondarySubNav.path || Math.random()}`}
permissions={secondarySubNav.authority} permissions={secondarySubNav.authority}
> >
{secondarySubNav.subMenu.length > 0 ? ( {secondarySubNav.subMenu.length > 0 ? (
@ -42,23 +45,34 @@ const HorizontalMenuContent = ({ manuVariant }: HorizontalMenuContentProps) => {
title={ title={
<div className="flex items-center"> <div className="flex items-center">
<HorizontalMenuIcon icon={secondarySubNav.icon} /> <HorizontalMenuIcon icon={secondarySubNav.icon} />
<span> <span>{t(secondarySubNav.translateKey, secondarySubNav.title)}</span>
{t(secondarySubNav.translateKey, secondarySubNav.title)}
</span>
</div> </div>
} }
> >
{secondarySubNav.subMenu.map((tertiarySubNav) => ( {secondarySubNav.subMenu.map((tertiarySubNav) => (
<PermissionCheck <PermissionCheck
key={tertiarySubNav.key} key={
tertiarySubNav.key || `ter-${tertiarySubNav.path || Math.random()}`
}
permissions={tertiarySubNav.authority} permissions={tertiarySubNav.authority}
> >
<HorizontalMenuDropdownItem nav={tertiarySubNav} /> <HorizontalMenuDropdownItem
key={
tertiarySubNav.key ||
`ter-item-${tertiarySubNav.path || Math.random()}`
}
nav={tertiarySubNav}
/>
</PermissionCheck> </PermissionCheck>
))} ))}
</Dropdown.Menu> </Dropdown.Menu>
) : ( ) : (
<HorizontalMenuDropdownItem key={secondarySubNav.key} nav={secondarySubNav} /> <HorizontalMenuDropdownItem
key={
secondarySubNav.key || `sec-item-${secondarySubNav.path || Math.random()}`
}
nav={secondarySubNav}
/>
)} )}
</PermissionCheck> </PermissionCheck>
))} ))}

View file

@ -5,33 +5,43 @@ import apiService, { Config } from '@/services/api.service'
export class MenuService { export class MenuService {
apiName = 'Default' apiName = 'Default'
// create = (input: MenuDto, config?: Partial<Rest.Config>) => update = (id: string, input: MenuDto, config?: Partial<Config>) =>
// this.restService.request<any, MenuDto>( apiService.fetchData<MenuDto, MenuDto>(
// { {
// method: 'POST', method: 'PUT',
// url: '/api/app/menu', url: `/api/app/menu/${id}`,
// body: input, data: input,
// }, },
// { apiName: this.apiName, ...config }, { apiName: this.apiName, ...config },
// ) )
// delete = (id: string, config?: Partial<Rest.Config>) => create = (input: MenuDto, config?: Partial<Config>) =>
// this.restService.request<any, void>( apiService.fetchData<MenuDto, MenuDto>(
// { {
// method: 'DELETE', method: 'POST',
// url: `/api/app/menu/${id}`, url: '/api/app/menu',
// }, data: input,
// { apiName: this.apiName, ...config }, },
// ) { apiName: this.apiName, ...config },
)
// get = (id: string, config?: Partial<Rest.Config>) => delete = (id: string, config?: Partial<Config>) =>
// this.restService.request<any, MenuDto>( apiService.fetchData<void>(
// { {
// method: 'GET', method: 'DELETE',
// url: `/api/app/menu/${id}`, url: `/api/app/menu/${id}`,
// }, },
// { apiName: this.apiName, ...config }, { apiName: this.apiName, ...config },
// ) )
get = (id: string, config?: Partial<Config>) =>
apiService.fetchData<MenuDto>(
{
method: 'GET',
url: `/api/app/menu/${id}`,
},
{ apiName: this.apiName, ...config },
)
getList = (input: PagedAndSortedResultRequestDto, config?: Partial<Config>) => getList = (input: PagedAndSortedResultRequestDto, config?: Partial<Config>) =>
apiService.fetchData<PagedResultDto<MenuDto>, PagedAndSortedResultRequestDto>( apiService.fetchData<PagedResultDto<MenuDto>, PagedAndSortedResultRequestDto>(
@ -47,15 +57,15 @@ export class MenuService {
{ apiName: this.apiName, ...config }, { apiName: this.apiName, ...config },
) )
// update = (id: string, input: MenuDto, config?: Partial<Rest.Config>) => updateAll = (inputs: MenuDto[], config?: Partial<Config>) =>
// this.restService.request<any, MenuDto>( apiService.fetchData<void, MenuDto[]>(
// { {
// method: 'PUT', method: 'PUT',
// url: `/api/app/menu/${id}`, url: '/api/app/menu/all',
// body: input, data: inputs,
// }, },
// { apiName: this.apiName, ...config }, { apiName: this.apiName, ...config },
// ) )
} }
export const getMenus = async (skipCount = 0, maxResultCount = 1000, sorting = 'order') => { export const getMenus = async (skipCount = 0, maxResultCount = 1000, sorting = 'order') => {

View file

@ -1,11 +1,13 @@
import { MenuApiResponse, MenuItem } from '@/@types/menu' import { MenuItem } from '@/@types/menu'
import { getMenus } from '@/services/menu.service' import { getMenus, MenuService } from '@/services/menu.service'
import { useStoreActions } from '@/store/store'
import { useState, useEffect } from 'react' import { useState, useEffect } from 'react'
export const useMenuData = () => { export const useMenuData = () => {
const [menuItems, setMenuItems] = useState<MenuItem[]>([]) const [menuItems, setMenuItems] = useState<MenuItem[]>([])
const [loading, setLoading] = useState(true) const [loading, setLoading] = useState(true)
const [error, setError] = useState<string | null>(null) const [error, setError] = useState<string | null>(null)
const { getConfig } = useStoreActions((a) => a.abpConfig)
const buildHierarchy = (items: MenuItem[]): MenuItem[] => { const buildHierarchy = (items: MenuItem[]): MenuItem[] => {
const itemMap = new Map<string, MenuItem>() const itemMap = new Map<string, MenuItem>()
@ -58,7 +60,6 @@ export const useMenuData = () => {
const hierarchicalMenu = buildHierarchy(response.data.items) const hierarchicalMenu = buildHierarchy(response.data.items)
setMenuItems(hierarchicalMenu) setMenuItems(hierarchicalMenu)
} }
} catch (err) { } catch (err) {
setError(err instanceof Error ? err.message : 'Failed to load menu data') setError(err instanceof Error ? err.message : 'Failed to load menu data')
} finally { } finally {
@ -67,6 +68,8 @@ export const useMenuData = () => {
} }
const saveMenuData = async (updatedMenuItems: MenuItem[]) => { const saveMenuData = async (updatedMenuItems: MenuItem[]) => {
const menuService = new MenuService()
try { try {
// Flatten the hierarchy for API // Flatten the hierarchy for API
const flatten = (items: MenuItem[], parentCode: string | null = null): MenuItem[] => { const flatten = (items: MenuItem[], parentCode: string | null = null): MenuItem[] => {
@ -86,14 +89,9 @@ export const useMenuData = () => {
}) })
return result return result
} }
const items = flatten(updatedMenuItems)
const flatMenuItems = flatten(updatedMenuItems) await menuService.updateAll(items)
getConfig(false)
// Simulate API call
await new Promise((resolve) => setTimeout(resolve, 1000))
console.log('Saving menu data:', flatMenuItems)
// In real implementation: await api.saveMenus(flatMenuItems);
return { success: true } return { success: true }
} catch (err) { } catch (err) {

View file

@ -45,7 +45,7 @@ function FormFieldTabPivotSetting({
initialValues={initialValues} initialValues={initialValues}
validationSchema={schema} validationSchema={schema}
onSubmit={async (values, formikHelpers) => { onSubmit={async (values, formikHelpers) => {
console.log(values) //console.log(values)
await onSubmit(ListFormFieldEditTabs.PivotSettingsForm, values, formikHelpers) await onSubmit(ListFormFieldEditTabs.PivotSettingsForm, values, formikHelpers)
}} }}
> >

View file

@ -230,7 +230,7 @@ const BlogManagement = () => {
const handleEditCategory = (category: BlogCategory) => { const handleEditCategory = (category: BlogCategory) => {
setEditingCategory(category) setEditingCategory(category)
console.log(category) //console.log(category)
setCategoryModalVisible(true) setCategoryModalVisible(true)
} }

View file

@ -25,7 +25,6 @@ export const MenuManager = () => {
setSaveMessage(null) setSaveMessage(null)
await saveMenuData(menuItems) await saveMenuData(menuItems)
setSaveMessage({ type: 'success', text: 'Menu configuration saved successfully!' }) setSaveMessage({ type: 'success', text: 'Menu configuration saved successfully!' })
setTimeout(() => setSaveMessage(null), 3000) setTimeout(() => setSaveMessage(null), 3000)
} catch (err) { } catch (err) {

View file

@ -186,7 +186,12 @@ export const SortableMenuTree: React.FC<SortableMenuTreeProps> = ({
const renderMenuItem = (item: MenuItem, depth: number = 0): React.ReactNode => { const renderMenuItem = (item: MenuItem, depth: number = 0): React.ReactNode => {
return ( return (
<MenuItemComponent key={item.id} item={item} isDesignMode={isDesignMode} depth={depth}> <MenuItemComponent
key={item.id || `temp-${Math.random().toString(36).substr(2, 9)}`}
item={item}
isDesignMode={isDesignMode}
depth={depth}
>
{item.children && item.children.length > 0 && ( {item.children && item.children.length > 0 && (
<div className="ml-4"> <div className="ml-4">
{item.children.map((child) => renderMenuItem(child, depth + 1))} {item.children.map((child) => renderMenuItem(child, depth + 1))}