Ejemplo n.º 1
0
export default function Bar({ index, bar, barPercentage }) {
  return (
    <section
      style={{
        display: 'flex',
        alignItems: 'center',
        width: '100%',
        marginTop: index === 0 ? 0 : '1rem'
      }}
    >
      <div
        style={{
          fontSize: '1.3rem',
          width: '2.5rem'
        }}
      >
        {bar.label}
      </div>
      <div
        style={{
          display: 'inline-block',
          whiteSpace: 'nowrap',
          minWidth: `${barPercentage}%`,
          padding: '0.5rem',
          marginLeft: '1rem',
          background: index === 0 ? Color.orange() : Color.logoBlue(),
          fontSize: '1.5rem',
          color: '#fff',
          textAlign: 'center',
          fontWeight: 'bold'
        }}
      >
        {`${addCommasToNumber(bar.value)} XP`}
      </div>
      {barPercentage < 100 && (
        <div style={{ width: `${100 - barPercentage}%` }} />
      )}
    </section>
  );
}
Ejemplo n.º 2
0
function VideoThumbImage({
  difficulty,
  height = '55%',
  playIcon,
  src,
  userId,
  videoId
}) {
  const [xpEarned, setXpEarned] = useState(false);
  const mounted = useRef(true);
  useEffect(() => {
    mounted.current = true;
    checkXpStatus();
    async function checkXpStatus() {
      const authorization = auth();
      const authExists = !!authorization.headers.authorization;
      if (authExists) {
        try {
          const {
            data: { xpEarned }
          } = await request.get(
            `${API_URL}/xpEarned?videoId=${videoId}`,
            auth()
          );
          if (mounted.current) setXpEarned(xpEarned);
        } catch (error) {
          console.error(error.response || error);
        }
      } else {
        setXpEarned(false);
      }
    }
    return function cleanUp() {
      mounted.current = false;
    };
  }, [videoId, difficulty, userId]);

  return (
    <div
      style={{
        display: 'block',
        width: '100%',
        height: 'auto',
        overFlow: 'hidden',
        paddingBottom: height,
        position: 'relative'
      }}
    >
      <img
        alt="Thumbnail"
        src={src}
        style={{
          display: 'block',
          width: '100%',
          height: '100%',
          position: 'absolute',
          top: 0,
          left: 0,
          bottom: 0,
          right: 0,
          margin: 'auto',
          borderBottom: !!xpEarned && `0.8rem solid ${Color.green()}`
        }}
      />
      {playIcon && (
        <a
          className={css`
            position: absolute;
            display: block;
            background: url('/img/play-button-image.png');
            background-size: contain;
            height: 3rem;
            width: 3rem;
            top: 50%;
            left: 50%;
            margin: -1.5rem 0 0 -1.5rem;
          `}
        />
      )}
      {!!difficulty && (
        <div
          style={{
            position: 'absolute',
            padding: '0.1rem 0.5rem',
            background:
              difficulty === 5
                ? Color.gold()
                : difficulty === 4
                ? Color.brownOrange()
                : difficulty === 3
                ? Color.orange()
                : difficulty === 2
                ? Color.pink()
                : Color.logoBlue(),
            fontSize: '1.5rem',
            fontWeight: 'bold',
            color: '#fff'
          }}
        >
          {addCommasToNumber(difficulty * xp)} XP
        </div>
      )}
    </div>
  );
}
Ejemplo n.º 3
0
export default function MyRank({ myId, rank, twinkleXP }) {
  const rankedColor =
    rank === 1
      ? Color.gold()
      : rank === 2
      ? '#fff'
      : rank === 3
      ? Color.bronze()
      : undefined;
  return (
    <div
      style={{
        marginTop: '1rem',
        marginBottom: myId ? '1rem' : 0,
        background: myId
          ? rank > 0
            ? rank < 4
              ? Color.black()
              : '#fff'
            : '#fff'
          : null
      }}
      className={css`
        width: 100%;
        margin-bottom: 0px;
        text-align: center;
        padding: 1rem;
        border: ${rank > 0 && rank < 4
          ? ''
          : `1px solid ${Color.borderGray()}`};
        border-radius: ${borderRadius};
        p {
          font-weight: bold;
        }
        a {
          font-size: 1.5rem;
          font-weight: bold;
        }
      `}
    >
      {
        <p>
          <span
            style={{
              color: rankedColor || Color.logoGreen(),
              fontSize: '3rem'
            }}
          >
            {twinkleXP ? addCommasToNumber(twinkleXP) : 0}
          </span>{' '}
          <span
            style={{
              color: rankedColor || Color.gold(),
              fontSize: '3rem'
            }}
          >
            XP
          </span>
          &nbsp;&nbsp;
          <span
            style={{
              color:
                rankedColor ||
                (rank > 0 && rank <= 10 ? Color.pink() : Color.darkGray()),
              fontSize: '2rem'
            }}
          >
            {rank ? `Rank #${rank}` : 'Unranked'}
          </span>
        </p>
      }
    </div>
  );
}
Ejemplo n.º 4
0
 render() {
   const {
     myId,
     loadMore,
     activeTab,
     notifications,
     numNewNotis,
     rewards,
     style,
     totalRewardAmount
   } = this.props
   const { loading } = this.state
   const { originalTotalReward, originalTwinkleXP } = this.state
   return (
     <div style={style}>
       <RoundList style={{ marginTop: '0' }}>
         {numNewNotis > 0 && (
           <Banner
             love
             style={{ marginBottom: '1rem' }}
             onClick={this.onNewNotiAlertClick}
           >
             Tap to See {numNewNotis} New Notification{numNewNotis > 1
               ? 's'
               : ''}
           </Banner>
         )}
         {activeTab === 'reward' && (
           <Banner
             love={totalRewardAmount > 0}
             success={totalRewardAmount === 0}
             style={{ marginBottom: '1rem' }}
             onClick={totalRewardAmount > 0 ? this.onCollectReward : null}
           >
             {totalRewardAmount > 0 && (
               <Fragment>
                 <p>Tap to collect all your rewards</p>
                 <p>
                   ({totalRewardAmount} stars x {rewardValue.star} XP/star ={' '}
                   {addCommasToNumber(totalRewardAmount * rewardValue.star)}{' '}
                   XP)
                 </p>
               </Fragment>
             )}
             {totalRewardAmount === 0 && (
               <Fragment>
                 <p>{originalTotalReward * rewardValue.star} XP Collected!</p>
                 <p>
                   Your XP went up from {addCommasToNumber(originalTwinkleXP)}{' '}
                   to{' '}
                   {addCommasToNumber(
                     originalTwinkleXP + originalTotalReward * rewardValue.star
                   )}
                 </p>
               </Fragment>
             )}
           </Banner>
         )}
         {activeTab === 'notification' &&
           notifications.map(notification => {
             return (
               <li className={notiFeedListItem} key={notification.id}>
                 {renderNotificationMessage(notification, myId)}
                 <small style={{ color: Color.gray() }}>
                   {timeSince(notification.timeStamp)}
                 </small>
               </li>
             )
           })}
         {activeTab === 'leaderboard' && <LeaderBoardTab myId={myId} />}
         {activeTab === 'reward' &&
           rewards.map(
             ({
               id,
               contentId,
               contentType,
               rewardAmount,
               rewardType,
               rewarderId,
               rewarderUsername,
               timeStamp
             }) => (
               <li className={notiFeedListItem} key={id}>
                 <div>
                   <UsernameText
                     user={{ id: rewarderId, name: rewarderUsername }}
                     color={Color.blue()}
                   />{' '}
                   <span
                     style={{
                       color: rewardAmount > 1 ? Color.gold() : Color.orange(),
                       fontWeight: 'bold'
                     }}
                   >
                     rewarded you {rewardAmount === 1 ? 'a' : rewardAmount}{' '}
                     {rewardType}
                     {rewardAmount > 1 ? 's' : ''}
                   </span>{' '}
                   for your{' '}
                   <ContentLink
                     style={{ color: Color.green() }}
                     content={{ id: contentId, title: contentType }}
                     type={contentType}
                   />
                 </div>
                 <small>{timeSince(timeStamp)}</small>
               </li>
             )
           )}
       </RoundList>
       {((activeTab === 'notification' && loadMore.notifications) ||
         (activeTab === 'reward' && loadMore.rewards)) && (
         <Button
           info
           filled
           style={{
             marginTop: '1rem',
             width: '100%'
           }}
           disabled={loading}
           onClick={this.onLoadMore}
         >
           Load More
         </Button>
       )}
     </div>
   )
 }
Ejemplo n.º 5
0
export default function RankBar({ className, profile, style }) {
  const rankColor =
    profile.rank === 1
      ? Color.gold()
      : profile.rank === 2
      ? '#fff'
      : profile.rank === 3
      ? Color.bronze()
      : undefined;

  return (
    <div
      style={style}
      className={`${css`
          padding: 1.5rem 0;
          font-size: 2rem;
          color: ${rankColor};
          font-weight: bold;
          text-align: center;
          border-bottom-left-radius: ${borderRadius};
          border-bottom-right-radius: ${borderRadius};
          ${profile.rank > 3 ? `border: 1px solid ${Color.borderGray()};` : ''}
          background: ${profile.rank < 4 ? Color.black() : '#fff'};
          @media (max-width: ${mobileMaxWidth}) {
            margin-left: 0;
            margin-right: 0;
            border-radius: 0;
            border-left: none;
            border-right: none;
          }
        `} ${className}`}
    >
      <span>
        <span
          style={{
            color:
              rankColor ||
              (profile.rank <= 10 ? Color.logoBlue() : Color.darkGray())
          }}
        >
          Rank
        </span>{' '}
        <span
          style={{
            color:
              rankColor ||
              (profile.rank <= 10 ? Color.logoBlue() : Color.darkGray())
          }}
        >
          #{profile.rank}
        </span>{' '}
        <span
          style={{
            color:
              rankColor ||
              (profile.rank <= 10 ? Color.logoBlue() : Color.darkGray())
          }}
        >
          with
        </span>
      </span>{' '}
      <span>
        <span
          style={{
            color:
              rankColor ||
              (profile.rank <= 10 ? Color.logoGreen() : Color.darkGray())
          }}
        >
          {addCommasToNumber(profile.twinkleXP)}
        </span>{' '}
        <span
          style={{
            color:
              rankColor ||
              (profile.rank <= 10 ? Color.gold() : Color.darkGray())
          }}
        >
          XP
        </span>
        {!!profile.xpThisMonth && (
          <span
            style={{
              fontSize: '1.7rem',
              color:
                rankColor ||
                (profile.xpThisMonth >= 1000 ? Color.pink() : Color.darkGray())
            }}
          >
            {' '}
            (↑
            {addCommasToNumber(profile.xpThisMonth)} this month)
          </span>
        )}
      </span>
    </div>
  );
}
Ejemplo n.º 6
0
function MainFeeds({
  activeTab,
  changeUserXP,
  clearRewards,
  fetchNotifications,
  loadMore,
  loadMoreNotifications,
  loadMoreRewards,
  notifications,
  numNewNotis,
  rank,
  rewards,
  selectNotiTab,
  style,
  totalRewardAmount,
  twinkleXP,
  userId
}) {
  const [loading, setLoading] = useState(false);
  const [originalTotalReward, setOriginalTotalReward] = useState(0);
  const [originalTwinkleXP, setOriginalTwinkleXP] = useState(0);

  return (
    <ErrorBoundary style={style}>
      {numNewNotis > 0 && (
        <Banner
          color="gold"
          style={{ marginBottom: '1rem' }}
          onClick={onNewNotiAlertClick}
        >
          Tap to See {numNewNotis} New Notification
          {numNewNotis > 1 ? 's' : ''}
        </Banner>
      )}
      {activeTab === 'reward' && (
        <Banner
          color={totalRewardAmount > 0 ? 'gold' : 'green'}
          style={{ marginBottom: '1rem' }}
          onClick={totalRewardAmount > 0 ? onCollectReward : null}
        >
          {totalRewardAmount > 0 && (
            <>
              <p>Tap to collect all your rewards</p>
              <p>
                ({totalRewardAmount} Twinkles x {rewardValue.star} XP/Twinkle ={' '}
                {addCommasToNumber(totalRewardAmount * rewardValue.star)} XP)
              </p>
            </>
          )}
          {totalRewardAmount === 0 && (
            <>
              <p>{originalTotalReward * rewardValue.star} XP Collected!</p>
              <p>
                Your XP: {addCommasToNumber(originalTwinkleXP)} {'=>'}{' '}
                {addCommasToNumber(
                  originalTwinkleXP + originalTotalReward * rewardValue.star
                )}
              </p>
            </>
          )}
        </Banner>
      )}
      {activeTab === 'reward' && !!userId && (
        <MyRank myId={userId} rank={rank} twinkleXP={twinkleXP} />
      )}
      {userId && activeTab === 'notification' && notifications.length > 0 && (
        <RoundList style={{ marginTop: 0 }}>
          {notifications.map(notification => {
            return (
              <li
                style={{ background: '#fff' }}
                className={notiFeedListItem}
                key={notification.id}
              >
                <NotiItem notification={notification} />
              </li>
            );
          })}
        </RoundList>
      )}
      {activeTab === 'rankings' && <Rankings />}
      {activeTab === 'reward' && rewards.length > 0 && (
        <RoundList style={{ marginTop: 0 }}>
          {rewards.map(
            ({
              id,
              contentId,
              contentType,
              rewardAmount,
              rewardType,
              rewarderId,
              rewarderUsername,
              timeStamp
            }) => (
              <li
                style={{ background: '#fff' }}
                className={notiFeedListItem}
                key={id}
              >
                <div>
                  <UsernameText
                    user={{ id: rewarderId, username: rewarderUsername }}
                    color={Color.blue()}
                  />{' '}
                  <span
                    style={{
                      color:
                        rewardAmount === 25
                          ? Color.gold()
                          : rewardAmount >= 10
                          ? Color.rose()
                          : rewardAmount >= 5
                          ? Color.orange()
                          : rewardAmount >= 3
                          ? Color.pink()
                          : Color.lightBlue(),
                      fontWeight: 'bold'
                    }}
                  >
                    rewarded you {rewardAmount === 1 ? 'a' : rewardAmount}{' '}
                    {rewardType}
                    {rewardAmount > 1 ? 's' : ''}
                  </span>{' '}
                  for your{' '}
                  <ContentLink
                    style={{ color: Color.green() }}
                    content={{
                      id: contentId,
                      title: contentType
                    }}
                    type={contentType}
                  />
                </div>
                <small>{timeSince(timeStamp)}</small>
              </li>
            )
          )}
        </RoundList>
      )}
      {((activeTab === 'notification' && loadMore.notifications) ||
        (activeTab === 'reward' && loadMore.rewards)) &&
        !!userId && (
          <LoadMoreButton
            style={{ marginTop: '1rem' }}
            loading={loading}
            color="lightBlue"
            filled
            stretch
            onClick={onLoadMore}
          />
        )}
    </ErrorBoundary>
  );

  async function onCollectReward() {
    setOriginalTotalReward(totalRewardAmount);
    setOriginalTwinkleXP(twinkleXP);
    await changeUserXP({
      action: 'collect'
    });
    clearRewards();
  }

  async function onNewNotiAlertClick() {
    await fetchNotifications();
    selectNotiTab();
  }

  async function onLoadMore() {
    setLoading(true);
    if (activeTab === 'notification') {
      await loadMoreNotifications(notifications[notifications.length - 1].id);
    } else {
      await loadMoreRewards(rewards[rewards.length - 1].id);
    }
    setLoading(false);
  }
}
Ejemplo n.º 7
0
export default function RankBar({ profile }) {
  const rankColor =
    profile.rank === 1
      ? Color.gold()
      : profile.rank === 2
        ? Color.silver()
        : profile.rank === 3
          ? '#fff'
          : undefined
  return (
    <div
      className={css`
          padding: 1.5rem 0;
          font-size: 2rem;
          color: ${rankColor};
          font-weight: bold;
          text-align: center;
          border-bottom-left-radius: ${borderRadius};
          border-bottom-right-radius: ${borderRadius};
          ${profile.rank > 3 ? `border: 1px solid #e7e7e7;` : ''}
          background: ${
            profile.rank < 3
              ? Color.black(1 - (profile.rank - 1) / 10)
              : profile.rank === 3
                ? Color.orange()
                : Color.whiteGray()
          };
          @media (max-width: ${mobileMaxWidth}) {
            border-radius: 0;
            border-left: none;
            border-right: none;
          }
        `}
    >
      <span>
        <span
          style={{
            color:
              rankColor ||
              (profile.rank <= 10 ? Color.logoBlue() : Color.buttonGray())
          }}
        >
          Rank
        </span>{' '}
        <span
          style={{
            color:
              rankColor ||
              (profile.rank <= 10 ? Color.logoBlue() : Color.buttonGray())
          }}
        >
          #{profile.rank}
        </span>{' '}
        <span
          style={{
            color:
              rankColor ||
              (profile.rank <= 10 ? Color.logoBlue() : Color.buttonGray())
          }}
        >
          with
        </span>
      </span>{' '}
      <span>
        <span
          style={{
            color:
              rankColor ||
              (profile.rank <= 10 ? Color.logoGreen() : Color.buttonGray())
          }}
        >
          {addCommasToNumber(profile.twinkleXP)}
        </span>{' '}
        <span
          style={{
            color:
              rankColor ||
              (profile.rank <= 10 ? Color.gold() : Color.buttonGray())
          }}
        >
          XP
        </span>
      </span>
    </div>
  )
}
Ejemplo n.º 8
0
function RewardStatus({
  className,
  difficulty,
  noMarginForEditButton,
  onCommentEdit,
  stars = [],
  userId,
  style
}) {
  const [loaded, setLoaded] = useState(2);
  const finalStar = stars.length > 0 ? stars[stars.length - 1] : {};
  const starsWithComment = stars.filter(
    star => !stringIsEmpty(star.rewardComment) && star.id !== finalStar.id
  );
  const starsWithoutComment = stars.filter(
    star => stringIsEmpty(star.rewardComment) && star.id !== finalStar.id
  );
  stars = starsWithoutComment
    .concat(starsWithComment)
    .concat(finalStar.id ? [finalStar] : []);
  const maxStars = returnMaxStars({ difficulty });
  let rewardedStars = stars.reduce((prev, star) => prev + star.rewardAmount, 0);
  rewardedStars = Math.min(rewardedStars, maxStars);
  if (!stars || stars.length === 0) return null;

  return (
    <ErrorBoundary>
      <div
        style={style}
        className={`${className} ${css`
          font-size: 1.6rem;
          padding: 0.4rem 1rem 0.2rem 1rem;
          color: #fff;
          display: flex;
          flex-direction: column;
          align-items: center;
          background: ${rewardedStars === maxStars
            ? Color.gold()
            : rewardedStars >= 25
            ? Color.brownOrange()
            : Color.logoBlue()};
        `}`}
      >
        <Starmarks stars={rewardedStars} />
        <div style={{ fontSize: '1.5rem' }}>
          {rewardedStars} Twinkle
          {rewardedStars > 1 ? 's' : ''} (
          {addCommasToNumber(rewardedStars * 200)} XP) rewarded out of max {maxStars}
        </div>
      </div>
      {loaded < stars.length && (
        <LoadMoreButton
          color={
            rewardedStars === maxStars || rewardedStars > 10
              ? 'orange'
              : 'lightBlue'
          }
          label="Show More Reward Records"
          filled
          style={{
            fontSize: '1.3rem',
            marginTop: '1rem'
          }}
          onClick={() => setLoaded(loaded + 3)}
        />
      )}
      {stars
        .filter((star, index) => index > stars.length - loaded - 1)
        .map(star => (
          <Comment
            maxRewardableStars={Math.ceil(maxStars / 2)}
            noMarginForEditButton={noMarginForEditButton}
            key={star.id}
            star={star}
            myId={userId}
            onEditDone={onCommentEdit}
          />
        ))}
    </ErrorBoundary>
  );
}