Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
SKIP_PREFLIGHT_CHECK=true
2 changes: 1 addition & 1 deletion .eslintcache
Original file line number Diff line number Diff line change
@@ -1 +1 @@
[{"/Users/edvinasbartkus/argyle/frontend-exercise/src/index.js":"1","/Users/edvinasbartkus/argyle/frontend-exercise/src/App.js":"2"},{"size":193,"mtime":1610055841961,"results":"3","hashOfConfig":"4"},{"size":197,"mtime":1610440606101,"results":"5","hashOfConfig":"4"},{"filePath":"6","messages":"7","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"10xp97u",{"filePath":"8","messages":"9","errorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"/Users/edvinasbartkus/argyle/frontend-exercise/src/index.js",[],"/Users/edvinasbartkus/argyle/frontend-exercise/src/App.js",[]]
[{"C:\\Users\\Andrei\\Desktop\\React interview\\Argyle\\frontend-exercise\\src\\index.js":"1","C:\\Users\\Andrei\\Desktop\\React interview\\Argyle\\frontend-exercise\\src\\App.js":"2","C:\\Users\\Andrei\\Desktop\\React interview\\Argyle\\frontend-exercise\\src\\constants\\numbers-map.js":"3"},{"size":203,"mtime":1715442174353,"results":"4","hashOfConfig":"5"},{"size":4794,"mtime":1715588215381,"results":"6","hashOfConfig":"5"},{"size":535,"mtime":1715498252092,"results":"7","hashOfConfig":"5"},{"filePath":"8","messages":"9","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"1xi86wq",{"filePath":"10","messages":"11","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"12","messages":"13","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"C:\\Users\\Andrei\\Desktop\\React interview\\Argyle\\frontend-exercise\\src\\index.js",[],"C:\\Users\\Andrei\\Desktop\\React interview\\Argyle\\frontend-exercise\\src\\App.js",[],"C:\\Users\\Andrei\\Desktop\\React interview\\Argyle\\frontend-exercise\\src\\constants\\numbers-map.js",[]]
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"web-vitals": "^0.2.4"
},
"scripts": {
"start": "react-scripts start",
"start": "NODE_OPTIONS=--openssl-legacy-provider react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
Expand Down
142 changes: 135 additions & 7 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,144 @@
import { numbersMap, separators } from "./constants/numbers-map";
import { useState } from 'react';

const INCORRECT_TEXT = "incorrect";
const LINK_WORD = "and";
const ZERO_CASE_WORD = "zero";

function App() {
const text = ''
const [text, setText] = useState('');

function transformTextToNumber(inputWord) {
// Do not display anything if input has only spaces or it's empty
if(!inputWord.trim()){
return "";
}
// Condition for zero case
if (inputWord.toLowerCase().trim() === ZERO_CASE_WORD) {
return 0;
}

// will lowercase, trim and remove excessive whitespace characters to enhance user experience
const numberWords = inputWord.toLowerCase().trim().split(" ").filter(word => word !== "");

// Condition for first number
// it should be a number lower then 100
if (numbersMap[numberWords[0]] > 99) {
return INCORRECT_TEXT;
}

// Array to keep track of the digits that are available to be modified in the block total
// It has the following representation
// [0] -> hundreds
// [1] -> tens
// [2] -> units
let digitBlockedForChange = [false, false, false];
let total = 0;
let blockTotal = 0;
let nextMaxSeparator = Math.max(...separators);


for (let index = 0; index < numberWords.length; index++) {
// Will not enforce "AND" word in order to enhance user experience as some users
// usually type numbers without it but we will not accept "AND" word in a non semantic position
if (numberWords[index] === LINK_WORD) {
if (isLinkWordInCorrectPosition(index, numberWords)) {
continue;
} else {
return INCORRECT_TEXT;
}
}

const value = numbersMap[numberWords[index]];

// Check if the current word is a number word
if (!value) {
return INCORRECT_TEXT;
}

// If it's a separator lower then maximum allowed we will do the following:
// - add block total to the total
// - calculate next maximum separator
// - refresh block array of blocked digits
if (separators.includes(value)) {
if (value <= nextMaxSeparator) {
total = total + blockTotal * value;
blockTotal = 0;
nextMaxSeparator = getNextMaxSeparator(value);
digitBlockedForChange = [false, false, false];
} else {
return INCORRECT_TEXT;
}
} else {
if (value > 99) {
blockTotal = blockTotal * value;

// Actually last numbers were linked to hundred digits, so we need to unblock them and block only the hundreds digit
digitBlockedForChange = [true, false, false];

// Condition for too big and too small block total, for 2 cases:
// - hundreds encountered after a number bigger then 9
// - hundred encountered first in the block
if (blockTotal > 999 || blockTotal === 0) {
return INCORRECT_TEXT;
}
} else {
// Check if the encountered number can be added
// - basically checks if the order of numbers is correct
if (isNumbersOrderCorrect(value, digitBlockedForChange)) {
blockTotal += value;
} else {
return INCORRECT_TEXT;
}
}
}
}

return total + blockTotal;
}

function isNumbersOrderCorrect(value, digitBlockedForChange) {
const digits = value
.toString()
.padStart(3, "0")
.split("")
.map((value) => +value);

for (let index = 0; index < 3; index++) {
if (digits[index]) {
// if the digit is blocked (already changed) will return false because the order of words is wrong
if (digitBlockedForChange[index]) {
return false;
} else {
// if the digit is not blocked (already changed) we will mark as blocked all digits from previous positions, including the current one
// in order to prevent future adding in this block
for (let j = 0; j <= index; j++) {
digitBlockedForChange[j] = true;
}
}
}
}
return true;
}

function isLinkWordInCorrectPosition(index, words) {
return numbersMap[words[index-1]] > 99 && numbersMap[words[index+1]] <= 99
}

function getNextMaxSeparator(currentMax) {
return Math.max(
...separators.filter((separator) => separator < currentMax)
);
}

return (
<div>
<input type='text' />
<input type="text" onChange={(event) => { setText(transformTextToNumber(event.target.value)) }} />
<div>
<p>
Output: {text}
</p>
<p role="paragraph">Output: {text}</p>
</div>
</div>
)
);
}

export default App
export default App;
Loading