diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 28233f1..5b54abb 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -61,7 +61,11 @@ "Read(/Z:\\Repos\\monacousa-portal\\assets\\scss/**)", "Read(/Z:\\Repos\\monacousa-portal\\pages\\admin/**)", "Read(/Z:\\Repos\\monacousa-portal\\pages\\admin/**)", - "Read(/Z:\\Repos\\monacousa-portal\\pages\\admin/**)" + "Read(/Z:\\Repos\\monacousa-portal\\pages\\admin/**)", + "Read(/Z:\\Repos\\monacousa-portal\\pages\\admin\\dashboard/**)", + "Read(/Z:\\Repos\\monacousa-portal\\components/**)", + "Read(/Z:\\Repos\\monacousa-portal\\components/**)", + "Read(/Z:\\Repos\\monacousa-portal\\pages\\admin\\settings/**)" ], "deny": [], "ask": [] diff --git a/.serena/cache/typescript/document_symbols_cache_v23-06-25.pkl b/.serena/cache/typescript/document_symbols_cache_v23-06-25.pkl index f1eb18d..cf6051f 100644 Binary files a/.serena/cache/typescript/document_symbols_cache_v23-06-25.pkl and b/.serena/cache/typescript/document_symbols_cache_v23-06-25.pkl differ diff --git a/components/DuesActionCard.vue b/components/DuesActionCard.vue index f0e6c72..feb8e76 100644 --- a/components/DuesActionCard.vue +++ b/components/DuesActionCard.vue @@ -118,14 +118,14 @@ - + mdi-check-circle Mark as Paid diff --git a/pages/admin/settings/index.vue b/pages/admin/settings/index.vue index 496c711..a6dc763 100644 --- a/pages/admin/settings/index.vue +++ b/pages/admin/settings/index.vue @@ -19,6 +19,10 @@ mdi-email Email + + mdi-database + NocoDB + @@ -327,6 +331,178 @@ + + + + + + + + + + + + + + + + + mdi-pencil + Edit NocoDB Configuration + + + + mdi-check + Save + + + mdi-connection + Test Connection + + + mdi-close + Cancel + + + + + + + +

NocoDB Database Configuration

+
+ + + + + + + + + + + + + + + +

Table Mappings

+
+ + + + + + + + + +
+ + + + + + {{ nocodbConnectionStatus.message }} + + + +
+
@@ -359,8 +535,12 @@ definePageMeta({ const activeTab = ref('general'); const generalEditMode = ref(false); const emailEditMode = ref(false); +const nocodbEditMode = ref(false); const showPassword = ref(false); +const showNocodbApiKey = ref(false); const testingEmail = ref(false); +const testingNocodb = ref(false); +const nocodbConnectionStatus = ref<{ success: boolean; message: string } | null>(null); const snackbar = ref(false); const snackbarText = ref(''); const snackbarColor = ref('success'); @@ -386,6 +566,16 @@ const settings = ref({ useTLS: true, fromName: 'MonacoUSA', fromEmail: 'noreply@monacousa.org' + }, + nocodb: { + url: '', + apiKey: '', + baseId: '', + tables: { + members: 'Members', + events: 'Events', + rsvps: 'RSVPs' + } } }); @@ -413,6 +603,7 @@ const currencies = [ // Load settings on mount onMounted(async () => { await loadSettings(); + await loadNocodbSettings(); }); // Methods @@ -488,6 +679,84 @@ const showNotification = (text: string, color: string = 'success') => { snackbar.value = true; }; +const loadNocodbSettings = async () => { + try { + const response = await $fetch<{ success: boolean; data?: any }>('/api/admin/nocodb-config'); + if (response.success && response.data) { + settings.value.nocodb = { + url: response.data.url || '', + apiKey: response.data.apiKey || '', + baseId: response.data.baseId || '', + tables: response.data.tables || { + members: 'Members', + events: 'Events', + rsvps: 'RSVPs' + } + }; + } + } catch (error) { + console.error('Error loading NocoDB settings:', error); + showNotification('Failed to load NocoDB settings', 'error'); + } +}; + +const saveNocodbSettings = async () => { + try { + const response = await $fetch('/api/admin/nocodb-config', { + method: 'POST', + body: settings.value.nocodb + }); + nocodbEditMode.value = false; + showNocodbApiKey.value = false; + showNotification('NocoDB settings saved successfully', 'success'); + // Reload settings to ensure they're persistent + await loadNocodbSettings(); + } catch (error) { + console.error('Error saving NocoDB settings:', error); + showNotification('Failed to save NocoDB settings', 'error'); + } +}; + +const testNocodbConnection = async () => { + testingNocodb.value = true; + nocodbConnectionStatus.value = null; + + try { + const response = await $fetch<{ success: boolean; message: string }>('/api/admin/nocodb-test', { + method: 'POST', + body: settings.value.nocodb + }); + + nocodbConnectionStatus.value = { + success: response.success, + message: response.message + }; + + if (response.success) { + showNotification('NocoDB connection successful', 'success'); + } else { + showNotification(response.message, 'error'); + } + } catch (error: any) { + nocodbConnectionStatus.value = { + success: false, + message: error.data?.message || 'Failed to connect to NocoDB' + }; + showNotification('Connection test failed', 'error'); + } finally { + testingNocodb.value = false; + } +}; + +const cancelNocodbEdit = () => { + if (originalSettings.value) { + settings.value.nocodb = { ...originalSettings.value.nocodb }; + } + nocodbEditMode.value = false; + showNocodbApiKey.value = false; + nocodbConnectionStatus.value = null; +}; + // Watch for edit mode changes to backup original settings watch(generalEditMode, (newVal) => { if (newVal) { @@ -505,6 +774,14 @@ watch(emailEditMode, (newVal) => { } }); +watch(nocodbEditMode, (newVal) => { + if (newVal) { + originalSettings.value = { + nocodb: { ...settings.value.nocodb } + }; + } +}); + // Prevent browser autofill on mount onMounted(() => { // Disable autofill for all inputs initially