-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: add code challenge files to repo
- Loading branch information
Showing
21 changed files
with
759 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Technical Write-Up | ||
|
||
Write a couple of paragraphs in here describing how you solved the problem, what challenges you encountered along the way, and how you overcame them. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,118 @@ | ||
# UiCodeChallenge | ||
# Autovance UI Code Challenge | ||
|
||
## Background | ||
|
||
This challenge is intended to be a short simulation of the environment and technologies that we work with every day at Autovance. More important than actually solving the problem, we want to see how you approach these sorts of problems and how you approach learning the technologies that are essential to your success on Autovance's development team. A secondary goal of this challenge is to demonstrate your working knowledge of TypeScript, Angular, NPM, and Git. | ||
|
||
**This challenge is not pass / fail**. We want you to perform as well as you can in an environment where you are comfortable. Your solution will be judged on the following elements: | ||
|
||
1. Behavior: Does the application do what the user expects it to do? | ||
2. Design: Is the resulting application aesthetically pleasing? Is it usable across device form factors? | ||
3. Robustness: Does the application handle errors reasonably? Did the developer make an effort to test their code? | ||
4. Completeness: Did the solution solve the entire problem, or only certain parts of it? | ||
|
||
Throughout the process, your interviewer remains as a first-class resource, and is available for pair programming and any questions: do not hesitate to reach out to [[email protected]](mailto:[email protected]) at any time during the exercise. | ||
|
||
## The Problem | ||
|
||
XYZ Motors is a car dealership that generates leads from a wide variety of sources (in-store visits, referrals from their BDC, Kijiji ads, the MyDeal digital retailing tool, etc). | ||
However, because the systems that generate these leads don't talk to one another, it is often the case that a person browsing XYZ Motors' website will submit multiple lead | ||
entries if they indicate that they are interested in test driving or looking at one or more vehicles (or if the prospective customer clicks on a Kijiji ad and then walks into the dealership later that day, for example). | ||
|
||
Your task is to use the Autovance Leads API (bundled in this repo as `leads-api.js`) to build a front-end application that will help the sales staff at XYZ Motors manage their | ||
leads. In order to do this, they require a user interface that will allow them to perform the following tasks: | ||
|
||
* Display a list of all the leads that were received through the various lead generation platforms that the dealership uses | ||
* For each lead in the list, show a list of "potential duplicates" associated with that lead | ||
* Allow the sales staff to mark one or more "potential duplicates" as "actual duplicates" of a given lead | ||
|
||
To facilitate each of these tasks, the Leads API offers the following methods: | ||
|
||
* `GET /api/leads`: returns a list of all the leads that the dealership has received in the last 30 days | ||
* `GET /api/leads/:lead_id/potential-duplicates`: returns a list of "potential duplicates" associated with a given lead (note that this route will only return the `lead_id`s of the potential duplicates, not the full lead objects: you can assume that if an ID appears in this list, its corresponding object will appear in the `GET /api/leads` response) | ||
* `PUT /api/leads/:lead_id`: update a lead object on the server | ||
|
||
Lead objects have the following shape: | ||
|
||
```typescript | ||
export interface Lead { | ||
// a GUID that uniquely identifies each lead object | ||
lead_id: string; | ||
|
||
// If the lead is a duplicate of another lead, this field | ||
// indicates the GUID of the lead that was duplicated. | ||
// If the lead is not a duplicate, or it has not been marked | ||
// as such, this field will be returned as `null` | ||
duplicate_of: string | null; | ||
|
||
// the source through which the lead was submitted | ||
// (could be an application, a website, or an in-person activity) | ||
source: string; | ||
|
||
// the first name of the prospective customer | ||
first_name: string; | ||
|
||
// the last name of the prospective customer | ||
last_name: string; | ||
|
||
// the e-mail address of the prospective customer | ||
email: string; | ||
|
||
// the cell phone number of the prospective customer | ||
cell_phone: string; | ||
|
||
// the home phone number of the prospective customer | ||
home_phone: string; | ||
} | ||
``` | ||
|
||
To mark Lead A (`lead_id === eb59dab2-b25f-4986-96fd-93a2d31f5a51`) as a duplicate of Lead B (`lead_id === 25341576-8eff-43fd-b1ea-e71b248621be`), it is necessary to set Lead A's `duplicate_of` field to Lead B's `lead_id` (this can be done using the `PUT /api/leads/:lead_id` method). The resulting objects should look like this: | ||
|
||
```json | ||
{ | ||
"lead_id": "eb59dab2-b25f-4986-96fd-93a2d31f5a51", | ||
"first_name": "Lead A", | ||
"duplicate_of": "25341576-8eff-43fd-b1ea-e71b248621be", | ||
... | ||
} | ||
``` | ||
|
||
```json | ||
{ | ||
"lead_id": "25341576-8eff-43fd-b1ea-e71b248621be", | ||
"first_name": "Lead B", | ||
"duplicate_of": null, | ||
... | ||
} | ||
``` | ||
|
||
|
||
## Instructions | ||
|
||
1. Make a private clone of the repo and do all of your work inside of this clone | ||
* Click 'use this template' on the top right of the GitHub page and create a private clone | ||
* IMPORTANT: Do not fork this repository, as the fork will be publicly-visible (consider using a new GitHub account if you are concerned about discretion) | ||
2. Install all dependencies using `npm install` (ensure that you have NodeJS 12+ and NPM installed before proceeding with this) | ||
3. Run the Angular development server on port 4200 using `ng serve` | ||
4. Run the Autovance Leads API server on port 3000 using `node leads-api.js` | ||
5. Complete the code to solve the problem described above | ||
6. Create a small technical write-up that describes how you solved the problem, and put it in `DESCRIPTION.md` | ||
7. Add @crabl to the private repository and send an e-mail to [email protected] once you've pushed your completed project up to GitHub | ||
|
||
## Notes | ||
|
||
* Data in the Leads API is only persisted in-memory, it does not connect to a real database and does not write its state out to disk at any point. If you restart the `leads-api` process, the data will be reset to its original state. | ||
* Due to government budget cuts, cosmic rays, and a variety of mitigating factors, the Leads API is notoriously unreliable: requests will frequently fail with HTTP 500 errors, so it is your responsibility to catch these errors in the application and surface them to the user in an appropriate manner. | ||
|
||
|
||
## Rules | ||
|
||
* You must build your solution within the existing Angular app from this repository (follow the instructions above to create a private clone): no other frameworks, such as React or Vue, are allowed | ||
* You may install third-party libraries if you feel so inclined, but please do so only through NPM (linking to CDN-hosted libraries is not permitted) | ||
* You may not make any modifications to `leads-api.js` or `mock-data.json` whatsoever, and you may not write your own back-end API | ||
|
||
|
||
--- | ||
|
||
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 11.2.3. | ||
|
||
|
@@ -25,3 +139,4 @@ Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protrac | |
## Further help | ||
|
||
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
const express = require('express'); | ||
const bodyParser = require('body-parser'); | ||
const cors = require('cors'); | ||
|
||
const leads_data = require('./mock-data.json'); | ||
|
||
const app = express(); | ||
app.use(bodyParser.json()) | ||
.use(bodyParser.urlencoded()) | ||
.use(cors()) | ||
.options('*', cors()); | ||
|
||
console.log(__dirname); | ||
|
||
let leads = leads_data; | ||
let PORT = process.env.PORT || 3000; | ||
|
||
function introduceChaos(res) { | ||
if (Math.floor(Math.random() * 20) === 10) { | ||
res.status(500).json({ | ||
error: 'Unable to process your request: an error has occurred' | ||
}); // random 500 error | ||
|
||
return true; | ||
} | ||
} | ||
|
||
app.get('/api/leads', (req, res, next) => { | ||
if (introduceChaos(res)) { return; } | ||
|
||
const leads_without_potential_duplicates = leads | ||
.map(({ potential_duplicates, ...lead }) => lead); | ||
|
||
return res.status(200).json(leads_without_potential_duplicates); | ||
}); | ||
|
||
app.put('/api/leads/:lead_id', (req, res, next) => { | ||
const lead = req.body; | ||
|
||
const [ matching_lead ] = leads.filter(l => l.lead_id === lead.lead_id); | ||
if (matching_lead) { | ||
const index = leads.indexOf(matching_lead); | ||
leads[index] = { | ||
...lead, | ||
potential_duplicates: matching_lead.potential_duplicates | ||
}; | ||
|
||
if (introduceChaos(res)) { return; } | ||
return res.status(200).json(lead); | ||
} else { | ||
if (introduceChaos(res)) { return; } | ||
return res.status(404).json({ error: `lead_id ${req.params.lead_id} not found`}) | ||
} | ||
|
||
|
||
}); | ||
|
||
app.get('/api/leads/:lead_id/potential-duplicates', (req, res, next) => { | ||
const [ lead ] = leads | ||
.filter(lead => lead.lead_id === req.params.lead_id); | ||
|
||
if (introduceChaos(res)) { return; } | ||
|
||
if (lead) { | ||
return res.status(200).json(lead.potential_duplicates); | ||
} else { | ||
return res.status(404).json({ error: `lead_id ${req.params.lead_id} not found`}); | ||
} | ||
}) | ||
|
||
app.listen(PORT, () => { | ||
console.log(`Autovance Leads API is listening on port ${PORT}`); | ||
}); |
Oops, something went wrong.