mirror of
https://github.com/usual2970/certimate.git
synced 2025-06-07 21:19:51 +00:00
85 lines
2.6 KiB
TypeScript
85 lines
2.6 KiB
TypeScript
import { useEffect, useState } from "react";
|
|
import { Avatar, Select, type SelectProps, Space, Typography } from "antd";
|
|
|
|
import { type AccessModel } from "@/domain/access";
|
|
import { accessProvidersMap } from "@/domain/provider";
|
|
import { useZustandShallowSelector } from "@/hooks";
|
|
import { useAccessesStore } from "@/stores/access";
|
|
|
|
export type AccessTypeSelectProps = Omit<
|
|
SelectProps,
|
|
"filterOption" | "filterSort" | "labelRender" | "loading" | "options" | "optionFilterProp" | "optionLabelProp" | "optionRender"
|
|
> & {
|
|
filter?: (record: AccessModel) => boolean;
|
|
};
|
|
|
|
const AccessSelect = ({ filter, ...props }: AccessTypeSelectProps) => {
|
|
const { accesses, loadedAtOnce, fetchAccesses } = useAccessesStore(useZustandShallowSelector(["accesses", "loadedAtOnce", "fetchAccesses"]));
|
|
useEffect(() => {
|
|
fetchAccesses();
|
|
}, []);
|
|
|
|
const [options, setOptions] = useState<Array<{ key: string; value: string; label: string; data: AccessModel }>>([]);
|
|
useEffect(() => {
|
|
const filteredItems = filter != null ? accesses.filter(filter) : accesses;
|
|
setOptions(
|
|
filteredItems.map((item) => ({
|
|
key: item.id,
|
|
value: item.id,
|
|
label: item.name,
|
|
data: item,
|
|
}))
|
|
);
|
|
}, [accesses, filter]);
|
|
|
|
const renderOption = (key: string) => {
|
|
const access = accesses.find((e) => e.id === key);
|
|
if (!access) {
|
|
return (
|
|
<Space className="max-w-full grow truncate" size={4}>
|
|
<Avatar size="small" />
|
|
<Typography.Text className="leading-loose" ellipsis>
|
|
{key}
|
|
</Typography.Text>
|
|
</Space>
|
|
);
|
|
}
|
|
|
|
const provider = accessProvidersMap.get(access.provider);
|
|
return (
|
|
<Space className="max-w-full grow truncate" size={4}>
|
|
<Avatar src={provider?.icon} size="small" />
|
|
<Typography.Text className="leading-loose" ellipsis>
|
|
{access.name}
|
|
</Typography.Text>
|
|
</Space>
|
|
);
|
|
};
|
|
|
|
return (
|
|
<Select
|
|
{...props}
|
|
filterOption={(inputValue, option) => {
|
|
if (!option) return false;
|
|
|
|
const value = inputValue.toLowerCase();
|
|
return option.label.toLowerCase().includes(value);
|
|
}}
|
|
labelRender={({ label, value }) => {
|
|
if (label) {
|
|
return renderOption(value as string);
|
|
}
|
|
|
|
return <Typography.Text type="secondary">{props.placeholder}</Typography.Text>;
|
|
}}
|
|
loading={!loadedAtOnce}
|
|
options={options}
|
|
optionFilterProp="label"
|
|
optionLabelProp={undefined}
|
|
optionRender={(option) => renderOption(option.data.value)}
|
|
/>
|
|
);
|
|
};
|
|
|
|
export default AccessSelect;
|