420 lines
16 KiB
C#
420 lines
16 KiB
C#
using LSFE.Infrastructure.Model.Admin;
|
|
using LSFE.MobApp.Contracts;
|
|
using LSFE.MobApp.Models;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Linq;
|
|
using System.Net.Http.Headers;
|
|
using System.Net.Http.Json;
|
|
using System.Text;
|
|
using System.Text.Json;
|
|
using System.Text.Json.Serialization;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace LSFE.MobApp.Services
|
|
{
|
|
public class ApiClient<T> : IApiClient<T> where T : class
|
|
{
|
|
private readonly HttpClient _httpClient;
|
|
private readonly string _baseEndpoint;
|
|
private readonly JsonSerializerOptions _jsonOptions;
|
|
public ApiClient(HttpClient httpClient, string baseEndpoint)
|
|
{
|
|
_httpClient = httpClient;
|
|
_baseEndpoint = baseEndpoint;
|
|
_jsonOptions = new JsonSerializerOptions
|
|
{
|
|
PropertyNameCaseInsensitive = true,
|
|
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
|
WriteIndented = false
|
|
};
|
|
}
|
|
public async Task<List<T>> GetAllAsync()
|
|
{
|
|
try
|
|
{
|
|
var response = await _httpClient.GetAsync(_baseEndpoint);
|
|
response.EnsureSuccessStatusCode();
|
|
|
|
var json = await response.Content.ReadAsStringAsync();
|
|
return JsonSerializer.Deserialize<List<T>>(json, _jsonOptions) ?? new List<T>();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Debug.WriteLine($"Error in GetAllAsync: {ex.Message}");
|
|
return new List<T>();
|
|
}
|
|
}
|
|
public async Task<List<T>> GetWithQueryAsync(Dictionary<string, string> queryParams)
|
|
{
|
|
try
|
|
{
|
|
var query = string.Join("&", queryParams
|
|
.Where(kv => !string.IsNullOrEmpty(kv.Value))
|
|
.Select(kv => $"{kv.Key}={Uri.EscapeDataString(kv.Value)}"));
|
|
|
|
var url = string.IsNullOrEmpty(query) ? _baseEndpoint : $"{_baseEndpoint}?{query}";
|
|
var response = await _httpClient.GetAsync(url);
|
|
response.EnsureSuccessStatusCode();
|
|
|
|
var json = await response.Content.ReadAsStringAsync();
|
|
return JsonSerializer.Deserialize<List<T>>(json, _jsonOptions);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Debug.WriteLine($"Error in GetWithQueryAsync: {ex.Message}");
|
|
return null;
|
|
}
|
|
}
|
|
public async Task<LoginResponse> LoginAsync(LoginRequest entity)
|
|
{
|
|
try
|
|
{
|
|
var json = JsonSerializer.Serialize(entity, _jsonOptions);
|
|
var content = new StringContent(json, Encoding.UTF8, "application/json");
|
|
|
|
var response = await _httpClient.PostAsync(_baseEndpoint, content);
|
|
var responseJson = await response.Content.ReadAsStringAsync();
|
|
|
|
return JsonSerializer.Deserialize<LoginResponse>(responseJson, _jsonOptions);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Debug.WriteLine($"Error in LoginAsync: {ex.Message}");
|
|
return null;
|
|
}
|
|
}
|
|
public async Task<T> GetByIdAsync(int id)
|
|
{
|
|
try
|
|
{
|
|
var response = await _httpClient.GetAsync($"{_baseEndpoint}/{id}");
|
|
response.EnsureSuccessStatusCode();
|
|
|
|
var json = await response.Content.ReadAsStringAsync();
|
|
return JsonSerializer.Deserialize<T>(json, _jsonOptions);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Debug.WriteLine($"Error in GetByIdAsync: {ex.Message}");
|
|
return null;
|
|
}
|
|
}
|
|
public async Task<ApiResponse<T>> CreateAsync(T entity)
|
|
{
|
|
try
|
|
{
|
|
var json = JsonSerializer.Serialize(entity, _jsonOptions);
|
|
var content = new StringContent(json, Encoding.UTF8, "application/json");
|
|
|
|
var response = await _httpClient.PostAsync(_baseEndpoint, content);
|
|
var responseJson = await response.Content.ReadAsStringAsync();
|
|
|
|
return JsonSerializer.Deserialize<ApiResponse<T>>(responseJson, _jsonOptions);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return new ApiResponse<T>
|
|
{
|
|
Success = false,
|
|
Message = ex.Message,
|
|
MessCode = 0
|
|
};
|
|
}
|
|
}
|
|
public async Task<ApiResponse<T>> CreateAttendanceAsync(T entity)
|
|
{
|
|
try
|
|
{
|
|
using var form = new MultipartFormDataContent();
|
|
|
|
// Convert your entity (Attendance) into key-value form fields
|
|
foreach (var prop in typeof(T).GetProperties())
|
|
{
|
|
var value = prop.GetValue(entity);
|
|
if (value != null)
|
|
{
|
|
// Skip SignatureImage byte array - we'll send the files instead
|
|
if (prop.Name == "SignatureImage")
|
|
continue;
|
|
|
|
// Convert Guid to string for AppAttendanceId
|
|
if (prop.Name == "AppAttendanceId" && value is Guid guid)
|
|
{
|
|
form.Add(new StringContent(guid.ToString()), prop.Name);
|
|
}
|
|
// Handle DateTime properties with ISO format
|
|
else if (value is DateTime dateTime)
|
|
{
|
|
form.Add(new StringContent(dateTime.ToString("o")), prop.Name); // ISO 8601 format
|
|
}
|
|
else
|
|
{
|
|
form.Add(new StringContent(value.ToString()), prop.Name);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add Time-In photo if exists
|
|
var fileInProp = typeof(T).GetProperty("SignatureFileNameIn");
|
|
if (fileInProp != null)
|
|
{
|
|
var fileName = fileInProp.GetValue(entity)?.ToString();
|
|
if (!string.IsNullOrEmpty(fileName))
|
|
{
|
|
var filePath = Path.Combine(FileSystem.AppDataDirectory, fileName);
|
|
if (File.Exists(filePath))
|
|
{
|
|
var stream = File.OpenRead(filePath);
|
|
var fileContent = new StreamContent(stream);
|
|
fileContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("image/jpeg");
|
|
form.Add(fileContent, "photoFileIn", fileName);
|
|
}
|
|
else
|
|
{
|
|
Debug.WriteLine($"Time-In file not found: {filePath}");
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add Time-Out photo if exists
|
|
var fileOutProp = typeof(T).GetProperty("SignatureFileNameOut");
|
|
if (fileOutProp != null)
|
|
{
|
|
var fileName = fileOutProp.GetValue(entity)?.ToString();
|
|
if (!string.IsNullOrEmpty(fileName))
|
|
{
|
|
var filePath = Path.Combine(FileSystem.AppDataDirectory, fileName);
|
|
if (File.Exists(filePath))
|
|
{
|
|
var stream = File.OpenRead(filePath);
|
|
var fileContent = new StreamContent(stream);
|
|
fileContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("image/jpeg");
|
|
form.Add(fileContent, "photoFileOut", fileName);
|
|
}
|
|
else
|
|
{
|
|
Debug.WriteLine($"Time-Out file not found: {filePath}");
|
|
}
|
|
}
|
|
}
|
|
|
|
var response = await _httpClient.PostAsync(_baseEndpoint, form);
|
|
var responseJson = await response.Content.ReadAsStringAsync();
|
|
|
|
if (!response.IsSuccessStatusCode)
|
|
{
|
|
return new ApiResponse<T>
|
|
{
|
|
Success = false,
|
|
Message = $"API returned {response.StatusCode}: {responseJson}",
|
|
MessCode = 0
|
|
};
|
|
}
|
|
|
|
return JsonSerializer.Deserialize<ApiResponse<T>>(responseJson, _jsonOptions);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Debug.WriteLine($"CreateWithPhotoAsync Exception: {ex.ToString()}");
|
|
return new ApiResponse<T>
|
|
{
|
|
Success = false,
|
|
Message = ex.Message,
|
|
MessCode = 0
|
|
};
|
|
}
|
|
}
|
|
public async Task<ApiResponse<T>> CreateCoveragePlanAsync(T entity)
|
|
{
|
|
try
|
|
{
|
|
using var form = new MultipartFormDataContent();
|
|
|
|
// Convert your entity (MRRawPlan) into key-value form fields
|
|
foreach (var prop in typeof(T).GetProperties())
|
|
{
|
|
var value = prop.GetValue(entity);
|
|
if (value != null)
|
|
{
|
|
// Skip SignatureBase64 if it exists - we'll send the file instead
|
|
if (prop.Name == "SignatureBase64")
|
|
continue;
|
|
|
|
// Convert Guid to string
|
|
if (value is Guid guid)
|
|
{
|
|
form.Add(new StringContent(guid.ToString()), prop.Name);
|
|
}
|
|
|
|
// Handle DateTime properties with ISO format
|
|
else if (value is DateTime dateTime)
|
|
{
|
|
form.Add(new StringContent(dateTime.ToString("o")), prop.Name); // ISO 8601 format
|
|
}
|
|
// Handle boolean
|
|
else if (value is bool boolValue)
|
|
{
|
|
form.Add(new StringContent(boolValue.ToString().ToLower()), prop.Name);
|
|
}
|
|
else
|
|
{
|
|
form.Add(new StringContent(value.ToString()), prop.Name);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add Signature photo if exists
|
|
var fileNameProp = typeof(T).GetProperty("SignatureFileName");
|
|
if (fileNameProp != null)
|
|
{
|
|
var fileName = fileNameProp.GetValue(entity)?.ToString();
|
|
if (!string.IsNullOrEmpty(fileName))
|
|
{
|
|
var filePath = Path.Combine(FileSystem.AppDataDirectory, fileName);
|
|
if (File.Exists(filePath))
|
|
{
|
|
var stream = File.OpenRead(filePath);
|
|
var fileContent = new StreamContent(stream);
|
|
fileContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("image/png");
|
|
form.Add(fileContent, "photoFile", fileName);
|
|
}
|
|
else
|
|
{
|
|
Debug.WriteLine($"Signature file not found: {filePath}");
|
|
return new ApiResponse<T>
|
|
{
|
|
Success = false,
|
|
Message = $"Signature file not found at: {filePath}",
|
|
MessCode = 0
|
|
};
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Debug.WriteLine("SignatureFileName is null or empty");
|
|
}
|
|
}
|
|
|
|
var response = await _httpClient.PostAsync(_baseEndpoint, form);
|
|
var responseJson = await response.Content.ReadAsStringAsync();
|
|
|
|
if (!response.IsSuccessStatusCode)
|
|
{
|
|
Debug.WriteLine($"API Error: {response.StatusCode} - {responseJson}");
|
|
return new ApiResponse<T>
|
|
{
|
|
Success = false,
|
|
Message = $"API returned {response.StatusCode}: {responseJson}",
|
|
MessCode = 0
|
|
};
|
|
}
|
|
|
|
return JsonSerializer.Deserialize<ApiResponse<T>>(responseJson, _jsonOptions);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Debug.WriteLine($"CreateWithPhotoAsync Exception: {ex.ToString()}");
|
|
return new ApiResponse<T>
|
|
{
|
|
Success = false,
|
|
Message = ex.Message,
|
|
MessCode = 0
|
|
};
|
|
}
|
|
}
|
|
public async Task<T> GetByIdAsync(Guid id)
|
|
{
|
|
try
|
|
{
|
|
var response = await _httpClient.GetAsync($"{_baseEndpoint}/{id}");
|
|
response.EnsureSuccessStatusCode();
|
|
|
|
var json = await response.Content.ReadAsStringAsync();
|
|
Debug.WriteLine($"GetByIdAsync Response: {json}");
|
|
|
|
return JsonSerializer.Deserialize<T>(json, _jsonOptions);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Debug.WriteLine($"Error in GetByIdAsync: {ex.Message}");
|
|
return null;
|
|
}
|
|
}
|
|
public async Task<ApiResponse<T>> UpdateAsync(Guid id, T entity)
|
|
{
|
|
try
|
|
{
|
|
var json = JsonSerializer.Serialize(entity, _jsonOptions);
|
|
Debug.WriteLine($"UpdateAsync Request: {json}");
|
|
|
|
var content = new StringContent(json, Encoding.UTF8, "application/json");
|
|
|
|
var response = await _httpClient.PutAsync($"{_baseEndpoint}/{id}", content);
|
|
var responseJson = await response.Content.ReadAsStringAsync();
|
|
|
|
Debug.WriteLine($"UpdateAsync Response: {responseJson}");
|
|
|
|
if (!response.IsSuccessStatusCode)
|
|
{
|
|
return new ApiResponse<T>
|
|
{
|
|
Success = false,
|
|
Message = $"Server returned {response.StatusCode}: {responseJson}",
|
|
MessCode = (int)response.StatusCode
|
|
};
|
|
}
|
|
|
|
return JsonSerializer.Deserialize<ApiResponse<T>>(responseJson, _jsonOptions);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Debug.WriteLine($"Error in UpdateAsync: {ex.Message}");
|
|
return new ApiResponse<T>
|
|
{
|
|
Success = false,
|
|
Message = ex.Message,
|
|
MessCode = 0
|
|
};
|
|
}
|
|
}
|
|
public async Task<ApiResponse<T>> DeleteAsync(Guid id)
|
|
{
|
|
try
|
|
{
|
|
var response = await _httpClient.DeleteAsync($"{_baseEndpoint}/{id}");
|
|
var responseJson = await response.Content.ReadAsStringAsync();
|
|
|
|
Debug.WriteLine($"DeleteAsync Response: {responseJson}");
|
|
|
|
if (!response.IsSuccessStatusCode)
|
|
{
|
|
return new ApiResponse<T>
|
|
{
|
|
Success = false,
|
|
Message = $"Server returned {response.StatusCode}: {responseJson}",
|
|
MessCode = (int)response.StatusCode
|
|
};
|
|
}
|
|
|
|
return JsonSerializer.Deserialize<ApiResponse<T>>(responseJson, _jsonOptions) ?? new ApiResponse<T>
|
|
{
|
|
Success = true,
|
|
Message = "Deleted successfully",
|
|
MessCode = 200
|
|
};
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Debug.WriteLine($"Error in DeleteAsync: {ex.Message}");
|
|
return new ApiResponse<T>
|
|
{
|
|
Success = false,
|
|
Message = ex.Message,
|
|
MessCode = 0
|
|
};
|
|
}
|
|
}
|
|
}
|
|
} |