├── .gitignore ├── FIRST_STEP.md ├── LICENSE ├── README.md ├── SECOND_STEP.md ├── elm.json ├── media └── screenshot.png └── src ├── Data ├── Audience.elm └── AudienceFolder.elm └── Main.elm /.gitignore: -------------------------------------------------------------------------------- 1 | elm-stuff/ 2 | -------------------------------------------------------------------------------- /FIRST_STEP.md: -------------------------------------------------------------------------------- 1 | # 1 - Browser Implementation 2 | 3 | This is **the required step** for completing application on position. 4 | Your job is to implement parsing of data from `JSON` format and fully usable interactive UI of audiences browser. 5 | 6 | ## Requirements 7 | 8 | This is required for successful implementation: 9 | 10 | - [ ] You must use data and type (aliases) provided. 11 | - [ ] You must use provided `JSON` fixtures in your app (*these are returned by API in production app*) 12 | - [ ] You must not change any of pre-defined types and fixtures. 13 | - However you can use existing files for your implementation. 14 | - [ ] You must successfully resolve all relations in data set. 15 | - [ ] By default component should display root level (items without any parent folder) 16 | - [ ] Only items from current level are shown (in UI) at any given time. 17 | - [ ] Folders are displayed before audiences in any level. 18 | - [ ] Click on any folder opens its content. 19 | - [ ] `Go up` button is not visible in root level. 20 | - [ ] `Go up` button is visible in any sub-level. 21 | - You can use name of parent folder if you want. 22 | - [ ] `Go up` button opens parent level on click. 23 | - [ ] Final solution should be compilable to html app or should contain HTML and source compilable to JavaScript included in HTML. 24 | 25 | ## Hints 26 | 27 | These are the things you might consider thinking about before you start with your implementation: 28 | 29 | - How to make `JSON` parsing scalable? 30 | - Do you know about [applicatives](https://toast.al/posts/2016-08-12-elm-applicatives-and-json-decoders.html)? 31 | - Is there any clever transformation of data that can be used as input of browser itself? 32 | - What data-structures can be helpful if any? 33 | - Do you prefer working with RoseTree or List? Why? (you can leave comment in your code) 34 | - Which parts can be decoupled for possible re-use? 35 | - Do you like to put those in separate module? Why yes or no? 36 | 37 | ## Final Words 38 | 39 | Please don't be afraid to ask (using email or by opening issue in this repository) if anything is not clear, 40 | can be improved in this documents or if you're just simply stuck with anything. 41 | We are happy to provide any help to degree we are able to. Also have in mind that there are no time restrictions for completing this challenge. 42 | Take as much time as you wish for completing this. *In the end the most important bit is to challenge your problem solving thinking*. 43 | And of course **good luck with this**! :rocket: 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2016 GlobalWebIndex 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Challenge: Elm 2 | 3 | Hello! Welcome to the Elm Challenge. 4 | 5 | This repository contains requirements definition of a project used for job applications 6 | on a **position of an [Elm](https://elm-lang.org/) developer**. 7 | The challenge consists of two parts, where **only the first part is required**. 8 | The whole assignment is based on a real part of our production app. 9 | However, since there is a lot of domain specific knowledge required for most parts of our system 10 | and we are aware of the fact that most of this logic might be confusing to newcomers, we've tried to 11 | pick a task which doesn't require any specific insight and removed all parts which might be possibly confusing to pick up. 12 | Thanks to this, this project can be used as a general challenge to build an Elm app. 13 | 14 | ## Position Description 15 | 16 | In its essence, GlobalWebIndex is a data company and our primary way how we deliver all our datasets to clients is the PRO Platform – our web application interface to our backend analytical engine. 17 | 18 | Praised and used by the world's largest organizations, the PRO Platform enables our clients to cut through our data using custom audiences, segmentations and modular charting library. 19 | 20 | You will be part of our PRO Platform team and will be jointly responsible for pushing the development of the platform forward. 21 | Day-to-day this involves new feature engineering, reviewing and discussing code of your colleagues and discussing the design decisions with the wider technical leadership team. 22 | 23 | - Ideate, brainstorm and implement new components and features using Elm. 24 | - Develop the project codebase, with the focus on long-term maintenance – we look for people who really care about the quality as a day-to-day routine. 25 | - Think forward and propose innovative approaches, which can push the project to the next level. 26 | We like to discuss things so you’ll be expected to demonstrate conclusive arguments and get a buy in from the whole team. 27 | - Evaluate external solutions (databases, frameworks, libraries), which might be beneficial to our platform. 28 | 29 | ## Basic Instructions 30 | 31 | You are required to provide an implementation of a component for browsing `Audience`s and `AudienceFolder`s in a hierarchical structure. 32 | Every `Audience` might or might not have a parent `folder` and every `Folder` might have (but not necessarily) its `parent` folder. 33 | This means the component should display `n`-levels deep tree. Always one level at the time. 34 | User can open any sub-folder or go back to the parent of the current level. 35 | All data is provided in a JSON format. 36 | 37 | **This is how a similar component looks like in our production system:** 38 | 39 | ![screenshot](media/screenshot.png) 40 | 41 | ## Introduction 42 | 43 | There are two models: `Audience` and `AudienceFolder`, defined each with its own API endpoint. 44 | You will find all the necessary data inside [/src/Data](/src/Data) folder. There is data in plain `JSON` format, which represents what API returns. 45 | You will also find particular type definitions of each model. Your job is to deserialize this data into collection and build an interactive browser. 46 | 47 | ## General Acceptance Criteria 48 | 49 | - The implementation must be done in the `Elm` language. 50 | - You can use any 3rd-party library you want. 51 | - `elm/html` must be used for rendering UI. 52 | - You are free to use `ports` and `subscriptions` in case you want to. 53 | - You can use [screenshot](/media/screenshot.png) as an inspiration for the UI or come up with your own layout if it satisfies the requirements. 54 | - All naming including comments and additional documentation must be in English. 55 | - The final result must be in the form of a full git repository with your own implementation. 56 | - There are **no time restrictions** for completing this challenge. 57 | - **Only the first part is required.** 58 | - **In case you want to apply for the job, but have no time to finish the first step soon, let us know you're interested anyway.** (We are people too!) 59 | 60 | ## Where to Start 61 | 62 | If you are interested in applying for this position or just want to challenge yourself (which is also 100% OK for us), 63 | please continue following the steps: 64 | 65 | - Fork this repository under your GitHub account. 66 | - Complete an implementation inside your fork. 67 | - Open pull request to [original](https://github.com/GlobalWebIndex/challenge-elm/) repository with your own implementation. 68 | - Comment your pull request with message containing `READY` or `RDY` to let us know that we can review your code. 69 | - Comment your PR with any question in case you need any help (or send us email - see below). 70 | 71 | **You can also open a pull request before you finish the implementation in case you are willing to discuss anything!** 72 | 73 | ## Parts 74 | 75 | - [First part](FIRST_STEP.md) - Browser Implementation 76 | - [Second part](SECOND_STEP.md) - Filters Implementation 77 | 78 | ## Goal 79 | 80 | The goal is to test your ability to come up with a solution for a real world problem which will be part of your day to day responsibility. 81 | Obviously the first thing what we will look at is a degree to what your implementation satisfies original requirements. 82 | Also we want to see your ability to come up with a robust solution and will look at the overall code quality. 83 | 84 | ## Contacts 85 | 86 | In case you want to apply for a position in our team, please contact `engineering-recruitment@globalwebindex.com`. 87 | If you have any questions about the implementation itself, you can send an e-mail to `asbernal@gwi.com` 88 | or open issue/PR in this repository so we can discuss any part together. 89 | 90 | ## License 91 | 92 | MIT 93 | -------------------------------------------------------------------------------- /SECOND_STEP.md: -------------------------------------------------------------------------------- 1 | # 2 - Filters Implementation 2 | 3 | **This part is optional and is not necessary for job application!** 4 | In this part you're going to implement basic filters for audience browser. 5 | Be aware that we assume that you've already completed [first step](/FIRST_STEP.md) since that implementation 6 | is what is required for this step. 7 | 8 | In this step you will implement basic filter for our previously built audience browser. 9 | This will split original tree of `Audience`s to three independent trees user can chose from. 10 | 11 | ## Requirements 12 | 13 | There are three categories of audiences we want to separate in data set. 14 | User should be able to select one of these at time and see only audiences which are member of this category. 15 | Categories are: 16 | 17 | - Authored Audiences - audiences created by user herself. 18 | - Shared Audiences - audiences which other users shared with user. 19 | - In this case structure is flat. 20 | - Curated Audiences - pre-build audiences provided to all users. 21 | 22 | ### These are the requirements for this step: 23 | 24 | - [ ] You must not change any of pre-defined types and fixtures. 25 | - However you can use existing files for your implementation. 26 | - [ ] Add 3 buttons - one for every category of audiences. 27 | - [ ] Clicking on each button activates particular category of audience. 28 | - [ ] By default `Authored` audiences are filtered. 29 | - [ ] There must by at least one category selected at the time. 30 | - [ ] Every-time user changes category she sees its root level. 31 | - [ ] In case of shared audiences ignore tree structure and display audiences in single level without any folder. 32 | - [ ] Final solution should be compilable to html app or should contain HTML and source compilable to JavaScript included in HTML. 33 | 34 | ## Hints 35 | 36 | These are things you might consider thinking about: 37 | 38 | - What are the best types for defining this state? 39 | - What is the most efficient way to split (group) audiences to categories? 40 | 41 | ## Final Words 42 | 43 | Thank you for picking up this challenge! 44 | You're amazing. I have no words. 45 | As always let us know in case you need any help. 46 | **Good luck!**:rocket: 47 | -------------------------------------------------------------------------------- /elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "application", 3 | "source-directories": [ 4 | "src" 5 | ], 6 | "elm-version": "0.19.1", 7 | "dependencies": { 8 | "direct": { 9 | "elm/browser": "1.0.1", 10 | "elm/core": "1.0.2", 11 | "elm/html": "1.0.0" 12 | }, 13 | "indirect": { 14 | "elm/json": "1.1.3", 15 | "elm/time": "1.0.0", 16 | "elm/url": "1.0.0", 17 | "elm/virtual-dom": "1.0.2" 18 | } 19 | }, 20 | "test-dependencies": { 21 | "direct": {}, 22 | "indirect": {} 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /media/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GlobalWebIndex/challenge-elm/d7e3eac3bc18e1b39840020759d69ed33a052cc0/media/screenshot.png -------------------------------------------------------------------------------- /src/Data/AudienceFolder.elm: -------------------------------------------------------------------------------- 1 | module Data.AudienceFolder exposing (AudienceFolder, audienceFoldersJSON) 2 | 3 | {-| Data.AudienceFolder module 4 | 5 | This module implements everything related to audience folder resource. 6 | 7 | 8 | # Interface 9 | 10 | @docs AudienceFolder, audienceFoldersJSON 11 | 12 | -} 13 | 14 | -- Type definition 15 | 16 | 17 | {-| Basic type of AudienceFolder record 18 | -} 19 | type alias AudienceFolder = 20 | { id : Int 21 | , name : String 22 | , parent : Maybe Int 23 | } 24 | 25 | 26 | 27 | -- Fixtures 28 | 29 | 30 | {-| Fixtures for audienceFolders 31 | In real world something like this is returned by `GET /api/audience_folders` 32 | -} 33 | audienceFoldersJSON : String 34 | audienceFoldersJSON = 35 | """ 36 | { 37 | "data": [ 38 | { 39 | "id": 357, 40 | "name": "Demographics", 41 | "curated": true, 42 | "parent": null 43 | }, 44 | { 45 | "id": 358, 46 | "name": "Marketing Personas", 47 | "curated": true, 48 | "parent": null 49 | }, 50 | { 51 | "id": 383, 52 | "name": "Reports", 53 | "curated": true, 54 | "parent": null 55 | }, 56 | { 57 | "id": 3110, 58 | "name": "New Group", 59 | "curated": false, 60 | "parent": null 61 | }, 62 | { 63 | "id": 3111, 64 | "name": "New Group 2", 65 | "curated": false, 66 | "parent": 3110 67 | } 68 | ] 69 | } 70 | """ 71 | -------------------------------------------------------------------------------- /src/Main.elm: -------------------------------------------------------------------------------- 1 | module Main exposing (main) 2 | 3 | import Data.Audience 4 | import Data.AudienceFolder 5 | import Html exposing (Html) 6 | 7 | 8 | main : Html msg 9 | main = 10 | Html.text "There will be app soon!" 11 | --------------------------------------------------------------------------------