crap
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
import {Select} from "@mantine/core";
|
||||
import useServiceCategoriesList from "../../hooks/useServiceCategoriesList.tsx";
|
||||
import {ServiceCategorySchema} from "../../../../client";
|
||||
import {FC, ReactNode} from "react";
|
||||
|
||||
type Props = {
|
||||
fullWidth?: boolean,
|
||||
defaultValue?: ServiceCategorySchema
|
||||
onChange: (category: ServiceCategorySchema) => void
|
||||
error?: ReactNode
|
||||
}
|
||||
const ServiceCategorySelect: FC<Props> = ({defaultValue, onChange, fullWidth, error}) => {
|
||||
const {categories} = useServiceCategoriesList();
|
||||
|
||||
return (
|
||||
<Select
|
||||
error={error}
|
||||
w={fullWidth ? "100%" : undefined}
|
||||
checkIconPosition={"right"}
|
||||
label={"Категория услуги"}
|
||||
placeholder={"Выберите категорию услуги"}
|
||||
data={categories.map(category => ({
|
||||
label: category.name,
|
||||
value: category.id.toString()
|
||||
}))}
|
||||
onChange={event => {
|
||||
if (!event) return;
|
||||
const category = categories.find(category => category.id == parseInt(event))
|
||||
if (!category) return;
|
||||
onChange(category)
|
||||
}}
|
||||
value={defaultValue && defaultValue.id.toString()}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export default ServiceCategorySelect;
|
||||
@@ -0,0 +1,30 @@
|
||||
import {ServiceSchema} from "../../../../client";
|
||||
import {FC, RefObject} from "react";
|
||||
import {useServicesTableColumns} from "./columns.tsx";
|
||||
import {BaseTable, BaseTableRef} from "../../../../components/BaseTable/BaseTable.tsx";
|
||||
import {MRT_TableOptions} from "mantine-react-table";
|
||||
|
||||
type Props = {
|
||||
services: ServiceSchema[];
|
||||
tableRef?: RefObject<BaseTableRef<ServiceSchema>>
|
||||
}
|
||||
const ServicesTable: FC<Props> = ({services, tableRef}) => {
|
||||
const columns = useServicesTableColumns();
|
||||
return (
|
||||
<BaseTable
|
||||
ref={tableRef}
|
||||
data={services}
|
||||
columns={columns}
|
||||
restProps={{
|
||||
enableGrouping: true,
|
||||
initialState: {grouping: ["category"]},
|
||||
enableColumnActions: false,
|
||||
mantineCreateRowModalProps: {
|
||||
transitionProps: {transition: 'rotate-left', duration: 300}
|
||||
},
|
||||
} as MRT_TableOptions<ServiceSchema>}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export default ServicesTable;
|
||||
31
src/pages/ServicesPage/components/ServicesTable/columns.tsx
Normal file
31
src/pages/ServicesPage/components/ServicesTable/columns.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
import {useMemo} from "react";
|
||||
import {MRT_ColumnDef} from "mantine-react-table";
|
||||
import {ServiceSchema} from "../../../../client";
|
||||
|
||||
export const useServicesTableColumns = () => {
|
||||
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,
|
||||
|
||||
|
||||
},
|
||||
], []);
|
||||
|
||||
}
|
||||
14
src/pages/ServicesPage/hooks/useServiceCategoriesList.tsx
Normal file
14
src/pages/ServicesPage/hooks/useServiceCategoriesList.tsx
Normal file
@@ -0,0 +1,14 @@
|
||||
import {useQuery} from "@tanstack/react-query";
|
||||
import {ServiceService} from "../../../client";
|
||||
|
||||
const useServiceCategoriesList = () => {
|
||||
const {isPending, error, data, refetch} = useQuery({
|
||||
queryKey: ['getAllServiceCategories'],
|
||||
queryFn: ServiceService.getAllServiceCategories,
|
||||
});
|
||||
const categories = isPending || error || !data ? [] : data.categories;
|
||||
|
||||
return {categories, refetch}
|
||||
}
|
||||
|
||||
export default useServiceCategoriesList;
|
||||
13
src/pages/ServicesPage/hooks/useServicesList.tsx
Normal file
13
src/pages/ServicesPage/hooks/useServicesList.tsx
Normal file
@@ -0,0 +1,13 @@
|
||||
import {useQuery} from "@tanstack/react-query";
|
||||
import {ServiceService} from "../../../client";
|
||||
|
||||
const useServicesList = () => {
|
||||
const {isPending, error, data, refetch} = useQuery({
|
||||
queryKey: ['getAllServices'],
|
||||
queryFn: ServiceService.getAllServices
|
||||
});
|
||||
const services = isPending || error || !data ? [] : data.services;
|
||||
|
||||
return {services, refetch}
|
||||
}
|
||||
export default useServicesList;
|
||||
1
src/pages/ServicesPage/index.ts
Normal file
1
src/pages/ServicesPage/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export {ServicesPage} from './ui/ServicesPage.tsx';
|
||||
52
src/pages/ServicesPage/modals/CreateServiceCategoryModal.tsx
Normal file
52
src/pages/ServicesPage/modals/CreateServiceCategoryModal.tsx
Normal file
@@ -0,0 +1,52 @@
|
||||
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
|
||||
}
|
||||
const CreateServiceCategoryModal = ({
|
||||
context,
|
||||
id,
|
||||
innerProps,
|
||||
}: ContextModalProps<Props>) => {
|
||||
const form = useForm({
|
||||
initialValues: {
|
||||
name: ''
|
||||
},
|
||||
validate: {
|
||||
name: (name) => name.trim() !== '' ? null : "Необходимо ввести название категории",
|
||||
}
|
||||
})
|
||||
const onSubmit = (values: { name: string }) => {
|
||||
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"}>
|
||||
<TextInput
|
||||
|
||||
placeholder={"Введите название категори"}
|
||||
label={"Название категории"}
|
||||
{...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>
|
||||
</Flex>
|
||||
|
||||
</form>
|
||||
</>
|
||||
)
|
||||
}
|
||||
export default CreateServiceCategoryModal;
|
||||
76
src/pages/ServicesPage/modals/CreateServiceModal.tsx
Normal file
76
src/pages/ServicesPage/modals/CreateServiceModal.tsx
Normal file
@@ -0,0 +1,76 @@
|
||||
import {ServiceSchema} from "../../../client";
|
||||
import {Button, Flex, NumberInput, rem, TextInput} from "@mantine/core";
|
||||
import ServiceCategorySelect from "../components/ServiceCategorySelect/ServiceCategorySelect.tsx";
|
||||
import {useForm} from "@mantine/form";
|
||||
import {ContextModalProps} from "@mantine/modals";
|
||||
|
||||
type Props = {
|
||||
onCreate: (service: ServiceSchema) => void
|
||||
}
|
||||
const CreateServiceModal = ({
|
||||
context,
|
||||
id,
|
||||
innerProps,
|
||||
}: ContextModalProps<Props>) => {
|
||||
const form = useForm({
|
||||
initialValues: {
|
||||
category: {
|
||||
id: -1,
|
||||
name: ''
|
||||
},
|
||||
name: '',
|
||||
price: NaN
|
||||
},
|
||||
validate: {
|
||||
category: (category) => category.id >= 0 ? null : "Необходимо выбрать категорию",
|
||||
name: (name) => name.trim() !== '' ? null : "Необходимо ввести название услуги",
|
||||
price: (price) => !isNaN(price) ? null : "Небходимо ввести стоимость услуги"
|
||||
}
|
||||
})
|
||||
|
||||
const onSubmit = (values: { category: { id: number; name: string; }; name: string; price: number; }) => {
|
||||
innerProps.onCreate({...values, id: -1});
|
||||
context.closeContextModal(id);
|
||||
}
|
||||
const onCancelClick = () => {
|
||||
context.closeContextModal(id);
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<form onSubmit={form.onSubmit((values) => onSubmit(values))}>
|
||||
<Flex gap={rem(10)} direction={"column"}>
|
||||
|
||||
<ServiceCategorySelect
|
||||
fullWidth
|
||||
onChange={event => {
|
||||
form.setFieldValue("category", event)
|
||||
}}
|
||||
error={form.getInputProps("category").error}
|
||||
/>
|
||||
<TextInput
|
||||
|
||||
placeholder={"Введите название услуги"}
|
||||
label={"Название услуги"}
|
||||
{...form.getInputProps('name')}
|
||||
/>
|
||||
<NumberInput
|
||||
placeholder={"Введите стоимость услуги"}
|
||||
label={"Стоимость услуги"}
|
||||
hideControls
|
||||
decimalScale={2}
|
||||
{...form.getInputProps('price')}
|
||||
/>
|
||||
|
||||
<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 CreateServiceModal;
|
||||
12
src/pages/ServicesPage/ui/ServicesPage.module.css
Normal file
12
src/pages/ServicesPage/ui/ServicesPage.module.css
Normal file
@@ -0,0 +1,12 @@
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
gap: rem(10);
|
||||
}
|
||||
|
||||
.top-panel {
|
||||
padding: rem(5);
|
||||
gap: rem(10);
|
||||
display: flex;
|
||||
}
|
||||
67
src/pages/ServicesPage/ui/ServicesPage.tsx
Normal file
67
src/pages/ServicesPage/ui/ServicesPage.tsx
Normal file
@@ -0,0 +1,67 @@
|
||||
import {FC, useRef} from "react";
|
||||
import ServicesTable from "../components/ServicesTable/ServicesTable.tsx";
|
||||
import useServicesList from "../hooks/useServicesList.tsx";
|
||||
import PageBlock from "../../../components/PageBlock/PageBlock.tsx";
|
||||
import styles from './ServicesPage.module.css';
|
||||
import {Button} from "@mantine/core";
|
||||
import {BaseTableRef} from "../../../components/BaseTable/BaseTable.tsx";
|
||||
import {ServiceCategorySchema, ServiceSchema, ServiceService} from "../../../client";
|
||||
import {notifications} from "../../../shared/lib/notifications.ts";
|
||||
import {modals} from "@mantine/modals";
|
||||
|
||||
export const ServicesPage: FC = () => {
|
||||
const {services, refetch} = useServicesList();
|
||||
|
||||
const tableRef = useRef<BaseTableRef<ServiceSchema>>(null);
|
||||
|
||||
const onCreateClick = () => {
|
||||
modals.openContextModal({
|
||||
modal: 'createService',
|
||||
title: 'Создание услуги',
|
||||
withCloseButton: false,
|
||||
innerProps: {
|
||||
onCreate
|
||||
}
|
||||
})
|
||||
}
|
||||
const onCreate = (values: ServiceSchema) => {
|
||||
ServiceService.createService({requestBody: {service: values}})
|
||||
.then(({ok, message}) => {
|
||||
notifications.guess(ok, {message: message});
|
||||
if (!ok) return;
|
||||
refetch();
|
||||
})
|
||||
}
|
||||
const onCreateCategoryClick = () => {
|
||||
modals.openContextModal({
|
||||
modal: "createServiceCategory",
|
||||
title: 'Создание категории',
|
||||
withCloseButton: false,
|
||||
innerProps: {
|
||||
onCreate: onCategoryCreate
|
||||
}
|
||||
})
|
||||
}
|
||||
const onCategoryCreate = (category: ServiceCategorySchema) => {
|
||||
ServiceService.createServiceCategory({requestBody: {category: category}})
|
||||
.then(({ok, message}) =>
|
||||
notifications.guess(ok, {message: message}))
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles['container']}>
|
||||
<PageBlock>
|
||||
<div className={styles['top-panel']}>
|
||||
<Button onClick={onCreateClick} variant={"default"}>Создать услугу</Button>
|
||||
<Button onClick={onCreateCategoryClick} variant={"default"}>Создать категорию</Button>
|
||||
</div>
|
||||
</PageBlock>
|
||||
<PageBlock>
|
||||
<ServicesTable
|
||||
tableRef={tableRef}
|
||||
services={services}
|
||||
/>
|
||||
</PageBlock>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user