344 lines
16 KiB
PHP
344 lines
16 KiB
PHP
<?php
|
|
require_once __DIR__ . '/includes/header.php';
|
|
require_once __DIR__ . '/mail/MailService.php';
|
|
|
|
if (!canView('internal')) {
|
|
redirect('index.php');
|
|
}
|
|
|
|
$user_id = $_SESSION['user_id'];
|
|
$success = '';
|
|
$error = '';
|
|
|
|
// Handle composing a new message
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'compose') {
|
|
if (!canAdd('internal')) {
|
|
$error = 'عذراً، ليس لديك الصلاحية لإرسال رسائل';
|
|
} else {
|
|
$recipient_id = $_POST['recipient_id'] ?? null;
|
|
$subject = $_POST['subject'] ?? '';
|
|
$description = $_POST['description'] ?? '';
|
|
$type = 'internal';
|
|
$ref_no = generateRefNo('internal');
|
|
$date_registered = date('Y-m-d');
|
|
$default_status_id = db()->query("SELECT id FROM mailbox_statuses WHERE is_default = 1 LIMIT 1")->fetchColumn() ?: 1;
|
|
|
|
if ($recipient_id && $subject) {
|
|
$should_notify = false;
|
|
$recipient_email = '';
|
|
try {
|
|
db()->beginTransaction();
|
|
$stmt = db()->prepare("INSERT INTO internal_mail (ref_no, date_registered, subject, description, status_id, assigned_to, created_by) VALUES (?, ?, ?, ?, ?, ?, ?)");
|
|
$stmt->execute([$ref_no, $date_registered, $subject, $description, $default_status_id, $recipient_id, $user_id]);
|
|
$mail_id = db()->lastInsertId();
|
|
|
|
// Handle Attachments
|
|
if (!empty($_FILES['attachments']['name'][0])) {
|
|
$upload_dir = 'uploads/attachments/';
|
|
if (!is_dir($upload_dir)) mkdir($upload_dir, 0777, true);
|
|
|
|
foreach ($_FILES['attachments']['name'] as $key => $name) {
|
|
if ($_FILES['attachments']['error'][$key] === 0) {
|
|
$file_name = time() . '_' . basename($name);
|
|
$target_path = $upload_dir . $file_name;
|
|
if (move_uploaded_file($_FILES['attachments']['tmp_name'][$key], $target_path)) {
|
|
$stmt = db()->prepare("INSERT INTO internal_attachments (mail_id, display_name, file_path, file_name, file_size) VALUES (?, ?, ?, ?, ?)");
|
|
$stmt->execute([$mail_id, $name, $target_path, $name, $_FILES['attachments']['size'][$key]]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Get recipient info for notification
|
|
$stmt_recp = db()->prepare("SELECT full_name, email FROM users WHERE id = ?");
|
|
$stmt_recp->execute([$recipient_id]);
|
|
$recipient = $stmt_recp->fetch();
|
|
|
|
if ($recipient && !empty($recipient['email'])) {
|
|
$should_notify = true;
|
|
$recipient_email = $recipient['email'];
|
|
}
|
|
|
|
db()->commit();
|
|
|
|
// Notify after commit
|
|
if ($should_notify) {
|
|
$email_subject = "رسالة داخلية جديدة من " . $_SESSION['name'];
|
|
$htmlBody = "
|
|
<div dir='rtl' style='font-family: Arial, sans-serif;'>
|
|
<h3>لديك رسالة داخلية جديدة</h3>
|
|
<p><strong>الموضوع:</strong> " . htmlspecialchars($subject) . "</p>
|
|
<p><strong>المرسل:</strong> " . htmlspecialchars($_SESSION['name']) . "</p>
|
|
<hr>
|
|
<div>" . $description . "</div>
|
|
<br>
|
|
<p>يمكنك الرد من خلال النظام.</p>
|
|
</div>
|
|
";
|
|
MailService::sendMail($recipient_email, $email_subject, $htmlBody);
|
|
}
|
|
|
|
$_SESSION['success'] = 'تم إرسال الرسالة بنجاح';
|
|
redirect('internal_outbox.php');
|
|
} catch (PDOException $e) {
|
|
if (db()->inTransaction()) db()->rollBack();
|
|
$error = 'حدث خطأ: ' . $e->getMessage();
|
|
}
|
|
} else {
|
|
$error = 'يرجى اختيار المرسل إليه وكتابة الموضوع';
|
|
}
|
|
}
|
|
}
|
|
|
|
// Get session messages
|
|
if (isset($_SESSION['success'])) {
|
|
$success = $_SESSION['success'];
|
|
unset($_SESSION['success']);
|
|
}
|
|
if (isset($_SESSION['error'])) {
|
|
$error = $_SESSION['error'];
|
|
unset($_SESSION['error']);
|
|
}
|
|
|
|
// Search and filtering
|
|
$search = $_GET['search'] ?? '';
|
|
$page = isset($_GET['page']) && is_numeric($_GET['page']) ? (int)$_GET['page'] : 1;
|
|
$limit = 10;
|
|
$offset = ($page - 1) * $limit;
|
|
|
|
$params = [$user_id];
|
|
$where = "1=1 AND m.created_by = ?";
|
|
|
|
if ($search) {
|
|
$where .= " AND (m.subject LIKE ? OR m.description LIKE ? OR u_recp.full_name LIKE ?)";
|
|
$params[] = "%$search%";
|
|
$params[] = "%$search%";
|
|
$params[] = "%$search%";
|
|
}
|
|
|
|
// Get total for pagination
|
|
$count_stmt = db()->prepare("SELECT COUNT(*) FROM internal_mail m LEFT JOIN users u_recp ON m.assigned_to = u_recp.id WHERE $where");
|
|
$count_stmt->execute($params);
|
|
$total_records = $count_stmt->fetchColumn();
|
|
$total_pages = ceil($total_records / $limit);
|
|
|
|
// Fetch messages
|
|
$query = "SELECT m.*, u_recp.full_name as recipient_name, u_recp.profile_image as recipient_image, s.name as status_name, s.color as status_color
|
|
FROM internal_mail m
|
|
LEFT JOIN users u_recp ON m.assigned_to = u_recp.id
|
|
LEFT JOIN mailbox_statuses s ON m.status_id = s.id
|
|
WHERE $where
|
|
ORDER BY m.created_at DESC
|
|
LIMIT $limit OFFSET $offset";
|
|
|
|
$stmt = db()->prepare($query);
|
|
$stmt->execute($params);
|
|
$messages = $stmt->fetchAll();
|
|
|
|
// Users for compose
|
|
$users_list = db()->prepare("SELECT id, full_name, username FROM users WHERE id != ? ORDER BY full_name");
|
|
$users_list->execute([$user_id]);
|
|
$users_list = $users_list->fetchAll();
|
|
|
|
function getStatusBadgeInternal($mail) {
|
|
$status_name = $mail['status_name'] ?? 'received';
|
|
$status_color = $mail['status_color'] ?? '#6c757d';
|
|
|
|
$display_name = $status_name;
|
|
if ($status_name == 'received') $display_name = 'مرسلة';
|
|
if ($status_name == 'in_progress') $display_name = 'قيد المتابعة';
|
|
if ($status_name == 'closed') $display_name = 'مؤرشفة';
|
|
|
|
return '<span class="badge" style="background-color: ' . $status_color . ';">' . htmlspecialchars($display_name) . '</span>';
|
|
}
|
|
?>
|
|
|
|
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
|
<h1 class="h2"><i class="fas fa-paper-plane me-2 text-success"></i> بريد الموظفين - الصادر</h1>
|
|
<div class="btn-toolbar mb-2 mb-md-0">
|
|
<?php if (canAdd('internal')): ?>
|
|
<button type="button" class="btn btn-primary shadow-sm" data-bs-toggle="modal" data-bs-target="#composeModal">
|
|
<i class="fas fa-plus-circle me-1"></i> إنشاء رسالة جديدة
|
|
</button>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
|
|
<?php if ($success): ?>
|
|
<div class="alert alert-success alert-dismissible fade show" role="alert">
|
|
<?= htmlspecialchars($success) ?>
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<?php if ($error): ?>
|
|
<div class="alert alert-danger alert-dismissible fade show" role="alert">
|
|
<?= htmlspecialchars($error) ?>
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<div class="card shadow-sm border-0 mb-4">
|
|
<div class="card-header bg-white py-3">
|
|
<form class="row g-3">
|
|
<div class="col-md-6">
|
|
<div class="input-group">
|
|
<span class="input-group-text bg-light border-end-0"><i class="fas fa-search text-muted"></i></span>
|
|
<input type="text" name="search" class="form-control border-start-0" placeholder="بحث في الموضوع، الرسالة، أو المستلم..." value="<?= htmlspecialchars($search) ?>">
|
|
<button type="submit" class="btn btn-primary">بحث</button>
|
|
</div>
|
|
</div>
|
|
<?php if ($search): ?>
|
|
<div class="col-auto">
|
|
<a href="internal_outbox.php" class="btn btn-outline-secondary">إعادة تعيين</a>
|
|
</div>
|
|
<?php endif; ?>
|
|
</form>
|
|
</div>
|
|
<div class="card-body p-0">
|
|
<div class="table-responsive">
|
|
<table class="table table-hover align-middle mb-0">
|
|
<thead class="bg-light">
|
|
<tr>
|
|
<th class="ps-4">المستلم</th>
|
|
<th>الموضوع</th>
|
|
<th>التاريخ</th>
|
|
<th>الحالة</th>
|
|
<th class="pe-4 text-center">الإجراء</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php if ($messages): ?>
|
|
<?php foreach ($messages as $msg): ?>
|
|
<tr style="cursor: pointer;" onclick="window.location='view_mail.php?id=<?= $msg['id'] ?>'">
|
|
<td class="ps-4">
|
|
<div class="d-flex align-items-center">
|
|
<?php if ($msg['recipient_image']): ?>
|
|
<img src="<?= $msg['recipient_image'] ?>" class="rounded-circle me-2" width="32" height="32" style="object-fit: cover;">
|
|
<?php else: ?>
|
|
<div class="rounded-circle bg-light d-flex align-items-center justify-content-center me-2" width="32" height="32" style="width:32px; height:32px;">
|
|
<i class="fas fa-user text-secondary small"></i>
|
|
</div>
|
|
<?php endif; ?>
|
|
<span class="fw-bold"><?= htmlspecialchars($msg['recipient_name'] ?: 'مستخدم غير معروف') ?></span>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<div class="fw-bold"><?= htmlspecialchars($msg['subject']) ?></div>
|
|
<small class="text-muted text-truncate d-inline-block" style="max-width: 300px;">
|
|
<?= strip_tags($msg['description']) ?>
|
|
</small>
|
|
</td>
|
|
<td>
|
|
<small class="text-muted"><?= date('Y-m-d H:i', strtotime($msg['created_at'])) ?></small>
|
|
</td>
|
|
<td><?= getStatusBadgeInternal($msg) ?></td>
|
|
<td class="pe-4 text-center">
|
|
<a href="view_mail.php?id=<?= $msg['id'] ?>" class="btn btn-sm btn-light rounded-pill px-3">عرض</a>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
<?php else: ?>
|
|
<tr>
|
|
<td colspan="5" class="text-center py-5 text-muted">
|
|
<i class="fas fa-paper-plane fa-3x mb-3 opacity-25"></i>
|
|
<p>لم يتم إرسال أي رسائل حالياً</p>
|
|
</td>
|
|
</tr>
|
|
<?php endif; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<?php if ($total_pages > 1): ?>
|
|
<div class="card-footer bg-white border-0 py-3">
|
|
<nav>
|
|
<ul class="pagination justify-content-center mb-0">
|
|
<?php for ($i = 1; $i <= $total_pages; $i++): ?>
|
|
<li class="page-item <?= ($page == $i) ? 'active' : '' ?>">
|
|
<a class="page-link" href="?page=<?= $i ?><?= $search ? '&search='.urlencode($search) : '' ?>"><?= $i ?></a>
|
|
</li>
|
|
<?php endfor; ?>
|
|
</ul>
|
|
</nav>
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<!-- Compose Modal -->
|
|
<div class="modal fade" id="composeModal" tabindex="-1" aria-labelledby="composeModalLabel" aria-hidden="true">
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content border-0 shadow-lg">
|
|
<div class="modal-header bg-dark text-white border-0">
|
|
<h5 class="modal-title fw-bold" id="composeModalLabel">إنشاء رسالة جديدة للموظفين</h5>
|
|
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
<form id="composeForm" method="POST" enctype="multipart/form-data">
|
|
<div class="modal-body p-4">
|
|
<input type="hidden" name="action" value="compose">
|
|
<div class="row g-3">
|
|
<div class="col-md-12">
|
|
<label class="form-label fw-bold">إلى <span class="text-danger">*</span></label>
|
|
<select name="recipient_id" class="form-select border-2" required>
|
|
<option value="">-- اختر الموظف --</option>
|
|
<?php foreach ($users_list as $u): ?>
|
|
<option value="<?= $u['id'] ?>"><?= htmlspecialchars($u['full_name'] . ' (@' . $u['username'] . ')') ?></option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-12">
|
|
<label class="form-label fw-bold">الموضوع <span class="text-danger">*</span></label>
|
|
<input type="text" name="subject" class="form-control border-2" required placeholder="عنوان الرسالة">
|
|
</div>
|
|
<div class="col-md-12">
|
|
<label class="form-label fw-bold">الرسالة</label>
|
|
<textarea name="description" id="composeEditor" class="form-control border-2" rows="10"></textarea>
|
|
</div>
|
|
<div class="col-md-12">
|
|
<label class="form-label fw-bold">المرفقات</label>
|
|
<input type="file" name="internal_attachments[]" class="form-control border-2" multiple>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer border-top-0 bg-light p-3">
|
|
<button type="button" class="btn btn-secondary px-4 py-2" data-bs-dismiss="modal">إلغاء</button>
|
|
<button type="submit" class="btn btn-primary px-5 py-2 fw-bold">إرسال الآن <i class="fas fa-paper-plane ms-2"></i></button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
let composeEditor;
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
if (typeof ClassicEditor !== 'undefined') {
|
|
ClassicEditor
|
|
.create(document.querySelector('#composeEditor'), {
|
|
language: 'ar',
|
|
toolbar: ['heading', '|', 'bold', 'italic', 'link', 'bulletedList', 'numberedList', 'blockQuote', 'undo', 'redo'],
|
|
direction: 'rtl'
|
|
})
|
|
.then(editor => {
|
|
composeEditor = editor;
|
|
// Force RTL style on editable area
|
|
editor.ui.view.editable.element.style.direction = 'rtl';
|
|
editor.ui.view.editable.element.style.textAlign = 'right';
|
|
})
|
|
.catch(error => {
|
|
console.error(error);
|
|
});
|
|
}
|
|
|
|
document.getElementById('composeForm').addEventListener('submit', function() {
|
|
if (composeEditor) composeEditor.updateSourceElement();
|
|
});
|
|
|
|
<?php if (isset($_GET['action']) && $_GET['action'] === 'compose'): ?>
|
|
var myModal = new bootstrap.Modal(document.getElementById('composeModal'));
|
|
myModal.show();
|
|
<?php endif; ?>
|
|
});
|
|
</script>
|
|
|
|
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|