All files / components/Commons commonsTableUtils.js

100% Statements 115/115
100% Branches 91/91
100% Functions 21/21
100% Lines 115/115

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 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 1361x   1x 6287x 1990x 1990x 4297x 4297x   1x 1400x 881x 881x   1x 1401x 507x 507x 894x 894x   1x 380x 380x 234x 234x 146x 353x 380x 380x 380x 58x 380x 11x 11x 135x 135x   1x 1x 1x 1x 1x 1x 1x 1x 1x 1x   1x 1x 1x 1x 1x   1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x   1x 377x 376x 377x   374x   377x 126x 81x 126x 126x   248x 377x   377x 377x   1x 31x 31x 31x   87x 87x 81x 3x 3x   1x 116x 1x 1x 116x   116x 165x 165x   165x 35x 32x 32x   165x 12x 12x   118x 118x 165x 87x 87x   31x 116x 116x  
// Utility helpers for CommonsTable (extracted to satisfy react-refresh rule)
 
export function formatPlain(value) {
  if (value === null || value === undefined || value === "") {
    return "—";
  }
  return `${value}`;
}
 
export function formatDate(value) {
  if (!value) return "—";
  return String(value).slice(0, 10);
}
 
export function formatBoolean(value) {
  if (value === null || value === undefined || value === "") {
    return "—";
  }
  return String(value);
}
 
export function computeEffectiveCapacity(commonsPlus) {
  const { effectiveCapacity, commons: commonsData, totalUsers } = commonsPlus;
  if (effectiveCapacity !== null && effectiveCapacity !== undefined) {
    return effectiveCapacity;
  }
  if (
    commonsData &&
    commonsData.capacityPerUser !== null &&
    commonsData.capacityPerUser !== undefined &&
    totalUsers !== null &&
    totalUsers !== undefined
  ) {
    return commonsData.capacityPerUser * totalUsers;
  }
  return null;
}
 
const NUMERIC_SORT_KEYS = new Set([
  "commons.cowPrice",
  "commons.milkPrice",
  "commons.startingBalance",
  "commons.degradationRate",
  "totalCows",
  "commons.capacityPerUser",
  "commons.carryingCapacity",
  "effectiveCapacity",
]);
 
const STRING_DEFAULT_EMPTY_KEYS = new Set([
  "commons.name",
  "commons.startingDate",
  "commons.lastDate",
]);
 
const sortableValueResolvers = {
  "commons.id": (commonsPlus) => commonsPlus.commons?.id,
  "commons.name": (commonsPlus) => commonsPlus.commons?.name,
  "commons.cowPrice": (commonsPlus) => commonsPlus.commons?.cowPrice,
  "commons.milkPrice": (commonsPlus) => commonsPlus.commons?.milkPrice,
  "commons.startingBalance": (commonsPlus) =>
    commonsPlus.commons?.startingBalance,
  "commons.startingDate": (commonsPlus) => commonsPlus.commons?.startingDate,
  "commons.lastDate": (commonsPlus) => commonsPlus.commons?.lastDate,
  "commons.degradationRate": (commonsPlus) =>
    commonsPlus.commons?.degradationRate,
  "commons.showLeaderboard": (commonsPlus) =>
    commonsPlus.commons?.showLeaderboard,
  "commons.showChat": (commonsPlus) => commonsPlus.commons?.showChat,
  totalCows: (commonsPlus) => commonsPlus.totalCows,
  "commons.capacityPerUser": (commonsPlus) =>
    commonsPlus.commons?.capacityPerUser,
  "commons.carryingCapacity": (commonsPlus) =>
    commonsPlus.commons?.carryingCapacity,
  effectiveCapacity: computeEffectiveCapacity,
};
 
export function getSortableValue(commonsPlus, key) {
  if (!commonsPlus) return null;
  const resolver = sortableValueResolvers[key];
  if (!resolver) return null;
 
  const val = resolver(commonsPlus);
 
  if (NUMERIC_SORT_KEYS.has(key)) {
    if (val == null || val === "") return null;
    const n = Number(val);
    return Number.isFinite(n) ? n : null;
  }
 
  // For string/date/boolean fields, return as-is (or empty string for missing names/dates)
  if (STRING_DEFAULT_EMPTY_KEYS.has(key)) return val ?? "";
 
  return val ?? null;
}
 
export function compareAsStrings(aVal, bVal, directionMultiplier) {
  const cmp = String(aVal).localeCompare(String(bVal));
  return directionMultiplier === -1 ? -cmp : cmp;
}
 
function compareAsNumbers(aNum, bNum, directionMultiplier) {
  if (aNum > bNum) return directionMultiplier;
  if (aNum < bNum) return -directionMultiplier;
  return 0;
}
 
export function createCommonsComparator(sortKey, sortDirection = "asc") {
  if (sortDirection !== "asc" && sortDirection !== "desc") {
    throw new Error("Invalid sort direction; expected 'asc' or 'desc'");
  }
  const directionMultiplier = sortDirection === "desc" ? -1 : 1;
 
  return (a, b) => {
    const aVal = getSortableValue(a, sortKey);
    const bVal = getSortableValue(b, sortKey);
 
    if (aVal == null) {
      if (bVal == null) return 0;
      return 1;
    }
 
    if (bVal == null) {
      return -1;
    }
 
    const aNum = Number(aVal);
    const bNum = Number(bVal);
    if (Number.isFinite(aNum) && Number.isFinite(bNum)) {
      return compareAsNumbers(aNum, bNum, directionMultiplier);
    }
 
    return compareAsStrings(aVal, bVal, directionMultiplier);
  };
}