Nuro 45-min FE Interview - late-June
Problem description:
1 2 3
| Self dismissing modal 1. When button is clicked, modal should cover the page 2. After 5 seconds, the modal closes on it's own
|
Revised implementation w/o error risk when using JSX element VS functional call:
App.tsx1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| import './App.css'; import 'h8k-components'; import React, { useState, useEffect } from 'react'; const title = "React App"; const App = () => { const [count, setCount] = useState(0); const [modalVisible, setModalVisible] = useState(false);
useEffect(() => { if (modalVisible) { const interval = setInterval(() => { if (modalVisible && count > 0) { setCount(count => count - 1); } }, 1000); return () => { clearInterval(interval); } } }, [modalVisible]); const Modal = () => ( <div style={{ display: modalVisible ? 'flex' : 'none', flexDirection: 'column', padding: '18px' }}> <h2>This is a modal</h2> <p>Countdown: {count} second(s) left ...</p> </div>); return ( <div className="App"> <Modal /> {/* {Modal()} */} <h8k-navbar header={title}></h8k-navbar> <div className="fill-height layout-column justify-content-center align-items-center"> {/* step 2: replace the button to open the model */} <button onClick={() => { setModalVisible(true); setCount(5); setTimeout(() => setModalVisible(false), 5000); }} disabled={modalVisible}>Open Modal</button> </div> </div> ); } export default App;
|
Original defective implementation during the interview:
./src/App.js1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| import './App.css'; import 'h8k-components'; import React, { useState, useEffect } from 'react'; const title = "React App";
const App = () => { const [count, setCount] = useState(0); const [modalVisible, setModalVisible] = useState(false); const [countDown, setCountDown] = useState(false); useEffect(() => { console.log('modal visible:', modalVisible); if (modalVisible && !countDown) { setInterval(() => { if (modalVisible && count > 0) { console.log('time left:', count); } }, 1000); } return () => { clearTimeout(); } }, [modalVisible]); const Modal = () => {
return (<div style={{ display: modalVisible ? 'flex' : 'none', flexDirection: 'column', padding: '18px' }}> <h2>This is a modal</h2> <p>Countdown: {count} second(s) left ...</p> </div>) }; return ( <div className="App"> <Modal /> {/* {Modal()} */} <h8k-navbar header={title}></h8k-navbar> <div className="fill-height layout-column justify-content-center align-items-center"> {/* <p data-testid="output">You clicked {count} times ...</p> */} {/* <button data-testid="add-button" onClick={() => setCount(count + 1)}>Click Me</button> */} {/* step 2: replace the button to open the model */} <button onClick={() => { setModalVisible(true); setCount(5); setTimeout(() => setModalVisible(false), 5000); setCountDown(true); }} disabled={modalVisible}>Open Modal</button> </div> </div> ); } export default App;
|
./src/App.css1
| @import '../node_modules/h8k-design/dist/index.css';
|
./src/index.js1 2 3 4 5 6 7 8 9
| import React from 'react'; import ReactDOM from 'react-dom'; import App from './App'; import {applyPolyfills, defineCustomElements} from 'h8k-components/loader';
ReactDOM.render(<App />, document.getElementById('root')); applyPolyfills().then(() => { defineCustomElements(window); })
|
package.json1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| { "name": "react-app", "version": "0.1.0", "private": true, "dependencies": { "h8k-components": "^1.0.0", "h8k-design": "^1.0.16", "react": "^16.13.1", "react-dom": "^16.13.1", "react-scripts": "3.4.1", "@testing-library/jest-dom": "5.16.1", "@testing-library/react": "12.1.2" }, "scripts": { "prestart": "npm install", "start": "cross-env HOST=0.0.0.0 PORT=8000 ./node_modules/.bin/react-scripts start" }, "devDependencies": { "cross-env": "^7.0.2" }, "browserslist": { "production": [ ">0.2%", "not dead", "not op_mini all" ], "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] } }
|
Yahoo Final Rounds - FE Section - mid-March
External references after revision:
Revised implementation of App
component:
App.tsx1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
| function App() { const [comments, setComments] = useState([]); const [inputValue, setInputValue] = useState({ id: '', name: '', email: '', body: '', }); const getComments = async () => { try { const response = await fetch('https://jsonplaceholder.typicode.com/posts/1/comments'); if (!response.ok) { throw new Error(`Response status: ${response.status}`); } const json = await response.json(); console.log('resp:', json); setComments(json); } catch (error) { console.error(error.message); } }; const submitComment = (event) => { event.preventDefault(); const newComment = { ...inputValue }; console.log('inputs:', newComment); setComments((prevComments) => [newComment, ...prevComments]); setInputValue({ id: '', name: '', email: '', body: '' }); }; useEffect(() => { getComments(); }, []); return ( <div className="app"> <h1>Comments</h1> <form> <div> <span>ID:</span> <input id="id-input" type="text" value={inputValue.id} onChange={(e) => setInputValue((prevInput) => { return { ...prevInput, id: e.target.value } })}/> </div> <div> <span>Name:</span> <input id="name-input" type="text" value={inputValue.name} onChange={(e) => setInputValue((prevInput) => { return { ...prevInput, name: e.target.value } })}/> </div> <div> <span>Email:</span> <input id="email-input" type="text" value={inputValue.email} onChange={(e) => setInputValue((prevInput) => { return { ...prevInput, email: e.target.value } })}/> </div> <div> <span>Content:</span> <input id="comment-input" type="text" value={inputValue.body} onChange={(e) => { // console.log('Input onchange:', e.target.value, e.currentTarget.value); // setInputValue(e.target.value); setInputValue((prevInput) => { return { ...prevInput, body: e.target.value } }) }} /> </div> <button type="submit" onClick={submitComment}>Submit Comment</button> </form> <ul> { comments.map((comment) => { const { id, name, email, body } = comment; return ( <li key={`comment-key-${id}`}> <div> <h4>{name} {email}</h4> <p>{body}</p> </div> </li> ); }) } </ul> </div> ) } export default App;
|
Wisdom AI 60-min Screening in FE - early-Feb
Problem: Implement a FE page of basic card game using stackblitz.com online IDE (JS only, no TS support).
Constants1 2
| const numbers = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A']; const suits = ['♠', '♣', '♥', '♦'];
|
Revised coding (online IDE / Live Demo):
style.css1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| h1, p { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; } .card-list { display: flex; column-gap: 4px; } .card { border: 2px solid green; border-radius: 4px; display: flex; align-items: center; justify-content: center; min-width: 50px; min-height: 30px; }
|
App.js1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| import React, { useState } from 'react'; import './style.css'; const numbers = [ '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A', ]; const suits = ['♠', '♣', '♥', '♦']; const generate_card = () => { const random_num = Math.floor(Math.random() * numbers.length); const random_suit = Math.floor(Math.random() * suits.length); return numbers[random_num] + suits[random_suit]; }; const draw_cards = (card_num) => { const cards = new Set(); while (cards.size < card_num) { const new_card = generate_card(); if (cards.has(new_card)) { continue; } cards.add(new_card); } return Array.from(cards); }; export default function App() { const [cardNum, setCardNum] = useState(5); const [cardList, setCardList] = useState([]); const deal_a_hand = () => { setCardList(() => { const cards = draw_cards(cardNum); return cards.map((card) => <span className="card">{card}</span>); }); setCardNum(4); }; return ( <div> {/* <h1>Hello StackBlitz!</h1> <p>Start editing to see some magic happen :)</p> */} <button onClick={deal_a_hand}>Deal a Hand</button> <h2>Cards</h2> <div className="card-column"> <p className="card-list">{cardList}</p> </div> </div> ); }
|