crap
This commit is contained in:
@@ -1,17 +1,18 @@
|
||||
import {FC} from "react";
|
||||
import styles from './ClientsPage.module.css';
|
||||
import ClientsTable from "./components/ClientsTable/ClientsTable.tsx";
|
||||
import {ClientService} from "../../client";
|
||||
import {useQuery} from "@tanstack/react-query";
|
||||
|
||||
import useClientsList from "./hooks/useClientsList.tsx";
|
||||
import PageBlock from "../../components/PageBlock/PageBlock.tsx";
|
||||
|
||||
const ClientsPage: FC = () => {
|
||||
const {data} = useQuery({queryKey: ['clients'], queryFn: ClientService.getAllClients})
|
||||
const {clients} = useClientsList();
|
||||
return (
|
||||
<div className={styles['container']}>
|
||||
<ClientsTable data={data?.clients || []}/>
|
||||
</div>
|
||||
<>
|
||||
<PageBlock>
|
||||
|
||||
<ClientsTable data={clients}/>
|
||||
</PageBlock>
|
||||
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default ClientsPage;
|
||||
@@ -1,52 +1,28 @@
|
||||
import {Checkbox, rem, Table} from "@mantine/core";
|
||||
import {columns} from "./columns.tsx";
|
||||
import React, {FC} from "react";
|
||||
import {Client} from "../../../../types/Client.ts";
|
||||
import {IconEdit} from "@tabler/icons-react";
|
||||
import {notifications} from "../../../../shared/lib/notifications.ts";
|
||||
import {FC} from "react";
|
||||
import {BaseTable} from "../../../../components/BaseTable/BaseTable.tsx";
|
||||
import {useClientsTableColumns} from "./columns.tsx";
|
||||
import {MantineReactTable, MRT_Table, MRT_TableOptions, useMantineReactTable} from "mantine-react-table";
|
||||
import {ClientSchema} from "../../../../client";
|
||||
|
||||
type Props = {
|
||||
data: Client[];
|
||||
data: ClientSchema[];
|
||||
|
||||
}
|
||||
const ClientsTable: FC<Props> = ({data}) => {
|
||||
|
||||
const columns = useClientsTableColumns();
|
||||
return (
|
||||
<Table.ScrollContainer minWidth={rem(50)}>
|
||||
<Table striped>
|
||||
|
||||
<Table.Thead>
|
||||
<Table.Tr>
|
||||
<Table.Th/>
|
||||
|
||||
{columns.map(column => (
|
||||
<Table.Th>{column.header}</Table.Th>
|
||||
))}
|
||||
</Table.Tr>
|
||||
</Table.Thead>
|
||||
<Table.Tbody>
|
||||
{data.map(client => (
|
||||
<Table.Tr key={client.name}>
|
||||
<Table.Td>
|
||||
|
||||
<IconEdit
|
||||
onClick={() => {
|
||||
notifications.success({message: `Редактирую ${client.id}`})
|
||||
}}
|
||||
style={{cursor: 'pointer'}}
|
||||
/>
|
||||
</Table.Td>
|
||||
|
||||
{columns.map(column => (
|
||||
<Table.Td>{client[column.accessorKey]}</Table.Td>
|
||||
|
||||
))}
|
||||
</Table.Tr>
|
||||
))}
|
||||
</Table.Tbody>
|
||||
</Table>
|
||||
|
||||
</Table.ScrollContainer>
|
||||
<BaseTable
|
||||
striped
|
||||
data={data}
|
||||
columns={columns}
|
||||
restProps={{
|
||||
enableSorting: false,
|
||||
enableColumnActions: false,
|
||||
enableRowSelection: true,
|
||||
enableColumnResizing: true,
|
||||
layoutMode: "grid"
|
||||
} as MRT_TableOptions<ClientSchema>}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,25 @@
|
||||
import {Client} from "../../../../types/Client.ts";
|
||||
import {useMemo} from "react";
|
||||
import {MRT_ColumnDef} from "mantine-react-table";
|
||||
import {ClientSchema} from "../../../../client";
|
||||
|
||||
type Column = {
|
||||
accessorKey: keyof Client;
|
||||
header: string;
|
||||
|
||||
export const useClientsTableColumns = () => {
|
||||
return useMemo<MRT_ColumnDef<ClientSchema>[]>(() => [
|
||||
{
|
||||
accessorKey: "name",
|
||||
header: "Имя",
|
||||
},
|
||||
{
|
||||
accessorKey: "details.address",
|
||||
header: "Адрес"
|
||||
},
|
||||
{
|
||||
accessorKey: "details.email",
|
||||
header: "EMAIL"
|
||||
},
|
||||
{
|
||||
accessorKey: "details.phone_number",
|
||||
header: "Телефон"
|
||||
}
|
||||
], []);
|
||||
}
|
||||
export const columns: Column[] = [
|
||||
{
|
||||
accessorKey: 'name',
|
||||
header: 'Название'
|
||||
}
|
||||
]
|
||||
13
src/pages/ClientsPage/hooks/useClientsList.tsx
Normal file
13
src/pages/ClientsPage/hooks/useClientsList.tsx
Normal file
@@ -0,0 +1,13 @@
|
||||
import {ClientService} from "../../../client";
|
||||
import {useQuery} from "@tanstack/react-query";
|
||||
|
||||
const useClientsList = () => {
|
||||
const {isPending, error, data, refetch} = useQuery({
|
||||
queryKey: ['getAllClients'],
|
||||
queryFn: ClientService.getAllClients
|
||||
});
|
||||
const clients = isPending || error || !data ? [] : data.clients;
|
||||
|
||||
return {clients, refetch}
|
||||
}
|
||||
export default useClientsList;
|
||||
15
src/pages/LeadsPage/hooks/useDealSummaries.tsx
Normal file
15
src/pages/LeadsPage/hooks/useDealSummaries.tsx
Normal file
@@ -0,0 +1,15 @@
|
||||
import {useQuery} from "@tanstack/react-query";
|
||||
import {DealService, DealSummary} from "../../../client";
|
||||
|
||||
export const useDealSummaries = (): DealSummary[] => {
|
||||
const {data: summaries = []} = useQuery({
|
||||
queryKey: ['getDealSummaries'],
|
||||
queryFn: DealService.getDealSummaries,
|
||||
select: data => data.summaries || [] // Трансформируем полученные данные
|
||||
});
|
||||
|
||||
// Теперь summaries будет содержать либо трансформированные данные, либо пустой массив по умолчанию
|
||||
// isLoading и isError могут быть использованы для отображения индикаторов загрузки или ошибки
|
||||
|
||||
return summaries;
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,31 +1,70 @@
|
||||
import {FC, useEffect} from "react";
|
||||
import React, {FC, useEffect, useState} from "react";
|
||||
import styles from './LeadsPage.module.css';
|
||||
import Board from "../../../components/Dnd/Board/Board.tsx";
|
||||
import {Button, TextInput} from "@mantine/core";
|
||||
import {DragDropContext} from "@hello-pangea/dnd";
|
||||
import {useDealSummaries} from "../hooks/useDealSummaries.tsx";
|
||||
import {DealStatus} from "../../../shared/enums/DealStatus.ts";
|
||||
import PageBlock from "../../../components/PageBlock/PageBlock.tsx";
|
||||
|
||||
|
||||
export const LeadsPage: FC = () => {
|
||||
|
||||
const summariesRaw = useDealSummaries();
|
||||
const [summaries, setSummaries] = useState(summariesRaw);
|
||||
useEffect(() => {
|
||||
// dispatch(setIsLoading(true));
|
||||
}, []);
|
||||
|
||||
setSummaries(summariesRaw);
|
||||
}, [summariesRaw]);
|
||||
const onDragEnd = () => {
|
||||
// if (!result.destination) return;
|
||||
//
|
||||
// const newStatus = getDealStatusByName(
|
||||
// result.destination.droppableId
|
||||
// );
|
||||
// const summaryId = parseInt(result.draggableId);
|
||||
//
|
||||
// return;
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<div className={styles['container']}>
|
||||
<div className={styles['boards']}>
|
||||
<DragDropContext onDragEnd={() => {
|
||||
}}>
|
||||
<Board title={"Ожидает приемки"} withCreateButton droppableId={"AWAITING_ACCEPTANCE"}/>
|
||||
<Board title={"Упаковка"} droppableId={"PACKAGING"}/>
|
||||
<Board title={"Ожидает отгрузки"} droppableId={"AWAITING_SHIPMENT"}/>
|
||||
<Board title={"Ожидает оплаты"} droppableId={"AWAITING_PAYMENT"}/>
|
||||
<Board title={"Завершена"} droppableId={"COMPLETED"}/>
|
||||
|
||||
</DragDropContext>
|
||||
|
||||
<PageBlock>
|
||||
<div className={styles['container']}>
|
||||
<div className={styles['boards']}>
|
||||
<DragDropContext onDragEnd={onDragEnd}>
|
||||
<Board
|
||||
withCreateButton
|
||||
summaries={summaries
|
||||
.filter(summary => summary.status == DealStatus.AWAITING_ACCEPTANCE)}
|
||||
title={"Ожидает приемки"}
|
||||
droppableId={"AWAITING_ACCEPTANCE"}
|
||||
/>
|
||||
<Board
|
||||
summaries={summaries
|
||||
.filter(summary => summary.status == DealStatus.PACKAGING)}
|
||||
title={"Упаковка"}
|
||||
droppableId={"PACKAGING"}
|
||||
/>
|
||||
<Board
|
||||
summaries={summaries
|
||||
.filter(summary => summary.status == DealStatus.AWAITING_SHIPMENT)}
|
||||
title={"Ожидает отгрузки"}
|
||||
droppableId={"AWAITING_SHIPMENT"}
|
||||
/>
|
||||
<Board
|
||||
summaries={summaries
|
||||
.filter(summary => summary.status == DealStatus.AWAITING_PAYMENT)}
|
||||
title={"Ожидает оплаты"}
|
||||
droppableId={"AWAITING_PAYMENT"}
|
||||
/>
|
||||
<Board
|
||||
summaries={summaries
|
||||
.filter(summary => summary.status == DealStatus.COMPLETED)}
|
||||
title={"Завершена"}
|
||||
droppableId={"COMPLETED"}
|
||||
/>
|
||||
</DragDropContext>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</PageBlock>
|
||||
|
||||
</>
|
||||
|
||||
)
|
||||
|
||||
14
src/pages/PageWrapper/PageWrapper.module.css
Normal file
14
src/pages/PageWrapper/PageWrapper.module.css
Normal file
@@ -0,0 +1,14 @@
|
||||
.main-container {
|
||||
@mixin dark {
|
||||
background-color: var(--mantine-color-dark-6);
|
||||
}
|
||||
@mixin light {
|
||||
background-color: var(--mantine-color-gray-0);
|
||||
}
|
||||
}
|
||||
|
||||
.container {
|
||||
padding: rem(20);
|
||||
display: flex;
|
||||
min-height: 100vh;
|
||||
}
|
||||
@@ -1,31 +1,35 @@
|
||||
import {FC, ReactNode} from "react";
|
||||
import {Flex, rem} from "@mantine/core";
|
||||
import {AppShell, rem} from "@mantine/core";
|
||||
import {Navbar} from "../../components/Navbar/Navbar.tsx";
|
||||
import {useSelector} from "react-redux";
|
||||
import {RootState} from "../../redux/store.ts";
|
||||
import Header from "../../components/Header/Header.tsx";
|
||||
import styles from './PageWrapper.module.css';
|
||||
|
||||
export type Props = {
|
||||
children: ReactNode;
|
||||
}
|
||||
const PageWrapper: FC<Props> = ({children}) => {
|
||||
const authState = useSelector((state: RootState) => state.auth);
|
||||
return (<Flex style={{flex: 1}}>
|
||||
|
||||
{authState.isAuthorized &&
|
||||
|
||||
return (
|
||||
<AppShell
|
||||
layout={"alt"}
|
||||
navbar={{width: rem('80px'), breakpoint: "sm"}}
|
||||
// header={{height:rem(60)}}
|
||||
>
|
||||
{/*<AppShell.Header>*/}
|
||||
{/* <Header/>*/}
|
||||
{/*</AppShell.Header>*/}
|
||||
<AppShell.Navbar>
|
||||
<Navbar/>
|
||||
}
|
||||
<div style={{flex: 1, display: 'flex', flexDirection: 'column'}}>
|
||||
<Header/>
|
||||
<div style={{padding:rem(20), flex:1}}>
|
||||
|
||||
</AppShell.Navbar>
|
||||
<AppShell.Main className={styles['main-container']}>
|
||||
<div className={styles['container']}>
|
||||
{children}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</Flex>
|
||||
</AppShell.Main>
|
||||
</AppShell>
|
||||
)
|
||||
}
|
||||
export default PageWrapper;
|
||||
@@ -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