diff --git a/frontend/src/melodies/MelodyList.jsx b/frontend/src/melodies/MelodyList.jsx index 9f4c1f4..35a416b 100644 --- a/frontend/src/melodies/MelodyList.jsx +++ b/frontend/src/melodies/MelodyList.jsx @@ -1,4 +1,4 @@ -import { useState, useEffect, useRef, useMemo } from "react"; +import { useState, useEffect, useRef, useMemo } from "react"; import { useNavigate } from "react-router-dom"; import api from "../api/client"; import { useAuth } from "../auth/AuthContext"; @@ -14,6 +14,12 @@ import { const MELODY_TYPES = ["", "orthodox", "catholic", "all"]; const MELODY_TONES = ["", "normal", "festive", "cheerful", "lamentation"]; const NOTE_LABELS = "ABCDEFGHIJKLMNOP"; +const SORTABLE_COLUMN_TO_KEY = { + name: "name", + totalActiveBells: "totalActiveBells", + dateCreated: "dateCreated", + dateEdited: "dateEdited", +}; // All available columns with their defaults const ALL_COLUMNS = [ @@ -271,7 +277,7 @@ export default function MelodyList() { switch (key) { case "name": return getDisplayName(info.name).toLowerCase(); - case "totalBells": + case "totalActiveBells": return Number(info.totalActiveBells || 0); case "dateEdited": return parseDateValue(metadata.dateEdited); @@ -300,6 +306,24 @@ export default function MelodyList() { }); }, [melodies, createdByFilter, sortBy, sortDir]); // eslint-disable-line react-hooks/exhaustive-deps + const handleSortClick = (columnKey) => { + const nextSortKey = SORTABLE_COLUMN_TO_KEY[columnKey]; + if (!nextSortKey) return; + if (sortBy === nextSortKey) { + setSortDir((prev) => (prev === "asc" ? "desc" : "asc")); + return; + } + setSortBy(nextSortKey); + setSortDir(nextSortKey === "dateCreated" || nextSortKey === "dateEdited" ? "desc" : "asc"); + }; + + const getSortIndicator = (columnKey) => { + const sortKey = SORTABLE_COLUMN_TO_KEY[columnKey]; + if (!sortKey) return null; + if (sortBy !== sortKey) return "↕"; + return sortDir === "asc" ? "▲" : "▼"; + }; + const renderCellValue = (key, row) => { const info = row.information || {}; const ds = row.default_settings || {}; @@ -398,7 +422,44 @@ export default function MelodyList() { ); case "duration": - return ds.duration != null ? formatDuration(ds.duration) : "-"; + if (ds.duration == null) return "-"; + if (Number(ds.duration) === 0) { + return ( + + Single Run + + ); + } + { + const allDurationValues = melodySettings?.duration_values || []; + const nonZeroDurations = allDurationValues.filter((v) => Number(v) > 0); + const idx = nonZeroDurations.indexOf(Number(ds.duration)); + const percent = idx >= 0 && nonZeroDurations.length > 0 + ? Math.round(((idx + 1) / nonZeroDurations.length) * 100) + : 0; + return ( +