Files
thetool/public/plugins/vue/tt-core/composables/useAsyncData.js
2025-12-09 05:34:24 +00:00

158 lines
4.4 KiB
JavaScript

/**
* TT-Core Async Data Composable (Vue 3)
* Provides async data fetching with loading states
*/
/**
* Create an async data composable
* @returns {Object} - Composable with state and methods
*/
export function useAsyncData() {
const { ref } = Vue;
const isLoading = ref(false);
const hasError = ref(false);
const errorMessage = ref(null);
const data = ref(null);
/**
* Execute async operation with loading state
* @param {Function} asyncFn - Async function to execute
* @param {Object} options - Options
* @returns {Promise<any>} - Result
*/
const executeAsync = async (asyncFn, options = {}) => {
isLoading.value = true;
hasError.value = false;
errorMessage.value = null;
try {
const result = await asyncFn();
data.value = result;
return result;
} catch (error) {
hasError.value = true;
errorMessage.value = error.message || 'Ein Fehler ist aufgetreten';
if (options.onError) {
options.onError(error);
}
throw error;
} finally {
isLoading.value = false;
}
};
/**
* Fetch data from API
* @param {string} url - API URL
* @param {Object} options - Fetch options
* @returns {Promise<any>} - Response data
*/
const fetchData = async (url, options = {}) => {
return executeAsync(async () => {
const response = await fetch(url, options);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const contentType = response.headers.get('content-type');
if (contentType && contentType.includes('application/json')) {
return await response.json();
}
return await response.text();
});
};
/**
* Reset state
*/
const reset = () => {
isLoading.value = false;
hasError.value = false;
errorMessage.value = null;
data.value = null;
};
return {
isLoading,
hasError,
errorMessage,
data,
executeAsync,
fetchData,
reset
};
}
/**
* Create an async data mixin (backward compatibility)
* @returns {Object} - Vue mixin
*/
export function createAsyncDataMixin() {
return {
data() {
return {
isLoading: false,
hasError: false,
errorMessage: null
};
},
methods: {
/**
* Execute async operation with loading state
* @param {Function} asyncFn - Async function to execute
* @param {Object} options - Options
* @returns {Promise<any>} - Result
*/
async executeAsync(asyncFn, options = {}) {
this.isLoading = true;
this.hasError = false;
this.errorMessage = null;
try {
const result = await asyncFn();
return result;
} catch (error) {
this.hasError = true;
this.errorMessage = error.message || 'Ein Fehler ist aufgetreten';
if (options.onError) {
options.onError(error);
}
throw error;
} finally {
this.isLoading = false;
}
},
/**
* Fetch data from API
* @param {string} url - API URL
* @param {Object} options - Fetch options
* @returns {Promise<any>} - Response data
*/
async fetchData(url, options = {}) {
return this.executeAsync(async () => {
const response = await fetch(url, options);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const contentType = response.headers.get('content-type');
if (contentType && contentType.includes('application/json')) {
return await response.json();
}
return await response.text();
});
}
}
};
}