All files / src/pages/flowsheet-page/economics/cost-curves/library CostCurveLibraryCard.tsx

88.57% Statements 31/35
91.66% Branches 33/36
100% Functions 1/1
86.66% Lines 26/30

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115                                  22x                                                     22x       2x   24x   2x           24x 24x             24x 24x 26x 26x   19x                 79x 136x 21x               79x 127x 64x 64x   2x   22x   24x   24x 2x               26x 106x      
import { Badge } from "@/ahuora-design-system/ui/badge";
import type {
  CostCurveEquipmentCategoryRead,
  CostCurveRead,
  PatchedCostCurveAuthoring,
} from "@/api/apiStore.gen";
import { EconomicsWarningNotice } from "../../shared/ui/EconomicsWarningNotice";
import { CostCurveDialog } from "../authoring/CostCurveDialog";
import {
  type CostCurveDraft,
  costCurveFormulaSummary,
  costCurvePatchPayload,
} from "../model/payloads";
import type { CostCurveUsageSummary } from "../types";
import { CostCurveDeleteButton } from "./CostCurveDeleteButton";
import { formatCostCurveLabel } from "./labels";
 
export function CostCurveLibraryCard({
  curve,
  curves,
  canEdit,
  saving,
  equipmentOptions,
  usage,
  onPatchCurve,
  onDeleteCurve,
  onSaved,
}: {
  curve: CostCurveRead;
  curves: CostCurveRead[];
  canEdit: boolean;
  saving: boolean;
  equipmentOptions: readonly CostCurveEquipmentCategoryRead[];
  usage: CostCurveUsageSummary;
  onPatchCurve: (
    curveId: number,
    patch: PatchedCostCurveAuthoring,
  ) => Promise<void>;
  onDeleteCurve: (curveId: number) => Promise<void>;
  onSaved: (message: string) => void;
}) {
  return (
    <article
      className="rounded-md border bg-background p-2.5"
      aria-label={`Cost curve ${curve.name}`}
    >
      <div className="flex items-start justify-between gap-2">
        <div className="min-w-0">
          <div className="truncate text-sm font-medium leading-tight">
            {curve.name}
          </div>
          <div className="mt-1 flex flex-wrap gap-1">
            <Badge
              variant="secondary"
              size="xs"
              borderRadius="round"
              className="px-1.5 py-0 text-[10px] leading-4"
            >
              {formatCostCurveLabel(curve.equipment_category)}
            </Badge>
            <Badge
              variant="secondary"
              size="xs"
              borderRadius="round"
              className="px-1.5 py-0 text-[10px] leading-4"
            >
              Basis: {formatCostCurveLabel(curve.cost_basis)}
            </Badge>
          </div>
        </div>
        <div className="flex shrink-0 items-center gap-1">
          <CostCurveDialog
            curve={curve}
            canEdit={canEdit}
            saving={saving}
            equipmentOptions={equipmentOptions}
            existingCurves={curves}
            onSubmit={async (draft: CostCurveDraft) => {
              await onPatchCurve(curve.id, costCurvePatchPayload(draft));
              onSaved("Cost curve updated");
            }}
          />
          <CostCurveDeleteButton
            curve={curve}
            canEdit={canEdit}
            saving={saving}
            usage={usage}
            onDelete={async () => {
              await onDeleteCurve(curve.id);
              onSaved("Cost curve deleted");
            }}
          />
        </div>
      </div>
      <div className="mt-2 grid gap-1">
        <div className="text-[11px] font-medium text-muted-foreground">
          Expression
        </div>
        <code className="block rounded-md bg-muted/30 px-2 py-1 text-[11px] leading-4 text-foreground">
          {costCurveFormulaSummary(curve)}
        </code>
      </div>
      {curve.applicability_warning && (
        <div className="mt-2">
          <EconomicsWarningNotice
            aria-label={`Cost curve warning for ${curve.name}`}
          >
            <span>{curve.applicability_warning}</span>
          </EconomicsWarningNotice>
        </div>
      )}
    </article>
  );
}