diff --git a/app/Config/Routes.php b/app/Config/Routes.php
index b56a59f..de6aa42 100644
--- a/app/Config/Routes.php
+++ b/app/Config/Routes.php
@@ -46,3 +46,4 @@ $routes->get('/admin/dashboard', 'Admin::dashboard');
$routes->post('/check-email', 'Admin::checkEmail');
$routes->get('admin/doctors/data', 'Admin::getDoctors');
$routes->get('admin/patients/data', 'Admin::getPatients');
+$routes->get('/admin/activity-log', 'ActivityLog::index');
diff --git a/app/Controllers/ActivityLog.php b/app/Controllers/ActivityLog.php
new file mode 100644
index 0000000..1f104c9
--- /dev/null
+++ b/app/Controllers/ActivityLog.php
@@ -0,0 +1,28 @@
+requireRole('admin')) {
+ return $r;
+ }
+
+ $logModel = new ActivityLogModel();
+ $filters = [
+ 'action' => trim((string) $this->request->getGet('action')),
+ 'role' => trim((string) $this->request->getGet('role')),
+ 'date_from' => trim((string) $this->request->getGet('date_from')),
+ 'date_to' => trim((string) $this->request->getGet('date_to')),
+ ];
+
+ return view('admin/activity_log', [
+ 'logs' => $logModel->getFiltered($filters),
+ 'filters' => $filters,
+ ]);
+ }
+}
diff --git a/app/Controllers/Admin.php b/app/Controllers/Admin.php
index 43c5268..9ecf7f7 100644
--- a/app/Controllers/Admin.php
+++ b/app/Controllers/Admin.php
@@ -2,6 +2,7 @@
namespace App\Controllers;
+use App\Models\ActivityLogModel;
use App\Models\UserModel;
use App\Models\DoctorModel;
use App\Models\DoctorSpecializationModel;
@@ -107,6 +108,24 @@ class Admin extends BaseController
];
}
+ private function validateDobInput(): bool
+ {
+ $dob = trim((string) $this->request->getPost('dob'));
+
+ if ($dob === '') {
+ return true;
+ }
+
+ $date = \DateTime::createFromFormat('Y-m-d', $dob);
+ $errors = \DateTime::getLastErrors();
+
+ if (! $date || ($errors['warning_count'] ?? 0) > 0 || ($errors['error_count'] ?? 0) > 0 || $date->format('Y-m-d') !== $dob) {
+ return false;
+ }
+
+ return $dob <= date('Y-m-d');
+ }
+
private function getDoctorFormData(int $userId): ?array
{
$userModel = new UserModel();
@@ -405,6 +424,9 @@ class Admin extends BaseController
return redirect()->back()->withInput()->with('error', 'Transaction failed.');
}
+ $logModel = new ActivityLogModel();
+ $logModel->log('create_doctor', "Admin created doctor {$firstName} {$lastName}", 'user', $userId);
+
return redirect()->to(site_url('admin/doctors'))->with('success', 'Doctor account created. Generated password: ' . $generatedPassword);
}
@@ -419,7 +441,7 @@ class Admin extends BaseController
'last_name' => 'required|min_length[2]|max_length[50]|alpha_space',
'email' => 'required|valid_email|is_unique[users.email]',
'phone' => 'required|min_length[10]|max_length[15]',
- 'age' => 'permit_empty|integer|greater_than_equal_to[0]|less_than_equal_to[120]',
+ 'dob' => 'permit_empty|valid_date[Y-m-d]',
'gender' => 'permit_empty|in_list[male,female,other]',
];
@@ -427,6 +449,10 @@ class Admin extends BaseController
return redirect()->back()->withInput();
}
+ if (! $this->validateDobInput()) {
+ return redirect()->back()->withInput()->with('error', 'Please enter a valid date of birth that is not in the future.');
+ }
+
$userModel = new UserModel();
$patientModel = new PatientModel();
$db = \Config\Database::connect();
@@ -434,7 +460,7 @@ class Admin extends BaseController
$firstName = trim((string) $this->request->getPost('first_name'));
$lastName = trim((string) $this->request->getPost('last_name'));
$generatedPassword = $this->generateAccountPassword();
- $ageRaw = (string) $this->request->getPost('age');
+ $dobRaw = trim((string) $this->request->getPost('dob'));
$db->transStart();
@@ -457,7 +483,7 @@ class Admin extends BaseController
$patientRow = [
'user_id' => $userId,
- 'age' => $ageRaw !== '' ? (int) $ageRaw : null,
+ 'dob' => $dobRaw !== '' ? $dobRaw : null,
'gender' => $this->request->getPost('gender') !== '' ? $this->request->getPost('gender') : null,
'phone' => trim((string) $this->request->getPost('phone')),
];
@@ -474,6 +500,9 @@ class Admin extends BaseController
return redirect()->back()->withInput()->with('error', 'Transaction failed.');
}
+ $logModel = new ActivityLogModel();
+ $logModel->log('create_patient', "Admin created patient {$firstName} {$lastName}", 'user', $userId);
+
return redirect()->to(site_url('admin/patients'))->with('success', 'Patient account created. Generated password: ' . $generatedPassword);
}
@@ -556,6 +585,9 @@ class Admin extends BaseController
return redirect()->back()->withInput()->with('error', 'Could not update doctor.');
}
+ $logModel = new ActivityLogModel();
+ $logModel->log('update_doctor', "Admin updated doctor {$firstName} {$lastName}", 'user', $userId);
+
return redirect()->to(site_url('admin/doctors'))->with('success', 'Doctor updated successfully.');
}
@@ -581,7 +613,7 @@ class Admin extends BaseController
'last_name' => 'required|min_length[2]|max_length[50]|alpha_space',
'email' => 'required|valid_email|is_unique[users.email,id,' . $userId . ']',
'phone' => 'required|min_length[10]|max_length[15]',
- 'age' => 'permit_empty|integer|greater_than_equal_to[0]|less_than_equal_to[120]',
+ 'dob' => 'permit_empty|valid_date[Y-m-d]',
'gender' => 'permit_empty|in_list[male,female,other]',
];
@@ -589,13 +621,17 @@ class Admin extends BaseController
return redirect()->back()->withInput();
}
+ if (! $this->validateDobInput()) {
+ return redirect()->back()->withInput()->with('error', 'Please enter a valid date of birth that is not in the future.');
+ }
+
$userModel = new UserModel();
$patientModel = new PatientModel();
$db = \Config\Database::connect();
$firstName = trim((string) $this->request->getPost('first_name'));
$lastName = trim((string) $this->request->getPost('last_name'));
- $ageRaw = (string) $this->request->getPost('age');
+ $dobRaw = trim((string) $this->request->getPost('dob'));
$db->transStart();
@@ -606,7 +642,7 @@ class Admin extends BaseController
]);
$patientModel->update($patientData['patient']['id'], [
- 'age' => $ageRaw !== '' ? (int) $ageRaw : null,
+ 'dob' => $dobRaw !== '' ? $dobRaw : null,
'gender' => $this->request->getPost('gender') !== '' ? $this->request->getPost('gender') : null,
'phone' => trim((string) $this->request->getPost('phone')),
]);
@@ -617,6 +653,9 @@ class Admin extends BaseController
return redirect()->back()->withInput()->with('error', 'Could not update patient.');
}
+ $logModel = new ActivityLogModel();
+ $logModel->log('update_patient', "Admin updated patient {$firstName} {$lastName}", 'user', $userId);
+
return redirect()->to(site_url('admin/patients'))->with('success', 'Patient updated successfully.');
}
public function checkEmail()
diff --git a/app/Controllers/Auth.php b/app/Controllers/Auth.php
index 2affb55..3ef184c 100644
--- a/app/Controllers/Auth.php
+++ b/app/Controllers/Auth.php
@@ -2,6 +2,7 @@
namespace App\Controllers;
+use App\Models\ActivityLogModel;
use App\Models\UserModel;
use App\Models\PatientModel;
@@ -56,6 +57,9 @@ class Auth extends BaseController
'phone' => '+91' . $this->request->getPost('phone'),
]);
+ $logModel = new ActivityLogModel();
+ $logModel->log('register_patient', "Patient account registered: {$firstName} {$lastName}", 'user', (int) $user_id);
+
return redirect()->to(site_url('/'))->with('success', 'Account created. You can log in now.');
}
@@ -91,6 +95,9 @@ class Auth extends BaseController
'login_token' => $loginToken,
]);
+ $logModel = new ActivityLogModel();
+ $logModel->log('login', "User logged in as {$user['role']}", 'user', (int) $user['id']);
+
if ($user['role'] === 'admin') {
return redirect()->to(site_url('admin/dashboard'));
}
@@ -107,8 +114,14 @@ class Auth extends BaseController
public function logout()
{
$userId = (int) session()->get('id');
+ $role = (string) session()->get('role');
$token = (string) session()->get('login_token');
+ if ($userId > 0) {
+ $logModel = new ActivityLogModel();
+ $logModel->log('logout', "User logged out from {$role} panel", 'user', $userId);
+ }
+
if ($userId > 0 && $token !== '') {
$db = \Config\Database::connect();
$db->table('users')
diff --git a/app/Controllers/Doctor.php b/app/Controllers/Doctor.php
index ebe10d7..702ed03 100644
--- a/app/Controllers/Doctor.php
+++ b/app/Controllers/Doctor.php
@@ -3,6 +3,7 @@
namespace App\Controllers;
use App\Models\AppointmentModel;
+use App\Models\ActivityLogModel;
use App\Models\DoctorModel;
use App\Models\DoctorSpecializationModel;
use App\Models\SpecializationModel;
@@ -129,6 +130,9 @@ class Doctor extends BaseController
$doctorSpecializationModel = new DoctorSpecializationModel();
$doctorSpecializationModel->syncDoctorSpecializations($doctor['id'], array_values($specializationMap), (int) session()->get('id'));
+ $logModel = new ActivityLogModel();
+ $logModel->log('update_profile', 'Doctor updated profile details', 'doctor', (int) $doctor['id']);
+
return redirect()->to(site_url('doctor/profile'))->with('success', 'Profile updated.');
}
@@ -193,6 +197,9 @@ class Doctor extends BaseController
$status = AppointmentModel::normalizeStatus($status);
$appointmentModel->update($appointmentId, ['status' => $status]);
+ $logModel = new ActivityLogModel();
+ $logModel->log('update_appointment_status', "Doctor changed appointment status to {$status}", 'appointment', $appointmentId);
+
return redirect()->back()->with('success', 'Appointment updated.');
}
}
diff --git a/app/Controllers/Patient.php b/app/Controllers/Patient.php
index a614224..e85b71f 100644
--- a/app/Controllers/Patient.php
+++ b/app/Controllers/Patient.php
@@ -3,6 +3,7 @@
namespace App\Controllers;
use App\Models\AppointmentModel;
+use App\Models\ActivityLogModel;
use App\Models\PatientModel;
class Patient extends BaseController
@@ -103,6 +104,10 @@ class Patient extends BaseController
return redirect()->back()->withInput()->with('error', 'Could not book appointment.');
}
+ $appointmentId = (int) $appointmentModel->getInsertID();
+ $logModel = new ActivityLogModel();
+ $logModel->log('book_appointment', 'Patient requested a new appointment', 'appointment', $appointmentId);
+
return redirect()->to(site_url('patient/dashboard'))->with('success', 'Appointment requested.');
}
}
diff --git a/app/Database/Migrations/2026-03-29-120000_InitAppointmentSchema.php b/app/Database/Migrations/2026-03-29-120000_InitAppointmentSchema.php
index f62d481..855eea0 100644
--- a/app/Database/Migrations/2026-03-29-120000_InitAppointmentSchema.php
+++ b/app/Database/Migrations/2026-03-29-120000_InitAppointmentSchema.php
@@ -40,7 +40,7 @@ class InitAppointmentSchema extends Migration
$this->forge->addField([
'id' => ['type' => 'INT', 'unsigned' => true, 'auto_increment' => true],
'user_id' => ['type' => 'INT', 'unsigned' => true],
- 'age' => ['type' => 'INT', 'null' => true],
+ 'dob' => ['type' => 'DATE', 'null' => true],
'gender' => ['type' => 'VARCHAR', 'constraint' => 20, 'null' => true],
'phone' => ['type' => 'VARCHAR', 'constraint' => 30, 'null' => true],
]);
diff --git a/app/Database/Migrations/2026-04-14-000000_ReplacePatientAgeWithDob.php b/app/Database/Migrations/2026-04-14-000000_ReplacePatientAgeWithDob.php
new file mode 100644
index 0000000..ce5c6af
--- /dev/null
+++ b/app/Database/Migrations/2026-04-14-000000_ReplacePatientAgeWithDob.php
@@ -0,0 +1,42 @@
+db->getFieldNames('patients');
+
+ if (in_array('dob', $fields, true) === false) {
+ $this->forge->addColumn('patients', [
+ 'dob' => ['type' => 'DATE', 'null' => true, 'after' => 'user_id'],
+ ]);
+ }
+
+ $fields = $this->db->getFieldNames('patients');
+
+ if (in_array('age', $fields, true)) {
+ $this->forge->dropColumn('patients', 'age');
+ }
+ }
+
+ public function down(): void
+ {
+ $fields = $this->db->getFieldNames('patients');
+
+ if (in_array('age', $fields, true) === false) {
+ $this->forge->addColumn('patients', [
+ 'age' => ['type' => 'INT', 'null' => true, 'after' => 'user_id'],
+ ]);
+ }
+
+ $fields = $this->db->getFieldNames('patients');
+
+ if (in_array('dob', $fields, true)) {
+ $this->forge->dropColumn('patients', 'dob');
+ }
+ }
+}
diff --git a/app/Database/Migrations/2026-04-14-170000_DropActivityLogs.php b/app/Database/Migrations/2026-04-14-170000_DropActivityLogs.php
new file mode 100644
index 0000000..914f136
--- /dev/null
+++ b/app/Database/Migrations/2026-04-14-170000_DropActivityLogs.php
@@ -0,0 +1,77 @@
+db->tableExists('activity_logs')) {
+ $this->forge->dropTable('activity_logs', true);
+ }
+ }
+
+ public function down(): void
+ {
+ $this->forge->addField([
+ 'id' => [
+ 'type' => 'INT',
+ 'constraint' => 11,
+ 'unsigned' => true,
+ 'auto_increment' => true,
+ ],
+ 'user_id' => [
+ 'type' => 'INT',
+ 'constraint' => 11,
+ 'unsigned' => true,
+ 'null' => true,
+ ],
+ 'user_role' => [
+ 'type' => 'ENUM',
+ 'constraint' => ['admin', 'doctor', 'patient', 'system'],
+ 'null' => true,
+ ],
+ 'action' => [
+ 'type' => 'VARCHAR',
+ 'constraint' => 100,
+ ],
+ 'description' => [
+ 'type' => 'TEXT',
+ 'null' => true,
+ ],
+ 'target_type' => [
+ 'type' => 'VARCHAR',
+ 'constraint' => 50,
+ 'null' => true,
+ ],
+ 'target_id' => [
+ 'type' => 'INT',
+ 'constraint' => 11,
+ 'unsigned' => true,
+ 'null' => true,
+ ],
+ 'ip_address' => [
+ 'type' => 'VARCHAR',
+ 'constraint' => 45,
+ 'null' => true,
+ ],
+ 'user_agent' => [
+ 'type' => 'VARCHAR',
+ 'constraint' => 255,
+ 'null' => true,
+ ],
+ 'created_at' => [
+ 'type' => 'DATETIME',
+ 'null' => false,
+ ],
+ ]);
+
+ $this->forge->addPrimaryKey('id');
+ $this->forge->addKey('user_id');
+ $this->forge->addKey('action');
+ $this->forge->addKey('created_at');
+ $this->forge->createTable('activity_logs', true);
+ }
+}
diff --git a/app/Database/Migrations/2026-04-14-180000_CreateActivityLogs.php b/app/Database/Migrations/2026-04-14-180000_CreateActivityLogs.php
new file mode 100644
index 0000000..6c8e15e
--- /dev/null
+++ b/app/Database/Migrations/2026-04-14-180000_CreateActivityLogs.php
@@ -0,0 +1,38 @@
+db->tableExists('activity_logs')) {
+ return;
+ }
+
+ $this->forge->addField([
+ 'id' => ['type' => 'INT', 'unsigned' => true, 'auto_increment' => true],
+ 'actor_user_id' => ['type' => 'INT', 'unsigned' => true, 'null' => true],
+ 'actor_role' => ['type' => 'VARCHAR', 'constraint' => 20, 'null' => true],
+ 'action' => ['type' => 'VARCHAR', 'constraint' => 100],
+ 'description' => ['type' => 'TEXT', 'null' => true],
+ 'target_type' => ['type' => 'VARCHAR', 'constraint' => 50, 'null' => true],
+ 'target_id' => ['type' => 'INT', 'unsigned' => true, 'null' => true],
+ 'ip_address' => ['type' => 'VARCHAR', 'constraint' => 45, 'null' => true],
+ 'user_agent' => ['type' => 'VARCHAR', 'constraint' => 255, 'null' => true],
+ 'created_at' => ['type' => 'DATETIME'],
+ ]);
+ $this->forge->addKey('id', true);
+ $this->forge->addKey('actor_user_id');
+ $this->forge->addKey('action');
+ $this->forge->addKey('created_at');
+ $this->forge->createTable('activity_logs', true);
+ }
+
+ public function down(): void
+ {
+ $this->forge->dropTable('activity_logs', true);
+ }
+}
diff --git a/app/Models/ActivityLogModel.php b/app/Models/ActivityLogModel.php
new file mode 100644
index 0000000..719bac8
--- /dev/null
+++ b/app/Models/ActivityLogModel.php
@@ -0,0 +1,79 @@
+insert([
+ 'actor_user_id' => session()->get('id') ? (int) session()->get('id') : null,
+ 'actor_role' => session()->get('role') ?: null,
+ 'action' => $action,
+ 'description' => $description,
+ 'target_type' => $targetType,
+ 'target_id' => $targetId,
+ 'ip_address' => method_exists($request, 'getIPAddress') ? $request->getIPAddress() : null,
+ 'user_agent' => method_exists($request, 'getUserAgent') ? $request->getUserAgent()->getAgentString() : null,
+ 'created_at' => date('Y-m-d H:i:s'),
+ ]);
+ }
+
+ public function getFiltered(array $filters = []): array
+ {
+ $builder = $this->db->table('activity_logs al')
+ ->select("al.*, CONCAT(COALESCE(u.first_name, ''), ' ', COALESCE(u.last_name, '')) AS actor_name, u.email AS actor_email")
+ ->join('users u', 'u.id = al.actor_user_id', 'left');
+
+ if (! empty($filters['action'])) {
+ $builder->like('al.action', $filters['action']);
+ }
+
+ if (! empty($filters['role'])) {
+ $builder->where('al.actor_role', $filters['role']);
+ }
+
+ if (! empty($filters['date_from'])) {
+ $builder->where('DATE(al.created_at) >=', $filters['date_from']);
+ }
+
+ if (! empty($filters['date_to'])) {
+ $builder->where('DATE(al.created_at) <=', $filters['date_to']);
+ }
+
+ return $builder
+ ->orderBy('al.created_at', 'DESC')
+ ->get()
+ ->getResultArray();
+ }
+
+ public function getRecent(int $limit = 8): array
+ {
+ return $this->db->table('activity_logs')
+ ->orderBy('created_at', 'DESC')
+ ->limit($limit)
+ ->get()
+ ->getResultArray();
+ }
+}
diff --git a/app/Models/DoctorModel.php b/app/Models/DoctorModel.php
index 5d88ce6..0ba8db1 100644
--- a/app/Models/DoctorModel.php
+++ b/app/Models/DoctorModel.php
@@ -78,7 +78,7 @@ class DoctorModel extends Model
public function getLatestDoctors(int $limit = 5): array
{
- return $this->select("TRIM(CONCAT(COALESCE(users.first_name, ''), ' ', COALESCE(users.last_name, ''))) as name, doctors.specialization")
+ return $this->select("COALESCE(NULLIF(users.formatted_user_id, ''), CONCAT('DOC', LPAD(users.id, 7, '0'))) as formatted_user_id, TRIM(CONCAT(COALESCE(users.first_name, ''), ' ', COALESCE(users.last_name, ''))) as name, doctors.specialization")
->join('users', 'users.id = doctors.user_id')
->orderBy('doctors.id', 'DESC')
->findAll($limit);
diff --git a/app/Models/PatientModel.php b/app/Models/PatientModel.php
index 41d168f..c6a6436 100644
--- a/app/Models/PatientModel.php
+++ b/app/Models/PatientModel.php
@@ -12,7 +12,7 @@ class PatientModel extends Model
protected $returnType = 'array';
protected $useSoftDeletes = false;
protected $protectFields = true;
- protected $allowedFields = ['user_id','age','gender','phone'];
+ protected $allowedFields = ['user_id','dob','gender','phone'];
protected bool $allowEmptyInserts = false;
protected bool $updateOnlyChanged = true;
@@ -76,7 +76,7 @@ class PatientModel extends Model
public function getLatestPatients(int $limit = 5): array
{
- return $this->select("TRIM(CONCAT(COALESCE(users.first_name, ''), ' ', COALESCE(users.last_name, ''))) as name, patients.phone")
+ return $this->select("CASE WHEN users.formatted_user_id IS NULL OR users.formatted_user_id = '' OR users.formatted_user_id LIKE 'PHY%' THEN CONCAT('PAT', LPAD(users.id, 7, '0')) ELSE users.formatted_user_id END as formatted_user_id, TRIM(CONCAT(COALESCE(users.first_name, ''), ' ', COALESCE(users.last_name, ''))) as name, patients.phone")
->join('users', 'users.id = patients.user_id')
->orderBy('patients.id', 'DESC')
->findAll($limit);
diff --git a/app/Views/admin/activity_log.php b/app/Views/admin/activity_log.php
new file mode 100644
index 0000000..0a68111
--- /dev/null
+++ b/app/Views/admin/activity_log.php
@@ -0,0 +1,149 @@
+
+
+
+
+
+ Activity Log
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ | Time |
+ Actor |
+ Role |
+ Action |
+ Description |
+ Target |
+ IP |
+
+
+
+
+
+ | No activity found. |
+
+
+
+
+ | = esc($log['created_at']) ?> |
+
+ = esc(trim((string) ($log['actor_name'] ?? ''))) !== '' ? esc(trim((string) $log['actor_name'])) : 'System' ?>
+ = esc($log['actor_email'] ?? '') ?>
+ |
+ = esc($log['actor_role'] ?? '-') ?> |
+ = esc($log['action']) ?> |
+ = esc($log['description']) ?> |
+ = esc(($log['target_type'] ?? '-') . ((isset($log['target_id']) && $log['target_id'] !== null) ? ' #' . $log['target_id'] : '')) ?> |
+ = esc($log['ip_address'] ?? '-') ?> |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/Views/admin/add_doctor.php b/app/Views/admin/add_doctor.php
index 4b43c50..cb395fb 100644
--- a/app/Views/admin/add_doctor.php
+++ b/app/Views/admin/add_doctor.php
@@ -28,7 +28,16 @@ if (! is_array($oldSpecializations)) {
Main
Dashboard
Manage
- Doctors
+
Appointments
- Add Doctor
+ Activity Log
diff --git a/app/Views/admin/add_patient.php b/app/Views/admin/add_patient.php
index 68cf632..f83c42e 100644
--- a/app/Views/admin/add_patient.php
+++ b/app/Views/admin/add_patient.php
@@ -7,6 +7,7 @@
+
@@ -24,7 +25,16 @@
Main
Dashboard
Manage
- Doctors
+
Appointments
- Add Doctor
+ Activity Log
@@ -113,39 +123,17 @@
= validation_show_error('phone') ?>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - At least 8 characters
- - One uppercase letter
- - One lowercase letter
- - One number
- - One special character
-
-
+
+ = view('components/password_field', ['id' => 'password']) ?>
+
-
-
- = validation_show_error('age') ?>
+
+
+ = validation_show_error('dob') ?>
@@ -218,82 +206,6 @@ function checkEmail() {
})
.catch(error => console.log(error));
}
-const password = document.getElementById("password");
-
-password.addEventListener("input", function () {
- const val = password.value;
-
- const length = document.getElementById("length");
- const upper = document.getElementById("uppercase");
- const lower = document.getElementById("lowercase");
- const number = document.getElementById("number");
- const special = document.getElementById("special");
- const strengthText = document.getElementById("strengthText");
-
- let strength = 0;
-
- // Rules check
- if (val.length >= 8) {
- length.classList.replace("text-danger", "text-success");
- strength++;
- } else {
- length.classList.replace("text-success", "text-danger");
- }
-
- if (/[A-Z]/.test(val)) {
- upper.classList.replace("text-danger", "text-success");
- strength++;
- } else {
- upper.classList.replace("text-success", "text-danger");
- }
-
- if (/[a-z]/.test(val)) {
- lower.classList.replace("text-danger", "text-success");
- strength++;
- } else {
- lower.classList.replace("text-success", "text-danger");
- }
-
- if (/[0-9]/.test(val)) {
- number.classList.replace("text-danger", "text-success");
- strength++;
- } else {
- number.classList.replace("text-success", "text-danger");
- }
-
- if (/[^A-Za-z0-9]/.test(val)) {
- special.classList.replace("text-danger", "text-success");
- strength++;
- } else {
- special.classList.replace("text-success", "text-danger");
- }
-
- // Strength display
- if (strength <= 2) {
- strengthText.innerHTML = "Weak Password ❌";
- strengthText.className = "text-danger";
- } else if (strength <= 4) {
- strengthText.innerHTML = "Medium Password ⚠️";
- strengthText.className = "text-warning";
- } else {
- strengthText.innerHTML = "Strong Password ✅";
- strengthText.className = "text-success";
- }
-});
-function togglePassword() {
- const password = document.getElementById("password");
- const icon = document.getElementById("eyeIcon");
-
- if (password.type === "password") {
- password.type = "text";
- icon.classList.remove("fa-eye");
- icon.classList.add("fa-eye-slash");
- } else {
- password.type = "password";
- icon.classList.remove("fa-eye-slash");
- icon.classList.add("fa-eye");
- }
-}