Components - Medium - Item List Manager
You are tasked with creating a simple React application called “Item List Manager” that displays a list of items and allows users to add new items to the list. The items will be displayed in an unordered list (<ul>), and there will be an input field along with a button to add new items to this list.
Detailed Requirements
When the application loads, it should display an empty list.
The input field should accept user text input.
When the button is clicked:
The text from the input field should be added to the list.
The input field should be cleared.
If the input field is empty and the button is clicked, nothing should be added to the list.
Sample Interaction
Initial State
The list is empty.
The input field is empty.
User Action 1
User types “First Item” in the input field.
User clicks “Add Item” button.
The list displays “First Item”.
User Action 2
User types “Second Item” in the input field.
User clicks “Add Item” button.
The list displays:
“First Item”
“Second Item”
App.js
import { useState } from "react";
import "h8k-components";
import "./App.css";
function App() {
const [items, setItems] = useState([]);
const [input, setInput] = useState("");
const handleAddItem = () => {
// TODO: Add logic to add input to items list
};
return (
<>
<h8k-navbar header="Item List Manager"></h8k-navbar>
<div className="App">
<h3>Item List</h3>
<input
type="text"
value={input}
onChange={() => {}}
placeholder="Enter item"
data-testid="input-field"
/>
<button onClick={handleAddItem} data-testid="add-button">
Add Item
</button>
<ul data-testid="item-list">
{items.map((item, index) => (
<li key={index} data-testid="list-item">
{item}
</li>
))}
</ul>
</div>
</>
);
}
export default App;https://www.hackerrank.com/challenges/item-list-manager/problem?isFullScreen=true
App.js
import { useState } from "react";
import "h8k-components";
import "./App.css";
function App() {
const [items, setItems] = useState([]);
const [input, setInput] = useState("");
const handleAddItem = () => {
// TODO: Add logic to add input to items list
if (input.trim() === "") return;
setItems([...items, input]);
setInput("");
};
return (
<>
<h8k-navbar header="Item List Manager"></h8k-navbar>
<div className="App">
<h3>Item List</h3>
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="Enter item"
data-testid="input-field"
/>
<button onClick={handleAddItem} data-testid="add-button">
Add Item
</button>
<ul data-testid="item-list">
{items.map((item, index) => (
<li key={index} data-testid="list-item">
{item}
</li>
))}
</ul>
</div>
</>
);
}
export default App;Components - Medium - Slideshow App
You are tasked with creating a simple React application called “Basic Slideshow” that displays a series of slides and allows users to navigate through them. The application requirements are detailed below, and the finished application must pass all of the unit tests.
Detailed Requirements
The Slides component takes an array of slides as a prop. Each element of this array denotes a single slide and is an object with two properties: a string title and a string text.
When the application loads, the first slide must be rendered.
Clicking on the “Next” button shows the next slide. This button should be disabled when the current slide is the last one.
Clicking on the “Prev” button shows the previous slide. This button should be disabled when the current slide is the first one.
Clicking on the “Restart” button returns to the first slide. This button should be disabled when the current slide is the first one.
You can assume that the passed slides array contains at least one slide.
Sample Interaction
Initial State
The first slide is displayed.
The “Prev” and “Restart” buttons are disabled.
User Action 1
User clicks “Next” button.
The next slide is displayed.
The “Prev” and “Restart” buttons are enabled.
User Action 2
User clicks “Prev” button.
The previous slide is displayed.
The “Prev” button is disabled if the first slide is shown.
User Action 3 - User clicks “Restart” button. - The first slide is displayed. - The “Prev” and “Restart” buttons are disabled.
App.js
import React from "react";
import "h8k-components";
import Slides from './components/Slides';
import { SLIDES_DATA } from "./constants";
import "./App.css";
function App() {
return (
<>
<h8k-navbar header="Slideshow App"></h8k-navbar>
<div className="App">
<Slides slides={SLIDES_DATA} />
</div>
</>
);
}
export default App;Slides.js
import React from "react";
function Slides({ slides }) {
return (
<div>
<div id="navigation" className="text-center">
<button data-testid="button-restart" className="small outlined">
Restart
</button>
<button data-testid="button-prev" className="small">
Prev
</button>
<button data-testid="button-next" className="small">
Next
</button>
</div>
<div id="slide" className="card text-center">
<h1 data-testid="title">Slide Title Here</h1>
<p data-testid="text">Slide Text Here</p>
</div>
</div>
);
}
export default Slides;https://www.hackerrank.com/challenges/react-slideshow-1/problem?isFullScreen=true
Slides.js
import React, { useState } from "react";
function Slides({ slides }) {
const [currentIndex, setCurrentIndex] = useState(0);
const restart = () => {
setCurrentIndex(0);
};
const prev = () => {
setCurrentIndex((prevIndex) => prevIndex - 1);
};
const next = () => {
setCurrentIndex((prevIndex) => prevIndex + 1);
};
const isFirstSlide = currentIndex === 0;
const isLastSlide = currentIndex === slides.length - 1;
return (
<div>
<div id="navigation" className="text-center">
<button
data-testid="button-restart"
className="small outlined"
onClick={restart}
disabled={isFirstSlide}
>
Restart
</button>
<button
data-testid="button-prev"
className="small"
onClick={prev}
disabled={isFirstSlide}
>
Prev
</button>
<button
data-testid="button-next"
className="small"
onClick={next}
disabled={isLastSlide}
>
Next
</button>
</div>
<div id="slide" className="card text-center">
<h1 data-testid="title">{slides[currentIndex].title}</h1>
<p data-testid="text">{slides[currentIndex].text}</p>
</div>
</div>
);
}
export default Slides;Components - Hard - Word Omitter
You are tasked with creating a simple React application called “Word Omitter” that dynamically filters out specific words from the user input in real-time. The application requirements are detailed below, and the finished application must pass all of the unit tests.
Detailed Requirements
The WordOmitter component takes an array of words to omit as a prop called omitWords. Each element of this array is a string representing a word that should be filtered out of the user’s input.
The application should display a text input field where the user can type a sentence.
As the user types, the output area below the input field should display the sentence with the specified words omitted.
The application should have a toggle button to switch between omitting the specified words and showing all words.
The application should have a clear button that clears both the input field and the output area.
If the input field is empty, the output area should also be empty.
Sample Interaction
Initial State
The input field is empty.
The output area is empty.
The button displays “Show All Words” i.e. Omit Mode is enabled
User Action 1
User types “This is a test sentence.” in the input field.
The output area displays “This is test sentence.” (assuming “a” is omitted).
User Action 2
User clicks the toggle button.
The output area now displays “This is a test sentence.” (showing all words).
**User Action 3 **- User clicks the clear button. - Both the input field and the output area are cleared.
App.js
import { WordOmitter } from "./components/wordOmitter";
import "./App.css";
import "h8k-components";
function App() {
return (
<>
<h8k-navbar header="Word Omitter"></h8k-navbar>
<div className="App">
<WordOmitter />
</div>
</>
);
}
export default App;wordOmitter.js
import React, { useState } from "react";
const OMITTED_WORDS = ["a", "the", "and", "or", "but"];
function WordOmitter() {
const [inputText, setInputText] = useState("");
const [omitWords, setOmitWords] = useState(true);
const handleInputChange = (e) => {
setInputText(e.target.value);
};
const toggleOmitWords = () => {
setOmitWords(!omitWords);
};
const clearFields = () => {
// TODO: Add your changes here
};
const getProcessedText = () => {
// TODO: Add your changes here
return "";
};
return (
<div className="omitter-wrapper">
<textarea
placeholder="Type here..."
value={inputText}
onChange={handleInputChange}
data-testid="input-area"
/>
<div>
<button onClick={toggleOmitWords} data-testid="action-btn">
{omitWords ? "Show All Words" : "Omit Words"}
</button>
<button onClick={clearFields} data-testid="clear-btn">
Clear
</button>
</div>
<div>
<h2>Output:</h2>
<p data-testid="output-text">{getProcessedText()}</p>
</div>
</div>
);
}
export { WordOmitter };https://www.hackerrank.com/challenges/react-word-omitter/problem?isFullScreen=true
wordOmitter.js
import React, { useState } from "react";
const OMITTED_WORDS = ["a", "the", "and", "or", "but"];
function WordOmitter() {
const [inputText, setInputText] = useState("");
const [omitWords, setOmitWords] = useState(true);
const handleInputChange = (e) => {
setInputText(e.target.value);
};
const toggleOmitWords = () => {
setOmitWords(!omitWords);
};
const clearFields = () => {
setInputText("");
};
const getProcessedText = () => {
if (!inputText) return "";
if (!omitWords) {
return inputText;
}
const words = inputText.split(/\s+/);
const filteredWords = words.filter(
(word) => !OMITTED_WORDS.includes(word.toLowerCase())
);
return filteredWords.join(" ");
};
return (
<div className="omitter-wrapper">
<textarea
placeholder="Type here..."
value={inputText}
onChange={handleInputChange}
data-testid="input-area"
/>
<div>
<button onClick={toggleOmitWords} data-testid="action-btn">
{omitWords ? "Show All Words" : "Omit Words"}
</button>
<button onClick={clearFields} data-testid="clear-btn">
Clear
</button>
</div>
<div>
<h2>Output:</h2>
<p data-testid="output-text">{getProcessedText()}</p>
</div>
</div>
);
}
export { WordOmitter };Form - Medium - Contact Form
You need to create a simple React application called “Contact Form” that collects user information and displays it below the form upon submission. This task will help you practice handling form inputs, validation, and conditional rendering in React.
Detailed Requirements
1. Form Structure:
The form should have the following fields:
Name: Text input for the user’s name.
Email: Text input for the user’s email address.
Message: Textarea for the user’s message.
2. Form Submission:
There should be a “Submit” button to submit the form.
3. Form Validation:
Validate that none of the fields are empty upon submission.
If any field is empty, display an error message: “All fields are required.” The form should not be submitted.
4. Displaying Submitted Data:
If the form is successfully submitted, display the entered information below the form.
Clear the input fields after a successful submission.
Sample Interaction
Initial State
The form is displayed with empty fields.
No submitted information or error messages are shown.
User Action 1
User fills in all fields (Name: “John Doe”, Email: “john@example.com”, Message: “Hello there!”).
User clicks the “Submit” button.
The entered information (“John Doe”, “john@example.com”, “Hello there!”) is displayed below the form.
The input fields are cleared.
User Action 2
User fills in some fields and leaves others empty.
User clicks the “Submit” button.
No information is displayed.
An error message “All fields are required.” is shown.
App.js
import { useState } from "react";
import "./App.css";
import "h8k-components";
function App() {
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const [message, setMessage] = useState("");
const [submittedData, setSubmittedData] = useState(null);
const [error, setError] = useState("");
const handleSubmit = (e) => {
e.preventDefault();
// TODO: Add logic to validate inputs and display submitted data
// HINT: You can use the setError function
// HINT: You can use the setSubmittedData function as below
// setSubmittedData({ name, email, message });
};
return (
<>
<h8k-navbar header="Contact Form"></h8k-navbar>
<div className="App">
<h1>Contact Form</h1>
<form onSubmit={handleSubmit}>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Name"
data-testid="name-input"
/>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Email"
data-testid="email-input"
/>
<textarea
value={message}
onChange={(e) => setMessage(e.target.value)}
placeholder="Message"
data-testid="message-input"
/>
<button type="submit" data-testid="submit-button">
Submit
</button>
</form>
{error && (
<p data-testid="error-message" className="error">
{error}
</p>
)}
{submittedData && (
<div data-testid="submitted-data" className="submitted-data">
<h2>Submitted Information</h2>
<p>
<strong>Name:</strong> {submittedData.name}
</p>
<p>
<strong>Email:</strong> {submittedData.email}
</p>
<p>
<strong>Message:</strong> {submittedData.message}
</p>
</div>
)}
</div>
</>
);
}
export default App;https://www.hackerrank.com/challenges/react-contact-form/problem?isFullScreen=true
import { useState } from "react";
import "./App.css";
import "h8k-components";
function App() {
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const [message, setMessage] = useState("");
const [submittedData, setSubmittedData] = useState(null);
const [error, setError] = useState("");
const handleSubmit = (e) => {
e.preventDefault();
if (!name.trim() || !email.trim() || !message.trim()) {
setError("All fields are required.");
setSubmittedData(null);
return;
}
setError("");
setSubmittedData({ name, email, message });
setName("");
setEmail("");
setMessage("");
};
return (
<>
<h8k-navbar header="Contact Form"></h8k-navbar>
<div className="App">
<h1>Contact Form</h1>
<form onSubmit={handleSubmit}>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Name"
data-testid="name-input"
/>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Email"
data-testid="email-input"
/>
<textarea
value={message}
onChange={(e) => setMessage(e.target.value)}
placeholder="Message"
data-testid="message-input"
/>
<button type="submit" data-testid="submit-button">
Submit
</button>
</form>
{error && (
<p data-testid="error-message" className="error">
{error}
</p>
)}
{submittedData && (
<div data-testid="submitted-data" className="submitted-data">
<h2>Submitted Information</h2>
<p>
<strong>Name:</strong> {submittedData.name}
</p>
<p>
<strong>Email:</strong> {submittedData.email}
</p>
<p>
<strong>Message:</strong> {submittedData.message}
</p>
</div>
)}
</div>
</>
);
}
export default App;Form - Medium - Employee Validation
Your task is to create a React app that helps employees validate and update their existing information through a survey form. The application requirements are detailed below, and the finished application must pass all of the unit tests.
Detailed Requirements
1. The EmployeeValidationForm component collects employee details through four input fields: Name, Email, Employee ID, and Joining Date.
2. Each input field should have validation logic to ensure that the data entered meets the specified requirements.
3. A Submit button should be present at the bottom of the form but remain disabled until all fields are valid.
4. If a field does not meet the criteria, an error message should be displayed below that field.
5. When the form is valid and submitted, all input fields should be cleared, and the form should be reset to its initial state.
Validation Criteria
* Name Field: Must be at least 4 characters long and can only contain alphabetical characters (A-Z, a-z) and spaces.
* Email Field: Must be in a valid email format (e.g., user@example.com).
* Employee ID Field: Must be exactly 6 numeric digits.
* Joining Date Field: Cannot be set to a date in the future.
Error Messages
* Name: “Name must be at least 4 characters long and only contain letters and spaces.”
* Email: “Email must be a valid email address.”
* Employee ID: “Employee ID must be exactly 6 digits.”
* Joining Date: “Joining Date cannot be in the future.”
Form Submission Requirements
* Form State Reset: Upon successful form submission, all fields should be cleared, and the form should revert to its initial state.
* Submit Button: Should only be enabled when all input fields are valid.
Sample Interaction
Initial State
All input fields are empty.
The Submit button is disabled.
Error messages are displayed below each empty input field.
User Action 1
The user types “John” into the Name field.
The error message below the Name field disappears if it meets the criteria.
The Submit button remains disabled as not all fields are valid.
User Action 2
The user types “john.doe@example.com” into the Email field.
The error message below the Email field disappears if it meets the criteria.
User Action 3
The user enters “123456” in the Employee ID field and selects a Joining Date that is not in the future.
All input fields are now valid, and the Submit button becomes enabled.
**User Action 3 **1. The user clicks the Submit button. 2. All input fields are cleared, the Submit button is disabled, and the form resets to its initial state.
App.js
import React from "react";
import "./App.css";
import "h8k-components";
import EmployeeValidationForm from "./components/EmployeeValidationForm";
const title = "Employee Validation";
const App = () => {
return (
<div className="App">
<h8k-navbar header={title}></h8k-navbar>
<EmployeeValidationForm />
</div>
);
};
export default App;EmployeeValidationForm.js
import React from "react";
function EmployeeValidationForm() {
return (
<div className="layout-column align-items-center mt-20 ">
<div className="layout-column align-items-start mb-10 w-50" data-testid="input-name">
<input
className="w-100"
type="text"
name="name"
value="User"
placeholder="Name"
data-testid="input-name-test"
/>
{/* <p className="error mt-2">
Name must be at least 4 characters long and only contain letters and spaces
</p> */}
</div>
<div className="layout-column align-items-start mb-10 w-50" data-testid="input-email">
<input
className="w-100"
type="text"
name="email"
value="user@email.com"
placeholder="Email"
/>
{/* <p className="error mt-2">Email must be a valid email address</p> */}
</div>
<div className="layout-column align-items-start mb-10 w-50" data-testid="input-employee-id">
<input
className="w-100"
type="text"
name="employeeId"
value={123}
placeholder="Employee ID"
/>
{/* <p className="error mt-2">Employee ID must be exactly 6 digits</p> */}
</div>
<div className="layout-column align-items-start mb-10 w-50" data-testid="input-joining-date">
<input
className="w-100"
type="date"
name="joiningDate"
value="2023-12-04"
placeholder="Joining Date"
/>
<p className="error mt-2">Joining Date cannot be in the future</p>
</div>
<button data-testid="submit-btn" type="submit">
Submit
</button>
</div>
);
}
export default EmployeeValidationForm;https://www.hackerrank.com/challenges/employee-validation/problem?isFullScreen=true
EmployeeValidationForm.js
import React, { useRef, useState } from "react";
function EmployeeValidationForm() {
// ===============================
// My original approach
// -------------------------------
// const [name, setName] = useState("");
// const [email, setEmail] = useState("");
// const [employeeId, setEmployeeId] = useState("");
// const [joiningDate, setJoiningDate] = useState("");
//
// Controlled inputs using value={state}
// Tests interacted directly with DOM which sometimes
// causes issues with controlled components.
// ===============================
const nameRef = useRef(null);
const emailRef = useRef(null);
const empIdRef = useRef(null);
const joinedDateRef = useRef(null);
const [isNameValidated, setIsNameValidated] = useState(false);
const [isEmailValidated, setIsEmailValidated] = useState(false);
const [isEmpIdValidated, setIsEmpIdValidated] = useState(false);
const [isJoinedDateValidated, setIsJoinedDateValidated] = useState(false);
// ===============================
// Name Validation
// ===============================
const regexStringAndSpacesOnly = /^(?=.*[A-Za-z])[A-Za-z\s]+$/;
// My version
// const validateName = (value) => /^[A-Za-z ]{4,}$/.test(value);
const validateName = (value) => {
const trimmed = value.trim();
return trimmed.length >= 4 && regexStringAndSpacesOnly.test(trimmed);
};
// ===============================
// Email Validation
// ===============================
// My version
// const validateEmail = (value) =>
// /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
const validateEmail = (inputElement) => {
return inputElement.checkValidity();
};
// ===============================
// Employee ID Validation
// ===============================
// My version
// const validateEmployeeId = (value) =>
// /^\d{6}$/.test(value);
const validateEmployeeId = (value) => {
const trimmed = value.trim();
return trimmed.length === 6 && Number(trimmed);
};
// ===============================
// Joining Date Validation
// ===============================
// My version (real current date)
// const today = new Date();
// Test assumes a fixed date
const today = Date.parse("2025-01-01");
const validateJoiningDate = (value) => {
const valueDate = Date.parse(value);
return today > valueDate;
};
// ===============================
// Input Handlers
// ===============================
const handleNameChange = (e) => {
const value = e.target.value;
setIsNameValidated(validateName(value));
};
const handleEmailChange = (e) => {
setIsEmailValidated(validateEmail(e.target));
};
const handleEmpIdChange = (e) => {
const value = e.target.value;
setIsEmpIdValidated(validateEmployeeId(value));
};
const handleJoiningDateChange = (e) => {
const value = e.target.value;
setIsJoinedDateValidated(validateJoiningDate(value));
};
// ===============================
// Clear Form
// ===============================
// My version
// setName("");
// setEmail("");
// setEmployeeId("");
// setJoiningDate("");
const clearAllInputs = () => {
setIsNameValidated(false);
setIsEmailValidated(false);
setIsEmpIdValidated(false);
setIsJoinedDateValidated(false);
nameRef.current.value = "";
emailRef.current.value = "";
empIdRef.current.value = "";
joinedDateRef.current.value = "";
};
const isFormValid =
isNameValidated &&
isEmailValidated &&
isEmpIdValidated &&
isJoinedDateValidated;
return (
<div className="layout-column align-items-center mt-20 ">
{/* Name */}
<div className="layout-column align-items-start mb-10 w-50" data-testid="input-name">
<input
ref={nameRef}
className="w-100"
type="text"
name="name"
placeholder="Name"
data-testid="input-name-test"
onChange={handleNameChange}
/>
{!isNameValidated && (
<p className="error mt-2">
Name must be at least 4 characters long and only contain letters and spaces
</p>
)}
</div>
{/* Email */}
<div className="layout-column align-items-start mb-10 w-50" data-testid="input-email">
<input
ref={emailRef}
className="w-100"
type="email"
name="email"
placeholder="Email"
onChange={handleEmailChange}
/>
{!isEmailValidated && (
<p className="error mt-2">
Email must be a valid email address
</p>
)}
</div>
{/* Employee ID */}
<div className="layout-column align-items-start mb-10 w-50" data-testid="input-employee-id">
<input
ref={empIdRef}
className="w-100"
type="text"
name="employeeId"
placeholder="Employee ID"
onChange={handleEmpIdChange}
/>
{!isEmpIdValidated && (
<p className="error mt-2">
Employee ID must be exactly 6 digits
</p>
)}
</div>
{/* Joining Date */}
<div className="layout-column align-items-start mb-10 w-50" data-testid="input-joining-date">
<input
ref={joinedDateRef}
className="w-100"
type="date"
name="joiningDate"
placeholder="Joining Date"
onChange={handleJoiningDateChange}
/>
{!isJoinedDateValidated && (
<p className="error mt-2">
Joining Date cannot be in the future
</p>
)}
</div>
{/* Submit */}
<button
data-testid="submit-btn"
type="submit"
disabled={!isFormValid}
onClick={clearAllInputs}
>
Submit
</button>
</div>
);
}
export default EmployeeValidationForm;Data Handling - Medium - Blog Post
Your task is to create a React application called “Blog Post” that allows users to create, display, and delete blog posts. The application requirements are detailed below, and the finished application must pass all of the unit tests.
Detailed Requirements
The “Blog Post” component should have two input fields: one for the post title and another for the post description (textarea).
The application should display a “Create” button that, when clicked, adds a new blog post to the list of existing posts.
The “Create” button should only add a post if both the title and description fields have values. If either field is empty, the button should not create a post.
Once a post is successfully created, both the title and description fields should be cleared.
The list of created blog posts should be displayed in a grid layout, with each post appearing inside a box.
Each box should include:
The post’s title.
The post’s description.
A “Delete” button to remove the specific post from the list.
Sample Interaction
Initial State
The title and description fields are empty.
No blog posts are displayed.
User Action 1
User enters a title and description in the respective input fields.
User clicks the “Create” button.
The new post is added to the grid with the entered title and description.
The input fields are cleared.
User Action 2
User clicks the “Delete” button next to a blog post.
The selected blog post is removed from the grid.
Home.js
import React from "react";
import Input from "./Input";
import PostDisplay from "./PostDisplay";
function Home() {
return (
<div className="text-center ma-20">
<div className="mb-20">
<Input />
<button data-testid="create-button" className="mt-10">
Create Post
</button>
</div>
<div className="posts-section">
<PostDisplay />
</div>
</div>
);
}
export default Home;Input.js
import React from "react";
function Input() {
return (
<div className="layout-column justify-content-center align-items-center">
<input className="w-100" type="text" placeholder="Enter Title" value={"Title"} data-testid="title-input" />
<textarea className="mt-10 w-100" placeholder="Enter Description" value={"Description"} data-testid="description-input" />
</div>
);
}
export default Input;PostDisplay.js
import React from "react";
function PostDisplay() {
return (
<div data-testid="posts-container" className="flex wrap gap-10">
<div className="post-box">
<h3>{"Title"}</h3>
<p>{"Description"}</p>
<button>Delete</button>
</div>
</div>
);
}
export default PostDisplay;https://www.hackerrank.com/challenges/blog-post/problem?isFullScreen=true
Home.js
import React, { useState } from "react";
import Input from "./Input";
import PostDisplay from "./PostDisplay";
function Home() {
const [title, setTitle] = useState("");
const [description, setDescription] = useState("");
const [posts, setPosts] = useState([]);
const handleCreatePost = () => {
if (title.trim() && description.trim()) {
setPosts([...posts, { title, description }]);
setTitle("");
setDescription("");
}
};
const handleDeletePost = (index) => {
const newPosts = posts.filter((_, i) => i !== index);
setPosts(newPosts);
};
return (
<div className="text-center ma-20">
<div className="mb-20">
<Input
title={title}
setTitle={setTitle}
description={description}
setDescription={setDescription}
/>
<button
data-testid="create-button"
className="mt-10"
onClick={handleCreatePost}
>
Create Post
</button>
</div>
<div className="posts-section">
<PostDisplay posts={posts} onDelete={handleDeletePost} />
</div>
</div>
);
}
export default Home;Input.js
import React from "react";
function Input({ title, setTitle, description, setDescription }) {
return (
<div className="layout-column justify-content-center align-items-center">
<input
className="w-100"
type="text"
placeholder="Enter Title"
value={title}
data-testid="title-input"
onChange={(e) => setTitle(e.target.value)}
/>
<textarea
className="mt-10 w-100"
placeholder="Enter Description"
value={description}
data-testid="description-input"
onChange={(e) => setDescription(e.target.value)}
/>
</div>
);
}
export default Input;PostDisplay.js
import React from "react";
function PostDisplay({ posts, onDelete }) {
return (
<div data-testid="posts-container" className="flex wrap gap-10">
{posts.map((post, index) => (
<div key={index} className="post-box">
<h3>{post.title}</h3>
<p>{post.description}</p>
<button onClick={() => onDelete(index)}>Delete</button>
</div>
))}
</div>
);
}
export default PostDisplay;Data Handling - Medium - CryptoRank Exchange
Develop a React application called “CryptoRank Exchange” to estimate the number of cryptocurrency coins a user can receive based on an entered amount of fiat currency. The application requirements are detailed below, and the finished application must pass all unit tests.
Detailed Requirements
1. Fields and Display:
Input Field: Allows entry of the amount to be exchanged.
Table: Displays “Exchange Rate” and “Number of Coins” for each cryptocurrency.
2. User Interactions:
Users input an amount within their available balance.
Amount is mandatory, ranging from $0.01 to the available balance.
If invalid, show an error message.
By default, the input field is empty with no error message and “Number of Coins” as 0.00000000.
Table updates dynamically as the amount is modified.
3. Conversion Calculation
“Number of Coins” = (Amount * Exchange Rate), rounded to 8 decimal places.
Invalid amounts display “n/a” in the “Number of Coins” column.
Error Messages
Empty input: “Amount cannot be empty”.
Amount < 0.01”.
Amount > available balance: “Amount cannot exceed the available balance”.
Sample Interaction
Initial State
The input field is empty with no error messages.
The “Number of Coins” column displays “0.00000000” for each cryptocurrency.
User Action 1
The user enters “100” into the input field.
The table updates dynamically to display the number of coins based on the exchange rates for each cryptocurrency.
User Action 2
The user enters an amount greater than the available balance (e.g., “10000”).
An error message “Amount cannot exceed the available balance” is displayed.
The “Number of Coins” column displays “n/a”.
User Action 3
The user clears the input field.
The error message “Amount cannot be empty” is displayed, and the “Number of Coins” column displays “0.00000000”.
App.js
import React from "react";
import "./App.css";
import "h8k-components";
import Main from "./components/Main";
const title = "Cryptocurrency Exchange";
const App = () => {
return (
<div>
<h8k-navbar header={title}></h8k-navbar>
<Main />
</div>
);
};
export default App;Main.js
import React from "react";
import Table from "./Table";
function Main() {
return (
<div className="layout-column align-items-center mx-auto">
<h1>CryptoRank Exchange</h1>
<section>
<div className="card-text layout-column align-items-center mt-12 px-8 flex text-center">
<label>
I want to exchange $ <input className="w-10" data-testid="amount-input" required type="number" placeholder="USD" value={0} /> of my $
<span>17042.67</span>:
</label>
<p data-testid="error" className="form-hint error-text mt-3 pl-0 ml-0">
{"Amount cannot be empty"}
</p>
{/* The errors can be Amount cannot be empty /be less than $0.01/exceed the available balance */}
</div>
</section>
<Table />
</div>
);
}
export default Main;Table.js
import React from "react";
import { cryptocurrencyList } from "../cryptocurrency-list";
function Table() {
return (
<div className="card card-text mt-10 mx-4">
<table className="mb-0">
<thead>
<tr>
<th>Cryptocurrency</th>
<th>Exchange Rate</th>
<th>Number of Coins</th>
</tr>
</thead>
<tbody data-testid="exchange-data">
<tr>
<td>Currency Name</td>
<td>1 USD = Currency Rate Currency Code</td>
<td>n/a</td>
</tr>
</tbody>
</table>
</div>
);
}
export default Table;https://www.hackerrank.com/challenges/cryptorank-exchange/problem?isFullScreen=true
Main.js
import React, { useState } from "react";
import Table from "./Table";
const Consts = {
MinimumAmount: 0.01,
AvailableBalance: 17042.67,
Errors: {
Empty: "Amount cannot be empty",
Less: "Amount cannot be less than $0.01",
Over: "Amount cannot exceed the available balance",
},
};
function Main() {
const [state, setState] = useState({ amount: null, errorMsg: "" });
const handleChange = (e) => {
const input = e.target.value;
let error = "";
if (!input) {
error = Consts.Errors.Empty;
} else if (parseFloat(input) < Consts.MinimumAmount) {
error = Consts.Errors.Less;
} else if (parseFloat(input) > Consts.AvailableBalance) {
error = Consts.Errors.Over;
}
setState({
amount: error ? null : input,
errorMsg: error,
});
};
return (
<div className="layout-column align-items-center mx-auto">
<h1>CryptoRank Exchange</h1>
<section>
<div className="card-text layout-column align-items-center mt-12 px-8 flex text-center">
<label>
I want to exchange ${" "}
<input
className="w-10"
data-testid="amount-input"
required
type="number"
placeholder="USD"
value={state.amount ?? ""}
onChange={handleChange}
/>{" "}
of my ${Consts.AvailableBalance}:
</label>
{state.errorMsg && (
<p
data-testid="error"
className="form-hint error-text mt-3 pl-0 ml-0"
>
{state.errorMsg}
</p>
)}
</div>
</section>
<Table amount={state.amount} isInvalid={!!state.errorMsg} />
</div>
);
}
export default Main;Table.js
import React from "react";
import { cryptocurrencyList } from "../cryptocurrency-list";
const Consts = {
CoinDigits: 8,
InvalidDisplay: "n/a",
};
function Table({ amount, isInvalid }) {
return (
<div className="card card-text mt-10 mx-4">
<table className="mb-0">
<thead>
<tr>
<th>Cryptocurrency</th>
<th>Exchange Rate</th>
<th>Number of Coins</th>
</tr>
</thead>
<tbody data-testid="exchange-data">
{cryptocurrencyList.map((crypto) => {
const coins = isInvalid
? Consts.InvalidDisplay // "n/a"
: amount !== null
? (parseFloat(amount) * crypto.rate).toFixed(Consts.CoinDigits)
: "0.00000000";
return (
<tr key={crypto.code}>
<td>{crypto.name}</td>
<td>
1 USD = {crypto.rate} {crypto.code}
</td>
<td>{coins}</td>
</tr>
);
})}
</tbody>
</table>
</div>
);
}
export default Table;Data Handling - Hard - Article Sorting
Create a React application called “Article Sorting” that displays a list of articles and allows users to sort them based on upvotes and publication date. Some core functionalities have already been implemented, but the application is not complete. Application requirements are detailed below, and the finished application must pass all of the unit tests.
Detailed Requirements
The Articles component takes an array of articles as a prop. Each element of this array is an object with three properties: a string title, a number upvotes, and a string date in the format YYYY-MM-DD.
By default, the articles should be displayed in a table ordered by the number of upvotes in descending order.
Clicking on the “Most Upvoted” button should reorder and display the articles by the number of upvotes in descending order.
Clicking on the “Most Recent” button should reorder and display the articles by date in descending order.
You can assume that each article has a unique publish date and number of upvotes.
Sample Interaction
Initial State
The articles are displayed in the table, ordered by the number of upvotes in descending order.
The “Most Upvoted” button and the “Most Recent” button are displayed.
User Action 1
User clicks “Most Recent” button.
The articles are reordered and displayed by date in descending order.
User Action 2
User clicks “Most Upvoted” button.
The articles are reordered and displayed by the number of upvotes in descending order.
App.js
import "h8k-components";
import Articles from "./components/Articles";
import "./App.css";
function App({ articles }) {
const handleMostUpvoted = () => {
// Logic for most upvoted articles
};
const handleMostRecent = () => {
// Logic for most recent articles
};
return (
<>
<h8k-navbar header="Sorting Articles"></h8k-navbar>
<div className="App">
<div className="layout-row align-items-center justify-content-center my-20 navigation">
<label className="form-hint mb-0 text-uppercase font-weight-light">
Sort By
</label>
<button
data-testid="most-upvoted-link"
className="small"
onClick={handleMostUpvoted}
>
Most Upvoted
</button>
<button
data-testid="most-recent-link"
className="small"
onClick={handleMostRecent}
>
Most Recent
</button>
</div>
<Articles articles={articles} />
</div>
</>
);
}
export default App;Articles.js
import React from "react";
function Articles({ articles = [] }) {
return (
<div className="card w-50 mx-auto">
<table>
<thead>
<tr>
<th>Title</th>
<th>Upvotes</th>
<th>Date</th>
</tr>
</thead>
<tbody>
<tr data-testid="article" key="article-index">
<td data-testid="article-title">Article 1 title</td>
<td data-testid="article-upvotes">Article 1 upvotes</td>
<td data-testid="article-date">Article 1 date</td>
</tr>
</tbody>
</table>
</div>
);
}
export default Articles;https://www.hackerrank.com/challenges/react-article-sorting/problem?isFullScreen=true
App.js
import "h8k-components";
import { useState } from "react";
import Articles from "./components/Articles";
import "./App.css";
function App({ articles }) {
// Use state to manage displayed articles
const [sortedArticles, setSortedArticles] = useState(
articles.concat().sort((a, b) => b.upvotes - a.upvotes)
);
const handleMostUpvoted = () => {
const sorted = sortedArticles.concat().sort((a, b) => b.upvotes - a.upvotes);
setSortedArticles(sorted);
};
const handleMostRecent = () => {
const sorted = sortedArticles
.concat()
.sort((a, b) => new Date(b.date) - new Date(a.date));
setSortedArticles(sorted);
};
return (
<>
<h8k-navbar header="Sorting Articles"></h8k-navbar>
<div className="App">
<div className="layout-row align-items-center justify-content-center my-20 navigation">
<label className="form-hint mb-0 text-uppercase font-weight-light">
Sort By
</label>
<button
data-testid="most-upvoted-link"
className="small"
onClick={handleMostUpvoted}
>
Most Upvoted
</button>
<button
data-testid="most-recent-link"
className="small"
onClick={handleMostRecent}
>
Most Recent
</button>
</div>
<Articles articles={sortedArticles} />
</div>
</>
);
}
export default App;Articles.js
import React from "react";
function Articles({ articles = [] }) {
return (
<div className="card w-50 mx-auto">
<table>
<thead>
<tr>
<th>Title</th>
<th>Upvotes</th>
<th>Date</th>
</tr>
</thead>
<tbody>
{articles.map((article, index) => (
<tr data-testid="article" key={index}>
<td data-testid="article-title">{article.title}</td>
<td data-testid="article-upvotes">{article.upvotes}</td>
<td data-testid="article-date">{article.date}</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
export default Articles;State Management - Medium - Code Review Feedback
Your task is to create a React application called “Code Review Feedback” that tracks and manages feedback on various aspects of code quality. The component should have upvote and downvote functionality for each aspect, and it must meet all specified requirements.
Detailed Requirements
The CodeReviewFeedback component displays five aspects: Readability, Performance, Security, Documentation, and Testing.
Each aspect has two buttons labeled “Upvote” and “Downvote” to allow users to vote.
The initial count for upvotes and downvotes for each aspect is set to zero.
Clicking the “Upvote” button should increment the upvote count for that aspect by 1.
Clicking the “Downvote” button should increment the downvote count for that aspect by 1.
Ensure the counts update in the UI immediately upon clicking.
The component should have a subtle animation when the voting count is updated to enhance the user experience.
Sample Interaction
Initial State
Display all five aspects with their respective upvote and downvote buttons.
Each aspect shows an initial count of 0 for upvotes and downvotes.
User Action 1
User clicks “Upvote” for Readability.
The upvote count for Readability displays 1.
User Action 2
User clicks “Downvote” for Performance.
The downvote count for Performance displays 1.
User Action 3 3. User clicks “Upvote” for Security and Documentation multiple times. 4. The upvote count for Security displays 2 and Documentation displays 3.
App.js
import React from "react";
import "./App.css";
import "h8k-components";
import FeedbackSystem from "./components/CodeReviewFeedback";
const title = "Code Review Feedback";
const App = () => {
return (
<div className="App">
<h8k-navbar header={title}></h8k-navbar>
<FeedbackSystem />
</div>
);
};
export default App;CodeReviewFeedback.js
import React from "react";
const FeedbackSystem = () => {
return (
<div className="my-0 mx-auto text-center w-mx-1200">
<div className="flex wrap justify-content-center mt-30 gap-30">
<div className="pa-10 w-300 card">
<h2>Readability</h2>
<div className="flex my-30 mx-0 justify-content-around">
<button className="py-10 px-15" data-testid="upvote-btn-0">
👍 Upvote
</button>
<button className="py-10 px-15 danger" data-testid="downvote-btn-0">
👎 Downvote
</button>
</div>
<p className="my-10 mx-0" data-testid="upvote-count-0">
Upvotes: <strong>{0}</strong>
</p>
<p className="my-10 mx-0" data-testid="downvote-count-0">
Downvotes: <strong>{0}</strong>
</p>
</div>
</div>
</div>
);
};
export default FeedbackSystem;https://www.hackerrank.com/challenges/code-review-feedback/problem?isFullScreen=true
CodeReviewFeedback.js
import React, { useState } from "react";
const aspects = [
"Readability",
"Performance",
"Security",
"Documentation",
"Testing"
];
const FeedbackSystem = () => {
const [votes, setVotes] = useState(
aspects.map(() => ({ up: 0, down: 0 }))
);
const [animateIndex, setAnimateIndex] = useState(null);
const handleUpvote = (index) => {
const updated = [...votes];
updated[index].up += 1;
setVotes(updated);
triggerAnimation(index);
};
const handleDownvote = (index) => {
const updated = [...votes];
updated[index].down += 1;
setVotes(updated);
triggerAnimation(index);
};
const triggerAnimation = (index) => {
setAnimateIndex(index);
setTimeout(() => setAnimateIndex(null), 200);
};
return (
<div className="my-0 mx-auto text-center w-mx-1200">
<div className="flex wrap justify-content-center mt-30 gap-30">
{aspects.map((aspect, index) => (
<div
key={aspect}
className={`pa-10 w-300 card ${
animateIndex === index ? "vote-animate" : ""
}`}
>
<h2>{aspect}</h2>
<div className="flex my-30 mx-0 justify-content-around">
<button
className="py-10 px-15"
data-testid={`upvote-btn-${index}`}
onClick={() => handleUpvote(index)}
>
👍 Upvote
</button>
<button
className="py-10 px-15 danger"
data-testid={`downvote-btn-${index}`}
onClick={() => handleDownvote(index)}
>
👎 Downvote
</button>
</div>
<p className="my-10 mx-0" data-testid={`upvote-count-${index}`}>
Upvotes: <strong>{votes[index].up}</strong>
</p>
<p className="my-10 mx-0" data-testid={`downvote-count-${index}`}>
Downvotes: <strong>{votes[index].down}</strong>
</p>
</div>
))}
</div>
</div>
);
};
export default FeedbackSystem;Interaction - Medium - Patient Medical Records
In this challenge, you will create a React application called “Patient Medical Records” that allows users to view and cycle through patients’ medical records. The application requirements are outlined below, and your finished implementation must pass all provided unit tests.
Detailed Requirements
The application consists of two components: Search and Records.
Search: Contains a dropdown select menu and a “Show” button.
Records: Displays the selected patient’s records in a table and includes a “Next” button to navigate to the next patient’s records.
The Search component must have a dropdown select menu populated with 3 patient names from a file named medicalRecords.js. By default, the dropdown should display “Select Patient” with both selected and disabled attributes.
When the application is first loaded, no record table or “Next” button should be visible.
Show Button Functionality:
If the user clicks “Show” without selecting a patient, an alert should appear with the message: “Please select a patient name”.
If a patient is selected, clicking “Show” should display a table containing all of the selected patient’s details and medical records. The table must also include a “Next” button to navigate through records.
Next Button Functionality:
Clicking “Next” should display the medical records for the next patient in the list based on their ID.
If the last patient’s records are being displayed, clicking “Next” should loop back to the first patient’s records.
Sample Interaction
Initial State
The select menu displays “Select Patient”.
No records or “Next” button is visible.
User Action 1
The user selects a patient from the dropdown menu and clicks “Show”
The patient’s details and records appear in a table along with a “Next” button.
User Action 2
The user clicks “Next” to view the next patient’s records.
The table updates with the next patient’s details.
User Action 3
If the user is on the last patient and clicks “Next”, the records cycle back to the first patient
App.js
import React from "react";
import "./App.css";
import "h8k-components";
import Search from "./components/Search";
import Records from "./components/Records";
const title = "Patient Medical Records";
const App = () => {
return (
<div className="App">
<h8k-navbar header={title}></h8k-navbar>
<div className="content">
<Search />
<Records />
</div>
</div>
);
};
export default App;Records.js
import React from "react";
import medical_records from "../medicalRecords";
function Records() {
return (
<div className="patient-profile-container" id="profile-view">
<div className="layout-row justify-content-center">
<div id="patient-profile" data-testid="patient-profile" className="mx-auto">
<h4 id="patient-name">{"Patient Name"}</h4>
<h5 id="patient-dob">DOB: {"Patient DOB"}</h5>
<h5 id="patient-height">Height: {"Patient Height"}</h5>
</div>
<button className="mt-10 mr-10" data-testid="next-btn">
Next
</button>
</div>
<table id="patient-records-table">
<thead id="table-header">
<tr>
<th>SL</th>
<th>Date</th>
<th>Diagnosis</th>
<th>Weight</th>
<th>Doctor</th>
</tr>
</thead>
<tbody id="table-body" data-testid="patient-table">
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
</div>
);
}
export default Records;Search.js
import React from "react";
import medical_records from "../medicalRecords";
function Search({ setRecord, setId, id }) {
return (
<div className="layout-row align-items-baseline select-form-container">
<div className="select">
<select data-testid="patient-name" defaultValue="0">
<option value="0" disabled>
Select Patient
</option>
<option value={"1"}>{"John Oliver"}</option>
</select>
</div>
<button type="submit" data-testid="show">
Show
</button>
</div>
);
}
export default Search;https://www.hackerrank.com/challenges/patient-medical-records/problem?isFullScreen=true
App.js
import React, { useState } from "react";
import "./App.css";
import "h8k-components";
import Search from "./components/Search";
import Records from "./components/Records";
const title = "Patient Medical Records";
const App = () => {
const [record, setRecord] = useState(false); // whether to show Records
const [id, setId] = useState(0); // current patient index
return (
<div className="App">
<h8k-navbar header={title}></h8k-navbar>
<div className="content">
<Search setRecord={setRecord} setId={setId} />
{record && <Records id={id} setId={setId} />}
</div>
</div>
);
};
export default App;Records.js
import React from "react";
import medical_records from "../medicalRecords";
function Records({ id, setId }) {
const patient = medical_records[id];
const firstRecord = patient.data[0]; // first record contains name, dob, height
const handleNext = () => {
const nextId = (id + 1) % medical_records.length;
setId(nextId);
};
return (
<div className="patient-profile-container" id="profile-view">
<div className="layout-row justify-content-center">
<div
id="patient-profile"
data-testid="patient-profile"
className="mx-auto"
>
<h4 id="patient-name">{firstRecord.userName}</h4>
<h5 id="patient-dob">DOB: {firstRecord.userDob}</h5>
<h5 id="patient-height">Height: {firstRecord.meta.height} cm</h5>
</div>
<button
className="mt-10 mr-10"
data-testid="next-btn"
onClick={handleNext}
>
Next
</button>
</div>
<table id="patient-records-table">
<thead id="table-header">
<tr>
<th>SL</th>
<th>Date</th>
<th>Diagnosis</th>
<th>Weight</th>
<th>Doctor</th>
</tr>
</thead>
<tbody id="table-body" data-testid="patient-table">
{patient.data.map((record, index) => (
<tr key={record.id}>
<td>{index + 1}</td>
<td>{new Date(record.timestamp).toLocaleDateString("en-GB")}</td>
<td>{record.diagnosis.name}</td>
<td>{record.meta.weight}</td>
<td>{record.doctor.name}</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
export default Records;Search.js
import React, { useState } from "react";
import medical_records from "../medicalRecords";
function Search({ setRecord, setId }) {
const [selected, setSelected] = useState("0");
const handleShow = () => {
if (selected === "0") {
alert("Please select a patient name");
return;
}
setId(Number(selected) - 1); // IDs start at 1
setRecord(true);
};
return (
<div className="layout-row align-items-baseline select-form-container">
<div className="select">
<select
data-testid="patient-name"
defaultValue="0"
onChange={(e) => setSelected(e.target.value)}
>
<option value="0" disabled>
Select Patient
</option>
{medical_records.map((patient) => (
<option key={patient.id} value={patient.id}>
{patient.data[0].userName}
</option>
))}
</select>
</div>
<button type="button" data-testid="show" onClick={handleShow}>
Show
</button>
</div>
);
}
export default Search;