newOS for Developers

Back to Overview

useRating

hook175 lines

Handles the voting/rating mechanism for posts with short taps, long-press progression, error handling, and Watts collection modal.

Source Path
apps/web/hooks/useRating.tsx
Package

@newos/web

Signature

useRating(): {
  rateDisabled: boolean;                    // Is rating currently disabled
  progress: number;                         // Progress bar value (0-100)
  err: string | null;                       // Error message if any
  pending: boolean;                         // Is a rating in progress
  shortRating: (id: string) => void;        // Handler for quick tap rating
  longClick: (id: string) => void;          // Handler for long press start
  longClickEnd: () => void;                 // Handler for long press end
  longClickProgress: () => void;            // Progress tick for long press
  modal: React.ReactElement;                // Watts collection modal
}

Data Flow & API Calls

Reads (Input)

current() — Gets current user to check Watts balance

Writes (Output)

rate({ id, value }) — Submits the rating for a post
Value: 1 for short rating, up to 100 for long-press
powerUp() — Triggered via modal when user needs more Watts

Hooks Used

useDialog() — Manages Watts collection modal
useIsWideScreen() — Responsive behavior

Key Features

Short Rating (Tap)

Call shortRating(id) for a quick +1 Watt vote. Automatically debounced to prevent double-taps.

Long Press Rating

For larger ratings: call longClick(id) on press start,longClickProgress() on interval, longClickEnd() on release.

Progress Bar

During long press, progress increments from 0 to 100. Final value determines the rating amount.

Watts Collection Modal

When user has 0 Watts, shows a modal to collect free Watts. Access via modal return value.

Error Handling

err contains error messages. Check for 401 (unauthorized) to prompt login, or 402 for insufficient Watts.

Usage Example

const {
  shortRating,
  longClick,
  longClickEnd,
  longClickProgress,
  progress,
  pending,
  modal
} = useRating();

// Set up interval for long press
const intervalRef = useRef<NodeJS.Timer>();

const handleMouseDown = (postId: string) => {
  longClick(postId);
  intervalRef.current = setInterval(longClickProgress, 50);
};

const handleMouseUp = () => {
  clearInterval(intervalRef.current);
  longClickEnd();
};

return (
  <>
    <button
      onClick={() => shortRating(postId)}
      onMouseDown={() => handleMouseDown(postId)}
      onMouseUp={handleMouseUp}
      disabled={pending}
    >
      <ProgressCircle progress={progress} />
      ⚡ Vote
    </button>
    {modal}
  </>
);

Edge Cases & Gotchas

rateDisabled State — Check rateDisabled before allowing rating actions. True when pending or user has no Watts.
Self-Rating Prevention — Some components check if author === current user before enabling rating. This hook doesn't enforce it.
Modal Rendering — Always render the modal return value in your component. It's null when not active.
Touch Events — For mobile, use onTouchStart andonTouchEnd in addition to mouse events.
Progress Reset — Progress automatically resets to 0 whenlongClickEnd() is called.

Related