This commit is contained in:
2024-04-11 07:57:01 +03:00
parent 4ce516307d
commit 18157972a1
30 changed files with 911 additions and 50 deletions

View File

@@ -7,10 +7,11 @@ import {
useMantineReactTable
} from "mantine-react-table";
import {MRT_Localization_RU} from "mantine-react-table/locales/ru/index.cjs";
import {forwardRef, useImperativeHandle} from 'react';
import {forwardRef, useEffect, useImperativeHandle} from 'react';
type Props<T extends Record<string, any>, K extends keyof T> = {
data: T[],
onSelectionChange?: (selectedRows: T[]) => void,
columns: MRT_ColumnDef<T>[],
restProps?: MRT_TableOptions<T>,
striped?: boolean
@@ -23,7 +24,7 @@ export type BaseTableRef<T extends MRT_RowData> = {
};
export const BaseTable = forwardRef<BaseTableRef<any>, Props<any>>((props, ref) => {
const {data, columns, restProps, striped} = props;
const {data, columns, restProps, striped, onSelectionChange} = props;
const table = useMantineReactTable({
localization: MRT_Localization_RU,
@@ -34,8 +35,14 @@ export const BaseTable = forwardRef<BaseTableRef<any>, Props<any>>((props, ref)
striped: striped
},
enableTopToolbar: false,
enableBottomToolbar: false,
enableRowSelection: onSelectionChange !== undefined,
...restProps,
});
useEffect(() => {
if (!onSelectionChange) return;
onSelectionChange(table.getSelectedRowModel().rows.map(row => row.original))
}, [table.getState().rowSelection]);
// Используем useImperativeHandle для определения, что будет доступно через ref
useImperativeHandle(ref, () => ({

View File

@@ -1,17 +1,25 @@
import {FC} from "react";
import {DealSummary} from "../../../client";
import {DealService, DealSummary} from "../../../client";
import styles from './DealSummaryCard.module.css';
import {Text} from '@mantine/core';
import classNames from "classnames";
import {useDealPageContext} from "../../../pages/LeadsPage/contexts/DealPageContext.tsx";
type Props = {
dealSummary: DealSummary
}
const DealSummaryCard: FC<Props> = ({dealSummary}) => {
const {setSelectedDeal} = useDealPageContext();
const onDealSummaryClick = () => {
DealService.getDealById({dealId: dealSummary.id})
.then((deal) => {
setSelectedDeal(deal);
})
}
return (
<div className={styles['container']}>
<div onClick={() => onDealSummaryClick()} className={styles['container']}>
<div className={styles['flex-row']}>
<div className={styles['flex-item']}>
<Text size={"sm"} c={"gray.6"}>

View File

@@ -0,0 +1,3 @@
.number-input {
width: rem(50);
}

View File

@@ -0,0 +1,97 @@
import {ActionIcon, Flex, NumberInput, rem} from "@mantine/core";
import {IconMinus, IconPlus} from "@tabler/icons-react";
import styles from './PlusMinusInput.module.css';
import {FC, useEffect, useState} from "react";
type ControlledValueProps = {
value: number;
onChange: (value: number) => void;
}
type RestProps = {
defaultValue?: number;
onChange: (value: number) => void;
}
type Props = RestProps & Partial<ControlledValueProps>;
const PlusMinusInput: FC<Props> = (props: Props) => {
const isControlled = props.value !== undefined;
const [internalValue, setInternalValue] = useState(props.defaultValue || 0);
const value = isControlled ? props.value : internalValue;
const onMinusClick = () => {
const newValue = (value || 0) - 1;
if (newValue < 0) {
return;
}
if (isControlled) {
props.onChange(newValue);
} else {
setInternalValue(newValue);
}
}
const onPlusClick = () => {
const newValue = (value || 0) + 1;
if (isControlled) {
props.onChange(newValue);
} else {
setInternalValue(newValue);
}
}
const handleInputChange = (event: number | string) => {
let newValue = typeof event === "string" ? 0 : event;
if (isNaN(newValue) || newValue < 0) {
newValue = 0;
}
if (isControlled) {
props.onChange(newValue);
} else {
setInternalValue(newValue);
}
}
useEffect(() => {
if (!isControlled) {
props.onChange(internalValue);
}
}, [internalValue]);
return (
<Flex
align={"center"}
gap={rem(10)}
>
<ActionIcon
disabled={value === 0}
onClick={onMinusClick}
variant={"default"}>
<IconMinus/>
</ActionIcon>
<NumberInput
min={0}
styles={{
input: {
textAlign: "center"
}
}}
allowNegative={false}
hideControls
value={value}
className={styles['number-input']}
onChange={(event) => handleInputChange(event)}
/>
<ActionIcon
onClick={onPlusClick}
variant={"default"}>
<IconPlus/>
</ActionIcon>
</Flex>
)
}
export default PlusMinusInput;

View File

@@ -0,0 +1,63 @@
import {ServiceSchema} from "../../client";
import {FC, useEffect, useMemo, useState} from "react";
import {Select, SelectProps} from "@mantine/core";
import useServicesList from "../../pages/ServicesPage/hooks/useServicesList.tsx";
type ControlledValueProps = {
value: ServiceSchema;
onChange: (value: ServiceSchema) => void;
}
type RestProps = {
defaultValue?: ServiceSchema;
onChange: (value: ServiceSchema) => void;
}
type Props = (RestProps & Partial<ControlledValueProps>) & Omit<SelectProps, 'value' | 'onChange'>;
const ServiceSelect: FC<Props> = (props) => {
const isControlled = props.value !== undefined;
const [internalValue, setInternalValue] = useState<ServiceSchema | undefined>(props.defaultValue);
const value = isControlled ? props.value : internalValue;
const {services} = useServicesList();
const categories = useMemo(() => services.reduce((acc, service) => {
if (!acc.includes(service.category.name)) {
acc.push(service.category.name);
}
return acc;
}, [] as string[]), [services]);
const data = useMemo(() => categories.map(category => ({
group: category,
items: services.filter(service => service.category.name === category)
.map(service => ({
value: service.id.toString(),
label: service.name
}))
})), [services, categories]);
const handleOnChange = (value: string) => {
if (isControlled) {
props.onChange(services.find(service => service.id.toString() === value) as ServiceSchema);
return;
}
setInternalValue(services.find(service => service.id.toString() === value) as ServiceSchema);
}
useEffect(() => {
if (!isControlled) {
props.onChange(internalValue as ServiceSchema);
}
}, [internalValue]);
return (
<Select
{...props}
value={value?.id.toString()}
withCheckIcon={false}
searchable
onChange={event => event && handleOnChange(event)}
data={data}
/>
)
}
export default ServiceSelect;