Require rejection reason and move approve/reject buttons inside manager detail view
This commit is contained in:
@@ -875,8 +875,6 @@ async function openAdminDashboard(){
|
|||||||
<div style="font-size:12px;color:#64748b;margin-top:6px">${escapeHtml(item.created_at || '')}</div>
|
<div style="font-size:12px;color:#64748b;margin-top:6px">${escapeHtml(item.created_at || '')}</div>
|
||||||
<div style="display:flex;gap:8px;margin-top:10px">
|
<div style="display:flex;gap:8px;margin-top:10px">
|
||||||
<button type="button" class="btn-secondary" onclick="openPendingManagerDetailByIndex(${index})">Detail</button>
|
<button type="button" class="btn-secondary" onclick="openPendingManagerDetailByIndex(${index})">Detail</button>
|
||||||
<button type="button" class="btn-destructive" onclick="rejectPendingUser('${escapeHtml(item.id)}')">Tolak</button>
|
|
||||||
<button type="button" class="btn-primary" onclick="approvePendingUser('${escapeHtml(item.id)}')">Setujui</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`).join('');
|
`).join('');
|
||||||
@@ -892,16 +890,25 @@ async function approvePendingUser(id){
|
|||||||
const jr = await resp.json().catch(()=>null);
|
const jr = await resp.json().catch(()=>null);
|
||||||
if(!resp.ok || !jr || !jr.success){ showToast('Gagal menyetujui user', 'error', 4000); return; }
|
if(!resp.ok || !jr || !jr.success){ showToast('Gagal menyetujui user', 'error', 4000); return; }
|
||||||
showToast('User disetujui', 'success', 3000);
|
showToast('User disetujui', 'success', 3000);
|
||||||
|
closePendingManagerDetail();
|
||||||
openAdminDashboard();
|
openAdminDashboard();
|
||||||
}catch(e){ console.error(e); showToast('Gagal menyetujui user', 'error', 4000); }
|
}catch(e){ console.error(e); showToast('Gagal menyetujui user', 'error', 4000); }
|
||||||
}
|
}
|
||||||
|
|
||||||
async function rejectPendingUser(id){
|
async function rejectPendingUser(id){
|
||||||
|
const reason = prompt("Masukkan alasan penolakan:");
|
||||||
|
if (reason === null) return; // user cancelled
|
||||||
|
const trimmedReason = reason.trim();
|
||||||
|
if (!trimmedReason) {
|
||||||
|
showToast("Alasan penolakan wajib diisi!", "error", 4000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
try{
|
try{
|
||||||
const resp = await fetch('src/api/admin/reject_user.php', { method: 'POST', headers: buildHeaders(), body: JSON.stringify({ id: id }), credentials: 'same-origin' });
|
const resp = await fetch('src/api/admin/reject_user.php', { method: 'POST', headers: buildHeaders(), body: JSON.stringify({ id: id, reason: trimmedReason }), credentials: 'same-origin' });
|
||||||
const jr = await resp.json().catch(()=>null);
|
const jr = await resp.json().catch(()=>null);
|
||||||
if(!resp.ok || !jr || !jr.success){ showToast('Gagal menolak user', 'error', 4000); return; }
|
if(!resp.ok || !jr || !jr.success){ showToast('Gagal menolak user', 'error', 4000); return; }
|
||||||
showToast('User ditolak', 'success', 3000);
|
showToast('User ditolak', 'success', 3000);
|
||||||
|
closePendingManagerDetail();
|
||||||
openAdminDashboard();
|
openAdminDashboard();
|
||||||
}catch(e){ console.error(e); showToast('Gagal menolak user', 'error', 4000); }
|
}catch(e){ console.error(e); showToast('Gagal menolak user', 'error', 4000); }
|
||||||
}
|
}
|
||||||
@@ -2413,6 +2420,10 @@ function openPendingManagerDetail(u){
|
|||||||
<div style="font-size:12px;color:#64748b">Bukti Organisasi</div>
|
<div style="font-size:12px;color:#64748b">Bukti Organisasi</div>
|
||||||
<div style="font-weight:700;color:#0f172a;margin-top:8px">${proofPreview}</div>
|
<div style="font-weight:700;color:#0f172a;margin-top:8px">${proofPreview}</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div style="display:flex;justify-content:flex-end;gap:8px;margin-top:18px;padding-top:12px;border-top:1px solid #e2e8f0">
|
||||||
|
<button type="button" class="btn-destructive" style="padding:8px 16px;font-size:14px" onclick="rejectPendingUser('${escapeHtml(u.id)}')">Tolak</button>
|
||||||
|
<button type="button" class="btn-primary" style="padding:8px 16px;font-size:14px" onclick="approvePendingUser('${escapeHtml(u.id)}')">Setujui</button>
|
||||||
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
modal.classList.remove('hidden');
|
modal.classList.remove('hidden');
|
||||||
|
|||||||
@@ -1,21 +1,60 @@
|
|||||||
<?php
|
<?php
|
||||||
include __DIR__ . '/../../config/koneksi.php';
|
include __DIR__ . '/../../config/koneksi.php';
|
||||||
include __DIR__ . '/../../config/auth.php';
|
include __DIR__ . '/../../config/auth.php';
|
||||||
|
include_once __DIR__ . '/../auth/mail_helper.php';
|
||||||
header('Content-Type: application/json; charset=utf-8');
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
|
|
||||||
require_role('admin');
|
require_role('admin');
|
||||||
|
|
||||||
|
// Ensure column exists
|
||||||
|
try {
|
||||||
|
$conn->query("ALTER TABLE users ADD COLUMN IF NOT EXISTS rejection_reason TEXT NULL");
|
||||||
|
} catch(Exception $e){}
|
||||||
|
|
||||||
$data = json_decode(file_get_contents('php://input'), true);
|
$data = json_decode(file_get_contents('php://input'), true);
|
||||||
$id = isset($data['id']) ? intval($data['id']) : 0;
|
$id = isset($data['id']) ? intval($data['id']) : 0;
|
||||||
if(!$id){ http_response_code(400); echo json_encode(['success'=>false,'error'=>'missing_id']); exit; }
|
if(!$id){ http_response_code(400); echo json_encode(['success'=>false,'error'=>'missing_id']); exit; }
|
||||||
|
|
||||||
$st = $conn->prepare('UPDATE users SET status = "rejected", approved_by = ?, approved_at = NOW() WHERE id = ?');
|
$reason = isset($data['reason']) ? trim($data['reason']) : '';
|
||||||
|
|
||||||
|
// 1. Fetch user email and name first
|
||||||
|
$email = null;
|
||||||
|
$name = null;
|
||||||
|
$uStmt = $conn->prepare("SELECT email, name FROM users WHERE id = ?");
|
||||||
|
if($uStmt){
|
||||||
|
$uStmt->bind_param('i', $id);
|
||||||
|
$uStmt->execute();
|
||||||
|
$uRes = $uStmt->get_result();
|
||||||
|
$uRow = $uRes ? $uRes->fetch_assoc() : null;
|
||||||
|
if($uRow){
|
||||||
|
$email = $uRow['email'];
|
||||||
|
$name = $uRow['name'];
|
||||||
|
}
|
||||||
|
$uStmt->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Perform the update
|
||||||
|
$st = $conn->prepare('UPDATE users SET status = "rejected", rejection_reason = ?, approved_by = ?, approved_at = NOW() WHERE id = ?');
|
||||||
if(!$st){ http_response_code(500); echo json_encode(['success'=>false,'error'=>$conn->error]); exit; }
|
if(!$st){ http_response_code(500); echo json_encode(['success'=>false,'error'=>$conn->error]); exit; }
|
||||||
$adminId = intval(get_current_user_info()['id']);
|
$adminId = intval(get_current_user_info()['id']);
|
||||||
$st->bind_param('ii', $adminId, $id);
|
$st->bind_param('sii', $reason, $adminId, $id);
|
||||||
$res = $st->execute();
|
$res = $st->execute();
|
||||||
$st->close();
|
$st->close();
|
||||||
if(!$res){ http_response_code(500); echo json_encode(['success'=>false,'error'=>$conn->error]); exit; }
|
if(!$res){ http_response_code(500); echo json_encode(['success'=>false,'error'=>$conn->error]); exit; }
|
||||||
|
|
||||||
|
// 3. Send email notification if user has email
|
||||||
|
if($email){
|
||||||
|
try {
|
||||||
|
$subject = 'Pendaftaran Pengelola Ditolak - WebGIS';
|
||||||
|
$message = "Halo " . ($name ? $name : 'Pengelola') . ",\n\n" .
|
||||||
|
"Pendaftaran akun pengelola Anda pada sistem WebGIS Poverty Mapping tidak disetujui oleh administrator.\n\n" .
|
||||||
|
"Alasan penolakan:\n" . ($reason ? $reason : '-') . "\n\n" .
|
||||||
|
"Terima kasih.";
|
||||||
|
send_mail_notify($email, $subject, $message, false);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
error_log("Failed to send rejection email: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
echo json_encode(['success'=>true]);
|
echo json_encode(['success'=>true]);
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -1,15 +1,37 @@
|
|||||||
<?php
|
<?php
|
||||||
include __DIR__ . '/../../config/koneksi.php';
|
include __DIR__ . '/../../config/koneksi.php';
|
||||||
include __DIR__ . '/../../config/auth.php';
|
include __DIR__ . '/../../config/auth.php';
|
||||||
|
include_once __DIR__ . '/mail_helper.php';
|
||||||
header('Content-Type: application/json; charset=utf-8');
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
|
|
||||||
$admin = require_bearer_login();
|
$admin = require_bearer_login();
|
||||||
if(!isset($admin['role']) || $admin['role'] !== 'admin'){ http_response_code(403); echo json_encode(['success'=>false,'error'=>'forbidden']); exit; }
|
if(!isset($admin['role']) || $admin['role'] !== 'admin'){ http_response_code(403); echo json_encode(['success'=>false,'error'=>'forbidden']); exit; }
|
||||||
|
|
||||||
|
// Ensure column exists
|
||||||
|
try {
|
||||||
|
$conn->query("ALTER TABLE users ADD COLUMN IF NOT EXISTS rejection_reason TEXT NULL");
|
||||||
|
} catch(Exception $e){}
|
||||||
|
|
||||||
$data = json_decode(file_get_contents('php://input'), true);
|
$data = json_decode(file_get_contents('php://input'), true);
|
||||||
if(!$data || !isset($data['id'])){ http_response_code(400); echo json_encode(['success'=>false,'error'=>'missing_id']); exit; }
|
if(!$data || !isset($data['id'])){ http_response_code(400); echo json_encode(['success'=>false,'error'=>'missing_id']); exit; }
|
||||||
$id = intval($data['id']);
|
$id = intval($data['id']);
|
||||||
$reason = isset($data['reason']) ? $data['reason'] : null;
|
$reason = isset($data['reason']) ? trim($data['reason']) : '';
|
||||||
|
|
||||||
|
// 1. Fetch user email and name first
|
||||||
|
$email = null;
|
||||||
|
$name = null;
|
||||||
|
$uStmt = $conn->prepare("SELECT email, name FROM users WHERE id = ?");
|
||||||
|
if($uStmt){
|
||||||
|
$uStmt->bind_param('i', $id);
|
||||||
|
$uStmt->execute();
|
||||||
|
$uRes = $uStmt->get_result();
|
||||||
|
$uRow = $uRes ? $uRes->fetch_assoc() : null;
|
||||||
|
if($uRow){
|
||||||
|
$email = $uRow['email'];
|
||||||
|
$name = $uRow['name'];
|
||||||
|
}
|
||||||
|
$uStmt->close();
|
||||||
|
}
|
||||||
|
|
||||||
$st = $conn->prepare('UPDATE users SET status = ?, rejection_reason = ?, approved_by = ?, approved_at = NOW() WHERE id = ? AND role = "manager"');
|
$st = $conn->prepare('UPDATE users SET status = ?, rejection_reason = ?, approved_by = ?, approved_at = NOW() WHERE id = ? AND role = "manager"');
|
||||||
if(!$st){ http_response_code(500); echo json_encode(['success'=>false,'error'=>$conn->error]); exit; }
|
if(!$st){ http_response_code(500); echo json_encode(['success'=>false,'error'=>$conn->error]); exit; }
|
||||||
@@ -17,5 +39,18 @@ $status = 'rejected'; $adminId = intval($admin['id']); $st->bind_param('ssii', $
|
|||||||
$res = $st->execute(); $st->close();
|
$res = $st->execute(); $st->close();
|
||||||
if(!$res){ http_response_code(500); echo json_encode(['success'=>false,'error'=>$conn->error]); exit; }
|
if(!$res){ http_response_code(500); echo json_encode(['success'=>false,'error'=>$conn->error]); exit; }
|
||||||
|
|
||||||
|
if($email){
|
||||||
|
try {
|
||||||
|
$subject = 'Pendaftaran Pengelola Ditolak - WebGIS';
|
||||||
|
$message = "Halo " . ($name ? $name : 'Pengelola') . ",\n\n" .
|
||||||
|
"Pendaftaran akun pengelola Anda pada sistem WebGIS Poverty Mapping tidak disetujui oleh administrator.\n\n" .
|
||||||
|
"Alasan penolakan:\n" . ($reason ? $reason : '-') . "\n\n" .
|
||||||
|
"Terima kasih.";
|
||||||
|
send_mail_notify($email, $subject, $message, false);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
error_log("Failed to send rejection email: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
echo json_encode(['success'=>true]);
|
echo json_encode(['success'=>true]);
|
||||||
?>
|
?>
|
||||||
Reference in New Issue
Block a user