LSFE/LSFE.MobApp/Services/ApiClient.cs
2026-07-30 10:31:04 +08:00

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
};
}
}
}
}