Spaces:
Running
Running
Add elapsed loading timer to UI during report generation
Browse files- frontend/src/App.jsx +25 -2
frontend/src/App.jsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
import { useMemo, useState } from "react";
|
| 2 |
|
| 3 |
const ACCEPTED_TYPES = ["video/mp4", "video/quicktime"];
|
| 4 |
|
|
@@ -10,8 +10,31 @@ const initialState = {
|
|
| 10 |
error: null
|
| 11 |
};
|
| 12 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
export default function App() {
|
| 14 |
const [state, setState] = useState(initialState);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
|
| 16 |
const filename = useMemo(() => {
|
| 17 |
if (!state.file) return "No file selected";
|
|
@@ -164,7 +187,7 @@ export default function App() {
|
|
| 164 |
disabled={!state.file || state.isLoading}
|
| 165 |
onClick={submitFile}
|
| 166 |
>
|
| 167 |
-
{state.isLoading ?
|
| 168 |
</button>
|
| 169 |
{state.error && (
|
| 170 |
<p className="rounded-lg border border-red-400/40 bg-red-500/10 p-3 text-sm text-red-200">
|
|
|
|
| 1 |
+
import { useEffect, useMemo, useRef, useState } from "react";
|
| 2 |
|
| 3 |
const ACCEPTED_TYPES = ["video/mp4", "video/quicktime"];
|
| 4 |
|
|
|
|
| 10 |
error: null
|
| 11 |
};
|
| 12 |
|
| 13 |
+
function formatTime(seconds) {
|
| 14 |
+
const m = Math.floor(seconds / 60);
|
| 15 |
+
const s = seconds % 60;
|
| 16 |
+
if (m > 0) return `${m}m ${s}s`;
|
| 17 |
+
return `${s}s`;
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
export default function App() {
|
| 21 |
const [state, setState] = useState(initialState);
|
| 22 |
+
const [elapsed, setElapsed] = useState(0);
|
| 23 |
+
const intervalRef = useRef(null);
|
| 24 |
+
|
| 25 |
+
useEffect(() => {
|
| 26 |
+
if (state.isLoading) {
|
| 27 |
+
setElapsed(0);
|
| 28 |
+
intervalRef.current = setInterval(() => {
|
| 29 |
+
setElapsed((prev) => prev + 1);
|
| 30 |
+
}, 1000);
|
| 31 |
+
} else {
|
| 32 |
+
if (intervalRef.current) clearInterval(intervalRef.current);
|
| 33 |
+
}
|
| 34 |
+
return () => {
|
| 35 |
+
if (intervalRef.current) clearInterval(intervalRef.current);
|
| 36 |
+
};
|
| 37 |
+
}, [state.isLoading]);
|
| 38 |
|
| 39 |
const filename = useMemo(() => {
|
| 40 |
if (!state.file) return "No file selected";
|
|
|
|
| 187 |
disabled={!state.file || state.isLoading}
|
| 188 |
onClick={submitFile}
|
| 189 |
>
|
| 190 |
+
{state.isLoading ? `Processing... (${formatTime(elapsed)})` : "Generate report"}
|
| 191 |
</button>
|
| 192 |
{state.error && (
|
| 193 |
<p className="rounded-lg border border-red-400/40 bg-red-500/10 p-3 text-sm text-red-200">
|