76 lines
2.2 KiB
TypeScript
76 lines
2.2 KiB
TypeScript
"use client";
|
|
|
|
import { useTranslations } from "next-intl";
|
|
import { useRouter } from "next/navigation";
|
|
import { PACKAGE_CATALOG } from "@/lib/packages";
|
|
import { PackageCard } from "./package-card";
|
|
|
|
interface Props {
|
|
tenantName: string;
|
|
enabledPackages: string[];
|
|
conditions?: Array<{ type: string; status: string; reason?: string }>;
|
|
onRefresh?: () => void;
|
|
/** Slice 5: when false, package toggles and edit affordances are hidden. */
|
|
canEdit?: boolean;
|
|
}
|
|
|
|
const CATEGORIES = [
|
|
{ key: "channel" as const, labelKey: "categories.channels" },
|
|
{ key: "skill" as const, labelKey: "categories.skills" },
|
|
] as const;
|
|
|
|
function getPackageStatus(
|
|
pkgId: string,
|
|
enabled: boolean,
|
|
conditions?: Props["conditions"]
|
|
): "pending" | "active" | "error" | undefined {
|
|
if (!enabled) return undefined;
|
|
const cond = conditions?.find((c) => c.type === `Package/${pkgId}`);
|
|
if (!cond) return "pending";
|
|
if (cond.status === "True") return "active";
|
|
if (cond.reason === "SecretReady") return "active";
|
|
return "error";
|
|
}
|
|
|
|
export function PackageList({
|
|
tenantName,
|
|
enabledPackages,
|
|
conditions,
|
|
onRefresh,
|
|
canEdit = true,
|
|
}: Props) {
|
|
const t = useTranslations("packages");
|
|
const router = useRouter();
|
|
const handleRefresh = onRefresh || (() => router.refresh());
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
{CATEGORIES.map(({ key, labelKey }) => {
|
|
const packages = PACKAGE_CATALOG.filter((p) => p.category === key);
|
|
if (packages.length === 0) return null;
|
|
|
|
return (
|
|
<div key={key}>
|
|
<h3 className="text-[10px] font-semibold uppercase tracking-wider text-text-muted mb-3">
|
|
{t(labelKey)}
|
|
</h3>
|
|
<div className="grid gap-3 sm:grid-cols-2">
|
|
{packages.map((pkg) => (
|
|
<PackageCard
|
|
key={pkg.id}
|
|
pkg={pkg}
|
|
enabled={enabledPackages.includes(pkg.id)}
|
|
status={getPackageStatus(pkg.id, enabledPackages.includes(pkg.id), conditions)}
|
|
tenantName={tenantName}
|
|
onToggled={handleRefresh}
|
|
canEdit={canEdit}
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
);
|
|
}
|