feat: services kit and copy
This commit is contained in:
		@@ -1,42 +1,77 @@
 | 
			
		||||
import {MultiSelect, MultiSelectProps} from "@mantine/core";
 | 
			
		||||
import {useEffect, useMemo, useState} from "react";
 | 
			
		||||
import {ObjectWithNameAndId} from "../../types/utils.ts";
 | 
			
		||||
import {groupBy} from "lodash";
 | 
			
		||||
 | 
			
		||||
interface ObjectWithIdAndName {
 | 
			
		||||
    id: number,
 | 
			
		||||
    name: string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type MultiselectObjectType<T extends ObjectWithNameAndId> = T;
 | 
			
		||||
export type MultiselectObjectType<T> = T;
 | 
			
		||||
 | 
			
		||||
type ControlledValueProps<T extends ObjectWithNameAndId> = {
 | 
			
		||||
type ControlledValueProps<T> = {
 | 
			
		||||
    value: MultiselectObjectType<T>[],
 | 
			
		||||
    onChange: (value: MultiselectObjectType<T>[]) => void;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type RestProps<T extends ObjectWithNameAndId> = {
 | 
			
		||||
type CustomLabelAndKeyProps<T> = {
 | 
			
		||||
    getLabelFn: (item: MultiselectObjectType<T>) => string;
 | 
			
		||||
    getValueFn: (item: MultiselectObjectType<T>) => string;
 | 
			
		||||
}
 | 
			
		||||
type RestProps<T> = {
 | 
			
		||||
    defaultValue?: MultiselectObjectType<T>[]
 | 
			
		||||
    onChange: (value: MultiselectObjectType<T>[]) => void;
 | 
			
		||||
    data: MultiselectObjectType<T>[];
 | 
			
		||||
    groupBy?: (item: MultiselectObjectType<T>) => string;
 | 
			
		||||
    filterBy?: (item: MultiselectObjectType<T>) => boolean;
 | 
			
		||||
}
 | 
			
		||||
const defaultGetLabelFn = <T extends { name: string }>(item: T): string => {
 | 
			
		||||
    return item.name;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type ObjectMultiSelectProps<T extends ObjectWithNameAndId> =
 | 
			
		||||
const defaultGetValueFn = <T extends { id: number }>(item: T): string => {
 | 
			
		||||
    return item.id.toString();
 | 
			
		||||
}
 | 
			
		||||
export type ObjectMultiSelectProps<T> =
 | 
			
		||||
    (RestProps<T> & Partial<ControlledValueProps<T>>)
 | 
			
		||||
    & Omit<MultiSelectProps, 'value' | 'onChange' | 'data'>;
 | 
			
		||||
    & Omit<MultiSelectProps, 'value' | 'onChange' | 'data'>
 | 
			
		||||
    & (T extends ObjectWithIdAndName ? Partial<CustomLabelAndKeyProps<T>> : CustomLabelAndKeyProps<T>);
 | 
			
		||||
 | 
			
		||||
const ObjectMultiSelect = <T extends ObjectWithNameAndId, >(props: ObjectMultiSelectProps<T>) => {
 | 
			
		||||
const ObjectMultiSelect = <T, >(props: ObjectMultiSelectProps<T>) => {
 | 
			
		||||
 | 
			
		||||
    const isControlled = 'value' in props;
 | 
			
		||||
    const haveGetValueFn = 'getValueFn' in props;
 | 
			
		||||
    const haveGetLabelFn = 'getLabelFn' in props;
 | 
			
		||||
 | 
			
		||||
    const [internalValue, setInternalValue] = useState<MultiselectObjectType<T>[] | undefined>(props.defaultValue);
 | 
			
		||||
 | 
			
		||||
    const value = (isControlled ? props.value : internalValue) || [];
 | 
			
		||||
 | 
			
		||||
    const data = useMemo(() => props.data.reduce((acc, item) => {
 | 
			
		||||
        acc.push({
 | 
			
		||||
            label: item.name,
 | 
			
		||||
            value: item.id.toString()
 | 
			
		||||
        });
 | 
			
		||||
        return acc;
 | 
			
		||||
    }, [] as { label: string, value: string }[]), [props.data]);
 | 
			
		||||
    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) {
 | 
			
		||||
 | 
			
		||||
            const groupedData = groupBy(propsData, props.groupBy);
 | 
			
		||||
            return Object.entries(groupedData).map(([group, items]) => ({
 | 
			
		||||
                group,
 | 
			
		||||
                items: items.map(item => ({
 | 
			
		||||
                    label: getLabelFn(item),
 | 
			
		||||
                    value: getValueFn(item)
 | 
			
		||||
                }))
 | 
			
		||||
            }));
 | 
			
		||||
        } else {
 | 
			
		||||
            return propsData.map(item => ({
 | 
			
		||||
                label: getLabelFn(item),
 | 
			
		||||
                value: getValueFn(item)
 | 
			
		||||
            }));
 | 
			
		||||
        }
 | 
			
		||||
    }, [props.data, props.groupBy]);
 | 
			
		||||
 | 
			
		||||
    const handleOnChange = (event: string[]) => {
 | 
			
		||||
        const objects = props.data.filter(item => event.includes(item.id.toString()));
 | 
			
		||||
        const objects = props.data.filter(item => event.includes(getValueFn(item)));
 | 
			
		||||
        if (isControlled) {
 | 
			
		||||
            props.onChange(objects);
 | 
			
		||||
            return;
 | 
			
		||||
@@ -51,7 +86,7 @@ const ObjectMultiSelect = <T extends ObjectWithNameAndId, >(props: ObjectMultiSe
 | 
			
		||||
    return (
 | 
			
		||||
        <MultiSelect
 | 
			
		||||
            {...props}
 | 
			
		||||
            value={value.map(item => item.id.toString())}
 | 
			
		||||
            value={value.map(item => getValueFn(item))}
 | 
			
		||||
            onChange={handleOnChange}
 | 
			
		||||
            data={data}
 | 
			
		||||
        />
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user