242 lines
6.1 KiB
JavaScript
242 lines
6.1 KiB
JavaScript
/**
|
|
* Enhanced API wrapper with PrimeVue Toast integration
|
|
*
|
|
* This provides a cleaner, simpler API error handling system using PrimeVue Toast
|
|
* instead of a complex custom notification system.
|
|
*/
|
|
|
|
import { useErrorStore } from "@/stores/errors";
|
|
import { useLoadingStore } from "@/stores/loading";
|
|
import Api from "./api";
|
|
|
|
export class ApiWithToast {
|
|
static async makeApiCall(apiFunction, options = {}) {
|
|
const {
|
|
// Error handling options
|
|
componentName = null,
|
|
showErrorToast = true,
|
|
showSuccessToast = false,
|
|
|
|
// Loading options
|
|
showLoading = true,
|
|
loadingMessage = "Loading...",
|
|
|
|
// Success options
|
|
successMessage = null,
|
|
|
|
// Error options
|
|
customErrorMessage = null,
|
|
|
|
// Retry options
|
|
retryCount = 0,
|
|
retryDelay = 1000,
|
|
|
|
// Operation identifier for tracking
|
|
operationKey = null,
|
|
rethrow = false,
|
|
} = options;
|
|
|
|
const errorStore = useErrorStore();
|
|
const loadingStore = useLoadingStore();
|
|
|
|
// Generate operation key if not provided
|
|
const operation = operationKey || `api-${Date.now()}`;
|
|
|
|
try {
|
|
// Clear any existing errors
|
|
if (componentName) {
|
|
errorStore.clearComponentError(componentName);
|
|
}
|
|
|
|
// Show loading state
|
|
if (showLoading) {
|
|
if (componentName) {
|
|
loadingStore.setComponentLoading(componentName, true, loadingMessage);
|
|
} else {
|
|
loadingStore.startOperation(operation, loadingMessage);
|
|
}
|
|
}
|
|
|
|
// Make the API call with retry logic
|
|
let attempt = 0;
|
|
while (attempt <= retryCount) {
|
|
try {
|
|
const result = await apiFunction();
|
|
|
|
// Show success toast if requested
|
|
if (showSuccessToast && successMessage) {
|
|
errorStore.setSuccess(successMessage);
|
|
}
|
|
|
|
return result;
|
|
} catch (error) {
|
|
attempt++;
|
|
|
|
if (attempt <= retryCount) {
|
|
// Wait before retry
|
|
await new Promise((resolve) => setTimeout(resolve, retryDelay));
|
|
continue;
|
|
}
|
|
|
|
// Final attempt failed - handle error
|
|
if (componentName) {
|
|
errorStore.setComponentError(componentName, error, false);
|
|
}
|
|
|
|
// Show error toast
|
|
if (showErrorToast) {
|
|
const errorMessage = customErrorMessage || this.extractErrorMessage(error);
|
|
errorStore.setGlobalError(new Error(errorMessage));
|
|
}
|
|
|
|
// Rethrow error if requested (default is to rethrow)
|
|
if (rethrow) {
|
|
throw error;
|
|
}
|
|
|
|
// If not rethrowing, return null to indicate failure
|
|
return null;
|
|
}
|
|
}
|
|
} finally {
|
|
// Always clear loading state
|
|
if (showLoading) {
|
|
if (componentName) {
|
|
loadingStore.setComponentLoading(componentName, false);
|
|
} else {
|
|
loadingStore.stopOperation(operation);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Helper to extract meaningful error messages
|
|
static extractErrorMessage(error) {
|
|
if (typeof error === "string") {
|
|
return error;
|
|
}
|
|
|
|
if (error?.response?.data?.message) {
|
|
return error.response.data.message;
|
|
}
|
|
|
|
if (error?.message) {
|
|
return error.message;
|
|
}
|
|
|
|
if (error?.request) {
|
|
return "Network error - please check your connection";
|
|
}
|
|
|
|
return "An unexpected error occurred";
|
|
}
|
|
|
|
// Convenience methods for common API operations
|
|
static async getClientStatusCounts(options = {}) {
|
|
return this.makeApiCall(() => Api.getClientStatusCounts(), {
|
|
operationKey: "client-status-counts",
|
|
componentName: "clients",
|
|
loadingMessage: "Loading client status data...",
|
|
showSuccessToast: false, // Don't show success for data fetches
|
|
...options,
|
|
});
|
|
}
|
|
|
|
static async getPaginatedClientDetails(paginationParams, filters, sorting, options = {}) {
|
|
return this.makeApiCall(
|
|
() => Api.getPaginatedClientDetails(paginationParams, filters, sorting),
|
|
{
|
|
operationKey: "client-table-data",
|
|
componentName: "dataTable",
|
|
loadingMessage: "Loading client data...",
|
|
showSuccessToast: false,
|
|
...options,
|
|
},
|
|
);
|
|
}
|
|
|
|
static async createClient(clientData, options = {}) {
|
|
return this.makeApiCall(() => Api.createClient(clientData), {
|
|
operationKey: "create-client",
|
|
componentName: "form",
|
|
loadingMessage: "Creating client...",
|
|
showSuccessToast: true,
|
|
successMessage: "Client created successfully!",
|
|
...options,
|
|
});
|
|
}
|
|
|
|
static async getPaginatedJobDetails(paginationParams, filters, sorting, options = {}) {
|
|
return this.makeApiCall(
|
|
() => Api.getPaginatedJobDetails(paginationParams, filters, sorting),
|
|
{
|
|
operationKey: "job-table-data",
|
|
componentName: "jobs",
|
|
loadingMessage: "Loading job data...",
|
|
showSuccessToast: false,
|
|
...options,
|
|
},
|
|
);
|
|
}
|
|
|
|
static async getPaginatedWarrantyData(paginationParams, filters, sorting, options = {}) {
|
|
return this.makeApiCall(
|
|
() => Api.getPaginatedWarrantyData(paginationParams, filters, sorting),
|
|
{
|
|
operationKey: "warranty-table-data",
|
|
componentName: "warranties",
|
|
loadingMessage: "Loading warranty data...",
|
|
showSuccessToast: false,
|
|
...options,
|
|
},
|
|
);
|
|
}
|
|
|
|
static async getCityStateByZip(zipcode, options = {}) {
|
|
return this.makeApiCall(() => Api.getCityStateByZip(zipcode), {
|
|
operationKey: "zip-lookup",
|
|
componentName: "form",
|
|
loadingMessage: "Looking up location...",
|
|
showSuccessToast: false,
|
|
customErrorMessage: "Unable to find location for the provided zip code",
|
|
retryCount: 2,
|
|
retryDelay: 1000,
|
|
...options,
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Simple usage examples:
|
|
*
|
|
* // Basic API call with automatic toast notifications
|
|
* try {
|
|
* const result = await ApiWithToast.getPaginatedClientDetails(pagination, filters, []);
|
|
* // Success - data loaded, no toast shown for data fetches
|
|
* } catch (error) {
|
|
* // Error toast automatically shown, component error set
|
|
* }
|
|
*
|
|
* // Create operation with success toast
|
|
* try {
|
|
* await ApiWithToast.createClient(formData);
|
|
* // Success toast shown automatically: "Client created successfully!"
|
|
* } catch (error) {
|
|
* // Error toast shown automatically with appropriate message
|
|
* }
|
|
*
|
|
* // Custom options
|
|
* await ApiWithToast.makeApiCall(
|
|
* () => someApiCall(),
|
|
* {
|
|
* componentName: 'myComponent',
|
|
* showSuccessToast: true,
|
|
* successMessage: 'Operation completed!',
|
|
* retryCount: 3,
|
|
* customErrorMessage: 'Custom error message'
|
|
* }
|
|
* );
|
|
*/
|
|
|
|
export default ApiWithToast;
|