Skip to content

Commit

Permalink
feat:update project structure and refactor code (#32)
Browse files Browse the repository at this point in the history
  • Loading branch information
NkwaTambe authored Oct 24, 2024
2 parents f003c26 + 4f4ec2b commit 8605c0b
Show file tree
Hide file tree
Showing 10 changed files with 113 additions and 93 deletions.
16 changes: 13 additions & 3 deletions src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,10 @@ button:hover {
/* Countdown text styles */
.countdown-text {
display: flex;
justify-content: space-between;
justify-content: center;
margin: 24px 0px;
display: flex;
flex-direction: column; /* Stacks the elements vertically */
justify-content: center;
align-items: center;
margin-top: 20px;
font-size: 16px;
Expand All @@ -57,15 +56,26 @@ button:hover {
font-weight: 400;
color: #2d1d35;
margin-bottom: 20px;
text-align: center;
}

/* Countdown text button styles */
.countdown-text > button {
.countdown-text button {
background-color: #fff;
border: none;
font-weight: 500;
text-decoration: underline;
cursor: pointer;
margin-top: 10px;
}
.countdown-wrapper button {
background-color: #fff;
border: none;
font-weight: 500;
text-decoration: underline;
cursor: pointer;
margin-left: 5px; /* Adjust spacing between text and button */
padding: 0;
}

/*Styling for Register Page */
Expand Down
75 changes: 4 additions & 71 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,83 +1,16 @@
import { useEffect, useState } from "react";
import OtpInput from "./pages/OtpInput.tsx";
import "./App.css";
import Register from "./pages/Register.tsx";
import Register from "./pages/RegisterPage.tsx";
import Otp from "./pages/OtpPage.tsx";

export default function App() {
//State variables to manage OTP inputs , minutes and seconds
const [otp, setOtp] = useState("1234");
const onChange = (value: string) => setOtp(value);
const [minutes, setMinutes] = useState(0);
const [seconds, setSeconds] = useState(30);

//Function to resend OTP
const resendOTP = () => {
setMinutes(1);
setSeconds(30);
};

useEffect(() => {
const interval = setInterval(() => {
//Decrease seconds if greater than 0
if (seconds > 0) {
setSeconds(seconds - 1);
}

//When seconds reach 0 , decrease minutes if greater than 0
if (seconds === 0) {
if (minutes === 0) {
//Stop the countdown when both minutes and seconds are 0
clearInterval(interval);
} else {
//Reset seconds to 59 and decrease minutes by 1
setSeconds(59);
setMinutes(minutes - 1);
}
}
}, 1000);
return () => {
//Cleanup:stop the interval when the component unmounts
clearInterval(interval);
};
}, [seconds, minutes]); //Re-run this effect whenever 'seconds' changes

return (
<>
<div>
<Register />;
</div>
<div className="container">
<h1>OTP Verification</h1>
<h4>Enter the verification code we just sent to your phone number</h4>
<OtpInput value={otp} valueLength={4} onChange={onChange} />
<button>Verify</button>
</div>

<div className="countdown-text">
<p>
Resend OTP in {""}
<span style={{ fontWeight: 600 }}>
{minutes < 10 ? `0${minutes}` : minutes}:
{seconds < 10 ? `0${seconds}` : seconds}
</span>
</p>

{/* button to resend OTP */}
<p>
Didn't you receive the OTP?{" "}
<button
disabled={seconds > 0 || minutes > 0}
style={{
color: seconds > 0 || minutes > 0 ? "#DFE3E8" : "#007FFF",
background: "none",
border: "none",
cursor: seconds > 0 || minutes > 0 ? "not-allowed" : "pointer",
}}
onClick={resendOTP}
>
Resend OTP
</button>
</p>
<div>
<Otp />
</div>
</>
);
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/OtpInput.test.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { fireEvent, render, screen } from "@testing-library/react";
import "@testing-library/jest-dom";
import { faker } from "@faker-js/faker";
import OtpInput, { Props } from "../pages/OtpInput.tsx";
import OtpInput, { Props } from "../components/OtpInput.tsx";
import { describe, it, expect, vi } from "vitest";

describe("<OtpInput />", () => {
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/Register.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { render, fireEvent, waitFor } from "@testing-library/react";
import "@testing-library/jest-dom";
import Register from "../pages/Register";
import Register from "../pages/RegisterPage";

describe("Register component", () => {
it("renders correctly", () => {
Expand Down
File renamed without changes.
33 changes: 18 additions & 15 deletions src/pages/OtpInput.tsx → src/components/OtpInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -145,21 +145,24 @@ export default function OtpInput({ value, valueLength, onChange }: Props) {
// Render the OTP input fields
return (
<div>
{valueItems.map((digit, idx) => (
<input
key={idx}
type="text"
inputMode="numeric"
autoComplete="one-time-code"
pattern="\d{1}" // Regex pattern to allow only one digit
maxLength={valueLength}
className="otp-input"
value={digit} // Current value of the input field
onChange={(e) => handleOTPInputChange(e, idx)} // Handle input change
onKeyDown={inputOnKeyDown} // Handle key press events
onFocus={inputOnFocus} // Handle input focus
/>
))}
<div>
{valueItems.map((digit, idx) => (
<input
key={idx}
type="text"
inputMode="numeric"
autoComplete="one-time-code"
pattern="\d{1}" // Regex pattern to allow only one digit
maxLength={valueLength}
className="otp-input"
value={digit} // Current value of the input field
onChange={(e) => handleOTPInputChange(e, idx)} // Handle input change
onKeyDown={inputOnKeyDown} // Handle key press events
onFocus={inputOnFocus} // Handle input focus
/>
))}
</div>
<button>Verify</button>
</div>
);
}
1 change: 1 addition & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export const RE_DIGIT = new RegExp(/^\d+$/);
export const PHONE_NUMBER_REGEX = /^\d*$/; // Allow only digits (empty string is valid for clearing the input)
1 change: 0 additions & 1 deletion src/constants.tsx

This file was deleted.

74 changes: 74 additions & 0 deletions src/pages/OtpPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { useEffect, useState } from "react";
import OtpInput from "../components/OtpInput.tsx";

const Otp = () => {
// State variables to track minutes and seconds
const [otp, setOtp] = useState("");
const onChange = (value: string) => setOtp(value);

const [minutes, setMinutes] = useState(0);
const [seconds, setSeconds] = useState(30);

// Function to reset the countdown timer when OTP is resent
const resendOTP = () => {
setMinutes(1); // Reset minutes to 1
setSeconds(30); // Reset seconds to 30
};

// useEffect to handle the countdown logic
useEffect(() => {
const interval = setInterval(() => {
// Decrease seconds if greater than 0
if (seconds > 0) {
setSeconds(seconds - 1);
}
// If seconds reach 0, and minutes are greater than 0, decrease minutes
else if (minutes > 0) {
setMinutes(minutes - 1);
setSeconds(59); // Reset seconds to 59
}
}, 1000); // Set the interval to 1000ms (1 second)

// Stop the interval when both minutes and seconds reach 0
if (minutes === 0 && seconds === 0) {
clearInterval(interval);
}

// Cleanup: clear the interval when the component unmounts or when seconds/minutes change
return () => clearInterval(interval);
}, [seconds, minutes]); // Dependency array ensures the effect re-runs when 'seconds' or 'minutes' change

return (
<div className="container">
<h1>OTP Verification</h1>
<h4>Enter the verification code we just sent to your phone number</h4>
{/* Render the OTP input */}
<OtpInput value={otp} valueLength={4} onChange={onChange} />
<div className="countdown-text">
<p>
{/* Display countdown timer in mm:ss format */}
Resend OTP in{" "}
<span style={{ fontWeight: 600 }}>
{minutes < 10 ? `0${minutes}` : minutes}:
{seconds < 10 ? `0${seconds}` : seconds}
</span>
</p>
<div className="countdown-wrapper">
<p>Didn't receive the OTP?</p>
<button
disabled={seconds > 0 || minutes > 0}
style={{
color: seconds > 0 || minutes > 0 ? "#DFE3E8" : "#007FFF",
cursor: seconds > 0 || minutes > 0 ? "not-allowed" : "pointer",
}}
onClick={resendOTP}
>
Resend OTP
</button>
</div>
</div>
</div>
);
};

export default Otp;
2 changes: 1 addition & 1 deletion src/pages/Register.tsx → src/pages/RegisterPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { useState } from "react";
import WebankLogo from "../assets/Webank.png";
import countryOptions from "../assets/countries.json";
import parsePhoneNumberFromString from "libphonenumber-js";
import { PHONE_NUMBER_REGEX } from "../constants.tsx";
import { PHONE_NUMBER_REGEX } from "../constants.ts";

type CountryOption = {
value: string;
Expand Down

0 comments on commit 8605c0b

Please sign in to comment.