feat: Add comprehensive terms & conditions with required acceptance

- Create responsive TermsModal component for mobile and desktop
- Add comprehensive legal terms with prominent AI disclaimer
- Update footer to show terms modal and AI warning on all pages
- Require terms acceptance checkbox during account registration
- Add validation to ensure users accept terms before registration
- Include clickable link in checkbox to view full terms in modal

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-07 13:14:36 -05:00
parent fc17db62d4
commit 8c66550987
4 changed files with 583 additions and 7 deletions

View File

@@ -1,12 +1,27 @@
<template>
<footer class="bg-gray-100 border-t border-gray-200 mt-auto">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4">
<p class="text-center text-sm text-gray-600">
Created for New Life Christian Church by Joshua Ryder with AI assistance
</p>
<div class="flex flex-col items-center gap-2">
<p class="text-center text-sm text-gray-600">
Created for New Life Christian Church by Joshua Ryder with AI assistance
</p>
<div class="flex items-center gap-4 text-xs text-gray-500">
<button
@click="showTermsModal = true"
class="hover:text-blue-600 hover:underline"
>
Terms of Use & Privacy Policy
</button>
<span>|</span>
<span> AI-Generated System - Use at Your Own Risk</span>
</div>
</div>
</div>
<TermsModal v-model="showTermsModal" />
</footer>
</template>
<script setup lang="ts">
const showTermsModal = ref(false)
</script>

288
components/TermsModal.vue Normal file
View File

@@ -0,0 +1,288 @@
<template>
<!-- Modal Overlay -->
<Teleport to="body">
<Transition name="modal">
<div
v-if="modelValue"
class="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black bg-opacity-50"
@click.self="closeModal"
>
<!-- Modal Content -->
<div
class="bg-white rounded-lg shadow-xl w-full max-w-4xl max-h-[90vh] flex flex-col"
@click.stop
>
<!-- Modal Header -->
<div class="flex items-center justify-between p-4 sm:p-6 border-b border-gray-200 sticky top-0 bg-white rounded-t-lg">
<h2 class="text-xl sm:text-2xl font-bold text-gray-900">Terms of Use & Privacy Policy</h2>
<button
@click="closeModal"
class="text-gray-400 hover:text-gray-600 transition-colors p-1"
aria-label="Close modal"
>
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
<!-- Modal Body (Scrollable) -->
<div class="overflow-y-auto p-4 sm:p-6 flex-1">
<!-- AI Disclaimer Section -->
<section class="mb-6 p-4 sm:p-6 bg-yellow-50 border-l-4 border-yellow-400 rounded">
<h3 class="text-lg sm:text-xl font-semibold text-gray-900 mb-3 flex items-center">
<span class="mr-2"></span> Important: AI-Generated Content Disclaimer
</h3>
<div class="space-y-3 text-sm sm:text-base text-gray-700">
<p class="font-semibold">
This website and application were created with artificial intelligence (AI) assistance.
</p>
<p>
<strong>Please be aware:</strong> AI technology, while powerful, is not perfect and can make mistakes.
This includes but is not limited to:
</p>
<ul class="list-disc list-inside ml-4 space-y-1">
<li>Errors in code or functionality</li>
<li>Unexpected behavior or bugs</li>
<li>Security vulnerabilities</li>
<li>Data processing or storage issues</li>
<li>Incorrect information display</li>
</ul>
<p class="font-semibold text-red-700 mt-3">
Users should not rely on this system as the sole repository for important information.
Always maintain backup copies of your sermon notes and important data.
</p>
</div>
</section>
<!-- Terms of Use -->
<section class="mb-6">
<h3 class="text-lg sm:text-xl font-semibold text-gray-900 mb-3">Terms of Use</h3>
<div class="space-y-3 text-sm sm:text-base text-gray-700">
<p>
By accessing and using this website (the "Service"), you accept and agree to be bound by the
terms and provisions of this agreement.
</p>
<h4 class="text-base sm:text-lg font-semibold text-gray-900 mt-4 mb-2">Purpose</h4>
<p>
This Service is provided by New Life Christian Church (the "Church") to assist members and
attendees in viewing sermon information and taking personal notes during services. The Service
is provided as-is for informational and organizational purposes only.
</p>
<h4 class="text-base sm:text-lg font-semibold text-gray-900 mt-4 mb-2">Use at Your Own Risk</h4>
<p>
You acknowledge and agree that your use of this Service is at your sole risk. The Service
is provided on an "AS IS" and "AS AVAILABLE" basis without warranties of any kind, either
express or implied.
</p>
</div>
</section>
<!-- Limitation of Liability -->
<section class="mb-6">
<h3 class="text-lg sm:text-xl font-semibold text-gray-900 mb-3">Limitation of Liability</h3>
<div class="space-y-3 text-sm sm:text-base text-gray-700">
<p class="font-semibold">
TO THE FULLEST EXTENT PERMITTED BY LAW, NEW LIFE CHRISTIAN CHURCH, ITS STAFF, VOLUNTEERS,
CONTRACTORS, AND AFFILIATES SHALL NOT BE LIABLE FOR ANY DAMAGES OF ANY KIND ARISING FROM
THE USE OF THIS SERVICE.
</p>
<p>This includes but is not limited to:</p>
<ul class="list-disc list-inside ml-4 space-y-1">
<li>Loss of data, including sermon notes or personal information</li>
<li>Service interruptions or downtime</li>
<li>Errors, bugs, or technical malfunctions</li>
<li>Security breaches or unauthorized access</li>
<li>Inaccurate or incomplete information</li>
<li>Any indirect, incidental, special, consequential, or punitive damages</li>
</ul>
<p class="mt-3">
The Church makes no guarantee regarding the availability, reliability, or accuracy of the
Service and reserves the right to modify, suspend, or discontinue the Service at any time
without notice.
</p>
</div>
</section>
<!-- Data & Privacy -->
<section class="mb-6">
<h3 class="text-lg sm:text-xl font-semibold text-gray-900 mb-3">Privacy & Data</h3>
<div class="space-y-3 text-sm sm:text-base text-gray-700">
<h4 class="text-base sm:text-lg font-semibold text-gray-900 mt-4 mb-2">Information We Collect</h4>
<p>When you register for an account, we collect:</p>
<ul class="list-disc list-inside ml-4 space-y-1">
<li>Username and password (password is encrypted)</li>
<li>Email address</li>
<li>First and last name</li>
<li>Your sermon notes and related content</li>
</ul>
<h4 class="text-base sm:text-lg font-semibold text-gray-900 mt-4 mb-2">How We Use Your Information</h4>
<p>Your information is used to:</p>
<ul class="list-disc list-inside ml-4 space-y-1">
<li>Provide access to the Service</li>
<li>Store and manage your sermon notes</li>
<li>Send you sermon notes via email when requested</li>
<li>Authenticate your account</li>
</ul>
<h4 class="text-base sm:text-lg font-semibold text-gray-900 mt-4 mb-2">Data Retention</h4>
<p>
Your notes are stored in our database and are associated with your account.
<strong class="text-red-700">Important:</strong> If a sermon is deleted by an administrator,
all associated user notes for that sermon are permanently deleted. We recommend regularly
downloading or emailing your notes to maintain personal backups.
</p>
<h4 class="text-base sm:text-lg font-semibold text-gray-900 mt-4 mb-2">Data Security</h4>
<p>
While we implement security measures to protect your data, no system is completely secure.
Given that this system was created with AI assistance, there may be unknown vulnerabilities.
The Church cannot guarantee the security of your information.
</p>
<h4 class="text-base sm:text-lg font-semibold text-gray-900 mt-4 mb-2">Third-Party Services</h4>
<p>
When you email your notes, we use third-party email service providers to deliver your messages.
Your email address and content are transmitted through these services.
</p>
</div>
</section>
<!-- User Responsibilities -->
<section class="mb-6">
<h3 class="text-lg sm:text-xl font-semibold text-gray-900 mb-3">User Responsibilities</h3>
<div class="space-y-3 text-sm sm:text-base text-gray-700">
<p>As a user of this Service, you agree to:</p>
<ul class="list-disc list-inside ml-4 space-y-1">
<li>Maintain the confidentiality of your account credentials</li>
<li>Use the Service only for its intended purpose</li>
<li>Maintain your own backups of important notes and information</li>
<li>Not attempt to compromise the security of the Service</li>
<li>Not use the Service for any unlawful purpose</li>
<li>Accept sole responsibility for any content you create or upload</li>
</ul>
</div>
</section>
<!-- Account Termination -->
<section class="mb-6">
<h3 class="text-lg sm:text-xl font-semibold text-gray-900 mb-3">Account Termination</h3>
<div class="space-y-3 text-sm sm:text-base text-gray-700">
<p>
The Church reserves the right to terminate or suspend your account at any time, with or
without notice, for any reason, including violation of these terms or at the Church's sole
discretion.
</p>
</div>
</section>
<!-- Changes to Terms -->
<section class="mb-6">
<h3 class="text-lg sm:text-xl font-semibold text-gray-900 mb-3">Changes to These Terms</h3>
<div class="space-y-3 text-sm sm:text-base text-gray-700">
<p>
The Church reserves the right to modify these terms at any time. Continued use of the
Service after changes constitutes acceptance of the modified terms.
</p>
</div>
</section>
<!-- Contact -->
<section class="mb-6">
<h3 class="text-lg sm:text-xl font-semibold text-gray-900 mb-3">Contact Information</h3>
<div class="space-y-3 text-sm sm:text-base text-gray-700">
<p>
If you have questions about these terms or the Service, please contact New Life Christian
Church through our regular church communication channels.
</p>
</div>
</section>
<!-- Acceptance -->
<section class="mb-6 p-4 sm:p-6 bg-gray-50 border rounded">
<p class="text-sm sm:text-base text-gray-700">
<strong>By using this Service, you acknowledge that you have read, understood, and agree to
be bound by these Terms of Use and Privacy Policy, including the AI-generated content disclaimer.</strong>
</p>
<p class="text-xs sm:text-sm text-gray-600 mt-3">
Last Updated: {{ new Date().toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' }) }}
</p>
</section>
</div>
<!-- Modal Footer -->
<div class="border-t border-gray-200 p-4 sm:p-6 bg-gray-50 rounded-b-lg">
<button
@click="closeModal"
class="w-full sm:w-auto px-6 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 font-medium transition-colors"
>
Close
</button>
</div>
</div>
</div>
</Transition>
</Teleport>
</template>
<script setup lang="ts">
const props = defineProps<{
modelValue: boolean
}>()
const emit = defineEmits<{
'update:modelValue': [value: boolean]
}>()
const closeModal = () => {
emit('update:modelValue', false)
}
// Close on escape key
onMounted(() => {
const handleEscape = (e: KeyboardEvent) => {
if (e.key === 'Escape' && props.modelValue) {
closeModal()
}
}
window.addEventListener('keydown', handleEscape)
onUnmounted(() => {
window.removeEventListener('keydown', handleEscape)
})
})
// Prevent body scroll when modal is open
watch(() => props.modelValue, (isOpen) => {
if (isOpen) {
document.body.style.overflow = 'hidden'
} else {
document.body.style.overflow = ''
}
})
</script>
<style scoped>
.modal-enter-active,
.modal-leave-active {
transition: opacity 0.3s ease;
}
.modal-enter-from,
.modal-leave-to {
opacity: 0;
}
.modal-enter-active .bg-white,
.modal-leave-active .bg-white {
transition: transform 0.3s ease;
}
.modal-enter-from .bg-white,
.modal-leave-to .bg-white {
transform: scale(0.9);
}
</style>

View File

@@ -136,7 +136,7 @@
required
class="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500"
/>
<!-- Password Match Indicator -->
<div v-if="confirmPassword.length > 0" class="mt-2 text-xs">
<div :class="passwordsMatch ? 'text-green-600' : 'text-red-600'">
@@ -146,14 +146,42 @@
</div>
</div>
<!-- Terms Acceptance (only show when registering) -->
<div v-if="isRegistering" class="flex items-start">
<div class="flex items-center h-5">
<input
id="termsAccepted"
v-model="termsAccepted"
type="checkbox"
required
class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded"
/>
</div>
<div class="ml-3 text-sm">
<label for="termsAccepted" class="font-medium text-gray-700">
I agree to the
<button
type="button"
@click="showTermsModal = true"
class="text-blue-600 hover:text-blue-700 underline"
>
Terms of Use & Privacy Policy
</button>
</label>
<p class="text-xs text-gray-500 mt-1">
This system was created with AI assistance and may contain errors. Please read the terms carefully.
</p>
</div>
</div>
<div v-if="error" class="text-red-600 text-sm">
{{ error }}
</div>
<button
type="submit"
:disabled="loading"
class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50"
:disabled="loading || (isRegistering && !termsAccepted)"
class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50 disabled:cursor-not-allowed"
>
{{ loading ? (isRegistering ? 'Creating account...' : 'Signing in...') : (isRegistering ? 'Create Account' : 'Sign In') }}
</button>
@@ -180,8 +208,9 @@
</div>
</div>
</div>
<Footer />
<TermsModal v-model="showTermsModal" />
</div>
</template>
@@ -202,6 +231,8 @@ const firstName = ref('')
const lastName = ref('')
const error = ref('')
const loading = ref(false)
const termsAccepted = ref(false)
const showTermsModal = ref(false)
// Initialize from URL query parameter
const isRegistering = ref(route.query.mode === 'register')
@@ -233,6 +264,7 @@ function toggleMode() {
email.value = ''
firstName.value = ''
lastName.value = ''
termsAccepted.value = false
// Update URL to reflect mode
const query = { ...route.query }
@@ -284,6 +316,12 @@ async function handleRegister() {
return
}
// Validate terms acceptance
if (!termsAccepted.value) {
error.value = 'You must agree to the Terms of Use & Privacy Policy'
return
}
loading.value = true
try {

235
pages/terms.vue Normal file
View File

@@ -0,0 +1,235 @@
<template>
<div class="min-h-screen bg-gray-50 flex flex-col">
<header class="bg-white shadow-sm">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
<div class="flex items-center justify-between">
<NuxtLink to="/" class="hover:opacity-80">
<img src="/logos/logo.png" alt="New Life Christian Church" class="h-16 w-auto" />
</NuxtLink>
<ClientOnly fallback-tag="div">
<Menu
:is-authenticated="isAuthenticated"
:is-admin="isAdmin"
:show-home="true"
:current-path="route.fullPath"
/>
</ClientOnly>
</div>
</div>
</header>
<main class="flex-1 max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-12 w-full">
<div class="bg-white shadow-lg rounded-lg p-8">
<h1 class="text-4xl font-bold text-gray-900 mb-8">Terms of Use & Privacy Policy</h1>
<!-- AI Disclaimer Section -->
<section class="mb-8 p-6 bg-yellow-50 border-l-4 border-yellow-400 rounded">
<h2 class="text-2xl font-semibold text-gray-900 mb-4 flex items-center">
<span class="mr-2"></span> Important: AI-Generated Content Disclaimer
</h2>
<div class="space-y-3 text-gray-700">
<p class="font-semibold">
This website and application were created with artificial intelligence (AI) assistance.
</p>
<p>
<strong>Please be aware:</strong> AI technology, while powerful, is not perfect and can make mistakes.
This includes but is not limited to:
</p>
<ul class="list-disc list-inside ml-4 space-y-2">
<li>Errors in code or functionality</li>
<li>Unexpected behavior or bugs</li>
<li>Security vulnerabilities</li>
<li>Data processing or storage issues</li>
<li>Incorrect information display</li>
</ul>
<p class="font-semibold text-red-700 mt-4">
Users should not rely on this system as the sole repository for important information.
Always maintain backup copies of your sermon notes and important data.
</p>
</div>
</section>
<!-- Terms of Use -->
<section class="mb-8">
<h2 class="text-2xl font-semibold text-gray-900 mb-4">Terms of Use</h2>
<div class="space-y-4 text-gray-700">
<p>
By accessing and using this website (the "Service"), you accept and agree to be bound by the
terms and provisions of this agreement.
</p>
<h3 class="text-xl font-semibold text-gray-900 mt-6 mb-3">Purpose</h3>
<p>
This Service is provided by New Life Christian Church (the "Church") to assist members and
attendees in viewing sermon information and taking personal notes during services. The Service
is provided as-is for informational and organizational purposes only.
</p>
<h3 class="text-xl font-semibold text-gray-900 mt-6 mb-3">Use at Your Own Risk</h3>
<p>
You acknowledge and agree that your use of this Service is at your sole risk. The Service
is provided on an "AS IS" and "AS AVAILABLE" basis without warranties of any kind, either
express or implied.
</p>
</div>
</section>
<!-- Limitation of Liability -->
<section class="mb-8">
<h2 class="text-2xl font-semibold text-gray-900 mb-4">Limitation of Liability</h2>
<div class="space-y-4 text-gray-700">
<p class="font-semibold">
TO THE FULLEST EXTENT PERMITTED BY LAW, NEW LIFE CHRISTIAN CHURCH, ITS STAFF, VOLUNTEERS,
CONTRACTORS, AND AFFILIATES SHALL NOT BE LIABLE FOR ANY DAMAGES OF ANY KIND ARISING FROM
THE USE OF THIS SERVICE.
</p>
<p>This includes but is not limited to:</p>
<ul class="list-disc list-inside ml-4 space-y-2">
<li>Loss of data, including sermon notes or personal information</li>
<li>Service interruptions or downtime</li>
<li>Errors, bugs, or technical malfunctions</li>
<li>Security breaches or unauthorized access</li>
<li>Inaccurate or incomplete information</li>
<li>Any indirect, incidental, special, consequential, or punitive damages</li>
</ul>
<p class="mt-4">
The Church makes no guarantee regarding the availability, reliability, or accuracy of the
Service and reserves the right to modify, suspend, or discontinue the Service at any time
without notice.
</p>
</div>
</section>
<!-- Data & Privacy -->
<section class="mb-8">
<h2 class="text-2xl font-semibold text-gray-900 mb-4">Privacy & Data</h2>
<div class="space-y-4 text-gray-700">
<h3 class="text-xl font-semibold text-gray-900 mt-6 mb-3">Information We Collect</h3>
<p>When you register for an account, we collect:</p>
<ul class="list-disc list-inside ml-4 space-y-2">
<li>Username and password (password is encrypted)</li>
<li>Email address</li>
<li>First and last name</li>
<li>Your sermon notes and related content</li>
</ul>
<h3 class="text-xl font-semibold text-gray-900 mt-6 mb-3">How We Use Your Information</h3>
<p>Your information is used to:</p>
<ul class="list-disc list-inside ml-4 space-y-2">
<li>Provide access to the Service</li>
<li>Store and manage your sermon notes</li>
<li>Send you sermon notes via email when requested</li>
<li>Authenticate your account</li>
</ul>
<h3 class="text-xl font-semibold text-gray-900 mt-6 mb-3">Data Retention</h3>
<p>
Your notes are stored in our database and are associated with your account.
<strong class="text-red-700">Important:</strong> If a sermon is deleted by an administrator,
all associated user notes for that sermon are permanently deleted. We recommend regularly
downloading or emailing your notes to maintain personal backups.
</p>
<h3 class="text-xl font-semibold text-gray-900 mt-6 mb-3">Data Security</h3>
<p>
While we implement security measures to protect your data, no system is completely secure.
Given that this system was created with AI assistance, there may be unknown vulnerabilities.
The Church cannot guarantee the security of your information.
</p>
<h3 class="text-xl font-semibold text-gray-900 mt-6 mb-3">Third-Party Services</h3>
<p>
When you email your notes, we use third-party email service providers to deliver your messages.
Your email address and content are transmitted through these services.
</p>
</div>
</section>
<!-- User Responsibilities -->
<section class="mb-8">
<h2 class="text-2xl font-semibold text-gray-900 mb-4">User Responsibilities</h2>
<div class="space-y-4 text-gray-700">
<p>As a user of this Service, you agree to:</p>
<ul class="list-disc list-inside ml-4 space-y-2">
<li>Maintain the confidentiality of your account credentials</li>
<li>Use the Service only for its intended purpose</li>
<li>Maintain your own backups of important notes and information</li>
<li>Not attempt to compromise the security of the Service</li>
<li>Not use the Service for any unlawful purpose</li>
<li>Accept sole responsibility for any content you create or upload</li>
</ul>
</div>
</section>
<!-- Account Termination -->
<section class="mb-8">
<h2 class="text-2xl font-semibold text-gray-900 mb-4">Account Termination</h2>
<div class="space-y-4 text-gray-700">
<p>
The Church reserves the right to terminate or suspend your account at any time, with or
without notice, for any reason, including violation of these terms or at the Church's sole
discretion.
</p>
</div>
</section>
<!-- Changes to Terms -->
<section class="mb-8">
<h2 class="text-2xl font-semibold text-gray-900 mb-4">Changes to These Terms</h2>
<div class="space-y-4 text-gray-700">
<p>
The Church reserves the right to modify these terms at any time. Continued use of the
Service after changes constitutes acceptance of the modified terms.
</p>
</div>
</section>
<!-- Contact -->
<section class="mb-8">
<h2 class="text-2xl font-semibold text-gray-900 mb-4">Contact Information</h2>
<div class="space-y-4 text-gray-700">
<p>
If you have questions about these terms or the Service, please contact New Life Christian
Church through our regular church communication channels.
</p>
</div>
</section>
<!-- Acceptance -->
<section class="mb-8 p-6 bg-gray-50 border rounded">
<p class="text-gray-700">
<strong>By using this Service, you acknowledge that you have read, understood, and agree to
be bound by these Terms of Use and Privacy Policy, including the AI-generated content disclaimer.</strong>
</p>
<p class="text-sm text-gray-600 mt-4">
Last Updated: {{ new Date().toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' }) }}
</p>
</section>
<!-- Back Button -->
<div class="border-t pt-6">
<NuxtLink
to="/"
class="inline-flex items-center text-blue-600 hover:text-blue-700 font-medium"
>
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
</svg>
Back to Home
</NuxtLink>
</div>
</div>
</main>
<Footer />
</div>
</template>
<script setup lang="ts">
const route = useRoute()
// Check authentication status
const { data: authData } = await useFetch('/api/auth/verify')
const isAuthenticated = computed(() => authData.value?.authenticated || false)
const isAdmin = computed(() => authData.value?.isAdmin || false)
</script>