Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions src/app/api/kyc/update/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,17 @@ export async function PUT(req: NextRequest) {
);
}

// Update the KYC record with new status and review timestamp
// Pull rejectionReason if provided
const { id, status, rejectionReason } = body;

// Update the KYC record with new status, review timestamp, and optional reason
const updatedRecord = await KYC.findByIdAndUpdate(
body.id,
id,
{
status: body.status,
status,
reviewed: new Date(),
// only include the field when rejecting
...(rejectionReason ? { rejectionReason } : {}),
},
{ new: true } // Return updated document instead of original
);
Expand Down
35 changes: 31 additions & 4 deletions src/components/Admin/dashboardContent/KYCContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ type KYCRecord = {
nicWithPersonUrl?: string; // URL to photo of person with NIC
frontPhotoUrl?: string; // URL to front photo of ID
backPhotoUrl?: string; // URL to back photo of ID
rejectionReason?: string; // Reason for rejection (if applicable)
};

// Color mapping for different statuses to provide visual feedback
Expand Down Expand Up @@ -207,7 +208,11 @@ export default function KYCContent() {
* @param id The KYC record ID to update
* @param newStatus The new status to set
*/
const updateStatus = async (id: string, newStatus: string) => {
const updateStatus = async (
id: string,
newStatus: string,
reason?: string
) => {
// Prevent duplicate status updates
if (loadingActions.statusUpdates[id]) return;

Expand All @@ -231,6 +236,7 @@ export default function KYCContent() {
body: JSON.stringify({
id,
status: newStatus,
...(reason ? { rejectionReason: reason } : {}),
}),
});

Expand All @@ -246,6 +252,7 @@ export default function KYCContent() {
...record,
status: newStatus,
reviewed: new Date().toISOString(),
...(reason ? { rejectionReason: reason } : {}),
}
: record
)
Expand Down Expand Up @@ -449,6 +456,7 @@ export default function KYCContent() {
<th className="px-4 py-2 text-left">Date Submitted</th>
<th className="px-4 py-2 text-left">Status</th>
<th className="px-4 py-2 text-left">Reviewed</th>
<th className="px-4 py-2 text-left">Rejection Reason</th>
<th className="px-4 py-2 text-left">Documents</th>
<th className="px-4 py-2 text-left">Accept/Reject</th>
</tr>
Expand Down Expand Up @@ -476,6 +484,11 @@ export default function KYCContent() {
<td className="px-4 py-3 border-b">
{record.reviewed ? formatDate(record.reviewed) : "-"}
</td>
<td className="px-4 py-3 border-b">
{record.status === KYC_STATUSES.REJECTED
? record.rejectionReason || "-"
: "-"}
</td>
{/* Document download buttons */}
<td className="px-4 py-3 border-b">
<div className="flex items-center gap-2">
Expand Down Expand Up @@ -553,10 +566,24 @@ export default function KYCContent() {
>
<Check className="h-4 w-4" />
</button>
+{" "}
<button
onClick={() =>
updateStatus(record._id, KYC_STATUSES.REJECTED)
}
onClick={() => {
const reason = window.prompt(
"Please enter a reason for rejection:"
);
if (!reason?.trim()) {
toast.error(
"A rejection reason is required."
);
return;
}
updateStatus(
record._id,
KYC_STATUSES.REJECTED,
reason.trim()
);
}}
className={`p-2 text-white rounded flex items-center justify-center ${
loadingActions.statusUpdates[record._id]
? "bg-red-300 cursor-not-allowed"
Expand Down
12 changes: 12 additions & 0 deletions src/lib/models/KYCSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,18 @@ const KYCSchema = new mongoose.Schema({

// URL to stored image of user holding their NIC (for verification)
nicWithPersonUrl: { type: String },

// Reason why an admin rejected this KYC (required when status === "Rejected")
rejectionReason: {
type: String,
required: [
// annotate `this` so TS knows it has a `.status`
function (this: any): boolean {
return this.status === "Rejected";
},
"Rejection reason is required",
],
},
});

/**
Expand Down
Loading