├── src
├── react-app-env.d.ts
├── App.tsx
├── index.tsx
├── setupTests.ts
├── App.test.tsx
└── assets
│ └── icons
│ ├── have-a-baby.svg
│ ├── throw-a-wedding-party.svg
│ ├── take-a-vacation.svg
│ ├── buy-a-car.svg
│ ├── go-to-college.svg
│ ├── build-an-emergency-fund.svg
│ └── buy-a-house.svg
├── .prettierrc
├── .gitignore
├── public
├── favicon.png
└── index.html
├── mockups
├── saving-goal-plan-desk.png
└── saving-goal-plan-mobile.png
├── .editorconfig
├── tsconfig.json
├── .circleci
└── config.yml
├── package.json
├── .eslintrc
└── README.md
/src/react-app-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "tabWidth": 2
4 | }
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 | .cache
4 | coverage
5 | *.DS_Store
6 | .idea/
7 |
--------------------------------------------------------------------------------
/public/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OriginFinancial/frontend-take-home-assignment/HEAD/public/favicon.png
--------------------------------------------------------------------------------
/mockups/saving-goal-plan-desk.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OriginFinancial/frontend-take-home-assignment/HEAD/mockups/saving-goal-plan-desk.png
--------------------------------------------------------------------------------
/mockups/saving-goal-plan-mobile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OriginFinancial/frontend-take-home-assignment/HEAD/mockups/saving-goal-plan-mobile.png
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | indent_size = 2
6 | charset = utf-8
7 | trim_trailing_whitespace = true
8 | insert_final_newline = true
--------------------------------------------------------------------------------
/src/App.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export function App(): JSX.Element {
4 | return
Welcome to the Origin THA
;
5 | }
6 |
--------------------------------------------------------------------------------
/src/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import { App } from './App';
4 |
5 | ReactDOM.render(
6 |
7 |
8 | ,
9 | document.getElementById('root')
10 | );
11 |
--------------------------------------------------------------------------------
/src/setupTests.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-var-requires,@typescript-eslint/naming-convention */
2 |
3 | import '@testing-library/jest-dom';
4 | const Adapter = require('@wojtekmaj/enzyme-adapter-react-17');
5 | const Enzyme = require('enzyme');
6 |
7 | Enzyme.configure({ adapter: new Adapter() });
8 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": [
5 | "dom",
6 | "dom.iterable",
7 | "esnext"
8 | ],
9 | "allowJs": true,
10 | "skipLibCheck": true,
11 | "esModuleInterop": true,
12 | "allowSyntheticDefaultImports": true,
13 | "strict": true,
14 | "forceConsistentCasingInFileNames": true,
15 | "noFallthroughCasesInSwitch": true,
16 | "module": "esnext",
17 | "moduleResolution": "node",
18 | "resolveJsonModule": true,
19 | "isolatedModules": true,
20 | "noEmit": true,
21 | "jsx": "react-jsx"
22 | },
23 | "include": [
24 | "src"
25 | ]
26 | }
27 |
--------------------------------------------------------------------------------
/src/App.test.tsx:
--------------------------------------------------------------------------------
1 | import { shallow } from 'enzyme';
2 | import { App } from './App';
3 | import { render } from '@testing-library/react';
4 |
5 | describe('App', () => {
6 | describe('using enzyme', () => {
7 | it('returns the text', () => {
8 | const component = shallow();
9 |
10 | expect(component.find('[data-testid="greetings-container"]').text()).toBe(
11 | 'Welcome to the Origin THA'
12 | );
13 | });
14 | });
15 |
16 | describe('using testing library', () => {
17 | it('returns the text', () => {
18 | const component = render();
19 |
20 | expect(component.getByTestId('greetings-container').innerHTML).toBe(
21 | 'Welcome to the Origin THA'
22 | );
23 | });
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | version: 2.1
2 | jobs:
3 | test_and_lint:
4 | docker:
5 | - image: circleci/node:latest-browsers
6 | working_directory: /home/circleci/frontend-take-home-assignment
7 | steps:
8 | - checkout
9 | - restore_cache:
10 | keys:
11 | - frontend-take-home-assignment-deps-{{ .Branch }}-{{ checksum "package.json" }}
12 | - frontend-take-home-assignment-deps-develop-{{ checksum "package.json" }}
13 | - frontend-take-home-assignment-deps-develop
14 | - run:
15 | name: Install dependencies
16 | command: |
17 | npm install
18 | - run:
19 | name: Linter
20 | command: |
21 | npm run lint
22 | - run:
23 | name: Run tests
24 | command: |
25 | npm run test
26 |
27 | workflows:
28 | version: 2
29 | pipeline:
30 | jobs:
31 | - test_and_lint
32 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 | Saving Goals - Origin
13 |
14 |
15 |
16 |
17 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "frontend-take-home-assignment",
3 | "version": "0.1.0",
4 | "dependencies": {
5 | "@testing-library/jest-dom": "^5.11.4",
6 | "@testing-library/react": "^11.1.0",
7 | "@testing-library/user-event": "^12.1.10",
8 | "@types/jest": "^26.0.15",
9 | "@types/node": "^12.0.0",
10 | "@types/react": "^17.0.0",
11 | "@types/react-dom": "^17.0.0",
12 | "react": "^17.0.2",
13 | "react-dom": "^17.0.2",
14 | "react-scripts": "4.0.3",
15 | "styled-components": "^5.3.0",
16 | "typescript": "^4.1.2",
17 | "web-vitals": "^1.0.1"
18 | },
19 | "scripts": {
20 | "start": "react-scripts start",
21 | "build": "react-scripts build",
22 | "test": "react-scripts test",
23 | "eject": "react-scripts eject",
24 | "format": "prettier --write src/**/*.{ts,tsx}",
25 | "lint": "eslint './src/**/*.{ts,tsx}' --max-warnings=0"
26 | },
27 | "eslintConfig": {
28 | "extends": [
29 | "react-app",
30 | "react-app/jest"
31 | ]
32 | },
33 | "browserslist": {
34 | "production": [
35 | ">0.2%",
36 | "not dead",
37 | "not op_mini all"
38 | ],
39 | "development": [
40 | "last 1 chrome version",
41 | "last 1 firefox version",
42 | "last 1 safari version"
43 | ]
44 | },
45 | "devDependencies": {
46 | "@types/enzyme": "^3.10.8",
47 | "@typescript-eslint/eslint-plugin": "^4.27.0",
48 | "@typescript-eslint/parser": "^4.27.0",
49 | "@wojtekmaj/enzyme-adapter-react-17": "^0.6.2",
50 | "enzyme": "^3.11.0",
51 | "eslint": "^7.28.0",
52 | "eslint-config-prettier": "^8.3.0",
53 | "eslint-plugin-prettier": "^3.4.0",
54 | "eslint-plugin-react": "^7.24.0",
55 | "eslint-plugin-react-hooks": "^4.2.0",
56 | "prettier": "^2.3.1"
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/assets/icons/have-a-baby.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "react-app",
4 | "eslint:recommended",
5 | "plugin:react/recommended",
6 | "plugin:@typescript-eslint/recommended",
7 | "plugin:prettier/recommended"
8 | ],
9 | "parser": "@typescript-eslint/parser",
10 | "rules": {
11 | "react/prop-types": [0],
12 | "react/react-in-jsx-scope": [0],
13 | "react/jsx-filename-extension": [1, { "extensions": [".ts", ".tsx"] }],
14 | "import/no-named-as-default": 0,
15 | "react-hooks/rules-of-hooks": "error",
16 | "react-hooks/exhaustive-deps": "warn",
17 | "prettier/prettier": ["error", { "singleQuote": true }],
18 | "@typescript-eslint/explicit-member-accessibility": 0,
19 | "@typescript-eslint/explicit-function-return-type": 0,
20 | "@typescript-eslint/no-explicit-any": 1,
21 | "@typescript-eslint/naming-convention": [
22 | "error",
23 | {
24 | "selector": "default",
25 | "format": ["camelCase"],
26 | "leadingUnderscore": "allow",
27 | "trailingUnderscore": "allow"
28 | },
29 | {
30 | "selector": "variable",
31 | "format": ["camelCase", "UPPER_CASE"],
32 | "leadingUnderscore": "allow",
33 | "trailingUnderscore": "allow"
34 | },
35 | {
36 | "selector": "typeLike",
37 | "format": ["PascalCase"]
38 | },
39 | {
40 | "selector": "function",
41 | "format": ["PascalCase", "camelCase"]
42 | }
43 | ]
44 | },
45 | "env": {
46 | "browser": true,
47 | "node": true,
48 | "es6": true,
49 | "jest": true
50 | },
51 | "globals": {
52 | "document": false
53 | },
54 | "plugins": ["react-hooks", "@typescript-eslint", "prettier"],
55 | "settings": {
56 | "import/resolver": {
57 | "node": {
58 | "paths": ["src"],
59 | "extensions": [".ts", ".tsx"]
60 | }
61 | },
62 | "react": {
63 | "pragma": "React",
64 | "version": "detect"
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/assets/icons/throw-a-wedding-party.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Origin Frontend Take-Home Assignment
2 |
3 | **IMPORTANT**: you can choose any technology stack to implement this assignment. Using our stack is not a requirement in the selection process - we will consider exclusively the quality of your project (technology and product-wise) to evaluate your work. We've added a project structure in this repository (a buildwith react, redux, jest, styled-components and typescript) to save you time if you want to use it. If you prefer another stack, feel free to use it.
4 |
5 | Origin is a platform that helps our customers' employees put their financial lives on track.
6 |
7 | One key to financial well-being is planning & saving for your goals. Users can have many saving goals (e.g. go to college or throw a wedding party) and it is our job to help them accomplish it.
8 |
9 | You will build a piece of our savings feature by creating the savings plan simulation screen.
10 |
11 | ### The Saving Goal Plan Simulation Screen
12 |
13 | 
14 |
15 | You will build a screen where the user will simulate saving towards the "Buy a house" savings goal.
16 | In it, the users choose (i) the value they want to save and (ii) the date they plan to reach the goal.
17 |
18 | When the users change the value of any of the inputs, the monthly deposit value is calculated and displayed to them.
19 |
20 | # Development Instructions
21 |
22 | ### Evaluation
23 | Be aware that Origin will mainly take into consideration the following evaluation criteria:
24 | * How close your page is to the mockups, both on mobile & desktop;
25 | * How clean and organized your code is;
26 | * How good your automated tests are, i.e.: qualitative over quantitative (in case of usage of this base project, feel free to choose between jest or testing library);
27 | * If you implemented the business rules correctly.
28 |
29 | ### Assets
30 | You can find the layout mockups here on our Figma project:
31 | [Layout mockups](https://www.figma.com/file/Axdg0WSJURcxp8Arq3gg9x/Take-Home-Assignment-v2)
32 |
33 | Once you have opened the link you must sign up and log in so you can have access to the colors, fonts, margins and assets information.
34 |
35 | #### Money input
36 |
37 | The money input component should:
38 |
39 | - Allow only numbers
40 | - Display the value formatted as money (e.g 3500.45 should be 3,500.45)
41 | - We recommend you name this input as "amount"
42 |
43 | #### Date input
44 |
45 | The date input component should:
46 |
47 | - Allow only future months
48 | - When clicking on the arrow buttons it should go up and down month by month
49 | - On focused, the users should be able to move the months by typing the Left and Right arrow key on the keyboard
50 | - We recommend you name this input as "reachDate"
51 |
52 | #### Confirm button
53 |
54 | You don't need to add any action on the confirmation button
55 |
56 | # Delivery Instructions
57 |
58 | Don't create a fork, send us the link to your repository and make sure to make it public.
59 |
60 | # Usage
61 |
62 | This project requires the latest LTS version of NodeJS and you may need to install the yarn as global dependency
63 | ```bash
64 | npm install -g yarn
65 | ```
66 |
67 | After you have cloned this repo and install the yarn, install the dependencies with:
68 |
69 | ```
70 | yarn install
71 | ```
72 |
73 | You can then start the application running:
74 |
75 | ```
76 | yarn start
77 | ```
78 |
79 | That's it. Just Access `http://localhost:3000` in your browser.
80 |
81 | ### Linting and Format
82 |
83 | ```
84 | yarn lint
85 | yarn format
86 | ```
87 |
88 | ### Testing
89 |
90 | ```
91 | yarn test
92 | ```
93 |
--------------------------------------------------------------------------------
/src/assets/icons/take-a-vacation.svg:
--------------------------------------------------------------------------------
1 |
25 |
--------------------------------------------------------------------------------
/src/assets/icons/buy-a-car.svg:
--------------------------------------------------------------------------------
1 |
17 |
--------------------------------------------------------------------------------
/src/assets/icons/go-to-college.svg:
--------------------------------------------------------------------------------
1 |
15 |
--------------------------------------------------------------------------------
/src/assets/icons/build-an-emergency-fund.svg:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/src/assets/icons/buy-a-house.svg:
--------------------------------------------------------------------------------
1 |
21 |
--------------------------------------------------------------------------------