FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Certification Project: Build a Digital Pet Game - Test #6 not allowing "onChange" handler for pet name · Issue #69604 · freeCodeCamp/freeCodeCamp · GitHub

Certification Project: Build a Digital Pet Game - Test #6 not allowing "onChange" handler for pet name #69604

Description

Describe the Issue

Test #6 has an issue, where you can only set the pet name, when the form is being submitted, not when putting in the pet name with "onChange", which wasn't specified anywhere.

Test #6 has worded it like this: "The second view should contain the provided pet name."
And when using the "onChange" handler inside the "input" element, this should count, which it doesn't.

I have included a comment showing the line of code in the "handleSubmit" event, which shows the line of code which is forced.
And I have included 2 comments showing which piece of code works, but isn't allowed in the input pet-name element.

Affected Page

https://www.freecodecamp.org/learn/front-end-development-libraries-v9/lab-digital-pet-game/lab-digital-pet-game

Your code

index.html:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Digital Pet Game</title>

    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Tektur:wght@400..900&display=swap" rel="stylesheet">

        <link rel="stylesheet" href="styles.css" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.development.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.development.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.26.5/babel.min.js"></script>
    <script
      data-plugins="transform-modules-umd"
      type="text/babel"
      src="index.tsx"
    ></script>
  </head>
  <body>
    <div id="root"></div>
    <script
      data-plugins="transform-modules-umd"
      type="text/babel"
      data-presets="react"
      data-type="module"
    >
      import { PetGame } from './index.tsx';
      ReactDOM.createRoot(document.getElementById('root')).render(<PetGame />);
    </script>
  </body>
</html>

styles.css:

:root {
  /* Backgrounds */
  --bg-gradient-start: #dbeafe;
  --bg-gradient-mid: #faf5ff;
  --bg-gradient-end: #fce7f3;

  /* Text */
  --text-primary: #1f2937;
  --text-muted: #6b7280;
  --text-muted-2: #9ca3af;

  /* Card / surface */
  --card-bg-translucent: rgba(255, 255, 255, 0.6);
  --card-bg-solid: rgba(255, 255, 255, 0.8);

  /* Accent / brand */
  --accent-purple: #8b5cf6;
  --accent-purple-dark: #7c3aed;

  /* Actions */
  --action-feed: #10b981;
  --action-feed-dark: #059669;
  --action-play: #3b82f6;
  --action-play-dark: #2563eb;
  --action-sleep: #8b5cf6;
  --action-sleep-dark: #7c3aed;
  --action-heal: #ec4899;
  --action-heal-dark: #db2777;

  /* Stats */
  --stat-high: #10b981;
  --stat-medium: #f59e0b;
  --stat-low: #ef4444;

  /* UI greys */
  --ui-bg-light: #e5e7eb;
  --ui-fill: #8b5cf6; /* used for exp fill as accent */

  /* Shadows */
  --shadow-strong: rgba(0, 0, 0, 0.25);
  --shadow-soft: rgba(0, 0, 0, 0.1);
}

html {
  /*color-scheme: light dark;*/
  font-family: system-ui;
  display: flex;
  justify-content: center;
  font-family:
    -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu",
    "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  background: linear-gradient(135deg, #dbeafe 0%, #faf5ff 50%, #fce7f3 100%);
  min-height: 100vh;
  padding: 1rem;
}

header {
  text-align: center;
  margin-bottom: 2rem;
}

body {
  max-width: 400px;
}

.base-container {
  background: rgba(255, 255, 255, 0.6);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border-radius: 1.5rem;
  padding: 2rem;
  box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
  .pet-name {
    text-align: center;
  }
}

.game-container {
  margin-bottom: 1.5rem;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

/* Stats Grid */
.stats-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1rem;
  margin-bottom: 1.5rem;
}

.stat-bar {
  background: rgba(255, 255, 255, 0.8);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border-radius: 0.75rem;
  padding: 1rem;
  box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
  transition: all 0.2s ease;
}

.stat-bar:hover {
  box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
}

.stat-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 0.5rem;
}

.stat-label {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.stat-icon {
  font-size: 1.25rem;
}

.stat-name {
  font-weight: 500;
  color: #374151;
}

.stat-value {
  font-weight: bold;
  color: #1f2937;
}

.stat-progress {
  width: 100%;
  height: 0.75rem;
  background: #e5e7eb;
  border-radius: 9999px;
  overflow: hidden;
}

.stat-fill {
  height: 100%;
  transition: width 0.5s ease-out;
  border-radius: 9999px;
}

.stat-fill.high {
  background: #10b981;
}

.stat-fill.medium {
  background: #f59e0b;
}

.stat-fill.low {
  background: #ef4444;
}

.pet-buttons {
  width: auto;
  display: flex;
  flex-direction: row;
  gap: 1rem;
}

.pet-buttons .pet-button {
  min-width: 80px;
  background: #c2214a;
  color: white;
  border-radius: 13%;
  border-style: solid;
  border-color: #870b04;
  box-shadow: rgba(120, 25, 23, 0.2) 2px 2px 4px 2px;
  &:active {
    transform: scale(0.95);
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15) inset;
  }
  text-align: center;
  cursor: pointer;
  padding: 0.5rem 1rem;
}

.pet-sprite {
  font-size: xxx-large;
  text-align: center;
}

.data-management * {
  margin: 0 0.5rem 0 0;
}

.info-panel {
  text-align: center;
}
.info-panel #hud,
.info-panel .start-questions {
  display: flex;
  align-items: center;
  flex-direction: column;
  gap: 1rem;
}

.info-panel #hud p {
  margin: 0rem;
}

.info-panel .start-questions div * {
  margin: 0 0.5rem 0 0;
}

#pet-fact {
  color: var(--text-muted-2);
  margin: 0 0 0.5rem 0;
}
#set-name-btn {
  display: inline-block;
  padding: 14px 28px;
  font-size: 1.15rem;
  font-weight: 600;
  background: linear-gradient(135deg, #6b8cff, #5ec2ff);
  color: #fff;
  border: none;
  border-radius: 10px;
  box-shadow: 0 6px 18px rgba(92, 132, 255, 0.25);
  cursor: pointer;
  transition:
    transform 0.08s ease,
    box-shadow 0.12s ease,
    opacity 0.12s;
}

#set-name-btn:hover {
  opacity: 0.98;
}

#set-name-btn:active,
#set-name-btn.pressed {
  transform: translateY(2px) scale(0.995);
  box-shadow: 0 3px 8px rgba(92, 132, 255, 0.18);
}

#set-name-btn:focus {
  outline: 3px solid rgba(94, 190, 255, 0.28);
  outline-offset: 2px;
}

index.tsx:

const { useState, useEffect } = React;

enum PetMood{
  HAPPY,
  EXCITED,
  CONTENT,
  SAD,
  TIRED,
  SICK,
  HUNGRY
}

const Mood: Record<PetMood, string> = {
  [PetMood.HAPPY]: "😺",
  [PetMood.EXCITED]: "😸",
  [PetMood.CONTENT]: "😼",
  [PetMood.SAD]: "😿",
  [PetMood.TIRED]: "😽",
  [PetMood.SICK]: "🙀",
  [PetMood.HUNGRY]: "😾"
}

export const PetGame = () => {
  const [petName, setPetName] = useState("");
  const [game, setGame] = useState(false);
  const [image, setImage] = useState(Mood[PetMood.EXCITED]);

  const [hunger, setHunger] = useState(0);
  const [happiness, setHappiness] = useState(100);
  const [energy, setEnergy] = useState(100);

  let interval: number;

  useEffect(() => {
    if (!game) return;

    interval = setInterval(() => {
      setHunger(hunger + 10 > 100 ? 100 : hunger + 10);
      setHappiness(happiness - 5 < 0 ? 0 : happiness - 5);
    }, 20000)

    return () => clearInterval(interval);
  }, [game, hunger, happiness, energy]);

  useEffect(() => {
    if (hunger > 70){
      setImage(Mood[PetMood.HUNGRY]);
    } else if(energy < 30){
      setImage(Mood[PetMood.TIRED]);
    } else if(happiness < 30){
      setImage(Mood[PetMood.SAD]);
    } else if(happiness > 80 && energy > 70){
      setImage(Mood[PetMood.EXCITED]);
    } else if(happiness > 60){
      setImage(Mood[PetMood.HAPPY]);
    } else{
      setImage(Mood[PetMood.CONTENT]);
    }
  }, [hunger, happiness, energy]);

  const handleSubmit = (e:SubmitEvent) => {
    e.preventDefault();
    setGame(true);
    // this is being forced
    const input = document.getElementById("pet-name") as HTMLInputElement;
    setPetName(input.value);
  }

  return (
    <>
      {!game ? (
        <div className="base-container info-panel">
          <form
            className="start-questions"
            onSubmit={handleSubmit as any}>
            <label htmlFor="pet-name">Choose your pet name:</label>
            <input
              id="pet-name"
              name="pet-name"
              type="text"
              // this isn't allowed
              // onChange={(e) => setPetName(e.target.value)}
              required
            />
            <button id="set-name-btn" type="submit">Submit</button>
          </form>
        </div>
      ) : (
        <>
          <div className="base-container game-container">
            <div className="pet-screen">
              <div className="pet-sprite">{image}</div>
              <h2 className="pet-name">{petName}</h2>
            </div>

            <div className="pet-buttons">
              <button
                id="eat-action"
                className="pet-button pet-buttons-left"
                onClick={() => {
                  setHunger(hunger - 10 < 0 ? 0 : hunger - 10);
                  setEnergy(energy + 5 > 100 ? 100 : energy + 5);
                }}
              >
                EAT
              </button>
              <button
                id="play-action"
                className="pet-button pet-buttons-middle"
                onClick={() => {
                  setEnergy(energy - 5 < 0 ? 0 : energy - 5);
                  setHappiness(happiness + 10 > 100 ? 100 : happiness + 10);
                }}
              >
                PLAY
              </button>
              <button
                id="sleep-action"
                className="pet-button pet-buttons-right"
                onClick={() => {
                  setHunger(hunger + 10 > 100 ? 100 : hunger + 10);
                  setEnergy(energy + 5 > 100 ? 100 : energy + 5);
                }}
              >
                SLEEP
              </button>
            </div>
          </div>

          <div className="stats-grid">

            <div className="stat-bar stat">
              <div className="stat-label">
                <div className="stat-icon">🍽️</div>
                <div className="stat-name">Hunger</div>
              </div>
              <div className="stat-value">{hunger}%</div>

              <div className="stat-progress">
                <div className="stat-fill"></div>
              </div>
            </div>

            <div className="stat-bar stat">
              <div className="stat-label">
                <div className="stat-icon">😊</div>
                <div className="stat-name">Happiness</div>
              </div>
              <div className="stat-value">{happiness}%</div>

              <div className="stat-progress">
                <div className="stat-fill"></div>
              </div>
            </div>

            <div className="stat-bar stat">
              <div className="stat-label">
                <div className="stat-icon">⚡</div>
                <div className="stat-name">Energy</div>
              </div>
              <div className="stat-value">{energy}%</div>

              <div className="stat-progress">
                <div className="stat-fill"></div>
              </div>
            </div>

          </div>
        </>
      )}
    </> 
  )
};

Expected behavior

When using the onChange handler in the input element, it would save the pet name and display it correctly, resulting in Test #6 succeeding and not having to worry about it.
Instead Test #6 fails, if you won't don't do it inside the submit event

Screenshots

No response

System

  • Device: PC
  • OS: Windows 11
  • Browser: Firefox
  • Version: 153.0.4 (64-Bit)

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    frontend libraries v9 certThis is for the issues dealing with the Frontend Libraries V9 Certification.scope: curriculumLessons, Challenges, Projects and other Curricular Content in curriculum directory.status: PR in worksWork in Progress (WIP) Issues.

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions


    Back | FazBrowse Home | New Git URL