0% found this document useful (0 votes)
5 views

Ticketing

Uploaded by

melbinjoseph726
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views

Ticketing

Uploaded by

melbinjoseph726
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 38

import { Component, ChangeDetectorRef } from '@angular/core';

import { ColDef, GridApi, ICellRendererParams } from 'ag-grid-


community';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { HttpCommonService } from '@libs/http-common';
import { ToastrService } from 'ngx-toastr';

@Component({
selector: 'app-ticketing',
templateUrl: './ticketing.component.html',
styleUrls: ['./ticketing.component.css']
})
export class TicketingComponent {

showDescriptionModal: boolean = false;


showcommantModal: boolean = false;
showcommantviewModal: boolean = false;
showActionModal: boolean = false;
selectedTicketId: string = '';
selectedAction: string = '';
actionComment: string = '';
showValidationMessage: boolean = false;

userImage: any;
isAdminCancel: boolean | undefined
// filter
fromDate: string = '';
toDate: string = '';
selectedStatus: string = '';
selectedLocation: string = '';
selectedService: string = '';
gridApi!: GridApi | undefined;

submitActionWithValidation() {
if (!this.actionComment || this.actionComment.trim() === '') {
this.showValidationMessage = true;
} else {
this.showValidationMessage = false;
this.submitAction();
}
}

cancelTicketWithValidation() {
if (!this.actionComment || this.actionComment.trim() === '') {
this.showValidationMessage = true;
} else {
this.showValidationMessage = false;
this.cancelTicket();
}
}

onFromDateChange(event: Event) {
this.fromDate = (event.target as HTMLInputElement).value;
}

onToDateChange(event: Event) {
this.toDate = (event.target as HTMLInputElement).value;
}

onStatusChange(event: Event) {
this.selectedStatus = (event.target as HTMLSelectElement).value;
}

onLocationChange(event: Event) {
this.selectedLocation = (event.target as HTMLSelectElement).value;
}

onServiceChange(event: Event) {
this.selectedService = (event.target as HTMLSelectElement).value;
}

selectedDescription: string = '';


selectedcomment: string = '';
selectedcommentview: string = '';
showImageModal: boolean = false;
imageUrl: string = '';
constructor(
private HttpCommonService: HttpCommonService,
private http: HttpClient,
private toastr: ToastrService,
private cdr: ChangeDetectorRef
) { }

activeTab = 'RaiseTicket';
formSubmitted = false;
ticketData = {
service: '',
location: '',
priority: '',
fileUpload: '',
issueDescription: ''
};
rowData: any[] = [];
quickFilterText = '';

isOpenRaiseTicketView = false;
isOpenViewTicketView = false;
isOpenResolveTicketView = false;
isModalOpen = false;
paginationPageSize = 20;

viewTicketColumnDefs: ColDef[] = [
{
headerName: 'SI No',
field: 'column1',
sortable: true,
filter: true,
editable: true,
cellClass: 'text-xs',
headerClass: 'text-center',
minWidth: 50,
flex: 1,
cellStyle: { 'text-align': 'center', 'display': 'flex', 'align-
items': 'center', 'justify-content': 'center' }
},
{
headerName: 'Created On',
field: 'createdOn',
sortable: true,
filter: 'agDateColumnFilter',
filterParams: {
comparator: function (filterLocalDateAtMidnight: Date,
cellValue: string) {
const dateAsString = cellValue;
const dateParts = dateAsString.split('-');
const cellDate = new Date(
Number(dateParts[0]),
Number(dateParts[1]) - 1,
Number(dateParts[2])
);
if (filterLocalDateAtMidnight.getTime() ===
cellDate.getTime()) {
return 0;
}
if (cellDate < filterLocalDateAtMidnight) {
return -1;
}
if (cellDate > filterLocalDateAtMidnight) {
return 1;
}
return 0;
},
},
cellClass: 'text-xs',
headerClass: 'text-center',
minWidth: 120,
flex: 2
},
{
headerName: 'Ticket ID',
field: 'ticketid',
sortable: true,
filter: true,
cellClass: 'text-xs',
minWidth: 120,
flex: 2,
cellStyle: { 'text-align': 'center', 'display': 'flex', 'align-
items': 'center', 'justify-content': 'center' },
headerClass: 'text-center',
},
{
headerName: 'Last Modified',
field: 'lastModified',
sortable: true,
filter: true,
cellClass: 'text-xs',
minWidth: 100,
flex: 1,
cellStyle: { 'text-align': 'center', 'display': 'flex', 'align-
items': 'center', 'justify-content': 'center' },
headerClass: 'text-center',
},
{ headerName: 'Modified By', field: 'modifiedby', sortable: true,
filter: true, cellClass: 'text-xs', minWidth: 100, flex: 1 },

{
headerName: 'Service',
field: 'service',
sortable: true,
filter: true,
cellClass: 'text-xs',
headerClass: 'text-center',
minWidth: 150,
flex: 2,

},
{
headerName: 'Location',
field: 'location',
sortable: true,
filter: true,
cellClass: 'text-xs',
headerClass: 'text-center',
minWidth: 150,
flex: 2,
},
{
headerName: 'Priority',
field: 'priority',
sortable: true,
filter: true,
cellClass: 'text-xs',
headerClass: 'text-center',
minWidth: 80,
flex: 1,

},
{
headerName: 'File Uploaded',
field: 'fileUploaded',
sortable: true,
filter: true,
cellClass: 'text-xs',
headerClass: 'text-center',
minWidth: 150,
flex: 2,
cellRenderer: this.fileUploadCellRenderer.bind(this),
cellStyle: { 'text-align': 'center', 'display': 'flex', 'align-
items': 'center', 'justify-content': 'center' }
},
{
headerName: 'Status',
field: 'status',
sortable: true,
filter: true,
cellClass: 'text-xs',
headerClass: 'text-center',
minWidth: 100,
flex: 1,

},
{
headerName: 'Comments',
field: 'commentsview',
sortable: true,
filter: true,
cellClass: 'text-xs',
headerClass: 'text-center',
minWidth: 200,
flex: 3,
cellRenderer: this.commantCellRenderer.bind(this),
cellStyle: { 'white-space': 'normal', 'word-wrap': 'break-word',
'text-align': 'center', 'display': 'flex', 'align-items': 'center',
'justify-content': 'center' }
},
{
headerName: 'Actions',
field: 'actions',
cellRenderer: this.actionCellRenderer.bind(this),
minWidth: 150,
headerClass: 'text-center',
cellClass: 'text-xs sticky-column',
flex: 0.5,
pinned: 'right',
cellStyle: { 'text-align': 'center', 'display': 'flex', 'align-
items': 'center', 'justify-content': 'center', 'padding': '0' } //
Removed extra padding
}
];

fileUploadCellRenderer(params: any): HTMLElement {


const svgContainer = document.createElement('div');
svgContainer.classList.add(
'px-3',
'py-1',
'rounded',
'hover:bg-blue-600',
'transition',
'duration-200',
'cursor-pointer',
'inline-flex',
'items-center',
'justify-center'
);

svgContainer.style.width = '24px';
svgContainer.style.height = '24px';
svgContainer.innerHTML = `<i class="fa fa-eye" aria-
hidden="true"></i>`;

svgContainer.addEventListener('click', () => {
const filePath = params.value;
if (filePath && filePath !== 'N/A') {
this.openImageModal(filePath);
} else {
this.toastr.warning('No file uploaded', 'Warning');
}

});

return svgContainer;
}

openImageModal(filePath: string): void {


this.fetchImage(filePath);
this.showImageModal = true;
console.log(this.showImageModal);
}

closeImageModal(): void {
this.showImageModal = false;
this.imageUrl = '';
}

resolveTicketColumnDefs: ColDef[] = [
{ headerName: 'SI No', field: 'column1', sortable: true, filter:
true, editable: true, cellClass: 'text-xs', minWidth: 50, flex: 1,
cellStyle: { 'text-align': 'center', 'display': 'flex', 'align-items':
'center', 'justify-content': 'center' } },
{ headerName: 'Created On', field: 'createdOn', sortable: true,
filter: true, cellClass: 'text-xs', minWidth: 120, flex: 2 },
{ headerName: 'Ticket ID', field: 'ticketid', sortable: true,
filter: true, cellClass: 'text-xs', minWidth: 120, flex: 2 },
{ headerName: 'Last Modified', field: 'lastModified', sortable:
true, filter: true, cellClass: 'text-xs', minWidth: 100, flex: 1 },
{ headerName: 'Modified By', field: 'modifiedby', sortable: true,
filter: true, cellClass: 'text-xs', minWidth: 100, flex: 1 },
{
headerName: 'Description',
field: 'description',
sortable: true,
filter: true,
cellClass: 'text-xs',
minWidth: 200,
flex: 3,
cellRenderer: this.descriptionCellRenderer.bind(this),

cellStyle: { 'text-align': 'center', 'display': 'flex', 'align-


items': 'center', 'justify-content': 'center' }
},
{ headerName: 'Service', field: 'service', sortable: true, filter:
true, cellClass: 'text-xs', minWidth: 150, flex: 2 },
{ headerName: 'Location', field: 'location', sortable: true,
filter: true, cellClass: 'text-xs', minWidth: 150, flex: 2 },
{ headerName: 'Priority', field: 'priority', sortable: true,
filter: true, cellClass: 'text-xs', minWidth: 80, flex: 1 },

{
headerName: 'File Uploaded',
field: 'fileUploaded',
sortable: true,
filter: true,
cellClass: 'text-xs',
minWidth: 150,
flex: 2,
cellRenderer: this.fileUploadCellRenderer.bind(this),
cellStyle: { 'text-align': 'center', 'display': 'flex', 'align-
items': 'center', 'justify-content': 'center' }
},
{ headerName: 'Status', field: 'status', sortable: true, filter:
true, cellClass: 'text-xs', minWidth: 100, flex: 1 },
{ headerName: 'Raised By', field: 'raisedBy', sortable: true,
filter: true, cellClass: 'text-xs', minWidth: 120, flex: 2 },
{
headerName: 'Comments',
field: 'comments',
sortable: true,
filter: true,
cellClass: 'text-xs',
minWidth: 200,
flex: 3,
cellRenderer: this.commantCellRenderer.bind(this),

cellStyle: { 'text-align': 'center', 'display': 'flex', 'align-


items': 'center', 'justify-content': 'center' }
},

{
headerName: 'Actions',
field: 'actions',
cellRenderer: this.actionCellRenderer.bind(this),
minWidth: 150,
headerClass: 'text-center',
cellClass: 'text-xs sticky-column',
flex: 0.5,
pinned: 'right',
cellStyle: { 'text-align': 'center', 'display': 'flex', 'align-
items': 'center', 'justify-content': 'center', 'padding': '0' }
}
];

Filter() {
if (this.rowData) {
let filteredData = [...this.rowData];

if (this.fromDate && this.toDate) {


const fromDateObj = new Date(this.fromDate);
const toDateObj = new Date(this.toDate);

if (!isNaN(fromDateObj.getTime()) && !
isNaN(toDateObj.getTime())) {

fromDateObj.setHours(0, 0, 0, 0);
toDateObj.setHours(23, 59, 59, 999);

filteredData = filteredData.filter((row: any) => {


const createdOnDate = this.convertDMYToDate(row.createdOn);
return createdOnDate >= fromDateObj && createdOnDate <=
toDateObj;
});
} else {
console.error("Invalid date input");
}
}

if (this.selectedStatus) {
filteredData = filteredData.filter((row: any) =>
row.status.toLocaleLowerCase() ==
this.selectedStatus.toLocaleLowerCase());
}

if (this.selectedLocation) {
console.log(filteredData);

console.log(this.selectedLocation);

filteredData = filteredData.filter((row: any) =>


row.location.toLocaleLowerCase() ==
this.selectedLocation.toLocaleLowerCase());
}
if (this.selectedService) {
filteredData = filteredData.filter((row: any) =>
row.service.toLocaleLowerCase() ==
this.selectedService.toLocaleLowerCase());
}

this.gridApi?.setRowData(filteredData);

} else {
console.error("Row data is not available.");
}

convertDMYToDate(dateStr: string): Date {


const [day, month, year] = dateStr.split('-').map(Number);
return new Date(year, month - 1, day);
}

clearDateFilter() {
this.fromDate = '';
this.toDate = '';
this.selectedStatus = '';
this.selectedLocation = '';
this.selectedService = '';

if (this.gridApi) {
this.gridApi.setFilterModel(null);
this.fetchData();
this.fetchTickets();
} else {
console.error("Grid API is not initialized.");
}
}

fetchData() {
console.log("Fetching data based on the filter model...");
// Add actual logic to fetch filtered data here
}

onGridReady(params: any) {
this.gridApi = params.api;
if (this.gridApi) {
if (this.rowData && this.rowData.length > 0) {
this.gridApi.setRowData(this.rowData);
} else {
console.warn('No row data available to set in the grid');
}

this.gridApi.sizeColumnsToFit();
} else {
console.error('Grid API is not initialized');
}
}

cancelTicket() {

if (this.activeTab === 'ResolveTicket') {

this.openActionModal(this.selectedTicketId, 'CANCELLD');
} else {

const payload = {
ticketId_Ticketing_Text: this.selectedTicketId,
ticketStatus_Ticketing_Text: 'CANCELLED',
ticketComment_Ticketing_Text: this.actionComment

};
console.log('payload', payload);
const headers = new HttpHeaders().set('Authorization',
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJLSlVzeXMtQXV0aG5BdXRoe
iIsImlhdCI6MTcyOTI1MDA1NywiZXhwIjoxNzI5MjUxODU3LCJlbWFpbCI6IkEuWEBLUklT
VFVKQVlBTlRJLkNPTSIsInJvbGVzIjoiW10ifQ.m-
H9OsTpksAnUEiOANDnpihsoTBtGybhucx2lcJRPnE');

this.http.post('http://172.21.14.245:8087/kjusys-api/ticketing/user-
action', payload, { headers })
.subscribe(
(response: any) => {
if (response.statusCode === 200) {
this.closeActionModal();
this.toastr.success('Ticket Cancelled Successfully',
'Success');
if (this.gridApi) {
this.fetchTickets();
}
} else if (response.responseData.message) {
this.toastr.warning(response.responseData.message[0],
'Warning');
this.closeActionModal();
} else {
this.toastr.error('Failed to cancel the ticket',
'Error');
this.closeActionModal();
}

},
error => {
console.error('Error cancelling ticket:', error);
//alert('Error cancelling the ticket');
this.toastr.error('Error cancelling the ticket','error');
this.closeActionModal();
complete: () => {

this.closeActionModal();

this.actionComment = '';
this.selectedTicketId = '';
this.selectedAction = '';
}
}

);
}
}

commantCellRenderer(params: any): HTMLElement {


const container = document.createElement('div');
container.style.width = '100%';
container.style.height = '100%';

container.classList.add(
'flex',
'items-center',
'justify-center'
);

const svg = document.createElementNS('http://www.w3.org/2000/svg',


'svg');
svg.setAttribute('viewBox', '0 0 24 24');
svg.setAttribute('width', '20');
svg.setAttribute('height', '20');
svg.classList.add(
'text-blue-500',
'hover:text-blue-800',
'transition',
'duration-200',
'cursor-pointer'
);

container.title = 'View Comments';

const path = document.createElementNS('http://www.w3.org/2000/svg',


'path');
path.setAttribute('d', 'M21.99 4c0-1.1-.89-2-1.99-2H4c-1.1 0-2 .9-2
2v12c0 1.1.9 2 2 2h14l4 4zM18 14H6v-2h12zm0-3H6V9h12zm0-3H6V6h12z');
path.setAttribute('fill', 'currentColor');

svg.appendChild(path);
container.appendChild(svg);

container.addEventListener('click', () => {
const status = params.data.status;
if (status === 'CANCELLED' || status === 'HOLD' || status ===
'RESOLVED') {
this.opencommantModal(params.data.comments);
} else {
this.toastr.info('No comments available', 'Info');
}

});

return container;
}

opencommantModal(comment: string): void {


this.selectedcomment = comment;
this.cdr.detectChanges();
this.showcommantModal = true;
}

closecommantModal(): void {
this.showcommantModal = false;
}
commantviewCellRenderer(params: any): HTMLElement {
const button = document.createElement('button');
button.innerText = 'View Comments';
button.classList.add(
'bg-blue-500',
'text-white',
'px-3',
'py-1',
'rounded',
'text-xs',
'hover:bg-blue-600',
'transition',
'duration-200',
'cursor-pointer'
);

button.addEventListener('click', () => {
const status = params.data.status;

if (status === 'CANCELLED' || status === 'HOLD' || status ===


'RESOLVED') {
this.opencommantviewModal(params.data.comments);
} else {
this.toastr.info('No comments available', 'Info');
}

});

return button;
}

opencommantviewModal(comment: string): void {


this.selectedcommentview = comment;
this.showcommantviewModal = true;
}

closecommantviewModal(): void {
this.showcommantviewModal = false;
}

openActionModal(ticketId: string, action: string): void {


this.selectedTicketId = ticketId;
this.selectedAction = action;
this.actionComment = '';
this.showActionModal = true;
this.cdr.detectChanges()
}

closeActionModal(): void {
this.showValidationMessage = false;
this.actionComment = '';
this.selectedTicketId = '';
this.selectedAction = '';
this.showActionModal = false;
this.cdr.detectChanges()
}

submitAction(): void {
if (!this.actionComment.trim()) {
this.toastr.warning('Please enter a comment', 'Warning');
return;
}

const payloadd = {
ticketId_Ticketing_Text: this.selectedTicketId,
ticketStatus_Ticketing_Text: this.selectedAction,
ticketComment_Ticketing_Text: this.actionComment
};

const headers = new HttpHeaders().set('Authorization',


'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJLSlVzeXMtQXV0aG5BdXRoe
iIsImlhdCI6MTcyOTI1MDA1NywiZXhwIjoxNzI5MjUxODU3LCJlbWFpbCI6IkEuWEBLUklT
VFVKQVlBTlRJLkNPTSIsInJvbGVzIjoiW10ifQ.m-
H9OsTpksAnUEiOANDnpihsoTBtGybhucx2lcJRPnE"');

this.http.post('http://172.21.14.245:8087/kjusys-api/ticketing/admin-
actions', payloadd, { headers })
.subscribe(
(response: any) => {
if (response.statusCode === 200) {
this.toastr.success(response.responseData.message[0],
'Success');
this.fetchResolvedTickets();
this.closeActionModal();
} else if (response.responseData.message) {
this.closeActionModal();
this.toastr.warning(response.responseData.message[0],
'Warning');
} else {
this.closeActionModal();
this.toastr.error('Failed to update ticket status',
'Error');
}

},
error => {
console.error('Error updating ticket:', error);
this.toastr.error('Error updating ticket status', 'Error');
this.closeActionModal();
complete: () => {

this.closeActionModal();

this.actionComment = '';
this.selectedTicketId = '';
this.selectedAction = '';
}
}
);
}

descriptionCellRenderer(params: any): HTMLElement {


const button = document.createElement('button');

button.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20"
viewBox="0 0 28 28">
<path d="M3 6a1 1 0 0 0 0 2h21.997a1 1 0 1 0 0-2zm0 15a1 1
0 1 0 0 2h14.997a1 1 0 1 0 0-2zm-1-9a1 1 0 0 1 1-1h21.997a1 1 0 1 1 0
2H3a1 1 0 0 1-1-1m1 4a1 1 0 1 0 0 2h21.997a1 1 0 1 0 0-2z"/>
</svg>
`;

button.classList.add(

'text-white',
'px-3',
'py-1',
'rounded',
'text-xs',
'hover:bg-blue-600',
'transition',
'duration-200',
'cursor-pointer'
);

button.addEventListener('click', () => {
this.openDescriptionModal(params.value);
});

return button;
}
openDescriptionModal(description: string): void {
this.selectedDescription = description;
this.showDescriptionModal = true;
}

closeDescriptionModal(): void {
this.showDescriptionModal = false;
}

get columnDefs(): ColDef[] {


return this.isOpenResolveTicketView ?
this.resolveTicketColumnDefs.slice().reverse() :
this.viewTicketColumnDefs.slice().reverse();
}

setActiveTab(tab: string) {
this.activeTab = tab;
if (tab === 'ViewTicket') {
this.isAdminCancel = false;
this.fetchTickets();

} else if (tab === 'ResolveTicket') {


this.isAdminCancel = true;
this.fetchResolvedTickets();

}
}

fetchTickets() {
const header = new HttpHeaders().set(
'Authorization',

'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJLSlVzeXMtQXV0aG5BdXRoe
iIsImlhdCI6MTcyOTI1MDA1NywiZXhwIjoxNzI5MjUxODU3LCJlbWFpbCI6IkEuWEBLUklT
VFVKQVlBTlRJLkNPTSIsInJvbGVzIjoiW10ifQ.m-
H9OsTpksAnUEiOANDnpihsoTBtGybhucx2lcJRPnE"'
);

this.http
.get('http://172.21.14.245:8087/kjusys-api/ticketing/view-
ticket', {
headers: header,
})
.subscribe(
(response: any) => {
if (response.statusCode === 200 &&
response.responseData?.data) {
this.rowData = response.responseData.data
.map((ticket: any, index: number) => {
const ticketRaisedDate = new
Date(ticket.ticketRaisedAt_Ticketing_Date);
const lastModifiedDate =
ticket.ticketLastModifiedAt_Ticketing_Date
? new
Date(ticket.ticketLastModifiedAt_Ticketing_Date)
: ticketRaisedDate;

const formatDate = (date: Date) => {


const day = String(date.getDate()).padStart(2, '0');
const month = String(date.getMonth() + 1).padStart(2,
'0');
const year = date.getFullYear();
return `${day}-${month}-${year}`;
};

return {
column1: index + 1,
createdOn: formatDate(ticketRaisedDate),
service:
ticket.chooseServiceForTicket_Ticketing_Text,
location: ticket.locationForTicket_Ticketing_Text,
lastModified: formatDate(lastModifiedDate),
priority: ticket.ticketPriority_Ticketing_Text,
fileUploaded: ticket.ticketFileUpload_Ticketing_File
|| 'N/A',
modifiedby: ticket.ticketModifiedBy_Ticketing_Text ||
'N/A',
status: ticket.ticketStatus_Ticketing_Text,
description:
ticket.ticketIssueDescription_Ticketing_Text,
commentsview: ticket.ticketComment_Ticketing_Text ||
'N/A',
raisedBy: ticket.ticketRaisedBy_Ticketing_Text ||
'Unknown',
ticketid: ticket.ticketId_Ticketing_Text,
comments: ticket.ticketComment_Ticketing_Text ||
'N/A',
};
})
.reverse();

if (this.gridApi) {
this.gridApi.setRowData(this.rowData);
}
} else {
console.error('Failed to fetch resolved ticket data',
response);
}
},
(error) => {
console.error('Error fetching resolved ticket data', error);
}
);
}

fetchResolvedTickets() {
// const header = new HttpHeaders().set('Authorization', 'your-
auth-token-here');

this.http.get('http://172.21.14.245:8087/kjusys-api/ticketing/admin-
view-all-tickets')
.subscribe(
(response: any) => {
if (response.statusCode === 200 &&
response.responseData?.data) {
const tickets = response.responseData.data[0]?.tickets ||
[];
this.rowData = tickets.map((ticket: any, index: number) =>
{
// Format date as dd-mm-yyyy
const formatDate = (date: Date) => {
const day = String(date.getDate()).padStart(2, '0');
const month = String(date.getMonth() + 1).padStart(2,
'0');
const year = date.getFullYear();
return `${day}-${month}-${year}`;
};

const createdOn = formatDate(new


Date(ticket.ticketRaisedAt_Ticketing_Date));
const lastModified =
ticket.ticketLastModifiedAt_Ticketing_Date
? formatDate(new
Date(ticket.ticketLastModifiedAt_Ticketing_Date))
: createdOn;

return {
column1: index + 1,
createdOn: createdOn,
service: ticket.chooseServiceForTicket_Ticketing_Text,
location: ticket.locationForTicket_Ticketing_Text,
comments: ticket.ticketComment_Ticketing_Text,
lastModified: lastModified,
priority: ticket.ticketPriority_Ticketing_Text,
fileUploaded: ticket.ticketFileUpload_Ticketing_File ||
'N/A',
modifiedby: ticket.ticketModifiedBy_Ticketing_Text ||
'N/A',
status: ticket.ticketStatus_Ticketing_Text,
raisedBy: ticket.ticketRaisedBy_Ticketing_Text,
description:
ticket.ticketIssueDescription_Ticketing_Text,
ticketid: ticket.ticketId_Ticketing_Text
};
})
.reverse();

if (this.gridApi) {
this.gridApi.setRowData(this.rowData);
}
} else {
console.error('Failed to fetch resolved ticket data',
response);
}
},
error => {
console.error('Error fetching resolved ticket data', error);
}
);
}

fetchImage(filePath: string): void {


const payload = { ticketFileUpload_Ticketing_Text: filePath };

this.http
.post('http://172.21.14.245:8087/kjusys-api/ticketing/ticket-
download-file', payload, { responseType: 'blob' })
.subscribe({
next: (response: Blob) => {
if (response && response.size > 0) {
const reader = new FileReader();
reader.onloadend = () => {
this.userImage = reader.result;
this.cdr.detectChanges();

};
reader.readAsDataURL(response);
} else {

}
},
error: (error: any) => {
if (error instanceof Blob) {
error.text().then((text: string) => {
try {
const errorJson = JSON.parse(text);
console.log("error fetching image: ", errorJson);
} catch (e) {
console.log("error fetching image: ", e);

}
});
}
},
});
}

onQuickFilterInput(event: any) {
this.quickFilterText = event.target.value;

if (this.gridApi) {
this.gridApi.setGridOption('quickFilterText',
this.quickFilterText);
}
}

actionCellRenderer(params: ICellRendererParams): HTMLElement {


const container = document.createElement('div');
container.style.display = 'flex';
container.style.gap = '8px';

const ticketId = params.data.ticketid;


const status = params.data.status;
console.log('TIC', ticketId);

if (this.activeTab === 'ResolveTicket' && ( status !== 'RESOLVED'&&


status !== 'CANCELLED')) {
const actions = ['HOLD', 'RESOLVED', 'CANCELLED'];

actions.forEach(action => {
const button = document.createElement('button');
const baseClasses = [
'px-1.5', 'py-0.5', 'mt-0.5', 'rounded', 'text-xs',
'transition', 'duration-200', 'cursor-pointer', 'text-white'
];
const actionClasses: { [key: string]: string[] } = {
'HOLD': ['bg-red-500', 'hover:bg-red-600'],
'RESOLVED': ['bg-green-500', 'hover:bg-green-600'],
'CANCELLED': ['bg-red-500', 'hover:bg-red-600']
};

button.classList.add(...baseClasses, ...actionClasses[action]);

if (action === 'HOLD') {


button.title = 'Put the ticket on hold';
button.innerHTML = `
<svg width="29" height="29" viewBox="0 0 29 29" fill="none"
xmlns="http://www.w3.org/2000/svg">
<rect width="28.7393" height="28.7393" rx="14.3696"
fill=""/>
<path d="M10.9775
18.8619V9.05742H13.2465V18.8619H10.9775ZM15.5733
18.8619V9.05742H17.8423V18.8619H15.5733Z" fill="white"/>
</svg>
`;
} else if (action === 'RESOLVED') {
button.title = 'Mark the ticket as resolved';
button.innerHTML = `
<svg width="29" height="29" viewBox="0 0 29 29" fill="none"
xmlns="http://www.w3.org/2000/svg">
<rect width="28.7393" height="28.7393" rx="14.3696"
fill=""/>
<path d="M9.23779 15.0826L12.0523 17.897L19.5575 10.3918"
stroke="white" stroke-width="2.81446" stroke-linecap="round" stroke-
linejoin="round"/>
</svg>
`;
} else if (action === 'CANCELLED') {
button.title = 'Cancel the ticket';
button.innerHTML = `
<svg width="29" height="29" viewBox="0 0 29 29" fill="none"
xmlns="http://www.w3.org/2000/svg">
<rect width="28.7393" height="28.7393" rx="14.3696"
fill=""/>
<path d="M9.73928 19.3097L13.9552 13.497V15.1498L9.92137
9.50523H12.4985L15.2858 13.441L14.2073 13.455L16.9526
9.50523H19.4177L15.4119 15.0518V13.427L19.6558 19.3097H17.0366L14.1513
15.1498H15.1878L12.3445 19.3097H9.73928Z" fill="white"/>
</svg>
`;
}
button.style.marginRight = '8px';
button.addEventListener('click', () => {
this.openActionModal(ticketId, action);
});

container.appendChild(button);
});
} else if (this.activeTab === 'ViewTicket' && (status !== 'HOLD' &&
status !== 'RESOLVED'&& status !== 'CANCELLED')) {

const cancelButton = document.createElement('button');


cancelButton.title = 'Cancel the ticket';
cancelButton.classList.add(
'bg-red-500', 'text-white', 'px-1.5', 'py-0.5',
'rounded', 'text-xs', 'hover:bg-red-600',
'transition', 'duration-200', 'cursor-pointer'
);

cancelButton.innerHTML = `
<svg width="29" height="29" viewBox="0 0 29 29" fill="none"
xmlns="http://www.w3.org/2000/svg">
<rect width="28.7393" height="28.7393" rx="14.3696" fill=""/>
<path d="M9.73928 19.3097L13.9552 13.497V15.1498L9.92137
9.50523H12.4985L15.2858 13.441L14.2073 13.455L16.9526
9.50523H19.4177L15.4119 15.0518V13.427L19.6558 19.3097H17.0366L14.1513
15.1498H15.1878L12.3445 19.3097H9.73928Z" fill="white"/>
</svg>
`;

cancelButton.addEventListener('click', () => {
this.openActionModalWithComment(ticketId);
});

container.appendChild(cancelButton);
}

return container;
}

openActionModalWithComment(ticketId: string): void {


this.selectedTicketId = ticketId;
this.selectedAction = 'CANCELLED';
this.actionComment = '';
this.showActionModal = true;
}

updateStatus(rowIndex: number, status: string) {


this.rowData[rowIndex].status = status;
if (this.gridApi) {
this.gridApi.setRowData(this.rowData);
}
}

clearQuickFilter() {
this.quickFilterText = '';
if (this.gridApi) {
this.gridApi.setQuickFilter(this.quickFilterText);
}
}

clearSearch() {
this.quickFilterText = '';
if (this.gridApi) {
this.gridApi.setQuickFilter('');
}
}

resetColFilters() {
if (this.gridApi) {
this.gridApi.setFilterModel(null);
this.gridApi.onFilterChanged();
}
}

submitTicket() {
this.formSubmitted = true;

if (!this.isFormValid()) {
this.toastr.warning('Please fill in all required fields: Choose a
Service, Location, Priority, and Issue Description', 'Warning');
return;
}

const formData = new FormData();


formData.append('chooseServiceForTicket_Ticketing_Text',
this.ticketData.service);
formData.append('locationForTicket_Ticketing_Text',
this.ticketData.location);
formData.append('ticketPriority_Ticketing_Text',
this.ticketData.priority);
formData.append('ticketFileUpload_Ticketing_File',
this.ticketData.fileUpload);
formData.append('ticketIssueDescription_Ticketing_Text',
this.ticketData.issueDescription);

const header = new HttpHeaders().set('Authorization',


'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJLSlVzeXMtQXV0aG5BdXRoe
iIsImlhdCI6MTcyOTI1MDA1NywiZXhwIjoxNzI5MjUxODU3LCJlbWFpbCI6IkEuWEBLUklT
VFVKQVlBTlRJLkNPTSIsInJvbGVzIjoiW10ifQ.m-
H9OsTpksAnUEiOANDnpihsoTBtGybhucx2lcJRPnE"');

this.http.post('http://172.21.14.245:8087/kjusys-api/ticketing/create-
Ticket', formData, { headers: header }).subscribe(
(response: any) => {
if (response.type === 'SUCCESS') {
const ticketId =
response.responseData?.data[0]?.ticketId_Ticketing_Text;
this.toastr.success(`Ticket submitted successfully, ID is: $
{ticketId}`, 'Success');
this.resetForm();
this.resetFileInput();
} else {
this.toastr.error(response.responseData?.message[0],
'Error');
}

this.cdr.detectChanges();
},
error => {
console.error('Error submitting ticket', error);
}
);
}

isFormValid(): boolean {
return !!this.ticketData.service &&
!!this.ticketData.location &&
!!this.ticketData.priority &&
!!this.ticketData.issueDescription;
}

resetForm() {
this.ticketData = {
service: '',
location: '',
priority: '',
fileUpload: '',
issueDescription: ''
};
this.formSubmitted = false;
}

resetFileInput() {
document.getElementById("fileUploadText")!.innerHTML = "Upload a
photo";
const fileInput = document.getElementById("fileUpload") as
HTMLInputElement;
if (fileInput) {
fileInput.value = '';
}
}

onFileChange(event: any): void {


const file = event.target.files[0];
const fileUploadText = document.getElementById("fileUploadText");
const fileErrorMessage =
document.getElementById('fileErrorMessage');

if (file) {
const validTypes = ['image/jpeg', 'image/jpg'];
const fileType = file.type;

if (!validTypes.includes(fileType)) {
if (fileErrorMessage) {
fileErrorMessage.classList.remove('hidden');
fileErrorMessage.textContent = 'Only JPG or JPEG files are
allowed.';
}

event.target.value = '';
if (fileUploadText) {
fileUploadText.textContent = 'Upload a photo';
}
return;
}

if (fileErrorMessage) {
fileErrorMessage.classList.add('hidden');
}

if (fileUploadText) {
fileUploadText.textContent = file.name;
}
this.ticketData.fileUpload = file;
}
}
}

<h1 class="mt-4 font-medium text-sm pl-2 ml-6 border-l-4 border-blue-


600 dark:text-blue-700">
Help & Support
</h1>

<div class="flex justify-center items-center w-full">


<div class="flex w-full justify-between space-x-4 p-4 sm:p-8 rounded-
md mt-6 flex-wrap">
<!-- Raise Ticket Button -->
<button
class="flex-grow flex items-center justify-center px-4 py-3
sm:px-6 sm:py-4 md:px-12 md:py-6 text-sm sm:text-lg md:text-2xl
rounded-md border-2 border-blue-500 mb-4 sm:mb-0"
[ngClass]="{'bg-blue-900 text-white': activeTab ===
'RaiseTicket', 'text-gray-800': activeTab !== 'RaiseTicket'}"
(click)="setActiveTab('RaiseTicket')">
<div
class="w-8 h-8 sm:w-12 sm:h-12 md:w-16 md:h-16 mr-2 sm:mr-4
flex items-center justify-center rounded-full bg-white">
<img

src="https://s3-alpha-sig.figma.com/img/c304/88fa/a2f5f4869b22742602630
074579aac41?Expires=1730073600&Key-Pair-
Id=APKAQ4GOSFWCVNEHN3O4&Signature=Dj7G~KJtpS-
zb19sWArdMwrGkPB4QAmIUo~H3JT4O1E9ksugXnLpRh5t55U2zdgZe7ZdT2EJAneSTI68k2
gS-9VlhPFx-lpSE~dWTruVTJkV3ypdqz4fUBdpfJc9x7yLT7mBKjXU-
Yao1WSw3ujtUrcPlC08k7hBu8fpp762Dqh0TZKWdu9DaBVx8mqMgtLn~z5o5AzovTbtftGl
e~7ldVzd1UXEABWlSP-
oseL0cS909npHoXauxEgG2Aj92xYJDqiErv61DjBfGpI6H~pov6a1x6IGMk2RMffypVl1YQ
bdvE8WZSNbNmkH5uFQEvLfP8PCJF-WMU5wCP7ht-Ub6A__"
class="w-6 h-6 sm:w-10 sm:h-10 md:w-12 md:h-12 rounded-full
object-cover bg-gray-200" />
</div>
<div class="flex flex-col items-start">
<span class="font-bold text-xs text-center">Raise a
Ticket</span>
<p class="text-xs sm:text-xs md:text-xs text-center">Facing an
issue? Click here to raise a new ticket</p>
</div>
</button>

<div class="hidden md:block border-l border-gray-300 h-auto mx-


4"></div>
<!-- View Ticket Button -->
<button
class="flex-grow flex items-center justify-center px-4 py-3
sm:px-6 sm:py-4 md:px-12 md:py-6 text-sm sm:text-lg md:text-2xl
rounded-md border-2 border-blue-500 mb-4 sm:mb-0"
[ngClass]="{'bg-blue-900 text-white': activeTab === 'ViewTicket',
'text-gray-800': activeTab !== 'ViewTicket'}"
(click)="setActiveTab('ViewTicket')">
<div
class="w-8 h-8 sm:w-12 sm:h-12 md:w-16 md:h-16 mr-2 sm:mr-4
flex items-center justify-center rounded-full bg-white">
<img

src="https://s3-alpha-sig.figma.com/img/19cd/6b4c/e6694fc6a7419b15bd92d
423fc9a79ee?Expires=1730073600&Key-Pair-
Id=APKAQ4GOSFWCVNEHN3O4&Signature=FZz6poXP5hSFNA4sVRII2zWB6CI7t2ndObFOL
jTHOTd8o1cXYJqET3Ubi~a-1xb~m-uAW9HVbAppXgtdwUDUzHcWrX5S4UQ5eDwiGw68Y-
FzcnU4uUOwiMkXWdLmImsmh21TEORzw7dD8vDGK-
s0D4LdkUXilU3~T2GNZTGacIpNJV8oaciQ9AQCOQBDn2B3y9Agi8kNpX3N0yZprS8SS8QD4
I868~zvTFrC2zstI-PzXQ-pks48s99QP6LNzLVC2ar~bnuugYCB-KqH-rbaGVZxcI9HdT-
k4X4Zuyx5dVsFZi~fbo5FVdtnKhKvKlLkR6wwV-3Q3~Y2eg8lrl-z9A__"
class="w-6 h-6 sm:w-10 sm:h-10 md:w-12 md:h-12 rounded-full
object-cover bg-gray-200" />
</div>
<div class="flex flex-col items-start">
<span class="font-bold text-xs text-center">View Ticket</span>
<p class="text-xs sm:text-xs md:text-xs text-center">Check the
status of your raised ticket</p>
</div>
</button>

<div class="hidden md:block border-l border-gray-300 h-auto mx-


4"></div>

<!-- Resolve Ticket Button -->


<button
class="flex-grow flex items-center justify-center px-4 py-3
sm:px-6 sm:py-4 md:px-12 md:py-6 text-sm sm:text-lg md:text-2xl
rounded-md border-2 border-blue-500 mb-4 sm:mb-0"
[ngClass]="{'bg-blue-900 text-white': activeTab ===
'ResolveTicket', 'text-gray-800': activeTab !== 'ResolveTicket'}"
(click)="setActiveTab('ResolveTicket')">
<div
class="w-8 h-8 sm:w-12 sm:h-12 md:w-16 md:h-16 mr-2 sm:mr-4
flex items-center justify-center rounded-full bg-white">
<img
src="https://s3-alpha-sig.figma.com/img/f1ba/8777/300946955c8a3a2000f4a
0c83cb3198e?Expires=1730073600&Key-Pair-
Id=APKAQ4GOSFWCVNEHN3O4&Signature=iDsfiEgMdZ6bJyRjcpcPiAD7vkLLI0v2mze28
1uZAW5~kcGzgjzON8EEetpxMhwG1E~nEgCdlYW6qH0aqtM27rcdFK1kFd-JLSmTG3nIHis-
kVbIveN7h4T3o7p4sv8Yj0uvFK2ZAR60t1nBCBSCRJ5dwT9BYDal8dsMNBjVhfivJzyMuK0
SU0gFdjvQWlOPYJoWpxkX-
n9WjqTkykLq2W70f4ucbvKW7fl1FTQ32eHOVVn1slYooSdpv67J133djJmSNRUPWpBwSLAj
SS3WYPjWkZcfi9q49SuTD8o0z0FcIR8ytCjTtut4~2Vgi33DixWmakh-
hGCtVqJ6tpl2gw__"
class="w-6 h-6 sm:w-10 sm:h-10 md:w-12 md:h-12 rounded-full
object-cover bg-gray-200" />
</div>
<div class="flex flex-col items-start">
<span class="font-bold text-xs text-center">Resolve
Ticket</span>
<p class="text-xs sm:text-xs md:text-xs text-center">Check
details and close the ticket</p>
</div>
</button>
</div>
</div>

<!-- Conditional Content Based on Selected Tab -->


<div *ngIf="activeTab === 'RaiseTicket'" class="ticketing-form">
<div *ngIf="!isOpenRaiseTicketView">
<div class="font-inter w-full max-w-[1280px] h-full px-4 py-5
sm:px-6 lg:px-8 lg:py-8 mx-auto">
<fieldset class="mt-8 border border-gray-200 p-6 rounded-lg bg-
white">
<legend class="text-blue-900 text-xs font-semibold px-2">Raise
a Ticket</legend>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
<!-- Service Selection (Required) -->
<div class="flex flex-col">
<label for="service" class="mb-2 text-gray-600 text-
xs">Choose a Service *</label>
<select id="service" [(ngModel)]="ticketData.service"
class="border border-gray-300 text-xs rounded-md p-2
focus:border-blue-500 focus:outline-none" required>
<option value="" disabled>Select a service</option>
<option value="IT">IT</option>
<option value="Maintenance">Maintenance</option>
</select>
<div *ngIf="!ticketData.service && formSubmitted"
class="text-red-500 text-xs mt-1">Service is required
</div>
</div>
<!-- Location Selection (Required) -->
<div class="flex flex-col">
<label for="location" class="mb-2 text-gray-600 text-
xs">Location *</label>
<select id="location" [(ngModel)]="ticketData.location"
class="border border-gray-300 text-xs rounded-md p-2
focus:border-blue-500 focus:outline-none" required>
<option value="" disabled>Location</option>
<option value="Admin block">Admin block</option>
<option value="Main Block">Main block</option>
<option value="PG block">PG block</option>
<option value="humanities block">Humanities
block</option>
</select>
<div *ngIf="!ticketData.location && formSubmitted"
class="text-red-500 text-xs mt-1">Location is required
</div>
</div>

<!-- Priority Selection (Required) -->


<div class="flex flex-col">
<label for="priority" class="mb-2 text-gray-600 text-
xs">Priority *</label>
<select id="priority" [(ngModel)]="ticketData.priority"
class="border border-gray-300 text-xs rounded-md p-2
focus:border-blue-500 focus:outline-none" required>
<option value="" disabled>Select priority</option>
<option value="high">High</option>
<option value="medium">Medium</option>
<option value="low">Low</option>
</select>
<div *ngIf="!ticketData.priority && formSubmitted"
class="text-red-500 text-xs mt-1">Priority is required
</div>
</div>

<div
class="flex flex-col items-center justify-center border-2 border-
dashed border-gray-300 rounded-lg p-3 hover:border-blue-500 transition
ease-in-out duration-300">
<label for="fileUpload" class="flex flex-col items-center space-y-1
cursor-pointer">
<!-- Upload Icon -->
<svg class="w-8 h-8 text-gray-400 group-hover:text-blue-500"
fill="none" stroke="currentColor" viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" stroke-
width="2" d="M12 4v16m8-8H4"></path>
</svg>

<!-- Upload Text -->


<span class="text-gray-600 text-sm font-bold"
id="fileUploadText">Upload a photo</span>

<span class="text-gray-400 text-xs">JPG file size no more than


250kb</span>

<!-- Hidden File Input -->


<input id="fileUpload" type="file" class="hidden"
accept=".jpg,.jpeg" (change)="onFileChange($event)" />
</label>

<!-- Error Message -->


<span id="fileErrorMessage" class="text-red-500 text-xs mt-2
hidden">Only JPG or JPEG files are allowed.</span>
</div>

<div class="flex flex-col sm:col-span-2">


<label for="issueDescription" class="mb-2 text-gray-600
text-xs">Issue Description *</label>
<textarea id="issueDescription"
[(ngModel)]="ticketData.issueDescription"
class="border border-gray-300 text-xs rounded-md p-2
focus:border-blue-500 focus:outline-none h-32 resize-none"
placeholder="Describe your issue here"
required></textarea>
<div *ngIf="!ticketData.issueDescription && formSubmitted"
class="text-red-500 text-xs mt-1">Issue
description is required</div>
</div>
</div>
</fieldset>
<div class="flex justify-between mt-4 p-4">
<button class="bg-gray-500 rounded-md text-xs text-white px-8
py-2" (click)="resetForm()">Clear</button>
<button (click)="submitTicket()"
class="bg-blue-900 rounded-md text-white px-4 py-2 mr-4 text-
xs">Submit</button>
</div>
</div>
</div>
</div>
<!-- File path: src/app/date-filter/date-filter.component.html -->
<div class="flex flex-col w-full items-center mb-6">
<!-- Filters Section (single row on desktop, stacked on mobile) -->
<div *ngIf="activeTab === 'ViewTicket' || activeTab ===
'ResolveTicket'" class="flex flex-wrap items-center justify-between
space-x-4 mb-4 w-full">

<!-- Date Filters (grouped together) -->


<div class="flex flex-wrap items-center space-x-4 border border-
slate-300 p-4 rounded-lg w-full md:w-auto">
<div class="flex items-center w-full sm:w-auto">
<label for="fromDate" class="text-xs font-medium mr-2">From
Date:</label>
<input type="date" id="fromDate" class="text-xs p-2 w-full
sm:w-48 rounded-lg border border-slate-300 focus:ring-2 focus:ring-
blue-500"
(change)="onFromDateChange($event)" [value]="fromDate">
</div>
<div class="flex items-center w-full sm:w-auto">
<label for="toDate" class="text-xs font-medium mr-2">To
Date:</label>
<input type="date" id="toDate" class="text-xs p-2 w-full sm:w-
48 rounded-lg border border-slate-300 focus:ring-2 focus:ring-blue-500"
(change)="onToDateChange($event)" [value]="toDate">
</div>

<!-- Location -->


<div class="flex items-center w-full sm:w-auto">
<label for="location" class="text-xs font-medium mr-
2">Location:</label>
<select id="location" class="text-xs p-2 w-full sm:w-48
rounded-lg border border-slate-300 focus:ring-2 focus:ring-blue-500"
(change)="onLocationChange($event)"
[value]="selectedLocation">
<option value="">All</option>
<option value="Admin block">Admin block</option>
<option value="Main block">Main block</option>
<option value="PG block">PG block</option>
<option value="Humanities block">Humanities block</option>
</select>
</div>

<!-- Service -->


<div class="flex items-center w-full sm:w-auto">
<label for="service" class="text-xs font-medium mr-
2">Service:</label>
<select id="service" class="text-xs p-2 w-full sm:w-48 rounded-lg
border border-slate-300 focus:ring-2 focus:ring-blue-500"
(change)="onServiceChange($event)" [value]="selectedService">
<option value="">All</option>
<option value="IT">IT</option>
<option value="Maintenance">Maintenance</option>
</select>
</div>

<!-- Status -->


<div class="flex items-center w-full sm:w-auto">
<label for="status" class="text-xs font-medium mr-2">Status:</label>
<select id="status" class="text-xs p-2 w-full sm:w-48 rounded-lg
border border-slate-300 focus:ring-2 focus:ring-blue-500"
(change)="onStatusChange($event)" [value]="selectedStatus">
<option value="">All</option>
<option value="OPEN">OPEN</option>
<option value="HOLD">HOLD</option>
<option value="RESOLVED">RESOLVED</option>
<option value="CANCELLED">CANCELLED</option>
</select>
</div>

</div>
</div>
</div>

<!-- Action Buttons Section (aligned to right) -->


<div *ngIf="activeTab === 'ViewTicket' || activeTab ===
'ResolveTicket'" class="flex justify-end w-full pr-4 mt-4">
<button class="text-xs text-slate-50 bg-green-500 hover:bg-green-
600 focus:ring-4 focus:ring-green-300 font-medium rounded-lg px-6 py-2"
(click)="Filter()">Filter</button>
<button class="text-xs text-slate-50 bg-red-500 hover:bg-red-600
focus:ring-4 focus:ring-red-300 font-medium rounded-lg px-6 py-2 ml-4"
(click)="clearDateFilter()">Clear</button>
</div>

<div *ngIf="activeTab === 'ViewTicket'" class="ticket-view">


<!-- Table or component for viewing tickets -->
<div class="filters-container mt-2 mb-4">
<input [(ngModel)]="quickFilterText"
(input)="onQuickFilterInput($event)" placeholder="Search..."
class="border p-2 rounded" />
<button (click)="clearSearch()" class="bg-gray-500 text-white p-2
text-xs rounded ml-2 equal-size-btn">Clear</button>
<button (click)="resetColFilters()" class="bg-red-500 text-white p-
2 text-xs rounded ml-2 equal-size-btn">Reset Column Filters</button>
</div>

<ag-grid-angular style="width: 100%; height: 400px;" class="ag-theme-


alpine" [rowData]="rowData"
[columnDefs]="viewTicketColumnDefs" [pagination]="true"
(gridReady)="onGridReady($event)"
[quickFilterText]="quickFilterText">
</ag-grid-angular>
</div>

<div *ngIf="activeTab === 'ResolveTicket'" class="ticket-resolution">


<!-- Form or component for resolving tickets -->
<div class="filters-container mt-2 text-xs mb-4">
<input [(ngModel)]="quickFilterText"
(input)="onQuickFilterInput($event)" placeholder="Search..."
class="border p-2 text-xs rounded" />
<button (click)="clearSearch()" class="bg-gray-500 text-white p-2
text-xs rounded ml-2">Clear</button>
<button (click)="resetColFilters()" class="bg-red-500 text-white p-
3 text-xs rounded ml-2 reset-btn">Reset Column Filters</button>
</div>
<ag-grid-angular style="width: 100%; height: 400px;" class="ag-theme-
alpine" [rowData]="rowData"
[columnDefs]="resolveTicketColumnDefs" [pagination]="true"
(gridReady)="onGridReady($event)"
[quickFilterText]="quickFilterText">

</ag-grid-angular>
</div>

<!-- Description Modal -->


<div *ngIf="showDescriptionModal"
class="fixed inset-0 flex items-center justify-center bg-black bg-
opacity-50 z-50 transition-opacity duration-300 ease-in-out"
[ngClass]="{'opacity-100': showDescriptionModal, 'opacity-0': !
showDescriptionModal}">
<div
class="bg-white rounded-lg shadow-lg p-6 w-full max-w-md md:max-w-
lg lg:max-w-xl mx-4 relative z-20 transform transition-transform
duration-300 ease-in-out"
[ngClass]="{'scale-100': showDescriptionModal, 'scale-95': !
showDescriptionModal}">
<!-- Close button -->
<button (click)="closeDescriptionModal()"
class="absolute top-4 right-4 text-gray-400 hover:text-gray-600
transition-colors duration-200"
aria-label="Close modal">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6"
fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-
width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>

<h2 class="text-xl font-bold mb-4 pr-8">Ticket Description</h2>


<div class="max-h-[60vh] overflow-y-auto">
<p class="text-gray-700 whitespace-pre-
wrap">{{ selectedDescription }}</p>
</div>
</div>
</div>
<!-- commant modal -->
<div *ngIf="showcommantModal"
class="fixed inset-0 flex items-center justify-center bg-black bg-
opacity-50 z-50 transition-opacity duration-300 ease-in-out"
[ngClass]="{'opacity-100': showcommantModal, 'opacity-0': !
showcommantModal}">
<div
class="bg-white rounded-lg shadow-lg p-6 w-full max-w-md md:max-w-
lg lg:max-w-xl mx-4 relative z-20 transform transition-transform
duration-300 ease-in-out"
[ngClass]="{'scale-100': showcommantModal, 'scale-95': !
showcommantModal}">
<!-- Close button -->
<button (click)="closecommantModal()"
class="absolute top-4 right-4 text-gray-400 hover:text-gray-600
transition-colors duration-200"
aria-label="Close modal">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6"
fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-
width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>

<h2 class="text-xl font-bold mb-4 pr-8">Comments</h2>


<div class="max-h-[60vh] overflow-y-auto">
<p class="text-gray-700 whitespace-pre-
wrap">{{ selectedcomment }}</p>
</div>
</div>
</div>
<!-- comment viewticket -->
<div *ngIf="showcommantviewModal"
class="fixed inset-0 flex items-center justify-center bg-black bg-
opacity-50 z-50 transition-opacity duration-300 ease-in-out"
[ngClass]="{'opacity-100': showcommantviewModal, 'opacity-0': !
showcommantviewModal}">
<div
class="bg-white rounded-lg shadow-lg p-6 w-full max-w-md md:max-w-
lg lg:max-w-xl mx-4 relative z-20 transform transition-transform
duration-300 ease-in-out"
[ngClass]="{'scale-100': showcommantviewModal, 'scale-95': !
showcommantviewModal}">
<!-- Close button -->
<button (click)="closecommantviewModal()"
class="absolute top-4 right-4 text-gray-400 hover:text-gray-600
transition-colors duration-200"
aria-label="Close modal">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6"
fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-
width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>

<h2 class="text-xl font-bold mb-4 pr-8">Comments</h2>


<div class="max-h-[60vh] overflow-y-auto">
<p class="text-gray-700 whitespace-pre-
wrap">{{ selectedcomment }}</p>
</div>
</div>
</div>

<!-- Action Modal -->


<div *ngIf="showActionModal" class="fixed inset-0 bg-black bg-opacity-
50 flex items-center justify-center z-50">
<div class="bg-white rounded-lg p-6 w-96 relative">
<!-- Close button -->
<button (click)="closeActionModal()"
class="absolute top-4 right-4 text-gray-400 hover:text-gray-600
transition-colors duration-200"
aria-label="Close modal">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6"
fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-
width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>

<h2 class="text-xl font-bold mb-4 pr-8">{{selectedAction}}


Ticket</h2>
<div class="mb-4">
<label class="block text-sm font-medium text-gray-700 mb-2">
Reason
</label>
<textarea [(ngModel)]="actionComment"
class="w-full px-3 py-2 border border-gray-300 rounded-md
focus:outline-none focus:ring-1 focus:ring-blue-500"
rows="4" placeholder="Enter your comment here..."></textarea>
<!-- Validation message -->
<p *ngIf="showValidationMessage" class="text-red-500 text-sm mt-
2">Please enter comments</p>
</div>

<div class="flex justify-end">


<button *ngIf="isAdminCancel"
(click)="submitActionWithValidation()" class="bg-blue-900 rounded-md
text-white px-5 py-2 text-xs">
Submit
</button>

<button *ngIf="!isAdminCancel"
(click)="cancelTicketWithValidation()" class="bg-blue-900 rounded-md
text-white px-5 py-2 text-xs">
Submit
</button>
</div>
</div>
</div>

<!-- Image Modal -->


<div class="fixed inset-0 flex items-center justify-center bg-black bg-
opacity-50" *ngIf="showImageModal ">
<div class="relative bg-white p-4 rounded-lg shadow-lg w-full max-w-
sm md:max-w-md">
<button class="absolute top-2 right-4 text-gray-500 hover:text-
gray-800" (click)="closeImageModal()">
&times;
</button>
<h2 class="text-lg font-semibold mb-4">Uploaded file</h2>
<img [src]="userImage" alt="Sample Image" class="max-w-full h-auto
object-contain mx-auto"
style="max-height: 300px;" />
</div>
</div>
<footer class="flex justify-center items-center w-full py-4 mt-8
border-t border-gray-300">
<p class="text-center text-gray-600 text-xs">
Note: Please allow up to 3 working days for your maintenance
request to be addressed. You can check the status of
your ticket anytime through the portal. Thank you for your patience
as we work to resolve your issue!
</p>
</footer>

You might also like