Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Password UI component #292

Merged
merged 13 commits into from
Aug 20, 2024
Merged
4 changes: 4 additions & 0 deletions src/assets/Languages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,10 @@
"single-step": "Single step",
"multiple-steps": "Multiple steps",
"There are no rooms yet": "There are no rooms yet",
"Enter your 4-digit passcode to unlock group access": "Enter your 4-digit passcode to unlock group access",
"Bravo! Your passcode is correct. Welcome aboard!": "Bravo! Your passcode is correct. Welcome aboard!",
"Something went wrong. Please try again!": "Something went wrong. Please try again!",
"Submit": "Submit",
"Click on": "Click on",
"Add suggestion button": "Add suggestion button",
"to add your suggestion": "to add your suggestion",
Expand Down
4 changes: 4 additions & 0 deletions src/assets/Languages/he.json
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,10 @@
"single-step": "שלב אחד",
"multiple-steps": "מספר שלבים",
"There are no rooms yet": "אין עדיין חדרים",
"Enter your 4-digit passcode to unlock group access": "הזן את קוד הסיסמה בן 4 הספרות שלך כדי לבטל את נעילת הגישה לקבוצה",
"Bravo! Your passcode is correct. Welcome aboard!": "בראבו! קוד הגישה שלך נכון. ברוכים הבאים!",
"Something went wrong. Please try again!": "משהו השתבש. בבקשה נסה שוב!",
"Submit": "שלח",
"Click on": "תלחץ על",
"Add suggestion button": "הוסף פתרון",
"to add your suggestion": "כדי להוסיף את הפתרון שלך",
Expand Down
Binary file added src/assets/images/passwordUiImgBlue.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/images/passwordUiImgGreen.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/images/passwordUiImgRed.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
60 changes: 60 additions & 0 deletions src/view/components/passwordUi/PasswordInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { useRef, Dispatch, SetStateAction, useEffect, useState } from 'react';
import styles from "./passwordUi.module.scss";

interface PasswordProps {
passwordLength: 4;
values: string[],
handleSubmit: () => void
setValues: Dispatch<SetStateAction<string[]>>
}

const PasswordInput = ({ handleSubmit, passwordLength: length, values, setValues }: PasswordProps) => {
const inputs = useRef<(HTMLInputElement | null)[]>([]);
const [isSubmitted, setIsSubmitted] = useState(false)

const handleChange = (event: React.ChangeEvent<HTMLInputElement>, index: number) => {
const val = event.target.value;
if (/^[0-9]$/.test(val) || val === '') {
const newValues = [...values];
newValues[index] = val;
setValues(newValues);
if (val && index < length - 1) {
inputs.current[index + 1]?.focus();
}
}
}

const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>, index: number) => {
if (event.key === "Backspace" && !values[index] && index > 0) {
inputs.current[index - 1]?.focus();
}
}

useEffect(() => {
if (values.every((val => val !== '')) && (!isSubmitted)) {
setIsSubmitted(true)
handleSubmit();
}
else {
setIsSubmitted(false)
}
}, [values, handleSubmit]);

return (
<div className={styles.passwordUi__inputSection} >
{values.map((val, index) => (
<input
key={index}
ref={(element) => { inputs.current[index] = element }}
maxLength={1}
type="text"
value={val}
onKeyDown={(event) => handleKeyDown(event, index)}
onChange={(event) => handleChange(event, index)}
/>
))}
</div>
);
};

export default PasswordInput;
109 changes: 109 additions & 0 deletions src/view/components/passwordUi/PasswordUi.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
"use client"
import { Dispatch, SetStateAction, useState } from "react"
import { useNavigate } from "react-router-dom"

//styles
import styles from "./passwordUi.module.scss"

//images
import passwordUiImgBlue from "../../../assets/images/passwordUiImgBlue.png"
import passwordUiImgRed from "../../../assets/images/passwordUiImgRed.png"
import passwordUiImgGreen from "../../../assets/images/passwordUiImgGreen.png"

//custom components
import Button from "../buttons/button/Button"
import PasswordInput from "./PasswordInput.tsx"
import { useLanguage } from "@/controllers/hooks/useLanguages";


interface PasswordProps {
setPasswordCheck: Dispatch<SetStateAction<boolean>>,
}

function PasswordUi({ setPasswordCheck }: PasswordProps) {

const navigate = useNavigate();
const { t } = useLanguage()

const PASSWORD_CODE = 7538
const PASSWORD_LENGTH = 4
const MAX_TRIES = 3;

const [triesCounter, setTriesCounter] = useState(MAX_TRIES)
const [values, setValues] = useState(Array(PASSWORD_LENGTH).fill(''));
const [passwordState, setPasswordState] = useState({
img: passwordUiImgBlue,
text: t("Enter your 4-digit passcode to unlock group access"),
textStyle: styles.passwordUi__statusSection__passwordTextDefault
});

function handleSubmit() {

const enteredCode = Number(values.join(""));

try {
if (enteredCode === PASSWORD_CODE) {
setPasswordState({
img: passwordUiImgGreen,
text: t(`Bravo! Your password is correct. Welcome aboard!`),
textStyle: styles.passwordUi__statusSection__passwordTextCorrect
});

setTimeout(() => {
setPasswordCheck(true);
}, 1000);

} else {
setPasswordState({
img: passwordUiImgRed,
text: t(`Something went wrong. Please try again!`),
textStyle: styles.passwordUi__statusSection__passwordTextIncorrect
});

setTriesCounter(prev => {
const newTriesCounter = prev - 1;
if (newTriesCounter <= 0) {
navigate("/401");
}

return newTriesCounter;
});
}
}
catch (err) {
console.error(err)
}
}


return (
<div className={styles.passwordUi}>
<div className={styles.passwordUi__imageSection}>
<img src={passwordState.img} />
</div>

<div className={styles.passwordUi__statusSection}>
<p className={passwordState.textStyle}>{passwordState.text}
</p>
</div>

<div className={styles.passwordUi__inputSection}>
<PasswordInput handleSubmit={handleSubmit} passwordLength={PASSWORD_LENGTH} values={values} setValues={setValues} />
</div>

<div className={styles.passwordUi__triesLeft}>
<p>Tries Left = {triesCounter}</p>
</div>

<div className={styles.passwordUi__buttonSection}>
<Button
text={t('Submit')}
onClick={() => handleSubmit()}
className="btn btn--affirmation"
/>
</div>
</div>
)
}

export default PasswordUi
79 changes: 79 additions & 0 deletions src/view/components/passwordUi/passwordUi.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
@import url("https://fonts.googleapis.com/css2?family=Bellefair&display=swap");

.passwordUi {
width: 23rem;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;

&__imageSection {
img {
width: 15rem;
height: 16rem;
}
}

&__statusSection {
margin-top: 4rem;
line-height: 1.5rem;
width: 15rem;

p {
font-size: 1.1rem;
text-align: center;
font-weight: 400;
}

&__passwordTextDefault {
color: var(--h2Color);
}
&__passwordTextIncorrect {
color: var(--incorrectText);
}
&__passwordTextCorrect {
color: var(--correctText);
}
}

&__inputSection {
direction: ltr;
margin-top: 1rem;
display: flex;
gap: 0.7rem;
border-radius: 2px;
width: 15rem;
height: 4rem;

input {
font-family: "Bellefair";
align-items: center;
text-align: center;
font-size: 2.1rem;
font-weight: 400;
color: white;
background-color: var(--button-blue);
}
}

&__triesLeft {
margin-top: 4rem;
line-height: 1.5rem;
width: 15rem;

p {
font-size: 1rem;
text-align: center;
font-weight: 400;
}
}

&__buttonSection {
margin-top: 4rem;

button {
justify-content: center;
width: 12.5vw;
}
}
}
Loading
Loading