125 lines
3.9 KiB
TypeScript
125 lines
3.9 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import { Loader2, Check, X } from "lucide-react";
|
|
import { toast } from "@/lib/toast";
|
|
|
|
type Recommendation = {
|
|
recommendation: {
|
|
id: string;
|
|
recommendationText: string;
|
|
activityPlan: string;
|
|
dietPlan: string;
|
|
createdAt: Date;
|
|
};
|
|
user: {
|
|
firstName: string;
|
|
lastName: string;
|
|
};
|
|
};
|
|
|
|
export function RecommendationList({
|
|
initialRecommendations,
|
|
}: {
|
|
initialRecommendations: Recommendation[];
|
|
}) {
|
|
const [recommendations, setRecommendations] = useState(
|
|
initialRecommendations,
|
|
);
|
|
const [processingId, setProcessingId] = useState<string | null>(null);
|
|
|
|
const handleAction = async (id: string, status: "approved" | "rejected") => {
|
|
setProcessingId(id);
|
|
try {
|
|
const res = await fetch("/api/recommendations/approve", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({
|
|
recommendationId: id,
|
|
status,
|
|
approvedBy: "admin_placeholder", // In real app, get from auth context
|
|
}),
|
|
});
|
|
|
|
if (!res.ok) {
|
|
toast.error("Failed to update status");
|
|
} else {
|
|
toast.success(
|
|
`Recommendation ${status === "approved" ? "approved" : "rejected"}`,
|
|
);
|
|
setRecommendations((prev) =>
|
|
prev.filter((item) => item.recommendation.id !== id),
|
|
);
|
|
}
|
|
} catch (error) {
|
|
console.error(error);
|
|
toast.error("Error processing request");
|
|
} finally {
|
|
setProcessingId(null);
|
|
}
|
|
};
|
|
|
|
if (recommendations.length === 0) {
|
|
return <p className="text-gray-500 italic">No pending recommendations.</p>;
|
|
}
|
|
|
|
return (
|
|
<ul className="space-y-6">
|
|
{recommendations.map(({ recommendation, user }) => (
|
|
<li key={recommendation.id} className="border rounded p-4">
|
|
<div className="flex justify-between items-start mb-2">
|
|
<h3 className="font-bold">
|
|
For: {user.firstName} {user.lastName}
|
|
</h3>
|
|
<span className="text-xs text-gray-500">
|
|
{new Date(recommendation.createdAt).toLocaleDateString()}
|
|
</span>
|
|
</div>
|
|
<div className="space-y-2 text-sm mb-4">
|
|
<div>
|
|
<span className="font-semibold">Advice:</span>{" "}
|
|
{recommendation.recommendationText}
|
|
</div>
|
|
<div>
|
|
<span className="font-semibold">Activity:</span>{" "}
|
|
{recommendation.activityPlan}
|
|
</div>
|
|
<div>
|
|
<span className="font-semibold">Diet:</span>{" "}
|
|
{recommendation.dietPlan}
|
|
</div>
|
|
</div>
|
|
<div className="flex space-x-2">
|
|
<button
|
|
onClick={() => handleAction(recommendation.id, "approved")}
|
|
disabled={processingId === recommendation.id}
|
|
className="flex-1 bg-green-600 text-white py-2 rounded hover:bg-green-700 disabled:opacity-50 flex justify-center items-center"
|
|
>
|
|
{processingId === recommendation.id ? (
|
|
<Loader2 className="h-4 w-4 animate-spin" />
|
|
) : (
|
|
<>
|
|
<Check className="mr-2 h-4 w-4" /> Approve
|
|
</>
|
|
)}
|
|
</button>
|
|
<button
|
|
onClick={() => handleAction(recommendation.id, "rejected")}
|
|
disabled={processingId === recommendation.id}
|
|
className="flex-1 bg-red-600 text-white py-2 rounded hover:bg-red-700 disabled:opacity-50 flex justify-center items-center"
|
|
>
|
|
{processingId === recommendation.id ? (
|
|
<Loader2 className="h-4 w-4 animate-spin" />
|
|
) : (
|
|
<>
|
|
<X className="mr-2 h-4 w-4" /> Reject
|
|
</>
|
|
)}
|
|
</button>
|
|
</div>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
);
|
|
}
|