Skip to content
This repository was archived by the owner on Mar 15, 2024. It is now read-only.

Add support for multiple Robinhood accounts #33

Open
wants to merge 47 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
b5f8ffc
Add Multiple Accounts to Settings page. Should allow to add and delet…
superpowered Jan 18, 2021
4f68e4f
Linting
superpowered Jan 18, 2021
8844554
re-indent head/body. formatOnSave causing issues here.
superpowered Jan 18, 2021
f7a47f4
Stop multiple event handlers from being registered on add button
superpowered Jan 18, 2021
5987e40
Get account name from robin hood account screen.
superpowered Jan 19, 2021
c3c6ef0
lint
superpowered Jan 19, 2021
cace38f
Update fields based on account name if we find a matching one.
superpowered Jan 19, 2021
afd222c
Can pass updated account name to success message. Definately needs cl…
superpowered Jan 19, 2021
831b84d
Merge commit 'c8ab2b380d1330a3ddac6caaa7a78b1487ae6660' into multiple…
superpowered Jan 19, 2021
c392b08
Mint value is unneeded
superpowered Jan 19, 2021
64c082c
Add Check / create for multiple accounts.
superpowered Jan 19, 2021
faf6b5f
Stop. Un.in.dent.ing.
superpowered Jan 19, 2021
92f9635
.vscode to gitignore. Should keep the original file, but allow it to …
superpowered Jan 19, 2021
cc20a1a
rm .vscode/settings.json
superpowered Jan 19, 2021
01bac47
Merge commit '1a10de5d0bbc6e6602076cae0bfcebe87e3cd906' into multiple…
superpowered Jan 19, 2021
2c6eb96
Pretty sure stellar wasn't supposed to get commited.
superpowered Jan 19, 2021
82f6ddf
Allow default
superpowered Jan 19, 2021
f115632
Recommend eslint to match recommended settings
superpowered Jan 22, 2021
da2d90f
Merge commit '4ea984ab381515819a83142426750e174cb95ea6' into multiple…
superpowered Jan 22, 2021
b98c8ab
Clean up the update script
superpowered Jan 22, 2021
3f218f6
Move Interfaces & urls to constants
superpowered Jan 22, 2021
298cec4
Add lint:fix, run it
superpowered Jan 22, 2021
6b043f6
Commenting.
superpowered Jan 22, 2021
42ac388
rename match to isMultipleAccounts. reorder functions by priority
superpowered Jan 22, 2021
47cbb2d
Browser typing is a dev extension
superpowered Jan 22, 2021
6ccd26a
Multiple Accounts readme
superpowered Jan 22, 2021
068b702
can remove `mint-force-sync`
superpowered Jan 22, 2021
9d9c457
Move `sanitizeInput` to utilities, `robinHoodValue` renamed to `robin…
superpowered Jan 22, 2021
4671502
Clean up settings
superpowered Jan 22, 2021
788043f
Clean up check
superpowered Jan 22, 2021
c983e8c
Some final cleanup
superpowered Jan 22, 2021
cdc2961
Error with missing args on timeout
superpowered Jan 22, 2021
aaca143
Fix issue with other not being set
superpowered Jan 22, 2021
8804287
Warnings for if a property cant be found or set
superpowered Jan 22, 2021
f6119d2
Add prettier to recommended extensions
pkmnct Jan 23, 2021
436f337
Run `npm i` to ensure package-lock.json up-to-date
pkmnct Jan 23, 2021
b07ac7c
Style/formatting changes, other minor tweaks
pkmnct Jan 23, 2021
735753e
Remove manual adding of accounts, now sync script will check if accou…
superpowered Jan 23, 2021
32813d1
Some debugs for the new flows
superpowered Jan 23, 2021
7189f49
Minor cleanup
pkmnct Jan 25, 2021
92e8f68
Fix typo
pkmnct Jan 25, 2021
143b47a
message may not have event key
pkmnct Jan 26, 2021
90cf1a5
Remove callbackData
pkmnct Jan 26, 2021
be3250c
Bump version
pkmnct Jan 26, 2021
d04ca78
Fix waitForElement
pkmnct Jan 26, 2021
422a3e3
Add additional default settings
pkmnct Jan 26, 2021
d110836
Merge commit '35de422d2a604bcbf7dafa2788f8521f398357a6' into multiple…
superpowered Jan 28, 2021
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
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,7 @@ node_modules
dist
*.zip

.stellar
.vscode/*

.stellar
stellar
11 changes: 0 additions & 11 deletions .vscode/settings.json

This file was deleted.

35 changes: 35 additions & 0 deletions public/css/settings.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,38 @@
input[type="checkbox"]:checked + label:before, input[type="radio"]:checked + label:before {
content: '✓';
}

.mutiple-accounts-wrapper {
display: none;
}
#setting-multipleAccountsEnabled:checked ~ .mutiple-accounts-wrapper {
display: block;
}

.mutiple-accounts-input-wrapper:first-child .multipleAccounts-delete{
display: none;
}

.mutiple-accounts-input-wrapper {
display: flex;
align-items: flex-end;
margin-bottom: 1.5em;
}

.mutiple-accounts-input-wrapper label {
width: calc(100% - 9em);
margin-right: 1em;
margin-bottom: 0;
}

.mutiple-accounts-input-wrapper label input {
width: 100%;
}

.multipleAccounts-delete {
width: 8em;
}

#main input[type="text"].error {
border-color: #762206;
}
41 changes: 38 additions & 3 deletions public/html/settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<link rel="stylesheet" href="/css/settings.css" />
<link rel="icon" type="image/png" href="/images/icon128.png" />
</head>

<body class="is-preload">
<!-- Wrapper -->
<div id="wrapper">
Expand All @@ -20,14 +21,16 @@ <h1>Settings</h1>
<!-- Nav -->
<nav id="nav">
<ul>
<li><a href="#welcome" class="active">Welcome Page</a></li>
<li><a href="#changeLog" class="active">Changelog</a></li>
<li><a href="#triangleFix">Triangle Indicator Fix</a></li>
<li><a href="#debugMode">Debug Mode</a></li>
<li><a href="#multipleAccounts">Multiple Accounts</a></li>
</ul>
</nav>

<!-- Main -->
<main id="main">
<section id="welcome" class="main">
<section id="changeLog" class="main">
<header class="major">
<h2>Changelog</h2>
</header>
Expand All @@ -38,6 +41,7 @@ <h2>Changelog</h2>
<input type="checkbox" id="setting-changelogOnUpdate" name="setting-changelogOnUpdate" />
<label for="setting-changelogOnUpdate">Display changelog on update</label>
</section>

<section id="triangleFix" class="main">
<header class="major">
<h2>Triangle Indicator Fix</h2>
Expand All @@ -49,6 +53,7 @@ <h2>Triangle Indicator Fix</h2>
<input type="checkbox" id="setting-fixTriangle" name="setting-fixTriangle" />
<label for="setting-fixTriangle">Triangle Indicator Fix</label>
</section>

<section id="debugMode" class="main">
<header class="major">
<h2>Debug Mode</h2>
Expand All @@ -60,6 +65,35 @@ <h2>Debug Mode</h2>
<input type="checkbox" id="setting-debugMode" name="setting-debugMode" />
<label for="setting-debugMode">Debug Mode</label>
</section>

<section id="multipleAccounts" class="main">
<header class="major">
<h2>Multiple Accounts</h2>
</header>
<p>
TODO: all this text. Probably a warning about not changing these values after the fact or risking data
loss.<br />
Robinhood Name will probably have to be the Name (First Lase) on the robinhood Account. <br />
</p>
<input type="checkbox" id="setting-multipleAccountsEnabled" name="setting-multipleAccountsEnabled" />
<label for="setting-multipleAccountsEnabled">Allow Multiple Accounts</label>

<div class="mutiple-accounts-wrapper">
<div id="mutiple-account-rows"></div>
<template id="mutiple-accounts-input-wrapper-template">
<div class="mutiple-accounts-input-wrapper">
<label>
RobinHood Account Name
<input required type="text" class="setting-multipleAccounts-robinHoodInput" />
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than having the user manually enter their account names, we can just scrape the account name every time we sync Robinhood. If the multiple account setting is not enabled, the value is ignored.

If it is enabled, we do a setup check (similar to the initial setup), where we check if this device has synced with the Robinhood account logged in. (These could be stored in an array in chrome.storage.sync). If the current device has not set up that account before, we can then trigger the property setup/check.

This would give users a more seamless experience, and reduce logic on the settings page since it would just be a checkbox.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, latest push should accomplish this...
Need to probably test some of the flows and make sure the notifications seem correct in each one.

... Probably also need to add a delete script under the debug at some point, more just for convienence, since adding and deleting all these accounts is crazy tedious.

Changing the returnValue.accountName = accountNameElement.innerText; to a static value works well enough for testing to add new accounts.

</label>
<button class="multipleAccounts-delete">Delete</button>
</div>
</template>
<button id="multipleAccounts-add">
Add Account
</button>
</div>
</section>
</main>

<!-- Footer -->
Expand All @@ -80,4 +114,5 @@ <h2>Debug Mode</h2>
<script src="/js/external/stellar/main.js"></script>
<script src="/js/settings.js"></script>
</body>
</html>

</html>
57 changes: 54 additions & 3 deletions src/background/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,21 @@ const eventHandlers = {
active: false,
});
},
"mint-force-sync": () => {
// TODO: This got removed in an earlier commit. Check if replaced?
debug.log("trigger-sync event");
// Send notification
chrome.tabs.sendMessage(mintTab, {
status: "Syncing Mint with Robinhood.",
persistent: true,
});

// Trigger the sync
chrome.tabs.create({
url: urls.robinhood.scrape,
active: false,
});
},
// This event is emitted by the main Robinhood content script.
"robinhood-login-needed": ({ sender }: eventHandler) => {
debug.log("robinhood-login-needed event");
Expand Down Expand Up @@ -134,11 +149,15 @@ const eventHandlers = {
}
},
// This event is emitted by the Mint property update content script.
"mint-sync-complete": () => {
"mint-sync-complete": ({ message }) => {
debug.log("mint-sync-complete event");
chrome.storage.sync.set({ syncTime: new Date().toString() });
let account = "";
if (message.account) {
account = " " + message.account; // TODO: sanitize
}
chrome.tabs.sendMessage(mintTab, {
status: "Sync Complete! Reload to see the change.",
status: "Sync Complete! Reload to see the change." + account,
link: "/overview.event",
linkText: "Reload",
persistent: true,
Expand Down Expand Up @@ -219,8 +238,40 @@ const eventHandlers = {
chrome.storage.sync.set({ needsOldPropertyRemoved: true });
if (!debug.isEnabled()) chrome.tabs.remove(sender.tab.id);
},
// This event is emitted by the Mint property check content script.
"mint-property-non-multiple-remove": ({ sender }: eventHandler) => {
debug.log("mint-property-non-multiple-remove event");
chrome.tabs.sendMessage(mintTab, {
status:
"Your account appears to have data from a non multiple account setup. Please remove the old 'Robinhood Cash', 'Robinhood Stocks', 'Robinhood Crypto' & 'Robinhood Other' properties from Mint to prevent duplication of your portfolio balance. Reload the overview to sync after removing the property.",
persistent: true,
link: "https://mint.intuit.com/settings.event?filter=property",
linkText: "Mint Properties",
newTab: true,
});
chrome.storage.sync.set({ needsOldPropertyRemoved: true });
if (!debug.isEnabled()) chrome.tabs.remove(sender.tab.id);
},
// This event is emitted by the Mint property check content script.
"mint-property-non-single-remove": ({ sender }: eventHandler) => {
debug.log("mint-property-non-multiple-remove event");
chrome.tabs.sendMessage(mintTab, {
status:
"Your account appears to have data from a multiple account setup. Please remove the old 'Robinhood Cash - [ACCOUNT_ NAME]', 'Robinhood Stocks - [ACCOUNT_ NAME]', 'Robinhood Crypto - [ACCOUNT_ NAME]' & 'Robinhood Other - [ACCOUNT_ NAME]' properties from Mint to prevent duplication of your portfolio balance. Reload the overview to sync after removing the property.",
persistent: true,
link: "https://mint.intuit.com/settings.event?filter=property",
linkText: "Mint Properties",
newTab: true,
});
chrome.storage.sync.set({ needsOldPropertyRemoved: true });
if (!debug.isEnabled()) chrome.tabs.remove(sender.tab.id);
},
};

chrome.runtime.onMessage.addListener((message, sender) => {
eventHandlers[message.event]({ message, sender });
if (message && message.event && typeof eventHandlers[message.event] === "function") {
eventHandlers[message.event]({ message, sender });
} else {
throw new Error(message.event);
}
});
117 changes: 95 additions & 22 deletions src/content/mint/properties/check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,54 +13,47 @@ new Overlay("Performing Initial Setup. Please Wait...", "This window will automa
export const robinhoodProperties = ["Cash", "Stocks", "Crypto", "Other"];

// Function to check if the propert exists on the page
const checkIfPropertyExists = (property) => {
const checkIfPropertyExists = (property, looseCheck = false) => {
debug.log("Checking if property exists:", property);

const propertyElements = document.querySelectorAll(".OtherPropertyView");

let foundProperty = false;
for (const propertyElement of propertyElements) {
if ((propertyElement as HTMLElement).innerText.includes(`Robinhood ${property}`)) {
const titleElement = propertyElement.querySelector(".summaryView span:first-child") as HTMLElement;
const title = titleElement.innerText.trim();
if (title === `Robinhood ${property}`) {
debug.log(`Found property "${property}"`, propertyElement);
foundProperty = true;
// Stop searching
break;
} else if (looseCheck && title.includes(`Robinhood ${property}`)) {
debug.log(`Found property "${property}" - loose check`, propertyElement);
foundProperty = true;
break;
}
}
return foundProperty;
};

const setupProperties = () => {
const setupProperties = (subLabel = "") => {
// Need to keep track of how many properties we added to ensure each gets set up before initiating sync
let newProperties = 0;

robinhoodProperties.forEach((property) => {
if (!checkIfPropertyExists(property)) {
debug.log(`Could not find "${property}", adding it.`);
if (!checkIfPropertyExists(property + subLabel)) {
debug.log(`Could not find "${property + subLabel}", adding it.`);

// Trigger setup of property
chrome.runtime.sendMessage({
event: "mint-create",
property,
property: property + subLabel,
});
newProperties++;
}
});

// Check for old version
if (checkIfPropertyExists("Account")) {
debug.log("Found old Robinhood Account property. This must be removed to finish setup.");
chrome.runtime.sendMessage({
event: "mint-property-remove",
});
return;
}

// Success.
debug.log("Finishing Setup");
chrome.runtime.sendMessage({
event: "mint-property-setup-complete",
newProperties,
});
return newProperties;
};

window.addEventListener("load", () => {
Expand All @@ -70,7 +63,87 @@ window.addEventListener("load", () => {
failureAttempts: 20,
callback: (result) => {
debug.log("Found Property View. Setting up properties.", result);
setupProperties();
chrome.storage.sync.get(
{
multipleAccountsEnabled: false,
multipleAccounts: [],
},
(result) => {
const { multipleAccountsEnabled, multipleAccounts } = result;
if (multipleAccountsEnabled && multipleAccounts && multipleAccounts.length) {
let newProperties = 0;
multipleAccounts.forEach((account) => {
const subLabel = ` - ${account.robinHoodValue}`;
newProperties += setupProperties(subLabel);
});

// Check for old version
if (checkIfPropertyExists("Account")) {
debug.log("Found old Robinhood Account property. This must be removed to finish setup.");
chrome.runtime.sendMessage({
event: "mint-property-remove",
});
return;
}

// Check for old non multiple account version
// Check for old multiple account version
let singleCheck = false;
robinhoodProperties.forEach((property) => {
if (checkIfPropertyExists(`${property}`)) {
singleCheck = true;
}
});
if (singleCheck) {
debug.log("Found old Robinhood Non Multiple Account property. This must be removed to finish setup.");
chrome.runtime.sendMessage({
event: "mint-property-non-multiple-remove",
});
return;
}

// Success.
debug.log("Finishing Setup");
chrome.runtime.sendMessage({
event: "mint-property-setup-complete",
newProperties,
});
return;
}
const newProperties = setupProperties();

// Check for old version
if (checkIfPropertyExists("Account")) {
debug.log("Found old Robinhood Account property. This must be removed to finish setup.");
chrome.runtime.sendMessage({
event: "mint-property-remove",
});
return;
}

// Check for old multiple account version
let multipleCheck = false;
robinhoodProperties.forEach((property) => {
if (checkIfPropertyExists(`${property} -`, true)) {
multipleCheck = true;
}
});
if (multipleCheck) {
debug.log("Found old Robinhood Multiple Account property. This must be removed to finish setup.");
chrome.runtime.sendMessage({
event: "mint-property-non-single-remove",
});
return;
}

// Success.
debug.log("Finishing Setup");
chrome.runtime.sendMessage({
event: "mint-property-setup-complete",
newProperties,
});
}
);
},
onError: () => {
// If we don't find the OtherPropertyView, check if no properties are set up
Expand Down
Loading