147 lines
4.6 KiB
TypeScript
147 lines
4.6 KiB
TypeScript
import { useQuery, useWidgetProps } from './utils';
|
|
import { useEffect, useState, type KeyboardEvent } from 'react';
|
|
|
|
export type Section = {
|
|
name: string;
|
|
id: number;
|
|
has_subsections: 0 | 1;
|
|
}
|
|
|
|
type SectionRowProps = {
|
|
section: { name: string; id: number; full_path?: string };
|
|
depth?: number;
|
|
hasSubsections?: boolean;
|
|
};
|
|
|
|
function getEndpoint(sectionId: number) {
|
|
return `/admin/autocomplete/sections/${sectionId}`;
|
|
}
|
|
|
|
export function SectionRow({ section, hasSubsections, depth = 0 }: SectionRowProps) {
|
|
const [showChildren, setShowChildren] = useState(false);
|
|
const [shouldFetchChildren, setShouldFetchChildren] = useState(false);
|
|
const { data } = useQuery<Section[]>(shouldFetchChildren ? getEndpoint(section.id): undefined);
|
|
const { onAddSection, onAddWithSubsections, onSelect, hide, shouldHideAfterSelect } = useWidgetProps();
|
|
|
|
useEffect(() => {
|
|
if (!shouldFetchChildren) {
|
|
setShouldFetchChildren(showChildren);
|
|
}
|
|
}, [showChildren]);
|
|
|
|
function handleKeyboardNav(ev: KeyboardEvent<HTMLDivElement>) {
|
|
switch (ev.key) {
|
|
case 'ArrowLeft':
|
|
setShowChildren(false);
|
|
break;
|
|
|
|
case 'ArrowRight':
|
|
setShowChildren(true);
|
|
break;
|
|
|
|
case 'Enter':
|
|
if (ev.ctrlKey) {
|
|
if (onAddWithSubsections) {
|
|
onAddWithSubsections(section.id);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if (onAddSection) {
|
|
onAddSection(section.id);
|
|
}
|
|
|
|
if (onSelect) {
|
|
onSelect(section.id);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<div
|
|
tabIndex={-1}
|
|
className={`section-row${depth > 0 ? ' subsection' : ''}`}
|
|
style={{ paddingLeft: `${depth * 28}px` }}
|
|
onKeyUp={handleKeyboardNav}
|
|
>
|
|
<div
|
|
className="SectionRow__content"
|
|
onClick={ev => {
|
|
if (onSelect) {
|
|
ev.stopPropagation();
|
|
if (shouldHideAfterSelect) {
|
|
hide();
|
|
}
|
|
|
|
onSelect(section.id);
|
|
}
|
|
}}
|
|
>
|
|
<div className="SectionRow__left">
|
|
{!!hasSubsections && (
|
|
<div className="SectionRow__unwrap-button">
|
|
<span
|
|
onClick={ev => {
|
|
ev.stopPropagation();
|
|
setShowChildren(prev => !prev);
|
|
}}
|
|
className={`bi bi-dash-circle opener ${showChildren ? 'minus' : 'plus'}`}
|
|
/>
|
|
</div>
|
|
)}
|
|
<div className="SectionRow__name">
|
|
<strong>
|
|
{section.name}
|
|
</strong>
|
|
{!!section.full_path && (
|
|
<span className="SectionRow__full-path">{section.full_path}</span>
|
|
)}
|
|
</div>
|
|
</div>
|
|
<div className="SectionRow__buttons">
|
|
{!!onAddSection && (
|
|
<button
|
|
key="btn-add"
|
|
type="button"
|
|
className="btn btn-sm btn-primary"
|
|
onClick={ev => {
|
|
ev.stopPropagation();
|
|
onAddSection(section.id);
|
|
}}
|
|
>
|
|
<span className="bi bi-plus-lg m-r-1"></span> Přidat
|
|
</button>
|
|
)}
|
|
{!!onAddWithSubsections && (
|
|
<button
|
|
type="button"
|
|
key="btn-add-all"
|
|
className="btn btn-sm btn-secondary"
|
|
disabled={!hasSubsections}
|
|
onClick={ev => {
|
|
ev.stopPropagation();
|
|
onAddWithSubsections(section.id);
|
|
}}
|
|
>
|
|
<span className="bi bi-plus-lg m-r-1"></span> Včetně podsekcí
|
|
</button>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{showChildren && data?.map((child, i) => (
|
|
<SectionRow
|
|
section={child}
|
|
key={`c${section.id}-${child.id}-${i}`}
|
|
depth={depth + 1}
|
|
hasSubsections={child.has_subsections === 1}
|
|
/>
|
|
))}
|
|
</>
|
|
);
|
|
}
|