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
6 changes: 6 additions & 0 deletions .buckconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

[android]
target = Google Inc.:Google APIs:23

[maven_repositories]
central = https://repo1.maven.org/maven2
2 changes: 2 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ENV=dev
API_URL=https://api.waveapps.com
2 changes: 2 additions & 0 deletions .env.prod
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ENV=PROD
API_URL=https://api.waveapps.com
74 changes: 74 additions & 0 deletions .flowconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
[ignore]
; We fork some components by platform
.*/*[.]android.js

; Ignore "BUCK" generated dirs
<PROJECT_ROOT>/\.buckd/

; Ignore polyfills
node_modules/react-native/Libraries/polyfills/.*

; These should not be required directly
; require from fbjs/lib instead: require('fbjs/lib/warning')
node_modules/warning/.*

; Flow doesn't support platforms
.*/Libraries/Utilities/LoadingView.js

[untyped]
.*/node_modules/@react-native-community/cli/.*/.*

[include]

[libs]
node_modules/react-native/interface.js
node_modules/react-native/flow/

[options]
emoji=true

esproposal.optional_chaining=enable
esproposal.nullish_coalescing=enable

module.file_ext=.js
module.file_ext=.json
module.file_ext=.ios.js

munge_underscores=true

module.name_mapper='^react-native/\(.*\)$' -> '<PROJECT_ROOT>/node_modules/react-native/\1'
module.name_mapper='^@?[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> '<PROJECT_ROOT>/node_modules/react-native/Libraries/Image/RelativeImageStub'

suppress_type=$FlowIssue
suppress_type=$FlowFixMe
suppress_type=$FlowFixMeProps
suppress_type=$FlowFixMeState

suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)?:? #[0-9]+
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError

[lints]
sketchy-null-number=warn
sketchy-null-mixed=warn
sketchy-number=warn
untyped-type-import=warn
nonstrict-import=warn
deprecated-type=warn
unsafe-getters-setters=warn
inexact-spread=warn
unnecessary-invariant=warn
signature-verification-failure=warn
deprecated-utility=error

[strict]
deprecated-type
nonstrict-import
sketchy-null
unclear-type
unsafe-getters-setters
untyped-import
untyped-type-import

[version]
^0.113.0
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.pbxproj -text
59 changes: 59 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# OSX
#
.DS_Store

# Xcode
#
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
*.xccheckout
*.moved-aside
DerivedData
*.hmap
*.ipa
*.xcuserstate

# Android/IntelliJ
#
build/
.idea
.gradle
local.properties
*.iml

# node.js
#
node_modules/
npm-debug.log
yarn-error.log

# BUCK
buck-out/
\.buckd/
*.keystore
!debug.keystore

# fastlane
#
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
# screenshots whenever they are needed.
# For more information about the recommended setup visit:
# https://docs.fastlane.tools/best-practices/source-control/

*/fastlane/report.xml
*/fastlane/Preview.html
*/fastlane/screenshots

# Bundle artifact
*.jsbundle

# CocoaPods
/ios/Pods/
9 changes: 9 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Ignore Folders for formatting

node_modules/

# Ignore Files for formatting

package.json
package-lock.json
*.java
12 changes: 12 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"arrowParens": "avoid",
"bracketSpacing": true,
"semi": true,
"singleQuote": true,
"jsxBracketSameLine": true,
"tabWidth": 4,
"trailingComma": "none",
"printWidth": 160,
"proseWrap": "never",
"useTabs": true
}
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"editor.formatOnSave": true
}
1 change: 1 addition & 0 deletions .watchmanconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
50 changes: 50 additions & 0 deletions App.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React, { createContext, useState } from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import SplashScreen from 'react-native-splash-screen';
import { Icon } from 'native-base';

import ProductsComponent from './app/views/products';
import globalStyles from './app/styles';
console.disableYellowBox = true;

export const UserContext = createContext({
authtoken: '',
setAuthtoken: () => {
console.log('called');
}
});

console.disableYellowBox = true;
const Stack = createStackNavigator();

function App() {
const [authtoken, setAuthtoken] = useState('Bearer 6W9hcvwRvyyZgPu9Odq7ko8DSY8Nfm'); // Ideally, this will be set after making api call
SplashScreen.hide();
return (
<UserContext.Provider value={{ authtoken, setAuthtoken }}>
<NavigationContainer>
<Stack.Navigator
initialRouteName="Products"
screenOptions={{
headerLeft: ({ color, size }) => (
<Icon
name={'menu'}
type={'MaterialCommunityIcons'}
style={[globalStyles.headerLeft, { size }]}
onPress={() => alert('Hello, from header')}
/>
),
headerTitleAlign: 'center',
headerTitle: 'Products',
headerStyle: globalStyles.headerTitleStyle,
headerTitleStyle: { color: 'white' }
}}>
<Stack.Screen name="Products" component={ProductsComponent} />
</Stack.Navigator>
</NavigationContainer>
</UserContext.Provider>
);
}

export default App;
29 changes: 21 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,41 @@
# Dev Comments

Although it's a simple task with just one screen, I am proud that the app used the concepts of hooks, modularity, helpers, integration with react navigation(just one stack but I would have loved to integrate more complex flow with stacks, tabs, bottom tabs), splash screen, formatters. As the app's state was not complex, I refrained myself from going for the redux which I have always used in my previous apps as the application state was more complex. I feel you shouldn't use something just for the sake of using. Here in this assignment, the task was simple and so was the application state, for that reason I chose not to use class components and redux. I have also setup the splash screen and code formatter with pre-commit hook. I think the pre-commit hook is very important as it paves way for consistent code formatting.

If given some more time, I would love to setup locale mapper so with en_ca, fr_ca files which would not only pave way for different languages but also help in storing all the messages and labels in separate file(currently, they are hardcoded in the JSX which is strict NO)

Finally, please refer to the screenshot.png

# Wave Software Development Challenge
Applicants for the [Mobile engineer](https://wave.bamboohr.co.uk/jobs/view.php?id=6) role at Wave must complete the following challenge, and submit a solution prior to the onsite interview.

The purpose of this exercise is to create something that we can work on together during the onsite. We do this so that you get a chance to collaborate with Wavers during the interview in a situation where you know something better than us (it's your code, after all!)
Applicants for the [Mobile engineer](https://wave.bamboohr.co.uk/jobs/view.php?id=6) role at Wave must complete the following challenge, and submit a solution prior to the onsite interview.

The purpose of this exercise is to create something that we can work on together during the onsite. We do this so that you get a chance to collaborate with Wavers during the interview in a situation where you know something better than us (it's your code, after all!)

There isn't a hard deadline for this exercise; take as long as you need to complete it. However, in terms of total time spent actively working on the challenge, we ask that you not spend more than a few hours, as we value your time and are happy to leave things open to discussion in the onsite interview.

You can write your app using your favorite language, tools, platform, etc. Whether that means something native or something hybrid is completely up to you.
You can write your app using your favorite language, tools, platform, etc. Whether that means something native or something hybrid is completely up to you.

Send your submission to [dev.careers@waveapps.com](dev.careers@waveapps.com). Feel free to email [dev.careers@waveapps.com](dev.careers@waveapps.com) if you have any questions.

## Submission Instructions

1. Fork this project on github. You will need to create an account if you don't already have one.
1. Complete the project as described below within your fork.
1. Push all of your changes to your fork on github and submit a pull request.
1. Push all of your changes to your fork on github and submit a pull request.
1. You should also email [dev.careers@waveapps.com](dev.careers@waveapps.com) and your recruiter to let them know you have submitted a solution. Make sure to include your github username in your email (so we can match applicants with pull requests.)

## Alternate Submission Instructions (if you don't want to publicize completing the challenge)

1. Clone the repository.
1. Complete your project as described below within your local repository.
1. Email a patch file to [dev.careers@waveapps.com](dev.careers@waveapps.com).

## Project Description
In this project, we're going to be creating a simple app that shows a Wave user the products that they can charge for on their invoices.

You'll be using the public Wave API in this challenge. You can find the documentation [here](http://docs.waveapps.io/). You will specifically be interested in [the products endpoint](http://docs.waveapps.io/endpoints/products.html#get--businesses-business_id-products-), and [using an access token with the API](http://docs.waveapps.io/oauth/index.html#use-the-access-token-to-access-the-api).
In this project, we're going to be creating a simple app that shows a Wave user the products that they can charge for on their invoices.

You'll be using the public Wave API in this challenge. You can find the documentation [here](http://docs.waveapps.io/). You will specifically be interested in [the products endpoint](http://docs.waveapps.io/endpoints/products.html#get--businesses-business_id-products-), and [using an access token with the API](http://docs.waveapps.io/oauth/index.html#use-the-access-token-to-access-the-api).

Your Wave contact will supply you with a business ID and a Wave API token before you begin.

Expand All @@ -33,14 +45,15 @@ Your Wave contact will supply you with a business ID and a Wave API token before
1. The list of products should be fetched and shown to the user in a list view when the app is launched.
1. Each item in the list view should show the product name and price (formatted as a dollar amount.)

You are not required to add any interactivity to the app -- i.e. you do not need to send the user to a detail view when they touch one of the list items.
You are not required to add any interactivity to the app -- i.e. you do not need to send the user to a detail view when they touch one of the list items.

Your app is allowed to render nothing if there is no internet connection when it loads.

Once you're done, please submit a paragraph or two in your `README` about what you are particularly proud of in your implementation, and why.

## Evaluation
Evaluation of your submission will be based on the following criteria.

Evaluation of your submission will be based on the following criteria.

1. Did your application fulfill the basic requirements?
1. Did you document the method for setting up and running your application?
Expand Down
14 changes: 14 additions & 0 deletions __tests__/App-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* @format
*/

import 'react-native';
import React from 'react';
import App from '../App';

// Note: test renderer must be required after react-native.
import renderer from 'react-test-renderer';

it('renders correctly', () => {
renderer.create(<App />);
});
55 changes: 55 additions & 0 deletions android/app/BUCK
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# To learn about Buck see [Docs](https://buckbuild.com/).
# To run your application with Buck:
# - install Buck
# - `npm start` - to start the packager
# - `cd android`
# - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"`
# - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck
# - `buck install -r android/app` - compile, install and run application
#

load(":build_defs.bzl", "create_aar_targets", "create_jar_targets")

lib_deps = []

create_aar_targets(glob(["libs/*.aar"]))

create_jar_targets(glob(["libs/*.jar"]))

android_library(
name = "all-libs",
exported_deps = lib_deps,
)

android_library(
name = "app-code",
srcs = glob([
"src/main/java/**/*.java",
]),
deps = [
":all-libs",
":build_config",
":res",
],
)

android_build_config(
name = "build_config",
package = "com.wavehqchallenge",
)

android_resource(
name = "res",
package = "com.wavehqchallenge",
res = "src/main/res",
)

android_binary(
name = "app",
keystore = "//android/keystores:debug",
manifest = "src/main/AndroidManifest.xml",
package_type = "debug",
deps = [
":app-code",
],
)
Loading