import Spinner from '@components/admin/Spinner.js'; import { CheckboxField } from '@components/common/form/CheckboxField.js'; import { InputField } from '@components/common/form/InputField.js'; import { Button } from '@components/common/ui/Button.js'; import { Dialog, DialogContent, DialogHeader, DialogTrigger, DialogTitle } from '@components/common/ui/Dialog.js'; import { Input } from '@components/common/ui/Input.js'; import { Item, ItemContent } from '@components/common/ui/Item.js'; import { DndContext, closestCenter, KeyboardSensor, PointerSensor, useSensor, useSensors } from '@dnd-kit/core'; import { arrayMove, SortableContext, sortableKeyboardCoordinates, verticalListSortingStrategy } from '@dnd-kit/sortable'; import { useSortable } from '@dnd-kit/sortable'; import { CSS } from '@dnd-kit/utilities'; import React, { useEffect } from 'react'; import { useFormContext } from 'react-hook-form'; import CreatableSelect from 'react-select/creatable'; import uniqid from 'uniqid'; import { useQuery } from 'urql'; import './BasicMenuSetting.scss'; const menuQuery = ` query Query ($filters: [FilterInput]) { categories (filters: $filters) { items { value: uuid, label: name path { name } } } cmsPages (filters: $filters) { items { value: uuid, label: name } } } `; interface MenuItem { id: string; name: string; url: string; type: string; uuid: string; children: MenuItem[]; } interface SortableMenuItemProps { item: MenuItem; updateItem: (item: MenuItem) => void; deleteItem: (item: MenuItem) => void; isChild?: boolean; } const SortableMenuItem: React.FC = ({ item, updateItem, deleteItem, isChild = false }) => { const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ id: item.id }); const [dialogOpen, setDialogOpen] = React.useState(false); const style = { transform: CSS.Transform.toString(transform), transition, opacity: isDragging ? 0.5 : 1 }; const [itemInEdit, setItemInEdit] = React.useState(item); const addChildren = (i) => { updateItem({ ...item, children: [...item.children, i] }); }; const updateItemFunc = (i) => { if (i.id === item.id) { updateItem(i); } else { addChildren(i); } setDialogOpen(false); }; return (
{item.name}
{!isChild && ( )}
{`Edit Menu Item: ${itemInEdit.name}`}
); }; const MenuSettingPopup: React.FC<{ item: MenuItem; updateItem: (item: MenuItem) => void; }> = ({ item, updateItem }) => { const [currentItem, setCurrentItem] = React.useState(item); const [err, setErr] = React.useState(null); const [result] = useQuery({ query: menuQuery, variables: { filters: [] } }); const { data, fetching, error } = result; if (fetching) { return ( ); } if (error) { return (
{error.message}
); } const groupOptions = [ { label: 'Categories', options: data.categories.items.map((i) => ({ ...i, label: i.path.map((p) => p.name).join(' > ') })) }, { label: 'CMS Pages', options: data.cmsPages.items }, { label: 'Custom', options: currentItem.type === 'custom' ? [ { value: currentItem.uuid, label: currentItem.uuid } ] : [] } ]; const handleCreate = (inputValue) => { setCurrentItem({ ...item, uuid: inputValue, name: inputValue, url: inputValue, type: 'custom' }); }; return (
setCurrentItem({ ...currentItem, name: e.target.value }) } className="w-full " />
{ setCurrentItem({ ...currentItem, uuid: newValue?.value || '', name: newValue?.label || '', type: newValue?.__typename === 'Category' ? 'category' : 'page' }); }} onCreateOption={handleCreate} options={groupOptions} value={{ value: currentItem.uuid, label: currentItem.type === 'custom' ? currentItem.uuid : [...groupOptions[0].options, ...groupOptions[1].options].find( (option) => option.value === currentItem.uuid )?.label || '' }} />
{err &&
{err}
}
); }; interface BasicMenuSettingProps { basicMenuWidget: { menus: MenuItem[]; isMain: boolean; className: string; }; } export default function BasicMenuSetting({ basicMenuWidget: { menus, isMain, className } }: BasicMenuSettingProps) { const { register, setValue } = useFormContext(); const [items, setItems] = React.useState(menus); const [dialogOpen, setDialogOpen] = React.useState(false); const sensors = useSensors( useSensor(PointerSensor), useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates }) ); const handleDragEnd = (event) => { const { active, over } = event; if (active.id !== over.id) { setItems((items) => { const oldIndex = items.findIndex((item) => item.id === active.id); const newIndex = items.findIndex((item) => item.id === over.id); return arrayMove(items, oldIndex, newIndex); }); } }; const handleChildDragEnd = (event, parentId) => { const { active, over } = event; if (active.id !== over.id) { setItems((items) => { return items.map((item) => { if (item.id === parentId) { const oldIndex = item.children.findIndex( (child) => child.id === active.id ); const newIndex = item.children.findIndex( (child) => child.id === over.id ); return { ...item, children: arrayMove(item.children, oldIndex, newIndex) }; } return item; }); }); } }; const updateItem = (item) => { setItems((prevItems) => { const newItems = prevItems.map((prevItem) => { if (prevItem.id === item.id) { return item; } else if (prevItem.children.length > 0) { return { ...prevItem, children: prevItem.children.map((child) => { if (child.id === item.id) { return item; } return child; }) }; } return prevItem; }); return newItems; }); }; const deleteItem = (item) => { setItems((prevItems) => { const newItems = prevItems.filter((prevItem) => { if (prevItem.id === item.id) { return false; } else if (prevItem.children.length > 0) { prevItem.children = prevItem.children.filter( (child) => child.id !== item.id ); } return true; }); return newItems; }); }; useEffect(() => { setValue('settings.menus', items); }, [items]); return ( <> item.id)} strategy={verticalListSortingStrategy} >
{items.map((menu) => (
{menu.children && menu.children.length > 0 && (
handleChildDragEnd(event, menu.id)} > child.id)} strategy={verticalListSortingStrategy} >
{menu.children.map((child) => ( ))}
)}
))}
Add Menu Item { setItems((prevItems) => [...prevItems, item]); setDialogOpen(false); }} />
); } export const query = ` query Query($settings: JSON) { basicMenuWidget(settings: $settings) { menus { id name url type uuid children { id name url type uuid } } isMain className } } `; export const variables = `{ settings: getWidgetSetting() }`;