feat(frontend): update eslint rules
This commit is contained in:
parent
dd9ae0b7c0
commit
457f4bbed2
@ -1,26 +1,26 @@
|
||||
export const items1 = [
|
||||
{
|
||||
id: '1',
|
||||
expenseListId: '1',
|
||||
title: 'Счет за интернет',
|
||||
description: 'Ежемесячная плата за интернет',
|
||||
date: '2024-04-01',
|
||||
amount: 500,
|
||||
currency: 'RUB',
|
||||
count: 1,
|
||||
createdAt: '2024-04-01T12:00:00Z',
|
||||
currency: 'RUB',
|
||||
date: '2024-04-01',
|
||||
description: 'Ежемесячная плата за интернет',
|
||||
expenseListId: '1',
|
||||
id: '1',
|
||||
title: 'Счет за интернет',
|
||||
updatedAt: '2024-04-01T12:00:00Z',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
expenseListId: '1',
|
||||
title: 'Покупка продуктов',
|
||||
description: 'Продукты на неделю',
|
||||
date: '2024-04-02',
|
||||
amount: 3000,
|
||||
currency: 'RUB',
|
||||
count: 1,
|
||||
createdAt: '2024-04-02T12:00:00Z',
|
||||
currency: 'RUB',
|
||||
date: '2024-04-02',
|
||||
description: 'Продукты на неделю',
|
||||
expenseListId: '1',
|
||||
id: '2',
|
||||
title: 'Покупка продуктов',
|
||||
updatedAt: '2024-04-02T12:00:00Z',
|
||||
},
|
||||
];
|
||||
@ -31,42 +31,42 @@ export const items3 = null;
|
||||
|
||||
export const items4 = [
|
||||
{
|
||||
id: '3',
|
||||
expenseListId: '4',
|
||||
title: 'Бензин',
|
||||
description: null,
|
||||
date: '2024-04-03',
|
||||
amount: 1500,
|
||||
currency: 'RUB',
|
||||
count: null,
|
||||
createdAt: '2024-04-03T12:00:00Z',
|
||||
currency: 'RUB',
|
||||
date: '2024-04-03',
|
||||
description: null,
|
||||
expenseListId: '4',
|
||||
id: '3',
|
||||
title: 'Бензин',
|
||||
updatedAt: '2024-04-03T12:00:00Z',
|
||||
},
|
||||
];
|
||||
|
||||
export const items5 = [
|
||||
{
|
||||
id: '4',
|
||||
expenseListId: '5',
|
||||
title: 'Ноутбук',
|
||||
description: 'Покупка нового ноутбука',
|
||||
date: '2024-04-04',
|
||||
amount: 50000,
|
||||
currency: 'RUB',
|
||||
count: 1,
|
||||
createdAt: '2024-04-04T12:00:00Z',
|
||||
currency: 'RUB',
|
||||
date: '2024-04-04',
|
||||
description: 'Покупка нового ноутбука',
|
||||
expenseListId: '5',
|
||||
id: '4',
|
||||
title: 'Ноутбук',
|
||||
updatedAt: '2024-04-04T12:00:00Z',
|
||||
},
|
||||
{
|
||||
id: '5',
|
||||
expenseListId: '5',
|
||||
title: 'Мышка',
|
||||
description: 'Механическая мышка',
|
||||
date: '2024-04-05',
|
||||
amount: 3000,
|
||||
currency: 'RUB',
|
||||
count: 1,
|
||||
createdAt: '2024-04-05T12:00:00Z',
|
||||
currency: 'RUB',
|
||||
date: '2024-04-05',
|
||||
description: 'Механическая мышка',
|
||||
expenseListId: '5',
|
||||
id: '5',
|
||||
title: 'Мышка',
|
||||
updatedAt: '2024-04-05T12:00:00Z',
|
||||
},
|
||||
];
|
||||
|
||||
@ -7,41 +7,41 @@ import {
|
||||
} from './items';
|
||||
|
||||
export const list1 = {
|
||||
id: '1',
|
||||
title: 'Расходы на быт',
|
||||
items: items1,
|
||||
createdAt: '2024-03-28T10:00:00Z',
|
||||
id: '1',
|
||||
items: items1,
|
||||
title: 'Расходы на быт',
|
||||
updatedAt: '2024-04-02T12:00:00Z',
|
||||
};
|
||||
|
||||
export const list2 = {
|
||||
id: '2',
|
||||
title: 'Дополнительные расходы',
|
||||
items: items2,
|
||||
createdAt: '2024-04-01T10:00:00Z',
|
||||
id: '2',
|
||||
items: items2,
|
||||
title: 'Дополнительные расходы',
|
||||
updatedAt: '2024-04-01T10:00:00Z',
|
||||
};
|
||||
|
||||
export const list3 = {
|
||||
id: '3',
|
||||
title: 'Кредиты',
|
||||
items: items3,
|
||||
createdAt: '2024-04-01T11:00:00Z',
|
||||
id: '3',
|
||||
items: items3,
|
||||
title: 'Кредиты',
|
||||
updatedAt: '2024-04-01T11:00:00Z',
|
||||
};
|
||||
|
||||
export const list4 = {
|
||||
id: '4',
|
||||
title: 'Автомобиль',
|
||||
items: items4,
|
||||
createdAt: '2024-04-03T10:00:00Z',
|
||||
id: '4',
|
||||
items: items4,
|
||||
title: 'Автомобиль',
|
||||
updatedAt: '2024-04-03T10:00:00Z',
|
||||
};
|
||||
|
||||
export const list5 = {
|
||||
id: '5',
|
||||
title: 'Техника',
|
||||
items: items5,
|
||||
createdAt: '2024-04-04T10:00:00Z',
|
||||
id: '5',
|
||||
items: items5,
|
||||
title: 'Техника',
|
||||
updatedAt: '2024-04-05T10:00:00Z',
|
||||
};
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
import { http, HttpResponse } from 'msw';
|
||||
|
||||
import {
|
||||
list1,
|
||||
list2,
|
||||
@ -7,6 +5,7 @@ import {
|
||||
list4,
|
||||
list5,
|
||||
} from '@mocks/browser/data/expenses/lists';
|
||||
import { http, HttpResponse } from 'msw';
|
||||
|
||||
import type { paths } from '@/shared/api/schema';
|
||||
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
export { getExpenseList } from './expense/list/get';
|
||||
export { getExpenseItemListById } from './expense/list/:id/get';
|
||||
export { loginHandler } from './auth/login/post';
|
||||
export { getExpenseItemListById } from './expense/list/:id/get';
|
||||
export { getExpenseList } from './expense/list/get';
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { setupWorker } from 'msw/browser';
|
||||
|
||||
import {
|
||||
getExpenseList,
|
||||
getExpenseItemListById,
|
||||
getExpenseList,
|
||||
loginHandler,
|
||||
} from './handlers';
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
|
||||
import type { PropsWithChildren } from 'react';
|
||||
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
|
||||
export const createReactQueryWrapper = () => {
|
||||
const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import pluginQuery from '@tanstack/eslint-plugin-query';
|
||||
// @ts-expect-error fix package
|
||||
import config from 'eslint-config-ksv741';
|
||||
import perfectionist from 'eslint-plugin-perfectionist';
|
||||
|
||||
// eslint-disable-next-line import/no-anonymous-default-export
|
||||
export default [
|
||||
@ -9,6 +10,10 @@ export default [
|
||||
...config,
|
||||
{
|
||||
rules: {
|
||||
'@stylistic/jsx-sort-props': 'off',
|
||||
'@typescript-eslint/no-floating-promises': 'off',
|
||||
'@typescript-eslint/strict-boolean-expressions': 'off',
|
||||
'func-style': 'off',
|
||||
'import/no-extraneous-dependencies': ['error', {
|
||||
devDependencies: [
|
||||
'eslint.config.ts',
|
||||
@ -23,71 +28,13 @@ export default [
|
||||
'__mocks__/**',
|
||||
],
|
||||
}],
|
||||
'import/order': [
|
||||
'error', {
|
||||
pathGroups: [
|
||||
{
|
||||
pattern: '__mocks__/**',
|
||||
group: 'builtin',
|
||||
position: 'before',
|
||||
},
|
||||
{
|
||||
pattern: 'apps/**',
|
||||
group: 'internal',
|
||||
position: 'after',
|
||||
},
|
||||
{
|
||||
pattern: 'pages/**',
|
||||
group: 'internal',
|
||||
position: 'after',
|
||||
},
|
||||
{
|
||||
pattern: 'widgets/**',
|
||||
group: 'internal',
|
||||
position: 'after',
|
||||
},
|
||||
{
|
||||
pattern: 'features/**',
|
||||
group: 'internal',
|
||||
position: 'after',
|
||||
},
|
||||
{
|
||||
pattern: 'entities/**',
|
||||
group: 'internal',
|
||||
position: 'after',
|
||||
},
|
||||
{
|
||||
pattern: 'shared/**',
|
||||
group: 'internal',
|
||||
position: 'after',
|
||||
},
|
||||
],
|
||||
distinctGroup: true,
|
||||
groups: [
|
||||
'builtin',
|
||||
'external',
|
||||
'internal',
|
||||
'parent',
|
||||
'sibling',
|
||||
'object',
|
||||
'index',
|
||||
'type',
|
||||
],
|
||||
'newlines-between': 'always',
|
||||
alphabetize: {
|
||||
order: 'asc',
|
||||
caseInsensitive: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
'@typescript-eslint/strict-boolean-expressions': 'off',
|
||||
'@typescript-eslint/no-floating-promises': 'off',
|
||||
'func-style': 'off',
|
||||
'import/order': 'off',
|
||||
'jsx-a11y/click-events-have-key-events': 'off',
|
||||
'jsx-a11y/no-static-element-interactions': 'off',
|
||||
'jsx-a11y/no-noninteractive-element-interactions': 'off',
|
||||
'jsx-a11y/no-static-element-interactions': 'off',
|
||||
},
|
||||
},
|
||||
perfectionist.configs['recommended-natural'],
|
||||
{
|
||||
ignores: ['./src/shared/api/schema.ts'],
|
||||
},
|
||||
|
||||
@ -1,6 +1,14 @@
|
||||
import type { Config } from 'jest';
|
||||
|
||||
export default {
|
||||
moduleNameMapper: {
|
||||
'@/(.*)': '<rootDir>/src/$1',
|
||||
'@mocks/(.*)': '<rootDir>/__mocks__/$1',
|
||||
'\\.(css|scss|sass|less)$': 'identity-obj-proxy',
|
||||
'\\.(jpg|jpeg|png|gif|webp|svg)$': '<rootDir>/__mocks__/jest/fileMock.js',
|
||||
},
|
||||
setupFilesAfterEnv: ['<rootDir>/configs/jest/setupTests.ts'],
|
||||
testEnvironment: '<rootDir>/configs/jest/jest-fixed-jsdom.ts',
|
||||
transform: {
|
||||
'^.+\\.(t|j)sx?$': ['@swc/jest', {
|
||||
jsc: {
|
||||
@ -12,12 +20,4 @@ export default {
|
||||
},
|
||||
}],
|
||||
},
|
||||
testEnvironment: '<rootDir>/configs/jest/jest-fixed-jsdom.ts',
|
||||
setupFilesAfterEnv: ['<rootDir>/configs/jest/setupTests.ts'],
|
||||
moduleNameMapper: {
|
||||
'@/(.*)': '<rootDir>/src/$1',
|
||||
'@mocks/(.*)': '<rootDir>/__mocks__/$1',
|
||||
'\\.(css|scss|sass|less)$': 'identity-obj-proxy',
|
||||
'\\.(jpg|jpeg|png|gif|webp|svg)$': '<rootDir>/__mocks__/jest/fileMock.js',
|
||||
},
|
||||
} as Config;
|
||||
|
||||
@ -4,6 +4,9 @@ import { pluginReact } from '@rsbuild/plugin-react';
|
||||
import { pluginTypeCheck } from '@rsbuild/plugin-type-check';
|
||||
|
||||
export default defineConfig({
|
||||
html: {
|
||||
title: 'Investments Control',
|
||||
},
|
||||
plugins: [
|
||||
pluginReact(),
|
||||
pluginEslint({
|
||||
@ -15,17 +18,14 @@ export default defineConfig({
|
||||
}),
|
||||
pluginTypeCheck(),
|
||||
],
|
||||
html: {
|
||||
title: 'Investments Control',
|
||||
},
|
||||
server: {
|
||||
proxy: {
|
||||
[`${process.env.PUBLIC_API_BASE_URL}`]: {
|
||||
target: process.env.BACKEND_BASE_URL,
|
||||
changeOrigin: true,
|
||||
pathRewrite: {
|
||||
[`^${process.env.PUBLIC_API_BASE_URL}`]: '',
|
||||
},
|
||||
target: process.env.BACKEND_BASE_URL,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
import type { paths } from '@/shared/api/schema';
|
||||
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
type LoginRequestBody = paths['/auth/login']['post']['requestBody']['content']['application/json'];
|
||||
type LoginSuccessResponse = paths['/auth/login']['post']['responses']['200']['content']['application/json'];
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
import type { paths } from '@/shared/api/schema';
|
||||
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
type LogoutSuccessResponse = paths['/auth/logout']['post']['responses']['200']['content']['application/json'];
|
||||
|
||||
export async function logout() {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
import type { paths } from '@/shared/api/schema';
|
||||
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
type RegisterRequestBody = paths['/auth/register']['post']['requestBody']['content']['application/json'];
|
||||
type RegisterSuccessResponse = paths['/auth/register']['post']['responses']['200']['content']['application/json'];
|
||||
|
||||
|
||||
@ -13,16 +13,16 @@ export const useLogin = () => {
|
||||
|
||||
return useMutation({
|
||||
mutationFn: login,
|
||||
onSuccess: async (data) => {
|
||||
setAccessToken(data.accessToken);
|
||||
localStorage.setItem('accessToken', data.accessToken);
|
||||
await navigate(PAGES.Home);
|
||||
},
|
||||
onError: (error) => {
|
||||
// eslint-disable-next-line
|
||||
console.log('Неуспешный логин', error);
|
||||
|
||||
throw error;
|
||||
},
|
||||
onSuccess: async (data) => {
|
||||
setAccessToken(data.accessToken);
|
||||
localStorage.setItem('accessToken', data.accessToken);
|
||||
await navigate(PAGES.Home);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
export { useLogin } from './hooks/useLogin';
|
||||
export { useRegister } from './hooks/useRegister';
|
||||
export { useLogout } from './hooks/useLogout';
|
||||
export { useRegister } from './hooks/useRegister';
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
import type { paths } from '@/shared/api/schema';
|
||||
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
export type AddBankCardBody = paths['/bank-card']['post']['requestBody']['content']['application/json'];
|
||||
export type AddBankCardResponse = paths['/bank-card']['post']['responses']['200']['content']['application/json'];
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
import type { paths } from '@/shared/api/schema';
|
||||
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
export type DeleteBankCardPath = paths['/bank-card/{id}']['delete']['parameters']['path'];
|
||||
export type DeleteBankCardResponse = paths['/bank-card/{id}']['delete']['responses']['200']['content']['application/json'];
|
||||
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
import type { paths } from '@/shared/api/schema';
|
||||
|
||||
export type EditBankCardPath = paths['/bank-card/{id}']['patch']['parameters']['path'];
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
export type EditBankCardBody = paths['/bank-card/{id}']['patch']['requestBody']['content']['application/json'];
|
||||
export type EditBankCardPath = paths['/bank-card/{id}']['patch']['parameters']['path'];
|
||||
export type EditBankCardResponse = paths['/bank-card/{id}']['patch']['responses']['200']['content']['application/json'];
|
||||
|
||||
export async function editBankCard({ path, data }: { path: EditBankCardPath; data: EditBankCardBody }) {
|
||||
export async function editBankCard({ data, path }: { data: EditBankCardBody; path: EditBankCardPath }) {
|
||||
const { data: result } = await api.patch<EditBankCardResponse>(`/bank-card/${path.id}`, data);
|
||||
|
||||
return result;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
import type { paths } from '@/shared/api/schema';
|
||||
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
type BankCardsResponse = paths['/bank-card']['get']['responses']['200']['content']['application/json'];
|
||||
|
||||
export async function getBankCards() {
|
||||
|
||||
@ -1,17 +1,18 @@
|
||||
export { useBankCards } from './hooks/useBankCards';
|
||||
export { useAddBankCard } from './hooks/useAddBankCard';
|
||||
export { useDeleteBankCard } from './hooks/useDeleteBankCard';
|
||||
export { useEditBankCard } from './hooks/useEditBankCard';
|
||||
|
||||
export { AddBankCardForm } from './ui/AddBankCardForm';
|
||||
export { DeleteBankCardForm } from './ui/DeleteBankCardForm';
|
||||
export { EditBankCardForm } from './ui/EditBankCardForm';
|
||||
|
||||
export type { AddBankCardBody, AddBankCardResponse } from './api/addBankCard';
|
||||
export type { DeleteBankCardPath, DeleteBankCardResponse } from './api/deleteBankCard';
|
||||
export type { EditBankCardBody, EditBankCardPath, EditBankCardResponse } from './api/editBankCard';
|
||||
|
||||
export type { AddBankCardFormValues } from './ui/AddBankCardForm';
|
||||
export type { EditBankCardFormValues } from './ui/EditBankCardForm';
|
||||
export { useAddBankCard } from './hooks/useAddBankCard';
|
||||
export { useBankCards } from './hooks/useBankCards';
|
||||
export { useDeleteBankCard } from './hooks/useDeleteBankCard';
|
||||
export { useEditBankCard } from './hooks/useEditBankCard';
|
||||
|
||||
export type { BankCards, BankCard } from './types';
|
||||
export type { BankCard, BankCards } from './types';
|
||||
|
||||
export type { AddBankCardFormValues } from './ui/AddBankCardForm';
|
||||
export { AddBankCardForm } from './ui/AddBankCardForm';
|
||||
|
||||
export { DeleteBankCardForm } from './ui/DeleteBankCardForm';
|
||||
|
||||
export type { EditBankCardFormValues } from './ui/EditBankCardForm';
|
||||
export { EditBankCardForm } from './ui/EditBankCardForm';
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import type { paths } from '@/shared/api/schema';
|
||||
|
||||
export type BankCards = paths['/bank-card']['get']['responses']['200']['content']['application/json'];
|
||||
export type BankCard = paths['/bank-card/{id}']['get']['responses']['200']['content']['application/json'];
|
||||
export type BankCards = paths['/bank-card']['get']['responses']['200']['content']['application/json'];
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
import AddBankCardForm from './AddBankCardForm.ui';
|
||||
|
||||
import type { AddBankCardFormProps } from './AddBankCardForm.ui';
|
||||
|
||||
import AddBankCardForm from './AddBankCardForm.ui';
|
||||
|
||||
const renderForm = (props?: Partial<AddBankCardFormProps>) => {
|
||||
const onSubmit = jest.fn();
|
||||
|
||||
@ -15,10 +15,10 @@ const renderForm = (props?: Partial<AddBankCardFormProps>) => {
|
||||
const submitButtonElem = screen.getByText('Добавить');
|
||||
|
||||
return {
|
||||
nameInputElem,
|
||||
balanceInputElem,
|
||||
submitButtonElem,
|
||||
nameInputElem,
|
||||
onSubmit,
|
||||
submitButtonElem,
|
||||
};
|
||||
};
|
||||
|
||||
@ -44,10 +44,10 @@ describe('Test AddBankCardForm', () => {
|
||||
|
||||
test('should call onSubmit with values', async () => {
|
||||
const {
|
||||
nameInputElem,
|
||||
balanceInputElem,
|
||||
submitButtonElem,
|
||||
nameInputElem,
|
||||
onSubmit,
|
||||
submitButtonElem,
|
||||
} = renderForm();
|
||||
|
||||
await userEvent.type(nameInputElem, 'Тестовая карта');
|
||||
@ -57,8 +57,8 @@ describe('Test AddBankCardForm', () => {
|
||||
|
||||
expect(onSubmit).toHaveBeenCalledTimes(1);
|
||||
expect(onSubmit).toHaveBeenCalledWith({
|
||||
name: 'Тестовая карта',
|
||||
balance: 500,
|
||||
name: 'Тестовая карта',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,7 +1,3 @@
|
||||
import { Input } from '@/shared/ui/Input';
|
||||
|
||||
import classes from './AddBankCardForm.module.css';
|
||||
|
||||
import type {
|
||||
FC,
|
||||
FormEventHandler,
|
||||
@ -9,12 +5,9 @@ import type {
|
||||
RefObject,
|
||||
} from 'react';
|
||||
|
||||
export type AddBankCardFormValues = {
|
||||
name: string;
|
||||
balance: number;
|
||||
};
|
||||
import { Input } from '@/shared/ui/Input';
|
||||
|
||||
type BaseFormProps = Omit<FormHTMLAttributes<HTMLFormElement>, 'onSubmit'>;
|
||||
import classes from './AddBankCardForm.module.css';
|
||||
|
||||
export type AddBankCardFormProps = BaseFormProps & {
|
||||
disabled?: boolean;
|
||||
@ -22,11 +15,18 @@ export type AddBankCardFormProps = BaseFormProps & {
|
||||
ref?: RefObject<HTMLFormElement>;
|
||||
};
|
||||
|
||||
export type AddBankCardFormValues = {
|
||||
balance: number;
|
||||
name: string;
|
||||
};
|
||||
|
||||
type BaseFormProps = Omit<FormHTMLAttributes<HTMLFormElement>, 'onSubmit'>;
|
||||
|
||||
const AddBankCardForm: FC<AddBankCardFormProps> = (props) => {
|
||||
const {
|
||||
ref,
|
||||
disabled,
|
||||
onSubmit,
|
||||
ref,
|
||||
...formProps
|
||||
} = props;
|
||||
|
||||
@ -40,26 +40,26 @@ const AddBankCardForm: FC<AddBankCardFormProps> = (props) => {
|
||||
|
||||
if (typeof name === 'string' && typeof balance === 'string') {
|
||||
onSubmit?.({
|
||||
name,
|
||||
balance: Number(balance),
|
||||
name,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<form
|
||||
ref={ref}
|
||||
className={classes.form}
|
||||
onSubmit={onFormSubmitHandler}
|
||||
ref={ref}
|
||||
{...formProps}
|
||||
>
|
||||
<h2>Добавить карту</h2>
|
||||
|
||||
<Input
|
||||
required
|
||||
disabled={disabled}
|
||||
label="Название"
|
||||
name="name"
|
||||
required
|
||||
/>
|
||||
|
||||
<Input
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
import DeleteBankCardForm from './DeleteBankCardForm.ui';
|
||||
|
||||
import type { DeleteBankCardFormProps } from './DeleteBankCardForm.ui';
|
||||
|
||||
import DeleteBankCardForm from './DeleteBankCardForm.ui';
|
||||
|
||||
const deletingBankCard: DeleteBankCardFormProps['bankCard'] = {
|
||||
balance: 1000,
|
||||
createdAt: '2025-08-29T07:57:40.503Z',
|
||||
id: 'af6da4e1-f24f-4b43-8556-fa885626897d',
|
||||
name: 'Тестовая карта',
|
||||
balance: 1000,
|
||||
updatedAt: '2025-08-29T07:57:40.503Z',
|
||||
createdAt: '2025-08-29T07:57:40.503Z',
|
||||
};
|
||||
|
||||
const renderForm = (props?: Partial<DeleteBankCardFormProps>) => {
|
||||
@ -28,8 +28,8 @@ const renderForm = (props?: Partial<DeleteBankCardFormProps>) => {
|
||||
const submitButtonElem = screen.getByText('Удалить');
|
||||
|
||||
return {
|
||||
submitButtonElem,
|
||||
onSubmit,
|
||||
submitButtonElem,
|
||||
};
|
||||
};
|
||||
|
||||
@ -43,8 +43,8 @@ describe('Test DeleteExpensesListForm', () => {
|
||||
|
||||
test('should call onSubmit with values', async () => {
|
||||
const {
|
||||
submitButtonElem,
|
||||
onSubmit,
|
||||
submitButtonElem,
|
||||
} = renderForm();
|
||||
|
||||
await userEvent.click(submitButtonElem);
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import type { BankCard } from '../../../types';
|
||||
import type {
|
||||
FC,
|
||||
FormEventHandler,
|
||||
@ -6,7 +5,7 @@ import type {
|
||||
RefObject,
|
||||
} from 'react';
|
||||
|
||||
type BaseFormProps = Omit<FormHTMLAttributes<HTMLFormElement>, 'onSubmit'>;
|
||||
import type { BankCard } from '../../../types';
|
||||
|
||||
export type DeleteBankCardFormProps = BaseFormProps & {
|
||||
bankCard: BankCard;
|
||||
@ -15,6 +14,8 @@ export type DeleteBankCardFormProps = BaseFormProps & {
|
||||
ref?: RefObject<HTMLFormElement>;
|
||||
};
|
||||
|
||||
type BaseFormProps = Omit<FormHTMLAttributes<HTMLFormElement>, 'onSubmit'>;
|
||||
|
||||
const DeleteBankCardForm: FC<DeleteBankCardFormProps> = (props) => {
|
||||
const {
|
||||
bankCard,
|
||||
@ -30,7 +31,7 @@ const DeleteBankCardForm: FC<DeleteBankCardFormProps> = (props) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<form ref={ref} onSubmit={onFormSubmitHandler} {...restProps}>
|
||||
<form onSubmit={onFormSubmitHandler} ref={ref} {...restProps}>
|
||||
<h2>Удалить список расходов</h2>
|
||||
|
||||
<p>
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
import EditBankCardForm from './EditBankCardForm.ui';
|
||||
|
||||
import type { EditBankCardFormProps } from './EditBankCardForm.ui';
|
||||
|
||||
import EditBankCardForm from './EditBankCardForm.ui';
|
||||
|
||||
const editingBankCard = {
|
||||
balance: 1000,
|
||||
createdAt: '2025-08-29T07:57:40.503Z',
|
||||
id: 'af6da4e1-f24f-4b43-8556-fa885626897d',
|
||||
name: 'Тестовая карта',
|
||||
balance: 1000,
|
||||
updatedAt: '2025-08-29T07:57:40.503Z',
|
||||
createdAt: '2025-08-29T07:57:40.503Z',
|
||||
};
|
||||
|
||||
const renderForm = (props?: Partial<EditBankCardFormProps>) => {
|
||||
@ -30,10 +30,10 @@ const renderForm = (props?: Partial<EditBankCardFormProps>) => {
|
||||
const submitButtonElem = screen.getByText('Сохранить');
|
||||
|
||||
return {
|
||||
titleInputElem,
|
||||
balanceInputElem,
|
||||
submitButtonElem,
|
||||
onSubmit,
|
||||
submitButtonElem,
|
||||
titleInputElem,
|
||||
};
|
||||
};
|
||||
|
||||
@ -47,8 +47,8 @@ describe('Test EditBankCardForm', () => {
|
||||
|
||||
test('should inputs have default value', () => {
|
||||
const {
|
||||
titleInputElem,
|
||||
balanceInputElem,
|
||||
titleInputElem,
|
||||
} = renderForm();
|
||||
expect(titleInputElem).toHaveValue('Тестовая карта');
|
||||
expect(balanceInputElem).toHaveValue(1000);
|
||||
@ -68,10 +68,10 @@ describe('Test EditBankCardForm', () => {
|
||||
|
||||
test('should call onSubmit with values', async () => {
|
||||
const {
|
||||
titleInputElem,
|
||||
balanceInputElem,
|
||||
submitButtonElem,
|
||||
onSubmit,
|
||||
submitButtonElem,
|
||||
titleInputElem,
|
||||
} = renderForm();
|
||||
|
||||
await userEvent.clear(titleInputElem);
|
||||
@ -84,8 +84,8 @@ describe('Test EditBankCardForm', () => {
|
||||
|
||||
expect(onSubmit).toHaveBeenCalledTimes(1);
|
||||
expect(onSubmit).toHaveBeenCalledWith({
|
||||
name: 'Новое название карты',
|
||||
balance: 5000,
|
||||
name: 'Новое название карты',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,8 +1,3 @@
|
||||
import { Input } from '@/shared/ui/Input';
|
||||
|
||||
import classes from './EditBankCardForm.module.css';
|
||||
|
||||
import type { BankCard } from '@/entity/cards';
|
||||
import type {
|
||||
FC,
|
||||
FormEventHandler,
|
||||
@ -10,12 +5,11 @@ import type {
|
||||
RefObject,
|
||||
} from 'react';
|
||||
|
||||
type BaseFormProps = Omit<FormHTMLAttributes<HTMLFormElement>, 'onSubmit'>;
|
||||
import type { BankCard } from '@/entity/cards';
|
||||
|
||||
export type EditBankCardFormValues = {
|
||||
name: string;
|
||||
balance: number;
|
||||
};
|
||||
import { Input } from '@/shared/ui/Input';
|
||||
|
||||
import classes from './EditBankCardForm.module.css';
|
||||
|
||||
export type EditBankCardFormProps = BaseFormProps & {
|
||||
bankCard: BankCard;
|
||||
@ -24,6 +18,13 @@ export type EditBankCardFormProps = BaseFormProps & {
|
||||
ref?: RefObject<HTMLFormElement>;
|
||||
};
|
||||
|
||||
export type EditBankCardFormValues = {
|
||||
balance: number;
|
||||
name: string;
|
||||
};
|
||||
|
||||
type BaseFormProps = Omit<FormHTMLAttributes<HTMLFormElement>, 'onSubmit'>;
|
||||
|
||||
const EditBankCardForm: FC<EditBankCardFormProps> = (props) => {
|
||||
const {
|
||||
bankCard,
|
||||
@ -43,27 +44,27 @@ const EditBankCardForm: FC<EditBankCardFormProps> = (props) => {
|
||||
|
||||
if (typeof name === 'string' && typeof balance === 'string') {
|
||||
onSubmit?.({
|
||||
name,
|
||||
balance: Number(balance),
|
||||
name,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<form
|
||||
ref={ref}
|
||||
className={classes.form}
|
||||
onSubmit={onFormSubmitHandler}
|
||||
ref={ref}
|
||||
{...restProps}
|
||||
>
|
||||
<h2>Добавить карту</h2>
|
||||
|
||||
<Input
|
||||
required
|
||||
defaultValue={bankCard.name}
|
||||
disabled={disabled}
|
||||
label="Название"
|
||||
name="name"
|
||||
required
|
||||
/>
|
||||
|
||||
<Input
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
import type { paths } from '@/shared/api/schema';
|
||||
|
||||
export type AddCashBody = paths['/cash']['post']['requestBody']['content']['application/json'];
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
export type AdCashResponse = paths['/cash']['post']['responses']['200']['content']['application/json'];
|
||||
export type AddCashBody = paths['/cash']['post']['requestBody']['content']['application/json'];
|
||||
|
||||
export async function addCash(data: AddCashBody) {
|
||||
const { data: result } = await api.post<AdCashResponse>('/cash', data);
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
import type { paths } from '@/shared/api/schema';
|
||||
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
export type DeleteCashPath = paths['/cash/{id}']['delete']['parameters']['path'];
|
||||
export type DeleteCashResponse = paths['/cash/{id}']['delete']['responses']['200']['content']['application/json'];
|
||||
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
import type { paths } from '@/shared/api/schema';
|
||||
|
||||
export type EditCashPath = paths['/cash/{id}']['patch']['parameters']['path'];
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
export type EditCashBody = paths['/cash/{id}']['patch']['requestBody']['content']['application/json'];
|
||||
export type EditCashPath = paths['/cash/{id}']['patch']['parameters']['path'];
|
||||
export type EditCashResponse = paths['/cash/{id}']['patch']['responses']['200']['content']['application/json'];
|
||||
|
||||
export async function editCash({ path, data }: { path: EditCashPath; data: EditCashBody }) {
|
||||
export async function editCash({ data, path }: { data: EditCashBody; path: EditCashPath }) {
|
||||
const { data: result } = await api.patch<EditCashResponse>(`/cash/${path.id}`, data);
|
||||
|
||||
return result;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
import type { paths } from '@/shared/api/schema';
|
||||
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
type CashResponse = paths['/cash']['get']['responses']['200']['content']['application/json'];
|
||||
|
||||
export async function getCash() {
|
||||
|
||||
@ -1,16 +1,18 @@
|
||||
export type { AdCashResponse, AddCashBody } from './api/addCash';
|
||||
export type { DeleteCashPath, DeleteCashResponse } from './api/deleteCash';
|
||||
export type { EditCashBody, EditCashPath, EditCashResponse } from './api/editCash';
|
||||
|
||||
export { useAddCash } from './hooks/useAddCash';
|
||||
export { useCash } from './hooks/useCash';
|
||||
export { useDeleteCash } from './hooks/useDeleteCash';
|
||||
export { useEditCash } from './hooks/useEditCash';
|
||||
|
||||
export type { CashItem, CashList } from './types';
|
||||
|
||||
export { AddCashForm } from './ui/AddCashForm';
|
||||
export { DeleteCashForm } from './ui/DeleteCashForm';
|
||||
export { EditCashForm } from './ui/EditCashForm';
|
||||
|
||||
export type { CashList, CashItem } from './types';
|
||||
|
||||
export type { AddCashFormValues } from './ui/AddCashForm';
|
||||
|
||||
export { DeleteCashForm } from './ui/DeleteCashForm';
|
||||
|
||||
export { EditCashForm } from './ui/EditCashForm';
|
||||
export type { EditCashFormValues } from './ui/EditCashForm';
|
||||
export type { AddCashBody, AdCashResponse } from './api/addCash';
|
||||
export type { DeleteCashPath, DeleteCashResponse } from './api/deleteCash';
|
||||
export type { EditCashBody, EditCashPath, EditCashResponse } from './api/editCash';
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import type { paths } from '@/shared/api/schema';
|
||||
|
||||
export type CashList = paths['/cash']['get']['responses']['200']['content']['application/json'];
|
||||
export type CashItem = paths['/cash/{id}']['get']['responses']['200']['content']['application/json'];
|
||||
export type CashList = paths['/cash']['get']['responses']['200']['content']['application/json'];
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
import AddCashForm from './AddCashForm.ui';
|
||||
|
||||
import type { AddCashFormProps } from './AddCashForm.ui';
|
||||
|
||||
import AddCashForm from './AddCashForm.ui';
|
||||
|
||||
const renderForm = (props?: Partial<AddCashFormProps>) => {
|
||||
const onSubmit = jest.fn();
|
||||
|
||||
@ -15,10 +15,10 @@ const renderForm = (props?: Partial<AddCashFormProps>) => {
|
||||
const submitButtonElem = screen.getByText('Добавить');
|
||||
|
||||
return {
|
||||
nameInputElem,
|
||||
balanceInputElem,
|
||||
submitButtonElem,
|
||||
nameInputElem,
|
||||
onSubmit,
|
||||
submitButtonElem,
|
||||
};
|
||||
};
|
||||
|
||||
@ -44,10 +44,10 @@ describe('Test AddCashForm', () => {
|
||||
|
||||
test('should call onSubmit with values', async () => {
|
||||
const {
|
||||
nameInputElem,
|
||||
balanceInputElem,
|
||||
submitButtonElem,
|
||||
nameInputElem,
|
||||
onSubmit,
|
||||
submitButtonElem,
|
||||
} = renderForm();
|
||||
|
||||
await userEvent.type(nameInputElem, 'Наличные');
|
||||
@ -57,8 +57,8 @@ describe('Test AddCashForm', () => {
|
||||
|
||||
expect(onSubmit).toHaveBeenCalledTimes(1);
|
||||
expect(onSubmit).toHaveBeenCalledWith({
|
||||
name: 'Наличные',
|
||||
balance: 500,
|
||||
name: 'Наличные',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,7 +1,3 @@
|
||||
import { Input } from '@/shared/ui/Input';
|
||||
|
||||
import classes from './AddCashForm.module.css';
|
||||
|
||||
import type {
|
||||
FC,
|
||||
FormEventHandler,
|
||||
@ -9,12 +5,9 @@ import type {
|
||||
RefObject,
|
||||
} from 'react';
|
||||
|
||||
export type AddCashFormValues = {
|
||||
name: string;
|
||||
balance: number;
|
||||
};
|
||||
import { Input } from '@/shared/ui/Input';
|
||||
|
||||
type BaseFormProps = Omit<FormHTMLAttributes<HTMLFormElement>, 'onSubmit'>;
|
||||
import classes from './AddCashForm.module.css';
|
||||
|
||||
export type AddCashFormProps = BaseFormProps & {
|
||||
disabled?: boolean;
|
||||
@ -22,11 +15,18 @@ export type AddCashFormProps = BaseFormProps & {
|
||||
ref?: RefObject<HTMLFormElement>;
|
||||
};
|
||||
|
||||
export type AddCashFormValues = {
|
||||
balance: number;
|
||||
name: string;
|
||||
};
|
||||
|
||||
type BaseFormProps = Omit<FormHTMLAttributes<HTMLFormElement>, 'onSubmit'>;
|
||||
|
||||
const AddCashForm: FC<AddCashFormProps> = (props) => {
|
||||
const {
|
||||
ref,
|
||||
disabled,
|
||||
onSubmit,
|
||||
ref,
|
||||
...formProps
|
||||
} = props;
|
||||
|
||||
@ -40,26 +40,26 @@ const AddCashForm: FC<AddCashFormProps> = (props) => {
|
||||
|
||||
if (typeof name === 'string' && typeof balance === 'string') {
|
||||
onSubmit?.({
|
||||
name,
|
||||
balance: Number(balance),
|
||||
name,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<form
|
||||
ref={ref}
|
||||
className={classes.form}
|
||||
onSubmit={onFormSubmitHandler}
|
||||
ref={ref}
|
||||
{...formProps}
|
||||
>
|
||||
<h2>Добавить наличные</h2>
|
||||
|
||||
<Input
|
||||
required
|
||||
disabled={disabled}
|
||||
label="Название"
|
||||
name="name"
|
||||
required
|
||||
/>
|
||||
|
||||
<Input
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
import DeleteCashForm from './DeleteCashForm.ui';
|
||||
|
||||
import type { DeleteCashFormProps } from './DeleteCashForm.ui';
|
||||
|
||||
import DeleteCashForm from './DeleteCashForm.ui';
|
||||
|
||||
const deletingCash: DeleteCashFormProps['cash'] = {
|
||||
balance: 1000,
|
||||
createdAt: '2025-08-29T07:57:40.503Z',
|
||||
id: 'af6da4e1-f24f-4b43-8556-fa885626897d',
|
||||
name: 'Наличные',
|
||||
balance: 1000,
|
||||
updatedAt: '2025-08-29T07:57:40.503Z',
|
||||
createdAt: '2025-08-29T07:57:40.503Z',
|
||||
};
|
||||
|
||||
const renderForm = (props?: Partial<DeleteCashFormProps>) => {
|
||||
@ -28,8 +28,8 @@ const renderForm = (props?: Partial<DeleteCashFormProps>) => {
|
||||
const submitButtonElem = screen.getByText('Удалить');
|
||||
|
||||
return {
|
||||
submitButtonElem,
|
||||
onSubmit,
|
||||
submitButtonElem,
|
||||
};
|
||||
};
|
||||
|
||||
@ -43,8 +43,8 @@ describe('Test DeleteCashForm', () => {
|
||||
|
||||
test('should call onSubmit with values', async () => {
|
||||
const {
|
||||
submitButtonElem,
|
||||
onSubmit,
|
||||
submitButtonElem,
|
||||
} = renderForm();
|
||||
|
||||
await userEvent.click(submitButtonElem);
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import type { CashItem } from '../../../types';
|
||||
import type {
|
||||
FC,
|
||||
FormEventHandler,
|
||||
@ -6,7 +5,7 @@ import type {
|
||||
RefObject,
|
||||
} from 'react';
|
||||
|
||||
type BaseFormProps = Omit<FormHTMLAttributes<HTMLFormElement>, 'onSubmit'>;
|
||||
import type { CashItem } from '../../../types';
|
||||
|
||||
export type DeleteCashFormProps = BaseFormProps & {
|
||||
cash: CashItem;
|
||||
@ -15,6 +14,8 @@ export type DeleteCashFormProps = BaseFormProps & {
|
||||
ref?: RefObject<HTMLFormElement>;
|
||||
};
|
||||
|
||||
type BaseFormProps = Omit<FormHTMLAttributes<HTMLFormElement>, 'onSubmit'>;
|
||||
|
||||
const DeleteCashForm: FC<DeleteCashFormProps> = (props) => {
|
||||
const {
|
||||
cash,
|
||||
@ -30,7 +31,7 @@ const DeleteCashForm: FC<DeleteCashFormProps> = (props) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<form ref={ref} onSubmit={onFormSubmitHandler} {...restProps}>
|
||||
<form onSubmit={onFormSubmitHandler} ref={ref} {...restProps}>
|
||||
<h2>Удалить наличные</h2>
|
||||
|
||||
<p>
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
import EditCashForm from './EditCashForm.ui';
|
||||
|
||||
import type { EditCashFormProps } from './EditCashForm.ui';
|
||||
|
||||
import EditCashForm from './EditCashForm.ui';
|
||||
|
||||
const editingCash = {
|
||||
balance: 1000,
|
||||
createdAt: '2025-08-29T07:57:40.503Z',
|
||||
id: 'af6da4e1-f24f-4b43-8556-fa885626897d',
|
||||
name: 'Наличные',
|
||||
balance: 1000,
|
||||
updatedAt: '2025-08-29T07:57:40.503Z',
|
||||
createdAt: '2025-08-29T07:57:40.503Z',
|
||||
};
|
||||
|
||||
const renderForm = (props?: Partial<EditCashFormProps>) => {
|
||||
@ -30,10 +30,10 @@ const renderForm = (props?: Partial<EditCashFormProps>) => {
|
||||
const submitButtonElem = screen.getByText('Сохранить');
|
||||
|
||||
return {
|
||||
titleInputElem,
|
||||
balanceInputElem,
|
||||
submitButtonElem,
|
||||
onSubmit,
|
||||
submitButtonElem,
|
||||
titleInputElem,
|
||||
};
|
||||
};
|
||||
|
||||
@ -47,8 +47,8 @@ describe('Test EditCashForm', () => {
|
||||
|
||||
test('should inputs have default value', () => {
|
||||
const {
|
||||
titleInputElem,
|
||||
balanceInputElem,
|
||||
titleInputElem,
|
||||
} = renderForm();
|
||||
expect(titleInputElem).toHaveValue('Наличные');
|
||||
expect(balanceInputElem).toHaveValue(1000);
|
||||
@ -68,10 +68,10 @@ describe('Test EditCashForm', () => {
|
||||
|
||||
test('should call onSubmit with values', async () => {
|
||||
const {
|
||||
titleInputElem,
|
||||
balanceInputElem,
|
||||
submitButtonElem,
|
||||
onSubmit,
|
||||
submitButtonElem,
|
||||
titleInputElem,
|
||||
} = renderForm();
|
||||
|
||||
await userEvent.clear(titleInputElem);
|
||||
@ -84,8 +84,8 @@ describe('Test EditCashForm', () => {
|
||||
|
||||
expect(onSubmit).toHaveBeenCalledTimes(1);
|
||||
expect(onSubmit).toHaveBeenCalledWith({
|
||||
name: 'Новое название наличных',
|
||||
balance: 5000,
|
||||
name: 'Новое название наличных',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,8 +1,3 @@
|
||||
import { Input } from '@/shared/ui/Input';
|
||||
|
||||
import classes from './EditCashForm.module.css';
|
||||
|
||||
import type { CashItem } from '@/entity/cash';
|
||||
import type {
|
||||
FC,
|
||||
FormEventHandler,
|
||||
@ -10,12 +5,11 @@ import type {
|
||||
RefObject,
|
||||
} from 'react';
|
||||
|
||||
type BaseFormProps = Omit<FormHTMLAttributes<HTMLFormElement>, 'onSubmit'>;
|
||||
import type { CashItem } from '@/entity/cash';
|
||||
|
||||
export type EditCashFormValues = {
|
||||
name: string;
|
||||
balance: number;
|
||||
};
|
||||
import { Input } from '@/shared/ui/Input';
|
||||
|
||||
import classes from './EditCashForm.module.css';
|
||||
|
||||
export type EditCashFormProps = BaseFormProps & {
|
||||
cash: CashItem;
|
||||
@ -24,6 +18,13 @@ export type EditCashFormProps = BaseFormProps & {
|
||||
ref?: RefObject<HTMLFormElement>;
|
||||
};
|
||||
|
||||
export type EditCashFormValues = {
|
||||
balance: number;
|
||||
name: string;
|
||||
};
|
||||
|
||||
type BaseFormProps = Omit<FormHTMLAttributes<HTMLFormElement>, 'onSubmit'>;
|
||||
|
||||
const EditCashForm: FC<EditCashFormProps> = (props) => {
|
||||
const {
|
||||
cash,
|
||||
@ -43,27 +44,27 @@ const EditCashForm: FC<EditCashFormProps> = (props) => {
|
||||
|
||||
if (typeof name === 'string' && typeof balance === 'string') {
|
||||
onSubmit?.({
|
||||
name,
|
||||
balance: Number(balance),
|
||||
name,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<form
|
||||
ref={ref}
|
||||
className={classes.form}
|
||||
onSubmit={onFormSubmitHandler}
|
||||
ref={ref}
|
||||
{...restProps}
|
||||
>
|
||||
<h2>Редактировать наличные</h2>
|
||||
|
||||
<Input
|
||||
required
|
||||
defaultValue={cash.name}
|
||||
disabled={disabled}
|
||||
label="Название"
|
||||
name="name"
|
||||
required
|
||||
/>
|
||||
|
||||
<Input
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
import type { paths } from '@/shared/api/schema';
|
||||
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
export type AddExpenseItemBody = paths['/expenses/list/{id}/items']['post']['requestBody']['content']['application/json'];
|
||||
export type AddExpenseItemPath = paths['/expenses/list/{id}/items']['post']['parameters']['path'];
|
||||
export type AddExpenseItemSuccessResponse = paths['/expenses/list/{id}/items']['post']['responses']['200']['content']['application/json'];
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
import type { paths } from '@/shared/api/schema';
|
||||
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
export type DeleteExpenseItemPath = paths['/expenses/list/{listId}/items/{id}']['delete']['parameters']['path'];
|
||||
export type DeleteExpenseItemSuccessResponse = paths['/expenses/list/{id}/items']['post']['responses']['200']['content']['application/json'];
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
import type { paths } from '@/shared/api/schema';
|
||||
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
export type EditExpenseItemBody = paths['/expenses/list/{listId}/items/{id}']['patch']['requestBody']['content']['application/json'];
|
||||
export type EditExpenseItemPath = paths['/expenses/list/{listId}/items/{id}']['patch']['parameters']['path'];
|
||||
export type EditExpenseItemSuccessResponse = paths['/expenses/list/{listId}/items/{id}']['patch']['responses']['200']['content']['application/json'];
|
||||
|
||||
@ -2,10 +2,10 @@ import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
|
||||
import { QueryKeys } from '@/shared/api/queryKeys';
|
||||
|
||||
import { deleteExpenseItem } from '../api/deleteExpenseItem';
|
||||
|
||||
import type { DeleteExpenseItemPath } from '../api/deleteExpenseItem';
|
||||
|
||||
import { deleteExpenseItem } from '../api/deleteExpenseItem';
|
||||
|
||||
export const useDeleteExpenseItem = (path: DeleteExpenseItemPath) => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
export type { AddExpenseItemBody, AddExpenseItemPath, AddExpenseItemSuccessResponse } from './api/addExpenseItem';
|
||||
export type { DeleteExpenseItemPath, DeleteExpenseItemSuccessResponse } from './api/deleteExpenseItem';
|
||||
export type { EditExpenseItemBody, EditExpenseItemPath, EditExpenseItemSuccessResponse } from './api/editExpenseItem';
|
||||
|
||||
export { useAddExpenseItem } from './hooks/useAddExpenseItem';
|
||||
export { useDeleteExpenseItem } from './hooks/useDeleteExpenseItem';
|
||||
export { useEditExpenseItem } from './hooks/useEditExpenseItem';
|
||||
|
||||
export type { AddExpenseItemSuccessResponse, AddExpenseItemBody, AddExpenseItemPath } from './api/addExpenseItem';
|
||||
export type { DeleteExpenseItemPath, DeleteExpenseItemSuccessResponse } from './api/deleteExpenseItem';
|
||||
export type { EditExpenseItemBody, EditExpenseItemPath, EditExpenseItemSuccessResponse } from './api/editExpenseItem';
|
||||
|
||||
export type { ExpenseListItem } from './types';
|
||||
export type { AddExpenseItemFormValues } from './ui/AddExpenseItemForm/AddExpenseItemForm.ui';
|
||||
|
||||
export { default as AddExpenseItemForm } from './ui/AddExpenseItemForm/AddExpenseItemForm.ui';
|
||||
|
||||
export type { EditExpenseItemFormValues } from './ui/EditExpenseItemForm/EditExpenseItemForm.ui';
|
||||
export { default as EditExpenseItemForm } from './ui/EditExpenseItemForm/EditExpenseItemForm.ui';
|
||||
|
||||
export { default as DeleteExpenseItemForm } from './ui/DeleteExpenseItemForm/DeleteExpenseItemForm.ui';
|
||||
|
||||
export type { ExpenseListItem } from './types';
|
||||
export type { EditExpenseItemFormValues } from './ui/EditExpenseItemForm/EditExpenseItemForm.ui';
|
||||
|
||||
export { default as EditExpenseItemForm } from './ui/EditExpenseItemForm/EditExpenseItemForm.ui';
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
import AddExpenseItemForm from './AddExpenseItemForm.ui';
|
||||
|
||||
import type { AddExpenseItemFormProps } from './AddExpenseItemForm.ui';
|
||||
|
||||
import AddExpenseItemForm from './AddExpenseItemForm.ui';
|
||||
|
||||
const renderForm = (props?: Partial<AddExpenseItemFormProps>) => {
|
||||
const onSubmit = jest.fn();
|
||||
|
||||
@ -18,13 +18,13 @@ const renderForm = (props?: Partial<AddExpenseItemFormProps>) => {
|
||||
const submitButtonElem = screen.getByText('Добавить');
|
||||
|
||||
return {
|
||||
titleInputElem,
|
||||
descriptionInputElem,
|
||||
dateInputElem,
|
||||
amountInputElem,
|
||||
countInputElem,
|
||||
submitButtonElem,
|
||||
dateInputElem,
|
||||
descriptionInputElem,
|
||||
onSubmit,
|
||||
submitButtonElem,
|
||||
titleInputElem,
|
||||
};
|
||||
};
|
||||
|
||||
@ -50,13 +50,13 @@ describe('Test AddExpenseItemForm', () => {
|
||||
|
||||
test('should call onSubmit with values', async () => {
|
||||
const {
|
||||
titleInputElem,
|
||||
descriptionInputElem,
|
||||
dateInputElem,
|
||||
amountInputElem,
|
||||
countInputElem,
|
||||
submitButtonElem,
|
||||
dateInputElem,
|
||||
descriptionInputElem,
|
||||
onSubmit,
|
||||
submitButtonElem,
|
||||
titleInputElem,
|
||||
} = renderForm();
|
||||
|
||||
await userEvent.type(titleInputElem, 'Название элемента');
|
||||
@ -69,12 +69,12 @@ describe('Test AddExpenseItemForm', () => {
|
||||
|
||||
expect(onSubmit).toHaveBeenCalledTimes(1);
|
||||
expect(onSubmit).toHaveBeenCalledWith({
|
||||
title: 'Название элемента',
|
||||
description: 'Описание элемента',
|
||||
date: '2025-08-29T00:00:00.000Z',
|
||||
amount: 12,
|
||||
count: 1,
|
||||
currency: 'RUB',
|
||||
date: '2025-08-29T00:00:00.000Z',
|
||||
description: 'Описание элемента',
|
||||
title: 'Название элемента',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,7 +1,3 @@
|
||||
import { Input } from '@/shared/ui/Input';
|
||||
|
||||
import classes from './AddExpenseItemForm.module.css';
|
||||
|
||||
import type {
|
||||
FC,
|
||||
FormEventHandler,
|
||||
@ -9,16 +5,9 @@ import type {
|
||||
RefObject,
|
||||
} from 'react';
|
||||
|
||||
export type AddExpenseItemFormValues = {
|
||||
title: string;
|
||||
description: string;
|
||||
date: string;
|
||||
amount: number;
|
||||
count: number;
|
||||
currency: string;
|
||||
};
|
||||
import { Input } from '@/shared/ui/Input';
|
||||
|
||||
type BaseFormProps = Omit<FormHTMLAttributes<HTMLFormElement>, 'onSubmit'>;
|
||||
import classes from './AddExpenseItemForm.module.css';
|
||||
|
||||
export type AddExpenseItemFormProps = BaseFormProps & {
|
||||
disabled?: boolean;
|
||||
@ -26,6 +15,17 @@ export type AddExpenseItemFormProps = BaseFormProps & {
|
||||
ref?: RefObject<HTMLFormElement>;
|
||||
};
|
||||
|
||||
export type AddExpenseItemFormValues = {
|
||||
amount: number;
|
||||
count: number;
|
||||
currency: string;
|
||||
date: string;
|
||||
description: string;
|
||||
title: string;
|
||||
};
|
||||
|
||||
type BaseFormProps = Omit<FormHTMLAttributes<HTMLFormElement>, 'onSubmit'>;
|
||||
|
||||
const AddExpenseItemForm: FC<AddExpenseItemFormProps> = (props) => {
|
||||
const {
|
||||
disabled,
|
||||
@ -47,30 +47,30 @@ const AddExpenseItemForm: FC<AddExpenseItemFormProps> = (props) => {
|
||||
|
||||
if (typeof title === 'string' && typeof date === 'string' && typeof amount === 'string' && typeof description === 'string' && typeof count === 'string') {
|
||||
onSubmit?.({
|
||||
title,
|
||||
date: new Date(date).toISOString(),
|
||||
amount: Number(amount),
|
||||
description,
|
||||
currency: 'RUB',
|
||||
count: Number(count),
|
||||
currency: 'RUB',
|
||||
date: new Date(date).toISOString(),
|
||||
description,
|
||||
title,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<form
|
||||
ref={ref}
|
||||
className={classes.form}
|
||||
onSubmit={onFormSubmitHandler}
|
||||
ref={ref}
|
||||
{...formProps}
|
||||
>
|
||||
<h2>Добавить список расходов</h2>
|
||||
|
||||
<Input
|
||||
required
|
||||
disabled={disabled}
|
||||
label="Название"
|
||||
name="title"
|
||||
required
|
||||
/>
|
||||
|
||||
<Input
|
||||
@ -80,18 +80,18 @@ const AddExpenseItemForm: FC<AddExpenseItemFormProps> = (props) => {
|
||||
/>
|
||||
|
||||
<Input
|
||||
required
|
||||
disabled={disabled}
|
||||
label="Дата"
|
||||
name="date"
|
||||
required
|
||||
type="date"
|
||||
/>
|
||||
|
||||
<Input
|
||||
required
|
||||
disabled={disabled}
|
||||
label="Сумма"
|
||||
name="amount"
|
||||
required
|
||||
step="0.01"
|
||||
type="number"
|
||||
/>
|
||||
|
||||
@ -1,21 +1,21 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
import DeleteExpenseItemForm from './DeleteExpenseItemForm.ui';
|
||||
|
||||
import type { DeleteExpenseItemFormProps } from './DeleteExpenseItemForm.ui';
|
||||
|
||||
import DeleteExpenseItemForm from './DeleteExpenseItemForm.ui';
|
||||
|
||||
const deletingItem = {
|
||||
id: '51a44dc0-597b-49b9-85bb-e0bcd42db3f6',
|
||||
title: 'Mock item',
|
||||
amount: 12,
|
||||
count: 12,
|
||||
updatedAt: '2025-08-29T07:57:40.503Z',
|
||||
expenseListId: '10cc093c-3875-4d33-a40a-df526266e262',
|
||||
createdAt: '2025-08-29T07:57:40.503Z',
|
||||
currency: 'RUB',
|
||||
date: '2025-08-22T00:00:03.000Z',
|
||||
description: 'Mock description',
|
||||
expenseListId: '10cc093c-3875-4d33-a40a-df526266e262',
|
||||
id: '51a44dc0-597b-49b9-85bb-e0bcd42db3f6',
|
||||
title: 'Mock item',
|
||||
updatedAt: '2025-08-29T07:57:40.503Z',
|
||||
};
|
||||
|
||||
const renderForm = (props?: Partial<DeleteExpenseItemFormProps>) => {
|
||||
@ -33,8 +33,8 @@ const renderForm = (props?: Partial<DeleteExpenseItemFormProps>) => {
|
||||
const submitButtonElem = screen.getByText('Удалить');
|
||||
|
||||
return {
|
||||
submitButtonElem,
|
||||
onSubmit,
|
||||
submitButtonElem,
|
||||
};
|
||||
};
|
||||
|
||||
@ -48,8 +48,8 @@ describe('Test DeleteExpenseItemForm', () => {
|
||||
|
||||
test('should call onSubmit with values', async () => {
|
||||
const {
|
||||
submitButtonElem,
|
||||
onSubmit,
|
||||
submitButtonElem,
|
||||
} = renderForm();
|
||||
|
||||
await userEvent.click(submitButtonElem);
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import type { ExpenseListItem } from '../../types';
|
||||
import type {
|
||||
FC,
|
||||
FormEventHandler,
|
||||
@ -6,21 +5,23 @@ import type {
|
||||
RefObject,
|
||||
} from 'react';
|
||||
|
||||
type BaseFormProps = Omit<FormHTMLAttributes<HTMLFormElement>, 'onSubmit'>;
|
||||
import type { ExpenseListItem } from '../../types';
|
||||
|
||||
export type DeleteExpenseItemFormProps = BaseFormProps & {
|
||||
disabled?: boolean;
|
||||
item: ExpenseListItem;
|
||||
onSubmit?: (item: ExpenseListItem) => Promise<void> | void;
|
||||
disabled?: boolean;
|
||||
ref?: RefObject<HTMLFormElement>;
|
||||
};
|
||||
|
||||
type BaseFormProps = Omit<FormHTMLAttributes<HTMLFormElement>, 'onSubmit'>;
|
||||
|
||||
const DeleteExpenseItemForm: FC<DeleteExpenseItemFormProps> = (props) => {
|
||||
const {
|
||||
disabled,
|
||||
item,
|
||||
onSubmit,
|
||||
ref,
|
||||
disabled,
|
||||
...restProps
|
||||
} = props;
|
||||
const onFormSubmitHandler: FormEventHandler<HTMLFormElement> = (event) => {
|
||||
@ -29,7 +30,7 @@ const DeleteExpenseItemForm: FC<DeleteExpenseItemFormProps> = (props) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<form ref={ref} onSubmit={onFormSubmitHandler} {...restProps}>
|
||||
<form onSubmit={onFormSubmitHandler} ref={ref} {...restProps}>
|
||||
<h2>Удалить элемент ?</h2>
|
||||
|
||||
<button disabled={disabled} type="submit">Удалить</button>
|
||||
|
||||
@ -1,21 +1,21 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
import EditExpenseItemForm from './EditExpenseItemForm.ui';
|
||||
|
||||
import type { EditExpenseItemFormProps } from './EditExpenseItemForm.ui';
|
||||
|
||||
import EditExpenseItemForm from './EditExpenseItemForm.ui';
|
||||
|
||||
const editingItem = {
|
||||
id: '51a44dc0-597b-49b9-85bb-e0bcd42db3f6',
|
||||
title: 'Mock item',
|
||||
amount: 12,
|
||||
count: 12,
|
||||
updatedAt: '2025-08-29T07:57:40.503Z',
|
||||
expenseListId: '10cc093c-3875-4d33-a40a-df526266e262',
|
||||
createdAt: '2025-08-29T07:57:40.503Z',
|
||||
currency: 'RUB',
|
||||
date: '2025-08-22T00:00:03.000Z',
|
||||
description: 'Mock description',
|
||||
expenseListId: '10cc093c-3875-4d33-a40a-df526266e262',
|
||||
id: '51a44dc0-597b-49b9-85bb-e0bcd42db3f6',
|
||||
title: 'Mock item',
|
||||
updatedAt: '2025-08-29T07:57:40.503Z',
|
||||
};
|
||||
|
||||
const renderForm = (props?: Partial<EditExpenseItemFormProps>) => {
|
||||
@ -38,13 +38,13 @@ const renderForm = (props?: Partial<EditExpenseItemFormProps>) => {
|
||||
const submitButtonElem = screen.getByText('Сохранить');
|
||||
|
||||
return {
|
||||
titleInputElem,
|
||||
descriptionInputElem,
|
||||
dateInputElem,
|
||||
amountInputElem,
|
||||
countInputElem,
|
||||
submitButtonElem,
|
||||
dateInputElem,
|
||||
descriptionInputElem,
|
||||
onSubmit,
|
||||
submitButtonElem,
|
||||
titleInputElem,
|
||||
};
|
||||
};
|
||||
|
||||
@ -58,11 +58,11 @@ describe('Test EditExpenseItemForm', () => {
|
||||
|
||||
test('should inputs have default value', () => {
|
||||
const {
|
||||
titleInputElem,
|
||||
descriptionInputElem,
|
||||
dateInputElem,
|
||||
amountInputElem,
|
||||
countInputElem,
|
||||
dateInputElem,
|
||||
descriptionInputElem,
|
||||
titleInputElem,
|
||||
} = renderForm();
|
||||
expect(titleInputElem).toHaveValue('Mock item');
|
||||
expect(descriptionInputElem).toHaveValue('Mock description');
|
||||
@ -85,13 +85,13 @@ describe('Test EditExpenseItemForm', () => {
|
||||
|
||||
test('should call onSubmit with values', async () => {
|
||||
const {
|
||||
titleInputElem,
|
||||
descriptionInputElem,
|
||||
dateInputElem,
|
||||
amountInputElem,
|
||||
countInputElem,
|
||||
submitButtonElem,
|
||||
dateInputElem,
|
||||
descriptionInputElem,
|
||||
onSubmit,
|
||||
submitButtonElem,
|
||||
titleInputElem,
|
||||
} = renderForm();
|
||||
|
||||
await userEvent.clear(titleInputElem);
|
||||
@ -113,12 +113,12 @@ describe('Test EditExpenseItemForm', () => {
|
||||
|
||||
expect(onSubmit).toHaveBeenCalledTimes(1);
|
||||
expect(onSubmit).toHaveBeenCalledWith({
|
||||
title: 'Название элемента',
|
||||
description: 'Описание элемента',
|
||||
date: '2025-08-29T00:00:00.000Z',
|
||||
amount: 12,
|
||||
count: 1,
|
||||
currency: 'RUB',
|
||||
date: '2025-08-29T00:00:00.000Z',
|
||||
description: 'Описание элемента',
|
||||
title: 'Название элемента',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,8 +1,3 @@
|
||||
import { Input } from '@/shared/ui/Input';
|
||||
|
||||
import classes from './EditExpenseItemForm.module.css';
|
||||
|
||||
import type { ExpenseListItem } from '../../types';
|
||||
import type {
|
||||
FC,
|
||||
FormEventHandler,
|
||||
@ -10,29 +5,35 @@ import type {
|
||||
RefObject,
|
||||
} from 'react';
|
||||
|
||||
import { Input } from '@/shared/ui/Input';
|
||||
|
||||
import type { ExpenseListItem } from '../../types';
|
||||
|
||||
import classes from './EditExpenseItemForm.module.css';
|
||||
|
||||
export type EditExpenseItemFormProps = BaseFormProps & {
|
||||
disabled?: boolean;
|
||||
item: ExpenseListItem;
|
||||
onSubmit?: (data: EditExpenseItemFormValues) => Promise<void> | void;
|
||||
ref?: RefObject<HTMLFormElement>;
|
||||
};
|
||||
|
||||
export type EditExpenseItemFormValues = {
|
||||
title: string;
|
||||
description: string;
|
||||
date: string;
|
||||
amount: number;
|
||||
count: number;
|
||||
currency: string;
|
||||
date: string;
|
||||
description: string;
|
||||
title: string;
|
||||
};
|
||||
|
||||
type BaseFormProps = Omit<FormHTMLAttributes<HTMLFormElement>, 'onSubmit'>;
|
||||
export type EditExpenseItemFormProps = BaseFormProps & {
|
||||
disabled?: boolean;
|
||||
onSubmit?: (data: EditExpenseItemFormValues) => Promise<void> | void;
|
||||
ref?: RefObject<HTMLFormElement>;
|
||||
item: ExpenseListItem;
|
||||
};
|
||||
|
||||
const EditExpenseItemForm: FC<EditExpenseItemFormProps> = (props) => {
|
||||
const {
|
||||
disabled,
|
||||
item,
|
||||
onSubmit,
|
||||
ref,
|
||||
item,
|
||||
...formProps
|
||||
} = props;
|
||||
|
||||
@ -49,21 +50,21 @@ const EditExpenseItemForm: FC<EditExpenseItemFormProps> = (props) => {
|
||||
|
||||
if (typeof title === 'string' && typeof date === 'string' && typeof amount === 'string' && typeof description === 'string' && typeof count === 'string') {
|
||||
await onSubmit?.({
|
||||
title,
|
||||
date: new Date(date).toISOString(),
|
||||
amount: Number(amount),
|
||||
description,
|
||||
currency: 'RUB',
|
||||
count: Number(count),
|
||||
currency: 'RUB',
|
||||
date: new Date(date).toISOString(),
|
||||
description,
|
||||
title,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<form
|
||||
ref={ref}
|
||||
className={classes.form}
|
||||
onSubmit={onFormSubmitHandler}
|
||||
ref={ref}
|
||||
{...formProps}
|
||||
>
|
||||
<h2>Добавить список расходов</h2>
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
import type { paths } from '@/shared/api/schema';
|
||||
|
||||
export type AddExpenseListPath = paths['/expenses/list']['post']['parameters']['path'];
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
export type AddExpenseListBody = paths['/expenses/list']['post']['requestBody']['content']['application/json'];
|
||||
export type AddExpenseListPath = paths['/expenses/list']['post']['parameters']['path'];
|
||||
export type AddExpenseListSuccessResponse = paths['/expenses/list']['post']['responses']['200']['content']['application/json'];
|
||||
|
||||
export async function addExpensesList(data: AddExpenseListBody) {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
import type { paths } from '@/shared/api/schema';
|
||||
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
export type DeleteExpenseListPath = paths['/expenses/list/{id}']['delete']['parameters']['path'];
|
||||
export type DeleteExpenseSuccessResponse = paths['/expenses/list/{id}']['delete']['responses']['200']['content']['application/json'];
|
||||
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
import type { paths } from '@/shared/api/schema';
|
||||
|
||||
export type EditExpenseListPath = paths['/expenses/list/{id}']['patch']['parameters']['path'];
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
export type EditExpenseListBody = paths['/expenses/list/{id}']['patch']['requestBody']['content']['application/json'];
|
||||
export type EditExpenseListPath = paths['/expenses/list/{id}']['patch']['parameters']['path'];
|
||||
export type EditExpenseListSuccessResponse = paths['/expenses/list/{id}']['patch']['responses']['200']['content']['application/json'];
|
||||
|
||||
export async function editExpensesList({ data, path }: {
|
||||
path: EditExpenseListPath;
|
||||
data: EditExpenseListBody;
|
||||
path: EditExpenseListPath;
|
||||
}) {
|
||||
const { id } = path;
|
||||
const { data: result } = await api.patch<EditExpenseListSuccessResponse>(`/expenses/list/${id}`, data);
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
import type { paths } from '@/shared/api/schema';
|
||||
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
type ExpenseListPath = paths['/expenses/list/{id}']['get']['parameters']['path'];
|
||||
type ExpenseListResponse = paths['/expenses/list/{id}']['get']['responses']['200']['content']['application/json'];
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
import type { paths } from '@/shared/api/schema';
|
||||
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
type ExpensesListResponse = paths['/expenses/list']['get']['responses']['200']['content']['application/json'];
|
||||
|
||||
export async function getExpenseLists() {
|
||||
|
||||
@ -2,10 +2,10 @@ import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { QueryKeys } from '@/shared/api/queryKeys';
|
||||
|
||||
import { getExpenseList } from '../api/getExpenseList';
|
||||
|
||||
import type { ExpenseList } from '../types';
|
||||
|
||||
import { getExpenseList } from '../api/getExpenseList';
|
||||
|
||||
export const useExpenseList = (id: ExpenseList['id']) => useQuery({
|
||||
queryFn: async () => getExpenseList({ id }),
|
||||
queryKey: [QueryKeys.ExpenseList, id],
|
||||
|
||||
@ -1,10 +1,14 @@
|
||||
export type { ExpenseList } from './types';
|
||||
export { useDeleteExpensesList } from './hooks/useDeleteExpensesList';
|
||||
export { useAddExpensesList } from './hooks/useAddExpensesList';
|
||||
export { useExpensesList } from './hooks/useExpensesList';
|
||||
export { useEditExpensesList } from './hooks/useEditExpensesList';
|
||||
export type { AddExpenseListBody, AddExpenseListPath, AddExpenseListSuccessResponse } from './api/addExpensesList';
|
||||
export type { DeleteExpenseListPath, DeleteExpenseSuccessResponse } from './api/deleteExpensesList';
|
||||
export type { EditExpenseListBody, EditExpenseListPath, EditExpenseListSuccessResponse } from './api/editExpensesList';
|
||||
|
||||
export { useAddExpensesList } from './hooks/useAddExpensesList';
|
||||
export { useDeleteExpensesList } from './hooks/useDeleteExpensesList';
|
||||
export { useEditExpensesList } from './hooks/useEditExpensesList';
|
||||
export { useExpenseList } from './hooks/useExpenseList';
|
||||
export { useExpensesList } from './hooks/useExpensesList';
|
||||
|
||||
export type { ExpenseList } from './types';
|
||||
|
||||
export type { AddExpenseListFormValues } from './ui/AddExpensesListForm/ui/AddExpensesListForm.ui';
|
||||
export { default as AddExpensesListForm } from './ui/AddExpensesListForm/ui/AddExpensesListForm.ui';
|
||||
@ -13,7 +17,3 @@ export { default as DeleteExpensesListForm } from './ui/DeleteExpensesListForm/u
|
||||
|
||||
export type { EditExpenseListFormValues } from './ui/EditExpensesListForm/ui/EditExpensesListForm.ui';
|
||||
export { default as EditExpensesListForm } from './ui/EditExpensesListForm/ui/EditExpensesListForm.ui';
|
||||
|
||||
export type { AddExpenseListPath, AddExpenseListBody, AddExpenseListSuccessResponse } from './api/addExpensesList';
|
||||
export type { DeleteExpenseListPath, DeleteExpenseSuccessResponse } from './api/deleteExpensesList';
|
||||
export type { EditExpenseListPath, EditExpenseListBody, EditExpenseListSuccessResponse } from './api/editExpensesList';
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
import AddExpensesListForm from './AddExpensesListForm.ui';
|
||||
|
||||
import type { AddExpenseListFormProps } from './AddExpensesListForm.ui';
|
||||
|
||||
import AddExpensesListForm from './AddExpensesListForm.ui';
|
||||
|
||||
const renderForm = (props?: Partial<AddExpenseListFormProps>) => {
|
||||
const onSubmit = jest.fn();
|
||||
|
||||
@ -14,9 +14,9 @@ const renderForm = (props?: Partial<AddExpenseListFormProps>) => {
|
||||
const submitButtonElem = screen.getByText('Добавить');
|
||||
|
||||
return {
|
||||
titleInputElem,
|
||||
submitButtonElem,
|
||||
onSubmit,
|
||||
submitButtonElem,
|
||||
titleInputElem,
|
||||
};
|
||||
};
|
||||
|
||||
@ -42,9 +42,9 @@ describe('Test AddExpensesListForm', () => {
|
||||
|
||||
test('should call onSubmit with values', async () => {
|
||||
const {
|
||||
titleInputElem,
|
||||
submitButtonElem,
|
||||
onSubmit,
|
||||
submitButtonElem,
|
||||
titleInputElem,
|
||||
} = renderForm();
|
||||
|
||||
await userEvent.type(titleInputElem, 'Название списка');
|
||||
|
||||
@ -1,31 +1,31 @@
|
||||
import type {
|
||||
FC,
|
||||
FormEventHandler,
|
||||
FormHTMLAttributes,
|
||||
RefObject,
|
||||
} from 'react';
|
||||
|
||||
import { Input } from '@/shared/ui/Input';
|
||||
|
||||
import classes from './AddExpenseListForm.module.css';
|
||||
|
||||
import type {
|
||||
FormHTMLAttributes,
|
||||
RefObject,
|
||||
FormEventHandler,
|
||||
FC,
|
||||
} from 'react';
|
||||
|
||||
export type AddExpenseListFormValues = {
|
||||
title: string;
|
||||
};
|
||||
|
||||
type BaseFormProps = Omit<FormHTMLAttributes<HTMLFormElement>, 'onSubmit'>;
|
||||
|
||||
export type AddExpenseListFormProps = BaseFormProps & {
|
||||
disabled?: boolean;
|
||||
onSubmit: (data: AddExpenseListFormValues) => Promise<void> | void;
|
||||
ref?: RefObject<HTMLFormElement>;
|
||||
};
|
||||
|
||||
export type AddExpenseListFormValues = {
|
||||
title: string;
|
||||
};
|
||||
|
||||
type BaseFormProps = Omit<FormHTMLAttributes<HTMLFormElement>, 'onSubmit'>;
|
||||
|
||||
const AddExpensesListForm: FC<AddExpenseListFormProps> = (props) => {
|
||||
const {
|
||||
ref,
|
||||
disabled,
|
||||
onSubmit,
|
||||
ref,
|
||||
...restProps
|
||||
} = props;
|
||||
|
||||
@ -45,9 +45,9 @@ const AddExpensesListForm: FC<AddExpenseListFormProps> = (props) => {
|
||||
|
||||
return (
|
||||
<form
|
||||
ref={ref}
|
||||
className={classes.form}
|
||||
onSubmit={onFormSubmitHandler}
|
||||
ref={ref}
|
||||
{...restProps}
|
||||
>
|
||||
<h2>Добавить список расходов</h2>
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
import DeleteExpensesListForm from './DeleteExpensesListForm.ui';
|
||||
|
||||
import type { DeleteExpenseListFormProps } from './DeleteExpensesListForm.ui';
|
||||
|
||||
import DeleteExpensesListForm from './DeleteExpensesListForm.ui';
|
||||
|
||||
const deletingList = {
|
||||
id: '10cc093c-3875-4d33-a40a-df526266e262',
|
||||
title: 'Mock list',
|
||||
items: [],
|
||||
updatedAt: '2025-08-29T07:57:40.503Z',
|
||||
createdAt: '2025-08-29T07:57:40.503Z',
|
||||
id: '10cc093c-3875-4d33-a40a-df526266e262',
|
||||
items: [],
|
||||
title: 'Mock list',
|
||||
updatedAt: '2025-08-29T07:57:40.503Z',
|
||||
};
|
||||
|
||||
const renderForm = (props?: Partial<DeleteExpenseListFormProps>) => {
|
||||
@ -28,8 +28,8 @@ const renderForm = (props?: Partial<DeleteExpenseListFormProps>) => {
|
||||
const submitButtonElem = screen.getByText('Удалить');
|
||||
|
||||
return {
|
||||
submitButtonElem,
|
||||
onSubmit,
|
||||
submitButtonElem,
|
||||
};
|
||||
};
|
||||
|
||||
@ -43,8 +43,8 @@ describe('Test DeleteExpensesListForm', () => {
|
||||
|
||||
test('should call onSubmit with values', async () => {
|
||||
const {
|
||||
submitButtonElem,
|
||||
onSubmit,
|
||||
submitButtonElem,
|
||||
} = renderForm();
|
||||
|
||||
await userEvent.click(submitButtonElem);
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import type { ExpenseList } from '@/entity/expenses/list';
|
||||
import type {
|
||||
FC,
|
||||
FormEventHandler,
|
||||
@ -6,21 +5,23 @@ import type {
|
||||
RefObject,
|
||||
} from 'react';
|
||||
|
||||
type BaseFormProps = Omit<FormHTMLAttributes<HTMLFormElement>, 'onSubmit'>;
|
||||
import type { ExpenseList } from '@/entity/expenses/list';
|
||||
|
||||
export type DeleteExpenseListFormProps = BaseFormProps & {
|
||||
disabled?: boolean;
|
||||
list: ExpenseList;
|
||||
onSubmit?: (list: ExpenseList) => Promise<void> | void;
|
||||
ref?: RefObject<HTMLFormElement>;
|
||||
list: ExpenseList;
|
||||
};
|
||||
|
||||
type BaseFormProps = Omit<FormHTMLAttributes<HTMLFormElement>, 'onSubmit'>;
|
||||
|
||||
const DeleteExpensesListForm: FC<DeleteExpenseListFormProps> = (props) => {
|
||||
const {
|
||||
ref,
|
||||
disabled,
|
||||
onSubmit,
|
||||
list,
|
||||
onSubmit,
|
||||
ref,
|
||||
...restProps
|
||||
} = props;
|
||||
|
||||
@ -30,7 +31,7 @@ const DeleteExpensesListForm: FC<DeleteExpenseListFormProps> = (props) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<form ref={ref} onSubmit={onFormSubmitHandler} {...restProps}>
|
||||
<form onSubmit={onFormSubmitHandler} ref={ref} {...restProps}>
|
||||
<h2>Удалить список расходов</h2>
|
||||
|
||||
<p>
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
import EditExpensesListForm from './EditExpensesListForm.ui';
|
||||
|
||||
import type { EditExpensesListFormProps } from './EditExpensesListForm.ui';
|
||||
|
||||
import EditExpensesListForm from './EditExpensesListForm.ui';
|
||||
|
||||
const editingList = {
|
||||
id: '10cc093c-3875-4d33-a40a-df526266e262',
|
||||
title: 'Mock list',
|
||||
items: [],
|
||||
updatedAt: '2025-08-29T07:57:40.503Z',
|
||||
createdAt: '2025-08-29T07:57:40.503Z',
|
||||
id: '10cc093c-3875-4d33-a40a-df526266e262',
|
||||
items: [],
|
||||
title: 'Mock list',
|
||||
updatedAt: '2025-08-29T07:57:40.503Z',
|
||||
};
|
||||
|
||||
const renderForm = (props?: Partial<EditExpensesListFormProps>) => {
|
||||
@ -29,9 +29,9 @@ const renderForm = (props?: Partial<EditExpensesListFormProps>) => {
|
||||
const submitButtonElem = screen.getByText('Сохранить');
|
||||
|
||||
return {
|
||||
titleInputElem,
|
||||
submitButtonElem,
|
||||
onSubmit,
|
||||
submitButtonElem,
|
||||
titleInputElem,
|
||||
};
|
||||
};
|
||||
|
||||
@ -64,9 +64,9 @@ describe('Test EditExpensesListForm', () => {
|
||||
|
||||
test('should call onSubmit with values', async () => {
|
||||
const {
|
||||
titleInputElem,
|
||||
submitButtonElem,
|
||||
onSubmit,
|
||||
submitButtonElem,
|
||||
titleInputElem,
|
||||
} = renderForm();
|
||||
|
||||
await userEvent.clear(titleInputElem);
|
||||
|
||||
@ -1,8 +1,3 @@
|
||||
import { Input } from '@/shared/ui/Input';
|
||||
|
||||
import classes from './EditExpenseListForm.module.css';
|
||||
|
||||
import type { ExpenseList } from '@/entity/expenses/list';
|
||||
import type {
|
||||
FC,
|
||||
FormEventHandler,
|
||||
@ -10,25 +5,31 @@ import type {
|
||||
RefObject,
|
||||
} from 'react';
|
||||
|
||||
import type { ExpenseList } from '@/entity/expenses/list';
|
||||
|
||||
import { Input } from '@/shared/ui/Input';
|
||||
|
||||
import classes from './EditExpenseListForm.module.css';
|
||||
|
||||
export type EditExpenseListFormValues = {
|
||||
title: string;
|
||||
};
|
||||
|
||||
type BaseFormProps = Omit<FormHTMLAttributes<HTMLFormElement>, 'onSubmit'>;
|
||||
|
||||
export type EditExpensesListFormProps = BaseFormProps & {
|
||||
disabled?: boolean;
|
||||
list: ExpenseList;
|
||||
onSubmit: (data: EditExpenseListFormValues) => Promise<void> | void;
|
||||
ref?: RefObject<HTMLFormElement>;
|
||||
list: ExpenseList;
|
||||
};
|
||||
|
||||
type BaseFormProps = Omit<FormHTMLAttributes<HTMLFormElement>, 'onSubmit'>;
|
||||
|
||||
const EditExpensesListForm: FC<EditExpensesListFormProps> = (props) => {
|
||||
const {
|
||||
ref,
|
||||
disabled,
|
||||
onSubmit,
|
||||
list,
|
||||
onSubmit,
|
||||
ref,
|
||||
...restProps
|
||||
} = props;
|
||||
|
||||
@ -46,9 +47,9 @@ const EditExpensesListForm: FC<EditExpensesListFormProps> = (props) => {
|
||||
|
||||
return (
|
||||
<form
|
||||
ref={ref}
|
||||
className={classes.form}
|
||||
onSubmit={onFormSubmitHandler}
|
||||
ref={ref}
|
||||
{...restProps}
|
||||
>
|
||||
<h2>Редактировать список расходов</h2>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
import type { paths } from '@/shared/api/schema';
|
||||
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
export type AddIncomeItemBody = paths['/incomes/list/{id}/items']['post']['requestBody']['content']['application/json'];
|
||||
export type AddIncomeItemPath = paths['/incomes/list/{id}/items']['post']['parameters']['path'];
|
||||
export type AddIncomeItemSuccessResponse = paths['/incomes/list/{id}/items']['post']['responses']['200']['content']['application/json'];
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
import type { paths } from '@/shared/api/schema';
|
||||
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
export type DeleteIncomeItemPath = paths['/incomes/list/{listId}/items/{id}']['delete']['parameters']['path'];
|
||||
export type DeleteIncomeItemSuccessResponse = paths['/incomes/list/{id}/items']['post']['responses']['200']['content']['application/json'];
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
import type { paths } from '@/shared/api/schema';
|
||||
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
export type EditIncomeItemBody = paths['/incomes/list/{listId}/items/{id}']['patch']['requestBody']['content']['application/json'];
|
||||
export type EditIncomeItemPath = paths['/incomes/list/{listId}/items/{id}']['patch']['parameters']['path'];
|
||||
export type EditIncomeItemSuccessResponse = paths['/incomes/list/{listId}/items/{id}']['patch']['responses']['200']['content']['application/json'];
|
||||
|
||||
@ -2,10 +2,10 @@ import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
|
||||
import { QueryKeys } from '@/shared/api/queryKeys';
|
||||
|
||||
import { deleteIncomeItem } from '../api/deleteIncomeItem';
|
||||
|
||||
import type { DeleteIncomeItemPath } from '../api/deleteIncomeItem';
|
||||
|
||||
import { deleteIncomeItem } from '../api/deleteIncomeItem';
|
||||
|
||||
export const useDeleteIncomeItem = (path: DeleteIncomeItemPath) => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
export type { AddIncomeItemBody, AddIncomeItemPath, AddIncomeItemSuccessResponse } from './api/addIncomeItem';
|
||||
export type { DeleteIncomeItemPath, DeleteIncomeItemSuccessResponse } from './api/deleteIncomeItem';
|
||||
export type { EditIncomeItemBody, EditIncomeItemPath, EditIncomeItemSuccessResponse } from './api/editIncomeItem';
|
||||
|
||||
export { useAddIncomeItem } from './hooks/useAddIncomeItem';
|
||||
export { useDeleteIncomeItem } from './hooks/useDeleteIncomeItem';
|
||||
export { useEditIncomeItem } from './hooks/useEditIncomeItem';
|
||||
|
||||
export type { AddIncomeItemPath, AddIncomeItemBody, AddIncomeItemSuccessResponse } from './api/addIncomeItem';
|
||||
export type { DeleteIncomeItemPath, DeleteIncomeItemSuccessResponse } from './api/deleteIncomeItem';
|
||||
export type { EditIncomeItemPath, EditIncomeItemBody, EditIncomeItemSuccessResponse } from './api/editIncomeItem';
|
||||
|
||||
export type { IncomeListItem } from './types';
|
||||
export type { AddIncomeItemFormValues } from './ui/AddIncomeItemForm/AddIncomeItemForm.ui';
|
||||
|
||||
export { default as AddIncomeItemForm } from './ui/AddIncomeItemForm/AddIncomeItemForm.ui';
|
||||
|
||||
export type { EditIncomeItemFormValues } from './ui/EditIncomeItemForm/EditIncomeItemForm.ui';
|
||||
export { default as EditIncomeItemForm } from './ui/EditIncomeItemForm/EditIncomeItemForm.ui';
|
||||
|
||||
export { default as DeleteIncomeItemForm } from './ui/DeleteIncomeItemForm/DeleteIncomeItemForm.ui';
|
||||
|
||||
export type { IncomeListItem } from './types';
|
||||
export type { EditIncomeItemFormValues } from './ui/EditIncomeItemForm/EditIncomeItemForm.ui';
|
||||
|
||||
export { default as EditIncomeItemForm } from './ui/EditIncomeItemForm/EditIncomeItemForm.ui';
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
import AddIncomeItemForm from './AddIncomeItemForm.ui';
|
||||
|
||||
import type { AddIncomeItemFormProps } from './AddIncomeItemForm.ui';
|
||||
|
||||
import AddIncomeItemForm from './AddIncomeItemForm.ui';
|
||||
|
||||
const renderForm = (props?: Partial<AddIncomeItemFormProps>) => {
|
||||
const onSubmit = jest.fn();
|
||||
|
||||
@ -17,12 +17,12 @@ const renderForm = (props?: Partial<AddIncomeItemFormProps>) => {
|
||||
const submitButtonElem = screen.getByText('Добавить');
|
||||
|
||||
return {
|
||||
titleInputElem,
|
||||
descriptionInputElem,
|
||||
dateInputElem,
|
||||
amountInputElem,
|
||||
submitButtonElem,
|
||||
dateInputElem,
|
||||
descriptionInputElem,
|
||||
onSubmit,
|
||||
submitButtonElem,
|
||||
titleInputElem,
|
||||
};
|
||||
};
|
||||
|
||||
@ -48,12 +48,12 @@ describe('Test AddIncomeItemForm', () => {
|
||||
|
||||
test('should call onSubmit with values', async () => {
|
||||
const {
|
||||
titleInputElem,
|
||||
descriptionInputElem,
|
||||
dateInputElem,
|
||||
amountInputElem,
|
||||
submitButtonElem,
|
||||
dateInputElem,
|
||||
descriptionInputElem,
|
||||
onSubmit,
|
||||
submitButtonElem,
|
||||
titleInputElem,
|
||||
} = renderForm();
|
||||
|
||||
await userEvent.type(titleInputElem, 'Название элемента');
|
||||
@ -65,11 +65,11 @@ describe('Test AddIncomeItemForm', () => {
|
||||
|
||||
expect(onSubmit).toHaveBeenCalledTimes(1);
|
||||
expect(onSubmit).toHaveBeenCalledWith({
|
||||
title: 'Название элемента',
|
||||
description: 'Описание элемента',
|
||||
date: '2025-08-29T00:00:00.000Z',
|
||||
amount: 12,
|
||||
currency: 'RUB',
|
||||
date: '2025-08-29T00:00:00.000Z',
|
||||
description: 'Описание элемента',
|
||||
title: 'Название элемента',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,7 +1,3 @@
|
||||
import { Input } from '@/shared/ui/Input';
|
||||
|
||||
import classes from './AddIncomeItemForm.module.css';
|
||||
|
||||
import type {
|
||||
FC,
|
||||
FormEventHandler,
|
||||
@ -9,15 +5,9 @@ import type {
|
||||
RefObject,
|
||||
} from 'react';
|
||||
|
||||
export type AddIncomeItemFormValues = {
|
||||
title: string;
|
||||
description: string;
|
||||
date: string;
|
||||
amount: number;
|
||||
currency: string;
|
||||
};
|
||||
import { Input } from '@/shared/ui/Input';
|
||||
|
||||
type BaseFormProps = Omit<FormHTMLAttributes<HTMLFormElement>, 'onSubmit'>;
|
||||
import classes from './AddIncomeItemForm.module.css';
|
||||
|
||||
export type AddIncomeItemFormProps = BaseFormProps & {
|
||||
disabled?: boolean;
|
||||
@ -25,6 +15,16 @@ export type AddIncomeItemFormProps = BaseFormProps & {
|
||||
ref?: RefObject<HTMLFormElement>;
|
||||
};
|
||||
|
||||
export type AddIncomeItemFormValues = {
|
||||
amount: number;
|
||||
currency: string;
|
||||
date: string;
|
||||
description: string;
|
||||
title: string;
|
||||
};
|
||||
|
||||
type BaseFormProps = Omit<FormHTMLAttributes<HTMLFormElement>, 'onSubmit'>;
|
||||
|
||||
const AddIncomeItemForm: FC<AddIncomeItemFormProps> = (props) => {
|
||||
const {
|
||||
disabled,
|
||||
@ -45,29 +45,29 @@ const AddIncomeItemForm: FC<AddIncomeItemFormProps> = (props) => {
|
||||
|
||||
if (typeof title === 'string' && typeof date === 'string' && typeof amount === 'string' && typeof description === 'string') {
|
||||
onSubmit?.({
|
||||
title,
|
||||
date: new Date(date).toISOString(),
|
||||
amount: Number(amount),
|
||||
description,
|
||||
currency: 'RUB',
|
||||
date: new Date(date).toISOString(),
|
||||
description,
|
||||
title,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<form
|
||||
ref={ref}
|
||||
className={classes.form}
|
||||
onSubmit={onFormSubmitHandler}
|
||||
ref={ref}
|
||||
{...formProps}
|
||||
>
|
||||
<h2>Добавить список доходов</h2>
|
||||
|
||||
<Input
|
||||
required
|
||||
disabled={disabled}
|
||||
label="Название"
|
||||
name="title"
|
||||
required
|
||||
/>
|
||||
|
||||
<Input
|
||||
@ -77,18 +77,18 @@ const AddIncomeItemForm: FC<AddIncomeItemFormProps> = (props) => {
|
||||
/>
|
||||
|
||||
<Input
|
||||
required
|
||||
disabled={disabled}
|
||||
label="Дата"
|
||||
name="date"
|
||||
required
|
||||
type="date"
|
||||
/>
|
||||
|
||||
<Input
|
||||
required
|
||||
disabled={disabled}
|
||||
label="Сумма"
|
||||
name="amount"
|
||||
required
|
||||
step="0.01"
|
||||
type="number"
|
||||
/>
|
||||
|
||||
@ -1,20 +1,20 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
import DeleteIncomeItemForm from './DeleteIncomeItemForm.ui';
|
||||
|
||||
import type { DeleteIncomeItemFormProps } from './DeleteIncomeItemForm.ui';
|
||||
|
||||
import DeleteIncomeItemForm from './DeleteIncomeItemForm.ui';
|
||||
|
||||
const deletingItem = {
|
||||
id: '51a44dc0-597b-49b9-85bb-e0bcd42db3f6',
|
||||
title: 'Mock item',
|
||||
amount: 12,
|
||||
updatedAt: '2025-08-29T07:57:40.503Z',
|
||||
incomeListId: '10cc093c-3875-4d33-a40a-df526266e262',
|
||||
createdAt: '2025-08-29T07:57:40.503Z',
|
||||
currency: 'RUB',
|
||||
date: '2025-08-22T00:00:03.000Z',
|
||||
description: 'Mock description',
|
||||
id: '51a44dc0-597b-49b9-85bb-e0bcd42db3f6',
|
||||
incomeListId: '10cc093c-3875-4d33-a40a-df526266e262',
|
||||
title: 'Mock item',
|
||||
updatedAt: '2025-08-29T07:57:40.503Z',
|
||||
};
|
||||
|
||||
const renderForm = (props?: Partial<DeleteIncomeItemFormProps>) => {
|
||||
@ -32,8 +32,8 @@ const renderForm = (props?: Partial<DeleteIncomeItemFormProps>) => {
|
||||
const submitButtonElem = screen.getByText('Удалить');
|
||||
|
||||
return {
|
||||
submitButtonElem,
|
||||
onSubmit,
|
||||
submitButtonElem,
|
||||
};
|
||||
};
|
||||
|
||||
@ -47,8 +47,8 @@ describe('Test DeleteIncomeItemForm', () => {
|
||||
|
||||
test('should call onSubmit with values', async () => {
|
||||
const {
|
||||
submitButtonElem,
|
||||
onSubmit,
|
||||
submitButtonElem,
|
||||
} = renderForm();
|
||||
|
||||
await userEvent.click(submitButtonElem);
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import type { IncomeListItem } from '../../types';
|
||||
import type {
|
||||
FC,
|
||||
FormEventHandler,
|
||||
@ -6,21 +5,23 @@ import type {
|
||||
RefObject,
|
||||
} from 'react';
|
||||
|
||||
type BaseFormProps = Omit<FormHTMLAttributes<HTMLFormElement>, 'onSubmit'>;
|
||||
import type { IncomeListItem } from '../../types';
|
||||
|
||||
export type DeleteIncomeItemFormProps = BaseFormProps & {
|
||||
disabled?: boolean;
|
||||
item: IncomeListItem;
|
||||
onSubmit?: (item: IncomeListItem) => Promise<void> | void;
|
||||
disabled?: boolean;
|
||||
ref?: RefObject<HTMLFormElement>;
|
||||
};
|
||||
|
||||
type BaseFormProps = Omit<FormHTMLAttributes<HTMLFormElement>, 'onSubmit'>;
|
||||
|
||||
const DeleteIncomeItemForm: FC<DeleteIncomeItemFormProps> = (props) => {
|
||||
const {
|
||||
disabled,
|
||||
item,
|
||||
onSubmit,
|
||||
ref,
|
||||
disabled,
|
||||
...restProps
|
||||
} = props;
|
||||
const onFormSubmitHandler: FormEventHandler<HTMLFormElement> = (event) => {
|
||||
@ -29,7 +30,7 @@ const DeleteIncomeItemForm: FC<DeleteIncomeItemFormProps> = (props) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<form ref={ref} onSubmit={onFormSubmitHandler} {...restProps}>
|
||||
<form onSubmit={onFormSubmitHandler} ref={ref} {...restProps}>
|
||||
<h2>Удалить элемент ?</h2>
|
||||
|
||||
<button disabled={disabled} type="submit">Удалить</button>
|
||||
|
||||
@ -1,21 +1,21 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
import EditIncomeItemForm from './EditIncomeItemForm.ui';
|
||||
|
||||
import type { EditIncomeItemFormProps } from './EditIncomeItemForm.ui';
|
||||
|
||||
import EditIncomeItemForm from './EditIncomeItemForm.ui';
|
||||
|
||||
const editingItem = {
|
||||
id: '51a44dc0-597b-49b9-85bb-e0bcd42db3f6',
|
||||
title: 'Mock item',
|
||||
amount: 12,
|
||||
count: 12,
|
||||
updatedAt: '2025-08-29T07:57:40.503Z',
|
||||
incomeListId: '10cc093c-3875-4d33-a40a-df526266e262',
|
||||
createdAt: '2025-08-29T07:57:40.503Z',
|
||||
currency: 'RUB',
|
||||
date: '2025-08-22T00:00:03.000Z',
|
||||
description: 'Mock description',
|
||||
id: '51a44dc0-597b-49b9-85bb-e0bcd42db3f6',
|
||||
incomeListId: '10cc093c-3875-4d33-a40a-df526266e262',
|
||||
title: 'Mock item',
|
||||
updatedAt: '2025-08-29T07:57:40.503Z',
|
||||
};
|
||||
|
||||
const renderForm = (props?: Partial<EditIncomeItemFormProps>) => {
|
||||
@ -37,12 +37,12 @@ const renderForm = (props?: Partial<EditIncomeItemFormProps>) => {
|
||||
const submitButtonElem = screen.getByText('Сохранить');
|
||||
|
||||
return {
|
||||
titleInputElem,
|
||||
descriptionInputElem,
|
||||
dateInputElem,
|
||||
amountInputElem,
|
||||
submitButtonElem,
|
||||
dateInputElem,
|
||||
descriptionInputElem,
|
||||
onSubmit,
|
||||
submitButtonElem,
|
||||
titleInputElem,
|
||||
};
|
||||
};
|
||||
|
||||
@ -56,10 +56,10 @@ describe('Test EditIncomeItemForm', () => {
|
||||
|
||||
test('should inputs have default value', () => {
|
||||
const {
|
||||
titleInputElem,
|
||||
descriptionInputElem,
|
||||
dateInputElem,
|
||||
amountInputElem,
|
||||
dateInputElem,
|
||||
descriptionInputElem,
|
||||
titleInputElem,
|
||||
} = renderForm();
|
||||
expect(titleInputElem).toHaveValue('Mock item');
|
||||
expect(descriptionInputElem).toHaveValue('Mock description');
|
||||
@ -81,12 +81,12 @@ describe('Test EditIncomeItemForm', () => {
|
||||
|
||||
test('should call onSubmit with values', async () => {
|
||||
const {
|
||||
titleInputElem,
|
||||
descriptionInputElem,
|
||||
dateInputElem,
|
||||
amountInputElem,
|
||||
submitButtonElem,
|
||||
dateInputElem,
|
||||
descriptionInputElem,
|
||||
onSubmit,
|
||||
submitButtonElem,
|
||||
titleInputElem,
|
||||
} = renderForm();
|
||||
|
||||
await userEvent.clear(titleInputElem);
|
||||
@ -105,11 +105,11 @@ describe('Test EditIncomeItemForm', () => {
|
||||
|
||||
expect(onSubmit).toHaveBeenCalledTimes(1);
|
||||
expect(onSubmit).toHaveBeenCalledWith({
|
||||
title: 'Название элемента',
|
||||
description: 'Описание элемента',
|
||||
date: '2025-08-29T00:00:00.000Z',
|
||||
amount: 12,
|
||||
currency: 'RUB',
|
||||
date: '2025-08-29T00:00:00.000Z',
|
||||
description: 'Описание элемента',
|
||||
title: 'Название элемента',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,8 +1,3 @@
|
||||
import { Input } from '@/shared/ui/Input';
|
||||
|
||||
import classes from './EditIncomeItemForm.module.css';
|
||||
|
||||
import type { IncomeListItem } from '../../types';
|
||||
import type {
|
||||
FC,
|
||||
FormEventHandler,
|
||||
@ -10,28 +5,34 @@ import type {
|
||||
RefObject,
|
||||
} from 'react';
|
||||
|
||||
export type EditIncomeItemFormValues = {
|
||||
title: string;
|
||||
description: string;
|
||||
date: string;
|
||||
amount: number;
|
||||
currency: string;
|
||||
};
|
||||
import { Input } from '@/shared/ui/Input';
|
||||
|
||||
import type { IncomeListItem } from '../../types';
|
||||
|
||||
import classes from './EditIncomeItemForm.module.css';
|
||||
|
||||
type BaseFormProps = Omit<FormHTMLAttributes<HTMLFormElement>, 'onSubmit'>;
|
||||
export type EditIncomeItemFormProps = BaseFormProps & {
|
||||
disabled?: boolean;
|
||||
item: IncomeListItem;
|
||||
onSubmit?: (data: EditIncomeItemFormValues) => Promise<void> | void;
|
||||
ref?: RefObject<HTMLFormElement>;
|
||||
item: IncomeListItem;
|
||||
};
|
||||
|
||||
export type EditIncomeItemFormValues = {
|
||||
amount: number;
|
||||
currency: string;
|
||||
date: string;
|
||||
description: string;
|
||||
title: string;
|
||||
};
|
||||
type BaseFormProps = Omit<FormHTMLAttributes<HTMLFormElement>, 'onSubmit'>;
|
||||
|
||||
const EditIncomeItemForm: FC<EditIncomeItemFormProps> = (props) => {
|
||||
const {
|
||||
disabled,
|
||||
item,
|
||||
onSubmit,
|
||||
ref,
|
||||
item,
|
||||
...formProps
|
||||
} = props;
|
||||
|
||||
@ -47,20 +48,20 @@ const EditIncomeItemForm: FC<EditIncomeItemFormProps> = (props) => {
|
||||
|
||||
if (typeof title === 'string' && typeof date === 'string' && typeof amount === 'string' && typeof description === 'string') {
|
||||
await onSubmit?.({
|
||||
title,
|
||||
date: new Date(date).toISOString(),
|
||||
amount: Number(amount),
|
||||
description,
|
||||
currency: 'RUB',
|
||||
date: new Date(date).toISOString(),
|
||||
description,
|
||||
title,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<form
|
||||
ref={ref}
|
||||
className={classes.form}
|
||||
onSubmit={onFormSubmitHandler}
|
||||
ref={ref}
|
||||
{...formProps}
|
||||
>
|
||||
<h2>Изменить доход</h2>
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
import type { paths } from '@/shared/api/schema';
|
||||
|
||||
export type AddIncomeListPath = paths['/incomes/list']['post']['parameters']['path'];
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
export type AddIncomeListBody = paths['/incomes/list']['post']['requestBody']['content']['application/json'];
|
||||
export type AddIncomeListPath = paths['/incomes/list']['post']['parameters']['path'];
|
||||
export type AddIncomeListSuccessResponse = paths['/incomes/list']['post']['responses']['200']['content']['application/json'];
|
||||
|
||||
export async function addIncomeList(data: AddIncomeListBody) {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
import type { paths } from '@/shared/api/schema';
|
||||
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
export type DeleteIncomeListPath = paths['/incomes/list/{id}']['delete']['parameters']['path'];
|
||||
export type DeleteIncomeListSuccessResponse = paths['/incomes/list/{id}']['delete']['responses']['200']['content']['application/json'];
|
||||
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
import type { paths } from '@/shared/api/schema';
|
||||
|
||||
export type EditIncomeListPath = paths['/incomes/list/{id}']['patch']['parameters']['path'];
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
export type EditIncomeListBody = paths['/incomes/list/{id}']['patch']['requestBody']['content']['application/json'];
|
||||
export type EditIncomeListPath = paths['/incomes/list/{id}']['patch']['parameters']['path'];
|
||||
export type EditIncomeListSuccessResponse = paths['/incomes/list/{id}']['patch']['responses']['200']['content']['application/json'];
|
||||
|
||||
export async function editIncomeList({ data, path }: {
|
||||
path: EditIncomeListPath;
|
||||
data: EditIncomeListBody;
|
||||
path: EditIncomeListPath;
|
||||
}) {
|
||||
const { id } = path;
|
||||
const { data: result } = await api.patch<EditIncomeListSuccessResponse>(`/incomes/list/${id}`, data);
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
import type { paths } from '@/shared/api/schema';
|
||||
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
type IncomeListPath = paths['/incomes/list/{id}']['get']['parameters']['path'];
|
||||
type IncomeListResponse = paths['/incomes/list/{id}']['get']['responses']['200']['content']['application/json'];
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
import type { paths } from '@/shared/api/schema';
|
||||
|
||||
import { api } from '@/shared/api/client';
|
||||
|
||||
type IncomesListResponse = paths['/incomes/list']['get']['responses']['200']['content']['application/json'];
|
||||
|
||||
export async function getIncomeLists() {
|
||||
|
||||
@ -2,10 +2,10 @@ import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { QueryKeys } from '@/shared/api/queryKeys';
|
||||
|
||||
import { getIncomeList } from '../api/getIncomeList';
|
||||
|
||||
import type { IncomeList } from '../types';
|
||||
|
||||
import { getIncomeList } from '../api/getIncomeList';
|
||||
|
||||
export const useIncomeList = (id: IncomeList['id']) => useQuery({
|
||||
queryFn: async () => getIncomeList({ id }),
|
||||
queryKey: [QueryKeys.IncomesList, id],
|
||||
|
||||
@ -1,10 +1,14 @@
|
||||
export type { IncomeList } from './types';
|
||||
export { useDeleteIncomesList } from './hooks/useDeleteIncomesList';
|
||||
export { useAddIncomesList } from './hooks/useAddIncomesList';
|
||||
export { useIncomesList } from './hooks/useIncomesList';
|
||||
export { useEditIncomesList } from './hooks/useEditIncomesList';
|
||||
export type { AddIncomeListBody, AddIncomeListPath, AddIncomeListSuccessResponse } from './api/addIncomeList';
|
||||
export type { DeleteIncomeListPath, DeleteIncomeListSuccessResponse } from './api/deleteIncomeList';
|
||||
export type { EditIncomeListBody, EditIncomeListPath, EditIncomeListSuccessResponse } from './api/editIncomeList';
|
||||
|
||||
export { useAddIncomesList } from './hooks/useAddIncomesList';
|
||||
export { useDeleteIncomesList } from './hooks/useDeleteIncomesList';
|
||||
export { useEditIncomesList } from './hooks/useEditIncomesList';
|
||||
export { useIncomeList } from './hooks/useIncomeList';
|
||||
export { useIncomesList } from './hooks/useIncomesList';
|
||||
|
||||
export type { IncomeList } from './types';
|
||||
|
||||
export type { AddIncomeListFormValues } from './ui/AddIncomeListForm/ui/AddIncomeListForm.ui';
|
||||
export { default as AddIncomeListForm } from './ui/AddIncomeListForm/ui/AddIncomeListForm.ui';
|
||||
@ -13,7 +17,3 @@ export { default as DeleteIncomeListForm } from './ui/DeleteIncomeListForm/ui/De
|
||||
|
||||
export type { EditIncomeListFormValues } from './ui/EditIncomeListForm/ui/EditIncomeListForm.ui';
|
||||
export { default as EditIncomeListForm } from './ui/EditIncomeListForm/ui/EditIncomeListForm.ui';
|
||||
|
||||
export type { AddIncomeListBody, AddIncomeListPath, AddIncomeListSuccessResponse } from './api/addIncomeList';
|
||||
export type { DeleteIncomeListPath, DeleteIncomeListSuccessResponse } from './api/deleteIncomeList';
|
||||
export type { EditIncomeListBody, EditIncomeListPath, EditIncomeListSuccessResponse } from './api/editIncomeList';
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
import AddIncomeListForm from './AddIncomeListForm.ui';
|
||||
|
||||
import type { AddIncomeListFormProps } from './AddIncomeListForm.ui';
|
||||
|
||||
import AddIncomeListForm from './AddIncomeListForm.ui';
|
||||
|
||||
const renderForm = (props?: Partial<AddIncomeListFormProps>) => {
|
||||
const onSubmit = jest.fn();
|
||||
|
||||
@ -14,9 +14,9 @@ const renderForm = (props?: Partial<AddIncomeListFormProps>) => {
|
||||
const submitButtonElem = screen.getByText('Добавить');
|
||||
|
||||
return {
|
||||
titleInputElem,
|
||||
submitButtonElem,
|
||||
onSubmit,
|
||||
submitButtonElem,
|
||||
titleInputElem,
|
||||
};
|
||||
};
|
||||
|
||||
@ -42,9 +42,9 @@ describe('Test AddIncomeListForm', () => {
|
||||
|
||||
test('should call onSubmit with values', async () => {
|
||||
const {
|
||||
titleInputElem,
|
||||
submitButtonElem,
|
||||
onSubmit,
|
||||
submitButtonElem,
|
||||
titleInputElem,
|
||||
} = renderForm();
|
||||
|
||||
await userEvent.type(titleInputElem, 'Название списка');
|
||||
|
||||
@ -1,31 +1,31 @@
|
||||
import type {
|
||||
FC,
|
||||
FormEventHandler,
|
||||
FormHTMLAttributes,
|
||||
RefObject,
|
||||
} from 'react';
|
||||
|
||||
import { Input } from '@/shared/ui/Input';
|
||||
|
||||
import classes from './AddIncomeListForm.module.css';
|
||||
|
||||
import type {
|
||||
FormHTMLAttributes,
|
||||
RefObject,
|
||||
FormEventHandler,
|
||||
FC,
|
||||
} from 'react';
|
||||
|
||||
export type AddIncomeListFormValues = {
|
||||
title: string;
|
||||
};
|
||||
|
||||
type BaseFormProps = Omit<FormHTMLAttributes<HTMLFormElement>, 'onSubmit'>;
|
||||
|
||||
export type AddIncomeListFormProps = BaseFormProps & {
|
||||
disabled?: boolean;
|
||||
onSubmit: (data: AddIncomeListFormValues) => Promise<void> | void;
|
||||
ref?: RefObject<HTMLFormElement>;
|
||||
};
|
||||
|
||||
export type AddIncomeListFormValues = {
|
||||
title: string;
|
||||
};
|
||||
|
||||
type BaseFormProps = Omit<FormHTMLAttributes<HTMLFormElement>, 'onSubmit'>;
|
||||
|
||||
const AddIncomeListForm: FC<AddIncomeListFormProps> = (props) => {
|
||||
const {
|
||||
ref,
|
||||
disabled,
|
||||
onSubmit,
|
||||
ref,
|
||||
...restProps
|
||||
} = props;
|
||||
|
||||
@ -45,9 +45,9 @@ const AddIncomeListForm: FC<AddIncomeListFormProps> = (props) => {
|
||||
|
||||
return (
|
||||
<form
|
||||
ref={ref}
|
||||
className={classes.form}
|
||||
onSubmit={onFormSubmitHandler}
|
||||
ref={ref}
|
||||
{...restProps}
|
||||
>
|
||||
<h2>Добавить список доходов</h2>
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
import DeleteIncomeListForm from './DeleteIncomeListForm.ui';
|
||||
|
||||
import type { DeleteIncomeListFormProps } from './DeleteIncomeListForm.ui';
|
||||
|
||||
import DeleteIncomeListForm from './DeleteIncomeListForm.ui';
|
||||
|
||||
const deletingList = {
|
||||
id: '10cc093c-3875-4d33-a40a-df526266e262',
|
||||
title: 'Mock list',
|
||||
items: [],
|
||||
updatedAt: '2025-08-29T07:57:40.503Z',
|
||||
createdAt: '2025-08-29T07:57:40.503Z',
|
||||
id: '10cc093c-3875-4d33-a40a-df526266e262',
|
||||
items: [],
|
||||
title: 'Mock list',
|
||||
updatedAt: '2025-08-29T07:57:40.503Z',
|
||||
};
|
||||
|
||||
const renderForm = (props?: Partial<DeleteIncomeListFormProps>) => {
|
||||
@ -28,8 +28,8 @@ const renderForm = (props?: Partial<DeleteIncomeListFormProps>) => {
|
||||
const submitButtonElem = screen.getByText('Удалить');
|
||||
|
||||
return {
|
||||
submitButtonElem,
|
||||
onSubmit,
|
||||
submitButtonElem,
|
||||
};
|
||||
};
|
||||
|
||||
@ -43,8 +43,8 @@ describe('Test DeleteIncomeListForm', () => {
|
||||
|
||||
test('should call onSubmit with values', async () => {
|
||||
const {
|
||||
submitButtonElem,
|
||||
onSubmit,
|
||||
submitButtonElem,
|
||||
} = renderForm();
|
||||
|
||||
await userEvent.click(submitButtonElem);
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import type { IncomeList } from '../../../types';
|
||||
import type {
|
||||
FC,
|
||||
FormEventHandler,
|
||||
@ -6,21 +5,23 @@ import type {
|
||||
RefObject,
|
||||
} from 'react';
|
||||
|
||||
type BaseFormProps = Omit<FormHTMLAttributes<HTMLFormElement>, 'onSubmit'>;
|
||||
import type { IncomeList } from '../../../types';
|
||||
|
||||
export type DeleteIncomeListFormProps = BaseFormProps & {
|
||||
disabled?: boolean;
|
||||
list: IncomeList;
|
||||
onSubmit?: (list: IncomeList) => Promise<void> | void;
|
||||
ref?: RefObject<HTMLFormElement>;
|
||||
list: IncomeList;
|
||||
};
|
||||
|
||||
type BaseFormProps = Omit<FormHTMLAttributes<HTMLFormElement>, 'onSubmit'>;
|
||||
|
||||
const DeleteIncomeListForm: FC<DeleteIncomeListFormProps> = (props) => {
|
||||
const {
|
||||
ref,
|
||||
disabled,
|
||||
onSubmit,
|
||||
list,
|
||||
onSubmit,
|
||||
ref,
|
||||
...restProps
|
||||
} = props;
|
||||
|
||||
@ -30,7 +31,7 @@ const DeleteIncomeListForm: FC<DeleteIncomeListFormProps> = (props) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<form ref={ref} onSubmit={onFormSubmitHandler} {...restProps}>
|
||||
<form onSubmit={onFormSubmitHandler} ref={ref} {...restProps}>
|
||||
<h2>Удалить список доходов</h2>
|
||||
|
||||
<p>
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
import EditIncomeListForm from './EditIncomeListForm.ui';
|
||||
|
||||
import type { EditExpensesListFormProps } from './EditIncomeListForm.ui';
|
||||
|
||||
import EditIncomeListForm from './EditIncomeListForm.ui';
|
||||
|
||||
const editingList = {
|
||||
id: '10cc093c-3875-4d33-a40a-df526266e262',
|
||||
title: 'Mock list',
|
||||
items: [],
|
||||
updatedAt: '2025-08-29T07:57:40.503Z',
|
||||
createdAt: '2025-08-29T07:57:40.503Z',
|
||||
id: '10cc093c-3875-4d33-a40a-df526266e262',
|
||||
items: [],
|
||||
title: 'Mock list',
|
||||
updatedAt: '2025-08-29T07:57:40.503Z',
|
||||
};
|
||||
|
||||
const renderForm = (props?: Partial<EditExpensesListFormProps>) => {
|
||||
@ -29,9 +29,9 @@ const renderForm = (props?: Partial<EditExpensesListFormProps>) => {
|
||||
const submitButtonElem = screen.getByText('Сохранить');
|
||||
|
||||
return {
|
||||
titleInputElem,
|
||||
submitButtonElem,
|
||||
onSubmit,
|
||||
submitButtonElem,
|
||||
titleInputElem,
|
||||
};
|
||||
};
|
||||
|
||||
@ -64,9 +64,9 @@ describe('Test EditIncomeListForm', () => {
|
||||
|
||||
test('should call onSubmit with values', async () => {
|
||||
const {
|
||||
titleInputElem,
|
||||
submitButtonElem,
|
||||
onSubmit,
|
||||
submitButtonElem,
|
||||
titleInputElem,
|
||||
} = renderForm();
|
||||
|
||||
await userEvent.clear(titleInputElem);
|
||||
|
||||
@ -1,8 +1,3 @@
|
||||
import { Input } from '@/shared/ui/Input';
|
||||
|
||||
import classes from './EditIncomeListForm.module.css';
|
||||
|
||||
import type { IncomeList } from '../../../types';
|
||||
import type {
|
||||
FC,
|
||||
FormEventHandler,
|
||||
@ -10,25 +5,31 @@ import type {
|
||||
RefObject,
|
||||
} from 'react';
|
||||
|
||||
import { Input } from '@/shared/ui/Input';
|
||||
|
||||
import type { IncomeList } from '../../../types';
|
||||
|
||||
import classes from './EditIncomeListForm.module.css';
|
||||
|
||||
export type EditExpensesListFormProps = BaseFormProps & {
|
||||
disabled?: boolean;
|
||||
list: IncomeList;
|
||||
onSubmit: (data: EditIncomeListFormValues) => Promise<void> | void;
|
||||
ref?: RefObject<HTMLFormElement>;
|
||||
};
|
||||
|
||||
export type EditIncomeListFormValues = {
|
||||
title: string;
|
||||
};
|
||||
|
||||
type BaseFormProps = Omit<FormHTMLAttributes<HTMLFormElement>, 'onSubmit'>;
|
||||
|
||||
export type EditExpensesListFormProps = BaseFormProps & {
|
||||
disabled?: boolean;
|
||||
onSubmit: (data: EditIncomeListFormValues) => Promise<void> | void;
|
||||
ref?: RefObject<HTMLFormElement>;
|
||||
list: IncomeList;
|
||||
};
|
||||
|
||||
const EditExpensesListForm: FC<EditExpensesListFormProps> = (props) => {
|
||||
const {
|
||||
ref,
|
||||
disabled,
|
||||
onSubmit,
|
||||
list,
|
||||
onSubmit,
|
||||
ref,
|
||||
...restProps
|
||||
} = props;
|
||||
|
||||
@ -46,9 +47,9 @@ const EditExpensesListForm: FC<EditExpensesListFormProps> = (props) => {
|
||||
|
||||
return (
|
||||
<form
|
||||
ref={ref}
|
||||
className={classes.form}
|
||||
onSubmit={onFormSubmitHandler}
|
||||
ref={ref}
|
||||
{...restProps}
|
||||
>
|
||||
<h2>Редактировать список доходов</h2>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { useLogout } from '@/entity/account';
|
||||
|
||||
const LogoutButton = () => {
|
||||
const { mutate: logout, isPending } = useLogout();
|
||||
const { isPending, mutate: logout } = useLogout();
|
||||
|
||||
const onClickHandler = () => {
|
||||
logout();
|
||||
@ -10,8 +10,8 @@ const LogoutButton = () => {
|
||||
return (
|
||||
<button
|
||||
disabled={isPending}
|
||||
type="button"
|
||||
onClick={onClickHandler}
|
||||
type="button"
|
||||
>
|
||||
Logout
|
||||
</button>
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { type MouseEventHandler, useState } from 'react';
|
||||
|
||||
import { useAddBankCard } from '@/entity/cards';
|
||||
|
||||
import type { AddBankCardFormValues } from '@/entity/cards';
|
||||
|
||||
import { useAddBankCard } from '@/entity/cards';
|
||||
|
||||
type UseAddBankCardButtonArgs = {
|
||||
onClick?: MouseEventHandler<HTMLButtonElement>;
|
||||
};
|
||||
@ -12,7 +12,7 @@ export const useAddBankCardButton = (args: UseAddBankCardButtonArgs) => {
|
||||
const { onClick } = args;
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
const { mutateAsync: addBankCardMutation, isPending } = useAddBankCard();
|
||||
const { isPending, mutateAsync: addBankCardMutation } = useAddBankCard();
|
||||
|
||||
const onCloseModalHandler = () => {
|
||||
setIsOpen(false);
|
||||
@ -31,8 +31,8 @@ export const useAddBankCardButton = (args: UseAddBankCardButtonArgs) => {
|
||||
return {
|
||||
isOpen,
|
||||
isPending,
|
||||
onCloseModalHandler,
|
||||
onClickHandler,
|
||||
onCloseModalHandler,
|
||||
onFormSubmitHandler,
|
||||
};
|
||||
};
|
||||
|
||||
@ -1,14 +1,13 @@
|
||||
import { server } from '@mocks/jest/server';
|
||||
import { createReactQueryWrapper } from '@mocks/jest/wrappers';
|
||||
import { render, screen, within } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { http, HttpResponse } from 'msw';
|
||||
|
||||
import { server } from '@mocks/jest/server';
|
||||
import { createReactQueryWrapper } from '@mocks/jest/wrappers';
|
||||
import type { AddBankCardBody, AddBankCardResponse } from '@/entity/cards';
|
||||
|
||||
import AddBankCardButton from './AddBankCardButton.ui';
|
||||
|
||||
import type { AddBankCardBody, AddBankCardResponse } from '@/entity/cards';
|
||||
|
||||
const renderButton = () => {
|
||||
render(
|
||||
<AddBankCardButton data-testid="test-button" />,
|
||||
@ -44,11 +43,11 @@ const submitHandler = (requestSpy: jest.Mock) => http.post<never, AddBankCardBod
|
||||
requestSpy(body);
|
||||
|
||||
return HttpResponse.json({
|
||||
balance: 999,
|
||||
createdAt: '2025-08-29T07:57:40.503Z',
|
||||
id: '10cc093c-3875-4d33-a40a-df526266e262',
|
||||
name: 'Название карты',
|
||||
balance: 999,
|
||||
updatedAt: '2025-08-29T07:57:40.503Z',
|
||||
createdAt: '2025-08-29T07:57:40.503Z',
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@ -1,37 +1,37 @@
|
||||
import type { ButtonHTMLAttributes, FC, Ref } from 'react';
|
||||
|
||||
import { AddBankCardForm } from '@/entity/cards';
|
||||
import { Modal } from '@/shared/ui/Modal';
|
||||
|
||||
import { useAddBankCardButton } from '../hooks/useAddBankCardButton';
|
||||
|
||||
import type { ButtonHTMLAttributes, FC, Ref } from 'react';
|
||||
|
||||
type AddBankCardButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {
|
||||
ref?: Ref<HTMLButtonElement>;
|
||||
};
|
||||
|
||||
const AddBankCardButton: FC<AddBankCardButtonProps> = (props) => {
|
||||
const { ref, onClick, ...restProps } = props;
|
||||
const { onClick, ref, ...restProps } = props;
|
||||
|
||||
const {
|
||||
isOpen,
|
||||
isPending,
|
||||
onCloseModalHandler,
|
||||
onClickHandler,
|
||||
onCloseModalHandler,
|
||||
onFormSubmitHandler,
|
||||
} = useAddBankCardButton({ onClick });
|
||||
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
onClick={onClickHandler}
|
||||
ref={ref}
|
||||
type="button"
|
||||
onClick={onClickHandler}
|
||||
{...restProps}
|
||||
>
|
||||
Добавить
|
||||
</button>
|
||||
|
||||
<Modal open={isOpen} onClose={onCloseModalHandler}>
|
||||
<Modal onClose={onCloseModalHandler} open={isOpen}>
|
||||
<AddBankCardForm disabled={isPending} onSubmit={onFormSubmitHandler} />
|
||||
</Modal>
|
||||
</>
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { useState } from 'react';
|
||||
|
||||
import { useDeleteBankCard } from '@/entity/cards';
|
||||
|
||||
import type { BankCard } from '@/entity/cards';
|
||||
|
||||
import { useDeleteBankCard } from '@/entity/cards';
|
||||
|
||||
type UseDeleteBankCardButtonArgs = {
|
||||
id: BankCard['id'];
|
||||
};
|
||||
@ -12,7 +12,7 @@ export const useDeleteBankCardButton = (args: UseDeleteBankCardButtonArgs) => {
|
||||
const { id } = args;
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
const { mutateAsync: deleteBankCardAsync, isPending } = useDeleteBankCard();
|
||||
const { isPending, mutateAsync: deleteBankCardAsync } = useDeleteBankCard();
|
||||
|
||||
const onClickHandler = () => {
|
||||
setIsOpen(true);
|
||||
|
||||
@ -1,21 +1,20 @@
|
||||
import { server } from '@mocks/jest/server';
|
||||
import { createReactQueryWrapper } from '@mocks/jest/wrappers';
|
||||
import { render, screen, within } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { http, HttpResponse } from 'msw';
|
||||
|
||||
import { server } from '@mocks/jest/server';
|
||||
import { createReactQueryWrapper } from '@mocks/jest/wrappers';
|
||||
|
||||
import DeleteBankCardButton from './DeleteBankCardButton.ui';
|
||||
|
||||
import type { BankCard } from '@/entity/cards';
|
||||
import type { DeleteExpenseListPath } from '@/entity/expenses/list';
|
||||
|
||||
import DeleteBankCardButton from './DeleteBankCardButton.ui';
|
||||
|
||||
const deletingBankCard: BankCard = {
|
||||
balance: 1000,
|
||||
createdAt: '2025-08-29T07:57:40.503Z',
|
||||
id: 'af6da4e1-f24f-4b43-8556-fa885626897d',
|
||||
name: 'Тестовая карта',
|
||||
balance: 1000,
|
||||
updatedAt: '2025-08-29T07:57:40.503Z',
|
||||
createdAt: '2025-08-29T07:57:40.503Z',
|
||||
};
|
||||
|
||||
const renderButton = () => {
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
import type { ButtonHTMLAttributes, FC, Ref } from 'react';
|
||||
|
||||
import type { BankCard } from '@/entity/cards';
|
||||
|
||||
import { DeleteBankCardForm } from '@/entity/cards';
|
||||
import { Modal } from '@/shared/ui/Modal';
|
||||
|
||||
import { useDeleteBankCardButton } from '../hooks/useDeleteBankCardButton';
|
||||
|
||||
import type { BankCard } from '@/entity/cards';
|
||||
import type { ButtonHTMLAttributes, FC, Ref } from 'react';
|
||||
|
||||
export type DeleteBankCardButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {
|
||||
bankCard: BankCard;
|
||||
ref?: Ref<HTMLButtonElement>;
|
||||
@ -14,26 +15,26 @@ export type DeleteBankCardButtonProps = ButtonHTMLAttributes<HTMLButtonElement>
|
||||
const DeleteBankCardButton: FC<DeleteBankCardButtonProps> = (props) => {
|
||||
const {
|
||||
bankCard,
|
||||
ref,
|
||||
onClick,
|
||||
ref,
|
||||
...restProps
|
||||
} = props;
|
||||
|
||||
const {
|
||||
isOpen,
|
||||
isPending,
|
||||
onCloseModalHandler,
|
||||
onClickHandler,
|
||||
onCloseModalHandler,
|
||||
onFormSubmitHandler,
|
||||
} = useDeleteBankCardButton({ id: bankCard.id });
|
||||
|
||||
return (
|
||||
<>
|
||||
<button type="button" onClick={onClickHandler} {...restProps}>
|
||||
<button onClick={onClickHandler} type="button" {...restProps}>
|
||||
Удалить
|
||||
</button>
|
||||
|
||||
<Modal open={isOpen} onClose={onCloseModalHandler}>
|
||||
<Modal onClose={onCloseModalHandler} open={isOpen}>
|
||||
<DeleteBankCardForm
|
||||
bankCard={bankCard}
|
||||
disabled={isPending}
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { useState } from 'react';
|
||||
|
||||
import { useEditBankCard } from '@/entity/cards';
|
||||
|
||||
import type { BankCard, EditBankCardFormValues } from '@/entity/cards';
|
||||
|
||||
import { useEditBankCard } from '@/entity/cards';
|
||||
|
||||
type UseDeleteBankCardButtonArgs = {
|
||||
bankCard: BankCard;
|
||||
};
|
||||
@ -12,7 +12,7 @@ export const useEditBankCardButton = (args: UseDeleteBankCardButtonArgs) => {
|
||||
const { bankCard } = args;
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
const { mutateAsync: editBankCardAsync, isPending } = useEditBankCard();
|
||||
const { isPending, mutateAsync: editBankCardAsync } = useEditBankCard();
|
||||
|
||||
const onClickHandler = () => {
|
||||
setIsOpen(true);
|
||||
|
||||
@ -1,12 +1,9 @@
|
||||
import { server } from '@mocks/jest/server';
|
||||
import { createReactQueryWrapper } from '@mocks/jest/wrappers';
|
||||
import { render, screen, within } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { http, HttpResponse } from 'msw';
|
||||
|
||||
import { server } from '@mocks/jest/server';
|
||||
import { createReactQueryWrapper } from '@mocks/jest/wrappers';
|
||||
|
||||
import EditBankCardButton from './EditBankCardButton.ui';
|
||||
|
||||
import type {
|
||||
BankCard,
|
||||
EditBankCardBody,
|
||||
@ -14,12 +11,14 @@ import type {
|
||||
EditBankCardResponse,
|
||||
} from '@/entity/cards';
|
||||
|
||||
import EditBankCardButton from './EditBankCardButton.ui';
|
||||
|
||||
const editingBankCard: BankCard = {
|
||||
balance: 1000,
|
||||
createdAt: '2025-08-29T07:57:40.503Z',
|
||||
id: 'af6da4e1-f24f-4b43-8556-fa885626897d',
|
||||
name: 'Тестовая карта',
|
||||
balance: 1000,
|
||||
updatedAt: '2025-08-29T07:57:40.503Z',
|
||||
createdAt: '2025-08-29T07:57:40.503Z',
|
||||
};
|
||||
|
||||
const fillForm = async (data: EditBankCardBody) => {
|
||||
@ -64,11 +63,11 @@ const submitHandler = (requestSpy: jest.Mock) => http.patch<EditBankCardPath, Ed
|
||||
requestSpy(body);
|
||||
|
||||
return HttpResponse.json({
|
||||
balance: 1000,
|
||||
createdAt: '2025-08-29T07:57:40.503Z',
|
||||
id: 'af6da4e1-f24f-4b43-8556-fa885626897d',
|
||||
name: 'Тестовая карта',
|
||||
balance: 1000,
|
||||
updatedAt: '2025-08-29T07:57:40.503Z',
|
||||
createdAt: '2025-08-29T07:57:40.503Z',
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
import type { ButtonHTMLAttributes, FC, Ref } from 'react';
|
||||
|
||||
import type { BankCard } from '@/entity/cards';
|
||||
|
||||
import { EditBankCardForm } from '@/entity/cards';
|
||||
import { Modal } from '@/shared/ui/Modal';
|
||||
|
||||
import { useEditBankCardButton } from '../hooks/useEditBankCardButton';
|
||||
|
||||
import type { BankCard } from '@/entity/cards';
|
||||
import type { ButtonHTMLAttributes, FC, Ref } from 'react';
|
||||
|
||||
export type EditBankCardButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {
|
||||
bankCard: BankCard;
|
||||
ref?: Ref<HTMLButtonElement>;
|
||||
@ -13,26 +14,26 @@ export type EditBankCardButtonProps = ButtonHTMLAttributes<HTMLButtonElement> &
|
||||
const EditBankCardButton: FC<EditBankCardButtonProps> = (props) => {
|
||||
const {
|
||||
bankCard,
|
||||
ref,
|
||||
onClick,
|
||||
ref,
|
||||
...restProps
|
||||
} = props;
|
||||
|
||||
const {
|
||||
isOpen,
|
||||
isPending,
|
||||
onCloseModalHandler,
|
||||
onClickHandler,
|
||||
onCloseModalHandler,
|
||||
onFormSubmitHandler,
|
||||
} = useEditBankCardButton({ bankCard });
|
||||
|
||||
return (
|
||||
<>
|
||||
<button type="button" onClick={onClickHandler} {...restProps}>
|
||||
<button onClick={onClickHandler} type="button" {...restProps}>
|
||||
Редактировать
|
||||
</button>
|
||||
|
||||
<Modal open={isOpen} onClose={onCloseModalHandler}>
|
||||
<Modal onClose={onCloseModalHandler} open={isOpen}>
|
||||
<EditBankCardForm
|
||||
bankCard={bankCard}
|
||||
disabled={isPending}
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { type MouseEventHandler, useState } from 'react';
|
||||
|
||||
import { useAddCash } from '@/entity/cash';
|
||||
|
||||
import type { AddCashFormValues } from '@/entity/cash';
|
||||
|
||||
import { useAddCash } from '@/entity/cash';
|
||||
|
||||
type UseAddCashButtonArgs = {
|
||||
onClick?: MouseEventHandler<HTMLButtonElement>;
|
||||
};
|
||||
@ -12,7 +12,7 @@ export const useAddCashButton = (args: UseAddCashButtonArgs) => {
|
||||
const { onClick } = args;
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
const { mutateAsync: addCashMutation, isPending } = useAddCash();
|
||||
const { isPending, mutateAsync: addCashMutation } = useAddCash();
|
||||
|
||||
const onCloseModalHandler = () => {
|
||||
setIsOpen(false);
|
||||
@ -31,8 +31,8 @@ export const useAddCashButton = (args: UseAddCashButtonArgs) => {
|
||||
return {
|
||||
isOpen,
|
||||
isPending,
|
||||
onCloseModalHandler,
|
||||
onClickHandler,
|
||||
onCloseModalHandler,
|
||||
onFormSubmitHandler,
|
||||
};
|
||||
};
|
||||
|
||||
@ -1,14 +1,13 @@
|
||||
import { server } from '@mocks/jest/server';
|
||||
import { createReactQueryWrapper } from '@mocks/jest/wrappers';
|
||||
import { render, screen, within } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { http, HttpResponse } from 'msw';
|
||||
|
||||
import { server } from '@mocks/jest/server';
|
||||
import { createReactQueryWrapper } from '@mocks/jest/wrappers';
|
||||
import type { AdCashResponse, AddCashBody } from '@/entity/cash';
|
||||
|
||||
import AddCashButton from './AddCashButton.ui';
|
||||
|
||||
import type { AddCashBody, AdCashResponse } from '@/entity/cash';
|
||||
|
||||
const renderButton = () => {
|
||||
render(
|
||||
<AddCashButton data-testid="test-button" />,
|
||||
@ -44,11 +43,11 @@ const submitHandler = (requestSpy: jest.Mock) => http.post<never, AddCashBody, A
|
||||
requestSpy(body);
|
||||
|
||||
return HttpResponse.json({
|
||||
balance: 999,
|
||||
createdAt: '2025-08-29T07:57:40.503Z',
|
||||
id: '10cc093c-3875-4d33-a40a-df526266e262',
|
||||
name: 'Наличные',
|
||||
balance: 999,
|
||||
updatedAt: '2025-08-29T07:57:40.503Z',
|
||||
createdAt: '2025-08-29T07:57:40.503Z',
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@ -1,37 +1,37 @@
|
||||
import type { ButtonHTMLAttributes, FC, Ref } from 'react';
|
||||
|
||||
import { AddCashForm } from '@/entity/cash';
|
||||
import { Modal } from '@/shared/ui/Modal';
|
||||
|
||||
import { useAddCashButton } from '../hooks/useAddCashButton';
|
||||
|
||||
import type { ButtonHTMLAttributes, FC, Ref } from 'react';
|
||||
|
||||
type AddCashButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {
|
||||
ref?: Ref<HTMLButtonElement>;
|
||||
};
|
||||
|
||||
const AddCashButton: FC<AddCashButtonProps> = (props) => {
|
||||
const { ref, onClick, ...restProps } = props;
|
||||
const { onClick, ref, ...restProps } = props;
|
||||
|
||||
const {
|
||||
isOpen,
|
||||
isPending,
|
||||
onCloseModalHandler,
|
||||
onClickHandler,
|
||||
onCloseModalHandler,
|
||||
onFormSubmitHandler,
|
||||
} = useAddCashButton({ onClick });
|
||||
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
onClick={onClickHandler}
|
||||
ref={ref}
|
||||
type="button"
|
||||
onClick={onClickHandler}
|
||||
{...restProps}
|
||||
>
|
||||
Добавить
|
||||
</button>
|
||||
|
||||
<Modal open={isOpen} onClose={onCloseModalHandler}>
|
||||
<Modal onClose={onCloseModalHandler} open={isOpen}>
|
||||
<AddCashForm disabled={isPending} onSubmit={onFormSubmitHandler} />
|
||||
</Modal>
|
||||
</>
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { useState } from 'react';
|
||||
|
||||
import { useDeleteCash } from '@/entity/cash';
|
||||
|
||||
import type { CashItem } from '@/entity/cash';
|
||||
|
||||
import { useDeleteCash } from '@/entity/cash';
|
||||
|
||||
type UseDeleteCashButtonArgs = {
|
||||
id: CashItem['id'];
|
||||
};
|
||||
@ -12,7 +12,7 @@ export const useDeleteCashButton = (args: UseDeleteCashButtonArgs) => {
|
||||
const { id } = args;
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
const { mutateAsync: deleteCashAsync, isPending } = useDeleteCash();
|
||||
const { isPending, mutateAsync: deleteCashAsync } = useDeleteCash();
|
||||
|
||||
const onClickHandler = () => {
|
||||
setIsOpen(true);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user