This commit is contained in:
2025-10-07 18:35:31 +02:00
parent 1bc3056c77
commit 5c98259148
21 changed files with 1237 additions and 99 deletions
+270 -21
View File
@@ -135,18 +135,134 @@
</div>
</div>
<!-- Page Content Tab -->
<div v-if="activeTab === 'content'" class="tab-content">
<div class="section-header">
<h2>Pagina Teksten Beheer</h2>
</div>
<div class="content-sections">
<!-- Home Page Hero -->
<div class="content-section">
<h3>Openingspagina - Hero Sectie</h3>
<div class="content-form">
<div class="form-group">
<label>Hoofdtekst (Header)</label>
<input type="text" :value="getContentValue('home_hero_title')" @input="updateContentValue('home_hero_title', $event.target.value)" @blur="savePageContent('home_hero_title')" />
</div>
<div class="form-group">
<label>Subtekst (Subheader)</label>
<input type="text" :value="getContentValue('home_hero_subtitle')" @input="updateContentValue('home_hero_subtitle', $event.target.value)" @blur="savePageContent('home_hero_subtitle')" />
</div>
</div>
</div>
<!-- Home Page Features -->
<div class="content-section">
<h3>Openingspagina - Panelen</h3>
<div class="content-form">
<div class="feature-group">
<h4>Paneel 1</h4>
<div class="form-group">
<label>Koptekst</label>
<input type="text" :value="getContentValue('home_feature_1_title')" @input="updateContentValue('home_feature_1_title', $event.target.value)" @blur="savePageContent('home_feature_1_title')" />
</div>
<div class="form-group">
<label>Onderschrift</label>
<textarea :value="getContentValue('home_feature_1_text')" @input="updateContentValue('home_feature_1_text', $event.target.value)" @blur="savePageContent('home_feature_1_text')" rows="2"></textarea>
</div>
</div>
<div class="feature-group">
<h4>Paneel 2</h4>
<div class="form-group">
<label>Koptekst</label>
<input type="text" :value="getContentValue('home_feature_2_title')" @input="updateContentValue('home_feature_2_title', $event.target.value)" @blur="savePageContent('home_feature_2_title')" />
</div>
<div class="form-group">
<label>Onderschrift</label>
<textarea :value="getContentValue('home_feature_2_text')" @input="updateContentValue('home_feature_2_text', $event.target.value)" @blur="savePageContent('home_feature_2_text')" rows="2"></textarea>
</div>
</div>
<div class="feature-group">
<h4>Paneel 3</h4>
<div class="form-group">
<label>Koptekst</label>
<input type="text" :value="getContentValue('home_feature_3_title')" @input="updateContentValue('home_feature_3_title', $event.target.value)" @blur="savePageContent('home_feature_3_title')" />
</div>
<div class="form-group">
<label>Onderschrift</label>
<textarea :value="getContentValue('home_feature_3_text')" @input="updateContentValue('home_feature_3_text', $event.target.value)" @blur="savePageContent('home_feature_3_text')" rows="2"></textarea>
</div>
</div>
<div class="feature-group">
<h4>Paneel 4</h4>
<div class="form-group">
<label>Koptekst</label>
<input type="text" :value="getContentValue('home_feature_4_title')" @input="updateContentValue('home_feature_4_title', $event.target.value)" @blur="savePageContent('home_feature_4_title')" />
</div>
<div class="form-group">
<label>Onderschrift</label>
<textarea :value="getContentValue('home_feature_4_text')" @input="updateContentValue('home_feature_4_text', $event.target.value)" @blur="savePageContent('home_feature_4_text')" rows="2"></textarea>
</div>
</div>
</div>
</div>
<!-- Home Page CTA -->
<div class="content-section">
<h3>Openingspagina - Knoppen Container</h3>
<div class="content-form">
<div class="form-group">
<label>Hoofdtekst</label>
<input type="text" :value="getContentValue('home_cta_title')" @input="updateContentValue('home_cta_title', $event.target.value)" @blur="savePageContent('home_cta_title')" />
</div>
<div class="form-group">
<label>Subtekst</label>
<textarea :value="getContentValue('home_cta_subtitle')" @input="updateContentValue('home_cta_subtitle', $event.target.value)" @blur="savePageContent('home_cta_subtitle')" rows="2"></textarea>
</div>
<div class="form-group">
<label>Knop 1 Tekst</label>
<input type="text" :value="getContentValue('home_cta_button_1_text')" @input="updateContentValue('home_cta_button_1_text', $event.target.value)" @blur="savePageContent('home_cta_button_1_text')" />
</div>
<div class="form-group">
<label>Knop 2 Tekst</label>
<input type="text" :value="getContentValue('home_cta_button_2_text')" @input="updateContentValue('home_cta_button_2_text', $event.target.value)" @blur="savePageContent('home_cta_button_2_text')" />
</div>
</div>
</div>
<!-- Booking Page -->
<div class="content-section">
<h3>Boekingspagina - Header</h3>
<div class="content-form">
<div class="form-group">
<label>Hoofdtekst (Header)</label>
<input type="text" :value="getContentValue('booking_header_title')" @input="updateContentValue('booking_header_title', $event.target.value)" @blur="savePageContent('booking_header_title')" />
</div>
<div class="form-group">
<label>Onderschrift</label>
<textarea :value="getContentValue('booking_header_subtitle')" @input="updateContentValue('booking_header_subtitle', $event.target.value)" @blur="savePageContent('booking_header_subtitle')" rows="2"></textarea>
</div>
</div>
</div>
</div>
</div>
<!-- Settings Tab -->
<div v-if="activeTab === 'settings'" class="tab-content">
<div class="section-header">
<h2>Applicatie Instellingen</h2>
</div>
<div class="settings-form">
<div class="setting-group">
<label for="admin_email">Beheer Notificatie E-mail</label>
<input
type="email"
id="admin_email"
<input
type="email"
id="admin_email"
v-model="settings.admin_notification_email"
placeholder="admin@voorbeeld.com"
/>
@@ -154,12 +270,12 @@
💾
</button>
</div>
<div class="setting-group">
<label for="business_name">Bedrijfsnaam</label>
<input
type="text"
id="business_name"
<input
type="text"
id="business_name"
v-model="settings.business_name"
placeholder="Fiets Service Centrum"
/>
@@ -381,6 +497,7 @@ export default {
const blockedDates = ref([])
const settings = ref({})
const pricelist = ref([])
const pageContent = ref([])
// Modal states
const showRequestModal = ref(false)
@@ -410,6 +527,7 @@ export default {
{ id: 'requests', label: 'Service Aanvragen' },
{ id: 'blocked', label: 'Geblokkeerde Data' },
{ id: 'pricelist', label: 'Prijslijst' },
{ id: 'content', label: 'Pagina Teksten' },
{ id: 'settings', label: 'Instellingen' }
]
@@ -516,6 +634,19 @@ export default {
console.error('Failed to fetch pricelist:', error)
}
}
const fetchPageContent = async () => {
try {
const response = await fetch('/api/page-content', {
headers: authStore.getAuthHeaders()
})
if (response.ok) {
pageContent.value = await response.json()
}
} catch (error) {
console.error('Failed to fetch page content:', error)
}
}
const refreshRequests = async () => {
loading.value = true
@@ -814,9 +945,9 @@ export default {
const deletePricelistItem = async (id) => {
if (!confirm('Weet je zeker dat je dit prijslijst item wilt verwijderen?')) return
try {
const response = await fetch(`/api/pricelist/${id}`, {
const response = await fetch(`/api/pricelist/${id}`, {
method: 'DELETE',
headers: authStore.getAuthHeaders()
})
@@ -827,6 +958,41 @@ export default {
console.error('Failed to delete pricelist item:', error)
}
}
// Page content functions
const getContentValue = (key) => {
const content = pageContent.value.find(c => c.key === key)
return content ? content.value : ''
}
const updateContentValue = (key, value) => {
const content = pageContent.value.find(c => c.key === key)
if (content) {
content.value = value
}
}
const savePageContent = async (key) => {
const content = pageContent.value.find(c => c.key === key)
if (!content) return
try {
const response = await fetch(`/api/page-content/key/${key}`, {
method: 'PUT',
headers: authStore.getAuthHeaders(),
body: JSON.stringify({
value: content.value,
description: content.description
})
})
if (response.ok) {
console.log(`Content ${key} updated successfully`)
}
} catch (error) {
console.error('Failed to update page content:', error)
}
}
// Utility functions
const formatDateTime = (date, time) => {
@@ -843,10 +1009,11 @@ export default {
onMounted(() => {
// Check authentication
authStore.checkAuth()
fetchRequests()
fetchBlockedDates()
fetchPricelist()
fetchPageContent()
fetchSettings()
})
@@ -858,6 +1025,7 @@ export default {
blockedDates,
settings,
pricelist,
pageContent,
user: computed(() => authStore.user),
showRequestModal,
showAddBlockedDate,
@@ -905,6 +1073,9 @@ export default {
updateRequestStatus,
updateRequestDate,
updateRequestTime,
getContentValue,
updateContentValue,
savePageContent,
formatDateTime,
formatDate
}
@@ -924,13 +1095,13 @@ export default {
}
.admin-header h1 {
color: #2c3e50;
color: var(--primary-color);
font-size: 2.5rem;
margin-bottom: 1rem;
}
.admin-header p {
color: #666;
color: var(--text-gray);
font-size: 1.2rem;
margin-bottom: 1rem;
}
@@ -984,8 +1155,8 @@ export default {
}
.tab-button.active {
border-bottom-color: #3498db;
color: #3498db;
border-bottom-color: var(--primary-color);
color: var(--primary-color);
font-weight: bold;
}
@@ -1008,12 +1179,12 @@ export default {
}
.section-header h2 {
color: #2c3e50;
color: var(--primary-color);
margin: 0;
}
.refresh-btn, .add-btn {
background: #3498db;
background: var(--primary-color);
color: white;
border: none;
width: 40px;
@@ -1029,9 +1200,9 @@ export default {
}
.refresh-btn:hover:not(:disabled), .add-btn:hover {
background: #2980b9;
background: var(--primary-dark);
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
box-shadow: 0 4px 8px rgba(44, 95, 93, 0.3);
}
.refresh-btn:disabled {
@@ -1612,12 +1783,13 @@ export default {
}
.btn-primary {
background: #3498db;
background: var(--primary-color);
color: white;
}
.btn-primary:hover:not(:disabled) {
background: #2980b9;
background: var(--primary-dark);
box-shadow: 0 4px 10px rgba(44, 95, 93, 0.3);
}
.btn-secondary {
@@ -1800,4 +1972,81 @@ export default {
gap: 0.5rem;
}
}
/* Page Content Styles */
.content-sections {
display: flex;
flex-direction: column;
gap: 2rem;
}
.content-section {
background: #f8f9fa;
padding: 1.5rem;
border-radius: 10px;
border: 1px solid #e1e8ed;
}
.content-section h3 {
color: #2c3e50;
margin-bottom: 1rem;
font-size: 1.3rem;
}
.content-section h4 {
color: #2c3e50;
margin-bottom: 0.75rem;
font-size: 1.1rem;
}
.content-form {
display: flex;
flex-direction: column;
gap: 1rem;
}
.feature-group {
background: white;
padding: 1rem;
border-radius: 8px;
border: 1px solid #e1e8ed;
}
.feature-group:not(:last-child) {
margin-bottom: 1rem;
}
.content-form .form-group {
margin-bottom: 0.5rem;
}
.content-form .form-group label {
font-weight: 600;
color: #2c3e50;
margin-bottom: 0.5rem;
display: block;
}
.content-form .form-group input,
.content-form .form-group textarea {
width: 100%;
padding: 0.75rem;
border: 2px solid #e1e8ed;
border-radius: 8px;
font-size: 1rem;
transition: border-color 0.3s ease;
}
.content-form .form-group input:focus,
.content-form .form-group textarea:focus {
outline: none;
border-color: var(--primary-color);
background: #f8f9fa;
box-shadow: 0 0 0 3px rgba(44, 95, 93, 0.1);
}
.content-form .form-group textarea {
resize: vertical;
font-family: inherit;
}
</style>