Skip to content

Commit b548f01

Browse files
committed
fix bug; cache Vsum item in repeated fetch items
1 parent 6602813 commit b548f01

File tree

1 file changed

+14
-17
lines changed

1 file changed

+14
-17
lines changed

src/components/ui/VsumsPanel.tsx

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// src/components/ui/VsumsPanel.tsx
21
import React, { useEffect, useRef, useState, useCallback } from 'react';
32
import { apiService } from '../../services/api';
43
import { Vsum } from '../../types';
@@ -92,75 +91,77 @@ export const VsumsPanel: React.FC = () => {
9291
const [search, setSearch] = useState('');
9392
const [page, setPage] = useState(0);
9493
const [hasMore, setHasMore] = useState(true);
95-
9694
const [showCreate, setShowCreate] = useState(false);
9795
const [detailsId, setDetailsId] = useState<number | null>(null);
9896

9997
const containerRef = useRef<HTMLDivElement | null>(null);
10098
const rafRef = useRef<number | null>(null);
99+
const requestSeq = useRef(0);
101100
const PAGE_SIZE = 10;
102101

103102
const formatDateTime = (iso: string) => {
104103
const d = new Date(iso);
105104
return `${d.toLocaleDateString()} ${d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}`;
106105
};
107106

108-
// Load first page (stable: only depends on search)
109107
const loadFirstPage = useCallback(async () => {
108+
const mySeq = ++requestSeq.current;
110109
setLoading(true);
111110
setError('');
111+
setItems([]);
112+
setPage(0);
113+
setHasMore(true);
114+
if (containerRef.current) containerRef.current.scrollTop = 0;
112115
try {
113116
const res = await apiService.getVsumsPaginated(search, 0, PAGE_SIZE);
117+
if (mySeq !== requestSeq.current) return;
114118
const newData: Vsum[] = res.data || [];
115119
setItems(newData);
116120
setPage(1);
117121
setHasMore(newData.length === PAGE_SIZE);
118122
} catch (e) {
123+
if (mySeq !== requestSeq.current) return;
119124
setError(e instanceof Error ? e.message : 'Failed to load VSUMs');
120125
} finally {
121-
setLoading(false);
126+
if (mySeq === requestSeq.current) setLoading(false);
122127
}
123128
}, [search]);
124129

125-
// Load next page for infinite scroll
126130
const loadNextPage = useCallback(async () => {
127131
if (loading || !hasMore) return;
132+
const mySeq = requestSeq.current;
128133
setLoading(true);
129134
setError('');
130135
try {
131136
const res = await apiService.getVsumsPaginated(search, page, PAGE_SIZE);
137+
if (mySeq !== requestSeq.current) return;
132138
const newData: Vsum[] = res.data || [];
133139
setItems(prev => [...prev, ...newData]);
134140
setPage(prev => prev + 1);
135141
setHasMore(newData.length === PAGE_SIZE);
136142
} catch (e) {
143+
if (mySeq !== requestSeq.current) return;
137144
setError(e instanceof Error ? e.message : 'Failed to load VSUMs');
138145
} finally {
139-
setLoading(false);
146+
if (mySeq === requestSeq.current) setLoading(false);
140147
}
141148
}, [search, page, hasMore, loading]);
142149

143-
// Reload list whenever search changes
144150
useEffect(() => {
145151
loadFirstPage();
146152
}, [loadFirstPage]);
147153

148-
// Infinite scroll listener (throttled with rAF)
149154
useEffect(() => {
150155
const el = containerRef.current;
151156
if (!el) return;
152-
153157
const onScroll = () => {
154158
if (rafRef.current) cancelAnimationFrame(rafRef.current);
155159
rafRef.current = requestAnimationFrame(() => {
156160
if (loading || !hasMore) return;
157161
const nearBottom = el.scrollHeight - el.scrollTop - el.clientHeight < 150;
158-
if (nearBottom) {
159-
loadNextPage();
160-
}
162+
if (nearBottom) loadNextPage();
161163
});
162164
};
163-
164165
el.addEventListener('scroll', onScroll);
165166
return () => {
166167
el.removeEventListener('scroll', onScroll);
@@ -180,7 +181,6 @@ export const VsumsPanel: React.FC = () => {
180181

181182
{error && <div style={errorStyle}>{error}</div>}
182183

183-
{/* Create first */}
184184
<button
185185
onClick={() => setShowCreate(true)}
186186
style={createButtonStyle}
@@ -190,7 +190,6 @@ export const VsumsPanel: React.FC = () => {
190190
Create
191191
</button>
192192

193-
{/* Search */}
194193
<div style={{ display: 'flex', gap: 8, marginBottom: 12 }}>
195194
<input
196195
type="text"
@@ -256,14 +255,12 @@ export const VsumsPanel: React.FC = () => {
256255
</div>
257256
))}
258257

259-
{/* Empty state (plain text) */}
260258
{!loading && items.length === 0 && (
261259
<div style={{ textAlign: 'center', color: '#6b7280', marginTop: 40, fontStyle: 'italic' }}>
262260
No VSUMs found. Create one to get started.
263261
</div>
264262
)}
265263

266-
{/* Loading pinned at bottom */}
267264
{loading && (
268265
<div style={{ padding: 12, fontStyle: 'italic', color: '#5a6c7d', marginTop: 12 }}>
269266
Loading...

0 commit comments

Comments
 (0)