Prettier format pending files
This commit is contained in:
parent
3371f2a53b
commit
170b5747bd
16 changed files with 130 additions and 123 deletions
|
|
@ -2,7 +2,7 @@ import { createClient } from "@supabase/supabase-js";
|
|||
|
||||
const supabase = createClient(
|
||||
process.env.VITE_SUPABASE_URL!,
|
||||
process.env.SUPABASE_SERVICE_ROLE!
|
||||
process.env.SUPABASE_SERVICE_ROLE!,
|
||||
);
|
||||
|
||||
export default async function handler(req: any, res: any) {
|
||||
|
|
@ -18,11 +18,9 @@ export default async function handler(req: any, res: any) {
|
|||
|
||||
res.status(200).json(achievements || []);
|
||||
} catch (error: any) {
|
||||
res
|
||||
.status(500)
|
||||
.json({
|
||||
error: error.message || "Failed to fetch achievements",
|
||||
});
|
||||
res.status(500).json({
|
||||
error: error.message || "Failed to fetch achievements",
|
||||
});
|
||||
}
|
||||
} else {
|
||||
res.status(405).json({ error: "Method not allowed" });
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { createClient } from "@supabase/supabase-js";
|
|||
|
||||
const supabase = createClient(
|
||||
process.env.VITE_SUPABASE_URL!,
|
||||
process.env.SUPABASE_SERVICE_ROLE!
|
||||
process.env.SUPABASE_SERVICE_ROLE!,
|
||||
);
|
||||
|
||||
export default async function handler(req: any, res: any) {
|
||||
|
|
@ -26,7 +26,7 @@ export default async function handler(req: any, res: any) {
|
|||
id,
|
||||
full_name
|
||||
)
|
||||
`
|
||||
`,
|
||||
)
|
||||
.order("created_at", { ascending: false });
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { createClient } from "@supabase/supabase-js";
|
|||
|
||||
const supabase = createClient(
|
||||
process.env.VITE_SUPABASE_URL!,
|
||||
process.env.SUPABASE_SERVICE_ROLE!
|
||||
process.env.SUPABASE_SERVICE_ROLE!,
|
||||
);
|
||||
|
||||
export default async function handler(req: any, res: any) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { createClient } from "@supabase/supabase-js";
|
|||
|
||||
const supabase = createClient(
|
||||
process.env.VITE_SUPABASE_URL!,
|
||||
process.env.SUPABASE_SERVICE_ROLE!
|
||||
process.env.SUPABASE_SERVICE_ROLE!,
|
||||
);
|
||||
|
||||
export default async function handler(req: any, res: any) {
|
||||
|
|
@ -25,7 +25,7 @@ export default async function handler(req: any, res: any) {
|
|||
full_name,
|
||||
email
|
||||
)
|
||||
`
|
||||
`,
|
||||
)
|
||||
.order("created_at", { ascending: false });
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { createClient } from "@supabase/supabase-js";
|
|||
|
||||
const supabase = createClient(
|
||||
process.env.VITE_SUPABASE_URL!,
|
||||
process.env.SUPABASE_SERVICE_ROLE!
|
||||
process.env.SUPABASE_SERVICE_ROLE!,
|
||||
);
|
||||
|
||||
export default async function handler(req: any, res: any) {
|
||||
|
|
@ -21,7 +21,8 @@ export default async function handler(req: any, res: any) {
|
|||
.update({
|
||||
approval_status,
|
||||
approved_by: req.user?.id, // Assumes middleware sets req.user
|
||||
approved_at: approval_status === "approved" ? new Date().toISOString() : null,
|
||||
approved_at:
|
||||
approval_status === "approved" ? new Date().toISOString() : null,
|
||||
})
|
||||
.eq("user_id", id)
|
||||
.select();
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { createClient } from "@supabase/supabase-js";
|
|||
|
||||
const supabase = createClient(
|
||||
process.env.VITE_SUPABASE_URL!,
|
||||
process.env.SUPABASE_SERVICE_ROLE!
|
||||
process.env.SUPABASE_SERVICE_ROLE!,
|
||||
);
|
||||
|
||||
export default async function handler(req: any, res: any) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { createClient } from "@supabase/supabase-js";
|
|||
|
||||
const supabase = createClient(
|
||||
process.env.VITE_SUPABASE_URL!,
|
||||
process.env.SUPABASE_SERVICE_ROLE!
|
||||
process.env.SUPABASE_SERVICE_ROLE!,
|
||||
);
|
||||
|
||||
export default async function handler(req: any, res: any) {
|
||||
|
|
@ -22,7 +22,7 @@ export default async function handler(req: any, res: any) {
|
|||
id,
|
||||
email
|
||||
)
|
||||
`
|
||||
`,
|
||||
)
|
||||
.order("created_at", { ascending: false });
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { createClient } from "@supabase/supabase-js";
|
|||
|
||||
const supabase = createClient(
|
||||
process.env.VITE_SUPABASE_URL!,
|
||||
process.env.SUPABASE_SERVICE_ROLE!
|
||||
process.env.SUPABASE_SERVICE_ROLE!,
|
||||
);
|
||||
|
||||
export default async function handler(req: any, res: any) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { createClient } from "@supabase/supabase-js";
|
|||
|
||||
const supabase = createClient(
|
||||
process.env.VITE_SUPABASE_URL!,
|
||||
process.env.SUPABASE_SERVICE_ROLE!
|
||||
process.env.SUPABASE_SERVICE_ROLE!,
|
||||
);
|
||||
|
||||
export default async function handler(req: any, res: any) {
|
||||
|
|
@ -25,7 +25,7 @@ export default async function handler(req: any, res: any) {
|
|||
id,
|
||||
email
|
||||
)
|
||||
`
|
||||
`,
|
||||
)
|
||||
.order("created_at", { ascending: false });
|
||||
|
||||
|
|
@ -46,11 +46,9 @@ export default async function handler(req: any, res: any) {
|
|||
|
||||
res.status(200).json(formattedOpp);
|
||||
} catch (error: any) {
|
||||
res
|
||||
.status(500)
|
||||
.json({
|
||||
error: error.message || "Failed to fetch opportunities",
|
||||
});
|
||||
res.status(500).json({
|
||||
error: error.message || "Failed to fetch opportunities",
|
||||
});
|
||||
}
|
||||
} else {
|
||||
res.status(405).json({ error: "Method not allowed" });
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { createClient } from "@supabase/supabase-js";
|
|||
|
||||
const supabase = createClient(
|
||||
process.env.VITE_SUPABASE_URL!,
|
||||
process.env.SUPABASE_SERVICE_ROLE!
|
||||
process.env.SUPABASE_SERVICE_ROLE!,
|
||||
);
|
||||
|
||||
export default async function handler(req: any, res: any) {
|
||||
|
|
@ -14,7 +14,11 @@ export default async function handler(req: any, res: any) {
|
|||
const updateData: any = {};
|
||||
|
||||
if (status) {
|
||||
if (!["open", "in_progress", "filled", "closed", "cancelled"].includes(status)) {
|
||||
if (
|
||||
!["open", "in_progress", "filled", "closed", "cancelled"].includes(
|
||||
status,
|
||||
)
|
||||
) {
|
||||
return res.status(400).json({ error: "Invalid status" });
|
||||
}
|
||||
updateData.status = status;
|
||||
|
|
@ -37,11 +41,9 @@ export default async function handler(req: any, res: any) {
|
|||
|
||||
res.status(200).json(data);
|
||||
} catch (error: any) {
|
||||
res
|
||||
.status(500)
|
||||
.json({
|
||||
error: error.message || "Failed to update opportunity",
|
||||
});
|
||||
res.status(500).json({
|
||||
error: error.message || "Failed to update opportunity",
|
||||
});
|
||||
}
|
||||
} else {
|
||||
res.status(405).json({ error: "Method not allowed" });
|
||||
|
|
|
|||
|
|
@ -11,13 +11,7 @@ export default async function handler(req: any, res: any) {
|
|||
|
||||
try {
|
||||
if (method === "GET") {
|
||||
const {
|
||||
id,
|
||||
project_id,
|
||||
build_type,
|
||||
limit = 50,
|
||||
offset = 0,
|
||||
} = query;
|
||||
const { id, project_id, build_type, limit = 50, offset = 0 } = query;
|
||||
|
||||
if (id) {
|
||||
// Get single build
|
||||
|
|
|
|||
|
|
@ -34,10 +34,8 @@ export default async function handler(req: any, res: any) {
|
|||
}
|
||||
|
||||
// List all projects with filters
|
||||
let dbQuery = supabase
|
||||
.from("gameforge_projects")
|
||||
.select(
|
||||
`
|
||||
let dbQuery = supabase.from("gameforge_projects").select(
|
||||
`
|
||||
id,
|
||||
name,
|
||||
description,
|
||||
|
|
@ -52,8 +50,8 @@ export default async function handler(req: any, res: any) {
|
|||
created_at,
|
||||
user_profiles!lead_id(id, full_name, avatar_url)
|
||||
`,
|
||||
{ count: "exact" },
|
||||
);
|
||||
{ count: "exact" },
|
||||
);
|
||||
|
||||
if (status) dbQuery = dbQuery.eq("status", status);
|
||||
if (platform) dbQuery = dbQuery.eq("platform", platform);
|
||||
|
|
@ -140,9 +138,7 @@ export default async function handler(req: any, res: any) {
|
|||
.single();
|
||||
|
||||
if (project?.lead_id !== userId) {
|
||||
return res
|
||||
.status(403)
|
||||
.json({ error: "Only project lead can update" });
|
||||
return res.status(403).json({ error: "Only project lead can update" });
|
||||
}
|
||||
|
||||
const updateData: any = {};
|
||||
|
|
@ -157,7 +153,8 @@ export default async function handler(req: any, res: any) {
|
|||
updateData.actual_release_date = actual_release_date;
|
||||
if (budget !== undefined) updateData.budget = budget;
|
||||
if (current_spend !== undefined) updateData.current_spend = current_spend;
|
||||
if (repository_url !== undefined) updateData.repository_url = repository_url;
|
||||
if (repository_url !== undefined)
|
||||
updateData.repository_url = repository_url;
|
||||
if (documentation_url !== undefined)
|
||||
updateData.documentation_url = documentation_url;
|
||||
|
||||
|
|
|
|||
|
|
@ -13,15 +13,13 @@ export default async function handler(req: any, res: any) {
|
|||
if (method === "GET") {
|
||||
const { user_id, project_id, role, limit = 50, offset = 0 } = query;
|
||||
|
||||
let dbQuery = supabase
|
||||
.from("gameforge_team_members")
|
||||
.select(
|
||||
`
|
||||
let dbQuery = supabase.from("gameforge_team_members").select(
|
||||
`
|
||||
*,
|
||||
user_profiles(id, full_name, avatar_url, email)
|
||||
`,
|
||||
{ count: "exact" },
|
||||
);
|
||||
{ count: "exact" },
|
||||
);
|
||||
|
||||
if (user_id) dbQuery = dbQuery.eq("user_id", user_id).single();
|
||||
if (project_id) dbQuery = dbQuery.contains("project_ids", [project_id]);
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ export default function AdminFoundationManager() {
|
|||
const [selectedMentor, setSelectedMentor] = useState<Mentor | null>(null);
|
||||
const [approvalDialogOpen, setApprovalDialogOpen] = useState(false);
|
||||
const [approvalAction, setApprovalAction] = useState<"approve" | "reject">(
|
||||
"approve"
|
||||
"approve",
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -146,12 +146,12 @@ export default function AdminFoundationManager() {
|
|||
method: "PUT",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ approval_status: approvalAction }),
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
if (!response.ok) throw new Error("Failed to update mentor");
|
||||
aethexToast.success(
|
||||
`Mentor ${approvalAction === "approve" ? "approved" : "rejected"}`
|
||||
`Mentor ${approvalAction === "approve" ? "approved" : "rejected"}`,
|
||||
);
|
||||
setApprovalDialogOpen(false);
|
||||
setSelectedMentor(null);
|
||||
|
|
@ -164,16 +164,17 @@ export default function AdminFoundationManager() {
|
|||
|
||||
const handlePublishCourse = async (courseId: string, publish: boolean) => {
|
||||
try {
|
||||
const response = await fetch(`/api/admin/foundation/courses/${courseId}`, {
|
||||
method: "PUT",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ is_published: publish }),
|
||||
});
|
||||
const response = await fetch(
|
||||
`/api/admin/foundation/courses/${courseId}`,
|
||||
{
|
||||
method: "PUT",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ is_published: publish }),
|
||||
},
|
||||
);
|
||||
|
||||
if (!response.ok) throw new Error("Failed to update course");
|
||||
aethexToast.success(
|
||||
`Course ${publish ? "published" : "unpublished"}`
|
||||
);
|
||||
aethexToast.success(`Course ${publish ? "published" : "unpublished"}`);
|
||||
fetchCourses();
|
||||
} catch (error) {
|
||||
aethexToast.error("Failed to update course");
|
||||
|
|
@ -183,9 +184,12 @@ export default function AdminFoundationManager() {
|
|||
|
||||
const handleDeleteCourse = async (courseId: string) => {
|
||||
try {
|
||||
const response = await fetch(`/api/admin/foundation/courses/${courseId}`, {
|
||||
method: "DELETE",
|
||||
});
|
||||
const response = await fetch(
|
||||
`/api/admin/foundation/courses/${courseId}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
},
|
||||
);
|
||||
|
||||
if (!response.ok) throw new Error("Failed to delete course");
|
||||
aethexToast.success("Course deleted");
|
||||
|
|
@ -197,20 +201,18 @@ export default function AdminFoundationManager() {
|
|||
};
|
||||
|
||||
const filteredMentors = mentors.filter((m) =>
|
||||
(m.user_name || "")
|
||||
.toLowerCase()
|
||||
.includes(searchMentor.toLowerCase())
|
||||
(m.user_name || "").toLowerCase().includes(searchMentor.toLowerCase()),
|
||||
);
|
||||
|
||||
const filteredCourses = courses.filter((c) =>
|
||||
c.title.toLowerCase().includes(searchCourse.toLowerCase())
|
||||
c.title.toLowerCase().includes(searchCourse.toLowerCase()),
|
||||
);
|
||||
|
||||
const pendingMentors = filteredMentors.filter(
|
||||
(m) => m.approval_status === "pending"
|
||||
(m) => m.approval_status === "pending",
|
||||
);
|
||||
const approvedMentors = filteredMentors.filter(
|
||||
(m) => m.approval_status === "approved"
|
||||
(m) => m.approval_status === "approved",
|
||||
);
|
||||
|
||||
const publishedCourses = courses.filter((c) => c.is_published).length;
|
||||
|
|
@ -484,7 +486,7 @@ export default function AdminFoundationManager() {
|
|||
onClick={() =>
|
||||
handlePublishCourse(
|
||||
course.id,
|
||||
!course.is_published
|
||||
!course.is_published,
|
||||
)
|
||||
}
|
||||
>
|
||||
|
|
@ -534,10 +536,7 @@ export default function AdminFoundationManager() {
|
|||
{achievement.description}
|
||||
</p>
|
||||
<div className="flex gap-2 mt-3">
|
||||
<Badge
|
||||
variant="secondary"
|
||||
className="text-xs"
|
||||
>
|
||||
<Badge variant="secondary" className="text-xs">
|
||||
{achievement.requirement_type}
|
||||
</Badge>
|
||||
<Badge variant="outline" className="text-xs">
|
||||
|
|
@ -555,10 +554,15 @@ export default function AdminFoundationManager() {
|
|||
</Tabs>
|
||||
|
||||
{/* Approval Dialog */}
|
||||
<AlertDialog open={approvalDialogOpen} onOpenChange={setApprovalDialogOpen}>
|
||||
<AlertDialog
|
||||
open={approvalDialogOpen}
|
||||
onOpenChange={setApprovalDialogOpen}
|
||||
>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogTitle>
|
||||
{approvalAction === "approve" ? "Approve Mentor?" : "Reject Mentor?"}
|
||||
{approvalAction === "approve"
|
||||
? "Approve Mentor?"
|
||||
: "Reject Mentor?"}
|
||||
</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
{approvalAction === "approve" ? (
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ export default function AdminGameForgeStudio() {
|
|||
// Fetch builds and metrics if project selected
|
||||
if (selectedProject) {
|
||||
const buildsRes = await fetch(
|
||||
`/api/gameforge/builds?project_id=${selectedProject}`
|
||||
`/api/gameforge/builds?project_id=${selectedProject}`,
|
||||
);
|
||||
if (buildsRes.ok) {
|
||||
const { data } = await buildsRes.json();
|
||||
|
|
@ -124,7 +124,7 @@ export default function AdminGameForgeStudio() {
|
|||
}
|
||||
|
||||
const metricsRes = await fetch(
|
||||
`/api/gameforge/metrics?project_id=${selectedProject}`
|
||||
`/api/gameforge/metrics?project_id=${selectedProject}`,
|
||||
);
|
||||
if (metricsRes.ok) {
|
||||
const { data } = await metricsRes.json();
|
||||
|
|
@ -142,8 +142,9 @@ export default function AdminGameForgeStudio() {
|
|||
|
||||
// Calculate KPIs
|
||||
const totalTeamSize = teamMembers.filter((m) => m.is_active).length;
|
||||
const activeProjects = projects.filter((p) => p.status === "in_development")
|
||||
.length;
|
||||
const activeProjects = projects.filter(
|
||||
(p) => p.status === "in_development",
|
||||
).length;
|
||||
const totalBudget = projects.reduce((sum, p) => sum + (p.budget || 0), 0);
|
||||
const totalSpent = projects.reduce(
|
||||
(sum, p) => sum + (p.current_spend || 0),
|
||||
|
|
@ -194,7 +195,9 @@ export default function AdminGameForgeStudio() {
|
|||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-3xl font-bold text-white">{activeProjects}</div>
|
||||
<div className="text-3xl font-bold text-white">
|
||||
{activeProjects}
|
||||
</div>
|
||||
<p className="text-sm text-slate-400 mt-1">in development</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
|
@ -302,16 +305,16 @@ export default function AdminGameForgeStudio() {
|
|||
return (
|
||||
<div key={project.id} className="flex items-center gap-3">
|
||||
<div className="flex-1">
|
||||
<p className="text-white font-medium">
|
||||
{project.name}
|
||||
</p>
|
||||
<p className="text-white font-medium">{project.name}</p>
|
||||
<p className="text-xs text-slate-400">
|
||||
{project.status}
|
||||
</p>
|
||||
</div>
|
||||
<Badge
|
||||
className={
|
||||
isOnSchedule ? "bg-green-500/20 text-green-400" : "bg-red-500/20 text-red-400"
|
||||
isOnSchedule
|
||||
? "bg-green-500/20 text-green-400"
|
||||
: "bg-red-500/20 text-red-400"
|
||||
}
|
||||
>
|
||||
{isOnSchedule ? "On Time" : "Delayed"}
|
||||
|
|
|
|||
|
|
@ -79,12 +79,14 @@ export default function AdminNexusManager() {
|
|||
const [loadingDisputes, setLoadingDisputes] = useState(true);
|
||||
const [loadingCommissions, setLoadingCommissions] = useState(true);
|
||||
const [searchOpp, setSearchOpp] = useState("");
|
||||
const [disputeFilter, setDisputeFilter] = useState<"all" | "open" | "resolved">("all");
|
||||
const [disputeFilter, setDisputeFilter] = useState<
|
||||
"all" | "open" | "resolved"
|
||||
>("all");
|
||||
const [selectedDispute, setSelectedDispute] = useState<Dispute | null>(null);
|
||||
const [disputeDialogOpen, setDisputeDialogOpen] = useState(false);
|
||||
const [disputeResolution, setDisputeResolution] = useState("");
|
||||
const [disputeAction, setDisputeAction] = useState<"resolve" | "escalate">(
|
||||
"resolve"
|
||||
"resolve",
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -140,7 +142,7 @@ export default function AdminNexusManager() {
|
|||
|
||||
const handleModerateOpportunity = async (
|
||||
opportunityId: string,
|
||||
status: "open" | "filled" | "closed" | "cancelled"
|
||||
status: "open" | "filled" | "closed" | "cancelled",
|
||||
) => {
|
||||
try {
|
||||
const response = await fetch(
|
||||
|
|
@ -149,7 +151,7 @@ export default function AdminNexusManager() {
|
|||
method: "PUT",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ status }),
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
if (!response.ok) throw new Error("Failed to update opportunity");
|
||||
|
|
@ -163,7 +165,7 @@ export default function AdminNexusManager() {
|
|||
|
||||
const handleFeatureOpportunity = async (
|
||||
opportunityId: string,
|
||||
featured: boolean
|
||||
featured: boolean,
|
||||
) => {
|
||||
try {
|
||||
const response = await fetch(
|
||||
|
|
@ -172,12 +174,12 @@ export default function AdminNexusManager() {
|
|||
method: "PUT",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ is_featured: featured }),
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
if (!response.ok) throw new Error("Failed to update opportunity");
|
||||
aethexToast.success(
|
||||
`Opportunity ${featured ? "featured" : "unfeatured"}`
|
||||
`Opportunity ${featured ? "featured" : "unfeatured"}`,
|
||||
);
|
||||
fetchOpportunities();
|
||||
} catch (error) {
|
||||
|
|
@ -199,12 +201,12 @@ export default function AdminNexusManager() {
|
|||
status: disputeAction === "resolve" ? "resolved" : "escalated",
|
||||
resolution_notes: disputeResolution,
|
||||
}),
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
if (!response.ok) throw new Error("Failed to update dispute");
|
||||
aethexToast.success(
|
||||
`Dispute ${disputeAction === "resolve" ? "resolved" : "escalated"}`
|
||||
`Dispute ${disputeAction === "resolve" ? "resolved" : "escalated"}`,
|
||||
);
|
||||
setDisputeDialogOpen(false);
|
||||
setSelectedDispute(null);
|
||||
|
|
@ -217,7 +219,7 @@ export default function AdminNexusManager() {
|
|||
};
|
||||
|
||||
const filteredOpportunities = opportunities.filter((o) =>
|
||||
o.title.toLowerCase().includes(searchOpp.toLowerCase())
|
||||
o.title.toLowerCase().includes(searchOpp.toLowerCase()),
|
||||
);
|
||||
|
||||
const filteredDisputes = disputes.filter((d) => {
|
||||
|
|
@ -228,12 +230,12 @@ export default function AdminNexusManager() {
|
|||
});
|
||||
|
||||
const openOpportunities = opportunities.filter(
|
||||
(o) => o.status === "open"
|
||||
(o) => o.status === "open",
|
||||
).length;
|
||||
const openDisputes = disputes.filter((d) => d.status === "open").length;
|
||||
const totalCommissionsRevenue = commissions.reduce(
|
||||
(sum, c) => sum + c.aethex_revenue,
|
||||
0
|
||||
0,
|
||||
);
|
||||
|
||||
return (
|
||||
|
|
@ -261,7 +263,9 @@ export default function AdminNexusManager() {
|
|||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-2xl font-bold text-red-500">{openDisputes}</div>
|
||||
<div className="text-2xl font-bold text-red-500">
|
||||
{openDisputes}
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground mt-1">
|
||||
Requires attention
|
||||
</p>
|
||||
|
|
@ -302,7 +306,10 @@ export default function AdminNexusManager() {
|
|||
{/* Tabs */}
|
||||
<Tabs defaultValue="opportunities" className="w-full">
|
||||
<TabsList className="grid w-full grid-cols-3">
|
||||
<TabsTrigger value="opportunities" className="flex items-center gap-2">
|
||||
<TabsTrigger
|
||||
value="opportunities"
|
||||
className="flex items-center gap-2"
|
||||
>
|
||||
<Briefcase className="h-4 w-4" />
|
||||
Opportunities
|
||||
</TabsTrigger>
|
||||
|
|
@ -333,7 +340,9 @@ export default function AdminNexusManager() {
|
|||
{loadingOpp ? (
|
||||
<Card>
|
||||
<CardContent className="pt-6">
|
||||
<p className="text-muted-foreground">Loading opportunities...</p>
|
||||
<p className="text-muted-foreground">
|
||||
Loading opportunities...
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
) : filteredOpportunities.length === 0 ? (
|
||||
|
|
@ -360,8 +369,8 @@ export default function AdminNexusManager() {
|
|||
opp.status === "open"
|
||||
? "bg-green-50"
|
||||
: opp.status === "filled"
|
||||
? "bg-blue-50"
|
||||
: "bg-gray-50"
|
||||
? "bg-blue-50"
|
||||
: "bg-gray-50"
|
||||
}
|
||||
>
|
||||
{opp.status}
|
||||
|
|
@ -386,7 +395,7 @@ export default function AdminNexusManager() {
|
|||
onClick={() =>
|
||||
handleFeatureOpportunity(
|
||||
opp.id,
|
||||
!opp.is_featured
|
||||
!opp.is_featured,
|
||||
)
|
||||
}
|
||||
>
|
||||
|
|
@ -408,10 +417,7 @@ export default function AdminNexusManager() {
|
|||
size="sm"
|
||||
variant="destructive"
|
||||
onClick={() =>
|
||||
handleModerateOpportunity(
|
||||
opp.id,
|
||||
"cancelled"
|
||||
)
|
||||
handleModerateOpportunity(opp.id, "cancelled")
|
||||
}
|
||||
>
|
||||
<XCircle className="h-4 w-4" />
|
||||
|
|
@ -429,7 +435,10 @@ export default function AdminNexusManager() {
|
|||
{/* DISPUTES TAB */}
|
||||
<TabsContent value="disputes" className="space-y-4">
|
||||
<div className="flex gap-2">
|
||||
<Select value={disputeFilter} onValueChange={(v: any) => setDisputeFilter(v)}>
|
||||
<Select
|
||||
value={disputeFilter}
|
||||
onValueChange={(v: any) => setDisputeFilter(v)}
|
||||
>
|
||||
<SelectTrigger className="w-40">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
|
|
@ -458,9 +467,7 @@ export default function AdminNexusManager() {
|
|||
{filteredDisputes.map((dispute) => (
|
||||
<Card
|
||||
key={dispute.id}
|
||||
className={
|
||||
dispute.status === "open" ? "border-red-300" : ""
|
||||
}
|
||||
className={dispute.status === "open" ? "border-red-300" : ""}
|
||||
>
|
||||
<CardContent className="pt-6">
|
||||
<div className="flex items-start justify-between">
|
||||
|
|
@ -474,8 +481,8 @@ export default function AdminNexusManager() {
|
|||
dispute.status === "open"
|
||||
? "bg-red-50"
|
||||
: dispute.status === "escalated"
|
||||
? "bg-orange-50"
|
||||
: "bg-green-50"
|
||||
? "bg-orange-50"
|
||||
: "bg-green-50"
|
||||
}
|
||||
>
|
||||
{dispute.status}
|
||||
|
|
@ -536,7 +543,7 @@ export default function AdminNexusManager() {
|
|||
<p className="text-xs text-muted-foreground">Period</p>
|
||||
<p className="font-medium text-sm">
|
||||
{new Date(
|
||||
commission.period_start
|
||||
commission.period_start,
|
||||
).toLocaleDateString()}{" "}
|
||||
-{" "}
|
||||
{new Date(commission.period_end).toLocaleDateString()}
|
||||
|
|
@ -566,8 +573,8 @@ export default function AdminNexusManager() {
|
|||
commission.status === "settled"
|
||||
? "bg-green-50"
|
||||
: commission.status === "disputed"
|
||||
? "bg-red-50"
|
||||
: "bg-yellow-50"
|
||||
? "bg-red-50"
|
||||
: "bg-yellow-50"
|
||||
}
|
||||
>
|
||||
{commission.status}
|
||||
|
|
@ -598,13 +605,18 @@ export default function AdminNexusManager() {
|
|||
</div>
|
||||
<div>
|
||||
<label className="text-sm font-medium">Action</label>
|
||||
<Select value={disputeAction} onValueChange={(v: any) => setDisputeAction(v)}>
|
||||
<Select
|
||||
value={disputeAction}
|
||||
onValueChange={(v: any) => setDisputeAction(v)}
|
||||
>
|
||||
<SelectTrigger className="mt-2">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="resolve">Resolve & Close</SelectItem>
|
||||
<SelectItem value="escalate">Escalate to Senior Team</SelectItem>
|
||||
<SelectItem value="escalate">
|
||||
Escalate to Senior Team
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in a new issue