Skip to content

Commit

Permalink
fix: improve submit button
Browse files Browse the repository at this point in the history
  • Loading branch information
exKAZUu committed Sep 26, 2024
1 parent 74a2211 commit d8bc843
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
Icon,
IconButton,
Spacer,
Spinner,
VStack,
} from '../../../../../../../../infrastructures/useClient/chakra';
import type { Problem } from '../../../../../../../../problems/generateProblem';
Expand All @@ -33,7 +34,7 @@ const DY = [1, 0, -1, 0];
interface TurtleGraphicsProps {
currentTraceItemIndex: number;
focusTraceItemIndex: number;
handleClickSubmitButton: () => Promise<void>;
handleSubmit: () => Promise<void>;
problem: Problem;
}

Expand All @@ -42,10 +43,11 @@ export interface TurtleGraphicsHandle {
}

export const BoardEditor = forwardRef<TurtleGraphicsHandle, TurtleGraphicsProps>(
({ currentTraceItemIndex, focusTraceItemIndex, handleClickSubmitButton, problem }, ref) => {
({ currentTraceItemIndex, focusTraceItemIndex, handleSubmit, problem }, ref) => {
const [board, updateBoard] = useImmer<ColorChar[][]>([]);
const [turtles, updateTurtles] = useImmer<TurtleTrace[]>([]);
const [selectedCell, setSelectedCell] = useState<SelectedCell>();
const [isSubmitting, setIsSubmitting] = useState(false);
const selectedTurtle = turtles.find((char) => char.x === selectedCell?.x && char.y === selectedCell?.y);
const focusTraceItem = problem.traceItems[focusTraceItemIndex];
const currentTraceItem = problem.traceItems[currentTraceItemIndex];
Expand Down Expand Up @@ -152,21 +154,29 @@ export const BoardEditor = forwardRef<TurtleGraphicsHandle, TurtleGraphicsProps>
};

const onCellRightClick = (x: number, y: number): void => {
if (isSubmitting) return;

onCellClick(x, y);
updateCellColor('.', x, y);
};

const selectedPosition = selectedCell ? { x: selectedCell.x, y: selectedCell.y } : undefined;

useShortcutKeys(handleClickSubmitButton);
const handleSubmitAndToggleSubmitting = useCallback(async () => {
setIsSubmitting(true);
try {
await handleSubmit();
} finally {
setIsSubmitting(false);
}
}, [handleSubmit]);
useShortcutKeys(handleSubmitAndToggleSubmitting, isSubmitting);

return (
<HStack align="stretch" bgColor="gray.50" overflow="hidden" rounded="md">
<Center flexBasis={0} flexGrow={2} minW={0} px={4} py={20}>
<BoardViewer
enableTransitions
board={board.map((cells) => cells.join('')).join('\n')}
focusedCell={selectedPosition}
focusedCell={selectedCell}
turtles={turtles}
onCellClick={onCellClick}
onCellRightClick={onCellRightClick}
Expand All @@ -181,10 +191,10 @@ export const BoardEditor = forwardRef<TurtleGraphicsHandle, TurtleGraphicsProps>
<VStack align="stretch">
<Heading size="sm">選択したマス</Heading>
<HStack spacing={4}>
{selectedPosition ? (
{selectedCell ? (
<>
<div>x = {selectedPosition.x}</div>
<div>y = {selectedPosition.y}</div>
<div>x = {selectedCell.x}</div>
<div>y = {selectedCell.y}</div>
</>
) : (
<Box color="gray.600">なし</Box>
Expand All @@ -201,6 +211,7 @@ export const BoardEditor = forwardRef<TurtleGraphicsHandle, TurtleGraphicsProps>
colorScheme="brand"
gridColumnStart={2}
gridRowStart={1}
isDisabled={isSubmitting}
size="sm"
variant="outline"
onClick={() => handleMoveTurtle(true)}
Expand All @@ -211,6 +222,7 @@ export const BoardEditor = forwardRef<TurtleGraphicsHandle, TurtleGraphicsProps>
colorScheme="brand"
gridColumnStart={2}
gridRowStart={2}
isDisabled={isSubmitting}
size="sm"
variant="outline"
onClick={() => handleMoveTurtle(false)}
Expand All @@ -223,6 +235,7 @@ export const BoardEditor = forwardRef<TurtleGraphicsHandle, TurtleGraphicsProps>
gridColumnStart={1}
gridRowStart={2}
icon={<Icon as={MdTurnLeft} />}
isDisabled={isSubmitting}
size="sm"
variant="outline"
onClick={() => handleTurnTurtle(true)}
Expand All @@ -233,6 +246,7 @@ export const BoardEditor = forwardRef<TurtleGraphicsHandle, TurtleGraphicsProps>
gridColumnStart={3}
gridRowStart={2}
icon={<Icon as={MdTurnRight} />}
isDisabled={isSubmitting}
size="sm"
variant="outline"
onClick={() => handleTurnTurtle(false)}
Expand All @@ -241,6 +255,7 @@ export const BoardEditor = forwardRef<TurtleGraphicsHandle, TurtleGraphicsProps>
<HStack justify="space-between" width="100%">
<Button
colorScheme="brand"
isDisabled={isSubmitting}
leftIcon={<Icon as={MdOutlineDelete} />}
size="sm"
variant="outline"
Expand All @@ -254,30 +269,41 @@ export const BoardEditor = forwardRef<TurtleGraphicsHandle, TurtleGraphicsProps>
) : (
<Box color="gray.600">なし</Box>
)}
{!selectedTurtle && selectedPosition && (
<Button colorScheme="brand" size="sm" variant="outline" onClick={() => handleAddCharacterButton()}>
{!selectedTurtle && selectedCell && (
<Button
colorScheme="brand"
isDisabled={isSubmitting}
size="sm"
variant="outline"
onClick={() => handleAddCharacterButton()}
>
タートルを配置
</Button>
)}
{selectedPosition && (
{selectedCell && (
<Box color="brand.600" fontSize="sm">
右クリックでマスを白色に戻せます。
</Box>
)}
</VStack>
<Spacer />
<Button colorScheme="brand" variant="outline" onClick={() => initialize()}>
<Button colorScheme="brand" isDisabled={isSubmitting} variant="outline" onClick={() => initialize()}>
盤面をリセット
</Button>

<Button
colorScheme="brand"
isDisabled={isSubmitting}
rightIcon={
<Box as="span" color="whiteAlpha.800" fontSize="sm" fontWeight="bold">
(Enter)
</Box>
isSubmitting ? (
<Spinner size="sm" />
) : (
<Box as="span" color="whiteAlpha.800" fontSize="sm" fontWeight="bold">
(Enter)
</Box>
)
}
onClick={() => handleClickSubmitButton()}
onClick={handleSubmitAndToggleSubmitting}
>
提出
</Button>
Expand All @@ -301,15 +327,17 @@ function parseBoard(boardString: string): ColorChar[][] {
.map((line) => [...line.trim()]) as ColorChar[][];
}

function useShortcutKeys(handleClickSubmitButton: () => Promise<void>): void {
function useShortcutKeys(handleSubmit: () => Promise<void>, isSubmitting: boolean): void {
useEffect(() => {
if (isSubmitting) return;

const handleKeyDown = (event: KeyboardEvent): void => {
if (event.key === 'Enter') {
event.preventDefault();
void handleClickSubmitButton();
void handleSubmit();
}
};
window.addEventListener('keydown', handleKeyDown);
return () => window.removeEventListener('keydown', handleKeyDown);
}, [handleClickSubmitButton]);
}, [handleSubmit, isSubmitting]);
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,15 @@ export const ProblemBody: React.FC<Props> = (props) => {
{ enabled: false }
);

const handleClickSubmitButton = useCallback(async (): Promise<void> => {
const handleSubmit = useCallback(async (): Promise<void> => {
if (isAlertOpen) return;

const isCorrect = turtleGraphicsRef.current?.isCorrect() || false;

switch (problemType) {
case 'executionResult': {
if (isCorrect) {
void props.createSubmissionUpdatingProblemSession(true, true);
await props.createSubmissionUpdatingProblemSession(true, true);
openAlertDialog(
'正解',
'一発正解です!この問題は完了です。問題一覧ページに戻りますので、次の問題に挑戦してください。',
Expand All @@ -89,14 +89,14 @@ export const ProblemBody: React.FC<Props> = (props) => {
} else {
const response = await fetchIncorrectSubmissionsCount();
const incorrectCount = (response.data ?? 0) + 1;
void props.createSubmissionUpdatingProblemSession(false, false);
await props.createSubmissionUpdatingProblemSession(false, false);
if (incorrectCount < MAX_CHALLENGE_COUNT) {
openAlertDialog(
'不正解',
`不正解です。あと${MAX_CHALLENGE_COUNT - incorrectCount}回間違えたら、ステップ実行モードに移ります。一発正解を目指しましょう!`
);
} else {
void props.updateProblemSession('step', 1);
await props.updateProblemSession('step', 1);
openAlertDialog(
'不正解',
`不正解です。${MAX_CHALLENGE_COUNT}回間違えたので、ステップ実行モードに移ります。ステップごとに問題を解いてください。`
Expand All @@ -106,7 +106,7 @@ export const ProblemBody: React.FC<Props> = (props) => {
break;
}
case 'step': {
void props.createSubmissionUpdatingProblemSession(
await props.createSubmissionUpdatingProblemSession(
isCorrect,
isCorrect && currentTraceItemIndex === props.problem.traceItems.length - 1
);
Expand All @@ -120,7 +120,7 @@ export const ProblemBody: React.FC<Props> = (props) => {
}
);
} else {
void props.updateProblemSession('step', currentTraceItemIndex + 1);
await props.updateProblemSession('step', currentTraceItemIndex + 1);
openAlertDialog('正解', '正解です。次のステップに進みます。');
setFocusTraceItemIndex(currentTraceItemIndex);
}
Expand Down Expand Up @@ -205,7 +205,7 @@ export const ProblemBody: React.FC<Props> = (props) => {
ref={turtleGraphicsRef}
currentTraceItemIndex={currentTraceItemIndex}
focusTraceItemIndex={focusTraceItemIndex}
handleClickSubmitButton={handleClickSubmitButton}
handleSubmit={handleSubmit}
problem={props.problem}
/>
</VStack>
Expand Down

0 comments on commit d8bc843

Please sign in to comment.