Feat : Create a group of backend team and assign ticket to the respective backend member
This commit is contained in:
parent
d436ef05d8
commit
b4da641769
@ -20,7 +20,8 @@ DB_PORT=5432
|
||||
DB_NAME=crm
|
||||
DB_USER_NAME=
|
||||
DB_USER_PASS
|
||||
|
||||
#Mantis
|
||||
MantisBT_Token=
|
||||
#CBS
|
||||
ONLINE_CBS_IP=
|
||||
ONLINE_CBS_PORT=
|
||||
@ -119,6 +120,6 @@ Here we are using "mantisBT" (open source application) for ticket management sys
|
||||
- Go to "My account".
|
||||
- Then create a API token.
|
||||
- Copy the API token.
|
||||
- And paste the token to those `route.ts` file of `CRM Customer Module` where the mantisBT API is calling.
|
||||
- And paste the token in `.env.local` file in place of `MantisBT_Token`
|
||||
- create development team's user as protected.
|
||||
- create a project, and keep the name as "KCCB".
|
@ -14,7 +14,6 @@ async function queryUser() {
|
||||
const response = await axios.get<User>('/api/user');
|
||||
user = response.data;
|
||||
} catch (error: AxiosError | any) {
|
||||
console.log(error);
|
||||
notifications.show({
|
||||
color: 'red',
|
||||
title: error.code,
|
||||
|
@ -7,6 +7,9 @@ export class Ticket {
|
||||
// @PrimaryColumn("int")
|
||||
id!: number
|
||||
|
||||
@PrimaryColumn()
|
||||
ticket_id! : number
|
||||
|
||||
@Column("varchar")
|
||||
category_of_request! : string
|
||||
|
||||
@ -24,6 +27,9 @@ export class Ticket {
|
||||
@Column('varchar')
|
||||
created_by! : string
|
||||
|
||||
@Column('bigint')
|
||||
customer_account_no! : number
|
||||
|
||||
@Column('varchar')
|
||||
created_date! : string
|
||||
|
||||
|
@ -11,7 +11,7 @@ class AppDataSource {
|
||||
username: process.env.DB_USER_NAME,
|
||||
password: process.env.DB_USER_PASS,
|
||||
database: process.env.DB_NAME,
|
||||
//dropSchema: process.env.NODE_ENV === 'development',
|
||||
// dropSchema: process.env.NODE_ENV === 'development',
|
||||
synchronize: process.env.NODE_ENV === 'development',
|
||||
logging: false,
|
||||
entities: [User,Ticket],
|
||||
|
@ -21,7 +21,6 @@ export async function GET(request: Request) {
|
||||
|
||||
}
|
||||
catch (error) {
|
||||
console.error(error);
|
||||
return Response.json(null, { status: 500 })
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,6 @@ export async function POST(req: Request) {
|
||||
const session = await getIronSession<SessionPayload>(cookies(), getSessionOptions())
|
||||
const body = await req.json();
|
||||
const { AccNo } = body;
|
||||
console.log(AccNo)
|
||||
if (!AccNo || AccNo === '') {
|
||||
return Response.json({ message: "Account No can't be empty" })
|
||||
}
|
||||
@ -25,18 +24,16 @@ export async function POST(req: Request) {
|
||||
.getRawOne();
|
||||
|
||||
if (!user)
|
||||
return Response.json({ message: 'Please Enter Valid Account No Or contact to administrator.' })
|
||||
return Response.json({ message: 'Please Enter Valid Account No Or contact to administrator.' },{status:404})
|
||||
|
||||
session.accountNo = user.bank_account_no;
|
||||
session.TwoStepAuthentication = false;
|
||||
session.otp = NaN;
|
||||
session.expiryTime = NaN;
|
||||
await session.save();
|
||||
//console.log(session);
|
||||
return Response.json({ ok: true })
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return Response.json(null, { status: 500 })
|
||||
}
|
||||
}
|
@ -15,7 +15,6 @@ export async function POST(request: Request) {
|
||||
return Response.json({message: 'logout successfully'});
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return Response.json(null, { status: 500 })
|
||||
}
|
||||
}
|
@ -31,7 +31,6 @@ export async function GET(request: Request) {
|
||||
return Response.json({ done: true });
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return Response.json("Failed", { status: 500 });
|
||||
|
||||
}
|
||||
|
@ -21,16 +21,13 @@ export async function GET(request: Request , { params }: { params: { account_no:
|
||||
if (user_mob_no.mobile_number == null)
|
||||
return Response.json({ message: "Mobile number is not updated.Please contact with administrator" })
|
||||
|
||||
console.log(user_mob_no.mobile_number)
|
||||
//session.otp = NaN;
|
||||
//session.mobileNo = user_mob_no.mobile_number;
|
||||
await session.save();
|
||||
console.log(session);
|
||||
return Response.json(user_mob_no)
|
||||
|
||||
}
|
||||
catch (error) {
|
||||
console.error(error);
|
||||
return Response.json(null, { status: 500 })
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,6 @@ export async function GET(req: Request) {
|
||||
session.expiryTime=Date.now() + 90 * 1000;
|
||||
|
||||
await session.save();
|
||||
//console.log(session);
|
||||
const maskedPartMobNo= 'x'.repeat(mobileNumber.toString().length -3);
|
||||
const lastThreeDigit= mobileNumber.toString().slice(-3);
|
||||
console.log( "OTP :" , otp);
|
||||
@ -40,7 +39,6 @@ export async function GET(req: Request) {
|
||||
|
||||
}
|
||||
catch (error) {
|
||||
console.error(error);
|
||||
return Response.json(null, { status: 500 })
|
||||
}
|
||||
}
|
||||
@ -61,14 +59,12 @@ export async function POST(req: Request) {
|
||||
if (!OTP || OTP === '' || Number.isNaN(OTP))
|
||||
return Response.json({ message: "OTP field can not be blank" })
|
||||
|
||||
console.log(session)
|
||||
// Check for OTP expiry time
|
||||
if(Date.now()> session.expiryTime){
|
||||
session.otp =NaN;
|
||||
session.expiryTime=NaN;
|
||||
await session.save();
|
||||
}
|
||||
//console.log(session);
|
||||
if(Number.isNaN(session.otp))
|
||||
return Response.json({ error: "The OTP Session has timed out "},{status:401})
|
||||
|
||||
@ -77,12 +73,10 @@ export async function POST(req: Request) {
|
||||
|
||||
session.TwoStepAuthentication = true;
|
||||
await session.save();
|
||||
//console.log(session);
|
||||
return Response.json({ ok: true })
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
console.error(error);
|
||||
return Response.json(null, { status: 500 })
|
||||
}
|
||||
}
|
83
src/app/api/ticket/[ticket_id]/route.ts
Normal file
83
src/app/api/ticket/[ticket_id]/route.ts
Normal file
@ -0,0 +1,83 @@
|
||||
import { getIronSession } from "iron-session";
|
||||
import { cookies } from "next/headers";
|
||||
import AppDataSource from "@/app/_data/source/app-data-source";
|
||||
import { User } from "@/app/_data/entities/User";
|
||||
import SessionPayload from "../../auth/session/payload";
|
||||
import getSessionOptions from "../../auth/session/options";
|
||||
|
||||
export async function GET(req: Request, { params }: { params: { ticket_id: number }})
|
||||
{
|
||||
try {
|
||||
const session = await getIronSession<SessionPayload>(cookies(), getSessionOptions());
|
||||
console.log("Session :",session);
|
||||
if (!session.TwoStepAuthentication) {
|
||||
return Response.json(null);
|
||||
}
|
||||
|
||||
if (!session.accountNo) {
|
||||
return Response.json({ message: `Please sign in before raise a ticket` })
|
||||
}
|
||||
|
||||
const connection_crm = await AppDataSource.getConnection();
|
||||
//const connection_mantis = await AppDataSource.getMantisConnection();
|
||||
const userRepo = connection_crm.getRepository(User);
|
||||
const user_table = await userRepo.createQueryBuilder('user')
|
||||
.select(['first_name', 'middle_name', 'last_name'])
|
||||
.where("user.bank_account_no = :AccountNo", { AccountNo: session.accountNo })
|
||||
.getRawOne();
|
||||
|
||||
const user_name = (user_table.first_name ? user_table.first_name + ' ' : '') +
|
||||
(user_table.middle_name ? user_table.middle_name + ' ' : '') +
|
||||
(user_table.last_name ? user_table.last_name + ' ' : '');
|
||||
|
||||
const ticketRepo = connection_crm.getRepository(Ticket);
|
||||
const ticket_list = await ticketRepo.createQueryBuilder('ticket')
|
||||
.select(['id', 'category_of_request', 'nature_of_request', 'created_date','additional_info'])
|
||||
.where("ticket.created_by = :created_by", { created_by: user_name }).getRawMany();
|
||||
|
||||
if(!ticket_list){return Response.json('No Details Found')}
|
||||
const ticket_ids = ticket_list.map(ticket => ticket.id);
|
||||
// Mantis-database fetching for "status" & "message"
|
||||
const queryRunner = connection_mantis.createQueryRunner();
|
||||
await queryRunner.connect();
|
||||
let ticketResolution: { [key: number]: string } = {};
|
||||
let ticketMessage: { [key: number]: string[] } = {};
|
||||
|
||||
for (const id of ticket_ids) {
|
||||
// For status of ticket
|
||||
const ticket_resolution = await queryRunner.query('SELECT resolution,handler_id FROM "kccb_bug" WHERE id = $1', [id]);
|
||||
const ticket_status =ticket_resolution[0]?.resolution
|
||||
const ticket_handler =ticket_resolution[0]?.handler_id
|
||||
let status :string ='';
|
||||
if(ticket_status === 10 && ticket_handler === 0){status = 'Open'}
|
||||
if(ticket_handler > 0){status = 'In Progress'}
|
||||
if(ticket_status === 20){status='Resolved'}
|
||||
if(ticket_status === 30){status='Reopen'}
|
||||
ticketResolution[id] = status
|
||||
|
||||
// For Message of ticket
|
||||
const ticket_note = await queryRunner.query('SELECT id FROM "kccb_bugnote" WHERE bug_id = $1', [id]);
|
||||
const ticket_note_ids =ticket_note.map((item:{id:number}) =>item.id)
|
||||
|
||||
for(const note_id of ticket_note_ids ){
|
||||
const ticket_note_text = await queryRunner.query('SELECT note FROM "kccb_bugnote_text" WHERE id = $1', [note_id]);
|
||||
if (!ticketMessage[id]) {
|
||||
ticketMessage[id] = [];
|
||||
}
|
||||
ticketMessage[id].push(...ticket_note_text);
|
||||
}
|
||||
}
|
||||
const result = ticket_list.map(item =>
|
||||
(
|
||||
{
|
||||
...item,status:ticketResolution[item.id]||null,message: ticketMessage[item.id]||null
|
||||
}
|
||||
)
|
||||
)
|
||||
queryRunner.release();
|
||||
return Response.json(result)
|
||||
}
|
||||
catch (error) {
|
||||
return Response.json(null, { status: 500 });
|
||||
}
|
||||
}
|
28
src/app/api/ticket/assign_memeber.ts
Normal file
28
src/app/api/ticket/assign_memeber.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import AppDataSource from "@/app/_data/source/app-data-source";
|
||||
|
||||
export async function assignUser(category_of_complaint :string) {
|
||||
const connection_mantis = await AppDataSource.getMantisConnection();
|
||||
let assign_team_id,random_assignee;
|
||||
if(category_of_complaint === 'ATM Related'){
|
||||
assign_team_id = 12 ;
|
||||
}
|
||||
if(category_of_complaint === 'Internet Banking'){
|
||||
assign_team_id = 13 ;
|
||||
}
|
||||
if(category_of_complaint === 'Mobile Banking'){
|
||||
assign_team_id = 14 ;
|
||||
}
|
||||
if(category_of_complaint === 'Others'){
|
||||
assign_team_id = 15 ;
|
||||
}
|
||||
const queryRunner = connection_mantis.createQueryRunner();
|
||||
await queryRunner.connect();
|
||||
const query = await queryRunner.query('SELECT id,username FROM "kccb_user" WHERE access_level = $1', [assign_team_id]);
|
||||
if(query.length == 0)
|
||||
random_assignee = 1 ;
|
||||
else{
|
||||
const team_list =query.map((row: { id: any; }) =>row.id)
|
||||
random_assignee = team_list[Math.floor(Math.random()* team_list.length)]
|
||||
}
|
||||
return random_assignee;
|
||||
}
|
@ -5,6 +5,7 @@ import SessionPayload from "../auth/session/payload";
|
||||
import AppDataSource from "@/app/_data/source/app-data-source";
|
||||
import { Ticket } from "@/app/_data/entities/Ticket";
|
||||
import { User } from "@/app/_data/entities/User";
|
||||
import { assignUser } from "./assign_memeber";
|
||||
|
||||
|
||||
export async function POST(request: Request) {
|
||||
@ -16,36 +17,53 @@ export async function POST(request: Request) {
|
||||
if (!session.accountNo) {
|
||||
return Response.json({ message: `Please sign in before raise a ticket` })
|
||||
}
|
||||
|
||||
if (!session.TwoStepAuthentication) {
|
||||
return Response.json(null);
|
||||
}
|
||||
//console.log(new Date().toLocaleString("en-IN"));
|
||||
const URL = "http://localhost/crm_internal/api/rest/issues/";
|
||||
|
||||
|
||||
const mantisBT_Token =process.env.MantisBT_Token || ""; //MantisBT Token
|
||||
console.log(mantisBT_Token);
|
||||
const body = await request.json();
|
||||
//request_category, nature_of_request, issue, message
|
||||
const { summary, description, additional_information, steps_to_reproduce } = body;
|
||||
const project = { id: 1 };
|
||||
const requestBody = { ...body, project };
|
||||
const result = await (await fetch(URL, {
|
||||
const response_for_issue_ticket = await (await fetch(`http://localhost/crm_internal/api/rest/issues/`, {
|
||||
method: "POST",
|
||||
headers:
|
||||
{ "Content-Type": "application/json", "Authorization": "M7xHFMiZcg_oPrGZoRY-kPoivoniK3BO" },
|
||||
{ "Content-Type": "application/json", "Authorization": mantisBT_Token },
|
||||
body: JSON.stringify(requestBody)
|
||||
}))
|
||||
if (result.status === 403) {
|
||||
if (response_for_issue_ticket.status === 403) {
|
||||
return Response.json({ message: 'Invalid Token' }, { status: 403 })
|
||||
}
|
||||
if (result.status === 400) {
|
||||
if (response_for_issue_ticket.status === 400) {
|
||||
return Response.json({ message: 'Project not specified' }, { status: 400 })
|
||||
}
|
||||
if (result.status === 404) {
|
||||
if (response_for_issue_ticket.status === 404) {
|
||||
return Response.json({ message: 'Project not found' }, { status: 404 })
|
||||
}
|
||||
if (result.status === 429) {
|
||||
if (response_for_issue_ticket.status === 429) {
|
||||
return Response.json({ message: 'Please raised ticket after sometime.' }, { status: 429 })
|
||||
}
|
||||
|
||||
// Assign backend team to the ticket
|
||||
const issue_id = parseInt(response_for_issue_ticket.statusText);
|
||||
const assign_person = await assignUser(summary);
|
||||
const response_for_assignee_issue_ticket = await (await fetch(`http://localhost/CRM_Internal/api/rest/issues/${issue_id}`, {
|
||||
method: "PATCH",
|
||||
headers:
|
||||
{ "Content-Type": "application/json", "Authorization": mantisBT_Token },
|
||||
body: JSON.stringify({handler :{ id : assign_person }})
|
||||
}))
|
||||
if (response_for_assignee_issue_ticket.status === 403) {
|
||||
return Response.json({ message: 'Invalid Token' }, { status: 403 })
|
||||
}
|
||||
if(response_for_assignee_issue_ticket.status ==200)
|
||||
{
|
||||
console.log("Assignee is assign against the ticket");
|
||||
}
|
||||
///CRM database management
|
||||
const connection_crm = await AppDataSource.getConnection();
|
||||
const userRepo = connection_crm.getRepository(User);
|
||||
@ -60,19 +78,19 @@ export async function POST(request: Request) {
|
||||
|
||||
const ticketRepo = connection_crm.getRepository(Ticket);
|
||||
const ticket = new Ticket();
|
||||
ticket.ticket_id = parseInt(response_for_issue_ticket.statusText);
|
||||
ticket.category_of_request = summary;
|
||||
ticket.nature_of_request = description;
|
||||
ticket.additional_info = additional_information
|
||||
ticket.message = steps_to_reproduce;
|
||||
ticket.created_by = user_name;
|
||||
//ticket.created_date = new Date().toString();
|
||||
ticket.customer_account_no = Number(session.accountNo);
|
||||
ticket.created_date=new Date().toLocaleString("en-IN");
|
||||
|
||||
|
||||
await ticketRepo.save(ticket);
|
||||
return Response.json({ message: `Ticket No:${result.statusText} created successfully` })
|
||||
return Response.json({ message: `Ticket No:${response_for_issue_ticket.statusText} created successfully` })
|
||||
}
|
||||
catch (error) {
|
||||
console.error(error);
|
||||
return Response.json(null, { status: 500 });
|
||||
}
|
||||
}
|
||||
@ -84,30 +102,32 @@ export async function GET(request: Request) {
|
||||
if (!session.TwoStepAuthentication) {
|
||||
return Response.json(null);
|
||||
}
|
||||
|
||||
if (!session.accountNo) {
|
||||
return Response.json({ message: `Please sign in before raise a ticket` })
|
||||
}
|
||||
|
||||
const connection_crm = await AppDataSource.getConnection();
|
||||
const connection_mantis = await AppDataSource.getMantisConnection();
|
||||
const userRepo = connection_crm.getRepository(User);
|
||||
// Get full name of user
|
||||
const user_table = await userRepo.createQueryBuilder('user')
|
||||
.select(['first_name', 'middle_name', 'last_name'])
|
||||
.where("user.bank_account_no = :AccountNo", { AccountNo: session.accountNo })
|
||||
.getRawOne();
|
||||
|
||||
const user_name = (user_table.first_name ? user_table.first_name + ' ' : '') +
|
||||
(user_table.middle_name ? user_table.middle_name + ' ' : '') +
|
||||
(user_table.last_name ? user_table.last_name + ' ' : '');
|
||||
|
||||
const ticketRepo = connection_crm.getRepository(Ticket);
|
||||
// Get list of ticket raised by the user
|
||||
const ticket_list = await ticketRepo.createQueryBuilder('ticket')
|
||||
.select(['id', 'category_of_request', 'nature_of_request', 'created_date','additional_info'])
|
||||
.where("ticket.created_by = :created_by", { created_by: user_name }).getRawMany();
|
||||
|
||||
.select(['id','ticket_id', 'category_of_request', 'nature_of_request', 'created_date','additional_info'])
|
||||
.where("ticket.created_by = :created_by" , { created_by: user_name })
|
||||
.andWhere("ticket.customer_account_no = :customer_account_no" ,{customer_account_no:session.accountNo })
|
||||
.getRawMany();
|
||||
|
||||
if(!ticket_list){return Response.json('No Details Found')}
|
||||
const ticket_ids = ticket_list.map(ticket => ticket.id);
|
||||
const ticket_ids = ticket_list.map(ticket => ticket.ticket_id); // collect the ticket_id (ticket_id store the mantisBT's bug id)
|
||||
|
||||
// Mantis-database fetching for "status" & "message"
|
||||
const queryRunner = connection_mantis.createQueryRunner();
|
||||
await queryRunner.connect();
|
||||
@ -125,31 +145,31 @@ export async function GET(request: Request) {
|
||||
if(ticket_status === 20){status='Resolved'}
|
||||
if(ticket_status === 30){status='Reopen'}
|
||||
ticketResolution[id] = status
|
||||
|
||||
// For Message of ticket
|
||||
const ticket_note = await queryRunner.query('SELECT id FROM "kccb_bugnote" WHERE bug_id = $1', [id]);
|
||||
const ticket_note_ids =ticket_note.map((item:{id:number}) =>item.id)
|
||||
const ticket_note = await queryRunner.query('SELECT bugnote_text_id FROM "kccb_bugnote" WHERE bug_id = $1', [id]);
|
||||
const ticket_note_ids =ticket_note.map((item:{bugnote_text_id:number}) =>item.bugnote_text_id) // collect all ids from kccb_bugnote table for a issue
|
||||
|
||||
for(const note_id of ticket_note_ids ){
|
||||
const ticket_note_text = await queryRunner.query('SELECT note FROM "kccb_bugnote_text" WHERE id = $1', [note_id]);
|
||||
|
||||
if (!ticketMessage[id]) {
|
||||
ticketMessage[id] = [];
|
||||
}
|
||||
ticketMessage[id].push(...ticket_note_text);
|
||||
}
|
||||
}
|
||||
const result = ticket_list.map(item =>
|
||||
// merge message & status in the response
|
||||
const response_for_issue_ticket = ticket_list.map(item =>
|
||||
(
|
||||
{
|
||||
...item,status:ticketResolution[item.id]||null,message: ticketMessage[item.id]||null
|
||||
...item,status:ticketResolution[item.ticket_id]||null,message: ticketMessage[item.ticket_id]||null
|
||||
}
|
||||
)
|
||||
)
|
||||
queryRunner.release();
|
||||
return Response.json(result)
|
||||
return Response.json(response_for_issue_ticket)
|
||||
}
|
||||
catch (error) {
|
||||
console.error(error);
|
||||
return Response.json(null, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
@ -24,15 +24,12 @@ export async function GET(request: Request) {
|
||||
.select(["id","bank_account_no"])
|
||||
.where("user.bank_account_no = :userAccountNo", { userAccountNo: session.accountNo })
|
||||
.getRawOne();
|
||||
|
||||
//console.log(session)
|
||||
// if (!user_details || session.TwoStepAuthentication === false)
|
||||
if (!user_details)
|
||||
return Response.json({ message: "User_details not found" }, { status: 404 });
|
||||
|
||||
return Response.json(user_details);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return Response.json(null, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,6 @@ async function logout() {
|
||||
try {
|
||||
await axios.post('/api/auth/logout');
|
||||
} catch (error: AxiosError | any) {
|
||||
console.log(error);
|
||||
notifications.show({
|
||||
color: 'red',
|
||||
title: error.code,
|
||||
|
@ -5,11 +5,14 @@ import { UserContextConsumer } from "../_components/user-context";
|
||||
export default function Home() {
|
||||
return (
|
||||
<>
|
||||
<p>Welcome to CRM Portal</p>
|
||||
<p>For Issue a ticket ,click on create ticket</p>
|
||||
<p>Welcome to CRM Portal</p>
|
||||
<UserContextConsumer>
|
||||
{user => user && <p>Account No: {user.bank_account_no}</p>}
|
||||
{
|
||||
user => user && <p><b>Your Present Login Account No: {user.bank_account_no}</b></p>
|
||||
}
|
||||
</UserContextConsumer>
|
||||
<p><li>For raise a complain or assistance ,please click on <b>Create Ticket</b></li></p>
|
||||
<p><li>For track a ticket ,please click on <b>View Ticket</b></li></p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ const ComplaintForm: React.FC = () => {
|
||||
}
|
||||
|
||||
const requestBody = {
|
||||
summary: description,
|
||||
summary: category,
|
||||
description: description,
|
||||
additional_information: additionalInformation.join(", "),
|
||||
steps_to_reproduce: message,
|
||||
@ -116,7 +116,6 @@ const ComplaintForm: React.FC = () => {
|
||||
try {
|
||||
const response = await axios.post("/api/ticket", requestBody);
|
||||
const data = await response.data;
|
||||
console.log('API response:', data);
|
||||
alert(data.message);
|
||||
window.location.reload();
|
||||
}
|
||||
@ -146,9 +145,9 @@ const ComplaintForm: React.FC = () => {
|
||||
<option value="" disabled>
|
||||
Select Category
|
||||
</option>
|
||||
<option value="ATM">ATM Related</option>
|
||||
<option value="IB">Internet Banking</option>
|
||||
<option value="MB">Mobile Banking</option>
|
||||
<option value="ATM Related">ATM Related</option>
|
||||
<option value="Internet Banking">Internet Banking</option>
|
||||
<option value="Mobile Banking">Mobile Banking</option>
|
||||
<option value="Others">Others</option>
|
||||
</select>
|
||||
</label>
|
||||
@ -165,16 +164,16 @@ const ComplaintForm: React.FC = () => {
|
||||
<option value="" disabled>
|
||||
Select Description
|
||||
</option>
|
||||
{category === "ATM" && <option value="Transaction Issue">Transaction Issue</option>}
|
||||
{category === "UPI" && <option value="UPI Issue">UPI Issue</option>}
|
||||
{category === "IB" && (
|
||||
{category === "ATM Related" && <option value="Transaction Issue">Transaction Issue</option>}
|
||||
{/* {category === "UPI" && <option value="UPI Issue">UPI Issue</option>} */}
|
||||
{category === "Internet Banking" && (
|
||||
<>
|
||||
{/* <option value="IMPS">IMPS Funds Transfer</option> */}
|
||||
<option value="Fund Transfer failure">Fund Transfer Failure</option>
|
||||
<option value="Network Issue">Network Issue</option>
|
||||
</>
|
||||
)}
|
||||
{category === "MB" && (
|
||||
{category === "Mobile Banking" && (
|
||||
<>
|
||||
{/* <option value="IMPS">IMPS Funds Transfer</option> */}
|
||||
<option value="Fund Transfer failure">Fund Transfer Failure</option>
|
||||
|
@ -23,7 +23,7 @@ interface Message {
|
||||
}
|
||||
|
||||
interface Ticket {
|
||||
id: string;
|
||||
ticket_id: string;
|
||||
category_of_request: string;
|
||||
nature_of_request: string;
|
||||
created_date: string;
|
||||
@ -42,7 +42,7 @@ export default function Page() {
|
||||
useEffect(() => {
|
||||
const sortedTickets = [...tickets].sort(
|
||||
// (a, b) => new Date(b.created_date).getTime() - new Date(a.created_date).getTime()
|
||||
(a, b) => parseInt(b.id) - parseInt(a.id)
|
||||
(a, b) => parseInt(b.ticket_id) - parseInt(a.ticket_id)
|
||||
);
|
||||
const results = sortedTickets.filter((ticket) =>
|
||||
ticket.category_of_request.toLowerCase().includes(searchQuery.toLowerCase())
|
||||
@ -69,18 +69,19 @@ export default function Page() {
|
||||
};
|
||||
|
||||
//Add conditional row styles
|
||||
const getRowStyle = (status: string) => {
|
||||
switch (status.toLowerCase()) {
|
||||
case "resolved":
|
||||
return { backgroundColor: "#e0e3df", color: "#000"}; // Grey for closed
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
};
|
||||
// const getRowStyle = (status: string) => {
|
||||
// switch (status.toLowerCase()) {
|
||||
// case "resolved":
|
||||
// return { backgroundColor: "#e0e3df", color: "#000"}; // Grey for closed
|
||||
// default:
|
||||
// return {};
|
||||
// }
|
||||
// };
|
||||
|
||||
const rows = filteredTickets.map((ticket) => (
|
||||
<Table.Tr key={ticket.id} style={getRowStyle(ticket.status)}>
|
||||
<Table.Td>{ticket.id}</Table.Td>
|
||||
// <Table.Tr key={ticket.ticket_id} style={getRowStyle(ticket.status)}>
|
||||
<Table.Tr key={ticket.ticket_id}>
|
||||
<Table.Td>{ticket.ticket_id}</Table.Td>
|
||||
<Table.Td>{ticket.category_of_request}</Table.Td>
|
||||
<Table.Td>{ticket.nature_of_request}</Table.Td>
|
||||
<Table.Td>{ticket.created_date}</Table.Td>
|
||||
|
@ -1,159 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import {
|
||||
ActionIcon,
|
||||
Button,
|
||||
Container,
|
||||
Flex,
|
||||
Group,
|
||||
Modal,
|
||||
Space,
|
||||
Table,
|
||||
TextInput,
|
||||
Title,
|
||||
Tooltip,
|
||||
} from "@mantine/core";
|
||||
import { useDisclosure } from "@mantine/hooks";
|
||||
import { IconMessage, IconSearch } from "@tabler/icons-react";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
interface Message {
|
||||
note: string;
|
||||
}
|
||||
|
||||
interface Ticket {
|
||||
id: string;
|
||||
category_of_request: string;
|
||||
nature_of_request: string;
|
||||
created_date: string;
|
||||
status: string;
|
||||
message: Message[];
|
||||
}
|
||||
|
||||
export default function Page() {
|
||||
const [opened, { open, close }] = useDisclosure(false);
|
||||
const [tickets, setTickets] = useState<Ticket[]>([]);
|
||||
const [searchQuery, setSearchQuery] = useState("");
|
||||
const [filteredTickets, setFilteredTickets] = useState<Ticket[]>([]);
|
||||
const [filteredUsers, setFilteredUsers] = useState<Ticket[]>([]);
|
||||
const [activeMessages, setActiveMessages] = useState<Message[] | null>(null);
|
||||
|
||||
// Fetch tickets from the API
|
||||
const fetchTickets = async () => {
|
||||
try {
|
||||
const response = await fetch("/api/ticket");
|
||||
if (!response.ok) {
|
||||
throw new Error("Failed to fetch tickets");
|
||||
}
|
||||
const data: Ticket[] = await response.json();
|
||||
setTickets(data);
|
||||
setFilteredTickets(data); // Set initial filtered tickets
|
||||
} catch (error) {
|
||||
console.error("Error fetching tickets:", error);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchTickets(); // Call API when component mounts
|
||||
}, []);
|
||||
|
||||
// Filter tickets based on the search query
|
||||
useEffect(() => {
|
||||
const results = tickets.filter((ticket) =>
|
||||
ticket.category_of_request.toLowerCase().includes(searchQuery.toLowerCase())
|
||||
);
|
||||
setFilteredTickets(results);
|
||||
}, [searchQuery, tickets]);
|
||||
|
||||
const handleOpenMessage = (messages: Message[]) => {
|
||||
setActiveMessages(messages);
|
||||
open();
|
||||
};
|
||||
|
||||
const rows = filteredUsers.map((ticket) => (
|
||||
<Table.Tr key={ticket.id}>
|
||||
<Table.Td>{ticket.id}</Table.Td>
|
||||
<Table.Td>{ticket.category_of_request}</Table.Td>
|
||||
<Table.Td>{ticket.nature_of_request}</Table.Td>
|
||||
<Table.Td>{ticket.created_date}</Table.Td>
|
||||
<Table.Td>{ticket.status}</Table.Td>
|
||||
<Table.Td>
|
||||
<Group>
|
||||
<ActionIcon
|
||||
variant="subtle"
|
||||
onClick={() => handleOpenMessage(ticket.message)}
|
||||
>
|
||||
<Tooltip label="Message">
|
||||
<IconMessage />
|
||||
</Tooltip>
|
||||
</ActionIcon>
|
||||
</Group>
|
||||
</Table.Td>
|
||||
</Table.Tr>
|
||||
));
|
||||
|
||||
return (
|
||||
<Container fluid>
|
||||
<Title order={3}>View Ticket</Title>
|
||||
<Space h="1rem" />
|
||||
<Flex align="center" justify="space-between" w={720}>
|
||||
<Flex align="center">
|
||||
<Title order={5}>Tickets</Title>
|
||||
<Space w="1rem" />
|
||||
<TextInput
|
||||
placeholder="Search"
|
||||
value={searchQuery}
|
||||
onChange={(event) => setSearchQuery(event.currentTarget.value)}
|
||||
radius="md"
|
||||
w={250}
|
||||
leftSection={<IconSearch size={16} />}
|
||||
/>
|
||||
</Flex>
|
||||
</Flex>
|
||||
|
||||
<Space h="1.5rem" />
|
||||
<Table
|
||||
w={720}
|
||||
stickyHeader
|
||||
stickyHeaderOffset={60}
|
||||
withTableBorder
|
||||
highlightOnHover
|
||||
horizontalSpacing="lg"
|
||||
>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Ticket ID</th>
|
||||
<th>Category</th>
|
||||
<th>Description</th>
|
||||
<th>Timestamp</th>
|
||||
<th>Status</th>
|
||||
<th>Message</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>{rows}</tbody>
|
||||
</Table>
|
||||
|
||||
<Modal opened={opened} onClose={close} title="Message">
|
||||
<Flex direction="column" gap="sm">
|
||||
{activeMessages?.map((msg, index) => (
|
||||
<div
|
||||
key={index}
|
||||
style={{
|
||||
padding: "0.5rem",
|
||||
background: index % 2 === 0 ? "#f1f3f5" : "#dce6f2",
|
||||
borderRadius: "8px",
|
||||
maxWidth: "70%",
|
||||
}}
|
||||
>
|
||||
{msg.note}
|
||||
</div>
|
||||
))}
|
||||
<Button onClick={close} mt="sm">
|
||||
Close
|
||||
</Button>
|
||||
</Flex>
|
||||
</Modal>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
@ -29,7 +29,6 @@ async function handleResendOTP() {
|
||||
// Object.assign(response.data);
|
||||
alert(response.data.message);
|
||||
} catch (error: AxiosError | any) {
|
||||
console.log(error);
|
||||
notifications.show({
|
||||
color: 'red',
|
||||
title: error.code,
|
||||
@ -49,13 +48,13 @@ async function handleValidateOTP(OtpInput: OtpInput) {
|
||||
}
|
||||
Object.assign(Result, response.data);
|
||||
} catch (error: AxiosError | any) {
|
||||
console.log(error);
|
||||
notifications.show({
|
||||
color: 'red',
|
||||
title: error.response.status,
|
||||
message: error.response.data.error
|
||||
alert(error.response.data.error);
|
||||
// notifications.show({
|
||||
// color: 'red',
|
||||
// title: error.response.status,
|
||||
// message: error.response.data.error
|
||||
|
||||
})
|
||||
// })
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
@ -20,25 +20,24 @@ type Result = {
|
||||
message?: string
|
||||
}
|
||||
async function handleRequestOTP(SendAccNoInput: SendAccNoInput) {
|
||||
|
||||
|
||||
let Result: Result = { ok: false }
|
||||
try {
|
||||
const response = await axios.post("/api/auth/login/account_no", SendAccNoInput);
|
||||
if (response.data.ok) {
|
||||
const otp_response = await axios.get("/api/otp");
|
||||
if (otp_response.status === 200) {
|
||||
// redirect('/otp');
|
||||
window.location.href = 'login/otp'
|
||||
}
|
||||
}
|
||||
Object.assign(Result, response.data);
|
||||
} catch (error: AxiosError | any) {
|
||||
console.log(error);
|
||||
notifications.show({
|
||||
color: 'red',
|
||||
title: error.response.status,
|
||||
message: error.response.data.message
|
||||
})
|
||||
alert(error.response.data.message)
|
||||
// notifications.show({
|
||||
// color: 'red',
|
||||
// title: error.response.status,
|
||||
// message: error.response.data.message
|
||||
// })
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user