This commit is contained in:
pradeepkumar
2026-01-24 21:06:13 +05:30
parent 0f84e3d4d7
commit eba83e2961
9 changed files with 585 additions and 26 deletions

View File

@@ -43,6 +43,31 @@ interface ApiResponse<T> {
message?: string;
}
export interface FieldValueInput {
fieldSlug: string;
value: string | number | boolean | string[] | Record<string, unknown> | null;
}
export interface FieldValueResponse {
fieldSlug: string;
fieldName: string;
fieldType: string;
sectionSlug: string;
sectionName: string;
value: unknown;
}
export interface GetFieldValuesResponse {
agentProfileId: string;
fieldValues: FieldValueResponse[];
}
export interface SaveFieldValuesResponse {
message: string;
savedCount: number;
data: unknown[];
}
// Agents Service for Web
class AgentsService {
private basePath = '/agents';
@@ -61,6 +86,21 @@ class AgentsService {
const response = await api.put<ApiResponse<AgentProfile>>(`${this.basePath}/profile`, data);
return response.data.data;
}
async saveFieldValues(fieldValues: FieldValueInput[]): Promise<SaveFieldValuesResponse> {
const response = await api.put<ApiResponse<SaveFieldValuesResponse>>(
`${this.basePath}/profile/field-values`,
{ fieldValues }
);
return response.data.data;
}
async getFieldValues(): Promise<GetFieldValuesResponse> {
const response = await api.get<ApiResponse<GetFieldValuesResponse>>(
`${this.basePath}/profile/field-values`
);
return response.data.data;
}
}
export const agentsService = new AgentsService();

View File

@@ -31,3 +31,7 @@ export type {
// Agents Service
export { agentsService } from './agents.service';
export type { AgentProfile, AgentType } from './agents.service';
// Upload Service
export { uploadService } from './upload.service';
export type { UploadedFile, UploadProgress } from './upload.service';

View File

@@ -12,7 +12,9 @@ export type FieldType =
| 'RANGE'
| 'NUMBER'
| 'DATE'
| 'TAG_INPUT';
| 'TAG_INPUT'
| 'FILE'
| 'FILE_UPLOAD';
// Types
export interface FieldOption {
@@ -33,6 +35,8 @@ export interface FieldValidation {
minLength?: number;
maxLength?: number;
pattern?: string;
allowedFormats?: string[];
maxFileSize?: number;
}
export interface FieldUiConfig {

View File

@@ -0,0 +1,151 @@
import api from './api';
export interface UploadedFile {
id: string;
name: string;
size: number;
type: string;
url: string;
uploadedAt: string;
}
export interface UploadProgress {
loaded: number;
total: number;
percentage: number;
}
interface PresignedUrlResponse {
uploadUrl: string;
publicUrl: string;
key: string;
}
type UploadFolder = 'avatars' | 'documents' | 'properties' | 'verification';
class UploadService {
private basePath = '/upload';
/**
* Get presigned URL from backend
*/
private async getPresignedUrl(
filename: string,
contentType: string,
folder: UploadFolder = 'documents'
): Promise<PresignedUrlResponse> {
const response = await api.post<{ data: PresignedUrlResponse }>(
`${this.basePath}/presigned-url`,
{
filename,
contentType,
folder,
}
);
return response.data.data;
}
/**
* Upload file directly to S3 using presigned URL
*/
private async uploadToS3(
uploadUrl: string,
file: File,
onProgress?: (progress: UploadProgress) => void
): Promise<void> {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.upload.addEventListener('progress', (event) => {
if (event.lengthComputable && onProgress) {
const percentage = Math.round((event.loaded * 100) / event.total);
onProgress({
loaded: event.loaded,
total: event.total,
percentage,
});
}
});
xhr.addEventListener('load', () => {
if (xhr.status >= 200 && xhr.status < 300) {
resolve();
} else {
reject(new Error(`Upload failed with status ${xhr.status}`));
}
});
xhr.addEventListener('error', () => {
reject(new Error('Upload failed'));
});
xhr.open('PUT', uploadUrl);
xhr.setRequestHeader('Content-Type', file.type);
xhr.send(file);
});
}
/**
* Upload a single file to S3
*/
async uploadFile(
file: File,
folder: UploadFolder = 'documents',
onProgress?: (progress: UploadProgress) => void
): Promise<UploadedFile> {
// Step 1: Get presigned URL from backend
const { uploadUrl, publicUrl, key } = await this.getPresignedUrl(
file.name,
file.type,
folder
);
// Step 2: Upload directly to S3
await this.uploadToS3(uploadUrl, file, onProgress);
// Step 3: Return uploaded file info
return {
id: key, // Use the S3 key as the ID
name: file.name,
size: file.size,
type: file.type,
url: publicUrl,
uploadedAt: new Date().toISOString(),
};
}
/**
* Upload multiple files to S3
*/
async uploadFiles(
files: File[],
folder: UploadFolder = 'documents',
onProgress?: (fileIndex: number, progress: UploadProgress) => void
): Promise<UploadedFile[]> {
const uploadedFiles: UploadedFile[] = [];
for (let i = 0; i < files.length; i++) {
const file = files[i];
const uploadedFile = await this.uploadFile(
file,
folder,
onProgress ? (progress) => onProgress(i, progress) : undefined
);
uploadedFiles.push(uploadedFile);
}
return uploadedFiles;
}
/**
* Delete a file from S3
*/
async deleteFile(fileKey: string): Promise<void> {
// The key needs to be URL encoded for path parameter
const encodedKey = encodeURIComponent(fileKey);
await api.delete(`${this.basePath}/${encodedKey}`);
}
}
export const uploadService = new UploadService();