Files
codey.lol/src/components/qs2/RequestManagement.jsx

465 lines
13 KiB
React
Raw Normal View History

2025-07-31 19:28:59 -04:00
import React, { useState, useEffect } from "react";
import { DataTable } from "primereact/datatable";
import { Column } from "primereact/column";
import { Dropdown } from "primereact/dropdown";
import { Button } from "@mui/joy";
import { toast } from "react-toastify";
import { Dialog } from "primereact/dialog";
2025-07-31 20:25:02 -04:00
import { confirmDialog, ConfirmDialog } from "primereact/confirmdialog";
2025-07-31 19:28:59 -04:00
import BreadcrumbNav from "./BreadcrumbNav";
2025-07-31 20:25:02 -04:00
2025-07-31 19:28:59 -04:00
const STATUS_OPTIONS = ["Pending", "Completed", "Failed"];
const TYPE_OPTIONS = ["Artist", "Album", "Track"];
const initialRequests = [
{
id: 1,
type: "Artist",
artist: "Bring Me The Horizon",
album: "",
track: "",
status: "Pending",
details: {
requestedBy: "codey",
timestamp: "2025-07-01T12:00:00Z",
comments: "",
},
2025-07-31 19:28:59 -04:00
},
{
id: 3,
type: "Track",
artist: "We Butter The Bread With Butter",
album: "Das Album",
track: "20 km/h",
status: "Failed",
details: {
requestedBy: "codey",
timestamp: "2025-06-11T09:00:00Z",
comments: "Track not found in external database.",
},
2025-07-31 19:28:59 -04:00
},
{
id: 3,
2025-07-31 19:28:59 -04:00
type: "Track",
artist: "We Butter The Bread With Butter",
album: "Das Album",
track: "20 km/h",
2025-07-31 19:28:59 -04:00
status: "Completed",
details: {
requestedBy: "codey",
timestamp: "2025-06-11T09:00:00Z",
comments: "Track retrieved succesfully.",
},
2025-07-31 19:28:59 -04:00
},
];
2025-07-31 19:28:59 -04:00
export default function RequestManagement() {
const [requests, setRequests] = useState(initialRequests);
const [filterType, setFilterType] = useState(null);
const [filterStatus, setFilterStatus] = useState(null);
const [filteredRequests, setFilteredRequests] = useState(initialRequests);
const [selectedRequest, setSelectedRequest] = useState(null);
const [isDialogVisible, setIsDialogVisible] = useState(false);
2025-07-31 19:28:59 -04:00
useEffect(() => {
let filtered = [...requests];
if (filterType) {
filtered = filtered.filter((r) => r.type === filterType);
}
if (filterStatus) {
filtered = filtered.filter((r) => r.status === filterStatus);
}
setFilteredRequests(filtered);
}, [filterType, filterStatus, requests]);
const confirmDelete = (requestId) => {
2025-07-31 20:25:02 -04:00
console.log("WHOAA");
2025-07-31 19:28:59 -04:00
confirmDialog({
message: "Are you sure you want to delete this request?",
header: "Confirm Delete",
icon: "pi pi-exclamation-triangle",
accept: () => deleteRequest(requestId),
});
};
const deleteRequest = (requestId) => {
setRequests((prev) => prev.filter((r) => r.id !== requestId));
toast.success("Request deleted");
};
const statusBodyTemplate = (rowData) => {
let colorClass = "";
switch (rowData.status) {
case "Pending":
colorClass = "bg-yellow-300 text-yellow-900";
break;
case "Completed":
colorClass = "bg-green-300 text-green-900";
break;
case "Failed":
colorClass = "bg-red-300 text-red-900";
break;
default:
colorClass = "bg-gray-300 text-gray-900";
}
return (
<span
className={`inline-block px-3 py-1 rounded-full font-semibold text-sm ${colorClass}`}
aria-label={`Status: ${rowData.status}`}
>
{rowData.status}
</span>
);
};
const actionBodyTemplate = (rowData) => {
return (
<Button
color="danger"
size="sm"
onClick={() => confirmDelete(rowData.id)}
variant="outlined"
>
Delete
</Button>
);
};
return (
<div
className="bg-white dark:bg-neutral-900 dark:text-neutral-100 rounded-xl shadow-md border border-neutral-200 dark:border-neutral-700 p-6 space-y-6"
style={{ display: "inline-block" }}
>
<style>{`
.p-datatable {
background-color: white;
color: #1a1a1a;
border-color: #ccc;
}
.p-datatable-header {
background-color: #f9f9f9;
color: #333;
border-bottom: 1px solid #ccc;
}
.p-datatable-thead > tr > th {
background-color: #f0f0f0;
color: #222;
border-bottom: 1px solid #ccc;
}
.p-datatable-tbody > tr > td {
border-bottom: 1px solid #eee;
}
/* Dark mode improvements with brighter text */
[data-theme="dark"] .p-datatable {
background-color: #121212;
color: #f0f0f0; /* brighter text */
border-color: #333;
}
[data-theme="dark"] .p-datatable-header {
background-color: #1f1f1f;
color: #f5f5f5; /* brighter */
border-bottom: 1px solid #444;
}
[data-theme="dark"] .p-datatable-thead > tr > th {
background-color: #222222;
color: #f5f5f5; /* brighter */
border-bottom: 1px solid #555;
}
[data-theme="dark"] .p-datatable-tbody > tr {
background-color: #1a1a1a;
border-bottom: 1px solid #333;
transition: background-color 0.2s ease;
color: #f0f0f0; /* brighter text */
}
/* Zebra stripes */
[data-theme="dark"] .p-datatable-tbody > tr:nth-child(odd) {
background-color: #181818;
color: #f0f0f0;
}
/* Hover effect */
[data-theme="dark"] .p-datatable-tbody > tr:hover {
background-color: #333333;
cursor: pointer;
color: #fff; /* brightest on hover */
}
/* Dropdown inside dark mode */
[data-theme="dark"] .p-dropdown,
[data-theme="dark"] .p-dropdown-label,
[data-theme="dark"] .p-dropdown-panel,
[data-theme="dark"] .p-dropdown-item {
background-color: #2a2a2a !important;
color: #f0f0f0 !important; /* brighter */
}
/* Buttons */
[data-theme="dark"] .p-button {
background-color: transparent !important;
color: #f0f0f0 !important; /* brighter */
border-color: #555 !important;
transition: background-color 0.2s ease;
}
[data-theme="dark"] .p-button:hover {
background-color: #555 !important;
color: #fff !important;
}
[data-theme="dark"] .p-button.p-button-danger {
border-color: #ff4d4f !important;
color: #ff4d4f !important;
}
[data-theme="dark"] .p-button.p-button-danger:hover {
background-color: #ff4d4f !important;
color: #fff !important;
}
/* ===== PrimeReact Paginator Light Mode ===== */
.p-paginator {
background-color: #fff;
color: #1a1a1a;
border-top: 1px solid #ddd;
}
.p-paginator .p-paginator-page,
.p-paginator .p-paginator-next,
.p-paginator .p-paginator-prev {
color: #1a1a1a;
border: none;
background: transparent;
}
.p-paginator .p-highlight {
background-color: #007bff;
color: white;
border-radius: 6px;
}
/* ===== PrimeReact Paginator Dark Mode ===== */
[data-theme="dark"] .p-paginator {
background-color: #121212;
color: #f0f0f0;
border-top: 1px solid #333;
}
[data-theme="dark"] .p-paginator .p-paginator-page,
[data-theme="dark"] .p-paginator .p-paginator-next,
[data-theme="dark"] .p-paginator .p-paginator-prev {
color: #ccc;
border: none;
background: transparent;
}
[data-theme="dark"] .p-paginator .p-paginator-page:hover,
[data-theme="dark"] .p-paginator .p-paginator-next:hover,
[data-theme="dark"] .p-paginator .p-paginator-prev:hover {
background-color: #333;
color: #fff;
border-radius: 6px;
}
[data-theme="dark"] .p-paginator .p-highlight {
background-color: #3b82f6; /* Tailwind blue-500 */
color: white;
border-radius: 6px;
}
.p-paginator .p-paginator-first,
.p-paginator .p-paginator-last {
color: #1a1a1a;
background: transparent;
border: none;
}
.p-paginator .p-paginator-first:hover,
.p-paginator .p-paginator-last:hover {
background-color: #f0f0f0;
border-radius: 6px;
}
/* Dark Mode: First/Last page buttons */
[data-theme="dark"] .p-paginator .p-paginator-first,
[data-theme="dark"] .p-paginator .p-paginator-last {
color: #ccc;
background: transparent;
border: none;
}
[data-theme="dark"] .p-paginator .p-paginator-first:hover,
[data-theme="dark"] .p-paginator .p-paginator-last:hover {
background-color: #333;
color: #fff;
border-radius: 6px;
2025-07-31 20:25:02 -04:00
}
/* ConfirmDialog - Light Theme */
.p-confirm-dialog {
background-color: #ffffff;
color: #1a1a1a;
border: 1px solid #ccc;
}
.p-confirm-dialog .p-dialog-header {
background-color: #f5f5f5;
color: #222;
}
.p-confirm-dialog .p-dialog-content {
background-color: #ffffff;
color: #333;
}
.p-confirm-dialog .p-dialog-footer {
background-color: #fafafa;
border-top: 1px solid #ddd;
}
.p-confirm-dialog .p-button {
border-radius: 0.5rem;
}
/* ConfirmDialog - Dark Theme */
[data-theme='dark'] .p-confirm-dialog {
background-color: #2a2a2a;
color: #e5e5e5;
border: 1px solid #444;
}
[data-theme='dark'] .p-confirm-dialog .p-dialog-header {
background-color: #1f1f1f;
color: #ddd;
}
[data-theme='dark'] .p-confirm-dialog .p-dialog-content {
background-color: #2a2a2a;
color: #ccc;
}
[data-theme='dark'] .p-confirm-dialog .p-dialog-footer {
background-color: #242424;
border-top: 1px solid #333;
}
[data-theme='dark'] .p-confirm-dialog .p-button {
background-color: transparent !important;
color: #ddd !important;
border-color: #555 !important;
}
[data-theme='dark'] .p-confirm-dialog .p-button.p-button-danger {
color: #ff4d4f !important;
border-color: #ff4d4f !important;
}
[data-theme='dark'] .p-dialog-title {
color: #eee;
}
[data-theme='dark'] .p-dialog-header-icon {
color: #ccc;
}
/* PrimeReact Dialog Theming */
.p-dialog {
background-color: #ffffff;
color: #000000;
}
2025-07-31 20:25:02 -04:00
[data-theme="dark"] .p-dialog {
background-color: #1e1e1e;
color: #ffffff;
}
[data-theme="dark"] .p-dialog .p-dialog-header {
background-color: #1e1e1e;
border-bottom: 1px solid #444;
}
[data-theme="dark"] .p-dialog .p-dialog-content {
background-color: #2a2a2a;
color: #ffffff;
}
[data-theme="dark"] .p-dialog .p-dialog-footer {
background-color: #1e1e1e;
border-top: 1px solid #444;
}
2025-07-31 20:25:02 -04:00
`}</style>
2025-07-31 19:28:59 -04:00
<BreadcrumbNav currentPage="management" />
<h2 className="text-3xl font-semibold" style={{ marginTop: 0 }}>
Media Request Management
</h2>
<div className="flex flex-wrap gap-6 mb-6">
<Dropdown
value={filterType}
options={[
{ label: "All Types", value: null },
...TYPE_OPTIONS.map((t) => ({ label: t, value: t })),
]}
onChange={(e) => setFilterType(e.value)}
placeholder="Filter by Type"
className="min-w-[180px]"
/>
<Dropdown
value={filterStatus}
options={[
{ label: "All Statuses", value: null },
...STATUS_OPTIONS.map((s) => ({ label: s, value: s })),
]}
onChange={(e) => setFilterStatus(e.value)}
placeholder="Filter by Status"
className="min-w-[180px]"
/>
</div>
<DataTable
value={filteredRequests}
paginator
rows={10}
removableSort
sortMode="multiple"
emptyMessage="No requests found."
rowClassName="!py-4"
className="min-w-full bg-white dark:bg-neutral-900 text-neutral-900 dark:text-neutral-100"
onRowClick={(e) => {
setSelectedRequest(e.data);
setIsDialogVisible(true);
}}
2025-07-31 19:28:59 -04:00
>
<Column field="id" header="ID" sortable style={{ width: "5rem" }} />
<Column field="type" header="Type" sortable />
<Column field="artist" header="Artist" sortable />
<Column field="album" header="Album" sortable />
<Column field="track" header="Track" sortable />
<Column
field="status"
header="Status"
body={statusBodyTemplate}
style={{ width: "10rem", textAlign: "center" }}
sortable
/>
<Column
body={actionBodyTemplate}
header="Actions"
style={{ width: "9rem", textAlign: "center" }}
/>
</DataTable>
2025-07-31 20:25:02 -04:00
<ConfirmDialog />
<Dialog
header="Request Details"
visible={isDialogVisible}
style={{ width: "500px" }}
onHide={() => setIsDialogVisible(false)}
breakpoints={{ '960px': '95vw' }}
>
{selectedRequest && (
<div className="space-y-4 text-sm">
<p><strong>ID:</strong> {selectedRequest.id}</p>
<p><strong>Type:</strong> {selectedRequest.type}</p>
<p><strong>Artist:</strong> {selectedRequest.artist}</p>
{selectedRequest.album && <p><strong>Album:</strong> {selectedRequest.album}</p>}
{selectedRequest.track && <p><strong>Track:</strong> {selectedRequest.track}</p>}
<p><strong>Status:</strong> {selectedRequest.status}</p>
{selectedRequest.details && (
<>
<p><strong>Requested By:</strong> {selectedRequest.details.requestedBy}</p>
<p><strong>Timestamp:</strong> {new Date(selectedRequest.details.timestamp).toLocaleString()}</p>
{selectedRequest.details.comments && (
<p><strong>Comments:</strong> {selectedRequest.details.comments}</p>
)}
</>
)}
</div>
)}
</Dialog>
2025-07-31 19:28:59 -04:00
</div>
);
}