This commit is contained in:
2024-07-20 09:32:01 +03:00
parent 5c6e7cf5f5
commit 54c9ca8908
48 changed files with 1057 additions and 87 deletions

View File

@@ -1,35 +1,55 @@
import {Select, SelectProps} from "@mantine/core";
import {useEffect, useMemo, useState} from "react";
import {ObjectWithNameAndId} from "../../types/utils.ts";
import {groupBy, omit} from "lodash";
interface ObjectWithIdAndName {
id: number,
name: string
}
export type SelectObjectType<T extends ObjectWithNameAndId> = T;
export type SelectObjectType<T> = T;
type ControlledValueProps<T extends ObjectWithNameAndId> = {
type ControlledValueProps<T> = {
value: SelectObjectType<T>,
onChange: (value: SelectObjectType<T>) => void;
}
type CustomLabelAndKeyProps<T> = {
getLabelFn: (item: SelectObjectType<T>) => string;
getValueFn: (item: SelectObjectType<T>) => string;
}
type RestProps<T extends ObjectWithNameAndId> = {
type RestProps<T> = {
defaultValue?: SelectObjectType<T>
onChange: (value: SelectObjectType<T>) => void;
data: SelectObjectType<T>[];
groupBy?: (item: SelectObjectType<T>) => string;
filterBy?: (item: SelectObjectType<T>) => boolean;
};
const defaultGetLabelFn = <T extends { name: string }>(item: T): string => {
return item.name;
}
export type ObjectSelectProps<T extends ObjectWithNameAndId> =
const defaultGetValueFn = <T extends { id: number }>(item: T): string => {
return item.id.toString();
}
export type ObjectSelectProps<T> =
(RestProps<T> & Partial<ControlledValueProps<T>>)
& Omit<SelectProps, 'value' | 'onChange' | 'data'>;
& Omit<SelectProps, 'value' | 'onChange' | 'data'>
& (T extends ObjectWithIdAndName ? Partial<CustomLabelAndKeyProps<T>> : CustomLabelAndKeyProps<T>)
const ObjectSelect = <T extends ObjectWithNameAndId, >(props: ObjectSelectProps<T>) => {
const ObjectSelect = <T, >(props: ObjectSelectProps<T>) => {
const isControlled = 'value' in props;
const haveGetValueFn = 'getValueFn' in props;
const haveGetLabelFn = 'getLabelFn' in props;
const [internalValue, setInternalValue] = useState<SelectObjectType<T> | undefined>(props.defaultValue);
const value = isControlled ? props.value : internalValue;
const getValueFn = (haveGetValueFn && props.getValueFn) || defaultGetValueFn;
const getLabelFn = (haveGetLabelFn && props.getLabelFn) || defaultGetLabelFn;
const data = useMemo(() => {
const propsData = props.filterBy ? props.data.filter(props.filterBy) : props.data;
if (props.groupBy) {
@@ -38,21 +58,21 @@ const ObjectSelect = <T extends ObjectWithNameAndId, >(props: ObjectSelectProps<
return Object.entries(groupedData).map(([group, items]) => ({
group,
items: items.map(item => ({
label: item.name,
value: item.id.toString()
label: getLabelFn(item),
value: getValueFn(item)
}))
}));
} else {
return propsData.map(item => ({
label: item.name,
value: item.id.toString()
label: getLabelFn(item),
value: getValueFn(item)
}));
}
}, [props.data, props.groupBy]);
const handleOnChange = (event: string | null) => {
if (!event) return;
const object = props.data.find(item => parseInt(event) == item.id);
const object = props.data.find(item => event == getValueFn(item));
if (!object) return;
if (isControlled) {
props.onChange(object);
@@ -65,11 +85,11 @@ const ObjectSelect = <T extends ObjectWithNameAndId, >(props: ObjectSelectProps<
if (isControlled || !internalValue) return;
props.onChange(internalValue);
}, [internalValue]);
const restProps = omit(props, ['filterBy', 'groupBy']);
const restProps = omit(props, ['filterBy', 'groupBy', 'getValueFn', 'getLabelFn']);
return (
<Select
{...restProps}
value={value?.id.toString()}
value={value && getValueFn(value)}
onChange={handleOnChange}
data={data}
/>