/** * @file Swipeable item component */ import { IonItemOptions, IonItemSliding, ItemSlidingCustomEvent, } from "@ionic/react"; import {FC, HTMLAttributes, ReactNode, useRef} from "react"; import {usePersistentStore} from "~/lib/stores/persistent"; /** * Swipeable item component props */ interface SwipeableItemProps extends HTMLAttributes { /** * Item content */ children: ReactNode; /** * Start option (Left side) */ startOption?: ReactNode; /** * End option (Right side) */ endOption?: ReactNode; /** * Start action */ startAction?: () => void | Promise; /** * End action */ endAction?: () => void | Promise; } /** * Swipeable item component * @param props Swipeable item component props * @returns JSX */ export const SwipeableItem: FC = ({ children, startOption, endOption, startAction, endAction, ...props }) => { // Hooks const previousRatio = useRef(); const useSlidingActions = usePersistentStore( state => state.useSlidingActions, ); // Methods /** * Item sliding swipe event handler * @param event Item sliding custom event */ const onItemSlidingSwipe = async (event: ItemSlidingCustomEvent) => { if (!useSlidingActions) { return; } // Cast the detail const detail = event.detail as { amount: number; ratio: number; }; // Upvote (Swiped left) if ( previousRatio.current !== undefined && detail.ratio <= -1 && previousRatio.current < detail.ratio ) { await startAction?.(); await event.target.closeOpened(); } // Downvote (Swiped right) else if ( previousRatio.current !== undefined && detail.ratio >= 1 && previousRatio.current > detail.ratio ) { await endAction?.(); await event.target.closeOpened(); } // Store the ratio previousRatio.current = detail.ratio; }; return ( {useSlidingActions && ( {startOption} )} {children} {useSlidingActions && ( {endOption} )} ); };