From 72492fb754d8fe8c7681e759c08af0ef36785f12 Mon Sep 17 00:00:00 2001 From: Matt Date: Fri, 8 Aug 2025 20:07:47 +0200 Subject: [PATCH] fixes --- pages/dashboard/admin.vue | 235 ++++++++++++++++++++++++++++++++ pages/dashboard/member-list.vue | 40 ++++++ 2 files changed, 275 insertions(+) diff --git a/pages/dashboard/admin.vue b/pages/dashboard/admin.vue index 6b2852b..32d4ab2 100644 --- a/pages/dashboard/admin.vue +++ b/pages/dashboard/admin.vue @@ -112,6 +112,55 @@ + + + + + + mdi-shield-check + reCAPTCHA Configuration + + +

Configure reCAPTCHA settings for form security.

+ + + mdi-shield-account + Configure reCAPTCHA + +
+
+
+ + + + + mdi-account-plus + Membership Configuration + + +

Configure membership fees and payment details.

+ + + mdi-bank + Configure Membership + +
+
+
+
+ @@ -165,6 +214,120 @@ @settings-saved="handleAdminConfigSaved" /> + + + + + mdi-shield-account + reCAPTCHA Configuration + + + + Security Configuration + Configure Google reCAPTCHA settings for form protection on the registration page. + + + + + + + + + Important + Keep your secret key confidential. You can get these keys from the Google reCAPTCHA admin console. + + + + + + Cancel + + Save Configuration + + + + + + + + + + mdi-bank + Membership Configuration + + + + Payment Configuration + Configure membership fees and payment details displayed on the registration page. + + + + + + + + + + + + + Cancel + + Save Configuration + + + + + @@ -253,6 +416,8 @@ const userCount = ref(0); const loading = ref(false); const showCreateUserDialog = ref(false); const showAdminConfig = ref(false); +const showRecaptchaConfig = ref(false); +const showMembershipConfig = ref(false); // Create user dialog data const createUserValid = ref(false); @@ -270,6 +435,23 @@ const roleOptions = [ { title: 'Administrator', value: 'admin' } ]; +// reCAPTCHA configuration data +const recaptchaValid = ref(false); +const savingRecaptcha = ref(false); +const recaptchaConfig = ref({ + siteKey: '', + secretKey: '' +}); + +// Membership configuration data +const membershipValid = ref(false); +const savingMembership = ref(false); +const membershipConfig = ref({ + membershipFee: 50, + iban: '', + accountHolder: '' +}); + const recentActivity = ref([ { id: 1, @@ -349,6 +531,59 @@ const handleAdminConfigSaved = () => { showAdminConfig.value = false; }; +const saveRecaptchaConfig = async () => { + if (!recaptchaValid.value) return; + + savingRecaptcha.value = true; + try { + const response = await $fetch('/api/admin/recaptcha-config', { + method: 'POST', + body: { + siteKey: recaptchaConfig.value.siteKey, + secretKey: recaptchaConfig.value.secretKey + } + }) as any; + + if (response?.success) { + showRecaptchaConfig.value = false; + console.log('reCAPTCHA configuration saved successfully'); + // TODO: Show success notification + } + } catch (error) { + console.error('Failed to save reCAPTCHA configuration:', error); + // TODO: Show error notification + } finally { + savingRecaptcha.value = false; + } +}; + +const saveMembershipConfig = async () => { + if (!membershipValid.value) return; + + savingMembership.value = true; + try { + const response = await $fetch('/api/admin/registration-config', { + method: 'POST', + body: { + membershipFee: membershipConfig.value.membershipFee, + iban: membershipConfig.value.iban, + accountHolder: membershipConfig.value.accountHolder + } + }) as any; + + if (response?.success) { + showMembershipConfig.value = false; + console.log('Membership configuration saved successfully'); + // TODO: Show success notification + } + } catch (error) { + console.error('Failed to save membership configuration:', error); + // TODO: Show error notification + } finally { + savingMembership.value = false; + } +}; + const createUserAccount = async () => { if (!createUserValid.value) return; diff --git a/pages/dashboard/member-list.vue b/pages/dashboard/member-list.vue index d0c30f6..89245e2 100644 --- a/pages/dashboard/member-list.vue +++ b/pages/dashboard/member-list.vue @@ -150,8 +150,11 @@ @edit="editMember" @delete="confirmDeleteMember" @view="viewMember" + @create-portal-account="createPortalAccount" :can-edit="canEditMembers" :can-delete="canDeleteMembers" + :can-create-portal-account="canCreatePortalAccounts" + :creating-portal-account="creatingPortalAccountIds.includes(member.Id)" /> @@ -258,6 +261,7 @@ const { firstName, isBoard, isAdmin } = useAuth(); const canCreateMembers = computed(() => isBoard.value || isAdmin.value); const canEditMembers = computed(() => isBoard.value || isAdmin.value); const canDeleteMembers = computed(() => isAdmin.value); +const canCreatePortalAccounts = computed(() => isAdmin.value); // Only admins can create portal accounts // Reactive data const members = ref([]); @@ -282,6 +286,9 @@ const deleteLoading = ref(false); const showSuccess = ref(false); const successMessage = ref(''); +// Portal account creation +const creatingPortalAccountIds = ref([]); + // Filter options const activeFilterOptions = [ { title: 'Active Members', value: 'active' }, @@ -493,6 +500,39 @@ const handleMemberUpdated = (updatedMember: Member) => { successMessage.value = `${updatedMember.FullName} has been updated successfully.`; }; +const createPortalAccount = async (member: Member) => { + if (!member.Id || creatingPortalAccountIds.value.includes(member.Id)) return; + + // Add to creating array to show loading state + creatingPortalAccountIds.value.push(member.Id); + + try { + const response = await $fetch(`/api/members/${member.Id}/create-portal-account`) as any; + + if (response?.success) { + // Update the member in the local array to reflect the new keycloak_id + const index = members.value.findIndex(m => m.Id === member.Id); + if (index !== -1) { + members.value[index] = { ...members.value[index], keycloak_id: response.keycloak_id }; + } + + showSuccess.value = true; + successMessage.value = `Portal account created successfully for ${member.FullName}. They will receive an email with login instructions.`; + } else { + throw new Error(response?.message || 'Failed to create portal account'); + } + } catch (err: any) { + console.error('Error creating portal account:', err); + error.value = err.data?.message || err.message || 'Failed to create portal account. Please try again.'; + } finally { + // Remove from creating array + const index = creatingPortalAccountIds.value.indexOf(member.Id); + if (index > -1) { + creatingPortalAccountIds.value.splice(index, 1); + } + } +}; + // Load members on mount onMounted(() => { loadMembers();