🎰 숫자 μΉ΄μš΄νŒ… μ• λ‹ˆλ©”μ΄μ…˜

μ†μœ€μ£ΌΒ·2022λ…„ 8μ›” 6일
3
post-thumbnail
post-custom-banner

κ·€λ†ν•œ 청년을 μœ„ν•œ 생산성 μ„œλΉ„μŠ€λ₯Ό 6μ£Όκ°„ 5λͺ…μ΄μ„œ κ°œλ°œν–ˆλ‹€.
πŸ‘‰ μ„œλΉ„μŠ€ ꡬ경가기

농μž₯의 μ—¬λŸ¬ 톡계λ₯Ό λ³΄μ—¬μ£ΌλŠ” 농μž₯ 관리 ν˜„ν™© νŽ˜μ΄μ§€λ₯Ό 맑아 κ΅¬ν˜„ 쀑 μž‘λ…„μ— λΉ„ν•΄
μž‘μ—…μ‹œκ°„ 증가/κ°μ†Œμœ¨ ν˜„ν™©μ„ λ³΄μ—¬μ£ΌλŠ” UIλ₯Ό 극적으둜 ν‘œν˜„ν•˜κΈ° μœ„ν•΄ 숫자 μΉ΄μš΄νŒ… μ• λ‹ˆλ©”μ΄μ…˜μ„ κ΅¬ν˜„ν–ˆλ‹€.

import React, { useEffect, useState } from "react";
import styled, { keyframes } from "styled-components";
import { useDispatch, useSelector } from "react-redux";
import { getRateDB } from "../../redux/modules/analysis";

import { ShimmerThumbnail } from "react-shimmer-effects";
import WorkTimeBarChart from "./WorkTimeBarChart";

const WorkTime = ({ workTimeData }) => {
  const dispatch = useDispatch();
    // 2️⃣ 증가/κ°μ†Œμœ¨ response κ°’ useSelector 둜 뢈러였기
  const rateData = useSelector((state) => state.analysis.rate);
  const [count, setCount] = useState(0);
  const [windowSize, setWindowSize] = useState(getWindowSize());
  const is_loaded = useSelector((state) => state.analysis.worktime_is_loaded);

  // 1️⃣ 증가/κ°μ†Œμœ¨ 데이터 API 호좜 
  useEffect(() => {
    dispatch(getRateDB());
  }, []);

  // 3️⃣ μΉ΄μš΄νŒ… μ• λ‹ˆλ©”μ΄μ…˜ end κ°’ λ°›μ•„μ˜¨ λ°μ΄ν„°λ‘œ 적용
  const end = rateData?.rate;
  const start = 0;
  const duration = 1000;

  const frameRate = 1000 / 60;
  const totalFrame = Math.round(duration / frameRate);

  const easeOutExpo = (number) => {
    return number === 1 ? 1 : 1 - Math.pow(2, -10 * number);
  };

  // 4️⃣ useEffect둜 화면이 그렀질 λ•Œλ§ˆλ‹€ μΉ΄μš΄νŒ… μ• λ‹ˆλ©”μ΄μ…˜ μ‹€ν–‰
  useEffect(() => {
    let currentNumber = start;
    const counter = setInterval(() => {
      // 5️⃣ currentNumber / totalFrame 이 1에 κ°€κΉŒμ›Œμ§ˆμˆ˜λ‘ 느리게 μΉ΄μš΄νŒ…
      const progress = easeOutExpo(++currentNumber / totalFrame);
      if (rateData.rate) setCount(Math.round(end * progress));

      if (progress === 1) {
        clearInterval(counter);
      }
    }, frameRate);
  }, [end, frameRate, start, totalFrame]);

  // μœˆλ„μš° μ‚¬μ΄μ¦ˆ 좔적
  useEffect(() => {
    function handleWindowResize() {
      setWindowSize(getWindowSize());
    }
    window.addEventListener("resize", handleWindowResize);
    return () => {
      window.removeEventListener("resize", handleWindowResize);
    };
  }, []);

  function getWindowSize() {
    const { innerWidth, innerHeight } = window;
    return { innerWidth, innerHeight };
  }

  return (
    <>
      <Wrap>
        <TitleWrap>
          <SmileIcon>πŸ’ͺ</SmileIcon>
          {windowSize.innerWidth > 760 ? (
            <Title>
              μž‘λ…„μ— λΉ„ν•΄ μ˜¬ν•΄ μž‘μ—… μ‹œκ°„μ΄ <br />
              {rateData.rate ? count + "%" : "0%"}{" "}
              {rateData.rateText ? rateData.rateText : "증가"}
              ν–ˆμ–΄μš”
            </Title>
          ) : (
            <TitleM>
              μž‘λ…„μ— λΉ„ν•΄ <br /> μ˜¬ν•΄ μž‘μ—… μ‹œκ°„μ΄ <br />
              {rateData.rate ? count + "%" : "0%"}{" "}
              {rateData.rateText ? rateData.rateText : "증가"}
              ν–ˆμ–΄μš”
            </TitleM>
          )}
        </TitleWrap>
        {is_loaded ? (
          <WorkTimeBarChart workTimeData={workTimeData} />
        ) : (
          <ShimmerThumbnail className="thumNail-weather" height={160} rounded />
        )}
      </Wrap>
    </>
  );
};

const Wrap = styled.div`
  background: #ffffff;
  box-shadow: 0px 2px 3px rgba(0, 0, 0, 0.25);
  border-radius: 10px;
  padding: 20px;
  grid-column: 7 / 10;
  grid-row: 2 / 3;
  display: flex;
  flex-direction: column;
  justify-content: space-between;

  @media only screen and (max-width: 760px) {
    padding: 20px 20px 30px 20px;
    grid-column: 2 / 3;
    grid-row: 3 / 4;
  }
`;
// 6️⃣ 투λͺ…ν–ˆλ‹€κ°€ μœ„λ‘œ 슀λ₯΄λ₯΅ μ˜¬λΌμ˜€λŠ” μ• λ‹ˆλ©”μ΄μ…˜
const boxFade = keyframes`
  0% {
    opacity: 0;
    transform: translateY(10%);
 
  }
  30% {
    opacity: 0.3;
    transform: translateY(6%);
  }
  100% {
    opacity: 1;
    transform: translateY(0);
  }
`;

const TitleWrap = styled.div`
  display: flex;
  flex-direction: row;
  animation: ${boxFade} 1s;
`;

const SmileIcon = styled.span`
  font-size: 24px;
`;

const Title = styled.span`
  font-size: 24px;
  font-weight: 700;
  margin-left: 10px;
  text-align: left;
`;

const TitleM = styled.span`
  font-size: 24px;
  font-weight: 700;
  margin-left: 10px;
  text-align: left;
  margin-bottom: 30px;
`;

export default WorkTime;

μž‘μ—…μ‹œκ°„ μΉ΄λ“œ ν•˜λ‚˜μ—λ„ λ§Žμ€ λ””ν…ŒμΌμ— 신경썼닀 😌

1️⃣ μ¦κ°€μœ¨/κ°μ†Œμœ¨ 숫자 μΉ΄μš΄νŒ… μ• λ‹ˆλ©”μ΄μ…˜

2️⃣ 전체 λ¬Έμž₯이 투λͺ…ν–ˆλ‹€κ°€ μœ„λ‘œ 슀λ₯΄λ₯΅ μ˜¬λΌμ˜€λŠ” μ• λ‹ˆλ©”μ΄μ…˜ 적용

3️⃣ μž‘μ—…μ‹œκ°„ λ°” κ·Έλž˜ν”„ - 데이터 λ‘œλ”© 쀑일 λ•Œ shimmer Effect 적용

4️⃣ window μ‚¬μ΄μ¦ˆ μΆ”μ μœΌλ‘œ λͺ¨λ°”일 μ „μš© λ¬Έμž₯ μ€„λ°”κΏˆ 적용

post-custom-banner

0개의 λŒ“κΈ€