From 45d80b7c86e39dad9b42132dadec5f2f914fd41f Mon Sep 17 00:00:00 2001 From: admin Date: Sun, 1 Sep 2024 01:05:20 +0300 Subject: [PATCH] feat: a lot of a lot --- src/client/index.ts | 14 +++ src/client/models/CreateMarketplaceRequest.ts | 9 ++ .../models/CreateMarketplaceResponse.ts | 9 ++ src/client/models/CreateTaskResponse.ts | 8 ++ src/client/models/DeleteMarketplaceRequest.ts | 8 ++ .../models/DeleteMarketplaceResponse.ts | 9 ++ .../models/GetClientMarketplacesRequest.ts | 8 ++ .../models/GetClientMarketplacesResponse.ts | 9 ++ src/client/models/MarketplaceCreateSchema.ts | 11 ++ src/client/models/MarketplaceSchema.ts | 14 +++ .../models/SynchronizeMarketplaceRequest.ts | 8 ++ src/client/models/TaskInfoResponse.ts | 9 ++ src/client/models/UpdateMarketplaceRequest.ts | 9 ++ .../models/UpdateMarketplaceResponse.ts | 9 ++ src/client/services/AuthService.ts | 11 ++ src/client/services/ClientService.ts | 2 +- src/client/services/MarketplaceService.ts | 88 ++++++++++++++ src/client/services/TaskService.ts | 53 ++++++++ src/components/Navbar/Navbar.tsx | 7 +- .../ClientSelectNew/ClientSelectNew.tsx | 1 + src/features/tasksSlice.tsx | 101 +++++++++++++++ src/hooks/usePollingEffect.tsx | 54 ++++++++ src/main.tsx | 9 +- src/modals/modals.ts | 4 +- .../MarketplacesTable/MarketplacesTable.tsx | 100 +++++++++++++++ .../components/MarketplacesTable/columns.tsx | 35 ++++++ .../hooks/useMarketplacesPageState.tsx | 115 ++++++++++++++++++ src/pages/MarketplacesPage/index.ts | 1 + .../MarketplaceAuthDataInput.tsx | 71 +++++++++++ .../MarketplaceFormModal.tsx | 70 +++++++++++ .../ui/MarketplacesPage.module.css | 17 +++ .../MarketplacesPage/ui/MarketplacesPage.tsx | 29 +++++ src/providers/TasksProvider/TasksProvider.tsx | 63 ++++++++++ src/redux/store.ts | 4 +- src/routeTree.gen.ts | 18 +++ src/routes/marketplaces.lazy.tsx | 6 + src/shared/enums/BaseMarketplaceType.ts | 6 + src/shared/enums/TaskStatus.ts | 7 ++ 38 files changed, 1000 insertions(+), 6 deletions(-) create mode 100644 src/client/models/CreateMarketplaceRequest.ts create mode 100644 src/client/models/CreateMarketplaceResponse.ts create mode 100644 src/client/models/CreateTaskResponse.ts create mode 100644 src/client/models/DeleteMarketplaceRequest.ts create mode 100644 src/client/models/DeleteMarketplaceResponse.ts create mode 100644 src/client/models/GetClientMarketplacesRequest.ts create mode 100644 src/client/models/GetClientMarketplacesResponse.ts create mode 100644 src/client/models/MarketplaceCreateSchema.ts create mode 100644 src/client/models/MarketplaceSchema.ts create mode 100644 src/client/models/SynchronizeMarketplaceRequest.ts create mode 100644 src/client/models/TaskInfoResponse.ts create mode 100644 src/client/models/UpdateMarketplaceRequest.ts create mode 100644 src/client/models/UpdateMarketplaceResponse.ts create mode 100644 src/client/services/TaskService.ts create mode 100644 src/features/tasksSlice.tsx create mode 100644 src/hooks/usePollingEffect.tsx create mode 100644 src/pages/MarketplacesPage/components/MarketplacesTable/MarketplacesTable.tsx create mode 100644 src/pages/MarketplacesPage/components/MarketplacesTable/columns.tsx create mode 100644 src/pages/MarketplacesPage/hooks/useMarketplacesPageState.tsx create mode 100644 src/pages/MarketplacesPage/index.ts create mode 100644 src/pages/MarketplacesPage/modals/MarketplaceFormModal/MarketplaceAuthDataInput.tsx create mode 100644 src/pages/MarketplacesPage/modals/MarketplaceFormModal/MarketplaceFormModal.tsx create mode 100644 src/pages/MarketplacesPage/ui/MarketplacesPage.module.css create mode 100644 src/pages/MarketplacesPage/ui/MarketplacesPage.tsx create mode 100644 src/providers/TasksProvider/TasksProvider.tsx create mode 100644 src/routes/marketplaces.lazy.tsx create mode 100644 src/shared/enums/BaseMarketplaceType.ts create mode 100644 src/shared/enums/TaskStatus.ts diff --git a/src/client/index.ts b/src/client/index.ts index ca67d63..a576cd2 100644 --- a/src/client/index.ts +++ b/src/client/index.ts @@ -44,6 +44,8 @@ export type { CreateBarcodeTemplateAttributeRequest } from './models/CreateBarco export type { CreateBarcodeTemplateAttributeResponse } from './models/CreateBarcodeTemplateAttributeResponse'; export type { CreateDealBillRequest } from './models/CreateDealBillRequest'; export type { CreateDealBillResponse } from './models/CreateDealBillResponse'; +export type { CreateMarketplaceRequest } from './models/CreateMarketplaceRequest'; +export type { CreateMarketplaceResponse } from './models/CreateMarketplaceResponse'; export type { CreatePaymentRecordRequest } from './models/CreatePaymentRecordRequest'; export type { CreatePaymentRecordResponse } from './models/CreatePaymentRecordResponse'; export type { CreatePayRateRequest } from './models/CreatePayRateRequest'; @@ -55,6 +57,7 @@ export type { CreateServicesKitRequest } from './models/CreateServicesKitRequest export type { CreateServicesKitResponse } from './models/CreateServicesKitResponse'; export type { CreateShippingWarehouseRequest } from './models/CreateShippingWarehouseRequest'; export type { CreateShippingWarehouseResponse } from './models/CreateShippingWarehouseResponse'; +export type { CreateTaskResponse } from './models/CreateTaskResponse'; export type { CreateUserRequest } from './models/CreateUserRequest'; export type { CreateUserResponse } from './models/CreateUserResponse'; export type { DealAddKitRequest } from './models/DealAddKitRequest'; @@ -107,6 +110,8 @@ export type { DealUpdateServiceQuantityRequest } from './models/DealUpdateServic export type { DealUpdateServiceQuantityResponse } from './models/DealUpdateServiceQuantityResponse'; export type { DealUpdateServiceRequest } from './models/DealUpdateServiceRequest'; export type { DealUpdateServiceResponse } from './models/DealUpdateServiceResponse'; +export type { DeleteMarketplaceRequest } from './models/DeleteMarketplaceRequest'; +export type { DeleteMarketplaceResponse } from './models/DeleteMarketplaceResponse'; export type { DeletePaymentRecordRequest } from './models/DeletePaymentRecordRequest'; export type { DeletePaymentRecordResponse } from './models/DeletePaymentRecordResponse'; export type { DeletePayRateRequest } from './models/DeletePayRateRequest'; @@ -128,6 +133,8 @@ export type { GetAllShippingWarehousesResponse } from './models/GetAllShippingWa export type { GetAllUsersResponse } from './models/GetAllUsersResponse'; export type { GetBarcodeTemplateByIdRequest } from './models/GetBarcodeTemplateByIdRequest'; export type { GetBarcodeTemplateByIdResponse } from './models/GetBarcodeTemplateByIdResponse'; +export type { GetClientMarketplacesRequest } from './models/GetClientMarketplacesRequest'; +export type { GetClientMarketplacesResponse } from './models/GetClientMarketplacesResponse'; export type { GetDealBillById } from './models/GetDealBillById'; export type { GetPaymentRecordsResponse } from './models/GetPaymentRecordsResponse'; export type { GetProductBarcodePdfRequest } from './models/GetProductBarcodePdfRequest'; @@ -138,6 +145,8 @@ export type { GetServiceKitSchema } from './models/GetServiceKitSchema'; export type { GetTimeTrackingRecordsRequest } from './models/GetTimeTrackingRecordsRequest'; export type { GetTimeTrackingRecordsResponse } from './models/GetTimeTrackingRecordsResponse'; export type { HTTPValidationError } from './models/HTTPValidationError'; +export type { MarketplaceCreateSchema } from './models/MarketplaceCreateSchema'; +export type { MarketplaceSchema } from './models/MarketplaceSchema'; export type { NotificationChannel } from './models/NotificationChannel'; export type { PaginationInfoSchema } from './models/PaginationInfoSchema'; export type { PaymentRecordCreateSchema } from './models/PaymentRecordCreateSchema'; @@ -177,8 +186,12 @@ export type { ServiceSchema } from './models/ServiceSchema'; export type { ServiceUpdateRequest } from './models/ServiceUpdateRequest'; export type { ServiceUpdateResponse } from './models/ServiceUpdateResponse'; export type { ShippingWarehouseSchema } from './models/ShippingWarehouseSchema'; +export type { SynchronizeMarketplaceRequest } from './models/SynchronizeMarketplaceRequest'; +export type { TaskInfoResponse } from './models/TaskInfoResponse'; export type { TimeTrackingData } from './models/TimeTrackingData'; export type { TimeTrackingRecord } from './models/TimeTrackingRecord'; +export type { UpdateMarketplaceRequest } from './models/UpdateMarketplaceRequest'; +export type { UpdateMarketplaceResponse } from './models/UpdateMarketplaceResponse'; export type { UpdatePayRateRequest } from './models/UpdatePayRateRequest'; export type { UpdatePayRateResponse } from './models/UpdatePayRateResponse'; export type { UpdateServiceKitSchema } from './models/UpdateServiceKitSchema'; @@ -207,5 +220,6 @@ export { ProductService } from './services/ProductService'; export { RoleService } from './services/RoleService'; export { ServiceService } from './services/ServiceService'; export { ShippingWarehouseService } from './services/ShippingWarehouseService'; +export { TaskService } from './services/TaskService'; export { TimeTrackingService } from './services/TimeTrackingService'; export { UserService } from './services/UserService'; diff --git a/src/client/models/CreateMarketplaceRequest.ts b/src/client/models/CreateMarketplaceRequest.ts new file mode 100644 index 0000000..51ef9bb --- /dev/null +++ b/src/client/models/CreateMarketplaceRequest.ts @@ -0,0 +1,9 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import type { MarketplaceCreateSchema } from './MarketplaceCreateSchema'; +export type CreateMarketplaceRequest = { + marketplace: MarketplaceCreateSchema; +}; + diff --git a/src/client/models/CreateMarketplaceResponse.ts b/src/client/models/CreateMarketplaceResponse.ts new file mode 100644 index 0000000..9ed8e26 --- /dev/null +++ b/src/client/models/CreateMarketplaceResponse.ts @@ -0,0 +1,9 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type CreateMarketplaceResponse = { + ok: boolean; + message: string; +}; + diff --git a/src/client/models/CreateTaskResponse.ts b/src/client/models/CreateTaskResponse.ts new file mode 100644 index 0000000..9822dc2 --- /dev/null +++ b/src/client/models/CreateTaskResponse.ts @@ -0,0 +1,8 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type CreateTaskResponse = { + taskId: string; +}; + diff --git a/src/client/models/DeleteMarketplaceRequest.ts b/src/client/models/DeleteMarketplaceRequest.ts new file mode 100644 index 0000000..2213586 --- /dev/null +++ b/src/client/models/DeleteMarketplaceRequest.ts @@ -0,0 +1,8 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type DeleteMarketplaceRequest = { + marketplaceId: number; +}; + diff --git a/src/client/models/DeleteMarketplaceResponse.ts b/src/client/models/DeleteMarketplaceResponse.ts new file mode 100644 index 0000000..1f764a3 --- /dev/null +++ b/src/client/models/DeleteMarketplaceResponse.ts @@ -0,0 +1,9 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type DeleteMarketplaceResponse = { + ok: boolean; + message: string; +}; + diff --git a/src/client/models/GetClientMarketplacesRequest.ts b/src/client/models/GetClientMarketplacesRequest.ts new file mode 100644 index 0000000..c166707 --- /dev/null +++ b/src/client/models/GetClientMarketplacesRequest.ts @@ -0,0 +1,8 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type GetClientMarketplacesRequest = { + clientId: number; +}; + diff --git a/src/client/models/GetClientMarketplacesResponse.ts b/src/client/models/GetClientMarketplacesResponse.ts new file mode 100644 index 0000000..809a9f0 --- /dev/null +++ b/src/client/models/GetClientMarketplacesResponse.ts @@ -0,0 +1,9 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import type { MarketplaceSchema } from './MarketplaceSchema'; +export type GetClientMarketplacesResponse = { + marketplaces: Array; +}; + diff --git a/src/client/models/MarketplaceCreateSchema.ts b/src/client/models/MarketplaceCreateSchema.ts new file mode 100644 index 0000000..69dd85b --- /dev/null +++ b/src/client/models/MarketplaceCreateSchema.ts @@ -0,0 +1,11 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type MarketplaceCreateSchema = { + name: string; + clientId: number; + baseMarketplaceKey: string; + authData: Record; +}; + diff --git a/src/client/models/MarketplaceSchema.ts b/src/client/models/MarketplaceSchema.ts new file mode 100644 index 0000000..ce970ee --- /dev/null +++ b/src/client/models/MarketplaceSchema.ts @@ -0,0 +1,14 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import type { BaseMarketplaceSchema } from './BaseMarketplaceSchema'; +import type { ClientSchema } from './ClientSchema'; +export type MarketplaceSchema = { + name: string; + baseMarketplace: BaseMarketplaceSchema; + client: ClientSchema; + authData: Record; + id: number; +}; + diff --git a/src/client/models/SynchronizeMarketplaceRequest.ts b/src/client/models/SynchronizeMarketplaceRequest.ts new file mode 100644 index 0000000..620431f --- /dev/null +++ b/src/client/models/SynchronizeMarketplaceRequest.ts @@ -0,0 +1,8 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type SynchronizeMarketplaceRequest = { + marketplaceId: number; +}; + diff --git a/src/client/models/TaskInfoResponse.ts b/src/client/models/TaskInfoResponse.ts new file mode 100644 index 0000000..a5a070a --- /dev/null +++ b/src/client/models/TaskInfoResponse.ts @@ -0,0 +1,9 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type TaskInfoResponse = { + taskId: string; + status: string; +}; + diff --git a/src/client/models/UpdateMarketplaceRequest.ts b/src/client/models/UpdateMarketplaceRequest.ts new file mode 100644 index 0000000..510e76b --- /dev/null +++ b/src/client/models/UpdateMarketplaceRequest.ts @@ -0,0 +1,9 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import type { MarketplaceSchema } from './MarketplaceSchema'; +export type UpdateMarketplaceRequest = { + marketplace: MarketplaceSchema; +}; + diff --git a/src/client/models/UpdateMarketplaceResponse.ts b/src/client/models/UpdateMarketplaceResponse.ts new file mode 100644 index 0000000..adc8c80 --- /dev/null +++ b/src/client/models/UpdateMarketplaceResponse.ts @@ -0,0 +1,9 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type UpdateMarketplaceResponse = { + ok: boolean; + message: string; +}; + diff --git a/src/client/services/AuthService.ts b/src/client/services/AuthService.ts index 6ba1ac4..ce20e88 100644 --- a/src/client/services/AuthService.ts +++ b/src/client/services/AuthService.ts @@ -28,4 +28,15 @@ export class AuthService { }, }); } + /** + * Test + * @returns any Successful Response + * @throws ApiError + */ + public static testAuthTestPost(): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/auth/test', + }); + } } diff --git a/src/client/services/ClientService.ts b/src/client/services/ClientService.ts index 74f7d8b..4b2b1da 100644 --- a/src/client/services/ClientService.ts +++ b/src/client/services/ClientService.ts @@ -71,7 +71,7 @@ export class ClientService { * @returns ClientCreateResponse Successful Response * @throws ApiError */ - public static createClient({ + public static createClientApi({ requestBody, }: { requestBody: ClientCreateRequest, diff --git a/src/client/services/MarketplaceService.ts b/src/client/services/MarketplaceService.ts index e014493..35e7fd4 100644 --- a/src/client/services/MarketplaceService.ts +++ b/src/client/services/MarketplaceService.ts @@ -2,7 +2,15 @@ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ +import type { CreateMarketplaceRequest } from '../models/CreateMarketplaceRequest'; +import type { CreateMarketplaceResponse } from '../models/CreateMarketplaceResponse'; +import type { DeleteMarketplaceRequest } from '../models/DeleteMarketplaceRequest'; +import type { DeleteMarketplaceResponse } from '../models/DeleteMarketplaceResponse'; import type { GetAllBaseMarketplacesResponse } from '../models/GetAllBaseMarketplacesResponse'; +import type { GetClientMarketplacesRequest } from '../models/GetClientMarketplacesRequest'; +import type { GetClientMarketplacesResponse } from '../models/GetClientMarketplacesResponse'; +import type { UpdateMarketplaceRequest } from '../models/UpdateMarketplaceRequest'; +import type { UpdateMarketplaceResponse } from '../models/UpdateMarketplaceResponse'; import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; @@ -18,4 +26,84 @@ export class MarketplaceService { url: '/marketplace/base/get-all', }); } + /** + * Get + * @returns GetClientMarketplacesResponse Successful Response + * @throws ApiError + */ + public static getClientMarketplaces({ + requestBody, + }: { + requestBody: GetClientMarketplacesRequest, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/marketplace/get', + body: requestBody, + mediaType: 'application/json', + errors: { + 422: `Validation Error`, + }, + }); + } + /** + * Create + * @returns CreateMarketplaceResponse Successful Response + * @throws ApiError + */ + public static createMarketplace({ + requestBody, + }: { + requestBody: CreateMarketplaceRequest, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/marketplace/create', + body: requestBody, + mediaType: 'application/json', + errors: { + 422: `Validation Error`, + }, + }); + } + /** + * Delete + * @returns DeleteMarketplaceResponse Successful Response + * @throws ApiError + */ + public static deleteMarketplace({ + requestBody, + }: { + requestBody: DeleteMarketplaceRequest, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/marketplace/delete', + body: requestBody, + mediaType: 'application/json', + errors: { + 422: `Validation Error`, + }, + }); + } + /** + * Update + * @returns UpdateMarketplaceResponse Successful Response + * @throws ApiError + */ + public static updateMarketplace({ + requestBody, + }: { + requestBody: UpdateMarketplaceRequest, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/marketplace/update', + body: requestBody, + mediaType: 'application/json', + errors: { + 422: `Validation Error`, + }, + }); + } } diff --git a/src/client/services/TaskService.ts b/src/client/services/TaskService.ts new file mode 100644 index 0000000..2e02cdf --- /dev/null +++ b/src/client/services/TaskService.ts @@ -0,0 +1,53 @@ +/* generated using openapi-typescript-codegen -- do not edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +import type { CreateTaskResponse } from '../models/CreateTaskResponse'; +import type { SynchronizeMarketplaceRequest } from '../models/SynchronizeMarketplaceRequest'; +import type { TaskInfoResponse } from '../models/TaskInfoResponse'; +import type { CancelablePromise } from '../core/CancelablePromise'; +import { OpenAPI } from '../core/OpenAPI'; +import { request as __request } from '../core/request'; +export class TaskService { + /** + * Synchronize Marketplace + * @returns CreateTaskResponse Successful Response + * @throws ApiError + */ + public static createSynchronizeMarketplaceTask({ + requestBody, + }: { + requestBody: SynchronizeMarketplaceRequest, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/task/synchronize-marketplace', + body: requestBody, + mediaType: 'application/json', + errors: { + 422: `Validation Error`, + }, + }); + } + /** + * Task Info + * @returns TaskInfoResponse Successful Response + * @throws ApiError + */ + public static getTaskInfo({ + taskId, + }: { + taskId: string, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'GET', + url: '/task/info/{task_id}', + path: { + 'task_id': taskId, + }, + errors: { + 422: `Validation Error`, + }, + }); + } +} diff --git a/src/components/Navbar/Navbar.tsx b/src/components/Navbar/Navbar.tsx index 30076fe..f82d8d4 100644 --- a/src/components/Navbar/Navbar.tsx +++ b/src/components/Navbar/Navbar.tsx @@ -8,7 +8,7 @@ import { IconHome2, IconLogout, IconMan, - IconMoon, + IconMoon, IconShoppingCart, IconSun, } from '@tabler/icons-react'; import classes from './Navbar.module.css'; @@ -76,6 +76,11 @@ const mockdata = [ icon: IconBuildingWarehouse, label: 'Склады отгрузки', href: '/shipping_warehouses' + }, + { + icon:IconShoppingCart, + label: 'Маркетплейсы', + href: '/marketplaces' } ]; diff --git a/src/components/Selects/ClientSelectNew/ClientSelectNew.tsx b/src/components/Selects/ClientSelectNew/ClientSelectNew.tsx index d36099c..d32c4e3 100644 --- a/src/components/Selects/ClientSelectNew/ClientSelectNew.tsx +++ b/src/components/Selects/ClientSelectNew/ClientSelectNew.tsx @@ -9,6 +9,7 @@ const ClientSelectNew: FC = (props) => { const {clients} = useClientsList(); return ( diff --git a/src/features/tasksSlice.tsx b/src/features/tasksSlice.tsx new file mode 100644 index 0000000..592d115 --- /dev/null +++ b/src/features/tasksSlice.tsx @@ -0,0 +1,101 @@ +import {createSlice, PayloadAction} from "@reduxjs/toolkit"; +import {notifications} from "../shared/lib/notifications.ts"; +import {IconCheck, IconX} from "@tabler/icons-react"; +import {rem} from "@mantine/core"; + +export type TaskData = { + title: string; + message: string; +}; + +export type TaskConfig = { + onSuccessData: TaskData; + onErrorData: TaskData; + onLoadingData: TaskData; +}; + +export type Task = { + id: string; + config: TaskConfig; + info: Record; +}; + +interface TasksState { + tasks: Task[]; + notificationTaskMap: { [key: string]: string }; +} + +const initialState: TasksState = { + tasks: [], + notificationTaskMap: {}, +}; + +const tasksSlice = createSlice({ + name: "tasks", + initialState, + reducers: { + addTask: (state, action: PayloadAction) => { + const task = action.payload; + state.notificationTaskMap[task.id] = notifications.show({ + loading: true, + title: task.config.onLoadingData.title, + message: task.config.onLoadingData.message, + autoClose: false, + withCloseButton: false, + withBorder: true, + radius: "sm" + }); + state.tasks.push(task); + localStorage.setItem("tasks", JSON.stringify(state.tasks)); + }, + removeTask: (state, action: PayloadAction) => { + state.tasks = state.tasks.filter((task) => task.id !== action.payload); + localStorage.setItem("tasks", JSON.stringify(state.tasks)); + }, + failTask: (state, action: PayloadAction) => { + const task = action.payload; + const notificationId = state.notificationTaskMap[task.id]; + + if (!notificationId) return; + notifications.update({ + id: notificationId, + color: 'red', + title: task.config.onErrorData.title, + message: task.config.onErrorData.message, + icon: , + loading: false, + autoClose: 2000, + }) + state.tasks = state.tasks.filter((task) => task.id !== action.payload.id); + state.notificationTaskMap = Object.fromEntries( + Object.entries(state.notificationTaskMap).filter(([taskId]) => taskId !== task.id) + ); + localStorage.setItem("tasks", JSON.stringify(state.tasks)); + }, + successTask: (state, action: PayloadAction) => { + const task = action.payload; + const notificationId = state.notificationTaskMap[task.id]; + + if (!notificationId) return; + notifications.update({ + id: notificationId, + color: 'teal', + title: task.config.onSuccessData.title, + message: task.config.onSuccessData.message, + icon: , + loading: false, + autoClose: 2000, + }) + state.tasks = state.tasks.filter((task) => task.id !== action.payload.id); + state.notificationTaskMap = Object.fromEntries( + Object.entries(state.notificationTaskMap).filter(([taskId]) => taskId !== task.id) + ); + + localStorage.setItem("tasks", JSON.stringify(state.tasks)); + } + }, +}); + +export const {addTask, removeTask, successTask, failTask} = tasksSlice.actions; + +export default tasksSlice.reducer; \ No newline at end of file diff --git a/src/hooks/usePollingEffect.tsx b/src/hooks/usePollingEffect.tsx new file mode 100644 index 0000000..f3afd59 --- /dev/null +++ b/src/hooks/usePollingEffect.tsx @@ -0,0 +1,54 @@ +import {useEffect, useRef, DependencyList} from 'react'; + +type UsePollingEffectOptions = { + interval?: number; + isActive?: boolean; + onCleanUp?: () => void; +}; + +function usePollingEffect( + asyncCallback: () => Promise, + dependencies: DependencyList = [], + options: UsePollingEffectOptions = {} +): void { + const { + interval = 3000, + isActive = true, + onCleanUp = () => { + } + } = options; + + const timeoutIdRef = useRef(null); + + useEffect(() => { + if (!isActive) { // If not active, don't do anything + return; + } + + let stopped = false; + + const pollingCallback = async () => { + try { + await asyncCallback(); + } finally { + if (!stopped) { + timeoutIdRef.current = setTimeout(pollingCallback, interval); + } + } + }; + + // Immediately invoke the polling callback when the effect runs + pollingCallback(); + + // Clean up function to clear the timeout if the component unmounts or dependencies change + return () => { + stopped = true; // This will prevent new timeouts from being scheduled + if (timeoutIdRef.current) { + clearTimeout(timeoutIdRef.current); + } + onCleanUp(); + }; + }, [...dependencies, interval, isActive]); // dependencies array spread with interval +} + +export default usePollingEffect; diff --git a/src/main.tsx b/src/main.tsx index e6e6414..3589e76 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -19,6 +19,7 @@ import {ModalsProvider} from "@mantine/modals"; import {OpenAPI} from "./client"; import {DatesProvider} from "@mantine/dates"; import {modals} from "./modals/modals.ts"; +import TasksProvider from "./providers/TasksProvider/TasksProvider.tsx"; // Configuring router const router = createRouter({routeTree}) @@ -46,8 +47,12 @@ ReactDOM.createRoot(document.getElementById('root')!).render( - - + + + + + + diff --git a/src/modals/modals.ts b/src/modals/modals.ts index 9cf5172..f1f0a0f 100644 --- a/src/modals/modals.ts +++ b/src/modals/modals.ts @@ -20,6 +20,7 @@ import ServiceKitModalForm from "../pages/ServicesPage/modals/ServicesKitModalFo import ServicesKitSelectModal from "./ServicesKitSelectModal/ServicesKitSelectModal.tsx"; import SelectDealProductsModal from "../pages/LeadsPage/modals/SelectDealProductsModal.tsx"; import ShippingWarehouseForm from "../pages/ShippingWarehousesPage/modals/ShippingWarehouseForm.tsx"; +import MarketplaceFormModal from "../pages/MarketplacesPage/modals/MarketplaceFormModal/MarketplaceFormModal.tsx"; export const modals = { enterDeadline: EnterDeadlineModal, @@ -42,5 +43,6 @@ export const modals = { serviceKitModalForm: ServiceKitModalForm, servicesKitSelectModal: ServicesKitSelectModal, selectDealProductsModal: SelectDealProductsModal, - shippingWarehouseForm: ShippingWarehouseForm + shippingWarehouseForm: ShippingWarehouseForm, + marketplaceFormModal: MarketplaceFormModal } diff --git a/src/pages/MarketplacesPage/components/MarketplacesTable/MarketplacesTable.tsx b/src/pages/MarketplacesPage/components/MarketplacesTable/MarketplacesTable.tsx new file mode 100644 index 0000000..efbb82c --- /dev/null +++ b/src/pages/MarketplacesPage/components/MarketplacesTable/MarketplacesTable.tsx @@ -0,0 +1,100 @@ +import {CRUDTableProps} from "../../../../types/CRUDTable.tsx"; +import {ClientSchema, MarketplaceSchema} from "../../../../client"; +import {FC} from "react"; +import {BaseTable} from "../../../../components/BaseTable/BaseTable.tsx"; +import useMarketplacesTableColumns from "./columns.tsx"; +import {MRT_TableOptions} from "mantine-react-table"; +import {ActionIcon, Button, Flex, rem, Text, Tooltip} from "@mantine/core"; +import {modals} from "@mantine/modals"; +import {IconEdit, IconRefresh, IconTrash} from "@tabler/icons-react"; + +type RestProps = { + client?: ClientSchema; + onSynchronize?: (marketplace: MarketplaceSchema) => void; + +} +type Props = CRUDTableProps & RestProps; + +const MarketplacesTable: FC = ({onDelete, onChange, onCreate, items, client, onSynchronize}) => { + const columns = useMarketplacesTableColumns(); + const onDeleteClick = (marketplace: MarketplaceSchema) => { + if (!onDelete) return; + modals.openConfirmModal({ + title: 'Удаление маркетплейса', + children: ( + + Вы уверены что хотите удалить маркетплейс {marketplace.name} + + ), + labels: {confirm: 'Да', cancel: "Нет"}, + confirmProps: {color: 'red'}, + onConfirm: () => onDelete(marketplace) + }); + } + const onEditClick = (marketplace: MarketplaceSchema) => { + if (!onChange) return; + modals.openContextModal({ + modal: "marketplaceFormModal", + withCloseButton: false, + innerProps: { + onChange: (event) => onChange(event), + element: marketplace + } + }) + } + const onCreateClick = () => { + if (!onCreate || !client) return; + modals.openContextModal({ + modal: "marketplaceFormModal", + withCloseButton: false, + innerProps: { + onCreate: (event) => onCreate({...event, client: client}) + } + }) + } + return ( + + + + ), + enableRowActions: true, + renderRowActions: ({row}) => ( + + + onEditClick(row.original)} + variant={"default"}> + + + + + onDeleteClick(row.original)} variant={"default"}> + + + + + onSynchronize && onSynchronize(row.original)} + variant={"default"}> + + + + + ) + } as MRT_TableOptions} + /> + ) +} +export default MarketplacesTable; \ No newline at end of file diff --git a/src/pages/MarketplacesPage/components/MarketplacesTable/columns.tsx b/src/pages/MarketplacesPage/components/MarketplacesTable/columns.tsx new file mode 100644 index 0000000..a677c44 --- /dev/null +++ b/src/pages/MarketplacesPage/components/MarketplacesTable/columns.tsx @@ -0,0 +1,35 @@ +import {MarketplaceSchema} from "../../../../client"; +import {MRT_ColumnDef} from "mantine-react-table"; +import {useMemo} from "react"; +import {ActionIcon, Image} from "@mantine/core"; + +const useMarketplacesTableColumns = () => { + return useMemo[]>(() => [ + { + header: "Маркетплейс", + size: 10, + Cell: ({row}) => ( + + + + ) + }, + { + accessorKey: "name", + header: "Название", + enableSorting: false, + }, + { + accessorKey: "client.name", + header: "Клиент", + enableSorting: false, + }, + // { + // accessorKey: "authData", + // header: "Данные авторизации", + // enableSorting: false, + // }, + ], []); +} + +export default useMarketplacesTableColumns; \ No newline at end of file diff --git a/src/pages/MarketplacesPage/hooks/useMarketplacesPageState.tsx b/src/pages/MarketplacesPage/hooks/useMarketplacesPageState.tsx new file mode 100644 index 0000000..7a75e46 --- /dev/null +++ b/src/pages/MarketplacesPage/hooks/useMarketplacesPageState.tsx @@ -0,0 +1,115 @@ +import {useEffect, useState} from "react"; +import {ClientSchema, MarketplaceSchema, MarketplaceService, TaskService} from "../../../client"; +import {notifications} from "../../../shared/lib/notifications.ts"; +import {RootState, useAppDispatch} from "../../../redux/store.ts"; +import {addTask} from "../../../features/tasksSlice.tsx"; +import {useSelector} from "react-redux"; + +const useMarketplacesPageState = () => { + const dispatch = useAppDispatch(); + const tasks = useSelector((state: RootState) => state.tasks.tasks); + const [client, setClient] = useState(); + const [items, setItems] = useState([]); + const fetchMarketplaces = async () => { + if (!client) return; + MarketplaceService.getClientMarketplaces({ + requestBody: { + clientId: client.id + } + }).then((response) => { + setItems(response.marketplaces); + }) + } + + const onCreate = (marketplace: MarketplaceSchema) => { + MarketplaceService.createMarketplace({ + requestBody: { + marketplace: { + ...marketplace, + clientId: marketplace.client.id, + baseMarketplaceKey: marketplace.baseMarketplace.key + } + } + }).then(async ({ok, message}) => { + notifications.guess(ok, {message}); + if (!ok) return; + await fetchMarketplaces(); + }) + } + const onDelete = (marketplace: MarketplaceSchema) => { + MarketplaceService.deleteMarketplace({ + requestBody: { + marketplaceId: marketplace.id + } + }).then(async ({ok, message}) => { + notifications.guess(ok, {message}); + if (!ok) return; + await fetchMarketplaces(); + }) + } + const onChange = (marketplace: MarketplaceSchema) => { + MarketplaceService.updateMarketplace({ + requestBody: { + marketplace: marketplace + } + }).then(async ({ok, message}) => { + notifications.guess(ok, {message}); + if (!ok) return; + await fetchMarketplaces(); + }) + } + + const onSynchronize = (marketplace: MarketplaceSchema) => { + + // If there is already synchronization task for this marketplace show notifications.error() + const task = tasks.find(task => task.info.marketplaceId === marketplace.id); + if (task) { + notifications.error({ + title: 'Ошибка', + message: `Синхронизация маркетплейса ${marketplace.name} уже запущена` + }); + return; + + } + TaskService.createSynchronizeMarketplaceTask({ + requestBody: { + marketplaceId: + marketplace.id + } + }).then(({taskId}) => { + dispatch(addTask({ + id: taskId, + config: { + onErrorData: { + title: 'Ошибка', + message: `Ошибка синхронизации маркетплейса: ${marketplace.name}` + }, + onLoadingData: { + title: 'Синхронизация', + message: `Синхронизация маркетплейса: ${marketplace.name}` + }, + onSuccessData: { + title: 'Успех', + message: `Маркетплейс ${marketplace.name} успешно синхронизирован` + } + }, + info: { + marketplaceId: marketplace.id + } + })); + }) + } + useEffect(() => { + fetchMarketplaces(); + }, [client]); + return { + client, + setClient, + items, + onDelete, + onChange, + onCreate, + onSynchronize + } +} +export default useMarketplacesPageState; \ No newline at end of file diff --git a/src/pages/MarketplacesPage/index.ts b/src/pages/MarketplacesPage/index.ts new file mode 100644 index 0000000..d10675e --- /dev/null +++ b/src/pages/MarketplacesPage/index.ts @@ -0,0 +1 @@ +export {MarketplacesPage} from './ui/MarketplacesPage.tsx'; \ No newline at end of file diff --git a/src/pages/MarketplacesPage/modals/MarketplaceFormModal/MarketplaceAuthDataInput.tsx b/src/pages/MarketplacesPage/modals/MarketplaceFormModal/MarketplaceAuthDataInput.tsx new file mode 100644 index 0000000..371ea4c --- /dev/null +++ b/src/pages/MarketplacesPage/modals/MarketplaceFormModal/MarketplaceAuthDataInput.tsx @@ -0,0 +1,71 @@ +import {TextInput} from "@mantine/core"; +import {BaseFormInputProps} from "../../../../types/utils.ts"; +import {FC} from "react"; +import {BaseMarketplaceSchema} from "../../../../client"; +import {BaseMarketplaceType} from "../../../../shared/enums/BaseMarketplaceType.ts"; + +type RestProps = { + baseMarketplace: BaseMarketplaceSchema; +} +type Props = BaseFormInputProps> & RestProps; + +const MarketplaceAuthDataInput: FC = (props: Props) => { + console.log(props.baseMarketplace); + const getWildberriesInputs = () => { + // return input that sets record "Authorization" to value + return props.onChange({...props.value, Authorization: value.target.value})} + /> + + } + const getOzonInputs = () => { + // return input that sets record "Client-Id" and "Api-Key" to value + + return ( + <> + props.onChange({...props.value, "Client-Id": value.target.value})} + /> + props.onChange({...props.value, "Api-Key": value.target.value})} + /> + + ) + + } + const getYandexMarketInputs = () => { + } + + const getInputs = () => { + if (props.baseMarketplace.key === BaseMarketplaceType.WILDBERRIES) { + return getWildberriesInputs(); + } + if (props.baseMarketplace.key === BaseMarketplaceType.OZON) { + return getOzonInputs(); + } + if (props.baseMarketplace.key === BaseMarketplaceType.YANDEX_MARKET) { + return getYandexMarketInputs(); + } + return <> + } + + return ( + <> + {getInputs()} + + ) +} + +export default MarketplaceAuthDataInput; \ No newline at end of file diff --git a/src/pages/MarketplacesPage/modals/MarketplaceFormModal/MarketplaceFormModal.tsx b/src/pages/MarketplacesPage/modals/MarketplaceFormModal/MarketplaceFormModal.tsx new file mode 100644 index 0000000..dc3b1de --- /dev/null +++ b/src/pages/MarketplacesPage/modals/MarketplaceFormModal/MarketplaceFormModal.tsx @@ -0,0 +1,70 @@ +import {ContextModalProps} from "@mantine/modals"; +import BaseFormModal, {CreateEditFormProps} from "../../../ClientsPage/modals/BaseFormModal/BaseFormModal.tsx"; +import {MarketplaceSchema} from "../../../../client"; +import {useForm} from "@mantine/form"; +import {Fieldset, Flex, rem, TextInput} from "@mantine/core"; +import BaseMarketplaceSelect from "../../../../components/Selects/BaseMarketplaceSelect/BaseMarketplaceSelect.tsx"; +import MarketplaceAuthDataInput from "./MarketplaceAuthDataInput.tsx"; + +type Props = CreateEditFormProps +const MarketplaceFormModal = ({ + context, + id, + innerProps + }: ContextModalProps) => { + const isEditing = 'element' in innerProps; + const initialValue: Partial = isEditing ? innerProps.element : { + authData: { + Authorization: '', + "Client-Id": '', + "Api-Key": '' + + }, + }; + const form = useForm>({ + initialValues: initialValue, + validate: { + baseMarketplace: (baseMarketplace) => !baseMarketplace && "Необходимо указать базовый маркетплейс", + name: (name) => !name && "Необходимо указать название маркетплейса", + authData: (authData) => !authData && "Необходимо указать данные авторизации" + } + }); + return ( + context.closeContextModal(id)} + {...innerProps} + > + + <> +
+ + + + + {form.values.baseMarketplace && + } + onChange={(value) => form.setFieldValue("authData", value)} + error={form.getInputProps("authData").error} + /> + } + + +
+ +
+
+ ) +} +export default MarketplaceFormModal; \ No newline at end of file diff --git a/src/pages/MarketplacesPage/ui/MarketplacesPage.module.css b/src/pages/MarketplacesPage/ui/MarketplacesPage.module.css new file mode 100644 index 0000000..9f31ce7 --- /dev/null +++ b/src/pages/MarketplacesPage/ui/MarketplacesPage.module.css @@ -0,0 +1,17 @@ +.container { + display: flex; + flex-direction: column; + flex: 1; + gap: rem(10); +} + +.top-panel { + padding: rem(5); + gap: rem(10); + display: flex; + +} + +.top-panel-last-item { + margin-left: auto; +} diff --git a/src/pages/MarketplacesPage/ui/MarketplacesPage.tsx b/src/pages/MarketplacesPage/ui/MarketplacesPage.tsx new file mode 100644 index 0000000..5c45e7a --- /dev/null +++ b/src/pages/MarketplacesPage/ui/MarketplacesPage.tsx @@ -0,0 +1,29 @@ +import styles from './MarketplacesPage.module.css'; +import PageBlock from "../../../components/PageBlock/PageBlock.tsx"; +import ClientSelectNew from "../../../components/Selects/ClientSelectNew/ClientSelectNew.tsx"; +import useMarketplacesPageState from "../hooks/useMarketplacesPageState.tsx"; +import MarketplacesTable from "../components/MarketplacesTable/MarketplacesTable.tsx"; + +export const MarketplacesPage = () => { + const state = useMarketplacesPageState(); + return ( +
+ +
+ +
+
+ + <> + + + + +
+ ) +} \ No newline at end of file diff --git a/src/providers/TasksProvider/TasksProvider.tsx b/src/providers/TasksProvider/TasksProvider.tsx new file mode 100644 index 0000000..473c831 --- /dev/null +++ b/src/providers/TasksProvider/TasksProvider.tsx @@ -0,0 +1,63 @@ +import {FC, ReactNode, useEffect, useState} from "react"; +import {TaskStatus} from "../../shared/enums/TaskStatus"; +import usePollingEffect from "../../hooks/usePollingEffect.tsx"; +import {RootState, useAppDispatch} from "../../redux/store.ts"; +import {useSelector} from "react-redux"; +import {TaskService} from "../../client"; +import {addTask, failTask, successTask, Task} from "../../features/tasksSlice.tsx"; + +type Props = { + children: ReactNode; +}; + +const POLLING_STATUSES = [ + TaskStatus.RETRY, + TaskStatus.STARTED, + TaskStatus.PENDING, +] as string[]; + +const TasksProvider: FC = ({children}) => { + const [isPooling, setIsPooling] = useState(false); + const tasks = useSelector((state: RootState) => state.tasks.tasks); + const notificationTaskMap = useSelector((state: RootState) => state.tasks.notificationTaskMap); + const dispatch = useAppDispatch(); + const poolTasks = async () => { + // get statuses of all tasks + const taskInfos = await Promise.all( + tasks.map((task) => TaskService.getTaskInfo({taskId: task.id})) + ); + taskInfos.forEach(({taskId, status}) => { + if (POLLING_STATUSES.includes(status)) return; + const task = tasks.find((task) => task.id === taskId); + if (!task) return; + if (status === TaskStatus.FAILURE) { + dispatch(failTask(task)); + } else if (status === TaskStatus.SUCCESS) { + dispatch(successTask(task)); + } + }) + } + + usePollingEffect( + poolTasks, + [tasks, notificationTaskMap, isPooling], + {interval: 1000, isActive: isPooling && tasks.length > 0} + ) + useEffect(() => { + if (tasks.length === 0) { + setIsPooling(false); + return + } + setIsPooling(true); + }, [tasks]); + useEffect(() => { + // loading from localstorage + const tasks = JSON.parse(localStorage.getItem("tasks") || "[]"); + tasks.forEach((task: Task) => { + dispatch(addTask(task)); + }); + }, []); + return <>{children}; +}; + +export default TasksProvider; \ No newline at end of file diff --git a/src/redux/store.ts b/src/redux/store.ts index e9f4297..73108ee 100644 --- a/src/redux/store.ts +++ b/src/redux/store.ts @@ -2,11 +2,13 @@ import {configureStore} from "@reduxjs/toolkit"; import {useDispatch} from "react-redux"; import authReducer from '../features/authSlice'; import uiReducer from '../features/uiSlice'; +import tasksReducer from '../features/tasksSlice.tsx'; export const store = configureStore({ reducer: { auth: authReducer, - ui: uiReducer + ui: uiReducer, + tasks: tasksReducer } }); diff --git a/src/routeTree.gen.ts b/src/routeTree.gen.ts index 9272f5a..25d0fb8 100644 --- a/src/routeTree.gen.ts +++ b/src/routeTree.gen.ts @@ -21,6 +21,7 @@ const TestLazyImport = createFileRoute('/test')() const ShippingwarehousesLazyImport = createFileRoute('/shipping_warehouses')() const ServicesLazyImport = createFileRoute('/services')() const ProductsLazyImport = createFileRoute('/products')() +const MarketplacesLazyImport = createFileRoute('/marketplaces')() const LoginLazyImport = createFileRoute('/login')() const LeadsLazyImport = createFileRoute('/leads')() const ClientsLazyImport = createFileRoute('/clients')() @@ -52,6 +53,11 @@ const ProductsLazyRoute = ProductsLazyImport.update({ getParentRoute: () => rootRoute, } as any).lazy(() => import('./routes/products.lazy').then((d) => d.Route)) +const MarketplacesLazyRoute = MarketplacesLazyImport.update({ + path: '/marketplaces', + getParentRoute: () => rootRoute, +} as any).lazy(() => import('./routes/marketplaces.lazy').then((d) => d.Route)) + const LoginLazyRoute = LoginLazyImport.update({ path: '/login', getParentRoute: () => rootRoute, @@ -133,6 +139,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof LoginLazyImport parentRoute: typeof rootRoute } + '/marketplaces': { + id: '/marketplaces' + path: '/marketplaces' + fullPath: '/marketplaces' + preLoaderRoute: typeof MarketplacesLazyImport + parentRoute: typeof rootRoute + } '/products': { id: '/products' path: '/products' @@ -180,6 +193,7 @@ export const routeTree = rootRoute.addChildren({ ClientsLazyRoute, LeadsLazyRoute, LoginLazyRoute, + MarketplacesLazyRoute, ProductsLazyRoute, ServicesLazyRoute, ShippingwarehousesLazyRoute, @@ -201,6 +215,7 @@ export const routeTree = rootRoute.addChildren({ "/clients", "/leads", "/login", + "/marketplaces", "/products", "/services", "/shipping_warehouses", @@ -226,6 +241,9 @@ export const routeTree = rootRoute.addChildren({ "/login": { "filePath": "login.lazy.tsx" }, + "/marketplaces": { + "filePath": "marketplaces.lazy.tsx" + }, "/products": { "filePath": "products.lazy.tsx" }, diff --git a/src/routes/marketplaces.lazy.tsx b/src/routes/marketplaces.lazy.tsx new file mode 100644 index 0000000..6173aab --- /dev/null +++ b/src/routes/marketplaces.lazy.tsx @@ -0,0 +1,6 @@ +import {createLazyFileRoute} from '@tanstack/react-router' +import {MarketplacesPage} from "../pages/MarketplacesPage"; + +export const Route = createLazyFileRoute('/marketplaces')({ + component: MarketplacesPage +}) \ No newline at end of file diff --git a/src/shared/enums/BaseMarketplaceType.ts b/src/shared/enums/BaseMarketplaceType.ts new file mode 100644 index 0000000..abcd6f0 --- /dev/null +++ b/src/shared/enums/BaseMarketplaceType.ts @@ -0,0 +1,6 @@ +export enum BaseMarketplaceType { + WILDBERRIES = 'wb', + OZON = 'ozon', + YANDEX_MARKET = 'ym' + +} \ No newline at end of file diff --git a/src/shared/enums/TaskStatus.ts b/src/shared/enums/TaskStatus.ts new file mode 100644 index 0000000..a476706 --- /dev/null +++ b/src/shared/enums/TaskStatus.ts @@ -0,0 +1,7 @@ +export enum TaskStatus { + PENDING = "PENDING", + STARTED = "STARTED", + RETRY = "RETRY", + FAILURE = "FAILURE", + SUCCESS = "SUCCESS", +} \ No newline at end of file