Skip to main content
React hooks for fetching user scores and calculating rank information based on completed goals.

useUserScore

Fetch the current user’s score and ranking information.
const { data, isLoading, error } = useUserScore()

Returns

data
UserScore | null
The user’s score data, or null if the user is not authenticated
isLoading
boolean
Loading state of the query
error
Error | null
Error object if the query failed

UserScore type

The UserScore object contains:
user_id
string
The ID of the user
total_score
number
The user’s total score from completed goals
goals_completed
number
The number of goals the user has completed
goals_total
number
The total number of goals the user has created

Example

import { useUserScore } from '@features/goals/api/use-score'
import { getRankInfo } from '@features/goals/api/use-score'

function UserScoreCard() {
  const { data: userScore, isLoading } = useUserScore()
  
  if (isLoading) return <div>Loading...</div>
  if (!userScore) return null
  
  const rank = getRankInfo(userScore.total_score)
  
  return (
    <div>
      <h2>Your Score</h2>
      <p>Total Score: {userScore.total_score}</p>
      <p>Goals Completed: {userScore.goals_completed} / {userScore.goals_total}</p>
      <p>Rank: {rank.rank_emoji} {rank.rank_name}</p>
      {rank.next_threshold && (
        <p>
          Next Rank: {rank.next_rank_name} at {rank.next_threshold} points
        </p>
      )}
    </div>
  )
}

getRankInfo

Utility function to calculate rank information based on a score.
const rankInfo = getRankInfo(score)

Parameters

score
number
required
The score to calculate rank information for

Returns

rank_name
string
The name of the current rank (e.g., 'Rookie', 'Hustler', 'Champion')
rank_emoji
string
The emoji representing the current rank
next_threshold
number | null
The score needed to reach the next rank, or null if at max rank
next_rank_name
string | null
The name of the next rank, or null if at max rank

Example

import { getRankInfo } from '@features/goals/api/use-score'

function calculateProgress(score: number) {
  const rank = getRankInfo(score)
  
  if (!rank.next_threshold) {
    return 100 // Max rank achieved
  }
  
  // Find the minimum score for the current rank
  const currentRankData = RANKS.find(r => r.rank_name === rank.rank_name)
  const currentMin = currentRankData?.min_score ?? 0
  
  const progress = ((score - currentMin) / (rank.next_threshold - currentMin)) * 100
  return Math.min(progress, 100)
}

function RankProgress({ score }: { score: number }) {
  const rank = getRankInfo(score)
  const progress = calculateProgress(score)
  
  return (
    <div>
      <h3>{rank.rank_emoji} {rank.rank_name}</h3>
      {rank.next_threshold && (
        <>
          <div className="progress-bar">
            <div className="progress" style={{ width: `${progress}%` }} />
          </div>
          <p>
            {score} / {rank.next_threshold} to {rank.next_rank_name}
          </p>
        </>
      )}
    </div>
  )
}

RANKS

Constant array containing all rank definitions.
export const RANKS: Array<RankInfo & { min_score: number }>

Rank tiers

The ranking system includes the following tiers:
RankEmojiMin ScoreNext Threshold
Rookie🌱050
Hustler50150
Achiever🎯150350
Go-Getter🔥350700
Champion🏆7001500
Legend👑1500-

Example

import { RANKS } from '@features/goals/api/use-score'

function RanksList() {
  return (
    <div>
      <h2>All Ranks</h2>
      <ul>
        {RANKS.map((rank) => (
          <li key={rank.rank_name}>
            {rank.rank_emoji} {rank.rank_name} - {rank.min_score}+ points
          </li>
        ))}
      </ul>
    </div>
  )
}

Build docs developers (and LLMs) love