256 lines
7.8 KiB
TypeScript
Executable File
256 lines
7.8 KiB
TypeScript
Executable File
import React, {ChangeEvent, FocusEvent, ReactNode, KeyboardEvent} from "react";
|
|
import {ScoreCellValue} from "../Classes/ScoreCell";
|
|
import {CellEventResponse} from "./KadiBoard";
|
|
import {CellLocation} from "../Classes/PlayerScoreCard";
|
|
import {useLongPress} from "./useLongPress";
|
|
import {CellFlag, FieldType} from "../../../shared/rulesets";
|
|
|
|
export type KadiCellDisplayValue = ScoreCellValue | CellFlag.strike;
|
|
|
|
export interface KadiCellProps {
|
|
location: CellLocation;
|
|
fieldType: FieldType;
|
|
playerId: string;
|
|
value: KadiCellDisplayValue;
|
|
showResults?: boolean;
|
|
onCellEdit: (response: CellEventResponse) => void;
|
|
}
|
|
|
|
interface KadiCellState {}
|
|
|
|
class KadiCell extends React.Component<KadiCellProps, KadiCellState> {
|
|
private readonly standardTimeoutTimeMs: number;
|
|
constructor(props: KadiCellProps) {
|
|
super(props);
|
|
this.standardTimeoutTimeMs = 400;
|
|
}
|
|
|
|
shouldComponentUpdate(
|
|
nextProps: Readonly<KadiCellProps>,
|
|
nextState: Readonly<KadiCellState>,
|
|
nextContext: any): boolean {
|
|
return nextProps.value != this.props.value;
|
|
}
|
|
|
|
updateCell = (value: ScoreCellValue): void => {
|
|
const response: CellEventResponse = {
|
|
value: value,
|
|
playerId: this.props.playerId,
|
|
location: this.props.location,
|
|
};
|
|
this.props.onCellEdit(response);
|
|
};
|
|
|
|
strikeCell = (): void => {
|
|
const response: CellEventResponse = {
|
|
value: CellFlag.strike,
|
|
playerId: this.props.playerId,
|
|
location: this.props.location,
|
|
};
|
|
this.props.onCellEdit(response);
|
|
};
|
|
|
|
unstrikeCell = (): void => {
|
|
const response: CellEventResponse = {
|
|
value: CellFlag.unstrike,
|
|
playerId: this.props.playerId,
|
|
location: this.props.location,
|
|
};
|
|
this.props.onCellEdit(response);
|
|
};
|
|
|
|
render(): ReactNode {
|
|
const {
|
|
fieldType,
|
|
value,
|
|
} = this.props;
|
|
|
|
const propsForEditableCell = {
|
|
timeoutMs: this.standardTimeoutTimeMs,
|
|
updateCell: this.updateCell,
|
|
strikeCell: this.strikeCell,
|
|
value: value as ScoreCellValue,
|
|
};
|
|
|
|
if (value === CellFlag.strike) {
|
|
return <StrikeKadiCell unstrikeCell={this.unstrikeCell} />;
|
|
}
|
|
else {
|
|
switch (fieldType) {
|
|
case FieldType.bonus:
|
|
case FieldType.subtotal:
|
|
case FieldType.total:
|
|
case FieldType.globalTotal:
|
|
return (
|
|
<GenericResultsKadiCell
|
|
classNameString={fieldType}
|
|
value={value}
|
|
/>
|
|
);
|
|
case FieldType.bool:
|
|
return <BoolKadiCell {...propsForEditableCell}/>;
|
|
case FieldType.multiplier:
|
|
return <MultipleKadiCell {...propsForEditableCell}/>;
|
|
case FieldType.number:
|
|
return <NumberKadiCell {...propsForEditableCell}/>;
|
|
case FieldType.superkadi:
|
|
return <SuperkadiKadiCell {...propsForEditableCell}/>;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
interface StandardKadiCellProps {
|
|
value: ScoreCellValue,
|
|
}
|
|
|
|
interface StrikeKadiCellProps {
|
|
unstrikeCell: () => void,
|
|
}
|
|
|
|
interface ResultsKadiCellProps extends StandardKadiCellProps {
|
|
}
|
|
|
|
interface UpdateableKadiCellProps extends StandardKadiCellProps {
|
|
updateCell: (updateVal: ScoreCellValue) => void,
|
|
}
|
|
|
|
interface LongPressStrikeKadiCellProps extends StandardKadiCellProps {
|
|
timeoutMs: number,
|
|
strikeCell: () => void,
|
|
}
|
|
|
|
interface GenericResultsKadiCellProps extends ResultsKadiCellProps {
|
|
classNameString: string;
|
|
}
|
|
|
|
type EditableKadiCellProps = UpdateableKadiCellProps & LongPressStrikeKadiCellProps;
|
|
|
|
const NumberKadiCell: React.FunctionComponent<EditableKadiCellProps> = ({ strikeCell, updateCell, value , timeoutMs}) => {
|
|
const [beingEdited, setBeingEdited] = React.useState(false);
|
|
const [currentEditValue, setCurrentEditValue] = React.useState("");
|
|
const strikeCellOnLongPress = useLongPress(strikeCell, timeoutMs);
|
|
|
|
const displayText: string = beingEdited ? currentEditValue : value.toString();
|
|
|
|
const handleFocus = (e: FocusEvent<HTMLInputElement>) => {
|
|
setBeingEdited(true);
|
|
};
|
|
|
|
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
|
|
setCurrentEditValue(e.target.value);
|
|
if (e.target.value == "") {
|
|
strikeCell();
|
|
endInput();
|
|
}
|
|
};
|
|
|
|
const handleBlur = (e: FocusEvent<HTMLInputElement>) => {
|
|
submitInput(e.target.value);
|
|
};
|
|
|
|
const handleKeyUp = (e: KeyboardEvent<HTMLInputElement>) => {
|
|
if (e.key === "Enter") {
|
|
submitInput(e.currentTarget.value);
|
|
}
|
|
};
|
|
|
|
const submitInput = (input: string) => {
|
|
updateCell(Number(input));
|
|
endInput();
|
|
};
|
|
|
|
const endInput = () => {
|
|
setBeingEdited(false);
|
|
setCurrentEditValue("");
|
|
};
|
|
|
|
return (
|
|
<td className={"kadiCell editable numberField"}>
|
|
<div className={"numberField"}>
|
|
<input
|
|
type={"number"}
|
|
onFocus={handleFocus}
|
|
onBlur={handleBlur}
|
|
onInput={handleChange}
|
|
onChange={handleChange}
|
|
onKeyUp={handleKeyUp}
|
|
value={displayText}
|
|
className={"numberField"}
|
|
onAuxClick={strikeCell}
|
|
{...strikeCellOnLongPress}
|
|
/>
|
|
</div>
|
|
</td>
|
|
)
|
|
};
|
|
|
|
const SuperkadiKadiCell: React.FunctionComponent<EditableKadiCellProps> = ({value, timeoutMs, strikeCell, updateCell}) => {
|
|
const handleClick = (): void => updateCell(true);
|
|
const strikeCellOnLongPress = useLongPress(strikeCell, timeoutMs);
|
|
return (
|
|
<td
|
|
className={"kadiCell editable superkadiField"}
|
|
onClick={handleClick}
|
|
{...strikeCellOnLongPress}
|
|
>
|
|
<div className={"superkadiField"}>
|
|
{value}
|
|
</div>
|
|
</td>
|
|
)
|
|
};
|
|
|
|
const BoolKadiCell: React.FunctionComponent<EditableKadiCellProps> = ({value, timeoutMs, strikeCell, updateCell}) => {
|
|
const handleClick = (): void => updateCell(true);
|
|
const strikeCellOnLongPress = useLongPress(strikeCell, timeoutMs);
|
|
return (
|
|
<td
|
|
className={"kadiCell editable boolField " + (value ? "checked" : "unchecked")}
|
|
>
|
|
<div
|
|
className="clickableArea"
|
|
onClick={handleClick}
|
|
{...strikeCellOnLongPress}
|
|
/>
|
|
</td>
|
|
)
|
|
};
|
|
|
|
const MultipleKadiCell: React.FunctionComponent<EditableKadiCellProps> = ({value, timeoutMs, strikeCell, updateCell}) => {
|
|
const handleClick = (): void => updateCell(true);
|
|
const strikeCellOnLongPress = useLongPress(strikeCell, timeoutMs);
|
|
return (
|
|
<td
|
|
className={"kadiCell editable multipleField"}
|
|
onClick={handleClick}
|
|
{...strikeCellOnLongPress}
|
|
>
|
|
<div className={"multipleField"}>
|
|
{value}
|
|
</div>
|
|
</td>
|
|
)
|
|
};
|
|
|
|
const GenericResultsKadiCell: React.FunctionComponent<GenericResultsKadiCellProps> = ({value, classNameString}) => {
|
|
return (
|
|
<td className={"kadiCell " + classNameString}>
|
|
<div className={classNameString}>
|
|
{value}
|
|
</div>
|
|
</td>
|
|
)
|
|
};
|
|
|
|
const StrikeKadiCell: React.FunctionComponent<StrikeKadiCellProps> = ({unstrikeCell}) => {
|
|
const updateCell = () => unstrikeCell();
|
|
return (
|
|
<td
|
|
className={"kadiCell strikeCell"}
|
|
onClick={updateCell}
|
|
/>
|
|
);
|
|
};
|
|
|
|
export default KadiCell; |