diff --git a/src/frontend/src/entities/file/api/contracts.ts b/src/frontend/src/entities/file/api/contracts.ts new file mode 100644 index 000000000..c64ac4144 --- /dev/null +++ b/src/frontend/src/entities/file/api/contracts.ts @@ -0,0 +1,7 @@ +export interface FileItem { + url: string; +} + +export interface UploadFilesResponse { + files: FileItem[]; +} diff --git a/src/frontend/src/entities/file/api/fileApi.ts b/src/frontend/src/entities/file/api/fileApi.ts new file mode 100644 index 000000000..66355b6c1 --- /dev/null +++ b/src/frontend/src/entities/file/api/fileApi.ts @@ -0,0 +1,14 @@ +import { api } from '@/shared/api'; +import { type UploadFilesResponse } from './contracts'; + +export const fileApi = api.injectEndpoints({ + endpoints: builder => ({ + uploadFiles: builder.mutation({ + query: body => ({ + url: '/api/files', + method: 'POST', + body, + }), + }), + }), +}); diff --git a/src/frontend/src/entities/file/api/index.ts b/src/frontend/src/entities/file/api/index.ts new file mode 100644 index 000000000..2b7e0649a --- /dev/null +++ b/src/frontend/src/entities/file/api/index.ts @@ -0,0 +1,2 @@ +export * from './fileApi'; +export * from './contracts'; diff --git a/src/frontend/src/entities/file/index.ts b/src/frontend/src/entities/file/index.ts new file mode 100644 index 000000000..b1c13e734 --- /dev/null +++ b/src/frontend/src/entities/file/index.ts @@ -0,0 +1 @@ +export * from './api'; diff --git a/src/frontend/src/pages/ui/PageDetailPage.tsx b/src/frontend/src/pages/ui/PageDetailPage.tsx index 318de0f8f..59627b57f 100644 --- a/src/frontend/src/pages/ui/PageDetailPage.tsx +++ b/src/frontend/src/pages/ui/PageDetailPage.tsx @@ -1,9 +1,9 @@ import { type FC } from 'react'; import { type ActionFunction, useLoaderData, redirect } from 'react-router-dom'; import { store } from '@/app/store'; +import { fileApi } from '@/entities/file'; import { noteApi, noteLib } from '@/entities/note'; import { pagesApi, PageDetailHeader, type Page } from '@/features/pages'; -import { MOCK_API_RESPONSE_DELAY } from '@/shared/config'; import { PrivateLayout } from '@/widgets/layout'; import { MealsList } from '@/widgets/MealsList'; import { withAuthStatusCheck } from '../lib'; @@ -27,23 +27,23 @@ export const loader = withAuthStatusCheck(async ({ params }) => { export const action: ActionFunction = async ({ request, params }) => { const pageId = Number(params.id); - const data = await request.formData(); - const photos = data.getAll('photos'); + const formData = await request.formData(); + const photos = formData.getAll('photos'); if (photos.length < 1) { return redirect(`/pages/${pageId}`); } - // TODO: upload file and get url - await new Promise(resolve => setTimeout(resolve, MOCK_API_RESPONSE_DELAY)); + const { files } = await store.dispatch(fileApi.endpoints.uploadFiles.initiate(formData)).unwrap(); - const photoUrls = [ - `https://storage.yandexcloud.net/food-diary-images/oranges.png`, - `https://storage.yandexcloud.net/food-diary-images/oranges.png`, - ]; + if (files.length < 1) { + return new Response(null, { status: 500 }); + } + + const photoUrls = files.map(file => file.url).join(','); const url = `/pages/${pageId}/add-note-by-photo?${new URLSearchParams({ - photoUrls: photoUrls.join(','), + photoUrls, }).toString()}`; return redirect(url); diff --git a/src/frontend/tests/mockApi/files/files.handlers.ts b/src/frontend/tests/mockApi/files/files.handlers.ts new file mode 100644 index 000000000..90e2acbad --- /dev/null +++ b/src/frontend/tests/mockApi/files/files.handlers.ts @@ -0,0 +1,25 @@ +import { http, type HttpHandler } from 'msw'; +import { type UploadFilesResponse } from '@/entities/file'; +import { API_URL } from '@/shared/config'; +import { DelayedHttpResponse } from '../DelayedHttpResponse'; + +const UPLOAD_FILE_FAKE_RESPONSE: UploadFilesResponse = { + files: [ + { + url: 'https://storage.yandexcloud.net/food-diary-images/oranges.png', + }, + ], +}; + +export const handlers: HttpHandler[] = [ + http.post(`${API_URL}/api/files`, async ({ request }) => { + const body = await request.formData(); + const photos = body.getAll('photos'); + + if (photos.length < 1) { + return await DelayedHttpResponse.badRequest(); + } + + return await DelayedHttpResponse.json(UPLOAD_FILE_FAKE_RESPONSE); + }), +]; diff --git a/src/frontend/tests/mockApi/files/index.ts b/src/frontend/tests/mockApi/files/index.ts new file mode 100644 index 000000000..4c4d458dc --- /dev/null +++ b/src/frontend/tests/mockApi/files/index.ts @@ -0,0 +1 @@ +export { handlers as filesHandlers } from './files.handlers'; diff --git a/src/frontend/tests/mockApi/handlers.ts b/src/frontend/tests/mockApi/handlers.ts index 7677d555d..9faa7e729 100644 --- a/src/frontend/tests/mockApi/handlers.ts +++ b/src/frontend/tests/mockApi/handlers.ts @@ -1,5 +1,6 @@ import { authHandlers } from './auth'; import { categoriesHandlers } from './categories'; +import { filesHandlers } from './files'; import { notesHandlers } from './notes'; import { pagesHandlers } from './pages'; import { productsHandlers } from './products'; @@ -10,4 +11,5 @@ export const handlers = [ ...notesHandlers, ...productsHandlers, ...categoriesHandlers, + ...filesHandlers, ];