feat: Add comprehensive documentation suite and reorganize project structure
- Created complete documentation in docs/ directory - Added PROJECT_OVERVIEW.md with feature highlights and getting started guide - Added ARCHITECTURE.md with system design and technical details - Added SECURITY.md with comprehensive security implementation guide - Added DEVELOPMENT.md with development workflows and best practices - Added DEPLOYMENT.md with production deployment instructions - Added API.md with complete REST API documentation - Added CONTRIBUTING.md with contribution guidelines - Added CHANGELOG.md with version history and migration notes - Reorganized all documentation files into docs/ directory for better organization - Updated README.md with proper documentation links and quick navigation - Enhanced project structure with professional documentation standards
This commit is contained in:
151
f_modules/m_frontend/m_donations/views/analytics_dashboard.php
Normal file
151
f_modules/m_frontend/m_donations/views/analytics_dashboard.php
Normal file
@@ -0,0 +1,151 @@
|
||||
<?php
|
||||
$title = "Donation Analytics";
|
||||
include_once '../../../f_core/header.php';
|
||||
|
||||
use Donations\AnalyticsHandler;
|
||||
|
||||
$analytics_handler = new AnalyticsHandler();
|
||||
$summary = $analytics_handler->getSummary($streamer_id);
|
||||
$trends = $analytics_handler->getTrends($streamer_id);
|
||||
$top_donors = $analytics_handler->getTopDonors($streamer_id);
|
||||
?>
|
||||
|
||||
<div class="container mt-4">
|
||||
<h2>Donation Analytics</h2>
|
||||
|
||||
<!-- Summary Cards -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-3">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Total Donations</h5>
|
||||
<h2 class="card-text"><?php echo number_format($summary['total_donations']); ?></h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Total Amount</h5>
|
||||
<h2 class="card-text">$<?php echo number_format($summary['total_amount'], 2); ?></h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Average Donation</h5>
|
||||
<h2 class="card-text">$<?php echo number_format($summary['average_donation'], 2); ?></h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Unique Donors</h5>
|
||||
<h2 class="card-text"><?php echo number_format($summary['unique_donors']); ?></h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Trends Chart -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Donation Trends</h5>
|
||||
<canvas id="trendsChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Top Donors -->
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Top Donors</h5>
|
||||
<div class="table-responsive">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Donor</th>
|
||||
<th>Donations</th>
|
||||
<th>Total Amount</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($top_donors as $donor): ?>
|
||||
<tr>
|
||||
<td><?php echo htmlspecialchars($donor['display_name']); ?></td>
|
||||
<td><?php echo number_format($donor['donation_count']); ?></td>
|
||||
<td>$<?php echo number_format($donor['total_amount'], 2); ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Prepare data for the trends chart
|
||||
const trendsData = <?php echo json_encode($trends); ?>;
|
||||
const dates = trendsData.map(item => item.date);
|
||||
const amounts = trendsData.map(item => item.total);
|
||||
const counts = trendsData.map(item => item.count);
|
||||
|
||||
// Create trends chart
|
||||
const ctx = document.getElementById('trendsChart').getContext('2d');
|
||||
new Chart(ctx, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: dates,
|
||||
datasets: [{
|
||||
label: 'Daily Amount',
|
||||
data: amounts,
|
||||
borderColor: 'rgb(75, 192, 192)',
|
||||
tension: 0.1,
|
||||
yAxisID: 'y'
|
||||
}, {
|
||||
label: 'Number of Donations',
|
||||
data: counts,
|
||||
borderColor: 'rgb(255, 99, 132)',
|
||||
tension: 0.1,
|
||||
yAxisID: 'y1'
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
interaction: {
|
||||
mode: 'index',
|
||||
intersect: false,
|
||||
},
|
||||
scales: {
|
||||
y: {
|
||||
type: 'linear',
|
||||
display: true,
|
||||
position: 'left',
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Amount ($)'
|
||||
}
|
||||
},
|
||||
y1: {
|
||||
type: 'linear',
|
||||
display: true,
|
||||
position: 'right',
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Number of Donations'
|
||||
},
|
||||
grid: {
|
||||
drawOnChartArea: false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php include_once '../../../f_core/footer.php'; ?>
|
||||
189
f_modules/m_frontend/m_donations/views/donation_form.php
Normal file
189
f_modules/m_frontend/m_donations/views/donation_form.php
Normal file
@@ -0,0 +1,189 @@
|
||||
<?php
|
||||
$title = "Donate to {$streamer['display_name']}";
|
||||
include_once '../../../f_core/header.php';
|
||||
?>
|
||||
|
||||
<div class="container mt-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">Donate to <?php echo htmlspecialchars($streamer['display_name']); ?></h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form id="donation-form">
|
||||
<input type="hidden" name="streamer_id" value="<?php echo $streamer['user_id']; ?>">
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Donation Amount</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text">$</span>
|
||||
<input type="number"
|
||||
class="form-control"
|
||||
name="amount"
|
||||
min="<?php echo $config['min_donation']; ?>"
|
||||
max="<?php echo $config['max_donation']; ?>"
|
||||
step="0.01"
|
||||
required>
|
||||
</div>
|
||||
<div class="form-text">
|
||||
Minimum: $<?php echo number_format($config['min_donation'], 2); ?><br>
|
||||
Maximum: $<?php echo number_format($config['max_donation'], 2); ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Quick Select Amount</label>
|
||||
<div class="btn-group w-100">
|
||||
<?php foreach ($config['default_amounts'] as $amount): ?>
|
||||
<button type="button"
|
||||
class="btn btn-outline-primary quick-amount"
|
||||
data-amount="<?php echo $amount; ?>">
|
||||
$<?php echo number_format($amount, 2); ?>
|
||||
</button>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Message (Optional)</label>
|
||||
<textarea class="form-control"
|
||||
name="message"
|
||||
rows="3"
|
||||
maxlength="200"></textarea>
|
||||
<div class="form-text">Maximum 200 characters</div>
|
||||
</div>
|
||||
|
||||
<div class="d-grid">
|
||||
<button type="submit" class="btn btn-primary">Donate Now</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Square Payment Form -->
|
||||
<div id="payment-form-container" style="display: none;">
|
||||
<div id="payment-form"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const form = document.getElementById('donation-form');
|
||||
const amountInput = form.querySelector('input[name="amount"]');
|
||||
const quickAmountButtons = document.querySelectorAll('.quick-amount');
|
||||
const paymentFormContainer = document.getElementById('payment-form-container');
|
||||
const paymentForm = document.getElementById('payment-form');
|
||||
|
||||
// Handle quick amount selection
|
||||
quickAmountButtons.forEach(button => {
|
||||
button.addEventListener('click', function() {
|
||||
amountInput.value = this.dataset.amount;
|
||||
amountInput.dispatchEvent(new Event('change'));
|
||||
});
|
||||
});
|
||||
|
||||
// Handle form submission
|
||||
form.addEventListener('submit', async function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const formData = new FormData(form);
|
||||
try {
|
||||
const response = await fetch('process_donation.php', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
// Initialize Square payment form
|
||||
const paymentForm = new SqPaymentForm({
|
||||
applicationId: '<?php echo $config['application_id']; ?>',
|
||||
locationId: '<?php echo $config['location_id']; ?>',
|
||||
inputClass: 'sq-input',
|
||||
inputStyles: [{
|
||||
fontSize: '16px',
|
||||
fontFamily: 'Helvetica Neue',
|
||||
padding: '16px',
|
||||
color: '#373F4A',
|
||||
backgroundColor: 'transparent',
|
||||
lineHeight: '20px',
|
||||
placeholderColor: '#999',
|
||||
_webkitFontSmoothing: 'antialiased',
|
||||
_mozOsxFontSmoothing: 'grayscale'
|
||||
}],
|
||||
cardNumber: {
|
||||
elementId: 'sq-card-number',
|
||||
placeholder: '•••• •••• •••• ••••'
|
||||
},
|
||||
cvv: {
|
||||
elementId: 'sq-cvv',
|
||||
placeholder: 'CVV'
|
||||
},
|
||||
expirationDate: {
|
||||
elementId: 'sq-expiration-date',
|
||||
placeholder: 'MM/YY'
|
||||
},
|
||||
postalCode: {
|
||||
elementId: 'sq-postal-code',
|
||||
placeholder: 'Postal'
|
||||
},
|
||||
callbacks: {
|
||||
cardNonceResponseReceived: function(err, nonce, cardData) {
|
||||
if (err) {
|
||||
console.error('Error generating card nonce:', err);
|
||||
alert('Error processing payment. Please try again.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Send payment to server
|
||||
fetch('process_payment.php', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
nonce: nonce,
|
||||
amount: formData.get('amount'),
|
||||
streamer_id: formData.get('streamer_id'),
|
||||
message: formData.get('message')
|
||||
})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(result => {
|
||||
if (result.success) {
|
||||
alert('Thank you for your donation!');
|
||||
window.location.reload();
|
||||
} else {
|
||||
alert(result.error || 'Error processing payment. Please try again.');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
alert('Error processing payment. Please try again.');
|
||||
});
|
||||
},
|
||||
unsupportedBrowserDetected: function() {
|
||||
alert('Your browser is not supported. Please use a modern browser.');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Show payment form
|
||||
paymentFormContainer.style.display = 'block';
|
||||
paymentForm.build();
|
||||
} else {
|
||||
alert(result.error || 'Error processing donation. Please try again.');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
alert('Error processing donation. Please try again.');
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php include_once '../../../f_core/footer.php'; ?>
|
||||
194
f_modules/m_frontend/m_donations/views/goals.php
Normal file
194
f_modules/m_frontend/m_donations/views/goals.php
Normal file
@@ -0,0 +1,194 @@
|
||||
<?php
|
||||
$title = "Donation Goals";
|
||||
include_once '../../../f_core/header.php';
|
||||
|
||||
use Donations\GoalHandler;
|
||||
|
||||
$goal_handler = new GoalHandler();
|
||||
$active_goals = $goal_handler->getActiveGoals($streamer_id);
|
||||
$all_goals = $goal_handler->getStreamerGoals($streamer_id);
|
||||
?>
|
||||
|
||||
<div class="container mt-4">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2>Donation Goals</h2>
|
||||
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#createGoalModal">
|
||||
Create New Goal
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Active Goals -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<h3>Active Goals</h3>
|
||||
</div>
|
||||
<?php foreach ($active_goals as $goal): ?>
|
||||
<?php
|
||||
$progress = ($goal['current_amount'] / $goal['target_amount']) * 100;
|
||||
$milestones = $goal_handler->getGoalMilestones($goal['goal_id']);
|
||||
?>
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><?php echo htmlspecialchars($goal['title']); ?></h5>
|
||||
<p class="card-text"><?php echo htmlspecialchars($goal['description']); ?></p>
|
||||
|
||||
<!-- Progress Bar -->
|
||||
<div class="progress mb-3">
|
||||
<div class="progress-bar" role="progressbar"
|
||||
style="width: <?php echo $progress; ?>%"
|
||||
aria-valuenow="<?php echo $progress; ?>"
|
||||
aria-valuemin="0"
|
||||
aria-valuemax="100">
|
||||
<?php echo number_format($progress, 1); ?>%
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Amount Info -->
|
||||
<div class="d-flex justify-content-between mb-3">
|
||||
<span>$<?php echo number_format($goal['current_amount'], 2); ?> raised</span>
|
||||
<span>Goal: $<?php echo number_format($goal['target_amount'], 2); ?></span>
|
||||
</div>
|
||||
|
||||
<!-- Milestones -->
|
||||
<?php if (!empty($milestones)): ?>
|
||||
<h6>Milestones</h6>
|
||||
<div class="list-group">
|
||||
<?php foreach ($milestones as $milestone): ?>
|
||||
<?php
|
||||
$milestone_progress = ($goal['current_amount'] / $milestone['target_amount']) * 100;
|
||||
$milestone_progress = min($milestone_progress, 100);
|
||||
?>
|
||||
<div class="list-group-item">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<h6 class="mb-1"><?php echo htmlspecialchars($milestone['title']); ?></h6>
|
||||
<small><?php echo htmlspecialchars($milestone['description']); ?></small>
|
||||
</div>
|
||||
<span class="badge <?php echo $milestone['is_achieved'] ? 'bg-success' : 'bg-secondary'; ?>">
|
||||
<?php echo $milestone['is_achieved'] ? 'Achieved' : 'In Progress'; ?>
|
||||
</span>
|
||||
</div>
|
||||
<div class="progress mt-2">
|
||||
<div class="progress-bar" role="progressbar"
|
||||
style="width: <?php echo $milestone_progress; ?>%"
|
||||
aria-valuenow="<?php echo $milestone_progress; ?>"
|
||||
aria-valuemin="0"
|
||||
aria-valuemax="100">
|
||||
$<?php echo number_format($goal['current_amount'], 2); ?> /
|
||||
$<?php echo number_format($milestone['target_amount'], 2); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<!-- Completed Goals -->
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<h3>Completed Goals</h3>
|
||||
</div>
|
||||
<?php foreach ($all_goals as $goal): ?>
|
||||
<?php if ($goal['status'] === 'completed'): ?>
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><?php echo htmlspecialchars($goal['title']); ?></h5>
|
||||
<p class="card-text"><?php echo htmlspecialchars($goal['description']); ?></p>
|
||||
<div class="progress mb-3">
|
||||
<div class="progress-bar bg-success" role="progressbar"
|
||||
style="width: 100%"
|
||||
aria-valuenow="100"
|
||||
aria-valuemin="0"
|
||||
aria-valuemax="100">
|
||||
100%
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between">
|
||||
<span>Completed on <?php echo date('M d, Y', strtotime($goal['updated_at'])); ?></span>
|
||||
<span>Total: $<?php echo number_format($goal['current_amount'], 2); ?></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Create Goal Modal -->
|
||||
<div class="modal fade" id="createGoalModal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Create New Goal</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="createGoalForm">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Title</label>
|
||||
<input type="text" class="form-control" name="title" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Description</label>
|
||||
<textarea class="form-control" name="description" rows="3"></textarea>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Target Amount</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text">$</span>
|
||||
<input type="number" class="form-control" name="target_amount"
|
||||
min="1" step="0.01" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">End Date (Optional)</label>
|
||||
<input type="date" class="form-control" name="end_date">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-primary" id="createGoalBtn">Create Goal</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const createGoalForm = document.getElementById('createGoalForm');
|
||||
const createGoalBtn = document.getElementById('createGoalBtn');
|
||||
|
||||
createGoalBtn.addEventListener('click', async function() {
|
||||
const formData = new FormData(createGoalForm);
|
||||
|
||||
try {
|
||||
const response = await fetch('create_goal.php', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
window.location.reload();
|
||||
} else {
|
||||
alert(result.error || 'Error creating goal. Please try again.');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
alert('Error creating goal. Please try again.');
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php include_once '../../../f_core/footer.php'; ?>
|
||||
125
f_modules/m_frontend/m_donations/views/notifications.php
Normal file
125
f_modules/m_frontend/m_donations/views/notifications.php
Normal file
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
$title = "Donation Notifications";
|
||||
include_once '../../../f_core/header.php';
|
||||
|
||||
use Donations\NotificationHandler;
|
||||
|
||||
$notification_handler = new NotificationHandler();
|
||||
$notifications = $notification_handler->getAllNotifications($streamer_id);
|
||||
$unread_count = $notification_handler->getUnreadCount($streamer_id);
|
||||
?>
|
||||
|
||||
<div class="container mt-4">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h2>Donation Notifications</h2>
|
||||
<?php if ($unread_count > 0): ?>
|
||||
<button type="button" class="btn btn-primary" id="markAllReadBtn">
|
||||
Mark All as Read
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<!-- Notifications List -->
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<?php if (empty($notifications)): ?>
|
||||
<div class="text-center py-5">
|
||||
<h5>No notifications yet</h5>
|
||||
<p class="text-muted">You'll see notifications here when you receive donations, achieve goals, or reach milestones.</p>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="list-group">
|
||||
<?php foreach ($notifications as $notification): ?>
|
||||
<div class="list-group-item <?php echo $notification['is_read'] ? '' : 'list-group-item-primary'; ?>"
|
||||
data-notification-id="<?php echo $notification['notification_id']; ?>">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<h6 class="mb-1"><?php echo htmlspecialchars($notification['title']); ?></h6>
|
||||
<p class="mb-1"><?php echo htmlspecialchars($notification['message']); ?></p>
|
||||
<small class="text-muted">
|
||||
<?php echo date('M d, Y H:i', strtotime($notification['created_at'])); ?>
|
||||
</small>
|
||||
</div>
|
||||
<?php if (!$notification['is_read']): ?>
|
||||
<button type="button" class="btn btn-sm btn-outline-primary mark-read-btn">
|
||||
Mark as Read
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Mark individual notification as read
|
||||
document.querySelectorAll('.mark-read-btn').forEach(button => {
|
||||
button.addEventListener('click', async function() {
|
||||
const notificationId = this.closest('.list-group-item').dataset.notificationId;
|
||||
|
||||
try {
|
||||
const response = await fetch('mark_read.php', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
notification_ids: [notificationId]
|
||||
})
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
this.closest('.list-group-item').classList.remove('list-group-item-primary');
|
||||
this.remove();
|
||||
|
||||
// Update unread count
|
||||
const unreadCount = document.querySelectorAll('.list-group-item-primary').length;
|
||||
if (unreadCount === 0) {
|
||||
document.getElementById('markAllReadBtn')?.remove();
|
||||
}
|
||||
} else {
|
||||
alert(result.error || 'Error marking notification as read. Please try again.');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
alert('Error marking notification as read. Please try again.');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Mark all notifications as read
|
||||
const markAllReadBtn = document.getElementById('markAllReadBtn');
|
||||
if (markAllReadBtn) {
|
||||
markAllReadBtn.addEventListener('click', async function() {
|
||||
try {
|
||||
const response = await fetch('mark_all_read.php', {
|
||||
method: 'POST'
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
document.querySelectorAll('.list-group-item-primary').forEach(item => {
|
||||
item.classList.remove('list-group-item-primary');
|
||||
});
|
||||
document.querySelectorAll('.mark-read-btn').forEach(btn => btn.remove());
|
||||
this.remove();
|
||||
} else {
|
||||
alert(result.error || 'Error marking notifications as read. Please try again.');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
alert('Error marking notifications as read. Please try again.');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php include_once '../../../f_core/footer.php'; ?>
|
||||
Reference in New Issue
Block a user