diff --git a/.babelrc b/.babelrc deleted file mode 100644 index 85a0c888..00000000 --- a/.babelrc +++ /dev/null @@ -1,41 +0,0 @@ -{ - "presets": [ - "@babel/preset-react", - [ - "@babel/preset-env", - { - "targets": { - "browsers": [ - "last 2 versions" - ] - } - } - ] - ], - "plugins": [ - "react-html-attrs", - "@babel/plugin-proposal-object-rest-spread", - [ - "@babel/plugin-transform-runtime", - { - "helpers": false, - "regenerator": true - } - ], - "@babel/plugin-proposal-class-properties", - "@babel/plugin-transform-react-constant-elements", - "@babel/plugin-transform-react-inline-elements", - "@babel/plugin-transform-react-jsx-source", - "@babel/plugin-syntax-dynamic-import" - ], - "env": { - "test": { - "plugins": [ - "babel-plugin-dynamic-import-node" - ] - }, - "development": { - "compact": false - } - } -} diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 00000000..7871fc37 --- /dev/null +++ b/babel.config.js @@ -0,0 +1,58 @@ +const { fixResolvePath, getResolverAlias } = require("./webpacktools"); + +module.exports = function (api) { + api.cache(true); + + return { + "presets": [ + "@babel/preset-react", + [ + "@babel/preset-env", + { + "targets": { + "browsers": [ + "last 2 versions" + ] + } + } + ] + ], + "plugins": [ + "react-html-attrs", + [ + "module-resolver", + { + root: ["./"], + alias: getResolverAlias(__dirname), + resolvePath: fixResolvePath(__dirname), + }, + ], + "@babel/plugin-proposal-object-rest-spread", + [ + "@babel/plugin-transform-runtime", + { + "helpers": false, + "regenerator": true + } + ], + "@babel/plugin-proposal-class-properties", + "@babel/plugin-proposal-nullish-coalescing-operator", + "@babel/plugin-proposal-optional-chaining", + "@babel/plugin-transform-react-constant-elements", + "@babel/plugin-transform-react-inline-elements", + "@babel/plugin-transform-react-jsx-source", + "@babel/plugin-syntax-dynamic-import" + ], + "env": { + "test": { + "plugins": [ + "babel-plugin-dynamic-import-node" + ] + }, + "development": { + "compact": false + } + } + }; +}; + diff --git a/package.json b/package.json index 2dc9458a..1f6981e2 100644 --- a/package.json +++ b/package.json @@ -101,7 +101,7 @@ "jest": { "globals": { "ts-jest": { - "useBabelrc": true + "babelConfig": true } }, "modulePathIgnorePatterns": [ @@ -120,15 +120,19 @@ "^.+\\.tsx?$": "ts-jest" }, "moduleFileExtensions": [ - "ts", - "tsx", "js", - "jsx", "json", - "node" - ] + "jsx", + "node", + "ts", + "tsx" + ], + "preset": "ts-jest/presets/js-with-babel", + "testMatch": null }, "dependencies": { + "@manaflair/redux-batch": "^1.0.0", + "@reduxjs/toolkit": "^1.2.3", "electron-localshortcut": "^3.2.1", "electron-log": "^2.2.9", "electron-settings": "^3.1.3", @@ -136,48 +140,55 @@ "glob": "^7.1.2", "i18next": "^10.6.0", "i18next-xhr-backend": "^1.5.1", + "lodash": "^4.17.15", + "redux-saga": "^1.1.3", "upath": "1.0.5" }, "devDependencies": { - "@babel/cli": "^7.7.7", - "@babel/core": "^7.7.7", - "@babel/plugin-proposal-class-properties": "^7.7.4", - "@babel/plugin-proposal-decorators": "^7.7.4", - "@babel/plugin-proposal-do-expressions": "^7.7.4", - "@babel/plugin-proposal-export-default-from": "^7.7.4", - "@babel/plugin-proposal-export-namespace-from": "^7.7.4", - "@babel/plugin-proposal-function-bind": "^7.7.4", - "@babel/plugin-proposal-function-sent": "^7.7.4", - "@babel/plugin-proposal-json-strings": "^7.7.4", - "@babel/plugin-proposal-logical-assignment-operators": "^7.7.4", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.7.4", - "@babel/plugin-proposal-numeric-separator": "^7.7.4", - "@babel/plugin-proposal-optional-chaining": "^7.7.4", - "@babel/plugin-proposal-pipeline-operator": "^7.7.4", - "@babel/plugin-proposal-throw-expressions": "^7.7.4", - "@babel/plugin-syntax-dynamic-import": "^7.7.4", - "@babel/plugin-syntax-import-meta": "^7.7.4", - "@babel/plugin-transform-react-constant-elements": "^7.7.4", - "@babel/plugin-transform-react-inline-elements": "^7.7.4", - "@babel/plugin-transform-react-jsx-source": "^7.7.4", - "@babel/plugin-transform-runtime": "^7.7.4", - "@babel/preset-env": "^7.7.7", - "@babel/preset-react": "^7.7.4", + "@babel/cli": "^7.8.3", + "@babel/core": "^7.8.3", + "@babel/plugin-proposal-class-properties": "^7.8.3", + "@babel/plugin-proposal-decorators": "^7.8.3", + "@babel/plugin-proposal-do-expressions": "^7.8.3", + "@babel/plugin-proposal-export-default-from": "^7.8.3", + "@babel/plugin-proposal-export-namespace-from": "^7.8.3", + "@babel/plugin-proposal-function-bind": "^7.8.3", + "@babel/plugin-proposal-function-sent": "^7.8.3", + "@babel/plugin-proposal-json-strings": "^7.8.3", + "@babel/plugin-proposal-logical-assignment-operators": "^7.8.3", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-proposal-numeric-separator": "^7.8.3", + "@babel/plugin-proposal-optional-chaining": "^7.8.3", + "@babel/plugin-proposal-pipeline-operator": "^7.8.3", + "@babel/plugin-proposal-throw-expressions": "^7.8.3", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-transform-react-constant-elements": "^7.8.3", + "@babel/plugin-transform-react-inline-elements": "^7.8.3", + "@babel/plugin-transform-react-jsx-source": "^7.8.3", + "@babel/plugin-transform-runtime": "^7.8.3", + "@babel/preset-env": "^7.8.3", + "@babel/preset-react": "^7.8.3", "@bunq-community/bunq-js-client": "^1.0.3", "@bunq-community/bunqdesktop-templates": "^1.2.0", "@fortawesome/fontawesome-free": "^5.2.0", "@material-ui/core": "^3.9.2", "@material-ui/icons": "^3.0.2", "@material-ui/lab": "^3.0.0-alpha.30", + "@rollup/plugin-typescript": "^2.1.0", "@types/jest": "^24.0.25", + "@types/lodash": "^4.14.149", "@types/moxios": "^0.4.9", "@types/node": "^13.1.4", "@types/react-i18next": "^8.1.0", + "@types/react-router": "^5.1.4", + "@types/react-router-dom": "^5.1.3", "animate.css": "^3.7.2", "awaiting": "^3.0.0", "axios": "0.18.1", "babel-loader": "^8.0.6", "babel-plugin-dynamic-import-node": "^2.3.0", + "babel-plugin-module-resolver": "^4.0.0", "babel-plugin-react-html-attrs": "^2.1.0", "babel-plugin-system-import-transformer": "^3.1.0", "chart.js": "^2.7.2", @@ -201,9 +212,9 @@ "gulp-watch": "^5.0.1", "hard-source-webpack-plugin": "^0.13.1", "html-webpack-plugin": "^3.2.0", - "iban": "^0.0.10", + "iban": "^0.0.12", "increase-memory-limit": "^1.0.6", - "jest": "^24.1.0", + "jest": "^24.9.0", "libphonenumber-js": "^1.6.4", "localforage": "^1.7.2", "loglevel": "^1.6.1", @@ -217,27 +228,27 @@ "prettier": "^1.14.2", "prop-types": "^15.6.2", "qrcode.react": "^0.8.0", - "react": "^16.6.3", + "react": "^16.12.0", "react-chartjs-2": "^2.7.2", "react-color": "^2.14.1", "react-copy-to-clipboard": "^5.0.1", - "react-dom": "^16.4.1", + "react-dom": "^16.12.0", "react-helmet": "^5.2.0", "react-i18next": "^7.7.0", "react-json-view": "^1.17.1", "react-loadable": "^5.4.0", "react-map-gl": "^3.3.5", "react-number-format": "^4.0.7", - "react-redux": "^5.0.7", - "react-router": "^4.3.1", - "react-router-dom": "^4.3.1", + "react-redux": "^7.1.3", + "react-router": "^5.1.2", + "react-router-dom": "^5.1.2", "react-spring": "^3.1.0", "react-sticky-box": "^0.6.1", "react-test-renderer": "^16.3.1", "react-visibility-sensor": "^5.0.2", "react-windowed-list": "^2.0.0", - "redux": "^3.7.2", - "redux-form": "^7.4.2", + "redux": "^4.0.5", + "redux-form": "^8.2.6", "redux-mock-store": "^1.5.1", "redux-thunk": "^2.2.0", "rollup": "^0.45.2", @@ -247,10 +258,10 @@ "spectron": "^3.7.2", "store": "^2.0.4", "style-loader": "^0.22.1", - "ts-jest": "^23.1.4", - "ts-loader": "^4.5.0", + "ts-jest": "^24.3.0", + "ts-loader": "^6.2.1", "typeface-roboto": "^0.0.54", - "typescript": "^3.0.1", + "typescript": "^3.7.5", "uglifyjs-webpack-plugin": "^1.3.0", "universal-analytics": "^0.4.15", "vcf": "^2.0.1", diff --git a/src/react/Actions/filters.js b/src/Actions/filters.js similarity index 100% rename from src/react/Actions/filters.js rename to src/Actions/filters.js diff --git a/src/react/Actions/master_card_action_info.js b/src/Actions/master_card_action_info.js similarity index 84% rename from src/react/Actions/master_card_action_info.js rename to src/Actions/master_card_action_info.js index b8104ddb..9a1cc95a 100644 --- a/src/react/Actions/master_card_action_info.js +++ b/src/Actions/master_card_action_info.js @@ -1,5 +1,5 @@ -import BunqErrorHandler from "../Functions/BunqErrorHandler"; -import MasterCardAction from "../Models/MasterCardAction"; +import BunqErrorHandler from "~functions/BunqErrorHandler"; +import MasterCardAction from "~models/MasterCardAction"; import { masterCardActionsSetInfo } from "./master_card_actions"; @@ -14,8 +14,21 @@ export function masterCardActionSetInfo(master_card_action_info, account_id, mas }; } -export function masterCardActionInfoUpdate(BunqJSClient, user_id, account_id, master_card_action_id) { +export function masterCardActionInfoLoading() { + return { type: "MASTER_CARD_ACTION_INFO_IS_LOADING" }; +} + +export function masterCardActionInfoNotLoading() { + return { type: "MASTER_CARD_ACTION_INFO_IS_NOT_LOADING" }; +} + +export function masterCardActionInfoClear() { + return { type: "MASTER_CARD_ACTION_INFO_CLEAR" }; +} + +export function masterCardActionInfoUpdate(user_id, account_id, master_card_action_id) { const failedMessage = window.t("We failed to load the mastercard payment information"); + const BunqJSClient = window.BunqDesktopClient.BunqJSClient; return dispatch => { dispatch(masterCardActionInfoLoading()); @@ -25,7 +38,7 @@ export function masterCardActionInfoUpdate(BunqJSClient, user_id, account_id, ma const masterCardActionInfo = new MasterCardAction(masterCardAction); // update this item in the list and the stored data - dispatch(masterCardActionsSetInfo([masterCardActionInfo], parseInt(account_id), false, BunqJSClient)); + dispatch(masterCardActionsSetInfo([masterCardActionInfo], parseInt(account_id), false)); dispatch(masterCardActionSetInfo(masterCardActionInfo, parseInt(account_id), master_card_action_id)); dispatch(masterCardActionInfoNotLoading()); @@ -37,14 +50,4 @@ export function masterCardActionInfoUpdate(BunqJSClient, user_id, account_id, ma }; } -export function masterCardActionInfoLoading() { - return { type: "MASTER_CARD_ACTION_INFO_IS_LOADING" }; -} -export function masterCardActionInfoNotLoading() { - return { type: "MASTER_CARD_ACTION_INFO_IS_NOT_LOADING" }; -} - -export function masterCardActionInfoClear() { - return { type: "MASTER_CARD_ACTION_INFO_CLEAR" }; -} diff --git a/src/react/Actions/master_card_actions.js b/src/Actions/master_card_actions.js similarity index 83% rename from src/react/Actions/master_card_actions.js rename to src/Actions/master_card_actions.js index 948cb9b4..03ec4bd3 100644 --- a/src/react/Actions/master_card_actions.js +++ b/src/Actions/master_card_actions.js @@ -1,22 +1,22 @@ -import BunqErrorHandler from "../Functions/BunqErrorHandler"; -import MasterCardAction from "../Models/MasterCardAction"; +import MasterCardAction from "~models/MasterCardAction"; export const STORED_MASTER_CARD_ACTIONS = "BUNQDESKTOP_STORED_MASTER_CARD_ACTIONS"; -export function masterCardActionsSetInfo(masterCardActions, account_id, resetOldItems = false, BunqJSClient = false) { +export function masterCardActionsSetInfo(masterCardActions, account_id, resetOldItems = false) { const type = resetOldItems ? "MASTER_CARD_ACTIONS_SET_INFO" : "MASTER_CARD_ACTIONS_UPDATE_INFO"; return { type: type, payload: { - BunqJSClient, masterCardActions, account_id } }; } -export function loadStoredMasterCardActions(BunqJSClient) { +export function loadStoredMasterCardActions() { + const BunqJSClient = window.BunqDesktopClient.BunqJSClient; + return dispatch => { dispatch(masterCardActionsLoading()); const BunqDesktopClient = window.BunqDesktopClient; @@ -36,7 +36,6 @@ export function loadStoredMasterCardActions(BunqJSClient) { } export function masterCardActionsUpdate( - BunqJSClient, userId, accountId, options = { @@ -49,18 +48,19 @@ export function masterCardActionsUpdate( return dispatch => { dispatch(masterCardActionsLoading()); - BunqJSClient.api.masterCardAction + window.BunqDesktopClient.BunqJSClient.api.masterCardAction .list(userId, accountId, options) .then(masterCardActions => { // turn plain objects into Model objects const masterCardActionsNew = masterCardActions.map(item => new MasterCardAction(item)); - dispatch(masterCardActionsSetInfo(masterCardActionsNew, accountId, false, BunqJSClient)); + dispatch(masterCardActionsSetInfo(masterCardActionsNew, accountId, false)); dispatch(masterCardActionsNotLoading()); }) .catch(error => { dispatch(masterCardActionsNotLoading()); - BunqErrorHandler(dispatch, error, failedMessage); + // FIXME + // BunqErrorHandler(dispatch, error, failedMessage); }); }; } diff --git a/src/react/Actions/modal.js b/src/Actions/modal.js similarity index 100% rename from src/react/Actions/modal.js rename to src/Actions/modal.js diff --git a/src/react/Actions/note_texts.js b/src/Actions/note_texts.js similarity index 75% rename from src/react/Actions/note_texts.js rename to src/Actions/note_texts.js index d10de06d..a8788df8 100644 --- a/src/react/Actions/note_texts.js +++ b/src/Actions/note_texts.js @@ -1,4 +1,4 @@ -import BunqErrorHandler from "../Functions/BunqErrorHandler"; +import BunqErrorHandler from "~functions/BunqErrorHandler"; export function noteTextsSetInfo(noteTexts, event_type, user_id, account_id, event_id) { return { @@ -13,16 +13,16 @@ export function noteTextsSetInfo(noteTexts, event_type, user_id, account_id, eve }; } -export function notesTextsAddNote(BunqJSClient, event_type, user_id, account_id, event_id, content) { +export function notesTextsAddNote(event_type, user_id, account_id, event_id, content) { const failedMessage = window.t("We failed to add a new note"); return dispatch => { dispatch(noteTextsLoading()); - BunqJSClient.api.noteText + window.BunqDesktopClient.BunqJSClient.api.noteText .post(event_type, user_id, account_id, event_id, content) .then(() => { // update the notes - dispatch(noteTextsUpdate(BunqJSClient, event_type, user_id, account_id, event_id)); + dispatch(noteTextsUpdate(event_type, user_id, account_id, event_id)); dispatch(noteTextsNotLoading()); }) .catch(error => { @@ -33,16 +33,16 @@ export function notesTextsAddNote(BunqJSClient, event_type, user_id, account_id, }; } -export function notesTextsUpdateNote(BunqJSClient, event_type, user_id, account_id, event_id, content, note_id) { +export function notesTextsUpdateNote(event_type, user_id, account_id, event_id, content, note_id) { const failedMessage = window.t("We failed to update the note"); return dispatch => { dispatch(noteTextsLoading()); - BunqJSClient.api.noteText + window.BunqDesktopClient.BunqJSClient.api.noteText .put(event_type, user_id, account_id, event_id, content, note_id) .then(() => { // update the notes - dispatch(noteTextsUpdate(BunqJSClient, event_type, user_id, account_id, event_id)); + dispatch(noteTextsUpdate(event_type, user_id, account_id, event_id)); dispatch(noteTextsNotLoading()); }) .catch(error => { @@ -52,16 +52,16 @@ export function notesTextsUpdateNote(BunqJSClient, event_type, user_id, account_ }; } -export function notesTextsDeleteNote(BunqJSClient, event_type, user_id, account_id, event_id, note_id) { +export function notesTextsDeleteNote(event_type, user_id, account_id, event_id, note_id) { const failedMessage = window.t("We failed to delete the note"); return dispatch => { dispatch(noteTextsLoading()); - BunqJSClient.api.noteText + window.BunqDesktopClient.BunqJSClient.api.noteText .delete(event_type, user_id, account_id, event_id, note_id) .then(() => { // update the notes - dispatch(noteTextsUpdate(BunqJSClient, event_type, user_id, account_id, event_id)); + dispatch(noteTextsUpdate(event_type, user_id, account_id, event_id)); dispatch(noteTextsNotLoading()); }) .catch(error => { @@ -71,12 +71,12 @@ export function notesTextsDeleteNote(BunqJSClient, event_type, user_id, account_ }; } -export function noteTextsUpdate(BunqJSClient, event_type, user_id, account_id, event_id) { +export function noteTextsUpdate(event_type, user_id, account_id, event_id) { const failedMessage = window.t("We failed to load your notes"); return dispatch => { dispatch(noteTextsLoading()); - BunqJSClient.api.noteText + window.BunqDesktopClient.BunqJSClient.api.noteText .list(event_type, user_id, account_id, event_id) .then(noteTexts => { dispatch(noteTextsSetInfo(noteTexts, event_type, user_id, account_id, event_id)); diff --git a/src/react/Actions/oauth.js b/src/Actions/oauth.js similarity index 100% rename from src/react/Actions/oauth.js rename to src/Actions/oauth.js diff --git a/src/react/Actions/options.js b/src/Actions/options.js similarity index 100% rename from src/react/Actions/options.js rename to src/Actions/options.js diff --git a/src/react/Actions/pagination.js b/src/Actions/pagination.js similarity index 100% rename from src/react/Actions/pagination.js rename to src/Actions/pagination.js diff --git a/src/react/Actions/pay.js b/src/Actions/pay.js similarity index 77% rename from src/react/Actions/pay.js rename to src/Actions/pay.js index e45d4ab6..f91f49fc 100644 --- a/src/react/Actions/pay.js +++ b/src/Actions/pay.js @@ -1,15 +1,16 @@ -import BunqErrorHandler from "../Functions/BunqErrorHandler"; -import { openSnackbar } from "./snackbar"; +import BunqErrorHandler from "~functions/BunqErrorHandler"; import { paymentInfoUpdate } from "./payments"; -import { accountsUpdate } from "./accounts"; import { shareInviteMonetaryAccountInquiriesInfoUpdate } from "./share_invite_monetary_account_inquiries"; import { shareInviteMonetaryAccountResponsesInfoUpdate } from "./share_invite_monetary_account_responses"; +import { actions as snackbarActions } from "~store/snackbar"; +import { accountsUpdate } from "~store/accounts/thunks"; -export function paySend(BunqJSClient, userId, accountId, description, amount, targets, draft = false) { +export function paySend(userId, accountId, description, amount, targets, draft = false) { const failedMessage = window.t("We received the following error while sending your payment"); const successMessage1 = window.t("Draft payment successfully created!"); const successMessage2 = window.t("Payments sent successfully!"); const successMessage3 = window.t("Payment sent successfully!"); + const BunqJSClient = window.BunqDesktopClient.BunqJSClient; return dispatch => { dispatch(payLoading()); @@ -28,14 +29,14 @@ export function paySend(BunqJSClient, userId, accountId, description, amount, ta paymentHandler .post(userId, accountId, description, amount, targetData) - .then(result => { + .then(() => { const notification = draft ? successMessage1 : isMultiple ? successMessage2 : successMessage3; - dispatch(openSnackbar(notification)); + dispatch(snackbarActions.open({ message: notification })); // update the payments, accounts and share list - dispatch(shareInviteMonetaryAccountResponsesInfoUpdate(BunqJSClient, userId)); - dispatch(accountsUpdate(BunqJSClient, userId)); + dispatch(shareInviteMonetaryAccountResponsesInfoUpdate(userId)); + dispatch(accountsUpdate(userId)); dispatch(payNotLoading()); }) @@ -46,10 +47,11 @@ export function paySend(BunqJSClient, userId, accountId, description, amount, ta }; } -export function paySchedule(BunqJSClient, userId, accountId, description, amount, targets, schedule) { +export function paySchedule(userId, accountId, description, amount, targets, schedule) { const failedMessage = window.t("We received the following error while sending your payment"); const successMessage1 = window.t("Payment was successfully scheduled!"); const successMessage2 = window.t("Payments were successfully scheduled!"); + const BunqJSClient = window.BunqDesktopClient.BunqJSClient; return dispatch => { dispatch(payLoading()); @@ -73,15 +75,15 @@ export function paySchedule(BunqJSClient, userId, accountId, description, amount scheduleTypeHandler .post(userId, accountId, paymentData, schedule) - .then(result => { + .then(() => { const notification = isMultiple ? successMessage1 : successMessage2; - dispatch(openSnackbar(notification)); + dispatch(snackbarActions.open({ message: notification })); // update the payments, accounts and share list - dispatch(paymentInfoUpdate(BunqJSClient, userId, accountId)); - dispatch(shareInviteMonetaryAccountInquiriesInfoUpdate(BunqJSClient, userId, accountId)); - dispatch(shareInviteMonetaryAccountResponsesInfoUpdate(BunqJSClient, userId)); - dispatch(accountsUpdate(BunqJSClient, userId)); + dispatch(paymentInfoUpdate(userId, accountId)); + dispatch(shareInviteMonetaryAccountInquiriesInfoUpdate(userId, accountId)); + dispatch(shareInviteMonetaryAccountResponsesInfoUpdate( userId)); + dispatch(accountsUpdate(userId)); dispatch(payNotLoading()); }) diff --git a/src/react/Actions/payment_info.js b/src/Actions/payment_info.js similarity index 85% rename from src/react/Actions/payment_info.js rename to src/Actions/payment_info.js index 4dad712f..0856401d 100644 --- a/src/react/Actions/payment_info.js +++ b/src/Actions/payment_info.js @@ -1,5 +1,5 @@ -import BunqErrorHandler from "../Functions/BunqErrorHandler"; -import Payment from "../Models/Payment"; +import BunqErrorHandler from "~functions/BunqErrorHandler"; +import Payment from "~models/Payment"; import { paymentsSetInfo } from "./payments"; @@ -14,8 +14,9 @@ export function paymentInfoSetInfo(payment, account_id, payment_id) { }; } -export function paymentsUpdate(BunqJSClient, user_id, account_id, payment_id) { +export function paymentsUpdate(user_id, account_id, payment_id) { const failedMessage = window.t("We failed to load the payment info"); + const BunqJSClient = window.BunqDesktopClient.BunqJSClient; return dispatch => { dispatch(paymentInfoLoading()); diff --git a/src/react/Actions/payments.js b/src/Actions/payments.js similarity index 88% rename from src/react/Actions/payments.js rename to src/Actions/payments.js index d2ac50f0..3754756d 100644 --- a/src/react/Actions/payments.js +++ b/src/Actions/payments.js @@ -1,7 +1,7 @@ -import BunqErrorHandler from "../Functions/BunqErrorHandler"; -import { paymentApiFilter } from "../Functions/DataFilters"; +import BunqErrorHandler from "~functions/BunqErrorHandler"; +import { paymentApiFilter } from "~functions/DataFilters"; -import Payment from "../Models/Payment"; +import Payment from "~models/Payment"; export const STORED_PAYMENTS = "BUNQDESKTOP_STORED_PAYMENTS"; @@ -11,14 +11,15 @@ export function paymentsSetInfo(payments, account_id, resetOldItems = false, Bun return { type: type, payload: { - BunqJSClient, payments, account_id } }; } -export function loadStoredPayments(BunqJSClient) { +export function loadStoredPayments() { + const BunqJSClient = window.BunqDesktopClient.BunqJSClient; + return dispatch => { dispatch(paymentsLoading()); const BunqDesktopClient = window.BunqDesktopClient; @@ -39,7 +40,6 @@ export function loadStoredPayments(BunqJSClient) { } export function paymentInfoUpdate( - BunqJSClient, user_id, account_id, options = { @@ -59,7 +59,7 @@ export function paymentInfoUpdate( // turn plain objects into Model objects const paymentsNew = payments.map(item => new Payment(item)).filter(paymentApiFilter); - dispatch(paymentsSetInfo(paymentsNew, account_id, false, BunqJSClient)); + dispatch(paymentsSetInfo(paymentsNew, account_id, false)); dispatch(paymentsNotLoading()); }) .catch(error => { diff --git a/src/react/Actions/pending_payments.js b/src/Actions/pending_payments.js similarity index 69% rename from src/react/Actions/pending_payments.js rename to src/Actions/pending_payments.js index 5e766728..07bb0e93 100644 --- a/src/react/Actions/pending_payments.js +++ b/src/Actions/pending_payments.js @@ -1,6 +1,6 @@ export const PENDING_PAYMENTS_LOCATION = "BUNQDESKTOP_STORED_PENDING_PAYMENTS"; -export function loadPendingPayments(BunqJSClient) { +export function loadPendingPayments() { return dispatch => { const BunqDesktopClient = window.BunqDesktopClient; BunqDesktopClient.storeDecrypt(PENDING_PAYMENTS_LOCATION) @@ -13,53 +13,48 @@ export function loadPendingPayments(BunqJSClient) { }; } -export function pendingPaymentsSetPayments(BunqJSClient, pendingPayments) { +export function pendingPaymentsSetPayments(pendingPayments) { return { type: "PENDING_PAYMENTS_SET_PAYMENTS", payload: { - BunqJSClient, pending_payments: pendingPayments } }; } -export function pendingPaymentsAddPayments(BunqJSClient, accountId, pendingPayments) { +export function pendingPaymentsAddPayments(accountId, pendingPayments) { return { type: "PENDING_PAYMENTS_ADD_PAYMENTS", payload: { - BunqJSClient, account_id: accountId, pending_payments: pendingPayments } }; } -export function pendingPaymentsAddPayment(BunqJSClient, accountId, pendingPayment) { +export function pendingPaymentsAddPayment(accountId, pendingPayment) { return { type: "PENDING_PAYMENTS_ADD_PAYMENT", payload: { - BunqJSClient, account_id: accountId, pending_payment: pendingPayment } }; } -export function pendingPaymentsClearAccount(BunqJSClient, accountId) { +export function pendingPaymentsClearAccount(accountId) { return { type: "PENDING_PAYMENTS_CLEAR_ACCOUNT", payload: { - BunqJSClient, account_id: accountId } }; } -export function pendingPaymentsRemovePayment(BunqJSClient, pendingPaymentId) { +export function pendingPaymentsRemovePayment(pendingPaymentId) { return { type: "PENDING_PAYMENTS_REMOVE_PAYMENT", payload: { - BunqJSClient, pending_payment_id: pendingPaymentId } }; diff --git a/src/react/Actions/queue.js b/src/Actions/queue.js similarity index 100% rename from src/react/Actions/queue.js rename to src/Actions/queue.js diff --git a/src/react/Actions/registration.js b/src/Actions/registration.js similarity index 80% rename from src/react/Actions/registration.js rename to src/Actions/registration.js index f93746ae..16742fea 100644 --- a/src/react/Actions/registration.js +++ b/src/Actions/registration.js @@ -1,18 +1,19 @@ -import BunqErrorHandler from "../Functions/BunqErrorHandler"; -import { applicationSetStatus } from "./application"; +import BunqErrorHandler from "~functions/BunqErrorHandler"; import { userSetInfo } from "./user"; import { loadStoredPayments } from "./payments"; -import { loadStoredAccounts } from "./accounts"; -import { loadStoredBunqMeTabs } from "./bunq_me_tabs"; +import { loadStoredAccounts } from "~store/accounts/thunks"; +import { loadStoredBunqMeTabs } from "~store/bunqMeTabs/thunks"; import { loadStoredMasterCardActions } from "./master_card_actions"; import { loadStoredRequestInquiries } from "./request_inquiries"; import { loadStoredrequestInquiryBatches } from "./request_inquiry_batches"; import { loadStoredRequestResponses } from "./request_responses"; -import { loadStoredContacts } from "./contacts"; +import { loadStoredContacts } from "~store/contacts/thunks"; import { loadStoredShareInviteMonetaryAccountResponses } from "./share_invite_monetary_account_responses"; import { loadStoredShareInviteBankInquiries } from "./share_invite_monetary_account_inquiries"; import { loadPendingPayments } from "./pending_payments"; -import { openSnackbar } from "./snackbar"; + +import { actions as applicationActions } from "~store/application"; +import { actions as snackbarActions } from "~store/snackbar"; /** * Logs out of current account and logs back in to the selected stored key @@ -50,28 +51,35 @@ export function registrationLogin(apiKey = false, deviceName = false, environmen dispatch(registrationLoading()); if (!apiKey) { - dispatch(applicationSetStatus(statusMessage)); + dispatch(applicationActions.setStatusMessage(statusMessage)); if (BunqDesktopClient.derivedPassword) { try { const hasStoredApiKey = await BunqDesktopClient.loadApiKey(); if (!hasStoredApiKey) { // no given key and no stored key - dispatch(registrationNotLoading()); - dispatch(registrationSetNotReady()); + dispatch([ + registrationNotLoading(), + registrationSetNotReady(), + ]); return; } apiKey = hasStoredApiKey; } catch (exception) { BunqDesktopClient.Logger.error(exception); - dispatch(openSnackbar(failedToDecryptDataMessage)); - dispatch(registrationLogOut(false)); - dispatch(registrationNotLoading()); - dispatch(registrationSetNotReady()); + dispatch([ + snackbarActions.open(failedToDecryptDataMessage), + registrationLogOut(false), + registrationNotLoading(), + registrationSetNotReady(), + ]); + return; } } else { - dispatch(registrationNotLoading()); - dispatch(registrationSetNotReady()); + dispatch([ + registrationNotLoading(), + registrationSetNotReady(), + ]); return; } @@ -83,13 +91,13 @@ export function registrationLogin(apiKey = false, deviceName = false, environmen try { await BunqDesktopClient.BunqJSClientRun(); - dispatch(applicationSetStatus(statusMessage2)); + dispatch(applicationActions.setStatusMessage(statusMessage2)); await BunqDesktopClient.BunqJSClientInstall(); - dispatch(applicationSetStatus(statusMessage3)); + dispatch(applicationActions.setStatusMessage(statusMessage3)); await BunqDesktopClient.BunqJSClientRegisterDevice(); - dispatch(applicationSetStatus(statusMessage4)); + dispatch(applicationActions.setStatusMessage(statusMessage4)); await BunqDesktopClient.BunqJSClientRegisterSession(); const users = await BunqDesktopClient.BunqJSClientGetUsers(); @@ -99,18 +107,23 @@ export function registrationLogin(apiKey = false, deviceName = false, environmen // load bunq api data and other data like contacts from storage dispatch(registrationLoadStoredData()); } catch (exception) { - BunqErrorHandler(dispatch, exception, false, BunqJSClient); - dispatch(registrationResetToApiScreen()); - dispatch(registrationNotLoading()); - dispatch(registrationSetNotReady()); + const batchedActions = []; + BunqErrorHandler(batchedActions, exception, false, BunqJSClient); + dispatch(batchedActions.concat([ + registrationResetToApiScreen(), + registrationNotLoading(), + registrationSetNotReady(), + ])); return; } setTimeout(() => { - dispatch(applicationSetStatus("")); - dispatch(registrationNotLoading()); - dispatch(registrationSetBunqDesktopClientData()); - dispatch(registrationSetReady()); + dispatch([ + applicationActions.setStatusMessage(""), + registrationNotLoading(), + registrationSetBunqDesktopClientData(), + registrationSetReady(), + ]); }, 500); }; } @@ -134,7 +147,7 @@ export const registrationSwitchStoredApiKey = keyIndex => { BunqDesktopClient.Logger.error("switchStoredApiKey"); BunqDesktopClient.Logger.error(error); dispatch(registrationNotLoading()); - dispatch(openSnackbar(failureMessage)); + dispatch(snackbarActions.open({ message: failureMessage })); }); }; }; @@ -159,7 +172,7 @@ export const registrationSetPassword = password => { BunqDesktopClient.Logger.error("setupPassword"); BunqDesktopClient.Logger.error(error); dispatch(registrationNotLoading()); - dispatch(openSnackbar(failureMessage)); + dispatch(snackbarActions.open({ message: failureMessage })); }); }; }; @@ -183,7 +196,7 @@ export const registrationSkipPassword = () => { BunqDesktopClient.Logger.error("skipPassword"); BunqDesktopClient.Logger.error(error); dispatch(registrationNotLoading()); - dispatch(openSnackbar(failureMessage)); + dispatch(snackbarActions.open({ message: failureMessage })); }); }; }; @@ -203,13 +216,13 @@ export const registrationChangePassword = newPassword => { .then(done => { dispatch(registrationNotLoading()); dispatch(registrationSetBunqDesktopClientData()); - dispatch(openSnackbar(successMessage)); + dispatch(snackbarActions.open({ message: successMessage })); }) .catch(error => { BunqDesktopClient.Logger.error("changePassword"); BunqDesktopClient.Logger.error(error); dispatch(registrationNotLoading()); - dispatch(openSnackbar(failureMessage)); + dispatch(snackbarActions.open({ message: failureMessage })); }); }; }; @@ -266,7 +279,7 @@ export function registrationResetToApiScreen(resetStoredApiKey = false) { /** * Log out without removing the stored apikey and go back to password screen - * @param resetPassword + * @param {boolean} resetStoredApiKey * @returns {function(*)} */ export function registrationLogOut(resetStoredApiKey = true) { @@ -353,22 +366,21 @@ export function registrationNotLoading() { export function registrationLoadStoredData() { const BunqDesktopClient = window.BunqDesktopClient; - const BunqJSClient = BunqDesktopClient.BunqJSClient; return dispatch => { // skip if no apiKey is set if (!BunqDesktopClient.apiKey) return; - dispatch(loadStoredAccounts(BunqJSClient)); - dispatch(loadStoredContacts(BunqJSClient)); - dispatch(loadPendingPayments(BunqJSClient)); - dispatch(loadStoredPayments(BunqJSClient)); - dispatch(loadStoredBunqMeTabs(BunqJSClient)); - dispatch(loadStoredMasterCardActions(BunqJSClient)); - dispatch(loadStoredRequestInquiries(BunqJSClient)); - dispatch(loadStoredrequestInquiryBatches(BunqJSClient)); - dispatch(loadStoredRequestResponses(BunqJSClient)); - dispatch(loadStoredShareInviteMonetaryAccountResponses(BunqJSClient)); - dispatch(loadStoredShareInviteBankInquiries(BunqJSClient)); + dispatch(loadStoredAccounts()); + dispatch(loadStoredContacts()); + dispatch(loadPendingPayments()); + dispatch(loadStoredPayments()); + dispatch(loadStoredBunqMeTabs()); + dispatch(loadStoredMasterCardActions()); + dispatch(loadStoredRequestInquiries()); + dispatch(loadStoredrequestInquiryBatches()); + dispatch(loadStoredRequestResponses()); + dispatch(loadStoredShareInviteMonetaryAccountResponses()); + dispatch(loadStoredShareInviteBankInquiries()); }; } diff --git a/src/react/Actions/request_inquiries.js b/src/Actions/request_inquiries.js similarity index 85% rename from src/react/Actions/request_inquiries.js rename to src/Actions/request_inquiries.js index b1b7505e..73dac221 100644 --- a/src/react/Actions/request_inquiries.js +++ b/src/Actions/request_inquiries.js @@ -1,5 +1,5 @@ -import BunqErrorHandler from "../Functions/BunqErrorHandler"; -import RequestInquiry from "../Models/RequestInquiry"; +import BunqErrorHandler from "~functions/BunqErrorHandler"; +import RequestInquiry from "~models/RequestInquiry"; export const STORED_REQUEST_INQUIRIES = "BUNQDESKTOP_STORED_REQUEST_INQUIRIES"; @@ -9,21 +9,22 @@ export function requestInquiriesSetInfo(requestInquiries, account_id, resetOldIt return { type: type, payload: { - BunqJSClient, requestInquiries, account_id } }; } -export function loadStoredRequestInquiries(BunqJSClient) { +export function loadStoredRequestInquiries() { + const BunqJSClient = window.BunqDesktopClient.BunqJSClient; + return dispatch => { dispatch(requestInquiriesLoading()); const BunqDesktopClient = window.BunqDesktopClient; BunqDesktopClient.storeDecrypt(STORED_REQUEST_INQUIRIES) .then(data => { if (data && data.items) { - const newRequestInquiries = data.items.map(item => new RequestInquiry(item)); + const newRequestInquiries = data.items.map(item => (new RequestInquiry(item)).toPlainObject()); dispatch(requestInquiriesSetInfo(newRequestInquiries, data.account_id)); } dispatch(requestInquiriesNotLoading()); @@ -35,7 +36,6 @@ export function loadStoredRequestInquiries(BunqJSClient) { } export function requestInquiriesUpdate( - BunqJSClient, userId, accountId, options = { @@ -51,8 +51,8 @@ export function requestInquiriesUpdate( BunqJSClient.api.requestInquiry .list(userId, accountId, options) .then(requestInquiries => { - const newRequestInquiries = requestInquiries.map(item => new RequestInquiry(item)); - dispatch(requestInquiriesSetInfo(newRequestInquiries, accountId, false, BunqJSClient)); + const newRequestInquiries = requestInquiries.map(item => (new RequestInquiry(item)).toPlainObject()); + dispatch(requestInquiriesSetInfo(newRequestInquiries, accountId, false)); dispatch(requestInquiriesNotLoading()); }) .catch(error => { diff --git a/src/react/Actions/request_inquiry.js b/src/Actions/request_inquiry.js similarity index 65% rename from src/react/Actions/request_inquiry.js rename to src/Actions/request_inquiry.js index b2b0802f..99ced0b9 100644 --- a/src/react/Actions/request_inquiry.js +++ b/src/Actions/request_inquiry.js @@ -1,42 +1,45 @@ -import BunqErrorHandler from "../Functions/BunqErrorHandler"; -import { openSnackbar } from "./snackbar"; +import BunqErrorHandler from "~functions/BunqErrorHandler"; import { requestInquiryUpdate } from "./request_inquiry_info"; import { requestInquiryBatchesUpdate } from "./request_inquiry_batches"; +import { actions as snackbarActions } from "~store/snackbar"; -export function requestInquirySend(BunqJSClient, userId, accountId, requestInquiries) { +export function requestInquirySend(userId, accountId, requestInquiries) { const failedMessage = window.t("We received the following error while sending your request"); const successMessage = window.t("Request was sent successfully!"); + const BunqJSClient = window.BunqDesktopClient.BunqJSClient; return dispatch => { dispatch(requestInquiryLoading()); BunqJSClient.api.requestInquiryBatch .post(userId, accountId, requestInquiries, false, {}) .then(result => { - dispatch(openSnackbar(successMessage)); + dispatch(snackbarActions.open({ message: successMessage })); dispatch(requestInquiryNotLoading()); }) .catch(error => { dispatch(requestInquiryNotLoading()); - BunqErrorHandler(dispatch, error, failedMessage); + // FIXME + // BunqErrorHandler(dispatch, error, failedMessage); }); }; } -export function requestInquiryCancel(BunqJSClient, userId, accountId, requestInquiryId) { +export function requestInquiryCancel(userId, accountId, requestInquiryId) { const failedMessage = window.t("We received the following error while trying to cancel your request inquiry"); const successMessage = window.t("Request was cancelled successfully!"); + const BunqJSClient = window.BunqDesktopClient.BunqJSClient; return dispatch => { dispatch(requestInquiryLoading()); BunqJSClient.api.requestInquiry .put(userId, accountId, requestInquiryId, "REVOKED") - .then(result => { - dispatch(openSnackbar(successMessage)); + .then(() => { + dispatch(snackbarActions.open({ message: successMessage })); dispatch(requestInquiryNotLoading()); // update the information page - dispatch(requestInquiryUpdate(BunqJSClient, userId, accountId, requestInquiryId)); - dispatch(requestInquiryBatchesUpdate(BunqJSClient, userId, accountId)); + dispatch(requestInquiryUpdate(userId, accountId, requestInquiryId)); + dispatch(requestInquiryBatchesUpdate(userId, accountId)); }) .catch(error => { dispatch(requestInquiryNotLoading()); diff --git a/src/react/Actions/request_inquiry_batches.js b/src/Actions/request_inquiry_batches.js similarity index 91% rename from src/react/Actions/request_inquiry_batches.js rename to src/Actions/request_inquiry_batches.js index 8034d62d..b1e72c82 100644 --- a/src/react/Actions/request_inquiry_batches.js +++ b/src/Actions/request_inquiry_batches.js @@ -1,5 +1,5 @@ -import BunqErrorHandler from "../Functions/BunqErrorHandler"; -import RequestInquiryBatch from "../Models/RequestInquiryBatch"; +import BunqErrorHandler from "~functions/BunqErrorHandler"; +import RequestInquiryBatch from "~models/RequestInquiryBatch"; export const STORED_REQUEST_INQUIRY_BATCHES = "BUNQDESKTOP_STORED_REQUEST_INQUIRY_BATCHES"; @@ -14,14 +14,15 @@ export function requestInquiryBatchesSetInfo( return { type: type, payload: { - BunqJSClient, requestInquiryBatches, account_id } }; } -export function loadStoredrequestInquiryBatches(BunqJSClient) { +export function loadStoredrequestInquiryBatches() { + const BunqJSClient = window.BunqDesktopClient.BunqJSClient; + return dispatch => { dispatch(requestInquiryBatchesLoading()); const BunqDesktopClient = window.BunqDesktopClient; @@ -40,7 +41,6 @@ export function loadStoredrequestInquiryBatches(BunqJSClient) { } export function requestInquiryBatchesUpdate( - BunqJSClient, user_id, accountId, options = { diff --git a/src/react/Actions/request_inquiry_info.js b/src/Actions/request_inquiry_info.js similarity index 86% rename from src/react/Actions/request_inquiry_info.js rename to src/Actions/request_inquiry_info.js index 9a075d14..08055dd9 100644 --- a/src/react/Actions/request_inquiry_info.js +++ b/src/Actions/request_inquiry_info.js @@ -1,5 +1,5 @@ -import BunqErrorHandler from "../Functions/BunqErrorHandler"; -import RequestInquiry from "../Models/RequestInquiry"; +import BunqErrorHandler from "~functions/BunqErrorHandler"; +import RequestInquiry from "~models/RequestInquiry"; import { requestInquiriesSetInfo } from "./request_inquiries"; @@ -14,8 +14,9 @@ export function requestInquirySetInfo(request_inquiry_info, account_id, request_ }; } -export function requestInquiryUpdate(BunqJSClient, user_id, account_id, request_inquiry_id) { +export function requestInquiryUpdate(user_id, account_id, request_inquiry_id) { const failedMessage = window.t("We failed to load the request information"); + const BunqJSClient = window.BunqDesktopClient.BunqJSClient; return dispatch => { dispatch(requestInquiryLoading()); diff --git a/src/react/Actions/request_response.js b/src/Actions/request_response.js similarity index 67% rename from src/react/Actions/request_response.js rename to src/Actions/request_response.js index 04461741..b273da22 100644 --- a/src/react/Actions/request_response.js +++ b/src/Actions/request_response.js @@ -1,11 +1,11 @@ -import BunqErrorHandler from "../Functions/BunqErrorHandler"; -import { openSnackbar } from "./snackbar"; +import BunqErrorHandler from "~functions/BunqErrorHandler"; import { requestResponseUpdate } from "./request_response_info"; import { requestInquiryBatchesUpdate } from "./request_inquiry_batches"; +import { actions as snackbarActions } from "~store/snackbar"; + // Disabled until after 0.7 release export function requestResponseAccept( - BunqJSClient, userId, accountId, requestResponseId, @@ -17,6 +17,7 @@ export function requestResponseAccept( ) { const failedMessage = window.t("We received the following error while trying to accept your request response"); const successMessage = window.t("Request response was successfully accepted!"); + const BunqJSClient = window.BunqDesktopClient.BunqJSClient; return dispatch => { dispatch(requestResponseLoading()); @@ -26,13 +27,13 @@ export function requestResponseAccept( address_shipping: options.address_shipping, amount_responded: amountResponded }) - .then(result => { - dispatch(openSnackbar(successMessage)); - dispatch(requestResponseNotLoading()); - - // update the information page - dispatch(requestResponseUpdate(BunqJSClient, userId, accountId, requestResponseId)); - dispatch(requestInquiryBatchesUpdate(BunqJSClient, userId, accountId)); + .then(() => { + dispatch([ + snackbarActions.open({ message: successMessage }), + requestResponseNotLoading(), + requestResponseUpdate(userId, accountId, requestResponseId), + requestInquiryBatchesUpdate(userId, accountId), + ]); }) .catch(error => { dispatch(requestResponseNotLoading()); @@ -41,24 +42,26 @@ export function requestResponseAccept( }; } -export function requestResponseReject(BunqJSClient, userId, accountId, requestResponseId) { +export function requestResponseReject(userId, accountId, requestResponseId) { const failedMessage = window.t("We received the following error while trying to cancel the request"); const successMessage = window.t("Request was rejected successfully!"); + const BunqJSClient = window.BunqDesktopClient.BunqJSClient; return dispatch => { dispatch(requestResponseLoading()); BunqJSClient.api.requestResponse .put(userId, accountId, requestResponseId, "REJECTED", {}) .then(result => { - dispatch(openSnackbar(successMessage)); + dispatch(snackbarActions.open({ message: successMessage })); dispatch(requestResponseNotLoading()); // update the information page - dispatch(requestResponseUpdate(BunqJSClient, userId, accountId, requestResponseId)); + dispatch(requestResponseUpdate(userId, accountId, requestResponseId)); }) .catch(error => { dispatch(requestResponseNotLoading()); - BunqErrorHandler(dispatch, error, failedMessage); + // FIXME: restore + // BunqErrorHandler(dispatch, error, failedMessage); }); }; } diff --git a/src/react/Actions/request_response_info.js b/src/Actions/request_response_info.js similarity index 86% rename from src/react/Actions/request_response_info.js rename to src/Actions/request_response_info.js index d4e13e5a..9ca6526c 100644 --- a/src/react/Actions/request_response_info.js +++ b/src/Actions/request_response_info.js @@ -1,5 +1,5 @@ -import BunqErrorHandler from "../Functions/BunqErrorHandler"; -import RequestResponse from "../Models/RequestResponse"; +import BunqErrorHandler from "~functions/BunqErrorHandler"; +import RequestResponse from "~models/RequestResponse"; import { requestResponsesSetInfo } from "./request_responses"; @@ -14,8 +14,9 @@ export function requestResponseSetInfo(request_response_info, account_id, reques }; } -export function requestResponseUpdate(BunqJSClient, user_id, account_id, request_response_id) { +export function requestResponseUpdate(user_id, account_id, request_response_id) { const failedMessage = window.t("We failed to load the request information"); + const BunqJSClient = window.BunqDesktopClient.BunqJSClient; return dispatch => { dispatch(requestResponseLoading()); diff --git a/src/react/Actions/request_responses.js b/src/Actions/request_responses.js similarity index 91% rename from src/react/Actions/request_responses.js rename to src/Actions/request_responses.js index 49058d9e..9e9fb72c 100644 --- a/src/react/Actions/request_responses.js +++ b/src/Actions/request_responses.js @@ -1,5 +1,5 @@ -import BunqErrorHandler from "../Functions/BunqErrorHandler"; -import RequestResponse from "../Models/RequestResponse"; +import BunqErrorHandler from "~functions/BunqErrorHandler"; +import RequestResponse from "~models/RequestResponse"; export const STORED_REQUEST_RESPONSES = "BUNQDESKTOP_STORED_REQUEST_RESPONSES"; @@ -9,14 +9,15 @@ export function requestResponsesSetInfo(requestResponses, account_id, resetOldIt return { type: type, payload: { - BunqJSClient, requestResponses, account_id } }; } -export function loadStoredRequestResponses(BunqJSClient) { +export function loadStoredRequestResponses() { + const BunqJSClient = window.BunqDesktopClient.BunqJSClient; + return dispatch => { dispatch(requestResponsesLoading()); const BunqDesktopClient = window.BunqDesktopClient; @@ -35,7 +36,6 @@ export function loadStoredRequestResponses(BunqJSClient) { } export function requestResponsesUpdate( - BunqJSClient, userId, accountId, options = { diff --git a/src/react/Actions/savings_goals.js b/src/Actions/savings_goals.js similarity index 100% rename from src/react/Actions/savings_goals.js rename to src/Actions/savings_goals.js diff --git a/src/react/Actions/scheduled_payments.js b/src/Actions/scheduled_payments.js similarity index 91% rename from src/react/Actions/scheduled_payments.js rename to src/Actions/scheduled_payments.js index 1fd0f226..5f0f80a7 100644 --- a/src/react/Actions/scheduled_payments.js +++ b/src/Actions/scheduled_payments.js @@ -1,4 +1,4 @@ -import BunqErrorHandler from "../Functions/BunqErrorHandler"; +import BunqErrorHandler from "~functions/BunqErrorHandler"; export function scheduledPaymentsSetInfo(scheduled_payments, account_id) { return { @@ -11,7 +11,6 @@ export function scheduledPaymentsSetInfo(scheduled_payments, account_id) { } export function scheduledPaymentsInfoUpdate( - BunqJSClient, user_id, account_id, options = { @@ -39,7 +38,6 @@ export function scheduledPaymentsInfoUpdate( } export function scheduledPaymentUpdate( - BunqJSClient, user_id, account_id, scheduled_payment_id, @@ -47,6 +45,7 @@ export function scheduledPaymentUpdate( schedule_info ) { const failedMessage = window.t("We failed to update the scheduled payment for this monetary account"); + const BunqJSClient = window.BunqDesktopClient.BunqJSClient; return dispatch => { dispatch(scheduledPaymentsLoading()); @@ -54,7 +53,7 @@ export function scheduledPaymentUpdate( BunqJSClient.api.schedulePayment .put(user_id, account_id, scheduled_payment_id, payment_info, schedule_info) .then(result => { - dispatch(scheduledPaymentsInfoUpdate(BunqJSClient, user_id, account_id)); + dispatch(scheduledPaymentsInfoUpdate(user_id, account_id)); dispatch(scheduledPaymentsNotLoading()); }) .catch(error => { diff --git a/src/react/Actions/share_invite_monetary_account_inquiries.js b/src/Actions/share_invite_monetary_account_inquiries.js similarity index 50% rename from src/react/Actions/share_invite_monetary_account_inquiries.js rename to src/Actions/share_invite_monetary_account_inquiries.js index 320116a9..99c1e7c3 100644 --- a/src/react/Actions/share_invite_monetary_account_inquiries.js +++ b/src/Actions/share_invite_monetary_account_inquiries.js @@ -1,41 +1,39 @@ -import BunqErrorHandler from "../Functions/BunqErrorHandler"; +import BunqErrorHandler from "~functions/BunqErrorHandler"; export const STORED_SHARE_INVITE_MONETARY_ACCOUNT_INQUIRIES = "BUNQDESKTOP_SHARE_INVITE_MONETARY_ACCOUNT_INQUIRIES"; export function shareInviteBankInquiriesSetInfo( share_invite_monetary_account_inquiries, account_id, - BunqJSClient = false ) { return { type: "SHARE_INVITE_INQUIRIES_SET_INFO", payload: { - BunqJSClient: BunqJSClient, account_id: account_id, share_invite_monetary_account_inquiries: share_invite_monetary_account_inquiries } }; } -export function loadStoredShareInviteBankInquiries(BunqJSClient) { - return dispatch => { - dispatch(shareInviteBankInquiriesLoading()); +export function loadStoredShareInviteBankInquiries() { + return async (dispatch) => { const BunqDesktopClient = window.BunqDesktopClient; - BunqDesktopClient.storeDecrypt(STORED_SHARE_INVITE_MONETARY_ACCOUNT_INQUIRIES) - .then(data => { - if (data && data.items) { - dispatch(shareInviteBankInquiriesSetInfo(data.items, data.account_id)); - } - dispatch(shareInviteBankInquiriesNotLoading()); - }) - .catch(error => { - dispatch(shareInviteBankInquiriesNotLoading()); - }); + + dispatch(shareInviteBankInquiriesLoading()); + + const batchedActions = []; + try { + const data = await BunqDesktopClient.storeDecrypt(STORED_SHARE_INVITE_MONETARY_ACCOUNT_INQUIRIES); + if (data && data.items) { + batchedActions.push(shareInviteBankInquiriesSetInfo(data.items, data.account_id)); + } + } finally { + dispatch(batchedActions.concat([shareInviteBankInquiriesNotLoading()])); + } }; } export function shareInviteMonetaryAccountInquiriesInfoUpdate( - BunqJSClient, user_id, account_id, options = { @@ -45,20 +43,20 @@ export function shareInviteMonetaryAccountInquiriesInfoUpdate( } ) { const failedMessage = window.t("We failed to load the share invite inquiries for this monetary account"); + const BunqJSClient = window.BunqDesktopClient.BunqJSClient; - return dispatch => { + return async (dispatch) => { dispatch(shareInviteBankInquiriesLoading()); - BunqJSClient.api.shareInviteMonetaryAccountInquiry - .list(user_id, account_id, options) - .then(shareInviteBankInquiries => { - dispatch(shareInviteBankInquiriesSetInfo(shareInviteBankInquiries, account_id, BunqJSClient)); - dispatch(shareInviteBankInquiriesNotLoading()); - }) - .catch(error => { - dispatch(shareInviteBankInquiriesNotLoading()); - BunqErrorHandler(dispatch, error, failedMessage); - }); + const batchedActions = []; + try { + const shareInviteBankInquiries = await BunqJSClient.api.shareInviteMonetaryAccountInquiry.list(user_id, account_id, options); + batchedActions.push(shareInviteBankInquiriesSetInfo(shareInviteBankInquiries, account_id, BunqJSClient)); + } catch (error) { + BunqErrorHandler(batchedActions, error, failedMessage); + } finally { + dispatch(batchedActions.concat([shareInviteBankInquiriesNotLoading()])); + } }; } diff --git a/src/Actions/share_invite_monetary_account_inquiry.js b/src/Actions/share_invite_monetary_account_inquiry.js new file mode 100644 index 00000000..a5a50776 --- /dev/null +++ b/src/Actions/share_invite_monetary_account_inquiry.js @@ -0,0 +1,72 @@ +import BunqErrorHandler from "~functions/BunqErrorHandler"; +import { shareInviteMonetaryAccountInquiriesInfoUpdate } from "./share_invite_monetary_account_inquiries"; +import { actions as snackbarActions } from "~store/snackbar"; + +export function shareInviteMonetaryAccountInquirySend( + userId, + accountId, + counterparty, + shareDetail, + shareOptions, + shareStatus = "PENDING" +) { + const failedMessage = window.t("We received the following error while sending your connect request"); + const successMessage = window.t("Connect request was sent successfully!"); + const BunqJSClient = window.BunqDesktopClient.BunqJSClient; + + return async (dispatch) => { + dispatch(shareInviteMonetaryAccountInquiryLoading()); + + const batchedActions = []; + try { + await BunqJSClient.api.shareInviteMonetaryAccountInquiry.post(userId, accountId, counterparty, shareDetail, shareStatus, { + share_type: "STANDARD", + ...shareOptions + }); + + batchedActions.push(snackbarActions.open({ message: successMessage })); + // update the payments, accounts and share list + batchedActions.push(shareInviteMonetaryAccountInquiriesInfoUpdate(userId, accountId)); + } catch (error) { + BunqErrorHandler(batchedActions, error, failedMessage); + } finally { + dispatch(batchedActions.concat([shareInviteMonetaryAccountInquiryNotLoading()])); + + } + }; +} + +export function shareInviteMonetaryAccountInquiryChangeStatus( + userId, + accountId, + shareInviteMonetaryAccountInquiryId, + status +) { + const failedMessage = window.t("We received the following error while updating your connect request"); + const successMessage = window.t("Connect request was updated successfully!"); + const BunqJSClient = window.BunqDesktopClient.BunqJSClient; + + return async (dispatch) => { + dispatch(shareInviteMonetaryAccountInquiryLoading()); + + const batchedActions = []; + try { + await BunqJSClient.api.shareInviteMonetaryAccountInquiry.putStatus(userId, accountId, shareInviteMonetaryAccountInquiryId, status); + batchedActions.push(snackbarActions.open({ message: successMessage })); + // update the payments, accounts and share list + batchedActions.push(shareInviteMonetaryAccountInquiriesInfoUpdate(userId, accountId)); + } catch (error) { + BunqErrorHandler(dispatch, error, failedMessage); + } finally { + dispatch(batchedActions.concat([shareInviteMonetaryAccountInquiryNotLoading()])) + } + }; +} + +export function shareInviteMonetaryAccountInquiryLoading() { + return { type: "SHARE_INVITE_MONETARY_ACCOUNT_INQUIRY_IS_LOADING" }; +} + +export function shareInviteMonetaryAccountInquiryNotLoading() { + return { type: "SHARE_INVITE_MONETARY_ACCOUNT_INQUIRY_IS_NOT_LOADING" }; +} diff --git a/src/react/Actions/share_invite_monetary_account_response.js b/src/Actions/share_invite_monetary_account_response.js similarity index 80% rename from src/react/Actions/share_invite_monetary_account_response.js rename to src/Actions/share_invite_monetary_account_response.js index 74b77df7..7da2069b 100644 --- a/src/react/Actions/share_invite_monetary_account_response.js +++ b/src/Actions/share_invite_monetary_account_response.js @@ -1,15 +1,14 @@ -import BunqErrorHandler from "../Functions/BunqErrorHandler"; -import { openSnackbar } from "./snackbar"; import { shareInviteMonetaryAccountResponsesInfoUpdate } from "./share_invite_monetary_account_responses"; +import { actions as snackbarActions } from "~store/snackbar"; export function shareInviteMonetaryAccountResponseChangeStatus( - BunqJSClient, userId, shareInviteMonetaryAccountResponseId, status ) { const failedMessage = window.t("We received the following error while updating your connect request"); const successMessage = window.t("Connect request was updated successfully!"); + const BunqJSClient = window.BunqDesktopClient.BunqJSClient; return dispatch => { dispatch(shareInviteMonetaryAccountResponseLoading()); @@ -17,15 +16,16 @@ export function shareInviteMonetaryAccountResponseChangeStatus( BunqJSClient.api.shareInviteMonetaryAccountResponse .putStatus(userId, shareInviteMonetaryAccountResponseId, status) .then(result => { - dispatch(openSnackbar(successMessage)); + dispatch(snackbarActions.open({ message: successMessage })); // update the payments, accounts and share list - dispatch(shareInviteMonetaryAccountResponsesInfoUpdate(BunqJSClient, userId, accountId)); + dispatch(shareInviteMonetaryAccountResponsesInfoUpdate(userId, accountId)); dispatch(shareInviteMonetaryAccountResponseNotLoading()); }) .catch(error => { dispatch(shareInviteMonetaryAccountResponseNotLoading()); - BunqErrorHandler(dispatch, error, failedMessage); + // FIXME + // BunqErrorHandler(dispatch, error, failedMessage); }); }; } diff --git a/src/react/Actions/share_invite_monetary_account_responses.js b/src/Actions/share_invite_monetary_account_responses.js similarity index 88% rename from src/react/Actions/share_invite_monetary_account_responses.js rename to src/Actions/share_invite_monetary_account_responses.js index 05e4f7d9..58710c14 100644 --- a/src/react/Actions/share_invite_monetary_account_responses.js +++ b/src/Actions/share_invite_monetary_account_responses.js @@ -1,4 +1,4 @@ -import BunqErrorHandler from "../Functions/BunqErrorHandler"; +import BunqErrorHandler from "~functions/BunqErrorHandler"; export const STORED_SHARE_INVITE_MONETARY_ACCOUNT_RESPONSES = "BUNQDESKTOP_SHARE_INVITE_MONETARY_ACCOUNT_RESPONSES"; @@ -9,13 +9,14 @@ export function shareInviteMonetaryAccountResponsesSetInfo( return { type: "SHARE_INVITE_RESPONSES_SET_INFO", payload: { - BunqJSClient: BunqJSClient, share_invite_monetary_account_responses: share_invite_monetary_account_responses } }; } -export function loadStoredShareInviteMonetaryAccountResponses(BunqJSClient) { +export function loadStoredShareInviteMonetaryAccountResponses() { + const BunqJSClient = window.BunqDesktopClient.BunqJSClient; + return dispatch => { dispatch(shareInviteMonetaryAccountResponsesLoading()); const BunqDesktopClient = window.BunqDesktopClient; @@ -33,7 +34,6 @@ export function loadStoredShareInviteMonetaryAccountResponses(BunqJSClient) { } export function shareInviteMonetaryAccountResponsesInfoUpdate( - BunqJSClient, user_id, options = { count: 200, @@ -42,6 +42,7 @@ export function shareInviteMonetaryAccountResponsesInfoUpdate( } ) { const failedMessage = window.t("We failed to load the share invite responses for this account"); + const BunqJSClient = window.BunqDesktopClient.BunqJSClient; return dispatch => { dispatch(shareInviteMonetaryAccountResponsesLoading()); @@ -49,7 +50,7 @@ export function shareInviteMonetaryAccountResponsesInfoUpdate( BunqJSClient.api.shareInviteMonetaryAccountResponse .list(user_id, options) .then(shareInviteMonetaryAccountResponses => { - dispatch(shareInviteMonetaryAccountResponsesSetInfo(shareInviteMonetaryAccountResponses, BunqJSClient)); + dispatch(shareInviteMonetaryAccountResponsesSetInfo(shareInviteMonetaryAccountResponses)); dispatch(shareInviteMonetaryAccountResponsesNotLoading()); }) .catch(error => { diff --git a/src/react/Actions/sidebar.js b/src/Actions/sidebar.js similarity index 100% rename from src/react/Actions/sidebar.js rename to src/Actions/sidebar.js diff --git a/src/react/Actions/user.js b/src/Actions/user.js similarity index 81% rename from src/react/Actions/user.js rename to src/Actions/user.js index 291cad10..eced4e53 100644 --- a/src/react/Actions/user.js +++ b/src/Actions/user.js @@ -1,8 +1,8 @@ import store from "store"; -import BunqErrorHandler from "../Functions/BunqErrorHandler"; +import BunqErrorHandler from "~functions/BunqErrorHandler"; import { registrationClearUserInfo } from "./registration"; -import { openSnackbar } from "./snackbar"; +import { actions as snackbarActions } from "~store/snackbar"; import { usersUpdate } from "./users"; const USER_ID_LOCATION = "BUNQDESKTOP_USER_ID"; @@ -29,9 +29,10 @@ export function userSetInfo(user, type) { }; } -export function userUpdateImage(BunqJSClient, userId, attachmentId, userType = "UserPerson") { +export function userUpdateImage(userId, attachmentId, userType = "UserPerson") { const failedMessage = window.t("We received the following error while updating the image for your account"); const successMessage = window.t("Image updated successfully!"); + const BunqJSClient = window.BunqDesktopClient.BunqJSClient; return dispatch => { // make the image public @@ -53,9 +54,9 @@ export function userUpdateImage(BunqJSClient, userId, attachmentId, userType = " } apiPromise - .then(result => { - dispatch(openSnackbar(successMessage)); - dispatch(usersUpdate(BunqJSClient, true)); + .then(() => { + dispatch(snackbarActions.open({ message: successMessage })); + dispatch(usersUpdate( true)); }) .catch(error => { BunqErrorHandler(dispatch, error, failedMessage); diff --git a/src/react/Actions/users.js b/src/Actions/users.js similarity index 84% rename from src/react/Actions/users.js rename to src/Actions/users.js index 27fb3c79..0961fbb4 100644 --- a/src/react/Actions/users.js +++ b/src/Actions/users.js @@ -1,8 +1,9 @@ -import BunqErrorHandler from "../Functions/BunqErrorHandler"; +import BunqErrorHandler from "~functions/BunqErrorHandler"; import { userSetInfo } from "./user"; -export function usersUpdate(BunqJSClient, updated = false) { +export function usersUpdate(updated = false) { const failedMessage = window.t("We failed to load your users"); + const BunqJSClient = window.BunqDesktopClient.BunqJSClient; return dispatch => { dispatch(usersLoading()); diff --git a/src/react/Reducers/general_filter.js b/src/Reducers/general_filter.js similarity index 95% rename from src/react/Reducers/general_filter.js rename to src/Reducers/general_filter.js index e0de2859..638d936e 100644 --- a/src/react/Reducers/general_filter.js +++ b/src/Reducers/general_filter.js @@ -1,5 +1,5 @@ export const defaultState = { - date: new Date() + date: +new Date() }; export default function reducer(state = defaultState, action) { @@ -50,9 +50,8 @@ export default function reducer(state = defaultState, action) { // any filter change updates the filter timestamp // for easier comparisons in shouldComponentUpdate handlers return { - date: new Date() + date: +new Date() }; - break; } return state; } diff --git a/src/react/Reducers/index.js b/src/Reducers/index.js similarity index 98% rename from src/react/Reducers/index.js rename to src/Reducers/index.js index be1e262b..951ae358 100644 --- a/src/react/Reducers/index.js +++ b/src/Reducers/index.js @@ -1,9 +1,9 @@ import { combineReducers } from "redux"; import { reducer as formReducer } from "redux-form"; -import amount_filter from "./amount_filter"; import account_id_filter from "./account_id_filter"; import accounts from "./accounts"; +import amount_filter from "./amount_filter"; import application from "./application"; import bunq_me_tabs from "./bunq_me_tabs"; import bunq_me_tab_filter from "./bunq_me_tab_filter"; @@ -13,7 +13,7 @@ import category_filter from "./category_filter"; import cards from "./cards"; import card_cvc2 from "./card_cvc2"; import card_id_filter from "./card_id_filter"; -import category_rules from "./category_rules.ts"; +import category_rules from "./category_rules"; import contacts from "./contacts"; import date_filter from "./date_filter"; import export_new from "./export_new"; diff --git a/src/react/Reducers/master_card_action_info.js b/src/Reducers/master_card_action_info.js similarity index 100% rename from src/react/Reducers/master_card_action_info.js rename to src/Reducers/master_card_action_info.js diff --git a/src/react/Reducers/master_card_actions.js b/src/Reducers/master_card_actions.js similarity index 75% rename from src/react/Reducers/master_card_actions.js rename to src/Reducers/master_card_actions.js index 2a5ff825..ff00e919 100644 --- a/src/react/Reducers/master_card_actions.js +++ b/src/Reducers/master_card_actions.js @@ -1,9 +1,6 @@ -import store from "store"; -import MergeApiObjects from "../Functions/MergeApiObjects"; -import { storeEncryptString } from "../Functions/Crypto/CryptoWorkerWrapper"; +import MergeApiObjects from "~functions/MergeApiObjects"; -import { STORED_MASTER_CARD_ACTIONS } from "../Actions/master_card_actions"; -import { STORED_BUNQ_ME_TABS } from "../Actions/bunq_me_tabs"; +import { STORED_MASTER_CARD_ACTIONS } from "~actions/master_card_actions"; export const defaultState = { master_card_actions: [], @@ -35,18 +32,15 @@ export default (state = defaultState, action) => { const mergedMasterCardActions = mergedInfo.items.slice(0, 1000); // store the data if we have access to the bunqjsclient - if (action.payload.BunqJSClient) { - const BunqDesktopClient = window.BunqDesktopClient; - BunqDesktopClient.storeEncrypt( - { - items: mergedMasterCardActions, - account_id: action.payload.account_id - }, - STORED_MASTER_CARD_ACTIONS - ) - .then(() => {}) - .catch(() => {}); - } + window.BunqDesktopClient.storeEncrypt( + { + items: mergedMasterCardActions, + account_id: action.payload.account_id + }, + STORED_MASTER_CARD_ACTIONS + ) + .then(() => {}) + .catch(() => {}); // update newer and older id for this monetary account const newerIds = { diff --git a/src/react/Reducers/modal.js b/src/Reducers/modal.js similarity index 100% rename from src/react/Reducers/modal.js rename to src/Reducers/modal.js diff --git a/src/react/Reducers/note_texts.js b/src/Reducers/note_texts.js similarity index 100% rename from src/react/Reducers/note_texts.js rename to src/Reducers/note_texts.js diff --git a/src/react/Reducers/oauth.js b/src/Reducers/oauth.js similarity index 98% rename from src/react/Reducers/oauth.js rename to src/Reducers/oauth.js index 277fef15..41a53209 100644 --- a/src/react/Reducers/oauth.js +++ b/src/Reducers/oauth.js @@ -5,7 +5,7 @@ import { OAUTH_CLIENT_DETAILS_SECRET, OAUTH_SANDBOX_CLIENT_DETAILS_ID, OAUTH_SANDBOX_CLIENT_DETAILS_SECRET -} from "../Actions/oauth"; +} from "~actions/oauth"; const storedClientId = store.get(OAUTH_CLIENT_DETAILS_ID); const storedClientSecret = store.get(OAUTH_CLIENT_DETAILS_SECRET); diff --git a/src/react/Reducers/options.js b/src/Reducers/options.js similarity index 99% rename from src/react/Reducers/options.js rename to src/Reducers/options.js index 217b4285..a717f5f1 100644 --- a/src/react/Reducers/options.js +++ b/src/Reducers/options.js @@ -1,6 +1,6 @@ import store from "store"; import { ipcRenderer } from "electron"; -import settings from "../ImportWrappers/electronSettings"; +import settings from "~importwrappers/electronSettings"; export const SYNC_ON_STARTUP_LOCATION = "BUNQDESKTOP_SYNC_ON_STARTUP"; export const THEME_LOCATION = "BUNQDESKTOP_THEME"; diff --git a/src/react/Reducers/pagination.js b/src/Reducers/pagination.js similarity index 100% rename from src/react/Reducers/pagination.js rename to src/Reducers/pagination.js diff --git a/src/react/Reducers/pay.js b/src/Reducers/pay.js similarity index 100% rename from src/react/Reducers/pay.js rename to src/Reducers/pay.js diff --git a/src/react/Reducers/payment_filter.js b/src/Reducers/payment_filter.js similarity index 100% rename from src/react/Reducers/payment_filter.js rename to src/Reducers/payment_filter.js diff --git a/src/react/Reducers/payment_info.js b/src/Reducers/payment_info.js similarity index 100% rename from src/react/Reducers/payment_info.js rename to src/Reducers/payment_info.js diff --git a/src/react/Reducers/payments.js b/src/Reducers/payments.js similarity index 75% rename from src/react/Reducers/payments.js rename to src/Reducers/payments.js index 6bb954d0..cdb3c42e 100644 --- a/src/react/Reducers/payments.js +++ b/src/Reducers/payments.js @@ -1,8 +1,8 @@ import store from "store"; -import MergeApiObjects from "../Functions/MergeApiObjects"; -import { storeEncryptString } from "../Functions/Crypto/CryptoWorkerWrapper"; +import MergeApiObjects from "~functions/MergeApiObjects"; +import { storeEncryptString } from "~functions/Crypto/CryptoWorkerWrapper"; -import { STORED_PAYMENTS } from "../Actions/payments"; +import { STORED_PAYMENTS } from "~actions/payments"; export const defaultState = { payments: [], @@ -27,21 +27,18 @@ export default (state = defaultState, action) => { ); // limit payments to 1000 in total - const mergedPayments = mergedInfo.items.slice(0, 1000); + const mergedPayments = mergedInfo.items.slice(0, 1000).map(item => item.toPlainObject()); // store the data if we have access to the bunqjsclient - if (action.payload.BunqJSClient) { - const BunqDesktopClient = window.BunqDesktopClient; - BunqDesktopClient.storeEncrypt( - { - items: mergedPayments, - account_id: action.payload.account_id - }, - STORED_PAYMENTS - ) - .then(() => {}) - .catch(() => {}); - } + window.BunqDesktopClient.storeEncrypt( + { + items: mergedPayments, + account_id: action.payload.account_id + }, + STORED_PAYMENTS + ) + .then(() => {}) + .catch(() => {}); // update newer and older id for this monetary account const newerIds = { diff --git a/src/react/Reducers/pending_payments.js b/src/Reducers/pending_payments.js similarity index 59% rename from src/react/Reducers/pending_payments.js rename to src/Reducers/pending_payments.js index 25a67536..7fd57a0d 100644 --- a/src/react/Reducers/pending_payments.js +++ b/src/Reducers/pending_payments.js @@ -1,10 +1,10 @@ import store from "store"; -import { generateGUID } from "../Functions/Utils"; -import { storeEncryptString } from "../Functions/Crypto/CryptoWorkerWrapper"; -import { PENDING_PAYMENTS_LOCATION } from "../Actions/pending_payments"; +import { generateGUID } from "~functions/Utils"; +import { storeEncryptString } from "~functions/Crypto/CryptoWorkerWrapper"; +import { PENDING_PAYMENTS_LOCATION } from "~actions/pending_payments"; export const defaultState = { - last_updated: new Date(), + last_updated: +new Date(), pending_payments: {} }; @@ -15,16 +15,15 @@ export default (state = defaultState, action) => { case "PENDING_PAYMENTS_SET_PAYMENTS": const newSetPendingPayment = action.payload.pending_payments; - if (action.payload.BunqJSClient) { - const BunqDesktopClient = window.BunqDesktopClient; - BunqDesktopClient.storeEncrypt(newSetPendingPayment, PENDING_PAYMENTS_LOCATION) - .then(() => {}) - .catch(() => {}); - } + window.BunqDesktopClient.storeEncrypt(newSetPendingPayment, PENDING_PAYMENTS_LOCATION) + .then(() => { + }) + .catch(() => { + }); return { ...state, - last_updated: new Date(), + last_updated: +new Date(), pending_payments: newSetPendingPayment }; @@ -38,16 +37,15 @@ export default (state = defaultState, action) => { payment: newPendingPayment }; - if (action.payload.BunqJSClient) { - const BunqDesktopClient = window.BunqDesktopClient; - BunqDesktopClient.storeEncrypt(pendingPayments, PENDING_PAYMENTS_LOCATION) - .then(() => {}) - .catch(() => {}); - } + window.BunqDesktopClient.storeEncrypt(pendingPayments, PENDING_PAYMENTS_LOCATION) + .then(() => { + }) + .catch(() => { + }); return { ...state, - last_updated: new Date(), + last_updated: +new Date(), pending_payments: pendingPayments }; @@ -64,16 +62,15 @@ export default (state = defaultState, action) => { }; }); - if (action.payload.BunqJSClient) { - const BunqDesktopClient = window.BunqDesktopClient; - BunqDesktopClient.storeEncrypt(pendingPayments, PENDING_PAYMENTS_LOCATION) - .then(() => {}) - .catch(() => {}); - } + window.BunqDesktopClient.storeEncrypt(pendingPayments, PENDING_PAYMENTS_LOCATION) + .then(() => { + }) + .catch(() => { + }); return { ...state, - last_updated: new Date(), + last_updated: +new Date(), pending_payments: pendingPayments }; @@ -88,16 +85,11 @@ export default (state = defaultState, action) => { } }); - if (action.payload.BunqJSClient) { - const BunqDesktopClient = window.BunqDesktopClient; - BunqDesktopClient.storeEncrypt(pendingPayments, PENDING_PAYMENTS_LOCATION) - .then(() => {}) - .catch(() => {}); - } + window.BunqDesktopClient.storeEncrypt(pendingPayments, PENDING_PAYMENTS_LOCATION).then(); return { ...state, - last_updated: new Date(), + last_updated: +new Date(), pending_payments: pendingPayments }; @@ -108,16 +100,11 @@ export default (state = defaultState, action) => { delete pendingPayments[clearPendingPaymentId]; } - if (action.payload.BunqJSClient) { - const BunqDesktopClient = window.BunqDesktopClient; - BunqDesktopClient.storeEncrypt(pendingPayments, PENDING_PAYMENTS_LOCATION) - .then(() => {}) - .catch(() => {}); - } + window.BunqDesktopClient.storeEncrypt(pendingPayments, PENDING_PAYMENTS_LOCATION).then(); return { ...state, - last_updated: new Date(), + last_updated: +new Date(), pending_payments: pendingPayments }; diff --git a/src/react/Reducers/queue.js b/src/Reducers/queue.js similarity index 97% rename from src/react/Reducers/queue.js rename to src/Reducers/queue.js index 4a53d054..b86fad28 100644 --- a/src/react/Reducers/queue.js +++ b/src/Reducers/queue.js @@ -52,7 +52,7 @@ export default function reducer(state = defaultState, action) { trigger_sync: false, request_counter: 0, max_request_counter: 0, - finished_queue: new Date() + finished_queue: +new Date(), }; case "QUEUE_START_SYNC": return { diff --git a/src/react/Reducers/registration.js b/src/Reducers/registration.js similarity index 100% rename from src/react/Reducers/registration.js rename to src/Reducers/registration.js diff --git a/src/react/Reducers/request_filter.js b/src/Reducers/request_filter.js similarity index 100% rename from src/react/Reducers/request_filter.js rename to src/Reducers/request_filter.js diff --git a/src/react/Reducers/request_inquiries.js b/src/Reducers/request_inquiries.js similarity index 75% rename from src/react/Reducers/request_inquiries.js rename to src/Reducers/request_inquiries.js index 4d5e8cb2..f90a0ce0 100644 --- a/src/react/Reducers/request_inquiries.js +++ b/src/Reducers/request_inquiries.js @@ -1,8 +1,8 @@ import store from "store"; -import MergeApiObjects from "../Functions/MergeApiObjects"; -import { storeEncryptString } from "../Functions/Crypto/CryptoWorkerWrapper"; +import MergeApiObjects from "~functions/MergeApiObjects"; +import { storeEncryptString } from "~functions/Crypto/CryptoWorkerWrapper"; -import { STORED_REQUEST_INQUIRIES } from "../Actions/request_inquiries"; +import { STORED_REQUEST_INQUIRIES } from "~actions/request_inquiries"; export const defaultState = { request_inquiries: [], @@ -31,21 +31,15 @@ export default (state = defaultState, action) => { ); // limit payments to 1000 in total - const mergedRequestInquiries = mergedInfo.items.slice(0, 1000); + const mergedRequestInquiries = mergedInfo.items.slice(0, 1000).map(item => item.toPlainObject()); - // store the data if we have access to the bunqjsclient - if (action.payload.BunqJSClient) { - const BunqDesktopClient = window.BunqDesktopClient; - BunqDesktopClient.storeEncrypt( - { - items: mergedRequestInquiries, - account_id: action.payload.account_id - }, - STORED_REQUEST_INQUIRIES - ) - .then(() => {}) - .catch(() => {}); - } + window.BunqDesktopClient.storeEncrypt( + { + items: mergedRequestInquiries, + account_id: action.payload.account_id + }, + STORED_REQUEST_INQUIRIES + ).then(); // update newer and older id for this monetary account const newerIds = { diff --git a/src/react/Reducers/request_inquiry.js b/src/Reducers/request_inquiry.js similarity index 100% rename from src/react/Reducers/request_inquiry.js rename to src/Reducers/request_inquiry.js diff --git a/src/react/Reducers/request_inquiry_batches.js b/src/Reducers/request_inquiry_batches.js similarity index 76% rename from src/react/Reducers/request_inquiry_batches.js rename to src/Reducers/request_inquiry_batches.js index 4a2e6883..6cdee761 100644 --- a/src/react/Reducers/request_inquiry_batches.js +++ b/src/Reducers/request_inquiry_batches.js @@ -1,8 +1,8 @@ import store from "store"; -import MergeApiObjects from "../Functions/MergeApiObjects"; -import { storeEncryptString } from "../Functions/Crypto/CryptoWorkerWrapper"; +import MergeApiObjects from "~functions/MergeApiObjects"; +import { storeEncryptString } from "~functions/Crypto/CryptoWorkerWrapper"; -import { STORED_REQUEST_INQUIRY_BATCHES } from "../Actions/request_inquiry_batches"; +import { STORED_REQUEST_INQUIRY_BATCHES } from "~actions/request_inquiry_batches"; export const defaultState = { request_inquiry_batches: [], @@ -31,21 +31,15 @@ export default (state = defaultState, action) => { ); // limit payments to 1000 in total - const mergedRequestBatches = mergedInfo.items.slice(0, 1000); + const mergedRequestBatches = mergedInfo.items.slice(0, 1000).map(item => item.toPlainObject()); - // store the data if we have access to the bunqjsclient - if (action.payload.BunqJSClient) { - const BunqDesktopClient = window.BunqDesktopClient; - BunqDesktopClient.storeEncrypt( - { - items: mergedRequestBatches, - account_id: action.payload.account_id - }, - STORED_REQUEST_INQUIRY_BATCHES - ) - .then(() => {}) - .catch(() => {}); - } + window.BunqDesktopClient.storeEncrypt( + { + items: mergedRequestBatches, + account_id: action.payload.account_id + }, + STORED_REQUEST_INQUIRY_BATCHES + ).then(); // update newer and older id for this monetary account const newerIds = { diff --git a/src/react/Reducers/request_inquiry_info.js b/src/Reducers/request_inquiry_info.js similarity index 100% rename from src/react/Reducers/request_inquiry_info.js rename to src/Reducers/request_inquiry_info.js diff --git a/src/react/Reducers/request_response.js b/src/Reducers/request_response.js similarity index 100% rename from src/react/Reducers/request_response.js rename to src/Reducers/request_response.js diff --git a/src/react/Reducers/request_response_info.js b/src/Reducers/request_response_info.js similarity index 100% rename from src/react/Reducers/request_response_info.js rename to src/Reducers/request_response_info.js diff --git a/src/react/Reducers/request_responses.js b/src/Reducers/request_responses.js similarity index 76% rename from src/react/Reducers/request_responses.js rename to src/Reducers/request_responses.js index bae57e92..fe28edbd 100644 --- a/src/react/Reducers/request_responses.js +++ b/src/Reducers/request_responses.js @@ -1,8 +1,8 @@ import store from "store"; -import MergeApiObjects from "../Functions/MergeApiObjects"; -import { storeEncryptString } from "../Functions/Crypto/CryptoWorkerWrapper"; +import MergeApiObjects from "~functions/MergeApiObjects"; +import { storeEncryptString } from "~functions/Crypto/CryptoWorkerWrapper"; -import { STORED_REQUEST_RESPONSES } from "../Actions/request_responses"; +import { STORED_REQUEST_RESPONSES } from "~actions/request_responses"; export const defaultState = { request_responses: [], @@ -33,19 +33,13 @@ export default (state = defaultState, action) => { // limit payments to 1000 in total const mergedRequestResponses = mergedInfo.items.slice(0, 1000); - // store the data if we have access to the bunqjsclient - if (action.payload.BunqJSClient) { - const BunqDesktopClient = window.BunqDesktopClient; - BunqDesktopClient.storeEncrypt( - { - items: mergedRequestResponses, - account_id: action.payload.account_id - }, - STORED_REQUEST_RESPONSES - ) - .then(() => {}) - .catch(() => {}); - } + window.BunqDesktopClient.storeEncrypt( + { + items: mergedRequestResponses, + account_id: action.payload.account_id + }, + STORED_REQUEST_RESPONSES + ).then(); // update newer and older id for this monetary account const newerIds = { diff --git a/src/react/Reducers/savings_goals.js b/src/Reducers/savings_goals.js similarity index 90% rename from src/react/Reducers/savings_goals.js rename to src/Reducers/savings_goals.js index 593468d7..275622e3 100644 --- a/src/react/Reducers/savings_goals.js +++ b/src/Reducers/savings_goals.js @@ -1,6 +1,6 @@ -import settings from "../ImportWrappers/electronSettings"; -import { generateGUID } from "../Functions/Utils"; -import SavingsGoal from "../Models/SavingsGoal"; +import settings from "~importwrappers/electronSettings"; +import { generateGUID } from "~functions/Utils"; +import SavingsGoal from "~models/SavingsGoal"; export const BUNQDESKTOP_SAVINGS_GOALS = "BUNQDESKTOP_SAVINGS_GOALS"; @@ -21,7 +21,7 @@ if (savingsGoalsStored === undefined) settings.set(BUNQDESKTOP_SAVINGS_GOALS, {} // construct the default state export const defaultState = { - last_update: new Date().getTime(), + last_update: +new Date(), savings_goals: mappedSavingsGoals }; @@ -57,7 +57,7 @@ export default function reducer(state = defaultState, action) { storeSavingsGoalsSafe(savingsGoals); return { ...state, - last_update: new Date().getTime(), + last_update: +new Date(), savings_goals: savingsGoals }; @@ -65,7 +65,7 @@ export default function reducer(state = defaultState, action) { storeSavingsGoalsSafe(action.payload.savings_goals); return { ...state, - last_update: new Date().getTime(), + last_update: +new Date(), savings_goals: action.payload.savings_goals }; @@ -76,7 +76,7 @@ export default function reducer(state = defaultState, action) { storeSavingsGoalsSafe(savingsGoals); return { ...state, - last_update: new Date().getTime(), + last_update: +new Date(), savings_goals: savingsGoals }; @@ -92,7 +92,7 @@ export default function reducer(state = defaultState, action) { storeSavingsGoalsSafe(currentSavingsGoals); return { ...state, - last_update: new Date().getTime(), + last_update: +new Date(), savings_goals: currentSavingsGoals }; @@ -113,7 +113,7 @@ export default function reducer(state = defaultState, action) { return { ...state, - last_update: new Date().getTime(), + last_update: +new Date(), savings_goals: { ...state.savings_goals, ...storedSavingsGoals diff --git a/src/react/Reducers/scheduled_payments.js b/src/Reducers/scheduled_payments.js similarity index 100% rename from src/react/Reducers/scheduled_payments.js rename to src/Reducers/scheduled_payments.js diff --git a/src/react/Reducers/search_filter.js b/src/Reducers/search_filter.js similarity index 100% rename from src/react/Reducers/search_filter.js rename to src/Reducers/search_filter.js diff --git a/src/react/Reducers/share_invite_monetary_account_inquiries.js b/src/Reducers/share_invite_monetary_account_inquiries.js similarity index 63% rename from src/react/Reducers/share_invite_monetary_account_inquiries.js rename to src/Reducers/share_invite_monetary_account_inquiries.js index e09bd40a..9c338046 100644 --- a/src/react/Reducers/share_invite_monetary_account_inquiries.js +++ b/src/Reducers/share_invite_monetary_account_inquiries.js @@ -1,6 +1,6 @@ import store from "store"; -import { STORED_SHARE_INVITE_MONETARY_ACCOUNT_INQUIRIES } from "../Actions/share_invite_monetary_account_inquiries"; -import { storeEncryptString } from "../Functions/Crypto/CryptoWorkerWrapper"; +import { STORED_SHARE_INVITE_MONETARY_ACCOUNT_INQUIRIES } from "~actions/share_invite_monetary_account_inquiries"; +import { storeEncryptString } from "~functions/Crypto/CryptoWorkerWrapper"; export const defaultState = { share_invite_monetary_account_inquiries: [], @@ -11,19 +11,13 @@ export const defaultState = { export default (state = defaultState, action) => { switch (action.type) { case "SHARE_INVITE_INQUIRIES_SET_INFO": - // store the data if we have access to the bunqjsclient - if (action.payload.BunqJSClient) { - const BunqDesktopClient = window.BunqDesktopClient; - BunqDesktopClient.storeEncrypt( - { - items: action.payload.share_invite_monetary_account_inquiries, - account_id: action.payload.account_id - }, - STORED_SHARE_INVITE_MONETARY_ACCOUNT_INQUIRIES - ) - .then(() => {}) - .catch(() => {}); - } + window.BunqDesktopClient.storeEncrypt( + { + items: action.payload.share_invite_monetary_account_inquiries, + account_id: action.payload.account_id + }, + STORED_SHARE_INVITE_MONETARY_ACCOUNT_INQUIRIES + ).then(); return { ...state, diff --git a/src/react/Reducers/share_invite_monetary_account_inquiry.js b/src/Reducers/share_invite_monetary_account_inquiry.js similarity index 100% rename from src/react/Reducers/share_invite_monetary_account_inquiry.js rename to src/Reducers/share_invite_monetary_account_inquiry.js diff --git a/src/react/Reducers/share_invite_monetary_account_responses.js b/src/Reducers/share_invite_monetary_account_responses.js similarity index 68% rename from src/react/Reducers/share_invite_monetary_account_responses.js rename to src/Reducers/share_invite_monetary_account_responses.js index f2f0a372..2278c49f 100644 --- a/src/react/Reducers/share_invite_monetary_account_responses.js +++ b/src/Reducers/share_invite_monetary_account_responses.js @@ -1,6 +1,6 @@ import store from "store"; -import { STORED_SHARE_INVITE_MONETARY_ACCOUNT_RESPONSES } from "../Actions/share_invite_monetary_account_responses"; -import { storeEncryptString } from "../Functions/Crypto/CryptoWorkerWrapper"; +import { STORED_SHARE_INVITE_MONETARY_ACCOUNT_RESPONSES } from "~actions/share_invite_monetary_account_responses"; +import { storeEncryptString } from "~functions/Crypto/CryptoWorkerWrapper"; export const defaultState = { share_invite_monetary_account_responses: [], @@ -11,17 +11,12 @@ export default (state = defaultState, action) => { switch (action.type) { case "SHARE_INVITE_RESPONSES_SET_INFO": // store the data if we have access to the bunqjsclient - if (action.payload.BunqJSClient) { - const BunqDesktopClient = window.BunqDesktopClient; - BunqDesktopClient.storeEncrypt( - { - items: action.payload.share_invite_monetary_account_responses - }, - STORED_SHARE_INVITE_MONETARY_ACCOUNT_RESPONSES - ) - .then(() => {}) - .catch(() => {}); - } + window.BunqDesktopClient.storeEncrypt( + { + items: action.payload.share_invite_monetary_account_responses + }, + STORED_SHARE_INVITE_MONETARY_ACCOUNT_RESPONSES + ).then(); return { ...state, diff --git a/src/react/Reducers/sidebar.js b/src/Reducers/sidebar.js similarity index 100% rename from src/react/Reducers/sidebar.js rename to src/Reducers/sidebar.js diff --git a/src/react/Reducers/user.js b/src/Reducers/user.js similarity index 100% rename from src/react/Reducers/user.js rename to src/Reducers/user.js diff --git a/src/react/Reducers/users.js b/src/Reducers/users.js similarity index 100% rename from src/react/Reducers/users.js rename to src/Reducers/users.js diff --git a/src/app.js b/src/app.js deleted file mode 100644 index c376dfc5..00000000 --- a/src/app.js +++ /dev/null @@ -1,2 +0,0 @@ -import "./helpers/context_menu.js"; -import "./helpers/external_links.js"; diff --git a/src/app.ts b/src/app.ts new file mode 100644 index 00000000..07b00456 --- /dev/null +++ b/src/app.ts @@ -0,0 +1,11 @@ +import "~helpers/context_menu"; +import "~helpers/external_links"; +import BunqDesktopClient from "~components/BunqDesktopClient"; +import { CryptoWorkerQueue } from "~functions/Crypto/CryptoWorkerWrapper"; + +export type AppWindow = Window & { + BunqDesktopClient?: BunqDesktopClient; + t: Function; + BUNQDESKTOP_LANGUAGE_SETTING: string; + cryptoWorkerQueue: CryptoWorkerQueue; +}; diff --git a/src/background.js b/src/background.ts similarity index 91% rename from src/background.js rename to src/background.ts index 8f61173d..4ee03718 100644 --- a/src/background.js +++ b/src/background.ts @@ -5,19 +5,19 @@ import url from "url"; import path from "path"; import log from "electron-log"; import settings from "electron-settings"; -import { devMenuTemplate } from "./menu/dev_menu_template"; -import { editMenuTemplate } from "./menu/edit_menu_template"; -import { helpMenuTemplate } from "./menu/help_menu_template"; -import { viewMenuTemplate } from "./menu/view_menu_template"; -import { windowMenuTemplate } from "./menu/window_menu_template"; -import darwinMenuTemplates from "./menu/darwin_menu_templates"; -import createWindow from "./helpers/window"; -import registerShortcuts from "./helpers/shortcuts"; -import registerTouchBar from "./helpers/touchbar"; -import setupTrayIcon from "./helpers/tray"; -import settingsHelper from "./helpers/settings"; -import oauth from "./helpers/oauth"; -import devTools from "./helpers/devtools"; +import { devMenuTemplate } from "~menu/dev_menu_template"; +import { editMenuTemplate } from "~menu/edit_menu_template"; +import { helpMenuTemplate } from "~menu/help_menu_template"; +import { viewMenuTemplate } from "~menu/view_menu_template"; +import { windowMenuTemplate } from "~menu/window_menu_template"; +import darwinMenuTemplates from "~menu/darwin_menu_templates"; +import createWindow from "~helpers/window"; +import registerShortcuts from "~helpers/shortcuts"; +import registerTouchBar from "~helpers/touchbar"; +import setupTrayIcon from "~helpers/tray"; +import settingsHelper from "~helpers/settings"; +import oauth from "~helpers/oauth"; +import devTools from "~helpers/devtools"; import env from "./env"; // disable security warnings since we need cross-origin requests @@ -27,7 +27,7 @@ const platform = os.platform(); let userDataPath = app.getPath("userData"); const imagesDir = path.join(__dirname, `..${path.sep}app${path.sep}images${path.sep}`); -let trayIcon = ""; +let trayIcon; if (platform === "darwin") { trayIcon = nativeImage.createFromPath(`${imagesDir}logoTemplate@1x.png`); trayIcon.setTemplateImage(true); diff --git a/src/react/Components/AccountCard.jsx b/src/components/AccountCard.tsx similarity index 85% rename from src/react/Components/AccountCard.jsx rename to src/components/AccountCard.tsx index 735932ee..3036c174 100644 --- a/src/react/Components/AccountCard.jsx +++ b/src/components/AccountCard.tsx @@ -12,16 +12,22 @@ import DeleteIcon from "@material-ui/icons/Delete"; import EditIcon from "@material-ui/icons/Edit"; import LinkIcon from "@material-ui/icons/Link"; import PeopleIcon from "@material-ui/icons/People"; +import { AppWindow } from "~app"; +import BunqDesktopClient from "~components/BunqDesktopClient"; +import { AppDispatch, ReduxState } from "~store/index"; import UploadFullscreen from "./FileUpload/UploadFullscreen"; import LazyAttachmentImage from "./AttachmentImage/LazyAttachmentImage"; import AccountQRFullscreen from "./QR/AccountQRFullscreen"; import AliasList from "./AliasList"; -import { formatMoney } from "../Functions/Utils"; -import { connectGetBudget } from "../Functions/ConnectGetPermissions"; -import { openSnackbar } from "../Actions/snackbar"; -import { accountsUpdateImage } from "../Actions/accounts"; +import { formatMoney } from "~functions/Utils"; +import { connectGetBudget } from "~functions/ConnectGetPermissions"; + +import { actions as snackbarActions } from "~store/snackbar"; +import { actions as accountsActions } from "~store/accounts"; + +declare let window: AppWindow; const styles = { avatar: { @@ -37,7 +43,17 @@ const styles = { } }; -class AccountCard extends React.Component { +interface IState { + [key: string]: any; +} + +interface IProps { + [key: string]: any; +} + +class AccountCard extends React.Component & ReturnType & IProps> { + state: IState; + constructor(props, context) { super(props, context); @@ -95,7 +111,6 @@ class AccountCard extends React.Component { return ( { +const mapStateToProps = (state: ReduxState) => { return { user: state.user.user }; }; -const mapDispatchToProps = (dispatch, props) => { - const { BunqJSClient } = props; +const mapDispatchToProps = (dispatch: AppDispatch) => { return { - openSnackbar: message => dispatch(openSnackbar(message)), + openSnackbar: message => dispatch(snackbarActions.open( { message })), accountsUpdateImage: (userId, accountId, attachmentId, accountType) => - dispatch(accountsUpdateImage(BunqJSClient, userId, accountId, attachmentId, accountType)) + // FIXME + dispatch(accountsActions.updateImage(userId, accountId, attachmentId, accountType)) }; }; diff --git a/src/react/Components/AccountList/AccountAvatarCircularProgress.jsx b/src/components/AccountList/AccountAvatarCircularProgress.tsx similarity index 77% rename from src/react/Components/AccountList/AccountAvatarCircularProgress.jsx rename to src/components/AccountList/AccountAvatarCircularProgress.tsx index 87697125..733a6eae 100644 --- a/src/react/Components/AccountList/AccountAvatarCircularProgress.jsx +++ b/src/components/AccountList/AccountAvatarCircularProgress.tsx @@ -1,6 +1,7 @@ -import React from "react"; +import React, { CSSProperties } from "react"; import { connect } from "react-redux"; import CircularProgress from "@material-ui/core/CircularProgress"; +import { ReduxState } from "~store/index"; const styles = { overlayCircular: { @@ -11,7 +12,19 @@ const styles = { top: 7 } }; -const AccountAvatarCircularProgress = ({ account, theme, selected = false, style = {} }) => { + +interface IState { + [key: string]: any; +} + +interface IProps { + account: any; + theme: any; + selected: boolean; + style: CSSProperties; +} + +const AccountAvatarCircularProgress = ({ account, theme, selected = false, style = {} }: ReturnType & IProps) => { let isSavingsAccount = false; if (account.accountType === "MonetaryAccountSavings") { isSavingsAccount = true; @@ -25,7 +38,7 @@ const AccountAvatarCircularProgress = ({ account, theme, selected = false, style if (!isSavingsAccount) return null; return ( - + <>
-
+ ); }; -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return { - theme: state.options.theme + // @ts-ignore + theme: state.options.theme, }; }; diff --git a/src/react/Components/AccountList/AccountList.jsx b/src/components/AccountList/AccountList.tsx similarity index 78% rename from src/react/Components/AccountList/AccountList.jsx rename to src/components/AccountList/AccountList.tsx index 7e21abfa..0dd1d944 100644 --- a/src/react/Components/AccountList/AccountList.jsx +++ b/src/components/AccountList/AccountList.tsx @@ -1,4 +1,5 @@ -import React from "react"; +import BunqJSClient from "@bunq-community/bunq-js-client"; +import React, { CSSProperties } from "react"; import { ipcRenderer } from "electron"; import { translate } from "react-i18next"; import { connect } from "react-redux"; @@ -14,28 +15,26 @@ import LinearProgress from "@material-ui/core/LinearProgress"; import RefreshIcon from "@material-ui/icons/Refresh"; import CheckBoxIcon from "@material-ui/icons/CheckBox"; import CheckBoxOutlinedIcon from "@material-ui/icons/CheckBoxOutlined"; +import { AppWindow } from "~app"; +import { accountsUpdate } from "~store/accounts/thunks"; +import { AppDispatch, ReduxState } from "~store/index"; import LimitedPremiumListItem from "../LimitedPremiumListItem"; import AccountListItem from "./AccountListItem"; import AddAccount from "./AddAccount"; -import { formatMoney } from "../../Functions/Utils"; -import { connectGetBudget } from "../../Functions/ConnectGetPermissions"; -import { filterShareInviteMonetaryAccountResponses } from "../../Functions/DataFilters"; - -import { - accountsSelectAccount, - accountsUpdate, - accountExcludeFromTotal, - accountIncludeInTotal -} from "../../Actions/accounts"; -import { paymentInfoUpdate } from "../../Actions/payments"; -import { requestResponsesUpdate } from "../../Actions/request_responses"; -import { bunqMeTabsUpdate } from "../../Actions/bunq_me_tabs"; -import { masterCardActionsUpdate } from "../../Actions/master_card_actions"; -import { requestInquiriesUpdate } from "../../Actions/request_inquiries"; -import { updateStatisticsSavingsGoals } from "../../Actions/savings_goals"; -import { shareInviteMonetaryAccountResponsesInfoUpdate } from "../../Actions/share_invite_monetary_account_responses"; -import { shareInviteMonetaryAccountInquiriesInfoUpdate } from "../../Actions/share_invite_monetary_account_inquiries"; +import { formatMoney } from "~functions/Utils"; +import { connectGetBudget } from "~functions/ConnectGetPermissions"; +import { filterShareInviteMonetaryAccountResponses } from "~functions/DataFilters"; + +import { paymentInfoUpdate } from "~actions/payments"; +import { requestResponsesUpdate } from "~actions/request_responses"; +import { masterCardActionsUpdate } from "~actions/master_card_actions"; +import { requestInquiriesUpdate } from "~actions/request_inquiries"; +import { updateStatisticsSavingsGoals } from "~actions/savings_goals"; +import { shareInviteMonetaryAccountResponsesInfoUpdate } from "~actions/share_invite_monetary_account_responses"; +import { shareInviteMonetaryAccountInquiriesInfoUpdate } from "~actions/share_invite_monetary_account_inquiries"; +import { actions as accountsActions } from "~store/accounts"; +import { actions as bunqMeTabsActions } from "~store/bunqMeTabs"; const styles = { list: { @@ -46,7 +45,26 @@ const styles = { } }; -class AccountList extends React.Component { +interface IState { + totalBalance: number; + fetchedAccounts: any; + accountTotalSelectionMode: any; + [key: string]: any; +} + +interface IProps { + t: AppWindow["t"]; + BunqJSClient: BunqJSClient; + [key: string]: any; +} + +class AccountList extends React.Component & ReturnType & IProps> { + static defaultProps = { + denseMode: false + }; + + state: IState; + constructor(props, context) { super(props, context); this.state = { @@ -63,7 +81,7 @@ class AccountList extends React.Component { componentDidUpdate(previousProps) { const { excludedAccountIds, shareInviteMonetaryAccountResponses, accounts } = this.props; - this.checkUpdateRequirement(this.props); + this.checkUpdateRequirement(); const accountsTrayItems = []; const totalBalance = accounts @@ -73,10 +91,10 @@ class AccountList extends React.Component { .reduce((total, account) => { const accountTrayItem = { description: account.description, - balance: formatMoney(account.getBalance()) + balance: formatMoney(account.balance.value) }; - if (account.balance) { + if (account?.balance?.value) { if (excludedAccountIds) { const isExcluded = excludedAccountIds.some( excludedAccountId => account.id === excludedAccountId @@ -92,7 +110,7 @@ class AccountList extends React.Component { // get budget from this response if (filteredResponses.length > 0) { - const connectBudget = connectGetBudget(filteredResponses); + const connectBudget: any = connectGetBudget(filteredResponses); if (connectBudget) { accountTrayItem.balance = formatMoney(parseFloat(connectBudget)); @@ -183,10 +201,10 @@ class AccountList extends React.Component { } }; - accountExcludeFromTotal = accountId => event => { + accountExcludeFromTotal = accountId => () => { this.props.accountExcludeFromTotal(accountId); }; - accountIncludeInTotal = accountId => event => { + accountIncludeInTotal = accountId => () => { this.props.accountIncludeInTotal(accountId); }; @@ -201,7 +219,7 @@ class AccountList extends React.Component { const { accountTotalSelectionMode } = this.state; let accounts = []; - if (this.props.accounts !== false) { + if (this.props.accounts.length) { accounts = this.props.accounts .filter(account => { if (account && account.status !== "ACTIVE") { @@ -222,7 +240,7 @@ class AccountList extends React.Component { } : false; - let secondaryAction = false; + let secondaryAction: false | React.ReactNode = false; if (accountTotalSelectionMode) { const excluded = excludedAccountIds.some(excludedAccountId => account.id === excludedAccountId); @@ -238,7 +256,6 @@ class AccountList extends React.Component { return ( + {isBunqPromoUser && ( - + <> - + )} {this.props.accountsLoading ? : } {accounts} {this.props.denseMode === false && this.props.limitedPermissions === false ? ( - + <> - + ) : null} ); } } -AccountList.defaultProps = { - denseMode: false -}; - -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return { user: state.user.user, userType: state.user.user_type, + + // @ts-ignore limitedPermissions: state.user.limited_permissions, applicationLastAutoUpdate: state.application.last_auto_update, + // @ts-ignore hideBalance: state.options.hide_balance, registrationIsLoading: state.registration.loading, registrationReady: state.registration.ready, accounts: state.accounts.accounts, - accountsSelectedId: state.accounts.selected_account, + accountsSelectedId: state.accounts.selectedAccount, accountsLoading: state.accounts.loading, - excludedAccountIds: state.accounts.excluded_account_ids, + excludedAccountIds: state.accounts.excludedAccountIds, shareInviteMonetaryAccountResponses: state.share_invite_monetary_account_responses.share_invite_monetary_account_responses, @@ -322,35 +338,34 @@ const mapStateToProps = state => { shareInviteBankInquiriesLoading: state.share_invite_monetary_account_inquiries.loading, paymentsLoading: state.payments.loading, - bunqMeTabsLoading: state.bunq_me_tabs.loading, + bunqMeTabsLoading: state.bunqMeTabs.loading, requestResponsesLoading: state.request_responses.loading, requestInquiriesLoading: state.request_inquiries.loading, masterCardActionsLoading: state.master_card_actions.loading }; }; -const mapDispatchToProps = (dispatch, ownProps) => { - const { BunqJSClient } = ownProps; +const mapDispatchToProps = (dispatch: AppDispatch) => { return { - paymentsUpdate: (userId, accountId) => dispatch(paymentInfoUpdate(BunqJSClient, userId, accountId)), + paymentsUpdate: (userId, accountId) => dispatch(paymentInfoUpdate(userId, accountId)), requestInquiriesUpdate: (userId, accountId) => - dispatch(requestInquiriesUpdate(BunqJSClient, userId, accountId)), + dispatch(requestInquiriesUpdate(userId, accountId)), requestResponsesUpdate: (userId, accountId) => - dispatch(requestResponsesUpdate(BunqJSClient, userId, accountId)), + dispatch(requestResponsesUpdate(userId, accountId)), masterCardActionsUpdate: (userId, accountId) => - dispatch(masterCardActionsUpdate(BunqJSClient, userId, accountId)), - bunqMeTabsUpdate: (userId, accountId) => dispatch(bunqMeTabsUpdate(BunqJSClient, userId, accountId)), + dispatch(masterCardActionsUpdate(userId, accountId)), + bunqMeTabsUpdate: (userId, accountId) => dispatch(bunqMeTabsActions.setInfo({ resetOldItems: false, user_id: userId, account_id: accountId })), - accountsUpdate: userId => dispatch(accountsUpdate(BunqJSClient, userId)), + accountsUpdate: userId => dispatch(accountsUpdate(userId)), - accountExcludeFromTotal: accountId => dispatch(accountExcludeFromTotal(accountId)), - accountIncludeInTotal: accountId => dispatch(accountIncludeInTotal(accountId)), + accountExcludeFromTotal: accountId => dispatch(accountsActions.excludeFromTotal(accountId)), + accountIncludeInTotal: accountId => dispatch(accountsActions.includeInTotal(accountId)), shareInviteMonetaryAccountResponsesInfoUpdate: userId => - dispatch(shareInviteMonetaryAccountResponsesInfoUpdate(BunqJSClient, userId)), + dispatch(shareInviteMonetaryAccountResponsesInfoUpdate(userId)), shareInviteMonetaryAccountInquiriesInfoUpdate: (userId, accountId) => - dispatch(shareInviteMonetaryAccountInquiriesInfoUpdate(BunqJSClient, userId, accountId)), - selectAccount: acountId => dispatch(accountsSelectAccount(acountId)), + dispatch(shareInviteMonetaryAccountInquiriesInfoUpdate(userId, accountId)), + selectAccount: accountId => dispatch(accountsActions.selectAccount(accountId)), updateStatisticsSavingsGoals: (accounts, shareInviteMonetaryAccountResponses) => dispatch(updateStatisticsSavingsGoals(accounts, shareInviteMonetaryAccountResponses)) diff --git a/src/react/Components/AccountList/AccountListItem.jsx b/src/components/AccountList/AccountListItem.tsx similarity index 79% rename from src/react/Components/AccountList/AccountListItem.jsx rename to src/components/AccountList/AccountListItem.tsx index 2a1af2ef..0dbd4ad3 100644 --- a/src/react/Components/AccountList/AccountListItem.jsx +++ b/src/components/AccountList/AccountListItem.tsx @@ -1,25 +1,29 @@ -import React from "react"; -import { connect } from "react-redux"; +import React, { CSSProperties } from "react"; import { translate } from "react-i18next"; +import { connect } from "react-redux"; +import Avatar from "@material-ui/core/Avatar"; +import OriginalIconButton from "@material-ui/core/IconButton"; import ListItem from "@material-ui/core/ListItem"; -import ListItemText from "@material-ui/core/ListItemText"; import ListItemSecondaryAction from "@material-ui/core/ListItemSecondaryAction"; -import Avatar from "@material-ui/core/Avatar"; -import IconButton from "@material-ui/core/IconButton"; +import ListItemText from "@material-ui/core/ListItemText"; import InfoIcon from "@material-ui/icons/InfoOutlined"; import LinkIcon from "@material-ui/icons/Link"; import PeopleIcon from "@material-ui/icons/People"; -import LazyAttachmentImage from "../../Components/AttachmentImage/LazyAttachmentImage"; -import NavLink from "../../Components/Routing/NavLink"; +import { addAccountIdFilter, removeAccountIdFilter, toggleAccountIdFilter } from "~actions/filters"; + +import LazyAttachmentImage from "~components/AttachmentImage/LazyAttachmentImage"; +import NavLink from "~components/Routing/NavLink"; +import { connectGetBudget } from "~functions/ConnectGetPermissions"; + +import { formatMoney } from "~functions/Utils"; +import { AppDispatch, ReduxState } from "~store/index"; import AccountAvatarCircularProgress from "./AccountAvatarCircularProgress"; -import { formatMoney } from "../../Functions/Utils"; -import { connectGetBudget } from "../../Functions/ConnectGetPermissions"; +import { actions as accountsActions } from "~store/accounts"; -import { accountsSelectAccount } from "../../Actions/accounts.js"; -import { addAccountIdFilter, removeAccountIdFilter, toggleAccountIdFilter } from "../../Actions/filters"; +const IconButton: any = OriginalIconButton; const styles = { bigAvatar: { @@ -40,7 +44,25 @@ const styles = { } }; -class AccountListItem extends React.Component { +interface IState { + [key: string]: any; +} + +interface IProps { + [key: string]: any; +} + +class AccountListItem extends React.Component & ReturnType & IProps> { + static defaultProps = { + clickable: true, + denseMode: false, + isJoint: false, + shareInviteMonetaryAccountResponses: [], + secondaryAction: false + }; + + state: IState; + constructor(props, context) { super(props, context); this.state = {}; @@ -99,7 +121,7 @@ class AccountListItem extends React.Component { } // check if any of the selected account ids are for this account - let displayStyle = { + let displayStyle: CSSProperties = { height: 83, paddingLeft: 20 }; @@ -125,7 +147,7 @@ class AccountListItem extends React.Component { ? e => this.props.removeAccountIdFilter(account.id) : e => this.props.addAccountIdFilter(account.id); - const listItemProps = {}; + const listItemProps: any = {}; if (this.props.clickable) { listItemProps.button = true; listItemProps.onClick = this.props.onClick @@ -139,7 +161,6 @@ class AccountListItem extends React.Component { @@ -159,22 +180,23 @@ class AccountListItem extends React.Component { } } -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return { user: state.user.user, + // @ts-ignore theme: state.options.theme, paymentsLoading: state.payments.loading, + // @ts-ignore hideBalance: state.options.hide_balance, - selectedAccountIds: state.account_id_filter.selected_account_ids, - toggleAccountIds: state.account_id_filter.toggle + selectedAccountIds: state.accountIdFilter.selectedAccountIds, + toggleAccountIds: state.accountIdFilter.toggle, }; }; -const mapDispatchToProps = (dispatch, ownProps) => { - const { BunqJSClient } = ownProps; +const mapDispatchToProps = (dispatch: AppDispatch) => { return { - selectAccount: acountId => dispatch(accountsSelectAccount(acountId)), + selectAccount: accountId => dispatch(accountsActions.selectAccount(accountId)), addAccountIdFilter: accountId => dispatch(addAccountIdFilter(accountId)), removeAccountIdFilter: index => dispatch(removeAccountIdFilter(index)), @@ -182,12 +204,4 @@ const mapDispatchToProps = (dispatch, ownProps) => { }; }; -AccountListItem.defaultProps = { - clickable: true, - denseMode: false, - isJoint: false, - shareInviteMonetaryAccountResponses: [], - secondaryAction: false -}; - export default connect(mapStateToProps, mapDispatchToProps)(translate("translations")(AccountListItem)); diff --git a/src/react/Components/AccountList/AccountListItemChip.jsx b/src/components/AccountList/AccountListItemChip.tsx similarity index 85% rename from src/react/Components/AccountList/AccountListItemChip.jsx rename to src/components/AccountList/AccountListItemChip.tsx index b1ea41a6..05f71d82 100644 --- a/src/react/Components/AccountList/AccountListItemChip.jsx +++ b/src/components/AccountList/AccountListItemChip.tsx @@ -2,11 +2,10 @@ import React from "react"; import Avatar from "@material-ui/core/Avatar"; import Chip from "@material-ui/core/Chip"; -import LazyAttachmentImage from "../../Components/AttachmentImage/LazyAttachmentImage"; +import LazyAttachmentImage from "~components/AttachmentImage/LazyAttachmentImage"; export default props => { const { - BunqJSClient, account, style = { margin: 6 @@ -15,7 +14,7 @@ export default props => { onDelete } = props; - const chipProps = { + const chipProps: any = { style: style, label: account.description }; @@ -42,7 +41,6 @@ export default props => { avatar={ diff --git a/src/react/Components/AccountList/AddAccount.jsx b/src/components/AccountList/AddAccount.tsx similarity index 73% rename from src/react/Components/AccountList/AddAccount.jsx rename to src/components/AccountList/AddAccount.tsx index 80c98f2a..fabef2cb 100644 --- a/src/react/Components/AccountList/AddAccount.jsx +++ b/src/components/AccountList/AddAccount.tsx @@ -1,13 +1,15 @@ import React from "react"; import { connect } from "react-redux"; -import ListItem from "@material-ui/core/ListItem"; +import OriginalListItem from "@material-ui/core/ListItem"; import ListItemText from "@material-ui/core/ListItemText"; import Avatar from "@material-ui/core/Avatar"; import AddBoxIcon from "@material-ui/icons/AddBox"; -import NavLink from "../../Components/Routing/NavLink"; +import NavLink from "~components/Routing/NavLink"; import { translate } from "react-i18next"; +const ListItem: any = OriginalListItem; + const styles = { bigAvatar: { width: 60, @@ -15,7 +17,17 @@ const styles = { } }; -class AddAccount extends React.Component { +interface IState { + [key: string]: any; +} + +interface IProps { + [key: string]: any; +} + +class AddAccount extends React.Component { + state: IState; + constructor(props, context) { super(props, context); this.state = {}; diff --git a/src/react/Components/AliasList.jsx b/src/components/AliasList.tsx similarity index 86% rename from src/react/Components/AliasList.jsx rename to src/components/AliasList.tsx index 8daf8cf7..0429ef5e 100644 --- a/src/react/Components/AliasList.jsx +++ b/src/components/AliasList.tsx @@ -9,10 +9,10 @@ import EmailIcon from "@material-ui/icons/Email"; import PersonIcon from "@material-ui/icons/Person"; import UrlIcon from "@material-ui/icons/Link"; -import { formatIban } from "../Functions/Utils"; -import CopyToClipboardWrap from "../Components/CopyToClipboardWrap"; +import { formatIban } from "~functions/Utils"; +import CopyToClipboardWrap from "~components/CopyToClipboardWrap"; -export default ({ aliasses, copiedValue = () => {} }) => { +export default ({ aliasses, copiedValue = () => {} }: { aliasses: any[]; copiedValue: Function }) => { return aliasses.map(alias => { let value = alias.value; let icon = ; diff --git a/src/react/App.jsx b/src/components/App.tsx similarity index 58% rename from src/react/App.jsx rename to src/components/App.tsx index 29a03c60..301fe667 100644 --- a/src/react/App.jsx +++ b/src/components/App.tsx @@ -4,15 +4,19 @@ import { HashRouter } from "react-router-dom"; import DateFnsUtils from "material-ui-pickers/utils/date-fns-utils"; import MuiPickersUtilsProvider from "material-ui-pickers/MuiPickersUtilsProvider"; -import Routes from "./Routes.jsx"; -import Layout from "./Components/Layout"; -import ErrorBoundary from "./Components/ErrorBoundary"; -import Store from "./Store.jsx"; +import Routes from "./Routes"; +import Layout from "~components/Layout"; +import ErrorBoundary from "~components/ErrorBoundary"; +import store from "~store/index"; // include translations setup import "./i18n"; -export default class App extends React.Component { +export interface IProps { + [key: string]: any; +} + +export default class App extends React.Component { constructor(props, context) { super(props, context); this.state = {}; @@ -22,13 +26,9 @@ export default class App extends React.Component { return ( - + - + diff --git a/src/react/Components/AttachmentImage/AttachmentImage.jsx b/src/components/AttachmentImage/AttachmentImage.tsx similarity index 84% rename from src/react/Components/AttachmentImage/AttachmentImage.jsx rename to src/components/AttachmentImage/AttachmentImage.tsx index eea293be..627f5803 100644 --- a/src/react/Components/AttachmentImage/AttachmentImage.jsx +++ b/src/components/AttachmentImage/AttachmentImage.tsx @@ -1,7 +1,16 @@ import React from "react"; -import Logger from "../../Functions/Logger"; +import { AppWindow } from "~app"; +import BunqDesktopClient from "~components/BunqDesktopClient"; +import Logger from "~functions/Logger"; + +declare let window: AppWindow; + +class AttachmentImage extends React.PureComponent { + state: any; + _isMounted: boolean; + timeout: number; + imageUrl: false | string; -class AttachmentImage extends React.PureComponent { constructor(props, context) { super(props, context); this.state = { @@ -44,7 +53,7 @@ class AttachmentImage extends React.PureComponent { } // set a timeout as a fallback incase loading the image takes too long - this.timeout = setTimeout(() => { + this.timeout = +setTimeout(() => { if (this.state.imageUrl === false) { // still no image, fallback to temporary placeholder this.setState({ @@ -61,6 +70,7 @@ class AttachmentImage extends React.PureComponent { loadImage = async () => { const indexedDb = window.BunqDesktopClient.ImageIndexedDb; + const BunqJSClient = window.BunqDesktopClient.BunqJSClient; const storageKey = `image_${this.props.imageUUID}`; const base64UrlStored = await indexedDb.get(storageKey); @@ -76,7 +86,7 @@ class AttachmentImage extends React.PureComponent { try { // get raw image contents - const base64Url = await this.props.BunqJSClient.api.attachmentContent.get(this.props.imageUUID); + const base64Url = await BunqJSClient.api.attachmentContent.get(this.props.imageUUID); // set the url first if (this._isMounted) { @@ -105,7 +115,7 @@ class AttachmentImage extends React.PureComponent { render() { // exclude custom props - const { BunqJSClient, imageUUID, defaultImage, ...props } = this.props; + const { imageUUID, defaultImage, ...props } = this.props; const defaultSizes = { width: "auto", diff --git a/src/react/Components/AttachmentImage/LazyAttachmentImage.jsx b/src/components/AttachmentImage/LazyAttachmentImage.tsx similarity index 92% rename from src/react/Components/AttachmentImage/LazyAttachmentImage.jsx rename to src/components/AttachmentImage/LazyAttachmentImage.tsx index 46ed878d..bf695c19 100644 --- a/src/react/Components/AttachmentImage/LazyAttachmentImage.jsx +++ b/src/components/AttachmentImage/LazyAttachmentImage.tsx @@ -2,7 +2,9 @@ import React from "react"; import VisibilitySensor from "react-visibility-sensor"; import AttachmentImage from "./AttachmentImage"; -class LazyAttachmentImage extends React.PureComponent { +class LazyAttachmentImage extends React.PureComponent { + state: any; + constructor(props, context) { super(props, context); this.state = { diff --git a/src/react/BunqDesktopClient.ts b/src/components/BunqDesktopClient.ts similarity index 97% rename from src/react/BunqDesktopClient.ts rename to src/components/BunqDesktopClient.ts index e5fb0d5f..acd7cc46 100644 --- a/src/react/BunqDesktopClient.ts +++ b/src/components/BunqDesktopClient.ts @@ -1,12 +1,12 @@ import BunqJSClient from "@bunq-community/bunq-js-client"; import StorageInterface from "@bunq-community/bunq-js-client/dist/Interfaces/StorageInterface"; import awaiting from "awaiting"; -import { Environment, StoredApiKey } from "./Types/Types"; +import { Environment, StoredApiKey } from "~types/Types"; -import { decryptString, derivePasswordKey, encryptString } from "./Functions/Crypto/Crypto"; -import { storeDecryptString, storeEncryptString } from "./Functions/Crypto/CryptoWorkerWrapper"; -import Logger from "./Functions/Logger"; -import localforage from "./ImportWrappers/localforage"; +import { decryptString, derivePasswordKey, encryptString } from "~functions/Crypto/Crypto"; +import { storeDecryptString, storeEncryptString } from "~functions/Crypto/CryptoWorkerWrapper"; +import Logger from "~functions/Logger"; +import localforage from "~importwrappers/localforage"; import store from "store/dist/store.legacy"; export const SALT_LOCATION = "BUNQDESKTOP_PASSWORD_SALT"; @@ -34,9 +34,12 @@ const sortApiKeyList = (a, b) => { }; export class IndexedDbWrapper implements StorageInterface { + // @ts-ignore private _indexedDb: LocalForageDriver; + // @ts-ignore constructor(config: LocalForageOptions) { + // @ts-ignore this._indexedDb = localforage.createInstance(config); } @@ -89,7 +92,9 @@ export class BunqDesktopClient { this.Logger = Logger; this.Store = Store; + // @ts-ignore const basicConfig: LocalForageOptions = { + // @ts-ignore driver: localforage.INDEXEDDB, name: "bunqDesktop", version: 1.0 @@ -186,7 +191,9 @@ export class BunqDesktopClient { // store the new api key in the stored api key list const storedApiKeyInfo: StoredApiKey = { identifier: this.password_identifier, + // @ts-ignore api_key: this.encrypted_api_key, + // @ts-ignore api_key_iv: this.encrypted_api_key_iv, permitted_ips: this.permitted_ips, device_name: this.device_name, @@ -263,9 +270,11 @@ export class BunqDesktopClient { this.derived_password_salt = this.getStoredValue(SALT_LOCATION, false); // derive a key from the new password + // @ts-ignore const derivedPassword = await derivePasswordKey(newPassword, this.derived_password_salt, 250000); const derivedIdentifier = await derivePasswordKey( derivedPassword.key + "identifier", + // @ts-ignore this.derived_password_salt, 100000 ); @@ -328,7 +337,8 @@ export class BunqDesktopClient { /** * Decrypts with the current password, and returns the encrypted version with a new password * @param {string} newEncryptionKey - * @param {StoredApiKey} storedApiKey + * @param {string} apiKey + * @param {string} apiKeyIv * @returns {Promise} */ private async updateApiKeyEncryption(newEncryptionKey: string, apiKey: string, apiKeyIv: string) { diff --git a/src/react/Components/BunqMeTabList.jsx b/src/components/BunqMeTabList.tsx similarity index 76% rename from src/react/Components/BunqMeTabList.jsx rename to src/components/BunqMeTabList.tsx index 7c2e66d8..8b4fc917 100644 --- a/src/react/Components/BunqMeTabList.jsx +++ b/src/components/BunqMeTabList.tsx @@ -6,20 +6,23 @@ import ListSubheader from "@material-ui/core/ListSubheader"; import ListItemSecondaryAction from "@material-ui/core/ListItemSecondaryAction"; import LinearProgress from "@material-ui/core/LinearProgress"; import Divider from "@material-ui/core/Divider"; -import Chip from "@material-ui/core/Chip"; +import OriginalChip from "@material-ui/core/Chip"; import Avatar from "@material-ui/core/Avatar"; import IconButton from "@material-ui/core/IconButton"; import Visible from "@material-ui/icons/Visibility"; import VisibleOff from "@material-ui/icons/VisibilityOff"; import UrlIcon from "@material-ui/icons/Link"; +import { AppDispatch, ReduxState } from "~store/index"; import BunqMeTabListItem from "./ListItems/BunqMeTabListItem"; -import { openSnackbar } from "../Actions/snackbar"; -import { bunqMeTabPut } from "../Actions/bunq_me_tab"; +import { actions as snackbarActions } from "~store/snackbar"; +import { bunqMeTabPut } from "~store/bunqMeTab/thunks"; -const styles = { +const Chip: any = OriginalChip; + +const styles: any = { list: { textAlign: "left" }, @@ -29,7 +32,21 @@ const styles = { } }; -class BunqMeTabList extends React.Component { +interface IState { + [key: string]: any; +} + +interface IProps { + [key: string]: any; +} + +class BunqMeTabList extends React.Component & ReturnType & IProps> { + static defaultProps = { + secondaryActions: null + }; + + state: IState; + constructor(props, context) { super(props, context); this.state = { @@ -49,7 +66,7 @@ class BunqMeTabList extends React.Component { const { t } = this.props; const loadingContent = this.props.bunqMeTabsLoading ? : ; - const bunqMeTabs = this.props.bunqMeTabs.map(bunqMeTab => { + const bunqMeTabs = this.props.bunqMeTabs.map((bunqMeTab: any) => { if (this.state.showInactiveTabs === false && bunqMeTab.BunqMeTab.status !== "WAITING_FOR_PAYMENT") { return null; } @@ -61,7 +78,6 @@ class BunqMeTabList extends React.Component { bunqMeTabLoading={this.props.bunqMeTabLoading} bunqMeTabsLoading={this.props.bunqMeTabsLoading} bunqMeTabPut={this.props.bunqMeTabPut} - BunqJSClient={this.props.BunqJSClient} user={this.props.user} /> ); @@ -100,28 +116,24 @@ class BunqMeTabList extends React.Component { } } -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return { user: state.user.user, + // @ts-ignore limitedPermissions: state.user.limited_permissions, - bunqMeTabs: state.bunq_me_tabs.bunq_me_tabs, - bunqMeTabLoading: state.bunq_me_tab.loading, - bunqMeTabsLoading: state.bunq_me_tabs.loading + bunqMeTabs: state.bunqMeTabs.bunq_me_tabs, + bunqMeTabLoading: state.bunqMeTab.loading, + bunqMeTabsLoading: state.bunqMeTabs.loading }; }; -const mapDispatchToProps = (dispatch, props) => { - const { BunqJSClient } = props; +const mapDispatchToProps = (dispatch: AppDispatch) => { return { - openSnackbar: message => dispatch(openSnackbar(message)), + openSnackbar: message => dispatch(snackbarActions.open(message)), bunqMeTabPut: (userId, accountId, tabId, status) => - dispatch(bunqMeTabPut(BunqJSClient, userId, accountId, tabId, status)) + dispatch(bunqMeTabPut(userId, accountId, tabId, status)) }; }; -BunqMeTabList.defaultProps = { - secondaryActions: null -}; - export default connect(mapStateToProps, mapDispatchToProps)(BunqMeTabList); diff --git a/src/react/Components/Categories/CategoryChip.jsx b/src/components/Categories/CategoryChip.tsx similarity index 97% rename from src/react/Components/Categories/CategoryChip.jsx rename to src/components/Categories/CategoryChip.tsx index d5197fab..e8165955 100644 --- a/src/react/Components/Categories/CategoryChip.jsx +++ b/src/components/Categories/CategoryChip.tsx @@ -1,6 +1,7 @@ import React from "react"; import Avatar from "@material-ui/core/Avatar"; import Chip from "@material-ui/core/Chip"; + import CustomIcon from "../CustomIcon"; export default props => { @@ -13,7 +14,7 @@ export default props => { onDelete } = props; - const chipProps = { + const chipProps: any = { style: style, label: category.label }; diff --git a/src/react/Components/Categories/CategoryChips.jsx b/src/components/Categories/CategoryChips.tsx similarity index 67% rename from src/react/Components/Categories/CategoryChips.jsx rename to src/components/Categories/CategoryChips.tsx index 03a73d6a..2e835974 100644 --- a/src/react/Components/Categories/CategoryChips.jsx +++ b/src/components/Categories/CategoryChips.tsx @@ -1,5 +1,6 @@ import React from "react"; import { connect } from "react-redux"; +import { AppDispatch, ReduxState } from "~store/index"; import CategoryChip from "./CategoryChip"; import CategoryHelper from "./CategoryHelper"; import PrioritySorter from "./PrioritySorter"; @@ -11,7 +12,30 @@ const style = { justifyContent: "center" }; -class CategoryChips extends React.PureComponent { +interface IState { + [key: string]: any; +} + +interface IProps { + [key: string]: any; +} + +class CategoryChips extends React.PureComponent & ReturnType & IProps> { + static defaultProps = { + chipStyle: { + margin: 5 + }, + // when true this list will show all categories which do NOT match the item id + reverseChips: false, + onClick: false, + onDelete: false, + // overwrite the categories set in redux with a custom set + customCategories: false, + style: style + }; + + state: IState; + constructor(props, context) { super(props, context); this.state = {}; @@ -48,20 +72,7 @@ class CategoryChips extends React.PureComponent { } } -CategoryChips.defaultProps = { - chipStyle: { - margin: 5 - }, - // when true this list will show all categories which do NOT match the item id - reverseChips: false, - onClick: false, - onDelete: false, - // overwrite the categories set in redux with a custom set - customCategories: false, - style: style -}; - -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return { categories: state.categories.categories, categories_last_udate: state.categories.last_update, @@ -69,7 +80,7 @@ const mapStateToProps = state => { }; }; -const mapDispatchToProps = dispatch => { +const mapDispatchToProps = (dispatch: AppDispatch) => { return {}; }; diff --git a/src/react/Components/Categories/CategoryEditor.jsx b/src/components/Categories/CategoryEditor.tsx similarity index 86% rename from src/react/Components/Categories/CategoryEditor.jsx rename to src/components/Categories/CategoryEditor.tsx index a166859d..af96a24e 100644 --- a/src/react/Components/Categories/CategoryEditor.jsx +++ b/src/components/Categories/CategoryEditor.tsx @@ -1,11 +1,11 @@ -import React from "react"; -import PropTypes from "prop-types"; +import React, { CSSProperties } from "react"; import { connect } from "react-redux"; import { translate } from "react-i18next"; import Chip from "@material-ui/core/Chip"; import Grid from "@material-ui/core/Grid"; import Avatar from "@material-ui/core/Avatar"; import TextField from "@material-ui/core/TextField"; +import { AppDispatch, ReduxState } from "~store/index"; import CustomIcon from "../CustomIcon"; import IconPicker from "../FormFields/IconPicker"; @@ -13,9 +13,9 @@ import ColorPicker from "../FormFields/ColorPicker"; import TranslateButton from "../TranslationHelpers/Button"; import TranslateTypography from "../TranslationHelpers/Typography"; -import { setCategory } from "../../Actions/categories"; +import { actions as categoriesActions } from "~store/categories"; -const styles = { +const styles: any = { titles: { textAlign: "center" }, iconPicker: { width: "100%" @@ -40,7 +40,22 @@ const styles = { } }; -class CategoryEditor extends React.Component { +export interface IProps { + style: CSSProperties; + deselectChip: Function; + setCategory: Function; + selectedCategoryId: boolean | string; + categories: any; + t: Function; +} + +class CategoryEditor extends React.Component & ReturnType & IProps> { + static defaultProps = { + style: {}, + }; + + state: any; + constructor(props, context) { super(props, context); this.state = { @@ -59,10 +74,10 @@ class CategoryEditor extends React.Component { componentDidUpdate() { if (this.state.categoryId !== this.props.selectedCategoryId) { - const stateChanges = { + const stateChanges: any = { categoryId: this.props.selectedCategoryId }; - if (this.props.selectedCategoryId && this.props.categories[this.props.selectedCategoryId]) { + if (typeof this.props.selectedCategoryId === 'string' && this.props.categories[this.props.selectedCategoryId]) { const categoryInfo = this.props.categories[this.props.selectedCategoryId]; stateChanges.label = categoryInfo.label; stateChanges.icon = categoryInfo.icon; @@ -85,7 +100,7 @@ class CategoryEditor extends React.Component { labelChange = event => { const labelValue = event.target.value; - const stateChanges = { + const stateChanges: any = { labelError: false }; if (labelValue.length <= 24) { @@ -212,17 +227,7 @@ class CategoryEditor extends React.Component { } } -CategoryEditor.defaultProps = { - style: {} -}; - -CategoryEditor.propTypes = { - style: PropTypes.object, - deselectChip: PropTypes.func, - selectedCategoryId: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]) -}; - -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return { categories: state.categories.categories, categories_last_udate: state.categories.last_update, @@ -230,9 +235,9 @@ const mapStateToProps = state => { }; }; -const mapDispatchToProps = dispatch => { +const mapDispatchToProps = (dispatch: AppDispatch) => { return { - setCategory: (...params) => dispatch(setCategory(...params)) + setCategory: (categoryId, label, color, icon, priority) => dispatch(categoriesActions.setCategory({ id: categoryId, label, color, icon, priority })), }; }; diff --git a/src/react/Components/Categories/CategoryHelper.js b/src/components/Categories/CategoryHelper.ts similarity index 100% rename from src/react/Components/Categories/CategoryHelper.js rename to src/components/Categories/CategoryHelper.ts diff --git a/src/react/Components/Categories/CategoryIcon.jsx b/src/components/Categories/CategoryIcon.tsx similarity index 100% rename from src/react/Components/Categories/CategoryIcon.jsx rename to src/components/Categories/CategoryIcon.tsx diff --git a/src/react/Components/Categories/CategoryIcons.jsx b/src/components/Categories/CategoryIcons.tsx similarity index 70% rename from src/react/Components/Categories/CategoryIcons.jsx rename to src/components/Categories/CategoryIcons.tsx index 7b2c409a..8ec8d6bb 100644 --- a/src/react/Components/Categories/CategoryIcons.jsx +++ b/src/components/Categories/CategoryIcons.tsx @@ -1,5 +1,6 @@ -import React from "react"; +import React, { CSSProperties } from "react"; import { connect } from "react-redux"; +import { AppDispatch, ReduxState } from "~store/index"; import CategoryHelper from "./CategoryHelper"; import PrioritySorter from "./PrioritySorter"; import CategoryIcon from "./CategoryIcon"; @@ -12,7 +13,26 @@ const style = { minWidth: 160 }; -class CategoryIcons extends React.Component { +interface IState { + [key: string]: any; +} + +interface IProps { + style: CSSProperties; + [key: string]: any; +} + +class CategoryIcons extends React.Component & ReturnType & IProps> { + static defaultProps = { + chipStyle: { + margin: 5 + }, + iconCount: 5, + style: style + }; + + state: IState; + constructor(props, context) { super(props, context); this.state = {}; @@ -51,19 +71,11 @@ class CategoryIcons extends React.Component { return ; }); - return
{chips}
; + return
{chips}
; } } -CategoryIcons.defaultProps = { - chipStyle: { - margin: 5 - }, - iconCount: 5, - style: style -}; - -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return { categories: state.categories.categories, categories_last_udate: state.categories.last_update, @@ -71,7 +83,7 @@ const mapStateToProps = state => { }; }; -const mapDispatchToProps = dispatch => { +const mapDispatchToProps = (dispatch: AppDispatch) => { return {}; }; diff --git a/src/react/Components/Categories/CategorySelector.jsx b/src/components/Categories/CategorySelector.tsx similarity index 74% rename from src/react/Components/Categories/CategorySelector.jsx rename to src/components/Categories/CategorySelector.tsx index 8417f7cd..a055ea05 100644 --- a/src/react/Components/Categories/CategorySelector.jsx +++ b/src/components/Categories/CategorySelector.tsx @@ -4,11 +4,12 @@ import { translate } from "react-i18next"; import Grid from "@material-ui/core/Grid"; import Divider from "@material-ui/core/Divider"; import Collapse from "@material-ui/core/Collapse"; +import { AppDispatch, ReduxState } from "~store/index"; import TranslateButton from "../TranslationHelpers/Button"; import CategoryChips from "./CategoryChips"; -import { removeCategoryConnection, setCategoryConnection } from "../../Actions/categories"; +import { actions as categoriesActions } from "~store/categories"; const styles = { title: { textAlign: "center" }, @@ -17,7 +18,22 @@ const styles = { } }; -class CategorySelector extends React.Component { +interface IState { + [key: string]: any; +} + +interface IProps { + [key: string]: any; +} + +class CategorySelector extends React.Component & ReturnType & IProps> { + static defaultProps = { + style: {}, + displayToggleButton: true + }; + + state: IState; + constructor(props, context) { super(props, context); this.state = { @@ -48,12 +64,12 @@ class CategorySelector extends React.Component { }; render() { - const { item, type, displayToggleButton, t } = this.props; + const { item, type, displayToggleButton } = this.props; if (!item[type]) return null; const itemInfo = item[type]; // don't allow the delete button by default - const categoryChipProps = { + const categoryChipProps: any = { type: type, id: itemInfo.id }; @@ -89,12 +105,7 @@ class CategorySelector extends React.Component { } } -CategorySelector.defaultProps = { - style: {}, - displayToggleButton: true -}; - -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return { categories: state.categories.categories, categories_last_udate: state.categories.last_update, @@ -102,10 +113,10 @@ const mapStateToProps = state => { }; }; -const mapDispatchToProps = dispatch => { +const mapDispatchToProps = (dispatch: AppDispatch) => { return { - setCategoryConnection: (...params) => dispatch(setCategoryConnection(...params)), - removeCategoryConnection: (...params) => dispatch(removeCategoryConnection(...params)) + setCategoryConnection: (id, type, itemInfo) => dispatch(categoriesActions.setCategoryConnection({ category_id: id, item_type: type, item_id: itemInfo })), + removeCategoryConnection: (id, type, itemInfo) => dispatch(categoriesActions.removeCategoryConnection({ category_id: id, item_type: type, item_id: itemInfo })) }; }; diff --git a/src/react/Components/Categories/CategorySelectorDialog.jsx b/src/components/Categories/CategorySelectorDialog.tsx similarity index 81% rename from src/react/Components/Categories/CategorySelectorDialog.jsx rename to src/components/Categories/CategorySelectorDialog.tsx index 8dd0dad0..19321796 100644 --- a/src/react/Components/Categories/CategorySelectorDialog.jsx +++ b/src/components/Categories/CategorySelectorDialog.tsx @@ -4,11 +4,21 @@ import DialogContent from "@material-ui/core/DialogContent"; import DialogActions from "@material-ui/core/DialogActions"; import DialogTitle from "@material-ui/core/DialogTitle"; import Dialog from "@material-ui/core/Dialog"; -import TranslateButton from "../../Components/TranslationHelpers/Button"; +import TranslateButton from "~components/TranslationHelpers/Button"; import CategorySelector from "./CategorySelector"; -class CategorySelectorDialog extends React.Component { +interface IState { + [key: string]: any; +} + +interface IProps { + [key: string]: any; +} + +class CategorySelectorDialog extends React.Component { + state: IState; + constructor(props, context) { super(props, context); this.state = {}; diff --git a/src/react/Components/Categories/PrioritySorter.js b/src/components/Categories/PrioritySorter.ts similarity index 100% rename from src/react/Components/Categories/PrioritySorter.js rename to src/components/Categories/PrioritySorter.ts diff --git a/src/react/Components/CodeSplitting/ComponentLoader.jsx b/src/components/CodeSplitting/ComponentLoader.tsx similarity index 100% rename from src/react/Components/CodeSplitting/ComponentLoader.jsx rename to src/components/CodeSplitting/ComponentLoader.tsx diff --git a/src/react/Components/CodeSplitting/Loading.jsx b/src/components/CodeSplitting/Loading.tsx similarity index 81% rename from src/react/Components/CodeSplitting/Loading.jsx rename to src/components/CodeSplitting/Loading.tsx index 54da1773..f74a793f 100644 --- a/src/react/Components/CodeSplitting/Loading.jsx +++ b/src/components/CodeSplitting/Loading.tsx @@ -1,5 +1,5 @@ import React from "react"; -import Logger from "../../Functions/Logger"; +import Logger from "~functions/Logger"; export default ({ isLoading, pastDelay, error }) => { if (isLoading && pastDelay) { @@ -8,7 +8,7 @@ export default ({ isLoading, pastDelay, error }) => { } else if (error && !isLoading) { // failed to load the component console.error(error); - Logger.error("Failed to load", error); + Logger.error("Failed to load"); throw error; } else { // during loading diff --git a/src/react/Components/CombinedList/CombinedList.jsx b/src/components/CombinedList/CombinedList.tsx similarity index 86% rename from src/react/Components/CombinedList/CombinedList.jsx rename to src/components/CombinedList/CombinedList.tsx index 80ed5cf0..266ab1ed 100644 --- a/src/react/Components/CombinedList/CombinedList.jsx +++ b/src/components/CombinedList/CombinedList.tsx @@ -1,4 +1,5 @@ import React from "react"; + const sessionStore = require("store/storages/sessionStorage"); import { connect } from "react-redux"; import { translate } from "react-i18next"; @@ -10,15 +11,16 @@ import ListSubheader from "@material-ui/core/ListSubheader"; import ListItemSecondaryAction from "@material-ui/core/ListItemSecondaryAction"; import InfoIcon from "@material-ui/icons/Info"; +import { AppWindow } from "~app"; +import { bunqMeTabPut } from "~store/bunqMeTab/thunks"; +import { AppDispatch, ReduxState } from "~store/index"; import ClearBtn from "../FilterComponents/ClearFilter"; import FilterDrawer from "../FilterComponents/FilterDrawer"; import ListControls from "./ListControls"; import EventData from "./EventData"; -import { openSnackbar } from "../../Actions/snackbar"; -import { bunqMeTabPut } from "../../Actions/bunq_me_tab"; -import { nextPage, previousPage, setPage, setPageSize, firstPage } from "../../Actions/pagination"; +import { nextPage, previousPage, setPage, setPageSize, firstPage } from "~actions/pagination"; import { paymentMapper, @@ -30,10 +32,12 @@ import { shareInviteMonetaryAccountInquiryMapper, shareInviteMonetaryAccountResponseMapper } from "./MapperFunctions"; -import { humanReadableDate } from "../../Functions/Utils"; -import FilterDisabledChecker from "../../Functions/FilterDisabledChecker"; +import { humanReadableDate } from "~functions/Utils"; +import FilterDisabledChecker from "~functions/FilterDisabledChecker"; + +import { actions as snackbarActions } from "~store/snackbar"; -const styles = { +const styles: any = { button: { width: "100%" }, @@ -59,7 +63,25 @@ const styles = { const STORED_SCROLL_POSITION = "STORED_SCROLL_POSITION"; -class CombinedList extends React.Component { +interface IProps { + displayAcceptedRequests: any; + displayRequestPayments: any; + t: AppWindow["t"]; +} + +interface IState { + displayEventData: boolean, + totalEvents: number, + events: Array; +} + +class CombinedList extends React.Component & ReturnType & IProps> { + static defaultProps = { + hiddenTypes: [] + }; + + state: IState; + constructor(props, context) { super(props, context); this.state = { @@ -141,8 +163,8 @@ class CombinedList extends React.Component { ...requestInquiryBatches, ...shareInviteBankInquiries, ...payments - ].sort(function(a, b) { - return new Date(b.filterDate) - new Date(a.filterDate); + ].sort(function (a, b) { + return +new Date(b.filterDate) - +new Date(a.filterDate); }); this.setState( @@ -338,7 +360,7 @@ class CombinedList extends React.Component { } } -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return { user: state.user.user, @@ -348,7 +370,7 @@ const mapStateToProps = state => { queueFinishedQueue: state.queue.finished_queue, accounts: state.accounts.accounts, - accountsAccountId: state.accounts.selected_account, + accountsAccountId: state.accounts.selectedAccount, forceUpdate: state.application.force_update, @@ -358,23 +380,23 @@ const mapStateToProps = state => { searchTerm: state.search_filter.search_term, paymentType: state.payment_filter.type, paymentVisibility: state.payment_filter.visible, - bunqMeTabType: state.bunq_me_tab_filter.type, - bunqMeTabVisibility: state.bunq_me_tab_filter.visible, + bunqMeTabType: state.bunqMeTabFilter.type, + bunqMeTabVisibility: state.bunqMeTabFilter.visible, requestType: state.request_filter.type, requestVisibility: state.request_filter.visible, - dateFromFilter: state.date_filter.from_date, - dateToFilter: state.date_filter.to_date, + dateFromFilter: state.dateFilter.from_date, + dateToFilter: state.dateFilter.to_date, generalFilterDate: state.general_filter.date, - amountFilterAmount: state.amount_filter.amount, - amountFilterType: state.amount_filter.type, + amountFilterAmount: state.amountFilter.amount, + amountFilterType: state.amountFilter.type, - selectedCategories: state.category_filter.selected_categories, - toggleCategoryIds: state.category_filter.toggle, - selectedAccountIds: state.account_id_filter.selected_account_ids, - toggleAccountIds: state.account_id_filter.toggle, - selectedCardIds: state.card_id_filter.selected_card_ids, - toggleCardIds: state.card_id_filter.toggle, + selectedCategories: state.categoryFilter.selected_categories, + toggleCategoryIds: state.categoryFilter.toggle, + selectedAccountIds: state.accountIdFilter.selectedAccountIds, + toggleAccountIds: state.accountIdFilter.toggle, + selectedCardIds: state.cardIdFilter.selected_card_ids, + toggleCardIds: state.cardIdFilter.toggle, categories: state.categories.categories, categoryConnections: state.categories.category_connections, @@ -382,9 +404,9 @@ const mapStateToProps = state => { payments: state.payments.payments, paymentsLoading: state.payments.loading, - bunqMeTabs: state.bunq_me_tabs.bunq_me_tabs, - bunqMeTabsLoading: state.bunq_me_tabs.loading, - bunqMeTabLoading: state.bunq_me_tab.loading, + bunqMeTabs: state.bunqMeTabs.bunq_me_tabs, + bunqMeTabsLoading: state.bunqMeTabs.loading, + bunqMeTabLoading: state.bunqMeTab.loading, masterCardActions: state.master_card_actions.master_card_actions, masterCardActionsLoading: state.master_card_actions.loading, @@ -402,17 +424,16 @@ const mapStateToProps = state => { shareInviteBankInquiriesLoading: state.share_invite_monetary_account_inquiries.loading, shareInviteMonetaryAccountResponses: - state.share_invite_monetary_account_responses.share_invite_monetary_account_responses, + state.share_invite_monetary_account_responses.share_invite_monetary_account_responses, shareInviteMonetaryAccountResponsesLoading: state.share_invite_monetary_account_responses.loading }; }; -const mapDispatchToProps = (dispatch, ownProps) => { - const { BunqJSClient } = ownProps; +const mapDispatchToProps = (dispatch: AppDispatch) => { return { - openSnackbar: message => dispatch(openSnackbar(message)), + openSnackbar: message => dispatch(snackbarActions.open({ message })), bunqMeTabPut: (userId, accountId, tabId, status) => - dispatch(bunqMeTabPut(BunqJSClient, userId, accountId, tabId, status)), + dispatch(bunqMeTabPut(userId, accountId, tabId, status)), firstPage: () => dispatch(firstPage()), nextPage: () => dispatch(nextPage()), previousPage: () => dispatch(previousPage()), @@ -421,8 +442,4 @@ const mapDispatchToProps = (dispatch, ownProps) => { }; }; -CombinedList.defaultProps = { - hiddenTypes: [] -}; - export default connect(mapStateToProps, mapDispatchToProps)(translate("translations")(CombinedList)); diff --git a/src/react/Components/CombinedList/EventData.jsx b/src/components/CombinedList/EventData.tsx similarity index 91% rename from src/react/Components/CombinedList/EventData.jsx rename to src/components/CombinedList/EventData.tsx index a5b6c1da..dbf7a976 100644 --- a/src/react/Components/CombinedList/EventData.jsx +++ b/src/components/CombinedList/EventData.tsx @@ -8,8 +8,9 @@ import Collapse from "@material-ui/core/Collapse"; import IncomingIcon from "@material-ui/icons/KeyboardArrowDown"; import OutgoingIcon from "@material-ui/icons/KeyboardArrowUp"; import ChangeIcon from "@material-ui/icons/CompareArrows"; +import { AppWindow } from "~app"; -import { formatMoney } from "../../Functions/Utils"; +import { formatMoney } from "~functions/Utils"; const styles = { gridContainer: { @@ -26,7 +27,20 @@ const styles = { } }; -class EventData extends React.Component { +interface IState { + [key: string]: any; +} + +interface IProps { + t: AppWindow["t"]; + theme: any; + events: any; + open: any; +} + +class EventData extends React.Component { + state: IState; + constructor(props, context) { super(props, context); this.state = {}; diff --git a/src/react/Components/CombinedList/ListControls.jsx b/src/components/CombinedList/ListControls.tsx similarity index 97% rename from src/react/Components/CombinedList/ListControls.jsx rename to src/components/CombinedList/ListControls.tsx index 90b1edb7..bf8639e3 100644 --- a/src/react/Components/CombinedList/ListControls.jsx +++ b/src/components/CombinedList/ListControls.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { CSSProperties } from "react"; import Grid from "@material-ui/core/Grid"; import IconButton from "@material-ui/core/IconButton"; import TextField from "@material-ui/core/TextField"; @@ -44,7 +44,7 @@ export default props => { - + { /> - + 5 10 diff --git a/src/react/Components/CombinedList/MapperFunctions.jsx b/src/components/CombinedList/MapperFunctions.tsx similarity index 99% rename from src/react/Components/CombinedList/MapperFunctions.jsx rename to src/components/CombinedList/MapperFunctions.tsx index b36542ce..52b9527a 100644 --- a/src/react/Components/CombinedList/MapperFunctions.jsx +++ b/src/components/CombinedList/MapperFunctions.tsx @@ -9,7 +9,7 @@ import RequestInquiryBatchListItem from "../ListItems/RequestInquiryBatchListIte import ShareInviteMonetaryAccountInquiryListItem from "../ListItems/ShareInviteMonetaryAccountInquiryListItem"; import ShareInviteMonetaryAccountResponseListItem from "../ListItems/ShareInviteMonetaryAccountResponseListItem"; -import { UTCDateToLocalDate } from "../../Functions/Utils"; +import { UTCDateToLocalDate } from "~functions/Utils"; import { paymentFilter, bunqMeTabsFilter, @@ -19,7 +19,7 @@ import { requestResponseFilter, shareInviteMonetaryAccountInquiryFilter, shareInviteMonetaryAccountResponseFilter -} from "../../Functions/DataFilters"; +} from "~functions/DataFilters"; export const paymentMapper = (settings, hiddenPaymentIds = []) => { if (settings.hiddenTypes.includes("Payment")) return []; diff --git a/src/react/Components/CopyToClipboardWrap.jsx b/src/components/CopyToClipboardWrap.tsx similarity index 100% rename from src/react/Components/CopyToClipboardWrap.jsx rename to src/components/CopyToClipboardWrap.tsx diff --git a/src/react/Components/CustomIcon.jsx b/src/components/CustomIcon.tsx similarity index 100% rename from src/react/Components/CustomIcon.jsx rename to src/components/CustomIcon.tsx diff --git a/src/react/Components/CustomSVG/FileDownload.jsx b/src/components/CustomSVG/FileDownload.tsx similarity index 100% rename from src/react/Components/CustomSVG/FileDownload.jsx rename to src/components/CustomSVG/FileDownload.tsx diff --git a/src/react/Components/CustomSVG/FileUpload.jsx b/src/components/CustomSVG/FileUpload.tsx similarity index 100% rename from src/react/Components/CustomSVG/FileUpload.jsx rename to src/components/CustomSVG/FileUpload.tsx diff --git a/src/react/Components/CustomSVG/Maximize.jsx b/src/components/CustomSVG/Maximize.tsx similarity index 100% rename from src/react/Components/CustomSVG/Maximize.jsx rename to src/components/CustomSVG/Maximize.tsx diff --git a/src/react/Components/CustomSVG/Minimize.jsx b/src/components/CustomSVG/Minimize.tsx similarity index 100% rename from src/react/Components/CustomSVG/Minimize.jsx rename to src/components/CustomSVG/Minimize.tsx diff --git a/src/react/Components/CustomSVG/Restore.jsx b/src/components/CustomSVG/Restore.tsx similarity index 100% rename from src/react/Components/CustomSVG/Restore.jsx rename to src/components/CustomSVG/Restore.tsx diff --git a/src/react/Components/CustomSVG/Trophy.jsx b/src/components/CustomSVG/Trophy.tsx similarity index 100% rename from src/react/Components/CustomSVG/Trophy.jsx rename to src/components/CustomSVG/Trophy.tsx diff --git a/src/react/Components/ErrorBoundary.jsx b/src/components/ErrorBoundary.tsx similarity index 87% rename from src/react/Components/ErrorBoundary.jsx rename to src/components/ErrorBoundary.tsx index 12f4d22c..b815d8d1 100644 --- a/src/react/Components/ErrorBoundary.jsx +++ b/src/components/ErrorBoundary.tsx @@ -1,11 +1,13 @@ import React from "react"; import Typography from "@material-ui/core/Typography"; -import Logger from "../Functions/Logger"; +import Logger from "~functions/Logger"; import TranslateButton from "./TranslationHelpers/Button"; import TranslateTypography from "./TranslationHelpers/Typography"; -export default class ErrorBoundary extends React.Component { +export default class ErrorBoundary extends React.Component { + state: any; + constructor(props) { super(props); this.state = { hasError: false, error: null, errorInfo: null }; @@ -33,11 +35,11 @@ export default class ErrorBoundary extends React.Component { {this.state.error.stack}
- {this.props.recoverableError === true ? ( + {!!this.props.recoverableError && ( Return to dashboard - ) : null} + )} ); } diff --git a/src/react/Components/ExportDialog.jsx b/src/components/ExportDialog.tsx similarity index 92% rename from src/react/Components/ExportDialog.jsx rename to src/components/ExportDialog.tsx index 58ae66c0..5d54339f 100644 --- a/src/react/Components/ExportDialog.jsx +++ b/src/components/ExportDialog.tsx @@ -7,8 +7,8 @@ import Slide from "@material-ui/core/Slide"; import TranslateButton from "./TranslationHelpers/Button"; import ReactJsonWrapper from "./ReactJsonWrapper"; -import { anonymizeObject } from "../Functions/Utils"; -import CopyToClipboardWrap from "../Components/CopyToClipboardWrap"; +import { anonymizeObject } from "~functions/Utils"; +import CopyToClipboardWrap from "~components/CopyToClipboardWrap"; const Transition = props => ; @@ -18,7 +18,9 @@ const styles = { } }; -export default class ExportDialog extends React.Component { +export default class ExportDialog extends React.Component { + state: any; + constructor(props, context) { super(props, context); this.state = { diff --git a/src/react/Components/FileUpload/FilePicker.jsx b/src/components/FileUpload/FilePicker.tsx similarity index 89% rename from src/react/Components/FileUpload/FilePicker.jsx rename to src/components/FileUpload/FilePicker.tsx index 82011a0b..c2e6937e 100644 --- a/src/react/Components/FileUpload/FilePicker.jsx +++ b/src/components/FileUpload/FilePicker.tsx @@ -1,5 +1,4 @@ -import React from "react"; -import PropTypes from "prop-types"; +import React, { RefObject } from "react"; import FileUpload from "../CustomSVG/FileUpload"; @@ -36,7 +35,19 @@ const styles = { const allowedFileTypes = ["image/jpeg", "image/png", "image/gif"]; -class FilePicker extends React.Component { +interface IState { + imagePreviewUrl: false | string; +} + +interface IProps { + handleFileDrop: Function; + onChange?: Function; +} + +class FilePicker extends React.Component { + state: IState; + fileInput: RefObject; + constructor(props, context) { super(props, context); this.state = { @@ -89,8 +100,4 @@ class FilePicker extends React.Component { } } -FilePicker.propTypes = { - onChange: PropTypes.func.isRequired -}; - export default FilePicker; diff --git a/src/react/Components/FileUpload/UploadFullscreen.jsx b/src/components/FileUpload/UploadFullscreen.tsx similarity index 78% rename from src/react/Components/FileUpload/UploadFullscreen.jsx rename to src/components/FileUpload/UploadFullscreen.tsx index 173e1905..992ae3a8 100644 --- a/src/react/Components/FileUpload/UploadFullscreen.jsx +++ b/src/components/FileUpload/UploadFullscreen.tsx @@ -1,14 +1,17 @@ -import React from "react"; +import React, { CSSProperties } from "react"; import { connect } from "react-redux"; import { translate } from "react-i18next"; import Dialog from "@material-ui/core/Dialog"; import Typography from "@material-ui/core/Typography"; import Slide from "@material-ui/core/Slide"; -import TranslateButton from "../../Components/TranslationHelpers/Button"; +import TranslateButton from "~components/TranslationHelpers/Button"; +import { AppDispatch, ReduxState } from "~store/index"; import FilePicker from "./FilePicker"; -import { openSnackbar } from "../../Actions/snackbar"; +import { actions as snackbarActions } from "~store/snackbar"; + +declare let window: any; const Transition = props => ; @@ -41,7 +44,22 @@ const styles = { } }; -class UploadFullscreen extends React.Component { +interface IState { + [key: string]: any; +} + +interface IProps { + [key: string]: any; +} + +class UploadFullscreen extends React.Component & ReturnType & IProps> { + static defaultProps = { + headlineText: "Upload a new avatar", + buttonText: "Upload" + }; + + state: IState; + constructor(props) { super(props); @@ -57,6 +75,7 @@ class UploadFullscreen extends React.Component { }; startUpload = () => { + const BunqJSClient = window.BunqDesktopClient.BunqJSClient; const file = this.state.file; // close the fullscreen page on upload @@ -76,9 +95,9 @@ class UploadFullscreen extends React.Component { fileReader.onload = () => resolve(fileReader.result); }).then(fileArrayBuffer => { // transform array buffer into regular buffer - const fileBuffer = Buffer.from(fileArrayBuffer); + const fileBuffer = Buffer.from(fileArrayBuffer as any); - this.props.BunqJSClient.api.attachmentPublic + BunqJSClient.api.attachmentPublic .post(fileBuffer, file.type) .then(response => { this.props.onComplete(response); @@ -118,7 +137,7 @@ class UploadFullscreen extends React.Component {
- + {t(this.props.headlineText)} @@ -140,18 +159,13 @@ class UploadFullscreen extends React.Component { } } -UploadFullscreen.defaultProps = { - headlineText: "Upload a new avatar", - buttonText: "Upload" -}; - -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return {}; }; -const mapDispatchToProps = dispatch => { +const mapDispatchToProps = (dispatch: AppDispatch) => { return { - openSnackbar: message => dispatch(openSnackbar(message)) + openSnackbar: message => dispatch(snackbarActions.open({ message })) }; }; diff --git a/src/react/Components/FilterComponents/AccountSelection.jsx b/src/components/FilterComponents/AccountSelection.tsx similarity index 84% rename from src/react/Components/FilterComponents/AccountSelection.jsx rename to src/components/FilterComponents/AccountSelection.tsx index 7df81f48..024f7db2 100644 --- a/src/react/Components/FilterComponents/AccountSelection.jsx +++ b/src/components/FilterComponents/AccountSelection.tsx @@ -1,4 +1,5 @@ -import React from "react"; +import BunqJSClient from "@bunq-community/bunq-js-client"; +import React, { CSSProperties } from "react"; import { connect } from "react-redux"; import Avatar from "@material-ui/core/Avatar"; import IconButton from "@material-ui/core/IconButton"; @@ -12,10 +13,12 @@ import Tooltip from "@material-ui/core/Tooltip"; import AddIcon from "@material-ui/icons/Add"; import FilterListIcon from "@material-ui/icons/FilterList"; +import { AppWindow } from "~app"; +import { AppDispatch, ReduxState } from "~store/index"; import LazyAttachmentImage from "../AttachmentImage/LazyAttachmentImage"; -import { addAccountIdFilter, removeAccountIdFilter, toggleAccountIdFilter } from "../../Actions/filters"; +import { addAccountIdFilter, removeAccountIdFilter, toggleAccountIdFilter } from "~actions/filters"; const styles = { listItem: { @@ -28,7 +31,18 @@ const styles = { } }; -class AccountSelection extends React.Component { +interface IProps { + BunqJSClient: BunqJSClient; + t: AppWindow["t"]; +} + +interface IState { + anchorEl: HTMLElement | null; +} + +class AccountSelection extends React.Component & ReturnType & IProps> { + state: IState; + constructor(props, context) { super(props, context); this.state = { @@ -68,7 +82,6 @@ class AccountSelection extends React.Component { @@ -96,10 +109,9 @@ class AccountSelection extends React.Component { return ( - + @@ -110,7 +122,7 @@ class AccountSelection extends React.Component { }); return ( - + <> {t("Account filter")} @@ -132,22 +144,22 @@ class AccountSelection extends React.Component { {accountMenuItems} - {selectedAccountChipItems} - + {selectedAccountChipItems} + ); } } -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return { accounts: state.accounts.accounts, - selectedAccountIds: state.account_id_filter.selected_account_ids, - toggleAccountIds: state.account_id_filter.toggle + selectedAccountIds: state.accountIdFilter.selectedAccountIds, + toggleAccountIds: state.accountIdFilter.toggle }; }; -const mapDispatchToProps = dispatch => { +const mapDispatchToProps = (dispatch: AppDispatch) => { return { addAccountIdFilter: accountId => dispatch(addAccountIdFilter(accountId)), removeAccountIdFilter: index => dispatch(removeAccountIdFilter(index)), diff --git a/src/react/Components/FilterComponents/AmountFilter.jsx b/src/components/FilterComponents/AmountFilter.tsx similarity index 72% rename from src/react/Components/FilterComponents/AmountFilter.jsx rename to src/components/FilterComponents/AmountFilter.tsx index 8c1de7f4..84b54261 100644 --- a/src/react/Components/FilterComponents/AmountFilter.jsx +++ b/src/components/FilterComponents/AmountFilter.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { CSSProperties } from "react"; import { connect } from "react-redux"; import Select from "@material-ui/core/Select"; import MenuItem from "@material-ui/core/MenuItem"; @@ -6,9 +6,22 @@ import TextField from "@material-ui/core/TextField"; import InputLabel from "@material-ui/core/InputLabel"; import FormControl from "@material-ui/core/FormControl"; -import { setAmountFilterAmount, setAmountFilterType, clearAmountFilter } from "../../Actions/filters"; +import { setAmountFilterAmount, setAmountFilterType, clearAmountFilter } from "~actions/filters"; +import { AppWindow } from "~app"; +import { AppDispatch, ReduxState } from "~store/index"; + +interface IProps { + style: CSSProperties; + t: AppWindow["t"]; +} + +interface IState { + [key: string]: any; +} + +class AmountFilter extends React.Component & ReturnType & IProps> { + state: IState; -class AmountFilter extends React.Component { constructor(props, context) { super(props, context); this.state = {}; @@ -24,7 +37,7 @@ class AmountFilter extends React.Component { render() { const t = this.props.t; return ( - + <> {`>`} - + ); } } -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return { - amountFilterAmount: state.amount_filter.amount, - amountFilterType: state.amount_filter.type + amountFilterAmount: state.amountFilter.amount, + amountFilterType: state.amountFilter.type }; }; -const mapDispatchToProps = dispatch => { +const mapDispatchToProps = (dispatch: AppDispatch) => { return { setAmountFilterAmount: amount => dispatch(setAmountFilterAmount(amount)), setAmountFilterType: amount => dispatch(setAmountFilterType(amount)) diff --git a/src/react/Components/FilterComponents/CardSelection.jsx b/src/components/FilterComponents/CardSelection.tsx similarity index 87% rename from src/react/Components/FilterComponents/CardSelection.jsx rename to src/components/FilterComponents/CardSelection.tsx index c3bffe77..67ed0088 100644 --- a/src/react/Components/FilterComponents/CardSelection.jsx +++ b/src/components/FilterComponents/CardSelection.tsx @@ -12,13 +12,16 @@ import Tooltip from "@material-ui/core/Tooltip"; import AddIcon from "@material-ui/icons/Add"; import FilterListIcon from "@material-ui/icons/FilterList"; +import { isBoolean } from "util"; -import { cardsUpdate } from "../../Actions/cards"; -import { addCardIdFilter, removeCardIdFilter, toggleCardIdFilter } from "../../Actions/filters"; -import { getCardTypeImage } from "../../Pages/Cards/CardListItem"; -import { getCardDescription } from "../../Functions/Utils"; +import { addCardIdFilter, removeCardIdFilter, toggleCardIdFilter } from "~actions/filters"; +import { AppWindow } from "~app"; +import { getCardTypeImage } from "~pages/Cards/CardListItem"; +import { getCardDescription } from "~functions/Utils"; +import { cardsUpdate } from "~store/cards/thunks"; +import { AppDispatch, ReduxState } from "~store/index"; -const styles = { +const styles: any = { listItem: { display: "flex", flexWrap: "wrap", @@ -45,7 +48,17 @@ const styles = { } }; -class CardSelection extends React.Component { +interface IState { + [key: string]: any; +} + +interface IProps { + t: AppWindow["t"]; +} + +class CardSelection extends React.Component & ReturnType & IProps> { + state: any; + constructor(props, context) { super(props, context); this.state = { @@ -132,7 +145,7 @@ class CardSelection extends React.Component { }); return ( - + <> {t("Card filter")} @@ -155,24 +168,24 @@ class CardSelection extends React.Component { {selectedCardChipItems} - + ); } } -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return { user: state.user.user, cards: state.cards.cards, cardsLoading: state.cards.loading, - selectedCardIds: state.card_id_filter.selected_card_ids, - toggleCardIds: state.card_id_filter.toggle + selectedCardIds: state.cardIdFilter.selected_card_ids, + toggleCardIds: state.cardIdFilter.toggle }; }; -const mapDispatchToProps = dispatch => { +const mapDispatchToProps = (dispatch: AppDispatch) => { return { addCardIdFilter: cardId => dispatch(addCardIdFilter(cardId)), removeCardIdFilter: index => dispatch(removeCardIdFilter(index)), diff --git a/src/react/Components/FilterComponents/CategorySelection.jsx b/src/components/FilterComponents/CategorySelection.tsx similarity index 85% rename from src/react/Components/FilterComponents/CategorySelection.jsx rename to src/components/FilterComponents/CategorySelection.tsx index 2c76d2cd..2a568105 100644 --- a/src/react/Components/FilterComponents/CategorySelection.jsx +++ b/src/components/FilterComponents/CategorySelection.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { CSSProperties } from "react"; import { connect } from "react-redux"; import IconButton from "@material-ui/core/IconButton"; import ListItem from "@material-ui/core/ListItem"; @@ -11,12 +11,14 @@ import Tooltip from "@material-ui/core/Tooltip"; import AddIcon from "@material-ui/icons/Add"; import FilterListIcon from "@material-ui/icons/FilterList"; +import { AppWindow } from "~app"; +import { AppDispatch, ReduxState } from "~store/index"; import CustomIcon from "../CustomIcon"; import CategoryIcon from "../Categories/CategoryIcon"; import CategoryChip from "../Categories/CategoryChip"; -import { addCategoryIdFilter, removeCategoryIdFilter, toggleCategoryIdFilter } from "../../Actions/filters"; +import { addCategoryIdFilter, removeCategoryIdFilter, toggleCategoryIdFilter } from "~actions/filters"; const styles = { listItem: { @@ -29,7 +31,17 @@ const styles = { } }; -class CategorySelection extends React.Component { +interface IState { + anchorEl: HTMLElement | null; +} + +interface IProps { + t: AppWindow["t"]; +} + +class CategorySelection extends React.Component & ReturnType & IProps> { + state: IState; + constructor(props, context) { super(props, context); this.state = { @@ -78,7 +90,7 @@ class CategorySelection extends React.Component { const category = categories[categoryId]; // don't display already selected items - if (selectedCategories.includes(categoryId)) { + if (selectedCategories.includes(+categoryId)) { return null; } @@ -101,7 +113,7 @@ class CategorySelection extends React.Component { }); return ( - + <> {t("Category filter")} @@ -131,22 +143,22 @@ class CategorySelection extends React.Component { {categoryMenuItems} - {categoryItems} - + {categoryItems} + ); } } -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return { categories: state.categories.categories, - toggleCategoryFilter: state.category_filter.toggle, - selectedCategories: state.category_filter.selected_categories + toggleCategoryFilter: state.categoryFilter.toggle, + selectedCategories: state.categoryFilter.selected_categories }; }; -const mapDispatchToProps = dispatch => { +const mapDispatchToProps = (dispatch: AppDispatch) => { return { toggleCategoryIdFilter: () => dispatch(toggleCategoryIdFilter()), addCategoryId: categoryId => dispatch(addCategoryIdFilter(categoryId)), diff --git a/src/react/Components/FilterComponents/ClearFilter.jsx b/src/components/FilterComponents/ClearFilter.tsx similarity index 61% rename from src/react/Components/FilterComponents/ClearFilter.jsx rename to src/components/FilterComponents/ClearFilter.tsx index ea625a9e..3edbb52d 100644 --- a/src/react/Components/FilterComponents/ClearFilter.jsx +++ b/src/components/FilterComponents/ClearFilter.tsx @@ -3,12 +3,30 @@ import { connect } from "react-redux"; import Button from "@material-ui/core/Button"; import IconButton from "@material-ui/core/IconButton"; import ClearIcon from "@material-ui/icons/Clear"; +import { AppWindow } from "~app"; -import FilterDisabledChecker from "../../Functions/FilterDisabledChecker"; +import FilterDisabledChecker from "~functions/FilterDisabledChecker"; -import { resetFilters } from "../../Actions/filters"; +import { resetFilters } from "~actions/filters"; +import { AppDispatch, ReduxState } from "~store/index"; + +interface IState { + [key: string]: any; +} + +interface IProps { + t: AppWindow["t"]; + [key: string]: any; +} + +class ClearFilter extends React.PureComponent & ReturnType & IProps> { + static defaultProps = { + bigButton: false, + buttonProps: {} + }; + + state: IState; -class ClearFilter extends React.PureComponent { constructor(props, context) { super(props, context); this.state = {}; @@ -28,7 +46,8 @@ class ClearFilter extends React.PureComponent { paymentVisibility, bunqMeTabVisibility, requestVisibility, - amountFilterAmount + amountFilterAmount, + t, } = this.props; if ( @@ -63,35 +82,30 @@ class ClearFilter extends React.PureComponent { } } -ClearFilter.defaultProps = { - bigButton: false, - buttonProps: {} -}; - -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return { searchTerm: state.search_filter.search_term, paymentType: state.payment_filter.type, paymentVisibility: state.payment_filter.visible, - bunqMeTabType: state.bunq_me_tab_filter.type, - bunqMeTabVisibility: state.bunq_me_tab_filter.visible, + bunqMeTabType: state.bunqMeTabFilter.type, + bunqMeTabVisibility: state.bunqMeTabFilter.visible, requestType: state.request_filter.type, requestVisibility: state.request_filter.visible, - dateFromFilter: state.date_filter.from_date, - dateToFilter: state.date_filter.to_date, + dateFromFilter: state.dateFilter.from_date, + dateToFilter: state.dateFilter.to_date, - selectedCategories: state.category_filter.selected_categories, - toggleCategoryIds: state.category_filter.toggle, - selectedAccountIds: state.account_id_filter.selected_account_ids, - toggleAccountIds: state.account_id_filter.toggle, - selectedCardIds: state.card_id_filter.selected_card_ids, - toggleCardIds: state.card_id_filter.toggle, + selectedCategories: state.categoryFilter.selected_categories, + toggleCategoryIds: state.categoryFilter.toggle, + selectedAccountIds: state.accountIdFilter.selectedAccountIds, + toggleAccountIds: state.accountIdFilter.toggle, + selectedCardIds: state.cardIdFilter.selected_card_ids, + toggleCardIds: state.cardIdFilter.toggle, - amountFilterAmount: state.amount_filter.amount + amountFilterAmount: state.amountFilter.amount }; }; -const mapDispatchToProps = dispatch => { +const mapDispatchToProps = (dispatch: AppDispatch) => { return { resetFilters: () => dispatch(resetFilters()) }; diff --git a/src/react/Components/FilterComponents/FilterDrawer.jsx b/src/components/FilterComponents/FilterDrawer.tsx similarity index 93% rename from src/react/Components/FilterComponents/FilterDrawer.jsx rename to src/components/FilterComponents/FilterDrawer.tsx index 5d3cdec0..860da460 100644 --- a/src/react/Components/FilterComponents/FilterDrawer.jsx +++ b/src/components/FilterComponents/FilterDrawer.tsx @@ -1,7 +1,7 @@ -import React from "react"; +import React, { CSSProperties } from "react"; import { connect } from "react-redux"; import { translate } from "react-i18next"; -import DatePicker from "material-ui-pickers/DatePicker/index.js"; +import DatePicker from "material-ui-pickers/DatePicker"; import { withTheme } from "@material-ui/core/styles"; import IconButton from "@material-ui/core/IconButton"; import Icon from "@material-ui/core/Icon"; @@ -41,7 +41,8 @@ import { clearFromDateFilter, clearToDateFilter, resetFilters -} from "../../Actions/filters"; +} from "~actions/filters"; +import { AppDispatch, ReduxState } from "~store/index"; import SearchFilter from "./SearchFilter"; import AccountSelection from "./AccountSelection"; @@ -101,7 +102,23 @@ const styles = { } }; -class FilterDrawer extends React.Component { +interface IProps { + [key: string]: any; +} + +interface IState { + [key: string]: any; +} + +class FilterDrawer extends React.Component & ReturnType & IProps> { + static defaultProps = { + bigButton: false, + buttonProps: {}, + buttonContent: null + }; + + state: IState; + constructor(props, context) { super(props, context); this.state = { @@ -174,7 +191,7 @@ class FilterDrawer extends React.Component { this.props.dateToFilter !== null || this.props.dateFromFilter !== null || this.state.displayDateFilter; const drawerList = ( - + @@ -199,7 +216,7 @@ class FilterDrawer extends React.Component { @@ -241,7 +258,7 @@ class FilterDrawer extends React.Component { @@ -283,7 +300,7 @@ class FilterDrawer extends React.Component { @@ -349,7 +366,7 @@ class FilterDrawer extends React.Component { {displayDateFilters && ( - + <> - + )} - + @@ -445,29 +462,23 @@ class FilterDrawer extends React.Component { } } -FilterDrawer.defaultProps = { - bigButton: false, - buttonProps: {}, - buttonContent: null -}; - -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return { paymentType: state.payment_filter.type, paymentVisibility: state.payment_filter.visible, - bunqMeTabType: state.bunq_me_tab_filter.type, - bunqMeTabVisibility: state.bunq_me_tab_filter.visible, + bunqMeTabType: state.bunqMeTabFilter.type, + bunqMeTabVisibility: state.bunqMeTabFilter.visible, requestType: state.request_filter.type, requestVisibility: state.request_filter.visible, - dateFromFilter: state.date_filter.from_date, - dateToFilter: state.date_filter.to_date + dateFromFilter: state.dateFilter.from_date, + dateToFilter: state.dateFilter.to_date }; }; -const mapDispatchToProps = dispatch => { +const mapDispatchToProps = (dispatch: AppDispatch) => { return { resetFilters: () => dispatch(resetFilters()), diff --git a/src/react/Components/FilterComponents/SearchFilter.jsx b/src/components/FilterComponents/SearchFilter.tsx similarity index 69% rename from src/react/Components/FilterComponents/SearchFilter.jsx rename to src/components/FilterComponents/SearchFilter.tsx index 5bf5af31..e77ad985 100644 --- a/src/react/Components/FilterComponents/SearchFilter.jsx +++ b/src/components/FilterComponents/SearchFilter.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { CSSProperties } from "react"; import { connect } from "react-redux"; import TextField from "@material-ui/core/TextField"; import IconButton from "@material-ui/core/IconButton"; @@ -6,9 +6,26 @@ import InputAdornment from "@material-ui/core/InputAdornment"; import ClearIcon from "@material-ui/icons/Clear"; -import { setSearchFilter, clearSearchFilter } from "../../Actions/filters"; +import { setSearchFilter, clearSearchFilter } from "~actions/filters"; +import { AppWindow } from "~app"; +import { AppDispatch, ReduxState } from "~store/index"; + +interface IState { + [key: string]: any; +} + +interface IProps { + t: AppWindow["t"]; + style: CSSProperties; +} + +class SearchFilter extends React.Component & ReturnType & IProps> { + static defaultProps = { + style: {} + }; + + state: IState; -class SearchFilter extends React.Component { constructor(props, context) { super(props, context); this.state = {}; @@ -40,17 +57,13 @@ class SearchFilter extends React.Component { } } -SearchFilter.defaultProps = { - style: {} -}; - -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return { searchTerm: state.search_filter.search_term }; }; -const mapDispatchToProps = dispatch => { +const mapDispatchToProps = (dispatch: AppDispatch) => { return { setSearchFilter: searchTerm => dispatch(setSearchFilter(searchTerm)), clearSearchFilter: () => dispatch(clearSearchFilter()) diff --git a/src/react/Components/FilterCreationDialog.jsx b/src/components/FilterCreationDialog.tsx similarity index 98% rename from src/react/Components/FilterCreationDialog.jsx rename to src/components/FilterCreationDialog.tsx index 769e5c43..23050d01 100644 --- a/src/react/Components/FilterCreationDialog.jsx +++ b/src/components/FilterCreationDialog.tsx @@ -9,7 +9,7 @@ import ListItemText from "@material-ui/core/ListItemText"; import TranslateButton from "./TranslationHelpers/Button"; import NavLink from "./Routing/NavLink"; -import { formatIban } from "../Functions/Utils"; +import { formatIban } from "~functions/Utils"; export default props => { const { t, item, open, onClose } = props; diff --git a/src/react/Components/FormFields/AccountSelectorDialog.jsx b/src/components/FormFields/AccountSelectorDialog.tsx similarity index 85% rename from src/react/Components/FormFields/AccountSelectorDialog.jsx rename to src/components/FormFields/AccountSelectorDialog.tsx index 9506f081..6b20dc05 100644 --- a/src/react/Components/FormFields/AccountSelectorDialog.jsx +++ b/src/components/FormFields/AccountSelectorDialog.tsx @@ -1,7 +1,6 @@ import React from "react"; import { connect } from "react-redux"; import { translate } from "react-i18next"; -import PropTypes from "prop-types"; import Avatar from "@material-ui/core/Avatar"; import FormControl from "@material-ui/core/FormControl"; import List from "@material-ui/core/List"; @@ -10,12 +9,13 @@ import ListItemText from "@material-ui/core/ListItemText"; import Dialog from "@material-ui/core/Dialog"; import DialogContent from "@material-ui/core/DialogContent"; import DialogTitle from "@material-ui/core/DialogTitle"; +import { ReduxState } from "~store/index"; import LazyAttachmentImage from "../AttachmentImage/LazyAttachmentImage"; -import { formatMoney } from "../../Functions/Utils"; -import { filterShareInviteMonetaryAccountResponses } from "../../Functions/DataFilters"; -import { connectGetBudget } from "../../Functions/ConnectGetPermissions"; +import { formatMoney } from "~functions/Utils"; +import { filterShareInviteMonetaryAccountResponses } from "~functions/DataFilters"; +import { connectGetBudget } from "~functions/ConnectGetPermissions"; const styles = { formControl: { @@ -30,7 +30,7 @@ const styles = { } }; -const AccountItem = ({ account, onClick, BunqJSClient, hideBalance, shareInviteMonetaryAccountResponses }) => { +const AccountItem = ({ account, onClick, hideBalance, shareInviteMonetaryAccountResponses }) => { // format default balance let formattedBalance = account.balance ? account.balance.value : 0; @@ -52,18 +52,34 @@ const AccountItem = ({ account, onClick, BunqJSClient, hideBalance, shareInviteM return ( - + />} ); }; -class AccountSelectorDialog extends React.Component { +interface IState { + [key: string]: any; +} + +interface IProps { + value: any; + onChange: Function; +} + +class AccountSelectorDialog extends React.Component & IProps> { + static defaultProps = { + hiddenConnectTypes: [], + style: styles.formControl, + selectStyle: styles.selectField + }; + + state: IState; + constructor(props, context) { super(props, context); this.state = { @@ -89,7 +105,6 @@ class AccountSelectorDialog extends React.Component { render() { const { - BunqJSClient, accounts, value, hiddenConnectTypes, @@ -135,7 +150,6 @@ class AccountSelectorDialog extends React.Component { shareInviteMonetaryAccountResponses={shareInviteMonetaryAccountResponses} onClick={this.onClickHandler(accountKey)} hideBalance={this.props.hideBalance} - BunqJSClient={BunqJSClient} account={account} /> ); @@ -147,7 +161,6 @@ class AccountSelectorDialog extends React.Component { @@ -174,18 +187,7 @@ class AccountSelectorDialog extends React.Component { } } -AccountSelectorDialog.propTypes = { - value: PropTypes.any.isRequired, - onChange: PropTypes.func.isRequired -}; - -AccountSelectorDialog.defaultProps = { - hiddenConnectTypes: [], - style: styles.formControl, - selectStyle: styles.selectField -}; - -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return { shareInviteMonetaryAccountResponses: state.share_invite_monetary_account_responses.share_invite_monetary_account_responses, diff --git a/src/react/Components/FormFields/ColorPicker.jsx b/src/components/FormFields/ColorPicker.tsx similarity index 84% rename from src/react/Components/FormFields/ColorPicker.jsx rename to src/components/FormFields/ColorPicker.tsx index e7ab9474..ef2bbf7d 100644 --- a/src/react/Components/FormFields/ColorPicker.jsx +++ b/src/components/FormFields/ColorPicker.tsx @@ -1,5 +1,4 @@ import React from "react"; -import PropTypes from "prop-types"; import { translate } from "react-i18next"; import ChromePicker from "react-color/lib/Chrome"; import Button from "@material-ui/core/Button"; @@ -19,7 +18,23 @@ const styles = { } }; -class ColorPicker extends React.Component { +interface IState { + [key: string]: any; +} + +interface IProps { + [key: string]: any; +} + +class ColorPicker extends React.Component { + static defaultProps = { + style: {}, + buttonStyle: {}, + buttonProps: {} + }; + + state: IState; + constructor(props, context) { super(props, context); this.state = { @@ -56,14 +71,4 @@ class ColorPicker extends React.Component { } } -ColorPicker.defaultProps = { - style: {}, - buttonStyle: {}, - buttonProps: {} -}; - -ColorPicker.propTypes = { - pickerProps: PropTypes.object.isRequired -}; - export default translate("translations")(ColorPicker); diff --git a/src/react/Components/FormFields/EmailSuggestions.jsx b/src/components/FormFields/EmailSuggestions.tsx similarity index 94% rename from src/react/Components/FormFields/EmailSuggestions.jsx rename to src/components/FormFields/EmailSuggestions.tsx index d627901b..5bd9cc93 100644 --- a/src/react/Components/FormFields/EmailSuggestions.jsx +++ b/src/components/FormFields/EmailSuggestions.tsx @@ -1,5 +1,4 @@ import React from "react"; -import PropTypes from "prop-types"; import TextField from "@material-ui/core/TextField"; import Paper from "@material-ui/core/Paper"; import ListItem from "@material-ui/core/ListItem"; @@ -18,7 +17,17 @@ const styles = { } }; -class EmailSuggestions extends React.Component { +interface IState { + [key: string]: any; +} + +interface IProps { + [key: string]: any; +} + +class EmailSuggestions extends React.Component { + state: IState; + constructor(props, context) { super(props, context); this.state = { @@ -94,8 +103,4 @@ class EmailSuggestions extends React.Component { } } -EmailSuggestions.propTypes = { - // itemSelected: PropTypes.func.isRequired -}; - export default EmailSuggestions; diff --git a/src/react/Components/FormFields/FilePicker.jsx b/src/components/FormFields/FilePicker.tsx similarity index 100% rename from src/react/Components/FormFields/FilePicker.jsx rename to src/components/FormFields/FilePicker.tsx diff --git a/src/react/Components/FormFields/GradientColorPicker.jsx b/src/components/FormFields/GradientColorPicker.tsx similarity index 100% rename from src/react/Components/FormFields/GradientColorPicker.jsx rename to src/components/FormFields/GradientColorPicker.tsx diff --git a/src/react/Components/FormFields/IconPicker.jsx b/src/components/FormFields/IconPicker.tsx similarity index 90% rename from src/react/Components/FormFields/IconPicker.jsx rename to src/components/FormFields/IconPicker.tsx index 57633c4f..d77a35be 100644 --- a/src/react/Components/FormFields/IconPicker.jsx +++ b/src/components/FormFields/IconPicker.tsx @@ -1,5 +1,4 @@ import React from "react"; -import PropTypes from "prop-types"; import { translate } from "react-i18next"; import WindowedList from "react-windowed-list"; import Button from "@material-ui/core/Button"; @@ -8,10 +7,10 @@ import TextField from "@material-ui/core/TextField"; import Dialog from "@material-ui/core/Dialog"; import DialogTitle from "@material-ui/core/DialogTitle"; -import Icons from "../../StaticData/Icons"; +import Icons from "~staticdata/Icons.json"; import CustomIcon from "../CustomIcon"; -const styles = { +const styles: any = { iconContainer: { height: 500, width: 600, @@ -23,7 +22,16 @@ const styles = { } }; -class IconPicker extends React.Component { +class IconPicker extends React.Component { + static defaultProps = { + buttonLabel: "Pick an icon", + style: {}, + buttonStyle: {}, + buttonProps: {} + }; + + state: any; + constructor(props, context) { super(props, context); this.state = { @@ -61,7 +69,7 @@ class IconPicker extends React.Component { } }; - selectIcon = icon => event => { + selectIcon = icon => () => { this.props.onClick(icon); this.handleClose(); }; @@ -110,15 +118,4 @@ class IconPicker extends React.Component { } } -IconPicker.defaultProps = { - buttonLabel: "Pick an icon", - style: {}, - buttonStyle: {}, - buttonProps: {} -}; - -IconPicker.propTypes = { - onClick: PropTypes.func.isRequired -}; - export default translate("translations")(IconPicker); diff --git a/src/react/Components/FormFields/InputSuggestions.jsx b/src/components/FormFields/InputSuggestions.tsx similarity index 95% rename from src/react/Components/FormFields/InputSuggestions.jsx rename to src/components/FormFields/InputSuggestions.tsx index c8f36a7b..963f3b6d 100644 --- a/src/react/Components/FormFields/InputSuggestions.jsx +++ b/src/components/FormFields/InputSuggestions.tsx @@ -1,5 +1,4 @@ -import React from "react"; -import PropTypes from "prop-types"; +import React, { CSSProperties } from "react"; import TextField from "@material-ui/core/TextField"; import Paper from "@material-ui/core/Paper"; import ListItem from "@material-ui/core/ListItem"; @@ -21,7 +20,18 @@ const styles = { } }; -class InputSuggestions extends React.Component { +interface IState { + [key: string]: any; +} + +interface IProps { + [key: string]: any; +} + +class InputSuggestions extends React.Component { + state: IState; + timeOut: null | number; + constructor(props, context) { super(props, context); this.state = { @@ -40,7 +50,7 @@ class InputSuggestions extends React.Component { onBlur = event => { // delay so click event can react before onBlur - this.timeOut = setTimeout(() => { + this.timeOut = +setTimeout(() => { if (this.state.isMounted) { this.setState({ visible: false, selectedIndex: 0 }); } @@ -170,7 +180,7 @@ class InputSuggestions extends React.Component { {...otherProps} /> {this.state.visible ? ( - + {filteredItems.map((filteredItem, index) => ( {index === this.state.selectedIndex ? ( @@ -192,9 +202,4 @@ class InputSuggestions extends React.Component { } } -InputSuggestions.propTypes = { - itemSelected: PropTypes.func.isRequired, - InputComponent: PropTypes.node -}; - export default InputSuggestions; diff --git a/src/react/Components/FormFields/MoneyFormatInput.jsx b/src/components/FormFields/MoneyFormatInput.tsx similarity index 97% rename from src/react/Components/FormFields/MoneyFormatInput.jsx rename to src/components/FormFields/MoneyFormatInput.tsx index 41768d2b..4b91929a 100644 --- a/src/react/Components/FormFields/MoneyFormatInput.jsx +++ b/src/components/FormFields/MoneyFormatInput.tsx @@ -2,7 +2,7 @@ import React from "react"; import NumberFormat from "react-number-format"; import { withTheme } from "@material-ui/core/styles"; -import { preferedThousandSeparator, preferedDecimalSeparator } from "../../Functions/Utils"; +import { preferedThousandSeparator, preferedDecimalSeparator } from "~functions/Utils"; const MoneyFormatInput = props => { const { style, ...otherProps } = props; diff --git a/src/react/Components/FormFields/MoneyFormatInputDefault.jsx b/src/components/FormFields/MoneyFormatInputDefault.tsx similarity index 82% rename from src/react/Components/FormFields/MoneyFormatInputDefault.jsx rename to src/components/FormFields/MoneyFormatInputDefault.tsx index b059bfe8..2690d3f3 100644 --- a/src/react/Components/FormFields/MoneyFormatInputDefault.jsx +++ b/src/components/FormFields/MoneyFormatInputDefault.tsx @@ -2,11 +2,25 @@ import React from "react"; import NumberFormat from "react-number-format"; import Input from "@material-ui/core/Input"; import FormControl from "@material-ui/core/FormControl"; -import { preferedThousandSeparator, preferedDecimalSeparator } from "../../Functions/Utils"; +import { preferedThousandSeparator, preferedDecimalSeparator } from "~functions/Utils"; import { withTheme } from "@material-ui/core/styles"; -class MoneyFormatInputDefault extends React.Component { +interface IState { + [key: string]: any; +} + +interface IProps { + [key: string]: any; +} + +class MoneyFormatInputDefault extends React.Component { + state: IState; + + static defaultProps = { + fontSize: 24 + }; + NumberFormatCustom = props => { const { inputRef, fontSize, ...other } = props; @@ -38,8 +52,4 @@ class MoneyFormatInputDefault extends React.Component { } } -MoneyFormatInputDefault.defaultProps = { - fontSize: 24 -}; - export default withTheme()(MoneyFormatInputDefault); diff --git a/src/react/Components/FormFields/RedirectUrl.jsx b/src/components/FormFields/RedirectUrl.tsx similarity index 100% rename from src/react/Components/FormFields/RedirectUrl.jsx rename to src/components/FormFields/RedirectUrl.tsx diff --git a/src/react/Components/FormFields/SchedulePaymentForm.jsx b/src/components/FormFields/SchedulePaymentForm.tsx similarity index 97% rename from src/react/Components/FormFields/SchedulePaymentForm.jsx rename to src/components/FormFields/SchedulePaymentForm.tsx index 560ccbc1..4b05fbc3 100644 --- a/src/react/Components/FormFields/SchedulePaymentForm.jsx +++ b/src/components/FormFields/SchedulePaymentForm.tsx @@ -11,8 +11,8 @@ import ListItem from "@material-ui/core/ListItem"; import ListItemText from "@material-ui/core/ListItemText"; import TranslateMenuItem from "../TranslationHelpers/MenuItem"; -import scheduleTexts from "../../Functions/ScheduleTexts"; -import { getUTCDate, UTCDateToLocalDate } from "../../Functions/Utils"; +import scheduleTexts from "~functions/ScheduleTexts"; +import { getUTCDate, UTCDateToLocalDate } from "~functions/Utils"; const styles = { textField: { diff --git a/src/react/Components/FormFields/TargetChip.jsx b/src/components/FormFields/TargetChip.tsx similarity index 100% rename from src/react/Components/FormFields/TargetChip.jsx rename to src/components/FormFields/TargetChip.tsx diff --git a/src/react/Components/FormFields/TargetChipList.jsx b/src/components/FormFields/TargetChipList.tsx similarity index 100% rename from src/react/Components/FormFields/TargetChipList.jsx rename to src/components/FormFields/TargetChipList.tsx diff --git a/src/react/Components/FormFields/TargetSelection.jsx b/src/components/FormFields/TargetSelection.tsx similarity index 94% rename from src/react/Components/FormFields/TargetSelection.jsx rename to src/components/FormFields/TargetSelection.tsx index e5a73728..98398a5b 100644 --- a/src/react/Components/FormFields/TargetSelection.jsx +++ b/src/components/FormFields/TargetSelection.tsx @@ -1,6 +1,5 @@ import React from "react"; import { connect } from "react-redux"; -import PropTypes from "prop-types"; import { translate } from "react-i18next"; import Grid from "@material-ui/core/Grid"; import Radio from "@material-ui/core/Radio"; @@ -11,13 +10,14 @@ import AccountBalanceIcon from "@material-ui/icons/AccountBalance"; import CompareArrowsIcon from "@material-ui/icons/CompareArrows"; import PersonIcon from "@material-ui/icons/Person"; import ContactsIcon from "@material-ui/icons/Contacts"; +import { AppDispatch, ReduxState } from "~store/index"; import NavLink from "../Routing/NavLink"; import InputSuggestions from "./InputSuggestions"; import AccountSelectorDialog from "./AccountSelectorDialog"; -import { openSnackbar } from "../../Actions/snackbar"; -import { formatIban } from "../../Functions/Utils"; +import { formatIban } from "~functions/Utils"; import TargetChipList from "./TargetChipList"; +import { actions as snackbarActions } from "~store/snackbar"; const styles = { button: { @@ -35,7 +35,21 @@ const styles = { } }; -class TargetSelection extends React.Component { +interface IState { + [key: string]: any; +} + +interface IProps { + [key: string]: any; +} + +class TargetSelection extends React.Component & ReturnType & IProps> { + static defaultProps = { + disabledTypes: [] + }; + + state: IState; + constructor(props, context) { super(props, context); this.state = { @@ -107,7 +121,6 @@ class TargetSelection extends React.Component { value={this.props.selectedTargetAccount} onChange={this.props.handleChangeDirect("selectedTargetAccount")} accounts={this.props.accounts} - BunqJSClient={this.props.BunqJSClient} /> ); break; @@ -286,7 +299,7 @@ class TargetSelection extends React.Component { } } -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return { contacts: state.contacts.contacts, contactsLoading: state.contacts.loading, @@ -295,22 +308,10 @@ const mapStateToProps = state => { }; }; -const mapDispatchToProps = dispatch => { +const mapDispatchToProps = (dispatch: AppDispatch) => { return { - openSnackbar: message => dispatch(openSnackbar(message)) + openSnackbar: message => dispatch(snackbarActions.open({ message })) }; }; -TargetSelection.propTypes = { - disabledTypes: PropTypes.array, - - addTarget: PropTypes.func.isRequired, - removeTarget: PropTypes.func.isRequired, - handleChange: PropTypes.func.isRequired, - handleChangeDirect: PropTypes.func.isRequired -}; -TargetSelection.defaultProps = { - disabledTypes: [] -}; - export default connect(mapStateToProps, mapDispatchToProps)(translate("translations")(TargetSelection)); diff --git a/src/react/Components/GeoLocation/GeoLocationListItem.jsx b/src/components/GeoLocation/GeoLocationListItem.tsx similarity index 83% rename from src/react/Components/GeoLocation/GeoLocationListItem.jsx rename to src/components/GeoLocation/GeoLocationListItem.tsx index a6b55cc3..5396dea7 100644 --- a/src/react/Components/GeoLocation/GeoLocationListItem.jsx +++ b/src/components/GeoLocation/GeoLocationListItem.tsx @@ -3,7 +3,17 @@ import ListItem from "@material-ui/core/ListItem"; import ListItemText from "@material-ui/core/ListItemText"; import GeoLocationView from "./GeoLocationView"; -class GeoLocationListItem extends React.Component { +interface IState { + [key: string]: any; +} + +interface IProps { + [key: string]: any; +} + +class GeoLocationListItem extends React.Component { + state: IState; + constructor(props, context) { super(props, context); this.state = { @@ -29,12 +39,12 @@ class GeoLocationListItem extends React.Component { if (!geoLocation) return null; return ( - + <> - + ); } } diff --git a/src/react/Components/GeoLocation/GeoLocationMap.jsx b/src/components/GeoLocation/GeoLocationMap.tsx similarity index 90% rename from src/react/Components/GeoLocation/GeoLocationMap.jsx rename to src/components/GeoLocation/GeoLocationMap.tsx index 99395280..214d537d 100644 --- a/src/react/Components/GeoLocation/GeoLocationMap.jsx +++ b/src/components/GeoLocation/GeoLocationMap.tsx @@ -7,6 +7,7 @@ import MarkerIcon from "@material-ui/icons/LocationOn"; // import the mapbox css sheet import "mapbox-gl/dist/mapbox-gl.css"; +import { ReduxState } from "~store/index"; const MAPBOX_TOKEN = "pk.eyJ1IjoiYnVucWNvbW11bml0eSIsImEiOiJjam1uZnExcjgwcjEzM3ZwazhuaDBmNWw1In0.iKFjMHlXQ8PkvTagdi74-w"; @@ -18,8 +19,24 @@ const styles = { } }; -class GeoLocationMap extends React.Component { - state = { +interface IState { + show: boolean; + mapStyle: string; + mapStyleMode: string; + viewport: { + zoom: number; + pitch: number; + height: number; + width: number; + } +} + +interface IProps { + [key: string]: any; +} + +class GeoLocationMap extends React.Component & IProps> { + state: IState = { show: false, mapStyle: "mapbox://styles/bunqcommunity/cjmngc001153m2ss143lhxlzw", mapStyleMode: "none", @@ -42,6 +59,7 @@ class GeoLocationMap extends React.Component { } }); } + componentDidUpdate() { this.updateMap(); } @@ -139,7 +157,7 @@ class GeoLocationMap extends React.Component { } } -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return { theme: state.options.theme }; diff --git a/src/react/Components/GeoLocation/GeoLocationView.jsx b/src/components/GeoLocation/GeoLocationView.tsx similarity index 80% rename from src/react/Components/GeoLocation/GeoLocationView.jsx rename to src/components/GeoLocation/GeoLocationView.tsx index 4ea1e11c..a96831ac 100644 --- a/src/react/Components/GeoLocation/GeoLocationView.jsx +++ b/src/components/GeoLocation/GeoLocationView.tsx @@ -2,7 +2,7 @@ import React from "react"; import Dialog from "@material-ui/core/Dialog"; import Slide from "@material-ui/core/Slide"; import GeoLocationMap from "./GeoLocationMap"; -import TranslateButton from "../../Components/TranslationHelpers/Button"; +import TranslateButton from "~components/TranslationHelpers/Button"; const Transition = props => ; @@ -18,7 +18,21 @@ const styles = { } }; -class GeoLocationView extends React.PureComponent { +interface IState { + [key: string]: any; +} + +interface IProps { + [key: string]: any; +} + +class GeoLocationView extends React.PureComponent { + static defaultProps = { + visible: false + }; + + state: IState; + constructor(props, context) { super(props, context); this.state = {}; @@ -32,7 +46,7 @@ class GeoLocationView extends React.PureComponent { return (
- +
@@ -186,20 +197,20 @@ class PDFExportHelper extends React.PureComponent { } } -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return { + // @ts-ignore theme: state.options.theme, pdfSaveModeEnabled: state.application.pdf_save_mode_enabled }; }; -const mapDispatchToProps = (dispatch, ownProps) => { - const { BunqJSClient } = ownProps; +const mapDispatchToProps = (dispatch: AppDispatch) => { return { - openSnackbar: message => dispatch(openSnackbar(message)), + openSnackbar: message => dispatch(snackbarActions.open({ message })), - applicationSetPDFMode: enabled => dispatch(applicationSetPDFMode(enabled)), + applicationSetPDFMode: enabled => dispatch(applicationActions.setPdfMode(enabled)), setTheme: theme => dispatch(setTheme(theme)) }; diff --git a/src/react/Components/QR/AccountQRCode.jsx b/src/components/QR/AccountQRCode.tsx similarity index 69% rename from src/react/Components/QR/AccountQRCode.jsx rename to src/components/QR/AccountQRCode.tsx index 5a256bcf..5846df96 100644 --- a/src/react/Components/QR/AccountQRCode.jsx +++ b/src/components/QR/AccountQRCode.tsx @@ -1,5 +1,6 @@ -import React from "react"; +import React, { CSSProperties } from "react"; import { connect } from "react-redux"; +import { ReduxState } from "~store/index"; import QRCode from "./QRCode"; const styles = { @@ -10,7 +11,23 @@ const styles = { } }; -class AccountQRCode extends React.Component { +interface IState { + [key: string]: any; +} + +interface IProps { + style: CSSProperties; + [key: string]: any; +} + +class AccountQRCode extends React.Component & IProps> { + static defaultProps = { + accountId: false, + size: 195 + }; + + state: IState; + constructor(props, context) { super(props, context); this.state = {}; @@ -33,6 +50,7 @@ class AccountQRCode extends React.Component { if (currentAccount === false) return null; + // @ts-ignore const value = `https://qr.bunq.com/2/8/${currentAccount.avatar.anchor_uuid}`; return ( @@ -45,15 +63,10 @@ class AccountQRCode extends React.Component { } } -AccountQRCode.defaultProps = { - accountId: false, - size: 195 -}; - -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return { accounts: state.accounts.accounts, - selectedAccount: state.accounts.selected_account + selectedAccount: state.accounts.selectedAccount }; }; diff --git a/src/react/Components/QR/AccountQRFullscreen.jsx b/src/components/QR/AccountQRFullscreen.tsx similarity index 77% rename from src/react/Components/QR/AccountQRFullscreen.jsx rename to src/components/QR/AccountQRFullscreen.tsx index 22ece6ac..0b9cd829 100644 --- a/src/react/Components/QR/AccountQRFullscreen.jsx +++ b/src/components/QR/AccountQRFullscreen.tsx @@ -7,6 +7,7 @@ import Slide from "@material-ui/core/Slide"; import ListItemText from "@material-ui/core/ListItemText"; import ListItem from "@material-ui/core/ListItem"; import Avatar from "@material-ui/core/Avatar"; +import { ReduxState } from "~store/index"; const Transition = props => ; @@ -15,7 +16,7 @@ import LazyAttachmentImage from "../AttachmentImage/LazyAttachmentImage"; import QRSvg from "./QRSvg"; import QRCode from "./QRCode"; -import { formatIban } from "../../Functions/Utils"; +import { formatIban } from "~functions/Utils"; const styles = theme => ({ btnIcon: { @@ -48,8 +49,21 @@ const styles = theme => ({ } }); -class AccountQRFullscreen extends React.PureComponent { - state = { +interface IState { + open: boolean; +} + +interface IProps { + [key: string]: any; +} + +class AccountQRFullscreen extends React.PureComponent & IProps> { + static defaultProps = { + accountId: false, + mode: "ACCOUNT" + }; + + state: IState = { open: false }; @@ -76,6 +90,7 @@ class AccountQRFullscreen extends React.PureComponent { accountInfo = account; } }); + // @ts-ignore accountInfo.alias.map(alias => { if (alias.type === "IBAN") { IBAN = alias.value; @@ -83,42 +98,47 @@ class AccountQRFullscreen extends React.PureComponent { }); dialogContent = ( - + <> - + - + ); break; case "TEXT": dialogContent = ( - + <> - + ); break; case "HIDDEN": dialogContent = ( - + <> - + ); break; } return ( - + <> @@ -134,21 +154,17 @@ class AccountQRFullscreen extends React.PureComponent {
{dialogContent}
- + ); } } -AccountQRFullscreen.defaultProps = { - accountId: false, - mode: "ACCOUNT" -}; - -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return { accounts: state.accounts.accounts, - selectedAccount: state.accounts.selected_account + selectedAccount: state.accounts.selectedAccount }; }; +// @ts-ignore export default withStyles(styles)(connect(mapStateToProps)(AccountQRFullscreen)); diff --git a/src/react/Components/QR/QRCode.jsx b/src/components/QR/QRCode.tsx similarity index 64% rename from src/react/Components/QR/QRCode.jsx rename to src/components/QR/QRCode.tsx index 5bcf09dc..c4d4c490 100644 --- a/src/react/Components/QR/QRCode.jsx +++ b/src/components/QR/QRCode.tsx @@ -1,6 +1,5 @@ import React from "react"; import QRCodeReact from "qrcode.react"; -import PropTypes from "prop-types"; const styles = { clickable: { @@ -8,7 +7,20 @@ const styles = { } }; -class QRCode extends React.PureComponent { +interface IState { + [key: string]: any; +} + +interface IProps { + [key: string]: any; +} + +class QRCode extends React.PureComponent { + static defaultProps = { + size: 195, + style: {} + }; + render() { const { size, value, style, onClick, ...otherProps } = this.props; @@ -23,21 +35,9 @@ class QRCode extends React.PureComponent { value={value} style={style} onClick={qrOnClick} - style={onClick && styles.clickable} /> ); } } -QRCode.defaultProps = { - size: 195, - style: {} -}; - -QRCode.propTypes = { - value: PropTypes.string.isRequired, - size: PropTypes.number, - style: PropTypes.object -}; - export default QRCode; diff --git a/src/react/Components/QR/QRSvg.jsx b/src/components/QR/QRSvg.tsx similarity index 100% rename from src/react/Components/QR/QRSvg.jsx rename to src/components/QR/QRSvg.tsx diff --git a/src/react/Components/Queue/QueueHeaderIcon.jsx b/src/components/Queue/QueueHeaderIcon.tsx similarity index 80% rename from src/react/Components/Queue/QueueHeaderIcon.jsx rename to src/components/Queue/QueueHeaderIcon.tsx index 20f715e5..a739b49f 100644 --- a/src/react/Components/Queue/QueueHeaderIcon.jsx +++ b/src/components/Queue/QueueHeaderIcon.tsx @@ -6,11 +6,21 @@ import IconButton from "@material-ui/core/IconButton"; import SyncIcon from "@material-ui/icons/Sync"; -import { queueStartSync } from "../../Actions/queue"; +import { queueStartSync } from "~actions/queue"; +import { AppDispatch, ReduxState } from "~store/index"; -const styles = {}; +interface IState { + [key: string]: any; +} + +interface IProps { + [key: string]: any; +} + +class QueueHeaderIcon extends React.Component & ReturnType & IProps> { + state: IState; + updateDelay: null | number; -class QueueHeaderIcon extends React.Component { constructor(props, context) { super(props, context); this.state = { @@ -24,7 +34,7 @@ class QueueHeaderIcon extends React.Component { // throttle updates by 250ms to gather up rapid redux events if (nextProps.queueRequestCounter !== this.state.queueRequestCounter) { if (this.updateDelay) clearTimeout(this.updateDelay); - this.updateDelay = setTimeout(this.setQueueRequestCounter, 250); + this.updateDelay = +setTimeout(this.setQueueRequestCounter, 250); } if (nextProps.user !== this.props.user) return true; @@ -71,7 +81,7 @@ class QueueHeaderIcon extends React.Component { } } -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return { user: state.user.user, @@ -81,7 +91,7 @@ const mapStateToProps = state => { }; }; -const mapDispatchToProps = dispatch => { +const mapDispatchToProps = (dispatch: AppDispatch) => { return { queueStartSync: () => dispatch(queueStartSync()) }; diff --git a/src/react/Components/Queue/QueueManager.jsx b/src/components/Queue/QueueManager.tsx similarity index 89% rename from src/react/Components/Queue/QueueManager.jsx rename to src/components/Queue/QueueManager.tsx index 63b81929..055de2c9 100644 --- a/src/react/Components/Queue/QueueManager.jsx +++ b/src/components/Queue/QueueManager.tsx @@ -1,17 +1,19 @@ +import BunqJSClient from "@bunq-community/bunq-js-client"; import React from "react"; import { ipcRenderer } from "electron"; import { translate } from "react-i18next"; import { connect } from "react-redux"; -import Payment from "../../Models/Payment"; -import BunqMeTab from "../../Models/BunqMeTab"; -import RequestResponse from "../../Models/RequestResponse"; -import RequestInquiry from "../../Models/RequestInquiry"; -import RequestInquiryBatch from "../../Models/RequestInquiryBatch"; -import MasterCardAction from "../../Models/MasterCardAction"; - -import NotificationHelper from "../../Functions/NotificationHelper"; -import { connectGetPermissions } from "../../Functions/ConnectGetPermissions"; -import { paymentApiFilter } from "../../Functions/DataFilters"; +import { AppWindow } from "~app"; + +import Payment from "~models/Payment"; +import BunqMeTab from "~models/BunqMeTab"; +import RequestResponse from "~models/RequestResponse"; +import RequestInquiry from "~models/RequestInquiry"; +import RequestInquiryBatch from "~models/RequestInquiryBatch"; +import MasterCardAction from "~models/MasterCardAction"; +import NotificationHelper from "~functions/NotificationHelper"; +import { connectGetPermissions } from "~functions/ConnectGetPermissions"; +import { paymentApiFilter } from "~functions/DataFilters"; import { queueDecreaseRequestCounter, @@ -20,21 +22,38 @@ import { queueFinishedSync, queueResetSyncState, queueStartSync -} from "../../Actions/queue"; -import { paymentsSetInfo } from "../../Actions/payments"; -import { bunqMeTabsSetInfo } from "../../Actions/bunq_me_tabs"; -import { masterCardActionsSetInfo } from "../../Actions/master_card_actions"; -import { requestInquiriesSetInfo } from "../../Actions/request_inquiries"; -import { requestInquiryBatchesSetInfo } from "../../Actions/request_inquiry_batches"; -import { requestResponsesSetInfo } from "../../Actions/request_responses"; -import { shareInviteBankInquiriesSetInfo } from "../../Actions/share_invite_monetary_account_inquiries"; -import { shareInviteMonetaryAccountResponsesSetInfo } from "../../Actions/share_invite_monetary_account_responses"; -import { openSnackbar } from "../../Actions/snackbar"; +} from "~actions/queue"; +import { paymentsSetInfo } from "~actions/payments"; +import { masterCardActionsSetInfo } from "~actions/master_card_actions"; +import { requestInquiriesSetInfo } from "~actions/request_inquiries"; +import { requestInquiryBatchesSetInfo } from "~actions/request_inquiry_batches"; +import { requestResponsesSetInfo } from "~actions/request_responses"; +import { shareInviteBankInquiriesSetInfo } from "~actions/share_invite_monetary_account_inquiries"; +import { shareInviteMonetaryAccountResponsesSetInfo } from "~actions/share_invite_monetary_account_responses"; +import { actions as bunqMeTabsActions } from "~store/bunqMeTabs"; +import { AppDispatch, ReduxState } from "~store/index"; +import { actions as snackbarActions } from "~store/snackbar"; export const DEFAULT_EVENT_COUNT_LIMIT = 50; export const EVENT_TOTAL_LIMIT = 1000; -class QueueManager extends React.Component { +declare let window: AppWindow; + +interface IProps { + [key: string]: any; +} + +interface IState { + [key: string]: any; +} + +class QueueManager extends React.Component & ReturnType & IProps> { + state: IState; + delayedQueue: null | number; + delayedSetState: null | number; + automaticUpdateTimer: null | number; + automaticUpdateTimerDuration: null | number; + constructor(props, context) { super(props, context); this.state = { @@ -90,14 +109,14 @@ class QueueManager extends React.Component { // clear existing timeout if it exists if (this.delayedQueue) clearTimeout(this.delayedQueue); // delay the queue update - this.delayedQueue = setTimeout(() => this.triggerQueueUpdate(eventCount), 100); + this.delayedQueue = +setTimeout(() => this.triggerQueueUpdate(eventCount), 100); } } else { if (!queueLoading && prevProps.queueLoading === true && queueRequestCounter === 0) { // clear existing timeout if it exists if (this.delayedSetState) clearTimeout(this.delayedSetState); // delay the queue update - this.delayedSetState = setTimeout(this.pushQueueData, 100); + this.delayedSetState = +setTimeout(this.pushQueueData, 100); } } } @@ -199,9 +218,11 @@ class QueueManager extends React.Component { if (newestPayment) newerPaymentCount += payments.filter(payment => payment.id > newestPayment.id).length; const newestBunqMeTab = this.props.bunqMeTabs.find( + // @ts-ignore bunqMeTab => account.id === bunqMeTab.monetary_account_id ); if (newestBunqMeTab) + // @ts-ignore newerBunqMeTabsCount += bunqMeTabs.filter(bunqMeTab => bunqMeTab.id > newestBunqMeTab.id).length; const newestRequestResponse = this.props.requestResponses.find( @@ -355,7 +376,7 @@ class QueueManager extends React.Component { // only set if not already set if (!this.automaticUpdateTimer) { - this.automaticUpdateTimer = setInterval(() => { + this.automaticUpdateTimer = +setInterval(() => { this.props.queueStartSync(); }, this.props.automaticUpdateDuration * 1000); @@ -376,12 +397,13 @@ class QueueManager extends React.Component { }; paymentsUpdate = (user_id, account_id, olderId = false, eventCount = 200) => { - const { BunqJSClient } = this.props; + const BunqJSClient = window.BunqDesktopClient.BunqJSClient; const currentEventCount = eventCount > 200 ? 200 : eventCount; const nextEventCount = eventCount > 200 ? eventCount - 200 : 0; BunqJSClient.api.payment .list(user_id, account_id, { + // @ts-ignore older_id: olderId, count: currentEventCount }) @@ -430,13 +452,13 @@ class QueueManager extends React.Component { }; bunqMeTabsUpdate = (user_id, account_id, olderId = false, eventCount = 200) => { - const { BunqJSClient } = this.props; + const BunqJSClient = window.BunqDesktopClient.BunqJSClient; const currentEventCount = eventCount > 200 ? 200 : eventCount; const nextEventCount = eventCount > 200 ? eventCount - 200 : 0; BunqJSClient.api.bunqMeTabs .list(user_id, account_id, { - older_id: olderId, + older_id: +olderId, count: currentEventCount }) .then(bunqMeTabs => { @@ -484,13 +506,13 @@ class QueueManager extends React.Component { }; requestResponsesUpdate = (user_id, account_id, olderId = false, eventCount = 200) => { - const { BunqJSClient } = this.props; + const BunqJSClient = window.BunqDesktopClient.BunqJSClient; const currentEventCount = eventCount > 200 ? 200 : eventCount; const nextEventCount = eventCount > 200 ? eventCount - 200 : 0; BunqJSClient.api.requestResponse .list(user_id, account_id, { - older_id: olderId, + older_id: +olderId, count: currentEventCount }) .then(requestResponses => { @@ -539,8 +561,8 @@ class QueueManager extends React.Component { }); }; - requestInquiriesUpdate = (user_id, account_id, olderId = false, eventCount = 200) => { - const { BunqJSClient } = this.props; + requestInquiriesUpdate = (user_id, account_id, olderId: false | number = false, eventCount = 200) => { + const BunqJSClient = window.BunqDesktopClient.BunqJSClient; const currentEventCount = eventCount > 200 ? 200 : eventCount; const nextEventCount = eventCount > 200 ? eventCount - 200 : 0; @@ -596,13 +618,13 @@ class QueueManager extends React.Component { }; requestInquiryBatchesUpdate = (user_id, account_id, olderId = false, eventCount = 200) => { - const { BunqJSClient } = this.props; + const BunqJSClient = window.BunqDesktopClient.BunqJSClient; const currentEventCount = eventCount > 200 ? 200 : eventCount; const nextEventCount = eventCount > 200 ? eventCount - 200 : 0; BunqJSClient.api.requestInquiryBatch .list(user_id, account_id, { - older_id: olderId, + older_id: +olderId, count: currentEventCount }) .then(requestInquiryBatches => { @@ -655,13 +677,13 @@ class QueueManager extends React.Component { }; masterCardActionsUpdate = (user_id, account_id, olderId = false, eventCount = 200) => { - const { BunqJSClient } = this.props; + const BunqJSClient = window.BunqDesktopClient.BunqJSClient; const currentEventCount = eventCount > 200 ? 200 : eventCount; const nextEventCount = eventCount > 200 ? eventCount - 200 : 0; BunqJSClient.api.masterCardAction .list(user_id, account_id, { - older_id: olderId, + older_id: +olderId, count: currentEventCount }) .then(masterCardActions => { @@ -710,8 +732,8 @@ class QueueManager extends React.Component { }); }; - shareInviteBankInquiriesUpdate = (user_id, account_id, olderId = false, eventCount = 200) => { - const { BunqJSClient } = this.props; + shareInviteBankInquiriesUpdate = (user_id, account_id, olderId: boolean | number = false, eventCount = 200) => { + const BunqJSClient = window.BunqDesktopClient.BunqJSClient; if (olderId !== false) this.props.queueIncreaseRequestCounter(); @@ -719,12 +741,14 @@ class QueueManager extends React.Component { const nextEventCount = eventCount > 200 ? eventCount - 200 : 0; BunqJSClient.api.shareInviteMonetaryAccountInquiry .list(user_id, account_id, { - older_id: olderId, + older_id: +olderId, count: currentEventCount }) .then(shareInviteBankInquiries => { // more shareInviteBankInquiries can be loaded for this account + // @ts-ignore if (shareInviteBankInquiries.length === currentEventCount && nextEventCount > 0) { + // @ts-ignore const oldestShareInviteMonetaryAccountInquiryIndex = shareInviteBankInquiries.length - 1; const oldestShareInviteMonetaryAccountInquiry = shareInviteBankInquiries[oldestShareInviteMonetaryAccountInquiryIndex]; @@ -745,6 +769,7 @@ class QueueManager extends React.Component { // update the list for the account id currentShareInviteBankInquiries[account_id] = [ ...accountShareInviteBankInquiries, + // @ts-ignore ...shareInviteBankInquiries ]; @@ -763,7 +788,7 @@ class QueueManager extends React.Component { }; shareInviteMonetaryAccountResponsesUpdate = (user_id, eventCount = 200) => { - const { BunqJSClient } = this.props; + const BunqJSClient = window.BunqDesktopClient.BunqJSClient; BunqJSClient.api.shareInviteMonetaryAccountResponse .list(user_id, { @@ -789,20 +814,26 @@ class QueueManager extends React.Component { } } -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return { user: state.user.user, userLoading: state.user.loading, + // @ts-ignore limitedPermissions: state.user.limited_permissions, accounts: state.accounts.accounts, accountsLoading: state.accounts.loading, + // @ts-ignore syncOnStartup: state.options.sync_on_startup, + // @ts-ignore eventCountLimit: state.options.event_count_limit, + // @ts-ignore automaticUpdateEnabled: state.options.automatic_update_enabled, + // @ts-ignore automaticUpdateSendNotification: state.options.automatic_update_send_notification, + // @ts-ignore automaticUpdateDuration: state.options.automatic_update_duration, queueRequestCounter: state.queue.request_counter, @@ -810,21 +841,20 @@ const mapStateToProps = state => { queueLoading: state.queue.loading, payments: state.payments.payments, - bunqMeTabs: state.bunq_me_tabs.bunq_me_tabs, + bunqMeTabs: state.bunqMeTabs.bunq_me_tabs, masterCardActions: state.master_card_actions.master_card_actions, requestInquiries: state.request_inquiries.request_inquiries, requestInquiryBatches: state.request_inquiry_batches.request_inquiry_batches, requestResponses: state.request_responses.request_responses, shareInviteBankInquiries: state.share_invite_monetary_account_inquiries.share_invite_monetary_account_inquiries, shareInviteMonetaryAccountResponses: - state.share_invite_monetary_account_responses.share_invite_monetary_account_responses + state.share_invite_monetary_account_responses.share_invite_monetary_account_responses }; }; -const mapDispatchToProps = (dispatch, ownProps) => { - const { BunqJSClient } = ownProps; +const mapDispatchToProps = (dispatch: AppDispatch) => { return { - openSnackbar: (message, duration = 4000) => dispatch(openSnackbar(message, duration)), + openSnackbar: (message, duration = 4000) => dispatch(snackbarActions.open({ message, duration })), queueDecreaseRequestCounter: () => dispatch(queueDecreaseRequestCounter()), queueIncreaseRequestCounter: () => dispatch(queueIncreaseRequestCounter()), @@ -833,21 +863,25 @@ const mapDispatchToProps = (dispatch, ownProps) => { queueFinishedSync: () => dispatch(queueFinishedSync()), queueResetSyncState: () => dispatch(queueResetSyncState()), - paymentsSetInfo: (payments, accountId) => dispatch(paymentsSetInfo(payments, accountId, false, BunqJSClient)), + paymentsSetInfo: (payments, accountId) => dispatch(paymentsSetInfo(payments, accountId, false)), bunqMeTabsSetInfo: (bunqMeTabs, accountId) => - dispatch(bunqMeTabsSetInfo(bunqMeTabs, accountId, false, BunqJSClient)), + dispatch(bunqMeTabsActions.setInfo({ + bunqMeTabs, + account_id: accountId, + resetOldItems: false, + })), masterCardActionsSetInfo: (masterCardActions, accountId) => - dispatch(masterCardActionsSetInfo(masterCardActions, accountId, false, BunqJSClient)), + dispatch(masterCardActionsSetInfo(masterCardActions, accountId, false)), requestInquiriesSetInfo: (requestInquiries, accountId) => - dispatch(requestInquiriesSetInfo(requestInquiries, accountId, false, BunqJSClient)), + dispatch(requestInquiriesSetInfo(requestInquiries, accountId, false)), requestInquiryBatchesSetInfo: (requestInquiryBatches, accountId) => - dispatch(requestInquiryBatchesSetInfo(requestInquiryBatches, accountId, false, BunqJSClient)), + dispatch(requestInquiryBatchesSetInfo(requestInquiryBatches, accountId, false)), requestResponsesSetInfo: (requestResponses, accountId) => - dispatch(requestResponsesSetInfo(requestResponses, accountId, false, BunqJSClient)), + dispatch(requestResponsesSetInfo(requestResponses, accountId, false)), shareInviteBankInquiriesSetInfo: (shareInviteBankInquiries, accountId) => - dispatch(shareInviteBankInquiriesSetInfo(shareInviteBankInquiries, accountId, BunqJSClient)), + dispatch(shareInviteBankInquiriesSetInfo(shareInviteBankInquiries, accountId)), shareInviteMonetaryAccountResponsesSetInfo: shareInviteMonetaryAccountResponses => - dispatch(shareInviteMonetaryAccountResponsesSetInfo(shareInviteMonetaryAccountResponses, BunqJSClient)) + dispatch(shareInviteMonetaryAccountResponsesSetInfo(shareInviteMonetaryAccountResponses)) }; }; diff --git a/src/react/Components/Queue/QueueSidebarListItem.jsx b/src/components/Queue/QueueSidebarListItem.tsx similarity index 84% rename from src/react/Components/Queue/QueueSidebarListItem.jsx rename to src/components/Queue/QueueSidebarListItem.tsx index 977d9fce..14a727d5 100644 --- a/src/react/Components/Queue/QueueSidebarListItem.jsx +++ b/src/components/Queue/QueueSidebarListItem.tsx @@ -7,7 +7,8 @@ import LinearProgress from "@material-ui/core/LinearProgress"; import SyncIcon from "@material-ui/icons/Sync"; -import { queueStartSync } from "../../Actions/queue"; +import { queueStartSync } from "~actions/queue"; +import { AppDispatch, ReduxState } from "~store/index"; const styles = { listItemText: { @@ -15,7 +16,18 @@ const styles = { } }; -class QueueSidebarListItem extends React.Component { +interface IState { + [key: string]: any; +} + +interface IProps { + [key: string]: any; +} + +class QueueSidebarListItem extends React.Component & ReturnType & IProps> { + state: IState; + updateDelay: null | number; + constructor(props, context) { super(props, context); this.state = { @@ -33,7 +45,7 @@ class QueueSidebarListItem extends React.Component { nextProps.queueMaxRequestCounter !== this.state.queueMaxRequestCounter ) { if (this.updateDelay) clearTimeout(this.updateDelay); - this.updateDelay = setTimeout(this.setQueueRequestCounter, 250); + this.updateDelay = +setTimeout(this.setQueueRequestCounter, 250); } if (nextProps.queueLoading !== this.props.queueLoading) return true; @@ -71,7 +83,7 @@ class QueueSidebarListItem extends React.Component { } const clickDisabled = queueLoading || queueTriggerSync; - const listItemProps = { + const listItemProps: any = { key: "listItem" }; @@ -81,7 +93,7 @@ class QueueSidebarListItem extends React.Component { } return ( - + <> @@ -94,12 +106,12 @@ class QueueSidebarListItem extends React.Component { /> {queueLoading && } - + ); } } -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return { queueMaxRequestCounter: state.queue.max_request_counter, queueRequestCounter: state.queue.request_counter, @@ -108,7 +120,7 @@ const mapStateToProps = state => { }; }; -const mapDispatchToProps = dispatch => { +const mapDispatchToProps = (dispatch: AppDispatch) => { return { queueStartSync: () => dispatch(queueStartSync()) }; diff --git a/src/react/Components/ReactJsonWrapper.jsx b/src/components/ReactJsonWrapper.tsx similarity index 96% rename from src/react/Components/ReactJsonWrapper.jsx rename to src/components/ReactJsonWrapper.tsx index 7967618f..f323656a 100644 --- a/src/react/Components/ReactJsonWrapper.jsx +++ b/src/components/ReactJsonWrapper.tsx @@ -9,6 +9,7 @@ export default ({ style, data, name = null, ...rest }) => { name={name} theme="monokai" iconStyle="square" + // @ts-ignore enableEdit={false} enableAdd={false} enabledDelete={false} diff --git a/src/react/Components/ReduxForm/Fields/renderAccountsPicker.jsx b/src/components/ReduxForm/Fields/renderAccountsPicker.tsx similarity index 91% rename from src/react/Components/ReduxForm/Fields/renderAccountsPicker.jsx rename to src/components/ReduxForm/Fields/renderAccountsPicker.tsx index 9e973dd0..d399f009 100644 --- a/src/react/Components/ReduxForm/Fields/renderAccountsPicker.jsx +++ b/src/components/ReduxForm/Fields/renderAccountsPicker.tsx @@ -3,10 +3,15 @@ import { connect } from "react-redux"; import { translate } from "react-i18next"; import Grid from "@material-ui/core/Grid"; import Typography from "@material-ui/core/Typography"; +import { ReduxState } from "~store/index"; import AccountListItemChip from "../../AccountList/AccountListItemChip"; -const renderAccountsPicker = ({ t, i18n, tReady, input, label, meta: { error }, accounts, ...otherProps }) => { +interface IProps { + [key: string]: any; +} + +const renderAccountsPicker = ({ t, i18n, tReady, input, label, meta: { error }, accounts, ...otherProps }: ReturnType & IProps) => { const inputValue = input.value; const inputOnChange = input.onChange; @@ -73,7 +78,7 @@ const renderAccountsPicker = ({ t, i18n, tReady, input, label, meta: { error }, ); }; -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return { accounts: state.accounts.accounts }; diff --git a/src/react/Components/ReduxForm/Fields/renderAmountField.jsx b/src/components/ReduxForm/Fields/renderAmountField.tsx similarity index 98% rename from src/react/Components/ReduxForm/Fields/renderAmountField.jsx rename to src/components/ReduxForm/Fields/renderAmountField.tsx index d890e112..fa023852 100644 --- a/src/react/Components/ReduxForm/Fields/renderAmountField.jsx +++ b/src/components/ReduxForm/Fields/renderAmountField.tsx @@ -37,7 +37,6 @@ const renderTextField = ({ t, i18n, tReady, input, formStyle = {}, label, meta: diff --git a/src/react/Components/ReduxForm/Fields/renderColorPickerGradient.jsx b/src/components/ReduxForm/Fields/renderColorPickerGradient.tsx similarity index 100% rename from src/react/Components/ReduxForm/Fields/renderColorPickerGradient.jsx rename to src/components/ReduxForm/Fields/renderColorPickerGradient.tsx diff --git a/src/react/Components/ReduxForm/Fields/renderDateTimePicker.jsx b/src/components/ReduxForm/Fields/renderDateTimePicker.tsx similarity index 92% rename from src/react/Components/ReduxForm/Fields/renderDateTimePicker.jsx rename to src/components/ReduxForm/Fields/renderDateTimePicker.tsx index 6339480b..97ed9171 100644 --- a/src/react/Components/ReduxForm/Fields/renderDateTimePicker.jsx +++ b/src/components/ReduxForm/Fields/renderDateTimePicker.tsx @@ -3,7 +3,7 @@ import { translate } from "react-i18next"; import DateTimePicker from "material-ui-pickers/DateTimePicker"; import Typography from "@material-ui/core/Typography"; -import { getUTCDate, UTCDateToLocalDate } from "../../../Functions/Utils"; +import { getUTCDate, UTCDateToLocalDate } from "~functions/Utils"; const styles = { dateTimePicker: {} @@ -35,7 +35,7 @@ const renderDateTimePicker = ({ t, i18n, tReady, input, label, meta: { touched, }; return ( - + <> {errorLabel} - + ); }; diff --git a/src/react/Components/ReduxForm/Fields/renderTextField.jsx b/src/components/ReduxForm/Fields/renderTextField.tsx similarity index 100% rename from src/react/Components/ReduxForm/Fields/renderTextField.jsx rename to src/components/ReduxForm/Fields/renderTextField.tsx diff --git a/src/react/Components/ReduxForm/Validators.js b/src/components/ReduxForm/Validators.ts similarity index 96% rename from src/react/Components/ReduxForm/Validators.js rename to src/components/ReduxForm/Validators.ts index 9fcc5222..b030b07a 100644 --- a/src/react/Components/ReduxForm/Validators.js +++ b/src/components/ReduxForm/Validators.ts @@ -1,5 +1,5 @@ import EmailValidator from "email-validator"; -import { isValidPhonenumber } from "../../Functions/PhoneLib"; +import { isValidPhonenumber } from "~functions/PhoneLib"; const t = window.t; diff --git a/src/react/Routes.jsx b/src/components/Routes.tsx similarity index 69% rename from src/react/Routes.jsx rename to src/components/Routes.tsx index d8c7b17f..ffae3099 100644 --- a/src/react/Routes.jsx +++ b/src/components/Routes.tsx @@ -1,14 +1,14 @@ import React from "react"; import { Route, Switch } from "react-router-dom"; -import PrivateRoute from "./Components/Routing/PrivateRoute"; -import PublicRoute from "./Components/Routing/PublicRoute"; -import CL from "./Components/CodeSplitting/ComponentLoader"; +import PrivateRoute from "~components/Routing/PrivateRoute"; +import PublicRoute from "~components/Routing/PublicRoute"; +import CL from "~components/CodeSplitting/ComponentLoader"; -import Dashboard from "./Pages/Dashboard/Dashboard"; -import NotFound from "./Pages/NotFound"; -import LoginPassword from "./Pages/LoginPassword"; -import Login from "./Pages/Login/Login"; +import Dashboard from "~pages/Dashboard/Dashboard"; +import NotFound from "~pages/NotFound"; +import LoginPassword from "~pages/LoginPassword"; +import Login from "~pages/Login/Login"; const privateRoutes = [ /** @@ -21,28 +21,28 @@ const privateRoutes = [ }, { path: "/pay", - component: CL(() => import(/* webpackChunkName: "pay" */ "./Pages/Pay/Pay")) + component: CL(() => import(/* webpackChunkName: "pay" */ "~pages/Pay/Pay")) }, { path: "/request", - component: CL(() => import(/* webpackChunkName: "requestinquiry" */ "./Pages/RequestInquiry/RequestInquiry")) + component: CL(() => import(/* webpackChunkName: "requestinquiry" */ "~pages/RequestInquiry/RequestInquiry")) }, { path: "/bunqme-tab", - component: CL(() => import(/* webpackChunkName: "bunqmetab" */ "./Pages/BunqMeTab/BunqMeTab")) + component: CL(() => import(/* webpackChunkName: "bunqmetab" */ "~pages/BunqMeTab/BunqMeTab")) }, { path: "/bunqme-personal", - component: CL(() => import(/* webpackChunkName: "bunqmepersonal" */ "./Pages/BunqMePersonal/BunqMePersonal")) + component: CL(() => import(/* webpackChunkName: "bunqmepersonal" */ "~pages/BunqMePersonal/BunqMePersonal")) }, { path: "/cards", - component: CL(() => import(/* webpackChunkName: "cards" */ "./Pages/Cards/Cards")) + component: CL(() => import(/* webpackChunkName: "cards" */ "~pages/Cards/Cards")) }, { path: "/scheduled-payments", component: CL(() => - import(/* webpackChunkName: "scheduled_payments" */ "./Pages/ScheduledPayments/ScheduledPayments") + import(/* webpackChunkName: "scheduled_payments" */ "~pages/ScheduledPayments/ScheduledPayments") ) }, /** @@ -50,42 +50,42 @@ const privateRoutes = [ */ { path: "/exports", - component: CL(() => import(/* webpackChunkName: "exports" */ "./Pages/Exports")) + component: CL(() => import(/* webpackChunkName: "exports" */ "~pages/Exports")) }, { path: "/pending-payments", - component: CL(() => import(/* webpackChunkName: "pendingPayments" */ "./Pages/PendingPayments/PendingPayments")) + component: CL(() => import(/* webpackChunkName: "pendingPayments" */ "~pages/PendingPayments/PendingPayments")) }, { path: "/stats", - component: CL(() => import(/* webpackChunkName: "stats" */ "./Pages/Stats/Stats")) + component: CL(() => import(/* webpackChunkName: "stats" */ "~pages/Stats/Stats")) }, { path: "/contacts", - component: CL(() => import(/* webpackChunkName: "contacts" */ "./Pages/Contacts/Contacts")) + component: CL(() => import(/* webpackChunkName: "contacts" */ "~pages/Contacts/Contacts")) }, { path: "/category-dashboard", component: CL(() => - import(/* webpackChunkName: "category_dashboard" */ "./Pages/CategoryDashboard/CategoryDashboard") + import(/* webpackChunkName: "category_dashboard" */ "~pages/CategoryDashboard/CategoryDashboard") ) }, { path: "/rules-dashboard", - component: CL(() => import(/* webpackChunkName: "rules_dashboard" */ "./Pages/RuleDashboard/RuleDashboard")) + component: CL(() => import(/* webpackChunkName: "rules_dashboard" */ "~pages/RuleDashboard/RuleDashboard")) }, { path: "/rule-page/:ruleId", - component: CL(() => import(/* webpackChunkName: "rules_page" */ "./Pages/RulePage/RulePage")) + component: CL(() => import(/* webpackChunkName: "rules_page" */ "~pages/RulePage/RulePage")) }, { path: "/savings-goals", - component: CL(() => import(/* webpackChunkName: "savings_goals" */ "./Pages/SavingsGoals/SavingsGoals")) + component: CL(() => import(/* webpackChunkName: "savings_goals" */ "~pages/SavingsGoals/SavingsGoals")) }, { path: "/savings-goal-page/:savingsGoalId", component: CL(() => - import(/* webpackChunkName: "savings_goal_page" */ "./Pages/SavingsGoalPage/SavingsGoalPage") + import(/* webpackChunkName: "savings_goal_page" */ "~pages/SavingsGoalPage/SavingsGoalPage") ) }, /** @@ -93,40 +93,40 @@ const privateRoutes = [ */ { path: "/payment/:paymentId/:accountId?", - component: CL(() => import(/* webpackChunkName: "paymentinfo" */ "./Pages/PaymentInfo")) + component: CL(() => import(/* webpackChunkName: "paymentinfo" */ "~pages/PaymentInfo")) }, { path: "/request-response-info/:requestResponseId/:accountId?", component: CL(() => - import(/* webpackChunkName: "requestresponseinfo" */ "./Pages/RequestResponseInfo/RequestResponseInfo") + import(/* webpackChunkName: "requestresponseinfo" */ "~pages/RequestResponseInfo/RequestResponseInfo") ) }, { path: "/request-inquiry-info/:requestInquiryId/:accountId?", - component: CL(() => import(/* webpackChunkName: "requestinquiryinfo" */ "./Pages/RequestInquiryInfo")) + component: CL(() => import(/* webpackChunkName: "requestinquiryinfo" */ "~pages/RequestInquiryInfo")) }, { path: "/mastercard-action-info/:masterCardActionId/:accountId?", - component: CL(() => import(/* webpackChunkName: "mastercardactioninfo" */ "./Pages/MasterCardActionInfo")) + component: CL(() => import(/* webpackChunkName: "mastercardactioninfo" */ "~pages/MasterCardActionInfo")) }, /** * Monetary account info and settings pages */ { path: "/account-info/:accountId", - component: CL(() => import(/* webpackChunkName: "accountinfo" */ "./Pages/AccountInfo")) + component: CL(() => import(/* webpackChunkName: "accountinfo" */ "~pages/AccountInfo")) }, { path: "/new-account", - component: CL(() => import(/* webpackChunkName: "addaccount" */ "./Pages/AddAccount")) + component: CL(() => import(/* webpackChunkName: "addaccount" */ "~pages/AddAccount")) }, { path: "/connect/:accountId", - component: CL(() => import(/* webpackChunkName: "connect" */ "./Pages/Connect/Connect")) + component: CL(() => import(/* webpackChunkName: "connect" */ "~pages/Connect/Connect")) }, { path: "/profile", - component: CL(() => import(/* webpackChunkName: "profile" */ "./Pages/Profile/Profile")) + component: CL(() => import(/* webpackChunkName: "profile" */ "~pages/Profile/Profile")) } ]; @@ -134,19 +134,19 @@ const privateRoutes = [ const standardRoutes = [ { path: "/settings", - component: CL(() => import(/* webpackChunkName: "settings" */ "./Pages/Settings/Settings")) + component: CL(() => import(/* webpackChunkName: "settings" */ "~pages/Settings/Settings")) }, { path: "/application-info", - component: CL(() => import(/* webpackChunkName: "applicationinfo" */ "./Pages/ApplicationInfo")) + component: CL(() => import(/* webpackChunkName: "applicationinfo" */ "~pages/ApplicationInfo")) }, { path: "/debug-page", - component: CL(() => import(/* webpackChunkName: "debug" */ "./Pages/DebugPage")) + component: CL(() => import(/* webpackChunkName: "debug" */ "~pages/DebugPage")) }, { path: "/disclaimer", - component: CL(() => import(/* webpackChunkName: "disclaimer" */ "./Pages/Disclaimer")) + component: CL(() => import(/* webpackChunkName: "disclaimer" */ "~pages/Disclaimer")) }, { path: "/login", @@ -154,7 +154,7 @@ const standardRoutes = [ }, { path: "/switch-api-keys", - component: CL(() => import(/* webpackChunkName: "switch_api_keys" */ "./Pages/SwitchApiKeys")) + component: CL(() => import(/* webpackChunkName: "switch_api_keys" */ "~pages/SwitchApiKeys")) } ]; @@ -166,19 +166,34 @@ const publicRoutes = [ } ]; -// router react component -export default class Routes extends React.Component { +interface IState { + [key: string]: any; +} + +interface IProps { + apiKey: false | string; + userType: false | string; + derivedPassword: false | string; + childProps: { + [key: string]: any; + }; +} + +export default class Routes extends React.Component { + state: IState; + constructor(props, context) { super(props, context); this.state = {}; } render() { - const privateRouteComponents = privateRoutes.map(route => { + const privateRouteComponents = privateRoutes.map((route, idx) => { const { component, ...props } = route; const Component = route.component; return ( ); }); - const stantardRouteComponents = standardRoutes.map(route => { + const stantardRouteComponents = standardRoutes.map((route, idx) => { const { component, ...props } = route; const Component = route.component; - return } {...props} />; + // @ts-ignore + return } {...props} />; }); - const publicRouteComponents = publicRoutes.map(route => { + const publicRouteComponents = publicRoutes.map((route, idx) => { const { component, ...props } = route; const Component = route.component; return ( } {...props} @@ -212,8 +229,11 @@ export default class Routes extends React.Component { {privateRouteComponents} {stantardRouteComponents} {publicRouteComponents} - - } /> + } /> )} /> diff --git a/src/react/Components/Routing/NavLink.jsx b/src/components/Routing/NavLink.tsx similarity index 57% rename from src/react/Components/Routing/NavLink.jsx rename to src/components/Routing/NavLink.tsx index 07330642..fb3462ea 100644 --- a/src/react/Components/Routing/NavLink.jsx +++ b/src/components/Routing/NavLink.tsx @@ -1,8 +1,9 @@ -// modules/NavLink.js import React from "react"; import { NavLink } from "react-router-dom"; -export default class NavLinkHelper extends React.Component { +type IProps = React.ComponentProps; + +export default class NavLinkHelper extends React.Component { render() { return ; } diff --git a/src/react/Components/Routing/PrivateRoute.jsx b/src/components/Routing/PrivateRoute.tsx similarity index 94% rename from src/react/Components/Routing/PrivateRoute.jsx rename to src/components/Routing/PrivateRoute.tsx index 432778c7..325849ce 100644 --- a/src/react/Components/Routing/PrivateRoute.jsx +++ b/src/components/Routing/PrivateRoute.tsx @@ -1,6 +1,10 @@ import React from "react"; import { Redirect, Route } from "react-router-dom"; +interface IProps { + [key: string]: any; +} + export default ({ component: Component, apiKey, @@ -9,7 +13,7 @@ export default ({ ignoreApiKey = false, ignoreUserType = false, ...rest -}) => { +}: IProps) => { const componentHandler = rest.render ? rest.render : props => Component; // no user selected or no derived password set diff --git a/src/react/Components/Routing/PublicRoute.jsx b/src/components/Routing/PublicRoute.tsx similarity index 92% rename from src/react/Components/Routing/PublicRoute.jsx rename to src/components/Routing/PublicRoute.tsx index 5b87aa2a..8db62049 100644 --- a/src/react/Components/Routing/PublicRoute.jsx +++ b/src/components/Routing/PublicRoute.tsx @@ -1,7 +1,11 @@ import React from "react"; import { Redirect, Route } from "react-router-dom"; -export default ({ component: Component, derivedPassword, ...rest }) => { +interface IProps { + [key: string]: any; +} + +export default ({ component: Component, derivedPassword, ...rest }: IProps) => { const componentHandler = rest.render ? rest.render : props => Component; // no user selected diff --git a/src/react/Components/RuleCollectionChecker.jsx b/src/components/RuleCollectionChecker.tsx similarity index 59% rename from src/react/Components/RuleCollectionChecker.jsx rename to src/components/RuleCollectionChecker.tsx index 8133e7f2..446fb822 100644 --- a/src/react/Components/RuleCollectionChecker.jsx +++ b/src/components/RuleCollectionChecker.tsx @@ -1,24 +1,44 @@ import React from "react"; -import PropTypes from "prop-types"; import { connect } from "react-redux"; +import Payment from "~models/Payment"; +import RequestInquiry from "~models/RequestInquiry"; -import { setCategoryConnectionMultiple } from "../Actions/categories"; -import { setCategoryRule } from "../Actions/category_rules"; +import { actions as categoriesActions } from "~store/categories"; +import { actions as categoryRulesActions } from "~store/categoryRules"; +import { AppDispatch, ReduxState } from "~store/index"; +import RuleCollection from "~models/RuleCollection"; // import typed worker -const RuleCollectionCheckWorker = require("worker-loader!../WebWorkers/rule_collection_check.worker.js"); +// TODO: find a way to support Jest +let RuleCollectionCheckWorker: any; +if (!process.env.JEST) { + RuleCollectionCheckWorker = require("worker-loader!../webworkers/rule_collection_check.worker.js"); +} + +interface IProps { + [key: string]: any; +} + +interface IState { + [key: string]: any; +} + +class RuleCollectionChecker extends React.Component & ReturnType & IProps> { + state: IState; + worker: any; -class RuleCollectionChecker extends React.Component { constructor(props, context) { super(props, context); this.state = {}; - this.worker = new RuleCollectionCheckWorker(); - this.worker.onmessage = this.handleWorkerEvent; + if (RuleCollectionCheckWorker) { + this.worker = new RuleCollectionCheckWorker(); + this.worker.onmessage = this.handleWorkerEvent; + } } componentWillUnmount() { - this.worker.terminate(); + this.worker?.terminate().then(); } componentDidUpdate(oldProps) { @@ -34,7 +54,8 @@ class RuleCollectionChecker extends React.Component { handleWorkerEvent = eventResults => { const events = eventResults.data.result; const ruleCollectionId = eventResults.data.ruleCollectionId; - const ruleCollection = this.props.categoryRules[ruleCollectionId]; + const ruleCollection = new RuleCollection(); + ruleCollection.fromObject(this.props.categoryRules[ruleCollectionId]); // go through all events const newCategoryConnections = []; @@ -58,15 +79,17 @@ class RuleCollectionChecker extends React.Component { triggerWorkerEvent = () => { // use json format - const payments = this.props.payments.map(item => item.toJSON()); - const requestInquiries = this.props.requestInquiries.map(item => item.toJSON()); + const payments = this.props.payments.map(item => Payment.fromPlainObject(item).toJSON()); + const requestInquiries = this.props.requestInquiries.map(item => RequestInquiry.fromPlainObject(item).toJSON()); const requestResponses = this.props.requestResponses.map(item => item.toJSON()); const masterCardActions = this.props.masterCardActions.map(item => item.toJSON()); - const bunqMeTabs = this.props.bunqMeTabs.map(item => item.toJSON()); + const bunqMeTabs = this.props.bunqMeTabs.map(item => JSON.stringify(item)); // get results for all our rule collections Object.keys(this.props.categoryRules).forEach(categoryRuleId => { - const ruleCollection = this.props.categoryRules[categoryRuleId]; + const ruleCollection = new RuleCollection(); + ruleCollection.fromObject(this.props.categoryRules[categoryRuleId]); + if (ruleCollection && ruleCollection.isEnabled()) { this.worker.postMessage({ ruleCollection: ruleCollection, @@ -85,29 +108,25 @@ class RuleCollectionChecker extends React.Component { } } -RuleCollectionChecker.propTypes = { - updateToggle: PropTypes.bool.isRequired -}; - -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return { categories: state.categories.categories, - categoryRules: state.category_rules.category_rules, + categoryRules: state.categoryRules.category_rules, queueFinishedSync: state.queue.finished_queue, requestResponses: state.request_responses.request_responses, payments: state.payments.payments, - bunqMeTabs: state.bunq_me_tabs.bunq_me_tabs, + bunqMeTabs: state.bunqMeTabs.bunq_me_tabs, masterCardActions: state.master_card_actions.master_card_actions, requestInquiries: state.request_inquiries.request_inquiries }; }; -const mapDispatchToProps = dispatch => { +const mapDispatchToProps = (dispatch: AppDispatch) => { return { - setCategoryConnectionMultiple: (...params) => dispatch(setCategoryConnectionMultiple(...params)), - setCategoryRule: rule_collection => dispatch(setCategoryRule(rule_collection)) + setCategoryConnectionMultiple: (...params) => dispatch(categoriesActions.setCategoryConnectionMultiple(...params)), + setCategoryRule: rule_collection => dispatch(categoryRulesActions.setRule(rule_collection)) }; }; diff --git a/src/react/Components/SavingsGoals/Helpers.js b/src/components/SavingsGoals/Helpers.ts similarity index 80% rename from src/react/Components/SavingsGoals/Helpers.js rename to src/components/SavingsGoals/Helpers.ts index 835ad0b6..8279da56 100644 --- a/src/react/Components/SavingsGoals/Helpers.js +++ b/src/components/SavingsGoals/Helpers.ts @@ -1,6 +1,5 @@ -import { connectGetBudget } from "../../Functions/ConnectGetPermissions"; -import { filterShareInviteMonetaryAccountResponses } from "../../Functions/DataFilters"; -import { formatMoney } from "../../Functions/Utils"; +import { connectGetBudget } from "~functions/ConnectGetPermissions"; +import { filterShareInviteMonetaryAccountResponses } from "~functions/DataFilters"; export const calculateTotalBalance = (accounts, accountIds, shareInviteMonetaryAccountResponses = []) => { return accounts.reduce((accumulator, account) => { @@ -16,6 +15,7 @@ export const calculateTotalBalance = (accounts, accountIds, shareInviteMonetaryA if (filteredResponses.length > 0) { const connectBudget = connectGetBudget(filteredResponses); if (connectBudget) { + // @ts-ignore accountBalance = parseFloat(connectBudget); } } diff --git a/src/react/Components/SavingsGoals/SavingsGoalListItem.jsx b/src/components/SavingsGoals/SavingsGoalListItem.tsx similarity index 90% rename from src/react/Components/SavingsGoals/SavingsGoalListItem.jsx rename to src/components/SavingsGoals/SavingsGoalListItem.tsx index 837a8dcc..6c9337bb 100644 --- a/src/react/Components/SavingsGoals/SavingsGoalListItem.jsx +++ b/src/components/SavingsGoals/SavingsGoalListItem.tsx @@ -1,7 +1,7 @@ -import React from "react"; +import React, { CSSProperties } from "react"; import Grid from "@material-ui/core/Grid"; import Paper from "@material-ui/core/Paper"; -import ListItem from "@material-ui/core/ListItem"; +import OriginalListItem from "@material-ui/core/ListItem"; import ListItemText from "@material-ui/core/ListItemText"; import ListItemIcon from "@material-ui/core/ListItemIcon"; import Typography from "@material-ui/core/Typography"; @@ -12,7 +12,9 @@ import ExpiredIcon from "@material-ui/icons/TimerOff"; import LinearProgressCustom from "../LinearProgress"; import NavLink from "../Routing/NavLink"; -import { formatMoney, humanReadableDate } from "../../Functions/Utils"; +import { formatMoney, humanReadableDate } from "~functions/Utils"; + +const ListItem: any = OriginalListItem; const styles = { listItem: { @@ -58,7 +60,7 @@ export default props => { const minusAmount = percentage < 10 ? 10 : 15; const progressLabelStyle = { ...styles.progressLabel, left: `calc(${percentage}% - ${minusAmount}px` }; - let listItemProps = { + let listItemProps: any = { button: true, component: NavLink, to: `/savings-goal-page/${savingsGoal.id}` @@ -73,7 +75,7 @@ export default props => { - + {savingsGoal.title} {savingsGoal.description && ( @@ -81,13 +83,13 @@ export default props => { )} - + {savedAmountText} - + {startAmountText} @@ -99,21 +101,21 @@ export default props => { /> - + {endAmountText} {percentage < 100 && ( - + <> - -
+ +
{percentage.toFixed(1)}%
- + )} diff --git a/src/react/Components/SavingsGoals/SavingsGoalListItemWrapper.jsx b/src/components/SavingsGoals/SavingsGoalListItemWrapper.tsx similarity index 78% rename from src/react/Components/SavingsGoals/SavingsGoalListItemWrapper.jsx rename to src/components/SavingsGoals/SavingsGoalListItemWrapper.tsx index e85eb035..d2fcb68b 100644 --- a/src/react/Components/SavingsGoals/SavingsGoalListItemWrapper.jsx +++ b/src/components/SavingsGoals/SavingsGoalListItemWrapper.tsx @@ -1,13 +1,17 @@ import React from "react"; -import PropTypes from "prop-types"; import { connect } from "react-redux"; +import { ReduxState } from "~store/index"; import SavingsGoalListItem from "./SavingsGoalListItem"; import SavingsGoalSmallListItem from "./SavingsGoalSmallListItem"; -import SavingsGoal from "../../Models/SavingsGoal"; +import SavingsGoal from "~models/SavingsGoal"; -const SavingsGoalListItemWrapper = props => { +interface IProps { + [key: string]: any; +} + +const SavingsGoalListItemWrapper = (props: ReturnType & IProps) => { const { t, type, @@ -18,7 +22,7 @@ const SavingsGoalListItemWrapper = props => { ...restProps } = props; - switch (type) { + switch (type ?? "regular") { case "regular": return ( { return null; }; -SavingsGoalListItemWrapper.defaultProps = { - type: "regular" -}; - -SavingsGoalListItemWrapper.propTypes = { - t: PropTypes.any.isRequired, - type: PropTypes.string.isRequired, - savingsGoal: PropTypes.instanceOf(SavingsGoal) -}; - -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return { accounts: state.accounts.accounts, diff --git a/src/react/Components/SavingsGoals/SavingsGoalSmallListItem.jsx b/src/components/SavingsGoals/SavingsGoalSmallListItem.tsx similarity index 98% rename from src/react/Components/SavingsGoals/SavingsGoalSmallListItem.jsx rename to src/components/SavingsGoals/SavingsGoalSmallListItem.tsx index adb8d175..125c1730 100644 --- a/src/react/Components/SavingsGoals/SavingsGoalSmallListItem.jsx +++ b/src/components/SavingsGoals/SavingsGoalSmallListItem.tsx @@ -22,7 +22,7 @@ const SavingsGoalSmallListItem = props => { const { t, savingsGoal, accounts, shareInviteMonetaryAccountResponses } = props; const { percentage } = savingsGoal.getStatistics(accounts, shareInviteMonetaryAccountResponses); - let listItemProps = { + let listItemProps: any = { button: true, component: NavLink, to: `/savings-goal-page/${savingsGoal.id}` diff --git a/src/react/Components/SavingsGoals/SavingsGoalsList.jsx b/src/components/SavingsGoals/SavingsGoalsList.tsx similarity index 89% rename from src/react/Components/SavingsGoals/SavingsGoalsList.jsx rename to src/components/SavingsGoals/SavingsGoalsList.tsx index 6d473f74..74aeef19 100644 --- a/src/react/Components/SavingsGoals/SavingsGoalsList.jsx +++ b/src/components/SavingsGoals/SavingsGoalsList.tsx @@ -3,6 +3,7 @@ import { connect } from "react-redux"; import { translate } from "react-i18next"; import List from "@material-ui/core/List"; import Grid from "@material-ui/core/Grid"; +import { ReduxState } from "~store/index"; import SavingsGoalListItemWrapper from "./SavingsGoalListItemWrapper"; @@ -15,8 +16,12 @@ const styles = { } }; -const SavingsGoalList = props => { - const { t, savingsGoals, type, hiddenTypes } = props; +interface IProps { + [key: string]: any; +} + +const SavingsGoalList = (props: ReturnType & IProps) => { + const { t, savingsGoals, type = "regular", hiddenTypes = [] } = props; const savingsGoalsList = Object.keys(savingsGoals) .filter(savingsGoalId => { @@ -32,6 +37,7 @@ const SavingsGoalList = props => { } return true; }) + // @ts-ignore .sort((savingsGoalIdA, savingsGoalIdB) => { const savingsGoalA = savingsGoals[savingsGoalIdA]; const savingsGoalB = savingsGoals[savingsGoalIdB]; @@ -68,12 +74,7 @@ const SavingsGoalList = props => { return null; }; -SavingsGoalList.defaultProps = { - type: "regular", - hiddenTypes: [] -}; - -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return { accounts: state.accounts.accounts, diff --git a/src/react/Components/Sidebar.jsx b/src/components/Sidebar.tsx similarity index 66% rename from src/react/Components/Sidebar.jsx rename to src/components/Sidebar.tsx index 7173d2ba..33238c20 100644 --- a/src/react/Components/Sidebar.jsx +++ b/src/components/Sidebar.tsx @@ -1,8 +1,7 @@ -import React from "react"; +import React, { CSSProperties } from "react"; import { translate } from "react-i18next"; import { connect } from "react-redux"; import { withStyles } from "@material-ui/core/styles"; -import PropTypes from "prop-types"; import Drawer from "@material-ui/core/Drawer"; import Hidden from "@material-ui/core/Hidden"; import Avatar from "@material-ui/core/Avatar"; @@ -21,15 +20,17 @@ import ShareIcon from "@material-ui/icons/Share"; import TimeLineIcon from "@material-ui/icons/Timeline"; import CardIcon from "@material-ui/icons/CreditCard"; import Bookmark from "@material-ui/icons/Bookmark"; +import { AppWindow } from "~app"; +import { AppDispatch, ReduxState } from "~store/index"; import FileUploadIcon from "./CustomSVG/FileUpload"; import TrophyIcon from "./CustomSVG/Trophy"; import QueueSidebarListItem from "./Queue/QueueSidebarListItem"; import NavLink from "./Routing/NavLink"; import ListItemWrapper from "./ListItemWrapper"; -import IsDarwin from "../Functions/IsDarwin"; +import IsDarwin from "~functions/IsDarwin"; -import { closeSidebar } from "../Actions/sidebar"; +import { closeSidebar } from "~actions/sidebar"; const styles = { list: { @@ -59,7 +60,18 @@ const styles = { } }; -class Sidebar extends React.Component { +interface IState { + [key: string]: any; +} + +interface IProps { + t: AppWindow["t"]; + [key: string]: any; +} + +class Sidebar extends React.Component & ReturnType & IProps> { + state: IState; + constructor(props, context) { super(props, context); this.state = { @@ -102,61 +114,63 @@ class Sidebar extends React.Component { const disableNavigationItems = userType === false || derivedPassword === false || apiKey === false; const navigationItems = disableNavigationItems ? null - : [ - , - , - pendingPaymentsCount === 0 ? null : ( - - ), - limitedPermissions ? null : ( - - ), - , - , - , - , - , - , - - ]; + : ( + <> + + + {pendingPaymentsCount === 0 ? null : ( + + )} + {!limitedPermissions && ( + + )} + + + + + + + + + ); const drawerList = ( - + - + + - + - + ); if (this.props.stickyMenu) { // dynamic menu with a hidden menu on smaller screens return ( - + <> - + ); } else { // menu is always hidden by default @@ -229,9 +243,10 @@ class Sidebar extends React.Component { } } -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return { open: state.sidebar.open, + // @ts-ignore stickyMenu: state.options.sticky_menu, pendingPayments: state.pending_payments.pending_payments, @@ -241,21 +256,19 @@ const mapStateToProps = state => { apiKey: state.registration.api_key, userType: state.user.user_type, + // @ts-ignore limitedPermissions: state.user.limited_permissions }; }; -const mapDispatchToProps = dispatch => { +const mapDispatchToProps = (dispatch: AppDispatch) => { return { closeDrawer: () => dispatch(closeSidebar()), closeSidebar: () => dispatch(closeSidebar()) }; }; -Sidebar.propTypes = { - classes: PropTypes.object.isRequired -}; - +// @ts-ignore export default withStyles(styles, { withTheme: true })( connect(mapStateToProps, mapDispatchToProps)(translate("translations")(Sidebar)) ); diff --git a/src/react/Components/SpeedDial.jsx b/src/components/SpeedDial.tsx similarity index 82% rename from src/react/Components/SpeedDial.jsx rename to src/components/SpeedDial.tsx index 2311fd34..54755a9f 100644 --- a/src/react/Components/SpeedDial.jsx +++ b/src/components/SpeedDial.tsx @@ -1,10 +1,12 @@ import React from "react"; -import SpeedDial from "@material-ui/lab/SpeedDial"; +import OriginalSpeedDial from "@material-ui/lab/SpeedDial"; import SpeedDialIcon from "@material-ui/lab/SpeedDialIcon"; import SpeedDialAction from "@material-ui/lab/SpeedDialAction"; import CloseIcon from "@material-ui/icons/Close"; +const SpeedDial: any = OriginalSpeedDial; + const styles = { speedDial: { position: "fixed", @@ -14,7 +16,26 @@ const styles = { } }; -class SpeedDialCustom extends React.Component { +interface IState { + open: boolean; + forceOpen: boolean; +} + +interface IProps { + [key: string]: any; +} + +class SpeedDialCustom extends React.Component { + state: IState; + + static defaultProps = { + style: {}, + actions: [], + ariaLabel: "More options", + hidden: false, + buttonColor: "primary" + }; + constructor(props, context) { super(props, context); this.state = { @@ -24,7 +45,7 @@ class SpeedDialCustom extends React.Component { } handleClick = () => { - this.setState(state => ({ + this.setState((state: IState) => ({ open: !state.open, forceOpen: !state.forceOpen })); @@ -82,12 +103,5 @@ class SpeedDialCustom extends React.Component { ); } } -SpeedDialCustom.defaultProps = { - style: {}, - actions: [], - ariaLabel: "More options", - hidden: false, - buttonColor: "primary" -}; export default SpeedDialCustom; diff --git a/src/react/Components/SwitchKeysMenu.jsx b/src/components/SwitchKeysMenu.tsx similarity index 90% rename from src/react/Components/SwitchKeysMenu.jsx rename to src/components/SwitchKeysMenu.tsx index e38e4883..a67729f2 100644 --- a/src/react/Components/SwitchKeysMenu.jsx +++ b/src/components/SwitchKeysMenu.tsx @@ -1,10 +1,10 @@ -import React from "react"; +import React, { CSSProperties } from "react"; import { translate } from "react-i18next"; import { connect } from "react-redux"; import IconButton from "@material-ui/core/IconButton"; import Drawer from "@material-ui/core/Drawer"; import List from "@material-ui/core/List"; -import ListItem from "@material-ui/core/ListItem"; +import OriginalListItem from "@material-ui/core/ListItem"; import ListItemText from "@material-ui/core/ListItemText"; import ListItemIcon from "@material-ui/core/ListItemIcon"; import TextField from "@material-ui/core/TextField"; @@ -14,6 +14,7 @@ import KeyIcon from "@material-ui/icons/VpnKey"; import RemoveIcon from "@material-ui/icons/Delete"; import EditIcon from "@material-ui/icons/Edit"; import VerifiedUserIcon from "@material-ui/icons/VerifiedUser"; +import { AppDispatch, ReduxState } from "~store/index"; import TranslateTypography from "./TranslationHelpers/Typography"; @@ -21,7 +22,9 @@ import { registrationRemoveStoredApiKey, registrationSetStoredApiKeys, registrationSwitchKeys -} from "../Actions/registration"; +} from "~actions/registration"; + +const ListItem: any = OriginalListItem; const styles = { list: { @@ -55,7 +58,17 @@ const styles = { } }; -class SwitchKeysMenu extends React.Component { +interface IState { + [key: string]: any; +} + +interface IProps { + [key: string]: any; +} + +class SwitchKeysMenu extends React.Component & ReturnType & IProps> { + state: IState; + constructor(props) { super(props); @@ -126,7 +139,7 @@ class SwitchKeysMenu extends React.Component { const secondaryText = `${OAuthText} ${environmentText}`; return this.state.editMode ? ( - + + <> @@ -170,7 +184,7 @@ class SwitchKeysMenu extends React.Component { style: { top: 50 } }} > - +
Stored API keys @@ -199,12 +213,12 @@ class SwitchKeysMenu extends React.Component { - + ); } } -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return { derivedPassword: state.registration.derived_password, derivedPasswordIdentifier: state.registration.identifier, @@ -216,8 +230,9 @@ const mapStateToProps = state => { }; }; -const mapDispatchToProps = dispatch => { +const mapDispatchToProps = (dispatch: AppDispatch) => { return { + // @ts-ignore registrationSwitchKeys: storedKeyIndex => dispatch(registrationSwitchKeys(storedKeyIndex)), registrationSetStoredApiKeys: storedApiKeys => dispatch(registrationSetStoredApiKeys(storedApiKeys)), diff --git a/src/react/Components/TransactionHeader.jsx b/src/components/TransactionHeader.tsx similarity index 92% rename from src/react/Components/TransactionHeader.jsx rename to src/components/TransactionHeader.tsx index 60de28ba..3c3917e2 100644 --- a/src/react/Components/TransactionHeader.jsx +++ b/src/components/TransactionHeader.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { CSSProperties } from "react"; import withTheme from "@material-ui/core/styles/withTheme"; import Grid from "@material-ui/core/Grid"; import Hidden from "@material-ui/core/Hidden"; @@ -14,7 +14,7 @@ import { defaultMastercardImage, defaultRequestResponseImage, defaultPaymentImage -} from "../Functions/DefaultImageHandlers"; +} from "~functions/DefaultImageHandlers"; const styles = { targetWrapper: { @@ -89,7 +89,7 @@ const TransactionHeader = props => { fromIsCounterparty = false; } - let defaultImage = false; + let defaultImage: any = false; if (props.type && props.type) { if (props.type === "payment") { defaultImage = defaultPaymentImage(props.event); @@ -103,12 +103,11 @@ const TransactionHeader = props => { } const components = [ - + { , - + - + {props.transferAmountComponent && ( @@ -135,7 +134,7 @@ const TransactionHeader = props => { , - + {props.transferAmountComponent && ( @@ -149,12 +148,11 @@ const TransactionHeader = props => { , - + { return components; }; +// @ts-ignore export default withTheme()(TransactionHeader); diff --git a/src/react/Components/TranslationHelpers/Button.jsx b/src/components/TranslationHelpers/Button.tsx similarity index 78% rename from src/react/Components/TranslationHelpers/Button.jsx rename to src/components/TranslationHelpers/Button.tsx index 31ec72f4..ab9bd25a 100644 --- a/src/react/Components/TranslationHelpers/Button.jsx +++ b/src/components/TranslationHelpers/Button.tsx @@ -1,6 +1,8 @@ import React from "react"; import { translate } from "react-i18next"; -import Button from "@material-ui/core/Button"; +import OrigButton from "@material-ui/core/Button"; + +const Button = OrigButton as never as any; const ButtonWrapper = ({ t, children, i18n, tReady, variant = "text", ...otherProps }) => { return ( diff --git a/src/react/Components/TranslationHelpers/MenuItem.jsx b/src/components/TranslationHelpers/MenuItem.tsx similarity index 100% rename from src/react/Components/TranslationHelpers/MenuItem.jsx rename to src/components/TranslationHelpers/MenuItem.tsx diff --git a/src/react/Components/TranslationHelpers/Typography.jsx b/src/components/TranslationHelpers/Typography.tsx similarity index 100% rename from src/react/Components/TranslationHelpers/Typography.jsx rename to src/components/TranslationHelpers/Typography.tsx diff --git a/src/react/i18n.jsx b/src/components/i18n.tsx similarity index 89% rename from src/react/i18n.jsx rename to src/components/i18n.tsx index 47b159ed..956f2e4a 100644 --- a/src/react/i18n.jsx +++ b/src/components/i18n.tsx @@ -2,8 +2,8 @@ import i18n from "i18next"; import Backend from "i18next-xhr-backend"; import { reactI18nextModule } from "react-i18next"; -import fs from "./ImportWrappers/fs"; -import path from "./ImportWrappers/path"; +import fs from "~importwrappers/fs"; +import path from "~importwrappers/path"; /** * Adds a new key to the reference locale data @@ -12,7 +12,7 @@ import path from "./ImportWrappers/path"; */ const addLocaleKey = async data => { // get the current localeData - const localeData = require("./Locales/en.json"); + const localeData = require("../locales/en.json"); // go through all the missing keys for this language Object.keys(data).forEach(missingKey => { @@ -33,7 +33,7 @@ const addLocaleKey = async data => { }); try { - const targetPath = path.join(__dirname, "../src/react/Locales/en.json"); + const targetPath = path.join(__dirname, "../locales/en.json"); // write the updated file back to the locale files fs.writeFileSync(targetPath, JSON.stringify(tempLocaleData, null, "\t")); @@ -52,7 +52,7 @@ const loadLocales = (url, options, callback, data) => { if (action === "LOAD") { try { - const locale = require("./Locales/" + language + ".json"); + const locale = require("../locales/" + language + ".json"); callback(locale, { status: "200" }); } catch (e) { console.error(e); diff --git a/src/react/react-app.jsx b/src/components/react-app.tsx similarity index 81% rename from src/react/react-app.jsx rename to src/components/react-app.tsx index 0589bc70..fa564c26 100644 --- a/src/react/react-app.jsx +++ b/src/components/react-app.tsx @@ -2,6 +2,7 @@ import React from "react"; import ReactDOM from "react-dom"; import store from "store"; import BunqJSClient from "@bunq-community/bunq-js-client"; +import { AppWindow } from "~app"; import BunqDesktopClient from "./BunqDesktopClient"; // bunqDesktop entry point @@ -12,12 +13,15 @@ import "../scss/main.scss"; import "animate.css"; import "typeface-roboto"; -import Logger from "./Functions/Logger"; -import Analytics from "./Functions/Analytics"; +import Logger from "~functions/Logger"; +import Analytics from "~functions/Analytics"; + +declare let window: AppWindow; Analytics(); // create a new bunq js client and inject into the app +// @ts-ignore const BunqJSClientInstance = new BunqJSClient(store, Logger); BunqJSClientInstance.setKeepAlive(false); diff --git a/src/env.js b/src/env.ts similarity index 100% rename from src/env.js rename to src/env.ts diff --git a/src/react/Functions/Analytics.js b/src/functions/Analytics.ts similarity index 85% rename from src/react/Functions/Analytics.js rename to src/functions/Analytics.ts index b25bb226..eccf27c2 100644 --- a/src/react/Functions/Analytics.js +++ b/src/functions/Analytics.ts @@ -1,8 +1,11 @@ import store from "store"; -import settings from "../ImportWrappers/electronSettings"; +import { AppWindow } from "~app"; +import settings from "~importwrappers/electronSettings"; import { generateGUID } from "./Utils"; import Logger from "./Logger"; -import { ANALYTICS_ENABLED } from "../Reducers/options"; +import { ANALYTICS_ENABLED } from "~reducers/options"; + +declare let window: AppWindow & { ga: any }; export default (forceEnable = false) => { if (process.env.NODE_ENV === "development") { @@ -26,14 +29,14 @@ export default (forceEnable = false) => { function() { (i[r].q = i[r].q || []).push(arguments); }), - (i[r].l = 1 * new Date()); + (i[r].l = +new Date()); (a = s.createElement(o)), (m = s.getElementsByTagName(o)[0]); a.async = 1; a.src = g; m.parentNode.insertBefore(a, m); })(window, document, "script", "https://www.google-analytics.com/analytics.js", "ga"); - // give global access + // @ts-ignore give global access window.ga = ga; } diff --git a/src/react/Functions/BunqErrorHandler.js b/src/functions/BunqErrorHandler.ts similarity index 69% rename from src/react/Functions/BunqErrorHandler.js rename to src/functions/BunqErrorHandler.ts index 4c09ed81..addc80d6 100644 --- a/src/react/Functions/BunqErrorHandler.js +++ b/src/functions/BunqErrorHandler.ts @@ -1,14 +1,18 @@ +import { AppWindow } from "~app"; +import { BatchedActions } from "~store/index"; import Logger from "./Logger"; -import { openModal } from "../Actions/modal"; -import { openSnackbar } from "../Actions/snackbar"; -import { applicationSetOffline } from "../Actions/application"; -import { registrationResetToApiScreen } from "../Actions/registration"; +import { openModal } from "~actions/modal"; +import { registrationResetToApiScreen } from "~actions/registration"; +import { actions as snackbarActions } from "~store/snackbar"; +import { actions as applicationActions } from "~store/application"; import ErrorCodes from "@bunq-community/bunq-js-client/dist/Helpers/ErrorCodes"; -const defaultErrorMessage = (dispatch, customError = false) => { - dispatch( +declare let window: AppWindow; + +const defaultErrorMessage = (batchedActions: BatchedActions, customError: boolean | string = false) => { + batchedActions.push( openModal( customError ? customError : "Something went wrong while trying to send a request", "Something went wrong" @@ -16,14 +20,7 @@ const defaultErrorMessage = (dispatch, customError = false) => { ); }; -/** - * @param dispatch - * @param error - * @param {boolean|string} customError - * @param {boolean|BunqJSClient} BunqJSClient - * @returns {*} - */ -export default (dispatch, error, customError = false, BunqJSClient = false) => { +export default (batchedActions: BatchedActions, error, customError: boolean | string = false, BunqJSClient = false) => { const response = error.response; const offlineError = window.t("We received a network error while trying to send a request! You might be offline"); @@ -39,10 +36,10 @@ export default (dispatch, error, customError = false, BunqJSClient = false) => { // check if a network error occured if (error.toString() === "Error: Network Error") { // show a less intrusive error using the snackbar - dispatch(openSnackbar(offlineError)); + batchedActions.push(snackbarActions.open(offlineError)); // enable offline mode - dispatch(applicationSetOffline()); + batchedActions.push(applicationActions.setOffline()); return; } @@ -50,13 +47,13 @@ export default (dispatch, error, customError = false, BunqJSClient = false) => { switch (error.errorCode) { // invalid response or it couldn't be verified case ErrorCodes.INVALID_RESPONSE_RECEIVED: - return defaultErrorMessage(dispatch, invalidResponseError); + return defaultErrorMessage(batchedActions, invalidResponseError); } } // fallback to a default message if (!response) { - return defaultErrorMessage(dispatch, customError); + return defaultErrorMessage(batchedActions, customError); } // check if we can display a bunq error @@ -86,13 +83,13 @@ export default (dispatch, error, customError = false, BunqJSClient = false) => { errorMessage = invalidAuthenticationError; // reset to api screen if possible - if (BunqJSClient) dispatch(registrationResetToApiScreen(BunqJSClient)); + batchedActions.push(registrationResetToApiScreen()); break; } - return dispatch(openModal(`${message}:\n ${errorMessage}${responseIdText}`, "Something went wrong")); + return batchedActions.push(openModal(`${message}:\n ${errorMessage}${responseIdText}`, "Something went wrong")); } } - return defaultErrorMessage(dispatch, customError); + return defaultErrorMessage(batchedActions, customError); }; diff --git a/src/react/Functions/ConnectGetPermissions.js b/src/functions/ConnectGetPermissions.ts similarity index 98% rename from src/react/Functions/ConnectGetPermissions.js rename to src/functions/ConnectGetPermissions.ts index d4f1afd9..4fd199fe 100644 --- a/src/react/Functions/ConnectGetPermissions.js +++ b/src/functions/ConnectGetPermissions.ts @@ -36,7 +36,7 @@ export const connectGetType = (shareInviteMonetaryAccountResponses, accountId) = return true; }; -export const connectGetBudget = (shareInviteMonetaryAccountResponses, accountId) => { +export const connectGetBudget = (shareInviteMonetaryAccountResponses, accountId = undefined) => { let inviteResponse = null; if (accountId) { inviteResponse = getInviteResponse(shareInviteMonetaryAccountResponses, accountId); diff --git a/src/react/Functions/Crypto/Crypto.js b/src/functions/Crypto/Crypto.ts similarity index 100% rename from src/react/Functions/Crypto/Crypto.js rename to src/functions/Crypto/Crypto.ts diff --git a/src/react/Functions/Crypto/CryptoWorkerWrapper.js b/src/functions/Crypto/CryptoWorkerWrapper.ts similarity index 84% rename from src/react/Functions/Crypto/CryptoWorkerWrapper.js rename to src/functions/Crypto/CryptoWorkerWrapper.ts index 475278f2..17c63dc9 100644 --- a/src/react/Functions/Crypto/CryptoWorkerWrapper.js +++ b/src/functions/Crypto/CryptoWorkerWrapper.ts @@ -1,13 +1,25 @@ import store from "store"; -const CryptoWorker = require("worker-loader!../../WebWorkers/crypto.worker.js"); +import { AppWindow } from "~app"; +let CryptoWorker; +// TODO: find a solution to support Jest +if (!process.env.JEST) { + require("worker-loader!../../webworkers/crypto.worker.js"); +} + +declare let window: AppWindow; + +export class CryptoWorkerQueue { + queue: any; + worker: any; -class CryptoWorkerQueue { constructor() { this.queue = {}; // setup a new cryptoWorker - this.worker = new CryptoWorker(); - this.worker.onmessage = this.onMessage; + if (CryptoWorker) { + this.worker = new CryptoWorker(); + this.worker.onmessage = this.onMessage; + } } addTask = task => { @@ -95,7 +107,7 @@ export const storeEncryptString = async (data, location, encryptionKey, type = " // stringify the data const jsonData = JSON.stringify(data); - const encryptedDetails = await window.cryptoWorkerQueue.addTask({ + const encryptedDetails: any = await window.cryptoWorkerQueue.addTask({ type: "ENCRYPT", encryptionKey: encryptionKey, data: jsonData diff --git a/src/react/Functions/Crypto/CustomForge.js b/src/functions/Crypto/CustomForge.ts similarity index 100% rename from src/react/Functions/Crypto/CustomForge.js rename to src/functions/Crypto/CustomForge.ts diff --git a/src/react/Functions/DataFilters.js b/src/functions/DataFilters.ts similarity index 99% rename from src/react/Functions/DataFilters.js rename to src/functions/DataFilters.ts index 4de4e519..2b714b94 100644 --- a/src/react/Functions/DataFilters.js +++ b/src/functions/DataFilters.ts @@ -1,4 +1,4 @@ -import CategoryHelper from "../Components/Categories/CategoryHelper"; +import CategoryHelper from "~components/Categories/CategoryHelper"; const checkDateRange = (fromDate, toDate, date) => { // nothing to check so always valid @@ -486,6 +486,7 @@ export const requestInquiryFilter = options => requestInquiry => { } } + console.log(requestInquiry.RequestInquiry); return checkDateRange(options.dateFromFilter, options.dateToFilter, requestInquiry.RequestInquiry.updated); }; diff --git a/src/react/Functions/DefaultImageHandlers.js b/src/functions/DefaultImageHandlers.ts similarity index 100% rename from src/react/Functions/DefaultImageHandlers.js rename to src/functions/DefaultImageHandlers.ts diff --git a/src/react/Functions/EventStatusTexts.js b/src/functions/EventStatusTexts.ts similarity index 100% rename from src/react/Functions/EventStatusTexts.js rename to src/functions/EventStatusTexts.ts diff --git a/src/react/Functions/FilterDisabledChecker.js b/src/functions/FilterDisabledChecker.ts similarity index 100% rename from src/react/Functions/FilterDisabledChecker.js rename to src/functions/FilterDisabledChecker.ts diff --git a/src/react/Functions/IpChecker.js b/src/functions/IpChecker.ts similarity index 100% rename from src/react/Functions/IpChecker.js rename to src/functions/IpChecker.ts diff --git a/src/react/Functions/IsDarwin.js b/src/functions/IsDarwin.ts similarity index 62% rename from src/react/Functions/IsDarwin.js rename to src/functions/IsDarwin.ts index 99b0216b..508b5824 100644 --- a/src/react/Functions/IsDarwin.js +++ b/src/functions/IsDarwin.ts @@ -1,4 +1,4 @@ -import os from "../ImportWrappers/os"; +import os from "~importwrappers/os"; export default () => { return os.platform() === "darwin"; diff --git a/src/react/Functions/Logger.js b/src/functions/Logger.ts similarity index 75% rename from src/react/Functions/Logger.js rename to src/functions/Logger.ts index cf1d96cd..c3639d49 100644 --- a/src/react/Functions/Logger.js +++ b/src/functions/Logger.ts @@ -2,7 +2,7 @@ const remote = require("electron").remote; const electronLog = remote ? remote.require("electron-log") : require("electron-log"); -const Logger = { +export default { log: params => { console.log(params); electronLog.log(params); @@ -30,14 +30,10 @@ const Logger = { silly: params => { console.debug(params); electronLog.silly(params); - } + }, + transports: electronLog.transports, + variables: electronLog.variables, + default: electronLog.default, + hooks: electronLog.hooks, + isDev: electronLog.isDev, }; - -Logger.catchErrors = electronLog.catchErrors; -Logger.transports = electronLog.transports; -Logger.variables = electronLog.variables; -Logger.default = electronLog.default; -Logger.hooks = electronLog.hooks; -Logger.isDev = electronLog.isDev; - -export default Logger; diff --git a/src/react/Functions/MergeApiObjects.js b/src/functions/MergeApiObjects.ts similarity index 100% rename from src/react/Functions/MergeApiObjects.js rename to src/functions/MergeApiObjects.ts diff --git a/src/react/Functions/NoteTextTypeParser.js b/src/functions/NoteTextTypeParser.ts similarity index 100% rename from src/react/Functions/NoteTextTypeParser.js rename to src/functions/NoteTextTypeParser.ts diff --git a/src/react/Functions/NotificationHelper.js b/src/functions/NotificationHelper.ts similarity index 100% rename from src/react/Functions/NotificationHelper.js rename to src/functions/NotificationHelper.ts diff --git a/src/react/Functions/PhoneLib.js b/src/functions/PhoneLib.ts similarity index 65% rename from src/react/Functions/PhoneLib.js rename to src/functions/PhoneLib.ts index df2c6249..1ccb3981 100644 --- a/src/react/Functions/PhoneLib.js +++ b/src/functions/PhoneLib.ts @@ -1,6 +1,6 @@ -import { parsePhoneNumber } from "libphonenumber-js"; +import { CountryCode, parsePhoneNumber } from "libphonenumber-js"; -export const isValidPhonenumber = (number, region = "NL") => { +export const isValidPhonenumber = (number, region: CountryCode = "NL") => { try { const phoneNumber = parsePhoneNumber(number, region); return phoneNumber.isValid(); @@ -8,7 +8,7 @@ export const isValidPhonenumber = (number, region = "NL") => { return false; }; -export const getInternationalFormat = (number, region = "NL") => { +export const getInternationalFormat = (number, region: CountryCode = "NL") => { try { const phoneNumber = parsePhoneNumber(number, region); const formattedPhone = phoneNumber.formatInternational(); diff --git a/src/react/Functions/ScheduleTexts.js b/src/functions/ScheduleTexts.ts similarity index 100% rename from src/react/Functions/ScheduleTexts.js rename to src/functions/ScheduleTexts.ts diff --git a/src/react/Functions/StatsFormattingTemplates.js b/src/functions/StatsFormattingTemplates.ts similarity index 100% rename from src/react/Functions/StatsFormattingTemplates.js rename to src/functions/StatsFormattingTemplates.ts diff --git a/src/react/Functions/Utils.js b/src/functions/Utils.ts similarity index 98% rename from src/react/Functions/Utils.js rename to src/functions/Utils.ts index ce50b76f..017fcf6a 100644 --- a/src/react/Functions/Utils.js +++ b/src/functions/Utils.ts @@ -1,3 +1,7 @@ +import { AppWindow } from "~app"; + +declare let window: AppWindow; + /** * Turn first character into uppercase * @param str @@ -77,7 +81,7 @@ export const anonymizedHandlerKeys = Object.keys(anonymizedHandlers); * @param object * @returns {*} */ -export const anonymizeObject = (object, key = false) => { +export const anonymizeObject = (object: any, key: any = false) => { // this could be an item itself if (key) { if (anonymizeKeys.includes(key)) { diff --git a/src/react/Functions/VersionChecker.js b/src/functions/VersionChecker.ts similarity index 95% rename from src/react/Functions/VersionChecker.js rename to src/functions/VersionChecker.ts index 02ed3c19..88c170f9 100644 --- a/src/react/Functions/VersionChecker.js +++ b/src/functions/VersionChecker.ts @@ -17,6 +17,7 @@ const isSemVer = (function() { ? (c ? d[1] || "==" : "") + '"' + (d[2] + ".0.0").match(/\d+(?:\.\d+){0,2}/)[0].replace(/(?:^|\.)(\d+)/g, function(g, f) { + // @ts-ignore return Array(9 - f.length).join(0) + f; }) + (d[3] || "~") + @@ -26,6 +27,7 @@ const isSemVer = (function() { : 1; } return function(e) { + // @ts-ignore e = b(e); for (var c, d = 1; (c = arguments[d++]); ) { if (!new Function("return " + e + b(c, 1))()) { @@ -46,6 +48,7 @@ export default async () => { return { currentVersion: currentVersion, latestVersion: latestVersion, + // @ts-ignore newerLink: isSemVer(currentVersion, `<${latestVersion}`) ? response.html_url : false }; } catch (ex) { diff --git a/src/helpers/context_menu.js b/src/helpers/context_menu.ts similarity index 92% rename from src/helpers/context_menu.js rename to src/helpers/context_menu.ts index 9f0bd455..f730c6fd 100644 --- a/src/helpers/context_menu.js +++ b/src/helpers/context_menu.ts @@ -41,16 +41,19 @@ textEditingMenu.append(paste); document.addEventListener( "contextmenu", - event => { + (event) => { + // @ts-ignore switch (event.target.nodeName) { case "TEXTAREA": case "INPUT": event.preventDefault(); + // @ts-ignore textEditingMenu.popup(remote.getCurrentWindow()); break; default: if (isAnyTextSelected()) { event.preventDefault(); + // @ts-ignore normalMenu.popup(remote.getCurrentWindow()); } } diff --git a/src/helpers/devtools.js b/src/helpers/devtools.ts similarity index 100% rename from src/helpers/devtools.js rename to src/helpers/devtools.ts diff --git a/src/helpers/external_links.js b/src/helpers/external_links.ts similarity index 100% rename from src/helpers/external_links.js rename to src/helpers/external_links.ts diff --git a/src/helpers/oauth.js b/src/helpers/oauth.ts similarity index 96% rename from src/helpers/oauth.js rename to src/helpers/oauth.ts index bb012a28..1349263e 100644 --- a/src/helpers/oauth.js +++ b/src/helpers/oauth.ts @@ -90,10 +90,13 @@ export default (window, log) => { } // check if we received an access token + // @ts-ignore if (params.code) { + // @ts-ignore log.debug("Received OAuth code: " + params.code.substring(0, 8)); // send data to renderer view + // @ts-ignore window.webContents.send("received-oauth-bunq-code", params.code); } else { window.webContents.send("received-oauth-failed"); @@ -109,6 +112,7 @@ export default (window, log) => { handleUrl(receivedUrl); }); + // @ts-ignore consentWindow.webContents.on("did-get-redirect-request", function(event, oldUrl, newUrl) { handleUrl(newUrl); }); @@ -137,8 +141,10 @@ export default (window, log) => { } // check if we received an access token + // @ts-ignore if (params.access_token) { // send data to renderer view + // @ts-ignore window.webContents.send("received-oauth-google-access-token", params.access_token); } else { window.webContents.send("received-oauth-failed"); @@ -154,6 +160,7 @@ export default (window, log) => { handleUrl(receivedUrl); }); + // @ts-ignore consentWindow.webContents.on("did-get-redirect-request", function(event, oldUrl, newUrl) { handleUrl(newUrl); }); @@ -181,13 +188,16 @@ export default (window, log) => { // Try to exchange the param values for an access token. } if (params["#access_token"]) { + // @ts-ignore params.access_token = params["#access_token"]; delete params["#access_token"]; } // check if we received an access token + // @ts-ignore if (params.access_token) { // send data to renderer view + // @ts-ignore window.webContents.send("received-oauth-office-365-access-token", params.access_token); } else { window.webContents.send("received-oauth-failed"); @@ -203,6 +213,7 @@ export default (window, log) => { handleUrl(receivedUrl); }); + // @ts-ignore consentWindow.webContents.on("did-get-redirect-request", function(event, oldUrl, newUrl) { handleUrl(newUrl); }); diff --git a/src/helpers/react_navigate.js b/src/helpers/react_navigate.ts similarity index 100% rename from src/helpers/react_navigate.js rename to src/helpers/react_navigate.ts diff --git a/src/helpers/settings.js b/src/helpers/settings.ts similarity index 100% rename from src/helpers/settings.js rename to src/helpers/settings.ts diff --git a/src/helpers/shortcuts.js b/src/helpers/shortcuts.ts similarity index 100% rename from src/helpers/shortcuts.js rename to src/helpers/shortcuts.ts diff --git a/src/helpers/touchbar.js b/src/helpers/touchbar.ts similarity index 98% rename from src/helpers/touchbar.js rename to src/helpers/touchbar.ts index 9adf0d0b..6303e57d 100644 --- a/src/helpers/touchbar.js +++ b/src/helpers/touchbar.ts @@ -52,6 +52,7 @@ export default (window, i18n) => { updateQueueButton.label = `🔄 ${newEventCount} new events`; }); + // @ts-ignore const bar = new TouchBar([dashboardButton, updateQueueButton, payButton, requestButton, bunqMeButton, cardsButton]); window.setTouchBar(bar); diff --git a/src/helpers/tray.js b/src/helpers/tray.ts similarity index 99% rename from src/helpers/tray.js rename to src/helpers/tray.ts index e693bab9..ff4e892f 100644 --- a/src/helpers/tray.js +++ b/src/helpers/tray.ts @@ -57,6 +57,7 @@ export default (mainWindow, trayIcon) => { } ]; + // @ts-ignore const contextMenu = Menu.buildFromTemplate(menuItems); tray.setContextMenu(contextMenu); diff --git a/src/helpers/window.js b/src/helpers/window.ts similarity index 100% rename from src/helpers/window.js rename to src/helpers/window.ts diff --git a/src/i18n-background.js b/src/i18n-background.ts similarity index 100% rename from src/i18n-background.js rename to src/i18n-background.ts diff --git a/src/react/ImportWrappers/README.md b/src/importwrappers/README.md similarity index 100% rename from src/react/ImportWrappers/README.md rename to src/importwrappers/README.md diff --git a/src/react/ImportWrappers/electronSettings.js b/src/importwrappers/electronSettings.ts similarity index 100% rename from src/react/ImportWrappers/electronSettings.js rename to src/importwrappers/electronSettings.ts diff --git a/src/react/ImportWrappers/fs.js b/src/importwrappers/fs.ts similarity index 100% rename from src/react/ImportWrappers/fs.js rename to src/importwrappers/fs.ts diff --git a/src/react/ImportWrappers/localforage.js b/src/importwrappers/localforage.ts similarity index 100% rename from src/react/ImportWrappers/localforage.js rename to src/importwrappers/localforage.ts diff --git a/src/react/ImportWrappers/os.js b/src/importwrappers/os.ts similarity index 100% rename from src/react/ImportWrappers/os.js rename to src/importwrappers/os.ts diff --git a/src/react/ImportWrappers/path.js b/src/importwrappers/path.ts similarity index 100% rename from src/react/ImportWrappers/path.js rename to src/importwrappers/path.ts diff --git a/dist/.gitkeep b/src/locales/Crowdin/.gitkeep similarity index 100% rename from dist/.gitkeep rename to src/locales/Crowdin/.gitkeep diff --git a/src/react/Locales/de.json b/src/locales/de.json similarity index 100% rename from src/react/Locales/de.json rename to src/locales/de.json diff --git a/src/react/Locales/en.json b/src/locales/en.json similarity index 100% rename from src/react/Locales/en.json rename to src/locales/en.json diff --git a/src/react/Locales/es.json b/src/locales/es.json similarity index 100% rename from src/react/Locales/es.json rename to src/locales/es.json diff --git a/src/react/Locales/gr.json b/src/locales/gr.json similarity index 100% rename from src/react/Locales/gr.json rename to src/locales/gr.json diff --git a/src/react/Locales/it.json b/src/locales/it.json similarity index 100% rename from src/react/Locales/it.json rename to src/locales/it.json diff --git a/src/react/Locales/nl.json b/src/locales/nl.json similarity index 100% rename from src/react/Locales/nl.json rename to src/locales/nl.json diff --git a/src/menu/darwin_menu_templates.js b/src/menu/darwin_menu_templates.ts similarity index 100% rename from src/menu/darwin_menu_templates.js rename to src/menu/darwin_menu_templates.ts diff --git a/src/menu/dev_menu_template.js b/src/menu/dev_menu_template.ts similarity index 95% rename from src/menu/dev_menu_template.js rename to src/menu/dev_menu_template.ts index 7e55063c..62aa0a6e 100644 --- a/src/menu/dev_menu_template.js +++ b/src/menu/dev_menu_template.ts @@ -14,6 +14,7 @@ export const devMenuTemplate = { label: "Toggle DevTools", accelerator: "Alt+CmdOrCtrl+I", click: () => { + // @ts-ignore BrowserWindow.getFocusedWindow().toggleDevTools(); } }, diff --git a/src/menu/edit_menu_template.js b/src/menu/edit_menu_template.ts similarity index 100% rename from src/menu/edit_menu_template.js rename to src/menu/edit_menu_template.ts diff --git a/src/menu/help_menu_template.js b/src/menu/help_menu_template.ts similarity index 100% rename from src/menu/help_menu_template.js rename to src/menu/help_menu_template.ts diff --git a/src/menu/view_menu_template.js b/src/menu/view_menu_template.ts similarity index 100% rename from src/menu/view_menu_template.js rename to src/menu/view_menu_template.ts diff --git a/src/menu/window_menu_template.js b/src/menu/window_menu_template.ts similarity index 100% rename from src/menu/window_menu_template.js rename to src/menu/window_menu_template.ts diff --git a/src/misc/consts.ts b/src/misc/consts.ts new file mode 100644 index 00000000..5ddadd8a --- /dev/null +++ b/src/misc/consts.ts @@ -0,0 +1,14 @@ +export const STORED_ACCOUNTS = "BUNQDESKTOP_STORED_ACCOUNTS"; +export const SELECTED_ACCOUNT_LOCATION = "BUNQDESKTOP_SELECTED_ACCOUNT"; +export const EXCLUDED_ACCOUNT_IDS = "BUNQDESKTOP_EXCLUDED_ACCOUNT_IDS"; + +export const STORED_BUNQ_ME_TABS = "BUNQDESKTOP_STORED_BUNQ_ME_TABS"; + +export const CARD_ORDER_LOCATION = "BUNQDESKTOP_CARD_ORDER"; + +export const BUNQDESKTOP_CATEGORIES = "BUNQDESKTOP_CATEGORIES"; +export const BUNQDESKTOP_CATEGORY_CONNECTIONS = "BUNQDESKTOP_CATEGORY_CONNECTIONS"; + +export const STORED_CATEGORY_RULES = "BUNQDESKTOP_STORED_CATEGORY_RULES"; + +export const STORED_CONTACTS = "BUNQDESKTOP_STORED_CONTACTS"; diff --git a/src/react/Models/BunqMeTab.ts b/src/models/BunqMeTab.ts similarity index 97% rename from src/react/Models/BunqMeTab.ts rename to src/models/BunqMeTab.ts index 4b5cbbf6..6386b665 100644 --- a/src/react/Models/BunqMeTab.ts +++ b/src/models/BunqMeTab.ts @@ -1,5 +1,5 @@ -import { BunqMeTabEntry, BunqMeTabResultInquiry, BunqMeTabStatus } from "../Types/Types"; -import Event, { EventTypeValue } from "../Types/Event"; +import { BunqMeTabEntry, BunqMeTabResultInquiry, BunqMeTabStatus } from "~types/Types"; +import Event, { EventTypeValue } from "~types/Event"; export default class BunqMeTab implements Event { // the original raw object diff --git a/src/react/Models/Card.ts b/src/models/Card.ts similarity index 98% rename from src/react/Models/Card.ts rename to src/models/Card.ts index 787ed51a..e43574e1 100644 --- a/src/react/Models/Card.ts +++ b/src/models/Card.ts @@ -1,4 +1,4 @@ -import { getObjectType } from "../Functions/Utils"; +import { getObjectType } from "~functions/Utils"; import { Alias, @@ -6,7 +6,7 @@ import { CountryPermissionCollection, PinCodeAssignmentCollection, PrimaryAccountNumberCollection -} from "../Types/Types"; +} from "~types/Types"; export default class Card { // the original raw object diff --git a/src/react/Models/MasterCardAction.ts b/src/models/MasterCardAction.ts similarity index 98% rename from src/react/Models/MasterCardAction.ts rename to src/models/MasterCardAction.ts index 077d4855..ea0482ae 100644 --- a/src/react/Models/MasterCardAction.ts +++ b/src/models/MasterCardAction.ts @@ -1,5 +1,5 @@ -import { Amount, LabelCard, PaymentAlias, RequestReferenceSplitTheBill } from "../Types/Types"; -import Event, { EventTypeValue } from "../Types/Event"; +import { Amount, LabelCard, PaymentAlias, RequestReferenceSplitTheBill } from "~types/Types"; +import Event, { EventTypeValue } from "~types/Event"; export type PanEntryModeUser = "ATM" | "ICC" | "MAGNETIC_STRIPE" | "E_COMMERCE"; diff --git a/src/react/Models/MonetaryAccount.ts b/src/models/MonetaryAccount.ts similarity index 71% rename from src/react/Models/MonetaryAccount.ts rename to src/models/MonetaryAccount.ts index 2907bab7..56a4a2d7 100644 --- a/src/react/Models/MonetaryAccount.ts +++ b/src/models/MonetaryAccount.ts @@ -1,6 +1,7 @@ -import { AccountType, MonetaryAccountSetting, AllCoOwner, Alias, Avatar, Balance, Amount } from "../Types/Types"; +import { IMonetaryAccount } from "~types/MonetaryAccount"; +import { AccountType, MonetaryAccountSetting, AllCoOwner, Alias, Avatar, Balance, Amount } from "~types/Types"; -import NotificationFilter from "@bunq-community/bunq-js-client/src/Types/NotificationFilter"; +import NotificationFilter from "@bunq-community/bunq-js-client/dist/Types/NotificationFilter"; export default class MonetaryAccount { // the original raw object @@ -67,10 +68,50 @@ export default class MonetaryAccount { * Used to store this object in JSON * @returns {string} */ - public toJSON(): any { + public toJSON(): string { return this._rawData; } + /** + * Converts a plain object into a MonetaryAccount object + */ + public static fromPlainObject(plainObject: IMonetaryAccount): MonetaryAccount { + return new MonetaryAccount({ [plainObject.accountType]: plainObject }); + } + + /** + * Converts this instantiated object into a serializable MonetaryAccount object + */ + public toPlainObject(): IMonetaryAccount { + return JSON.parse(JSON.stringify({ + accountType: this._accountType, + id: this._id, + created: this._created, + updated: this._updated, + avatar: this._avatar, + currency: this._currency, + description: this._description, + daily_limit: this._daily_limit, + daily_spent: this._daily_spent, + overdraft_limit: this._overdraft_limit, + balance: this._balance, + alias: this._alias, + public_uuid: this._public_uuid, + status: this._status, + sub_status: this._sub_status, + user_id: this._user_id, + monetary_account_profile: this._monetary_account_profile, + notification_filters: this._notification_filters, + setting: this._setting, + + savings_goal: this._savings_goal, + savings_goal_progress: this._savings_goal_progress, + + // only available on MonetaryAccountJoint objects + all_co_owner: this._all_co_owner, + })); + } + /** * Returns the current account balance as float * @returns {number} diff --git a/src/react/Models/Payment.ts b/src/models/Payment.ts similarity index 72% rename from src/react/Models/Payment.ts rename to src/models/Payment.ts index 3dae06ca..b7b635c5 100644 --- a/src/react/Models/Payment.ts +++ b/src/models/Payment.ts @@ -1,3 +1,4 @@ +import { IPayment } from "~types/Payment"; import { Address, Amount, @@ -7,8 +8,8 @@ import { PaymentSubType, PaymentType, RequestReferenceSplitTheBill -} from "../Types/Types"; -import Event, { EventTypeValue } from "../Types/Event"; +} from "~types/Types"; +import Event, { EventTypeValue } from "~types/Event"; export default class Payment implements Event { // the original raw object @@ -76,6 +77,48 @@ export default class Payment implements Event { return this._rawData; } + /** + * Convert from a plain serializable object + */ + public static fromPlainObject(plainObject: IPayment): Payment { + return new Payment({ Payment: plainObject }); + } + + /** + * Convert to a serializable plain object + */ + public toPlainObject(): IPayment { + return JSON.parse(JSON.stringify({ + Payment: { + id: this._id, + created: this._created, + updated: this._updated, + monetary_account_id: this._monetary_account_id, + amount: this._amount, + alias: this._alias, + counterparty_alias: this._counterparty_alias, + description: this._description, + type: this._type, + sub_type: this._sub_type, + bunqto_status: this._bunqto_status, + bunqto_sub_status: this._bunqto_sub_status, + bunqto_share_url: this._bunqto_share_url, + bunqto_expiry: this._bunqto_expiry, + bunqto_time_responded: this._bunqto_time_responded, + attachment: this._attachment, + balance_after_mutation: this._balance_after_mutation, + merchant_reference: this._merchant_reference, + batch_id: this._batch_id, + scheduled_id: this._scheduled_id, + address_shipping: this._address_shipping, + address_billing: this._address_billing, + geolocation: this._geolocation, + allow_chat: this._allow_chat, + request_reference_split_the_bill: this._request_reference_split_the_bill, + }, + })); + } + /** * @returns {number} */ diff --git a/src/react/Models/RequestInquiry.ts b/src/models/RequestInquiry.ts similarity index 71% rename from src/react/Models/RequestInquiry.ts rename to src/models/RequestInquiry.ts index 67eff6b5..f5efcf7b 100644 --- a/src/react/Models/RequestInquiry.ts +++ b/src/models/RequestInquiry.ts @@ -1,3 +1,4 @@ +import { IRequestInquiry } from "~types/RequestInquiry"; import { Address, Amount, @@ -7,14 +8,15 @@ import { PaymentAlias, RequestStatus, RequestSplitTheBill -} from "../Types/Types"; -import Event, { EventTypeValue } from "../Types/Event"; +} from "~types/Types"; +import Event, { EventTypeValue } from "~types/Event"; export default class RequestInquiry implements Event { // the original raw object private _rawData: any; public RequestInquiry = this; + get eventType(): EventTypeValue { return "RequestInquiry"; } @@ -71,6 +73,53 @@ export default class RequestInquiry implements Event { return this._rawData; } + /** + * Convert from a plain serializable object + */ + public static fromPlainObject(plainObject: IRequestInquiry): RequestInquiry { + return new RequestInquiry(plainObject); + } + + /** + * Convert to a plain serializable object + */ + public toPlainObject(): IRequestInquiry { + return JSON.parse(JSON.stringify({ + RequestInquiry: { + id: this._id, + created: this._created, + updated: this._updated, + time_responded: this._time_responded, + time_expiry: this._time_expiry, + monetary_account_id: this._monetary_account_id, + amount_inquired: this._amount_inquired, + amount_responded: this._amount_responded, + user_alias_created: this._user_alias_created, + user_alias_revoked: this._user_alias_revoked, + counterparty_alias: this._counterparty_alias, + description: this._description, + merchant_reference: this._merchant_reference, + attachment: this._attachment, + status: this._status, + batch_id: this._batch_id, + bunqme_share_url: this._bunqme_share_url, + scheduled_id: this._scheduled_id, + minimum_age: this._minimum_age, + require_address: this._require_address, + redirect_url: this._redirect_url, + address_shipping: this._address_shipping, + address_billing: this._address_billing, + geolocation: this._geolocation, + allow_chat: this._allow_chat, + request_reference_split_the_bill: this._request_reference_split_the_bill, + }, + })); + } + + get raw(): any { + return this._rawData; + } + /** * @returns {number} */ @@ -102,75 +151,99 @@ export default class RequestInquiry implements Event { get id(): number { return this._id; } + get created(): Date { return this._created; } + get updated(): Date { return this._updated; } + get time_responded(): Date { return this._time_responded; } + get time_expiry(): Date { return this._time_expiry; } + get monetary_account_id(): number { return this._monetary_account_id; } + get amount_inquired(): Amount { return this._amount_inquired; } + get amount_responded(): Amount | null { return this._amount_responded; } + get user_alias_created(): ExtendedAlias { return this._user_alias_created; } + get user_alias_revoked(): ExtendedAlias | null { return this._user_alias_revoked; } + get counterparty_alias(): PaymentAlias { return this._counterparty_alias; } + get description(): string { return this._description; } + get merchant_reference(): string { return this._merchant_reference; } + get attachment(): AttachmentList { return this._attachment; } + get status(): RequestStatus { return this._status; } + get batch_id(): number | null { return this._batch_id; } + get bunqme_share_url(): string | null { return this._bunqme_share_url; } + get scheduled_id(): number | null { return this._scheduled_id; } + get minimum_age(): number | null { return this._minimum_age; } + get require_address(): string { return this._require_address; } + get address_shipping(): Address | null { return this._address_shipping; } + get address_billing(): Address | null { return this._address_billing; } + get geolocation(): Geolocation { return this._geolocation; } + get allow_chat(): boolean { return this._allow_chat; } + get request_reference_split_the_bill(): RequestSplitTheBill { return this._request_reference_split_the_bill; } diff --git a/src/react/Models/RequestInquiryBatch.ts b/src/models/RequestInquiryBatch.ts similarity index 75% rename from src/react/Models/RequestInquiryBatch.ts rename to src/models/RequestInquiryBatch.ts index fbd7d39a..86555d66 100644 --- a/src/react/Models/RequestInquiryBatch.ts +++ b/src/models/RequestInquiryBatch.ts @@ -1,5 +1,6 @@ -import { Amount, RequestSplitTheBill } from "../Types/Types"; -import Event, { EventTypeValue } from "../Types/Event"; +import { IRequestInquiryBatch } from "~types/RequestInquiryBatch"; +import { Amount, RequestSplitTheBill } from "~types/Types"; +import Event, { EventTypeValue } from "~types/Event"; import RequestInquiry from "./RequestInquiry"; export default class RequestInquiryBatch implements Event { @@ -55,6 +56,29 @@ export default class RequestInquiryBatch implements Event { return this._rawData; } + /** + * Convert from a plain serializable object + */ + public static fromPlainObject(plainObject: IRequestInquiryBatch): RequestInquiryBatch { + return new RequestInquiryBatch(plainObject); + } + + /** + * Convert to a plain serializable object + */ + public toPlainObject(): IRequestInquiryBatch { + return JSON.parse(JSON.stringify({ + RequestInquiryBatch: { + id: this._id, + created: this._created, + updated: this._updated, + reference_split_the_bill: this._reference_split_the_bill, + request_inquiries: this.request_inquiries, + total_amount_inquired: this._total_amount_inquired, + }, + })); + } + /** * @returns {number} */ diff --git a/src/react/Models/RequestResponse.ts b/src/models/RequestResponse.ts similarity index 98% rename from src/react/Models/RequestResponse.ts rename to src/models/RequestResponse.ts index c1c6ef4e..1a839de8 100644 --- a/src/react/Models/RequestResponse.ts +++ b/src/models/RequestResponse.ts @@ -8,8 +8,8 @@ import { RequestSplitTheBill, RequestResponseType, RequestResponseSubType -} from "../Types/Types"; -import Event, { EventTypeValue } from "../Types/Event"; +} from "~types/Types"; +import Event, { EventTypeValue } from "~types/Event"; export default class RequestResponse implements Event { // the original raw object diff --git a/src/react/Types/RuleCollection.ts b/src/models/RuleCollection.ts similarity index 93% rename from src/react/Types/RuleCollection.ts rename to src/models/RuleCollection.ts index 5303df3e..13ff0fe6 100644 --- a/src/react/Types/RuleCollection.ts +++ b/src/models/RuleCollection.ts @@ -1,40 +1,26 @@ -import { Rule } from "./Rules/Rule"; -import TransactionAmountRule from "./Rules/TransactionAmountRule"; -import ValueRule from "./Rules/ValueRule"; -import TypeRule from "./Rules/TypeRule"; -import AccountRule from "./Rules/AccountRule"; -import { generateGUID } from "../Functions/Utils"; -import { RuleTypes, EventObject, EventTypes } from "./Types"; - -export type RuleCollectionMatchType = "OR" | "AND"; - -export type ValidationResult = { - valid: boolean; - message: string; -}; - -export type EventObjectMatchingRule = { - rule: Rule; - matched: boolean; -}; -export type EventObjectResult = { - item: any; - type: EventTypes; - matches: boolean; - matchingRules: EventObjectMatchingRule[]; -}; -export type RuleCollectionCheckRulesResult = { - ruleResult: boolean; - matchedRules: EventObjectMatchingRule[]; -}; - -export default class RuleCollection { - private id: string | null = null; - private title: string = ""; - private matchType: RuleCollectionMatchType = "OR"; - private rules: Rule[] = []; - private categories: string[] = []; - private enabled: boolean; +import { generateGUID } from "~functions/Utils"; +import { + EventObjectMatchingRule, + EventObjectResult, + IRuleCollection, + RuleCollectionCheckRulesResult, + RuleCollectionMatchType, + ValidationResult, +} from "~types/RuleCollection"; +import AccountRule from "~types/Rules/AccountRule"; +import { Rule } from "~types/Rules/Rule"; +import TransactionAmountRule from "~types/Rules/TransactionAmountRule"; +import TypeRule from "~types/Rules/TypeRule"; +import ValueRule from "~types/Rules/ValueRule"; +import { EventObject } from "~types/Types"; + +export default class RuleCollection implements IRuleCollection { + public id: string | null = null; + public title: string = ""; + public matchType: RuleCollectionMatchType = "OR"; + public rules: Rule[] = []; + public categories: string[] = []; + public enabled: boolean; constructor(rules: Rule[] = [], categories: string[] = []) { this.rules = rules; @@ -87,7 +73,7 @@ export default class RuleCollection { * Ensure a valid ID is set and generate a new one if not */ public ensureId(): void { - if (!this.id || this.id === null || this.id.length === 0) { + if (!this.id || this.id.length === 0) { this.generateId(); } } diff --git a/src/react/Models/SavingsGoal.ts b/src/models/SavingsGoal.ts similarity index 96% rename from src/react/Models/SavingsGoal.ts rename to src/models/SavingsGoal.ts index 4f423bfc..2e98a077 100644 --- a/src/react/Models/SavingsGoal.ts +++ b/src/models/SavingsGoal.ts @@ -1,6 +1,6 @@ import MonetaryAccount from "./MonetaryAccount"; -import { generateGUID } from "../Functions/Utils"; -import { calculateTotalBalance } from "../Components/SavingsGoals/Helpers.js"; +import { generateGUID } from "~functions/Utils"; +import { calculateTotalBalance } from "~components/SavingsGoals/Helpers"; export type SavingsGoalSettings = { startAmount?: number; @@ -31,7 +31,7 @@ export default class SavingsGoal { private _rawData: any; - constructor(savingsGoalObject: any | undefined) { + constructor(savingsGoalObject?: any) { if (!savingsGoalObject) return this; this._rawData = savingsGoalObject; diff --git a/src/react/Pages/AccountInfo.jsx b/src/pages/AccountInfo.tsx similarity index 88% rename from src/react/Pages/AccountInfo.jsx rename to src/pages/AccountInfo.tsx index 3fb0e36d..9bf266bc 100644 --- a/src/react/Pages/AccountInfo.jsx +++ b/src/pages/AccountInfo.tsx @@ -1,6 +1,6 @@ import React from "react"; import { translate } from "react-i18next"; -import Redirect from "react-router-dom/Redirect"; +import { Redirect } from "react-router-dom"; import { connect } from "react-redux"; import Helmet from "react-helmet"; import CirclePicker from "react-color/lib/Circle"; @@ -20,32 +20,32 @@ import DialogTitle from "@material-ui/core/DialogTitle"; import List from "@material-ui/core/List"; import ListItem from "@material-ui/core/ListItem"; import ListItemText from "@material-ui/core/ListItemText"; - import ArrowBackIcon from "@material-ui/icons/ArrowBack"; -import TranslateTypography from "../Components/TranslationHelpers/Typography"; -import LazyAttachmentImage from "../Components/AttachmentImage/LazyAttachmentImage"; -import NavLink from "../Components/Routing/NavLink"; -import CombinedList from "../Components/CombinedList/CombinedList"; -import AccountCard from "../Components/AccountCard"; -import TranslateButton from "../Components/TranslationHelpers/Button"; -import MoneyFormatInput from "../Components/FormFields/MoneyFormatInput"; - -import { filterShareInviteMonetaryAccountResponses, filterShareInviteBankInquiries } from "../Functions/DataFilters"; - -import { openSnackbar } from "../Actions/snackbar"; -import { accountsUpdate, accountsUpdateSettings, accountsDeactivate } from "../Actions/accounts"; -import { paymentInfoUpdate } from "../Actions/payments"; -import { requestResponsesUpdate } from "../Actions/request_responses"; -import { bunqMeTabsUpdate } from "../Actions/bunq_me_tabs"; -import { masterCardActionsUpdate } from "../Actions/master_card_actions"; -import { requestInquiriesUpdate } from "../Actions/request_inquiries"; -import { requestInquiryBatchesUpdate } from "../Actions/request_inquiry_batches"; -import { shareInviteMonetaryAccountInquiriesInfoUpdate } from "../Actions/share_invite_monetary_account_inquiries"; -import { shareInviteMonetaryAccountResponsesInfoUpdate } from "../Actions/share_invite_monetary_account_responses"; -import { shareInviteMonetaryAccountResponseChangeStatus } from "../Actions/share_invite_monetary_account_response"; -import { shareInviteMonetaryAccountInquiryChangeStatus } from "../Actions/share_invite_monetary_account_inquiry"; -import { connectGetPermissions } from "../Functions/ConnectGetPermissions"; +import TranslateTypography from "~components/TranslationHelpers/Typography"; +import LazyAttachmentImage from "~components/AttachmentImage/LazyAttachmentImage"; +import NavLink from "~components/Routing/NavLink"; +import CombinedList from "~components/CombinedList/CombinedList"; +import AccountCard from "~components/AccountCard"; +import TranslateButton from "~components/TranslationHelpers/Button"; +import MoneyFormatInput from "~components/FormFields/MoneyFormatInput"; + +import { filterShareInviteMonetaryAccountResponses, filterShareInviteBankInquiries } from "~functions/DataFilters"; + +import { paymentInfoUpdate } from "~actions/payments"; +import { requestResponsesUpdate } from "~actions/request_responses"; +import { masterCardActionsUpdate } from "~actions/master_card_actions"; +import { requestInquiriesUpdate } from "~actions/request_inquiries"; +import { requestInquiryBatchesUpdate } from "~actions/request_inquiry_batches"; +import { shareInviteMonetaryAccountInquiriesInfoUpdate } from "~actions/share_invite_monetary_account_inquiries"; +import { shareInviteMonetaryAccountResponsesInfoUpdate } from "~actions/share_invite_monetary_account_responses"; +import { shareInviteMonetaryAccountResponseChangeStatus } from "~actions/share_invite_monetary_account_response"; +import { shareInviteMonetaryAccountInquiryChangeStatus } from "~actions/share_invite_monetary_account_inquiry"; +import { connectGetPermissions } from "~functions/ConnectGetPermissions"; +import { accountsDeactivate, accountsUpdate, accountsUpdateSettings } from "~store/accounts/thunks"; +import { bunqMeTabsUpdate } from "~store/bunqMeTabs/thunks"; +import { AppDispatch, ReduxState } from "~store/index"; +import { actions as snackbarActions } from "~store/snackbar"; const styles = { paper: { @@ -87,7 +87,7 @@ const styles = { } }; -const PersonChip = ({ alias, BunqJSClient, ...otherProps }) => { +const PersonChip = ({ alias, ...otherProps }) => { return ( { @@ -107,7 +106,17 @@ const PersonChip = ({ alias, BunqJSClient, ...otherProps }) => { ); }; -class AccountInfo extends React.Component { +interface IState { + [key: string]: any; +} + +interface IProps { + [key: string]: any; +} + +class AccountInfo extends React.Component & ReturnType & IProps> { + state: IState; + constructor(props, context) { super(props, context); this.state = { @@ -332,7 +341,7 @@ class AccountInfo extends React.Component { return coOwner.alias.uuid !== user.avatar.anchor_uuid; }) .map(coOwner => { - return ; + return ; }); } else { if (filteredInviteResponses.length > 0) { @@ -345,7 +354,6 @@ class AccountInfo extends React.Component { return null; return ( { this.props.shareInviteMonetaryAccountResponseChangeStatus( @@ -364,7 +372,6 @@ class AccountInfo extends React.Component { profileIconList = filteredShareInquiries.map(filteredShareInquiry => { return ( { this.props.shareInviteMonetaryAccountInquiryChangeStatus( @@ -416,7 +423,7 @@ class AccountInfo extends React.Component { }; content = ( - + <> {t("Cancel account")} @@ -526,7 +533,6 @@ class AccountInfo extends React.Component { - + ); } else { content = ( @@ -579,7 +584,7 @@ class AccountInfo extends React.Component { } } -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return { hideBalance: state.options.hide_balance, @@ -598,21 +603,19 @@ const mapStateToProps = state => { }; }; -const mapDispatchToProps = (dispatch, ownProps) => { - const { BunqJSClient } = ownProps; +const mapDispatchToProps = (dispatch: AppDispatch) => { return { - openSnackbar: message => dispatch(openSnackbar(message)), + openSnackbar: message => dispatch(snackbarActions.open({ message })), - accountsUpdate: userId => dispatch(accountsUpdate(BunqJSClient, userId)), + accountsUpdate: userId => dispatch(accountsUpdate(userId)), deactivateAccount: (userId, accountId, reason, accountType) => - dispatch(accountsDeactivate(BunqJSClient, userId, accountId, reason, accountType)), + dispatch(accountsDeactivate(userId, accountId, reason, accountType)), updateSettings: (userId, accountId, settings, accountType) => - dispatch(accountsUpdateSettings(BunqJSClient, userId, accountId, settings, accountType)), + dispatch(accountsUpdateSettings(userId, accountId, settings, accountType)), shareInviteMonetaryAccountResponseChangeStatus: (userId, shareInviteMonetaryAccountResponseId, status) => dispatch( shareInviteMonetaryAccountResponseChangeStatus( - BunqJSClient, userId, shareInviteMonetaryAccountResponseId, status @@ -626,7 +629,6 @@ const mapDispatchToProps = (dispatch, ownProps) => { ) => dispatch( shareInviteMonetaryAccountInquiryChangeStatus( - BunqJSClient, userId, accountId, shareInviteMonetaryAccountInquiryId, @@ -635,19 +637,19 @@ const mapDispatchToProps = (dispatch, ownProps) => { ), shareInviteMonetaryAccountInquiriesInfoUpdate: (userId, accountId) => - dispatch(shareInviteMonetaryAccountInquiriesInfoUpdate(BunqJSClient, userId, accountId)), + dispatch(shareInviteMonetaryAccountInquiriesInfoUpdate(userId, accountId)), shareInviteMonetaryAccountResponsesInfoUpdate: (userId, accountId) => - dispatch(shareInviteMonetaryAccountResponsesInfoUpdate(BunqJSClient, userId)), - paymentsUpdate: (userId, accountId) => dispatch(paymentInfoUpdate(BunqJSClient, userId, accountId)), + dispatch(shareInviteMonetaryAccountResponsesInfoUpdate(userId)), + paymentsUpdate: (userId, accountId) => dispatch(paymentInfoUpdate(userId, accountId)), requestInquiriesUpdate: (userId, accountId) => - dispatch(requestInquiriesUpdate(BunqJSClient, userId, accountId)), + dispatch(requestInquiriesUpdate(userId, accountId)), requestInquiryBatchesUpdate: (userId, accountId) => - dispatch(requestInquiryBatchesUpdate(BunqJSClient, userId, accountId)), + dispatch(requestInquiryBatchesUpdate(userId, accountId)), requestResponsesUpdate: (userId, accountId) => - dispatch(requestResponsesUpdate(BunqJSClient, userId, accountId)), + dispatch(requestResponsesUpdate(userId, accountId)), masterCardActionsUpdate: (userId, accountId) => - dispatch(masterCardActionsUpdate(BunqJSClient, userId, accountId)), - bunqMeTabsUpdate: (userId, accountId) => dispatch(bunqMeTabsUpdate(BunqJSClient, userId, accountId)) + dispatch(masterCardActionsUpdate(userId, accountId)), + bunqMeTabsUpdate: (userId, accountId) => dispatch(bunqMeTabsUpdate(userId, accountId)) }; }; diff --git a/src/react/Pages/AddAccount.jsx b/src/pages/AddAccount.tsx similarity index 89% rename from src/react/Pages/AddAccount.jsx rename to src/pages/AddAccount.tsx index 8d648392..83f49495 100644 --- a/src/react/Pages/AddAccount.jsx +++ b/src/pages/AddAccount.tsx @@ -15,14 +15,15 @@ import RadioGroup from "@material-ui/core/RadioGroup"; import ArrowBackIcon from "@material-ui/icons/ArrowBack"; -import { openSnackbar } from "../Actions/snackbar"; -import { createAccount } from "../Actions/accounts"; +import MoneyFormatInput from "~components/FormFields/MoneyFormatInput"; +import TranslateButton from "~components/TranslationHelpers/Button"; +import TranslateTypography from "~components/TranslationHelpers/Typography"; -import MoneyFormatInput from "../Components/FormFields/MoneyFormatInput"; -import TranslateButton from "../Components/TranslationHelpers/Button"; -import TranslateTypography from "../Components/TranslationHelpers/Typography"; +import { createAccount } from "~store/accounts/thunks"; +import { AppDispatch, ReduxState } from "~store/index"; +import { actions as snackbarActions } from "~store/snackbar"; -const styles = { +const styles: any = { bigAvatar: { width: 60, height: 60 @@ -46,7 +47,17 @@ const styles = { } }; -class AddAccount extends React.Component { +interface IState { + [key: string]: any; +} + +interface IProps { + [key: string]: any; +} + +class AddAccount extends React.Component & ReturnType & IProps> { + state: IState; + constructor(props, context) { super(props, context); this.state = { @@ -246,24 +257,23 @@ class AddAccount extends React.Component { } } -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return { accounts: state.accounts.accounts, accountsLoading: state.accounts.loading, - accountsCreateLoading: state.accounts.create_loading, + accountsCreateLoading: state.accounts.createLoading, user: state.user.user }; }; -const mapDispatchToProps = (dispatch, ownProps) => { - const { BunqJSClient } = ownProps; +const mapDispatchToProps = (dispatch: AppDispatch) => { return { createAccount: (userId, currency, description, dailyLimit, color, savingsGoal, accountType) => dispatch( - createAccount(BunqJSClient, userId, currency, description, dailyLimit, color, savingsGoal, accountType) + createAccount(userId, currency, description, dailyLimit, color, savingsGoal, accountType) ), - openSnackbar: message => dispatch(openSnackbar(message)) + openSnackbar: message => dispatch(snackbarActions.open({ message })), }; }; diff --git a/src/react/Pages/ApplicationInfo.jsx b/src/pages/ApplicationInfo.tsx similarity index 86% rename from src/react/Pages/ApplicationInfo.jsx rename to src/pages/ApplicationInfo.tsx index 1cbeb014..5fab84e4 100644 --- a/src/react/Pages/ApplicationInfo.jsx +++ b/src/pages/ApplicationInfo.tsx @@ -18,16 +18,18 @@ const remote = require("electron").remote; const shell = require("electron").shell; const app = remote.app; -import NavLink from "../Components/Routing/NavLink"; -import TranslateButton from "../Components/TranslationHelpers/Button"; -import TranslateTypography from "../Components/TranslationHelpers/Typography"; +import NavLink from "~components/Routing/NavLink"; +import TranslateButton from "~components/TranslationHelpers/Button"; +import TranslateTypography from "~components/TranslationHelpers/Typography"; -import { openSnackbar } from "../Actions/snackbar"; -import { allReleases } from "../Functions/VersionChecker"; -import { humanReadableDate } from "../Functions/Utils"; -import Logger from "../Functions/Logger"; +import { allReleases } from "~functions/VersionChecker"; +import { humanReadableDate } from "~functions/Utils"; +import Logger from "~functions/Logger"; +import { AppDispatch, ReduxState } from "~store/index"; -const styles = { +import { actions as snackbarActions } from "~store/snackbar"; + +const styles: any = { avatar: { width: 55, height: 55 @@ -37,7 +39,17 @@ const styles = { } }; -class ApplicationInfo extends React.Component { +interface IState { + [key: string]: any; +} + +interface IProps { + [key: string]: any; +} + +class ApplicationInfo extends React.Component & ReturnType & IProps> { + state: IState; + constructor(props, context) { super(props, context); this.state = { @@ -162,14 +174,13 @@ class ApplicationInfo extends React.Component { } } -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return {}; }; -const mapDispatchToProps = (dispatch, ownProps) => { - const { BunqJSClient } = ownProps; +const mapDispatchToProps = (dispatch: AppDispatch) => { return { - openSnackbar: message => dispatch(openSnackbar(message)) + openSnackbar: message => dispatch(snackbarActions.open({ message })), }; }; diff --git a/src/react/Pages/BunqMePersonal/BunqMePersonal.jsx b/src/pages/BunqMePersonal/BunqMePersonal.tsx similarity index 93% rename from src/react/Pages/BunqMePersonal/BunqMePersonal.jsx rename to src/pages/BunqMePersonal/BunqMePersonal.tsx index 6d544344..e6a1be59 100644 --- a/src/react/Pages/BunqMePersonal/BunqMePersonal.jsx +++ b/src/pages/BunqMePersonal/BunqMePersonal.tsx @@ -10,12 +10,12 @@ import List from "@material-ui/core/List"; import ListItem from "@material-ui/core/ListItem"; import ListItemIcon from "@material-ui/core/ListItemIcon"; import ListItemText from "@material-ui/core/ListItemText"; - import UrlIcon from "@material-ui/icons/Link"; +import { AppDispatch, ReduxState } from "~store/index"; import LinkPreviewField from "./LinkPreviewField"; -import QRCode from "../../Components/QR/QRCode"; -import MoneyFormatInput from "../../Components/FormFields/MoneyFormatInput"; +import QRCode from "~components/QR/QRCode"; +import MoneyFormatInput from "~components/FormFields/MoneyFormatInput"; const styles = { headerTypography: { @@ -63,7 +63,17 @@ const styles = { } }; -class BunqMePersonal extends React.Component { +interface IState { + [key: string]: any; +} + +interface IProps { + [key: string]: any; +} + +class BunqMePersonal extends React.Component & ReturnType & IProps> { + state: IState; + constructor(props, context) { super(props, context); this.state = { @@ -226,15 +236,14 @@ class BunqMePersonal extends React.Component { } } -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return { user: state.user.user, accounts: state.accounts.accounts }; }; -const mapDispatchToProps = (dispatch, props) => { - const { BunqJSClient } = props; +const mapDispatchToProps = (dispatch: AppDispatch) => { return {}; }; diff --git a/src/react/Pages/BunqMePersonal/LinkPreviewField.jsx b/src/pages/BunqMePersonal/LinkPreviewField.tsx similarity index 85% rename from src/react/Pages/BunqMePersonal/LinkPreviewField.jsx rename to src/pages/BunqMePersonal/LinkPreviewField.tsx index 5a54b981..9f8516ae 100644 --- a/src/react/Pages/BunqMePersonal/LinkPreviewField.jsx +++ b/src/pages/BunqMePersonal/LinkPreviewField.tsx @@ -1,14 +1,13 @@ import React from "react"; -import PropTypes from "prop-types"; import { withStyles } from "@material-ui/core/styles"; import Paper from "@material-ui/core/Paper"; import InputBase from "@material-ui/core/InputBase"; import Divider from "@material-ui/core/Divider"; import IconButton from "@material-ui/core/IconButton"; - import ClearIcon from "@material-ui/icons/Clear"; import CopyIcon from "@material-ui/icons/FileCopy"; -import CopyToClipboardWrap from "../../Components/CopyToClipboardWrap"; + +import CopyToClipboardWrap from "~components/CopyToClipboardWrap"; const styles = { root: { @@ -53,11 +52,4 @@ const LinkPreviewField = props => { ); }; -LinkPreviewField.propTypes = { - classes: PropTypes.object.isRequired, - - value: PropTypes.string.isRequired, - reset: PropTypes.func.isRequired -}; - export default withStyles(styles)(LinkPreviewField); diff --git a/src/react/Pages/BunqMeTab/BunqMeTab.jsx b/src/pages/BunqMeTab/BunqMeTab.tsx similarity index 80% rename from src/react/Pages/BunqMeTab/BunqMeTab.jsx rename to src/pages/BunqMeTab/BunqMeTab.tsx index 9da44ef0..048348ce 100644 --- a/src/react/Pages/BunqMeTab/BunqMeTab.jsx +++ b/src/pages/BunqMeTab/BunqMeTab.tsx @@ -10,19 +10,29 @@ import IconButton from "@material-ui/core/IconButton"; import CloseIcon from "@material-ui/icons/Close"; import AddIcon from "@material-ui/icons/Add"; -import AccountList from "../../Components/AccountList/AccountList"; -import BunqMeTabList from "../../Components/BunqMeTabList"; +import AccountList from "~components/AccountList/AccountList"; +import BunqMeTabList from "~components/BunqMeTabList"; +import { bunqMeTabsUpdate } from "~store/bunqMeTabs/thunks"; +import { AppDispatch, ReduxState } from "~store/index"; import BunqMeTabForm from "./BunqMeTabForm"; -import { bunqMeTabsUpdate } from "../../Actions/bunq_me_tabs"; - const styles = { paper: { marginBottom: 20 } }; -class BunqMeTab extends React.Component { +interface IState { + [key: string]: any; +} + +interface IProps { + [key: string]: any; +} + +class BunqMeTab extends React.Component & ReturnType & IProps> { + state: IState; + constructor(props, context) { super(props, context); this.state = { @@ -57,19 +67,18 @@ class BunqMeTab extends React.Component { - + - + { +const mapStateToProps = (state: ReduxState) => { return { accounts: state.accounts.accounts, selectedAccount: state.accounts.selected_account, @@ -97,10 +106,9 @@ const mapStateToProps = state => { }; }; -const mapDispatchToProps = (dispatch, props) => { - const { BunqJSClient } = props; +const mapDispatchToProps = (dispatch: AppDispatch) => { return { - bunqMeTabsUpdate: (userId, accountId) => dispatch(bunqMeTabsUpdate(BunqJSClient, userId, accountId)) + bunqMeTabsUpdate: (userId, accountId) => dispatch(bunqMeTabsUpdate(userId, accountId)) }; }; diff --git a/src/react/Pages/BunqMeTab/BunqMeTabForm.jsx b/src/pages/BunqMeTab/BunqMeTabForm.tsx similarity index 89% rename from src/react/Pages/BunqMeTab/BunqMeTabForm.jsx rename to src/pages/BunqMeTab/BunqMeTabForm.tsx index 9976c0fd..93c20d43 100644 --- a/src/react/Pages/BunqMeTab/BunqMeTabForm.jsx +++ b/src/pages/BunqMeTab/BunqMeTabForm.tsx @@ -5,16 +5,18 @@ import { connect } from "react-redux"; import TextField from "@material-ui/core/TextField"; import FormControl from "@material-ui/core/FormControl"; -import AccountSelectorDialog from "../../Components/FormFields/AccountSelectorDialog"; -import MoneyFormatInput from "../../Components/FormFields/MoneyFormatInput"; -import TranslateTypography from "../../Components/TranslationHelpers/Typography"; -import TranslateButton from "../../Components/TranslationHelpers/Button"; +import AccountSelectorDialog from "~components/FormFields/AccountSelectorDialog"; +import MoneyFormatInput from "~components/FormFields/MoneyFormatInput"; +import TranslateTypography from "~components/TranslationHelpers/Typography"; +import TranslateButton from "~components/TranslationHelpers/Button"; +import { bunqMeTabSend } from "~store/bunqMeTab/thunks"; + +import { actions as snackbarActions } from "~store/snackbar"; +import { actions as bunqMeTabsActions } from "~store/bunqMeTabs"; -import { openSnackbar } from "../../Actions/snackbar"; -import { bunqMeTabSend } from "../../Actions/bunq_me_tab"; import ConfirmationDialog from "./ConfirmationDialog"; -const styles = { +const styles: any = { payButton: { width: "100%" }, @@ -27,7 +29,9 @@ const styles = { } }; -class BunqMeTabForm extends React.Component { +class BunqMeTabForm extends React.Component { + state: any; + constructor(props, context) { super(props, context); this.state = { @@ -165,7 +169,6 @@ class BunqMeTabForm extends React.Component { value={this.state.selectedAccount} onChange={this.handleChange("selectedAccount")} accounts={this.props.accounts} - BunqJSClient={this.props.BunqJSClient} /> { }; const mapDispatchToProps = (dispatch, props) => { - const { BunqJSClient } = props; return { bunqMeTabSend: (userId, accountId, description, amount, options) => - dispatch(bunqMeTabSend(BunqJSClient, userId, accountId, description, amount, options)), - openSnackbar: message => dispatch(openSnackbar(message)) + dispatch(bunqMeTabSend(userId, accountId, description, amount, options)), + openSnackbar: message => dispatch(snackbarActions.open({ message })) }; }; diff --git a/src/react/Pages/BunqMeTab/ConfirmationDialog.jsx b/src/pages/BunqMeTab/ConfirmationDialog.tsx similarity index 86% rename from src/react/Pages/BunqMeTab/ConfirmationDialog.jsx rename to src/pages/BunqMeTab/ConfirmationDialog.tsx index fa1a5f58..2b02629d 100644 --- a/src/react/Pages/BunqMeTab/ConfirmationDialog.jsx +++ b/src/pages/BunqMeTab/ConfirmationDialog.tsx @@ -8,11 +8,19 @@ import DialogContent from "@material-ui/core/DialogContent"; import DialogTitle from "@material-ui/core/DialogTitle"; import Dialog from "@material-ui/core/Dialog"; -import { formatMoney } from "../../Functions/Utils"; +import { formatMoney } from "~functions/Utils"; -import TranslateButton from "../../Components/TranslationHelpers/Button"; +import TranslateButton from "~components/TranslationHelpers/Button"; -class ConfirmationDialog extends React.Component { +interface IState { + [key: string]: any; +} + +interface IProps { + [key: string]: any; +} + +class ConfirmationDialog extends React.Component { render() { const { confirmModalOpen, description, amount, t } = this.props; diff --git a/src/react/Pages/Cards/CardListItem.jsx b/src/pages/Cards/CardListItem.tsx similarity index 95% rename from src/react/Pages/Cards/CardListItem.jsx rename to src/pages/Cards/CardListItem.tsx index 4622b189..89b345fe 100644 --- a/src/react/Pages/Cards/CardListItem.jsx +++ b/src/pages/Cards/CardListItem.tsx @@ -1,4 +1,5 @@ import React from "react"; +import Card from "~models/Card"; const styles = { cardWrapper: {}, @@ -61,7 +62,7 @@ export const getCardTypeImage = (card) => { return { cardImage, cardType }; }; -class CardListItem extends React.Component { +class CardListItem extends React.Component<{ card: Card; onClick: any }> { constructor(props, context) { super(props, context); this.state = {}; diff --git a/src/react/Pages/Cards/Cards.jsx b/src/pages/Cards/Cards.tsx similarity index 94% rename from src/react/Pages/Cards/Cards.jsx rename to src/pages/Cards/Cards.tsx index a3986587..f5b74793 100644 --- a/src/react/Pages/Cards/Cards.jsx +++ b/src/pages/Cards/Cards.tsx @@ -16,16 +16,18 @@ import Typography from "@material-ui/core/Typography"; import CircularProgress from "@material-ui/core/CircularProgress"; import DeleteIcon from "@material-ui/icons/Delete"; +import { AppDispatch, ReduxState } from "~store/index"; import CardListItem from "./CardListItem"; import CvcCodeListItem from "./CvcCodeListItem"; import VirtualAccountNumbersDialog from "./VirtualAccountNumbersDialog"; -import TranslateTypography from "../../Components/TranslationHelpers/Typography"; -import AccountSelectorDialog from "../../Components/FormFields/AccountSelectorDialog"; +import TranslateTypography from "~components/TranslationHelpers/Typography"; +import AccountSelectorDialog from "~components/FormFields/AccountSelectorDialog"; -import { getCardDescription } from "../../Functions/Utils"; -import { cardStatus, cardOrderStatus } from "../../Functions/EventStatusTexts"; -import { cardsUpdate, cardsSetCardOrder, cardsAssignAccounts } from "../../Actions/cards"; +import { getCardDescription } from "~functions/Utils"; +import { cardStatus, cardOrderStatus } from "~functions/EventStatusTexts"; +import { cardsUpdate, cardsAssignAccounts } from "~store/cards/thunks"; +import { actions as cardsActions } from "~store/cards"; const styles = { gridContainer: { @@ -50,7 +52,17 @@ const styles = { } }; -class Cards extends React.Component { +interface IState { + [key: string]: any; +} + +interface IProps { + [key: string]: any; +} + +class Cards extends React.Component & ReturnType & IProps> { + state: IState; + constructor(props, context) { super(props, context); this.state = { @@ -255,7 +267,6 @@ class Cards extends React.Component { // then generate the items seperately cardItems = filteredCards.map((card, index) => ( @@ -310,7 +321,7 @@ class Cards extends React.Component { : ""; const secondaryAssignmentSelection = secondaryAccountIndex !== "" && ( - + <> {t("Secondary account")} @@ -325,14 +336,13 @@ class Cards extends React.Component { value={secondaryAccountIndex} onChange={this.handleAccountChange("SECONDARY")} accounts={this.props.accounts} - BunqJSClient={this.props.BunqJSClient} hiddenConnectTypes={["draftOnly", "showOnly"]} /> - + ); const lastDigitsComponent = cardInfo.primary_account_number_four_digit && ( - + <> - + ); const countryComponent = cardInfo.country && ( - + <> - + ); return ( @@ -388,7 +398,6 @@ class Cards extends React.Component { value={primaryAccountIndex} onChange={this.handleAccountChange("PRIMARY")} accounts={this.props.accounts} - BunqJSClient={this.props.BunqJSClient} hiddenConnectTypes={["draftOnly", "showOnly"]} /> @@ -435,7 +444,7 @@ class Cards extends React.Component { } } -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return { user: state.user.user, limitedPermissions: state.user.limited_permissions, @@ -447,10 +456,10 @@ const mapStateToProps = state => { }; }; -const mapDispatchToProps = dispatch => { +const mapDispatchToProps = (dispatch: AppDispatch) => { return { cardsUpdate: userId => dispatch(cardsUpdate(userId)), - cardsSetCardOrder: cardOrder => dispatch(cardsSetCardOrder(cardOrder)), + cardsSetCardOrder: cardOrder => dispatch(cardsActions.setOrder(cardOrder)), cardsAssignAccounts: (user_id, card_id, assignment) => dispatch(cardsAssignAccounts(user_id, card_id, assignment)) diff --git a/src/react/Pages/Cards/CvcCodeListItem.jsx b/src/pages/Cards/CvcCodeListItem.tsx similarity index 83% rename from src/react/Pages/Cards/CvcCodeListItem.jsx rename to src/pages/Cards/CvcCodeListItem.tsx index 960bdae8..2197110f 100644 --- a/src/react/Pages/Cards/CvcCodeListItem.jsx +++ b/src/pages/Cards/CvcCodeListItem.tsx @@ -9,9 +9,20 @@ import ListItemSecondaryAction from "@material-ui/core/ListItemSecondaryAction"; import RefreshIcon from "@material-ui/icons/Refresh"; import VisibilityIcon from "@material-ui/icons/Visibility"; -import { cardGenerateCvc2, cardUpdateCvc2Codes } from "../../Actions/card_cvc2"; +import { cardGenerateCvc2, cardUpdateCvc2Codes } from "~store/cardCvc2/thunks"; +import { AppDispatch, ReduxState } from "~store/index"; + +interface IState { + [key: string]: any; +} + +interface IProps { + [key: string]: any; +} + +class CvcCodeListItem extends React.Component & ReturnType & IProps> { + state: IState; -class CvcCodeListItem extends React.Component { constructor(props, context) { super(props, context); this.state = {}; @@ -46,7 +57,7 @@ class CvcCodeListItem extends React.Component { } return ( - + <> @@ -60,12 +71,12 @@ class CvcCodeListItem extends React.Component { - + ); } } -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return { user: state.user.user, cvcCodes: state.card_cvc2.cvc2_codes, @@ -76,7 +87,7 @@ const mapStateToProps = state => { }; }; -const mapDispatchToProps = dispatch => { +const mapDispatchToProps = (dispatch: AppDispatch) => { return { cardUpdateCvc2Codes: (userId, cardId) => dispatch(cardUpdateCvc2Codes(userId, cardId)), cardGenerateCvc2: (userId, cardId) => dispatch(cardGenerateCvc2(userId, cardId)) diff --git a/src/react/Pages/Cards/VirtualAccountNumbersDialog.jsx b/src/pages/Cards/VirtualAccountNumbersDialog.tsx similarity index 82% rename from src/react/Pages/Cards/VirtualAccountNumbersDialog.jsx rename to src/pages/Cards/VirtualAccountNumbersDialog.tsx index 3218324a..1afec01d 100644 --- a/src/react/Pages/Cards/VirtualAccountNumbersDialog.jsx +++ b/src/pages/Cards/VirtualAccountNumbersDialog.tsx @@ -8,7 +8,8 @@ import List from "@material-ui/core/List"; import ListItem from "@material-ui/core/ListItem"; import ListItemText from "@material-ui/core/ListItemText"; -import AccountListItem from "../../Components/AccountList/AccountListItem"; +import AccountListItem from "~components/AccountList/AccountListItem"; +import { ReduxState } from "~store/index"; const styles = { list: { @@ -16,7 +17,17 @@ const styles = { } }; -class VirtualAccountNumbersDialog extends React.Component { +interface IState { + [key: string]: any; +} + +interface IProps { + [key: string]: any; +} + +class VirtualAccountNumbersDialog extends React.Component & ReturnType & IProps> { + state: IState; + constructor(props, context) { super(props, context); this.state = { @@ -41,7 +52,7 @@ class VirtualAccountNumbersDialog extends React.Component { }); return ( - + <> {accountInfo && } - + ); }) ) : ( @@ -59,7 +70,7 @@ class VirtualAccountNumbersDialog extends React.Component { ); return ( - + <> @@ -68,12 +79,12 @@ class VirtualAccountNumbersDialog extends React.Component { {virtualCardComponents} - + ); } } -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return { accounts: state.accounts.accounts }; diff --git a/src/react/Pages/CategoryDashboard/CategoryDashboard.jsx b/src/pages/CategoryDashboard/CategoryDashboard.tsx similarity index 85% rename from src/react/Pages/CategoryDashboard/CategoryDashboard.jsx rename to src/pages/CategoryDashboard/CategoryDashboard.tsx index cb059734..04bd360d 100644 --- a/src/react/Pages/CategoryDashboard/CategoryDashboard.jsx +++ b/src/pages/CategoryDashboard/CategoryDashboard.tsx @@ -6,17 +6,18 @@ import { translate } from "react-i18next"; import Grid from "@material-ui/core/Grid"; import Paper from "@material-ui/core/Paper"; -import CategoryEditor from "../../Components/Categories/CategoryEditor"; -import CategoryChip from "../../Components/Categories/CategoryChip"; -import ImportDialog from "../../Components/ImportDialog"; -import ExportDialog from "../../Components/ExportDialog"; -import TranslateTypography from "../../Components/TranslationHelpers/Typography"; -import TranslateButton from "../../Components/TranslationHelpers/Button"; - -import { removeCategory, removeCategoryConnection, setCategory } from "../../Actions/categories"; -import { openSnackbar } from "../../Actions/snackbar"; - -const styles = { +import CategoryEditor from "~components/Categories/CategoryEditor"; +import CategoryChip from "~components/Categories/CategoryChip"; +import ImportDialog from "~components/ImportDialog"; +import ExportDialog from "~components/ExportDialog"; +import TranslateTypography from "~components/TranslationHelpers/Typography"; +import TranslateButton from "~components/TranslationHelpers/Button"; + +import { actions as categoriesActions } from "~store/categories"; +import { AppDispatch, ReduxState } from "~store/index"; +import { actions as snackbarActions } from "~store/snackbar"; + +const styles: any = { chipWrapper: { display: "flex", justifyContent: "center", @@ -28,7 +29,17 @@ const styles = { } }; -class CategoryDashboard extends React.Component { +interface IState { + [key: string]: any; +} + +interface IProps { + [key: string]: any; +} + +class CategoryDashboard extends React.Component & ReturnType & IProps> { + state: IState; + constructor(props, context) { super(props, context); this.state = { @@ -217,7 +228,7 @@ class CategoryDashboard extends React.Component { } } -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return { categories: state.categories.categories, categories_last_udate: state.categories.last_update, @@ -225,12 +236,12 @@ const mapStateToProps = state => { }; }; -const mapDispatchToProps = dispatch => { +const mapDispatchToProps = (dispatch: AppDispatch) => { return { - openSnackbar: message => dispatch(openSnackbar(message)), - removeCategory: (...params) => dispatch(removeCategory(...params)), - removeCategoryConnection: (...params) => dispatch(removeCategoryConnection(...params)), - setCategory: (...params) => dispatch(setCategory(...params)) + openSnackbar: message => dispatch(snackbarActions.open({ message })), + removeCategory: (...params) => dispatch(categoriesActions.removeCategory(...params)), + removeCategoryConnection: (...params) => dispatch(categoriesActions.removeCategoryConnection(...params)), + setCategory: (...params) => dispatch(categoriesActions.setCategory(...params)) }; }; diff --git a/src/react/Pages/Connect/BudgetFields.jsx b/src/pages/Connect/BudgetFields.tsx similarity index 92% rename from src/react/Pages/Connect/BudgetFields.jsx rename to src/pages/Connect/BudgetFields.tsx index e9eec22f..3f919c7d 100644 --- a/src/react/Pages/Connect/BudgetFields.jsx +++ b/src/pages/Connect/BudgetFields.tsx @@ -7,8 +7,8 @@ import Switch from "@material-ui/core/Switch"; import FormControl from "@material-ui/core/FormControl"; import FormControlLabel from "@material-ui/core/FormControlLabel"; -import MoneyFormatInput from "../../Components/FormFields/MoneyFormatInput"; -import TranslateMenuItem from "../../Components/TranslationHelpers/MenuItem"; +import MoneyFormatInput from "~components/FormFields/MoneyFormatInput"; +import TranslateMenuItem from "~components/TranslationHelpers/MenuItem"; const styles = { formControl: { @@ -38,7 +38,7 @@ export default props => { {props.setBudget ? ( - + <> & ReturnType & IProps> { + state: IState; + passwordInput: RefObject; + passwordRepeatInput: RefObject; + constructor(props, context) { super(props, context); this.state = { @@ -159,17 +172,23 @@ class LoginPassword extends React.Component { toggleShowPassword = event => { this.setState({ showPassword: !this.state.showPassword }); setTimeout(() => { - this.passwordInput.focus(); - this.passwordInput.selectionStart = 1000; - this.passwordInput.selectionEnd = 1000; + // @ts-ignore + this.passwordInput.current.focus(); + // @ts-ignore + this.passwordInput.current.selectionStart = 1000; + // @ts-ignore + this.passwordInput.current.selectionEnd = 1000; }, 300); }; toggleShowPasswordRepeat = event => { this.setState({ showPasswordRepeat: !this.state.showPasswordRepeat }); setTimeout(() => { - this.passwordRepeatInput.focus(); - this.passwordRepeatInput.selectionStart = 1000; - this.passwordRepeatInput.selectionEnd = 1000; + // @ts-ignore + this.passwordRepeatInput.current.focus(); + // @ts-ignore + this.passwordRepeatInput.current.selectionStart = 1000; + // @ts-ignore + this.passwordRepeatInput.current.selectionEnd = 1000; }, 300); }; @@ -220,7 +239,7 @@ class LoginPassword extends React.Component { registrationLoading === true; let cardContent = registrationLoading ? ( - + Loading @@ -230,7 +249,7 @@ class LoginPassword extends React.Component { ) : ( - + {isExistingInstallation ? t("Enter your password") : t("Enter a password")} @@ -332,7 +351,7 @@ class LoginPassword extends React.Component { ) : null} {(hasStoredApiKey === true && useNoPassword === true) || hasStoredApiKey === false ? ( - + <> - + ) : ( )} @@ -386,10 +405,10 @@ class LoginPassword extends React.Component { } } -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return { statusMessage: state.application.status_message, - + // @ts-ignore analyticsEnabled: state.options.analytics_enabled, storedApiKeys: state.registration.stored_api_keys, @@ -403,12 +422,14 @@ const mapStateToProps = state => { }; }; -const mapDispatchToProps = dispatch => { +const mapDispatchToProps = (dispatch: AppDispatch) => { return { // use no password + // @ts-ignore useNoPasswordLogin: () => dispatch(registrationSkipPassword()), // use password + // @ts-ignore usePasswordLogin: password => dispatch(registrationSetPassword(password)), // clear api key from bunqjsclient and bunqdesktop diff --git a/src/react/Pages/MasterCardActionInfo.jsx b/src/pages/MasterCardActionInfo.tsx similarity index 88% rename from src/react/Pages/MasterCardActionInfo.jsx rename to src/pages/MasterCardActionInfo.tsx index a432975d..7123d855 100644 --- a/src/react/Pages/MasterCardActionInfo.jsx +++ b/src/pages/MasterCardActionInfo.tsx @@ -19,20 +19,21 @@ import BookmarkIcon from "@material-ui/icons/Bookmark"; import SaveIcon from "@material-ui/icons/Save"; import FilterIcon from "@material-ui/icons/FilterList"; -import FilterCreationDialog from "../Components/FilterCreationDialog"; -import PDFExportHelper from "../Components/PDFExportHelper/PDFExportHelper"; -import ExportDialog from "../Components/ExportDialog"; -import SpeedDial from "../Components/SpeedDial"; -import TransactionHeader from "../Components/TransactionHeader"; -import MoneyAmountLabel from "../Components/MoneyAmountLabel"; -import CategorySelectorDialog from "../Components/Categories/CategorySelectorDialog"; -import CategoryChips from "../Components/Categories/CategoryChips"; -import NoteTextForm from "../Components/NoteTexts/NoteTextForm"; - -import { formatMoney, humanReadableDate } from "../Functions/Utils"; -import { masterCardActionText, masterCardActionParser } from "../Functions/EventStatusTexts"; -import { masterCardActionInfoUpdate } from "../Actions/master_card_action_info"; -import { applicationSetPDFMode } from "../Actions/application"; +import FilterCreationDialog from "~components/FilterCreationDialog"; +import PDFExportHelper from "~components/PDFExportHelper/PDFExportHelper"; +import ExportDialog from "~components/ExportDialog"; +import SpeedDial from "~components/SpeedDial"; +import TransactionHeader from "~components/TransactionHeader"; +import MoneyAmountLabel from "~components/MoneyAmountLabel"; +import CategorySelectorDialog from "~components/Categories/CategorySelectorDialog"; +import CategoryChips from "~components/Categories/CategoryChips"; +import NoteTextForm from "~components/NoteTexts/NoteTextForm"; + +import { formatMoney, humanReadableDate } from "~functions/Utils"; +import { masterCardActionText, masterCardActionParser } from "~functions/EventStatusTexts"; +import { masterCardActionInfoUpdate } from "~actions/master_card_action_info"; +import { actions as applicationActions } from "~store/application"; +import { AppDispatch, ReduxState } from "~store/index"; const styles = { btn: {}, @@ -48,7 +49,17 @@ const styles = { } }; -class MasterCardActionInfo extends React.Component { +interface IState { + [key: string]: any; +} + +interface IProps { + [key: string]: any; +} + +class MasterCardActionInfo extends React.Component & ReturnType & IProps> { + state: IState; + constructor(props, context) { super(props, context); this.state = { @@ -155,12 +166,11 @@ class MasterCardActionInfo extends React.Component { ); } - noteTextsForm = ; + noteTextsForm = ; content = ( {isSettled === false && ( - + <> - + )} @@ -313,7 +323,7 @@ class MasterCardActionInfo extends React.Component { } } -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return { user: state.user.user, @@ -326,13 +336,12 @@ const mapStateToProps = state => { }; }; -const mapDispatchToProps = (dispatch, ownProps) => { - const { BunqJSClient } = ownProps; +const mapDispatchToProps = (dispatch: AppDispatch) => { return { - applicationSetPDFMode: enabled => dispatch(applicationSetPDFMode(enabled)), + applicationSetPDFMode: enabled => dispatch(applicationActions.setPdfMode(enabled)), masterCardActionInfoUpdate: (user_id, account_id, master_card_action_id) => - dispatch(masterCardActionInfoUpdate(BunqJSClient, user_id, account_id, master_card_action_id)) + dispatch(masterCardActionInfoUpdate(user_id, account_id, master_card_action_id)) }; }; diff --git a/src/react/Pages/NotFound.jsx b/src/pages/NotFound.tsx similarity index 73% rename from src/react/Pages/NotFound.jsx rename to src/pages/NotFound.tsx index dde75922..3aa7bbc1 100644 --- a/src/react/Pages/NotFound.jsx +++ b/src/pages/NotFound.tsx @@ -2,9 +2,17 @@ import React from "react"; import Helmet from "react-helmet"; import { translate } from "react-i18next"; -import TranslateTypography from "../Components/TranslationHelpers/Typography"; +import TranslateTypography from "~components/TranslationHelpers/Typography"; -class NotFound extends React.Component { +interface IState { + [key: string]: any; +} + +interface IProps { + [key: string]: any; +} + +class NotFound extends React.Component { constructor(props, context) { super(props, context); this.state = {}; diff --git a/src/react/Pages/Pay/ConfirmationDialog.jsx b/src/pages/Pay/ConfirmationDialog.tsx similarity index 92% rename from src/react/Pages/Pay/ConfirmationDialog.jsx rename to src/pages/Pay/ConfirmationDialog.tsx index 6e8c2e6a..f4f8efa9 100644 --- a/src/react/Pages/Pay/ConfirmationDialog.jsx +++ b/src/pages/Pay/ConfirmationDialog.tsx @@ -12,11 +12,22 @@ import DialogActions from "@material-ui/core/DialogActions"; import DialogContent from "@material-ui/core/DialogContent"; import DialogTitle from "@material-ui/core/DialogTitle"; -import { formatMoney } from "../../Functions/Utils"; +import { formatMoney } from "~functions/Utils"; +import { ReduxState } from "~store/index"; const styles = {}; -class ConfirmationDialog extends React.Component { +interface IState { + [key: string]: any; +} + +interface IProps { + [key: string]: any; +} + +class ConfirmationDialog extends React.Component & IProps> { + state: IState; + constructor(props, context) { super(props, context); this.state = {}; @@ -107,7 +118,7 @@ class ConfirmationDialog extends React.Component { } } -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return { accounts: state.accounts.accounts }; diff --git a/src/react/Pages/Pay/Pay.jsx b/src/pages/Pay/Pay.tsx similarity index 93% rename from src/react/Pages/Pay/Pay.jsx rename to src/pages/Pay/Pay.tsx index 4fa8c5ad..d96941e2 100644 --- a/src/react/Pages/Pay/Pay.jsx +++ b/src/pages/Pay/Pay.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { CSSProperties } from "react"; import { translate } from "react-i18next"; import { connect } from "react-redux"; import Helmet from "react-helmet"; @@ -12,7 +12,7 @@ import DateFnsUtils from "material-ui-pickers/utils/date-fns-utils"; import MuiPickersUtilsProvider from "material-ui-pickers/MuiPickersUtilsProvider"; import Grid from "@material-ui/core/Grid"; import Paper from "@material-ui/core/Paper"; -import Button from "@material-ui/core/Button"; +import OrigButton from "@material-ui/core/Button"; import Switch from "@material-ui/core/Switch"; import TextField from "@material-ui/core/TextField"; import InputLabel from "@material-ui/core/InputLabel"; @@ -26,25 +26,28 @@ import Tooltip from "@material-ui/core/Tooltip"; import EventIcon from "@material-ui/icons/Event"; import ListIcon from "@material-ui/icons/List"; import ArrowBackIcon from "@material-ui/icons/ArrowBack"; +import { AppDispatch, ReduxState } from "~store/index"; import ConfirmationDialog from "./ConfirmationDialog"; -import AccountSelectorDialog from "../../Components/FormFields/AccountSelectorDialog"; -import MoneyFormatInput from "../../Components/FormFields/MoneyFormatInput"; -import TargetSelection from "../../Components/FormFields/TargetSelection"; -import SchedulePaymentForm from "../../Components/FormFields/SchedulePaymentForm"; -import TranslateButton from "../../Components/TranslationHelpers/Button"; -import NavLink from "../../Components/Routing/NavLink"; - -import { openSnackbar } from "../../Actions/snackbar"; -import { paySchedule, paySend } from "../../Actions/pay"; -import { paymentInfoUpdate } from "../../Actions/payments"; -import { pendingPaymentsAddPayment } from "../../Actions/pending_payments"; - -import { getInternationalFormat, isValidPhonenumber } from "../../Functions/PhoneLib"; -import { formatMoney, getUTCDate } from "../../Functions/Utils"; -import { filterShareInviteMonetaryAccountResponses } from "../../Functions/DataFilters"; -import scheduleTexts from "../../Functions/ScheduleTexts"; -import { connectGetBudget, connectGetType, connectGetPermissions } from "../../Functions/ConnectGetPermissions"; +import AccountSelectorDialog from "~components/FormFields/AccountSelectorDialog"; +import MoneyFormatInput from "~components/FormFields/MoneyFormatInput"; +import TargetSelection from "~components/FormFields/TargetSelection"; +import SchedulePaymentForm from "~components/FormFields/SchedulePaymentForm"; +import TranslateButton from "~components/TranslationHelpers/Button"; +import NavLink from "~components/Routing/NavLink"; + +import { paySchedule, paySend } from "~actions/pay"; +import { paymentInfoUpdate } from "~actions/payments"; +import { pendingPaymentsAddPayment } from "~actions/pending_payments"; +import { actions as snackbarActions } from "~store/snackbar"; + +import { getInternationalFormat, isValidPhonenumber } from "~functions/PhoneLib"; +import { formatMoney, getUTCDate } from "~functions/Utils"; +import { filterShareInviteMonetaryAccountResponses } from "~functions/DataFilters"; +import scheduleTexts from "~functions/ScheduleTexts"; +import { connectGetBudget, connectGetType, connectGetPermissions } from "~functions/ConnectGetPermissions"; + +const Button: any = OrigButton; const styles = { payButton: { @@ -72,7 +75,22 @@ const styles = { } }; -class Pay extends React.Component { +interface IState { + target: any; + ibanName: any; + selectedAccount: any; + selectedTargetAccount: any; + targetType: any; + [key: string]: any; +} + +interface IProps { + [key: string]: any; +} + +class Pay extends React.Component & ReturnType & IProps> { + state: IState; + constructor(props, context) { super(props, context); this.state = { @@ -149,7 +167,7 @@ class Pay extends React.Component { }; // callbacks for input fields and selectors - setTargetType = type => event => { + setTargetType = type => () => { this.setState( { targetType: type, @@ -371,7 +389,7 @@ class Pay extends React.Component { }; // validate only the taret inputs - validateTargetInput = (callback = () => {}) => { + validateTargetInput = (callback = (valid) => {}) => { const { target, ibanName, selectedAccount, selectedTargetAccount, targetType } = this.state; const ibanNameErrorCondition = ibanName.length < 1 || ibanName.length > 64; @@ -493,7 +511,7 @@ class Pay extends React.Component { const targetInfoList = []; targets.forEach(target => { // check if the target is valid based onthe targetType - let targetInfo = false; + let targetInfo: any = false; switch (target.type) { case "CONTACT": const validEmail = EmailValidator.validate(target.value); @@ -557,6 +575,7 @@ class Pay extends React.Component { }; if (scheduleEndDate) { + // @ts-ignore schedule.time_end = format(getUTCDate(scheduleEndDate), "yyyy-MM-dd HH:mm:ss"); } @@ -622,10 +641,12 @@ class Pay extends React.Component { if (filteredInviteResponses.length > 0) { const connectBudget = connectGetBudget(filteredInviteResponses); if (connectBudget) { + // @ts-ignore accountBalance = connectBudget; } } } + // @ts-ignore accountBalance = formatMoney(accountBalance, true); let scheduledPaymentText = null; @@ -669,7 +690,7 @@ class Pay extends React.Component { } return ( - + {`bunqDesktop - Pay`} @@ -709,14 +730,13 @@ class Pay extends React.Component { - + {t("New Payment")} {this.state.insufficientFundsCondition !== false ? ( @@ -862,13 +882,14 @@ class Pay extends React.Component { } } -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return { payLoading: state.pay.loading, accounts: state.accounts.accounts, - selectedAccount: state.accounts.selected_account, + selectedAccount: state.accounts.selectedAccount, + // @ts-ignore language: state.options.language, pendingPayments: state.pending_payments.pending_payments, @@ -877,23 +898,24 @@ const mapStateToProps = state => { state.share_invite_monetary_account_responses.share_invite_monetary_account_responses, user: state.user.user, + + // @ts-ignore limitedPermissions: state.user.limited_permissions }; }; -const mapDispatchToProps = (dispatch, props) => { - const { BunqJSClient } = props; +const mapDispatchToProps = (dispatch: AppDispatch) => { return { paySend: (userId, accountId, description, amount, targets, draft = false) => - dispatch(paySend(BunqJSClient, userId, accountId, description, amount, targets, draft)), + dispatch(paySend(userId, accountId, description, amount, targets, draft)), paySchedule: (userId, accountId, description, amount, targets, schedule) => - dispatch(paySchedule(BunqJSClient, userId, accountId, description, amount, targets, schedule)), - openSnackbar: message => dispatch(openSnackbar(message)), + dispatch(paySchedule(userId, accountId, description, amount, targets, schedule)), + openSnackbar: message => dispatch(snackbarActions.open({ message })), - paymentInfoUpdate: (userId, accountId) => dispatch(paymentInfoUpdate(BunqJSClient, userId, accountId)), + paymentInfoUpdate: (userId, accountId) => dispatch(paymentInfoUpdate(userId, accountId)), pendingPaymentsAddPayment: (accountId, pendingPayment) => - dispatch(pendingPaymentsAddPayment(BunqJSClient, accountId, pendingPayment)) + dispatch(pendingPaymentsAddPayment(accountId, pendingPayment)) }; }; diff --git a/src/react/Pages/PaymentInfo.jsx b/src/pages/PaymentInfo.tsx similarity index 84% rename from src/react/Pages/PaymentInfo.jsx rename to src/pages/PaymentInfo.tsx index b220a514..3919d25b 100644 --- a/src/react/Pages/PaymentInfo.jsx +++ b/src/pages/PaymentInfo.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { CSSProperties } from "react"; import { translate } from "react-i18next"; import { connect } from "react-redux"; import { ipcRenderer } from "electron"; @@ -18,23 +18,24 @@ import HelpIcon from "@material-ui/icons/Help"; import BookmarkIcon from "@material-ui/icons/Bookmark"; import FilterIcon from "@material-ui/icons/FilterList"; -import { formatMoney, humanReadableDate, formatIban } from "../Functions/Utils"; -import { paymentText, paymentTypeParser } from "../Functions/EventStatusTexts"; - -import FilterCreationDialog from "../Components/FilterCreationDialog"; -import GeoLocationListItem from "../Components/GeoLocation/GeoLocationListItem"; -import PDFExportHelper from "../Components/PDFExportHelper/PDFExportHelper"; -import SpeedDial from "../Components/SpeedDial"; -import ExportDialog from "../Components/ExportDialog"; -import MoneyAmountLabel from "../Components/MoneyAmountLabel"; -import TransactionHeader from "../Components/TransactionHeader"; -import CategorySelectorDialog from "../Components/Categories/CategorySelectorDialog"; -import CategoryChips from "../Components/Categories/CategoryChips"; -import NoteTextForm from "../Components/NoteTexts/NoteTextForm"; - -import { setTheme } from "../Actions/options"; -import { paymentsUpdate } from "../Actions/payment_info"; -import { applicationSetPDFMode } from "../Actions/application"; +import { formatMoney, humanReadableDate, formatIban } from "~functions/Utils"; +import { paymentText, paymentTypeParser } from "~functions/EventStatusTexts"; + +import FilterCreationDialog from "~components/FilterCreationDialog"; +import GeoLocationListItem from "~components/GeoLocation/GeoLocationListItem"; +import PDFExportHelper from "~components/PDFExportHelper/PDFExportHelper"; +import SpeedDial from "~components/SpeedDial"; +import ExportDialog from "~components/ExportDialog"; +import MoneyAmountLabel from "~components/MoneyAmountLabel"; +import TransactionHeader from "~components/TransactionHeader"; +import CategorySelectorDialog from "~components/Categories/CategorySelectorDialog"; +import CategoryChips from "~components/Categories/CategoryChips"; +import NoteTextForm from "~components/NoteTexts/NoteTextForm"; + +import { setTheme } from "~actions/options"; +import { paymentsUpdate } from "~actions/payment_info"; +import { actions as applicationActions } from "~store/application"; +import { AppDispatch, ReduxState } from "~store/index"; const styles = { btn: {}, @@ -50,7 +51,17 @@ const styles = { } }; -class PaymentInfo extends React.Component { +interface IState { + [key: string]: any; +} + +interface IProps { + [key: string]: any; +} + +class PaymentInfo extends React.Component & ReturnType & IProps> { + state: IState; + constructor(props, context) { super(props, context); this.state = { @@ -154,10 +165,9 @@ class PaymentInfo extends React.Component { ); } - noteTextsForm = ; + noteTextsForm = ; const transactionHeaderProps = { - BunqJSClient: this.props.BunqJSClient, to: payment.counterparty_alias, from: payment.alias, user: this.props.user, @@ -173,12 +183,15 @@ class PaymentInfo extends React.Component { ) }; if (paymentInfo.getDelta() < 0) { + // @ts-ignore transactionHeaderProps.onRequest = this.onRequest; } else { + // @ts-ignore transactionHeaderProps.onForward = this.onForward; } content = ( + // @ts-ignore @@ -190,19 +203,19 @@ class PaymentInfo extends React.Component { /> - + {paymentDescription && paymentDescription.length > 0 ? ( - + <> - + ) : null} @@ -219,16 +232,16 @@ class PaymentInfo extends React.Component { {counterPartyIban && counterPartyIban.length > 0 ? ( - + <> - + ) : null} - + @@ -308,7 +321,7 @@ class PaymentInfo extends React.Component { } } -const mapStateToProps = state => { +const mapStateToProps = (state: ReduxState) => { return { user: state.user.user, @@ -321,13 +334,12 @@ const mapStateToProps = state => { }; }; -const mapDispatchToProps = (dispatch, ownProps) => { - const { BunqJSClient } = ownProps; +const mapDispatchToProps = (dispatch: AppDispatch) => { return { - applicationSetPDFMode: enabled => dispatch(applicationSetPDFMode(enabled)), + applicationSetPDFMode: enabled => dispatch(applicationActions.setPdfMode(enabled)), updatePayment: (user_id, account_id, payment_id) => - dispatch(paymentsUpdate(BunqJSClient, user_id, account_id, payment_id)), + dispatch(paymentsUpdate(user_id, account_id, payment_id)), setTheme: theme => dispatch(setTheme(theme)) }; diff --git a/src/react/Pages/PendingPayments/ConfirmationDialog.jsx b/src/pages/PendingPayments/ConfirmationDialog.tsx similarity index 100% rename from src/react/Pages/PendingPayments/ConfirmationDialog.jsx rename to src/pages/PendingPayments/ConfirmationDialog.tsx diff --git a/src/react/Pages/PendingPayments/PendingPaymentRow.jsx b/src/pages/PendingPayments/PendingPaymentRow.tsx similarity index 92% rename from src/react/Pages/PendingPayments/PendingPaymentRow.jsx rename to src/pages/PendingPayments/PendingPaymentRow.tsx index b27caf9e..ad999b18 100644 --- a/src/react/Pages/PendingPayments/PendingPaymentRow.jsx +++ b/src/pages/PendingPayments/PendingPaymentRow.tsx @@ -9,10 +9,10 @@ import Typography from "@material-ui/core/Typography"; import SubdirectoryArrowRightIcon from "@material-ui/icons/SubdirectoryArrowRight"; import DeleteIcon from "@material-ui/icons/Delete"; -import TargetChipList from "../../Components/FormFields/TargetChipList"; -import TargetChip from "../../Components/FormFields/TargetChip"; +import TargetChipList from "~components/FormFields/TargetChipList"; +import TargetChip from "~components/FormFields/TargetChip"; -import { formatMoney } from "../../Functions/Utils"; +import { formatMoney } from "~functions/Utils"; const styles = { subdirectoryIconGrid: { @@ -39,6 +39,7 @@ export default ({ pendingPayment, selectedCheckBoxes, accounts, togglePaymentChe if (paymentObject.counterparty_aliases) { targetComponents = ; } else { + // @ts-ignore targetComponents = ; } diff --git a/src/react/Pages/PendingPayments/PendingPayments.jsx b/src/pages/PendingPayments/PendingPayments.tsx similarity index 92% rename from src/react/Pages/PendingPayments/PendingPayments.jsx rename to src/pages/PendingPayments/PendingPayments.tsx index e3453bf9..ea816369 100644 --- a/src/react/Pages/PendingPayments/PendingPayments.jsx +++ b/src/pages/PendingPayments/PendingPayments.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { CSSProperties } from "react"; import Helmet from "react-helmet"; import { connect } from "react-redux"; import { translate } from "react-i18next"; @@ -16,21 +16,25 @@ import Checkbox from "@material-ui/core/Checkbox"; import Typography from "@material-ui/core/Typography"; import DeleteIcon from "@material-ui/icons/Delete"; +import { AppWindow } from "~app"; -import LazyAttachmentImage from "../../Components/AttachmentImage/LazyAttachmentImage"; -import TranslateTypography from "../../Components/TranslationHelpers/Typography"; +import LazyAttachmentImage from "~components/AttachmentImage/LazyAttachmentImage"; +import TranslateTypography from "~components/TranslationHelpers/Typography"; +import { AppDispatch, ReduxState } from "~store/index"; import ConfirmationDialog from "./ConfirmationDialog"; import PendingPaymentRow from "./PendingPaymentRow"; -import { formatMoney } from "../../Functions/Utils"; -import BunqErrorHandler from "../../Functions/BunqErrorHandler"; +import { formatMoney } from "~functions/Utils"; +import BunqErrorHandler from "~functions/BunqErrorHandler"; import { pendingPaymentsClear, pendingPaymentsClearAccount, pendingPaymentsRemovePayment -} from "../../Actions/pending_payments"; -import { openSnackbar } from "../../Actions/snackbar"; +} from "~actions/pending_payments"; +import { actions as snackbarActions } from "~store/snackbar"; + +declare let window: AppWindow; const styles = { paper: { @@ -68,7 +72,17 @@ const styles = { } }; -class PendingPayments extends React.Component { +interface IState { + [key: string]: any; +} + +interface IProps { + [key: string]: any; +} + +class PendingPayments extends React.Component & ReturnType & IProps> { + state: IState; + constructor(props, context) { super(props, context); this.state = { @@ -247,8 +261,9 @@ class PendingPayments extends React.Component { decrementPromiseCounter = () => this.setState({ paymentPromiseCount: this.state.paymentPromiseCount - 1 }); paySelected = () => { - const { t, BunqJSClient, user } = this.props; + const { t, user } = this.props; const failedText = t("Failed to complete some of the selected payments"); + const BunqJSClient = window.BunqDesktopClient.BunqJSClient; this.confirmAction("Are you sure you wish to complete these payments?", () => { const groupedParsedPayments = this.parsePendingPayments(); @@ -272,8 +287,9 @@ class PendingPayments extends React.Component { }); }; draftSelected = () => { - const { t, BunqJSClient, user } = this.props; + const { t, user } = this.props; const failedText = t("Failed to draft some of the selected payments"); + const BunqJSClient = window.BunqDesktopClient.BunqJSClient; this.confirmAction("Are you sure you wish to draft these payments?", () => { const groupedParsedPayments = this.parsePendingPayments(); @@ -298,7 +314,7 @@ class PendingPayments extends React.Component { }; render() { - const { t, BunqJSClient, accounts, pendingPayments } = this.props; + const { t, accounts, pendingPayments } = this.props; let groupedPayments = {}; Object.keys(pendingPayments).forEach(pendingPaymentId => { @@ -357,7 +373,6 @@ class PendingPayments extends React.Component { @@ -384,7 +399,7 @@ class PendingPayments extends React.Component { Pending payments - + {componentList.length > 0 && (