crap
This commit is contained in:
@@ -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, () => ({
|
||||
|
||||
@@ -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"}>
|
||||
|
||||
3
src/components/PlusMinusInput/PlusMinusInput.module.css
Normal file
3
src/components/PlusMinusInput/PlusMinusInput.module.css
Normal file
@@ -0,0 +1,3 @@
|
||||
.number-input {
|
||||
width: rem(50);
|
||||
}
|
||||
97
src/components/PlusMinusInput/PlusMinusInput.tsx
Normal file
97
src/components/PlusMinusInput/PlusMinusInput.tsx
Normal 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;
|
||||
63
src/components/ServiceSelect/ServiceSelect.tsx
Normal file
63
src/components/ServiceSelect/ServiceSelect.tsx
Normal 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;
|
||||
Reference in New Issue
Block a user