Merge pull request #14 from djwesty/vutukuri15/2

Implement Player Count Selector Component (Issue #2)
This commit is contained in:
Vutukuri15 2025-02-09 15:10:50 -08:00 committed by GitHub
commit ef7e9fd081
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 358 additions and 12 deletions

View File

@ -1,15 +1,21 @@
import { Text, View } from "react-native";
import React, { useState } from "react";
import { ScrollView, Text } from "react-native";
import PlayerSelector from "@/components/PlayerSelector";
const IndexScreen = () => {
const [playerCount, setPlayerCount] = useState(2);
export default function Index() {
return (
<View
style={{
flex: 1,
justifyContent: "center",
alignItems: "center",
}}
>
<Text>Edit app/index.tsx to edit this screen.</Text>
</View>
<ScrollView contentContainerStyle={{ padding: 20, flexGrow: 1 }}>
<Text style={{ fontSize: 24, marginBottom: 30, marginTop: 50 }}>
Poker Chip Helper
</Text>
<PlayerSelector
playerCount={playerCount}
setPlayerCount={setPlayerCount}
/>
</ScrollView>
);
}
};
export default IndexScreen;

View File

@ -0,0 +1,64 @@
import React from "react";
import { View, Text, Button, Image, StyleSheet } from "react-native";
interface PlayerSelectorProps {
playerCount: number;
setPlayerCount: React.Dispatch<React.SetStateAction<number>>;
}
const PlayerSelector: React.FC<PlayerSelectorProps> = ({
playerCount,
setPlayerCount,
}) => {
const increasePlayers = () => {
if (playerCount < 8) setPlayerCount(playerCount + 1);
};
const decreasePlayers = () => {
if (playerCount > 2) setPlayerCount(playerCount - 1);
};
return (
<View style={styles.container}>
<View style={styles.header}>
<Image
source={{
uri: "https://static.thenounproject.com/png/3890959-200.png",
}}
style={styles.icon}
/>
<Text style={styles.title}>Select Number of Players:</Text>
</View>
<Text style={styles.playerCount}>{playerCount}</Text>
<View style={{ flexDirection: "row" }}>
<Button title="-" onPress={decreasePlayers} />
<Button title="+" onPress={increasePlayers} />
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
padding: 20,
},
header: {
flexDirection: "row",
alignItems: "center",
},
title: {
fontSize: 18,
marginLeft: 10, // Spacing between icon and text
},
icon: {
width: 48, // Increased size
height: 48, // Increased size
},
playerCount: {
fontSize: 24,
marginVertical: 10,
},
});
export default PlayerSelector;

View File

@ -0,0 +1,57 @@
import React from "react";
import { fireEvent, render } from "@testing-library/react-native";
import PlayerSelector from "@/components/PlayerSelector";
describe("PlayerSelector Component", () => {
it("renders the initial player count and buttons correctly", () => {
const setPlayerCount = jest.fn();
const { getByText, getByRole } = render(
<PlayerSelector playerCount={4} setPlayerCount={setPlayerCount} />
);
expect(getByText("Select Number of Players:")).toBeTruthy();
expect(getByText("4")).toBeTruthy();
expect(getByRole("button", { name: "-" })).toBeTruthy();
expect(getByRole("button", { name: "+" })).toBeTruthy();
});
it('increases player count when "+" button is pressed', () => {
const setPlayerCount = jest.fn();
const { getByRole } = render(
<PlayerSelector playerCount={4} setPlayerCount={setPlayerCount} />
);
fireEvent.press(getByRole("button", { name: "+" }));
expect(setPlayerCount).toHaveBeenCalledWith(5);
});
it('decreases player count when "-" button is pressed', () => {
const setPlayerCount = jest.fn();
const { getByRole } = render(
<PlayerSelector playerCount={4} setPlayerCount={setPlayerCount} />
);
fireEvent.press(getByRole("button", { name: "-" }));
expect(setPlayerCount).toHaveBeenCalledWith(3);
});
it("does not increase player count beyond 8", () => {
const setPlayerCount = jest.fn();
const { getByRole } = render(
<PlayerSelector playerCount={8} setPlayerCount={setPlayerCount} />
);
fireEvent.press(getByRole("button", { name: "+" }));
expect(setPlayerCount).not.toHaveBeenCalled();
});
it("does not decrease player count below 2", () => {
const setPlayerCount = jest.fn();
const { getByRole } = render(
<PlayerSelector playerCount={2} setPlayerCount={setPlayerCount} />
);
fireEvent.press(getByRole("button", { name: "-" }));
expect(setPlayerCount).not.toHaveBeenCalled();
});
});

215
package-lock.json generated
View File

@ -35,6 +35,10 @@
},
"devDependencies": {
"@babel/core": "^7.25.2",
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-native": "^5.4.3",
"@testing-library/react": "^16.2.0",
"@testing-library/react-native": "^13.0.1",
"@types/jest": "^29.5.12",
"@types/react": "~18.3.12",
"@types/react-test-renderer": "^18.3.0",
@ -4476,6 +4480,136 @@
"@sinonjs/commons": "^3.0.0"
}
},
"node_modules/@testing-library/dom": {
"version": "10.4.0",
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz",
"integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.10.4",
"@babel/runtime": "^7.12.5",
"@types/aria-query": "^5.0.1",
"aria-query": "5.3.0",
"chalk": "^4.1.0",
"dom-accessibility-api": "^0.5.9",
"lz-string": "^1.5.0",
"pretty-format": "^27.0.2"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@testing-library/dom/node_modules/ansi-styles": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/@testing-library/dom/node_modules/pretty-format": {
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz",
"integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"ansi-regex": "^5.0.1",
"ansi-styles": "^5.0.0",
"react-is": "^17.0.1"
},
"engines": {
"node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
}
},
"node_modules/@testing-library/dom/node_modules/react-is": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
"dev": true,
"license": "MIT"
},
"node_modules/@testing-library/jest-native": {
"version": "5.4.3",
"resolved": "https://registry.npmjs.org/@testing-library/jest-native/-/jest-native-5.4.3.tgz",
"integrity": "sha512-/sSDGaOuE+PJ1Z9Kp4u7PQScSVVXGud59I/qsBFFJvIbcn4P6yYw6cBnBmbPF+X9aRIsTJRDl6gzw5ZkJNm66w==",
"deprecated": "DEPRECATED: This package is no longer maintained.\nPlease use the built-in Jest matchers available in @testing-library/react-native v12.4+.\n\nSee migration guide: https://callstack.github.io/react-native-testing-library/docs/migration/jest-matchers",
"dev": true,
"license": "MIT",
"dependencies": {
"chalk": "^4.1.2",
"jest-diff": "^29.0.1",
"jest-matcher-utils": "^29.0.1",
"pretty-format": "^29.0.3",
"redent": "^3.0.0"
},
"peerDependencies": {
"react": ">=16.0.0",
"react-native": ">=0.59",
"react-test-renderer": ">=16.0.0"
}
},
"node_modules/@testing-library/react": {
"version": "16.2.0",
"resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.2.0.tgz",
"integrity": "sha512-2cSskAvA1QNtKc8Y9VJQRv0tm3hLVgxRGDB+KYhIaPQJ1I+RHbhIXcM+zClKXzMes/wshsMVzf4B9vS4IZpqDQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.12.5"
},
"engines": {
"node": ">=18"
},
"peerDependencies": {
"@testing-library/dom": "^10.0.0",
"@types/react": "^18.0.0 || ^19.0.0",
"@types/react-dom": "^18.0.0 || ^19.0.0",
"react": "^18.0.0 || ^19.0.0",
"react-dom": "^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@testing-library/react-native": {
"version": "13.0.1",
"resolved": "https://registry.npmjs.org/@testing-library/react-native/-/react-native-13.0.1.tgz",
"integrity": "sha512-sKMRNNniSOZ68qe1OBQAWvK87WCEmbfLp/MXfn2JE3x3WrNU8OFCVL0z/YKqw0/JO/d44J8Wq6FmRSaod/+VAg==",
"dev": true,
"license": "MIT",
"dependencies": {
"chalk": "^4.1.2",
"jest-matcher-utils": "^29.7.0",
"pretty-format": "^29.7.0",
"redent": "^3.0.0"
},
"engines": {
"node": ">=18"
},
"peerDependencies": {
"jest": ">=29.0.0",
"react": ">=18.2.0",
"react-native": ">=0.71",
"react-test-renderer": ">=18.2.0"
},
"peerDependenciesMeta": {
"jest": {
"optional": true
}
}
},
"node_modules/@tootallnate/once": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz",
@ -4486,6 +4620,13 @@
"node": ">= 10"
}
},
"node_modules/@types/aria-query": {
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
"integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/babel__core": {
"version": "7.20.5",
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
@ -5204,6 +5345,16 @@
"sprintf-js": "~1.0.2"
}
},
"node_modules/aria-query": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
"integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"dequal": "^2.0.3"
}
},
"node_modules/array-buffer-byte-length": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz",
@ -6847,6 +6998,16 @@
"node": ">= 0.8"
}
},
"node_modules/dequal": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
"integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/destroy": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
@ -6914,6 +7075,13 @@
"node": ">=0.10.0"
}
},
"node_modules/dom-accessibility-api": {
"version": "0.5.16",
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
"integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
"dev": true,
"license": "MIT"
},
"node_modules/domexception": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz",
@ -11627,6 +11795,16 @@
"yallist": "^3.0.2"
}
},
"node_modules/lz-string": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz",
"integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==",
"dev": true,
"license": "MIT",
"bin": {
"lz-string": "bin/bin.js"
}
},
"node_modules/make-dir": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz",
@ -12185,6 +12363,16 @@
"node": ">=4"
}
},
"node_modules/min-indent": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
"integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=4"
}
},
"node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@ -14014,6 +14202,20 @@
"node": ">=0.10.0"
}
},
"node_modules/redent": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz",
"integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==",
"dev": true,
"license": "MIT",
"dependencies": {
"indent-string": "^4.0.0",
"strip-indent": "^3.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/reflect.getprototypeof": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
@ -15403,6 +15605,19 @@
"node": ">=6"
}
},
"node_modules/strip-indent": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
"integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"min-indent": "^1.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/strip-json-comments": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",

View File

@ -42,6 +42,10 @@
},
"devDependencies": {
"@babel/core": "^7.25.2",
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-native": "^5.4.3",
"@testing-library/react": "^16.2.0",
"@testing-library/react-native": "^13.0.1",
"@types/jest": "^29.5.12",
"@types/react": "~18.3.12",
"@types/react-test-renderer": "^18.3.0",