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
27 changes: 27 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,30 @@ It is important that you minimally attempt the problems, even if you do not arri
## Submission ##
You can either provide a link to an online repository, attach the solution in your application, or whichever method you prefer.
We're cool as long as we can view your solution without any pain.

## Execution ##

**Prerequisites:** [Node.js](https://nodejs.org) 18+ (only needed for Problem 2).

### Problem 1 — Sum to N
Runs the three implementations against a built-in test suite:

```bash
node src/problem1/index.js
```

### Problem 2 — Currency Swap Form
First install dependencies, then start the dev server:

```bash
cd src/problem2
npm install
npm run dev
```

Then open http://localhost:5173 in your browser.
Run the test suite with `npm run test:run`.

### Problem 3 — React Code Review
The list of issues and the refactored solution are written at the bottom of
[`src/problem3/task.md`](src/problem3/task.md).
75 changes: 75 additions & 0 deletions src/problem1/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Three unique implementations of summation to n.

// Implementation A: closed-form (Gauss) formula. O(1) time and space.
var sum_to_n_a = function (n) {
const sign = n < 0 ? -1 : 1;
const m = Math.abs(n);
return sign * (m * (m + 1)) / 2;
};

// Implementation B: iterative accumulation. O(n) time, O(1) space.
var sum_to_n_b = function (n) {
let sum = 0;
const sign = n < 0 ? -1 : 1;
for (let i = 1; i <= Math.abs(n); i++) {
sum += i * sign;
}
return sum;
};

// Implementation C: functional reduce over a generated range. O(n) time and space.
var sum_to_n_c = function (n) {
const sign = n < 0 ? -1 : 1;
return Array.from({ length: Math.abs(n) }, function (_, i) {
return (i + 1) * sign;
}).reduce(function (acc, value) {
return acc + value;
}, 0);
};

// --- Tests ---------------------------------------------------------------
// Contract: any integer. Negative n sums |n| terms with n's sign, e.g.
// sum_to_n(-5) === -(1+2+3+4+5) === -15. All three should agree everywhere.
function runTestCases() {
const testCases = [
{ input: 0, expected: 0 },
{ input: 1, expected: 1 },
{ input: 5, expected: 15 },
{ input: 10, expected: 55 },
{ input: 100, expected: 5050 },
{ input: -1, expected: -1 },
{ input: -5, expected: -15 },
{ input: -10, expected: -55 },
{ input: -100, expected: -5050 },
];

const implementations = [
{ name: "Implementation A", fn: sum_to_n_a },
{ name: "Implementation B", fn: sum_to_n_b },
{ name: "Implementation C", fn: sum_to_n_c },
];

console.log("Running Tests...\n");

let passed = 0;
let failed = 0;

testCases.forEach(({ input, expected }) => {
console.log(`Test n = ${input} (expected: ${expected})`);
implementations.forEach(({ name, fn }) => {
const result = fn(input);
const pass = result === expected;
pass ? passed++ : failed++;
console.log(
` ${name}: ${result} → ${pass ? "PASS" : "FAIL"}`
);
});
console.log("");
});

const total = passed + failed;
console.log(`All tests completed: ${passed}/${total} passed, ${failed} failed.`);
}

// Execute test cases
runTestCases();
11 changes: 11 additions & 0 deletions src/problem2/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
node_modules
dist
dist-ssr
*.local
.vite

# Editor / OS
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
79 changes: 79 additions & 0 deletions src/problem2/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Fancy Swap — Currency Swap Form

A polished currency swap interface built with **Vite + React + TypeScript**.

![stack](https://img.shields.io/badge/Vite-React-TypeScript-7c6cff)

## Run it

```bash
cd src/problem2
npm install
npm run dev # http://localhost:5173
```

Other scripts:

```bash
npm run build # type-check (tsc -b) + production build to dist/
npm run preview # serve the production build
npm test # run the Vitest suite in watch mode
npm run test:run # run the suite once (CI)
```

> On Windows PowerShell, chain commands with `;` (and `if ($?)`) rather than
> `&&`, e.g. `cd src/problem2; if ($?) { npm run dev }`.

## What it does

- **Live prices & rates** — fetches the [Switcheo price feed](https://interview.switcheo.com/prices.json),
de-duplicates it (keeping the most recent record per currency), and computes the
exchange rate as `priceFrom / priceTo`. Tokens without a price are omitted.
- **Token picker** — searchable modal listing every priced token with its icon
(from the [Switcheo token-icons repo](https://github.com/Switcheo/token-icons/tree/main/tokens))
and USD price. Icons that don't exist fall back to a coloured monogram.
- **Two-way form** — type into "You pay" to compute "You receive"; the flip
button swaps direction and carries the amount over.
- **Validation** — rejects non-numeric/negative input and flags
*insufficient balance* against a mock per-token wallet ("Max" fills the field).
- **Simulated backend** — "Confirm swap" shows a loading spinner for ~1.6s,
then a success state (no real funds move).

## Structure

```
src/
components/
SwapForm.tsx # form state, validation, submit simulation
TokenSelect.tsx # searchable token-picker modal
TokenIcon.tsx # SVG icon with monogram fallback
hooks/
usePrices.ts # fetches the feed -> derived token list
lib/
tokens.ts # price parsing, icon URLs, number formatting
types.ts # shared types
App.tsx # loading / error / form states
index.css # design system + component styles
```

## Tests

[Vitest](https://vitest.dev) + React Testing Library (chosen over Jest because it
reuses the Vite pipeline — native TS/ESM, no separate transform config). 21 specs:

- `lib/tokens.test.ts` — price de-duplication (latest-by-date, the timestamp-tie
rule, dropping non-positive/malformed records, sorting) and number formatting.
- `hooks/usePrices.test.ts` — loading → tokens / error transitions with a mocked `fetch`.
- `components/SwapForm.test.tsx` — rate calculation, input guarding, the
insufficient-balance error, the flip button, and the simulated swap lifecycle.

```bash
npm run test:run
```

## Notes

- Wallet balances are mocked (deterministic per symbol) since there is no
real account — enough to make the balance/Max/insufficient checks meaningful.
- No UI framework was used; the design system lives in `index.css` so the visual
style is fully hand-authored.
40 changes: 14 additions & 26 deletions src/problem2/index.html
Original file line number Diff line number Diff line change
@@ -1,27 +1,15 @@
<html>

<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Fancy Form</title>

<!-- You may add more stuff here -->
<link href="style.css" rel="stylesheet" />
</head>

<body>

<!-- You may reorganise the whole HTML, as long as your form achieves the same effect. -->
<form onsubmit="return !1">
<h5>Swap</h5>
<label for="input-amount">Amount to send</label>
<input id="input-amount" />

<label for="output-amount">Amount to receive</label>
<input id="output-amount" />

<button>CONFIRM SWAP</button>
</form>
<script src="script.js"></script>
</body>

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/swap.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="preconnect" href="https://raw.githubusercontent.com" crossorigin />
<link rel="dns-prefetch" href="https://raw.githubusercontent.com" />
<title>Fancy Swap — Currency Exchange</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
Loading