Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dysons solution #16

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
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
33 changes: 31 additions & 2 deletions src/components/BillingStatement.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import React from "react";
import { StyleSheet, View, Text } from 'react-native'
import { BillingStatementProps } from '../screens/BillingHistory'

{
/* This component renders each individual billing statement. Some requirements to note:
1. Display product name, date and amount.
Expand All @@ -8,6 +11,32 @@ import React from "react";
5. If price is above 100, add another line of text that says "Big Savings!". */
}

type BillingStatementProps = {};
// type BillingStatementProps = {};

export const BillingStatement = ({productName, date, amount}: BillingStatementProps) => {
return (
<View style={styles.primary}>
<Text>
{productName}
</Text>
<Text>
{date || ""}
</Text>
<Text>
{`$${amount}`}
{amount > 100.00 ? <Text>Big Savings!</Text> : null }
</Text>
</View>

);
};


export const BillingStatement = ({}: BillingStatementProps) => {};
const styles = StyleSheet.create({
primary: {
flex: 1,
height: 80,
justifyContent: "center",
alignItems: 'center'
}
})
20 changes: 15 additions & 5 deletions src/screens/BillingHistory.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React from "react";
import { StyleSheet, View, Text } from "react-native";
import { StyleSheet, View, Text, FlatList } from "react-native";
import { BillingStatement } from "../components/BillingStatement";

type BillingStatement = {
export type BillingStatementProps = {
id: number;
productName?: string;
date?: string;
Expand All @@ -14,7 +14,7 @@ type BillingStatement = {
However, for this task it is simplified and all data is stored inside array called billingStatements. */}

export const BillingHistoryScreen = () => {
const billingStatements: BillingStatement[] = [
const billingStatements: BillingStatementProps[] = [
{
id: 1,
productName: "Jeans",
Expand All @@ -35,11 +35,21 @@ export const BillingHistoryScreen = () => {
},
];

const billingStatementsComponents = (statement: any) => {
return (
<BillingStatement amount={0} date={statement.date} productName={statement.productName} id={statement.id}></BillingStatement>
)
};

return (
<View style={Styles.container}>
<Text>Billing History</Text>

{/* Show Billing Statements here */}
<FlatList
data={billingStatements}
renderItem={({item}) => billingStatementsComponents(item)}
keyExtractor={ item => item.id as unknown as string }
>
</FlatList>
</View>
);
};
Expand Down
28 changes: 26 additions & 2 deletions src/screens/Initialization.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useState, useEffect } from "react";
import { ActivityIndicator, View } from "react-native";
import { ActivityIndicator, View, Text } from "react-native";

/*
When user first opens the app, this screen is displayed.
Expand All @@ -19,6 +19,9 @@ type UserDetails = {
};

export const Initialization = () => {
const [loading, setLoading] = useState<boolean>(true)
const [user, setUser] = useState<UserDetails>({ name: "", email: "" })

const getUserDetails = async () => {
// pretends to get user details from AsyncStorage
return new Promise<UserDetails>((resolve) => {
Expand All @@ -31,5 +34,26 @@ export const Initialization = () => {
});
};

return <View></View>;
useEffect(() => {
getUserDetails().then((deets) => {
setUser(deets);
}).catch((e) => {
throw `Error loading user details: ${e.message}`
}).finally(() => {
setLoading(false);
})
}, []);

return (
loading ?
<ActivityIndicator style={{flex: 1}}></ActivityIndicator>
:
<View>
<Text>
{user.name}
{user.email}
</Text>
</View>

);
};
33 changes: 33 additions & 0 deletions src/utils/dysonsExplanation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
## Explanation

I wish that I had selected this for the live coding challenge, this was fun to work on.

I want to thank everyone who met with me today for the interview, I enjoyed talking to you all and I hope to speak with you again soon.


#### Summary
The assignment here is to take an array of strings, cycle through them and check each string for the following conditions:

1. the string should NOT appear in the array 'alreadyEnrolledDependents'
2. the string SHOULD appear in the array 'ehrAttachedDependents'
3. if there's a corresponding object in the 'dependentEhrInfo' array, the "age" property should be below 18

- strings which pass these conditions are put into the 'verified' array within the AnalyzedDependents instance
- strings which don't get put into the 'unverified' array
- strings which are invalid are placed in neither (if I'm understanding that correctly)

#### Approach

The thing to avoid here is having to iterate through each of the three subarrays for each element in the dependedIds array, because each new array you have to iterate through multiplies the time complexity by the length of that array. For this particular use case, none of the arrays are particularly long, so it wouldn't be that big of a deal, but if you're doing this many times or if any of the arrays get long, then the time and compute power would get out of hand pretty quickly.

Instead, my plan is to create an object for each array with the element as the key and an integer or boolean as the value. Then, for each element in the dependentIds array, it will be a nearly instant lookup for each of the other three arrays, so it will be a max time complexity of n * 3 if I'm doing my math right. This is probably a little bit overengineering for this use case but I think it's the right thing to do in the long run.

In ruby, there's a method called "each_with_object" which is an array method that returns a ruby hash (js object). I couldn't find an analogue in typescript in the limited amount of time I gave myself for this challenge (to simulate the live-coding experience), but given more time I'm positive there's alternative out there somewhere. In the meantime I'm declaring separate objects. It's the same space complexity but a little longer to read.

Another important note: in the real world, I would set up a series of tests to ensure that the information is being processed as it should. There's also some refactoring that could be done, I put everything inside the exported function so that it's all in one place for you to read.


#### Notes
Learning regex in a new language can be daunting, but I've been working on a project recently which utilizes regex pretty heavily and I feel very comfortable using regex in ruby. The regex that I wrote for ensuring that the string is a string of digits is in ruby and I'm 99% sure it would work - basically a negative lookahead to find non-digit characters, with a matcher for at least 1 digit character. From what I can tell js/ts regex is very similar, but it might not be exactly the same.

If you had been live coding this with me, you would have seen me get hung up because the results weren't what I expected; after a period of debugging I found that I had an exclamation point in the wrong place.
38 changes: 36 additions & 2 deletions src/utils/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,16 @@ const dependentEhrInfo = [
{ id: "161718", name: "Jenny", "age": 3, relation: "daughter" },
];

['101112', '131415', '161718']
// returned value type
type AnalyzedDependents = {
userId: string;
verified: string[];
unverified: string[];
}



export const verifyDependents = (
): AnalyzedDependents => {
// In a real-world scenario, the function would take in userId and dependentIds as arguments. However, for this task, we will hardcode the values.
Expand All @@ -51,6 +54,37 @@ export const verifyDependents = (
verified: [],
unverified: [],
}


////// BEGIN DYSON'S SOLUTION /////

const alreadyEnrolledMap: { [id: string]: boolean } = {} // NOT in this one
const attachedDependentsMap: { [id: string]: boolean } = {} // YES in this one
const dependentEhrMap: { [id: string]: number } = {} // under 18

alreadyEnrolledDependents.forEach((dependent) => {
alreadyEnrolledMap[dependent] = true
});
ehrAttachedDependents.forEach((dependent) => {
attachedDependentsMap[dependent] = true
});
dependentEhrInfo.forEach((dependent) => {
dependentEhrMap[dependent.id] = dependent.age
});


// kind of hardcoded this, since by the time we're in this function I'm assuming that we've narrowed the user down to this particular user
analyzedDependents.userId = userId
dependentIds.forEach((dependent) => {
console.log(`${dependent}: ${!alreadyEnrolledMap[dependent]}`)
if(!((typeof dependent) === 'string') || dependent.length < 1 || !dependent.match(/^(?!.?\D)\d+/)) {
return;
} else if(!alreadyEnrolledMap[dependent] && attachedDependentsMap[dependent] && dependentEhrMap[dependent] && dependentEhrMap[dependent] < 18) {
analyzedDependents.verified.push(dependent);
} else {
analyzedDependents.unverified.push(dependent);
}
});

return analyzedDependents;
};
};

1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"extends": "expo/tsconfig.base",
"compilerOptions": {
"jsx": "react",
"strict": true,
"paths": {
"@/*": [
Expand Down