Ability to pick the number of chip colors, and their counts (Issue #11) #16

Merged
djwesty merged 4 commits from djwesty/11 into main 2025-02-10 22:31:29 -08:00
3 changed files with 102 additions and 16 deletions
Showing only changes of commit 5a2d7cfe54 - Show all commits

View File

@ -3,7 +3,6 @@ import {
View, View,
Text, Text,
TextInput, TextInput,
TouchableOpacity,
StyleSheet, StyleSheet,
Button, Button,
ColorValue, ColorValue,
@ -25,27 +24,40 @@ const ChipInputModal = ({
const color: ColorValue = useMemo(() => showModal[1], [showModal]); const color: ColorValue = useMemo(() => showModal[1], [showModal]);
const colorIdx = useMemo(() => colors.indexOf(color), [color]); const colorIdx = useMemo(() => colors.indexOf(color), [color]);
const value: number = useMemo( const [value, setValue] = useState<number | undefined>(); // value may be undefined initially
() => totalChipsCount[colorIdx],
[totalChipsCount, colorIdx] // Reset the color value when the specific color this modal is for, changes. The same modal is shared/reused in all cases.
); useEffect(() => {
setValue(totalChipsCount[colorIdx]);
}, [colorIdx]);
return ( return (
<Modal <Modal
visible={showModal[0]} visible={showModal[0]}
onRequestClose={() => setShowModal([false, color])} onRequestClose={() => setShowModal([false, color])}
> >
{value !== undefined && (
<>
<Text>Number of {showModal[1]?.toString()} chips</Text> <Text>Number of {showModal[1]?.toString()} chips</Text>
<TextInput <TextInput
style={{ color: showModal[1] }} style={{ color: showModal[1] }}
keyboardType="numeric" keyboardType="numeric"
value={value.toString()} value={value.toString()}
onChangeText={(v) => { onChangeText={(v) => {
const n = parseInt(v); const dirtyNum: number = parseInt(v);
update(showModal[1], Number.isNaN(n) ? 0 : n); !isNaN(dirtyNum) ? setValue(dirtyNum) : setValue(0);
}}
testID="modalInput"
/>
</>
)}
<Button
title="Accept"
onPress={() => {
update(showModal[1], Number.isNaN(value) ? 0 : value);
setShowModal([false, color]);
}} }}
/> />
<Button title="Accept" onPress={() => setShowModal([false, color])} />
</Modal> </Modal>
); );
}; };
@ -74,7 +86,7 @@ const ChipsSelector = ({
numberOfChips, numberOfChips,
totalChipsCount, totalChipsCount,
setTotalChipsCount, setTotalChipsCount,
setNumberOfChips, setNumberOfChips, // todo
}: { }: {
numberOfChips: number; numberOfChips: number;
totalChipsCount: number[]; totalChipsCount: number[];
@ -90,6 +102,7 @@ const ChipsSelector = ({
[numberOfChips] [numberOfChips]
); );
// Callback for ChipInputModal to update the chips in the parents state.
const update = useCallback( const update = useCallback(
(color: ColorValue, count: number) => { (color: ColorValue, count: number) => {
const newTotalChipsCount = totalChipsCount.slice(); const newTotalChipsCount = totalChipsCount.slice();
@ -99,6 +112,8 @@ const ChipsSelector = ({
}, },
[numberOfChips, totalChipsCount, setTotalChipsCount] [numberOfChips, totalChipsCount, setTotalChipsCount]
); );
// When the number of chips changes (dec or inc), update the array being careful to add in sensible default values where they belong
useEffect(() => { useEffect(() => {
if (numberOfChips !== totalChipsCount.length) { if (numberOfChips !== totalChipsCount.length) {
let newTotalChipsCount = totalChipsCount.slice(); let newTotalChipsCount = totalChipsCount.slice();
@ -150,7 +165,6 @@ const styles = StyleSheet.create({
backgroundColor: "#ddd", backgroundColor: "#ddd",
}, },
chip: { chip: {
// backgroundColor: "blue",
textAlign: "center", textAlign: "center",
fontSize: 16, fontSize: 16,
fontWeight: "bold", fontWeight: "bold",

View File

@ -0,0 +1,72 @@
import React from "react";
import {
userEvent,
render,
screen,
waitForElementToBeRemoved,
waitFor,
} from "@testing-library/react-native";
import ChipsSelector from "@/components/ChipsSelector";
const TOTAL_CHIPS_COUNT = [100, 80, 60, 20, 10];
const mocktTotalChipsCount = jest.fn();
const mockSetNumberOfChips = jest.fn();
const rend = () =>
render(
<ChipsSelector
numberOfChips={TOTAL_CHIPS_COUNT.length}
totalChipsCount={TOTAL_CHIPS_COUNT}
setTotalChipsCount={mocktTotalChipsCount}
setNumberOfChips={mockSetNumberOfChips}
/>
);
describe("tests for ChipsSelector", () => {
test("ChipsSelector appears with correct default values", () => {
rend();
const white = screen.getByText(TOTAL_CHIPS_COUNT[0].toString());
expect(white).toHaveStyle({ color: "white" });
const red = screen.getByText(TOTAL_CHIPS_COUNT[1].toString());
expect(red).toHaveStyle({ color: "red" });
const green = screen.getByText(TOTAL_CHIPS_COUNT[2].toString());
expect(green).toHaveStyle({ color: "green" });
const blue = screen.getByText(TOTAL_CHIPS_COUNT[3].toString());
expect(blue).toHaveStyle({ color: "blue" });
const black = screen.getByText(TOTAL_CHIPS_COUNT[4].toString());
expect(black).toHaveStyle({ color: "black" });
});
test("updating chip count works as expected", async () => {
rend();
const green = screen.getByText("60");
expect(green).toHaveStyle({ color: "green" });
userEvent.press(green);
const modalLabel = await screen.findByText(/number of green chips/i);
expect(modalLabel).toBeDefined();
const modalInput = screen.getByTestId("modalInput");
expect(modalInput).toHaveDisplayValue("60");
await userEvent.press(modalInput);
await userEvent.clear(modalInput);
await userEvent.type(modalInput, "64");
const acceptButton = screen.getByRole("button", { name: /accept/i });
await userEvent.press(acceptButton);
const modalLabelAgain = screen.queryByText(/number of green chips/i); //If the label is gone, we know the modal is no longer visible
expect(modalLabelAgain).not.toBeVisible();
expect(mocktTotalChipsCount).toHaveBeenCalledWith([100, 80, 64, 20, 10]);
});
test.todo("updating total amount of color chips works as expected");
});