158 lines
4.4 KiB
JavaScript
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();
|
|
});
|
|
}
|
|
}
|
|
};
|
|
}
|