All files / components/screens/endscreen/components NavigationButtonsOverlayHtml.tsx

100% Statements 16/16
88.88% Branches 16/18
100% Functions 4/4
100% Lines 16/16

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130                                                            2x                   28x       28x 28x   28x 1x 1x     28x 1x 1x 1x       28x 1x 1x 1x       28x                                                                                                                              
import React, { useCallback } from "react";
import { BaseButtonOverlayHtml } from "../../../shared/base/BaseButtonOverlayHtml";
import { slideUpAnimation } from "./animations";
 
export interface NavigationButtonsProps {
  readonly onReturnToMenu: () => void;
  readonly onRematch?: () => void;
  readonly onViewReplay?: () => void;
  readonly isMobile: boolean;
  readonly isTablet: boolean;
  readonly width: number;
  /** Optional audio callback for click sounds - passed from parent to avoid Html portal context issues */
  readonly onPlaySelectSound?: () => void;
  /** Optional audio callback for hover sounds - passed from parent to avoid Html portal context issues */
  readonly onPlayHoverSound?: () => void;
}
 
/**
 * Navigation Buttons Component
 * Provides action buttons for replay and menu navigation.
 *
 * This component delegates visual styling and accessibility behavior to
 * BaseButtonOverlayHtml, providing:
 * - Consistent Korean / English bilingual theming
 * - Centralized button behavior and standard browser keyboard support
 * - Reduced code duplication (113 lines saved: 237 → 124)
 *
 * Note: Audio callbacks are passed as props since this component is rendered
 * inside a Canvas Html portal which doesn't have access to AudioProvider context.
 */
export const NavigationButtons: React.FC<NavigationButtonsProps> = ({
  onReturnToMenu,
  onRematch,
  onViewReplay,
  isMobile,
  isTablet,
  width,
  onPlaySelectSound,
  onPlayHoverSound,
}) => {
  const spacing = isMobile ? 10 : isTablet ? 12 : 15;
  
  // Determine button size based on screen width (resolution-based, not device detection)
  // Small screens (<768px): sm, Medium/Large (>=768px): md
  const buttonSize = width < 768 ? "sm" : "md";
  const buttonMinWidth = width < 768 ? "200px" : "150px";
 
  const handleReturnToMenu = useCallback(() => {
    onPlaySelectSound?.();
    onReturnToMenu();
  }, [onPlaySelectSound, onReturnToMenu]);
 
  const handleRematch = useCallback(() => {
    Eif (onRematch) {
      onPlaySelectSound?.();
      onRematch();
    }
  }, [onPlaySelectSound, onRematch]);
 
  const handleViewReplay = useCallback(() => {
    Eif (onViewReplay) {
      onPlaySelectSound?.();
      onViewReplay();
    }
  }, [onPlaySelectSound, onViewReplay]);
 
  return (
    <div
      data-testid="navigation-buttons"
      style={{
        display: "flex",
        flexDirection: isMobile ? "column" : "row",
        gap: spacing,
        marginTop: spacing * 2,
        animation: "slideUp 0.6s ease-out 0.3s both",
        alignItems: "center",
        justifyContent: "center",
      }}
    >
      {/* Return to Menu Button - Primary Action */}
      <BaseButtonOverlayHtml
        korean="메뉴로"
        english="Return to Menu"
        onClick={handleReturnToMenu}
        onMouseEnter={onPlayHoverSound}
        variant="primary"
        size={buttonSize}
        testId="return-to-menu-button"
        isMobile={isMobile}
        style={{ minWidth: buttonMinWidth }}
      />
 
      {/* Rematch Button - Secondary Action */}
      {onRematch && (
        <BaseButtonOverlayHtml
          korean="재대결"
          english="Rematch"
          onClick={handleRematch}
          onMouseEnter={onPlayHoverSound}
          variant="secondary"
          size={buttonSize}
          testId="rematch-button"
          isMobile={isMobile}
          style={{ minWidth: buttonMinWidth }}
        />
      )}
 
      {/* Training Mode Button - Tertiary Action */}
      {onViewReplay && (
        <BaseButtonOverlayHtml
          korean="훈련"
          english="Training"
          onClick={handleViewReplay}
          onMouseEnter={onPlayHoverSound}
          variant="secondary"
          size={buttonSize}
          testId="view-training-button"
          isMobile={isMobile}
          style={{ minWidth: buttonMinWidth }}
        />
      )}
 
      {/* CSS Animations */}
      <style>{`
        ${slideUpAnimation}
      `}</style>
    </div>
  );
};