Search code examples
reactjsprogress-barcountdown

Reset LinearProgress countdown by click on the button in ReactJs


Intro: In the part of my reactjs app, after entering mobile number, a pin code is send to the user and then a modal is open and user should enter pin code. In this modal there is a countdown that render a progress-bar for waiting time.

Problem: After complete progress (For example, the user has not entered a pin or received a message), resend button is appears and if user click on, this progress should be reset.

Question: How to reset progress-bar by clicking on the button? Or How to reset component with initial states?

Code: CounterProgress

import React, { useEffect, useState } from 'react'
import Countdown from "react-countdown";
import { Button, LinearProgress,} from "@material-ui/core";


function CounterProgress() {

    const waitingTime = 10000;
    const [counterRemained, setCounterRemained] = useState(waitingTime);
    const [currentTime, setCurrentTime] = useState(Date.now() + counterRemained);
    const [resend, setResend] = useState(true);


    const counterRenderer = ({ minutes, seconds, completed, total }) => {
        setCounterRemained(total)
        const mainMin = waitingTime;
        const onePercent = mainMin / 100;
        const leftedPercent = total / onePercent;
        
        return (
            resend ? (
                <>
                    <LinearProgress
                        variant="determinate"
                        value={leftedPercent}
                        dir="ltr"
                        style={{ height: "0.7rem", borderRadius: "10px" }}
                        className={` w-75 mx-auto`}
                    />
                    <div style={{
                        display: "block",
                        marginLeft: "auto",
                        marginRight: "auto",
                    }}>
                        <Button
                            disabled={true}
                            style={counterRemained === 0 ? { textColor: "#6dd06d" } : {}}
                        >
                            resend code
                        </Button>
                        <span style={{ textColor: "black", fontSize: "10px" }}>{minutes}:{seconds}</span>
                    </div>
                </>

            ) : (
                <>
                    <Button
                        style={counterRemained === 0 ? { textColor: "#6dd06d" } : {}}
                        onClick={() => setResend(true)}

                    >
                        resend code
                    </Button>
                </>
            )

        );

    };   

    return (
        <Countdown
            date={currentTime}
            renderer={counterRenderer}
            onComplete={() => {
                setResend(false);
            }}
        />
    );
}

export default CounterProgress;

This code work when user click button but progress-bar is not reset and does not work.

My solutions but do not works:

  1. Reset CounterProgress component using force update.
  2. Using key option inside countdown. This method is working automatically and without onClick.

Using key option:

const [times, setTimes] = useState([Date.now() + waitingTime, Date.now() + 2 * waitingTime]);
const [currentTimeIndex, setCurrentTimeIndex] = useState(0);

return (
    <Countdown
        date={currentTime}
        key={currentTimeIndex}
        renderer={counterRenderer}
        onComplete={() => {
            console.log("completed", currentTimeIndex)
            if (times.length - 1 <= times.indexOf(currentTime)) return;
            setCurrentTimeIndex(currentTimeIndex + 1);
            setCurrentTime(new Date(times[currentTimeIndex + 1]));
        }}
    />
);

Solution

  • I used key option for countdown. I made resend state as a state three values (-1, 0, 1).

    The part of code that changed:

    const waitingTime = 120000;
    
    const [counterRemained, setCounterRemained] = useState(waitingTime);
    const [times, setTimes] = useState([Date.now() + waitingTime, Date.now() + 2 * waitingTime]);
    const [currentTime, setCurrentTime] = useState(Date.now() + counterRemained);
    const [currentTimeIndex, setCurrentTimeIndex] = useState(0);
    const [resend, setResend] = useState(-1);
    
    
    
    useEffect(() => {
        // resend sms to user
        if (resend === 0) { // by clicking on the button, resend be 0
            setResend(-1) // for initializing
            setCurrentTimeIndex(currentTimeIndex + 1);
            setCurrentTime(new Date(times[currentTimeIndex + 1]));
        }
    
    }, [resend])
    
    return (
        <>
            <Countdown
                date={currentTime}
                key={currentTimeIndex}
                renderer={counterRenderer}
                onComplete={() => {
                    if (times.length - 1 <= times.indexOf(currentTime)) return;
                }}
            />
        </>
    );