@craftercms/studio-ui
Version:
Services, components, models & utils to build CrafterCMS authoring extensions.
158 lines (156 loc) • 5.97 kB
JavaScript
/*
* Copyright (C) 2007-2022 Crafter Software Corporation. All Rights Reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Copyright (C) 2007-2023 Crafter Software Corporation. All Rights Reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { createLookupTable } from '../../utils/object';
function intersection(listItemsA, listItemsB) {
return listItemsA.filter((itemA) => listItemsB.find((itemB) => itemA.id === itemB.id));
}
export function excludeCommonItems(listItemsA, listItemsB) {
return listItemsA.filter((itemA) => !listItemsB.find((itemB) => itemA.id === itemB.id));
}
export const filterTransferListItemsByKeyword = (items, keyword) => {
var _a;
return (_a =
items === null || items === void 0
? void 0
: items.filter((item) => `${item.title}${item.subtitle}`.toLowerCase().includes(keyword.toLowerCase()))) !==
null && _a !== void 0
? _a
: null;
};
export const useTransferListState = () => {
const [sourceItems, setSourceItems] = useState([]);
const [targetItems, setTargetItems] = useState([]);
const [checkedList, setCheckedList] = useState({});
const [sourceFilterKeyword, setSourceFilterKeyword] = useState('');
const [targetFilterKeyword, setTargetFilterKeyword] = useState('');
// Client-side filtered items
const filteredSourceItems = filterTransferListItemsByKeyword(sourceItems, sourceFilterKeyword);
const filteredTargetItems = filterTransferListItemsByKeyword(targetItems, targetFilterKeyword);
const [itemsLookup, setItemsLookup] = useState({});
const itemsLookupRef = useRef({});
itemsLookupRef.current = itemsLookup;
useEffect(() => {
setItemsLookup(
Object.assign(
Object.assign(Object.assign({}, itemsLookupRef.current), createLookupTable(sourceItems)),
createLookupTable(targetItems)
)
);
}, [sourceItems, targetItems]);
const isAllChecked = useCallback(
(items) => {
return (items === null || items === void 0 ? void 0 : items.length)
? !items.some(
(item) =>
!Object.keys(checkedList).find(function (checked) {
return checked === item.id && checkedList[checked];
})
)
: false;
},
[checkedList]
);
const getChecked = (items) => {
return intersection(
Object.keys(checkedList)
.filter((key) => checkedList[key])
.map((id) => itemsLookup[id]),
items
);
};
const disableAdd = getChecked(sourceItems).length === 0;
const disableRemove = getChecked(targetItems).length === 0;
const onItemClicked = (item) => {
if (checkedList[item.id]) {
setCheckedList(Object.assign(Object.assign({}, checkedList), { [item.id]: false }));
} else {
setCheckedList(Object.assign(Object.assign({}, checkedList), { [item.id]: true }));
}
};
const onCheckAllClicked = (items, checked) => {
const nextCheckedList = {};
items.forEach((item) => {
nextCheckedList[item.id] = checked;
});
setCheckedList(Object.assign(Object.assign({}, checkedList), nextCheckedList));
};
const addToTarget = () => {
const nextCheckedList = {};
const leftCheckedItems = getChecked(sourceItems);
if (leftCheckedItems.length) {
leftCheckedItems.forEach((item) => (nextCheckedList[item.id] = false));
setCheckedList(Object.assign(Object.assign({}, checkedList), nextCheckedList));
setSourceItems(excludeCommonItems(sourceItems, leftCheckedItems));
setTargetItems([...targetItems, ...leftCheckedItems]);
}
};
const removeFromTarget = () => {
const nextCheckedList = {};
const rightCheckedItems = getChecked(targetItems);
if (rightCheckedItems.length) {
rightCheckedItems.forEach((item) => (nextCheckedList[item.id] = false));
setCheckedList(Object.assign(Object.assign({}, checkedList), nextCheckedList));
setTargetItems(excludeCommonItems(targetItems, rightCheckedItems));
setSourceItems([...sourceItems, ...rightCheckedItems]);
}
};
const sourceItemsAllChecked = useMemo(() => {
return isAllChecked(filteredSourceItems);
}, [isAllChecked, filteredSourceItems]);
const targetItemsAllChecked = useMemo(() => {
return isAllChecked(filteredTargetItems);
}, [isAllChecked, filteredTargetItems]);
return {
sourceItems,
setSourceItems,
sourceFilterKeyword,
setSourceFilterKeyword,
filteredSourceItems,
targetItems,
setTargetItems,
targetFilterKeyword,
setTargetFilterKeyword,
filteredTargetItems,
checkedList,
setCheckedList,
onItemClicked,
isAllChecked,
onCheckAllClicked,
getChecked,
disableAdd,
disableRemove,
sourceItemsAllChecked,
targetItemsAllChecked,
addToTarget,
removeFromTarget
};
};