Skip to content

Commit

Permalink
[Feat] 브래킷 점수 수정 #1125
Browse files Browse the repository at this point in the history
  • Loading branch information
greatSweetMango committed Dec 13, 2023
1 parent bd209b9 commit e3b564a
Show file tree
Hide file tree
Showing 10 changed files with 513 additions and 30 deletions.
76 changes: 76 additions & 0 deletions components/admin/tournament/TournamentEditBraket.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import dynamic from 'next/dynamic';
import {
SVGViewer as StaticSVGViewer,
SingleEliminationBracket as StaticSingleEliminationBracket,
} from '@g-loot/react-tournament-brackets';
import { Match } from '@g-loot/react-tournament-brackets/dist/src/types';
import React from 'react';
import TournamentEditMatch from './TournamentEditMatch';

if (typeof window !== 'undefined' && typeof window.navigator !== 'undefined') {
import('@g-loot/react-tournament-brackets');
}

const SingleEliminationBracket = dynamic<
React.ComponentProps<typeof StaticSingleEliminationBracket>
>(
() => {
return import('@g-loot/react-tournament-brackets').then(
(mod) => mod.SingleEliminationBracket
);
},
{ ssr: false }
);

const SVGViewer = dynamic<React.ComponentProps<typeof StaticSVGViewer>>(
() => {
return import('@g-loot/react-tournament-brackets').then(
(mod) => mod.SVGViewer
);
},
{ ssr: false }
);

interface TournamentEditBraketProps {
singleEliminationBracketMatchs: Match[];
containerSize: { width: number | undefined; height: number | undefined };
}

export default function TournamentEditBraket({
singleEliminationBracketMatchs,
containerSize,
}: TournamentEditBraketProps) {
if (singleEliminationBracketMatchs.length === 0) {
return <h1 style={{ color: 'white' }}>Loading...</h1>;
}

return (
<SingleEliminationBracket
matches={singleEliminationBracketMatchs}
matchComponent={TournamentEditMatch}
options={{
style: {
width: 230,
boxHeight: 120,
roundHeader: {
isShown: false,
fontColor: '#FFFFFF',
},
connectorColor: '#FFFFFF',
connectorColorHighlight: '#da96c6',
},
}}
svgWrapper={({ children, ...props }) => (
<SVGViewer
background={'rgba(0, 0, 0, 0)'}
SVGBackground={'rgba(0, 0, 0, 0)'}
width={containerSize.width}
height={containerSize.height}
{...props}
>
{children}
</SVGViewer>
)}
/>
);
}
208 changes: 208 additions & 0 deletions components/admin/tournament/TournamentEditMatch.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
import {
Match,
MatchComponentProps,
Participant,
} from '@g-loot/react-tournament-brackets/dist/src/types';
import { useContext, useRef, useState } from 'react';
import { TournamentIdContext } from 'components/modal/admin/AdminEditTournamentBraket';
import PlayerImage from 'components/PlayerImage';
import useTournamentMatchEditor from 'hooks/tournament/useTournamentMatchEditor';
import styles from 'styles/admin/tournament/TournamentEditMatch.module.scss';

interface TournamentMatchPartyProps {
party: Participant;
teamNameFallback: string;
resultFallback: (participant: Participant) => string;
onMouseEnter: (partyId: string | number) => void;
}

function TournamentMatchParty({
party,
teamNameFallback,
onMouseEnter,
resultFallback,
}: TournamentMatchPartyProps) {
return (
<div
className={styles.tournamentPartyWrapper}
onMouseEnter={() => onMouseEnter(party.id)}
>
<PlayerImage
src={party.picture ?? '/image/match_qustion.png'}
styleName={`tournament`}
size={1}
/>

<div className={styles.partyName}>{party.name || teamNameFallback}</div>
<div className={styles.score}>
{party.resultText ?? resultFallback(party)}
</div>
</div>
);
}

interface TournamentMatchProps {
topParty: Participant;
bottomParty: Participant;
teamNameFallback: string;
resultFallback: (participant: Participant) => string;
onMouseEnter: (partyId: string | number) => void;
}

function TournamentMatch({
topParty,
bottomParty,
teamNameFallback,
onMouseEnter,
resultFallback,
}: TournamentMatchProps) {
return (
<>
<TournamentMatchParty
party={topParty}
teamNameFallback={teamNameFallback}
onMouseEnter={onMouseEnter}
resultFallback={resultFallback}
></TournamentMatchParty>
<TournamentMatchParty
party={bottomParty}
teamNameFallback={teamNameFallback}
onMouseEnter={onMouseEnter}
resultFallback={resultFallback}
></TournamentMatchParty>
</>
);
}

interface TournamentEditMatchPartyProps {
party: Participant;
handleScoreInputChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
}

function TournamentEditMatchParty({
party,
handleScoreInputChange,
}: TournamentEditMatchPartyProps) {
const inputRef = useRef<HTMLInputElement>(null);

return (
<div className={styles.tournamentPartyWrapper}>
<PlayerImage
src={party.picture ?? '/image/match_qustion.png'}
styleName={`tournament`}
size={1}
/>

<div className={styles.partyName}>{party.name}</div>
<input
ref={inputRef}
className={styles.scoreInput}
name={`team-${party.id}-score`}
value={party.resultText ?? ''}
onChange={handleScoreInputChange}
onClick={() => {
inputRef.current?.focus();
}}
/>
</div>
);
}

interface TournamentMatchEditorProps {
topParty: Participant;
bottomParty: Participant;
unsetEditor: () => void;
handleScoreInputChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
putHandler: () => void;
}

function TournamentMatchEditor({
topParty,
bottomParty,
unsetEditor,
handleScoreInputChange,
putHandler,
}: TournamentMatchEditorProps) {
return (
<>
<TournamentEditMatchParty
party={topParty}
handleScoreInputChange={handleScoreInputChange}
/>
<TournamentEditMatchParty
party={bottomParty}
handleScoreInputChange={handleScoreInputChange}
/>
<div className={styles.buttonsContainer}>
<button onClick={unsetEditor}>취소</button>
<button onClick={putHandler}>수정하기</button>
</div>
</>
);
}

export default function TournamentEditMatch({
match,
onMatchClick,
onPartyClick,
onMouseEnter,
onMouseLeave,
topWon,
bottomWon,
topHovered,
bottomHovered,
topText,
bottomText,
connectorColor,
computedStyles,
teamNameFallback,
resultFallback,
}: MatchComponentProps) {
const tournamentId = useContext(TournamentIdContext);
const {
isEditor,
topParty,
bottomParty,
setEditor,
unsetEditor,
handleScoreInputChange,
putHandler,
} = useTournamentMatchEditor(match, tournamentId);
return (
<>
<div
className={
match.isModifiable && isEditor === false
? styles.tournamentEditMatchContainer
: styles.tournamentMatchContainer
}
>
{match.isModifiable && isEditor === false && (
<button
className={styles.tournamentEditMatchButton}
onClick={setEditor}
>
수정하기
</button>
)}
{isEditor === true ? (
<TournamentMatchEditor
topParty={topParty}
bottomParty={bottomParty}
unsetEditor={unsetEditor}
handleScoreInputChange={handleScoreInputChange}
putHandler={putHandler}
/>
) : (
<TournamentMatch
topParty={topParty}
bottomParty={bottomParty}
teamNameFallback={teamNameFallback}
onMouseEnter={onMouseEnter}
resultFallback={resultFallback}
/>
)}
</div>
</>
);
}
23 changes: 13 additions & 10 deletions components/modal/admin/AdminEditTournamentBraket.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { Match } from '@g-loot/react-tournament-brackets/dist/src/types';
import { useCallback, useEffect, useState, useRef } from 'react';
import { useCallback, useEffect, useState, useRef, createContext } from 'react';
import { ITournament } from 'types/admin/adminTournamentTypes';
import { TournamentGame } from 'types/tournamentTypes';
import { instance } from 'utils/axios';
import { convertTournamentGamesToBracketMatchs } from 'utils/handleTournamentGame';
import { mockInstance } from 'utils/mockAxios';
import TournamentBraket from 'components/tournament/TournamentBraket';
import TournamentEditBraket from 'components/admin/tournament/TournamentEditBraket';
import useComponentSize from 'hooks/util/useComponentSize';
import styles from 'styles/admin/modal/AdminEditTournamentBraket.module.scss';

const tournamentId = 1;
export const TournamentIdContext = createContext<number>(0);

export default function AdminEditTournamentBraket({
tournamentId,
Expand All @@ -19,7 +19,9 @@ export default function AdminEditTournamentBraket({
const fetchTournamentGames = useCallback(async () => {
console.log('Fetching more data...');
try {
const res = await mockInstance.get(`/tournament/${tournamentId}/games`);
const res = await instance.get(
`pingpong/tournaments/${tournamentId}/games`
);
const data: TournamentGame[] = res.data.games;
const bracketMatchs = convertTournamentGamesToBracketMatchs(data);
setBracketMatchs(bracketMatchs);
Expand All @@ -35,11 +37,12 @@ export default function AdminEditTournamentBraket({

return (
<div className={styles['whole']} ref={ref}>
<TournamentBraket
singleEliminationBracketMatchs={bracketMatchs}
containerSize={size}
/>
<button className={styles.editBtn}>수정 하기</button>
<TournamentIdContext.Provider value={tournamentId}>
<TournamentEditBraket
singleEliminationBracketMatchs={bracketMatchs}
containerSize={size}
/>
</TournamentIdContext.Provider>
</div>
); //*onClick={putHandler}
}
Loading

0 comments on commit e3b564a

Please sign in to comment.