5d01d66ea3
feat(image-upload): introduce ImageUploadField component for enhanced image uploads - Added ImageUploadField component to streamline image uploads with improved UI and functionality. - Integrated file upload handling with a new file service for better management of image uploads. - Updated SectionStep component to utilize ImageUploadField for icon uploads, enhancing user experience. - Refactored TenderListFilters to use isDateRangeActive utility for improved date range filtering logic.
165 lines
4.8 KiB
TypeScript
165 lines
4.8 KiB
TypeScript
import api from "../axios";
|
|
import { extractFileId } from "../config";
|
|
import { API_ENDPOINTS } from "../endpoints";
|
|
import { fileService } from "./file-service";
|
|
import {
|
|
ApiResponse,
|
|
IAdminListResponse,
|
|
ICreateAdminCredentials,
|
|
ILoginCredentials,
|
|
ILoginResponse,
|
|
ILogoutResponse,
|
|
LoginResponseSchema,
|
|
LogoutResponseSchema,
|
|
TChangeAdminStatusCredentials,
|
|
TResetPasswordResponse,
|
|
} from "../types";
|
|
|
|
export const userService = {
|
|
login: async (
|
|
credentials: ILoginCredentials,
|
|
): Promise<ApiResponse<ILoginResponse>> => {
|
|
try {
|
|
const response = await api.post(API_ENDPOINTS.USER.LOGIN, credentials);
|
|
|
|
const result = LoginResponseSchema.safeParse(response.data);
|
|
if (!result.success) {
|
|
throw new Error(result.error.message);
|
|
}
|
|
return result.data;
|
|
} catch (error) {
|
|
console.error("ERROR caught in User Service Login:", error);
|
|
throw error;
|
|
}
|
|
},
|
|
logout: async (): Promise<ApiResponse<ILogoutResponse>> => {
|
|
try {
|
|
const response = await api.delete(API_ENDPOINTS.USER.LOGOUT);
|
|
return LogoutResponseSchema.parse(response.data);
|
|
} catch (error) {
|
|
console.error("ERROR caught in User Service Logout", error);
|
|
throw error;
|
|
}
|
|
},
|
|
adminsList: async (
|
|
params?: Record<string, any>,
|
|
): Promise<ApiResponse<IAdminListResponse>> => {
|
|
try {
|
|
const response = await api.get(API_ENDPOINTS.USER.ADMINS, { params });
|
|
return response.data;
|
|
} catch (error) {
|
|
console.error("ERROR caught in User Service User List", error);
|
|
throw error;
|
|
}
|
|
},
|
|
createAdmin: async (credentials: ICreateAdminCredentials) => {
|
|
try {
|
|
return (await api.post(API_ENDPOINTS.USER.ADMINS, credentials)).data
|
|
.message;
|
|
} catch (error) {
|
|
console.error("ERROR caught in User Service Create Admin", error);
|
|
throw error;
|
|
}
|
|
},
|
|
updateAdmin: async ({
|
|
id,
|
|
credentials,
|
|
}: {
|
|
id: string;
|
|
credentials: ICreateAdminCredentials;
|
|
}) => {
|
|
try {
|
|
return (await api.put(API_ENDPOINTS.USER.ADMIN_DETAILS(id), credentials))
|
|
.data.message;
|
|
} catch (error) {
|
|
console.error("ERROR caught in User Service Update Admin", error);
|
|
throw error;
|
|
}
|
|
},
|
|
|
|
adminDetails: async (id: string) => {
|
|
try {
|
|
return (await api.get(API_ENDPOINTS.USER.ADMIN_DETAILS(id))).data;
|
|
} catch (error) {
|
|
console.error("ERROR caught in User Service Admin Details", error);
|
|
throw error;
|
|
}
|
|
},
|
|
deleteAdmin: async (
|
|
id: string,
|
|
): Promise<ApiResponse<{ message: string }>> => {
|
|
try {
|
|
return await api.delete(`${API_ENDPOINTS.USER.ADMINS}/${id}`);
|
|
} catch (error) {
|
|
console.error("ERROR caught in User Service Delete Admin", error);
|
|
throw error;
|
|
}
|
|
},
|
|
resetAdminPassword: async (
|
|
id: string,
|
|
): Promise<ApiResponse<TResetPasswordResponse>> => {
|
|
try {
|
|
return (await api.post(API_ENDPOINTS.USER.RESET_ADMIN_PASSWORD(id))).data;
|
|
} catch (error) {
|
|
console.error("ERROR caught in User Service Reset Admin Password", error);
|
|
throw error;
|
|
}
|
|
},
|
|
changeAdminStatus: async ({
|
|
id,
|
|
credentials,
|
|
}: {
|
|
id: string;
|
|
credentials: TChangeAdminStatusCredentials;
|
|
}) => {
|
|
try {
|
|
return (
|
|
await api.put(API_ENDPOINTS.USER.CHANGE_ADMIN_STATUS(id), credentials)
|
|
).data;
|
|
} catch (error) {
|
|
console.error("ERROR Caught in user service => change status", error);
|
|
throw error;
|
|
}
|
|
},
|
|
uploadProfileImage: async ({
|
|
file,
|
|
onProgress,
|
|
}: {
|
|
file: File;
|
|
onProgress?: (percent: number) => void;
|
|
}) => {
|
|
try {
|
|
// Persisted on the backend as the profile image, so it must be an
|
|
// absolute, directly-loadable URL — not the frontend `/api/proxy` path.
|
|
return fileService.uploadFile({
|
|
file,
|
|
category: "profile_images",
|
|
tags: ["user", "profile"],
|
|
description: "Admin profile image",
|
|
onProgress,
|
|
});
|
|
} catch (error) {
|
|
console.error("ERROR caught in User Service Upload Profile Image", error);
|
|
throw error;
|
|
}
|
|
},
|
|
/**
|
|
* Fetch an auth-protected file download through the proxy (so the axios
|
|
* interceptor attaches the bearer token) and return a local object URL that
|
|
* can be used directly as an `<img>` source.
|
|
*/
|
|
fetchFileObjectUrl: async (url: string): Promise<string> => {
|
|
try {
|
|
const fileId = extractFileId(url);
|
|
// Route via the relative proxy endpoint when this is a backend file URL;
|
|
// otherwise fetch the URL as-is.
|
|
const path = fileId ? API_ENDPOINTS.FILES.DOWNLOAD(fileId) : url;
|
|
const response = await api.get(path, { responseType: "blob" });
|
|
return URL.createObjectURL(response.data as Blob);
|
|
} catch (error) {
|
|
console.error("ERROR caught in User Service Fetch File Object Url", error);
|
|
throw error;
|
|
}
|
|
},
|
|
};
|