compassmock/src/hooks/use-pull-to-refresh.ts
Nicholai d30decf723
feat(ui): add mobile support and dashboard improvements (#30)
* feat(schema): add auth, people, and financial tables

Add users, organizations, teams, groups, and project
members tables. Extend customers/vendors with netsuite
fields. Add netsuite schema for invoices, bills,
payments, and credit memos. Include all migrations,
seeds, new UI primitives, and config updates.

* feat(auth): add WorkOS authentication system

Add login, signup, password reset, email verification,
and invitation flows via WorkOS AuthKit. Includes auth
middleware, permission helpers, dev mode fallbacks,
and auth page components.

* feat(people): add people management system

Add user, team, group, and organization management
with CRUD actions, dashboard pages, invite dialog,
user drawer, and role-based filtering. Includes
WorkOS invitation integration.

* feat(netsuite): add NetSuite integration and financials

Add bidirectional NetSuite REST API integration with
OAuth 2.0, rate limiting, sync engine, and conflict
resolution. Includes invoices, vendor bills, payments,
credit memos CRUD, customer/vendor management pages,
and financial dashboard with tabbed views.

* feat(ui): add mobile support and dashboard improvements

Add mobile bottom nav, FAB, filter bar, search, project
switcher, pull-to-refresh, and schedule mobile view.
Update sidebar with new nav items, settings modal with
integrations tab, responsive dialogs, improved schedule
and file components, PWA manifest, and service worker.

* ci: retrigger build

* ci: retrigger build

---------

Co-authored-by: Nicholai <nicholaivogelfilms@gmail.com>
2026-02-04 16:39:39 -07:00

60 lines
1.4 KiB
TypeScript
Executable File

"use client"
import { useState, useRef, useCallback } from "react"
const TRIGGER_THRESHOLD = 80
const MAX_PULL = 120
interface PullToRefreshResult {
isRefreshing: boolean
pullDistance: number
handlers: {
onTouchStart: (e: React.TouchEvent) => void
onTouchMove: (e: React.TouchEvent) => void
onTouchEnd: () => void
}
}
export function usePullToRefresh(
onRefresh: () => Promise<void>
): PullToRefreshResult {
const [isRefreshing, setIsRefreshing] = useState(false)
const [pullDistance, setPullDistance] = useState(0)
const startY = useRef<number | null>(null)
const onTouchStart = useCallback((e: React.TouchEvent) => {
if (window.scrollY === 0) {
startY.current = e.touches[0].clientY
}
}, [])
const onTouchMove = useCallback((e: React.TouchEvent) => {
if (startY.current === null || window.scrollY > 0) return
const currentY = e.touches[0].clientY
const distance = Math.max(
0,
Math.min(currentY - startY.current, MAX_PULL)
)
setPullDistance(distance)
}, [])
const onTouchEnd = useCallback(async () => {
if (pullDistance > TRIGGER_THRESHOLD) {
setIsRefreshing(true)
try {
await onRefresh()
} finally {
setIsRefreshing(false)
}
}
setPullDistance(0)
startY.current = null
}, [pullDistance, onRefresh])
return {
isRefreshing,
pullDistance,
handlers: { onTouchStart, onTouchMove, onTouchEnd },
}
}