This commit is contained in:
2024-03-19 09:02:58 +03:00
parent cc14105276
commit c9f3d4ee12
56 changed files with 995 additions and 121 deletions

View File

@@ -0,0 +1,49 @@
import {
MantineReactTable,
MRT_ColumnDef,
MRT_RowData,
MRT_Table,
MRT_TableInstance,
MRT_TableOptions,
useMantineReactTable
} from "mantine-react-table";
import {MRT_Localization_RU} from "mantine-react-table/locales/ru/index.cjs";
import {forwardRef, useEffect, useImperativeHandle} from 'react';
type Props<T extends Record<string, any>, K extends keyof T> = {
data: T[],
columns: MRT_ColumnDef<T>[],
restProps?: MRT_TableOptions<T>,
striped?: boolean
}
// Экспортируем тип рефа, чтобы он мог быть использован в других компонентах
export type BaseTableRef<T extends MRT_RowData> = {
getTable: () => MRT_TableInstance<T>;
};
export const BaseTable = forwardRef<BaseTableRef<any>, Props<any>>((props, ref) => {
const {data, columns, restProps, striped} = props;
const table = useMantineReactTable({
localization: MRT_Localization_RU,
enablePagination: false,
data,
columns,
mantineTableProps: {
striped: striped
},
enableTopToolbar: false,
...restProps,
});
// Используем useImperativeHandle для определения, что будет доступно через ref
useImperativeHandle(ref, () => ({
// Предполагаем, что есть метод getTable в table, который мы хотим выставить
getTable: () => table
}));
return <MantineReactTable table={table}/>;
});

View File

@@ -21,4 +21,20 @@
flex-direction: column;
/*background-color: red;*/
height: 100%;
}
.items-list::after {
height: 5rem;
content: "";
}
.items-list-drag-over {
@mixin light {
background-color: var(--mantine-color-gray-1);
}
@mixin dark {
background-color: var(--mantine-color-dark-5);
}
border-radius: var(--item-border-radius);
}

View File

@@ -3,14 +3,18 @@ import styles from './Board.module.css';
import {Divider, Text, Title} from '@mantine/core';
import {Draggable, Droppable} from "@hello-pangea/dnd";
import CreateDealButton from "../CreateDealButton/CreateDealButton.tsx";
import {DealSummary} from "../../../client";
import DealSummaryCard from "../DealSummaryCard/DealSummaryCard.tsx";
import classNames from "classnames";
type Props = {
droppableId: string;
title: string;
withCreateButton?: boolean;
summaries: DealSummary[];
}
export const Board: FC<Props> = ({droppableId, title, withCreateButton = false}) => {
export const Board: FC<Props> = ({droppableId, title, summaries, withCreateButton = false}) => {
return (
@@ -20,26 +24,43 @@ export const Board: FC<Props> = ({droppableId, title, withCreateButton = false})
<Text>12 сделок: 500р</Text>
<Divider size={"xl"} my={10} color={"blue"}/>
</div>
<Droppable droppableId={droppableId}>
{(provided) => (
<div ref={provided.innerRef} className={styles["items-list"]}>
<Droppable
droppableId={droppableId}
>
{(provided, snapshot) => (
<div ref={provided.innerRef}
className={classNames(
styles["items-list"],
(snapshot.isDraggingOver && !snapshot.draggingFromThisWith)
&& styles["items-list-drag-over"]
)}
{...provided.droppableProps}
>
{withCreateButton &&
<CreateDealButton
onClick={() => {
}}
/>}
<Draggable draggableId={droppableId + '1'} index={1}>
{(provided) => (
<div {...provided.draggableProps}
{...provided.dragHandleProps}
ref={provided.innerRef}
{summaries.map(summary =>
(
<Draggable
draggableId={summary.id.toString()}
index={1}
key={summary.id}
>
</div>
{(provided) => (
<div {...provided.draggableProps}
{...provided.dragHandleProps}
ref={provided.innerRef}
)}
</Draggable>
>
<DealSummaryCard dealSummary={summary}/>
</div>
)}
</Draggable>
))}
{provided.placeholder}
</div>

View File

@@ -3,9 +3,9 @@
min-height: 5rem;
display: flex;
justify-content: center;
align-items: center;
align-items: stretch;
text-align: center;
flex-direction: column;
border: dashed var(--item-border-size) var(--mantine-color-default-border);
border-radius: var(--item-border-radius);
cursor: pointer;

View File

@@ -9,7 +9,7 @@ import {dateWithoutTimezone} from "../../../shared/lib/utils.ts";
type Props = {
onClick: () => void;
}
const CreateDealButton: FC<Props> = ({onClick}) => {
const CreateDealButton: FC<Props> = () => {
const [isCreating, setIsCreating] = useState(false);
const [isTransitionEnded, setIsTransitionEnded] = useState(true);
return (
@@ -27,6 +27,7 @@ const CreateDealButton: FC<Props> = ({onClick}) => {
mounted={isCreating}
transition={"scale-y"}
onExited={() => setIsTransitionEnded(true)}
>
{(styles) => (
<div style={styles}>
@@ -35,7 +36,6 @@ const CreateDealButton: FC<Props> = ({onClick}) => {
setIsCreating(false)
}}
onSubmit={(quickDeal) => {
console.log(quickDeal);
DealService.quickCreateDealQuickCreatePost({
requestBody: {
...quickDeal,

View File

@@ -0,0 +1,33 @@
.container {
min-height: 5rem;
display: flex;
flex-direction: row;
justify-content: space-between;
border: dashed var(--item-border-size) var(--mantine-color-default-border);
border-radius: var(--item-border-radius);
cursor: pointer;
padding-left: rem(10);
padding-right: rem(10);
padding-top: rem(5);
padding-bottom: rem(5);
font-size: var(--mantine-font-size-sm);
flex: 1;
flex-wrap: wrap;
@mixin light {
background-color: var(--mantine-color-gray-0);
}
@mixin dark {
background-color: var(--mantine-color-dark-5);
}
}
.flex-row {
display: flex;
flex-direction: column;
justify-content: space-between;
}
.flex-row-right {
align-items: flex-end;
}

View File

@@ -0,0 +1,46 @@
import {FC} from "react";
import {DealSummary} from "../../../client";
import styles from './DealSummaryCard.module.css';
import {Text} from '@mantine/core';
import classNames from "classnames";
type Props = {
dealSummary: DealSummary
}
const DealSummaryCard: FC<Props> = ({dealSummary}) => {
return (
<div className={styles['container']}>
<div className={styles['flex-row']}>
<div className={styles['flex-item']}>
<Text size={"sm"} c={"gray.6"}>
{dealSummary.client_name}
</Text>
</div>
<div className={styles['flex-item']}>
<Text size={"md"} c={"blue.5"}>{dealSummary.name}</Text>
</div>
<div className={styles['flex-item']}>
<Text size={"sm"} c={"gray.6"}>
228 руб
</Text>
</div>
</div>
<div className={classNames(styles['flex-row'], styles['flex-row-right'])}>
<div className={styles['flex-item']}>
<Text size={"sm"} c={"gray.6"}>
{new Date(dealSummary.changed_at).toLocaleString('ru-RU')}
</Text>
</div>
<div className={styles['flex-item']}>
<Text size={"sm"} c={"yellow.8"}>
Нет задач
</Text>
</div>
</div>
</div>
)
}
export default DealSummaryCard;

View File

@@ -8,7 +8,7 @@
}
.header-button {
height: 100%;
height: 100% !important;
width: 10%;
min-width: 5rem;
min-width: 10rem;
}

View File

@@ -6,6 +6,7 @@ const Header: FC = ()=>{
return (
<div className={styles['header']}>
<TextInput
radius={0}
placeholder={"Поиск и фильтры"}

View File

@@ -1,5 +1,5 @@
import {Center, Image, rem, Stack, Tooltip, UnstyledButton, useMantineColorScheme} from '@mantine/core';
import {IconCash, IconHome2, IconLogout, IconMan, IconMoon, IconSun,} from '@tabler/icons-react';
import {IconBox, IconCash, IconHome2, IconLogout, IconMan, IconMoon, IconSun,} from '@tabler/icons-react';
import classes from './Navbar.module.css';
import {useAppDispatch} from "../../redux/store.ts";
import {logout} from "../../features/authSlice.ts";
@@ -44,7 +44,12 @@ const mockdata = [
icon: IconMan,
label: 'Клиенты',
href: '/clients'
}
},
{
icon: IconBox,
label: 'Услуги',
href: '/services'
},
];
export function Navbar() {

View File

@@ -0,0 +1,6 @@
.container {
border-radius: rem(20);
background-color: var(--mantine-color-body);
padding: rem(10);
flex: 1;
}

View File

@@ -0,0 +1,14 @@
import {FC, ReactNode} from "react";
import styles from './PageBlock.module.css';
type Props = {
children: ReactNode
}
export const PageBlock: FC<Props> = ({children}) => {
return (
<div className={styles['container']}>
{children}
</div>
)
}
export default PageBlock;

View File

@@ -42,7 +42,7 @@ const ClientSelect: FC<Props> = ({onSelect, addressRestProps, nameRestProps, wit
{
name: value,
id: -1,
address: ''
address: ""
});
}, [value]);
useEffect(() => {
@@ -74,6 +74,12 @@ const ClientSelect: FC<Props> = ({onSelect, addressRestProps, nameRestProps, wit
{withAddress &&
<TextInput
placeholder={'Клиент: адрес'}
styles={{
input: {
borderTopLeftRadius: 0,
borderTopRightRadius: 0,
}
}}
value={selectedClient?.address || ''}
onChange={event => {
selectClient(prevState => prevState && {...prevState, address: event.target.value})