2
\$\begingroup\$

I recently completed the Multi-Step Form Challenge on Frontend Mentor using React, and I'm eager to receive constructive feedback on my code. I've put in a lot of effort to make the form functional, responsive, and user-friendly, but I believe there's always room for improvement. Your insights and suggestions would be greatly appreciated. I'm particularly interested in your thoughts on code structure, best practices, and potential optimizations.

Index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
    <React.StrictMode>
      <App />
    </React.StrictMode>
);

App.js

import './App.css';
import React, {useState} from 'react';
import Header from './components/Header';
import Card1 from './components/Card1';
import Card2 from './components/Card2';
import Card3 from './components/Card3';
import Card4 from './components/Card4';
import Card5 from './components/Card5';

function App() {

  const [display, setDisplay] = useState(1);
  const [details, setDetails] = useState({});
  const [plan, setPlan] = useState("");
  const [mode, setMode] = useState("Monthly");
  const [addOns, setAddOns] = useState([]);

  const handleUserDetails = (name, email, phone) =>{
    setDetails({name, email, phone});
  }

  const capitalizeFirstWord = (str) => !str ? str : str.charAt(0).toUpperCase() + str.slice(1);

  const handlePlanSelection = (plan) => {
    setPlan(plan);
  }

  const handleModeSelection = (slider) => {
    if (slider === 1) setMode("Monthly");
    else setMode("Yearly");
  }

  const handleAddOnSelection = (addOn) => {
    addOn = capitalizeFirstWord(addOn);
    setAddOns((prev) => {
      if (prev.includes(addOn)) return prev.filter((item) => item !== addOn);
      else return [...prev, addOn];
    });
  };
  
  const handleNextClick = () => {
    setDisplay(display + 1);
  };

  const handleGoBackClick = () => {
    setDisplay(display - 1);
  };

  const handlePlanChange = () => {
    if (window.confirm("Are you sure you want to change plan.")) setDisplay(2);
  }

  return (
    <div className="App">
      <Header step={display}/>
      <Card1 status={display} handleDetails={handleUserDetails} onNextClick={handleNextClick} onGoBackClick={handleGoBackClick}/>
      <Card2 status={display} onNextClick={handleNextClick} onGoBackClick={handleGoBackClick} handlePlan={handlePlanSelection} handleMode={handleModeSelection}/>
      <Card3 status={display} onNextClick={handleNextClick} onGoBackClick={handleGoBackClick} handleAddOns={handleAddOnSelection} selectedAddOns={addOns}/>
      <Card4 status={display} onNextClick={handleNextClick} onGoBackClick={handleGoBackClick} selectedPlan={plan} selectedAddOns={addOns} selectedMode={mode} handlePlanChange={handlePlanChange}/>
      <Card5 status={display} onNextClick={handleNextClick} onGoBackClick={handleGoBackClick} userDetails={details}/>
    </div>
  );
}

export default App;

JSX React Components

Header.jsx

import React from "react";

function Header(props) {
    return (
        <div>
            <div className="headerWrapper">
                <div className="headerBubbles" style={{ backgroundColor: (props.step === 1 || props.step === 5) ? 'hsl(206, 94%, 87%)' : 'transparent', color: (props.step === 1 || props.step === 5) ? 'hsl(213, 96%, 18%)' : 'white' }}>1</div>
                <div className="headerBubbles" style={{ backgroundColor: (props.step === 2 || props.step === 5) ? 'hsl(206, 94%, 87%)' : 'transparent', color: (props.step === 2 || props.step === 5) ? 'hsl(213, 96%, 18%)' : 'white' }}>2</div>
                <div className="headerBubbles" style={{ backgroundColor: (props.step === 3 || props.step === 5) ? 'hsl(206, 94%, 87%)' : 'transparent', color: (props.step === 3 || props.step === 5) ? 'hsl(213, 96%, 18%)' : 'white' }}>3</div>
                <div className="headerBubbles" style={{ backgroundColor: (props.step === 4 || props.step === 5) ? 'hsl(206, 94%, 87%)' : 'transparent', color: (props.step === 4 || props.step === 5) ? 'hsl(213, 96%, 18%)' : 'white' }}>4</div>
            </div>
            <div className="headerWrapperDesktop">
                <div className="headerBubblesDesktop" style={{ backgroundColor: (props.step === 1 || props.step === 5) ? 'hsl(206, 94%, 87%)' : 'transparent', color: (props.step === 1 || props.step === 5) ? 'hsl(213, 96%, 18%)' : 'white' }}>1</div>
                <div className="sideHeaderDetails">
                    <h5 className="headerStep">Step 1</h5>
                    <h5 className="headerStepInfo">YOUR INFO</h5><br></br>
                </div>
                <div className="headerBubblesDesktop" style={{ backgroundColor: (props.step === 2 || props.step === 5) ? 'hsl(206, 94%, 87%)' : 'transparent', color: (props.step === 2 || props.step === 5) ? 'hsl(213, 96%, 18%)' : 'white' }}>2</div>
                <div className="sideHeaderDetails">
                    <h5 className="headerStep">Step 2</h5>
                    <h5 className="headerStepInfo">SELECT PLANS</h5><br></br>
                </div>
                <div className="headerBubblesDesktop" style={{ backgroundColor: (props.step === 3 || props.step === 5) ? 'hsl(206, 94%, 87%)' : 'transparent', color: (props.step === 3 || props.step === 5) ? 'hsl(213, 96%, 18%)' : 'white' }}>3</div>
                <div className="sideHeaderDetails">
                    <h5 className="headerStep">Step 3</h5>
                    <h5 className="headerStepInfo">ADD-ONS</h5><br></br>
                </div>
                <div className="headerBubblesDesktop" style={{ backgroundColor: (props.step === 4 || props.step === 5) ? 'hsl(206, 94%, 87%)' : 'transparent', color: (props.step === 4 || props.step === 5) ? 'hsl(213, 96%, 18%)' : 'white' }}>4</div>
                <div className="sideHeaderDetails">
                    <h5 className="headerStep">Step 4</h5>
                    <h5 className="headerStepInfo">SUMMARY</h5><br></br>
                </div>
            </div>
        </div>
    )
}

export default Header;

Card1.jsx

import React, { useState } from "react";

function Card1(props) {
    const [name, setName] = useState("");
    const [email, setEmail] = useState("");
    const [phone, setPhone] = useState("");
    const [isNameValid, setIsNameValid] = useState(true);
    const [isEmailValid, setIsEmailValid] = useState(true);
    const [isPhoneValid, setIsPhoneValid] = useState(true);

    const handleNameChange = (event) => {
        const newName = event.target.value;
        const namePattern = /^[a-zA-Z\s]+$/;
        const isValid = namePattern.test(newName);
        setName(newName);
        setIsNameValid(isValid); 
    };

    const handleEmailChange = (event) => {
        const newEmail = event.target.value;
        const emailPattern = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
        const isValid = emailPattern.test(newEmail);
        setEmail(newEmail);
        setIsEmailValid(isValid);
    };

    const handlePhoneChange = (event) => {
        const newPhone = event.target.value;
        const phonePattern = /^[0-9]{10}$/;
        const isValid = phonePattern.test(newPhone);
        setPhone(newPhone);
        setIsPhoneValid(isValid); 
    };

    const onNextClick = () => {
        if (isNameValid && isEmailValid && isPhoneValid && name !== "" && email !== "" && phone !== "") {
            props.handleDetails(name, email, phone);
            props.onNextClick();
        }
        else alert("Please fill in all fields correctly.");
    };

    return props.status === 1 ? (
        <div>
            <div className="card1">
                <h1>Personal info</h1>
                <p>Please provide your name, email address, and phone number.</p>
                <label>Name</label><br></br>
                {!isNameValid && (<p className="step1Error">Incorrect Name</p>)}
                <input id="name" type="text" placeholder="e.g. Stephen King" value={name} onChange={handleNameChange}/><br></br>
                <label>Email Address</label><br></br>
                {!isEmailValid && (<p className="step1Error">Incorrect Email Address</p>)}
                <input id="email" type="text" placeholder="e.g. [email protected]" value={email} onChange={handleEmailChange}/><br></br>
                <label>Phone Number</label><br></br>
                {!isPhoneValid && (<p className="step1Error">Incorrect Phone Number</p>)}
                <input id="phone" type="text" placeholder="e.g. 9345678900" value={phone} onChange={handlePhoneChange}/>
                <button className="nextBtnDesktop" onClick={onNextClick}>Next Step</button>
            </div>

            <div className="next">
                <button className="nextBtn" onClick={onNextClick}>Next</button>
            </div>
        </div>
    ) : null;
}

export default Card1;

Card2.jsx

import React, {useState} from "react";

function Card2(props) {
    const [selectedPlan, setSelectedPlan] = useState(null);
    const [slider, setSlider] = useState(1);

    const selectBtn = (plan) => {
        setSelectedPlan(plan);
        props.handleMode(slider);
        props.handlePlan(plan);
    }

    const handleSliderClick = () => {
        if (slider === 1) setSlider(2);
        else setSlider(1);
        setSelectedPlan(null);
    }
    
    const handleNextClick = () => {
        if (selectedPlan === null) alert("Select a plan.");
        else props.onNextClick();
    }

    return props.status === 2 ? (
        <div>
            <div className="card2">
                <h1>Select your plan</h1>
                <p>You have the option of monthly or yearly billing.</p>
                <button className={`step2Btn ${selectedPlan === "Arcade" ? "step2BtnSelected" : "step2Btn"}`} onClick={() => selectBtn("Arcade")}>
                    <svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 40 40"><g fill="none" fill-rule="evenodd"><circle cx="20" cy="20" r="20" fill="#FFAF7E" /><path fill="#FFF" fill-rule="nonzero" d="M24.995 18.005h-3.998v5.998h-2v-5.998H15a1 1 0 0 0-1 1V29a1 1 0 0 0 1 1h9.995a1 1 0 0 0 1-1v-9.995a1 1 0 0 0-1-1Zm-5.997 8.996h-2v-1.999h2v2Zm2-11.175a2.999 2.999 0 1 0-2 0v2.18h2v-2.18Z" /></g></svg>
                    <h4>Arcade</h4>
                    <p>{slider === 1 ? "$9/mo" : "$90/yr"}</p>
                    {slider === 2 && (<p id="step2Offer">2 months free</p>)}
                </button>
                <button className={`step2Btn ${selectedPlan === "Advanced" ? "step2BtnSelected" : "step2Btn"}`} onClick={() => selectBtn("Advanced")}>
                    <svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 40 40"><g fill="none" fill-rule="evenodd"><circle cx="20" cy="20" r="20" fill="#F9818E" /><path fill="#FFF" fill-rule="nonzero" d="M25.057 15H14.944C12.212 15 10 17.03 10 19.885c0 2.857 2.212 4.936 4.944 4.936h10.113c2.733 0 4.943-2.08 4.943-4.936S27.79 15 25.057 15ZM17.5 20.388c0 .12-.108.237-.234.237h-1.552v1.569c0 .126-.138.217-.259.217H14.5c-.118 0-.213-.086-.213-.203v-1.583h-1.569c-.126 0-.217-.139-.217-.26v-.956c0-.117.086-.213.202-.213h1.584v-1.554c0-.125.082-.231.203-.231h.989c.12 0 .236.108.236.234v1.551h1.555c.125 0 .231.083.231.204v.988Zm5.347.393a.862.862 0 0 1-.869-.855c0-.472.39-.856.869-.856.481 0 .87.384.87.856 0 .471-.389.855-.87.855Zm1.9 1.866a.86.86 0 0 1-.87-.852.86.86 0 0 1 .87-.855c.48 0 .87.38.87.855a.86.86 0 0 1-.87.852Zm0-3.736a.862.862 0 0 1-.87-.854c0-.472.39-.856.87-.856s.87.384.87.856a.862.862 0 0 1-.87.854Zm1.899 1.87a.862.862 0 0 1-.868-.855c0-.472.389-.856.868-.856s.868.384.868.856a.862.862 0 0 1-.868.855Z" /></g></svg>
                    <h4>Advanced</h4>
                    <p>{slider === 1 ? "$12/mo" : "$120/yr"}</p>
                    {slider === 2 && (<p id="step2Offer">2 months free</p>)}
                </button>
                <button className={`step2Btn ${selectedPlan === "Pro" ? "step2BtnSelected" : "step2Btn"}`} onClick={() => selectBtn("Pro")}>
                    <svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 40 40"><g fill="none" fill-rule="evenodd"><circle cx="20" cy="20" r="20" fill="#483EFF" /><path fill="#FFF" fill-rule="nonzero" d="M26.666 13H13.334A3.333 3.333 0 0 0 10 16.333v7.193a3.447 3.447 0 0 0 2.14 3.24c1.238.5 2.656.182 3.56-.8L18.52 23h2.96l2.82 2.966a3.2 3.2 0 0 0 3.56.8 3.447 3.447 0 0 0 2.14-3.24v-7.193A3.333 3.333 0 0 0 26.666 13Zm-9.333 6H16v1.333a.667.667 0 0 1-1.333 0V19h-1.333a.667.667 0 0 1 0-1.334h1.333v-1.333a.667.667 0 1 1 1.333 0v1.333h1.333a.667.667 0 1 1 0 1.334Zm7.333 2a2.667 2.667 0 1 1 0-5.333 2.667 2.667 0 0 1 0 5.333ZM26 18.333a1.333 1.333 0 1 1-2.667 0 1.333 1.333 0 0 1 2.667 0Z" /></g></svg>
                    <h4>Pro</h4>
                    <p>{slider === 1 ? "$15/mo" : "$150/yr"}</p>                    
                    {slider === 2 && (<p id="step2Offer">2 months free</p>)}
                </button>
                <div className="sliderParent">
                    <h4 className="sliderLabel">Monthly</h4>
                    <div class="slider">
                        <div id="sliderHandle" onClick={handleSliderClick} style={{ left: slider === 1 ? "0%" : "76%" }}></div>
                    </div>
                    <h4 className="sliderLabel">Yearly</h4>
                </div>

                <button className="goBackBtnDesktop" onClick={props.onGoBackClick}>Go Back</button>
                <button className="nextBtnDesktop" onClick={handleNextClick}>Next Step</button>

            </div>

            <div className="next">
                <button className="goBackBtn" onClick={props.onGoBackClick}>Go Back</button>
                <button className="nextBtn" onClick={handleNextClick}>Next</button>
            </div>
        </div>
    ) : null;
}

export default Card2;

Card3.jsx

import React, {useEffect} from "react";

function Card3(props) {
    
    useEffect(() => {
        const selectedAddOns = props.selectedAddOns;
        for (const addon of selectedAddOns) {
          let id;
          if (addon === "Online service") id = "check1";
          else if (addon === "Larger storage") id = "check2";
          else if (addon === "Customizable profile") id = "check3";
          const div = document.getElementById(id);
          if (div) div.style.backgroundColor = 'rgb(173, 190, 255)';
        }
    });
      
    const handleCheckMarkClick = (event) => {
        const div = event.currentTarget; 
        const id = div.id;
        let currentBackgroundColor = div.style.backgroundColor;
        if (currentBackgroundColor === 'rgb(173, 190, 255)') div.style.backgroundColor = 'white';
        else div.style.backgroundColor = 'rgb(173, 190, 255)';
        if (id === 'check1') props.handleAddOns('Online service');
        else if (id === 'check2') props.handleAddOns('Larger storage');
        else props.handleAddOns('Customizable profile');
    }

    return props.status === 3 ? (
        <div>
            <div className="card3">
                <h1>Pick add-ons</h1>
                <p>Add-ons help enhance your gaming experience.</p>
                <button className="step3Btn" >
                    <div className="step3BtnCheck" id="check1" onClick={handleCheckMarkClick}><svg xmlns="http://www.w3.org/2000/svg" width="12" height="9" viewBox="0 0 12 9"><path fill="none" stroke="#FFF" stroke-width="2" d="m1 4 3.433 3.433L10.866 1" /></svg></div>
                    <div className="step3BtnDetails">
                        <h2 className="step3BtnHeading">Online service</h2>
                        <h4 className="step3BtnSubHeading">Access to multiplayer games</h4>
                        <p className="step3BtnPrice">+$1/mo</p>
                    </div>
                </button>
                <button className="step3Btn" >
                    <div className="step3BtnCheck" id="check2" onClick={handleCheckMarkClick}><svg xmlns="http://www.w3.org/2000/svg" width="12" height="9" viewBox="0 0 12 9"><path fill="none" stroke="#FFF" stroke-width="2" d="m1 4 3.433 3.433L10.866 1" /></svg></div>
                    <div className="step3BtnDetails" id="step3BtnSecond">
                        <h2 className="step3BtnHeading">Larger storage</h2>
                        <h4 className="step3BtnSubHeading">Extra 1TB of cloud save</h4>
                        <p className="step3BtnPrice">+$2/mo</p>
                    </div>
                </button>
                <button className="step3Btn" >
                    <div className="step3BtnCheck" id="check3" onClick={handleCheckMarkClick}><svg xmlns="http://www.w3.org/2000/svg" width="12" height="9" viewBox="0 0 12 9"><path fill="none" stroke="#FFF" stroke-width="2" d="m1 4 3.433 3.433L10.866 1" /></svg></div>
                    <div className="step3BtnDetails">
                        <h2 className="step3BtnHeading">Customizable Profile</h2>
                        <h4 className="step3BtnSubHeading">Custom theme on your profile</h4>
                        <p className="step3BtnPrice">+$2/mo</p>
                    </div>
                </button>
                <button className="goBackBtnDesktop" onClick={props.onGoBackClick}>Go Back</button>
                <button className="nextBtnDesktop" onClick={props.onNextClick}>Next Step</button>
            </div>
            
            <div className="next">
                <button className="goBackBtn" onClick={props.onGoBackClick}>Go Back</button>
                <button className="nextBtn" onClick={props.onNextClick}>Next</button>
            </div>
        </div>
    ) : null;
}

export default Card3;

Card4.jsx

import React from "react";

function Card4(props) {
    let addOns = props.selectedAddOns;
    let addOnPrices = ["$1/mo", "$2/mo", "$2/mo"];
    let planValue = "";

    const extractNumberFromString = (inputString) => {
        const regex = /\d+/;
        const match = inputString.match(regex);
        if (match) return parseInt(match[0], 10);
        else return null;
    }

    const handlePlan = (plan, mode) =>{
        if (plan === 'Arcade' && mode === "Monthly") planValue = '$9/mo';
        else if (plan === 'Advanced' && mode === "Monthly") planValue = '$12/mo';
        else if (plan === 'Pro' && mode === "Monthly") planValue = '$15/mo';
        else if (plan === 'Arcade' && mode === "Yearly") planValue = '$90/yr';
        else if (plan === 'Advanced' && mode === "Yearly") planValue = '$120/yr';
        else if (plan === 'Pro' && mode === "Yearly") planValue = '$150/yr';
        return planValue;
    }

    const calculateTotal = () => {
        let total = 0, res = "";
        if (props.selectedMode === "Monthly") {
            total = extractNumberFromString(planValue);
            for (let addOn of addOns) {
                if (addOn === "Online service") total += 1;
                if (addOn === "Larger storage") total += 2;
                if (addOn === "Customizable profile") total += 2;
            }
            res = "+$" + total + "/mo";
        }
        else {
            total = extractNumberFromString(planValue);
            for (let addOn of addOns) {
                if (addOn === "Online service") total += 10;
                if (addOn === "Larger storage") total += 20;
                if (addOn === "Customizable profile") total += 20;
            }
            res = "+$" + total + "/yr";
        }
        return res;
    }

    return props.status === 4 ? (
        <div>
            <div className="card4">
                <h1>Finishing up</h1>
                <p>Double-check everything looks OK before confirming.</p>
                <div className="planSummaryBox">
                    <h4 className="step4PlanName">{props.selectedPlan} ({props.selectedMode})</h4>
                    <h4 id="planValue">{handlePlan(props.selectedPlan, props.selectedMode)}</h4><br></br>
                    <button id="changePlanBtn" onClick={props.handlePlanChange}>Change</button>
                    <hr />
                    {addOns.map((addOn, index) => (
                        <div key={index}>
                            <h5>{addOn}</h5>
                            <h5 className="step4AddOnValue">{addOn === "Online service" ? addOnPrices[0] : addOn === "Larger storage" ? addOnPrices[1] : addOnPrices[2]}</h5>
                        </div>
                    ))}
                </div>
                <h5 className="step4Total">Total (per {props.selectedMode === "Monthly" ? 'month' : 'year'})</h5>
                <h4 className="step4TotalValue">{calculateTotal()}</h4><br></br>
                <button className="goBackBtnDesktop" onClick={props.onGoBackClick} style={{marginTop: "5%"}}>Go Back</button>
                <button className="nextBtnDesktop" onClick={props.onNextClick} style={{marginTop: "5%"}}>Confirm</button>
            </div>

            <div className="next">
                <button className="goBackBtn" onClick={props.onGoBackClick}>Go Back</button>
                <button className="nextBtn" onClick={props.onNextClick}>Confirm</button>
            </div>
        </div>
    ) : null;
}

export default Card4;

Card5.jsx

import React from "react";

function Card5(props){
    return props.status === 5 ? (
        <div className="card5">
            <div className="thankYouBox">
                <svg xmlns="http://www.w3.org/2000/svg" width="80" height="80" viewBox="0 0 80 80"><g fill="none"><circle cx="40" cy="40" r="40" fill="#F9818E"/><path fill="#E96170" d="M48.464 79.167c.768-.15 1.53-.321 2.288-.515a40.04 40.04 0 0 0 3.794-1.266 40.043 40.043 0 0 0 3.657-1.63 40.046 40.046 0 0 0 12.463-9.898A40.063 40.063 0 0 0 78.3 51.89c.338-1.117.627-2.249.867-3.391L55.374 24.698a21.6 21.6 0 0 0-15.332-6.365 21.629 21.629 0 0 0-15.344 6.365c-8.486 8.489-8.486 22.205 0 30.694l23.766 23.775Z"/><path fill="#FFF" d="M40.003 18.333a21.58 21.58 0 0 1 15.31 6.351c8.471 8.471 8.471 22.158 0 30.63-8.47 8.47-22.156 8.47-30.627 0-8.47-8.472-8.47-22.159 0-30.63a21.594 21.594 0 0 1 15.317-6.35Zm9.865 15c-.316.028-.622.15-.872.344l-12.168 9.13-5.641-5.642c-1.224-1.275-3.63 1.132-2.356 2.356l6.663 6.663c.56.56 1.539.63 2.173.156l13.326-9.995c1.122-.816.43-2.993-.956-3.013a1.666 1.666 0 0 0-.17 0Z"/></g></svg>
                <h1>Thank you!</h1>
                <p>Thanks for confirming your subscription! We hope you have fun using our platform. If you ever need support, please feel free to email us at [email protected].</p>
            </div>
        </div>
    ) : null;
}

export default Card5;

App.css

body {
  background-image: url(../assets/images/bg-sidebar-mobile.svg);
  background-repeat: no-repeat;
  background-size: 100% auto; 
  background-position: top center; 
  background-attachment: fixed;
  background-color: hsl(205, 46%, 92%);
  font-family: 'Ubuntu', sans-serif;
}

h1{
  color: hsl(213, 96%, 18%);
}

h4{
  color: hsl(213, 96%, 18%);
  margin: 0%;
}

h5{
  margin: 2%;
  color: gray;
  font-weight: lighter;
  display: inline-block;
  margin-left: 1%;
}

hr{
  border: solid gray 1px;
  margin: 5%;
}

label{
  color: hsl(213, 96%, 18%);
  font-weight: bold;
}

p{
  color: grey;
}

input{
  margin-bottom: 3%;
  cursor: pointer;
  padding: 2%;
  width: 70%;
}

.headerWrapper{
  display: block;
  width: 90%;
  margin: 5% 10% 0% 10%;
}

.headerWrapperDesktop{
  display: none;
}

.headerBubbles{
  display: inline-flex; 
  justify-content: center; 
  align-items: center; 
  font-size: 1rem;
  font-weight: bolder;
  border-radius: 100%;
  border: white solid 1.5px;
  color: white;
  margin: 2% 5% 0% 5%;
  padding: 4%;
  width: 1rem; 
  height: 1rem;
}

.card1, .card2, .card3, .card4, .card5{
  width: 70%;
  border-radius: 5%;
  z-index: 1;
  background-color: white;
  margin: 15% 10% 0% 10%;
  line-height: 25px;
  padding: 5%;
}

.card3{
  margin: 5% 10% 0% 10%;
}

.card5{
  text-align: center;
  padding: 10%;
  margin: 10% 5% 0% 5%;
}

.step1Error{
  color: red;
  display: inline;
  margin-left: 0%;
}

.step2Btn{
  display: block;
  width: 100%;
  padding: 2%;
  cursor: pointer;
  background-color: white;
  margin-bottom: 5%;
}

#step2Offer{
  margin-left: 15%;
  font-weight: bolder;
  color: hsl(213, 96%, 18%);
  text-align: center
}

.step2Btn svg{
  float: left;
  margin-right: 0%;
}

.step2Btn h4, .step2Btn p{
  margin: 3%;
}

.step2Btn:hover{
  background-color: aliceblue;
}

.step2BtnSelected{
  border-color: hsl(213, 96%, 18%);
  background-color: hsl(228, 100%, 84%);
}

.sliderParent {
  background-color: hsl(227, 85%, 92%);
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 10%;
}

.sliderLabel {
  color: hsl(213, 96%, 18%);
  font-weight: bolder;
  flex: 1;
  text-align: center;
}

.slider {
  flex: 0.3;
  position: relative;
  height: 10px;
  background-color: hsl(213, 96%, 18%);
  border-radius: 5px;
  margin-top: 1px;
}

#sliderHandle {
  width: 20px;
  height: 20px;
  background-color: #fff;
  border-radius: 50%;
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  cursor: pointer;
  transition: left 0.2s ease-in-out;
}

.step3Btn{
  display: block;
  width: 100%;
  background-color: white;
  padding: 3%;
  margin: 5% 0% 5% 0%;
  border: gray solid 0.1px;
  border-radius: 3%;
}

.step3BtnDetails{
  float: right;
}

.step3BtnCheck{
  display: inline-flex; 
  justify-content: center; 
  align-items: center; 
  float: left;
  background-color: white;
  width: 20px;
  height: 20px;
  border: gray solid 0.1px;
}

.step3BtnHeading{
  float: left;
  margin: 2%;
  display: inline-flex;
  color: hsl(213, 96%, 18%);
}

.step3BtnSubHeading{
  float: left;
  margin: 2%;
  display: inline-flex;
  color: gray;
}

.step3BtnPrice{
  float: right;
  color: hsl(228, 100%, 84%);
}

.planSummaryBox{
  background-color: hsl(208, 65%, 95%);
  color: hsl(213, 96%, 18%);
  padding: 5%;
  margin-bottom: 5%;
}

#changePlanBtn{
  color: gray;
  text-decoration: underline;
  border: none;
  background-color: hsl(206, 94%, 87%);
  margin: 0%;
  display: inline-block;
  cursor: pointer;
}

.step4PlanName{
  display: inline-flex;
  float: left;
}

#planValue{
  display: inline-flex;
  float: right;
}

.step4AddOnValue{
  display: inline;
  float: right;
  color: hsl(213, 96%, 18%);
}

.step4Total{
  margin: 5%;
  color: gray;
  font-weight: bold;
  display: inline;
}

.step4TotalValue{
  display: inline;
  margin-left: 25%;
  color: hsl(243, 100%, 62%);
}

.next{
  position: fixed;
  display: block;
  background-color: white;
  width: 90%;
  bottom: 0%;
  padding: 5%;
}

.goBackBtn{
  margin-top: 4%;
  color: gray;
  border: none;
  background-color: white;
}

.nextBtn{
  background-color: hsl(213, 96%, 18%);
  color: white;
  padding: 2%;
  width: 25%;
  font-size: large;
  float: right;
}

.nextBtnDesktop, .goBackBtnDesktop{
  display: none;
}

/* Desktop CSS */

@media only screen and (min-width: 700px) {
  body{
    background: none;
    background-color: white;
    overflow: hidden;
  }
  .headerWrapperDesktop{
    display: block;
    background-image: url(../assets/images/bg-sidebar-desktop.svg);
    background-repeat: no-repeat;
    height: 87vh;
    float: left;
    padding: 2%;
    border-radius: 3%;
    width: 15%;
    margin: 1% 0% 0% 1%;
  }
  .headerWrapper{
    display: none;
  }
  .headerBubblesDesktop{
    display: inline-flex; 
    justify-content: center; 
    align-items: center; 
    font-size: 1rem;
    font-weight: bolder;
    border-radius: 100%;
    border: white solid 1.5px;
    color: white;
    margin: 2% 5% 0% 5%;
    padding: 4%;
    width: 1rem; 
    height: 1rem;
  }
  .sideHeaderDetails {
    display: inline-flex;
    flex-direction: column;
    width: 50%;
    margin: 0% 0% 2% 2%;
  }
  .headerStep{
    width: 100%;
    color: white;
    margin: 0%;
    font-weight: lighter;
  }
  .headerStepInfo{
    width: 100%;
    color: white;
    margin: 0%;
    margin-top: 2%;
  }
  .card1, .card2, .card3, .card4, .card5{
    width: 50%;
    border-radius: 0%;
    margin: 0% 0% 0% 30%;
    padding: 2%;
  }
  input{
    width: 100%;
    height: 2rem;
  }
  .step2Btn{
    display: inline-block;
    width: 25%;
    margin: 3% 5% 5% 3%;
    padding: 3%;
    cursor: pointer;
  }
  .step2Btn svg{
    float: left;
    margin: 2% 0% 2% 0%;
  }
  #step2Offer{
    margin-left: 30%;
  }
  .sliderParent{
    margin: 2% 0% 5% 0%;
  }
  .step3Btn{
    width: 80%;
    padding: 2%;
    margin: 0% 0% 2% 0%;
    border: gray solid 0.1px;
    border-radius: 2%;
    height: fit-content;
  }
  .step3BtnDetails{
    display: inline-flex;
    flex-direction: column;
    float: left;
    margin: 0% 10% 0% 25%;
  }
  #step3BtnSecond{
    margin-left: 30%;
  }
  .step3BtnHeading{
    margin: 0% 0% 0% 5%;
    justify-content: center; 
    align-items: center; 
  }
  .step3BtnSubHeading{
    display: inline-flex;
    margin: 1%;
  }
  .step3BtnPrice{
    margin: 0%;
  }  
  .planSummaryBox{
    margin-bottom: 3%;
    padding: 3%;
  }
  .step4Total{
    margin: 5%;
    display: inline;
  }
  .step4TotalValue{
    display: inline;
    margin-left: 60%;
    font-size: 1.2rem;
  }
  .thankYouBox{
    margin-top: 20%;
  }
  .next{
    display: none;
  }
  .nextBtnDesktop{
    display: block;
    border-radius: 4%;
    background-color: hsl(257, 89%, 59%);
    color: white;
    padding: 2%;
    width: 25%;
    font-size: medium;
    float: right;
  }
  .goBackBtnDesktop{
    display: inline-block;
    margin-top: 2%;
    color: gray;
    border: none;
    background-color: white;
  }
}

Live Site URL - Click Here

Source Repo - Click Here

\$\endgroup\$
2
  • \$\begingroup\$ I didn't add the tag programming-challenge though it could be added if desired over one of the existing tags. Per its guidance: "Use this tag when the code is a solution to a programming challenge. Always include a sufficient description of the problem to be solved - while a link to the challenge is welcome, the review request needs to be complete when the challenge site is unavailable." (emphasis mine) \$\endgroup\$ Oct 4, 2023 at 17:35
  • 1
    \$\begingroup\$ One thing that can improve the UX, is to make the "Pick add-ons" boxes clickable instead of just relying on the small checkboxes. \$\endgroup\$ Jan 30 at 16:43

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.