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
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# See https://help.github.com/customers/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
Expand Down
42 changes: 41 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,44 @@
# Getting Started with Create React App
# Customer List Test Project

Thanks for taking the time to look at this code test project. This project aims to give a reasonable baseline view of the tools and structure we work with, it is far from perfect and plays fast with some of the rules, but the overall structure looks a lot like something you'd see in an Alinta Energy project.

This project implements a customer list using a redux store, with a Formik form for adding customers. It is styled using styled-components at the most minimal level; our regular projects use a shared component library (ASG) which handles most elements and layout out of the box.

The redux store follows the slightly dated pattern of having actions, reducers and types in separate files. This is deliberate as it mirrors many of our existing projects, which were built before Redux Toolkit was available and stable.

## Setup

This project is bootstrap from react-create-app which allow you to use any of the [documentation for CRA](https://create-react-app.dev/docs/getting-started).

### Initial Set up steps:

- Run `yarn` this will install the needed npm packages and only needs to be run once.
- Run `yarn start` to run the app locally this will open a browser window for the site.
- Run `yarn test` to run the test. The results will display in the terminal window.

## Tasks

Please attempt one or more of the following improvement tasks on this project, and then either make a PR for review or submit a zip of the project.

**Time box yourself to 1 to 2 hours of work.**

We realise your time is valuable and don't need to see all these issues resolved. Pick a task or area that you excel or are passionate about. Complete as much as you can in the time you choose. We'll review your code in the technical interview, discuss choices you made and anything you'd like to improve if you had the time.

### Suggested Tasks

Use one of our suggested tasks or complete your own improvement to the project if you see something we haven't listed.

- Move the Add new customer, form it takes up a lot of space on mobile. It could move to another page or be hidden in an accordion.
- Add a birthday to the customers. Consider using a date-picker and it's pros and cons.
- Add validation. Currently, the form allows blank customers to be submitted; we only want customers with all fields filled in. Add validation that handles phone numbers in different formats.
- Improve accessibility. Add extra aria for screen readers and ensure users with other disabilities are catered for in the design.
- Convert the customer list to a table. The block layout is hard for users to scan down.
- Add search and sorting. As the list grows, users want to be able to search by name or phone number.
- Add a duplicate customer check. Prevent users from entering users with the same first and last name or phone number.
- Refactor the store; this is an expansive task. You could update the IDs to be unique and convert the customer list to a map to make editing more efficient. Or convert to a Redux Toolkit slices structure. Whatever you do, make sure it improves the implementation.
- Improve the tests. The current tests work as little more than a smoke test. They should be testing the functionality of the form and the delete button at a minimum.

## Getting Started with Create React App

This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).

Expand Down
12 changes: 11 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,21 @@
"@types/node": "^12.0.0",
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
"@types/react-redux": "^7.1.16",
"@types/react-router-dom": "^5.1.7",
"@types/styled-components": "^5.1.10",
"@types/yup": "^0.29.11",
"formik": "^2.2.9",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-redux": "^7.2.4",
"react-router-dom": "^5.2.0",
"react-scripts": "4.0.3",
"redux": "^4.1.0",
"styled-components": "^5.3.0",
"typescript": "^4.1.2",
"web-vitals": "^1.0.1"
"web-vitals": "^1.0.1",
"yup": "^0.32.9"
},
"scripts": {
"start": "react-scripts start",
Expand Down
Binary file removed public/favicon.ico
Binary file not shown.
14 changes: 7 additions & 7 deletions public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
<meta name="description" content="Customer List - Code Test" />
<link
rel="icon"
type="image/svg+xml"
href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 width=%22256%22 height=%22256%22 viewBox=%220 0 100 100%22><rect width=%22100%22 height=%22100%22 rx=%2220%22 fill=%22%23f26722%22></rect><path fill=%22%23fff%22 d=%22M34.71 81.99L33.17 70.04L12.73 70.04L7.07 81.99L-9.50 81.99L24.38 18.01L38.53 18.01L50.35 81.99L34.71 81.99ZM28.82 36.07L18.36 58.13L31.63 58.13L28.82 36.07ZM100.76 43.41L98.78 54.88L75.27 54.88L72.59 70.13L100.41 70.13L98.34 81.99L55.49 81.99L66.57 18.01L109.50 18.01L107.44 29.92L79.58 29.92L77.20 43.41L100.76 43.41Z%22></path></svg>"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
Expand All @@ -24,9 +24,9 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
<title>Customer List</title>
</head>
<body>
<body style="padding: 0; margin: 0">
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
Expand Down
Binary file removed public/logo192.png
Binary file not shown.
Binary file removed public/logo512.png
Binary file not shown.
38 changes: 0 additions & 38 deletions src/App.css

This file was deleted.

9 changes: 0 additions & 9 deletions src/App.test.tsx

This file was deleted.

39 changes: 18 additions & 21 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,23 @@
import React from 'react';
import logo from './logo.svg';
import './App.css';
import * as React from "react";
import { StyledMain, StyledHeader, StyledHeaderText } from "./StyledApp";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import Home from "./views/Home";

function App() {
const App: React.FC = () => {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.tsx</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
<StyledMain>
<StyledHeader>
<StyledHeaderText>Customer List</StyledHeaderText>
</StyledHeader>
<Router>
<Switch>
<Route path="/">
<Home />
</Route>
</Switch>
</Router>
</StyledMain>
);
}
};

export default App;
25 changes: 25 additions & 0 deletions src/StyledApp.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import styled from "styled-components";

export const StyledMain = styled.main`
box-sizing: border-box;
max-width: 100vw;
margin: 0;
padding: 0 1rem;
display: flex;
flex-direction: column;
align-items: center;
`;

export const StyledHeader = styled.div`
box-sizing: border-box;
min-width: 100vw;
background: rgb(4, 121, 205);
color: white;
padding: 1rem 2rem;
margin: 0 0 1rem;
`;

export const StyledHeaderText = styled.h1`
margin: 0;
padding: 0;
`;
12 changes: 12 additions & 0 deletions src/components/AddCustomer/AddCustomerForm.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import * as React from "react";
import { render } from "../../utils/testUtils";
import { AddCustomerForm } from "./AddCustomerForm";

describe("<AddCustomerForm />", () => {
it("should render a <AddCustomerForm />", () => {
const wrapper = render(<AddCustomerForm saveCustomer={() => {}} />);
expect(wrapper.container).toMatchSnapshot();
});

//@TODO Add tests for entering data and clicking submit
});
61 changes: 61 additions & 0 deletions src/components/AddCustomer/AddCustomerForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { Field, Formik, FormikHelpers } from "formik";
import * as React from "react";
import { ICustomer, Customer } from "../../types/types";
import {
StyledForm,
StyledInput,
StyledLabel,
StyledAddButton,
} from "./StyledAddCustomerForm";

type Props = {
saveCustomer: (customer: ICustomer | any) => void;
};

export const AddCustomerForm: React.FC<Props> = ({ saveCustomer }) => {
return (
<Formik
initialValues={{
firstName: "",
lastName: "",
phoneNumber: "",
}}
onSubmit={(
values: Customer,
{ setSubmitting }: FormikHelpers<Customer>
) => {
saveCustomer(values);
setSubmitting(false);
}}
>
<StyledForm>
<StyledLabel htmlFor="firstName">First Name</StyledLabel>
<Field
as={StyledInput}
id="firstName"
name="firstName"
placeholder="John"
/>

<StyledLabel htmlFor="lastName">Last Name</StyledLabel>
<Field
as={StyledInput}
id="lastName"
name="lastName"
placeholder="Doe"
/>

<StyledLabel htmlFor="phoneNumber">Phone Number</StyledLabel>
<Field
as={StyledInput}
id="phoneNumber"
name="phoneNumber"
placeholder="john@acme.com"
type="tel"
/>

<StyledAddButton type="submit">Add Customer</StyledAddButton>
</StyledForm>
</Formik>
);
};
32 changes: 32 additions & 0 deletions src/components/AddCustomer/StyledAddCustomerForm.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Form } from "formik";
import styled from "styled-components";

export const StyledForm = styled(Form)`
box-sizing: border-box;
min-width: 100%;
border: 1px solid #ccc;
margin: 0 1rem;
padding: 1rem;
display: flex;
flex-direction: column;
`;

export const StyledLabel = styled.label`
margin: 0 0 0.5rem;
padding: 0;
`;

export const StyledInput = styled.input`
margin: 0 0 1rem;
padding: 0.5rem;
font-size: 16px;
`;

export const StyledAddButton = styled.button`
padding: 1rem;
background-color: rgb(4, 121, 205);
color: white;
border: none;
border-radius: 4px;
font-size: 16px;
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`<AddCustomerForm /> should render a <AddCustomerForm /> 1`] = `
<div>
<form
action="#"
class="sc-bdnxRM hrMVqk"
>
<label
class="sc-gtsrHT bmgxMS"
for="firstName"
>
First Name
</label>
<input
class="sc-dlnjwi fstXny"
id="firstName"
name="firstName"
placeholder="John"
value=""
/>
<label
class="sc-gtsrHT bmgxMS"
for="lastName"
>
Last Name
</label>
<input
class="sc-dlnjwi fstXny"
id="lastName"
name="lastName"
placeholder="Doe"
value=""
/>
<label
class="sc-gtsrHT bmgxMS"
for="phoneNumber"
>
Phone Number
</label>
<input
class="sc-dlnjwi fstXny"
id="phoneNumber"
name="phoneNumber"
placeholder="john@acme.com"
type="tel"
value=""
/>
<button
class="sc-hKFxyN jrRSci"
type="submit"
>
Add Customer
</button>
</form>
</div>
`;
Loading