Commit 651d4bd9 authored by Merekeyev Dias's avatar Merekeyev Dias

fixed edit org function, added delete org function

parent 7615238c
...@@ -7,7 +7,7 @@ import AuthPage from './pages/AuthPage/AuthPage'; ...@@ -7,7 +7,7 @@ import AuthPage from './pages/AuthPage/AuthPage';
import HomePage from './pages/HomePage/HomePage'; import HomePage from './pages/HomePage/HomePage';
import RequestPage from './pages/RequestPage/RequestPage'; import RequestPage from './pages/RequestPage/RequestPage';
import ManualPage from './pages/ManualPage/ManualPage'; import ManualPage from './pages/ManualPage/ManualPage';
import AddEditPage from './pages/(crudPages)/AddEditPage'; import AddEditPage from './pages/ManageOrganization/ManageOrganization';
import './App.css'; import './App.css';
const AuthLayout: React.FC = () => { const AuthLayout: React.FC = () => {
......
...@@ -32,16 +32,16 @@ export const organizationApiSlice = apiSlice.injectEndpoints({ ...@@ -32,16 +32,16 @@ export const organizationApiSlice = apiSlice.injectEndpoints({
}), }),
editOrganization: builder.mutation<Organization, Partial<Organization>>({ editOrganization: builder.mutation<Organization, Partial<Organization>>({
query: ({ ...rest }) => ({ query: ({ ...rest }) => ({
url: `organizations/save`, url: `organizations/save?id=${rest.id}`,
method: 'POST', method: 'POST',
body: rest, body: rest,
}), }),
invalidatesTags: ["organizations"], invalidatesTags: ["organizations"],
}), }),
deleteOrganization: builder.mutation<{ success: boolean; id: number }, number>({ deleteOrganization: builder.mutation<{ success: boolean; code: string }, string>({
query: (orgId) => ({ query: (orgCode) => ({
url: `organizations/delete?id=${orgId}`, url: `organizations/delete?code=${orgCode}`,
method: 'DELETE', method: 'POST'
}), }),
invalidatesTags: ["organizations"], invalidatesTags: ["organizations"],
}), }),
......
import React from 'react';
import { useNavigate } from 'react-router';
import { Form, Input, Button, Select, message } from 'antd';
import { useAddNewOrganizationMutation } from '../../features/api/organizationApiSlice';
import { setTotalOrgNumber, setCurrentPage } from '../../features/pagination/mainPagination';
import { useSelector, useDispatch } from 'react-redux';
import './style.css';
interface AddValues {
bin: string;
host: string;
login: string;
organization_code: string;
organization_name: string;
password: string;
status: string;
}
const { Item } = Form;
const { Option } = Select;
const AddPage: React.FC = () => {
const navigate = useNavigate();
const dispatch = useDispatch();
const totalOrgNumber = useSelector((state: any) => state.mainPagination.totalOrgNumber);
const ORG_NUMBER_PER_PAGE = useSelector((state: any) => state.mainPagination.ORG_NUMBER_PER_PAGE);
const [addNewOrganization] = useAddNewOrganizationMutation();
const onFinish = async (values: AddValues) => {
const newValues = {
...values,
status: values.status === 'active' ? 2 : values.status === 'blocked' ? 1 : 0,
deleted: null,
created: new Date().toISOString(),
};
console.log("Sending data:", newValues);
try {
await addNewOrganization(newValues).unwrap();
message.success('Организация успешно добавлена!');
dispatch(setTotalOrgNumber(totalOrgNumber + 1));
const newTotalPages = Math.ceil((totalOrgNumber + 1) / ORG_NUMBER_PER_PAGE);
dispatch(setCurrentPage(newTotalPages));
navigate('/');
} catch (err) {
message.error('Произошла ошибка при добавлении организации!');
console.error(err);
}
};
return (
<div className='container'>
<Form
layout="vertical"
name="organization_form"
initialValues={{ status: 'active' }}
onFinish={onFinish}
className='form'
>
<Item
label="БИН организации"
name="bin"
rules={[
{ required: true, message: 'Пожалуйста, введите БИН организации!' },
{ pattern: /^\d{12}$/, message: 'БИН должен состоять из 12 цифр!' }
]}
>
<Input maxLength={12} placeholder="Максимальная длина: 12 цифр" />
</Item>
<Item
label="Код организации"
name="code"
rules={[
{ required: true, message: 'Пожалуйста, введите код организации!' },
{ pattern: /^[a-zA-Z0-9-_]+$/, message: 'Код организации должен содержать только английские буквы, цифры, символы "-" и "_"' }
]}
>
<Input maxLength={128} placeholder='Максимальная длина: 128 символов'/>
</Item>
<Item
label="Наименование организации"
name="name"
rules={[{ required: true, message: 'Пожалуйста, введите наименование организации!' }]}
>
<Input maxLength={128} placeholder='Максимальная длина: 128 символов' />
</Item>
<Item
label="Адрес системы/хост"
name="host"
rules={[{ required: true, message: 'Пожалуйста, введите адрес системы/хост!' }]}
>
<Input maxLength={128} placeholder='Максимальная длина: 128 символов' />
</Item>
<Item
label="Логин"
name="login"
rules={[
{ required: true, message: 'Пожалуйста, введите логин!' },
{ pattern: /^[a-zA-Z0-9-_]+$/, message: 'Логин должен содержать только английские буквы, цифры, символы "-" и "_"' }
]}
>
<Input maxLength={128} placeholder='Максимальная длина: 128 символов' />
</Item>
<Item
label="Пароль"
name="password"
rules={[
{ required: true, message: 'Пожалуйста, введите пароль!' },
{ pattern: /^[a-zA-Z0-9-_]+$/, message: 'Пароль должен содержать только английские буквы, цифры, символы "-" и "_"' }
]}
>
<Input.Password maxLength={128} placeholder='Максимальная длина: 128 символов' />
</Item>
<Item
label="Статус"
name="status"
rules={[{ required: true, message: 'Пожалуйста, выберите статус!' }]}
>
<Select placeholder="Выберите статус">
<Option value="active">Активен</Option>
<Option value="blocked">Заблокирован</Option>
<Option value="deleted">Удален</Option>
</Select>
</Item>
<div className='form-footer'>
<Item className='form-footer-item'>
<Button type="default" style={{ marginRight: '8px' }} onClick={() => navigate("/")}>
Отмена
</Button>
<Button type="primary" htmlType="submit">
Сохранить
</Button>
</Item>
</div>
</Form>
</div>
);
};
export default AddPage;
import React, { useEffect } from 'react';
import { useNavigate, useParams } from 'react-router';
import { Form, Input, Button, Select, message } from 'antd';
import { useGetOrganizationQuery, useEditOrganizationMutation } from '../../features/api/organizationApiSlice';
import './style.css';
interface EditValues {
id: number;
bin: string;
host: string;
login: string;
organization_code: string;
organization_name: string;
password: string;
status: string;
}
const { Item } = Form;
const { Option } = Select;
const EditPage: React.FC = () => {
const navigate = useNavigate();
const { id } = useParams<{ id: string }>();
const { data, isLoading, isError } = useGetOrganizationQuery(id!);
const [editOrganization] = useEditOrganizationMutation();
const [form] = Form.useForm();
useEffect(() => {
if (data) {
form.setFieldsValue({
...data,
status: data.status === 2 ? 'active' : data.status === 1 ? 'blocked' : 'deleted'
});
}
}, [data, form]);
const onFinish = async (values: EditValues) => {
const updatedValues = {
...values,
status: values.status === 'active' ? 2 : values.status === 'blocked' ? 1 : 0,
deleted: null,
};
console.log(updatedValues);
try {
await editOrganization({ ...updatedValues }).unwrap();
message.success('Организация успешно обновлена!');
navigate('/');
} catch (err) {
message.error('Произошла ошибка при обновлении организации!');
}
};
if (isLoading) return <div>Loading...</div>;
if (isError) return <div>Error loading organization data</div>;
return (
<div className="container">
<Form
form={form}
layout="vertical"
name="organization_form"
onFinish={onFinish}
className='form'
>
<Item
label="ID"
name="id"
>
<Input disabled />
</Item>
<Item
label="БИН организации"
name="bin"
rules={[
{ required: true, message: 'Пожалуйста, введите БИН организации!' },
{ pattern: /^\d{12}$/, message: 'БИН должен состоять из 12 цифр!' }
]}
>
<Input maxLength={12} placeholder="12 цифр" />
</Item>
<Item
label="Код организации"
name="code"
rules={[
{ required: true, message: 'Пожалуйста, введите код организации!' },
{ pattern: /^[a-zA-Z0-9-_]+$/, message: 'Код организации должен содержать только английские буквы, цифры, символы "-" и "_"' }
]}
>
<Input maxLength={128} />
</Item>
<Item
label="Наименование организации"
name="name"
rules={[{ required: true, message: 'Пожалуйста, введите наименование организации!' }]}
>
<Input maxLength={128} />
</Item>
<Item
label="Адрес системы/хост"
name="host"
rules={[{ required: true, message: 'Пожалуйста, введите адрес системы/хост!' }]}
>
<Input maxLength={128} />
</Item>
<Item
label="Логин"
name="login"
rules={[
{ required: true, message: 'Пожалуйста, введите логин!' },
{ pattern: /^[a-zA-Z0-9-_]+$/, message: 'Логин должен содержать только английские буквы, цифры, символы "-" и "_"' }
]}
>
<Input maxLength={128} />
</Item>
<Item
label="Пароль"
name="password"
rules={[
{ required: true, message: 'Пожалуйста, введите пароль!' },
{ pattern: /^[a-zA-Z0-9-_]+$/, message: 'Пароль должен содержать только английские буквы, цифры, символы "-" и "_"' }
]}
>
<Input.Password maxLength={128} />
</Item>
<Item
label="Статус"
name="status"
rules={[{ required: true, message: 'Пожалуйста, выберите статус!' }]}
>
<Select placeholder="Выберите статус">
<Option value="active">Активен</Option>
<Option value="blocked">Заблокирован</Option>
<Option value="deleted">Удален</Option>
</Select>
</Item>
<div className='form-footer'>
<Item className='form-footer-item'>
<Button type="default" style={{ marginRight: '8px' }} onClick={() => navigate("/")}>
Отмена
</Button>
<Button type="primary" htmlType="submit">
Сохранить
</Button>
</Item>
</div>
</Form>
</div>
);
};
export default EditPage;
...@@ -72,7 +72,7 @@ export const ActionColumn: React.FC<{ data: DataType }> = ({ data }) => { ...@@ -72,7 +72,7 @@ export const ActionColumn: React.FC<{ data: DataType }> = ({ data }) => {
const handleDeleteModalOk = async () => { const handleDeleteModalOk = async () => {
try { try {
await deleteOrganization(data.id).unwrap(); await deleteOrganization(data.code);
message.success('Организация успешно удалена!'); message.success('Организация успешно удалена!');
setOpen(false); setOpen(false);
} catch (err) { } catch (err) {
......
...@@ -21,6 +21,9 @@ const HomePage: React.FC = () => { ...@@ -21,6 +21,9 @@ const HomePage: React.FC = () => {
}; };
const handlePaginationChange = (page: number) => { const handlePaginationChange = (page: number) => {
/*
scrollIntoView resets to the top of the table after changing the page with Pagination. But the bug was found - the div above the table scrolls to top of the page too, under the Header component. It happens because of overflow
*/
// tableRef.current?.nativeElement.scrollIntoView({ behavior: 'smooth' }); // tableRef.current?.nativeElement.scrollIntoView({ behavior: 'smooth' });
dispatch(setCurrentPage(page)); dispatch(setCurrentPage(page));
}; };
...@@ -52,7 +55,6 @@ const HomePage: React.FC = () => { ...@@ -52,7 +55,6 @@ const HomePage: React.FC = () => {
ref={tableRef} ref={tableRef}
/> />
} else if (isError) { } else if (isError) {
console.log(error)
table = <div>{error.toString()}</div> table = <div>{error.toString()}</div>
} }
...@@ -78,7 +80,15 @@ const HomePage: React.FC = () => { ...@@ -78,7 +80,15 @@ const HomePage: React.FC = () => {
{table} {table}
</div> </div>
<div className='pagination-container'> <div className='pagination-container'>
<Pagination current={currentPage} defaultCurrent={1} pageSize={ORG_NUMBER_PER_PAGE} total={totalOrgNumber} onChange={handlePaginationChange} /> <Pagination
current={currentPage}
defaultCurrent={1}
pageSize={ORG_NUMBER_PER_PAGE}
total={totalOrgNumber}
onChange={handlePaginationChange}
hideOnSinglePage={true}
showSizeChanger={false}
/>
</div> </div>
</section> </section>
</div> </div>
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
.data { .data {
flex: 1; flex: 1;
overflow-y: auto; overflow-y: auto;
padding-bottom: 20px; padding-bottom: 60px;
margin-top: 20px; margin-top: 20px;
margin-left: -10px; margin-left: -10px;
} }
......
...@@ -4,7 +4,7 @@ import { Form, Input, Button, Select, message } from 'antd'; ...@@ -4,7 +4,7 @@ import { Form, Input, Button, Select, message } from 'antd';
import { useAddNewOrganizationMutation, useEditOrganizationMutation, useGetOrganizationQuery, useGetOrganizationsQuery } from '../../features/api/organizationApiSlice'; import { useAddNewOrganizationMutation, useEditOrganizationMutation, useGetOrganizationQuery, useGetOrganizationsQuery } from '../../features/api/organizationApiSlice';
import { setTotalOrgNumber, setCurrentPage } from '../../features/pagination/mainPagination'; import { setTotalOrgNumber, setCurrentPage } from '../../features/pagination/mainPagination';
import { useSelector, useDispatch } from 'react-redux'; import { useSelector, useDispatch } from 'react-redux';
import './style.css'; import './ManageOrganization.css';
interface OrganizationValues { interface OrganizationValues {
id?: number; id?: number;
...@@ -20,7 +20,7 @@ interface OrganizationValues { ...@@ -20,7 +20,7 @@ interface OrganizationValues {
const { Item } = Form; const { Item } = Form;
const { Option } = Select; const { Option } = Select;
const AddEditPage: React.FC = () => { const ManageOrganization: React.FC = () => {
const navigate = useNavigate(); const navigate = useNavigate();
const dispatch = useDispatch(); const dispatch = useDispatch();
const { id } = useParams<{ id: string }>(); const { id } = useParams<{ id: string }>();
...@@ -174,4 +174,4 @@ const AddEditPage: React.FC = () => { ...@@ -174,4 +174,4 @@ const AddEditPage: React.FC = () => {
); );
}; };
export default AddEditPage; export default ManageOrganization;
\ No newline at end of file
...@@ -11,6 +11,10 @@ import './RequestPage.css'; ...@@ -11,6 +11,10 @@ import './RequestPage.css';
dayjs.extend(isBetween); dayjs.extend(isBetween);
const dateFormat = 'YYYY-MM-DD'; const dateFormat = 'YYYY-MM-DD';
const defaultDates = {
startDate: '2024/01/01',
endDate: '2024/12/31'
}
const RequestPage: React.FC = () => { const RequestPage: React.FC = () => {
const dispatch = useDispatch(); const dispatch = useDispatch();
...@@ -19,14 +23,14 @@ const RequestPage: React.FC = () => { ...@@ -19,14 +23,14 @@ const RequestPage: React.FC = () => {
const currentPage = useSelector((state: any) => state.reqPagination.currentPage); const currentPage = useSelector((state: any) => state.reqPagination.currentPage);
const REQ_NUMBER_PER_PAGE = useSelector((state: any) => state.reqPagination.REQ_NUMBER_PER_PAGE); const REQ_NUMBER_PER_PAGE = useSelector((state: any) => state.reqPagination.REQ_NUMBER_PER_PAGE);
const [startDate, setStartDate] = useState<Dayjs>(dayjs('2024/01/01', dateFormat)); const [startDate, setStartDate] = useState<Dayjs>(dayjs(defaultDates.startDate, dateFormat));
const [endDate, setEndDate] = useState<Dayjs>(dayjs('2024/12/31', dateFormat)); const [endDate, setEndDate] = useState<Dayjs>(dayjs(defaultDates.endDate, dateFormat));
const [data, setData] = useState<DataType[]>([]); const [data, setData] = useState<DataType[]>([]);
const [method, setMethod] = useState(''); const [method, setMethod] = useState('');
const handlePaginationChange = (page: number) => { const handlePaginationChange = (page: number) => {
/* /*
scrollIntoView resets to the top of the table after changing the page with Pagination. But the bug was found - the add button scrolls to top of the page too, under the Header component. It happens because of overflow scrollIntoView resets to the top of the table after changing the page with Pagination. But the bug was found - the div above the table scrolls to top of the page too, under the Header component. It happens because of overflow
*/ */
// tableRef.current?.nativeElement.scrollIntoView({ behavior: 'smooth' }); // tableRef.current?.nativeElement.scrollIntoView({ behavior: 'smooth' });
dispatch(setCurrentPage(page)); dispatch(setCurrentPage(page));
...@@ -40,11 +44,14 @@ const RequestPage: React.FC = () => { ...@@ -40,11 +44,14 @@ const RequestPage: React.FC = () => {
const applyFilters = () => { const applyFilters = () => {
let filtered = reqs.list; let filtered = reqs.list;
/*
subtract method is added because of the unique dates (hh:mm:ss = 00:00:00). The code below is the easiest way to deal with it, but it is not the ideal form
*/
const adjustedStartDate = dayjs(startDate).subtract(1, 'day'); const adjustedStartDate = dayjs(startDate).subtract(1, 'day');
if (startDate && endDate) { if (startDate && endDate) {
filtered = filtered.filter((req) => { filtered = filtered.filter((req) => {
const sendDate = dayjs(req.sendDate, dateFormat); const sendDate = dayjs(req.sendDate, dateFormat);
return sendDate.isBetween(adjustedStartDate, endDate, 'second', '[]'); return sendDate.isBetween(adjustedStartDate, endDate, 'day', '[]');
}); });
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment