Medium Flashcards

Medium level React coding assignments (22 cards)

1
Q

Todo List

Description
Build a Todo List component where users can:
* Add a new todo item.
* Mark a todo as completed.
* Delete a todo item.
* View the list of all todos.

Requirements
* The component should maintain a list of todos in its state.
* A todo has: id, text, and completed (boolean).
* An input box with placeholder “Enter todo” to type a new todo.
* A button labelled “Add” to add a todo.
* Each todo should display its text and a checkbox to toggle completion.
* Each todo should have a delete button labelled “Delete” to delete a todo.
* Completed todos should appear with a strikethrough style.

Constraints & Edge Cases
* Todo text should not be empty.
* Case-insensitive duplicate entries should be allowed.
* Deleting an item should not affect the remaining list.
* All operations should update the Ul immediately.

styles.css

body {
  font-family: sans-serif;
  -webkit-font-smoothing: auto;
  -moz-font-smoothing: auto;
  -moz-osx-font-smoothing: grayscale;
  font-smoothing: auto;
  text-rendering: optimizeLegibility;
  font-smooth: always;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
}

h1 {
  font-size: 1.5rem;
}

TodoList.js

import React from "react";

function TodoList() {

    return (
        <div>
          {/* write code here */}
        </div>
    );
}

export default TodoList;

App.js

import TodoList from "./TodoList";

export default function App() {
  return <TodoList />;
}

https://namastedev.com/practice/todo-list

A

styles.css

body {
  font-family: sans-serif;
  -webkit-font-smoothing: auto;
  -moz-font-smoothing: auto;
  -moz-osx-font-smoothing: grayscale;
  font-smoothing: auto;
  text-rendering: optimizeLegibility;
  font-smooth: always;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
}

h1 {
  font-size: 1.5rem;
}

TodoList.js

import React, { useState } from "react";
import "./styles.css";

function TodoList() {
  const [todos, setTodos] = useState([]);
  const [inputValue, setInputValue] = useState("");

  const handleAdd = () => {
    const trimmed = inputValue.trim();
    if (trimmed === "") return;

    const newTodo = {
      id: Date.now(),
      text: trimmed,
      completed: false,
    };

    setTodos((prevTodos) => [...prevTodos, newTodo]);
    setInputValue("");
  };

  const toggleComplete = (id) => {
    setTodos((prevTodos) =>
      prevTodos.map((todo) =>
        todo.id === id ? { ...todo, completed: !todo.completed } : todo
      )
    );
  };

  const deleteTodo = (id) => {
    setTodos((prevTodos) => prevTodos.filter((todo) => todo.id !== id));
  };

  return (
    <div style={{ padding: "20px", maxWidth: "400px", margin: "0 auto" }}>
      <h1>Todo List</h1>
      <div>
        <input
          type="text"
          placeholder="Enter todo"
          value={inputValue}
          onChange={(e) => setInputValue(e.target.value)}
          style={{ padding: "8px", width: "70%", marginRight: "10px" }}
        />
        <button onClick={handleAdd} style={{ padding: "8px 12px" }}>
          Add
        </button>
      </div>

      <ul style={{ listStyle: "none", padding: 0, marginTop: "20px" }}>
        {todos.map((todo) => (
          <li
            key={todo.id}
            style={{
              display: "flex",
              alignItems: "center",
              marginBottom: "10px",
            }}
          >
            <input
              type="checkbox"
              checked={todo.completed}
              onChange={() => toggleComplete(todo.id)}
              style={{ marginRight: "10px" }}
            />
            <span
              style={{
                textDecoration: todo.completed ? "line-through" : "none",
                flex: 1,
              }}
            >
              {todo.text}
            </span>
            <button onClick={() => deleteTodo(todo.id)}>Delete</button>
          </li>
        ))}
      </ul>
    </div>
  );
}

export default TodoList;

App.js

import TodoList from "./TodoList";

export default function App() {
  return <TodoList />;
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

Tabs Component

Description
Implement a Tabs Component that allows users to switch * between different tab content sections. Each tab should be clickable, and clicking on a tab should update the displayed content accordingly.

Requirements
1. The component should accept a list of tabs as props.
2. Each tab should have a title and content.
3. The first tab should be selected by default.
4. Clicking on a tab should update the displayed content.
5. The component should be reusable and scalable.
Constraints
* Constraint 1: The tabs prop is an array of objects, each containing title and content.
* Constraint 2: Handle an empty tabs array gracefully by displaying “No tabs available”.
* Constraint 3: Handle cases where title is missing in a tab by displaying “Tab 1”, “Tab 2”, according to the tab number.
* Constraint 4: Handle cases where content is missing in a tab by displaying “No content available”.

styles.css

body {
  font-family: sans-serif;
  -webkit-font-smoothing: auto;
  -moz-font-smoothing: auto;
  -moz-osx-font-smoothing: grayscale;
  font-smoothing: auto;
  text-rendering: optimizeLegibility;
  font-smooth: always;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
}

h1 {
  font-size: 1.5rem;
}

Tabs.js

import React from "react";
import './styles.css'

function Tabs({ tabs }) {
    return (
        <div>
            {/* Implement the Tabs component logic here */}
        </div>
    );
}

export default Tabs;

App.js

import Tabs from "./Tabs";

export default function App() {
    const tabsData = [
        { title: "Tab 1", content: "This is the content of Tab 1" },
        { title: "Tab 2", content: "This is the content of Tab 2" },
        { title: "Tab 3", content: "This is the content of Tab 3" }
    ];
    
    return <Tabs tabs={tabsData} />;
}

https://namastedev.com/practice/tabs-component

A

styles.css

body {
  font-family: sans-serif;
  -webkit-font-smoothing: auto;
  -moz-font-smoothing: auto;
  -moz-osx-font-smoothing: grayscale;
  font-smoothing: auto;
  text-rendering: optimizeLegibility;
  font-smooth: always;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
}

h1 {
  font-size: 1.5rem;
}

Tabs.js

import React, { useState } from "react";
import "./styles.css";

function Tabs({ tabs }) {
  const [activeIndex, setActiveIndex] = useState(0);

  if (!tabs || tabs.length === 0) {
    return <p>No tabs available</p>;
  }

  const getTitle = (tab, index) => tab.title || `Tab ${index + 1}`;
  const getContent = (tab) => tab.content || "No content available";

  return (
    <div>
      {/* Tab Titles */}
      <div style={{ display: "flex", marginBottom: "10px" }}>
        {tabs.map((tab, index) => (
          <button
            key={index}
            onClick={() => setActiveIndex(index)}
            style={{
              padding: "10px 20px",
              marginRight: "5px",
              cursor: "pointer",
              border: "1px solid #ccc",
              backgroundColor: index === activeIndex ? "#eee" : "#fff",
              fontWeight: index === activeIndex ? "bold" : "normal",
            }}
          >
            {getTitle(tab, index)}
          </button>
        ))}
      </div>

      {/* Active Tab Content */}
      <div
        style={{
          padding: "15px",
          border: "1px solid #ccc",
          backgroundColor: "#f9f9f9",
        }}
      >
        {getContent(tabs[activeIndex])}
      </div>
    </div>
  );
}

export default Tabs;

App.js

import Tabs from "./Tabs";

export default function App() {
    const tabsData = [
        { title: "Tab 1", content: "This is the content of Tab 1" },
        { title: "Tab 2", content: "This is the content of Tab 2" },
        { title: "Tab 3", content: "This is the content of Tab 3" }
    ];
    
    return <Tabs tabs={tabsData} />;
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

Todo List II

Description
Build a Todo List component with timer functionality where users can:
* Add a new todo item.
* Start/Pause a timer for each todo.
* Reset a timer to zero.
* Delete a todo item.
* View the list of all todos with their timers.

Requirements
* The component should maintain a list of todos in its state.
* A todo has: id, title, time (in seconds), and isRunning (boolean).
* An input box with placeholder “Enter todo” to type a new todo.
* A button labeled “Add” to add a todo.
* Each todo item must be an < li> element with the attribute data-testid=”todo-item”
* Example of a correctly structured todo item:

<li data-testid="todo-item" className="todo-item">
  <span className="todo-text">Example Todo</span>
  <div className="timer">00:00</div>
  <div className="button-group">
    <button className="timer-button start">Start</button>
    <button className="timer-button reset">Reset</button>
    <button className="delete-button">Delete</button>
  </div>
</li>
  • Each todo should display its text and current time in
    MM:SS format.
  • Each todo should have a labeled Start/Pause, Reset, and Delete buttons.
  • The timer should increment every second when running.
  • Multiple timers should be able to run simultaneously.

Constraints & Edge Cases
* Todo text should not be empty.
* Empty todos should not be added to the list.
* Deleting an item should not affect the remaining list or their timers.
* Pausing a timer should stop it from incrementing until resumed.
* Resetting a timer should set it to 00:00 and stop it.
* All operations should update the UI immediately.
* Timers should continue running even when other todos are being manipulated.

Implementation Details
* Use React hooks for state management.
* Implement proper cleanup for timers to prevent memory leaks.
* Format time display in MM:SS format (e.g., “01:45” for 1 minute and 45 seconds).
* Use appropriate styling to distinguish between running and paused timers.

Expected Output
A functional todo list application where:
* Users can add new todos
* Each todo has its own independent timer
* Timers can be started, paused, and reset
* Todos can be deleted
* The Ul updates in real-time as timers increment

styles.css

.App {
  font-family: sans-serif;
  max-width: 800px;
  margin: 0 auto;
  padding: 20px;
}

.container {
  background-color: #f8f9fa;
  border-radius: 8px;
  padding: 20px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}

.todo-container {
  width: 100%;
}

h1 {
  color: #333;
  margin-bottom: 10px;
}

h2 {
  color: #444;
  margin-bottom: 20px;
}

.input-container {
  display: flex;
  margin-bottom: 20px;
}

.todo-input {
  flex-grow: 1;
  padding: 10px;
  border: 1px solid #ddd;
  border-radius: 4px;
  font-size: 16px;
}

.add-button {
  background-color: #4a90e2;
  color: white;
  border: none;
  padding: 10px 15px;
  margin-left: 10px;
  border-radius: 4px;
  cursor: pointer;
  font-weight: bold;
}

.add-button:hover {
  background-color: #3a80d2;
}

.todo-list {
  list-style: none;
  padding: 0;
}

.todo-item {
  background-color: white;
  border-radius: 4px;
  padding: 15px;
  margin-bottom: 10px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}

.todo-content {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.todo-title {
  font-weight: bold;
  margin: 0;
  font-size: 18px;
}

.todo-time {
  color: #666;
  font-size: 16px;
  font-weight: bold;
  margin: 0;
  min-width: 60px;
  text-align: right;
}

.todo-actions {
  display: flex;
  gap: 10px;
}

.timer-button,
.reset-button,
.delete-button {
  padding: 8px 12px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 14px;
  font-weight: bold;
  transition: background-color 0.2s;
}

.timer-button.start {
  background-color: #4caf50;
  color: white;
}

.timer-button.start:hover {
  background-color: #3d9c40;
}

.timer-button.pause {
  background-color: #ff9800;
  color: white;
}

.timer-button.pause:hover {
  background-color: #e68900;
}

.reset-button {
  background-color: #f44336;
  color: white;
}

.reset-button:hover {
  background-color: #e53935;
}

.delete-button {
  background-color: #757575;
  color: white;
}

.delete-button:hover {
  background-color: #616161;
}

@media (max-width: 600px) {
  .todo-content {
    flex-direction: column;
    align-items: flex-start;
  }

  .todo-time {
    text-align: left;
    margin-top: 5px;
  }

  .todo-actions {
    flex-wrap: wrap;
  }
}

App.js

import React from "react";
import TodoWithTimeout from "./TodoWithTimeout";
import "./styles.css";

export default function App() {
  return (
    <div className="App">
      <h2>Todo List with Timer</h2>
      <p>
        Build a todo list where each task has its own timer that can be started,
        paused, and reset.
      </p>
      <div className="container">
        <TodoWithTimeout />
        {/* <Template /> */}
      </div>
    </div>
  );
}

TodoWithTimeout.js

import React, { useState, useEffect } from "react";
import "./styles.css";

function TodoWithTimeout() {
  // Add your state variables here

  // Add your useEffect for cleanup here

  // Add your helper functions here (formatTime, handleAddTodo, etc.)

  return (
    <div className="todo-container">
      <h2>Todo with Timer</h2>
      <div className="input-container">
        <input
          type="text"
          className="todo-input"
          data-testid="todo-input"
          placeholder="Enter todo"
          // Add your value and onChange handlers
        />
        <button
          className="add-button"
          data-testid="add-button"
          // Add your onClick handler
        >
          Add
        </button>
      </div>
      <ul className="todo-list">
        {/* Map through your todos here */}
        <li data-testid="todo-item" className="todo-item">
          <span className="todo-text">Example Todo</span>
          <div className="timer">00:00</div>
          <div className="button-group">
            <button className="timer-button start">Start</button>
            <button className="timer-button reset">Reset</button>
            <button className="delete-button">Delete</button>
          </div>
        </li>
      </ul>
    </div>
  );
}

export default TodoWithTimeout;

https://namastedev.com/practice/todo-list-ii

A
.App {
  font-family: sans-serif;
  max-width: 800px;
  margin: 0 auto;
  padding: 20px;
}

.container {
  background-color: #f8f9fa;
  border-radius: 8px;
  padding: 20px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}

.todo-container {
  width: 100%;
}

h1 {
  color: #333;
  margin-bottom: 10px;
}

h2 {
  color: #444;
  margin-bottom: 20px;
}

.input-container {
  display: flex;
  margin-bottom: 20px;
}

.todo-input {
  flex-grow: 1;
  padding: 10px;
  border: 1px solid #ddd;
  border-radius: 4px;
  font-size: 16px;
}

.add-button {
  background-color: #4a90e2;
  color: white;
  border: none;
  padding: 10px 15px;
  margin-left: 10px;
  border-radius: 4px;
  cursor: pointer;
  font-weight: bold;
}

.add-button:hover {
  background-color: #3a80d2;
}

.todo-list {
  list-style: none;
  padding: 0;
}

.todo-item {
  background-color: white;
  border-radius: 4px;
  padding: 15px;
  margin-bottom: 10px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}

.todo-content {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.todo-title {
  font-weight: bold;
  margin: 0;
  font-size: 18px;
}

.todo-time {
  color: #666;
  font-size: 16px;
  font-weight: bold;
  margin: 0;
  min-width: 60px;
  text-align: right;
}

.todo-actions {
  display: flex;
  gap: 10px;
}

.timer-button,
.reset-button,
.delete-button {
  padding: 8px 12px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 14px;
  font-weight: bold;
  transition: background-color 0.2s;
}

.timer-button.start {
  background-color: #4caf50;
  color: white;
}

.timer-button.start:hover {
  background-color: #3d9c40;
}

.timer-button.pause {
  background-color: #ff9800;
  color: white;
}

.timer-button.pause:hover {
  background-color: #e68900;
}

.reset-button {
  background-color: #f44336;
  color: white;
}

.reset-button:hover {
  background-color: #e53935;
}

.delete-button {
  background-color: #757575;
  color: white;
}

.delete-button:hover {
  background-color: #616161;
}

@media (max-width: 600px) {
  .todo-content {
    flex-direction: column;
    align-items: flex-start;
  }

  .todo-time {
    text-align: left;
    margin-top: 5px;
  }

  .todo-actions {
    flex-wrap: wrap;
  }
}

App.js
~~~

import React from “react”;
import TodoWithTimeout from “./TodoWithTimeout”;
import “./styles.css”;

export default function App() {
return (
<div className="App">
<h2>Todo List with Timer</h2>
<p>
Build a todo list where each task has its own timer that can be started,
paused, and reset.
</p>
<div className="container">
<TodoWithTimeout></TodoWithTimeout>
{/* <Template></Template> */}
</div>
</div>
);
}

TodoWithTimeout.js

import React, { useState, useEffect, useRef } from “react”;
import “./styles.css”;

function formatTime(seconds) {
const mins = String(Math.floor(seconds / 60)).padStart(2, “0”);
const secs = String(seconds % 60).padStart(2, “0”);
return ${mins}:${secs};
}

function TodoWithTimeout() {
const [todos, setTodos] = useState([]);
const [input, setInput] = useState(“”);

const timers = useRef({}); // Holds timer intervals keyed by todo id

useEffect(() => {
return () => {
// Cleanup intervals on unmount
Object.values(timers.current).forEach(clearInterval);
};
}, []);

const handleAddTodo = () => {
const trimmed = input.trim();
if (!trimmed) return;

const newTodo = {
  id: Date.now(),
  text: trimmed,
  time: 0,
  running: false,
};
setTodos((prev) => [...prev, newTodo]);
setInput("");   };

const toggleTimer = (id) => {
setTodos((prevTodos) =>
prevTodos.map((todo) => {
if (todo.id === id) {
if (todo.running) {
clearInterval(timers.current[id]);
delete timers.current[id];
} else {
timers.current[id] = setInterval(() => {
setTodos((prev) =>
prev.map((t) =>
t.id === id ? { …t, time: t.time + 1 } : t
)
);
}, 1000);
}
return { …todo, running: !todo.running };
}
return todo;
})
);
};

const resetTimer = (id) => {
clearInterval(timers.current[id]);
delete timers.current[id];
setTodos((prev) =>
prev.map((todo) =>
todo.id === id ? { …todo, time: 0, running: false } : todo
)
);
};

const deleteTodo = (id) => {
clearInterval(timers.current[id]);
delete timers.current[id];
setTodos((prev) => prev.filter((todo) => todo.id !== id));
};

return (
<div className="todo-container">
<h2>Todo with Timer</h2>
<div className="input-container">
<input
type=”text”
className=”todo-input”
data-testid=”todo-input”
placeholder=”Enter todo”
value={input}
onChange={(e) => setInput(e.target.value)}
/>
<button
className=”add-button”
data-testid=”add-button”
onClick={handleAddTodo}
>
Add
</button>
</div>
<ul className="todo-list">
{todos.map((todo) => (
<li key={todo.id} data-testid=”todo-item” className=”todo-item”>
<div className="todo-content">
<p className="todo-title">{todo.text}</p>
<p className="todo-time">{formatTime(todo.time)}</p>
</div>
<div className="todo-actions">
<button
className={timer-button ${todo.running ? "pause" : "start"}}
onClick={() => toggleTimer(todo.id)}
>
{todo.running ? “Pause” : “Start”}
</button>
<button
className=”reset-button”
onClick={() => resetTimer(todo.id)}
>
Reset
</button>
<button
className=”delete-button”
onClick={() => deleteTodo(todo.id)}
>
Delete
</button>
</div>
</li>
))}
</ul>
</div>
);
}

export default TodoWithTimeout;
~~~

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Image Gallery

Description
You are tasked with creating a dynamic Image Gallery
Application using React. The application should allow users to view, add, and delete images. Each image is represented bỳ a URL. Users can input a URL to add a new image, click an image to view a larger version, and remove any image they wish.

Requirements
Component Structure
* Use React Functional Components to build the application.
* Structure the application with a main ImageGallery component inside an App component.
Ul Behavior
* Display images in a responsive grid layout.
* Users should be able to:
Add a new image by entering a URL and clicking a button.
Delete an image from the gallery.
Click on any image to open it in a larger view.

Expected Output
* A heading: “Image Gallery”.
* An input field with the placeholder text “Enter image
URL” and a button labeled “Add Image” for adding image URLs.
* A responsive grid layout displaying all added images.
* A delete button on each image labelled “Delete” for deleting image.
* A modal-style popup must display a larger version of the image when clicked, and the modal ‹div> must have id=”modal” so it can be consistently and accurately targeted in tests.
* The large image view should close when the user clicks outside the image.

styles.css

body {
  font-family: sans-serif;
  -webkit-font-smoothing: auto;
  -moz-font-smoothing: auto;
  -moz-osx-font-smoothing: grayscale;
  font-smoothing: auto;
  text-rendering: optimizeLegibility;
  font-smooth: always;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
}

h1 {
  font-size: 1.5rem;
}

ImageGallery.jsx

import React, { useState } from 'react';
import './styles.css'
// Image Gallery Component
const ImageGallery = () => {

  return (
    <div>
      <h1>Image Gallery Application</h1>
      {/* Input for adding a new image */}
      <div>
        <input type="text" placeholder="Enter image URL" />
        <button>Add Image</button>
      </div>
      {/* Display images */}
      <div>
        {/* Map over images array and display them */}
      </div>
    </div>
  );
};

export default ImageGallery

App.js

 import ImageGallery from './ImageGallery'
export default function App() {
  return <ImageGallery/>
}

https://namastedev.com/practice/image-gallery

A

styles.css

body {
  font-family: sans-serif;
  -webkit-font-smoothing: auto;
  -moz-font-smoothing: auto;
  -moz-osx-font-smoothing: grayscale;
  font-smoothing: auto;
  text-rendering: optimizeLegibility;
  font-smooth: always;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
}

h1 {
  font-size: 1.5rem;
}

ImageGallery.jsx

import React, { useState } from 'react';
import './styles.css';

const ImageGallery = () => {
  const [images, setImages] = useState([]);
  const [input, setInput] = useState('');
  const [selectedImage, setSelectedImage] = useState(null);

  const handleAddImage = () => {
    const trimmed = input.trim();
    if (trimmed) {
      setImages((prev) => [...prev, trimmed]);
      setInput('');
    }
  };

  const handleDeleteImage = (index) => {
    setImages((prev) => prev.filter((_, i) => i !== index));
  };

  const handleClickOutside = (e) => {
    if (e.target.id === 'modal') {
      setSelectedImage(null);
    }
  };

  return (
    <div>
      <h1>Image Gallery</h1>
      {/* Input */}
      <div style={{ marginBottom: '20px' }}>
        <input
          type="text"
          placeholder="Enter image URL"
          value={input}
          onChange={(e) => setInput(e.target.value)}
          style={{ padding: '10px', width: '300px', marginRight: '10px' }}
        />
        <button onClick={handleAddImage}>Add Image</button>
      </div>

      {/* Image Grid */}
      <div
        style={{
          display: 'grid',
          gridTemplateColumns: 'repeat(auto-fit, minmax(150px, 1fr))',
          gap: '15px'
        }}
      >
        {images.map((url, index) => (
          <div key={index} style={{ position: 'relative' }}>
            <img
              src={url}
              alt={`Gallery ${index}`}
              style={{
                width: '100%',
                height: '150px',
                objectFit: 'cover',
                cursor: 'pointer',
                borderRadius: '8px'
              }}
              onClick={() => setSelectedImage(url)}
            />
            <button
              onClick={() => handleDeleteImage(index)}
              style={{
                position: 'absolute',
                top: '5px',
                right: '5px',
                backgroundColor: '#ff4d4f',
                color: 'white',
                border: 'none',
                padding: '5px 10px',
                borderRadius: '4px',
                cursor: 'pointer'
              }}
            >
              Delete
            </button>
          </div>
        ))}
      </div>

      {/* Modal */}
      {selectedImage && (
        <div
          id="modal"
          onClick={handleClickOutside}
          style={{
            position: 'fixed',
            top: 0,
            left: 0,
            width: '100vw',
            height: '100vh',
            backgroundColor: 'rgba(0,0,0,0.7)',
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
            zIndex: 999
          }}
        >
          <img
            src={selectedImage}
            alt="Enlarged"
            style={{
              maxWidth: '90%',
              maxHeight: '90%',
              borderRadius: '8px',
              boxShadow: '0 0 10px rgba(255,255,255,0.5)'
            }}
          />
        </div>
      )}
    </div>
  );
};

export default ImageGallery;

App.js

 import ImageGallery from './ImageGallery'
export default function App() {
  return <ImageGallery/>
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

Stopwatch

Description
Build a simple stopwatch with Start, Stop, and Reset functionality. The stopwatch should display elapsed time in seconds and update every second while running.

Requirements
* Display a timer starting at 0.
* Include three buttons: Start, Stop, and Reset.
* On clicking Start, the timer should begin incrementing every second.
* Stop should pause the timer.
* Reset should stop the timer and reset it back to 0.
* Ensure the timer doesn’t increment multiple times if
Start is clicked repeatedly.

Constraints & Edge Cases
* Timer should not increment if already running and Start is clicked again.
* After Reset, the timer should show 0 and stop ticking.
* Stop should not reset the time.
* Memory leaks must be avoided when using intervals.

styles.css

body {
  font-family: sans-serif;
  -webkit-font-smoothing: auto;
  -moz-font-smoothing: auto;
  -moz-osx-font-smoothing: grayscale;
  font-smoothing: auto;
  text-rendering: optimizeLegibility;
  font-smooth: always;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
}

h1 {
  font-size: 1.5rem;
}

Stopwatch.js

import React, { useState } from "react";
import './styles.css'

function Stopwatch() {
  const [seconds, setSeconds] = useState(0);

  return (
    <div style={{ textAlign: "center", marginTop: "20px" }}>
      <h1>Time: {seconds}s</h1>
      <button>Start</button>
      <button>Stop</button>
      <button>Reset</button>
    </div>
  );
}

export default Stopwatch;

App.js

import Stopwatch from "./Stopwatch";

export default function App() {
  return <Stopwatch />;
}

https://namastedev.com/practice/stopwatch

A

styles.css

body {
  font-family: sans-serif;
  -webkit-font-smoothing: auto;
  -moz-font-smoothing: auto;
  -moz-osx-font-smoothing: grayscale;
  font-smoothing: auto;
  text-rendering: optimizeLegibility;
  font-smooth: always;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
}

h1 {
  font-size: 1.5rem;
}

Stopwatch.js

import React, { useState, useRef, useEffect } from "react";
import "./styles.css";

function Stopwatch() {
  const [seconds, setSeconds] = useState(0);
  const [isRunning, setIsRunning] = useState(false);
  const intervalRef = useRef(null);

  const startTimer = () => {
    if (!isRunning) {
      setIsRunning(true);
      intervalRef.current = setInterval(() => {
        setSeconds(prev => prev + 1);
      }, 1000);
    }
  };

  const stopTimer = () => {
    if (intervalRef.current) {
      clearInterval(intervalRef.current);
      intervalRef.current = null;
    }
    setIsRunning(false);
  };

  const resetTimer = () => {
    stopTimer();
    setSeconds(0);
  };

  // Cleanup interval on component unmount
  useEffect(() => {
    return () => {
      clearInterval(intervalRef.current);
    };
  }, []);

  return (
    <div style={{ textAlign: "center", marginTop: "20px" }}>
      <h1>Time: {seconds}s</h1>
      <button onClick={startTimer}>Start</button>
      <button onClick={stopTimer}>Stop</button>
      <button onClick={resetTimer}>Reset</button>
    </div>
  );
}

export default Stopwatch;

App.js

import Stopwatch from "./Stopwatch";

export default function App() {
  return <Stopwatch />;
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

Drag and Drop

Description
Create a drag-and-drop fruits organizer using React that allows users to move fruits between “Available Fruits” and
“Dropped Fruits” columns, reorder them, and reset to the initial state.

Requirements
* Render two droppable columns:
Left column: Available Fruits
Right column: Dropped Fruits
* Display a reset button labeled “Reset Lists” to restore the initial state.
* Fruit Items Display:
Each fruit is a draggable item with a unique name.
Initially, all fruits appear in the “Available Fruits” column.
Empty messages display when a column has no items:
“Drop fruits here” for the Dropped column.
“No fruits here” for the Available column.
* Drag & Drop Behavior:
Dragging a fruit from one column to another moves it to the target column.
Dropping a fruit on another fruit within the same column reorders the items.
Dropping in an empty column area appends the fruit at the end.
Visual feedback during drag helps indicate valid drop targets.

Edge Cases & Constraints:
* Reordering within the same column keeps all items intact.
* Dragging to a different column moves the item entirely.
* Reset button:
Clears the dropped fruits.
Restores all original fruits back to the Available column.

Testing Requirements
1. Data Test IDs (required for testing):
* data-testid=”available-column” - Column for available fruits
* data-testid=”dropped-column” - Column for dropped fruits
* data-testid=”item-{id}” - Individual fruit items, e.g., item-1, item-2
* data-testid=”reset-button” - Reset button to reset all items
* data-testid=”available-empty” - Message when available list is empty
* data-testid=”dropped-empty” - Message when dropped list is empty

styles.css

body {
  font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
  background: #f4f6f8;
  margin: 0;
  padding: 20px;
  color: #2e3a59;
}

.app-wrapper {
  max-width: 900px;
  margin: 0 auto;
}

header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 28px;
  border-bottom: 1px solid #d1d9e6;
  padding-bottom: 10px;
}

h1 {
  font-weight: 700;
  font-size: 1.9rem;
  color: #1f2937;
  margin: 0;
}

.reset-btn {
  background-color: #374151;
  color: #f3f4f6;
  border: none;
  padding: 10px 20px;
  border-radius: 8px;
  font-weight: 600;
  font-size: 1rem;
  cursor: pointer;
  box-shadow: 0 3px 6px rgb(55 65 81 / 0.3);
  transition: background-color 0.3s ease, box-shadow 0.3s ease;
  user-select: none;
}

.reset-btn:hover {
  background-color: #1f2937;
  box-shadow: 0 6px 12px rgb(31 41 55 / 0.5);
}

.container {
  display: flex;
  justify-content: space-between;
  gap: 24px;
}

.column {
  background: #ffffff;
  padding: 24px 28px;
  width: 48%;
  min-height: 360px;
  border-radius: 12px;
  box-shadow: 0 10px 20px rgb(0 0 0 / 0.07);
  border: 1px solid #cbd5e1;
  transition: border-color 0.3s ease;
}

.column.drop-zone {
  border: 2px dashed #4b5563;
}

.column:hover {
  border-color: #4b5563;
}

h2 {
  margin-top: 0;
  font-weight: 600;
  font-size: 1.5rem;
  color: #181c23;
  border-bottom: 1px solid #e5e7eb;
  padding-bottom: 8px;
}

.item {
  background: #c8e0f9;
  margin: 14px 0;
  padding: 14px 20px;
  border-radius: 10px;
  cursor: grab;
  user-select: none;
  font-size: 1.15rem;
  color: #374151;
  box-shadow: 0 3px 8px rgb(100 116 139 / 0.1);
  transition: background-color 0.25s ease, box-shadow 0.25s ease;
  border: 1px solid transparent;
}

.item:active {
  cursor: grabbing;
  background-color: #e5e7eb;
  box-shadow: 0 8px 16px rgb(100 116 139 / 0.2);
  border-color: #9ca3af;
}

.empty {
  color: #6b7280;
  font-style: italic;
  margin-top: 36px;
  font-size: 1rem;
  text-align: center;
}

App.js

import DragDrop from "./DragDrop";

export default function App() {
  return <DragDrop />;
}

DragDrop.js

import React from "react";
import "./styles.css";

function DragDrop() {
  return (
    <div className="app-wrapper">
      <header>
        <h1>Drag & Drop Fruits</h1>
        <button className="reset-btn">Reset Lists</button>
      </header>

      <div className="container">
        <div className="column">
          <h2>Available Fruits</h2>
          <p className="empty">No fruits here</p>
          <div className="item">Fruit Name</div>
        </div>

        <div className="column drop-zone">
          <h2>Dropped Fruits</h2>
          <p className="empty">Drop fruits here</p>
          <div className="item">Fruit Name</div>
        </div>
      </div>
    </div>
  );
}

export default DragDrop;

https://namastedev.com/practice/drag-and-drop

A

styles.css

body {
  font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
  background: #f4f6f8;
  margin: 0;
  padding: 20px;
  color: #2e3a59;
}

.app-wrapper {
  max-width: 900px;
  margin: 0 auto;
}

header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 28px;
  border-bottom: 1px solid #d1d9e6;
  padding-bottom: 10px;
}

h1 {
  font-weight: 700;
  font-size: 1.9rem;
  color: #1f2937;
  margin: 0;
}

.reset-btn {
  background-color: #374151;
  color: #f3f4f6;
  border: none;
  padding: 10px 20px;
  border-radius: 8px;
  font-weight: 600;
  font-size: 1rem;
  cursor: pointer;
  box-shadow: 0 3px 6px rgb(55 65 81 / 0.3);
  transition: background-color 0.3s ease, box-shadow 0.3s ease;
  user-select: none;
}

.reset-btn:hover {
  background-color: #1f2937;
  box-shadow: 0 6px 12px rgb(31 41 55 / 0.5);
}

.container {
  display: flex;
  justify-content: space-between;
  gap: 24px;
}

.column {
  background: #ffffff;
  padding: 24px 28px;
  width: 48%;
  min-height: 360px;
  border-radius: 12px;
  box-shadow: 0 10px 20px rgb(0 0 0 / 0.07);
  border: 1px solid #cbd5e1;
  transition: border-color 0.3s ease;
}

.column.drop-zone {
  border: 2px dashed #4b5563;
}

.column:hover {
  border-color: #4b5563;
}

h2 {
  margin-top: 0;
  font-weight: 600;
  font-size: 1.5rem;
  color: #181c23;
  border-bottom: 1px solid #e5e7eb;
  padding-bottom: 8px;
}

.item {
  background: #c8e0f9;
  margin: 14px 0;
  padding: 14px 20px;
  border-radius: 10px;
  cursor: grab;
  user-select: none;
  font-size: 1.15rem;
  color: #374151;
  box-shadow: 0 3px 8px rgb(100 116 139 / 0.1);
  transition: background-color 0.25s ease, box-shadow 0.25s ease;
  border: 1px solid transparent;
}

.item:active {
  cursor: grabbing;
  background-color: #e5e7eb;
  box-shadow: 0 8px 16px rgb(100 116 139 / 0.2);
  border-color: #9ca3af;
}

.empty {
  color: #6b7280;
  font-style: italic;
  margin-top: 36px;
  font-size: 1rem;
  text-align: center;
}

App.js

import DragDrop from "./DragDrop";

export default function App() {
  return <DragDrop />;
}

DragDrop.js

import React, { useState } from "react";
import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd";
import "./styles.css";

const initialFruits = [
  { id: "1", name: "Apple" },
  { id: "2", name: "Banana" },
  { id: "3", name: "Cherry" },
  { id: "4", name: "Date" },
  { id: "5", name: "Elderberry" }
];

const DragDrop = () => {
  const [available, setAvailable] = useState(initialFruits);
  const [dropped, setDropped] = useState([]);

  const handleDragEnd = (result) => {
    const { source, destination } = result;

    if (!destination) return;

    const sourceList = source.droppableId === "available" ? available : dropped;
    const destList = destination.droppableId === "available" ? available : dropped;
    const setSourceList = source.droppableId === "available" ? setAvailable : setDropped;
    const setDestList = destination.droppableId === "available" ? setAvailable : setDropped;

    const [movedItem] = sourceList.splice(source.index, 1);

    if (source.droppableId === destination.droppableId) {
      // Reordering within the same column
      const updatedList = Array.from(sourceList);
      updatedList.splice(destination.index, 0, movedItem);
      setSourceList(updatedList);
    } else {
      // Moving to another column
      const updatedSource = Array.from(sourceList);
      const updatedDest = Array.from(destList);
      updatedDest.splice(destination.index, 0, movedItem);
      setSourceList(updatedSource);
      setDestList(updatedDest);
    }
  };

  const handleReset = () => {
    setAvailable(initialFruits);
    setDropped([]);
  };

  return (
    <div className="app-wrapper">
      <header>
        <h1>Drag & Drop Fruits</h1>
        <button
          className="reset-btn"
          onClick={handleReset}
          data-testid="reset-button"
        >
          Reset Lists
        </button>
      </header>

      <DragDropContext onDragEnd={handleDragEnd}>
        <div className="container">
          {/* Available Fruits Column */}
          <Droppable droppableId="available">
            {(provided, snapshot) => (
              <div
                className={`column ${snapshot.isDraggingOver ? "drop-zone" : ""}`}
                ref={provided.innerRef}
                {...provided.droppableProps}
                data-testid="available-column"
              >
                <h2>Available Fruits</h2>
                {available.length === 0 && (
                  <p className="empty" data-testid="available-empty">
                    No fruits here
                  </p>
                )}
                {available.map((fruit, index) => (
                  <Draggable key={fruit.id} draggableId={fruit.id} index={index}>
                    {(provided) => (
                      <div
                        className="item"
                        ref={provided.innerRef}
                        {...provided.draggableProps}
                        {...provided.dragHandleProps}
                        data-testid={`item-${fruit.id}`}
                      >
                        {fruit.name}
                      </div>
                    )}
                  </Draggable>
                ))}
                {provided.placeholder}
              </div>
            )}
          </Droppable>

          {/* Dropped Fruits Column */}
          <Droppable droppableId="dropped">
            {(provided, snapshot) => (
              <div
                className={`column ${snapshot.isDraggingOver ? "drop-zone" : ""}`}
                ref={provided.innerRef}
                {...provided.droppableProps}
                data-testid="dropped-column"
              >
                <h2>Dropped Fruits</h2>
                {dropped.length === 0 && (
                  <p className="empty" data-testid="dropped-empty">
                    Drop fruits here
                  </p>
                )}
                {dropped.map((fruit, index) => (
                  <Draggable key={fruit.id} draggableId={fruit.id} index={index}>
                    {(provided) => (
                      <div
                        className="item"
                        ref={provided.innerRef}
                        {...provided.draggableProps}
                        {...provided.dragHandleProps}
                        data-testid={`item-${fruit.id}`}
                      >
                        {fruit.name}
                      </div>
                    )}
                  </Draggable>
                ))}
                {provided.placeholder}
              </div>
            )}
          </Droppable>
        </div>
      </DragDropContext>
    </div>
  );
};

export default DragDrop;
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

Animated Loading Skeleton

Description
Create a React component named LoadingSkeleton that® simulates loading a user profile card. While loading, show an animated skeleton (grey boxes and lines with a shimmer effect). After 2 seconds, replace it with real profile content: an image, name, and bio.

Requirements
1. Create a LoadingSkeleton component.
2. Show a skeleton Ul (name line, bio line) while loading.
3. Use a shimmer animation for a smooth user experience.
4. After 2 seconds, display:
A user image (placeholder)
User name (e.g., John Doe)
Bio (e.g., Full-stack developer at XYZ company)

styles.css

.card {

}

.line {

}

.name {
  width: 60%;
}

.bio {
  width: 80%;
}

.skeleton {

}

.skeleton::after {

}

@keyframes shimmer {
  100% {
    transform: translateX(100%);
  }
}

LoadingSkeleton.js

import React, { useState, useEffect } from "react";
import "../styles.css";

function LoadingSkeleton() {
  const [loading, setLoading] = useState(true);

  return (
    <div className="card">
      {loading ? (
        <div className="skeleton-wrapper">
          {/* write code here */}
        </div>
      ) : (
        <div className="content">
          <h2>John Doe</h2>
          <p>Full-stack developer at XYZ company</p>
        </div>
      )}
    </div>
  );
}

export default LoadingSkeleton;

App.js

import LoadingSkeleton from "./LoadingSkeleton";

export default function App() {
  return <LoadingSkeleton />;
}

https://namastedev.com/practice/animated-loading-skeleton

A

styles.css

.card {
  width: 300px;
  margin: 40px auto;
  padding: 20px;
  background: white;
  border-radius: 12px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
  text-align: center;
  font-family: sans-serif;
}

.skeleton-wrapper {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.line {
  height: 20px;
  background-color: #e2e2e2;
  border-radius: 4px;
  margin: 10px 0;
}

.name {
  width: 60%;
}

.bio {
  width: 80%;
}

.skeleton {
  position: relative;
  overflow: hidden;
  background-color: #ddd;
}

.skeleton::after {
  content: "";
  position: absolute;
  top: 0;
  left: -100%;
  height: 100%;
  width: 100%;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,0.6), transparent);
  animation: shimmer 1.5s infinite;
}

.image-skeleton {
  width: 100px;
  height: 100px;
  border-radius: 50%;
  margin-bottom: 20px;
}

@keyframes shimmer {
  100% {
    transform: translateX(100%);
  }
}

.profile-img {
  width: 100px;
  height: 100px;
  border-radius: 50%;
  margin-bottom: 20px;
}

LoadingSkeleton.js

import React, { useState, useEffect } from "react";
import "./styles.css";

function LoadingSkeleton() {
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const timer = setTimeout(() => setLoading(false), 2000);
    return () => clearTimeout(timer);
  }, []);

  return (
    <div className="card">
      {loading ? (
        <div className="skeleton-wrapper">
          <div className="skeleton image-skeleton"></div>
          <div className="skeleton line name"></div>
          <div className="skeleton line bio"></div>
        </div>
      ) : (
        <div className="content">
          <img
            src="https://via.placeholder.com/150"
            alt="John Doe"
            className="profile-img"
          />
          <h2>John Doe</h2>
          <p>Full-stack developer at XYZ company</p>
        </div>
      )}
    </div>
  );
}

export default LoadingSkeleton;

App.js

import LoadingSkeleton from "./LoadingSkeleton";

export default function App() {
  return <LoadingSkeleton />;
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

Transfer List

Description
Build a simple Transfer List component in React that allows users to move items between two lists: “Available Items” and
“Selected Items”.

Requirements
* Display two lists: Available Items and Selected Items.
* Each item should be represented by a checkbox.
* Provide buttons to move selected items between the lists.
* Only use these items “Item A”, “Item B”, “Item C”
* Handle selection/deselection of items.
* Lists should update accordingly after every move.

Constraints & Edge Cases
* Items must not duplicate when moved.
* Moving an item should remove it from its current list.
* Handle empty selection without error.
* Initial state can be hardcoded for simplicity.

styles.css

body {
  font-family: sans-serif;
  -webkit-font-smoothing: auto;
  -moz-font-smoothing: auto;
  -moz-osx-font-smoothing: grayscale;
  font-smoothing: auto;
  text-rendering: optimizeLegibility;
  font-smooth: always;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
}

h1 {
  font-size: 1.5rem;
}

TransferList.js

import React from "react";
import './styles.css'

export default function TransferList() {
  return 
  <div>
          {/* TransferList Implementation */}
  </div>;
}

App.js

import TransferList from "./TransferList";

export default function App() {
  return <TransferList />;
}

https://namastedev.com/practice/transfer-list

A

styles.css

body {
  font-family: sans-serif;
  -webkit-font-smoothing: auto;
  -moz-font-smoothing: auto;
  -moz-osx-font-smoothing: grayscale;
  font-smoothing: auto;
  text-rendering: optimizeLegibility;
  font-smooth: always;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
}

h1 {
  font-size: 1.5rem;
}

TransferList.js

import React, { useState } from "react";
import "./styles.css";

export default function TransferList() {
  const initialItems = ["Item A", "Item B", "Item C"];
  const [available, setAvailable] = useState(initialItems);
  const [selected, setSelected] = useState([]);

  const [checkedAvailable, setCheckedAvailable] = useState([]);
  const [checkedSelected, setCheckedSelected] = useState([]);

  const handleCheck = (item, list, setter) => {
    setter((prev) =>
      prev.includes(item)
        ? prev.filter((i) => i !== item)
        : [...prev, item]
    );
  };

  const moveToSelected = () => {
    const newAvailable = available.filter((item) => !checkedAvailable.includes(item));
    const newSelected = [...selected, ...checkedAvailable];
    setAvailable(newAvailable);
    setSelected(newSelected);
    setCheckedAvailable([]);
  };

  const moveToAvailable = () => {
    const newSelected = selected.filter((item) => !checkedSelected.includes(item));
    const newAvailable = [...available, ...checkedSelected];
    setSelected(newSelected);
    setAvailable(newAvailable);
    setCheckedSelected([]);
  };

  return (
    <div style={{ display: "flex", justifyContent: "center", gap: "50px", paddingTop: "30px" }}>
      <div>
        <h1>Available Items</h1>
        {available.length === 0 ? <p>No items</p> : null}
        {available.map((item) => (
          <div key={item}>
            <label>
              <input
                type="checkbox"
                checked={checkedAvailable.includes(item)}
                onChange={() => handleCheck(item, available, setCheckedAvailable)}
              />
              {item}
            </label>
          </div>
        ))}
        <button onClick={moveToSelected} disabled={checkedAvailable.length === 0}>
          Move to Selected →
        </button>
      </div>

      <div>
        <h1>Selected Items</h1>
        {selected.length === 0 ? <p>No items</p> : null}
        {selected.map((item) => (
          <div key={item}>
            <label>
              <input
                type="checkbox"
                checked={checkedSelected.includes(item)}
                onChange={() => handleCheck(item, selected, setCheckedSelected)}
              />
              {item}
            </label>
          </div>
        ))}
        <button onClick={moveToAvailable} disabled={checkedSelected.length === 0}>
          ← Move to Available
        </button>
      </div>
    </div>
  );
}

App.js

import TransferList from "./TransferList";

export default function App() {
  return <TransferList />;
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

Modal In React

Description
Create a simple, functional modal popup in React with clear open/close behavior. This component demonstrates Ul state management with useState, conditional rendering, and handling user interactions such as clicking outside the modal or on the close button.

Component Details
You need to implement a Modal component that:
1. Displays a button labeled “Open Modal”.
2. Opens the modal when the “Open Modal” button is
* clicked.
3. Displays modal content with the following:
A heading: “Modal Header”
A paragraph: “This is the modal body”
A “Close” button inside the modal
4. Closes the modal when:
The “Close” button is clicked
The user clicks outside the modal (on the backdrop)
5. Does not close the modal when clicking inside the modal content
6. The outermost div that wraps the modal (when visible) must have data-testid=”modal-backdrop” for testing.

styles.css

body {
  font-family: sans-serif;
  -webkit-font-smoothing: auto;
  -moz-font-smoothing: auto;
  -moz-osx-font-smoothing: grayscale;
  font-smoothing: auto;
  text-rendering: optimizeLegibility;
  font-smooth: always;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
}

h1 {
  font-size: 1.5rem;
}

Modal.js

import React, { useState } from "react";

function Modal() {
  // Step 1: Create a state variable isOpen and setIsOpen using useState

  // Step 2: Create functions handleOpen and handleClose to toggle modal visibility

  return (
    <div style={{ textAlign: "center", padding: "50px", height: "100vh" }}>
      <h1>Modal Popup</h1>

     <button 
        style={{ padding: "10px", cursor: "pointer" }}
      >
        Open Modal
      </button>

      {/* Step 4: Conditionally render the modal when isOpen is true */}
      {/* Modal should close when clicking the backdrop or the Close button */}
      {/* Modal content should not close when clicking inside */}
    </div>
  );
}

export default Modal;

App.js

import React, { useState } from "react";
import Modal from "./Modal"; 
import './styles.css'

export default function App() {
  return (
   <Modal/>
  );
}

https://namastedev.com/practice/modal-in-react

A

styles.css

body {
  font-family: sans-serif;
  -webkit-font-smoothing: auto;
  -moz-font-smoothing: auto;
  -moz-osx-font-smoothing: grayscale;
  font-smoothing: auto;
  text-rendering: optimizeLegibility;
  font-smooth: always;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
}

h1 {
  font-size: 1.5rem;
}

Modal.js

import React, { useState } from "react";

function Modal() {
  const [isOpen, setIsOpen] = useState(false);

  const handleOpen = () => setIsOpen(true);
  const handleClose = () => setIsOpen(false);

  const handleBackdropClick = (e) => {
    // Only close if the user clicks directly on the backdrop
    if (e.target.dataset.testid === "modal-backdrop") {
      handleClose();
    }
  };

  return (
    <div style={{ textAlign: "center", padding: "50px", height: "100vh" }}>
      <h1>Modal Popup</h1>

      <button
        style={{ padding: "10px", cursor: "pointer" }}
        onClick={handleOpen}
      >
        Open Modal
      </button>

      {isOpen && (
        <div
          data-testid="modal-backdrop"
          onClick={handleBackdropClick}
          style={{
            position: "fixed",
            top: 0,
            left: 0,
            right: 0,
            bottom: 0,
            backgroundColor: "rgba(0, 0, 0, 0.4)",
            display: "flex",
            justifyContent: "center",
            alignItems: "center",
            zIndex: 1000,
          }}
        >
          <div
            onClick={(e) => e.stopPropagation()}
            style={{
              background: "white",
              padding: "30px",
              borderRadius: "8px",
              minWidth: "300px",
              boxShadow: "0 4px 12px rgba(0,0,0,0.2)",
              textAlign: "left",
            }}
          >
            <h2>Modal Header</h2>
            <p>This is the modal body</p>
            <button onClick={handleClose} style={{ marginTop: "20px" }}>
              Close
            </button>
          </div>
        </div>
      )}
    </div>
  );
}

export default Modal;

App.js

import React, { useState } from "react";
import Modal from "./Modal"; 
import './styles.css'

export default function App() {
  return (
   <Modal/>
  );
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

List Sorter

Description
The ListSorter component allows users to view and sort a predefined list of fruits by three different criteria: alphabetically A-Z, reverse alphabetically Z-A, and by name length (shortest to longest). The component starts by displaying the fruits in their original, hardcoded order, and only updates when the user chooses a sort option from a dropdown.
To maintain correctness, the original input list must remain consistent across usage and tests - this list is:
["Banana", "Apple", "Cherry", "Mango", "Blueberry”]
This list is used to check the initial state of the component before any sorting is applied. It ensures test reliability and aligns with expected behaviors such as stable sorting and unaltered default rendering. The component leverages React’s useState to manage both the list and the selected sort type, updating the list based on the selected sort criteria while preserving the original list structure through immutability.

Requirements
* Display a list of fruit names.
* Provide a dropdown to select the sort type with three options:
“A - Z (Alphabetical)” - sort the list alphabetically from A to Z.
“Z - A (Reverse Alphabetical) - sort the list alphabetically from Z to A.
“Length (Shortest First)” - sort the list by the length of the fruit names from shortest to longest.
* When the user selects a sort option, the list updates immediately to reflect the sorting order.
* The component should maintain the current sorting state and update the list accordingly.
* The dropdown should use the following values for selection, which must be tested using:
Corresponding dropdown option values:
* A - Z (Alphabetical) - “az”
* Z - A (Reverse Alphabetical) - “za”
* Length (Shortest First) - “length”

Edge Cases & Constraints
* The initial list order should be preserved until the user selects a sort option.
* Sorting should be stable and accurate for all fruit names.
* Sorting by length should order fruits by their string length in ascending order.
* The list should update on every change of the dropdown value.
* The component should handle cases where multiple fruits might have the same length or alphabetical order.

Example Inputs & Outputs

// Initial List
["Banana", "Apple", "Cherry", "Mango", "Blueberry", "Kiwi", "Pineapple", "Fig"]

// After selecting "A - Z (Alphabetical)"
["Apple", "Banana", "Blueberry", "Cherry", "Fig", "Kiwi", "Mango", "Pineapple"]

// After selecting "Z - A (Reverse Alphabetical)"
["Pineapple", "Mango", "Kiwi", "Fig", "Cherry", "Blueberry", "Banana", "Apple"]

// After selecting "Length (Shortest First)"
["Fig", "Kiwi", "Apple", "Mango", "Banana", "Cherry", "Blueberry", "Pineapple"]

Testing Requirements
* Verify that the component renders the heading, dropdown, and all list items correctly.
* Verify that the initial list order is exactly the original list.
* Test sorting for each sort type:
Alphabetical A-Z
Alphabetical Z-A
Length (Shortest First)
* Verify that the dropdown reflects the current selected sort option after user interaction.
Data Test IDs (required for testing)
* data-testid=”container” - main component container div.
* data-testid=”heading” - heading element with the component title.
* data-testid=”sort-dropdown” - select dropdown element for sorting.
* data-testid=”list-item” - each < li> representing a fruit.

styles.css

div[data-testid="container"] {
  max-width: 400px;
  margin: 50px auto;
  padding: 36px 32px;
  font-family: "Poppins", "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
  background-color: #ede7f6;
  border-radius: 20px;
  box-shadow: 0 15px 40px rgba(107, 91, 149, 0.25);
  color: #4b3b72;
  user-select: none;
}

h2[data-testid="heading"] {
  font-size: 2.25rem;
  margin-bottom: 32px;
  font-weight: 700;
  color: #6b5b95;
  text-align: center;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  text-shadow: 0 1px 3px rgba(155, 89, 182, 0.2);
}

label[for="sort"] {
  display: block;
  margin-bottom: 16px;
  font-weight: 600;
  font-size: 1.1rem;
  color: #6b5b95;
}

select[data-testid="sort-dropdown"] {
  width: 100%;
  padding: 14px 18px;
  font-size: 1.1rem;
  border-radius: 14px;
  border: 2px solid #b8a9c9;
  background-color: #ffffff;
  color: #4b3b72;
  cursor: pointer;
  transition: border-color 0.35s ease, box-shadow 0.35s ease;
  box-shadow: inset 0 3px 8px rgba(184, 169, 201, 0.3);
  font-weight: 600;
}

select[data-testid="sort-dropdown"]:focus {
  border-color: #9b59b6;
  box-shadow: 0 0 14px rgba(155, 89, 182, 0.6);
  outline: none;
}

ul[data-testid="list"] {
  list-style: none;
  padding-left: 0;
  margin-top: 36px;
  border-radius: 18px;
  background-color: #ffffff;
  box-shadow: 0 12px 40px rgba(107, 91, 149, 0.15);
  border: 1.8px solid #b8a9c9;
  user-select: text;
}

li[data-testid="list-item"] {
  padding: 18px 28px;
  border-bottom: 1.4px solid #b8a9c9;
  font-size: 1.2rem;
  color: #4b3b72;
  font-weight: 600;
  transition: background-color 0.3s ease, color 0.3s ease;
  cursor: default;
}

li[data-testid="list-item"]:hover {
  background-color: #59a2b6;
  color: #ede7f6;
  font-weight: 700;
  transform: scale(1.03);
  box-shadow: 0 6px 14px rgba(155, 89, 182, 0.4);
}

li[data-testid="list-item"]:last-child {
  border-bottom: none;
}

App.js

import React from "react";
import ListSorter from "./ListSorter";
import "./styles.css";

// Default list passed as prop
const defaultFruits = [
  "Banana",
  "Apple",
  "Cherry",
  "Mango",
  "Blueberry",
  "Kiwi",
  "Pineapple",
  "Fig",
];

export default function App() {
  return <ListSorter initialList={defaultFruits} />;
}

ListSorter.js

import React, { useState, useEffect } from "react";
import "./styles.css";

export default function ListSorter({ initialList = [] }) {
  return (
    <div data-testid="container">
      <div>
        <h2> List Sorter</h2>
      </div>
      <label htmlFor="sort">Sort By:</label>
      <select
        id="sort"
        data-testid="sort-dropdown"
      >     
      </select>
    </div>
  );
}

https://namastedev.com/practice/list-sorter

A

styles.css

div[data-testid="container"] {
  max-width: 400px;
  margin: 50px auto;
  padding: 36px 32px;
  font-family: "Poppins", "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
  background-color: #ede7f6;
  border-radius: 20px;
  box-shadow: 0 15px 40px rgba(107, 91, 149, 0.25);
  color: #4b3b72;
  user-select: none;
}

h2[data-testid="heading"] {
  font-size: 2.25rem;
  margin-bottom: 32px;
  font-weight: 700;
  color: #6b5b95;
  text-align: center;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  text-shadow: 0 1px 3px rgba(155, 89, 182, 0.2);
}

label[for="sort"] {
  display: block;
  margin-bottom: 16px;
  font-weight: 600;
  font-size: 1.1rem;
  color: #6b5b95;
}

select[data-testid="sort-dropdown"] {
  width: 100%;
  padding: 14px 18px;
  font-size: 1.1rem;
  border-radius: 14px;
  border: 2px solid #b8a9c9;
  background-color: #ffffff;
  color: #4b3b72;
  cursor: pointer;
  transition: border-color 0.35s ease, box-shadow 0.35s ease;
  box-shadow: inset 0 3px 8px rgba(184, 169, 201, 0.3);
  font-weight: 600;
}

select[data-testid="sort-dropdown"]:focus {
  border-color: #9b59b6;
  box-shadow: 0 0 14px rgba(155, 89, 182, 0.6);
  outline: none;
}

ul[data-testid="list"] {
  list-style: none;
  padding-left: 0;
  margin-top: 36px;
  border-radius: 18px;
  background-color: #ffffff;
  box-shadow: 0 12px 40px rgba(107, 91, 149, 0.15);
  border: 1.8px solid #b8a9c9;
  user-select: text;
}

li[data-testid="list-item"] {
  padding: 18px 28px;
  border-bottom: 1.4px solid #b8a9c9;
  font-size: 1.2rem;
  color: #4b3b72;
  font-weight: 600;
  transition: background-color 0.3s ease, color 0.3s ease;
  cursor: default;
}

li[data-testid="list-item"]:hover {
  background-color: #59a2b6;
  color: #ede7f6;
  font-weight: 700;
  transform: scale(1.03);
  box-shadow: 0 6px 14px rgba(155, 89, 182, 0.4);
}

li[data-testid="list-item"]:last-child {
  border-bottom: none;
}

App.js

import React from "react";
import ListSorter from "./ListSorter";
import "./styles.css";

// Default list passed as prop
const defaultFruits = [
  "Banana",
  "Apple",
  "Cherry",
  "Mango",
  "Blueberry",
  "Kiwi",
  "Pineapple",
  "Fig",
];

export default function App() {
  return <ListSorter initialList={defaultFruits} />;
}

ListSorter.js

import React, { useState } from "react";
import "./styles.css";

export default function ListSorter({ initialList = [] }) {
  const [sortType, setSortType] = useState(""); // No sort by default
  const [displayList, setDisplayList] = useState([...initialList]);

  const handleSortChange = (e) => {
    const value = e.target.value;
    setSortType(value);

    let sorted = [...initialList]; // Always sort from the original list

    if (value === "az") {
      sorted.sort((a, b) => a.localeCompare(b));
    } else if (value === "za") {
      sorted.sort((a, b) => b.localeCompare(a));
    } else if (value === "length") {
      sorted.sort((a, b) => a.length - b.length);
    }

    setDisplayList(sorted);
  };

  return (
    <div data-testid="container">
      <div>
        <h2 data-testid="heading">List Sorter</h2>
      </div>

      <label htmlFor="sort">Sort By:</label>
      <select
        id="sort"
        data-testid="sort-dropdown"
        value={sortType}
        onChange={handleSortChange}
      >
        <option value="">-- Select --</option>
        <option value="az">A - Z (Alphabetical)</option>
        <option value="za">Z - A (Reverse Alphabetical)</option>
        <option value="length">Length (Shortest First)</option>
      </select>

      <ul data-testid="list">
        {displayList.map((fruit, index) => (
          <li key={index} data-testid="list-item">
            {fruit}
          </li>
        ))}
      </ul>
    </div>
  );
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

Multiselect Dropdown

Description
Create a React component that allows users to select multiple options with checkboxes from a dropdown menu. The component must handle option selection, deselection, and allow resetting all selections. It should display the current selection count and the selected options and validate user input on submission.

Requirements
Functional Requirements
* The component must:
Display a label above the dropdown with the text
“Select Options:”.
Show a dropdown toggle button with placeholder text
“Choose Options” when no option is selected.
Show the count of selected options (e.g., “3 selected”’) when options are selected.
Include a dropdown icon that rotates on toggle open/close. Use lucide-icon “ChevronDown” Display exactly 10 options (eg. “Option 2, Option 7” ) with checkboxes inside the dropdown menu. The menu should be scrollable. It should be in a list format (<li></li>)
Allow selecting or deselecting multiple options by clicking each option.
Provide a “Reset Selection” button on top inside the dropdown menu to clear all selections.
Close the dropdown menu when clicking outside the component.
Show a submit button below the dropdown. The button is clicked after the menu is closed.
On submit:
If no option is selected, display an error message:
“Please select at least one option.”
If options are selected, display the selected options below the submit button: “Selected: Option 3, Option 5”

Edge cases and constraints
* Submitting with valid selections should not show any error.
* Clicking an option multiple times should toggle selection (select/deselect).
* Leading/trailing spaces in option labels (if any) must not affect selection logic.
* Dropdown button should display “Choose Options” if no options are selected.
* After valid submission, selected options should be clearly displayed in the result area.
* Clicking the Reset button must:
Clear all selected options
, Hide any error messages
Clear previous results
* Dropdown icon must rotate only when the menu is open.

Testing Requirements
Data Test IDs (Required for Testing)
* data-testid=”label”: Label text element.
* data-testid=”dropdown-button”: The dropdown toggle button.
* data-testid=”dropdown-icon”: Icon element indicating dropdown toggle state.
* data-testid=”dropdown-menu”: The container element for the dropdown options.
* data-testid={option-${option}}: Each option item container, e.g., option-Option 1.
* data-testid=”reset-button”: The Reset selections button.
* data-testid=”submit-button”: Submit button element.
* data-testid=”error-message”: Element showing validation error messages.
* data-testid=”selected-options”: Element
showing the list of selected options.
* classname= “rotate”: Used to check the rotation of the icon.

App.js

import MultiSelectDropdown from "./MultiSelectDropdown";

export default function App() {
  return <MultiSelectDropdown />;
}

MultiSelectDropdown.js

import React from "react";
import "./styles.css";

function MultiSelectDropdown() {
  return (
    <div className="dropdown-container">
      <h2 className="dropdown-title">Multiselect Dropdown Menu</h2>
      <label className="dropdown-label">Select Options:</label>
      <div className="dropdown-wrapper">
        <button className="dropdown-toggle">
          <span className="dropdown-icon">Icon</span>
          <span className="dropdown-button-label">Choose Options</span>
        </button>
        <ul className="dropdown-menu">
          <li className="dropdown-reset">Reset Selection</li>
          <li className="dropdown-option">
            <input type="checkbox" />
            <span className="option-label">Option 1</span>
          </li>
        </ul>
      </div>

      <button className="submit-button">Submit</button>
      <div className="result-area"></div>
    </div>
  );
}

export default MultiSelectDropdown;

https://namastedev.com/practice/multiselect-dropdown

A

App.js

import MultiSelectDropdown from "./MultiSelectDropdown";

export default function App() {
  return <MultiSelectDropdown />;
}

MultiSelectDropdown.js

import React, { useState, useRef, useEffect } from "react";
import { ChevronDown } from "lucide-react";
import "./styles.css";

const OPTIONS = Array.from({ length: 10 }, (_, i) => `Option ${i + 1}`);

function MultiSelectDropdown() {
  const [isOpen, setIsOpen] = useState(false);
  const [selected, setSelected] = useState([]);
  const [error, setError] = useState("");
  const [submittedOptions, setSubmittedOptions] = useState([]);
  const dropdownRef = useRef(null);

  const toggleDropdown = () => {
    setIsOpen((prev) => !prev);
  };

  const handleOptionToggle = (option) => {
    setSelected((prev) =>
      prev.includes(option)
        ? prev.filter((item) => item !== option)
        : [...prev, option]
    );
    setError("");
    setSubmittedOptions([]);
  };

  const handleReset = () => {
    setSelected([]);
    setError("");
    setSubmittedOptions([]);
  };

  const handleSubmit = () => {
    setIsOpen(false);
    if (selected.length === 0) {
      setError("Please select at least one option.");
      setSubmittedOptions([]);
    } else {
      setError("");
      setSubmittedOptions([...selected]);
    }
  };

  const handleClickOutside = (e) => {
    if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
      setIsOpen(false);
    }
  };

  useEffect(() => {
    document.addEventListener("mousedown", handleClickOutside);
    return () => document.removeEventListener("mousedown", handleClickOutside);
  }, []);

  return (
    <div className="dropdown-container" ref={dropdownRef}>
      <h2 className="dropdown-title">Multiselect Dropdown Menu</h2>
      <label data-testid="label" className="dropdown-label">Select Options:</label>

      <div className="dropdown-wrapper">
        <button
          className="dropdown-toggle"
          onClick={toggleDropdown}
          data-testid="dropdown-button"
        >
          <span
            data-testid="dropdown-icon"
            className={`dropdown-icon ${isOpen ? "rotate" : ""}`}
          >
            <ChevronDown />
          </span>
          <span className="dropdown-button-label">
            {selected.length === 0
              ? "Choose Options"
              : `${selected.length} selected`}
          </span>
        </button>

        {isOpen && (
          <ul className="dropdown-menu" data-testid="dropdown-menu">
            <li
              className="dropdown-reset"
              onClick={handleReset}
              data-testid="reset-button"
            >
              Reset Selection
            </li>
            {OPTIONS.map((option) => (
              <li
                key={option}
                className="dropdown-option"
                data-testid={`option-${option}`}
                onClick={() => handleOptionToggle(option)}
              >
                <input
                  type="checkbox"
                  checked={selected.includes(option)}
                  onChange={() => {}}
                />
                <span className="option-label">{option}</span>
              </li>
            ))}
          </ul>
        )}
      </div>

      <button
        className="submit-button"
        onClick={handleSubmit}
        data-testid="submit-button"
      >
        Submit
      </button>

      {error && (
        <div className="error" data-testid="error-message">
          {error}
        </div>
      )}

      {submittedOptions.length > 0 && (
        <div className="result-area" data-testid="selected-options">
          Selected: {submittedOptions.join(", ")}
        </div>
      )}
    </div>
  );
}

export default MultiSelectDropdown;
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

Progress Bar II

Description
You’re given a task to display a list of progress bars with different percentage values (10%, 20%, .*, 100%), Each progress bar should:
1. Animate to the given percentage after a delay of 1 second.
2. Visually fill the bar based on the percentage using a
CSS transform.
3. Display the numeric progress as text (e.g., “20%”).
4. Show the text color as:
Black if progress is less than 5%.
White otherwise.
5. Have a green background and smooth animation using CSS transitions.
You are provided with two components:
* App. js: Renders a list of ProgressBar components.
* ProgressBar. js: A single progress bar that updates after 1 second using useEffect.

Your Task:
1. The progress bar text updates from 0% to the correct percentage after 100 ms.
2. The visual fill (via transform: translateX(…))
corresponds to the progress value.
3. The background color is green.
4. Text color should be white > 5% else black.
5. The transition style is smooth (transition: 0.5s ease-in).
6. The update happens with a delay of 100ms.
7. It is mandatory for the ProgressBar to have role=”progressbar” so it can be properly identified and tested for accessibility and styling.

styles.css

.App {
  font-family: sans-serif;
  text-align: center;
}
.outer {

}
.inner {
  
}

App.js

import "./styles.css";
import ProgressBar from "./ProgressBar";
export default function App() {
  const bars = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100];
  return (
    <div className="App">
      <h1>Progress bar</h1>
    </div>
  );
}

ProgressBar.js

import { useEffect, useState } from "react";
import './styles.css'
const ProgressBar = ({ progress }) => {
  
  return (
    <div className="outer">
      <div
        className="inner"
        role="progressbar"
      >
      </div>
    </div>
  );
};
export default ProgressBar;

https://namastedev.com/practice/progress-bar-ii

A

styles.css

.App {
  font-family: sans-serif;
  text-align: center;
  padding: 20px;
}

.outer {
  width: 80%;
  height: 30px;
  margin: 20px auto;
  border: 1px solid #ccc;
  background-color: #eee;
  border-radius: 6px;
  overflow: hidden;
  position: relative;
}

.inner {
  height: 100%;
  background-color: green;
  display: flex;
  align-items: center;
  justify-content: right;
  transition: transform 0.5s ease-in;
  transform: translateX(-100%);
  white-space: nowrap;
  font-weight: bold;
  font-size: 14px;
}

App.js

import "./styles.css";
import ProgressBar from "./ProgressBar";

export default function App() {
  const bars = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100];

  return (
    <div className="App">
      <h1>Progress bar</h1>
      {bars.map((value, index) => (
        <ProgressBar key={index} progress={value} />
      ))}
    </div>
  );
}

ProgressBar.js

import { useEffect, useState } from "react";
import "./styles.css";

const ProgressBar = ({ progress }) => {
  const [currentProgress, setCurrentProgress] = useState(0);

  useEffect(() => {
    const timer = setTimeout(() => {
      setCurrentProgress(progress);
    }, 100);
    return () => clearTimeout(timer);
  }, [progress]);

  const transformStyle = {
    transform: `translateX(${currentProgress - 100}%)`,
    color: currentProgress < 5 ? "black" : "white"
  };

  return (
    <div className="outer">
      <div
        className="inner"
        role="progressbar"
        style={transformStyle}
      >
        {currentProgress}%
      </div>
    </div>
  );
};

export default ProgressBar;
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

Reusable Toast

Description
In this problem, you need to implement a “toast” notification feature that provides brief feedback to users in the form of a popup. The toast should:
* Accept a message (string)
* Accept a type (success, error, or info)
* Accept a duration (milliseconds)
Toasts should:
* Appear at the top or bottom of the screen
* Automatically disappear after the specified time
* Allow multiple toasts to be displayed simultaneously
* Show different styles depending on the type (color-coded: green for success, red for error, blue for info)
Toast Container:
* Show Success - On clicking this button a success toast appears.
* Show Error - On clicking this button an error toast appears.
* Show Info - On clicking this button an info toast appears.

Example Inputs & Outputs

Input: addToast("Data saved successfully!", "success", 3000)
Output: Toast with green background appears for 3 seconds

Input: addToast("Error saving data!", "error", 5000)
Output: Toast with red background appears for 5 seconds

Input: addToast("Information loaded", "info", 4000)
Output: Toast with blue background appears for 4 seconds

Constraints & Edge Cases
* Each toast should auto-dismiss after its specified duration.
* Support showing multiple toasts at once.
* Each toast should be uniquely identifiable for removal.
* The component must support easy customization of message, duration, and type.
* Ensure toasts don’t overlap visually in a confusing way.
* Make sure to use inline css.

Toast.jsx

import React, { useState, useEffect } from 'react';

// Toast Component
const Toast = ({ message, type, duration }) => {

  return (
    <div>
      
    </div>
  );
};

export default Toast;

ToastContainer.jsx

import React, { useState } from 'react';

const ToastContainer = () => {

  return (
    <div>
      <div>
        <button >Show Success</button>
        <button >Show Error</button>
        <button >Show Info</button>
      </div>
    </div>
  );
};

export default ToastContainer;

App.js

import React from 'react';
import ToastContainer from './ToastContainer';

const App = () => {
  return (
    <div>
      <ToastContainer />
    </div>
  );
};

export default App;

https://namastedev.com/practice/reusable-toast

A

Toast.jsx

import React, { useEffect } from 'react';

const Toast = ({ id, message, type, duration, onRemove }) => {
  useEffect(() => {
    const timer = setTimeout(() => onRemove(id), duration);
    return () => clearTimeout(timer);
  }, [id, duration, onRemove]);

  const backgroundColors = {
    success: '#4CAF50',
    error: '#F44336',
    info: '#2196F3',
  };

  const toastStyle = {
    padding: '12px 20px',
    marginBottom: '10px',
    color: 'white',
    borderRadius: '6px',
    backgroundColor: backgroundColors[type] || '#333',
    minWidth: '200px',
    boxShadow: '0 2px 8px rgba(0,0,0,0.2)',
    fontSize: '16px',
  };

  return <div style={toastStyle}>{message}</div>;
};

export default Toast;

ToastContainer.jsx

import React, { useState } from 'react';
import Toast from './Toast';

let toastId = 0;

const ToastContainer = () => {
  const [toasts, setToasts] = useState([]);

  const addToast = (message, type, duration) => {
    const id = toastId++;
    const newToast = { id, message, type, duration };
    setToasts((prev) => [...prev, newToast]);
  };

  const removeToast = (id) => {
    setToasts((prev) => prev.filter((toast) => toast.id !== id));
  };

  const containerStyle = {
    position: 'fixed',
    top: '20px',
    right: '20px',
    zIndex: 1000,
    display: 'flex',
    flexDirection: 'column',
    alignItems: 'flex-end',
  };

  const buttonContainerStyle = {
    display: 'flex',
    gap: '10px',
    marginBottom: '20px',
  };

  const buttonStyle = {
    padding: '10px 16px',
    fontSize: '14px',
    fontWeight: 'bold',
    borderRadius: '6px',
    border: 'none',
    cursor: 'pointer',
    color: 'white',
  };

  return (
    <div>
      <div style={buttonContainerStyle}>
        <button
          style={{ ...buttonStyle, backgroundColor: '#4CAF50' }}
          onClick={() => addToast('Data saved successfully!', 'success', 3000)}
        >
          Show Success
        </button>
        <button
          style={{ ...buttonStyle, backgroundColor: '#F44336' }}
          onClick={() => addToast('Error saving data!', 'error', 5000)}
        >
          Show Error
        </button>
        <button
          style={{ ...buttonStyle, backgroundColor: '#2196F3' }}
          onClick={() => addToast('Information loaded', 'info', 4000)}
        >
          Show Info
        </button>
      </div>

      <div style={containerStyle}>
        {toasts.map((toast) => (
          <Toast key={toast.id} {...toast} onRemove={removeToast} />
        ))}
      </div>
    </div>
  );
};

export default ToastContainer;

App.js

import React from 'react';
import ToastContainer from './ToastContainer';

const App = () => {
  return (
    <div>
      <ToastContainer />
    </div>
  );
};

export default App;
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

BMI Calculator

**Description **
Create a BMI (Body Mass Index) Calculator in React. The application should allow users to enter their weight in kilograms and height in centimeters, and on clicking a button, it should compute the BMI and display the corresponding category.

Requirements
Input Fields
* Weight (in kg) with placeholder “Weight (kg)”
* Height (in cm) with placeholder “Height (cm)”
On Clicking a button with label “Calculate BMI”
* Use the formula:
BMI = weight / ((height / 100) ^ 2)
* Round the BMI to 1 decimal place
* Display:
The BMI value - The BMI value with the text: “Your BMI:
X”
The BMI category - The BMI category with the text:
“Category: Y”
Where X is the calculated BMI and Y is the corresponding category (like Normal, Overweight, etc.).

BMI Categories
* Underweight: BMI < 18.5
* Normal: 18.5 ≤ BMI < 24.9
* Overweight: 25 ≤ BMI < 29.9
* Obese: BMI ≥ 30
Additional Feature
* Add a “Reset” button with label Reset to clear both inputs and the result.

Constraints & Edge Cases
* Weight and height must be positive numbers
* Input fields must not be empty before calculation
* Result should be rounded to 1 decimal place
* Reset must clear all fields and result
* BMI result must not be shown before clicking
“Calculate BMI”

styles.css

body {
  font-family: sans-serif;
  -webkit-font-smoothing: auto;
  -moz-font-smoothing: auto;
  -moz-osx-font-smoothing: grayscale;
  font-smoothing: auto;
  text-rendering: optimizeLegibility;
  font-smooth: always;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
}

h1 {
  font-size: 1.5rem;
}

BMICalculator.js

import React, { useState } from "react";
import './styles.css'

function BMICalculator() {
  // TODO: useState for weight
  // TODO: useState for height
  // TODO: useState for calculated BMI
  // TODO: useState for BMI category

  // TODO: Function to calculate BMI
  const calculateBMI = () => {
    // - Convert inputs to numbers
    // - Validate they are positive
    // - Apply BMI formula: weight / ((height / 100) ^ 2)
    // - Round the result
    // - Set BMI and category
  };

  // TODO: Function to return category based on BMI value
  const getCategory = (bmi) => {
    // - if bmi < 18.5 => "Underweight"
    // - else if bmi < 24.9 => "Normal"
    // - else if bmi < 29.9 => "Overweight"
    // - else => "Obese"
  };

  // Optional: Function to reset inputs and outputs
  const reset = () => {
    // - Clear all state values
  };

  return (
    <div>
      <h2>BMI Calculator</h2>

      {/* TODO: Input field for weight */}
      {/* TODO: Input field for height */}
      
      {/* TODO: Button to calculate BMI */}
      {/* TODO: Button to reset */}

      {/* TODO: Conditionally render result */}
    </div>
  );
}

export default BMICalculator;

App.js

import BMICalculator from "./BMICalculator";

export default function App() {
  return <BMICalculator />;
}

https://namastedev.com/practice/bmi-calculator

A

styles.css

body {
  font-family: sans-serif;
  -webkit-font-smoothing: auto;
  -moz-font-smoothing: auto;
  -moz-osx-font-smoothing: grayscale;
  font-smoothing: auto;
  text-rendering: optimizeLegibility;
  font-smooth: always;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
}

h1 {
  font-size: 1.5rem;
}

BMICalculator.js

import React, { useState } from "react";
import './styles.css';

function BMICalculator() {
  const [weight, setWeight] = useState('');
  const [height, setHeight] = useState('');
  const [bmi, setBMI] = useState(null);
  const [category, setCategory] = useState('');

  const calculateBMI = () => {
    const w = parseFloat(weight);
    const h = parseFloat(height);

    if (!w || !h || w <= 0 || h <= 0) {
      alert("Please enter valid positive numbers for weight and height.");
      return;
    }

    const bmiValue = w / ((h / 100) ** 2);
    const roundedBMI = Math.round(bmiValue * 10) / 10;
    setBMI(roundedBMI);
    setCategory(getCategory(roundedBMI));
  };

  const getCategory = (bmi) => {
    if (bmi < 18.5) return "Underweight";
    else if (bmi < 24.9) return "Normal";
    else if (bmi < 29.9) return "Overweight";
    else return "Obese";
  };

  const reset = () => {
    setWeight('');
    setHeight('');
    setBMI(null);
    setCategory('');
  };

  return (
    <div style={{ padding: '20px', maxWidth: '400px', margin: '0 auto' }}>
      <h2>BMI Calculator</h2>

      <div style={{ marginBottom: '10px' }}>
        <input
          type="number"
          value={weight}
          onChange={(e) => setWeight(e.target.value)}
          placeholder="Weight (kg)"
          style={{ padding: '8px', width: '100%' }}
        />
      </div>

      <div style={{ marginBottom: '10px' }}>
        <input
          type="number"
          value={height}
          onChange={(e) => setHeight(e.target.value)}
          placeholder="Height (cm)"
          style={{ padding: '8px', width: '100%' }}
        />
      </div>

      <div style={{ marginBottom: '10px', display: 'flex', gap: '10px' }}>
        <button onClick={calculateBMI} style={{ padding: '8px 16px' }}>Calculate BMI</button>
        <button onClick={reset} style={{ padding: '8px 16px' }}>Reset</button>
      </div>

      {bmi !== null && (
        <div style={{ marginTop: '15px' }}>
          <p><strong>Your BMI:</strong> {bmi}</p>
          <p><strong>Category:</strong> {category}</p>
        </div>
      )}
    </div>
  );
}

export default BMICalculator;

App.js

import BMICalculator from "./BMICalculator";

export default function App() {
  return <BMICalculator />;
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

Image Carousel

Description
The image carousel component takes in an array of image URLs. Example image URLs are provided in the skeleton code.

Layout and positioning:
* The image carousel should be centered on the screen with a maximum size of 600px by 400px. Images should shrink to fit within the carousel so that the entire image is visible.
* Empty parts of the carousel can be filled with black.
* If the screen width is smaller than the image, the carousel should be resized to fit within the available horizontal space.

Navigation:
* Left and Right Navigation Buttons to allow users to navigate through the images.
The left button (®) must have id=”Previous”.
The right button (E) must have id=”Next”.
* The buttons should allow a cycling behavior, i.e. after the last image, the image cycles back to the first.
* Add page buttons at the bottom to directly jump to an image. You may assume there will be fewer than 10 images.
* Each page button must have a unique id in the format pageButton-<index> (e.g., pageButton-0, pageButton-1).
* A message “No images available.” must be shown when the image array is empty.</index>

styles.css

body {
  font-family: sans-serif;
  -webkit-font-smoothing: auto;
  -moz-font-smoothing: auto;
  -moz-osx-font-smoothing: grayscale;
  font-smoothing: auto;
  text-rendering: optimizeLegibility;
  font-smooth: always;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
}

h1 {
  font-size: 1.5rem;
}

ImageCarousel.jsx

import React, { useState } from "react";
import './styles.css'

const ImageCarousel = ({ images = [] }) => {

  return (
    <div>
    </div>
  );
};

export default ImageCarousel;

App.js

import ImageCarousel from './ImageCarousel'
export default function App() {
  const images = [
  {
    src: 'https://do6gp1uxl3luu.cloudfront.net/question-webp/image-carousel1.jpg',
    alt: 'nature',
  },
  {
    src: 'https://do6gp1uxl3luu.cloudfront.net/question-webp/image-carousel2.jpg',
    alt: 'Beach',
  },
  {
    src: 'https://do6gp1uxl3luu.cloudfront.net/question-webp/image-carousel3.jpg',
    alt: 'Yak',
  },
  {
    src: 'https://do6gp1uxl3luu.cloudfront.net/question-webp/image-carousel4.jpg',
    alt: 'Hay',
  },
  {
    src: 'https://do6gp1uxl3luu.cloudfront.net/question-webp/image-carousel5.jpg',
    alt: 'Plants',
  },
  {
    src: 'https://do6gp1uxl3luu.cloudfront.net/question-webp/image-carousel6.jpg',
    alt: 'Building',
  },
];
return (
  <>
    <h2>Image Carousel</h2>
     <ImageCarousel images={images} />
  </>
)
}

https://namastedev.com/practice/image-carousel

A

styles.css

body {
  font-family: sans-serif;
  -webkit-font-smoothing: auto;
  -moz-font-smoothing: auto;
  -moz-osx-font-smoothing: grayscale;
  font-smoothing: auto;
  text-rendering: optimizeLegibility;
  font-smooth: always;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
}

h1 {
  font-size: 1.5rem;
}

ImageCarousel.jsx

import React, { useState } from "react";
import "./styles.css";

const ImageCarousel = ({ images = [] }) => {
  const [currentIndex, setCurrentIndex] = useState(0);

  const hasImages = images.length > 0;

  const goToPrevious = () => {
    setCurrentIndex((prev) => (prev === 0 ? images.length - 1 : prev - 1));
  };

  const goToNext = () => {
    setCurrentIndex((prev) => (prev === images.length - 1 ? 0 : prev + 1));
  };

  const goToPage = (index) => {
    setCurrentIndex(index);
  };

  if (!hasImages) {
    return (
      <div style={{ textAlign: "center", marginTop: "20px" }}>
        No images available.
      </div>
    );
  }

  return (
    <div
      style={{
        maxWidth: "600px",
        width: "100%",
        margin: "0 auto",
        textAlign: "center",
        position: "relative",
      }}
    >
      <div
        style={{
          backgroundColor: "black",
          height: "400px",
          display: "flex",
          alignItems: "center",
          justifyContent: "center",
        }}
      >
        <img
          src={images[currentIndex].src}
          alt={images[currentIndex].alt}
          style={{
            maxWidth: "100%",
            maxHeight: "100%",
            objectFit: "contain",
          }}
        />
      </div>

      {/* Navigation Arrows */}
      <button
        id="Previous"
        onClick={goToPrevious}
        style={{
          position: "absolute",
          top: "50%",
          left: "10px",
          transform: "translateY(-50%)",
          fontSize: "24px",
          background: "rgba(255,255,255,0.7)",
          border: "none",
          cursor: "pointer",
          padding: "8px",
        }}
      >
        ◀
      </button>

      <button
        id="Next"
        onClick={goToNext}
        style={{
          position: "absolute",
          top: "50%",
          right: "10px",
          transform: "translateY(-50%)",
          fontSize: "24px",
          background: "rgba(255,255,255,0.7)",
          border: "none",
          cursor: "pointer",
          padding: "8px",
        }}
      >
        ▶
      </button>

      {/* Pagination Buttons */}
      <div style={{ marginTop: "10px" }}>
        {images.map((_, index) => (
          <button
            key={index}
            id={`pageButton-${index}`}
            onClick={() => goToPage(index)}
            style={{
              margin: "0 4px",
              padding: "5px 10px",
              borderRadius: "50%",
              backgroundColor: index === currentIndex ? "#333" : "#ddd",
              color: index === currentIndex ? "white" : "black",
              border: "none",
              cursor: "pointer",
            }}
          >
            {index + 1}
          </button>
        ))}
      </div>
    </div>
  );
};

export default ImageCarousel;

App.js

import ImageCarousel from './ImageCarousel'
export default function App() {
  const images = [
  {
    src: 'https://do6gp1uxl3luu.cloudfront.net/question-webp/image-carousel1.jpg',
    alt: 'nature',
  },
  {
    src: 'https://do6gp1uxl3luu.cloudfront.net/question-webp/image-carousel2.jpg',
    alt: 'Beach',
  },
  {
    src: 'https://do6gp1uxl3luu.cloudfront.net/question-webp/image-carousel3.jpg',
    alt: 'Yak',
  },
  {
    src: 'https://do6gp1uxl3luu.cloudfront.net/question-webp/image-carousel4.jpg',
    alt: 'Hay',
  },
  {
    src: 'https://do6gp1uxl3luu.cloudfront.net/question-webp/image-carousel5.jpg',
    alt: 'Plants',
  },
  {
    src: 'https://do6gp1uxl3luu.cloudfront.net/question-webp/image-carousel6.jpg',
    alt: 'Building',
  },
];
return (
  <>
    <h2>Image Carousel</h2>
     <ImageCarousel images={images} />
  </>
)
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

Cards Carousel

Description
Build a card carousel component that displays one card at a time with navigation buttons (“Previous” and “Next” to scroll through a list of cards.

Requirements
* The component accepts a prop cards (an array of objects with title and description).
* Initially shows the first card with title and description.
* Clicking “Next” shows the next card, and “Previous” shows the previous one.
* Buttons should be disabled appropriately at the start/end of the list.
* Display the card number like “1 of 5”.
Constraints & Edge Cases
* If cards array is empty, show “No cards available”.
* Buttons must be disabled when there’s no next or previous card.
* Should handle single-card array gracefully.

styles.css

body {
  font-family: sans-serif;
  -webkit-font-smoothing: auto;
  -moz-font-smoothing: auto;
  -moz-osx-font-smoothing: grayscale;
  font-smoothing: auto;
  text-rendering: optimizeLegibility;
  font-smooth: always;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
}

h1 {
  font-size: 1.5rem;
}

Carousel.js

import React from "react";
import './styles.css'

function Carousel({ }) {
  return (
    <div>
      {/* write code here */}
    </div>
  );
}

export default Carousel;

App.js

import Carousel from "./Carousel";

export default function App() {
  const cards = [
    { title: "Card 1", description: "Description for Card 1" },
    { title: "Card 2", description: "Description for Card 2" },
    { title: "Card 3", description: "Description for Card 3" },
  ];

  return <Carousel cards={cards} />;
}

https://namastedev.com/practice/cards-carousel

A

styles.css

body {
  font-family: sans-serif;
  -webkit-font-smoothing: auto;
  -moz-font-smoothing: auto;
  -moz-osx-font-smoothing: grayscale;
  font-smoothing: auto;
  text-rendering: optimizeLegibility;
  font-smooth: always;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
}

h1 {
  font-size: 1.5rem;
}

Carousel.js

import React, { useState } from "react";
import "./styles.css";

function Carousel({ cards = [] }) {
  const [currentIndex, setCurrentIndex] = useState(0);

  if (cards.length === 0) {
    return <div style={{ textAlign: "center", marginTop: "20px" }}>No cards available</div>;
  }

  const currentCard = cards[currentIndex];

  const handlePrevious = () => {
    if (currentIndex > 0) setCurrentIndex(currentIndex - 1);
  };

  const handleNext = () => {
    if (currentIndex < cards.length - 1) setCurrentIndex(currentIndex + 1);
  };

  return (
    <div
      style={{
        maxWidth: "400px",
        margin: "40px auto",
        padding: "20px",
        border: "1px solid #ccc",
        borderRadius: "10px",
        textAlign: "center",
      }}
    >
      <h2>{currentCard.title}</h2>
      <p>{currentCard.description}</p>

      <div style={{ marginTop: "20px" }}>
        <button onClick={handlePrevious} disabled={currentIndex === 0} style={{ marginRight: "10px" }}>
          Previous
        </button>
        <button onClick={handleNext} disabled={currentIndex === cards.length - 1}>
          Next
        </button>
      </div>

      <div style={{ marginTop: "10px", color: "#666" }}>
        {currentIndex + 1} of {cards.length}
      </div>
    </div>
  );
}

export default Carousel;

App.js

import Carousel from "./Carousel";

export default function App() {
  const cards = [
    { title: "Card 1", description: "Description for Card 1" },
    { title: "Card 2", description: "Description for Card 2" },
    { title: "Card 3", description: "Description for Card 3" },
  ];

  return <Carousel cards={cards} />;
}
17
Q

Sortable List

Description
Create a React component called SortableList that allows users to add new items to a list and sort the list either in ascending or descending order. The sorting action should be optimized using the useCallback hook to avoid unnecessary re-renders of the sorting function when the list or the order is updated.

You need to:
1. Implement an input field with the placeholder “Add a new item”
2. A button labelled “Add Item” to add new items to the list.
3. Ensure each item in the list has a unique id in the format item-<index>.
4. Implement two buttons labelled "Sort Ascending" and
"Sort Descending" to sort the list in ascending or descending order.
5. Use JavaScript's built-in .sort) method to sort the list items alphabetically.
6. Use useCallback to memoize the sorting function to avoid unnecessary re-creation of the function during re-renders.
7. The list should dynamically update after each operation (adding items or sorting).</index>

styles.css

.sortable-list-container {
  max-width: 400px;
  margin: 0 auto;
  padding: 20px;
  border-radius: 8px;
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:20px
  
}

.sortable-list-container h3 {
  text-align: center;
  color: #333;
}

.sortable-list-container input {
  width: calc(100% - 90px);
  padding: 8px;
  margin-right: 10px;
  border: 1px solid #ccc;
  border-radius: 4px;
}

.sortable-list-container button {
  padding: 8px 12px;
  border: none;
  background-color: #007bff;
  color: white;
  border-radius: 4px;
  cursor: pointer;
  margin:5px
}

.sortable-list-container button:hover {
  background-color: #0056b3;
}

.sortable-list-container div {
  text-align: center;
  margin-bottom: 20px;
}

.list-items {
   background-color: #e9ecef;
  padding:20px;
  width:100%;
  display:flex;
  flex-direction:column;
  align-items:start
}
``` 

SortableList.js

import React, { useState, useCallback } from ‘react’;
import ‘./styles.css’;

const SortableList = () => {

return (
<div className="sortable-list-container">
<h3>Sortable List</h3>
<input></input>
<button>Add Item</button>

  <div>
    <button>Sort Ascending</button>
    <button>Sort Descending</button>
  </div>
 <div className="list-items">
 </div>
</div>   ); };

export default SortableList;
~~~

App.js

import SortableList from './SortableList'
const App = () => {
  const items = ['Apple', 'Banana', 'Orange', 'Grapes', 'Mango'];

  return <SortableList items={items} />;
};

export default App;

https://namastedev.com/practice/sortable-list

A

styles.css

.sortable-list-container {
  max-width: 400px;
  margin: 0 auto;
  padding: 20px;
  border-radius: 8px;
  display:flex;
  flex-direction:column;
  align-items:center;
  gap:20px
  
}

.sortable-list-container h3 {
  text-align: center;
  color: #333;
}

.sortable-list-container input {
  width: calc(100% - 90px);
  padding: 8px;
  margin-right: 10px;
  border: 1px solid #ccc;
  border-radius: 4px;
}

.sortable-list-container button {
  padding: 8px 12px;
  border: none;
  background-color: #007bff;
  color: white;
  border-radius: 4px;
  cursor: pointer;
  margin:5px
}

.sortable-list-container button:hover {
  background-color: #0056b3;
}

.sortable-list-container div {
  text-align: center;
  margin-bottom: 20px;
}

.list-items {
   background-color: #e9ecef;
  padding:20px;
  width:100%;
  display:flex;
  flex-direction:column;
  align-items:start
}
``` 

SortableList.js

import React, { useState, useCallback } from ‘react’;
import ‘./styles.css’;

const SortableList = ({ items = [] }) => {
const [inputValue, setInputValue] = useState(‘’);
const [list, setList] = useState(items);

// Add new item to the list
const handleAddItem = () => {
if (inputValue.trim() === ‘’) return;
setList([…list, inputValue.trim()]);
setInputValue(‘’);
};

// Memoized ascending sort function
const sortAscending = useCallback(() => {
setList(prevList => […prevList].sort((a, b) => a.localeCompare(b)));
}, []);

// Memoized descending sort function
const sortDescending = useCallback(() => {
setList(prevList => […prevList].sort((a, b) => b.localeCompare(a)));
}, []);

return (
<div className="sortable-list-container">
<h3>Sortable List</h3>
<div style={{ display: ‘flex’, width: ‘100%’ }}>
<input
type=”text”
placeholder=”Add a new item”
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
/>
<button onClick={handleAddItem}>Add Item</button>
</div>

  <div>
    <button onClick={sortAscending}>Sort Ascending</button>
    <button onClick={sortDescending}>Sort Descending</button>
  </div>

  <div className="list-items">
    {list.map((item, index) => (
      <div key={`item-${index}`} id={`item-${index}`}>
        {item}
      </div>
    ))}
  </div>
</div>   ); };

export default SortableList;
~~~

App.js

import SortableList from './SortableList'
const App = () => {
  const items = ['Apple', 'Banana', 'Orange', 'Grapes', 'Mango'];

  return <SortableList items={items} />;
};

export default App;
18
Q

Star Rating

Description
You need to implement a star rating component where users can select a rating by clicking on stars. The rating should update dynamically, and there should be a reset button to clear the rating.

Requirements
* The component should display five stars *****.
* Clicking on a star should update the rating and highlight the selected stars.
* The highlighted stars should be yellow (#FFD700), and unselected stars should be gray (#CCCCC).
* There should be a reset button below the stars that resets the rating to 0. The button should be labelled
“Reset Rating”.
* Display the current rating below the stars with the text :
“Current Rating: X”, where X is the selected star rating.
* The default rating should be 0 (no stars selected).

styles.css

body {
  font-family: sans-serif;
  -webkit-font-smoothing: auto;
  -moz-font-smoothing: auto;
  -moz-osx-font-smoothing: grayscale;
  font-smoothing: auto;
  text-rendering: optimizeLegibility;
  font-smooth: always;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
}

h1 {
  font-size: 1.5rem;
}

StarRating.js

// StarRating.js

import React from "react";

function StarRating() {
  // Step 1: Create state variables
  // use `rating` to store the selected rating, and `setRating` to update it

  return (
    <div style={{ textAlign: "center", padding: "20px" }}>
      <h1>Star Rating</h1>
      <h3>by NamasteDev</h3>

      {/* Step 2: Render 5 stars using a loop ★★★★★ */}
      {/* Step 3: Update rating when a star is clicked */}
      {/* Step 4: Style stars based on rating */}

      {/* Step 5: Display current rating */}
      
      {/* Step 6: Add a Reset button to clear the rating */}
    </div>
  );
}

export default StarRating;

App.js

import StarRating from "./StarRating";
import './styles.css'

export default function App() {
  return <StarRating />;
}

https://namastedev.com/practice/star-rating

A

styles.css

body {
  font-family: sans-serif;
  -webkit-font-smoothing: auto;
  -moz-font-smoothing: auto;
  -moz-osx-font-smoothing: grayscale;
  font-smoothing: auto;
  text-rendering: optimizeLegibility;
  font-smooth: always;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
}

h1 {
  font-size: 1.5rem;
}

StarRating.js

// StarRating.js

import React, { useState } from "react";

function StarRating() {
  // Step 1: Create state variable for rating
  const [rating, setRating] = useState(0);

  // Function to render stars dynamically
  const renderStars = () => {
    const stars = [];
    for (let i = 1; i <= 5; i++) {
      stars.push(
        <span
          key={i}
          onClick={() => setRating(i)}
          style={{
            fontSize: "2rem",
            cursor: "pointer",
            color: i <= rating ? "#FFD700" : "#CCCCCC",
          }}
        >
          ★
        </span>
      );
    }
    return stars;
  };

  // Reset handler
  const resetRating = () => {
    setRating(0);
  };

  return (
    <div style={{ textAlign: "center", padding: "20px" }}>
      <h1>Star Rating</h1>
      <h3>by NamasteDev</h3>

      {/* Step 2: Render 5 stars */}
      <div>{renderStars()}</div>

      {/* Step 5: Display current rating */}
      <p>Current Rating: {rating}</p>

      {/* Step 6: Reset button */}
      <button onClick={resetRating}>Reset Rating</button>
    </div>
  );
}

export default StarRating;

App.js

import StarRating from "./StarRating";
import './styles.css'

export default function App() {
  return <StarRating />;
}
19
Q

Grid Lights

Requirements:
You are tasked with simulating a grid of lights that can be toggled on or off. The grid is initially in the “off” state. Each light in the grid can be toggled by clicking on it. When a light is toggled, the light itself and all adjacent lights (horizontally and vertically) also toggle their states.
The grid is composed of n x n cells, and each cell represents a light that can either be on (1) or off (0). The grid starts with all lights in the off state.
You need to implement a solution that allows toggling the lights and keeps track of the current state of the grid. Make sure to use inline css.

Component Structure:
* A single functional component named GridLights.
* Grid size n should be passed as a prop (default to 5 if not provided).
State Management:
* Use useState to manage the grid state.
* Maintain a 2D array to represent the current on/off state of each light.

Ul Behavior:
* Display the grid using simple square cells.
* A light in the “on” state should be visually different and have background color “gold”.
* A light in the “off” state should have a neutral background color “lightgray”.
* Clicking on a cell toggles the state of:
The clicked cell
The top neighbor (if it exists)
The bottom neighbor (if it exists)
The left neighbor (if it exists)
The right neighbor (if it exists)
* Each cell should have role=”cell”

User Interaction:
* Clicking on a cell updates the grid immediately.
* Ul should be responsive and update in real-time based on state.

GridLights.jsx

// GridLight.jsx
const GridLights = ()=>{
  return (
    <div>
      <h2>Grid Lights</h2>
    </div>
  )
}
export default GridLights

App.js

import GridLights from './GridLights'
export default function App() {
  return <GridLights/>
}

https://namastedev.com/practice/grid-lights

A

GridLights.jsx

// GridLights.jsx
import React, { useState } from "react";

const GridLights = ({ n = 5 }) => {
  const [grid, setGrid] = useState(
    Array.from({ length: n }, () => Array(n).fill(0))
  );

  const toggleLight = (row, col) => {
    const newGrid = grid.map((r) => [...r]);

    const toggle = (i, j) => {
      if (i >= 0 && i < n && j >= 0 && j < n) {
        newGrid[i][j] = newGrid[i][j] === 1 ? 0 : 1;
      }
    };

    toggle(row, col);       // current
    toggle(row - 1, col);   // top
    toggle(row + 1, col);   // bottom
    toggle(row, col - 1);   // left
    toggle(row, col + 1);   // right

    setGrid(newGrid);
  };

  return (
    <div>
      <h2 style={{ textAlign: "center" }}>Grid Lights</h2>
      <div
        style={{
          display: "grid",
          gridTemplateColumns: `repeat(${n}, 40px)`,
          gap: "5px",
          justifyContent: "center",
        }}
      >
        {grid.map((row, i) =>
          row.map((cell, j) => (
            <div
              key={`${i}-${j}`}
              role="cell"
              onClick={() => toggleLight(i, j)}
              style={{
                width: "40px",
                height: "40px",
                backgroundColor: cell === 1 ? "gold" : "lightgray",
                border: "1px solid #ccc",
                cursor: "pointer",
                transition: "background-color 0.2s ease",
              }}
            ></div>
          ))
        )}
      </div>
    </div>
  );
};

export default GridLights;

App.js

import GridLights from './GridLights'
export default function App() {
  return <GridLights/>
}
20
Q

Calculator

Create a simple responsive calculator component that performs basic arithmetic operations. It should feature interactive buttons and intuitive behavior for clear, backspace, and evaluation. The operators should be displayed using icons.

Requirements
* A container for visual calculator boundary.
* A display area implemented using an input field:
Placeholder text: “Enter expression”
Dynamically updates with user input
Displays both ongoing expressions and evaluation results
* Input must support the following characters:
Numbers: 0-9
Operators: +, -, *, /,%, v
Parentheses: ( and )
Decimal: *
* Button Grid:
A grid layout of numeric and operator buttons
Pressing = evaluates the expression
Clear button resets the entire input
Backspace button removes the last character only
* Use icons from lucide-react for enhanced visual clarity:
Clear - Trash
Backspace -> Delete
= > Equals
% -> Percent
/ -> Divide
→> Minus
> Plus
V -> Radical
* Invalid expressions should display Error in the input box

Edge Cases & Constraints
* Initial state: display is empty
* Invalid expressions should not break app
* Repeated operators must be handled gracefully
* Equal button should safely evaluate valid expressions
* Icons must respond on click and be testable
* Display should align text to the right and scroll if needed

Example Behaviors

// Example 1: User inputs "7 * 8"
Display: "7*8"
On "=" click → Display: "56"

// Example 2: Clear
Display: "56" → Click Clear (Trash icon) → ""

// Example 3: Backspace
Display: "5+" → Click Delete icon → "5"

// Example 4: Invalid
Display: "+" → "=" → Error

Testing Requirements
Data Test IDs (Required for Testing)

General Elements
* data-testid=”calc-container”. Test for rendering the container
* data-testid=”calc-display” - Calculator input display field with placeholder

Buttons
* data-testid=”btn-clear” - Clear all input
* data-testid=”btn-sqrt” - Square root operator (V)
* data-testid=”btn-modulus” - Modulus operator (%)
* data-testid=”btn-divide” - Division operator (/)
* data-testid=”btn-7” - Number 7
* data-testid=”btn-8” - Number 8
* data-testid=”btn-g” - Number 9
* data-testid=”btn-multiply” - Multiplication
operator ()
* data-testid=”btn-4” - Number 4
* data-testid=”btn-5” - Number 5
* data-testid=”btn-6” - Number 6
* data-testid=”btn-minus” - Subtraction operator
(-)
* data-testid=”btn-1” - Number 1
* data-testid=”btn-2” - Number 2
* data-testid=”btn-3” - Number 3
* data-testid=”btn-plus” - Addition operator (+)
* data-testid=”btn-0” - Number 0
* data-testid=”btn-dot” - Decimal point (
)
* data-testid=”btn-open” - Open parenthesis (
* data-testid=”btn-close” - Close parenthesis )
* data-testid=”btn-back” - Backspace/delete last character
* data-testid=”btn-equal” - Evaluate expression (=)

Icon-Specific Elements
* data-testid=”icon-clear” - Icon inside clear
(Trash)
* data-testid=”icon-backspace” - Icon inside
backspace (Delete)
* data-testid=”icon-equals” - Icon inside equals
button (Equals)
* data-testid=”icon-sqrt”- Icon inside Squareroot
button (Radical)
* data-testid=”icon-percent” - Icon inside
modulus button (Percent)
* data-testid=”icon-divide” - Icon inside divide
button (Divide)
* data-testid=”icon-multiply”- Icon inside
multiply button (X)
* data-testid=”icon-minus”- Icon inside minus
button (Minus)
* data-testid=”icon-plus” - Icon inside plus button
(Plus)

styles.css

body {
  margin: 0;
  font-family: "Poppins", sans-serif;
  background: linear-gradient(135deg, #f4f4f4, #dfe6e9);
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
}

.calculator-container {
  background-color: #ffffff;
  padding: 30px 20px;
  border-radius: 20px;
  box-shadow: 0px 12px 24px rgba(0, 0, 0, 0.15);
  width: 320px;
  text-align: center;
}

.title {
  font-size: 25px;
  margin-bottom: 20px;
  margin-top: 8px;
  color: #22b691;
}

.display {
  width: 90%;
  height: 40px;
  font-size: 20px;
  padding: 10px;
  border-radius: 10px;
  border: 2px solid #000000;
  text-align: right;
  margin-bottom: 25px;
  background-color: #e6efe7;
  color: #2f3542;
}

.display::placeholder {
  color: #b2bec3;
}

.button-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
}

button {
  padding: 15px 0;
  font-size: 18px;
  border: none;
  border-radius: 10px;
  background-color: #d2f6ec;
  color: #2d3436;
  cursor: pointer;
  transition: all 0.2s ease;
}

button:hover {
  background-color: #a6dfc1;
  transform: scale(1.05);
}

/*special buttons*/
.clear-btn {
  background-color: #2d3436;
}

.clear-btn:hover {
  background-color: #000000;
}

.back-btn {
  background-color: #fd5a5a;
}

.back-btn:hover {
  background-color: #ff2b2b;
}

.equal-btn {
  grid-column: span 3;
  background-color: #00b894;
}

.equal-btn:hover {
  background-color: #019875;
}

/* Icon Styling for Lucide icons */
button svg {
  width: 20px;
  height: 20px;
  vertical-align: middle;
  stroke: #2d3436;
}

/* Icon colors for special buttons */
.clear-btn svg {
  stroke: #ffffff;
}

.back-btn svg {
  stroke: #ffffff;
}

.equal-btn svg {
  stroke: #ffffff;
}

Calculator.js

import React from "react";
import "./styles.css";

function Calculator() {
  return (
    <div className="calculator-container">
      <h1 className="title">Simple Calculator</h1>
      <input className="display" readOnly />

      <div className="button-grid">
        <button className="clear-btn">
          <span className="icon-clear"></span>
        </button>
        <button>
          <span className="icon-sqrt"></span>
        </button>
        <button>
          <span className="icon-percent"></span>
        </button>
        <button>
          <span className="icon-divide"></span>
        </button>

        <button>7</button>
        <button>8</button>
        <button>9</button>
        <button>
          <span className="icon-multiply"></span>
        </button>

        <button>4</button>
        <button>5</button>
        <button>6</button>
        <button>
          <span className="icon-minus"></span>
        </button>

        <button>1</button>
        <button>2</button>
        <button>3</button>
        <button>
          <span className="icon-plus"></span>
        </button>

        <button>0</button>
        <button>.</button>
        <button>(</button>
        <button>)</button>

        <button className="back-btn">
          <span className="icon-backspace"></span>
        </button>
        <button className="equal-btn">
          <span className="icon-equal"></span>
        </button>
      </div>
    </div>
  );
}

export default Calculator;

App.js

import Calculator from './Calculator.js'
export default function App() {
  return <Calculator/>
}

https://namastedev.com/practice/calculator

A

styles.css

body {
  margin: 0;
  font-family: "Poppins", sans-serif;
  background: linear-gradient(135deg, #f4f4f4, #dfe6e9);
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
}

.calculator-container {
  background-color: #ffffff;
  padding: 30px 20px;
  border-radius: 20px;
  box-shadow: 0px 12px 24px rgba(0, 0, 0, 0.15);
  width: 320px;
  text-align: center;
}

.title {
  font-size: 25px;
  margin-bottom: 20px;
  margin-top: 8px;
  color: #22b691;
}

.display {
  width: 90%;
  height: 40px;
  font-size: 20px;
  padding: 10px;
  border-radius: 10px;
  border: 2px solid #000000;
  text-align: right;
  margin-bottom: 25px;
  background-color: #e6efe7;
  color: #2f3542;
}

.display::placeholder {
  color: #b2bec3;
}

.button-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
}

button {
  padding: 15px 0;
  font-size: 18px;
  border: none;
  border-radius: 10px;
  background-color: #d2f6ec;
  color: #2d3436;
  cursor: pointer;
  transition: all 0.2s ease;
}

button:hover {
  background-color: #a6dfc1;
  transform: scale(1.05);
}

/*special buttons*/
.clear-btn {
  background-color: #2d3436;
}

.clear-btn:hover {
  background-color: #000000;
}

.back-btn {
  background-color: #fd5a5a;
}

.back-btn:hover {
  background-color: #ff2b2b;
}

.equal-btn {
  grid-column: span 3;
  background-color: #00b894;
}

.equal-btn:hover {
  background-color: #019875;
}

/* Icon Styling for Lucide icons */
button svg {
  width: 20px;
  height: 20px;
  vertical-align: middle;
  stroke: #2d3436;
}

/* Icon colors for special buttons */
.clear-btn svg {
  stroke: #ffffff;
}

.back-btn svg {
  stroke: #ffffff;
}

.equal-btn svg {
  stroke: #ffffff;
}

Calculator.js

import React, { useState } from "react";
import "./styles.css";
import {
  Trash,
  Delete,
  Equal as Equals,
  Percent,
  Divide,
  Minus,
  Plus,
  Radical,
  X,
} from "lucide-react";

function Calculator() {
const [expression, setExpression] = useState("");

  const appendToExpression = (value) => {
    setExpression((prev) => prev + value);
  };

  const handleBackspace = () => {
    setExpression((prev) => prev.slice(0, -1));
  };

  const handleClear = () => {
    setExpression("");
  };

  const handleEvaluate = () => {
    try {
      // Replace √ with Math.sqrt syntax
      let sanitized = expression.replace(/v/g, "Math.sqrt");

      // Evaluate
      const result = eval(sanitized); // Safe here because user controls input
      setExpression(result.toString());
    } catch {
      setExpression("Error");
    }
  };

  return (
    <div className="calculator-container" data-testid="calc-container">
      <h1 className="title">Simple Calculator</h1>
      <input
        className="display"
        data-testid="calc-display"
        placeholder="Enter expression"
        readOnly
        value={expression}
      />

      <div className="button-grid">
        <button className="clear-btn" data-testid="btn-clear" onClick={handleClear}>
          <Trash data-testid="icon-clear" />
        </button>
        <button className="icon-sqrt" data-testid="btn-sqrt" onClick={() => appendToExpression("v")}>
          <Radical data-testid="icon-sqrt" />
        </button>
        <button
          data-testid="btn-modulus"
          onClick={() => appendToExpression("%")}
        >
          <Percent data-testid="icon-percent" />
        </button>
         <button
          data-testid="btn-divide"
          onClick={() => appendToExpression("/")}
        >
          <Divide data-testid="icon-divide" />
        </button>

        <button data-testid="btn-7" onClick={() => appendToExpression("7")}>
          7
        </button>
        <button data-testid="btn-8" onClick={() => appendToExpression("8")}>
          8
        </button>
        <button data-testid="btn-g" onClick={() => appendToExpression("9")}>
          9
        </button>
        <button
          data-testid="btn-multiply"
          onClick={() => appendToExpression("*")}
        >
          <X data-testid="icon-multiply" />
        </button>

        <button data-testid="btn-4" onClick={() => appendToExpression("4")}>
          4
        </button>
        <button data-testid="btn-5" onClick={() => appendToExpression("5")}>
          5
        </button>
        <button data-testid="btn-6" onClick={() => appendToExpression("6")}>
          6
        </button>
        <button
          data-testid="btn-minus"
          onClick={() => appendToExpression("-")}
        >
          <Minus data-testid="icon-minus" />
        </button>

        <button data-testid="btn-1" onClick={() => appendToExpression("1")}>
          1
        </button>
        <button data-testid="btn-2" onClick={() => appendToExpression("2")}>
          2
        </button>
        <button data-testid="btn-3" onClick={() => appendToExpression("3")}>
          3
        </button>
        <button
          data-testid="btn-plus"
          onClick={() => appendToExpression("+")}
        >
          <Plus data-testid="icon-plus" />
        </button>

        <button data-testid="btn-0" onClick={() => appendToExpression("0")}>
          0
        </button>
        <button data-testid="btn-dot" onClick={() => appendToExpression(".")}>
          .
        </button>
        <button
          data-testid="btn-open"
          onClick={() => appendToExpression("(")}
        >
          (
        </button>
        <button
          data-testid="btn-close"
          onClick={() => appendToExpression(")")}
        >
          )
        </button>

        <button
          className="back-btn"
          data-testid="btn-back"
          onClick={handleBackspace}
        >
          <Delete data-testid="icon-backspace" />
        </button>
        <button
          className="equal-btn"
          data-testid="btn-equal"
          onClick={handleEvaluate}
        >
          <Equals data-testid="icon-equals" />
        </button>
      </div>
    </div>
  );
}

export default Calculator;

App.js

import Calculator from './Calculator.js'
export default function App() {
  return <Calculator/>
}
21
Q

Tic Tac Toe

styles.css

.game {
  text-align: center;
  margin-top: 50px;
  font-family: sans-serif;
}

.board {
  display: grid;
  grid-template-columns: repeat(3, 80px);
  grid-gap: 10px;
  justify-content: center;
  margin: 20px auto;
}

.square {
  width: 80px;
  height: 80px;
  font-size: 2rem;
  font-weight: bold;
  cursor: pointer;
  background-color: #f0f0f0;
  border: 2px solid #999;
  border-radius: 8px;
}

.restart-button {
  margin-top: 20px;
  padding: 10px 20px;
  font-size: 1rem;
}

TicTacToe.js

import React, { useState } from "react";
import "./styles.css"; 

function TicTacToe() {
  return (
    <div>
      <h1>Tic Tac Toe</h1>
    </div>
  );
}

export default TicTacToe;

App.js

import TicTacToe from './TicTacToe'
export default function App() {
  return <TicTacToe/>
}

https://namastedev.com/practice/tic-tac-toe

A

styles.css

.game {
  text-align: center;
  margin-top: 50px;
  font-family: sans-serif;
}

.board {
  display: grid;
  grid-template-columns: repeat(3, 80px);
  grid-gap: 10px;
  justify-content: center;
  margin: 20px auto;
}

.square {
  width: 80px;
  height: 80px;
  font-size: 2rem;
  font-weight: bold;
  cursor: pointer;
  background-color: #f0f0f0;
  border: 2px solid #999;
  border-radius: 8px;
}

.restart-button {
  margin-top: 20px;
  padding: 10px 20px;
  font-size: 1rem;
}

TicTacToe.js

import React, { useState } from "react";
import "./styles.css"; 

function TicTacToe() {
  return (
    <div>
      <h1>Tic Tac Toe</h1>
    </div>
  );
}

export default TicTacToe;

App.js

import TicTacToe from './TicTacToe'
export default function App() {
  return <TicTacToe/>
}
22
Q

Dice Roller

styles.css

body {
  font-family: sans-serif;
  -webkit-font-smoothing: auto;
  -moz-font-smoothing: auto;
  -moz-osx-font-smoothing: grayscale;
  font-smoothing: auto;
  text-rendering: optimizeLegibility;
  font-smooth: always;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
}

h1 {
  font-size: 1.5rem;
}

DiceRoller.js

import React from "react";
import './styles.css'

function DiceRoller() {
    return (
        <div>
            {/* Implement Dice Roller logic here */}
        </div>
    );
}

export default DiceRoller;

App.js

import DiceRoller from "./DiceRoller";

export default function App() {
    return <DiceRoller />;
}

https://namastedev.com/practice/dice-roller

A

styles.css

body {
  font-family: sans-serif;
  -webkit-font-smoothing: auto;
  -moz-font-smoothing: auto;
  -moz-osx-font-smoothing: grayscale;
  font-smoothing: auto;
  text-rendering: optimizeLegibility;
  font-smooth: always;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
}

h1 {
  font-size: 1.5rem;
}

DiceRoller.js

import React from "react";
import './styles.css'

function DiceRoller() {
    return (
        <div>
            {/* Implement Dice Roller logic here */}
        </div>
    );
}

export default DiceRoller;

App.js

import DiceRoller from "./DiceRoller";

export default function App() {
    return <DiceRoller />;
}