Changes for eveai_chat_client:

- Modal display of privacy statement & Terms & Conditions
- Consent-flag ==> check of privacy and Terms & Conditions
- customisation option added to show or hide DynamicForm titles
This commit is contained in:
Josako
2025-07-28 21:47:56 +02:00
parent ef138462d9
commit 5e81595622
28 changed files with 1609 additions and 2271 deletions

View File

@@ -0,0 +1,191 @@
// eveai_chat_client/static/assets/js/composables/useContentModal.js
import { ref, reactive, provide, inject } from 'vue';
// Injection key for the composable
export const CONTENT_MODAL_KEY = Symbol('contentModal');
// Create the composable
export function useContentModal() {
// Reactive state for modal
const modalState = reactive({
show: false,
title: '',
content: '',
version: '',
loading: false,
error: false,
errorMessage: '',
lastContentUrl: '' // Add this for retry functionality
});
// Content cache to avoid repeated API calls
const contentCache = ref({});
// Show modal with content
const showModal = async (options = {}) => {
const {
title = 'Content',
contentUrl = null,
content = null,
version = ''
} = options;
// Set initial state
modalState.show = true;
modalState.title = title;
modalState.content = content || '';
modalState.version = version;
modalState.loading = !!contentUrl; // Only show loading if we need to fetch content
modalState.error = false;
modalState.errorMessage = '';
modalState.lastContentUrl = contentUrl || ''; // Store for retry functionality
// If content is provided directly, no need to fetch
if (content) {
modalState.loading = false;
return;
}
// If contentUrl is provided, fetch the content
if (contentUrl) {
await loadContent(contentUrl);
}
};
// Hide modal
const hideModal = () => {
console.log('Hiding content modal');
modalState.show = false;
modalState.title = '';
modalState.content = '';
modalState.version = '';
modalState.loading = false;
modalState.error = false;
modalState.errorMessage = '';
modalState.lastContentUrl = ''; // Clear for next use
};
// Load content from API
const loadContent = async (contentUrl) => {
try {
console.log('Loading content from:', contentUrl);
modalState.loading = true;
modalState.error = false;
modalState.errorMessage = '';
// Check cache first
if (contentCache.value[contentUrl]) {
console.log('Content found in cache for:', contentUrl);
const cached = contentCache.value[contentUrl];
modalState.content = cached.content;
modalState.version = cached.version;
modalState.loading = false;
return;
}
// Fetch from API
console.log('Fetching content from API:', contentUrl);
const response = await fetch(contentUrl);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const data = await response.json();
console.log('API response received:', {
hasSuccess: data.success !== undefined,
hasContent: data.content !== undefined,
hasError: data.error !== undefined,
contentLength: data.content ? data.content.length : 0
});
// Support both response formats
if (data.success !== undefined) {
// New format with success property
if (data.success) {
modalState.content = data.content || '';
modalState.version = data.version || '';
} else {
throw new Error(data.error || 'Onbekende fout bij het laden van content');
}
} else if (data.content !== undefined) {
// Legacy format without success property (current privacy/terms endpoints)
modalState.content = data.content || '';
modalState.version = data.version || '';
} else if (data.error) {
// Error response format
throw new Error(data.message || data.error || 'Er is een fout opgetreden');
} else {
throw new Error('Invalid response format: no content or success property found');
}
// Cache the result
contentCache.value[contentUrl] = {
content: modalState.content,
version: modalState.version,
timestamp: Date.now()
};
} catch (error) {
console.error('Error loading content:', error);
modalState.error = true;
modalState.errorMessage = error.message || 'Er is een fout opgetreden bij het laden van de content.';
} finally {
modalState.loading = false;
}
};
// Retry loading content
const retryLoad = async () => {
if (modalState.lastContentUrl) {
console.log('Retrying content load for:', modalState.lastContentUrl);
await loadContent(modalState.lastContentUrl);
} else {
console.warn('No content URL available for retry');
modalState.error = true;
modalState.errorMessage = 'Geen content URL beschikbaar voor opnieuw proberen.';
}
};
// Clear cache (useful for development or when content updates)
const clearCache = () => {
contentCache.value = {};
};
// Get cache size for debugging
const getCacheInfo = () => {
return {
size: Object.keys(contentCache.value).length,
entries: Object.keys(contentCache.value)
};
};
return {
// State
modalState,
// Methods
showModal,
hideModal,
loadContent,
retryLoad,
clearCache,
getCacheInfo
};
}
// Provider function to be used in the root component
export function provideContentModal() {
const contentModal = useContentModal();
provide(CONTENT_MODAL_KEY, contentModal);
return contentModal;
}
// Injector function to be used in child components
export function injectContentModal() {
const contentModal = inject(CONTENT_MODAL_KEY);
if (!contentModal) {
throw new Error('useContentModal must be provided before it can be injected');
}
return contentModal;
}

View File

@@ -211,7 +211,7 @@ export function useComponentTranslations(componentName, originalTexts) {
const translations = provider.registerComponent(componentName, originalTexts);
return {
translations: computed(() => translations.translated),
texts: computed(() => translations.translated),
isLoading: computed(() => translations.isLoading),
error: computed(() => translations.error),
currentLanguage: provider.currentLanguage