Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
'use client';

import { useMemo } from 'react';
import { useTranslations } from 'next-intl';
import {
Dialog,
DialogTitle,
DialogContent,
DialogActions,
Button,
Grid,
Box,
IconButton,
CircularProgress,
Alert
} from '@mui/material';
import { Close } from '@mui/icons-material';
import { useQuery } from '@apollo/client/react';
import { CompareProvider } from '../../compare/compare-context';
import { CompareTeam } from '../../compare/components';
import { GET_UNIFIED_DIVISION } from '../../compare/graphql';
import type {
Team,
Award,
UnifiedDivisionData,
UnifiedDivisionVars
} from '../../compare/graphql/types';
import type { EnrichedTeam } from '../types';

interface CompareModalProps {
open: boolean;
onClose: () => void;
team1?: EnrichedTeam | null;
team2?: EnrichedTeam | null;
divisionId: string;
awards?: Award[];
allTeams?: Team[];
}

export const CompareModal: React.FC<CompareModalProps> = ({
open,
onClose,
team1,
team2,
divisionId,
awards = [],
allTeams = []
}) => {
const t = useTranslations('pages.deliberations.category.compare-modal');

// Extract team slugs from the EnrichedTeam objects
const teamSlugs = useMemo(() => {
const slugs: string[] = [];
if (team1?.slug) slugs.push(team1.slug);
if (team2?.slug) slugs.push(team2.slug);
return slugs;
}, [team1, team2]);

// Fetch the full team data from the compare query
const { data, loading, error } = useQuery<UnifiedDivisionData, UnifiedDivisionVars>(
GET_UNIFIED_DIVISION,
{
variables: {
divisionId,
teamSlugs: teamSlugs.length > 0 ? teamSlugs : undefined
},
skip: !open || teamSlugs.length === 0
}
);

const teamsToCompare = useMemo(() => {
return data?.division?.selectedTeams ?? [];
}, [data?.division?.selectedTeams]);

const divisionAwards = useMemo(() => {
return data?.division?.awards ?? awards;
}, [data?.division?.awards, awards]);

const divisionAllTeams = useMemo(() => {
return data?.division?.allTeams ?? allTeams;
}, [data?.division?.allTeams, allTeams]);

if (teamSlugs.length === 0) {
return null;
}

return (
<Dialog
open={open}
onClose={onClose}
maxWidth="lg"
fullWidth
PaperProps={{
sx: {
maxHeight: '90vh'
}
}}
>
<DialogTitle
sx={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center'
}}
>
{t('title')}
<IconButton
onClick={onClose}
sx={{
color: 'inherit'
}}
>
<Close />
</IconButton>
</DialogTitle>
<DialogContent
sx={{
overflowY: 'auto'
}}
>
{loading ? (
<Box
sx={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
minHeight: '300px'
}}
>
<CircularProgress />
</Box>
) : error ? (
<Alert severity="error">{t('error-loading-teams')}</Alert>
) : teamsToCompare.length === 0 ? (
<Alert severity="warning">{t('teams-not-found')}</Alert>
) : (
<CompareProvider
teams={teamsToCompare}
awards={divisionAwards}
allTeams={divisionAllTeams as unknown as Team[]}
>
<Box sx={{ pt: 2 }}>
<Grid container spacing={3}>
{teamsToCompare.map((team: Team) => (
<Grid key={team.id} size={{ xs: 12, sm: 6 }}>
<CompareTeam team={team} />
</Grid>
))}
</Grid>
</Box>
</CompareProvider>
)}
</DialogContent>
<DialogActions>
<Button onClick={onClose} variant="contained">
{t('close')}
</Button>
</DialogActions>
</Dialog>
);
};
Original file line number Diff line number Diff line change
@@ -1,29 +1,62 @@
'use client';

import { useState } from 'react';
import { useState, useMemo } from 'react';
import { useRouter } from 'next/navigation';
import { useTranslations } from 'next-intl';
import { Autocomplete, Button, Paper, Stack, TextField, Typography } from '@mui/material';
import { CompareArrows } from '@mui/icons-material';
import {
Autocomplete,
Button,
Paper,
Stack,
TextField,
Typography,
IconButton
} from '@mui/material';
import { OpenInNew } from '@mui/icons-material';
import { useEvent } from '../../components/event-context';
import { useCategoryDeliberation } from '../deliberation-context';
import { CompareModal } from './compare-modal';
import type { EnrichedTeam } from '../types';

interface CompareTeamsPickerProps {
teams: EnrichedTeam[];
onCompare?: (team1Id: string, team2Id: string) => void;
}

export function CompareTeamsPicker({ teams, onCompare }: CompareTeamsPickerProps) {
export function CompareTeamsPicker({ teams }: CompareTeamsPickerProps) {
const t = useTranslations('pages.deliberations.category.compare-teams-picker');
const router = useRouter();
const { currentDivision } = useEvent();
const { division } = useCategoryDeliberation();

const [selectedTeam1, setSelectedTeam1] = useState<string | null>(null);
const [selectedTeam2, setSelectedTeam2] = useState<string | null>(null);
const [isModalOpen, setIsModalOpen] = useState(false);

const teamOptions = teams.map(t => ({
label: `${t.number} - ${t.name}`,
value: t.id
}));

const handleCompare = () => {
if (selectedTeam1 && selectedTeam2) {
onCompare?.(selectedTeam1, selectedTeam2);
// Memoized calculation of awards and allTeams from division data
const { awards, allTeamsData } = useMemo(() => {
return {
awards: division?.awards ?? [],
allTeamsData: division?.allTeams ?? []
};
}, [division]);

// Get the selected team objects from the teams array
const team1 = teams.find(t => t.id === selectedTeam1);
const team2 = teams.find(t => t.id === selectedTeam2);

const handleOpenModal = () => {
setIsModalOpen(true);
};

const handleOpenComparePageInNewTab = () => {
const teamSlugs = [team1?.slug, team2?.slug].filter(Boolean).join(',');
if (teamSlugs) {
router.push(`/lems/deliberation/compare?teams=${teamSlugs}`);
}
};

Expand All @@ -49,7 +82,16 @@ export function CompareTeamsPicker({ teams, onCompare }: CompareTeamsPickerProps
>
{t('title')}
</Typography>
<CompareArrows />
<IconButton
size="small"
onClick={handleOpenComparePageInNewTab}
disabled={!team1 || !team2 || team1.id === team2.id}
sx={{
p: 0.5
}}
>
<OpenInNew fontSize="small" />
</IconButton>
</Stack>

<Autocomplete
Expand Down Expand Up @@ -106,7 +148,7 @@ export function CompareTeamsPicker({ teams, onCompare }: CompareTeamsPickerProps
fullWidth
disabled={!selectedTeam1 || !selectedTeam2 || selectedTeam1 === selectedTeam2}
size="small"
onClick={handleCompare}
onClick={handleOpenModal}
sx={{
mt: 1,
fontWeight: 600,
Expand All @@ -122,6 +164,16 @@ export function CompareTeamsPicker({ teams, onCompare }: CompareTeamsPickerProps
>
{t('compare')}
</Button>

<CompareModal
open={isModalOpen}
onClose={() => setIsModalOpen(false)}
team1={team1}
team2={team2}
divisionId={currentDivision.id}
awards={awards}
allTeams={allTeamsData as any}
/>
</Stack>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
'use client';

import { Paper } from '@mui/material';
import { useCompareContext } from '../compare-context';
import {
TeamHeader,
ScoreSummary,
RubricScores,
ExceedingNotes,
Nominations,
GpScores,
Feedback
} from '.';
import type { Team } from '../graphql/types';

interface CompareTeamProps {
team: Team;
}

export function CompareTeam({ team }: CompareTeamProps) {
const { category } = useCompareContext();

return (
<Paper
sx={{
p: 2,
height: '100%',
display: 'flex',
flexDirection: 'column',
gap: 2
}}
>
<TeamHeader team={team} />
<ScoreSummary team={team} />
<RubricScores team={team} />
<ExceedingNotes team={team} />
<Nominations team={team} />
{(!category || category === 'core-values') && <GpScores team={team} />}
<Feedback team={team} />
</Paper>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ export { GpScores } from './gp-scores';
export { Feedback } from './feedback';
export { CategoryFilter } from './category-filter';
export { TeamSelector } from './team-selector';
export { CompareTeam } from './compare-team';
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,14 @@

import { useSearchParams } from 'next/navigation';
import { useTranslations } from 'next-intl';
import { Container, Alert, Box, Grid, Card, Paper, CircularProgress } from '@mui/material';
import { Container, Alert, Box, Grid, Card, CircularProgress } from '@mui/material';
import { JudgingCategory } from '@lems/types/judging';
import { useEvent } from '../../components/event-context';
import { PageHeader } from '../../(dashboard)/components/page-header';
import { usePageData } from '../../hooks/use-page-data';
import { GET_UNIFIED_DIVISION, type DivisionTeam } from './graphql';
import { CompareProvider } from './compare-context';
import {
EmptyState,
TeamHeader,
ScoreSummary,
RubricScores,
ExceedingNotes,
Nominations,
GpScores,
Feedback,
CategoryFilter,
TeamSelector
} from './components';
import { EmptyState, CategoryFilter, TeamSelector, CompareTeam } from './components';

export default function ComparePage() {
const t = useTranslations('layouts.deliberation.compare');
Expand Down Expand Up @@ -137,23 +126,7 @@ export default function ComparePage() {
: { xs: 12, sm: 6, md: 6, lg: teams.length > 2 ? 4 : 6 }
}
>
<Paper
sx={{
p: 2,
height: '100%',
display: 'flex',
flexDirection: 'column',
gap: 2
}}
>
<TeamHeader team={team} />
<ScoreSummary team={team} />
<RubricScores team={team} />
<ExceedingNotes team={team} />
<Nominations team={team} />
{(!categoryParam || categoryParam === 'core-values') && <GpScores team={team} />}
<Feedback team={team} />
</Paper>
<CompareTeam team={team} />
</Grid>
))}
</Grid>
Expand Down