refactor(new-game): extract PlayerSelectModal to separate file
Refs #30 - Create src/components/new-game/PlayerSelectModal.tsx - Replace inline modal with imported component in NewGame.tsx - No behavior changes; purely structural extraction
This commit is contained in:
@@ -2,6 +2,7 @@ import { h } from 'preact';
|
|||||||
import { useState, useEffect, useRef } from 'preact/hooks';
|
import { useState, useEffect, useRef } from 'preact/hooks';
|
||||||
import styles from './NewGame.module.css';
|
import styles from './NewGame.module.css';
|
||||||
import modalStyles from './PlayerSelectModal.module.css';
|
import modalStyles from './PlayerSelectModal.module.css';
|
||||||
|
import { PlayerSelectModal } from './new-game/PlayerSelectModal';
|
||||||
import {
|
import {
|
||||||
UI_CONSTANTS,
|
UI_CONSTANTS,
|
||||||
WIZARD_STEPS,
|
WIZARD_STEPS,
|
||||||
@@ -16,29 +17,7 @@ import {
|
|||||||
} from '../utils/constants';
|
} from '../utils/constants';
|
||||||
import type { BreakRule } from '../types/game';
|
import type { BreakRule } from '../types/game';
|
||||||
|
|
||||||
interface PlayerSelectModalProps {
|
// PlayerSelectModal moved to ./new-game/PlayerSelectModal
|
||||||
players: string[];
|
|
||||||
onSelect: (player: string) => void;
|
|
||||||
onClose: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const PlayerSelectModal = ({ players, onSelect, onClose }: PlayerSelectModalProps) => (
|
|
||||||
<div className={modalStyles.modalOverlay} onClick={onClose}>
|
|
||||||
<div className={modalStyles.modalContent} onClick={e => e.stopPropagation()}>
|
|
||||||
<div className={modalStyles.modalHeader}>
|
|
||||||
<h3>Alle Spieler</h3>
|
|
||||||
<button className={modalStyles.closeButton} onClick={onClose}>×</button>
|
|
||||||
</div>
|
|
||||||
<div className={modalStyles.playerList}>
|
|
||||||
{players.map(player => (
|
|
||||||
<button key={player} className={modalStyles.playerItem} onClick={() => onSelect(player)}>
|
|
||||||
{player}
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
interface PlayerStepProps {
|
interface PlayerStepProps {
|
||||||
playerNameHistory: string[];
|
playerNameHistory: string[];
|
||||||
@@ -811,10 +790,10 @@ const RaceToStep = ({ onNext, onCancel, initialValue = '', gameType }: RaceToSte
|
|||||||
interface BreakRuleStepProps {
|
interface BreakRuleStepProps {
|
||||||
onNext: (rule: BreakRule) => void;
|
onNext: (rule: BreakRule) => void;
|
||||||
onCancel: () => void;
|
onCancel: () => void;
|
||||||
initialValue?: BreakRule | '';
|
initialValue?: BreakRule | 'winnerbreak';
|
||||||
}
|
}
|
||||||
|
|
||||||
const BreakRuleStep = ({ onNext, onCancel, initialValue = '' }: BreakRuleStepProps) => {
|
const BreakRuleStep = ({ onNext, onCancel, initialValue = 'winnerbreak' }: BreakRuleStepProps) => {
|
||||||
const [rule, setRule] = useState<BreakRule | ''>(initialValue);
|
const [rule, setRule] = useState<BreakRule | ''>(initialValue);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -866,11 +845,18 @@ interface BreakOrderStepProps {
|
|||||||
initialSecond?: number;
|
initialSecond?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const BreakOrderStep = ({ players, rule, onNext, onCancel, initialFirst = 0, initialSecond }: BreakOrderStepProps) => {
|
const BreakOrderStep = ({ players, rule, onNext, onCancel, initialFirst = 1, initialSecond }: BreakOrderStepProps) => {
|
||||||
const playerCount = players.filter(Boolean).length;
|
const playerCount = players.filter(Boolean).length;
|
||||||
const [first, setFirst] = useState<number>(initialFirst);
|
const [first, setFirst] = useState<number>(initialFirst);
|
||||||
const [second, setSecond] = useState<number | undefined>(initialSecond);
|
const [second, setSecond] = useState<number | undefined>(initialSecond);
|
||||||
|
|
||||||
|
// Default selections: player 1 breaks first; if 3 players with wechselbreak, player 2 breaks second
|
||||||
|
useEffect(() => {
|
||||||
|
if (!initialSecond && rule === 'wechselbreak' && playerCount === 3) {
|
||||||
|
setSecond(2);
|
||||||
|
}
|
||||||
|
}, [initialSecond, rule, playerCount]);
|
||||||
|
|
||||||
const handleFirst = (idx: number) => {
|
const handleFirst = (idx: number) => {
|
||||||
setFirst(idx);
|
setFirst(idx);
|
||||||
// Auto-advance cases: winnerbreak (any players) OR wechselbreak with 2 players
|
// Auto-advance cases: winnerbreak (any players) OR wechselbreak with 2 players
|
||||||
@@ -904,7 +890,7 @@ const BreakOrderStep = ({ players, rule, onNext, onCancel, initialFirst = 0, ini
|
|||||||
</div>
|
</div>
|
||||||
{rule === 'wechselbreak' && playerCount === 3 && (
|
{rule === 'wechselbreak' && playerCount === 3 && (
|
||||||
<>
|
<>
|
||||||
<div style={{ marginTop: 24, marginBottom: 16, fontWeight: 600 }}>Wer bricht als Zweites?</div>
|
<div style={{ marginTop: 24, marginBottom: 16, fontWeight: 600 }}>Wer hat den zweiten Anstoss?</div>
|
||||||
<div style={{ display: 'flex', gap: 12, flexWrap: 'wrap' }}>
|
<div style={{ display: 'flex', gap: 12, flexWrap: 'wrap' }}>
|
||||||
{players.filter(Boolean).map((name, idx) => (
|
{players.filter(Boolean).map((name, idx) => (
|
||||||
<button key={`second-${idx}`} type="button" className={styles['quick-pick-btn']} onClick={() => handleSecond(idx + 1)} aria-label={`Zweites Break: ${name}`}>{name}</button>
|
<button key={`second-${idx}`} type="button" className={styles['quick-pick-btn']} onClick={() => handleSecond(idx + 1)} aria-label={`Zweites Break: ${name}`}>{name}</button>
|
||||||
|
|||||||
28
src/components/new-game/PlayerSelectModal.tsx
Normal file
28
src/components/new-game/PlayerSelectModal.tsx
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import { h } from 'preact';
|
||||||
|
import modalStyles from '../PlayerSelectModal.module.css';
|
||||||
|
|
||||||
|
interface PlayerSelectModalProps {
|
||||||
|
players: string[];
|
||||||
|
onSelect: (player: string) => void;
|
||||||
|
onClose: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const PlayerSelectModal = ({ players, onSelect, onClose }: PlayerSelectModalProps) => (
|
||||||
|
<div className={modalStyles.modalOverlay} onClick={onClose}>
|
||||||
|
<div className={modalStyles.modalContent} onClick={e => e.stopPropagation()}>
|
||||||
|
<div className={modalStyles.modalHeader}>
|
||||||
|
<h3>Alle Spieler</h3>
|
||||||
|
<button className={modalStyles.closeButton} onClick={onClose}>×</button>
|
||||||
|
</div>
|
||||||
|
<div className={modalStyles.playerList}>
|
||||||
|
{players.map(player => (
|
||||||
|
<button key={player} className={modalStyles.playerItem} onClick={() => onSelect(player)}>
|
||||||
|
{player}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user