1346 lines
66 KiB
PHP
1346 lines
66 KiB
PHP
<?php
|
|
|
|
function frontendEnrollmentControlGeneric($attributes)
|
|
{
|
|
|
|
nocache_headers();
|
|
|
|
// Append nocache query parameter to bust cache
|
|
if (!isset($_GET['nocache'])) {
|
|
$new_url = add_query_arg('nocache', time(), get_permalink());
|
|
wp_redirect($new_url);
|
|
exit();
|
|
}
|
|
|
|
// Prevent back/forward navigation cache
|
|
$output = '<script>
|
|
if (performance.navigation.type === performance.navigation.TYPE_BACK_FORWARD) {
|
|
window.location.reload();
|
|
}
|
|
</script>';
|
|
|
|
if (!is_user_logged_in()) {
|
|
// Add the style to the head section of the page
|
|
return '<p>You need to be logged in to view this page.</p>';
|
|
}
|
|
|
|
$user = wp_get_current_user();
|
|
$roles = $user->roles;
|
|
$args = shortcode_atts(array('activity_id' => 'none', 'allowed_role' => 'none'), $attributes);
|
|
$allowed_role = $args['allowed_role'];
|
|
$has_access = array($allowed_role, 'administrator');
|
|
$user_allowed_roles = array_intersect($roles, $has_access);
|
|
|
|
if (empty($user_allowed_roles)) {
|
|
// Add the style for the restricted message
|
|
return '
|
|
<p>Sorry, you don\'t have permission to view this content.</p>
|
|
';
|
|
} else {
|
|
global $wpdb;
|
|
//$current_user = wp_get_current_user();
|
|
$user_id = $user->ID;
|
|
$activity_id = intval($args['activity_id']);
|
|
|
|
// Define the additional meta keys
|
|
$additional_meta_keys = [
|
|
'forca',
|
|
'full_name',
|
|
'posto',
|
|
'militar',
|
|
'instituição',
|
|
'nacionalidade',
|
|
'efetivo_dcta',
|
|
'cidade',
|
|
'estado',
|
|
'areaatividadeprincipal',
|
|
'setordeatuacao',
|
|
'cargofuncao',
|
|
'ehativa',
|
|
'circulo_hierarquico',
|
|
'pais',
|
|
'formacao_academica',
|
|
'regiao_do_brasil',
|
|
'genero'
|
|
];
|
|
|
|
// Handle saving additional features selection
|
|
if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['additional_features_applied'])) {
|
|
$selected_meta_keys = isset($_POST['additional_features']) ? array_intersect($additional_meta_keys, $_POST['additional_features']) : [];
|
|
update_user_meta($user_id, 'selected_additional_features_frontend', $selected_meta_keys);
|
|
// Redirect to avoid resubmission
|
|
wp_safe_redirect(add_query_arg([], wp_get_referer()));
|
|
exit;
|
|
} else {
|
|
$selected_meta_keys = get_user_meta($user_id, 'selected_additional_features_frontend', true);
|
|
if (!$selected_meta_keys) {
|
|
$selected_meta_keys = ['full_name', 'militar', 'posto', 'instituição', 'nacionalidade', 'efetivo_dcta'];
|
|
}
|
|
}
|
|
|
|
// Handle form submission for updating enrollment status
|
|
if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['apply_status']) && isset($_POST['selected_enrollments'])) {
|
|
$new_status = sanitize_text_field($_POST['new_status']);
|
|
$selected_enrollments = array_map('intval', $_POST['selected_enrollments']);
|
|
|
|
if (!empty($selected_enrollments)) {
|
|
foreach ($selected_enrollments as $enrollment_id) {
|
|
$wpdb->update(
|
|
"{$wpdb->prefix}sige_enrollments",
|
|
['status' => $new_status],
|
|
['id' => $enrollment_id]
|
|
);
|
|
$enrollment_data = $wpdb->get_row(
|
|
$wpdb->prepare("
|
|
SELECT user_id, activity_id
|
|
FROM {$wpdb->prefix}sige_enrollments
|
|
WHERE id = %d", $enrollment_id)
|
|
);
|
|
send_email_notification($enrollment_data->user_id, $new_status, $enrollment_data->activity_id);
|
|
usleep(100_000);
|
|
}
|
|
// Redirect to the same page to clear POST data
|
|
wp_safe_redirect(add_query_arg([], wp_get_referer()));
|
|
exit;
|
|
} else {
|
|
echo '<div class="notice notice-error"><p>Please select at least one enrollment.</p></div>';
|
|
}
|
|
}
|
|
|
|
// Fetch summary counts
|
|
$summary_counts = $wpdb->get_results("
|
|
SELECT
|
|
a.name as activity_name,
|
|
a.slots,
|
|
COUNT(e.id) as total_requests,
|
|
SUM(CASE WHEN e.status = 'Enrollment Canceled by User' THEN 1 ELSE 0 END) as canceled_by_user,
|
|
SUM(CASE WHEN e.status = 'Waiting List' THEN 1 ELSE 0 END) as waiting_list,
|
|
SUM(CASE WHEN e.status = 'Approved' THEN 1 ELSE 0 END) as approved,
|
|
SUM(CASE WHEN e.status = 'Not Approved' THEN 1 ELSE 0 END) as not_approved,
|
|
SUM(CASE WHEN e.status = 'Under Analysis' THEN 1 ELSE 0 END) as under_analysis,
|
|
a.slots - SUM(CASE WHEN e.status = 'Approved' THEN 1 ELSE 0 END) as available_slots
|
|
FROM {$wpdb->prefix}sige_enrollments e
|
|
LEFT JOIN {$wpdb->prefix}sige_activities a ON e.activity_id = a.id
|
|
WHERE a.id = $activity_id
|
|
GROUP BY a.name, a.slots
|
|
");
|
|
|
|
ob_start();
|
|
$unique_id = uniqid('sige_');
|
|
//sige_enqueue_export_csv_script($unique_id);
|
|
// Display summary counts table
|
|
echo '<h3>Enrollment Summary</h3>';
|
|
echo '<table id="summary-table-' . $unique_id . '" class="display" style="width: 100%; margin: 0; padding: 0;">
|
|
<thead>
|
|
<tr>
|
|
<th>Activity Name</th>
|
|
<th>Enrollment Canceled by User</th>
|
|
<th>Waiting List</th>
|
|
<th>Approved</th>
|
|
<th>Not Approved</th>
|
|
<th>Under Analysis</th>
|
|
<th>Total Enrollment Requests</th>
|
|
<th>Enrollment Availables</th>
|
|
<th>Slots</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>';
|
|
|
|
if ($summary_counts) {
|
|
foreach ($summary_counts as $summary) {
|
|
echo '<tr>
|
|
<td>' . esc_html($summary->activity_name) . '</td>
|
|
<td>' . esc_html($summary->canceled_by_user) . '</td>
|
|
<td>' . esc_html($summary->waiting_list) . '</td>
|
|
<td>' . esc_html($summary->approved) . '</td>
|
|
<td>' . esc_html($summary->not_approved) . '</td>
|
|
<td>' . esc_html($summary->under_analysis) . '</td>
|
|
<td>' . esc_html($summary->total_requests) . '</td>
|
|
<td>' . esc_html($summary->available_slots) . '</td>
|
|
<td>' . esc_html($summary->slots) . '</td>
|
|
</tr>';
|
|
}
|
|
} else {
|
|
echo '<tr><td colspan="9" style="text-align: center;">No data found</td></tr>';
|
|
}
|
|
|
|
echo '</tbody></table>';
|
|
|
|
// Fetch enrollments with additional meta data if selected
|
|
$meta_selects = '';
|
|
$meta_joins = '';
|
|
foreach ($selected_meta_keys as $meta_key) {
|
|
$meta_selects .= ", um_$meta_key.meta_value as $meta_key";
|
|
$meta_joins .= " LEFT JOIN {$wpdb->prefix}usermeta um_$meta_key ON um_$meta_key.user_id = u.ID AND um_$meta_key.meta_key = '$meta_key'";
|
|
}
|
|
|
|
$query = $wpdb->prepare("
|
|
SELECT e.*, a.name as activity_name, u.user_email $meta_selects
|
|
FROM {$wpdb->prefix}sige_enrollments e
|
|
LEFT JOIN {$wpdb->prefix}sige_activities a ON e.activity_id = a.id
|
|
LEFT JOIN {$wpdb->prefix}users u ON e.user_id = u.ID
|
|
$meta_joins
|
|
WHERE a.id = %d
|
|
ORDER BY e.enrollment_date ASC
|
|
", $activity_id);
|
|
|
|
$enrollments = $wpdb->get_results($query);
|
|
|
|
// Display additional features form
|
|
echo '<div class="additional-features-container" style="display: flex; align-items: center; margin-bottom: 20px;">';
|
|
echo '<h3 style="margin: 0;">Additional Features</h3>';
|
|
echo '<button id="toggle-features" class="button button-secondary" style="margin-left: 10px;">Expand Features</button>';
|
|
echo '</div>';
|
|
echo '<div id="features-container" style="display: none; width: 100%; margin-top: 20px;">';
|
|
echo '<form method="post" action="" style="width: 100%;">';
|
|
foreach ($additional_meta_keys as $meta_key) {
|
|
$checked = in_array($meta_key, $selected_meta_keys) ? 'checked' : '';
|
|
echo '<label style="display: block; margin-bottom: 10px;"><input type="checkbox" name="additional_features[]" value="' . $meta_key . '" ' . $checked . '> ' . ucfirst(str_replace('_', ' ', $meta_key)) . '</label>';
|
|
}
|
|
echo '<input type="hidden" name="additional_features_applied" value="1">';
|
|
echo '<input type="submit" value="Apply" class="button button-primary" style="margin-top: 20px;">';
|
|
echo '</form>';
|
|
echo '</div>';
|
|
|
|
|
|
// Display the enrollments table
|
|
echo '<h3>Existing Enrollments</h3>';
|
|
echo '<div style="width: 100%; margin: 0; padding: 0;">';
|
|
echo '<form method="post" action="" style="width: 100%; margin: 0; padding: 0;">';
|
|
echo '<input type="hidden" id="selected-meta-keys" value="' . esc_attr(json_encode(array_values($selected_meta_keys))) . '">';
|
|
echo '<button id="export-csv" type="button" class="button button-secondary" style="margin-bottom: 20px;">Export to CSV</button>';
|
|
echo '<table id="enrollments-table' . $unique_id . '" class="display" style="width: 100%; margin: 0; padding: 0;">
|
|
<thead>
|
|
<tr>
|
|
<th style="text-align: center;"><input type="checkbox" id="select_all"> Select All</th>
|
|
<th>Activity Name</th>
|
|
<th>User ID</th>
|
|
<th>User Email</th>
|
|
<th>Enrollment Date</th>
|
|
<th>Status</th>';
|
|
foreach ($selected_meta_keys as $meta_key) {
|
|
echo '<th>' . ucfirst(str_replace('_', ' ', $meta_key)) . '</th>';
|
|
}
|
|
echo '</tr></thead><tbody>';
|
|
|
|
if ($enrollments) {
|
|
foreach ($enrollments as $enrollment) {
|
|
$row_style = '';
|
|
$checkbox_disabled = '';
|
|
if ($enrollment->status == 'Enrollment Canceled by User') {
|
|
$row_style = 'style="background-color: #f38d8d;"';
|
|
$checkbox_disabled = 'disabled';
|
|
} elseif ($enrollment->status == 'Waiting List') {
|
|
$row_style = 'style="background-color: #e3db69;"';
|
|
} elseif ($enrollment->status == 'Approved') {
|
|
$row_style = 'style="background-color: #33ff7a;"';
|
|
} elseif ($enrollment->status == 'Not Approved') {
|
|
$row_style = 'style="background-color: #bc97cd;"';
|
|
} elseif ($enrollment->status == 'Under Analysis') {
|
|
$row_style = 'style="background-color: #5ecac7;"';
|
|
}
|
|
|
|
$formatted_date = date('d-m-Y', strtotime($enrollment->enrollment_date));
|
|
|
|
echo "<tr $row_style>
|
|
<td style='text-align: center;'><input type='checkbox' class='select-enrollment' name='selected_enrollments[]' value='{$enrollment->id}' $checkbox_disabled></td>
|
|
<td style='font-weight: bold;'>{$enrollment->activity_name}</td>
|
|
<td style='font-weight: bold;'>{$enrollment->user_id}</td>
|
|
<td style='font-weight: bold;'>{$enrollment->user_email}</td>
|
|
<td style='font-weight: bold;'>$formatted_date</td>
|
|
<td style='font-weight: bold;'>{$enrollment->status}</td>";
|
|
foreach ($selected_meta_keys as $meta_key) {
|
|
echo '<td style="font-weight: bold;">' . esc_html($enrollment->$meta_key) . '</td>';
|
|
}
|
|
echo '</tr>';
|
|
}
|
|
} else {
|
|
$colspan = 6 + count($selected_meta_keys); // 6 base columns + dynamic meta columns
|
|
echo '<tr><td colspan="' . $colspan . '" style="text-align: center;">No enrollments found</td></tr>';
|
|
}
|
|
|
|
echo '</tbody></table>';
|
|
|
|
if ($enrollments) {
|
|
echo '<div style="margin-top: 20px;">
|
|
<select name="new_status" required>
|
|
<option value="" disabled selected>Select status</option>
|
|
<option value="Waiting List">Waiting List</option>
|
|
<option value="Not Approved">Not Approved</option>
|
|
<option value="Approved">Approved</option>
|
|
</select>
|
|
<input type="submit" name="apply_status" value="Apply" class="button button-primary">';
|
|
echo '</div>';
|
|
}
|
|
|
|
echo '</form>';
|
|
echo '</div>';
|
|
|
|
// Add the color legend
|
|
echo '<div style="margin-top: 20px; display: flex; align-items: center;">
|
|
<h3 style="margin-right: 20px;">Legend:</h3>';
|
|
echo '<div style="display: flex; flex-wrap: wrap; gap: 10px;">
|
|
<span style="background-color: #f38d8d; padding: 5px; border-radius: 3px; width: 150px; text-align: center;">Enrollment Canceled by User</span>
|
|
<span style="background-color: #33ff7a; padding: 5px; border-radius: 3px; width: 150px; text-align: center;">Approved</span>
|
|
<span style="background-color: #e3db69; padding: 5px; border-radius: 3px; width: 150px; text-align: center;">Waiting List</span>
|
|
<span style="background-color: #bc97cd; padding: 5px; border-radius: 3px; width: 150px; text-align: center;">Not Approved</span>
|
|
<span style="background-color: #5ecac7; padding: 5px; border-radius: 3px; width: 150px; text-align: center;">Under Analysis</span>
|
|
</div></div>';
|
|
|
|
echo '<script>
|
|
jQuery(document).ready(function($) {
|
|
$("#summary-table-' . $unique_id . '").DataTable({
|
|
"paging": false,
|
|
"searching": false,
|
|
"info": false,
|
|
"scrollX": true,
|
|
"autoWidth": true
|
|
});
|
|
|
|
$("#enrollments-table' . $unique_id . '").DataTable({
|
|
"scrollX": true,
|
|
"autoWidth": true,
|
|
"pageLength": 50, // Set the default number of entries to show
|
|
"lengthMenu": [ [10, 25, 50, 100, 200, 500, -1], [10, 25, 50, 100, 200, 500, "All"] ] // Add custom options for the number of entries
|
|
});
|
|
|
|
$("#select_all").click(function() {
|
|
$("input[type=checkbox].select-enrollment").each(function() {
|
|
if (!$(this).is(":disabled")) {
|
|
$(this).prop("checked", $("#select_all").prop("checked"));
|
|
}
|
|
});
|
|
});
|
|
|
|
$("#toggle-features").click(function() {
|
|
$("#features-container").slideToggle();
|
|
$(this).text(function(i, text){
|
|
return text === "Expand Features" ? "Collapse Features" : "Expand Features";
|
|
});
|
|
});
|
|
|
|
$("#export-csv").click(function(e) {
|
|
e.preventDefault();
|
|
|
|
const selectedMetaKeys = JSON.parse($("#selected-meta-keys").val());
|
|
|
|
const now = new Date();
|
|
const formattedDate = `${("0" + now.getDate()).slice(-2)}_${("0" + (now.getMonth() + 1)).slice(-2)}_${now.getFullYear()}_${("0" + now.getHours()).slice(-2)}_${("0" + now.getMinutes()).slice(-2)}_${("0" + now.getSeconds()).slice(-2)}`;
|
|
const filename = `enrollments_${formattedDate}.csv`;
|
|
|
|
let csvContent = "data:text/csv;charset=utf-8,";
|
|
csvContent += "Activity Name,User ID,User Email,Enrollment Date,Status";
|
|
|
|
// Add selected meta keys to CSV header
|
|
if (selectedMetaKeys.length > 0) {
|
|
selectedMetaKeys.forEach(function(metaKey) {
|
|
csvContent += "," + metaKey.charAt(0).toUpperCase() + metaKey.slice(1).replace(/_/g, " ");
|
|
});
|
|
}
|
|
csvContent += "\n";
|
|
|
|
$("#enrollments-table' . $unique_id . ' tbody tr").each(function() {
|
|
const row = $(this);
|
|
const activityName = row.find("td:nth-child(2)").text().trim();
|
|
const userID = row.find("td:nth-child(3)").text().trim();
|
|
const userEmail = row.find("td:nth-child(4)").text().trim();
|
|
const enrollmentDate = row.find("td:nth-child(5)").text().trim();
|
|
const status = row.find("td:nth-child(6)").text().trim();
|
|
let rowData = `${activityName},${userID},${userEmail},${enrollmentDate},${status}`;
|
|
|
|
if (selectedMetaKeys.length > 0) {
|
|
selectedMetaKeys.forEach(function(metaKey, index) {
|
|
rowData += "," + row.find("td:nth-child(" + (7 + index) + ")").text().trim();
|
|
});
|
|
}
|
|
|
|
csvContent += rowData + "\n";
|
|
});
|
|
|
|
const encodedUri = encodeURI(csvContent);
|
|
const link = document.createElement("a");
|
|
link.setAttribute("href", encodedUri);
|
|
link.setAttribute("download", filename);
|
|
document.body.appendChild(link);
|
|
link.click();
|
|
document.body.removeChild(link);
|
|
});
|
|
|
|
});
|
|
</script>';
|
|
|
|
return ob_get_clean();
|
|
}
|
|
}
|
|
add_shortcode('genericEnrollmentControl', 'frontendEnrollmentControlGeneric');
|
|
|
|
/**
|
|
* Handles user enrollment for a specific activity via shortcode.
|
|
*
|
|
* @param array $attributes Shortcode attributes, expects 'activity_id'.
|
|
* @return string HTML output for enrollment status and form.
|
|
*/
|
|
function get_enrollment($attributes)
|
|
{
|
|
global $wpdb;
|
|
$user = wp_get_current_user();
|
|
$user_id = $user->ID;
|
|
|
|
$args = shortcode_atts(array('activity_id' => 'none', 'open' => 'yes'), $attributes);
|
|
$activity_id = $args['activity_id'];
|
|
$open_enrollment = $args['open'];
|
|
|
|
// Handle form submission
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['activity_id']) && $_POST['activity_id'] == $activity_id) {
|
|
if (isset($_POST['enrollment_action'])) {
|
|
if ($_POST['enrollment_action'] === 'add') {
|
|
// Add or update enrollment to "Under Analysis"
|
|
$existing = $wpdb->get_var($wpdb->prepare(
|
|
"SELECT id FROM {$wpdb->prefix}sige_enrollments WHERE activity_id = %d AND user_id = %d",
|
|
$activity_id,
|
|
$user_id
|
|
));
|
|
if ($existing) {
|
|
$wpdb->update(
|
|
"{$wpdb->prefix}sige_enrollments",
|
|
['status' => 'Under Analysis'],
|
|
['activity_id' => $activity_id, 'user_id' => $user_id]
|
|
);
|
|
send_email_notification($user_id, 'Under Analysis', $activity_id);
|
|
} else {
|
|
$wpdb->insert(
|
|
"{$wpdb->prefix}sige_enrollments",
|
|
[
|
|
'activity_id' => $activity_id,
|
|
'user_id' => $user_id,
|
|
'enrollment_date' => current_time('mysql'),
|
|
'status' => 'Under Analysis'
|
|
]
|
|
);
|
|
send_email_notification($user_id, 'Under Analysis', $activity_id);
|
|
}
|
|
} elseif ($_POST['enrollment_action'] === 'cancel') {
|
|
// Cancel enrollment
|
|
$wpdb->update(
|
|
"{$wpdb->prefix}sige_enrollments",
|
|
['status' => 'Enrollment Canceled by User'],
|
|
['activity_id' => $activity_id, 'user_id' => $user_id]
|
|
);
|
|
send_email_notification($user_id, 'Enrollment Canceled by User', $activity_id);
|
|
}
|
|
$referer = wp_get_referer();
|
|
$safe_referer = wp_validate_redirect($referer, home_url());
|
|
wp_safe_redirect(home_url('/inscricoes/'));
|
|
exit;
|
|
}
|
|
}
|
|
|
|
// Fetch current status only if user is logged in
|
|
if (!$user_id) {
|
|
return '';
|
|
}
|
|
|
|
$enrollment = $wpdb->get_var($wpdb->prepare("
|
|
SELECT status FROM {$wpdb->prefix}sige_enrollments
|
|
WHERE activity_id = %d AND user_id = %d
|
|
", $activity_id, $user_id));
|
|
|
|
$headline = '<p>Você ainda não se inscreveu nesta atividade!</p><br>';
|
|
$button = '';
|
|
|
|
if ($enrollment) {
|
|
$headline = '<p>Status da sua inscrição: ' . esc_html($enrollment) . '</p><br>';
|
|
if ($enrollment !== 'Enrollment Canceled by User' && $enrollment !== 'Not Approved') {
|
|
$button =
|
|
'<form method="post" style="display:inline;">
|
|
<input type="hidden" name="activity_id" value="' . esc_attr($activity_id) . '">
|
|
<button type="submit" name="enrollment_action" value="cancel" style="background:#f44336;color:#fff;">Cancelar inscrição</button>
|
|
</form>';
|
|
}
|
|
} else if ($open_enrollment !== 'yes') {
|
|
$headline = '<p>Inscrições encerradas</p><br>';
|
|
}
|
|
if ($open_enrollment === 'yes' && (empty($enrollment) || $enrollment === 'Enrollment Canceled by User'))
|
|
$button =
|
|
'<form method="post">
|
|
<input type="hidden" name="activity_id" value="' . esc_attr($activity_id) . '">
|
|
<button type="submit" name="enrollment_action" value="add">Solicite sua inscrição</button>
|
|
</form>';
|
|
|
|
return $headline . ' ' . $button;
|
|
}
|
|
add_shortcode('get_enroll', 'get_enrollment');
|
|
|
|
function frontendAttendanceControl()
|
|
{
|
|
ob_start();
|
|
|
|
nocache_headers();
|
|
|
|
// Append nocache query parameter to bust cache
|
|
if (!isset($_GET['nocache'])) {
|
|
// Append a unique timestamp-based parameter to the URL
|
|
$permalink = get_permalink();
|
|
if (!$permalink) {
|
|
$permalink = home_url();
|
|
}
|
|
$new_url = add_query_arg('nocache', time(), $permalink);
|
|
wp_redirect($new_url);
|
|
exit;
|
|
exit();
|
|
}
|
|
|
|
if (!is_user_logged_in()) {
|
|
|
|
return '
|
|
<div style="
|
|
position: fixed;
|
|
top: 50%;
|
|
left: 50%;
|
|
transform: translate(-50%, -50%);
|
|
background-color: #808080; /* Gray background */
|
|
color: #fff; /* White text color */
|
|
padding: 20px;
|
|
box-shadow: 0px 0px 15px rgba(0, 0, 0, 0.3);
|
|
z-index: 1000;
|
|
text-align: center;
|
|
border-radius: 10px;
|
|
">
|
|
<p>You must be logged in to handle the attendance control.</p>
|
|
</div>';
|
|
}
|
|
|
|
// Check if the user has administrator or contributor role
|
|
if (!(current_user_can('administrator') || current_user_can('comissao_secretaria') || current_user_can('comissao_suporte')) && !current_user_can('contributor')) {
|
|
|
|
return '<div style="position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background-color: #e0e0e0; padding: 20px; border-radius: 10px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.5); z-index: 999; text-align: center;">
|
|
<p>You do not have the required permissions to handle the attendance control.</p>
|
|
</div>';
|
|
}
|
|
|
|
// Handle form submission to update attendance
|
|
if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['update_attendance'])) {
|
|
//error_log('******************************************');
|
|
//error_log('Form submitted with update_attendance');
|
|
$enrollment_id = isset($_POST['enrollment_id']) ? intval($_POST['enrollment_id']) : 0;
|
|
//error_log('enrollment_id: ' . $enrollment_id);
|
|
$attended = isset($_POST['attended']) ? sanitize_text_field($_POST['attended']) : '';
|
|
//error_log('attended: ' . $attended);
|
|
$user_id = isset($_POST['user_id']) ? intval($_POST['user_id']) : 0;
|
|
//error_log('user_id: ' . $user_id);
|
|
//$selected_activity = isset($_POST['selected_activity']) ? sanitize_text_field($_POST['selected_activity']) : 'All';
|
|
$selected_activity = sanitize_text_field($_POST['selected_activity']);
|
|
|
|
if ($enrollment_id && $attended) {
|
|
//error_log('Valid enrollment_id and attended values');
|
|
global $wpdb;
|
|
|
|
// Fetch the activity_id from the sige_enrollments table
|
|
$activity_id = $wpdb->get_var($wpdb->prepare("SELECT activity_id FROM {$wpdb->prefix}sige_enrollments WHERE id = %d", $enrollment_id));
|
|
//error_log('activity_id: ' . $activity_id);
|
|
|
|
$existing_record = $wpdb->get_var($wpdb->prepare("SELECT id FROM {$wpdb->prefix}sige_enrollment_attendance_control WHERE enrollment_id = %d", $enrollment_id));
|
|
|
|
if ($existing_record) {
|
|
$wpdb->update(
|
|
"{$wpdb->prefix}sige_enrollment_attendance_control",
|
|
['attended' => $attended],
|
|
['id' => $existing_record]
|
|
);
|
|
} else {
|
|
$wpdb->insert(
|
|
"{$wpdb->prefix}sige_enrollment_attendance_control",
|
|
[
|
|
'enrollment_id' => $enrollment_id,
|
|
'attended' => $attended
|
|
]
|
|
);
|
|
}
|
|
}
|
|
|
|
if ($activity_id !== null) {
|
|
// error_log('Sending email notification');
|
|
send_email_notification($user_id, $attended, $activity_id);
|
|
} else {
|
|
//error_log('Activity ID not found for enrollment ID ' . $enrollment_id);
|
|
}
|
|
} else {
|
|
$selected_activity = isset($_POST['selected_activity']) ? sanitize_text_field($_POST['selected_activity']) : 'SIGE XXVII';
|
|
//$selected_activity = sanitize_text_field($_POST['selected_activity']);
|
|
}
|
|
|
|
// Handle QR code verification
|
|
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
|
if (isset($_POST['qr_scanner_used']) && $_POST['qr_scanner_used'] == '1') {
|
|
$hashed_user_id = sanitize_text_field($_POST['filtered_user_id']);
|
|
$filtered_user_id = verifyUserBasedOnQRCode($hashed_user_id);
|
|
} else {
|
|
$filtered_user_id = isset($_POST['filtered_user_id']) ? intval($_POST['filtered_user_id']) : '';
|
|
}
|
|
} else {
|
|
$filtered_user_id = '';
|
|
}
|
|
|
|
// Fetch enrollments with status "Approved/Waiting List" and modality "In-person or Hybrid"
|
|
global $wpdb;
|
|
$query = "
|
|
SELECT e.id as enrollment_id, e.activity_id, a.name as activity_name, e.user_id, um1.meta_value as full_name, u.user_email, e.enrollment_date, e.status, ac.attended
|
|
FROM {$wpdb->prefix}sige_enrollments e
|
|
LEFT JOIN {$wpdb->prefix}sige_activities a ON e.activity_id = a.id
|
|
LEFT JOIN {$wpdb->prefix}usermeta um1 ON e.user_id = um1.user_id AND um1.meta_key = 'full_name'
|
|
LEFT JOIN {$wpdb->prefix}users u ON e.user_id = u.ID
|
|
LEFT JOIN {$wpdb->prefix}sige_enrollment_attendance_control ac ON e.id = ac.enrollment_id
|
|
WHERE (e.status = 'Approved' OR e.status = 'Waiting List') AND (a.modality = 'In-person' OR a.modality = 'Hybrid')
|
|
";
|
|
|
|
if ($selected_activity !== 'All') {
|
|
$query .= $wpdb->prepare(" AND a.id = %d", $selected_activity);
|
|
}
|
|
|
|
if ($filtered_user_id) {
|
|
$query .= $wpdb->prepare(" AND e.user_id = %d", $filtered_user_id);
|
|
}
|
|
|
|
$enrollments = $wpdb->get_results($query);
|
|
$activities = $wpdb->get_results("SELECT id, name FROM {$wpdb->prefix}sige_activities WHERE modality IN ('In-person', 'Hybrid') AND YEAR(start_date) = YEAR(CURDATE());");
|
|
|
|
?>
|
|
<div class="wrap">
|
|
<h2>Attendance Control</h2>
|
|
<div style="background-color: #f0f0f0; padding: 20px; border-radius: 5px; margin-bottom: 20px; text-align: center;">
|
|
<div style="margin-bottom: 20px;">
|
|
<div id="qr-reader" style="width:300px; margin: 0 auto;"></div>
|
|
<button id="start-qr-reader" class="button button-secondary"
|
|
style="display: inline-block; margin-top: 10px; width: 300px;">Start QR Scanner</button>
|
|
</div>
|
|
<form method="post" action="" id="attendanceForm"
|
|
style="display: flex; flex-direction: column; gap: 10px; align-items: center;">
|
|
<input type="text" name="filtered_user_id" id="filtered_user_id" placeholder="Enter User ID"
|
|
value="<?php echo esc_attr($filtered_user_id); ?>" style="width: 300px;" />
|
|
<input type="hidden" name="qr_scanner_used" id="qr_scanner_used" value="0" />
|
|
<div style="display: flex; align-items: center; gap: 10px;">
|
|
<label for="activityFilter">Activity:</label>
|
|
<select id="activityFilter" name="selected_activity" form="attendanceForm">
|
|
<option value="All">All</option>
|
|
<?php foreach ($activities as $activity) { ?>
|
|
<option value="<?php echo esc_attr($activity->id); ?>" <?php selected($selected_activity, $activity->id); ?>><?php echo esc_html($activity->name); ?></option>
|
|
<?php } ?>
|
|
</select>
|
|
</div>
|
|
<input type="submit" value="Filter" class="button button-secondary" style="width: 300px;" />
|
|
</form>
|
|
</div>
|
|
|
|
<div style="background-color: #f0f0f0; padding: 20px; border-radius: 5px; overflow-x: auto; margin-bottom: 20px;">
|
|
<table id="attendanceTable" class="display" style="width:100%">
|
|
<thead>
|
|
<tr>
|
|
<th>Activity Name</th>
|
|
<th>User ID</th>
|
|
<th>User Full Name</th>
|
|
<th>Email</th>
|
|
<th>Enrollment Date</th>
|
|
<th>Status</th>
|
|
<th>Attended</th>
|
|
<th>Action</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="tableBody">
|
|
<?php
|
|
if ($enrollments) {
|
|
foreach ($enrollments as $enrollment) {
|
|
?>
|
|
<tr data-attended="<?php echo esc_attr($enrollment->attended); ?>">
|
|
<td><?php echo esc_html($enrollment->activity_name); ?></td>
|
|
<td><?php echo esc_html($enrollment->user_id); ?></td>
|
|
<td><?php echo esc_html($enrollment->full_name); ?></td>
|
|
<td><?php echo esc_html($enrollment->user_email); ?></td>
|
|
<td><?php echo esc_html($enrollment->enrollment_date); ?></td>
|
|
<td><?php echo esc_html($enrollment->status); ?></td>
|
|
<td><?php echo esc_html($enrollment->attended); ?></td>
|
|
<td>
|
|
<form method="post" action="">
|
|
<input type="hidden" name="enrollment_id"
|
|
value="<?php echo esc_attr($enrollment->enrollment_id); ?>" />
|
|
<input type="hidden" name="user_id" value="<?php echo esc_attr($enrollment->user_id); ?>" />
|
|
<input type="hidden" name="selected_activity"
|
|
value="<?php echo esc_attr($selected_activity); ?>" />
|
|
<select name="attended">
|
|
<option value="yes" <?php selected($enrollment->attended, 'yes'); ?>>Yes</option>
|
|
<option value="no" <?php selected($enrollment->attended, 'no'); ?>>No</option>
|
|
</select>
|
|
<input type="submit" name="update_attendance" value="Update"
|
|
class="button button-primary" />
|
|
</form>
|
|
</td>
|
|
</tr>
|
|
<?php
|
|
}
|
|
} else {
|
|
?>
|
|
<tr>
|
|
<td colspan="8">No approved enrollments found.</td>
|
|
</tr>
|
|
<?php
|
|
}
|
|
?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<div style="background-color: #f0f0f0; padding: 20px; border-radius: 5px; text-align: center;">
|
|
<button id="export-csv" class="button button-secondary" style="margin-top: 10px;">Export to CSV</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Include DataTables JS and CSS -->
|
|
<script src="https://cdn.datatables.net/1.10.24/js/jquery.dataTables.min.js"></script>
|
|
<script src="https://cdn.datatables.net/1.10.24/js/dataTables.jqueryui.min.js"></script>
|
|
<link rel="stylesheet" href="https://cdn.datatables.net/1.10.24/css/dataTables.jqueryui.min.css">
|
|
|
|
<script>
|
|
jQuery(document).ready(function($) {
|
|
function initializeQrCodeScanner() {
|
|
if (typeof Html5Qrcode !== "undefined") {
|
|
const qrReader = new Html5Qrcode("qr-reader");
|
|
const startQrReaderBtn = document.getElementById("start-qr-reader");
|
|
const userIdInput = document.getElementById("filtered_user_id");
|
|
const qrScannerUsedInput = document.getElementById("qr_scanner_used");
|
|
let qrScannerRunning = false;
|
|
|
|
startQrReaderBtn.addEventListener("click", function() {
|
|
if (!qrScannerRunning) {
|
|
qrReader.start({
|
|
facingMode: "environment"
|
|
}, {
|
|
fps: 10,
|
|
qrbox: 250
|
|
},
|
|
qrCodeMessage => {
|
|
userIdInput.value = qrCodeMessage;
|
|
qrScannerUsedInput.value = 1; // Set this to indicate scanner was used
|
|
qrReader.stop().then(() => {
|
|
qrScannerRunning = false;
|
|
startQrReaderBtn.textContent = "Start QR Scanner";
|
|
// Auto-submit the form after scanning the QR code
|
|
document.getElementById("attendanceForm").submit();
|
|
});
|
|
},
|
|
errorMessage => {
|
|
console.warn(`QR Code scanning error: ${errorMessage}`);
|
|
}
|
|
).then(() => {
|
|
qrScannerRunning = true;
|
|
startQrReaderBtn.textContent = "Stop QR Scanner";
|
|
}).catch(err => {
|
|
console.error(`Unable to start QR Code scanning: ${err}`);
|
|
});
|
|
} else {
|
|
qrReader.stop().then(() => {
|
|
qrScannerRunning = false;
|
|
startQrReaderBtn.textContent = "Start QR Scanner";
|
|
}).catch(err => {
|
|
console.error(`Unable to stop QR Code scanning: ${err}`);
|
|
});
|
|
}
|
|
});
|
|
} else {
|
|
console.error("Html5Qrcode library is not loaded properly.");
|
|
}
|
|
}
|
|
|
|
function exportToCsv(filename, rows) {
|
|
const processRow = function(row) {
|
|
let finalVal = '';
|
|
for (let j = 0; j < row.length; j++) {
|
|
let innerValue = row[j] === null ? '' : row[j].toString();
|
|
if (row[j] instanceof Date) {
|
|
innerValue = row[j].toLocaleString();
|
|
}
|
|
let result = innerValue.replace(/"/g, '""');
|
|
if (result.search(/("|,|\n)/g) >= 0)
|
|
result = '"' + result + '"';
|
|
if (j > 0)
|
|
finalVal += ';'; // Changed to semicolon
|
|
finalVal += result;
|
|
}
|
|
return finalVal + '\n';
|
|
};
|
|
|
|
let csvFile = '';
|
|
for (let i = 0; i < rows.length; i++) {
|
|
csvFile += processRow(rows[i]);
|
|
}
|
|
|
|
const blob = new Blob([csvFile], {
|
|
type: 'text/csv;charset=utf-8;'
|
|
});
|
|
if (navigator.msSaveBlob) { // IE 10+
|
|
navigator.msSaveBlob(blob, filename);
|
|
} else {
|
|
const link = document.createElement("a");
|
|
if (link.download !== undefined) { // feature detection
|
|
// Browsers that support HTML5 download attribute
|
|
const url = URL.createObjectURL(blob);
|
|
link.setAttribute("href", url);
|
|
link.setAttribute("download", filename);
|
|
link.style.visibility = 'hidden';
|
|
document.body.appendChild(link);
|
|
link.click();
|
|
document.body.removeChild(link);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
function generateCsvFileName() {
|
|
const now = new Date();
|
|
const formattedDate = `${("0" + now.getDate()).slice(-2)}_${("0" + (now.getMonth() + 1)).slice(-2)}_${now.getFullYear()}_${("0" + now.getHours()).slice(-2)}_${("0" + now.getMinutes()).slice(-2)}_${("0" + now.getSeconds()).slice(-2)}`;
|
|
return `attendance_${formattedDate}.csv`;
|
|
}
|
|
|
|
document.getElementById('export-csv').addEventListener('click', function() {
|
|
const table = document.querySelector('#attendanceTable');
|
|
const rows = [];
|
|
rows.push(["Activity Name", "User ID", "User Full Name", "Email", "Enrollment Date", "Status", "Attended"]);
|
|
|
|
table.querySelectorAll('tbody tr').forEach(function(row) {
|
|
const rowData = [];
|
|
row.querySelectorAll('td').forEach(function(cell, index) {
|
|
if (index < 7) { // Exclude the last column (Action)
|
|
rowData.push(cell.innerText.trim());
|
|
}
|
|
});
|
|
rows.push(rowData);
|
|
});
|
|
|
|
exportToCsv(generateCsvFileName(), rows);
|
|
});
|
|
|
|
initializeQrCodeScanner();
|
|
|
|
// Initialize DataTables
|
|
$('#attendanceTable').DataTable({
|
|
paging: true,
|
|
searching: true,
|
|
lengthChange: true,
|
|
pageLength: -1,
|
|
autoWidth: false,
|
|
scrollX: true,
|
|
order: [
|
|
[2, 'asc']
|
|
],
|
|
lengthMenu: [
|
|
[10, 25, 50, 100, 200, 500, -1],
|
|
[10, 25, 50, 100, 200, 500, "All"]
|
|
], // Add custom options for the number of entries
|
|
language: {
|
|
lengthMenu: "Show _MENU_ entries",
|
|
info: "Showing _START_ to _END_ of _TOTAL_ entries",
|
|
infoFiltered: "(filtered from _MAX_ total entries)",
|
|
paginate: {
|
|
previous: "Previous",
|
|
next: "Next"
|
|
}
|
|
}
|
|
});
|
|
|
|
// Highlight rows based on "Attended" column value
|
|
$('#attendanceTable tbody tr').each(function() {
|
|
const attended = $(this).data('attended');
|
|
if (attended === 'yes') {
|
|
$(this).css('background-color', '#33ff7a');
|
|
} else if (attended === 'no') {
|
|
$(this).css('background-color', '#f54949');
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
|
|
<?php
|
|
return ob_get_clean();
|
|
}
|
|
|
|
add_shortcode('frontend_attendance_control', 'frontendAttendanceControl');
|
|
|
|
// Ensure the phpqrcode and tcpdf library are included
|
|
|
|
require_once plugin_dir_path(__FILE__) . '../phpqrcode/qrlib.php';
|
|
require_once plugin_dir_path(__FILE__) . '../tcpdf/tcpdf.php';
|
|
|
|
function frontendAttendanceControlAutomatic()
|
|
{
|
|
ob_start();
|
|
session_start(); // Start the session to store the success message
|
|
|
|
nocache_headers();
|
|
|
|
// Append nocache query parameter to bust cache
|
|
if (!isset($_GET['nocache'])) {
|
|
// Append a unique timestamp-based parameter to the URL
|
|
$permalink = get_permalink();
|
|
if (!$permalink) {
|
|
$permalink = home_url();
|
|
}
|
|
$new_url = add_query_arg('nocache', time(), $permalink);
|
|
wp_redirect($new_url);
|
|
exit;
|
|
exit();
|
|
}
|
|
|
|
if (!is_user_logged_in()) {
|
|
return '<div style="position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background-color: #e0e0e0; padding: 20px; border-radius: 10px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.5); z-index: 999; text-align: center;">
|
|
<p>You must be logged in to handle the attendance control.</p>
|
|
</div>';
|
|
}
|
|
|
|
if (!(current_user_can('administrator') || current_user_can('comissao_secretaria') || current_user_can('comissao_suporte')) && !current_user_can('contributor')) {
|
|
|
|
return '<div style="position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background-color: #e0e0e0; padding: 20px; border-radius: 10px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.5); z-index: 999; text-align: center;">
|
|
<p>You do not have the required permissions to handle the attendance control.</p>
|
|
</div>';
|
|
}
|
|
|
|
global $wpdb;
|
|
$success_message = '';
|
|
|
|
$selected_activity = isset($_POST['selected_activity']) ? intval($_POST['selected_activity']) : (isset($_GET['selected_activity']) ? intval($_GET['selected_activity']) : 0);
|
|
$selected_status = isset($_POST['statusFilter']) ? sanitize_text_field($_POST['statusFilter']) : (isset($_GET['statusFilter']) ? sanitize_text_field($_GET['statusFilter']) : 'Approved');
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
|
if (isset($_POST['qr_scanner_used']) && $_POST['qr_scanner_used'] == '1') {
|
|
$hashed_user_id = sanitize_text_field($_POST['qr_code_message']);
|
|
$filtered_user_id = verifyUserBasedOnQRCode($hashed_user_id);
|
|
|
|
if ($selected_activity === -1 || $selected_activity > 0) {
|
|
$status_condition = $selected_status === 'Not Requested' ? 'Not Requested' : $selected_status;
|
|
|
|
$query = $wpdb->prepare("
|
|
SELECT e.id as enrollment_id, e.user_id, e.status, u.user_email, um1.meta_value as full_name, a.name as activity_name, a.id as activity_id
|
|
FROM {$wpdb->prefix}sige_enrollments e
|
|
LEFT JOIN {$wpdb->prefix}users u ON e.user_id = u.ID
|
|
LEFT JOIN {$wpdb->prefix}usermeta um1 ON e.user_id = um1.user_id AND um1.meta_key = 'full_name'
|
|
LEFT JOIN {$wpdb->prefix}sige_activities a ON e.activity_id = a.id
|
|
WHERE e.user_id = %d AND e.status = %s
|
|
", $filtered_user_id, $status_condition);
|
|
|
|
if ($selected_activity === -1) {
|
|
$query .= " AND a.type = 'Main Event' AND (a.modality = 'In-person' OR a.modality = 'Hybrid')";
|
|
} else {
|
|
$query .= $wpdb->prepare(" AND e.activity_id = %d", $selected_activity);
|
|
}
|
|
|
|
$enrollments = $wpdb->get_results($query);
|
|
|
|
if ($enrollments) {
|
|
foreach ($enrollments as $enrollment) {
|
|
$existing_attendance = $wpdb->get_var($wpdb->prepare("
|
|
SELECT attended FROM {$wpdb->prefix}sige_enrollment_attendance_control
|
|
WHERE enrollment_id = %d
|
|
", $enrollment->enrollment_id));
|
|
|
|
if ($existing_attendance === 'yes') {
|
|
$success_message .= '
|
|
<div class="notice notice-warning" style="position: relative; margin-bottom: 10px; background-color: #fff3cd; padding: 20px; border-radius: 10px;">
|
|
<button class="notice-close" style="position: absolute; top: 10px; right: 10px; background-color: transparent; border: none; font-size: 20px; cursor: pointer;">×</button>
|
|
<p>Mr./Mrs. ' . esc_html($enrollment->full_name) . '</p>
|
|
<p>Email: ' . esc_html($enrollment->user_email) . '</p>
|
|
<p>You have already attended the ' . esc_html($enrollment->activity_name) . '</p>
|
|
</div>';
|
|
} else {
|
|
if ($existing_attendance) {
|
|
$wpdb->update(
|
|
"{$wpdb->prefix}sige_enrollment_attendance_control",
|
|
['attended' => 'yes'],
|
|
['enrollment_id' => $enrollment->enrollment_id]
|
|
);
|
|
} else {
|
|
$wpdb->insert(
|
|
"{$wpdb->prefix}sige_enrollment_attendance_control",
|
|
[
|
|
'enrollment_id' => $enrollment->enrollment_id,
|
|
'attended' => 'yes'
|
|
]
|
|
);
|
|
}
|
|
|
|
|
|
send_email_notification($enrollment->user_id, 'yes', $enrollment->activity_id);
|
|
|
|
$enrollment_date = isset($enrollment->enrollment_date) ? esc_html(date('d-m-Y', strtotime($enrollment->enrollment_date))) : 'N/A';
|
|
$success_message .= '
|
|
<div class="notice notice-success" style="position: relative; margin-bottom: 10px; background-color: #d4edda; padding: 20px; border-radius: 10px;">
|
|
<button class="notice-close" style="position: absolute; top: 10px; right: 10px; background-color: transparent; border: none; font-size: 20px; cursor: pointer;">×</button>
|
|
<p>Mr./Mrs. ' . esc_html($enrollment->full_name) . '</p>
|
|
<p>Email: ' . esc_html($enrollment->user_email) . '</p>
|
|
<p>Thank you for attending the ' . esc_html($enrollment->activity_name) . '</p>
|
|
<p>Date of the Activity: ' . $enrollment_date . '</p>
|
|
<p>You will soon receive an email confirming your participation.</p>
|
|
</div>';
|
|
}
|
|
}
|
|
} else {
|
|
if ($selected_status === 'Not Requested') {
|
|
$new_enrollment_data = [
|
|
'activity_id' => $selected_activity === -1 ? $wpdb->get_var("SELECT id FROM {$wpdb->prefix}sige_activities WHERE modality = 'Hybrid' AND type = 'Main Event' LIMIT 1") : $selected_activity,
|
|
'user_id' => $filtered_user_id,
|
|
'enrollment_date' => current_time('mysql'),
|
|
'status' => 'Not Requested'
|
|
];
|
|
|
|
$wpdb->insert("{$wpdb->prefix}sige_enrollments", $new_enrollment_data);
|
|
$new_enrollment_id = $wpdb->insert_id;
|
|
|
|
if ($new_enrollment_id) {
|
|
$wpdb->insert("{$wpdb->prefix}sige_enrollment_attendance_control", [
|
|
'enrollment_id' => $new_enrollment_id,
|
|
'attended' => 'yes'
|
|
]);
|
|
|
|
// Fetch new user's email and full name for the email
|
|
$new_enrollment_user = $wpdb->get_row($wpdb->prepare("
|
|
SELECT u.user_email, um1.meta_value as full_name
|
|
FROM {$wpdb->prefix}users u
|
|
LEFT JOIN {$wpdb->prefix}usermeta um1 ON u.ID = um1.user_id AND um1.meta_key = 'full_name'
|
|
WHERE u.ID = %d
|
|
", $filtered_user_id));
|
|
|
|
// Send email for the new enrollment and attendance
|
|
if ($new_enrollment_user) {
|
|
$to = $new_enrollment_user->user_email;
|
|
$subject = 'Your Enrollment and Attendance Have Been Recorded';
|
|
$message = 'Dear ' . esc_html($new_enrollment_user->full_name) . ',<br><br>' .
|
|
'You have been successfully enrolled in the activity, and your attendance has been recorded.<br>' .
|
|
'Thank you for your participation!<br><br>' .
|
|
'Best regards,<br>The Event Team';
|
|
|
|
$headers = ['Content-Type: text/html; charset=UTF-8'];
|
|
|
|
// Send the email
|
|
wp_mail($to, $subject, $message, $headers);
|
|
}
|
|
|
|
// Log the email variables for debugging
|
|
//error_log("New enrollment email sent to: " . esc_html($new_enrollment_user->user_email));
|
|
//error_log("New enrollment user full name: " . esc_html($new_enrollment_user->full_name));
|
|
$success_message .= '
|
|
<div class="notice notice-success" style="position: relative; margin-bottom: 10px; background-color: #d4edda; padding: 20px; border-radius: 10px;">
|
|
<button class="notice-close" style="position: absolute; top: 10px; right: 10px; background-color: transparent; border: none; font-size: 20px; cursor: pointer;">×</button>
|
|
<p>A new enrollment has been added and attendance has been recorded.</p>
|
|
</div>';
|
|
}
|
|
} else {
|
|
$success_message .= '
|
|
<div class="notice notice-error" style="position: relative; margin-bottom: 10px; background-color: #f8d7da; padding: 20px; border-radius: 10px;">
|
|
<button class="notice-close" style="position: absolute; top: 10px; right: 10px; background-color: transparent; border: none; font-size: 20px; cursor: pointer;">×</button>
|
|
<p>No enrollments found for the user with the selected status.</p>
|
|
</div>';
|
|
}
|
|
}
|
|
|
|
// Store success message in session and reload the page with the selected_activity and statusFilter in the URL
|
|
$_SESSION['success_message'] = $success_message;
|
|
wp_safe_redirect(add_query_arg(['selected_activity' => $selected_activity, 'statusFilter' => $selected_status]));
|
|
exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Display the success message if it exists
|
|
if (isset($_SESSION['success_message'])) {
|
|
echo $_SESSION['success_message'];
|
|
unset($_SESSION['success_message']); // Clear the message after displaying it
|
|
}
|
|
|
|
// Fetch enrollments with the selected status
|
|
$query = "
|
|
SELECT e.id as enrollment_id, e.activity_id, a.name as activity_name, e.user_id, um1.meta_value as full_name, u.user_email, e.enrollment_date, e.status, ac.attended
|
|
FROM {$wpdb->prefix}sige_enrollments e
|
|
LEFT JOIN {$wpdb->prefix}sige_activities a ON e.activity_id = a.id
|
|
LEFT JOIN {$wpdb->prefix}usermeta um1 ON e.user_id = um1.user_id AND um1.meta_key = 'full_name'
|
|
LEFT JOIN {$wpdb->prefix}users u ON e.user_id = u.ID
|
|
LEFT JOIN {$wpdb->prefix}sige_enrollment_attendance_control ac ON e.id = ac.enrollment_id
|
|
WHERE e.status = %s
|
|
";
|
|
$status_condition = $selected_status === 'Not Requested' ? 'Not Requested' : $selected_status;
|
|
$query = $wpdb->prepare($query, $status_condition);
|
|
|
|
if ($selected_activity === -1) {
|
|
$query .= " AND a.type = 'Main Event' AND (a.modality = 'In-person' OR a.modality = 'Hybrid')";
|
|
} elseif ($selected_activity > 0) {
|
|
$query .= $wpdb->prepare(" AND a.id = %d", $selected_activity);
|
|
}
|
|
|
|
$enrollments = $wpdb->get_results($query);
|
|
|
|
$activities = $wpdb->get_results("SELECT id, name FROM {$wpdb->prefix}sige_activities WHERE modality IN ('In-person', 'Hybrid') AND YEAR(start_date) = YEAR(CURDATE());")
|
|
|
|
?>
|
|
<div class="wrap">
|
|
<h2>Attendance Control</h2>
|
|
<div style="background-color: #f0f0f0; padding: 20px; border-radius: 5px; margin-bottom: 20px; text-align: center;">
|
|
<div style="margin-bottom: 20px;">
|
|
<div id="qr-reader" style="width:300px; margin: 0 auto;"></div>
|
|
<button id="start-qr-reader" class="button button-secondary" style="display: inline-block; margin-top: 10px; width: 300px;">Start QR Scanner</button>
|
|
</div>
|
|
<form method="post" action="" id="attendanceForm" style="display: flex; flex-direction: column; gap: 10px; align-items: center;">
|
|
<input type="hidden" name="qr_scanner_used" id="qr_scanner_used" value="0" />
|
|
<input type="hidden" name="qr_code_message" id="qr_code_message" />
|
|
<div style="display: flex; align-items: center; gap: 10px;">
|
|
<label for="activityFilter">Activity:</label>
|
|
<select id="activityFilter" name="selected_activity" form="attendanceForm" onchange="this.form.submit();" required>
|
|
<option value="">Select an Activity</option>
|
|
<option value="-1" <?php selected($selected_activity, -1); ?>>Main Event</option>
|
|
<?php foreach ($activities as $activity) { ?>
|
|
<option value="<?php echo esc_attr($activity->id); ?>" <?php selected($selected_activity, $activity->id); ?>><?php echo esc_html($activity->name); ?></option>
|
|
<?php } ?>
|
|
</select>
|
|
</div>
|
|
<div style="display: flex; align-items: center; gap: 10px;">
|
|
<label for="statusFilter">Status:</label>
|
|
<select id="statusFilter" name="statusFilter" form="attendanceForm" onchange="this.form.submit();" required>
|
|
<option value="Approved" <?php selected($selected_status, 'Approved'); ?>>Approved</option>
|
|
<option value="Waiting List" <?php selected($selected_status, 'Waiting List'); ?>>Waiting List</option>
|
|
<option value="Not Requested" <?php selected($selected_status, 'Not Requested'); ?>>Not Requested</option>
|
|
</select>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<div style="background-color: #f0f0f0; padding: 20px; border-radius: 5px; overflow-x: auto; margin-bottom: 20px;">
|
|
<table id="attendanceTable" class="display" style="width:100%">
|
|
<thead>
|
|
<tr>
|
|
<th>Activity Name</th>
|
|
<th>User ID</th>
|
|
<th>User Full Name</th>
|
|
<th>Email</th>
|
|
<th>Enrollment Date</th>
|
|
<th>Status</th>
|
|
<th>Attended</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="tableBody">
|
|
<?php
|
|
if ($enrollments) {
|
|
foreach ($enrollments as $enrollment) {
|
|
?>
|
|
<tr data-attended="<?php echo esc_attr($enrollment->attended); ?>">
|
|
<td><?php echo esc_html($enrollment->activity_name); ?></td>
|
|
<td><?php echo esc_html($enrollment->user_id); ?></td>
|
|
<td><?php echo esc_html($enrollment->full_name); ?></td>
|
|
<td><?php echo esc_html($enrollment->user_email); ?></td>
|
|
<td><?php echo esc_html($enrollment->enrollment_date); ?></td>
|
|
<td><?php echo esc_html($enrollment->status); ?></td>
|
|
<td><?php echo esc_html($enrollment->attended); ?></td>
|
|
</tr>
|
|
<?php
|
|
}
|
|
} else {
|
|
?>
|
|
<tr>
|
|
<td colspan="7">No enrollments found for the selected status.</td>
|
|
</tr>
|
|
<?php
|
|
}
|
|
?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<div style="background-color: #f0f0f0; padding: 20px; border-radius: 5px; text-align: center;">
|
|
<button id="export-csv" class="button button-secondary" style="margin-top: 10px;">Export to CSV</button>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="https://cdn.datatables.net/1.10.24/js/jquery.dataTables.min.js"></script>
|
|
<script src="https://cdn.datatables.net/1.10.24/js/dataTables.jqueryui.min.js"></script>
|
|
<link rel="stylesheet" href="https://cdn.datatables.net/1.10.24/css/dataTables.jqueryui.min.css">
|
|
|
|
<script>
|
|
jQuery(document).ready(function($) {
|
|
|
|
function applyAttendanceStyles() {
|
|
$('#attendanceTable tbody tr').each(function() {
|
|
const attended = $(this).data('attended');
|
|
if (attended === 'yes') {
|
|
$(this).css('background-color', '#33ff7a');
|
|
} else if (attended === 'no') {
|
|
$(this).css('background-color', '#f54949');
|
|
} else if (attended === '') {
|
|
$(this).css('background-color', '#d1ca3b');
|
|
}
|
|
|
|
|
|
});
|
|
}
|
|
|
|
function initializeQrCodeScanner() {
|
|
if (typeof Html5Qrcode !== "undefined") {
|
|
const qrReader = new Html5Qrcode("qr-reader");
|
|
const startQrReaderBtn = document.getElementById("start-qr-reader");
|
|
const qrCodeMessageInput = document.getElementById("qr_code_message");
|
|
const qrScannerUsedInput = document.getElementById("qr_scanner_used");
|
|
let qrScannerRunning = false;
|
|
|
|
startQrReaderBtn.addEventListener("click", function() {
|
|
if (!qrScannerRunning) {
|
|
qrReader.start({
|
|
facingMode: "environment"
|
|
}, {
|
|
fps: 10,
|
|
qrbox: 250
|
|
},
|
|
qrCodeMessage => {
|
|
qrCodeMessageInput.value = qrCodeMessage;
|
|
qrScannerUsedInput.value = 1; // Set this to indicate scanner was used
|
|
qrReader.stop().then(() => {
|
|
qrScannerRunning = false;
|
|
startQrReaderBtn.textContent = "Start QR Scanner";
|
|
document.getElementById("attendanceForm").submit();
|
|
});
|
|
},
|
|
errorMessage => {
|
|
console.warn(`QR Code scanning error: ${errorMessage}`);
|
|
}
|
|
).then(() => {
|
|
qrScannerRunning = true;
|
|
startQrReaderBtn.textContent = "Stop QR Scanner";
|
|
}).catch(err => {
|
|
console.error(`Unable to start QR Code scanning: ${err}`);
|
|
});
|
|
} else {
|
|
qrReader.stop().then(() => {
|
|
qrScannerRunning = false;
|
|
startQrReaderBtn.textContent = "Start QR Scanner";
|
|
}).catch(err => {
|
|
console.error(`Unable to stop QR Code scanning: ${err}`);
|
|
});
|
|
}
|
|
});
|
|
} else {
|
|
console.error("Html5Qrcode library is not loaded properly.");
|
|
}
|
|
}
|
|
|
|
function exportToCsv(filename, rows) {
|
|
const processRow = function(row) {
|
|
let finalVal = '';
|
|
for (let j = 0; j < row.length; j++) {
|
|
let innerValue = row[j] === null ? '' : row[j].toString();
|
|
if (row[j] instanceof Date) {
|
|
innerValue = row[j].toLocaleString();
|
|
}
|
|
let result = innerValue.replace(/"/g, '""');
|
|
if (result.search(/("|,|\n)/g) >= 0)
|
|
result = '"' + result + '"';
|
|
if (j > 0)
|
|
finalVal += ';'; // Changed to semicolon
|
|
finalVal += result;
|
|
}
|
|
return finalVal + '\n';
|
|
};
|
|
|
|
let csvFile = '';
|
|
for (let i = 0; i < rows.length; i++) {
|
|
csvFile += processRow(rows[i]);
|
|
}
|
|
|
|
const blob = new Blob([csvFile], {
|
|
type: 'text/csv;charset=utf-8;'
|
|
});
|
|
if (navigator.msSaveBlob) { // IE 10+
|
|
navigator.msSaveBlob(blob, filename);
|
|
} else {
|
|
const link = document.createElement("a");
|
|
if (link.download !== undefined) { // feature detection
|
|
const url = URL.createObjectURL(blob);
|
|
link.setAttribute("href", url);
|
|
link.setAttribute("download", filename);
|
|
link.style.visibility = 'hidden';
|
|
document.body.appendChild(link);
|
|
link.click();
|
|
document.body.removeChild(link);
|
|
}
|
|
}
|
|
}
|
|
|
|
function generateCsvFileName() {
|
|
const now = new Date();
|
|
const formattedDate = `${("0" + now.getDate()).slice(-2)}_${("0" + (now.getMonth() + 1)).slice(-2)}_${now.getFullYear()}_${("0" + now.getHours()).slice(-2)}_${("0" + now.getMinutes()).slice(-2)}_${("0" + now.getSeconds()).slice(-2)}`;
|
|
return `attendance_${formattedDate}.csv`;
|
|
}
|
|
|
|
document.getElementById('export-csv').addEventListener('click', function() {
|
|
const table = document.querySelector('#attendanceTable');
|
|
const rows = [];
|
|
rows.push(["Activity Name", "User ID", "User Full Name", "Email", "Enrollment Date", "Status", "Attended"]);
|
|
|
|
table.querySelectorAll('tbody tr').forEach(function(row) {
|
|
const rowData = [];
|
|
row.querySelectorAll('td').forEach(function(cell, index) {
|
|
if (index < 7) {
|
|
rowData.push(cell.innerText.trim());
|
|
}
|
|
});
|
|
rows.push(rowData);
|
|
});
|
|
|
|
exportToCsv(generateCsvFileName(), rows);
|
|
});
|
|
|
|
initializeQrCodeScanner();
|
|
|
|
$('#attendanceTable').DataTable({
|
|
paging: true,
|
|
searching: true,
|
|
lengthChange: true,
|
|
pageLength: -1,
|
|
autoWidth: false,
|
|
scrollX: true,
|
|
order: [
|
|
[2, 'asc']
|
|
],
|
|
lengthMenu: [
|
|
[10, 25, 50, 100, 200, 500, -1],
|
|
[10, 25, 50, 100, 200, 500, "All"]
|
|
],
|
|
language: {
|
|
lengthMenu: "Show _MENU_ entries",
|
|
info: "Showing _START_ to _END_ of _TOTAL_ entries",
|
|
infoFiltered: "(filtered from _MAX_ total entries)",
|
|
paginate: {
|
|
previous: "Previous",
|
|
next: "Next"
|
|
}
|
|
},
|
|
// Call applyAttendanceStyles after each table redraw
|
|
drawCallback: function() {
|
|
applyAttendanceStyles();
|
|
}
|
|
});
|
|
|
|
// Auto-hide success message after 5 seconds
|
|
setTimeout(function() {
|
|
$('.notice').fadeOut('slow', function() {
|
|
$(this).remove();
|
|
$('#start-qr-reader').click();
|
|
});
|
|
}, 10000);
|
|
|
|
// Close button logic for notices
|
|
$(document).on('click', '.notice-close', function() {
|
|
$(this).closest('.notice').fadeOut('slow', function() {
|
|
$(this).remove();
|
|
$('#start-qr-reader').click();
|
|
});
|
|
});
|
|
});
|
|
</script>
|
|
|
|
<?php
|
|
return ob_get_clean();
|
|
}
|
|
|
|
add_shortcode('frontend_attendance_control_automatic', 'frontendAttendanceControlAutomatic');
|