This commit is contained in:
2024-03-05 04:58:05 +03:00
parent 659d76b694
commit e2962f3be2
11 changed files with 141 additions and 56 deletions

View File

@@ -12,6 +12,8 @@ export type { AuthLoginResponse } from './models/AuthLoginResponse';
export type { DealChangeStatusRequest } from './models/DealChangeStatusRequest'; export type { DealChangeStatusRequest } from './models/DealChangeStatusRequest';
export type { DealChangeStatusResponse } from './models/DealChangeStatusResponse'; export type { DealChangeStatusResponse } from './models/DealChangeStatusResponse';
export type { DealCreateRequest } from './models/DealCreateRequest'; export type { DealCreateRequest } from './models/DealCreateRequest';
export type { DealCreateResponse } from './models/DealCreateResponse';
export type { DealQuickCreateRequest } from './models/DealQuickCreateRequest';
export type { HTTPValidationError } from './models/HTTPValidationError'; export type { HTTPValidationError } from './models/HTTPValidationError';
export type { ValidationError } from './models/ValidationError'; export type { ValidationError } from './models/ValidationError';

View File

@@ -5,6 +5,8 @@
import type { DealChangeStatusRequest } from '../models/DealChangeStatusRequest'; import type { DealChangeStatusRequest } from '../models/DealChangeStatusRequest';
import type { DealChangeStatusResponse } from '../models/DealChangeStatusResponse'; import type { DealChangeStatusResponse } from '../models/DealChangeStatusResponse';
import type { DealCreateRequest } from '../models/DealCreateRequest'; import type { DealCreateRequest } from '../models/DealCreateRequest';
import type { DealCreateResponse } from '../models/DealCreateResponse';
import type { DealQuickCreateRequest } from '../models/DealQuickCreateRequest';
import type { CancelablePromise } from '../core/CancelablePromise'; import type { CancelablePromise } from '../core/CancelablePromise';
import { OpenAPI } from '../core/OpenAPI'; import { OpenAPI } from '../core/OpenAPI';
import { request as __request } from '../core/request'; import { request as __request } from '../core/request';
@@ -29,6 +31,26 @@ export class DealService {
}, },
}); });
} }
/**
* Quick Create
* @returns DealCreateResponse Successful Response
* @throws ApiError
*/
public static quickCreateDealQuickCreatePost({
requestBody,
}: {
requestBody: DealQuickCreateRequest,
}): CancelablePromise<DealCreateResponse> {
return __request(OpenAPI, {
method: 'POST',
url: '/deal/quickCreate',
body: requestBody,
mediaType: 'application/json',
errors: {
422: `Validation Error`,
},
});
}
/** /**
* Change Status * Change Status
* @returns DealChangeStatusResponse Successful Response * @returns DealChangeStatusResponse Successful Response

View File

@@ -1,30 +1,53 @@
import {FC, useState} from "react"; import {FC, useState} from "react";
import styles from './CreateDealButton.module.css'; import styles from './CreateDealButton.module.css';
import {Button, rem, Text, TextInput, Transition} from '@mantine/core'; import {Text, Transition} from '@mantine/core';
import CreateDealFrom from "../CreateDealForm/CreateDealFrom.tsx"; import CreateDealFrom from "../CreateDealForm/CreateDealFrom.tsx";
import {DealService} from "../../../client";
import {dateWithoutTimezone} from "../../../shared/lib/utils.ts";
type Props = { type Props = {
onClick: () => void; onClick: () => void;
} }
const CreateDealButton: FC<Props> = ({onClick}) => { const CreateDealButton: FC<Props> = ({onClick}) => {
const [isCreating, setIsCreating] = useState(false); const [isCreating, setIsCreating] = useState(false);
const [isTransitionEnded, setIsTransitionEnded] = useState(true);
return ( return (
<div className={styles['container']} <div className={styles['container']}
onClick={() => { onClick={() => {
if (isCreating) return; if (isCreating) return;
setIsCreating(prevState => !prevState) setIsCreating(prevState => !prevState)
setIsTransitionEnded(false);
}} }}
> >
{(!isCreating && isTransitionEnded) &&
<Text>Быстрое добавление</Text>
}
<Transition
mounted={isCreating}
transition={"scale-y"}
onExited={() => setIsTransitionEnded(true)}
>
{(styles) => (
<div style={styles}>
<CreateDealFrom
onCancel={() => {
setIsCreating(false)
}}
onSubmit={(quickDeal) => {
console.log(quickDeal);
DealService.quickCreateDealQuickCreatePost({
requestBody: {
...quickDeal,
acceptance_date: dateWithoutTimezone(quickDeal.acceptance_date)
}
})
}}
/>
</div>
)}
</Transition>
<Text>Быстрое добавление</Text>
<CreateDealFrom
onCancel={() => {
}}
onSubmit={() => {
}}
/>
</div> </div>
) )
} }

View File

@@ -14,8 +14,8 @@ const CreateDealFrom: FC<Props> = ({onSubmit, onCancel}) => {
const form = useForm({ const form = useForm({
initialValues: { initialValues: {
name: '', name: '',
clientName: '', client_name: '',
clientAddress: '', client_address: '',
comment: '', comment: '',
acceptance_date: new Date() acceptance_date: new Date()
} }
@@ -23,7 +23,7 @@ const CreateDealFrom: FC<Props> = ({onSubmit, onCancel}) => {
return ( return (
<form <form
style={{width: '100%'}} style={{width: '100%'}}
onSubmit={form.onSubmit((values) => console.log(values))} onSubmit={form.onSubmit((values) => onSubmit(values))}
> >
<div style={{ <div style={{
@@ -43,10 +43,9 @@ const CreateDealFrom: FC<Props> = ({onSubmit, onCancel}) => {
<div className={styles['inputs']}> <div className={styles['inputs']}>
<ClientSelect <ClientSelect
withAddress withAddress
nameRestProps={form.getInputProps('clientName')} nameRestProps={form.getInputProps('client_name')}
addressRestProps={form.getInputProps('clientAddress')} addressRestProps={form.getInputProps('client_address')}
onSelect={() => { />
}}/>
</div> </div>
<div className={styles['inputs']}> <div className={styles['inputs']}>
@@ -61,6 +60,7 @@ const CreateDealFrom: FC<Props> = ({onSubmit, onCancel}) => {
<div className={styles['inputs']}> <div className={styles['inputs']}>
<DateTimePicker <DateTimePicker
placeholder={'Дата приемки'} placeholder={'Дата приемки'}
{...form.getInputProps('acceptance_date')}
/> />
</div> </div>

View File

@@ -74,7 +74,7 @@ const ClientSelect: FC<Props> = ({onSelect, addressRestProps, nameRestProps, wit
{withAddress && {withAddress &&
<TextInput <TextInput
placeholder={'Клиент: адрес'} placeholder={'Клиент: адрес'}
value={selectedClient?.address} value={selectedClient?.address || ''}
onChange={event => { onChange={event => {
selectClient(prevState => prevState && {...prevState, address: event.target.value}) selectClient(prevState => prevState && {...prevState, address: event.target.value})
}} }}

23
src/features/uiSlice.ts Normal file
View File

@@ -0,0 +1,23 @@
import {createSlice, PayloadAction} from "@reduxjs/toolkit";
interface UIState {
isLoading: boolean;
}
const initialState: UIState = {
isLoading: false
}
const uiSlice = createSlice({
name: 'ui',
initialState,
reducers: {
setIsLoading: (state, action: PayloadAction<boolean>) => {
state.isLoading = action.payload;
}
}
}
)
export default uiSlice.reducer;
export const {setIsLoading} = uiSlice.actions;

View File

@@ -1,42 +1,49 @@
import {FC} from "react"; import {FC, useEffect} from "react";
import styles from './LeadsPage.module.css'; import styles from './LeadsPage.module.css';
import Board from "../../../components/Dnd/Board/Board.tsx"; import Board from "../../../components/Dnd/Board/Board.tsx";
import {Button, TextInput} from "@mantine/core"; import {Button, TextInput} from "@mantine/core";
import {DragDropContext} from "@hello-pangea/dnd"; import {DragDropContext} from "@hello-pangea/dnd";
import ClientSelect from "../../../components/Selects/ClientSelect/ClientSelect.tsx"; import {useAppDispatch} from "../../../redux/store.ts";
import {DateTimePicker} from "@mantine/dates"; import {setIsLoading} from "../../../features/uiSlice.ts";
export const LeadsPage: FC = () => { export const LeadsPage: FC = () => {
const dispatch = useAppDispatch();
useEffect(() => {
dispatch(setIsLoading(true));
}, []);
return ( return (
<div className={styles['container']}> <>
<div className={styles['header']}> <div className={styles['container']}>
<div className={styles['header']}>
<TextInput
radius={0}
placeholder={"Поиск и фильтры"}
size={"xl"}
className={styles['header-input']}
/>
<Button
radius={0}
color={"gray"}
variant={'default'}
className={styles['header-button']}
>Поиск</Button>
</div>
<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"}/>
<TextInput </DragDropContext>
radius={0}
placeholder={"Поиск и фильтры"} </div>
size={"xl"}
className={styles['header-input']}
/>
<Button
radius={0}
color={"gray"}
variant={'default'}
className={styles['header-button']}
>Поиск</Button>
</div> </div>
<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>
</div>
</div>
) )
} }

View File

@@ -4,9 +4,11 @@ import {useSelector} from "react-redux";
import {RootState} from "../../redux/store.ts"; import {RootState} from "../../redux/store.ts";
import {OpenAPI} from "../../client"; import {OpenAPI} from "../../client";
import PageWrapper from "../PageWrapper/PageWrapper.tsx"; import PageWrapper from "../PageWrapper/PageWrapper.tsx";
import {LoadingOverlay} from "@mantine/core";
const RootPage = () => { const RootPage = () => {
const authState = useSelector((state: RootState) => state.auth); const authState = useSelector((state: RootState) => state.auth);
const uiState = useSelector((state: RootState) => state.ui);
const rewriteLocalStorage = () => { const rewriteLocalStorage = () => {
const jsonData = JSON.stringify(authState); const jsonData = JSON.stringify(authState);
localStorage.setItem('authState', jsonData); localStorage.setItem('authState', jsonData);
@@ -21,13 +23,11 @@ const RootPage = () => {
return ( return (
<> <>
<LoadingOverlay visible={uiState.isLoading}/>
<PageWrapper> <PageWrapper>
<Outlet/> <Outlet/>
</PageWrapper> </PageWrapper>
</> </>
) )
} }

View File

@@ -1,10 +1,12 @@
import {configureStore} from "@reduxjs/toolkit"; import {configureStore} from "@reduxjs/toolkit";
import {useDispatch} from "react-redux"; import {useDispatch} from "react-redux";
import authReducer from '../features/authSlice'; import authReducer from '../features/authSlice';
import uiReducer from '../features/uiSlice';
export const store = configureStore({ export const store = configureStore({
reducer: { reducer: {
auth: authReducer auth: authReducer,
ui: uiReducer
} }
}); });

7
src/shared/lib/utils.ts Normal file
View File

@@ -0,0 +1,7 @@
export const dateWithoutTimezone = (date: Date) => {
const tzoffset = date.getTimezoneOffset() * 60000; //offset in milliseconds
const withoutTimezone = new Date(date.valueOf() - tzoffset)
.toISOString()
.slice(0, -1);
return withoutTimezone;
};

View File

@@ -1,8 +1,7 @@
import {Client} from "./Client.ts";
export type QuickDeal = { export type QuickDeal = {
name: string; name: string
client: Client client_name: string
comment: string; client_address: string
acceptance_date: string; comment:string
acceptance_date: Date
} }