Advertisement
HjHimansh

React

Sep 15th, 2020 (edited)
69
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import React, { useState, useRef, useEffect } from 'react';
  2. import { useStoreState, useStoreActions } from 'easy-peasy';
  3. import { isEmpty, get } from 'lodash-es';
  4. import { Toast } from 'widget';
  5.  
  6. import BottomNavBar from 'components/BottomNavBar/BottomNavBar';
  7. import DashboardBanner from 'components/DashboardBanner/DashboardBanner';
  8. import ShareLink from 'components/ShareLink/ShareLink';
  9. import CardShimmer from 'components/CardShimmer/CardShimmer';
  10. import RecommendedCards from 'components/RecommendedCards/RecommendedCards';
  11. import JoinClassScreen from 'containers/JoinClassScreen/JoinClassScreen';
  12. import UpcomingClassCard from 'containers/UpcomingClassCard/UpcomingClassCard';
  13.  
  14. import { sendEvent } from 'utils/analyticsUtils';
  15. import {
  16.   getTimeStamp, getUTCTimeStamp, addDateTime, getCurrentServerTime, getLocalMidNight
  17. } from 'utils/dateUtils';
  18. import { getIfStudentAttendedClass, setIfStudentAttendedClass } from 'helpers/localStorage';
  19.  
  20. import { normalizeGetClassStructure } from 'helpers/app';
  21.  
  22. import commonStyles from 'scss/Common.module.scss';
  23. import styles from './Dashboard.module.scss';
  24.  
  25. const minuteSeconds = 60;
  26. const hourSeconds = minuteSeconds * 60;
  27.  
  28. const Dashboard = props => {
  29.   const apiTimer = useRef(null);
  30.   const serverTimer = useRef(null);
  31.   const [statusScreen, setStatusScreen] = useState(false);
  32.   const [loading, setLoading] = useState(true);
  33.   const navValue = useStoreState(state => state.navigation);
  34.   const { setNavValue } = useStoreActions(actions => actions.navigation);
  35.  
  36.   const {
  37.     id: userId, isBookingPossible
  38.   } = useStoreState(state => state.profile);
  39.  
  40.   const {
  41.     bookingStatus,
  42.     upcomingClass,
  43.     alreadyBookedFlag,
  44.     classTimeBreaks,
  45.     errorStatus
  46.   } = useStoreState(state => state.booking);
  47.  
  48.   const {
  49.     gradeId,
  50.   } = useStoreState(state => state.profile);
  51.  
  52.   const {
  53.     serverTime,
  54.     clientTime
  55.   } = useStoreState(state => state.app);
  56.  
  57.   const localServerTime = useRef(getCurrentServerTime(serverTime, clientTime).valueOf());
  58.  
  59.   const studentAttendedClass = getIfStudentAttendedClass();
  60.  
  61.   const {
  62.     getUpcomingClass,
  63.     getVcId,
  64.     resetBooking,
  65.     updateUserUpcomingClassDetails,
  66.   } = useStoreActions(actions => actions.booking);
  67.  
  68.   const {
  69.     updateUserClassesInClientStore,
  70.   } = useStoreActions(actions => actions.classes);
  71.  
  72.   const {
  73.     startTime,
  74.     endTime,
  75.     virtualClassId,
  76.     timeLeft
  77.   } = upcomingClass || {};
  78.  
  79.   useEffect(() => {
  80.     const eventObj = {
  81.       event: 'pageview',
  82.       screenName: 'dashboard_screen',
  83.       eventDetails: {
  84.         event: 'dashboard_screen',
  85.       },
  86.     };
  87.  
  88.     sendEvent(eventObj);
  89.   }, []);
  90.  
  91.   const getUpcomingDemoClass = () => {
  92.     getUpcomingClass()
  93.       .then(response => {
  94.         const upcomingClasses = get(response, 'data.upcoming_class', []);
  95.         if (upcomingClasses.length) {
  96.           // eslint-disable-next-line array-callback-return
  97.           const data = upcomingClasses.find((cur, index, arr) => {
  98.             if (arr.length === 1) {
  99.               return cur;
  100.             }
  101.             const endTimeStamp = getUTCTimeStamp(cur.end_time);
  102.             const clientTimeStamp = getTimeStamp();
  103.             if (clientTimeStamp < endTimeStamp) {
  104.               return cur;
  105.             }
  106.           });
  107.           if (data.vc_id) {
  108.             clearInterval(apiTimer.current);
  109.           }
  110.           const upcomingClassInfo = normalizeGetClassStructure(data);
  111.           const classInfo = {
  112.             unit: {
  113.               slug: upcomingClassInfo.slug,
  114.               title: upcomingClassInfo.title,
  115.               description: upcomingClassInfo.description,
  116.             },
  117.             course: {
  118.               name: upcomingClassInfo.subjectName
  119.             },
  120.             teacherName: upcomingClassInfo.teacherName,
  121.             startTime: upcomingClassInfo.startTime,
  122.             endTime: upcomingClassInfo.endTime,
  123.             virtualClassId: upcomingClassInfo.virtualClassId
  124.           };
  125.           updateUserUpcomingClassDetails({
  126.             upcomingClass: upcomingClassInfo,
  127.             classTimeBreaks: '',
  128.           });
  129.           updateUserClassesInClientStore(classInfo);
  130.         } else {
  131.           updateUserUpcomingClassDetails({
  132.             upcomingClass: {},
  133.             classTimeBreaks: '',
  134.           });
  135.         }
  136.         setLoading(false);
  137.       }).catch(() => {
  138.         setLoading(false);
  139.         // TODO: if response is not present 401 / 403
  140.       });
  141.   };
  142.  
  143.   const getUpcomingClassDetails = () => {
  144.     if (!userId || !gradeId) {
  145.       resetBooking();
  146.       setIfStudentAttendedClass(false);
  147.       props.history.replace('/booking');
  148.     } else {
  149.       getUpcomingDemoClass();
  150.     }
  151.   };
  152.  
  153.   const updateServerTime = () => {
  154.     serverTimer.current = setInterval(() => {
  155.       localServerTime.current = addDateTime(localServerTime.current, 30, 'seconds');
  156.       updateUserUpcomingClassDetails({ serverTime: localServerTime.current });
  157.     }, 30000);
  158.   };
  159.  
  160.   const apiCallForDemoClass = () => {
  161.     apiTimer.current = setInterval(() => {
  162.       if (!isEmpty(bookingStatus)) {
  163.         getVcId({ scheduled_session_id: bookingStatus.scheduled_session_id })
  164.           .then(response => {
  165.             if (response.data) {
  166.               const { id: vcId } = response.data.get_vc_id || {};
  167.               if (vcId) {
  168.                 clearInterval(apiTimer.current);
  169.               }
  170.               const upcomingClassObj = {
  171.                 ...upcomingClass,
  172.                 virtualClassId: vcId
  173.               };
  174.               updateUserUpcomingClassDetails({ upcomingClass: upcomingClassObj });
  175.             }
  176.           });
  177.       }
  178.     }, 300000);
  179.   };
  180.  
  181.   useEffect(() => {
  182.     getUpcomingClassDetails();
  183.     updateServerTime();
  184.  
  185.     return () => {
  186.       if (serverTimer.current) {
  187.         clearInterval(serverTimer.current);
  188.       }
  189.       if (apiTimer.current) {
  190.         clearInterval(apiTimer.current);
  191.       }
  192.     };
  193.   }, []);
  194.  
  195.   useEffect(() => {
  196.     /* upcoming class details being fetch */
  197.     if (isEmpty(upcomingClass) || loading) {
  198.       return;
  199.     }
  200.     const serverTimeStamp = localServerTime.current;
  201.     const startTimeStamp = getUTCTimeStamp(startTime);
  202.     const endTimeStamp = getUTCTimeStamp(endTime);
  203.  
  204.     const beforeFiveMins = (startTimeStamp - (minuteSeconds * 5 * 1000));
  205.     const afterTenMins = (startTimeStamp + (minuteSeconds * 10 * 1000));
  206.  
  207.     const midNightStamp = getLocalMidNight(startTime);
  208.     if (serverTimeStamp > midNightStamp) {
  209.       updateUserUpcomingClassDetails({
  210.         classTimeBreaks: 'midNight'
  211.       });
  212.       clearInterval(serverTimer.current);
  213.       return;
  214.     }
  215.  
  216.     if (serverTimeStamp > endTimeStamp) {
  217.       clearInterval(apiTimer.current);
  218.       updateUserUpcomingClassDetails({
  219.         classTimeBreaks: 'classEnded'
  220.       });
  221.       return;
  222.     }
  223.  
  224.     if (serverTimeStamp > afterTenMins) {
  225.       updateUserUpcomingClassDetails({
  226.         classTimeBreaks: 'post10mins'
  227.       });
  228.       return;
  229.     }
  230.  
  231.     if (serverTimeStamp >= beforeFiveMins && serverTimeStamp <= afterTenMins) {
  232.       updateUserUpcomingClassDetails({
  233.         classTimeBreaks: ''
  234.       });
  235.       setStatusScreen(true);
  236.     } else {
  237.       updateUserUpcomingClassDetails({
  238.         classTimeBreaks: ''
  239.       });
  240.       setStatusScreen(false);
  241.     }
  242.  
  243.     /* current time is 1 hour before the class start time
  244.       make an API call to get virtual_class_id in 5 mins interval
  245.     */
  246.     if (serverTimeStamp >= (startTimeStamp - (hourSeconds * 1000))) {
  247.       if (!apiTimer.current) {
  248.         apiCallForDemoClass();
  249.       }
  250.     }
  251.   }, [localServerTime.current]);
  252.  
  253.   const _onClick = () => {
  254.     setStatusScreen(false);
  255.   };
  256.  
  257.   useEffect(() => {
  258.     setNavValue('home');
  259.   }, []);
  260.  
  261.   /* navbar function */
  262.   const handleChange = newValue => {
  263.     props.history.push(`/${newValue === 'home' ? 'dashboard' : 'library'}`);
  264.     setNavValue(newValue);
  265.   };
  266.  
  267.   const _onHide = () => {
  268.     updateUserUpcomingClassDetails({ alreadyBookedFlag: false });
  269.   };
  270.  
  271.   const getCardHeading = () => {
  272.     if (studentAttendedClass) {
  273.       return 'Explore other Lido subjects';
  274.     } if (!isEmpty(upcomingClass) && classTimeBreaks === 'classEnded') {
  275.       return 'Missed the class?';
  276.     }
  277.     return 'Try your first Lido class for free';
  278.   };
  279.  
  280.   const getCardSubHeading = () => {
  281.     if (studentAttendedClass) {
  282.       return null;
  283.     }
  284.     if (!isEmpty(upcomingClass) && classTimeBreaks === 'classEnded') {
  285.       return <div className={styles.subHeading}>Missed the class?</div>;
  286.     }
  287.     return <div className={styles.subHeading}>Book a trial class in any of our awesome subjects</div>;
  288.   };
  289.  
  290.   const getUpcomingClassCard = () => {
  291.     if (loading) {
  292.       return (
  293.         <CardShimmer
  294.           bookingDate
  295.           slotTime
  296.           buttonText
  297.           className={styles.cardShimmer}
  298.         />
  299.       );
  300.     }
  301.     const recommendedCardsMarkup = (
  302.       <div className={styles.innerWrapper}>
  303.         <div className={`${commonStyles.heading} ${styles.heading}`}>
  304.           {getCardHeading()}
  305.         </div>
  306.         {getCardSubHeading()}
  307.         <RecommendedCards history={props.history} />
  308.       </div>
  309.     );
  310.  
  311.     let actualContent;
  312.  
  313.     if(alreadyBookedFlag && (errorStatus === 409 || errorStatus === 429)){
  314.       if(!isBookingPossible){
  315.         actualContent =  (
  316.           <>
  317.             <Toast
  318.               heading="Thank you for registering!"
  319.               subHeading={(
  320.                 <>
  321.                   <p>Currently we require a laptop/desktop to take a free trial class with Lido.</p>
  322.                   <p>We will be supporting class via mobile very soon and will reach out to you when this is live!</p>
  323.                   <p>In the meanwhile, explore our content library filled with games, videos and quizzes</p>
  324.                   <p><small>Thanks again for showing interest!</small></p>
  325.                 </>
  326.               )}
  327.             />
  328.             {getUpcomingClassCard()}
  329.           </>
  330.         );
  331.       }
  332.       else if(errorStatus===409){
  333.         actualContent = (
  334.           (
  335.             <>
  336.               <Toast
  337.                 onHide={_onHide}
  338.                 heading="Hello again!"
  339.                 subHeading="You have already booked a class with this number. Please check the details below!"
  340.               />
  341.               {getUpcomingClassCard()}
  342.             </>
  343.         );
  344.       }
  345.       else{
  346.         actualContent = (
  347.           <>
  348.             <Toast
  349.               onHide={_onHide}
  350.               heading="We cannot make the booking"
  351.               subHeading="Oopse! You have gone over the limit of free classes you can take this month."
  352.             />
  353.             {getUpcomingClassCard()}
  354.           </>
  355.         );
  356.       }
  357.     }
  358.     else{
  359.       actualContent = (
  360.         {getUpcomingClassCard()}
  361.       );
  362.     }
  363.  
  364.  
  365.  
  366.     if (!isEmpty(upcomingClass) && classTimeBreaks !== 'midNight') {
  367.       if (!(classTimeBreaks === 'classEnded' && studentAttendedClass)) {
  368.         return (
  369.           <UpcomingClassCard
  370.             virtualClassId={virtualClassId}
  371.             timeLeft={timeLeft}
  372.             history={props.history}
  373.           />
  374.         );
  375.       }
  376.       return recommendedCardsMarkup;
  377.     }
  378.  
  379.     return recommendedCardsMarkup;
  380.   };
  381.  
  382.   return (
  383.     <div className={styles.root}>
  384.       {statusScreen
  385.         ? (
  386.           <JoinClassScreen
  387.             history={props.history}
  388.             virtualClassId={virtualClassId}
  389.             onClick={_onClick}
  390.           />
  391.         )
  392.         : null}
  393.       <div className={styles.body}>
  394.         <DashboardBanner
  395.           history={props.history}
  396.           headerType={(studentAttendedClass && classTimeBreaks === 'classEnded') ? 'premiumHeader' : ''}
  397.         />
  398.         <actualContent />
  399.         <ShareLink />
  400.       </div>
  401.       <BottomNavBar
  402.         selectedTab={navValue.navValue}
  403.         onChange={handleChange}
  404.       />
  405.     </div>
  406.   );
  407. };
  408.  
  409. export default Dashboard;
  410.  
Advertisement
RAW Paste Data Copied
Advertisement