Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -7,8 +7,6 @@ export { CancelablePromise, CancelError } from './core/CancelablePromise';
|
|||||||
export { OpenAPI } from './core/OpenAPI';
|
export { OpenAPI } from './core/OpenAPI';
|
||||||
export type { OpenAPIConfig } from './core/OpenAPI';
|
export type { OpenAPIConfig } from './core/OpenAPI';
|
||||||
|
|
||||||
export type { ActiveWorkShiftSchema } from './models/ActiveWorkShiftSchema';
|
|
||||||
export type { ActiveWorkShiftsResponse } from './models/ActiveWorkShiftsResponse';
|
|
||||||
export type { AuthLoginRequest } from './models/AuthLoginRequest';
|
export type { AuthLoginRequest } from './models/AuthLoginRequest';
|
||||||
export type { AuthLoginResponse } from './models/AuthLoginResponse';
|
export type { AuthLoginResponse } from './models/AuthLoginResponse';
|
||||||
export type { BarcodeAttributeSchema } from './models/BarcodeAttributeSchema';
|
export type { BarcodeAttributeSchema } from './models/BarcodeAttributeSchema';
|
||||||
@@ -30,6 +28,7 @@ export type { BaseMarketplaceSchema } from './models/BaseMarketplaceSchema';
|
|||||||
export type { BaseShippingWarehouseSchema } from './models/BaseShippingWarehouseSchema';
|
export type { BaseShippingWarehouseSchema } from './models/BaseShippingWarehouseSchema';
|
||||||
export type { BillPaymentStatus } from './models/BillPaymentStatus';
|
export type { BillPaymentStatus } from './models/BillPaymentStatus';
|
||||||
export type { BillStatusUpdateRequest } from './models/BillStatusUpdateRequest';
|
export type { BillStatusUpdateRequest } from './models/BillStatusUpdateRequest';
|
||||||
|
export type { Body_upload_passport_image } from './models/Body_upload_passport_image';
|
||||||
export type { Body_upload_product_barcode_image } from './models/Body_upload_product_barcode_image';
|
export type { Body_upload_product_barcode_image } from './models/Body_upload_product_barcode_image';
|
||||||
export type { Body_upload_product_image } from './models/Body_upload_product_image';
|
export type { Body_upload_product_image } from './models/Body_upload_product_image';
|
||||||
export type { CancelDealBillRequest } from './models/CancelDealBillRequest';
|
export type { CancelDealBillRequest } from './models/CancelDealBillRequest';
|
||||||
@@ -151,6 +150,8 @@ export type { DeleteShippingWarehouseRequest } from './models/DeleteShippingWare
|
|||||||
export type { DeleteShippingWarehouseResponse } from './models/DeleteShippingWarehouseResponse';
|
export type { DeleteShippingWarehouseResponse } from './models/DeleteShippingWarehouseResponse';
|
||||||
export type { ExpenseSchemaBase } from './models/ExpenseSchemaBase';
|
export type { ExpenseSchemaBase } from './models/ExpenseSchemaBase';
|
||||||
export type { ExpenseTagSchema } from './models/ExpenseTagSchema';
|
export type { ExpenseTagSchema } from './models/ExpenseTagSchema';
|
||||||
|
export type { FinishPauseByShiftIdResponse } from './models/FinishPauseByShiftIdResponse';
|
||||||
|
export type { FinishPauseByUserIdResponse } from './models/FinishPauseByUserIdResponse';
|
||||||
export type { FinishShiftByIdResponse } from './models/FinishShiftByIdResponse';
|
export type { FinishShiftByIdResponse } from './models/FinishShiftByIdResponse';
|
||||||
export type { FinishShiftResponse } from './models/FinishShiftResponse';
|
export type { FinishShiftResponse } from './models/FinishShiftResponse';
|
||||||
export type { GetAllBarcodeTemplateAttributesResponse } from './models/GetAllBarcodeTemplateAttributesResponse';
|
export type { GetAllBarcodeTemplateAttributesResponse } from './models/GetAllBarcodeTemplateAttributesResponse';
|
||||||
@@ -187,12 +188,14 @@ export type { GetProfitTableDataResponse } from './models/GetProfitTableDataResp
|
|||||||
export type { GetServiceKitSchema } from './models/GetServiceKitSchema';
|
export type { GetServiceKitSchema } from './models/GetServiceKitSchema';
|
||||||
export type { GetTimeTrackingRecordsRequest } from './models/GetTimeTrackingRecordsRequest';
|
export type { GetTimeTrackingRecordsRequest } from './models/GetTimeTrackingRecordsRequest';
|
||||||
export type { GetTimeTrackingRecordsResponse } from './models/GetTimeTrackingRecordsResponse';
|
export type { GetTimeTrackingRecordsResponse } from './models/GetTimeTrackingRecordsResponse';
|
||||||
|
export type { GetWorkShiftsResponse } from './models/GetWorkShiftsResponse';
|
||||||
export type { GroupBillRequestSchema } from './models/GroupBillRequestSchema';
|
export type { GroupBillRequestSchema } from './models/GroupBillRequestSchema';
|
||||||
export type { HTTPValidationError } from './models/HTTPValidationError';
|
export type { HTTPValidationError } from './models/HTTPValidationError';
|
||||||
export type { MarketplaceCreateSchema } from './models/MarketplaceCreateSchema';
|
export type { MarketplaceCreateSchema } from './models/MarketplaceCreateSchema';
|
||||||
export type { MarketplaceSchema } from './models/MarketplaceSchema';
|
export type { MarketplaceSchema } from './models/MarketplaceSchema';
|
||||||
export type { NotificationChannel } from './models/NotificationChannel';
|
export type { NotificationChannel } from './models/NotificationChannel';
|
||||||
export type { PaginationInfoSchema } from './models/PaginationInfoSchema';
|
export type { PaginationInfoSchema } from './models/PaginationInfoSchema';
|
||||||
|
export type { PassportImageSchema } from './models/PassportImageSchema';
|
||||||
export type { PaymentRecordCreateSchema } from './models/PaymentRecordCreateSchema';
|
export type { PaymentRecordCreateSchema } from './models/PaymentRecordCreateSchema';
|
||||||
export type { PaymentRecordGetSchema } from './models/PaymentRecordGetSchema';
|
export type { PaymentRecordGetSchema } from './models/PaymentRecordGetSchema';
|
||||||
export type { PayRateSchema } from './models/PayRateSchema';
|
export type { PayRateSchema } from './models/PayRateSchema';
|
||||||
@@ -246,6 +249,8 @@ export type { ServiceUpdateCategoryResponse } from './models/ServiceUpdateCatego
|
|||||||
export type { ServiceUpdateRequest } from './models/ServiceUpdateRequest';
|
export type { ServiceUpdateRequest } from './models/ServiceUpdateRequest';
|
||||||
export type { ServiceUpdateResponse } from './models/ServiceUpdateResponse';
|
export type { ServiceUpdateResponse } from './models/ServiceUpdateResponse';
|
||||||
export type { ShippingWarehouseSchema } from './models/ShippingWarehouseSchema';
|
export type { ShippingWarehouseSchema } from './models/ShippingWarehouseSchema';
|
||||||
|
export type { StartPauseByShiftIdResponse } from './models/StartPauseByShiftIdResponse';
|
||||||
|
export type { StartPauseByUserIdResponse } from './models/StartPauseByUserIdResponse';
|
||||||
export type { StartShiftResponse } from './models/StartShiftResponse';
|
export type { StartShiftResponse } from './models/StartShiftResponse';
|
||||||
export type { SynchronizeMarketplaceRequest } from './models/SynchronizeMarketplaceRequest';
|
export type { SynchronizeMarketplaceRequest } from './models/SynchronizeMarketplaceRequest';
|
||||||
export type { TaskInfoResponse } from './models/TaskInfoResponse';
|
export type { TaskInfoResponse } from './models/TaskInfoResponse';
|
||||||
@@ -271,10 +276,13 @@ export type { UpdateTimeTrackingRecordRequest } from './models/UpdateTimeTrackin
|
|||||||
export type { UpdateTimeTrackingRecordResponse } from './models/UpdateTimeTrackingRecordResponse';
|
export type { UpdateTimeTrackingRecordResponse } from './models/UpdateTimeTrackingRecordResponse';
|
||||||
export type { UpdateUserRequest } from './models/UpdateUserRequest';
|
export type { UpdateUserRequest } from './models/UpdateUserRequest';
|
||||||
export type { UpdateUserResponse } from './models/UpdateUserResponse';
|
export type { UpdateUserResponse } from './models/UpdateUserResponse';
|
||||||
|
export type { UploadPassportImageResponse } from './models/UploadPassportImageResponse';
|
||||||
export type { UserCreate } from './models/UserCreate';
|
export type { UserCreate } from './models/UserCreate';
|
||||||
export type { UserSchema } from './models/UserSchema';
|
export type { UserSchema } from './models/UserSchema';
|
||||||
export type { UserUpdate } from './models/UserUpdate';
|
export type { UserUpdate } from './models/UserUpdate';
|
||||||
export type { ValidationError } from './models/ValidationError';
|
export type { ValidationError } from './models/ValidationError';
|
||||||
|
export type { WorkShiftRowSchema } from './models/WorkShiftRowSchema';
|
||||||
|
export type { WorkShiftSchema } from './models/WorkShiftSchema';
|
||||||
|
|
||||||
export { AuthService } from './services/AuthService';
|
export { AuthService } from './services/AuthService';
|
||||||
export { BarcodeService } from './services/BarcodeService';
|
export { BarcodeService } from './services/BarcodeService';
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
/* generated using openapi-typescript-codegen -- do not edit */
|
|
||||||
/* istanbul ignore file */
|
|
||||||
/* tslint:disable */
|
|
||||||
/* eslint-disable */
|
|
||||||
import type { ActiveWorkShiftSchema } from './ActiveWorkShiftSchema';
|
|
||||||
export type ActiveWorkShiftsResponse = {
|
|
||||||
shifts: Array<ActiveWorkShiftSchema>;
|
|
||||||
};
|
|
||||||
|
|
||||||
8
src/client/models/Body_upload_passport_image.ts
Normal file
8
src/client/models/Body_upload_passport_image.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
/* generated using openapi-typescript-codegen -- do not edit */
|
||||||
|
/* istanbul ignore file */
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
export type Body_upload_passport_image = {
|
||||||
|
upload_file: Blob;
|
||||||
|
};
|
||||||
|
|
||||||
9
src/client/models/FinishPauseByShiftIdResponse.ts
Normal file
9
src/client/models/FinishPauseByShiftIdResponse.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
/* generated using openapi-typescript-codegen -- do not edit */
|
||||||
|
/* istanbul ignore file */
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
export type FinishPauseByShiftIdResponse = {
|
||||||
|
ok: boolean;
|
||||||
|
message: string;
|
||||||
|
};
|
||||||
|
|
||||||
9
src/client/models/FinishPauseByUserIdResponse.ts
Normal file
9
src/client/models/FinishPauseByUserIdResponse.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
/* generated using openapi-typescript-codegen -- do not edit */
|
||||||
|
/* istanbul ignore file */
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
export type FinishPauseByUserIdResponse = {
|
||||||
|
ok: boolean;
|
||||||
|
message: string;
|
||||||
|
};
|
||||||
|
|
||||||
11
src/client/models/GetWorkShiftsResponse.ts
Normal file
11
src/client/models/GetWorkShiftsResponse.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
/* generated using openapi-typescript-codegen -- do not edit */
|
||||||
|
/* istanbul ignore file */
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
import type { PaginationInfoSchema } from './PaginationInfoSchema';
|
||||||
|
import type { WorkShiftRowSchema } from './WorkShiftRowSchema';
|
||||||
|
export type GetWorkShiftsResponse = {
|
||||||
|
shifts: Array<WorkShiftRowSchema>;
|
||||||
|
paginationInfo: PaginationInfoSchema;
|
||||||
|
};
|
||||||
|
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
/* tslint:disable */
|
/* tslint:disable */
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
export type PaginationInfoSchema = {
|
export type PaginationInfoSchema = {
|
||||||
totalPages?: number;
|
totalPages: number;
|
||||||
totalItems?: number;
|
totalItems: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
10
src/client/models/PassportImageSchema.ts
Normal file
10
src/client/models/PassportImageSchema.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
/* generated using openapi-typescript-codegen -- do not edit */
|
||||||
|
/* istanbul ignore file */
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
export type PassportImageSchema = {
|
||||||
|
id: number;
|
||||||
|
userId: number;
|
||||||
|
imageUrl: string;
|
||||||
|
};
|
||||||
|
|
||||||
9
src/client/models/StartPauseByShiftIdResponse.ts
Normal file
9
src/client/models/StartPauseByShiftIdResponse.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
/* generated using openapi-typescript-codegen -- do not edit */
|
||||||
|
/* istanbul ignore file */
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
export type StartPauseByShiftIdResponse = {
|
||||||
|
ok: boolean;
|
||||||
|
message: string;
|
||||||
|
};
|
||||||
|
|
||||||
9
src/client/models/StartPauseByUserIdResponse.ts
Normal file
9
src/client/models/StartPauseByUserIdResponse.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
/* generated using openapi-typescript-codegen -- do not edit */
|
||||||
|
/* istanbul ignore file */
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
export type StartPauseByUserIdResponse = {
|
||||||
|
ok: boolean;
|
||||||
|
message: string;
|
||||||
|
};
|
||||||
|
|
||||||
10
src/client/models/UploadPassportImageResponse.ts
Normal file
10
src/client/models/UploadPassportImageResponse.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
/* generated using openapi-typescript-codegen -- do not edit */
|
||||||
|
/* istanbul ignore file */
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
export type UploadPassportImageResponse = {
|
||||||
|
ok: boolean;
|
||||||
|
message: string;
|
||||||
|
imageUrl?: (string | null);
|
||||||
|
};
|
||||||
|
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
/* istanbul ignore file */
|
/* istanbul ignore file */
|
||||||
/* tslint:disable */
|
/* tslint:disable */
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
|
import type { PassportImageSchema } from './PassportImageSchema';
|
||||||
import type { PayRateSchema } from './PayRateSchema';
|
import type { PayRateSchema } from './PayRateSchema';
|
||||||
export type UserCreate = {
|
export type UserCreate = {
|
||||||
telegramId: number;
|
telegramId: number;
|
||||||
@@ -16,6 +17,8 @@ export type UserCreate = {
|
|||||||
isDeleted: boolean;
|
isDeleted: boolean;
|
||||||
roleKey: string;
|
roleKey: string;
|
||||||
payRate?: (PayRateSchema | null);
|
payRate?: (PayRateSchema | null);
|
||||||
|
passportImageUrl?: (string | null);
|
||||||
|
passportImages?: (Array<PassportImageSchema> | null);
|
||||||
positionKey?: (string | null);
|
positionKey?: (string | null);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
/* istanbul ignore file */
|
/* istanbul ignore file */
|
||||||
/* tslint:disable */
|
/* tslint:disable */
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
|
import type { PassportImageSchema } from './PassportImageSchema';
|
||||||
import type { PayRateSchema } from './PayRateSchema';
|
import type { PayRateSchema } from './PayRateSchema';
|
||||||
import type { PositionSchema } from './PositionSchema';
|
import type { PositionSchema } from './PositionSchema';
|
||||||
import type { RoleSchema } from './RoleSchema';
|
import type { RoleSchema } from './RoleSchema';
|
||||||
@@ -18,6 +19,8 @@ export type UserSchema = {
|
|||||||
isDeleted: boolean;
|
isDeleted: boolean;
|
||||||
roleKey: string;
|
roleKey: string;
|
||||||
payRate?: (PayRateSchema | null);
|
payRate?: (PayRateSchema | null);
|
||||||
|
passportImageUrl?: (string | null);
|
||||||
|
passportImages?: (Array<PassportImageSchema> | null);
|
||||||
id: number;
|
id: number;
|
||||||
role: RoleSchema;
|
role: RoleSchema;
|
||||||
position?: (PositionSchema | null);
|
position?: (PositionSchema | null);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
/* istanbul ignore file */
|
/* istanbul ignore file */
|
||||||
/* tslint:disable */
|
/* tslint:disable */
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
|
import type { PassportImageSchema } from './PassportImageSchema';
|
||||||
import type { PayRateSchema } from './PayRateSchema';
|
import type { PayRateSchema } from './PayRateSchema';
|
||||||
export type UserUpdate = {
|
export type UserUpdate = {
|
||||||
telegramId: number;
|
telegramId: number;
|
||||||
@@ -16,6 +17,8 @@ export type UserUpdate = {
|
|||||||
isDeleted: boolean;
|
isDeleted: boolean;
|
||||||
roleKey: string;
|
roleKey: string;
|
||||||
payRate?: (PayRateSchema | null);
|
payRate?: (PayRateSchema | null);
|
||||||
|
passportImageUrl?: (string | null);
|
||||||
|
passportImages?: (Array<PassportImageSchema> | null);
|
||||||
id: number;
|
id: number;
|
||||||
positionKey?: (string | null);
|
positionKey?: (string | null);
|
||||||
};
|
};
|
||||||
|
|||||||
11
src/client/models/WorkShiftRowSchema.ts
Normal file
11
src/client/models/WorkShiftRowSchema.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
/* generated using openapi-typescript-codegen -- do not edit */
|
||||||
|
/* istanbul ignore file */
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
import type { WorkShiftSchema } from './WorkShiftSchema';
|
||||||
|
export type WorkShiftRowSchema = {
|
||||||
|
workShift: WorkShiftSchema;
|
||||||
|
totalHours?: (number | null);
|
||||||
|
pauseHours?: (number | null);
|
||||||
|
};
|
||||||
|
|
||||||
@@ -3,9 +3,11 @@
|
|||||||
/* tslint:disable */
|
/* tslint:disable */
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
import type { UserSchema } from './UserSchema';
|
import type { UserSchema } from './UserSchema';
|
||||||
export type ActiveWorkShiftSchema = {
|
export type WorkShiftSchema = {
|
||||||
id: number;
|
id: number;
|
||||||
startedAt: string;
|
startedAt: string;
|
||||||
|
finishedAt?: (string | null);
|
||||||
|
isPaused?: (boolean | null);
|
||||||
user: UserSchema;
|
user: UserSchema;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -2,12 +2,14 @@
|
|||||||
/* istanbul ignore file */
|
/* istanbul ignore file */
|
||||||
/* tslint:disable */
|
/* tslint:disable */
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
|
import type { Body_upload_passport_image } from '../models/Body_upload_passport_image';
|
||||||
import type { CreateUserRequest } from '../models/CreateUserRequest';
|
import type { CreateUserRequest } from '../models/CreateUserRequest';
|
||||||
import type { CreateUserResponse } from '../models/CreateUserResponse';
|
import type { CreateUserResponse } from '../models/CreateUserResponse';
|
||||||
import type { GetAllUsersResponse } from '../models/GetAllUsersResponse';
|
import type { GetAllUsersResponse } from '../models/GetAllUsersResponse';
|
||||||
import type { GetManagersResponse } from '../models/GetManagersResponse';
|
import type { GetManagersResponse } from '../models/GetManagersResponse';
|
||||||
import type { UpdateUserRequest } from '../models/UpdateUserRequest';
|
import type { UpdateUserRequest } from '../models/UpdateUserRequest';
|
||||||
import type { UpdateUserResponse } from '../models/UpdateUserResponse';
|
import type { UpdateUserResponse } from '../models/UpdateUserResponse';
|
||||||
|
import type { UploadPassportImageResponse } from '../models/UploadPassportImageResponse';
|
||||||
import type { CancelablePromise } from '../core/CancelablePromise';
|
import type { CancelablePromise } from '../core/CancelablePromise';
|
||||||
import { OpenAPI } from '../core/OpenAPI';
|
import { OpenAPI } from '../core/OpenAPI';
|
||||||
import { request as __request } from '../core/request';
|
import { request as __request } from '../core/request';
|
||||||
@@ -74,4 +76,29 @@ export class UserService {
|
|||||||
url: '/user/get-managers',
|
url: '/user/get-managers',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Upload Passport Image
|
||||||
|
* @returns UploadPassportImageResponse Successful Response
|
||||||
|
* @throws ApiError
|
||||||
|
*/
|
||||||
|
public static uploadPassportImage({
|
||||||
|
userId,
|
||||||
|
formData,
|
||||||
|
}: {
|
||||||
|
userId: number,
|
||||||
|
formData: Body_upload_passport_image,
|
||||||
|
}): CancelablePromise<UploadPassportImageResponse> {
|
||||||
|
return __request(OpenAPI, {
|
||||||
|
method: 'POST',
|
||||||
|
url: '/user/passport-images/upload/{user_id}',
|
||||||
|
path: {
|
||||||
|
'user_id': userId,
|
||||||
|
},
|
||||||
|
formData: formData,
|
||||||
|
mediaType: 'multipart/form-data',
|
||||||
|
errors: {
|
||||||
|
422: `Validation Error`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,14 @@
|
|||||||
/* istanbul ignore file */
|
/* istanbul ignore file */
|
||||||
/* tslint:disable */
|
/* tslint:disable */
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
import type { ActiveWorkShiftsResponse } from '../models/ActiveWorkShiftsResponse';
|
|
||||||
import type { DeleteShiftResponse } from '../models/DeleteShiftResponse';
|
import type { DeleteShiftResponse } from '../models/DeleteShiftResponse';
|
||||||
|
import type { FinishPauseByShiftIdResponse } from '../models/FinishPauseByShiftIdResponse';
|
||||||
|
import type { FinishPauseByUserIdResponse } from '../models/FinishPauseByUserIdResponse';
|
||||||
import type { FinishShiftByIdResponse } from '../models/FinishShiftByIdResponse';
|
import type { FinishShiftByIdResponse } from '../models/FinishShiftByIdResponse';
|
||||||
import type { FinishShiftResponse } from '../models/FinishShiftResponse';
|
import type { FinishShiftResponse } from '../models/FinishShiftResponse';
|
||||||
|
import type { GetWorkShiftsResponse } from '../models/GetWorkShiftsResponse';
|
||||||
|
import type { StartPauseByShiftIdResponse } from '../models/StartPauseByShiftIdResponse';
|
||||||
|
import type { StartPauseByUserIdResponse } from '../models/StartPauseByUserIdResponse';
|
||||||
import type { StartShiftResponse } from '../models/StartShiftResponse';
|
import type { StartShiftResponse } from '../models/StartShiftResponse';
|
||||||
import type { CancelablePromise } from '../core/CancelablePromise';
|
import type { CancelablePromise } from '../core/CancelablePromise';
|
||||||
import { OpenAPI } from '../core/OpenAPI';
|
import { OpenAPI } from '../core/OpenAPI';
|
||||||
@@ -96,14 +100,32 @@ export class WorkShiftsService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Get Active Shifts
|
* Get Shifts
|
||||||
* @returns ActiveWorkShiftsResponse Successful Response
|
* @returns GetWorkShiftsResponse Successful Response
|
||||||
* @throws ApiError
|
* @throws ApiError
|
||||||
*/
|
*/
|
||||||
public static getActiveShifts(): CancelablePromise<ActiveWorkShiftsResponse> {
|
public static getShifts({
|
||||||
|
isActive,
|
||||||
|
page,
|
||||||
|
itemsPerPage,
|
||||||
|
}: {
|
||||||
|
isActive: boolean,
|
||||||
|
page?: (number | null),
|
||||||
|
itemsPerPage?: (number | null),
|
||||||
|
}): CancelablePromise<GetWorkShiftsResponse> {
|
||||||
return __request(OpenAPI, {
|
return __request(OpenAPI, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url: '/work-shifts/get-active-shifts',
|
url: '/work-shifts/get-shifts/{is_active}',
|
||||||
|
path: {
|
||||||
|
'is_active': isActive,
|
||||||
|
},
|
||||||
|
query: {
|
||||||
|
'page': page,
|
||||||
|
'items_per_page': itemsPerPage,
|
||||||
|
},
|
||||||
|
errors: {
|
||||||
|
422: `Validation Error`,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@@ -127,4 +149,88 @@ export class WorkShiftsService {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Start Pause By Shift Id
|
||||||
|
* @returns StartPauseByShiftIdResponse Successful Response
|
||||||
|
* @throws ApiError
|
||||||
|
*/
|
||||||
|
public static startPauseByShiftId({
|
||||||
|
shiftId,
|
||||||
|
}: {
|
||||||
|
shiftId: number,
|
||||||
|
}): CancelablePromise<StartPauseByShiftIdResponse> {
|
||||||
|
return __request(OpenAPI, {
|
||||||
|
method: 'POST',
|
||||||
|
url: '/work-shifts/pause/start/{shift_id}',
|
||||||
|
path: {
|
||||||
|
'shift_id': shiftId,
|
||||||
|
},
|
||||||
|
errors: {
|
||||||
|
422: `Validation Error`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Start Pause By User Id
|
||||||
|
* @returns StartPauseByUserIdResponse Successful Response
|
||||||
|
* @throws ApiError
|
||||||
|
*/
|
||||||
|
public static startPauseByUserId({
|
||||||
|
userId,
|
||||||
|
}: {
|
||||||
|
userId: number,
|
||||||
|
}): CancelablePromise<StartPauseByUserIdResponse> {
|
||||||
|
return __request(OpenAPI, {
|
||||||
|
method: 'POST',
|
||||||
|
url: '/work-shifts/pause/start/for-user/{user_id}',
|
||||||
|
path: {
|
||||||
|
'user_id': userId,
|
||||||
|
},
|
||||||
|
errors: {
|
||||||
|
422: `Validation Error`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Finish Pause By Shift Id
|
||||||
|
* @returns FinishPauseByShiftIdResponse Successful Response
|
||||||
|
* @throws ApiError
|
||||||
|
*/
|
||||||
|
public static finishPauseByShiftId({
|
||||||
|
shiftId,
|
||||||
|
}: {
|
||||||
|
shiftId: number,
|
||||||
|
}): CancelablePromise<FinishPauseByShiftIdResponse> {
|
||||||
|
return __request(OpenAPI, {
|
||||||
|
method: 'POST',
|
||||||
|
url: '/work-shifts/pause/finish/{shift_id}',
|
||||||
|
path: {
|
||||||
|
'shift_id': shiftId,
|
||||||
|
},
|
||||||
|
errors: {
|
||||||
|
422: `Validation Error`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Finish Pause By User Id
|
||||||
|
* @returns FinishPauseByUserIdResponse Successful Response
|
||||||
|
* @throws ApiError
|
||||||
|
*/
|
||||||
|
public static finishPauseByUserId({
|
||||||
|
userId,
|
||||||
|
}: {
|
||||||
|
userId: number,
|
||||||
|
}): CancelablePromise<FinishPauseByUserIdResponse> {
|
||||||
|
return __request(OpenAPI, {
|
||||||
|
method: 'POST',
|
||||||
|
url: '/work-shifts/pause/finish/for-user/{shift_id}',
|
||||||
|
query: {
|
||||||
|
'user_id': userId,
|
||||||
|
},
|
||||||
|
errors: {
|
||||||
|
422: `Validation Error`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,77 +1,34 @@
|
|||||||
import { Dropzone, DropzoneProps, FileWithPath } from "@mantine/dropzone";
|
import { Dropzone, DropzoneProps, FileWithPath } from "@mantine/dropzone";
|
||||||
import { FC, useState } from "react";
|
import { FC } from "react";
|
||||||
import {
|
import { Button, Fieldset, Flex, Group, Image, Loader, rem, Text } from "@mantine/core";
|
||||||
Button,
|
|
||||||
Fieldset,
|
|
||||||
Flex,
|
|
||||||
Group,
|
|
||||||
Image,
|
|
||||||
Loader,
|
|
||||||
rem,
|
|
||||||
Text,
|
|
||||||
} from "@mantine/core";
|
|
||||||
import { IconPhoto, IconUpload, IconX } from "@tabler/icons-react";
|
import { IconPhoto, IconUpload, IconX } from "@tabler/icons-react";
|
||||||
import { omit } from "lodash";
|
import { omit } from "lodash";
|
||||||
import { BaseFormInputProps } from "../../types/utils.ts";
|
import UseImageDropzone from "../../types/UseImageDropzone.tsx";
|
||||||
import { notifications } from "../../shared/lib/notifications.ts";
|
|
||||||
import { ProductService } from "../../client";
|
|
||||||
|
|
||||||
interface RestProps {
|
interface RestProps {
|
||||||
imageUrlInputProps?: BaseFormInputProps<string>;
|
imageDropzone: UseImageDropzone;
|
||||||
productId?: number;
|
onDrop: (files: FileWithPath[]) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
type Props = Omit<DropzoneProps, "onDrop"> & RestProps;
|
type Props = Omit<DropzoneProps, "onDrop"> & RestProps;
|
||||||
|
|
||||||
const ImageDropzone: FC<Props> = (props: Props) => {
|
const ImageDropzone: FC<Props> = (props: Props) => {
|
||||||
const [showDropzone, setShowDropzone] = useState(
|
const {
|
||||||
!(
|
showDropzone,
|
||||||
typeof props.imageUrlInputProps?.value === "string" &&
|
setShowDropzone,
|
||||||
props.imageUrlInputProps.value.trim() !== ""
|
isLoading,
|
||||||
)
|
imageUrlInputProps,
|
||||||
);
|
} = props.imageDropzone;
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
|
||||||
const restProps = omit(props, [
|
const restProps = omit(props, [
|
||||||
"imageUrl",
|
"imageUrl",
|
||||||
"productId",
|
"productId",
|
||||||
"imageUrlInputProps",
|
"imageUrlInputProps",
|
||||||
]);
|
]);
|
||||||
const onDrop = (files: FileWithPath[]) => {
|
|
||||||
if (!props.productId || !props.imageUrlInputProps) return;
|
|
||||||
if (files.length > 1) {
|
|
||||||
notifications.error({ message: "Прикрепите одно изображение" });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const file = files[0];
|
|
||||||
// TODO check if file is image
|
|
||||||
setIsLoading(true);
|
|
||||||
ProductService.uploadProductImage({
|
|
||||||
productId: props.productId,
|
|
||||||
formData: {
|
|
||||||
upload_file: file,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.then(({ ok, message, imageUrl }) => {
|
|
||||||
notifications.guess(ok, { message });
|
|
||||||
setIsLoading(false);
|
|
||||||
|
|
||||||
if (!ok || !imageUrl) {
|
|
||||||
setShowDropzone(true);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
props.imageUrlInputProps?.onChange(imageUrl);
|
|
||||||
setShowDropzone(false);
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
notifications.error({ message: error.toString() });
|
|
||||||
setShowDropzone(true);
|
|
||||||
setIsLoading(false);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
const getBody = () => {
|
const getBody = () => {
|
||||||
return props.imageUrlInputProps?.value && !showDropzone ? (
|
return imageUrlInputProps?.value && !showDropzone ? (
|
||||||
<Image src={props.imageUrlInputProps.value} />
|
<Image src={imageUrlInputProps.value} />
|
||||||
) : (
|
) : (
|
||||||
<Dropzone
|
<Dropzone
|
||||||
{...restProps}
|
{...restProps}
|
||||||
@@ -87,7 +44,7 @@ const ImageDropzone: FC<Props> = (props: Props) => {
|
|||||||
"image/heic",
|
"image/heic",
|
||||||
]}
|
]}
|
||||||
multiple={false}
|
multiple={false}
|
||||||
onDrop={onDrop}>
|
onDrop={props.onDrop}>
|
||||||
<Group
|
<Group
|
||||||
justify="center"
|
justify="center"
|
||||||
gap="xl"
|
gap="xl"
|
||||||
|
|||||||
26
src/hooks/useImageDropzone.tsx
Normal file
26
src/hooks/useImageDropzone.tsx
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { useState } from "react";
|
||||||
|
import { BaseFormInputProps } from "../types/utils.ts";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
imageUrlInputProps?: BaseFormInputProps<string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const useImageDropzone = ({ imageUrlInputProps }: Props) => {
|
||||||
|
const [showDropzone, setShowDropzone] = useState(
|
||||||
|
!(
|
||||||
|
typeof imageUrlInputProps?.value === "string" &&
|
||||||
|
imageUrlInputProps.value.trim() !== ""
|
||||||
|
),
|
||||||
|
);
|
||||||
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
|
||||||
|
return {
|
||||||
|
showDropzone,
|
||||||
|
setShowDropzone,
|
||||||
|
isLoading,
|
||||||
|
setIsLoading,
|
||||||
|
imageUrlInputProps,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useImageDropzone;
|
||||||
@@ -1,116 +0,0 @@
|
|||||||
import { BaseTable } from "../../../../components/BaseTable/BaseTable.tsx";
|
|
||||||
import { useActiveShiftsTableColumns } from "./columns.tsx";
|
|
||||||
import { ActionIcon, Flex, Stack, Text, Title, Tooltip } from "@mantine/core";
|
|
||||||
import { IconCheck, IconTrash } from "@tabler/icons-react";
|
|
||||||
import { ActiveWorkShiftSchema, WorkShiftsService } from "../../../../client";
|
|
||||||
import { modals } from "@mantine/modals";
|
|
||||||
import { formatDate } from "../../../../types/utils.ts";
|
|
||||||
import { MRT_TableOptions } from "mantine-react-table";
|
|
||||||
import { notifications } from "../../../../shared/lib/notifications.ts";
|
|
||||||
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
activeShifts: ActiveWorkShiftSchema[];
|
|
||||||
fetchActiveShifts: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ActiveShiftsTable = ({ activeShifts, fetchActiveShifts }: Props) => {
|
|
||||||
const columns = useActiveShiftsTableColumns();
|
|
||||||
|
|
||||||
const onDelete = (workShift: ActiveWorkShiftSchema) => {
|
|
||||||
WorkShiftsService.deleteWorkShift({
|
|
||||||
shiftId: workShift.id,
|
|
||||||
})
|
|
||||||
.then(({ ok, message }) => {
|
|
||||||
notifications.guess(ok, { message });
|
|
||||||
fetchActiveShifts();
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
console.log(err);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const onDeleteClick = (workShift: ActiveWorkShiftSchema) => {
|
|
||||||
modals.openConfirmModal({
|
|
||||||
title: "Удаление записи о начале смены",
|
|
||||||
children: (
|
|
||||||
<Text size="sm">
|
|
||||||
Вы уверены что хотите удалить запись о начале смены работника{" "}
|
|
||||||
{workShift.user.firstName} {workShift.user.secondName} от{" "}
|
|
||||||
{formatDate(workShift.startedAt)}
|
|
||||||
</Text>
|
|
||||||
),
|
|
||||||
labels: { confirm: "Да", cancel: "Нет" },
|
|
||||||
confirmProps: { color: "red" },
|
|
||||||
onConfirm: () => onDelete(workShift),
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const onShiftFinish = (workShift: ActiveWorkShiftSchema) => {
|
|
||||||
WorkShiftsService.finishWorkShiftById({
|
|
||||||
shiftId: workShift.id,
|
|
||||||
})
|
|
||||||
.then(({ ok, message }) => {
|
|
||||||
notifications.guess(ok, { message });
|
|
||||||
fetchActiveShifts();
|
|
||||||
})
|
|
||||||
.catch(err => console.log(err));
|
|
||||||
}
|
|
||||||
|
|
||||||
const onShiftFinishClick = (workShift: ActiveWorkShiftSchema) => {
|
|
||||||
modals.openConfirmModal({
|
|
||||||
title: "Завершение смены",
|
|
||||||
children: (
|
|
||||||
<Text size="sm">
|
|
||||||
Вы уверены что хотите завершить смену работника{" "}
|
|
||||||
{workShift.user.firstName} {workShift.user.secondName} от{" "}
|
|
||||||
{formatDate(workShift.startedAt)}
|
|
||||||
</Text>
|
|
||||||
),
|
|
||||||
labels: { confirm: "Да", cancel: "Нет" },
|
|
||||||
confirmProps: { color: "red" },
|
|
||||||
onConfirm: () => onShiftFinish(workShift),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Stack mx={"xs"}>
|
|
||||||
<Title order={4} mt={"md"}>
|
|
||||||
Активные смены
|
|
||||||
</Title>
|
|
||||||
<BaseTable
|
|
||||||
data={activeShifts}
|
|
||||||
columns={columns}
|
|
||||||
restProps={
|
|
||||||
{
|
|
||||||
enableRowActions: true,
|
|
||||||
enableSorting: true,
|
|
||||||
enableColumnActions: false,
|
|
||||||
renderRowActions: ({ row }) => (
|
|
||||||
<Flex gap="md">
|
|
||||||
<Tooltip label="Удалить">
|
|
||||||
<ActionIcon
|
|
||||||
onClick={() =>
|
|
||||||
onDeleteClick(row.original)
|
|
||||||
}
|
|
||||||
variant={"default"}>
|
|
||||||
<IconTrash />
|
|
||||||
</ActionIcon>
|
|
||||||
</Tooltip>
|
|
||||||
<Tooltip label="Завершить смену">
|
|
||||||
<ActionIcon
|
|
||||||
onClick={() =>
|
|
||||||
onShiftFinishClick(row.original)
|
|
||||||
}
|
|
||||||
variant={"default"}>
|
|
||||||
<IconCheck />
|
|
||||||
</ActionIcon>
|
|
||||||
</Tooltip>
|
|
||||||
</Flex>
|
|
||||||
),
|
|
||||||
} as MRT_TableOptions<ActiveWorkShiftSchema>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Stack>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
import { useMemo } from "react";
|
|
||||||
import { MRT_ColumnDef } from "mantine-react-table";
|
|
||||||
import { ActiveWorkShiftSchema } from "../../../../client";
|
|
||||||
|
|
||||||
export const useActiveShiftsTableColumns = () => {
|
|
||||||
return useMemo<MRT_ColumnDef<ActiveWorkShiftSchema>[]>(
|
|
||||||
() => [
|
|
||||||
{
|
|
||||||
header: "Начало смены",
|
|
||||||
accessorKey: "startedAt",
|
|
||||||
Cell: ({ row }) =>
|
|
||||||
new Date(row.original.startedAt).toLocaleString("ru-RU"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
header: "ФИО",
|
|
||||||
Cell: ({ row }) =>
|
|
||||||
`${row.original.user.firstName} ${row.original.user.secondName}`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
header: "Роль",
|
|
||||||
accessorKey: "user.role.name",
|
|
||||||
enableSorting: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
header: "Должность",
|
|
||||||
accessorKey: "user.position.name",
|
|
||||||
enableSorting: false,
|
|
||||||
}
|
|
||||||
],
|
|
||||||
[]
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
import { DropzoneProps, FileWithPath } from "@mantine/dropzone";
|
||||||
|
import { FC } from "react";
|
||||||
|
import { notifications } from "../../../../shared/lib/notifications.ts";
|
||||||
|
import { UserService } from "../../../../client";
|
||||||
|
import { BaseFormInputProps } from "../../../../types/utils.ts";
|
||||||
|
import useImageDropzone from "../../../../hooks/useImageDropzone.tsx";
|
||||||
|
import ImageDropzone from "../../../../components/ImageDropzone/ImageDropzone.tsx";
|
||||||
|
|
||||||
|
interface RestProps {
|
||||||
|
imageUrlInputProps?: BaseFormInputProps<string>;
|
||||||
|
userId?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
type Props = Omit<DropzoneProps, "onDrop"> & RestProps;
|
||||||
|
|
||||||
|
const ProductImageDropzone: FC<Props> = ({ imageUrlInputProps, userId }: Props) => {
|
||||||
|
const imageDropzoneProps = useImageDropzone({
|
||||||
|
imageUrlInputProps,
|
||||||
|
});
|
||||||
|
|
||||||
|
const onDrop = (files: FileWithPath[]) => {
|
||||||
|
if (!userId || !imageUrlInputProps) return;
|
||||||
|
if (files.length > 1) {
|
||||||
|
notifications.error({ message: "Прикрепите одно изображение" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const { setIsLoading, setShowDropzone } = imageDropzoneProps;
|
||||||
|
const file = files[0];
|
||||||
|
|
||||||
|
setIsLoading(true);
|
||||||
|
UserService.uploadPassportImage({
|
||||||
|
userId: userId,
|
||||||
|
formData: {
|
||||||
|
upload_file: file,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then(({ ok, message, imageUrl }) => {
|
||||||
|
notifications.guess(ok, { message });
|
||||||
|
setIsLoading(false);
|
||||||
|
|
||||||
|
if (!ok || !imageUrl) {
|
||||||
|
setShowDropzone(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
imageUrlInputProps?.onChange(imageUrl);
|
||||||
|
setShowDropzone(false);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
notifications.error({ message: error.toString() });
|
||||||
|
setShowDropzone(true);
|
||||||
|
setIsLoading(false);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ImageDropzone onDrop={onDrop} imageDropzone={imageDropzoneProps} />
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ProductImageDropzone;
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import { SegmentedControl, SegmentedControlProps } from "@mantine/core";
|
||||||
|
import { FC } from "react";
|
||||||
|
|
||||||
|
export enum ShiftsTableType {
|
||||||
|
ACTIVE,
|
||||||
|
HISTORY,
|
||||||
|
}
|
||||||
|
|
||||||
|
type Props = Omit<SegmentedControlProps, "data">;
|
||||||
|
const data = [
|
||||||
|
{
|
||||||
|
label: "Активные смены",
|
||||||
|
value: ShiftsTableType.ACTIVE.toString(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Завершенные смены",
|
||||||
|
value: ShiftsTableType.HISTORY.toString(),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const ShiftsTableSegmentedControl: FC<Props> = props => {
|
||||||
|
return (
|
||||||
|
<SegmentedControl
|
||||||
|
data={data}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -10,6 +10,8 @@ import { capitalize } from "lodash";
|
|||||||
import { IMaskInput } from "react-imask";
|
import { IMaskInput } from "react-imask";
|
||||||
import phone from "phone";
|
import phone from "phone";
|
||||||
import PayRateSelect from "../../../../components/Selects/PayRateSelect/PayRateSelect.tsx";
|
import PayRateSelect from "../../../../components/Selects/PayRateSelect/PayRateSelect.tsx";
|
||||||
|
import { BaseFormInputProps } from "../../../../types/utils.ts";
|
||||||
|
import PassportImageDropzone from "../../components/PassportImageDropzone/PassportImageDropzone.tsx";
|
||||||
|
|
||||||
type Props = CreateEditFormProps<UserSchema>;
|
type Props = CreateEditFormProps<UserSchema>;
|
||||||
const UserFormModal = ({
|
const UserFormModal = ({
|
||||||
@@ -107,6 +109,10 @@ const UserFormModal = ({
|
|||||||
{...form.getInputProps("phoneNumber")}
|
{...form.getInputProps("phoneNumber")}
|
||||||
/>
|
/>
|
||||||
</Input.Wrapper>
|
</Input.Wrapper>
|
||||||
|
</Stack>
|
||||||
|
</Fieldset>
|
||||||
|
<Fieldset legend={"Паспортные данные"}>
|
||||||
|
<Stack>
|
||||||
<Input.Wrapper
|
<Input.Wrapper
|
||||||
label={"Серия и номер паспорта"}
|
label={"Серия и номер паспорта"}
|
||||||
error={form.getInputProps("passportData").error}>
|
error={form.getInputProps("passportData").error}>
|
||||||
@@ -117,6 +123,18 @@ const UserFormModal = ({
|
|||||||
{...form.getInputProps("passportData")}
|
{...form.getInputProps("passportData")}
|
||||||
/>
|
/>
|
||||||
</Input.Wrapper>
|
</Input.Wrapper>
|
||||||
|
{
|
||||||
|
isEditing && (
|
||||||
|
<PassportImageDropzone
|
||||||
|
imageUrlInputProps={
|
||||||
|
form.getInputProps(
|
||||||
|
"passportImageUrl",
|
||||||
|
) as BaseFormInputProps<string>
|
||||||
|
}
|
||||||
|
userId={innerProps?.element.id}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
</Stack>
|
</Stack>
|
||||||
</Fieldset>
|
</Fieldset>
|
||||||
<Fieldset legend={"Роль и должность"}>
|
<Fieldset legend={"Роль и должность"}>
|
||||||
|
|||||||
@@ -1,91 +1,52 @@
|
|||||||
import { Button, Group, Stack } from "@mantine/core";
|
import { Divider, Flex, Pagination, rem, Skeleton, Stack } from "@mantine/core";
|
||||||
import { ActiveWorkShiftSchema, WorkShiftsService } from "../../../../client";
|
import { ShiftsTable } from "./components/ShiftsTable.tsx";
|
||||||
import { useEffect, useState } from "react";
|
import {
|
||||||
import { notifications } from "../../../../shared/lib/notifications.ts";
|
ShiftsTableSegmentedControl,
|
||||||
import { modals } from "@mantine/modals";
|
} from "../../components/ShiftsTableSegmentedControl/ShiftsTableSegmentedControl.tsx";
|
||||||
import { ActiveShiftsTable } from "../../components/ActiveShiftsTable/ActiveShiftsTable.tsx";
|
import useWorkShiftsTable from "./hooks/useWorkShiftsTable.tsx";
|
||||||
|
import WorkShiftInput from "./components/WorkShiftInput.tsx";
|
||||||
|
|
||||||
export const WorkShiftsTab = () => {
|
export const WorkShiftsTab = () => {
|
||||||
let inputType: "StartShift" | "FinishShift" = "StartShift";
|
const {
|
||||||
const [activeShifts, setActiveShifts] = useState<ActiveWorkShiftSchema[]>([]);
|
shifts,
|
||||||
|
shiftsTableType,
|
||||||
const fetchActiveShifts = () => {
|
setShiftsTableType,
|
||||||
WorkShiftsService.getActiveShifts()
|
totalPages,
|
||||||
.then(res => {
|
page,
|
||||||
setActiveShifts(res.shifts);
|
setPage,
|
||||||
})
|
fetchShifts,
|
||||||
.catch(err => console.log(err));
|
isLoading,
|
||||||
}
|
} = useWorkShiftsTable();
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
fetchActiveShifts();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const onInputFinish = (userIdInput: string) => {
|
|
||||||
const userId = parseInt(userIdInput);
|
|
||||||
if (isNaN(userId)) {
|
|
||||||
notifications.error({ message: "Ошибка, некорректные данные в QR-коде" });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inputType === "StartShift") {
|
|
||||||
WorkShiftsService.startShift({
|
|
||||||
userId: userId!,
|
|
||||||
})
|
|
||||||
.then(async ({ ok, message }) => {
|
|
||||||
notifications.guess(ok, { message });
|
|
||||||
fetchActiveShifts();
|
|
||||||
})
|
|
||||||
.catch(err => console.log(err));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
WorkShiftsService.finishShift({
|
|
||||||
userId: userId!,
|
|
||||||
})
|
|
||||||
.then(async ({ ok, message }) => {
|
|
||||||
notifications.guess(ok, { message });
|
|
||||||
fetchActiveShifts();
|
|
||||||
})
|
|
||||||
.catch(err => console.log(err));
|
|
||||||
};
|
|
||||||
|
|
||||||
const onScanningStart = () => {
|
|
||||||
modals.openContextModal({
|
|
||||||
modal: "scanningModal",
|
|
||||||
innerProps: {
|
|
||||||
label: "Отсканируйте QR-код",
|
|
||||||
onScan: onInputFinish,
|
|
||||||
closeOnScan: true,
|
|
||||||
},
|
|
||||||
withCloseButton: false,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const onShiftStart = () => {
|
|
||||||
inputType = "StartShift";
|
|
||||||
onScanningStart();
|
|
||||||
};
|
|
||||||
|
|
||||||
const onShiftFinish = () => {
|
|
||||||
inputType = "FinishShift";
|
|
||||||
onScanningStart();
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack>
|
<Stack gap={0}>
|
||||||
<Group ml={"xs"} mt={"xs"}>
|
<WorkShiftInput fetchShifts={fetchShifts} />
|
||||||
<Button variant={"default"} onClick={onShiftStart}>
|
<Divider />
|
||||||
Начать смену
|
<ShiftsTableSegmentedControl
|
||||||
</Button>
|
value={shiftsTableType.toString()}
|
||||||
<Button variant={"default"} onClick={onShiftFinish}>
|
onChange={event => {
|
||||||
Закончить смену
|
setPage(1);
|
||||||
</Button>
|
setShiftsTableType(parseInt(event));
|
||||||
</Group>
|
}}
|
||||||
<ActiveShiftsTable
|
|
||||||
activeShifts={activeShifts}
|
|
||||||
fetchActiveShifts={fetchActiveShifts}
|
|
||||||
/>
|
/>
|
||||||
|
<Skeleton visible={isLoading}>
|
||||||
|
<Flex gap={rem(10)} direction={"column"}>
|
||||||
|
<ShiftsTable
|
||||||
|
shiftsTableType={shiftsTableType}
|
||||||
|
shifts={shifts}
|
||||||
|
fetchShifts={fetchShifts}
|
||||||
|
/>
|
||||||
|
{totalPages > 1 && (
|
||||||
|
<Pagination
|
||||||
|
style={{ alignSelf: "flex-end" }}
|
||||||
|
withEdges
|
||||||
|
onChange={event => setPage(event)}
|
||||||
|
value={page}
|
||||||
|
total={totalPages}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Flex>
|
||||||
|
</Skeleton>
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
175
src/pages/AdminPage/tabs/WorkShifts/components/ShiftsTable.tsx
Normal file
175
src/pages/AdminPage/tabs/WorkShifts/components/ShiftsTable.tsx
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
import { BaseTable } from "../../../../../components/BaseTable/BaseTable.tsx";
|
||||||
|
import { useShiftsTableColumns } from "../hooks/columns.tsx";
|
||||||
|
import { ActionIcon, Flex, Text, Tooltip } from "@mantine/core";
|
||||||
|
import { IconCheck, IconPlayerPause, IconPlayerPlay, IconTrash } from "@tabler/icons-react";
|
||||||
|
import { WorkShiftRowSchema, WorkShiftsService } from "../../../../../client";
|
||||||
|
import { modals } from "@mantine/modals";
|
||||||
|
import { formatDate } from "../../../../../types/utils.ts";
|
||||||
|
import { MRT_Row, MRT_TableOptions } from "mantine-react-table";
|
||||||
|
import { notifications } from "../../../../../shared/lib/notifications.ts";
|
||||||
|
import { ShiftsTableType } from "../../../components/ShiftsTableSegmentedControl/ShiftsTableSegmentedControl.tsx";
|
||||||
|
import { ReactNode } from "react";
|
||||||
|
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
shifts: WorkShiftRowSchema[];
|
||||||
|
fetchShifts: () => void;
|
||||||
|
shiftsTableType: ShiftsTableType;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ShiftsTable = ({
|
||||||
|
shifts,
|
||||||
|
fetchShifts,
|
||||||
|
shiftsTableType,
|
||||||
|
}: Props) => {
|
||||||
|
const isActiveShiftsTable = shiftsTableType === ShiftsTableType.ACTIVE;
|
||||||
|
const columns = useShiftsTableColumns({ isActiveShiftsTable });
|
||||||
|
|
||||||
|
const onDelete = (workShiftRow: WorkShiftRowSchema) => {
|
||||||
|
WorkShiftsService.deleteWorkShift({
|
||||||
|
shiftId: workShiftRow.workShift.id,
|
||||||
|
})
|
||||||
|
.then(({ ok, message }) => {
|
||||||
|
notifications.guess(ok, { message });
|
||||||
|
fetchShifts();
|
||||||
|
})
|
||||||
|
.catch(err => console.log(err));
|
||||||
|
};
|
||||||
|
|
||||||
|
const onDeleteClick = (workShiftRow: WorkShiftRowSchema) => {
|
||||||
|
modals.openConfirmModal({
|
||||||
|
title: "Удаление смены",
|
||||||
|
children: (
|
||||||
|
<Text size="sm">
|
||||||
|
Вы уверены что хотите удалить смену работника{" "}
|
||||||
|
{workShiftRow.workShift.user.firstName} {workShiftRow.workShift.user.secondName} от{" "}
|
||||||
|
{formatDate(workShiftRow.workShift.startedAt)}
|
||||||
|
</Text>
|
||||||
|
),
|
||||||
|
labels: { confirm: "Да", cancel: "Нет" },
|
||||||
|
confirmProps: { color: "red" },
|
||||||
|
onConfirm: () => onDelete(workShiftRow),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const onShiftFinish = (workShiftRow: WorkShiftRowSchema) => {
|
||||||
|
WorkShiftsService.finishWorkShiftById({
|
||||||
|
shiftId: workShiftRow.workShift.id,
|
||||||
|
})
|
||||||
|
.then(({ ok, message }) => {
|
||||||
|
notifications.guess(ok, { message });
|
||||||
|
fetchShifts();
|
||||||
|
})
|
||||||
|
.catch(err => console.log(err));
|
||||||
|
};
|
||||||
|
|
||||||
|
const onShiftFinishClick = (workShiftRow: WorkShiftRowSchema) => {
|
||||||
|
modals.openConfirmModal({
|
||||||
|
title: "Завершение смены",
|
||||||
|
children: (
|
||||||
|
<Text size="sm">
|
||||||
|
Вы уверены что хотите завершить смену работника{" "}
|
||||||
|
{workShiftRow.workShift.user.firstName} {workShiftRow.workShift.user.secondName} от{" "}
|
||||||
|
{formatDate(workShiftRow.workShift.startedAt)}
|
||||||
|
</Text>
|
||||||
|
),
|
||||||
|
labels: { confirm: "Да", cancel: "Нет" },
|
||||||
|
confirmProps: { color: "red" },
|
||||||
|
onConfirm: () => onShiftFinish(workShiftRow),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const onShiftPauseClick = (workShiftRow: WorkShiftRowSchema) => {
|
||||||
|
WorkShiftsService.startPauseByShiftId({
|
||||||
|
shiftId: workShiftRow.workShift.id,
|
||||||
|
})
|
||||||
|
.then(({ ok, message }) => {
|
||||||
|
notifications.guess(ok, { message });
|
||||||
|
fetchShifts();
|
||||||
|
})
|
||||||
|
.catch(err => console.log(err));
|
||||||
|
};
|
||||||
|
|
||||||
|
const onShiftResumeClick = (workShiftRow: WorkShiftRowSchema) => {
|
||||||
|
WorkShiftsService.finishPauseByShiftId({
|
||||||
|
shiftId: workShiftRow.workShift.id,
|
||||||
|
})
|
||||||
|
.then(({ ok, message }) => {
|
||||||
|
notifications.guess(ok, { message });
|
||||||
|
fetchShifts();
|
||||||
|
})
|
||||||
|
.catch(err => console.log(err));
|
||||||
|
};
|
||||||
|
|
||||||
|
const getAction = (
|
||||||
|
label: string,
|
||||||
|
func: () => void,
|
||||||
|
icon: ReactNode,
|
||||||
|
) => {
|
||||||
|
return (
|
||||||
|
<Tooltip label={label}>
|
||||||
|
<ActionIcon
|
||||||
|
onClick={func}
|
||||||
|
variant={"default"}>
|
||||||
|
{icon}
|
||||||
|
</ActionIcon>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getRowActions = (row: MRT_Row<WorkShiftRowSchema>) => {
|
||||||
|
const actions = [
|
||||||
|
getAction("Удалить", () => onDeleteClick(row.original), <IconTrash />),
|
||||||
|
];
|
||||||
|
|
||||||
|
if (isActiveShiftsTable) {
|
||||||
|
actions.push(
|
||||||
|
getAction(
|
||||||
|
"Завершить смену",
|
||||||
|
() => onShiftFinishClick(row.original),
|
||||||
|
<IconCheck />,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if (row.original.workShift.isPaused) {
|
||||||
|
actions.push(
|
||||||
|
getAction(
|
||||||
|
"Продолжить смену",
|
||||||
|
() => onShiftResumeClick(row.original),
|
||||||
|
<IconPlayerPlay />,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
actions.push(
|
||||||
|
getAction(
|
||||||
|
"Поставить смену на паузу",
|
||||||
|
() => onShiftPauseClick(row.original),
|
||||||
|
<IconPlayerPause />,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return actions;
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<BaseTable
|
||||||
|
data={shifts}
|
||||||
|
columns={columns}
|
||||||
|
restProps={
|
||||||
|
{
|
||||||
|
enableRowActions: true,
|
||||||
|
enableSorting: false,
|
||||||
|
enableColumnActions: false,
|
||||||
|
renderRowActions: ({ row }) => {
|
||||||
|
return (
|
||||||
|
<Flex gap="md">
|
||||||
|
{...getRowActions(row)}
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
} as MRT_TableOptions<WorkShiftRowSchema>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import { Button, Group } from "@mantine/core";
|
||||||
|
import useWorkShiftInput from "../hooks/useWorkShiftInput.tsx";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
fetchShifts: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const WorkShiftInput = ({ fetchShifts }: Props) => {
|
||||||
|
const {
|
||||||
|
onShiftStart,
|
||||||
|
onShiftFinish,
|
||||||
|
onShiftResume,
|
||||||
|
onShiftPause,
|
||||||
|
} = useWorkShiftInput({ fetchShifts });
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Group ml={"xs"} my={"xs"}>
|
||||||
|
<Button variant={"default"} onClick={onShiftStart}>
|
||||||
|
Начать смену
|
||||||
|
</Button>
|
||||||
|
<Button variant={"default"} onClick={onShiftFinish}>
|
||||||
|
Закончить смену
|
||||||
|
</Button>
|
||||||
|
<Button variant={"default"} onClick={onShiftPause}>
|
||||||
|
Начать перерыв
|
||||||
|
</Button>
|
||||||
|
<Button variant={"default"} onClick={onShiftResume}>
|
||||||
|
Закончить перерыв
|
||||||
|
</Button>
|
||||||
|
</Group>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default WorkShiftInput;
|
||||||
73
src/pages/AdminPage/tabs/WorkShifts/hooks/columns.tsx
Normal file
73
src/pages/AdminPage/tabs/WorkShifts/hooks/columns.tsx
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
import { useMemo } from "react";
|
||||||
|
import { MRT_ColumnDef, MRT_Row } from "mantine-react-table";
|
||||||
|
import { WorkShiftRowSchema } from "../../../../../client";
|
||||||
|
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
isActiveShiftsTable: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useShiftsTableColumns = ({ isActiveShiftsTable }: Props) => {
|
||||||
|
const getWorkedHoursString = (seconds: number) => {
|
||||||
|
const hours = Math.floor(seconds / 3_600);
|
||||||
|
const minutes = Math.floor(seconds % 3_600 / 60);
|
||||||
|
if (hours === 0) {
|
||||||
|
return `${minutes} мин.`;
|
||||||
|
}
|
||||||
|
return `${hours} ч. ${minutes} мин.`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getColumnsForHistory = () => {
|
||||||
|
return isActiveShiftsTable ? [] : [
|
||||||
|
{
|
||||||
|
header: "Конец смены",
|
||||||
|
accessorKey: "workShift.finishedAt",
|
||||||
|
Cell: ({ row }: { row: MRT_Row<WorkShiftRowSchema> }) =>
|
||||||
|
row.original.workShift.finishedAt && new Date(row.original.workShift.finishedAt).toLocaleString("ru-RU"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
header: "Длительность смены",
|
||||||
|
accessorKey: "totalHours",
|
||||||
|
Cell: ({ row }: { row: MRT_Row<WorkShiftRowSchema> }) =>
|
||||||
|
getWorkedHoursString(row.original.totalHours ?? 0),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
header: "Перерывы",
|
||||||
|
accessorKey: "pauseHours",
|
||||||
|
Cell: ({ row }: { row: MRT_Row<WorkShiftRowSchema> }) =>
|
||||||
|
getWorkedHoursString(row.original.pauseHours ?? 0),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
header: "Отработано",
|
||||||
|
Cell: ({ row }: { row: MRT_Row<WorkShiftRowSchema> }) =>
|
||||||
|
getWorkedHoursString((row.original.totalHours ?? 0) - (row.original.pauseHours ?? 0)),
|
||||||
|
},
|
||||||
|
] as MRT_ColumnDef<WorkShiftRowSchema>[];
|
||||||
|
};
|
||||||
|
|
||||||
|
return useMemo<MRT_ColumnDef<WorkShiftRowSchema>[]>(
|
||||||
|
() => [
|
||||||
|
{
|
||||||
|
header: "ФИО",
|
||||||
|
Cell: ({ row }: { row: MRT_Row<WorkShiftRowSchema> }) =>
|
||||||
|
`${row.original.workShift.user.firstName} ${row.original.workShift.user.secondName}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
header: "Роль",
|
||||||
|
accessorKey: "workShift.user.role.name",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
header: "Должность",
|
||||||
|
accessorKey: "workShift.user.position.name",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
header: "Начало смены",
|
||||||
|
accessorKey: "workShift.startedAt",
|
||||||
|
Cell: ({ row }) =>
|
||||||
|
new Date(row.original.workShift.startedAt).toLocaleString("ru-RU"),
|
||||||
|
},
|
||||||
|
...getColumnsForHistory(),
|
||||||
|
],
|
||||||
|
[isActiveShiftsTable],
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
import { WorkShiftsService } from "../../../../../client";
|
||||||
|
import { notifications } from "../../../../../shared/lib/notifications.ts";
|
||||||
|
import { modals } from "@mantine/modals";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
fetchShifts: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum InputType {
|
||||||
|
START_SHIFT,
|
||||||
|
FINISH_SHIFT,
|
||||||
|
RESUME_SHIFT,
|
||||||
|
PAUSE_SHIFT,
|
||||||
|
}
|
||||||
|
|
||||||
|
const useWorkShiftInput = ({ fetchShifts }: Props) => {
|
||||||
|
let inputType: InputType = InputType.START_SHIFT;
|
||||||
|
|
||||||
|
const workShiftMethods = {
|
||||||
|
[InputType.START_SHIFT]: WorkShiftsService.startShift,
|
||||||
|
[InputType.FINISH_SHIFT]: WorkShiftsService.finishShift,
|
||||||
|
[InputType.RESUME_SHIFT]: WorkShiftsService.finishPauseByUserId,
|
||||||
|
[InputType.PAUSE_SHIFT]: WorkShiftsService.startPauseByUserId,
|
||||||
|
};
|
||||||
|
|
||||||
|
const onInputFinish = (userIdInput: string) => {
|
||||||
|
const userId = parseInt(userIdInput);
|
||||||
|
if (isNaN(userId)) {
|
||||||
|
notifications.error({ message: "Ошибка, некорректные данные в QR-коде" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
workShiftMethods[inputType]({ userId })
|
||||||
|
.then(async ({ ok, message }) => {
|
||||||
|
notifications.guess(ok, { message });
|
||||||
|
fetchShifts();
|
||||||
|
})
|
||||||
|
.catch(err => console.log(err));
|
||||||
|
};
|
||||||
|
|
||||||
|
const onScanningStart = () => {
|
||||||
|
modals.openContextModal({
|
||||||
|
modal: "scanningModal",
|
||||||
|
innerProps: {
|
||||||
|
label: "Отсканируйте QR-код",
|
||||||
|
onScan: onInputFinish,
|
||||||
|
closeOnScan: true,
|
||||||
|
},
|
||||||
|
withCloseButton: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const onShiftStart = () => {
|
||||||
|
inputType = InputType.START_SHIFT;
|
||||||
|
onScanningStart();
|
||||||
|
};
|
||||||
|
|
||||||
|
const onShiftFinish = () => {
|
||||||
|
inputType = InputType.FINISH_SHIFT;
|
||||||
|
onScanningStart();
|
||||||
|
};
|
||||||
|
|
||||||
|
const onShiftResume = () => {
|
||||||
|
inputType = InputType.RESUME_SHIFT;
|
||||||
|
onScanningStart();
|
||||||
|
};
|
||||||
|
|
||||||
|
const onShiftPause = () => {
|
||||||
|
inputType = InputType.PAUSE_SHIFT;
|
||||||
|
onScanningStart();
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
onShiftStart,
|
||||||
|
onShiftFinish,
|
||||||
|
onShiftResume,
|
||||||
|
onShiftPause,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useWorkShiftInput;
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { WorkShiftRowSchema, WorkShiftsService } from "../../../../../client";
|
||||||
|
import { ShiftsTableType } from "../../../components/ShiftsTableSegmentedControl/ShiftsTableSegmentedControl.tsx";
|
||||||
|
|
||||||
|
|
||||||
|
const useWorkShiftsTable = () => {
|
||||||
|
const [totalPages, setTotalPages] = useState(1);
|
||||||
|
const [page, setPage] = useState(1);
|
||||||
|
const [shifts, setShifts] = useState<WorkShiftRowSchema[]>([]);
|
||||||
|
const [shiftsTableType, setShiftsTableType] = useState<ShiftsTableType>(ShiftsTableType.ACTIVE);
|
||||||
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
|
||||||
|
const fetchShifts = () => {
|
||||||
|
setIsLoading(true);
|
||||||
|
WorkShiftsService.getShifts({
|
||||||
|
isActive: shiftsTableType === ShiftsTableType.ACTIVE,
|
||||||
|
page,
|
||||||
|
itemsPerPage: 10,
|
||||||
|
})
|
||||||
|
.then(res => {
|
||||||
|
setShifts(res.shifts);
|
||||||
|
setTotalPages(res.paginationInfo.totalPages);
|
||||||
|
})
|
||||||
|
.catch(err => console.log(err))
|
||||||
|
.finally(() => setIsLoading(false));
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchShifts();
|
||||||
|
}, [shiftsTableType, page]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
shifts,
|
||||||
|
shiftsTableType,
|
||||||
|
setShiftsTableType,
|
||||||
|
totalPages,
|
||||||
|
page,
|
||||||
|
setPage,
|
||||||
|
fetchShifts,
|
||||||
|
isLoading,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useWorkShiftsTable;
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
import { DropzoneProps, FileWithPath } from "@mantine/dropzone";
|
||||||
|
import { FC } from "react";
|
||||||
|
import { notifications } from "../../../../shared/lib/notifications.ts";
|
||||||
|
import { ProductService } from "../../../../client";
|
||||||
|
import { BaseFormInputProps } from "../../../../types/utils.ts";
|
||||||
|
import useImageDropzone from "../../../../hooks/useImageDropzone.tsx";
|
||||||
|
import ImageDropzone from "../../../../components/ImageDropzone/ImageDropzone.tsx";
|
||||||
|
|
||||||
|
interface RestProps {
|
||||||
|
imageUrlInputProps?: BaseFormInputProps<string>;
|
||||||
|
productId?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
type Props = Omit<DropzoneProps, "onDrop"> & RestProps;
|
||||||
|
|
||||||
|
const ProductImageDropzone: FC<Props> = ({ imageUrlInputProps, productId }: Props) => {
|
||||||
|
const imageDropzoneProps = useImageDropzone({
|
||||||
|
imageUrlInputProps,
|
||||||
|
});
|
||||||
|
|
||||||
|
const onDrop = (files: FileWithPath[]) => {
|
||||||
|
if (!productId || !imageUrlInputProps) return;
|
||||||
|
if (files.length > 1) {
|
||||||
|
notifications.error({ message: "Прикрепите одно изображение" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const { setIsLoading, setShowDropzone } = imageDropzoneProps;
|
||||||
|
const file = files[0];
|
||||||
|
|
||||||
|
setIsLoading(true);
|
||||||
|
ProductService.uploadProductImage({
|
||||||
|
productId,
|
||||||
|
formData: {
|
||||||
|
upload_file: file,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then(({ ok, message, imageUrl }) => {
|
||||||
|
notifications.guess(ok, { message });
|
||||||
|
setIsLoading(false);
|
||||||
|
|
||||||
|
if (!ok || !imageUrl) {
|
||||||
|
setShowDropzone(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
imageUrlInputProps?.onChange(imageUrl);
|
||||||
|
setShowDropzone(false);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
notifications.error({ message: error.toString() });
|
||||||
|
setShowDropzone(true);
|
||||||
|
setIsLoading(false);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ImageDropzone onDrop={onDrop} imageDropzone={imageDropzoneProps} />
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ProductImageDropzone;
|
||||||
@@ -4,9 +4,9 @@ import { useForm } from "@mantine/form";
|
|||||||
import { BaseProduct, CreateProductRequest } from "../../types.ts";
|
import { BaseProduct, CreateProductRequest } from "../../types.ts";
|
||||||
import { ProductSchema } from "../../../../client";
|
import { ProductSchema } from "../../../../client";
|
||||||
import BarcodeTemplateSelect from "../../../../components/Selects/BarcodeTemplateSelect/BarcodeTemplateSelect.tsx";
|
import BarcodeTemplateSelect from "../../../../components/Selects/BarcodeTemplateSelect/BarcodeTemplateSelect.tsx";
|
||||||
import ImageDropzone from "../../../../components/ImageDropzone/ImageDropzone.tsx";
|
|
||||||
import { BaseFormInputProps } from "../../../../types/utils.ts";
|
import { BaseFormInputProps } from "../../../../types/utils.ts";
|
||||||
import BarcodeImageDropzone from "../../../../components/BarcodeImageDropzone/BarcodeImageDropzone.tsx";
|
import BarcodeImageDropzone from "../../../../components/BarcodeImageDropzone/BarcodeImageDropzone.tsx";
|
||||||
|
import ProductImageDropzone from "../../components/ProductImageDropzone/ProductImageDropzone.tsx";
|
||||||
|
|
||||||
type CreateProps = {
|
type CreateProps = {
|
||||||
clientId: number;
|
clientId: number;
|
||||||
@@ -117,7 +117,7 @@ const CreateProductModal = ({
|
|||||||
isEditProps && (
|
isEditProps && (
|
||||||
// <Fieldset legend={"Изображение"}>
|
// <Fieldset legend={"Изображение"}>
|
||||||
<>
|
<>
|
||||||
<ImageDropzone
|
<ProductImageDropzone
|
||||||
imageUrlInputProps={
|
imageUrlInputProps={
|
||||||
form.getInputProps(
|
form.getInputProps(
|
||||||
"imageUrl",
|
"imageUrl",
|
||||||
|
|||||||
12
src/types/UseImageDropzone.tsx
Normal file
12
src/types/UseImageDropzone.tsx
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { Dispatch, SetStateAction } from "react";
|
||||||
|
import { BaseFormInputProps } from "./utils.ts";
|
||||||
|
|
||||||
|
type UseImageDropzone = {
|
||||||
|
showDropzone: boolean;
|
||||||
|
setShowDropzone: Dispatch<SetStateAction<boolean>>;
|
||||||
|
isLoading: boolean;
|
||||||
|
setIsLoading: Dispatch<SetStateAction<boolean>>;
|
||||||
|
imageUrlInputProps?: BaseFormInputProps<string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UseImageDropzone;
|
||||||
@@ -45,7 +45,7 @@ export function ObjectStateToTableProps<T extends MRT_RowData>(
|
|||||||
|
|
||||||
export const floatHoursToHoursAndMinutes = (hours: number): number[] => {
|
export const floatHoursToHoursAndMinutes = (hours: number): number[] => {
|
||||||
const resHours = Math.floor(hours);
|
const resHours = Math.floor(hours);
|
||||||
const minutes = Math.round((hours - resHours) * 60);
|
const minutes = Math.floor((hours - resHours) * 60);
|
||||||
return [resHours, minutes];
|
return [resHours, minutes];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user