mirror of
https://github.com/duckietm/Nitro-V3.git
synced 2026-06-19 15:06:20 +00:00
305 lines
11 KiB
TypeScript
305 lines
11 KiB
TypeScript
import { CatalogAdminCreateOfferComposer, CatalogAdminCreatePageComposer, CatalogAdminDeleteOfferComposer, CatalogAdminDeletePageComposer, CatalogAdminMoveOfferComposer, CatalogAdminMovePageComposer, CatalogAdminPublishComposer, CatalogAdminResultEvent, CatalogAdminSaveOfferComposer, CatalogAdminSavePageComposer } from '@nitrots/nitro-renderer';
|
|
import { createContext, FC, ReactNode, useCallback, useContext, useEffect, useRef, useState } from 'react';
|
|
import { ICatalogNode, IPurchasableOffer, NotificationAlertType, SendMessageComposer } from '../../api';
|
|
import { useCatalogUiState, useMessageEvent, useNotification } from '../../hooks';
|
|
|
|
export interface IPageEditData
|
|
{
|
|
pageId?: number;
|
|
caption: string;
|
|
captionSave: string;
|
|
parentId: number;
|
|
catalogMode: string;
|
|
pageLayout: string;
|
|
iconImage: number;
|
|
enabled: string;
|
|
visible: string;
|
|
minRank: number;
|
|
clubOnly?: string;
|
|
orderNum: number;
|
|
pageHeadline?: string;
|
|
pageTeaser?: string;
|
|
pageSpecial?: string;
|
|
pageText1?: string;
|
|
pageText2?: string;
|
|
pageTextDetails?: string;
|
|
pageTextTeaser?: string;
|
|
}
|
|
|
|
export interface IOfferEditData
|
|
{
|
|
offerId?: number;
|
|
pageId: number;
|
|
itemIds: string;
|
|
catalogName: string;
|
|
costCredits: number;
|
|
costPoints: number;
|
|
pointsType: number;
|
|
amount: number;
|
|
clubOnly: string;
|
|
extradata: string;
|
|
haveOffer: string;
|
|
offerId_group: number;
|
|
limitedStack: number;
|
|
orderNumber: number;
|
|
}
|
|
|
|
interface ICatalogAdminContext
|
|
{
|
|
adminMode: boolean;
|
|
setAdminMode: (value: boolean) => void;
|
|
editingOffer: IPurchasableOffer | null;
|
|
setEditingOffer: (offer: IPurchasableOffer | null) => void;
|
|
editingPageData: boolean;
|
|
setEditingPageData: (value: boolean) => void;
|
|
editingRootPage: boolean;
|
|
setEditingRootPage: (value: boolean) => void;
|
|
editingPageNode: ICatalogNode | null;
|
|
setEditingPageNode: (node: ICatalogNode | null) => void;
|
|
loading: boolean;
|
|
lastError: string | null;
|
|
savePage: (data: IPageEditData) => void;
|
|
createPage: (data: IPageEditData) => void;
|
|
deletePage: (pageId: number) => void;
|
|
saveOffer: (data: IOfferEditData) => void;
|
|
createOffer: (data: IOfferEditData) => void;
|
|
deleteOffer: (offerId: number) => void;
|
|
reorderOffers: (orders: { id: number; orderNumber: number }[]) => void;
|
|
reorderPage: (pageId: number, newParentId: number, newIndex: number) => void;
|
|
togglePageEnabled: (pageId: number) => void;
|
|
togglePageVisible: (pageId: number) => void;
|
|
publishCatalog: () => void;
|
|
hasPendingChanges: boolean;
|
|
}
|
|
|
|
const CatalogAdminContext = createContext<ICatalogAdminContext>(null);
|
|
|
|
export const useCatalogAdmin = () => useContext(CatalogAdminContext);
|
|
|
|
export const CatalogAdminProvider: FC<{ children: ReactNode }> = ({ children }) =>
|
|
{
|
|
const { currentType } = useCatalogUiState();
|
|
const [ adminMode, setAdminMode ] = useState(false);
|
|
const [ editingOffer, setEditingOffer ] = useState<IPurchasableOffer | null>(null);
|
|
const [ editingPageData, setEditingPageData ] = useState(false);
|
|
const [ editingRootPage, setEditingRootPage ] = useState(false);
|
|
const [ editingPageNode, setEditingPageNode ] = useState<ICatalogNode | null>(null);
|
|
const [ loading, setLoading ] = useState(false);
|
|
const [ lastError, setLastError ] = useState<string | null>(null);
|
|
const [ hasPendingChanges, setHasPendingChanges ] = useState(false);
|
|
const pendingActionRef = useRef<string | null>(null);
|
|
const { simpleAlert = null } = useNotification();
|
|
|
|
useEffect(() =>
|
|
{
|
|
if(!adminMode) return;
|
|
|
|
const handleKeyDown = (e: KeyboardEvent) =>
|
|
{
|
|
if(e.key === 'Escape')
|
|
{
|
|
if(editingOffer)
|
|
{
|
|
setEditingOffer(null); e.preventDefault(); return;
|
|
}
|
|
if(editingPageData || editingRootPage || editingPageNode)
|
|
{
|
|
setEditingPageData(false);
|
|
setEditingRootPage(false);
|
|
setEditingPageNode(null);
|
|
e.preventDefault();
|
|
}
|
|
}
|
|
};
|
|
|
|
window.addEventListener('keydown', handleKeyDown);
|
|
|
|
return () => window.removeEventListener('keydown', handleKeyDown);
|
|
}, [ adminMode, editingOffer, editingPageData, editingRootPage, editingPageNode ]);
|
|
|
|
useMessageEvent(CatalogAdminResultEvent, (event: CatalogAdminResultEvent) =>
|
|
{
|
|
const parser = event.getParser();
|
|
const action = pendingActionRef.current;
|
|
|
|
pendingActionRef.current = null;
|
|
setLoading(false);
|
|
|
|
if(!parser.success)
|
|
{
|
|
setLastError(parser.message || 'Operation failed');
|
|
|
|
if(simpleAlert)
|
|
{
|
|
simpleAlert(parser.message || 'Operation failed', NotificationAlertType.ALERT, null, null, 'Admin Error');
|
|
}
|
|
}
|
|
else
|
|
{
|
|
setLastError(null);
|
|
setEditingOffer(null);
|
|
setEditingPageData(false);
|
|
setEditingRootPage(false);
|
|
setEditingPageNode(null);
|
|
|
|
if(action === 'publish')
|
|
{
|
|
setHasPendingChanges(false);
|
|
}
|
|
else
|
|
{
|
|
setHasPendingChanges(true);
|
|
}
|
|
|
|
if(simpleAlert && action)
|
|
{
|
|
const messages: Record<string, string> = {
|
|
'savePage': 'Page saved (publish to apply)',
|
|
'createPage': 'Page created (publish to apply)',
|
|
'deletePage': 'Page deleted (publish to apply)',
|
|
'saveOffer': 'Offer saved (publish to apply)',
|
|
'createOffer': 'Offer created (publish to apply)',
|
|
'deleteOffer': 'Offer deleted (publish to apply)',
|
|
'reorder': 'Order updated (publish to apply)',
|
|
'toggleEnabled': 'Page toggled (publish to apply)',
|
|
'toggleVisible': 'Visibility toggled (publish to apply)',
|
|
'movePage': 'Page moved (publish to apply)',
|
|
'publish': 'Catalog published! All users updated.',
|
|
};
|
|
|
|
simpleAlert(messages[action] || 'Operation completed', NotificationAlertType.DEFAULT, null, null, 'Catalog Admin');
|
|
}
|
|
}
|
|
});
|
|
|
|
const savePage = useCallback((data: IPageEditData) =>
|
|
{
|
|
setLoading(true);
|
|
setLastError(null);
|
|
pendingActionRef.current = 'savePage';
|
|
|
|
SendMessageComposer(new CatalogAdminSavePageComposer(
|
|
data.pageId || 0, data.caption, data.captionSave, data.pageLayout, data.iconImage,
|
|
data.minRank, data.visible === '1', data.enabled === '1',
|
|
data.orderNum, data.parentId,
|
|
data.pageHeadline || '', data.pageTeaser || '', data.pageTextDetails || '', currentType, data.catalogMode,
|
|
data.pageText1 || ''
|
|
));
|
|
}, [ currentType ]);
|
|
|
|
const createPage = useCallback((data: IPageEditData) =>
|
|
{
|
|
setLoading(true);
|
|
setLastError(null);
|
|
pendingActionRef.current = 'createPage';
|
|
SendMessageComposer(new CatalogAdminCreatePageComposer(
|
|
data.caption, data.captionSave, data.pageLayout, data.iconImage,
|
|
data.minRank, data.visible === '1', data.enabled === '1',
|
|
data.orderNum, data.parentId, currentType, data.catalogMode
|
|
));
|
|
}, [ currentType ]);
|
|
|
|
const deletePage = useCallback((pageId: number) =>
|
|
{
|
|
setLoading(true);
|
|
setLastError(null);
|
|
pendingActionRef.current = 'deletePage';
|
|
SendMessageComposer(new CatalogAdminDeletePageComposer(pageId, currentType));
|
|
}, [ currentType ]);
|
|
|
|
const saveOffer = useCallback((data: IOfferEditData) =>
|
|
{
|
|
setLoading(true);
|
|
setLastError(null);
|
|
pendingActionRef.current = 'saveOffer';
|
|
SendMessageComposer(new CatalogAdminSaveOfferComposer(
|
|
data.offerId || 0, data.pageId, data.itemIds || '',
|
|
data.catalogName, data.costCredits, data.costPoints, data.pointsType,
|
|
data.amount, data.clubOnly === '1' ? 1 : 0, data.extradata,
|
|
data.haveOffer === '1', data.offerId_group, data.limitedStack, data.orderNumber, currentType
|
|
));
|
|
}, [ currentType ]);
|
|
|
|
const createOffer = useCallback((data: IOfferEditData) =>
|
|
{
|
|
setLoading(true);
|
|
setLastError(null);
|
|
pendingActionRef.current = 'createOffer';
|
|
SendMessageComposer(new CatalogAdminCreateOfferComposer(
|
|
data.pageId, data.itemIds || '',
|
|
data.catalogName, data.costCredits, data.costPoints, data.pointsType,
|
|
data.amount, data.clubOnly === '1' ? 1 : 0, data.extradata,
|
|
data.haveOffer === '1', data.offerId_group, data.limitedStack, data.orderNumber, currentType
|
|
));
|
|
}, [ currentType ]);
|
|
|
|
const deleteOffer = useCallback((offerId: number) =>
|
|
{
|
|
setLoading(true);
|
|
setLastError(null);
|
|
pendingActionRef.current = 'deleteOffer';
|
|
SendMessageComposer(new CatalogAdminDeleteOfferComposer(offerId, currentType));
|
|
}, [ currentType ]);
|
|
|
|
const reorderOffers = useCallback((orders: { id: number; orderNumber: number }[]) =>
|
|
{
|
|
setLoading(true);
|
|
setLastError(null);
|
|
pendingActionRef.current = 'reorder';
|
|
|
|
for(const order of orders)
|
|
{
|
|
SendMessageComposer(new CatalogAdminMoveOfferComposer(order.id, order.orderNumber, currentType));
|
|
}
|
|
}, [ currentType ]);
|
|
|
|
const reorderPage = useCallback((pageId: number, newParentId: number, newIndex: number) =>
|
|
{
|
|
setLoading(true);
|
|
setLastError(null);
|
|
pendingActionRef.current = 'movePage';
|
|
SendMessageComposer(new CatalogAdminMovePageComposer(pageId, newParentId, newIndex, currentType));
|
|
}, [ currentType ]);
|
|
|
|
const togglePageEnabled = useCallback((pageId: number) =>
|
|
{
|
|
setLoading(true);
|
|
setLastError(null);
|
|
pendingActionRef.current = 'toggleEnabled';
|
|
SendMessageComposer(new CatalogAdminMovePageComposer(pageId, -1, -1, currentType));
|
|
}, [ currentType ]);
|
|
|
|
const togglePageVisible = useCallback((pageId: number) =>
|
|
{
|
|
setLoading(true);
|
|
setLastError(null);
|
|
pendingActionRef.current = 'toggleVisible';
|
|
SendMessageComposer(new CatalogAdminMovePageComposer(pageId, -2, -1, currentType));
|
|
}, [ currentType ]);
|
|
|
|
const publishCatalog = useCallback(() =>
|
|
{
|
|
setLoading(true);
|
|
setLastError(null);
|
|
pendingActionRef.current = 'publish';
|
|
SendMessageComposer(new CatalogAdminPublishComposer());
|
|
}, []);
|
|
|
|
return (
|
|
<CatalogAdminContext value={ {
|
|
adminMode, setAdminMode,
|
|
editingOffer, setEditingOffer,
|
|
editingPageData, setEditingPageData,
|
|
editingRootPage, setEditingRootPage,
|
|
editingPageNode, setEditingPageNode,
|
|
loading, lastError, hasPendingChanges,
|
|
savePage, createPage, deletePage,
|
|
saveOffer, createOffer, deleteOffer,
|
|
reorderOffers, reorderPage, togglePageEnabled, togglePageVisible,
|
|
publishCatalog
|
|
} }>
|
|
{ children }
|
|
</CatalogAdminContext>
|
|
);
|
|
};
|