Refactor components to utilize formatNumber utility for consistent number formatting across BuildingButton, NextBuildingPreview, ResourceDisplay, and App. Removed deprecated upgrades section in App for cleaner UI, enhancing overall user experience.

This commit is contained in:
billy 2025-03-30 15:03:50 -04:00
parent c940b424a3
commit a25fa4a94c
5 changed files with 58 additions and 24 deletions

View File

@ -4,6 +4,7 @@ import { NextBuildingPreview } from './components/NextBuildingPreview'
import { ResetButton } from './components/ResetButton' import { ResetButton } from './components/ResetButton'
import { useGameStore } from './store/gameStore' import { useGameStore } from './store/gameStore'
import { playClickSound, initAudio } from './utils/soundUtils' import { playClickSound, initAudio } from './utils/soundUtils'
import { formatNumber } from './utils/numberUtils'
import { import {
ChakraProvider, ChakraProvider,
Box, Box,
@ -115,17 +116,6 @@ function App() {
))} ))}
<NextBuildingPreview /> <NextBuildingPreview />
</SimpleGrid> </SimpleGrid>
<Box h="1px" bg="gray.600" w="full" />
{/* Upgrades Section */}
<Box bg="gray.800" p={6} borderRadius="lg" w="full">
<Heading as="h2" size="xl" mb={6} color="green.400">Upgrades</Heading>
<SimpleGrid columns={{ base: 1, md: 2, lg: 3 }} gap={4}>
{/* Click Power button has been moved to ResourceDisplay header */}
{/* Add other upgrades here in the future */}
</SimpleGrid>
</Box>
</VStack> </VStack>
</VStack> </VStack>
</Container> </Container>

View File

@ -11,6 +11,7 @@ import {
AspectRatio AspectRatio
} from '@chakra-ui/react' } from '@chakra-ui/react'
import { useGameStore } from '../store/gameStore' import { useGameStore } from '../store/gameStore'
import { formatNumber } from '../utils/numberUtils'
// Import all building images // Import all building images
import mouseImg from '../assets/mouse.png' import mouseImg from '../assets/mouse.png'
@ -96,7 +97,7 @@ export function BuildingButton({
if (owned === 0) { if (owned === 0) {
return "You need to own this building first"; return "You need to own this building first";
} else if (points < upgradeCost) { } else if (points < upgradeCost) {
return `Not enough points (${points}/${upgradeCost})`; return `Not enough points (${formatNumber(points)}/${formatNumber(upgradeCost)})`;
} }
return `Upgrade to level ${level + 1}`; return `Upgrade to level ${level + 1}`;
}; };
@ -150,7 +151,7 @@ export function BuildingButton({
borderTopLeftRadius="md" borderTopLeftRadius="md"
borderBottomRightRadius="md" borderBottomRightRadius="md"
> >
<Text fontSize="sm">Owned: {owned}</Text> <Text fontSize="sm">Owned: {formatNumber(owned)}</Text>
</Box> </Box>
{/* Level badge */} {/* Level badge */}
@ -172,8 +173,8 @@ export function BuildingButton({
<Flex justifyContent="space-between" alignItems="center" mb={1}> <Flex justifyContent="space-between" alignItems="center" mb={1}>
<Text fontSize="sm" fontWeight="bold">Production:</Text> <Text fontSize="sm" fontWeight="bold">Production:</Text>
</Flex> </Flex>
<Text fontSize="sm">Points: {(pointsPerSecond * level).toFixed(1)}/s per building</Text> <Text fontSize="sm">Points: {formatNumber(pointsPerSecond * level)}/s per building</Text>
<Text fontSize="sm">Total: {(pointsPerSecond * level * owned).toFixed(1)}/s</Text> <Text fontSize="sm">Total: {formatNumber(pointsPerSecond * level * owned)}/s</Text>
</Box> </Box>
<HStack spacing={2}> <HStack spacing={2}>
<Button <Button
@ -185,7 +186,7 @@ export function BuildingButton({
size="sm" size="sm"
flexGrow={1} flexGrow={1}
> >
Buy ({cost} points) Buy ({formatNumber(cost)} points)
</Button> </Button>
<Tooltip label={getUpgradeTooltip()}> <Tooltip label={getUpgradeTooltip()}>
<Button <Button
@ -197,7 +198,7 @@ export function BuildingButton({
size="sm" size="sm"
flexGrow={1} flexGrow={1}
> >
Upgrade ({upgradeCost} points) Upgrade ({formatNumber(upgradeCost)} points)
</Button> </Button>
</Tooltip> </Tooltip>
</HStack> </HStack>

View File

@ -7,6 +7,7 @@ import {
} from '@chakra-ui/react' } from '@chakra-ui/react'
import { useGameStore } from '../store/gameStore' import { useGameStore } from '../store/gameStore'
import { BUILDING_INFO } from '../store/gameStore' import { BUILDING_INFO } from '../store/gameStore'
import { formatNumber } from '../utils/numberUtils'
interface BuildingInfo { interface BuildingInfo {
cost: number cost: number
@ -48,12 +49,12 @@ export function NextBuildingPreview() {
</Box> </Box>
<Text fontSize="sm" color="gray.400">{info.description}</Text> <Text fontSize="sm" color="gray.400">{info.description}</Text>
<Box display="flex" justifyContent="space-between" alignItems="center"> <Box display="flex" justifyContent="space-between" alignItems="center">
<Text>Cost: {info.cost} points</Text> <Text>Cost: {formatNumber(info.cost)} points</Text>
<Text>Level Required: {info.levelRequirement}</Text> <Text>Level Required: {info.levelRequirement}</Text>
</Box> </Box>
<Box> <Box>
<Text fontSize="sm">Production:</Text> <Text fontSize="sm">Production:</Text>
<Text fontSize="sm">Points: {info.production.points}/s</Text> <Text fontSize="sm">Points: {formatNumber(info.production.points || 0)}/s</Text>
</Box> </Box>
</VStack> </VStack>
</Box> </Box>

View File

@ -4,6 +4,7 @@ import logoImg from '../assets/logo.png'
import { ResetButton } from './ResetButton' import { ResetButton } from './ResetButton'
import { SoundToggleButton } from './SoundToggleButton' import { SoundToggleButton } from './SoundToggleButton'
import { AddIcon } from '@chakra-ui/icons' import { AddIcon } from '@chakra-ui/icons'
import { formatNumber } from '../utils/numberUtils'
export function ResourceDisplay() { export function ResourceDisplay() {
const { points, pointsPerSecond, clickPower, playerLevel, getClickPowerUpgradeCost, buyUpgrade } = useGameStore() const { points, pointsPerSecond, clickPower, playerLevel, getClickPowerUpgradeCost, buyUpgrade } = useGameStore()
@ -87,8 +88,8 @@ export function ResourceDisplay() {
{/* Points */} {/* Points */}
<Box textAlign="center" minW="120px"> <Box textAlign="center" minW="120px">
<Text fontSize="sm" fontWeight="bold">Points</Text> <Text fontSize="sm" fontWeight="bold">Points</Text>
<Text fontSize="md" fontWeight="bold">{Math.floor(points)}</Text> <Text fontSize="md" fontWeight="bold">{formatNumber(Math.floor(points))}</Text>
<Text fontSize="xs" color="green.400">+{pointsPerSecond.toFixed(1)}/s</Text> <Text fontSize="xs" color="green.400">+{formatNumber(pointsPerSecond)}/s</Text>
</Box> </Box>
<Divider orientation="vertical" h="40px" /> <Divider orientation="vertical" h="40px" />
@ -97,8 +98,8 @@ export function ResourceDisplay() {
<Box textAlign="center" minW="120px"> <Box textAlign="center" minW="120px">
<Text fontSize="sm" fontWeight="bold">Click Power</Text> <Text fontSize="sm" fontWeight="bold">Click Power</Text>
<Flex justify="center" align="center" gap={1}> <Flex justify="center" align="center" gap={1}>
<Text fontSize="md">{clickPower}</Text> <Text fontSize="md">{formatNumber(clickPower)}</Text>
<Tooltip label={`Upgrade to level ${clickPower + 1} (${clickPowerUpgradeCost} points)`}> <Tooltip label={`Upgrade to level ${clickPower + 1} (${formatNumber(clickPowerUpgradeCost)} points)`}>
<Button <Button
size="xs" size="xs"
colorScheme="green" colorScheme="green"
@ -126,7 +127,7 @@ export function ResourceDisplay() {
</Box> </Box>
{/* Progress to next level */} {/* Progress to next level */}
<Tooltip label={`${pointsPerSecond.toFixed(1)}/${nextLevelPPS} PPS`}> <Tooltip label={`${formatNumber(pointsPerSecond)}/${formatNumber(nextLevelPPS)} PPS`}>
<Box flex="1" maxW="300px"> <Box flex="1" maxW="300px">
<Flex justify="space-between" mb={1}> <Flex justify="space-between" mb={1}>
<Text fontSize="xs" color="gray.400">Level {playerLevel}</Text> <Text fontSize="xs" color="gray.400">Level {playerLevel}</Text>

41
src/utils/numberUtils.ts Normal file
View File

@ -0,0 +1,41 @@
/**
* Formats a number with appropriate suffixes (K, M, B, etc.) and optional commas
*
* @param value The number to format
* @param decimals Number of decimal places to show for values > 1000 (default: 3)
* @param useCommas Whether to add commas to numbers (default: true)
* @returns Formatted string representation of the number
*/
export function formatNumber(value: number, decimals: number = 3, useCommas: boolean = true): string {
// Handle zero or undefined values
if (!value || value === 0) return '0';
// Define number suffixes
const suffixes = ['', 'K', 'M', 'B', 'T', 'Qa', 'Qi', 'Sx', 'Sp', 'Oc', 'No', 'Dc'];
// If the number is 1000 or less, format without decimals
if (value <= 1000) {
return useCommas ? Math.floor(value).toLocaleString() : Math.floor(value).toString();
}
// Calculate the appropriate suffix tier
const tier = Math.floor(Math.log10(Math.abs(value)) / 3);
// Make sure we don't exceed available suffixes
const suffix = suffixes[Math.min(tier, suffixes.length - 1)];
// Scale the number to the appropriate tier
const scale = Math.pow(10, tier * 3);
const scaled = value / scale;
// Format the scaled number with exactly 3 decimal places
let formattedValue = scaled.toFixed(decimals);
// Add commas if requested
if (useCommas) {
const parts = formattedValue.split('.');
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
formattedValue = parts.join('.');
}
return `${formattedValue}${suffix}`;
}