feat: prettier
This commit is contained in:
@@ -1,44 +1,56 @@
|
||||
import {Select, SelectProps} from "@mantine/core";
|
||||
import { Select, SelectProps } from "@mantine/core";
|
||||
import useServiceCategoriesList from "../../hooks/useServiceCategoriesList.tsx";
|
||||
import {ServiceCategorySchema} from "../../../../client";
|
||||
import {FC, useEffect, useMemo, useState} from "react";
|
||||
import { ServiceCategorySchema } from "../../../../client";
|
||||
import { FC, useEffect, useMemo, useState } from "react";
|
||||
|
||||
type ControlledValueProps = {
|
||||
value: ServiceCategorySchema
|
||||
onChange: (value: ServiceCategorySchema) => void
|
||||
}
|
||||
value: ServiceCategorySchema;
|
||||
onChange: (value: ServiceCategorySchema) => void;
|
||||
};
|
||||
|
||||
type RestProps = {
|
||||
fullWidth?: boolean,
|
||||
defaultValue?: ServiceCategorySchema
|
||||
onChange: (category: ServiceCategorySchema) => void
|
||||
}
|
||||
type Props = (RestProps & Partial<ControlledValueProps>) & Omit<SelectProps, 'value' | 'onChange'>;
|
||||
fullWidth?: boolean;
|
||||
defaultValue?: ServiceCategorySchema;
|
||||
onChange: (category: ServiceCategorySchema) => void;
|
||||
};
|
||||
type Props = (RestProps & Partial<ControlledValueProps>) &
|
||||
Omit<SelectProps, "value" | "onChange">;
|
||||
const ServiceCategorySelect: FC<Props> = (props: Props) => {
|
||||
const {categories} = useServiceCategoriesList();
|
||||
const { categories } = useServiceCategoriesList();
|
||||
|
||||
const data = useMemo(() => categories.reduce((acc, category) => {
|
||||
acc.push({
|
||||
label: category.name,
|
||||
value: category.id.toString()
|
||||
});
|
||||
return acc;
|
||||
}, [] as { label: string, value: string }[]), [categories]);
|
||||
const data = useMemo(
|
||||
() =>
|
||||
categories.reduce(
|
||||
(acc, category) => {
|
||||
acc.push({
|
||||
label: category.name,
|
||||
value: category.id.toString(),
|
||||
});
|
||||
return acc;
|
||||
},
|
||||
[] as { label: string; value: string }[]
|
||||
),
|
||||
[categories]
|
||||
);
|
||||
|
||||
const isControlled = 'value' in props;
|
||||
const [internalValue, setInternalValue] = useState<ServiceCategorySchema | undefined>(props.defaultValue);
|
||||
const isControlled = "value" in props;
|
||||
const [internalValue, setInternalValue] = useState<
|
||||
ServiceCategorySchema | undefined
|
||||
>(props.defaultValue);
|
||||
const value = isControlled ? props.value : internalValue;
|
||||
|
||||
const handleOnChange = (event: string | null) => {
|
||||
if (!event) return;
|
||||
const category = categories.find(category => parseInt(event) == category.id);
|
||||
const category = categories.find(
|
||||
category => parseInt(event) == category.id
|
||||
);
|
||||
if (!category) return;
|
||||
if (isControlled) {
|
||||
props.onChange(category);
|
||||
return;
|
||||
}
|
||||
setInternalValue(category);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (isControlled || !internalValue) return;
|
||||
@@ -51,7 +63,7 @@ const ServiceCategorySelect: FC<Props> = (props: Props) => {
|
||||
onChange={handleOnChange}
|
||||
data={data}
|
||||
/>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export default ServiceCategorySelect;
|
||||
export default ServiceCategorySelect;
|
||||
|
||||
@@ -7,35 +7,47 @@ import { MRT_TableOptions } from "mantine-react-table";
|
||||
import { ActionIcon, Flex, Tooltip } from "@mantine/core";
|
||||
import { IconEdit, IconTrash } from "@tabler/icons-react";
|
||||
|
||||
type Props = CRUDTableProps<ServicePriceCategorySchema>
|
||||
type Props = CRUDTableProps<ServicePriceCategorySchema>;
|
||||
|
||||
const ServicePriceCategoryTable: FC<Props> = ({ items, onChange, onDelete }) => {
|
||||
const ServicePriceCategoryTable: FC<Props> = ({
|
||||
items,
|
||||
onChange,
|
||||
onDelete,
|
||||
}) => {
|
||||
const columns = useServicePriceCategoryTableColumns();
|
||||
return (
|
||||
<BaseTable
|
||||
data={items}
|
||||
columns={columns}
|
||||
restProps={{
|
||||
enableRowActions: true,
|
||||
renderRowActions: ({ row }) => (
|
||||
<Flex gap="md">
|
||||
<Tooltip label="Редактировать">
|
||||
<ActionIcon
|
||||
onClick={() => onChange && onChange(row.original)}
|
||||
variant={"default"}>
|
||||
<IconEdit />
|
||||
</ActionIcon>
|
||||
</Tooltip>
|
||||
<Tooltip label="Удалить">
|
||||
<ActionIcon onClick={() => onDelete && onDelete(row.original)} variant={"default"}>
|
||||
<IconTrash />
|
||||
</ActionIcon>
|
||||
</Tooltip>
|
||||
</Flex>
|
||||
),
|
||||
} as MRT_TableOptions<ServicePriceCategorySchema>}
|
||||
restProps={
|
||||
{
|
||||
enableRowActions: true,
|
||||
renderRowActions: ({ row }) => (
|
||||
<Flex gap="md">
|
||||
<Tooltip label="Редактировать">
|
||||
<ActionIcon
|
||||
onClick={() =>
|
||||
onChange && onChange(row.original)
|
||||
}
|
||||
variant={"default"}>
|
||||
<IconEdit />
|
||||
</ActionIcon>
|
||||
</Tooltip>
|
||||
<Tooltip label="Удалить">
|
||||
<ActionIcon
|
||||
onClick={() =>
|
||||
onDelete && onDelete(row.original)
|
||||
}
|
||||
variant={"default"}>
|
||||
<IconTrash />
|
||||
</ActionIcon>
|
||||
</Tooltip>
|
||||
</Flex>
|
||||
),
|
||||
} as MRT_TableOptions<ServicePriceCategorySchema>
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default ServicePriceCategoryTable;
|
||||
export default ServicePriceCategoryTable;
|
||||
|
||||
@@ -3,15 +3,17 @@ import { MRT_ColumnDef } from "mantine-react-table";
|
||||
import { ServicePriceCategorySchema } from "../../../../client";
|
||||
|
||||
const useServicePriceCategoryTableColumns = () => {
|
||||
|
||||
return useMemo<MRT_ColumnDef<ServicePriceCategorySchema>[]>(() => [
|
||||
{
|
||||
accessorKey: "name",
|
||||
header: "Название",
|
||||
enableColumnActions: false,
|
||||
enableSorting: false,
|
||||
},
|
||||
], []);
|
||||
return useMemo<MRT_ColumnDef<ServicePriceCategorySchema>[]>(
|
||||
() => [
|
||||
{
|
||||
accessorKey: "name",
|
||||
header: "Название",
|
||||
enableColumnActions: false,
|
||||
enableSorting: false,
|
||||
},
|
||||
],
|
||||
[]
|
||||
);
|
||||
};
|
||||
|
||||
export default useServicePriceCategoryTableColumns;
|
||||
export default useServicePriceCategoryTableColumns;
|
||||
|
||||
@@ -1,15 +1,25 @@
|
||||
import { BaseFormInputProps } from "../../../../types/utils.ts";
|
||||
import type { ServiceCategoryPriceSchema, ServicePriceCategorySchema } from "../../../../client";
|
||||
import type {
|
||||
ServiceCategoryPriceSchema,
|
||||
ServicePriceCategorySchema,
|
||||
} from "../../../../client";
|
||||
import { FC, useEffect, useState } from "react";
|
||||
import { Flex, NumberInput, rem } from "@mantine/core";
|
||||
import ServicePriceCategorySelect
|
||||
from "../../../../components/Selects/ServicePriceCategorySelect/ServicePriceCategorySelect.tsx";
|
||||
import ServicePriceCategorySelect from "../../../../components/Selects/ServicePriceCategorySelect/ServicePriceCategorySelect.tsx";
|
||||
|
||||
export type PriceCategoryInputProps = BaseFormInputProps<ServiceCategoryPriceSchema[]>
|
||||
export type PriceCategoryInputProps = BaseFormInputProps<
|
||||
ServiceCategoryPriceSchema[]
|
||||
>;
|
||||
|
||||
const PriceCategoryInput: FC<PriceCategoryInputProps> = (props: PriceCategoryInputProps) => {
|
||||
const [innerState, setInnerState] = useState<ServiceCategoryPriceSchema[]>(props.value || []);
|
||||
const [category, setCategory] = useState<ServicePriceCategorySchema | undefined>(undefined);
|
||||
const PriceCategoryInput: FC<PriceCategoryInputProps> = (
|
||||
props: PriceCategoryInputProps
|
||||
) => {
|
||||
const [innerState, setInnerState] = useState<ServiceCategoryPriceSchema[]>(
|
||||
props.value || []
|
||||
);
|
||||
const [category, setCategory] = useState<
|
||||
ServicePriceCategorySchema | undefined
|
||||
>(undefined);
|
||||
|
||||
const getValue = (): number | undefined | string => {
|
||||
if (category === undefined) return undefined;
|
||||
@@ -20,14 +30,18 @@ const PriceCategoryInput: FC<PriceCategoryInputProps> = (props: PriceCategoryInp
|
||||
const handleChange = (value: number | string) => {
|
||||
// remove value if is string
|
||||
if (typeof value === "string") {
|
||||
setInnerState(innerState.filter(item => item.category.id !== category?.id));
|
||||
setInnerState(
|
||||
innerState.filter(item => item.category.id !== category?.id)
|
||||
);
|
||||
return;
|
||||
}
|
||||
const newValue = {
|
||||
category: category as ServicePriceCategorySchema,
|
||||
price: value,
|
||||
};
|
||||
const newInnerState = innerState.filter(item => item.category.id !== category?.id);
|
||||
const newInnerState = innerState.filter(
|
||||
item => item.category.id !== category?.id
|
||||
);
|
||||
setInnerState([...newInnerState, newValue]);
|
||||
};
|
||||
useEffect(() => {
|
||||
@@ -35,7 +49,9 @@ const PriceCategoryInput: FC<PriceCategoryInputProps> = (props: PriceCategoryInp
|
||||
props.onChange(innerState);
|
||||
}, [innerState]);
|
||||
return (
|
||||
<Flex direction={"column"} gap={rem(10)}>
|
||||
<Flex
|
||||
direction={"column"}
|
||||
gap={rem(10)}>
|
||||
<ServicePriceCategorySelect
|
||||
label={"Категория цены"}
|
||||
placeholder={"Выберите категорию цены"}
|
||||
@@ -51,4 +67,4 @@ const PriceCategoryInput: FC<PriceCategoryInputProps> = (props: PriceCategoryInp
|
||||
);
|
||||
};
|
||||
|
||||
export default PriceCategoryInput;
|
||||
export default PriceCategoryInput;
|
||||
|
||||
@@ -1,100 +1,138 @@
|
||||
import {BaseFormInputProps} from "../../../../types/utils.ts";
|
||||
import {ServicePriceRangeSchema} from "../../../../client";
|
||||
import {FC, useEffect, useState} from "react";
|
||||
import {ActionIcon, Button, Flex, Input, NumberInput, rem} from "@mantine/core";
|
||||
import {IconTrash} from "@tabler/icons-react";
|
||||
import {isNumber} from "lodash";
|
||||
import { BaseFormInputProps } from "../../../../types/utils.ts";
|
||||
import { ServicePriceRangeSchema } from "../../../../client";
|
||||
import { FC, useEffect, useState } from "react";
|
||||
import {
|
||||
ActionIcon,
|
||||
Button,
|
||||
Flex,
|
||||
Input,
|
||||
NumberInput,
|
||||
rem,
|
||||
} from "@mantine/core";
|
||||
import { IconTrash } from "@tabler/icons-react";
|
||||
import { isNumber } from "lodash";
|
||||
|
||||
export type PriceRangeInputType = BaseFormInputProps<ServicePriceRangeSchema[]>;
|
||||
|
||||
const RangePriceInput: FC<PriceRangeInputType> = (props: PriceRangeInputType) => {
|
||||
const {value} = props;
|
||||
const [innerValue, setInnerValue] = useState<ServicePriceRangeSchema[]>(props.value || []);
|
||||
const RangePriceInput: FC<PriceRangeInputType> = (
|
||||
props: PriceRangeInputType
|
||||
) => {
|
||||
const { value } = props;
|
||||
const [innerValue, setInnerValue] = useState<ServicePriceRangeSchema[]>(
|
||||
props.value || []
|
||||
);
|
||||
const onAddRange = () => {
|
||||
const newRange = {
|
||||
fromQuantity: 0,
|
||||
toQuantity: 0,
|
||||
price: 0,
|
||||
id: null
|
||||
}
|
||||
id: null,
|
||||
};
|
||||
setInnerValue([...innerValue, newRange]);
|
||||
props.onChange([...innerValue, newRange]);
|
||||
}
|
||||
};
|
||||
const onDeleteRange = (idx: number) => {
|
||||
const newRanges = innerValue.filter((_, i) => i !== idx);
|
||||
setInnerValue(newRanges);
|
||||
props.onChange(newRanges);
|
||||
}
|
||||
};
|
||||
const onFromQuantityChange = (idx: number, value: number) => {
|
||||
const newRanges = innerValue.map((item, i) => i === idx ? {
|
||||
...item,
|
||||
fromQuantity: value
|
||||
} : item);
|
||||
const newRanges = innerValue.map((item, i) =>
|
||||
i === idx
|
||||
? {
|
||||
...item,
|
||||
fromQuantity: value,
|
||||
}
|
||||
: item
|
||||
);
|
||||
setInnerValue(newRanges);
|
||||
props.onChange(newRanges);
|
||||
}
|
||||
};
|
||||
const onToQuantityChange = (idx: number, value: number) => {
|
||||
const newRanges = innerValue.map((item, i) => i === idx ? {
|
||||
...item,
|
||||
toQuantity: value
|
||||
} : item);
|
||||
const newRanges = innerValue.map((item, i) =>
|
||||
i === idx
|
||||
? {
|
||||
...item,
|
||||
toQuantity: value,
|
||||
}
|
||||
: item
|
||||
);
|
||||
setInnerValue(newRanges);
|
||||
props.onChange(newRanges);
|
||||
}
|
||||
};
|
||||
const onPriceChange = (idx: number, value: number) => {
|
||||
const newRanges = innerValue.map((item, i) => i === idx ? {
|
||||
...item,
|
||||
price: value
|
||||
} : item);
|
||||
const newRanges = innerValue.map((item, i) =>
|
||||
i === idx
|
||||
? {
|
||||
...item,
|
||||
price: value,
|
||||
}
|
||||
: item
|
||||
);
|
||||
setInnerValue(newRanges);
|
||||
props.onChange(newRanges);
|
||||
}
|
||||
};
|
||||
useEffect(() => {
|
||||
if (props.value === innerValue) return;
|
||||
setInnerValue(props.value || []);
|
||||
}, [value]);
|
||||
|
||||
return (
|
||||
<Input.Wrapper error={props.error} label={"Диапазон цен"}>
|
||||
<Flex direction={"column"} gap={rem(10)}>
|
||||
<Input.Wrapper
|
||||
error={props.error}
|
||||
label={"Диапазон цен"}>
|
||||
<Flex
|
||||
direction={"column"}
|
||||
gap={rem(10)}>
|
||||
{innerValue.map((range, idx) => (
|
||||
<Flex
|
||||
key={idx}
|
||||
gap={rem(10)}
|
||||
align={"flex-end"}
|
||||
>
|
||||
<ActionIcon onClick={() => onDeleteRange(idx)} variant={"default"}>
|
||||
<IconTrash/>
|
||||
align={"flex-end"}>
|
||||
<ActionIcon
|
||||
onClick={() => onDeleteRange(idx)}
|
||||
variant={"default"}>
|
||||
<IconTrash />
|
||||
</ActionIcon>
|
||||
<NumberInput
|
||||
label={"От количества"}
|
||||
placeholder={"От"}
|
||||
hideControls
|
||||
value={range.fromQuantity}
|
||||
onChange={event => (event && isNumber(event)) && onFromQuantityChange(idx, event)}
|
||||
onChange={event =>
|
||||
event &&
|
||||
isNumber(event) &&
|
||||
onFromQuantityChange(idx, event)
|
||||
}
|
||||
/>
|
||||
<NumberInput
|
||||
label={"До количества"}
|
||||
placeholder={"До"}
|
||||
hideControls
|
||||
value={range.toQuantity}
|
||||
onChange={event => (event && isNumber(event)) && onToQuantityChange(idx, event)}
|
||||
onChange={event =>
|
||||
event &&
|
||||
isNumber(event) &&
|
||||
onToQuantityChange(idx, event)
|
||||
}
|
||||
/>
|
||||
<NumberInput
|
||||
label={"Цена"}
|
||||
placeholder={"Цена"}
|
||||
hideControls
|
||||
value={range.price}
|
||||
onChange={event => (event && isNumber(event)) && onPriceChange(idx, event)}
|
||||
onChange={event =>
|
||||
event &&
|
||||
isNumber(event) &&
|
||||
onPriceChange(idx, event)
|
||||
}
|
||||
/>
|
||||
|
||||
</Flex>
|
||||
))}
|
||||
|
||||
<Button onClick={onAddRange}>Добавить диапазон</Button>
|
||||
</Flex>
|
||||
</Input.Wrapper>
|
||||
|
||||
)
|
||||
}
|
||||
export default RangePriceInput
|
||||
);
|
||||
};
|
||||
export default RangePriceInput;
|
||||
|
||||
@@ -1,39 +1,40 @@
|
||||
import {FC, useState} from "react";
|
||||
import {Button, Flex} from "@mantine/core";
|
||||
import SinglePriceInput, {PriceInputType} from "./SinglePriceInput.tsx";
|
||||
import RangePriceInput, {PriceRangeInputType} from "./RangePriceInput.tsx";
|
||||
import { FC, useState } from "react";
|
||||
import { Button, Flex } from "@mantine/core";
|
||||
import SinglePriceInput, { PriceInputType } from "./SinglePriceInput.tsx";
|
||||
import RangePriceInput, { PriceRangeInputType } from "./RangePriceInput.tsx";
|
||||
|
||||
type Props = {
|
||||
singlePriceInputProps: PriceInputType;
|
||||
priceRangeInputProps: PriceRangeInputType;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
const ServicePriceInput: FC<Props> = ({priceRangeInputProps, singlePriceInputProps}) => {
|
||||
const [isUsingRange, setIsUsingRange] = useState<boolean>(priceRangeInputProps.value.length > 0);
|
||||
const ServicePriceInput: FC<Props> = ({
|
||||
priceRangeInputProps,
|
||||
singlePriceInputProps,
|
||||
}) => {
|
||||
const [isUsingRange, setIsUsingRange] = useState<boolean>(
|
||||
priceRangeInputProps.value.length > 0
|
||||
);
|
||||
return (
|
||||
<>
|
||||
<Flex
|
||||
direction={"column"}
|
||||
gap={10}
|
||||
>
|
||||
{isUsingRange ?
|
||||
<RangePriceInput
|
||||
{...priceRangeInputProps}
|
||||
/> :
|
||||
<SinglePriceInput
|
||||
{...singlePriceInputProps}
|
||||
/>}
|
||||
gap={10}>
|
||||
{isUsingRange ? (
|
||||
<RangePriceInput {...priceRangeInputProps} />
|
||||
) : (
|
||||
<SinglePriceInput {...singlePriceInputProps} />
|
||||
)}
|
||||
<Button
|
||||
variant={"default"}
|
||||
onClick={() => setIsUsingRange(!isUsingRange)}
|
||||
>
|
||||
{isUsingRange ? "Использовать одну цену" : "Использовать диапазон цен"}
|
||||
onClick={() => setIsUsingRange(!isUsingRange)}>
|
||||
{isUsingRange
|
||||
? "Использовать одну цену"
|
||||
: "Использовать диапазон цен"}
|
||||
</Button>
|
||||
</Flex>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
export default ServicePriceInput;
|
||||
export default ServicePriceInput;
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
import {FC} from "react";
|
||||
import {NumberInput, NumberInputProps} from "@mantine/core";
|
||||
import { FC } from "react";
|
||||
import { NumberInput, NumberInputProps } from "@mantine/core";
|
||||
|
||||
export type PriceInputType = NumberInputProps;
|
||||
|
||||
const SinglePriceInput: FC<PriceInputType> = (props) => {
|
||||
return (
|
||||
<NumberInput
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
const SinglePriceInput: FC<PriceInputType> = props => {
|
||||
return <NumberInput {...props} />;
|
||||
};
|
||||
|
||||
export default SinglePriceInput;
|
||||
export default SinglePriceInput;
|
||||
|
||||
@@ -11,9 +11,10 @@ export enum ServicePriceType {
|
||||
type RestProps = {
|
||||
onChange: (value: ServicePriceType) => void;
|
||||
value?: ServicePriceType;
|
||||
}
|
||||
type Props = Omit<SegmentedControlProps, "data" | "value" | "onChange"> & RestProps;
|
||||
const ServicePriceTypeSegmentedControl: FC<Props> = (props) => {
|
||||
};
|
||||
type Props = Omit<SegmentedControlProps, "data" | "value" | "onChange"> &
|
||||
RestProps;
|
||||
const ServicePriceTypeSegmentedControl: FC<Props> = props => {
|
||||
const { onChange, value } = props;
|
||||
|
||||
const data = [
|
||||
@@ -32,7 +33,6 @@ const ServicePriceTypeSegmentedControl: FC<Props> = (props) => {
|
||||
];
|
||||
const handleChange = (value: string) => {
|
||||
onChange(Number(value));
|
||||
|
||||
};
|
||||
|
||||
const restProps = omit(props, ["onChange", "value"]);
|
||||
|
||||
@@ -5,10 +5,9 @@ export enum ServicesTab {
|
||||
DEAL_SERVICE,
|
||||
PRODUCT_SERVICE,
|
||||
SERVICES_KITS,
|
||||
SERVICES_PRICE_CATEGORIES
|
||||
SERVICES_PRICE_CATEGORIES,
|
||||
}
|
||||
|
||||
|
||||
type Props = Omit<SegmentedControlProps, "data">;
|
||||
const data = [
|
||||
{
|
||||
@@ -28,8 +27,7 @@ const data = [
|
||||
value: ServicesTab.SERVICES_PRICE_CATEGORIES.toString(),
|
||||
},
|
||||
];
|
||||
const ServiceTypeSegmentedControl: FC<Props> = (props) => {
|
||||
|
||||
const ServiceTypeSegmentedControl: FC<Props> = props => {
|
||||
return (
|
||||
<SegmentedControl
|
||||
data={data}
|
||||
@@ -37,4 +35,4 @@ const ServiceTypeSegmentedControl: FC<Props> = (props) => {
|
||||
/>
|
||||
);
|
||||
};
|
||||
export default ServiceTypeSegmentedControl;
|
||||
export default ServiceTypeSegmentedControl;
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import {ServiceService} from "../../../../client";
|
||||
import {FC} from "react";
|
||||
import BaseEnumSelect, {EnumSelectProps} from "../../../../components/Selects/BaseEnumSelect/BaseEnumSelect.tsx";
|
||||
|
||||
import { ServiceService } from "../../../../client";
|
||||
import { FC } from "react";
|
||||
import BaseEnumSelect, {
|
||||
EnumSelectProps,
|
||||
} from "../../../../components/Selects/BaseEnumSelect/BaseEnumSelect.tsx";
|
||||
|
||||
const ServiceTypeSelect: FC<EnumSelectProps> = (props: EnumSelectProps) => {
|
||||
return (
|
||||
<BaseEnumSelect
|
||||
{...props}
|
||||
fetchFn={ServiceService.getAllServiceTypes}
|
||||
queryKey='getAllServiceTypes'
|
||||
queryKey="getAllServiceTypes"
|
||||
/>
|
||||
)
|
||||
}
|
||||
export default ServiceTypeSelect;
|
||||
);
|
||||
};
|
||||
export default ServiceTypeSelect;
|
||||
|
||||
@@ -1,60 +1,64 @@
|
||||
import {CRUDTableProps} from "../../../../types/CRUDTable.tsx";
|
||||
import {GetServiceKitSchema} from "../../../../client";
|
||||
import {FC} from "react";
|
||||
import { CRUDTableProps } from "../../../../types/CRUDTable.tsx";
|
||||
import { GetServiceKitSchema } from "../../../../client";
|
||||
import { FC } from "react";
|
||||
import useServicesKitsTableColumns from "./columns.tsx";
|
||||
import {BaseTable} from "../../../../components/BaseTable/BaseTable.tsx";
|
||||
import {ActionIcon, Flex, Tooltip} from "@mantine/core";
|
||||
import {IconEdit, IconTrash} from "@tabler/icons-react";
|
||||
import {MRT_TableOptions} from "mantine-react-table";
|
||||
import {modals} from "@mantine/modals";
|
||||
import { BaseTable } from "../../../../components/BaseTable/BaseTable.tsx";
|
||||
import { ActionIcon, Flex, Tooltip } from "@mantine/core";
|
||||
import { IconEdit, IconTrash } from "@tabler/icons-react";
|
||||
import { MRT_TableOptions } from "mantine-react-table";
|
||||
import { modals } from "@mantine/modals";
|
||||
|
||||
type Props = CRUDTableProps<GetServiceKitSchema>;
|
||||
const ServicesKitsTable: FC<Props> = ({items, onDelete, onChange}) => {
|
||||
const ServicesKitsTable: FC<Props> = ({ items, onDelete, onChange }) => {
|
||||
const columns = useServicesKitsTableColumns();
|
||||
const onEditClick = (kit: GetServiceKitSchema) => {
|
||||
if (!onChange) return;
|
||||
modals.openContextModal({
|
||||
modal: 'serviceKitModalForm',
|
||||
title: 'Создание набора услуг',
|
||||
modal: "serviceKitModalForm",
|
||||
title: "Создание набора услуг",
|
||||
withCloseButton: false,
|
||||
innerProps: {
|
||||
element: kit,
|
||||
onChange
|
||||
}
|
||||
})
|
||||
}
|
||||
onChange,
|
||||
},
|
||||
});
|
||||
};
|
||||
const onDeleteClick = () => {
|
||||
if (!onDelete) return;
|
||||
}
|
||||
};
|
||||
return (
|
||||
<BaseTable
|
||||
data={items}
|
||||
columns={columns}
|
||||
restProps={{
|
||||
enableSorting: false,
|
||||
enableColumnActions: false,
|
||||
enableRowActions: true,
|
||||
renderRowActions: ({row}) => (
|
||||
<Flex gap="md">
|
||||
<Tooltip label="Редактировать">
|
||||
<ActionIcon
|
||||
onClick={() => onEditClick(row.original)}
|
||||
variant={"default"}>
|
||||
<IconEdit/>
|
||||
</ActionIcon>
|
||||
</Tooltip>
|
||||
<Tooltip label="Удалить">
|
||||
<ActionIcon onClick={() => {
|
||||
if (onDelete) onDeleteClick();
|
||||
}} variant={"default"}>
|
||||
<IconTrash/>
|
||||
</ActionIcon>
|
||||
</Tooltip>
|
||||
</Flex>
|
||||
)
|
||||
} as MRT_TableOptions<GetServiceKitSchema>}
|
||||
restProps={
|
||||
{
|
||||
enableSorting: false,
|
||||
enableColumnActions: false,
|
||||
enableRowActions: true,
|
||||
renderRowActions: ({ row }) => (
|
||||
<Flex gap="md">
|
||||
<Tooltip label="Редактировать">
|
||||
<ActionIcon
|
||||
onClick={() => onEditClick(row.original)}
|
||||
variant={"default"}>
|
||||
<IconEdit />
|
||||
</ActionIcon>
|
||||
</Tooltip>
|
||||
<Tooltip label="Удалить">
|
||||
<ActionIcon
|
||||
onClick={() => {
|
||||
if (onDelete) onDeleteClick();
|
||||
}}
|
||||
variant={"default"}>
|
||||
<IconTrash />
|
||||
</ActionIcon>
|
||||
</Tooltip>
|
||||
</Flex>
|
||||
),
|
||||
} as MRT_TableOptions<GetServiceKitSchema>
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export default ServicesKitsTable;
|
||||
export default ServicesKitsTable;
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
import {useMemo} from "react";
|
||||
import {MRT_ColumnDef} from "mantine-react-table";
|
||||
import {GetServiceKitSchema} from "../../../../client";
|
||||
import { useMemo } from "react";
|
||||
import { MRT_ColumnDef } from "mantine-react-table";
|
||||
import { GetServiceKitSchema } from "../../../../client";
|
||||
|
||||
const useServicesKitsTableColumns = () => {
|
||||
return useMemo<MRT_ColumnDef<GetServiceKitSchema>[]>(() => [
|
||||
{
|
||||
accessorKey: "name",
|
||||
header: "Название набора"
|
||||
},
|
||||
{
|
||||
header: "Кол-во услуг",
|
||||
Cell: ({row}) => row.original.services.length
|
||||
}
|
||||
], []);
|
||||
}
|
||||
export default useServicesKitsTableColumns;
|
||||
return useMemo<MRT_ColumnDef<GetServiceKitSchema>[]>(
|
||||
() => [
|
||||
{
|
||||
accessorKey: "name",
|
||||
header: "Название набора",
|
||||
},
|
||||
{
|
||||
header: "Кол-во услуг",
|
||||
Cell: ({ row }) => row.original.services.length,
|
||||
},
|
||||
],
|
||||
[]
|
||||
);
|
||||
};
|
||||
export default useServicesKitsTableColumns;
|
||||
|
||||
@@ -1,58 +1,66 @@
|
||||
import {ServiceSchema} from "../../../../client";
|
||||
import {FC} from "react";
|
||||
import {useServicesTableColumns} from "./columns.tsx";
|
||||
import {BaseTable} from "../../../../components/BaseTable/BaseTable.tsx";
|
||||
import {MRT_TableOptions} from "mantine-react-table";
|
||||
import {CRUDTableProps} from "../../../../types/CRUDTable.tsx";
|
||||
import {ActionIcon, Flex, Tooltip} from "@mantine/core";
|
||||
import {IconEdit, IconTrash} from "@tabler/icons-react";
|
||||
import {modals} from "@mantine/modals";
|
||||
import { ServiceSchema } from "../../../../client";
|
||||
import { FC } from "react";
|
||||
import { useServicesTableColumns } from "./columns.tsx";
|
||||
import { BaseTable } from "../../../../components/BaseTable/BaseTable.tsx";
|
||||
import { MRT_TableOptions } from "mantine-react-table";
|
||||
import { CRUDTableProps } from "../../../../types/CRUDTable.tsx";
|
||||
import { ActionIcon, Flex, Tooltip } from "@mantine/core";
|
||||
import { IconEdit, IconTrash } from "@tabler/icons-react";
|
||||
import { modals } from "@mantine/modals";
|
||||
|
||||
const ServicesTable: FC<CRUDTableProps<ServiceSchema>> = ({items, onDelete, onChange}) => {
|
||||
const ServicesTable: FC<CRUDTableProps<ServiceSchema>> = ({
|
||||
items,
|
||||
onDelete,
|
||||
onChange,
|
||||
}) => {
|
||||
const columns = useServicesTableColumns();
|
||||
|
||||
const onEditClick = (service: ServiceSchema) => {
|
||||
if (!onChange) return;
|
||||
modals.openContextModal({
|
||||
modal: "createService",
|
||||
title: 'Создание услуги',
|
||||
title: "Создание услуги",
|
||||
withCloseButton: false,
|
||||
innerProps: {
|
||||
onChange: (newService) => onChange(newService),
|
||||
onChange: newService => onChange(newService),
|
||||
element: service,
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
return (
|
||||
<BaseTable
|
||||
data={items}
|
||||
columns={columns}
|
||||
restProps={{
|
||||
enableGrouping: true,
|
||||
initialState: {grouping: ["category"]},
|
||||
enableColumnActions: false,
|
||||
enableRowActions: true,
|
||||
renderRowActions: ({row}) => (
|
||||
<Flex gap="md">
|
||||
<Tooltip label="Редактировать">
|
||||
<ActionIcon
|
||||
onClick={() => onEditClick(row.original)}
|
||||
variant={"default"}>
|
||||
<IconEdit/>
|
||||
</ActionIcon>
|
||||
</Tooltip>
|
||||
<Tooltip label="Удалить">
|
||||
<ActionIcon onClick={() => {
|
||||
if (onDelete) onDelete(row.original);
|
||||
}} variant={"default"}>
|
||||
<IconTrash/>
|
||||
</ActionIcon>
|
||||
</Tooltip>
|
||||
</Flex>
|
||||
)
|
||||
} as MRT_TableOptions<ServiceSchema>}
|
||||
restProps={
|
||||
{
|
||||
enableGrouping: true,
|
||||
initialState: { grouping: ["category"] },
|
||||
enableColumnActions: false,
|
||||
enableRowActions: true,
|
||||
renderRowActions: ({ row }) => (
|
||||
<Flex gap="md">
|
||||
<Tooltip label="Редактировать">
|
||||
<ActionIcon
|
||||
onClick={() => onEditClick(row.original)}
|
||||
variant={"default"}>
|
||||
<IconEdit />
|
||||
</ActionIcon>
|
||||
</Tooltip>
|
||||
<Tooltip label="Удалить">
|
||||
<ActionIcon
|
||||
onClick={() => {
|
||||
if (onDelete) onDelete(row.original);
|
||||
}}
|
||||
variant={"default"}>
|
||||
<IconTrash />
|
||||
</ActionIcon>
|
||||
</Tooltip>
|
||||
</Flex>
|
||||
),
|
||||
} as MRT_TableOptions<ServiceSchema>
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export default ServicesTable;
|
||||
export default ServicesTable;
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import {useMemo} from "react";
|
||||
import {MRT_ColumnDef} from "mantine-react-table";
|
||||
import {ServiceSchema} from "../../../../client";
|
||||
import {List} from "@mantine/core";
|
||||
import { useMemo } from "react";
|
||||
import { MRT_ColumnDef } from "mantine-react-table";
|
||||
import { ServiceSchema } from "../../../../client";
|
||||
import { List } from "@mantine/core";
|
||||
|
||||
export const useServicesTableColumns = () => {
|
||||
const getPriceRow = (service: ServiceSchema) => {
|
||||
if (service.priceRanges.length == 0)
|
||||
return <>{service.price}₽</>;
|
||||
if (service.priceRanges.length == 0) return <>{service.price}₽</>;
|
||||
return (
|
||||
<>
|
||||
<List>
|
||||
@@ -18,37 +17,37 @@ export const useServicesTableColumns = () => {
|
||||
</List>
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return useMemo<MRT_ColumnDef<ServiceSchema>[]>(() => [
|
||||
{
|
||||
accessorKey: "category",
|
||||
header: "Категория",
|
||||
enableGrouping: false,
|
||||
enableSorting: false,
|
||||
accessorFn: (row) => row.category.name
|
||||
},
|
||||
{
|
||||
accessorKey: "name",
|
||||
header: "Услуга",
|
||||
enableGrouping: false,
|
||||
enableSorting: false,
|
||||
|
||||
},
|
||||
{
|
||||
accessorKey: "price",
|
||||
header: "Цена",
|
||||
enableGrouping: false,
|
||||
enableSorting: false,
|
||||
Cell: ({row}) => getPriceRow(row.original)
|
||||
},
|
||||
{
|
||||
accessorKey: "cost",
|
||||
header: "Себестоимость",
|
||||
enableGrouping: false,
|
||||
enableSorting: false,
|
||||
},
|
||||
|
||||
], []);
|
||||
|
||||
}
|
||||
return useMemo<MRT_ColumnDef<ServiceSchema>[]>(
|
||||
() => [
|
||||
{
|
||||
accessorKey: "category",
|
||||
header: "Категория",
|
||||
enableGrouping: false,
|
||||
enableSorting: false,
|
||||
accessorFn: row => row.category.name,
|
||||
},
|
||||
{
|
||||
accessorKey: "name",
|
||||
header: "Услуга",
|
||||
enableGrouping: false,
|
||||
enableSorting: false,
|
||||
},
|
||||
{
|
||||
accessorKey: "price",
|
||||
header: "Цена",
|
||||
enableGrouping: false,
|
||||
enableSorting: false,
|
||||
Cell: ({ row }) => getPriceRow(row.original),
|
||||
},
|
||||
{
|
||||
accessorKey: "cost",
|
||||
header: "Себестоимость",
|
||||
enableGrouping: false,
|
||||
enableSorting: false,
|
||||
},
|
||||
],
|
||||
[]
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import {useQuery} from "@tanstack/react-query";
|
||||
import {ServiceService} from "../../../client";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { ServiceService } from "../../../client";
|
||||
|
||||
const useServiceCategoriesList = () => {
|
||||
const {isPending, error, data, refetch} = useQuery({
|
||||
queryKey: ['getAllServiceCategories'],
|
||||
const { isPending, error, data, refetch } = useQuery({
|
||||
queryKey: ["getAllServiceCategories"],
|
||||
queryFn: ServiceService.getAllServiceCategories,
|
||||
});
|
||||
const categories = isPending || error || !data ? [] : data.categories;
|
||||
|
||||
return {categories, refetch}
|
||||
}
|
||||
return { categories, refetch };
|
||||
};
|
||||
|
||||
export default useServiceCategoriesList;
|
||||
export default useServiceCategoriesList;
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import ObjectList from "../../../hooks/objectList.tsx";
|
||||
import { ServiceService } from "../../../client";
|
||||
|
||||
const useServicePriceCategoriesList = () => ObjectList({
|
||||
queryFn: ServiceService.getAllPriceCategories,
|
||||
getObjectsFn: (response) => response.priceCategories,
|
||||
queryKey: "getAllPriceCategories",
|
||||
});
|
||||
const useServicePriceCategoriesList = () =>
|
||||
ObjectList({
|
||||
queryFn: ServiceService.getAllPriceCategories,
|
||||
getObjectsFn: response => response.priceCategories,
|
||||
queryKey: "getAllPriceCategories",
|
||||
});
|
||||
|
||||
export default useServicePriceCategoriesList;
|
||||
export default useServicePriceCategoriesList;
|
||||
|
||||
@@ -1,62 +1,45 @@
|
||||
import UseObjectState from "../../../types/UseObjectState.ts";
|
||||
import { type ServicePriceCategorySchema, ServiceService } from "../../../client";
|
||||
import {
|
||||
type ServicePriceCategorySchema,
|
||||
ServiceService,
|
||||
} from "../../../client";
|
||||
import useServicePriceCategoriesList from "./useServicePriceCategoriesList.tsx";
|
||||
import { modals } from "@mantine/modals";
|
||||
import { notifications } from "../../../shared/lib/notifications.ts";
|
||||
|
||||
const useServicePriceCategoryState = (): UseObjectState<ServicePriceCategorySchema> => {
|
||||
const { objects, refetch } = useServicePriceCategoriesList();
|
||||
const onCreateClick = () => {
|
||||
modals.openContextModal({
|
||||
modal: "servicePriceCategoryForm",
|
||||
title: "Создание категории цен",
|
||||
withCloseButton: false,
|
||||
innerProps: {
|
||||
onCreate,
|
||||
},
|
||||
});
|
||||
};
|
||||
const onCreate = (values: ServicePriceCategorySchema) => {
|
||||
console.log(ServiceService);
|
||||
ServiceService.createPriceCategory({
|
||||
requestBody: {
|
||||
name: values.name,
|
||||
},
|
||||
}).then(async ({ ok, message }) => {
|
||||
notifications.guess(ok, { message: message });
|
||||
if (!ok) return;
|
||||
await refetch();
|
||||
});
|
||||
};
|
||||
const onDelete = (item: ServicePriceCategorySchema) => {
|
||||
modals.openConfirmModal({
|
||||
title: "Удаление категории",
|
||||
children: "Вы уверены, что хотите удалить категорию?",
|
||||
onConfirm: () => {
|
||||
|
||||
ServiceService.deletePriceCategory({
|
||||
requestBody: {
|
||||
id: item.id,
|
||||
},
|
||||
}).then(async ({ ok, message }) => {
|
||||
notifications.guess(ok, { message: message });
|
||||
if (!ok) return;
|
||||
await refetch();
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
const onChange = (item: ServicePriceCategorySchema) => {
|
||||
modals.openContextModal({
|
||||
modal: "servicePriceCategoryForm",
|
||||
title: "Изменение категории цен",
|
||||
withCloseButton: false,
|
||||
innerProps: {
|
||||
onChange: (values: ServicePriceCategorySchema) => {
|
||||
ServiceService.updatePriceCategory({
|
||||
const useServicePriceCategoryState =
|
||||
(): UseObjectState<ServicePriceCategorySchema> => {
|
||||
const { objects, refetch } = useServicePriceCategoriesList();
|
||||
const onCreateClick = () => {
|
||||
modals.openContextModal({
|
||||
modal: "servicePriceCategoryForm",
|
||||
title: "Создание категории цен",
|
||||
withCloseButton: false,
|
||||
innerProps: {
|
||||
onCreate,
|
||||
},
|
||||
});
|
||||
};
|
||||
const onCreate = (values: ServicePriceCategorySchema) => {
|
||||
console.log(ServiceService);
|
||||
ServiceService.createPriceCategory({
|
||||
requestBody: {
|
||||
name: values.name,
|
||||
},
|
||||
}).then(async ({ ok, message }) => {
|
||||
notifications.guess(ok, { message: message });
|
||||
if (!ok) return;
|
||||
await refetch();
|
||||
});
|
||||
};
|
||||
const onDelete = (item: ServicePriceCategorySchema) => {
|
||||
modals.openConfirmModal({
|
||||
title: "Удаление категории",
|
||||
children: "Вы уверены, что хотите удалить категорию?",
|
||||
onConfirm: () => {
|
||||
ServiceService.deletePriceCategory({
|
||||
requestBody: {
|
||||
id: item.id,
|
||||
name: values.name,
|
||||
},
|
||||
}).then(async ({ ok, message }) => {
|
||||
notifications.guess(ok, { message: message });
|
||||
@@ -64,17 +47,37 @@ const useServicePriceCategoryState = (): UseObjectState<ServicePriceCategorySche
|
||||
await refetch();
|
||||
});
|
||||
},
|
||||
element: item,
|
||||
},
|
||||
});
|
||||
};
|
||||
});
|
||||
};
|
||||
const onChange = (item: ServicePriceCategorySchema) => {
|
||||
modals.openContextModal({
|
||||
modal: "servicePriceCategoryForm",
|
||||
title: "Изменение категории цен",
|
||||
withCloseButton: false,
|
||||
innerProps: {
|
||||
onChange: (values: ServicePriceCategorySchema) => {
|
||||
ServiceService.updatePriceCategory({
|
||||
requestBody: {
|
||||
id: item.id,
|
||||
name: values.name,
|
||||
},
|
||||
}).then(async ({ ok, message }) => {
|
||||
notifications.guess(ok, { message: message });
|
||||
if (!ok) return;
|
||||
await refetch();
|
||||
});
|
||||
},
|
||||
element: item,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
onCreateClick,
|
||||
onCreate,
|
||||
onDelete,
|
||||
onChange,
|
||||
objects,
|
||||
return {
|
||||
onCreateClick,
|
||||
onCreate,
|
||||
onDelete,
|
||||
onChange,
|
||||
objects,
|
||||
};
|
||||
};
|
||||
};
|
||||
export default useServicePriceCategoryState;
|
||||
export default useServicePriceCategoryState;
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import ObjectList from "../../../hooks/objectList.tsx";
|
||||
import {ServiceService} from "../../../client";
|
||||
import { ServiceService } from "../../../client";
|
||||
|
||||
const useServicesKitsList = () => ObjectList({
|
||||
queryFn: ServiceService.getAllServicesKits,
|
||||
getObjectsFn: (response) => response.servicesKits,
|
||||
queryKey: "getAllServicesKits"
|
||||
})
|
||||
const useServicesKitsList = () =>
|
||||
ObjectList({
|
||||
queryFn: ServiceService.getAllServicesKits,
|
||||
getObjectsFn: response => response.servicesKits,
|
||||
queryKey: "getAllServicesKits",
|
||||
});
|
||||
|
||||
export default useServicesKitsList;
|
||||
export default useServicesKitsList;
|
||||
|
||||
@@ -5,7 +5,8 @@ import { modals } from "@mantine/modals";
|
||||
import useServicesKitsList from "./useServicesKitsList.tsx";
|
||||
|
||||
const useServicesKitsState = () => {
|
||||
const { objects: servicesKits, refetch: refetchKits } = useServicesKitsList();
|
||||
const { objects: servicesKits, refetch: refetchKits } =
|
||||
useServicesKitsList();
|
||||
|
||||
const onKitCreate = (kit: GetServiceKitSchema) => {
|
||||
ServiceService.createServicesKit({
|
||||
@@ -54,4 +55,4 @@ const useServicesKitsState = () => {
|
||||
};
|
||||
};
|
||||
|
||||
export default useServicesKitsState;
|
||||
export default useServicesKitsState;
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import {useQuery} from "@tanstack/react-query";
|
||||
import {ServiceService} from "../../../client";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { ServiceService } from "../../../client";
|
||||
|
||||
const useServicesList = () => {
|
||||
const {isPending, error, data, refetch} = useQuery({
|
||||
queryKey: ['getAllServices'],
|
||||
queryFn: ServiceService.getAllServices
|
||||
const { isPending, error, data, refetch } = useQuery({
|
||||
queryKey: ["getAllServices"],
|
||||
queryFn: ServiceService.getAllServices,
|
||||
});
|
||||
const services = isPending || error || !data ? [] : data.services;
|
||||
|
||||
return {services, refetch}
|
||||
}
|
||||
export default useServicesList;
|
||||
return { services, refetch };
|
||||
};
|
||||
export default useServicesList;
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import { modals } from "@mantine/modals";
|
||||
import { ServiceCategorySchema, ServiceSchema, ServiceService } from "../../../client";
|
||||
import {
|
||||
ServiceCategorySchema,
|
||||
ServiceSchema,
|
||||
ServiceService,
|
||||
} from "../../../client";
|
||||
import { notifications } from "../../../shared/lib/notifications.ts";
|
||||
import useServicesList from "./useServicesList.tsx";
|
||||
import { Text } from "@mantine/core";
|
||||
@@ -18,12 +22,13 @@ const useServicesState = () => {
|
||||
});
|
||||
};
|
||||
const onCreate = (values: ServiceSchema) => {
|
||||
ServiceService.createService({ requestBody: { service: values } })
|
||||
.then(async ({ ok, message }) => {
|
||||
ServiceService.createService({ requestBody: { service: values } }).then(
|
||||
async ({ ok, message }) => {
|
||||
notifications.guess(ok, { message: message });
|
||||
if (!ok) return;
|
||||
await refetch();
|
||||
});
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const onCreateCategoryClick = () => {
|
||||
@@ -37,24 +42,29 @@ const useServicesState = () => {
|
||||
});
|
||||
};
|
||||
const onCategoryCreate = (category: ServiceCategorySchema) => {
|
||||
ServiceService.createServiceCategory({ requestBody: { category: category } })
|
||||
.then(({ ok, message }) =>
|
||||
notifications.guess(ok, { message: message }));
|
||||
ServiceService.createServiceCategory({
|
||||
requestBody: { category: category },
|
||||
}).then(({ ok, message }) =>
|
||||
notifications.guess(ok, { message: message })
|
||||
);
|
||||
};
|
||||
|
||||
const onServiceDelete = (service: ServiceSchema) => {
|
||||
modals.openConfirmModal({
|
||||
title: "Удаление услуги",
|
||||
children: (<Text>
|
||||
Вы уверены, что хотите удалить услугу "{service.name}"?
|
||||
</Text>),
|
||||
children: (
|
||||
<Text>
|
||||
Вы уверены, что хотите удалить услугу "{service.name}"?
|
||||
</Text>
|
||||
),
|
||||
onConfirm: () => {
|
||||
ServiceService.deleteService({ requestBody: { serviceId: service.id } })
|
||||
.then(async ({ ok, message }) => {
|
||||
notifications.guess(ok, { message: message });
|
||||
if (!ok) return;
|
||||
await refetch();
|
||||
});
|
||||
ServiceService.deleteService({
|
||||
requestBody: { serviceId: service.id },
|
||||
}).then(async ({ ok, message }) => {
|
||||
notifications.guess(ok, { message: message });
|
||||
if (!ok) return;
|
||||
await refetch();
|
||||
});
|
||||
},
|
||||
labels: {
|
||||
confirm: "Удалить",
|
||||
@@ -64,17 +74,15 @@ const useServicesState = () => {
|
||||
};
|
||||
|
||||
const onServiceUpdate = (service: ServiceSchema) => {
|
||||
ServiceService
|
||||
.updateService({
|
||||
requestBody: {
|
||||
data: service,
|
||||
},
|
||||
})
|
||||
.then(async ({ ok, message }) => {
|
||||
notifications.guess(ok, { message: message });
|
||||
if (!ok) return;
|
||||
await refetch();
|
||||
});
|
||||
ServiceService.updateService({
|
||||
requestBody: {
|
||||
data: service,
|
||||
},
|
||||
}).then(async ({ ok, message }) => {
|
||||
notifications.guess(ok, { message: message });
|
||||
if (!ok) return;
|
||||
await refetch();
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
@@ -86,4 +94,4 @@ const useServicesState = () => {
|
||||
};
|
||||
};
|
||||
|
||||
export default useServicesState;
|
||||
export default useServicesState;
|
||||
|
||||
@@ -1 +1 @@
|
||||
export {ServicesPage} from './ui/ServicesPage.tsx';
|
||||
export { ServicesPage } from "./ui/ServicesPage.tsx";
|
||||
|
||||
@@ -1,52 +1,64 @@
|
||||
import {ServiceCategorySchema} from "../../../client";
|
||||
import {Button, Flex, rem, TextInput} from "@mantine/core";
|
||||
import {useForm} from "@mantine/form";
|
||||
import {ContextModalProps} from "@mantine/modals";
|
||||
import { ServiceCategorySchema } from "../../../client";
|
||||
import { Button, Flex, rem, TextInput } from "@mantine/core";
|
||||
import { useForm } from "@mantine/form";
|
||||
import { ContextModalProps } from "@mantine/modals";
|
||||
|
||||
type Props = {
|
||||
onCreate: (category: ServiceCategorySchema) => void
|
||||
}
|
||||
onCreate: (category: ServiceCategorySchema) => void;
|
||||
};
|
||||
const CreateServiceCategoryModal = ({
|
||||
context,
|
||||
id,
|
||||
innerProps,
|
||||
}: ContextModalProps<Props>) => {
|
||||
context,
|
||||
id,
|
||||
innerProps,
|
||||
}: ContextModalProps<Props>) => {
|
||||
const form = useForm({
|
||||
initialValues: {
|
||||
name: ''
|
||||
name: "",
|
||||
},
|
||||
validate: {
|
||||
name: (name) => name.trim() !== '' ? null : "Необходимо ввести название категории",
|
||||
}
|
||||
})
|
||||
name: name =>
|
||||
name.trim() !== ""
|
||||
? null
|
||||
: "Необходимо ввести название категории",
|
||||
},
|
||||
});
|
||||
const onSubmit = (values: { name: string }) => {
|
||||
innerProps.onCreate({name: values.name, id: -1});
|
||||
innerProps.onCreate({ name: values.name, id: -1 });
|
||||
context.closeContextModal(id);
|
||||
|
||||
}
|
||||
};
|
||||
const onCancelClick = () => {
|
||||
context.closeContextModal(id);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<form onSubmit={form.onSubmit((values) => onSubmit(values))}>
|
||||
<Flex gap={rem(10)} direction={"column"}>
|
||||
<form onSubmit={form.onSubmit(values => onSubmit(values))}>
|
||||
<Flex
|
||||
gap={rem(10)}
|
||||
direction={"column"}>
|
||||
<TextInput
|
||||
|
||||
placeholder={"Введите название категори"}
|
||||
label={"Название категории"}
|
||||
{...form.getInputProps('name')}
|
||||
{...form.getInputProps("name")}
|
||||
/>
|
||||
|
||||
|
||||
<Flex justify={"center"} mt={rem(5)} gap={rem(10)}>
|
||||
<Button onClick={() => onCancelClick()} variant={"subtle"}>Отменить</Button>
|
||||
<Button type={"submit"} variant={"default"}>Сохранить</Button>
|
||||
<Flex
|
||||
justify={"center"}
|
||||
mt={rem(5)}
|
||||
gap={rem(10)}>
|
||||
<Button
|
||||
onClick={() => onCancelClick()}
|
||||
variant={"subtle"}>
|
||||
Отменить
|
||||
</Button>
|
||||
<Button
|
||||
type={"submit"}
|
||||
variant={"default"}>
|
||||
Сохранить
|
||||
</Button>
|
||||
</Flex>
|
||||
</Flex>
|
||||
|
||||
</form>
|
||||
</>
|
||||
)
|
||||
}
|
||||
export default CreateServiceCategoryModal;
|
||||
);
|
||||
};
|
||||
export default CreateServiceCategoryModal;
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { ServicePriceRangeSchema, ServiceSchema } from "../../../client";
|
||||
import { useForm } from "@mantine/form";
|
||||
import { ContextModalProps } from "@mantine/modals";
|
||||
import BaseFormModal, { CreateEditFormProps } from "../../ClientsPage/modals/BaseFormModal/BaseFormModal.tsx";
|
||||
import BaseFormModal, {
|
||||
CreateEditFormProps,
|
||||
} from "../../ClientsPage/modals/BaseFormModal/BaseFormModal.tsx";
|
||||
import { Fieldset, Flex, rem, TextInput } from "@mantine/core";
|
||||
import ServiceCategorySelect from "../components/ServiceCategorySelect/ServiceCategorySelect.tsx";
|
||||
import ServiceTypeSelect from "../components/ServiceTypeSelect/ServiceTypeSelect.tsx";
|
||||
@@ -9,44 +11,57 @@ import ServicePriceTypeSegmentedControl, {
|
||||
ServicePriceType,
|
||||
} from "../components/ServicePriceTypeSegmentedControl/ServicePriceTypeSegmentedControl.tsx";
|
||||
import { useEffect, useState } from "react";
|
||||
import RangePriceInput, { PriceRangeInputType } from "../components/ServicePriceInput/RangePriceInput.tsx";
|
||||
import RangePriceInput, {
|
||||
PriceRangeInputType,
|
||||
} from "../components/ServicePriceInput/RangePriceInput.tsx";
|
||||
import SinglePriceInput from "../components/ServicePriceInput/SinglePriceInput.tsx";
|
||||
import PriceCategoryInput, { PriceCategoryInputProps } from "../components/ServicePriceInput/PriceCategoryInput.tsx";
|
||||
import PriceCategoryInput, {
|
||||
PriceCategoryInputProps,
|
||||
} from "../components/ServicePriceInput/PriceCategoryInput.tsx";
|
||||
|
||||
type Props = CreateEditFormProps<ServiceSchema>
|
||||
type Props = CreateEditFormProps<ServiceSchema>;
|
||||
const CreateServiceModal = ({
|
||||
context,
|
||||
id,
|
||||
innerProps,
|
||||
}: ContextModalProps<Props>) => {
|
||||
const [priceType, setPriceType] = useState<ServicePriceType>(ServicePriceType.DEFAULT);
|
||||
context,
|
||||
id,
|
||||
innerProps,
|
||||
}: ContextModalProps<Props>) => {
|
||||
const [priceType, setPriceType] = useState<ServicePriceType>(
|
||||
ServicePriceType.DEFAULT
|
||||
);
|
||||
const isEditing = "onChange" in innerProps;
|
||||
const initialValues: ServiceSchema = isEditing ? innerProps.element : {
|
||||
id: -1,
|
||||
name: "",
|
||||
price: 0,
|
||||
category: {
|
||||
id: -1,
|
||||
name: "",
|
||||
},
|
||||
serviceType: -1,
|
||||
priceRanges: [] as ServicePriceRangeSchema[],
|
||||
cost: null,
|
||||
categoryPrices: [],
|
||||
};
|
||||
const initialValues: ServiceSchema = isEditing
|
||||
? innerProps.element
|
||||
: {
|
||||
id: -1,
|
||||
name: "",
|
||||
price: 0,
|
||||
category: {
|
||||
id: -1,
|
||||
name: "",
|
||||
},
|
||||
serviceType: -1,
|
||||
priceRanges: [] as ServicePriceRangeSchema[],
|
||||
cost: null,
|
||||
categoryPrices: [],
|
||||
};
|
||||
|
||||
const form = useForm<ServiceSchema>({
|
||||
initialValues: initialValues,
|
||||
validate: {
|
||||
name: (name: string) => name.trim() !== "" ? null : "Необходимо ввести название услуги",
|
||||
category: (category: {
|
||||
id: number,
|
||||
name: string
|
||||
}) => category.id !== -1 ? null : "Необходимо выбрать категорию",
|
||||
serviceType: (serviceType: number) => serviceType !== -1 ? null : "Необходимо выбрать тип услуги",
|
||||
priceRanges: (value, values) => value.length > 0 || values.price > 0 ? null : "Необходимо добавить хотя бы один диапазон цен или указать цену за единицу услуги",
|
||||
price: (value, values) => value > 0 || values.priceRanges.length > 0 ? null : "Необходимо добавить хотя бы один диапазон цен или указать цену за единицу услуги",
|
||||
|
||||
name: (name: string) =>
|
||||
name.trim() !== "" ? null : "Необходимо ввести название услуги",
|
||||
category: (category: { id: number; name: string }) =>
|
||||
category.id !== -1 ? null : "Необходимо выбрать категорию",
|
||||
serviceType: (serviceType: number) =>
|
||||
serviceType !== -1 ? null : "Необходимо выбрать тип услуги",
|
||||
priceRanges: (value, values) =>
|
||||
value.length > 0 || values.price > 0
|
||||
? null
|
||||
: "Необходимо добавить хотя бы один диапазон цен или указать цену за единицу услуги",
|
||||
price: (value, values) =>
|
||||
value > 0 || values.priceRanges.length > 0
|
||||
? null
|
||||
: "Необходимо добавить хотя бы один диапазон цен или указать цену за единицу услуги",
|
||||
},
|
||||
});
|
||||
useEffect(() => {
|
||||
@@ -55,20 +70,30 @@ const CreateServiceModal = ({
|
||||
const getPriceBody = () => {
|
||||
switch (priceType) {
|
||||
case ServicePriceType.DEFAULT:
|
||||
return <SinglePriceInput
|
||||
placeholder={"Введите стоимость услуги"}
|
||||
label={"Cтоимость услуги"}
|
||||
hideControls
|
||||
{...form.getInputProps("cost")}
|
||||
/>;
|
||||
return (
|
||||
<SinglePriceInput
|
||||
placeholder={"Введите стоимость услуги"}
|
||||
label={"Cтоимость услуги"}
|
||||
hideControls
|
||||
{...form.getInputProps("cost")}
|
||||
/>
|
||||
);
|
||||
case ServicePriceType.BY_RANGE:
|
||||
return <RangePriceInput
|
||||
{...form.getInputProps("priceRanges") as PriceRangeInputType}
|
||||
/>;
|
||||
return (
|
||||
<RangePriceInput
|
||||
{...(form.getInputProps(
|
||||
"priceRanges"
|
||||
) as PriceRangeInputType)}
|
||||
/>
|
||||
);
|
||||
case ServicePriceType.BY_CATEGORY:
|
||||
return <PriceCategoryInput
|
||||
{...form.getInputProps("categoryPrices") as PriceCategoryInputProps}
|
||||
/>;
|
||||
return (
|
||||
<PriceCategoryInput
|
||||
{...(form.getInputProps(
|
||||
"categoryPrices"
|
||||
) as PriceCategoryInputProps)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
const onCancelClick = () => {
|
||||
@@ -79,8 +104,7 @@ const CreateServiceModal = ({
|
||||
{...innerProps}
|
||||
closeOnSubmit
|
||||
form={form}
|
||||
onClose={onCancelClick}
|
||||
>
|
||||
onClose={onCancelClick}>
|
||||
<BaseFormModal.Body>
|
||||
<>
|
||||
<Fieldset legend={"Общие параметры"}>
|
||||
@@ -101,21 +125,21 @@ const CreateServiceModal = ({
|
||||
/>
|
||||
</Fieldset>
|
||||
<Fieldset legend={"Стоимость"}>
|
||||
<Flex direction={"column"} gap={rem(10)} justify={"center"}>
|
||||
<Flex
|
||||
direction={"column"}
|
||||
gap={rem(10)}
|
||||
justify={"center"}>
|
||||
<ServicePriceTypeSegmentedControl
|
||||
value={priceType}
|
||||
onChange={setPriceType}
|
||||
/>
|
||||
{getPriceBody()}
|
||||
|
||||
</Flex>
|
||||
|
||||
</Fieldset>
|
||||
|
||||
</>
|
||||
</BaseFormModal.Body>
|
||||
</BaseFormModal>
|
||||
);
|
||||
};
|
||||
|
||||
export default CreateServiceModal;
|
||||
export default CreateServiceModal;
|
||||
|
||||
@@ -1,16 +1,24 @@
|
||||
import { ServicePriceCategorySchema } from "../../../client";
|
||||
import BaseFormModal, { CreateEditFormProps } from "../../ClientsPage/modals/BaseFormModal/BaseFormModal.tsx";
|
||||
import BaseFormModal, {
|
||||
CreateEditFormProps,
|
||||
} from "../../ClientsPage/modals/BaseFormModal/BaseFormModal.tsx";
|
||||
import { ContextModalProps } from "@mantine/modals";
|
||||
import { TextInput } from "@mantine/core";
|
||||
import { useForm } from "@mantine/form";
|
||||
|
||||
type Props = CreateEditFormProps<ServicePriceCategorySchema>;
|
||||
|
||||
const ServicePriceCategoryForm = ({ context, id, innerProps }: ContextModalProps<Props>) => {
|
||||
const ServicePriceCategoryForm = ({
|
||||
context,
|
||||
id,
|
||||
innerProps,
|
||||
}: ContextModalProps<Props>) => {
|
||||
const isEditing = "element" in innerProps;
|
||||
const initialValues: Partial<ServicePriceCategorySchema> = isEditing ? innerProps.element : {
|
||||
name: "",
|
||||
};
|
||||
const initialValues: Partial<ServicePriceCategorySchema> = isEditing
|
||||
? innerProps.element
|
||||
: {
|
||||
name: "",
|
||||
};
|
||||
const form = useForm<Partial<ServicePriceCategorySchema>>({
|
||||
initialValues,
|
||||
});
|
||||
@@ -19,8 +27,7 @@ const ServicePriceCategoryForm = ({ context, id, innerProps }: ContextModalProps
|
||||
{...innerProps}
|
||||
form={form}
|
||||
closeOnSubmit
|
||||
onClose={() => context.closeContextModal(id)}
|
||||
>
|
||||
onClose={() => context.closeContextModal(id)}>
|
||||
<BaseFormModal.Body>
|
||||
<>
|
||||
<TextInput
|
||||
@@ -32,7 +39,6 @@ const ServicePriceCategoryForm = ({ context, id, innerProps }: ContextModalProps
|
||||
</BaseFormModal.Body>
|
||||
</BaseFormModal>
|
||||
);
|
||||
|
||||
};
|
||||
|
||||
export default ServicePriceCategoryForm;
|
||||
export default ServicePriceCategoryForm;
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import BaseFormModal, { CreateEditFormProps } from "../../ClientsPage/modals/BaseFormModal/BaseFormModal.tsx";
|
||||
import BaseFormModal, {
|
||||
CreateEditFormProps,
|
||||
} from "../../ClientsPage/modals/BaseFormModal/BaseFormModal.tsx";
|
||||
import { GetServiceKitSchema } from "../../../client";
|
||||
import { ContextModalProps } from "@mantine/modals";
|
||||
import { useForm } from "@mantine/form";
|
||||
@@ -9,29 +11,28 @@ import ServicesMultiselect from "../../../components/Selects/ServicesMultiselect
|
||||
|
||||
type Props = CreateEditFormProps<GetServiceKitSchema>;
|
||||
const ServiceKitModalForm = ({
|
||||
context,
|
||||
id,
|
||||
innerProps,
|
||||
}: ContextModalProps<Props>) => {
|
||||
context,
|
||||
id,
|
||||
innerProps,
|
||||
}: ContextModalProps<Props>) => {
|
||||
const isEditing = "element" in innerProps;
|
||||
const initialValues: Partial<GetServiceKitSchema> = isEditing ? innerProps.element : {
|
||||
name: "",
|
||||
serviceType: ServiceType.DEAL_SERVICE,
|
||||
services: [],
|
||||
};
|
||||
const initialValues: Partial<GetServiceKitSchema> = isEditing
|
||||
? innerProps.element
|
||||
: {
|
||||
name: "",
|
||||
serviceType: ServiceType.DEAL_SERVICE,
|
||||
services: [],
|
||||
};
|
||||
|
||||
const form = useForm<Partial<GetServiceKitSchema>>(
|
||||
{
|
||||
initialValues,
|
||||
},
|
||||
);
|
||||
const form = useForm<Partial<GetServiceKitSchema>>({
|
||||
initialValues,
|
||||
});
|
||||
return (
|
||||
<BaseFormModal
|
||||
{...innerProps}
|
||||
form={form}
|
||||
closeOnSubmit
|
||||
onClose={() => context.closeContextModal(id)}
|
||||
>
|
||||
onClose={() => context.closeContextModal(id)}>
|
||||
<BaseFormModal.Body>
|
||||
<>
|
||||
<TextInput
|
||||
@@ -47,8 +48,10 @@ const ServiceKitModalForm = ({
|
||||
<ServicesMultiselect
|
||||
label={"Услуги"}
|
||||
placeholder={"Выберите услуги"}
|
||||
filterBy={(service) => service.serviceType === form.values.serviceType}
|
||||
groupBy={(service) => service.category.name}
|
||||
filterBy={service =>
|
||||
service.serviceType === form.values.serviceType
|
||||
}
|
||||
groupBy={service => service.category.name}
|
||||
{...form.getInputProps("services")}
|
||||
/>
|
||||
</>
|
||||
@@ -57,4 +60,4 @@ const ServiceKitModalForm = ({
|
||||
);
|
||||
};
|
||||
|
||||
export default ServiceKitModalForm;
|
||||
export default ServiceKitModalForm;
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
padding: rem(5);
|
||||
gap: rem(10);
|
||||
display: flex;
|
||||
|
||||
}
|
||||
|
||||
.top-panel-last-item {
|
||||
|
||||
@@ -13,12 +13,21 @@ import useServicesKitsState from "../hooks/useServicesKitsState.tsx";
|
||||
import useServicePriceCategoryState from "../hooks/useServicePriceCategoryState.tsx";
|
||||
import { ObjectStateToTableProps } from "../../../types/utils.ts";
|
||||
|
||||
|
||||
export const ServicesPage: FC = () => {
|
||||
const [serviceType, setServiceType] = useState(ServicesTab.DEAL_SERVICE);
|
||||
const { services, onServiceDelete, onServiceUpdate, onCreateClick, onCreateCategoryClick } = useServicesState();
|
||||
const { servicesKits, onKitUpdate, onKitCreateClick } = useServicesKitsState();
|
||||
const { onCreateClick: onCreatePriceCategoryClick, ...priceCategoryRestProps } = useServicePriceCategoryState();
|
||||
const {
|
||||
services,
|
||||
onServiceDelete,
|
||||
onServiceUpdate,
|
||||
onCreateClick,
|
||||
onCreateCategoryClick,
|
||||
} = useServicesState();
|
||||
const { servicesKits, onKitUpdate, onKitCreateClick } =
|
||||
useServicesKitsState();
|
||||
const {
|
||||
onCreateClick: onCreatePriceCategoryClick,
|
||||
...priceCategoryRestProps
|
||||
} = useServicePriceCategoryState();
|
||||
const getBody = () => {
|
||||
switch (serviceType) {
|
||||
case ServicesTab.SERVICES_KITS:
|
||||
@@ -34,7 +43,9 @@ export const ServicesPage: FC = () => {
|
||||
<ServicesTable
|
||||
onDelete={onServiceDelete}
|
||||
onChange={onServiceUpdate}
|
||||
items={services.filter(service => service.serviceType == serviceType)}
|
||||
items={services.filter(
|
||||
service => service.serviceType == serviceType
|
||||
)}
|
||||
/>
|
||||
);
|
||||
case ServicesTab.SERVICES_PRICE_CATEGORIES:
|
||||
@@ -50,23 +61,39 @@ export const ServicesPage: FC = () => {
|
||||
switch (serviceType) {
|
||||
case ServicesTab.SERVICES_KITS:
|
||||
return (
|
||||
<Button onClick={onKitCreateClick} variant={"default"}>Создать набор</Button>
|
||||
<Button
|
||||
onClick={onKitCreateClick}
|
||||
variant={"default"}>
|
||||
Создать набор
|
||||
</Button>
|
||||
);
|
||||
case ServicesTab.DEAL_SERVICE:
|
||||
case ServicesTab.PRODUCT_SERVICE:
|
||||
return (
|
||||
<>
|
||||
<Button onClick={onCreateClick} variant={"default"}>Создать услугу</Button>
|
||||
<Button onClick={onCreateCategoryClick} variant={"default"}>Создать категорию</Button>
|
||||
<Button
|
||||
onClick={onCreateClick}
|
||||
variant={"default"}>
|
||||
Создать услугу
|
||||
</Button>
|
||||
<Button
|
||||
onClick={onCreateCategoryClick}
|
||||
variant={"default"}>
|
||||
Создать категорию
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
case ServicesTab.SERVICES_PRICE_CATEGORIES:
|
||||
return (
|
||||
<Button variant={"default"} onClick={() => {
|
||||
if (onCreatePriceCategoryClick) {
|
||||
onCreatePriceCategoryClick();
|
||||
}
|
||||
}}>Создать категорию</Button>
|
||||
<Button
|
||||
variant={"default"}
|
||||
onClick={() => {
|
||||
if (onCreatePriceCategoryClick) {
|
||||
onCreatePriceCategoryClick();
|
||||
}
|
||||
}}>
|
||||
Создать категорию
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -78,13 +105,11 @@ export const ServicesPage: FC = () => {
|
||||
<ServiceTypeSegmentedControl
|
||||
className={styles["top-panel-last-item"]}
|
||||
value={serviceType.toString()}
|
||||
onChange={(event) => setServiceType(parseInt(event))}
|
||||
onChange={event => setServiceType(parseInt(event))}
|
||||
/>
|
||||
</div>
|
||||
</PageBlock>
|
||||
<PageBlock>
|
||||
{getBody()}
|
||||
</PageBlock>
|
||||
<PageBlock>{getBody()}</PageBlock>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user