0

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]));
        }}
    />
);
ParisaN
  • 1,816
  • 2
  • 23
  • 55

2 Answers2

1

Well, you can use useEffect hook for resending the code when the progress bar finishes.

You can put resend as a dependency in useEffect so whenever the value of resend updates or changes useEffect will get called.

Example:

 useEffect(() => {
    //reset your state to initial state.
 }, [resend])
Dharmik Patel
  • 1,041
  • 6
  • 12
  • I try this but LinearProgress does not progress. I set this codes in useEffect: `setCounterRemained(waitingTime); setCurrentTime(Date.now() + counterRemained); setResend(true);` – ParisaN Mar 07 '22 at 20:56
0

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;
            }}
        />
    </>
);
ParisaN
  • 1,816
  • 2
  • 23
  • 55