← back to Govarbitrage

apps/mobile/components/ScoreBadge.tsx

65 lines

import React from "react";
import { StyleSheet, Text, View } from "react-native";
import { Colors, Radius, Spacing, Typography } from "../constants/theme";
import { fmtScore } from "../lib/format";

interface Props {
  label: string;
  score: number | null | undefined;
  size?: "sm" | "md" | "lg";
}

function scoreColor(score: number | null | undefined): string {
  if (score == null || !Number.isFinite(score)) return Colors.neutral;
  if (score >= 70) return Colors.scoreHigh;
  if (score >= 40) return Colors.scoreMid;
  return Colors.scoreLow;
}

export function ScoreBadge({ label, score, size = "md" }: Props) {
  const color = scoreColor(score);
  const sz = size === "lg" ? 44 : size === "md" ? 36 : 28;
  const fontSize = size === "lg" ? Typography.sizes.lg : size === "md" ? Typography.sizes.base : Typography.sizes.xs;

  return (
    <View style={styles.container}>
      <View
        style={[
          styles.circle,
          { width: sz, height: sz, borderRadius: sz / 2, borderColor: color },
        ]}
      >
        <Text style={[styles.value, { fontSize, color }]}>{fmtScore(score)}</Text>
      </View>
      <Text style={[styles.label, size === "sm" && styles.labelSm]}>{label}</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    alignItems: "center",
    gap: Spacing.xs,
  },
  circle: {
    borderWidth: 2,
    alignItems: "center",
    justifyContent: "center",
    backgroundColor: Colors.surface,
  },
  value: {
    fontWeight: "700",
    fontVariant: ["tabular-nums"],
  },
  label: {
    fontSize: Typography.sizes.xs,
    color: Colors.textMuted,
    textAlign: "center",
    textTransform: "uppercase",
    letterSpacing: 0.5,
  },
  labelSm: {
    fontSize: 9,
  },
});