Preview:
import React, { useContext, useEffect, useState } from "react";
import { useParams, useNavigate, useLocation } from "react-router-dom";
import { Box, Paper, Grid } from "@mui/material";
import SessionView from "./components/SessionView";
import { getEventLevel } from "../../../components/utils";
import EventEntryList from "./components/entries/EventEntryList";
import Summary from "./components/summary/Summary";
import HeatList from "./components/heats/HeatList";
import { GET_SESSION_EVENTS } from "../../../utils/graphql/queries";
import { ROUND_HEAT_STATUS_SUBSCRIPTION } from "../../../utils/graphql/subscriptions";
import { GET_HEAT_LIST } from "../../../utils/graphql/queries";
import useFetch from "../../../hooks/graphql/useFetch";
import EventHeader from "./components/EventHeader";
import { getView } from "../../../components/utils/getView";
import CombinedResults from "./components/combined/CombinedResults";
import useCombinedResults from "../../../hooks/useCombinedResults";
import useConditionalSub from "../../../hooks/graphql/useConditionalSub";
import { CompetitionDetailsContext } from "../../../context/CompetitionDetailsContext";

interface EventViewProps {
  competition: Competition | undefined;
  session: CompetitionSession | undefined;
  setSelectedSession: React.Dispatch<
    React.SetStateAction<CompetitionSession | undefined>
  >;
  setSessionTabIndex: React.Dispatch<React.SetStateAction<number>>;
  timeProgramEntryId: number | undefined;
  setTimeProgramEntryId: React.Dispatch<
    React.SetStateAction<number | undefined>
  >;
  eventView: View;
  setEventView: React.Dispatch<React.SetStateAction<View>>;
  isCompetitionActive: boolean;
}

const findEventView = (eventView: string | undefined): View => {
  switch (eventView as View) {
    case "entries":
      return "entries";
    case "heats":
      return "heats";
    case "summary":
      return "summary";
    case "combined":
      return "combined";
    default:
      return "entries";
  }
};

export default function EventView({
  competition,
  isCompetitionActive,
  session,
  setSelectedSession,
  setSessionTabIndex,
  timeProgramEntryId,
  setTimeProgramEntryId,
  eventView,
  setEventView,
}: EventViewProps) {
  const competitionId = competition?.id;
  const combinedGroup = competition?.combined_group;
  const showAge = competition?.show_age;
  const poolType = competition?.pool_type;
  const sessions = competition?.competition_sessions;
  const combinedType = competition?.combined_type;

  const params = useParams();
  const navigate = useNavigate();
  const location = useLocation();

  const {
    loading,
    error,
    data,
    refresh: refetch,
  } = useFetch<TimeProgramEntry[]>(
    GET_SESSION_EVENTS,
    { _id: session?.id },
    "_id",
    "cache-and-network"
  );

  const { data: heatData } = useFetch<TimeProgramEntry>(
    GET_HEAT_LIST,
    { id: timeProgramEntryId },
    );

  const [eventId, setEventId] = useState<number | undefined>(undefined);
  const [selectedEventViewTab, setSelectedEventViewTab] = useState<number>(0);
  const [tpes, setTpes] = useState<TimeProgramEntry[]>([]);
  const [selectedTpe, setSelectedTpe] = useState<TimeProgramEntry | undefined>(
    undefined
  );
  const [tpeFinal, setTpeFinal] = useState<boolean>(false);
  const [eventLevel, setEventLevel] = useState<number>(0);
  const [showOfficialTimeStamp, setShowOfficialTimeStamp] =
    useState<boolean>(false);
  const [roundStatus, setRoundStatus] = useState<number | undefined>(undefined);
  const [summaryTypes, setSummaryTypes] = useState<SummaryType[] | undefined>(
    selectedTpe?.round?.summary_types
  );

  useEffect(() => {
    setSelectedTpe(data ? data[0] : undefined);
  }, [data])

  const { shouldSubscribe } = useContext(CompetitionDetailsContext);

  const handleStatusClick = () => {
    if (showOfficialTimeStamp) {
      setShowOfficialTimeStamp(false);
    } else setShowOfficialTimeStamp(true);
  };

  useEffect(() => {
    if (data) {
      //INFO: avoid error if query only returns one tpe as an object
      if (!Array.isArray(data)) {
        try {
          let arr = [] as TimeProgramEntry[];
          arr.push(data);
          setTpes(arr);
          setSelectedTpe(data);
        } catch (err) {
          console.log(err);
        }
      } else {
        try {
          setTpes(data);
          const foundTpe = data.find((tpe) => tpe?.id === timeProgramEntryId);
          foundTpe && setSelectedTpe(foundTpe);
        } catch (err) {
          console.log(err);
        }
      }
    }
  }, [data]);

  useEffect(() => {
    if (selectedTpe) {
      setTimeProgramEntryId(selectedTpe?.id);
    }
  }, [selectedTpe]);

  useEffect(() => {
    refetch();
  }, [timeProgramEntryId]);

  const {
    data: roundHeatSubData,
    isActive,
    endSub,
  } = useConditionalSub<Round>(
    ROUND_HEAT_STATUS_SUBSCRIPTION,
    { id: selectedTpe?.round?.id },
    !(isCompetitionActive && !!selectedTpe?.round?.id) /* || !shouldSubscribe */
  );

  useEffect(() => {
    if (roundHeatSubData?.status) {
      setRoundStatus(roundHeatSubData?.status);
    }
  }, [roundHeatSubData]);

  /* CHECK AND SET COMPETITION-/EVENT LEVEL (SHOW/DON'T SHOW RANK) */
  useEffect(() => {
    if (selectedTpe) {
      setEventLevel(
        getEventLevel(selectedTpe?.round?.event?.event_competition_level)
      );
      setSummaryTypes(selectedTpe?.round?.summary_types);
    }
  }, [selectedTpe, timeProgramEntryId]);

  useEffect(() => {
    if (selectedTpe?.round?.sort_order && selectedTpe?.round?.sort_order >= 2) {
      setTpeFinal(true);
    } else {
      setTpeFinal(false);
    }
  }, [selectedTpe]);

  // useEffect(() => {
  //   const foundEventView: View = findEventView(params?.eventView);
  //   const parsedSession = Number(params.session);
  //   const foundSession = sessions?.find(
  //     (session) => session.oid === parsedSession
  //   );
  //   const parsedTpe = Number(params.tpe);
  //   const foundTpe = foundSession?.time_program_entries?.find(
  //     (tpe) => tpe?.oid === parsedTpe
  //   );

  //   if (location?.state?.tpeCard && selectedTpe?.round) {
  //     switch (selectedTpe?.round?.status) {
  //       case 0:
  //         setEventView("entries");
  //         setSelectedEventViewTab(0);
  //         navigate(
  //           `../competitions/${params.competitionName}/events/entries/${session?.oid}/${selectedTpe?.oid}`
  //         );
  //         break;
  //       case 1:
  //       case 3:
  //         setEventView("heats");
  //         setSelectedEventViewTab(1);
  //         navigate(
  //           `../competitions/${params.competitionName}/events/heats/${session?.oid}/${selectedTpe?.oid}`
  //         );
  //         break;
  //       case 5:
  //         setEventView("summary");
  //         setSelectedEventViewTab(2);
  //         navigate(
  //           `../competitions/${params.competitionName}/events/summary/${session?.oid}/${selectedTpe?.oid}`
  //         );
  //         break;
  //     }
  //   } else if (params.eventView && params.session && params.tpe) {
  //     if (foundEventView && foundSession && foundTpe) {
  //       //console.log('found event view, session and tpe');
  //       const foundSessionIndex = sessions?.findIndex(
  //         (session) => session?.id === foundSession?.id
  //       );
  //       foundSessionIndex && setSessionTabIndex(foundSessionIndex);
  //       setEventView(foundEventView);
  //       setSelectedEventViewTab(getView.AsIndex(foundEventView));
  //       setSelectedSession(foundSession);
  //       setTimeProgramEntryId(foundTpe?.id);
  //       setEventId(foundTpe?.round?.event?.id);
  //       navigate(
  //         `../competitions/${params.competitionName}/events/${foundEventView}/${foundSession?.oid}/${foundTpe?.oid}`
  //       );
  //     } else {
  //       //TODO: if no view in params, check tpe status to decide between entries, heats and summary
  //       //console.log('eventView, session & tpe: did not find event view');
  //       setEventView("entries");
  //       setSelectedEventViewTab(0);
  //       sessions &&
  //         sessions[0].time_program_entries &&
  //         setTimeProgramEntryId(sessions[0]?.time_program_entries[0]?.id);
  //       sessions &&
  //         sessions[0].time_program_entries &&
  //         navigate(
  //           `../competitions/${params.competitionName}/events/entries/${sessions[0]?.oid}/${sessions[0]?.time_program_entries[0]?.oid}`
  //         );
  //     }
  //   } else if (params.eventView && params.session) {
  //     const foundEventView: View = findEventView(params?.eventView);
  //     const parsedSession = Number(params.session);
  //     const foundSession = sessions?.find(
  //       (session) => session?.oid === parsedSession
  //     );
  //     if (foundEventView && foundSession) {
  //       //console.log('found event view and session');
  //       setEventView(foundEventView);
  //       setSelectedEventViewTab(getView.AsIndex(foundEventView));
  //       foundSession?.time_program_entries &&
  //         setTimeProgramEntryId(foundSession?.time_program_entries[0]?.id);
  //       foundSession?.time_program_entries &&
  //         setEventId(foundSession?.time_program_entries[0]?.round?.event?.id);
  //       foundSession?.time_program_entries &&
  //         navigate(
  //           `../competitions/${params.competitionName}/events/${foundEventView}/${foundSession.oid}/${foundSession?.time_program_entries[0]?.oid}`
  //         );
  //     } else {
  //       //console.log('eventView & session: did not find event view');
  //       setEventView("entries");
  //       setSelectedEventViewTab(0);
  //       navigate(
  //         `../competitions/${params.competitionName}/events/entries/${session?.oid}/${selectedTpe?.oid}`
  //       );
  //     }
  //   } else {
  //     setEventView("entries");
  //     setSelectedEventViewTab(0);
  //     sessions &&
  //       sessions[0].time_program_entries &&
  //       setTimeProgramEntryId(sessions[0]?.time_program_entries[0]?.id);
  //     sessions &&
  //       sessions[0].time_program_entries &&
  //       setEventId(sessions[0]?.time_program_entries[0]?.round?.event?.id);
  //     sessions &&
  //       sessions[0].time_program_entries &&
  //       navigate(
  //         `../competitions/${params.competitionName}/events/entries/${sessions[0]?.oid}/${sessions[0]?.time_program_entries[0]?.oid}`
  //       );
  //   }
  // }, [eventView, timeProgramEntryId, params.eventView]);

  useEffect(() => {
    return () => {
      endSub();
    };
  }, []);
  
  const handleEventViewChange = (e: React.ChangeEvent, newValue: number) => {
    setSelectedEventViewTab(newValue);
    localStorage.setItem('lastVisitedTab', String(newValue));
    navigate(
      `../competitions/${params.competitionName}/events/${getView.AsView(
        newValue as 0 | 1 | 2 | 3
      )}/${session?.oid}/${selectedTpe?.oid}`
    );
  };

  // Handle default view settings
  useEffect(() => {
    // if a view is selected by the user then keep that view as default, else execute the logic below ...
    if(eventView === "entries" && selectedEventViewTab === 0) {
      setEventView("entries")
      setSelectedEventViewTab(0); 
    }
    if(eventView && selectedEventViewTab) {
      return
    }
    if (selectedTpe && selectedTpe.round) {
      const status = selectedTpe?.round?.status;
      const hasHeats = heatData?.heats !== undefined || heatData?.heats !== null ? true : false;
  
      if (status === 5) {
        // If status is 5, set default view to "summary" and selected tab to 2
        setEventView("summary");
        setSelectedEventViewTab(2);
      } 
      else if(hasHeats) {
        // If round is "heat", set default view to "heats" and selected tab to 1
        setEventView("heats");
        setSelectedEventViewTab(1);
      } 
      else {
        // If status is not 5 and round is not "heat", set default view to "entries" and selected tab to 0
        setEventView("entries");
        setSelectedEventViewTab(0);
      }
    }
  }, [selectedTpe]);

  useEffect(() => {
    const lastVisitedTab = localStorage.getItem('lastVisitedTab');
    const defaultView = eventView || 'entries';
    const defaultTab = lastVisitedTab ? parseInt(lastVisitedTab) : 0;
    
    // Check if a view is already selected by the user
    if (!eventView && selectedEventViewTab === 0) {
      setEventView(defaultView);
      setSelectedEventViewTab(defaultTab);
    }
  }, [eventView, selectedEventViewTab]);

  const sponsorImg = selectedTpe?.round?.event?.sponsor?.img;
  const sponsorLink = selectedTpe?.round?.event?.sponsor?.link;
  const sponsorText = selectedTpe?.round?.event?.sponsor?.name;

  const eventNumber = selectedTpe?.round?.event?.number;
  const roundType = selectedTpe?.round?.round_type;

  const {
    combinedData: competitions,
    unsub,
    restartSub,
    lanes,
    loading: combinedLoading,
    error: combinedError,
    setSelectedAgeGroup,
    selectedAgeGroup,
    setAgeGroupTabIndex,
    ageGroupTabIndex,
  } = useCombinedResults(
    combinedGroup,
    eventNumber,
    roundType,
    combinedType,
    isCompetitionActive && eventView === "combined",
    eventView
  );

  return (
    <>
      <Grid container>
        <Grid item xs={4}>
          <Paper
            elevation={3}
            sx={{
              position: "sticky",
              maxHeight: "100vh",
              overflowY: "scroll",
              "&::-webkit-scrollbar": { display: "none" },
              top: "1px",
            }}
          >
            {session && (
              <SessionView
                competitionId={competitionId}
                session={session}
                time_program_entries={tpes}
                setEventId={setEventId}
                setSelectedTpe={setSelectedTpe}
                time_programId={timeProgramEntryId}
                setSummaryTypes={setSummaryTypes}
              />
            )}
          </Paper>
        </Grid>
        <Grid item xs={8} sx={{ bgcolor: "" }}>
          <Box ml={1} sx={{ bgcolor: "" }}>
            <EventHeader
              combinedCompetitions={competitions}
              combinedGroup={combinedGroup}
              eventView={eventView}
              eventId={selectedTpe?.round?.event?.id}
              selectedEventViewTab={selectedEventViewTab}
              setEventView={setEventView}
              handleEventViewChange={handleEventViewChange}
              handleStatusClick={handleStatusClick}
              selectedTpe={selectedTpe}
              sponsorImg={sponsorImg}
              showOfficialTimeStamp={showOfficialTimeStamp}
              setShowOfficialTimeStamp={setShowOfficialTimeStamp}
              sponsorLink={sponsorLink}
              sponsorText={sponsorText}
              roundStatus={roundStatus}
              tpeFinal={tpeFinal}
              isActive={isActive}
            />

            {selectedTpe?.type === 1 && (
              <Grid item xs={12} mx={0} mt={1} mb={2} sx={{ bgcolor: "" }}>
                {eventView === "entries" && (
                  <EventEntryList
                    competitionId={competitionId}
                    event={selectedTpe?.round?.event}
                    round={selectedTpe?.round}
                    time_programId={selectedTpe?.id}
                    tpeFinal={tpeFinal}
                    eventLevel={eventLevel}
                    showAge={showAge}
                    competitionPoolType={poolType}
                    sortByName={
                      selectedTpe.round?.event?.entry_list_types?.[0] &&
                      selectedTpe.round?.event?.entry_list_types?.[0]
                        .sort_by_name
                    }
                  />
                )}
                {eventView === "heats" && (
                  <HeatList
                    eventView={eventView}
                    eventType={selectedTpe.round?.event?.event_type}
                    roundHeatSubData={roundHeatSubData}
                    isCompetitionActive={isCompetitionActive}
                    timeProgramEntry={selectedTpe}
                    round={selectedTpe?.round}
                    time_programId={selectedTpe?.id}
                    eventLevel={eventLevel}
                    showAge={showAge}
                    superliveSeo={session?.superlive_seo_link}
                  />
                )}
                {eventView === "summary" &&
                  summaryTypes &&
                  summaryTypes?.length > 0 && (
                    <Summary
                      eventView={eventView}
                      roundHeatSubData={roundHeatSubData}
                      roundStatus={selectedTpe?.round?.status}
                      isCompetitionActive={isCompetitionActive}
                      summary_types={summaryTypes}
                      time_programId={selectedTpe?.id}
                      eventLevel={eventLevel}
                      showAge={showAge}
                    />
                  )}
                {eventView === "combined" && (
                  <CombinedResults
                    restartSub={restartSub}
                    unsub={unsub}
                    ageGroupTabIndex={ageGroupTabIndex}
                    selectedAgeGroup={selectedAgeGroup}
                    setAgeGroupTabIndex={setAgeGroupTabIndex}
                    setSelectedAgeGroup={setSelectedAgeGroup}
                    loading={combinedLoading}
                    error={combinedError}
                    eventLevel={eventLevel}
                    showAge={showAge}
                    compId={competitionId}
                    competitions={competitions}
                    lanes={lanes}
                  />
                )}
              </Grid>
            )}
          </Box>
        </Grid>
      </Grid>
    </>
  );
}
downloadDownload PNG downloadDownload JPEG downloadDownload SVG

Tip: You can change the style, width & colours of the snippet with the inspect tool before clicking Download!

Click to optimize width for Twitter