RC-10: add new custom hooks
This commit is contained in:
@@ -1,20 +1,3 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
export function useWindowDimensions() {
|
||||
const getWindowDimensions = () => {
|
||||
const { innerWidth: width, innerHeight: height } = window;
|
||||
|
||||
return { width, height };
|
||||
};
|
||||
const [windowDimensions, setWindowDimensions] = useState(getWindowDimensions());
|
||||
|
||||
useEffect(() => {
|
||||
const onRecize = () => setWindowDimensions(getWindowDimensions());
|
||||
|
||||
window.addEventListener('resize', onRecize);
|
||||
|
||||
return () => window.removeEventListener('resize', onRecize);
|
||||
}, []);
|
||||
|
||||
return windowDimensions;
|
||||
}
|
||||
export { default as useWindowDimensions } from './useWindowDimensions';
|
||||
export { default as useOnClickOutside } from './useOnClickOutside';
|
||||
export { default as usePropertiesHeader } from './usePropertiesHeader';
|
||||
|
||||
29
src/app/hooks/useOnClickOutside.js
Normal file
29
src/app/hooks/useOnClickOutside.js
Normal file
@@ -0,0 +1,29 @@
|
||||
import { useEffect } from 'react';
|
||||
|
||||
export default function useOnClickOutside(ref, handler) {
|
||||
useEffect(() => {
|
||||
const onEvent = (event) => {
|
||||
if (!ref.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event instanceof KeyboardEvent && event.key === 'Escape') {
|
||||
handler(event);
|
||||
} else if (ref.current.contains(event.target)) {
|
||||
return;
|
||||
}
|
||||
|
||||
handler(event);
|
||||
};
|
||||
|
||||
document.addEventListener('mousedown', onEvent);
|
||||
document.addEventListener('touchstart', onEvent);
|
||||
document.addEventListener('keydown', onEvent);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('mousedown', onEvent);
|
||||
document.removeEventListener('touchstart', onEvent);
|
||||
document.removeEventListener('keydown', onEvent);
|
||||
};
|
||||
}, [ref, handler]);
|
||||
}
|
||||
105
src/app/hooks/usePropertiesHeader.js
Normal file
105
src/app/hooks/usePropertiesHeader.js
Normal file
@@ -0,0 +1,105 @@
|
||||
import { PROPERTIES_LAYOUTS } from 'app/configs/consts';
|
||||
import { useState, useMemo, useCallback, useEffect } from 'react';
|
||||
|
||||
export default function usePropertiesHeader(items) {
|
||||
const [categories, setCategories] = useState([
|
||||
{
|
||||
name: 'all',
|
||||
amount: 0,
|
||||
active: true,
|
||||
},
|
||||
]);
|
||||
const [layouts, setLayouts] = useState([
|
||||
{ name: PROPERTIES_LAYOUTS.list, active: true },
|
||||
{ name: PROPERTIES_LAYOUTS.grid, active: false },
|
||||
]);
|
||||
|
||||
const activeCategory = useMemo(
|
||||
() => categories.find(({ active }) => active)?.name ?? categories[0].name,
|
||||
[categories]
|
||||
);
|
||||
const activeLayout = useMemo(
|
||||
() => layouts.find(({ active }) => active)?.name ?? PROPERTIES_LAYOUTS.list,
|
||||
[layouts]
|
||||
);
|
||||
|
||||
const onCategory = useCallback(
|
||||
(value) => {
|
||||
if (value === activeCategory) {
|
||||
return;
|
||||
}
|
||||
|
||||
setCategories((prevState) =>
|
||||
prevState.map((category) => ({ ...category, active: category.name === value }))
|
||||
);
|
||||
},
|
||||
[activeCategory]
|
||||
);
|
||||
|
||||
const onLayout = useCallback(
|
||||
(value) => {
|
||||
if (value === activeLayout) {
|
||||
return;
|
||||
}
|
||||
|
||||
setLayouts((prevState) => prevState.map(({ name }) => ({ name, active: name === value })));
|
||||
},
|
||||
[activeLayout]
|
||||
);
|
||||
|
||||
const onItemDelete = (itemCategory) => {
|
||||
setCategories((prevState) => {
|
||||
const isItemCategoryLast =
|
||||
prevState.find((category) => category.name === itemCategory)?.amount === 1;
|
||||
|
||||
return prevState
|
||||
.map((category, idx) => {
|
||||
if (!idx) {
|
||||
return {
|
||||
name: category.name,
|
||||
amount: category.amount - 1,
|
||||
active: isItemCategoryLast,
|
||||
};
|
||||
}
|
||||
|
||||
if (category?.name === itemCategory) {
|
||||
if (category.amount > 1) {
|
||||
return { ...category, amount: category.amount - 1 };
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return category;
|
||||
})
|
||||
.filter((category) => category);
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
let updatedCategories = [...categories];
|
||||
items.forEach((item) => {
|
||||
const hasItemCategory = updatedCategories.find((category) => category.name === item.category);
|
||||
updatedCategories = updatedCategories.map((category, idx) => {
|
||||
if (!idx) {
|
||||
category.amount += 1;
|
||||
}
|
||||
|
||||
return category;
|
||||
});
|
||||
|
||||
if (hasItemCategory) {
|
||||
updatedCategories = updatedCategories.map((category) => ({
|
||||
...category,
|
||||
amount: item.category === category.name ? category.amount + 1 : category.amount,
|
||||
}));
|
||||
} else {
|
||||
updatedCategories.push({ name: item.category, amount: 1, active: false });
|
||||
}
|
||||
});
|
||||
setCategories(updatedCategories);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
return { categories, activeCategory, onCategory, layouts, activeLayout, onLayout, onItemDelete };
|
||||
}
|
||||
20
src/app/hooks/useWindowDimensions.js
Normal file
20
src/app/hooks/useWindowDimensions.js
Normal file
@@ -0,0 +1,20 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
export default function useWindowDimensions() {
|
||||
const getWindowDimensions = () => {
|
||||
const { innerWidth: width, innerHeight: height } = window;
|
||||
|
||||
return { width, height };
|
||||
};
|
||||
const [windowDimensions, setWindowDimensions] = useState(getWindowDimensions());
|
||||
|
||||
useEffect(() => {
|
||||
const onRecize = () => setWindowDimensions(getWindowDimensions());
|
||||
|
||||
window.addEventListener('resize', onRecize);
|
||||
|
||||
return () => window.removeEventListener('resize', onRecize);
|
||||
}, []);
|
||||
|
||||
return windowDimensions;
|
||||
}
|
||||
Reference in New Issue
Block a user