1- import { useState , useRef } from "react" ;
1+ import { useRef , useEffect } from "react" ;
22import { Card } from "@/components/ui/card" ;
33import { Checkbox } from "@/components/ui/checkbox" ;
44import { MiniScanner } from "@/components/ui/mini-scanner" ;
55import { Trash2 , Clock } from "lucide-react" ;
66import { formatDistanceToNow } from "date-fns" ;
77import type { Session } from "@/api/types" ;
8+ import { useSwipe } from "@/hooks/useSwipe" ;
89
910interface SessionCardProps {
1011 session : Session ;
@@ -25,57 +26,26 @@ export const SessionCard = ({
2526 onToggleSelection,
2627 onDelete,
2728} : SessionCardProps ) => {
28- const [ swipeOffset , setSwipeOffset ] = useState ( 0 ) ;
29- const [ isSwipeOpen , setIsSwipeOpen ] = useState ( false ) ;
30- const touchStartX = useRef < number | null > ( null ) ;
3129 const cardRef = useRef < HTMLDivElement > ( null ) ;
30+ const { bind, swipeOffset, isOpen, isSwipingBack, close, swipeStyles } = useSwipe ( ) ;
3231
33- const handleTouchStart = ( e : React . TouchEvent ) => {
34- touchStartX . current = e . touches [ 0 ] . clientX ;
35- } ;
36-
37- const handleTouchMove = ( e : React . TouchEvent ) => {
38- if ( touchStartX . current === null ) return ;
39-
40- const currentX = e . touches [ 0 ] . clientX ;
41- const diff = touchStartX . current - currentX ;
42-
43- if ( diff > 0 ) {
44- const newOffset = Math . min ( diff , 80 ) ;
45- setSwipeOffset ( newOffset ) ;
46- } else if ( diff < 0 && isSwipeOpen ) {
47- const newOffset = Math . max ( 0 , 80 + diff ) ;
48- setSwipeOffset ( newOffset ) ;
49- }
50- } ;
51-
52- const handleTouchEnd = ( ) => {
53- if ( swipeOffset > 50 ) {
54- setIsSwipeOpen ( true ) ;
55- setSwipeOffset ( 80 ) ;
56- } else if ( swipeOffset < 30 ) {
57- setIsSwipeOpen ( false ) ;
58- setSwipeOffset ( 0 ) ;
32+ useEffect ( ( ) => {
33+ if ( cardRef . current ) {
34+ return bind ( cardRef . current ) ;
5935 }
60- touchStartX . current = null ;
61- } ;
62-
63- const closeSwipe = ( ) => {
64- setSwipeOffset ( 0 ) ;
65- setIsSwipeOpen ( false ) ;
66- } ;
36+ } , [ bind ] ) ;
6737
6838 const handleDeleteClick = ( e : React . MouseEvent < HTMLButtonElement > ) => {
6939 e . stopPropagation ( ) ;
7040 onDelete ( e ) ;
71- closeSwipe ( ) ;
41+ close ( ) ;
7242 } ;
7343
7444 return (
75- < div className = "relative" onClick = { closeSwipe } >
45+ < div className = "relative" onClick = { close } >
7646 < div
7747 className = { `absolute top-0.5 right-0 bottom-0.5 w-20 bg-red-600 flex items-center justify-center rounded-r-lg transition-opacity ${
78- swipeOffset > 20 || isSwipeOpen ? "opacity-100" : "opacity-0"
48+ ! isSwipingBack && ( isOpen || swipeOffset > 40 ) ? "opacity-100" : "opacity-0"
7949 } `}
8050 >
8151 < button
@@ -85,17 +55,10 @@ export const SessionCard = ({
8555 < Trash2 className = "w-5 h-5" />
8656 </ button >
8757 </ div >
88- < div
89- ref = { cardRef }
90- onTouchStart = { handleTouchStart }
91- onTouchMove = { handleTouchMove }
92- onTouchEnd = { handleTouchEnd }
93- style = { { transform : `translateX(-${ swipeOffset } px)` } }
94- className = "transition-transform"
95- >
58+ < div ref = { cardRef } style = { swipeStyles } >
9659 < Card
9760 className = { `p-2 cursor-pointer transition-all overflow-hidden ${
98- isSwipeOpen
61+ isOpen
9962 ? "rounded-none"
10063 : "rounded-r-lg"
10164 } ${
@@ -106,7 +69,7 @@ export const SessionCard = ({
10669 : "bg-card border-border hover:bg-accent hover:border-border"
10770 } hover:shadow-lg`}
10871 onClick = { ( ) => {
109- if ( ! isSwipeOpen ) {
72+ if ( ! isOpen ) {
11073 onSelect ( session . id ) ;
11174 }
11275 } }
0 commit comments