111 lines
3.1 KiB
React
111 lines
3.1 KiB
React
import React, {
|
|
useCallback,
|
|
useEffect,
|
|
useMemo,
|
|
useState,
|
|
} from 'react';
|
|
import PanelHeader from '../ui/PanelHeader';
|
|
import { DEFAULT_SETTINGS_SECTIONS } from './sections';
|
|
|
|
const SettingsModal = ({
|
|
open = false,
|
|
onClose,
|
|
sections,
|
|
defaultSectionId,
|
|
...sectionProps
|
|
}) => {
|
|
const sectionList = useMemo(() => {
|
|
if (Array.isArray(sections) && sections.length) {
|
|
return sections;
|
|
}
|
|
return DEFAULT_SETTINGS_SECTIONS;
|
|
}, [sections]);
|
|
|
|
const firstSectionId = sectionList[0]?.id ?? null;
|
|
const resolvedDefaultSection = defaultSectionId || firstSectionId;
|
|
|
|
const [activeSection, setActiveSection] = useState(resolvedDefaultSection);
|
|
|
|
useEffect(() => {
|
|
if (!open) {
|
|
setActiveSection(resolvedDefaultSection);
|
|
return;
|
|
}
|
|
const hasActiveSection = sectionList.some((section) => section.id === activeSection);
|
|
if (!hasActiveSection) {
|
|
setActiveSection(resolvedDefaultSection);
|
|
}
|
|
}, [open, sectionList, resolvedDefaultSection, activeSection]);
|
|
|
|
const handleBackdropClick = useCallback(() => {
|
|
onClose?.();
|
|
}, [onClose]);
|
|
|
|
const handleInnerClick = useCallback((event) => {
|
|
event.stopPropagation();
|
|
}, []);
|
|
|
|
if (!open) {
|
|
return null;
|
|
}
|
|
|
|
const activeSectionConfig = sectionList.find((section) => section.id === activeSection);
|
|
let sectionContent = null;
|
|
if (activeSectionConfig) {
|
|
if (activeSectionConfig.component) {
|
|
const SectionComponent = activeSectionConfig.component;
|
|
sectionContent = <SectionComponent {...sectionProps} />;
|
|
} else if (typeof activeSectionConfig.render === 'function') {
|
|
sectionContent = activeSectionConfig.render(sectionProps);
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div className="modal-backdrop" role="presentation" onClick={handleBackdropClick}>
|
|
<div
|
|
className="modal modal--panel settings-modal"
|
|
role="dialog"
|
|
aria-modal="true"
|
|
aria-labelledby="settings-modal-title"
|
|
onClick={handleInnerClick}
|
|
>
|
|
<PanelHeader
|
|
className="panel-modal__header"
|
|
title="Settings"
|
|
titleTag="h3"
|
|
titleProps={{ id: 'settings-modal-title' }}
|
|
actions={(
|
|
<button type="button" className="secondary" onClick={onClose}>
|
|
Close
|
|
</button>
|
|
)}
|
|
/>
|
|
<div className="settings-modal__body">
|
|
<nav className="settings-modal__sidebar" aria-label="Settings sections">
|
|
<ul>
|
|
{sectionList.map((section) => (
|
|
<li key={section.id}>
|
|
<button
|
|
type="button"
|
|
className={section.id === activeSection ? 'active' : ''}
|
|
onClick={() => setActiveSection(section.id)}
|
|
>
|
|
{section.label}
|
|
</button>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</nav>
|
|
<div className="settings-modal__content">
|
|
{sectionContent || (
|
|
<p>Select a settings section.</p>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default SettingsModal;
|