99 CheckSquare ,
1010 RefreshCw
1111} from "lucide-react" ;
12+ import { getPlatformInfo } from "@/utils/platform" ;
1213import {
1314 DropdownMenu ,
1415 DropdownMenuContent ,
@@ -87,6 +88,7 @@ export function ChatHistoryList({
8788 const [ pullDistance , setPullDistance ] = useState ( 0 ) ;
8889 const pullStartY = useRef ( 0 ) ;
8990 const isPulling = useRef ( false ) ;
91+ const pullDistanceRef = useRef ( 0 ) ;
9092
9193 // Fetch initial conversations from API using the OpenSecret SDK
9294 const { isPending, error } = useQuery ( {
@@ -182,19 +184,27 @@ export function ChatHistoryList({
182184 // Pull-to-refresh handler
183185 const handleRefresh = useCallback ( async ( ) => {
184186 setIsPullRefreshing ( true ) ;
185- await pollForUpdates ( ) ;
186- // Add a small delay to show the refresh indicator
187- setTimeout ( ( ) => {
188- setIsPullRefreshing ( false ) ;
189- setPullDistance ( 0 ) ;
190- } , 300 ) ;
187+ try {
188+ await pollForUpdates ( ) ;
189+ } catch ( error ) {
190+ console . error ( "Refresh failed:" , error ) ;
191+ } finally {
192+ // Add a small delay to show the refresh indicator
193+ setTimeout ( ( ) => {
194+ setIsPullRefreshing ( false ) ;
195+ setPullDistance ( 0 ) ;
196+ } , 300 ) ;
197+ }
191198 } , [ pollForUpdates ] ) ;
192199
193200 // Pull-to-refresh event handlers
194201 useEffect ( ( ) => {
195202 const container = containerRef ?. current ;
196203 if ( ! container ) return ;
197204
205+ const platformInfo = getPlatformInfo ( ) ;
206+ const isDesktopPlatform = platformInfo . isDesktop || platformInfo . isWeb ;
207+
198208 const handleTouchStart = ( e : TouchEvent ) => {
199209 // Only start pull if we're at the top of the scroll
200210 if ( container . scrollTop === 0 && ! isPullRefreshing ) {
@@ -216,6 +226,7 @@ export function ChatHistoryList({
216226 // Apply resistance: diminishing returns as you pull further
217227 const resistanceFactor = 0.4 ;
218228 const adjustedDistance = Math . min ( distance * resistanceFactor , 80 ) ;
229+ pullDistanceRef . current = adjustedDistance ;
219230 setPullDistance ( adjustedDistance ) ;
220231 }
221232 } ;
@@ -226,7 +237,7 @@ export function ChatHistoryList({
226237 isPulling . current = false ;
227238
228239 // Trigger refresh if pulled far enough (threshold: 60px)
229- if ( pullDistance > 60 ) {
240+ if ( pullDistanceRef . current > 60 ) {
230241 handleRefresh ( ) ;
231242 } else {
232243 // Reset if not pulled far enough
@@ -235,6 +246,9 @@ export function ChatHistoryList({
235246 } ;
236247
237248 const handleMouseDown = ( e : MouseEvent ) => {
249+ // Only for mobile platforms - desktop uses wheel event
250+ if ( isDesktopPlatform ) return ;
251+
238252 // Only start pull if we're at the top of the scroll
239253 if ( container . scrollTop === 0 && ! isPullRefreshing ) {
240254 pullStartY . current = e . clientY ;
@@ -243,7 +257,7 @@ export function ChatHistoryList({
243257 } ;
244258
245259 const handleMouseMove = ( e : MouseEvent ) => {
246- if ( ! isPulling . current || isPullRefreshing ) return ;
260+ if ( ! isPulling . current || isPullRefreshing || isDesktopPlatform ) return ;
247261
248262 const currentY = e . clientY ;
249263 const distance = currentY - pullStartY . current ;
@@ -253,41 +267,63 @@ export function ChatHistoryList({
253267 // Apply resistance: diminishing returns as you pull further
254268 const resistanceFactor = 0.4 ;
255269 const adjustedDistance = Math . min ( distance * resistanceFactor , 80 ) ;
270+ pullDistanceRef . current = adjustedDistance ;
256271 setPullDistance ( adjustedDistance ) ;
257272 }
258273 } ;
259274
260275 const handleMouseUp = ( ) => {
261- if ( ! isPulling . current ) return ;
276+ if ( ! isPulling . current || isDesktopPlatform ) return ;
262277
263278 isPulling . current = false ;
264279
265280 // Trigger refresh if pulled far enough (threshold: 60px)
266- if ( pullDistance > 60 ) {
281+ if ( pullDistanceRef . current > 60 ) {
267282 handleRefresh ( ) ;
268283 } else {
269284 // Reset if not pulled far enough
270285 setPullDistance ( 0 ) ;
271286 }
272287 } ;
273288
274- // Add event listeners for touch (mobile) and mouse (desktop)
289+ // Desktop: detect scroll up when already at top (overscroll)
290+ const handleWheel = ( e : WheelEvent ) => {
291+ if ( ! isDesktopPlatform || isPullRefreshing ) return ;
292+
293+ // Check if we're at the top and trying to scroll up
294+ if ( container . scrollTop === 0 && e . deltaY < 0 ) {
295+ // Prevent default to avoid browser overscroll bounce
296+ e . preventDefault ( ) ;
297+ // Trigger refresh on upward scroll attempt
298+ handleRefresh ( ) ;
299+ }
300+ } ;
301+
302+ // Add event listeners based on platform
275303 container . addEventListener ( "touchstart" , handleTouchStart , { passive : true } ) ;
276304 container . addEventListener ( "touchmove" , handleTouchMove , { passive : false } ) ;
277305 container . addEventListener ( "touchend" , handleTouchEnd ) ;
278- container . addEventListener ( "mousedown" , handleMouseDown ) ;
279- window . addEventListener ( "mousemove" , handleMouseMove ) ;
280- window . addEventListener ( "mouseup" , handleMouseUp ) ;
306+
307+ if ( isDesktopPlatform ) {
308+ // Desktop: use wheel event for scroll-to-refresh
309+ container . addEventListener ( "wheel" , handleWheel , { passive : false } ) ;
310+ } else {
311+ // Mobile: use mouse events for pull-to-refresh
312+ container . addEventListener ( "mousedown" , handleMouseDown ) ;
313+ window . addEventListener ( "mousemove" , handleMouseMove ) ;
314+ window . addEventListener ( "mouseup" , handleMouseUp ) ;
315+ }
281316
282317 return ( ) => {
283318 container . removeEventListener ( "touchstart" , handleTouchStart ) ;
284319 container . removeEventListener ( "touchmove" , handleTouchMove ) ;
285320 container . removeEventListener ( "touchend" , handleTouchEnd ) ;
321+ container . removeEventListener ( "wheel" , handleWheel ) ;
286322 container . removeEventListener ( "mousedown" , handleMouseDown ) ;
287323 window . removeEventListener ( "mousemove" , handleMouseMove ) ;
288324 window . removeEventListener ( "mouseup" , handleMouseUp ) ;
289325 } ;
290- } , [ containerRef , isPullRefreshing , pullDistance , handleRefresh ] ) ;
326+ } , [ containerRef , isPullRefreshing , handleRefresh ] ) ;
291327
292328 // Set up polling every 60 seconds
293329 useEffect ( ( ) => {
0 commit comments