Build Complaint Management System with PHP & MySQL

In our previous tutorial, we have explained how to develop AI ChatBot using ChatGPT and PHP. In this tutorial, we are going to develop Complaint Management System with PHP & MySQL.

Complaint management system is an online system that used to allow users make complaints, manage complaints, categorize complaints etc.

Here in this tutorial, we will develop a complaint management system using PHP and MySQL. The system will consist user section and admin section. In user section, user will be able to register himself and login to system to manage account and manage complaints. In admin section, administrator will be able to manage users, manage category and manage complaints.

So let’s proceed with developing system. The file structure are:

  • build-complaint-system-php-mysql
    • index.php
    • dashboard.php
    • login.php
    • user.php
    • registration.php
    • user_action.php
    • complaint.php
    • complaint_action.php
    • config
      • Database.php
    • class
      • User.php
      • Complaint.php
    • css
      • style.css
    • admin
      • index.php
      • user.php
      • category.php
      • class
        • User.php
        • Complaint.php
        • Category.php

Create Database and Tables

First we will create database tables that we will use in our system tp store data.


So we will create user table to store user’s data.

CREATE TABLE `user` (
  `id` int(11) UNSIGNED NOT NULL,
  `first_name` varchar(255) DEFAULT NULL,
  `last_name` varchar(255) DEFAULT NULL,
  `email` varchar(255) DEFAULT NULL,
  `password` varchar(64) NOT NULL,
  `role` enum('admin','user') DEFAULT 'admin'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

ALTER TABLE `user`
  ADD PRIMARY KEY (`id`);
  
ALTER TABLE `user`
  MODIFY `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=8;

we will create category table to store category’s data.

CREATE TABLE `category` (
  `categoryid` int(11) NOT NULL,
  `name` varchar(200) COLLATE utf8_unicode_ci NOT NULL,
  `status` enum('Enable','Disable') COLLATE utf8_unicode_ci NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;


ALTER TABLE `category`
  ADD PRIMARY KEY (`categoryid`);
  
ALTER TABLE `category`
  MODIFY `categoryid` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=9;

we will create complaints table to store complaints’s data to manage complaints.

CREATE TABLE `complaints` (
  `complaint_id` int(11) NOT NULL,
  `details` text NOT NULL,
  `complaint_date` datetime NOT NULL DEFAULT current_timestamp(),
  `userid` int(11) NOT NULL,
  `categoryid` int(11) NOT NULL,
  `status` enum('open','inprogress','closed') NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

ALTER TABLE `category`
  ADD PRIMARY KEY (`categoryid`);


ALTER TABLE `complaints`
  ADD PRIMARY KEY (`complaint_id`);  

Design Complaint Front Page

We will create index.php and design front page of our project with login, register and admin panel link.

<div class="header_section">
  <div class="container-fluid ">
	 <div class="row">
		<div class="col-sm-8 col-6">
		   <nav class="navbar navbar-expand-lg navbar-light bg-light">
			  <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav"
				 aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
				 <span class="navbar-toggler-icon"></span>
			  </button>
			  <div class="collapse navbar-collapse" id="navbarNav">
				 <ul class="navbar-nav">
					<li class="nav-item active">
					   <a class="nav-link" href="index.php">Home</a>
					</li>                        
					<li class="nav-item">
					   <a class="nav-link" href="login.php">Login</a>
					</li>
					<li class="nav-item">
					   <a class="nav-link" href="registration.php">Register</a>
					</li>
				   <li class="nav-item">
					   <a class="nav-link" href="admin/index.php">Admin Panel</a>
					</li>                        
				 </ul>
			  </div>
		   </nav>
		</div>	 
	 </div>
  </div>
</div>

Create Login Page and Implement

We will create login.php and design login page.


<div class="row row-offcanvas row-offcanvas-left">     
<div class="col-md-9 col-lg-10 main"> 
<div class="row mb-3">	
		
	<div style="padding:30px" class="panel-body">
		<h4>User Login</h4>
		<br>
		<?php if ($loginMessage != '') { ?>
			<div id="login-alert" class="alert alert-danger col-sm-12"><?php echo $loginMessage; ?></div>                            
		<?php } ?>
		<form id="loginform" class="form-horizontal" role="form" method="POST" action="">                                    
			<div style="margin-bottom: 25px" class="input-group">
				<span class="input-group-addon"><i class="glyphicon glyphicon-user"></i></span>
				<input type="text" class="form-control" id="email" name="email" value="<?php if(!empty($_POST["email"])) { echo $_POST["email"]; } ?>" placeholder="email" style="background:white;" required>                                        
			</div>                                
			<div style="margin-bottom: 25px" class="input-group">
				<span class="input-group-addon"><i class="glyphicon glyphicon-lock"></i></span>
				<input type="password" class="form-control" id="password" name="password" value="<?php if(!empty($_POST["password"])) { echo $_POST["password"]; } ?>" placeholder="password" required>
			</div>						
			
			<div style="margin-top:10px" class="form-group">      
				<input type="submit" name="login" value="Login" class="btn btn-info"> 
				<a href="index.php" class="btn btn-info" role="button">Back</a>
			</div>				
			
		</form>   
	</div>    
</div>  

We will create a login() function to handle login functionaltiy.

public function login(){
	if($this->email && $this->password) {			
		$sqlQuery = "
			SELECT * FROM ".$this->userTable." 
			WHERE email = ? AND password = ?";			
		$stmt = $this->conn->prepare($sqlQuery);
		$password = md5($this->password);
		$stmt->bind_param("ss", $this->email, $password);	
		$stmt->execute();
		$result = $stmt->get_result();
		if($result->num_rows > 0){
			$user = $result->fetch_assoc();
			$_SESSION["user_userid"] = $user['id'];
			$_SESSION["user_role"] = $user['role'];
			$_SESSION["user_name"] = $user['email'];					
			return 1;		
		} else {
			return 0;		
		}			
	} else {
		return 0;
	}
}

we will check for login form submit and handle login functionality.

if(!empty($_POST["login"]) && !empty($_POST["email"]) && !empty($_POST["password"])) {	
	$user->email = $_POST["email"];
	$user->password = $_POST["password"];	
	if($user->login()) {
		header("Location: dashboard.php");	
	} else {
		$loginMessage = 'Invalid login! Please try again.';
	}
}

Create Register Page and Implement

We will create registration.php file and dsign user register page.

<div class="row row-offcanvas row-offcanvas-left">     
	  <div class="col-md-9 col-lg-10 main"> 
		<div class="row mb-3">				
			<div style="padding:30px" class="panel-body">
				<h4>User Registration</h4>	
				<br>
				<?php if ($registerMessage != '') { ?>
					<div id="login-alert" class="alert alert-danger col-sm-12"><?php echo $registerMessage; ?></div>                            
				<?php } ?>
				<form id="registerform" class="form-horizontal" role="form" method="POST" action="">	
					<div class="form-group">							
						<label for="first name" class="control-label">First Name</label>					
						<input type="text" name="first_name" id="first_name" autocomplete="off" class="form-control" placeholder="first name"/>										
					</div>					
					<div class="form-group"
						<label for="last name" class="control-label">Last Name</label>
						<input type="text" class="form-control" id="last_name" name="last_name" placeholder="Last name" >			
					</div>	
					<div class="form-group"
						<label for="email" class="control-label">Email</label>
						<input type="email" class="form-control" id="email" name="email" placeholder="Email" >			
					</div>					
					<div class="form-group"
						<label for="new password" class="control-label">Password</label>
						<input type="password" class="form-control" id="password" name="password" placeholder="password" >			
					</div>			
					<div style="margin-top:10px" class="form-group">
						<input type="hidden" name="role" id="role" value="user" />					
						<input type="submit" name="register" value="register" class="btn btn-info">
						<a href="index.php" class="btn btn-info" role="button">Back</a>
					</div>				
				</form>   
			</div> 
        <hr>         
</div>  

we will create function insert() to insert user details to register.

public function insert(){		
	if($this->role && $this->email && $this->password) {
		$stmt = $this->conn->prepare("
			INSERT INTO ".$this->userTable."(`first_name`, `last_name`, `email`, `password`, `role`)
			VALUES(?, ?, ?, ?, ?)");		
		$this->role = htmlspecialchars(strip_tags($this->role));
		$this->email = htmlspecialchars(strip_tags($this->email));
		$this->first_name = htmlspecialchars(strip_tags($this->first_name));
		$this->last_name = htmlspecialchars(strip_tags($this->last_name));
		$this->password = md5($this->password);
		$stmt->bind_param("sssss", $this->first_name, $this->last_name, $this->email, $this->password, $this->role);
		
		if($stmt->execute()){
			return true;
		}		
	}
}

We will handle register form submit and registration functionality by calling insert() function.


if(!empty($_POST["register"]) && !empty($_POST["first_name"]) && !empty($_POST["email"]) && !empty($_POST["password"])) {		
	$user->role = $_POST["role"];
	$user->first_name = $_POST["first_name"];
	$user->last_name = $_POST["last_name"];
	$user->email = $_POST["email"];
	$user->password = $_POST["password"];	
	if($user->insert()) {
		header("Location: login.php");	
	} 
}

Create Dashboard

As we will display dashbaord page to logged in user, we will create dashboard.php file and implement to display dashboard details.

<div class="col-md-9 col-lg-10 main"> 
	<h2>User Dashboard</h2>
	<div class="row mb-3">		
	  <div class="col-xl-3 col-lg-6">
		<div class="card card-inverse card-success">
		  <div class="card-block bg-success">
			<div class="rotate">
			  <i class="fa fa-user fa-5x"></i>
			</div>
			<h6 class="text-uppercase">Total Complaints</h6>
			<h1 class="display-1"><a href="complaint.php"><?php echo $user->getComplaint('all'); ?></a></h1>
		  </div>
		</div> 
	  </div>        
	  <div class="col-xl-3 col-lg-6">
		<div class="card card-inverse card-info">
		  <div class="card-block bg-info">
			<div class="rotate">
			  <i class="fa fa-twitter fa-5x"></i>
			</div>
			<h6 class="text-uppercase">Open Complaints</h6>
			<h1 class="display-1"><a href="complaint.php"><?php echo $user->getComplaint('open'); ?></a></h1>
		  </div>
		</div>
	  </div>
	  <div class="col-xl-3 col-lg-6">
		<div class="card card-inverse card-warning">
		  <div class="card-block bg-warning">
			<div class="rotate">
			  <i class="fa fa-share fa-5x"></i>
			</div>
			<h6 class="text-uppercase">In Process Complaints</h6>
			<h1 class="display-1"><a href="complaint.php"><?php echo $user->getComplaint('inprogress'); ?></a></h1>
		  </div>
		</div>
	  </div>
	  <div class="col-xl-3 col-lg-6">
		<div class="card card-inverse card-danger">
		  <div class="card-block bg-danger">
			<div class="rotate">
			  <i class="fa fa-list fa-4x"></i>
			</div>
			<h6 class="text-uppercase">Closed Complaints</h6>
			<h1 class="display-1"><a href="complaint.php"><?php echo $user->getComplaint('closed'); ?></a></h1>
		  </div>
		</div>
	  </div>
	</div>
	<hr>         
 </div>
 

Manage Complaints

Now we will implement functionality to create complaints and manage these. We will create complaint.php file and design html to manage complaints.

<div class="row row-offcanvas row-offcanvas-left">
			<?php include('left_menus.php'); ?>
			<div class="col-md-9 col-lg-10 main"> 
			<h2>Manage Complaints</h2>
			<div class="panel-heading">
				<div class="row">
					<div class="col-md-10">
						<h3 class="panel-title"></h3>
					</div>
					<div class="col-md-2" align="right">
						<button type="button" id="addComplaints" class="btn btn-info" title="Add Complaintss"><span class="glyphicon glyphicon-plus">Add</span></button>
					</div>
				</div>
			</div>			
			<table id="complaintsListing" class="table table-striped table-bordered">
				<thead>
					<tr>						
						<th>Sn.</th>					
						<th>Details</th>	
						<th>Category</th>
						<th>Created By</th>							
						<th>Created</th>						
						<th>Status</th>						
						<th></th>
						<th></th>					
					</tr>
				</thead>
			</table>	`			
			</div>
		</div>		
		<div id="complaintsModal" class="modal fade">
			<div class="modal-dialog">
				<form method="post" id="complaintForm">
					<div class="modal-content">
						<div class="modal-header">
							<button type="button" class="close" data-dismiss="modal"></button>
							<h4 class="modal-title"><i class="fa fa-plus"></i> Edit Complaints</h4>
						</div>
						<div class="modal-body">						
							
							<div class="form-group">
								<label for="country" class="control-label">Category</label>						
								<select class="form-control" id="category" name="category"/>
									<option value="">Select</option>							
									<?php 
									$categoryResult = $complaint->getCategoryList();
									while ($category = $categoryResult->fetch_assoc()) { 	
									?>
									<option value="<?php echo $category['categoryid']; ?>"><?php echo $category['name']; ?></option>			
									<?php } ?>									
								</select>							
							</div>
							
							<div class="form-group">							
								<label for="first name" class="control-label">Complain Details</label>		
								<textarea class="form-control" rows="5" id="details" name="details"></textarea>		
							</div>

							<div class="form-group">
								<label for="status" class="control-label">Status</label>							
								<select class="form-control" id="status" name="status"/>
									<option value="">Select</option>							
									<option value="open">Open</option>
									<option value="inprogress">In Progress</option>
									<option value="closed">Closed</option>							
								</select>							
							</div>										
						</div>
						<div class="modal-footer">
							<input type="hidden" name="id" id="id" />						
							<input type="hidden" name="action" id="action" value="" />
							<input type="submit" name="save" id="save" class="btn btn-info" value="Save" />
							<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
						</div>
					</div>
				</form>
			</div>
		</div>

We have also implemented user manage and admin section to manage everything by administrative user. To complete project code, please download project zip file.

Demo Download


Leave a Reply

Your email address will not be published. Required fields are marked *