diff --git a/app/(main)/league/[leagueId]/entry/[entryId]/week/Week.interface.ts b/app/(main)/league/[leagueId]/entry/[entryId]/week/Week.interface.ts index 38356e44..c4b0c7da 100644 --- a/app/(main)/league/[leagueId]/entry/[entryId]/week/Week.interface.ts +++ b/app/(main)/league/[leagueId]/entry/[entryId]/week/Week.interface.ts @@ -23,6 +23,7 @@ export interface IWeeklyPickChange { entry: string; league: string; NFLTeams: INFLTeam[]; + setLoadingTeamName: React.Dispatch>; setUserPick: React.Dispatch>; updateWeeklyPicks: ({}: IWeeklyPicks) => void; user: IUser; diff --git a/app/(main)/league/[leagueId]/entry/[entryId]/week/Week.tsx b/app/(main)/league/[leagueId]/entry/[entryId]/week/Week.tsx index abcecdff..ffdcc5af 100644 --- a/app/(main)/league/[leagueId]/entry/[entryId]/week/Week.tsx +++ b/app/(main)/league/[leagueId]/entry/[entryId]/week/Week.tsx @@ -44,6 +44,7 @@ const Week = ({ entry, league, NFLTeams, week }: IWeekProps): JSX.Element => { const [selectedLeague, setSelectedLeague] = useState(); const [selectedTeams, setSelectedTeams] = useState([]); const [loadingData, setLoadingData] = useState(true); + const [loadingTeamName, setLoadingTeamName] = useState(null); const [userPick, setUserPick] = useState(''); const { user, updateCurrentWeek, updateWeeklyPicks, weeklyPicks } = useDataStore((state) => state); @@ -173,6 +174,7 @@ const Week = ({ entry, league, NFLTeams, week }: IWeekProps): JSX.Element => { entry, league, NFLTeams, + setLoadingTeamName, setUserPick, updateWeeklyPicks, user, @@ -248,6 +250,7 @@ const Week = ({ entry, league, NFLTeams, week }: IWeekProps): JSX.Element => { => { try { - const selectedTeamName = NFLTeams.find( - (team) => team.teamName === teamSelect, - )?.teamName; + const team = NFLTeams.find((team) => team.teamName === teamSelect); - const currentUserPick = parseUserPick( - user.id, - entry, - selectedTeamName || '', - ); + setLoadingTeamName(team?.teamId ?? null); + + const currentUserPick = parseUserPick(user.id, entry, team?.teamName || ''); // combines current picks and the user pick into one object. // if the user pick exists then it overrides the pick of the user. @@ -109,5 +107,7 @@ export const onWeeklyPickChange = async ({ message="There was an error processing your request." />, ); + } finally { + setLoadingTeamName(null); } }; diff --git a/app/(main)/league/[leagueId]/entry/[entryId]/week/WeekTeams.interface.ts b/app/(main)/league/[leagueId]/entry/[entryId]/week/WeekTeams.interface.ts index 4ed46818..11350033 100644 --- a/app/(main)/league/[leagueId]/entry/[entryId]/week/WeekTeams.interface.ts +++ b/app/(main)/league/[leagueId]/entry/[entryId]/week/WeekTeams.interface.ts @@ -27,11 +27,12 @@ export interface ISchedule { export interface IWeekTeamsProps { field: ControllerRenderProps; + loadingTeamName: string | null; + onWeeklyPickChange: ({}: NFLTeams) => Promise; schedule: ISchedule[]; selectedTeams: INFLTeam['teamName'][]; userPick: string; // eslint-disable-next-line no-unused-vars - onWeeklyPickChange: (teamSelect: NFLTeams) => Promise; } interface ICompetition { diff --git a/app/(main)/league/[leagueId]/entry/[entryId]/week/WeekTeams.test.tsx b/app/(main)/league/[leagueId]/entry/[entryId]/week/WeekTeams.test.tsx index edea111d..a722ac95 100644 --- a/app/(main)/league/[leagueId]/entry/[entryId]/week/WeekTeams.test.tsx +++ b/app/(main)/league/[leagueId]/entry/[entryId]/week/WeekTeams.test.tsx @@ -24,11 +24,16 @@ const mockNewUserPick = 'Chiefs'; const mockOnWeeklyPickChange = jest.fn(); const mockHasTeamBeenPicked = hasTeamBeenPicked as jest.Mock; -const TestWeekTeamsComponent = () => { +const TestWeekTeamsComponent = ({ + loadingTeamName, +}: { + loadingTeamName: string; +}) => { const formMethods = useForm(); return ( { it('the team should render active and the user currently has them selected', () => { mockHasTeamBeenPicked.mockReturnValue(false); - render(); + render(); const weekTeamsRadioItems: HTMLButtonElement[] = screen.getAllByTestId('team-radio'); @@ -64,7 +69,7 @@ describe('WeekTeams', () => { it('the team should render active and the user should be able to select the team', () => { mockHasTeamBeenPicked.mockReturnValue(false); - render(); + render(); const weeklyPickButtons = screen.getAllByTestId('team-label'); const chiefsButton = weeklyPickButtons.filter( @@ -82,7 +87,7 @@ describe('WeekTeams', () => { it('the team should render disabled if the team has already been used and the user should not be able to select the team', () => { mockHasTeamBeenPicked.mockReturnValue(true); - render(); + render(); const weeklyPickButtons: HTMLButtonElement[] = screen.getAllByTestId('team-radio'); @@ -94,4 +99,5 @@ describe('WeekTeams', () => { expect(packersButton).toBeInTheDocument(); expect(packersButton).toBeDisabled(); }); + }); diff --git a/app/(main)/league/[leagueId]/entry/[entryId]/week/WeekTeams.tsx b/app/(main)/league/[leagueId]/entry/[entryId]/week/WeekTeams.tsx index 2ed9c61f..8f4973e8 100644 --- a/app/(main)/league/[leagueId]/entry/[entryId]/week/WeekTeams.tsx +++ b/app/(main)/league/[leagueId]/entry/[entryId]/week/WeekTeams.tsx @@ -42,6 +42,7 @@ const formatDateTime = (dateString: string): string => { * @param props.selectedTeams The user's selected teams. * @param props.userPick The user's pick. * @param props.onWeeklyPickChange The function to call when the user's pick changes. + * @param props.loadingTeamName The loading state for selecting teams. * @returns The rendered weekly picks page. */ const WeekTeams = ({ @@ -50,6 +51,7 @@ const WeekTeams = ({ selectedTeams, userPick, onWeeklyPickChange, + loadingTeamName, }: IWeekTeamsProps): JSX.Element => ( onWeeklyPickChange(value as NFLTeams)} @@ -76,13 +78,15 @@ const WeekTeams = ({ diff --git a/components/WeeklyPickButton/WeeklyPickButton.stories.tsx b/components/WeeklyPickButton/WeeklyPickButton.stories.tsx index 360e0865..d4dcd23f 100644 --- a/components/WeeklyPickButton/WeeklyPickButton.stories.tsx +++ b/components/WeeklyPickButton/WeeklyPickButton.stories.tsx @@ -34,7 +34,7 @@ type Story = StoryObj; const withRadioGroup: Decorator = (Story) => ( - + ); @@ -43,6 +43,8 @@ export const Primary: Story = { homeAway: 'Home', team: 'Ravens', src: '/assets/team-logo-placeholder.jpg', + loadingTeamName: 'ravens', + selectedTeam: '', }, decorators: withRadioGroup, }; diff --git a/components/WeeklyPickButton/WeeklyPickButton.test.tsx b/components/WeeklyPickButton/WeeklyPickButton.test.tsx index e8bb8821..408470b2 100644 --- a/components/WeeklyPickButton/WeeklyPickButton.test.tsx +++ b/components/WeeklyPickButton/WeeklyPickButton.test.tsx @@ -12,27 +12,66 @@ const weeklyPickData = { }; describe('WeeklyPickButton', () => { - it.each(['Home', 'Away'])('renders correctly with homeAway data', (homeAway) => { - render( - - - , - ); + it.each(['Home', 'Away'])( + 'renders correctly with homeAway data', + (homeAway) => { + render( + + + , + ); - const homeAwayLabel = screen.getByTestId('home-away'); - expect(homeAwayLabel).toBeInTheDocument(); - expect(homeAwayLabel).toHaveTextContent(homeAway); + const homeAwayLabel = screen.getByTestId('home-away'); + expect(homeAwayLabel).toBeInTheDocument(); + expect(homeAwayLabel).toHaveTextContent(homeAway); - const image = screen.getByTestId('team-image'); + const image = screen.getByTestId('team-image'); - expect(image).toBeInTheDocument(); - expect(image).toHaveAttribute('src', weeklyPickData.src); + expect(image).toBeInTheDocument(); + expect(image).toHaveAttribute('src', weeklyPickData.src); - const teamName = screen.getByTestId('team-label'); - expect(teamName).toBeInTheDocument(); + const teamName = screen.getByTestId('team-label'); + expect(teamName).toBeInTheDocument(); - expect(image).toHaveAttribute('width', weeklyPickData.width); - expect(image).toHaveAttribute('height', weeklyPickData.height); - expect(image).toHaveAttribute('alt', weeklyPickData.alt); + expect(image).toHaveAttribute('width', weeklyPickData.width); + expect(image).toHaveAttribute('height', weeklyPickData.height); + expect(image).toHaveAttribute('alt', weeklyPickData.alt); + }, + ); + + it('the loading spinner should display after team selection', () => { + render( + + + , + ); + expect(screen.queryByTestId('loading-spinner')).toBeInTheDocument(); + }); + + it('the loading spinner should not display after team selection', () => { + render( + + + , + ); + expect(screen.queryByTestId('loading-spinner')).not.toBeInTheDocument(); }); }); diff --git a/components/WeeklyPickButton/WeeklyPickButton.tsx b/components/WeeklyPickButton/WeeklyPickButton.tsx index dd9fc852..f0dc9380 100644 --- a/components/WeeklyPickButton/WeeklyPickButton.tsx +++ b/components/WeeklyPickButton/WeeklyPickButton.tsx @@ -5,12 +5,15 @@ import React, { JSX } from 'react'; import Image from 'next/image'; import { Label } from '../Label/Label'; import { RadioGroupItem } from '../RadioGroup/RadioGroup'; +import LoadingSpinner from '../LoadingSpinner/LoadingSpinner'; type WeeklyPickButtonProps = { homeAway: string; team: string; src: string; isDisabled?: boolean; + loadingTeamName: string | null; + selectedTeam: string; }; /** @@ -20,6 +23,8 @@ type WeeklyPickButtonProps = { * @param props.src - The image source * @param props.isDisabled - Whether the button is disabled * @param props.homeAway - Shows whether the team is home or away. + * @param props.loadingTeamName - The loading state for selecting teams. + * @param props.selectedTeam - The selected team that the user chose. * @returns The rendered weekly pick button. */ const WeeklyPickButton: React.FC = ({ @@ -27,6 +32,8 @@ const WeeklyPickButton: React.FC = ({ team, src, isDisabled = false, + loadingTeamName, + selectedTeam, }): JSX.Element => { return ( <> @@ -40,6 +47,7 @@ const WeeklyPickButton: React.FC = ({ disabled={isDisabled} data-testid="team-radio" /> + diff --git a/next.config.js b/next.config.js index faeb7f39..6774ae1e 100644 --- a/next.config.js +++ b/next.config.js @@ -18,7 +18,12 @@ module.exports = { ] }, images: { - domains: ['a.espncdn.com'], + remotePatterns: [{ + protocol: 'https', + hostname: 'a.espncdn.com', + port: '', + pathname: '/**', + }], }, eslint: { ignoreDuringBuilds: false, diff --git a/package.json b/package.json index 69391057..cdd54c0f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "private": true, - "version": "0.4.1", + "version": "0.4.2", "scripts": { "dev": "next dev", "build": "next build", diff --git a/utils/getBaseUrl.test.ts b/utils/getBaseUrl.test.ts index 2a0149ae..33d46f21 100644 --- a/utils/getBaseUrl.test.ts +++ b/utils/getBaseUrl.test.ts @@ -3,9 +3,8 @@ import { getBaseURL } from './getBaseUrl'; describe('getBaseURL', () => { it('should return the correct base URL for production', () => { process.env.NEXT_PUBLIC_VERCEL_ENV = 'production'; - process.env.NEXT_PUBLIC_VERCEL_URL = 'production.com'; const result = getBaseURL(); - expect(result).toBe('https://production.com'); + expect(result).toBe('https://www.gridironsurvivor.com'); }); it('should return the correct base URL for preview', () => { diff --git a/utils/getBaseUrl.ts b/utils/getBaseUrl.ts index 5008e735..e86f2256 100644 --- a/utils/getBaseUrl.ts +++ b/utils/getBaseUrl.ts @@ -8,7 +8,7 @@ export const getBaseURL = (): string => { // Check for Vercel production environment if (process.env.NEXT_PUBLIC_VERCEL_ENV === 'production') { - return `https://${process.env.NEXT_PUBLIC_VERCEL_URL}`; + return `https://www.gridironsurvivor.com`; } // Check for Vercel preview environment