Simplify item status cycling logic
Replaced long-press and multiple buttons with a single click-based cycle for item status changes (unknown → green → red → gray → unknown). Removed redundant code and associated styles for a cleaner and more intuitive user experience.
This commit is contained in:
@@ -126,7 +126,7 @@ function AdminPanel() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{ fontSize: 12, opacity: 0.75 }}>
|
<div style={{ fontSize: 12, opacity: 0.75 }}>
|
||||||
Tipp: Tap auf Item = rot (ausschließen), Long-Press = grün (bestätigt), ? = unsicher.
|
Tipp: Klick auf Item: Grün → Rot → Grau → Leer
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -136,39 +136,6 @@ function AdminPanel() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function useLongPress(onLongPress, onClick, { delay = 450 } = {}) {
|
|
||||||
const [longPressed, setLongPressed] = useState(false);
|
|
||||||
const timeoutRef = React.useRef(null);
|
|
||||||
|
|
||||||
const start = (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
setLongPressed(false);
|
|
||||||
timeoutRef.current = setTimeout(() => {
|
|
||||||
setLongPressed(true);
|
|
||||||
onLongPress();
|
|
||||||
}, delay);
|
|
||||||
};
|
|
||||||
|
|
||||||
const clear = () => {
|
|
||||||
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
|
||||||
timeoutRef.current = null;
|
|
||||||
};
|
|
||||||
|
|
||||||
const end = () => {
|
|
||||||
clear();
|
|
||||||
if (!longPressed) onClick();
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
onMouseDown: start,
|
|
||||||
onMouseUp: end,
|
|
||||||
onMouseLeave: clear,
|
|
||||||
onTouchStart: start,
|
|
||||||
onTouchEnd: end,
|
|
||||||
onTouchMove: clear,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
const [me, setMe] = useState(null);
|
const [me, setMe] = useState(null);
|
||||||
const [loginEmail, setLoginEmail] = useState("admin@local");
|
const [loginEmail, setLoginEmail] = useState("admin@local");
|
||||||
@@ -236,30 +203,20 @@ export default function App() {
|
|||||||
setSheet(sh);
|
setSheet(sh);
|
||||||
};
|
};
|
||||||
|
|
||||||
const toggleCross = async (entry) => {
|
// ✅ Cycle: unknown -> green -> red -> gray -> unknown
|
||||||
const next = entry.status === 1 ? 0 : 1;
|
const cycleStatus = async (entry) => {
|
||||||
await api(`/games/${gameId}/sheet/${entry.entry_id}`, {
|
let next = 0;
|
||||||
method: "PATCH",
|
|
||||||
body: JSON.stringify({ status: next }),
|
|
||||||
});
|
|
||||||
await reloadSheet();
|
|
||||||
};
|
|
||||||
|
|
||||||
const toggleConfirmed = async (entry) => {
|
if (entry.status === 0) next = 2; // grün (confirmed)
|
||||||
const next = entry.status === 2 ? 0 : 2;
|
else if (entry.status === 2) next = 1; // rot (crossed)
|
||||||
await api(`/games/${gameId}/sheet/${entry.entry_id}`, {
|
else if (entry.status === 1) next = 3; // grau (maybe)
|
||||||
method: "PATCH",
|
else next = 0; // zurück unknown
|
||||||
body: JSON.stringify({ status: next }),
|
|
||||||
});
|
|
||||||
await reloadSheet();
|
|
||||||
};
|
|
||||||
|
|
||||||
const toggleMaybe = async (entry) => {
|
|
||||||
const next = entry.status === 3 ? 0 : 3;
|
|
||||||
await api(`/games/${gameId}/sheet/${entry.entry_id}`, {
|
await api(`/games/${gameId}/sheet/${entry.entry_id}`, {
|
||||||
method: "PATCH",
|
method: "PATCH",
|
||||||
body: JSON.stringify({ status: next }),
|
body: JSON.stringify({ status: next }),
|
||||||
});
|
});
|
||||||
|
|
||||||
await reloadSheet();
|
await reloadSheet();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -316,16 +273,16 @@ export default function App() {
|
|||||||
: [];
|
: [];
|
||||||
|
|
||||||
const getRowBg = (status) => {
|
const getRowBg = (status) => {
|
||||||
if (status === 1) return "rgba(255, 0, 0, 0.06)"; // crossed
|
if (status === 1) return "rgba(255, 0, 0, 0.06)"; // rot
|
||||||
if (status === 2) return "rgba(0, 170, 60, 0.07)"; // confirmed
|
if (status === 2) return "rgba(0, 170, 60, 0.07)"; // grün
|
||||||
if (status === 3) return "rgba(255, 180, 70, 0.12)"; // maybe
|
if (status === 3) return "rgba(120, 120, 120, 0.14)"; // grau
|
||||||
return "rgba(255,255,255,0.22)";
|
return "rgba(255,255,255,0.22)";
|
||||||
};
|
};
|
||||||
|
|
||||||
const getNameColor = (status) => {
|
const getNameColor = (status) => {
|
||||||
if (status === 1) return "#b10000";
|
if (status === 1) return "#b10000";
|
||||||
if (status === 2) return "#0b6a1e";
|
if (status === 2) return "#0b6a1e";
|
||||||
if (status === 3) return "#6b4d00";
|
if (status === 3) return "#444444";
|
||||||
return "#20140c";
|
return "#20140c";
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -371,14 +328,7 @@ export default function App() {
|
|||||||
<div style={styles.sectionHeader}>{sec.title}</div>
|
<div style={styles.sectionHeader}>{sec.title}</div>
|
||||||
|
|
||||||
<div style={{ display: "grid" }}>
|
<div style={{ display: "grid" }}>
|
||||||
{sec.entries.map((e) => {
|
{sec.entries.map((e) => (
|
||||||
const pressHandlers = useLongPress(
|
|
||||||
() => toggleConfirmed(e), // long press -> confirmed
|
|
||||||
() => toggleCross(e), // tap -> crossed
|
|
||||||
{ delay: 450 }
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
<div
|
||||||
key={e.entry_id}
|
key={e.entry_id}
|
||||||
style={{
|
style={{
|
||||||
@@ -386,34 +336,20 @@ export default function App() {
|
|||||||
background: getRowBg(e.status),
|
background: getRowBg(e.status),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{/* Name: Tap = rot, Long-Press = grün */}
|
{/* ✅ Klick Cycle */}
|
||||||
<div
|
<div
|
||||||
{...pressHandlers}
|
onClick={() => cycleStatus(e)}
|
||||||
style={{
|
style={{
|
||||||
...styles.name,
|
...styles.name,
|
||||||
textDecoration: e.status === 1 ? "line-through" : "none",
|
textDecoration: e.status === 1 ? "line-through" : "none",
|
||||||
color: getNameColor(e.status),
|
color: getNameColor(e.status),
|
||||||
opacity: e.status === 1 ? 0.75 : 1,
|
opacity: e.status === 1 ? 0.75 : 1,
|
||||||
}}
|
}}
|
||||||
title="Tippen = ausschließen | Lange halten = bestätigt"
|
title="Klick: Grün → Rot → Grau → Leer"
|
||||||
>
|
>
|
||||||
{e.label}
|
{e.label}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* ? = maybe */}
|
|
||||||
<button
|
|
||||||
onClick={() => toggleMaybe(e)}
|
|
||||||
style={{
|
|
||||||
...styles.maybeBtn,
|
|
||||||
background: e.status === 3
|
|
||||||
? "linear-gradient(180deg, rgba(255,210,120,0.9), rgba(180,120,20,0.25))"
|
|
||||||
: styles.maybeBtn.background,
|
|
||||||
}}
|
|
||||||
title="Unsicher"
|
|
||||||
>
|
|
||||||
?
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<div style={styles.cell}>{e.status === 1 ? "X" : ""}</div>
|
<div style={styles.cell}>{e.status === 1 ? "X" : ""}</div>
|
||||||
<div style={styles.cell}>{e.status === 1 ? "✓" : ""}</div>
|
<div style={styles.cell}>{e.status === 1 ? "✓" : ""}</div>
|
||||||
<div style={styles.cell}>{e.status === 2 ? "✓" : ""}</div>
|
<div style={styles.cell}>{e.status === 2 ? "✓" : ""}</div>
|
||||||
@@ -422,8 +358,7 @@ export default function App() {
|
|||||||
{e.note_tag || "—"}
|
{e.note_tag || "—"}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
);
|
))}
|
||||||
})}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
@@ -486,7 +421,7 @@ const styles = {
|
|||||||
},
|
},
|
||||||
row: {
|
row: {
|
||||||
display: "grid",
|
display: "grid",
|
||||||
gridTemplateColumns: "1fr 42px 40px 40px 40px 56px", // ✅ extra Spalte für ?
|
gridTemplateColumns: "1fr 40px 40px 40px 56px", // ✅ ohne ? Button
|
||||||
gap: 8,
|
gap: 8,
|
||||||
padding: "10px 12px",
|
padding: "10px 12px",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
@@ -504,15 +439,6 @@ const styles = {
|
|||||||
fontWeight: 1000,
|
fontWeight: 1000,
|
||||||
color: "#20140c",
|
color: "#20140c",
|
||||||
},
|
},
|
||||||
maybeBtn: {
|
|
||||||
padding: "8px 0",
|
|
||||||
fontWeight: 1000,
|
|
||||||
borderRadius: 10,
|
|
||||||
border: "1px solid rgba(0,0,0,0.25)",
|
|
||||||
background: "linear-gradient(180deg, rgba(255,255,255,0.55), rgba(0,0,0,0.06))",
|
|
||||||
color: "#6b4d00",
|
|
||||||
cursor: "pointer",
|
|
||||||
},
|
|
||||||
tagBtn: {
|
tagBtn: {
|
||||||
padding: "8px 0",
|
padding: "8px 0",
|
||||||
fontWeight: 1000,
|
fontWeight: 1000,
|
||||||
|
|||||||
Reference in New Issue
Block a user