From af29bd52fece034621434c9110cbb3e46f5aeb62 Mon Sep 17 00:00:00 2001 From: Rameez Khan Date: Tue, 9 Feb 2021 07:27:38 +0200 Subject: [PATCH 01/16] Clean slate for v2 --- .gitignore | 14 - LICENSE.md | 2 +- Makefile | 7 - README.md | 34 +- dev.cljs.edn | 4 - example-data.csv | 93 --- figwheel-main.edn | 31 - project.clj | 25 - resources/public/android-chrome-192x192.png | Bin 10725 -> 0 bytes resources/public/android-chrome-512x512.png | Bin 35740 -> 0 bytes resources/public/apple-touch-icon.png | Bin 9664 -> 0 bytes resources/public/css/style.css | 12 - resources/public/favicon-16x16.png | Bin 636 -> 0 bytes resources/public/favicon-32x32.png | Bin 1344 -> 0 bytes resources/public/index.html | 45 -- resources/public/site.webmanifest | 1 - resources/public/test.html | 7 - src/financial_health_dashboard/changelog.cljs | 7 - src/financial_health_dashboard/core.cljs | 709 ------------------ src/financial_health_dashboard/domain.cljs | 337 --------- src/financial_health_dashboard/example.cljs | 83 -- .../localstorage.cljs | 11 - src/financial_health_dashboard/parse.cljs | 78 -- src/financial_health_dashboard/scratch.cljs | 7 - test.cljs.edn | 10 - .../financial_health_dashboard/core_test.cljs | 10 - .../test_runner.cljs | 9 - 27 files changed, 2 insertions(+), 1534 deletions(-) delete mode 100644 .gitignore delete mode 100644 Makefile delete mode 100644 dev.cljs.edn delete mode 100644 example-data.csv delete mode 100644 figwheel-main.edn delete mode 100644 project.clj delete mode 100644 resources/public/android-chrome-192x192.png delete mode 100644 resources/public/android-chrome-512x512.png delete mode 100644 resources/public/apple-touch-icon.png delete mode 100644 resources/public/css/style.css delete mode 100644 resources/public/favicon-16x16.png delete mode 100644 resources/public/favicon-32x32.png delete mode 100644 resources/public/index.html delete mode 100644 resources/public/site.webmanifest delete mode 100644 resources/public/test.html delete mode 100644 src/financial_health_dashboard/changelog.cljs delete mode 100644 src/financial_health_dashboard/core.cljs delete mode 100644 src/financial_health_dashboard/domain.cljs delete mode 100644 src/financial_health_dashboard/example.cljs delete mode 100644 src/financial_health_dashboard/localstorage.cljs delete mode 100644 src/financial_health_dashboard/parse.cljs delete mode 100644 src/financial_health_dashboard/scratch.cljs delete mode 100644 test.cljs.edn delete mode 100644 test/financial_health_dashboard/core_test.cljs delete mode 100644 test/financial_health_dashboard/test_runner.cljs diff --git a/.gitignore b/.gitignore deleted file mode 100644 index b8549d4..0000000 --- a/.gitignore +++ /dev/null @@ -1,14 +0,0 @@ -pom.xml -*jar -/lib/ -/classes/ -/out/ -/target/ -.lein-deps-sum -.lein-repl-history -.lein-plugins/ -.repl -.nrepl-port -.cpcache/ -.rebel_readline_history -resources/public/cljs-out/ diff --git a/LICENSE.md b/LICENSE.md index 5bf5beb..b9f1610 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2020 Rameez Khan +Copyright (c) 2021 Rameez Khan Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Makefile b/Makefile deleted file mode 100644 index ef45b3a..0000000 --- a/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -.PHONY: build test - -build: - lein fig:build - -production: - lein fig:min diff --git a/README.md b/README.md index f750502..248a214 100644 --- a/README.md +++ b/README.md @@ -10,43 +10,11 @@ Live version can be accessed [here](https://financialhealth.app) 👈🏽. Assess your financial health with a high level dashboard. -### Features -- [x] Chart to view your salary over time -- [ ] View your current net worth - -### Future work -- [ ] View your net worth over time -- [ ] Track TFSA contributions - -## Development - -To get an interactive development environment run: - - lein fig:build - -This will auto compile and send all changes to the browser without the -need to reload. After the compilation process is complete, you will -get a Browser Connected REPL. An easy way to try it is: - - (js/alert "Am I connected?") - -and you should see an alert in the browser window. - -To clean all compiled files: - - lein clean - -To create a production build run: - - lein clean - lein fig:min - - ## License MIT License -Copyright (c) 2020 Rameez Khan +Copyright (c) 2021 Rameez Khan Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/dev.cljs.edn b/dev.cljs.edn deleted file mode 100644 index 17f64af..0000000 --- a/dev.cljs.edn +++ /dev/null @@ -1,4 +0,0 @@ -^{:watch-dirs ["test" "src"] - :css-dirs ["resources/public/css"] - :auto-testing true} -{:main financial-health-dashboard.core} diff --git a/example-data.csv b/example-data.csv deleted file mode 100644 index 120ada1..0000000 --- a/example-data.csv +++ /dev/null @@ -1,93 +0,0 @@ -fi-expense|15000 -emergency-monthly-expense|2020|5|25000 - -comment|July 2020 - -income|salary|2020|7|55000 -expense|day-to-day|2020|7|7000 -expense|recurring|2020|7|12000 -expense|home-loan-payment|2020|7|3000 - -asset|home|2020|7|1000000 -liability|home-loan|2020|7|700000 - -asset|car|2020|7|98887 -liability|car-loan|2020|7|20000 - -asset|cheque-account|2020|7|6636 -asset|credit-card|2020|7|3198 -liability|credit-card|2020|7|0 -asset|tyme-goalsave|2020|7|100000 - -asset|ra-1|2020|7|120000 -asset|preservation-1|2020|7|170000 -asset|ra-2|2020|7|1500 -asset|tfsa|2020|7|45000 -asset|education-fund|2020|7|5000 - -emergency-fund|2020|7|140000 - -comment|Aug 2020 - -income|salary|2020|8|55000 -expense|day-to-day|2020|8|8000 -expense|recurring|2020|8|12000 -expense|home-loan-payment|2020|8|3000 - -asset|home|2020|8|1000000 -liability|home-loan|2020|8|790000 - -asset|car|2020|8|98887 -liability|car-loan|2020|8|19500 - -asset|cheque-account|2020|8|6636 -asset|credit-card|2020|8|3198 -liability|credit-card|2020|8|0 -asset|tyme-goalsave|2020|8|100000 - -asset|ra-1|2020|8|125000 -asset|preservation-1|2020|8|17000 -asset|ra-2|2020|8|1600 -asset|tfsa|2020|8|80000 -asset|education-fund|2020|8|5000 - -emergency-fund|2020|8|150000 - -comment|Sep 2020 - -income|salary|2020|9|50000 -expense|day-to-day|2020|9|8500 -expense|recurring|2020|9|11000 -expense|home-loan-payment|2020|9|3000 - -asset|home|2020|9|1000000 -liability|home-loan|2020|9|780000 - -asset|car|2020|9|98887 -liability|car-loan|2020|9|19000 - -asset|cheque-account|2020|9|6636 -asset|credit-card|2020|9|3198 -liability|credit-card|2020|9|0 -asset|tyme-goalsave|2020|9|100000 - -asset|ra-1|2020|9|125000 -asset|preservation-1|2020|9|210000 -asset|ra-2|2020|9|1800 -asset|tfsa|2020|9|90000 -asset|education-fund|2020|9|5000 - -emergency-fund|2020|9|151000 - -comment|tfsa -tfsa-contribution|2019|6|4100 -tfsa-contribution|2019|8|2750 -tfsa-contribution|2019|11|2750 -tfsa-contribution|2020|1|500 -tfsa-contribution|2020|2|500 -tfsa-contribution|2020|3|6000 -tfsa-contribution|2020|4|6000 -tfsa-contribution|2020|5|6000 -tfsa-contribution|2020|6|6000 -tfsa-contribution|2020|7|6000 -tfsa-contribution|2020|8|6000 diff --git a/figwheel-main.edn b/figwheel-main.edn deleted file mode 100644 index 63dc990..0000000 --- a/figwheel-main.edn +++ /dev/null @@ -1,31 +0,0 @@ -;; Figwheel-main configuration options see: https://figwheel.org/config-options -;; these will be overriden by the metadata config options in dev.cljs.edn build file -{ - ;; Set the server port https://figwheel.org/config-options#ring-server-options - ;; :ring-server-options {:port 9500} - - ;; Change the target directory from the "target" to "resources" - ;; https://figwheel.org/config-options#target-dir - :target-dir "resources" - - ;; Server Ring Handler (optional) https://figwheel.org/docs/ring-handler.html - ;; If you want to embed a ring handler into the figwheel server, this - ;; is for simple ring servers - ;; :ring-handler hello_world.server/handler - - ;; To be able to open files in your editor from the heads up display - ;; you will need to put a script on your path. This script will have - ;; to take a file path and a line number ie. - ;; in ~/bin/myfile-opener: - ;; - ;; #! /bin/sh - ;; emacsclient -n +$2:$3 $1 - ;; - ;; :open-file-command "myfile-opener" - - ;; if you are using emacsclient you can just use - ;; :open-file-command "emacsclient" - - ;; Logging output gets printed to the REPL, if you want to redirect it to a file: - ;; :log-file "figwheel-main.log" -} diff --git a/project.clj b/project.clj deleted file mode 100644 index 2276811..0000000 --- a/project.clj +++ /dev/null @@ -1,25 +0,0 @@ -(defproject financial-health-dashboard "0.1.0-SNAPSHOT" - :description "FIXME: write this!" - :url "http://example.com/FIXME" - :license {:name "Eclipse Public License" - :url "http://www.eclipse.org/legal/epl-v10.html"} - - :min-lein-version "2.7.1" - - :dependencies [[org.clojure/clojure "1.9.0"] - [org.clojure/clojurescript "1.10.520"] - [testdouble/clojurescript.csv "0.4.5"] - [com.andrewmcveigh/cljs-time "0.5.2"] - [reagent "0.8.1"]] - - :source-paths ["src"] - - :aliases {"fig" ["trampoline" "run" "-m" "figwheel.main"] - "fig:build" ["trampoline" "run" "-m" "figwheel.main" "-b" "dev" "-r"] - "fig:min" ["run" "-m" "figwheel.main" "-O" "advanced" "-bo" "dev"] - "fig:test" ["run" "-m" "figwheel.main" "-co" "test.cljs.edn" "-m" "financial-health-dashboard.test-runner"]} - - :profiles {:dev {:dependencies [[com.bhauman/figwheel-main "0.2.3"] - [com.bhauman/rebel-readline-cljs "0.1.4"]] - }}) - diff --git a/resources/public/android-chrome-192x192.png b/resources/public/android-chrome-192x192.png deleted file mode 100644 index a1ce2919a134bfa98c832f339bced829ca521263..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10725 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 XViNJ;8zF;h6VgM_M5r{ zftWz5igM5VO!wYn`_XOuz3V*MUo3Aui^%4k>nG6QD#%O*fk`0ed4xD!2oe=}H*9NS zH_R<;wuUh1gcXcUJbcVq0{SMq#^yWundy&xpXCeLgF%ikb9IS7i+`3zuB4vy&cFBF z6gpTO>9C1l(u6@XKnCf3B&k9Zb#8+BS{(9>{Eb%mu%TDx!6c{rR`lF2DiCQk+tf7T zp9ImijL%ONe{8&(7jOAMW=}?CLV&Hy#Zn?Ve@*|0^r-akP@8oZgjCq%d_%~!!bHkw z9`^=H2eoL$;*&D}!MA7l(&E$bm);7ycU`OMBF(WPXPok~{1WKKJVIfQm7t+>(3qs-v6}Zb)<1oOa#y8O3-J9JZgJ@ZV;vgeJ$4?a~;(Cdr@I$rD*KX$z z1q^C0z$`9bH*S}c@@T?th76y?Hc|V1kJ)Z2^ZPe~I5K`*^^7zqJmZsj2?`_@U+~0S zxpyRFR#lY-_ofyoC9LIs;@rU#~2D%j& zwxB{W(BK}h1trFTQCJ8%Mn)YYq(OkZy+nTVcJML%zto#=QNMPnq{tA*Zevr)`x^Y_ z*|N}&RxAFPCt?ri&wi%ElAOX3C9tCHw=8;_DxGsrkX!GRb3V1aD~tM)C6Y(LM2Q$; zl^j-Z=7EKLUb{@nsT=q%oxIyZWh&STY8g=(4&)|&-xvFQ%k6xbD5l90RMOu)R zX{Mt%n!ofyv8V5cA7K|OiXd$=LebKZm+IY{@pb{Xe?^%a$N=32#Lr6sr`I=9G$s}h zsDnKE9aQk-+p0QMVQL7hCi9c2bbE@=6h5*85eBgx`TJ5Kl;g>Jtj@vs4#|M)R7&ZC z59AR4jm7tLeKJI00!2e#WU{>-NTL2GV~*iIcit75)MeP?4AX7!*p_s1f0UZb+{SZk z(|*;qkeL?ia$~Y>e2#V0q7ADyEwKpy2dtG&E_Lm%Xw}w!-U<~`hzu(e7&%JEvXfD~ z(?X$N^~knr-|o}5zZ}i<-s}p^6zD-%t0W_0(SFc{Zi)%qe&kYWa-Ds-P=^HfWovAwxHJv zKTLX9tZ!r?GT6NcEDaD@!|2DkC>^|RN32_y`lHgE32yb2h>1bkKOcV^JQyRQ5*Jvs z!bR)bE?93&OKaae*fDm9S$G7MVud&Gk&oh2%H6V}p9{UEQ#VtM&%$*(z;~Dh^!!ql~l6tGmlT9J zsU0t!7I1V%H6AD-a!@BsQsw9b-GQRU@@Y;}=_4|mwd|sEI)07Al#$GYXW4e^V#t~# zk@h0i^XHX*-NxnnsRmjH)p9dPcT8~5T3X! zVgSxR5V&XGHK4ZpT8=6+HkNE*4PNuc!sl~Ep6)I2wR>wy&g0
jPrn5$&V?21vmkCd1okKSRQ9AnMhVek%tdJ}y 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 - - - - - - - - - - - - Financial Health Dashboard - - - - - - -
- - - - - diff --git a/resources/public/site.webmanifest b/resources/public/site.webmanifest deleted file mode 100644 index 45dc8a2..0000000 --- a/resources/public/site.webmanifest +++ /dev/null @@ -1 +0,0 @@ -{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} \ No newline at end of file diff --git a/resources/public/test.html b/resources/public/test.html deleted file mode 100644 index b08b182..0000000 --- a/resources/public/test.html +++ /dev/null @@ -1,7 +0,0 @@ - - - -

Test host page

- - - diff --git a/src/financial_health_dashboard/changelog.cljs b/src/financial_health_dashboard/changelog.cljs deleted file mode 100644 index 5c0717e..0000000 --- a/src/financial_health_dashboard/changelog.cljs +++ /dev/null @@ -1,7 +0,0 @@ -(ns financial-health-dashboard.changelog) - -(defn render [] - [:div - [:ul - [:li "thing 2"] - [:li "thing 1"]]]) diff --git a/src/financial_health_dashboard/core.cljs b/src/financial_health_dashboard/core.cljs deleted file mode 100644 index ee3e69c..0000000 --- a/src/financial_health_dashboard/core.cljs +++ /dev/null @@ -1,709 +0,0 @@ -(ns ^:figwheel-hooks financial-health-dashboard.core - (:require - [financial-health-dashboard.changelog :as changelog] - [financial-health-dashboard.parse :as parse] - [financial-health-dashboard.domain :as domain] - [financial-health-dashboard.localstorage :as localstorage] - [financial-health-dashboard.example :as example] - [clojure.edn :as edn] - [cljs-time.format :as tf] - [goog.dom :as gdom] - [goog.dom.classlist :as gc] - [reagent.core :as reagent :refer [atom]])) - -(defn multiply [a b] (* a b)) - -(def number-formatter (js/Intl.NumberFormat.)) - -(defn format-number [number] (.format number-formatter number)) - -;; define your app data so that it doesn't get over-written on reload -(defonce state (reagent/atom {:page :loading - :delimiter parse/pipe - :modal {:key :hidden :data nil} - :data nil})) - -(defmulti render-page :page) - -(defn page [page] (swap! state #(assoc % :page page))) - -(defmulti render-modal (fn [state] (get-in @state [:modal :key]))) - -(defn show-modal [key data] - (swap! state #(assoc % :modal {:key key :data data}))) - -(defn hide-modal [] - (swap! state #(assoc % :modal {:key :hidden}))) - -(defn toggle-burger-menu [] - (gc/toggle (js/document.getElementById "nav-menu") "is-active") - (gc/toggle (js/document.getElementById "nav-menu-burger") "is-active")) - - -(defn set-file-data [data] - (swap! state #(assoc-in % [:modal :data] data))) - -(defn set-app-data [data] - (swap! state #(assoc % :data data))) - -(defn save-data-to-localstorage [data] - (localstorage/set-item! "data" (prn-str data))) - -(defn build-app-data-from-uploaded-data [parsed-data] - (save-data-to-localstorage parsed-data) - (set-app-data (-> parsed-data parse/as-domain-values domain/all-your-bucks))) - -(defn build-app-data-from-localstorage-data [localstorage-data] - (when-not (nil? localstorage-data) - (set-app-data (-> localstorage-data - parse/as-domain-values - domain/all-your-bucks)))) - -(defn get-data-from-localstorage [] - (or (->> (localstorage/get-item "data") (edn/read-string)) nil)) - -(defn get-sample-data [] - (parse/parse parse/pipe example/data-piped)) - -(defmethod render-modal :upload [{:keys [modal delimiter]}] - [:div.has-text-dark - [:h1.heading.has-text-centered "Choose file"] - [:form - [:div.file.is-centered - [:label.file-label - [:input.file-input {:type "file" :name "storage" - :on-change (fn [e] - (let [file (aget (.. e -target -files) 0) - reader (js/FileReader.)] - (set! (.-onload reader) - #(set-file-data (.. % -target -result))) - (.readAsText reader file)))}] - [:span.file-cta - [:span.file-icon - [:i.fa.fa-upload]] - [:span.file-label "Upload"]]]]] - (when-let [content (get-in @state [:modal :data])] - (let [result - (->> content - (parse/parse parse/pipe)) - errors - (->> result - (filter (comp not :valid?)) - (map (juxt :i :error)))] - (if-not (empty? errors) - [:div.content - [:hr] - [:p.heading.has-text-centered.has-text-danger "Oops. You have some errors"] - [:ul - (map-indexed - (fn [i [row e]] - [:li {:key i} "row: " row ": " e]) - errors)]] - [:div.content - [:hr] - [:p.heading.has-text-centered.has-text-primary "Awesome! No errors!"] - [:div.buttons.is-centered - [:button.button.is-primary - {:on-click (fn [_] (build-app-data-from-uploaded-data result) - (hide-modal) - (toggle-burger-menu) - (page :loading) - (js/setTimeout #(page :main)))} - "GO"]]])))]) - -(defmethod render-modal :help [{:keys [modal delimiter]}] - (println "help modal")) - -(defmethod render-modal :save [{:keys [modal delimiter]}] - (println "save modal")) - -(defmethod render-modal :changelog [] - (changelog/render)) - -(defn bar-chart - [id] - (let [context (.getContext (.getElementById js/document id) "2d") - chart-data {:type "bar" - :options {:legend {:labels {:fontColor "white"}} - :scales {:xAxes [{:ticks {:fontColor "white"}}] - :yAxes [{:ticks {:fontColor "white"}}]}} - :data {:labels ["2012" "2013" "2014" "2015" "2016"] - :datasets [{:data [5 10 15 20 25] - :label "Rev in MM" - :backgroundColor "#90EE90"} - {:data [3 6 9 12 15] - :label "Cost in MM" - :backgroundColor "#F08080"}]}}] - (js/Chart. context (clj->js chart-data)))) - -(defn cash-flow-chart - [id labels incomes expenses] - (let [context (.getContext (.getElementById js/document id) "2d") - chart-data {:type "line" - :options {:legend {:labels {:fontColor "white"}} - :scales {:xAxes [{:ticks {:fontColor "white" :maxTicksLimit 12}}] - :yAxes [{:ticks {:fontColor "white"}}]}} - :data {:labels labels - :datasets [{:data incomes - :label "Income" - :lineTension 0 - :fill false - :borderColor "#90EE90" - :cubicInterpolationMode "linear" - :backgroundColor "#90EE90"} - {:data expenses - :label "Expense" - :lineTension 0 - :fill false - :borderColor "#EA3C53" - :cubicInterpolationMode "linear" - :backgroundColor "#EA3C53"}]}}] - - (js/Chart. context (clj->js chart-data)))) - -(defn savings-rate-chart - [id labels savings-rate] - (let [context (.getContext (.getElementById js/document id) "2d") - chart-data {:type "line" - :options {:legend {:labels {:fontColor "white"}} - :scales {:xAxes [{:ticks {:fontColor "white" :maxTicksLimit 12}}] - :yAxes [{:ticks {:fontColor "white"}}]}} - :data {:labels labels - :datasets [{:data savings-rate - :label "Savings Rate" - :lineTension 0 - :fill false - :borderColor "#8e44ad" - :cubicInterpolationMode "linear" - :backgroundColor "#8e44ad"}]}}] - - (js/Chart. context (clj->js chart-data)))) - -(defn net-worth-line-chart - [id labels net-worth] - (let [context (.getContext (.getElementById js/document id) "2d") - chart-data {:type "line" - :options {:legend {:labels {:fontColor "white"}} - :scales {:xAxes [{:ticks {:fontColor "white" :maxTicksLimit 12}}] - :yAxes [{:ticks {:fontColor "white"}}]}} - :data {:labels labels - :datasets [{:data net-worth - :label "Net Worth" - :lineTension 0 - :fill false - :borderColor "#90EE90" - :cubicInterpolationMode "linear" - :backgroundColor "#90EE90"}]}}] - - (js/Chart. context (clj->js chart-data)))) - -(defn assets-line-chart - [id labels assets] - (let [context (.getContext (.getElementById js/document id) "2d") - chart-data {:type "line" - :options {:legend {:labels {:fontColor "white"}} - :scales {:xAxes [{:ticks {:fontColor "white" :maxTicksLimit 12}}] - :yAxes [{:ticks {:fontColor "white"}}]}} - :data {:labels labels - :datasets [{:data assets - :label "Assets" - :lineTension 0 - :fill false - :borderColor "#EA3C53" - :cubicInterpolationMode "linear" - :backgroundColor "#EA3C53"}]}}] - - (js/Chart. context (clj->js chart-data)))) - -(defn liabilities-line-chart - [id labels liabilities] - (let [context (.getContext (.getElementById js/document id) "2d") - chart-data {:type "line" - :options {:legend {:labels {:fontColor "white"}} - :scales {:xAxes [{:ticks {:fontColor "white" :maxTicksLimit 12}}] - :yAxes [{:ticks {:fontColor "white"}}]}} - :data {:labels labels - :datasets [{:data liabilities - :label "Liabilities" - :lineTension 0 - :fill false - :borderColor "#e67e22" - :cubicInterpolationMode "linear" - :backgroundColor "#e67e22"}]}}] - - (js/Chart. context (clj->js chart-data)))) - -(defn tfsa-yearly-chart - [id labels contributions limits] - (let [context (.getContext (.getElementById js/document id) "2d") - chart-data {:type "horizontalBar" - :options {:legend {:labels {:fontColor "white"}} - :scales {:xAxes [{:ticks {:fontColor "white" :beginAtZero true}}] - :yAxes [{:ticks {:fontColor "white"}}]}} - :data {:labels labels - :datasets [{:data limits - :label "Limit" - :backgroundColor "#EA3C53"} - {:data contributions - :label "Contribution" - :backgroundColor "#90EE90"}]}}] - (js/Chart. context (clj->js chart-data)))) - -(defn tfsa-lifetime-chart - [id contribution limit] - (let [context (.getContext (.getElementById js/document id) "2d") - chart-data {:type "horizontalBar" - :options {:legend {:labels {:fontColor "white"}} - :scales {:xAxes [{:ticks {:fontColor "white" :beginAtZero true}}] - :yAxes [{:ticks {:fontColor "white"}}]}} - :data {:labels ["Lifetime"] - :datasets [{:data limit - :label "Limit" - :backgroundColor "#EA3C53"} - {:data contribution - :label "Contribution" - :backgroundColor "#90EE90"}]}}] - (js/Chart. context (clj->js chart-data)))) - -(defn pie-chart-1 - [id] - (let [context (.getContext (.getElementById js/document id) "2d") - chart-data {:type "pie" - :options {:legend {:labels {:fontColor "white"}} - :scales {}} - :data {:labels ["Retirement Annuity" - "Preservation Fund" - "Emergency Fund" - "TFSA" - "Discretionary Investments"] - :datasets [{:data [20 20 20 20 20] - :backgroundColor ["#2ecc71" - "#3498db" - "#e67e22" - "#9b59b6" - "#1abc9c"]}]}}] - (js/Chart. context (clj->js chart-data)))) - -(defn pie-chart-2 - [id] - (let [context (.getContext (.getElementById js/document id) "2d") - chart-data {:type "pie" - :options {:legend {:labels {:fontColor "white"}} - :scales {}} - :data {:labels ["Local" - "Offshore"] - :datasets [{:data [90 10] - :backgroundColor ["#2ecc71" - "#3498db"]}]}}] - (js/Chart. context (clj->js chart-data)))) - -(defn pie-chart-3 - [id] - (let [context (.getContext (.getElementById js/document id) "2d") - chart-data {:type "pie" - :options {:legend {:labels {:fontColor "white"}} - :scales {}} - :data {:labels ["Property" - "Bonds" - "Equity" - "Cash" - "Vehicle" - "Offshore"] - :datasets [{:data [2 20 29 35 8 6] - :backgroundColor ["#2ecc71" - "#3498db" - "#e67e22" - "#9b59b6" - "#f1c40f" - "#c0392b"]}]}}] - (js/Chart. context (clj->js chart-data)))) - -(defn draw-chart [id chart x y1 y2 y3] - (reagent/create-class - {:component-did-mount #(chart id x y1 y2 y3) - :display-name "chart" - :reagent-render (fn [] [:canvas {:id id}])})) - -(defn nav [] - [:div - [:nav.navbar.is-dark - [:div.navbar-brand - [:a.navbar-item {:href "#"} "💰 Financial Health Dashboard"] - [:a.navbar-burger.burger {:id "nav-menu-burger" - :on-click (fn [] - (toggle-burger-menu))} - [:span {:aria-hidden "true"}] - [:span {:aria-hidden "true"}] - [:span {:aria-hidden "true"}]]] - [:div.navbar-menu {:id "nav-menu"} - [:div.navbar-end - ;; [:a.navbar-item {:on-click #(show-modal :help nil)} - ;; [:span.icon [:i.fa.fa-question-circle]]] - [:a.navbar-item {:on-click #(show-modal :upload nil)} - [:span.icon [:i.fa.fa-upload]] - [:span.is-hidden-desktop "Upload Data"]] - ;; [:a.navbar-item {:on-click #(show-modal :save nil)} - ;; [:span.icon [:i.fa.fa-save]]] - ;; [:a.navbar-item {:on-click #(show-modal :changelog nil)} - ;; [:span.icon [:i.fa.fa-history]]] - ]]]]) - -(defn modal [model-state] - [:div.modal.is-active - [:div.modal-background {:on-click hide-modal}] - [:div.modal-content - [:div.box.has-background-light - (render-modal model-state)] - [:button.modal-close.is-large {:on-click hide-modal}]]]) - -(defn col-real-data [size-desktop size-mobile & children] - [:div.column {:class (str "is-" size-desktop "-desktop " "is-" size-mobile "-mobile " "is-" size-mobile "-tablet")} - [:div.box.is-shadowless.has-text-grey-lighter - children]]) - -(defn col-sample-data [size-desktop size-mobile & children] - [:div.column {:class (str "is-" size-desktop "-desktop " "is-" size-mobile "-mobile " "is-" size-mobile "-tablet")} - [:div.box.is-shadowless.has-text-grey-lighter - [:span.tag.is-warning.is-size-7.sample-tag "sample"] - children]]) - -(defn info-box [title info change & [class]] - [:div.has-text-centered.info-box - [:p.heading title] - [:p.title {:class (or class "has-text-light")} info] - (if (> change 0) - [:p.subtitle.is-size-7.has-text-light.has-text-success - [:i.fa.fa-arrow-up] (str " " change)] - [:p.subtitle.is-size-7.has-text-light.has-text-danger - [:i.fa.fa-arrow-down] (str " " change)])]) - -(defn chart-box [title content & [class]] - [:div.has-text-centered.info-box - [:p.heading title] - [:div.is-centered - [content]]]) - -(def custom-month-year - (tf/formatter "MMM-yy")) - -(defn cash-flow-over-time-chart [{:keys [income expenses]}] - (let [labels (->> income (map :cljs-date) (map #(tf/unparse custom-month-year %)) (take-last 13)) - income (->> income (map :amount) (take-last 13)) - expenses (->> expenses (map :amount) (take-last 13))] - (chart-box "CASH FLOW OVER TIME" (draw-chart - "cash-flow-over-time" - cash-flow-chart labels income expenses nil)))) - -(defn savings-rate-over-time-chart [{:keys [income expenses]}] - (let [labels (->> income (map :cljs-date) (map #(tf/unparse custom-month-year %)) (take-last 13)) - income (->> income (map :amount) (take-last 13)) - expenses (->> expenses (map :amount) (take-last 13)) - savings (map - income expenses) - savings-rate (map #(* % 100) (map / savings income))] - (chart-box "SAVINGS RATE OVER TIME" (draw-chart - "savings-rate-over-time" - savings-rate-chart labels savings-rate nil nil)))) - -(defn calculate-growth [amount rate] - (* amount (+ 1 rate))) - -(defn monthly-rate-from-annual [annual-rate] - (- (Math/pow (+ 1 annual-rate) (/ 1 12)) 1)) - -(defn is-new-year? [month] - (zero? (mod month 12))) - -(defn apply-inflation [amount inflation-rate years] - (/ amount (Math/pow (+ 1 inflation-rate) years))) - - -(defn calculate-investment-value [{:keys [monthly-amount - annual-growth-rate - annual-monthly-amount-escalation - annual-inflation - years-invested]}] - (apply-inflation - (let [monthly-growth (monthly-rate-from-annual annual-growth-rate) - months (* years-invested 12)] - (loop [month 1 - monthly-amount monthly-amount - total (calculate-growth monthly-amount monthly-growth)] - (if (>= month months) - total - (recur (inc month) - (if (is-new-year? (inc month)) - (calculate-growth monthly-amount annual-monthly-amount-escalation) - monthly-amount) - (calculate-growth (+ total monthly-amount) monthly-growth))))) - annual-inflation - years-invested)) - -(defn investment-benchmark-chart - [id labels investment investment2 investment3] - (let [context (.getContext (.getElementById js/document id) "2d") - chart-data {:type "line" - :options {:legend {:labels {:fontColor "white"}} - :scales {:xAxes [{:scaleLabel {:display true :labelString "years" :fontColor "white"} :ticks {:fontColor "white" :maxTicksLimit 12}}] - :yAxes [{:ticks {:callback (fn [value, index, values] (format-number value)) :fontColor "white"}}]} - :tooltips {:callbacks {:label (fn [tooltip-item data] (format-number (aget tooltip-item "yLabel")))}}} - :data {:labels labels - :datasets [{:data investment - :label "Current Investment" - :lineTension 0 - :fill false - :borderColor "#8e44ad" - :cubicInterpolationMode "linear" - :backgroundColor "#8e44ad"} - {:data investment2 - :label "Invest 25,000 Monthly" - :lineTension 0 - :fill false - :borderColor "#e67e22" - :cubicInterpolationMode "linear" - :backgroundColor "#e67e22"} - {:data investment3 - :label "Invest 10,000 Monthly" - :lineTension 0 - :fill false - :borderColor "#2ecc71" - :cubicInterpolationMode "linear" - :backgroundColor "#2ecc71"}]}}] - - (js/Chart. context (clj->js chart-data)))) - -(defn investment-benchmark-over-time-chart [] - (let [labels (range 36) - investment (->> labels (map #(calculate-investment-value {:monthly-amount 6000 - :annual-growth-rate 0.15 - :annual-monthly-amount-escalation 0.06 - :annual-inflation 0.06 - :years-invested %}))) - invest-2 (->> labels (map #(calculate-investment-value {:monthly-amount 25000 - :annual-growth-rate 0.15 - :annual-monthly-amount-escalation 0.06 - :annual-inflation 0.06 - :years-invested %}))) - invest-3 (->> labels (map #(calculate-investment-value {:monthly-amount 10000 - :annual-growth-rate 0.15 - :annual-monthly-amount-escalation 0.06 - :annual-inflation 0.06 - :years-invested %})))] - (chart-box "INVESTMENT BENCHMARK" (draw-chart - "investment-benchmark-chart" - investment-benchmark-chart labels investment invest-2 invest-3)))) - -(defn net-worth-over-time-chart [{:keys [net-worths]}] - (let [labels (->> net-worths (map :cljs-date) (map #(tf/unparse custom-month-year %))) - net-worth (->> net-worths (map :amount))] - (chart-box "NET WORTH OVER TIME" (draw-chart - "net-worth-over-time" - net-worth-line-chart labels net-worth nil nil)))) - -(defn assets-over-time-chart [{:keys [net-assets]}] - (let [labels (->> net-assets (map :cljs-date) (map #(tf/unparse custom-month-year %))) - assets (->> net-assets (map :amount))] - (chart-box "ASSETS OVER TIME" (draw-chart - "assets-over-time" - assets-line-chart labels assets nil nil)))) - -(defn liabilities-over-time-chart [{:keys [net-liabilities]}] - (let [labels (->> net-liabilities (map :cljs-date) (map #(tf/unparse custom-month-year %))) - liabilities (->> net-liabilities (map :amount))] - (chart-box "LIABILITIES OVER TIME" (draw-chart - "liabilities-over-time" - liabilities-line-chart labels liabilities nil nil)))) - -(defn emergency-fund-months-info-box [{:keys [emergency-fund-months emergency-fund-months-change]}] - [:div.has-text-centered.info-box - [:p.heading "EMERGENCY FUND MONTHS"] - [:p.title {:class "has-text-light"} (format-number emergency-fund-months)] - (if (= (get emergency-fund-months-change :direction) :up) - [:p.subtitle.is-size-7.has-text-light.has-text-success - [:i.fa.fa-arrow-up] (str " " (format-number (get emergency-fund-months-change :delta)) " (" (format-number (get emergency-fund-months-change :percentage)) "%)")] - (if (= (get emergency-fund-months-change :direction) :down) - [:p.subtitle.is-size-7.has-text-light.has-text-danger - [:i.fa.fa-arrow-down] (str " " (format-number (get emergency-fund-months-change :delta)) " (" (format-number (get emergency-fund-months-change :percentage)) "%)")] - [:p.subtitle.is-size-7.has-text-light.has-text-warning - [:i.fa.fa-arrow-right] (str " " (format-number (get emergency-fund-months-change :delta)) " (" (format-number (get emergency-fund-months-change :percentage)) "%)")]))]) - -(defn net-worth-info-box [{:keys [net-worth net-worth-change]}] - [:div.has-text-centered.info-box - [:p.heading "NET WORTH"] - [:p.title {:class "has-text-light"} (format-number net-worth)] - (if (= (get net-worth-change :direction) :up) - [:p.subtitle.is-size-7.has-text-light.has-text-success - [:i.fa.fa-arrow-up] (str " " (format-number (get net-worth-change :delta)) " (" (format-number (get net-worth-change :percentage)) "%)")] - (if (= (get net-worth-change :direction) :down) - [:p.subtitle.is-size-7.has-text-light.has-text-danger - [:i.fa.fa-arrow-down] (str " " (format-number (get net-worth-change :delta)) " (" (format-number (get net-worth-change :percentage)) "%)")] - [:p.subtitle.is-size-7.has-text-light.has-text-warning - [:i.fa.fa-arrow-right] (str " " (format-number (get net-worth-change :delta)) " (" (format-number (get net-worth-change :percentage)) "%)")]))]) - - -(defn fi-investments-info-box [{:keys [fi-investments fi-investments-change]}] - [:div.has-text-centered.info-box - [:p.heading "FI INVESTMENTS"] - [:p.title {:class "has-text-light"} (format-number (:amount (last fi-investments)))] - (if (= (get fi-investments-change :direction) :up) - [:p.subtitle.is-size-7.has-text-light.has-text-success - [:i.fa.fa-arrow-up] (str " " (format-number (get fi-investments-change :delta)) " (" (format-number (get fi-investments-change :percentage)) "%)")] - (if (= (get fi-investments-change :direction) :down) - [:p.subtitle.is-size-7.has-text-light.has-text-danger - [:i.fa.fa-arrow-down] (str " " (format-number (get fi-investments-change :delta)) " (" (format-number (get fi-investments-change :percentage)) "%)")] - [:p.subtitle.is-size-7.has-text-light.has-text-warning - [:i.fa.fa-arrow-right] (str " " (format-number (get fi-investments-change :delta)) " (" (format-number (get fi-investments-change :percentage)) "%)")]))]) - -(defn change-str [change change-percentage] - (if (nil? change-percentage) - (str " " (format-number change)) - (str " " (format-number change) " (" (format-number change-percentage) "%)"))) - -(defn info-box-with-amount-and-change [title amount change change-percentage change-direction] - [:div.has-text-centered.info-box - [:p.heading title] - [:p.title {:class "has-text-light"} (format-number amount)] - (if (= change-direction :up) - [:p.subtitle.is-size-7.has-text-light.has-text-success - [:i.fa.fa-arrow-up] (change-str change change-percentage)] - (if (= change-direction :down) - [:p.subtitle.is-size-7.has-text-light.has-text-danger - [:i.fa.fa-arrow-down] (change-str change change-percentage)] - [:p.subtitle.is-size-7.has-text-light.has-text-warning - [:i.fa.fa-arrow-right] (change-str change change-percentage)]))]) - -(defn fi-monthly-withdrawal-info-box [{:keys [fi-investments fi-monthly-withdrawal-change]}] - (let [title "FI MONTHLY WITHDRAWAL" - amount (:fi-monthly-withdrawal (last fi-investments)) - change (:delta fi-monthly-withdrawal-change) - change-percentage (:percentage fi-monthly-withdrawal-change) - change-direction (:direction fi-monthly-withdrawal-change)] - (info-box-with-amount-and-change title amount change change-percentage change-direction))) - -(defn fi-percentage-info-box [{:keys [fi-investments]}] - (let [title "FI PERCENTAGE" - amount (:fi-percentage (last fi-investments)) - change (- amount (:fi-percentage (first (take-last 2 fi-investments)))) - change-percentage nil - change-direction (if (pos? change) - :up - (if (neg? change) - :down - :same))] - (info-box-with-amount-and-change title amount change change-percentage change-direction))) - -(defn investments-info-box [{:keys [investments investments-change]}] - (let [title "INVESTMENTS" - amount (:amount (last investments)) - change (:delta investments-change) - change-percentage (:percentage investments-change) - change-direction (:direction investments-change)] - (info-box-with-amount-and-change title amount change change-percentage change-direction))) - - -(defn tfsa-yearly-contributions-chart [{:keys [tfsa-contributions-per-year]}] - (let [labels (->> tfsa-contributions-per-year (map :year)) - contributions (->> tfsa-contributions-per-year (map :amount)) - limits (->> tfsa-contributions-per-year (map :limit))] - (chart-box "TFSA YEARLY CONTRIBUTIONS" - (draw-chart - "tfsa-yearly-contributions" - tfsa-yearly-chart labels contributions limits nil)))) - -(defn tfsa-lifetime-contribution-chart [{:keys [tfsa-contributions-over-lifetime]}] -(let [contribution [(:amount tfsa-contributions-over-lifetime)] - limit [(:limit tfsa-contributions-over-lifetime)]] - (chart-box "TFSA LIFETIME CONTRIBUTION" - (draw-chart - "tfsa-lifetime-contribution" - tfsa-lifetime-chart contribution limit nil nil)))) - -(defn asset-distribution-chart [] -(chart-box "ASSET TYPE DISTRIBUTION" - (draw-chart "asset-distribution" pie-chart-1 nil nil nil nil))) - -(defn asset-geographic-distribution-chart [] -(chart-box "ASSET GEOGRAPHIC DISTRIBUTION" - (draw-chart "asset-geographic-distribution" pie-chart-2 nil nil nil nil))) - -(defn asset-allocation-chart [] -(chart-box "ASSET ALLOCATION" - (draw-chart "asset-allocation" pie-chart-3 nil nil nil nil))) - -(defmethod render-page :main [{:keys [data]}] - (let [col - (if (= (-> - data - (get :sample) - (first) - (get :is-sample)) - "yes") - col-sample-data - col-real-data)] - [:div.columns.is-multiline.is-centered - [col 2 12 (net-worth-info-box data)] - [col 2 12 (emergency-fund-months-info-box data)] - [col 2 12 (investments-info-box data)] - [col 2 12 (fi-investments-info-box data)] - [col 2 12 (fi-monthly-withdrawal-info-box data)] - [col 2 12 (fi-percentage-info-box data)] - [col 4 12 (net-worth-over-time-chart data)] - [col 4 12 (assets-over-time-chart data)] - [col 4 12 (liabilities-over-time-chart data)] - [col 6 12 (cash-flow-over-time-chart data)] - [col 6 12 (savings-rate-over-time-chart data)] - [col 6 12 (tfsa-yearly-contributions-chart data)] - [col 6 12 (tfsa-lifetime-contribution-chart data)] - [col 12 12 (investment-benchmark-over-time-chart)] - ;; [col 4 12 (asset-distribution-chart)] - ;; [col 4 12 (asset-geographic-distribution-chart)] - ;; [col 4 12 (asset-allocation-chart)] - ])) - -(defn footer [] - [:footer.footer - [:div.content.has-text-centered - [:p "Built with ❤️ by " - [:a {:href "https://rameezkhan.me"} "Rameez"]]]]) - -(defn app [] - [:div - [nav] - (when-not (= :hidden (get-in @state [:modal :key])) - [modal state]) - [:div.section.has-background-light - (render-page @state)] - (footer)]) - -(defn sleep [f ms] -(js/setTimeout f ms)) - -(defmethod render-page :loading [state] -[:div "loading"]) - -(defn get-app-element [] -(gdom/getElement "app")) - -(defn mount [el] -(reagent/render-component [app] el)) - -(defn mount-app-element [] -(when-let [el (get-app-element)] - (mount el))) - -(when (= :loading (:page @state)) -(build-app-data-from-localstorage-data (or - (get-data-from-localstorage) - (get-sample-data))) -(js/setTimeout #(page :main))) - -;; conditionally start your application based on the presence of an "app" element -;; this is particularly helpful for testing this ns without launching the app -(mount-app-element) - -;; specify reload hook with ^;after-load metadata -(defn ^:after-load on-reload [] -(mount-app-element) -;; optionally touch your app-state to force rerendering depending on -;; your application -;; (swap! app-state update-in [:__figwheel_counter] inc) -) diff --git a/src/financial_health_dashboard/domain.cljs b/src/financial_health_dashboard/domain.cljs deleted file mode 100644 index 752f1f1..0000000 --- a/src/financial_health_dashboard/domain.cljs +++ /dev/null @@ -1,337 +0,0 @@ -(ns financial-health-dashboard.domain - (:require - [clojure.spec.alpha :as s] - [cljs-time.core :as time])) - -(defn not-empty-string? [s] (and (string? s) - (not-empty s))) -(defn year? [n] (boolean (and (number? n) (>= n 1900) (> 3000 n)))) -(defn month? [n] (boolean (and (number? n) (>= n 1) (> 13 n)))) -(def yes "yes") -(def no "no") - -(def tfsa-lifetime-limit 500000) - -(def tfsa-limits - {:2016 30000 - :2017 30000 - :2018 33000 - :2019 33000 - :2020 33000 - :2021 36000}) - -(def fi-yearly-withdrawal-rate 0.04) -(def fi-monthly-withdrawal-rate (/ fi-yearly-withdrawal-rate 12)) - - -;; SPECS - - -(s/def :d/year year?) -(s/def :d/month month?) -(s/def :d/amount number?) -(s/def :d/name not-empty-string?) -(s/def :d/is-sample #(contains? #{yes no} %)) - - -;; DATA TYPES - - -(def data-types-config - [["sample" - [:d/is-sample] - "Indicate sample data"] - ["comment" - [] - "A row used for any kind of comment"] - ["income" - [:d/name :d/year :d/month :d/amount] - "Income"] - ["expense" - [:d/name :d/year :d/month :d/amount] - "Expense"] - ["emergency-monthly-expense" - [:d/year :d/month :d/amount] - "Monthly expense. This doesn't include contributions to RA's, investments or savings accounts."] - ["emergency-fund" - [:d/year :d/month :d/amount] - "Emergency fund balance."] - ["asset" - [:d/name :d/year :d/month :d/amount]] - ["liability" - [:d/name :d/year :d/month :d/amount]] - ["tfsa-contribution" - [:d/year :d/month :d/amount]] - ["fi-expense" - [:d/amount]]]) - -(def data-types (->> data-types-config - (map (juxt first second)) - (into {}))) - -(defn type-of? [data-type m] - (= data-type (:data-type m))) - -(defn type-of-f? [data-type] (partial type-of? data-type)) - -(defn types-of-f? [& types] - (fn [m] (->> types - (map #(type-of? % m)) - (filter true?) - not-empty))) - -(defn timestamped [{:keys [year month day] :as m}] - (let [date (js/Date. year (dec month) day)] ;;js months start at 0 - (assoc m - :date date - :cljs-date (time/date-time year month day) - :timestamp (.getTime date)))) - - -;; DATA EXTRACTORS -(defn income [data] - (->> data (filter (type-of-f? :income)) - (map timestamped) - (sort-by :timestamp))) - -(defn emergency-monthly-expense [data] - (->> data (filter (type-of-f? :emergency-monthly-expense)) - (map timestamped) - (sort-by :timestamp))) - -(defn emergency-fund [data] - (->> data (filter (type-of-f? :emergency-fund)) - (map timestamped) - (sort-by :timestamp))) - -(defn emergency-fund-months [emergency-fund emergency-monthly-expense] - (let [latest-emergency-monthly-expense (get (last emergency-monthly-expense) :amount) - latest-emergency-fund-balance (get (last emergency-fund) :amount)] - (/ latest-emergency-fund-balance latest-emergency-monthly-expense))) - -(defn emergency-fund-months-change [emergency-fund emergency-monthly-expense] - (if (> (count emergency-fund) 1) - (let [latest-emergency-monthly-expense (get (last emergency-monthly-expense) :amount) - latest-em-fund-balance (get (last emergency-fund) :amount) - second-last-em-fund-balance (get (-> emergency-fund (reverse) (nth 1 nil)) :amount) - change-in-amount (- latest-em-fund-balance second-last-em-fund-balance) - delta (/ change-in-amount latest-emergency-monthly-expense)] - (if (= delta 0.0) - {:direction :same :delta delta :percentage 0} - (if (< delta 0) - {:direction :down :delta (* -1 delta) :percentage (* (/ change-in-amount second-last-em-fund-balance) -100)} - {:direction :up :delta delta :percentage (* (/ change-in-amount second-last-em-fund-balance) 100)}))) - nil)) - -(defn sample [data] - (->> data (filter (type-of-f? :sample)))) - -(defn assets [data] - (->> data (filter (type-of-f? :asset)) - (map timestamped) - (sort-by :timestamp))) - -(defn net-per-month [data] - (->> data (map #(assoc % :grouping [(:year %) (:month %)])) - (group-by :grouping) - (map (fn [[g t]] - [g (->> t (map :amount) (reduce +))])) - (into (sorted-map)))) - -(defn liabilities [data] - (->> data (filter (type-of-f? :liability)) - (map timestamped) - (sort-by :timestamp))) - -(defn net-worth - ([net-assets net-liabilities] (net-worth net-assets net-liabilities 1)) - ([net-assets net-liabilities n-last] - (let [latest-monthly-net-assets (->> net-assets (take-last n-last) (first) (second)) - latest-monthly-net-liabilities (->> net-liabilities (take-last n-last) (first) (second))] - (- latest-monthly-net-assets latest-monthly-net-liabilities)))) - -(defn net-worth-change [net-assets-per-month net-liabilities-per-month] - (if (or (> (count net-assets-per-month) 1) (> (count net-liabilities-per-month) 1)) - (let [latest-net-worth (net-worth net-assets-per-month net-liabilities-per-month) - second-last-net-worth (net-worth net-assets-per-month net-liabilities-per-month 2) - delta (- latest-net-worth second-last-net-worth)] - (if (zero? delta) - {:direction :same :delta delta :percentage 0} - (if (neg? delta) - {:direction :down :delta (* -1 delta) :percentage (* (/ delta second-last-net-worth) -100)} - {:direction :up :delta delta :percentage (* (/ delta second-last-net-worth) 100)}))) - nil)) - -(defn flatten-grouped-months [grouped-months] - (map (fn [[[y m] a]] {:year y :month m :amount a}) grouped-months)) - -(defn net-worths [assets liabilities] - (let [l (->> liabilities (map #(assoc % :amount (* -1 (:amount %))))) - al (concat assets l)] - (->> al (map #(assoc % :grouping [(:year %) (:month %)])) - (group-by :grouping) - (map (fn [[g t]] - [g (->> t (map :amount) (reduce +))])) - (into {})))) - -(defn make-series-from-grouped-data [grouped-data] - (->> grouped-data (flatten-grouped-months) - (map timestamped) - (sort-by :timestamp))) - -(defn tfsa-contributions [data] - (->> data (filter (type-of-f? :tfsa-contribution)) - (map timestamped) - (sort-by :timestamped))) - -(defn tax-year [date] - (let [year (time/year date) - month (time/month date)] - (if (> month 2) (inc year) year))) - -(defn tfsa-contributions-per-year [contributions] - (->> contributions (map #(assoc % :tax-year [(tax-year (:cljs-date %))])) - (group-by :tax-year) - (map (fn [[g t]] - [g (->> t (map :amount) (reduce +))])) - (into {}))) - -(defn tfsa-contributions-over-lifetime [contributions] - (let [total (->> contributions (map :amount) (reduce +))] - {:amount total :limit tfsa-lifetime-limit})) - -(defn map-tfsa-yearly-limits [contributions] - (->> contributions (map #(assoc % - :limit (get tfsa-limits - (keyword (str (:year %)))))))) - -(defn expenses [data] - (->> data (filter (type-of-f? :expense)) - (map timestamped) - (sort-by :timestamp))) - -(defn fi-expense [data] - (last (->> data (filter (type-of-f? :fi-expense))))) - - -(defn investments [assets] - (->> assets - (filter #(or - (= (:name %) "tfsa") - (= (:name %) "liberty-ra") - (= (:name %) "liberty-preservation-fund") - (= (:name %) "sygnia-ra") - (= (:name %) "td-ameritrade") - (= (:name %) "education-fund"))) - (map #(assoc % :grouping [(:year %) (:month %)])) - (group-by :grouping) - (map (fn [[g t]] - [g (->> t (map :amount) (reduce +))])) - (into {}))) - -(defn investments-change [investments] - (if (> (count investments) 1) - (let [latest-amount (:amount (last investments )) - second-last-amount (:amount (first (take-last 2 investments))) - delta (- latest-amount second-last-amount)] - (if (zero? delta) - {:direction :same :delta delta :percentage 0} - (if (neg? delta) - {:direction :down :delta (* -1 delta) :percentage (* (/ delta second-last-amount) -100)} - {:direction :up :delta delta :percentage (* (/ delta second-last-amount) 100)}))) - nil)) - -(defn fi-investments [assets] - (->> assets - (filter #(or - (= (:name %) "tfsa") - (= (:name %) "td-ameritrade"))) - (map #(assoc % :grouping [(:year %) (:month %)])) - (group-by :grouping) - (map (fn [[g t]] - [g (->> t (map :amount) (reduce +))])) - (into {}))) - -(defn fi-investments-change [fi-investments] - (if (> (count fi-investments) 1) - (let [latest-amount (:amount (last fi-investments )) - second-last-amount (:amount (first (take-last 2 fi-investments))) - delta (- latest-amount second-last-amount)] - (if (zero? delta) - {:direction :same :delta delta :percentage 0} - (if (neg? delta) - {:direction :down :delta (* -1 delta) :percentage (* (/ delta second-last-amount) -100)} - {:direction :up :delta delta :percentage (* (/ delta second-last-amount) 100)}))) - nil)) - -(defn map-fi-withdrawals [investments] - (->> investments (map #(assoc % - :fi-monthly-withdrawal (Math/ceil ( * fi-monthly-withdrawal-rate (:amount %) )))))) - -(defn map-fi-percentage [fi-expense investments] - (->> investments (map #(assoc % - :fi-percentage (* (/ (:amount %) (* (:amount fi-expense) 300)) 100))))) - - - -(defn fi-monthly-withdrawal-change [fi-investments] - (if (> (count fi-investments) 1) - (let [latest-amount (:fi-monthly-withdrawal (last fi-investments )) - second-last-amount (:fi-monthly-withdrawal (first (take-last 2 fi-investments))) - delta (- latest-amount second-last-amount)] - (if (zero? delta) - {:direction :same :delta delta :percentage 0} - (if (neg? delta) - {:direction :down :delta (* -1 delta) :percentage (* (/ delta second-last-amount) -100)} - {:direction :up :delta delta :percentage (* (/ delta second-last-amount) 100)}))) - nil)) - - -(defn all-your-bucks[data] - (let [sample (sample data) - income (income data) - expenses (->> data (expenses) (net-per-month) (make-series-from-grouped-data)) - emergency-fund (emergency-fund data) - emergency-monthly-expense (emergency-monthly-expense data) - emergency-fund-months (emergency-fund-months emergency-fund emergency-monthly-expense) - emergency-fund-months-change (emergency-fund-months-change emergency-fund emergency-monthly-expense) - assets (assets data) - net-assets-per-month (net-per-month assets) - net-assets-series (make-series-from-grouped-data net-assets-per-month) - liabilities (liabilities data) - net-liabilities-per-month (net-per-month liabilities) - net-liabilities-series (make-series-from-grouped-data net-liabilities-per-month) - net-worth (net-worth net-assets-per-month net-liabilities-per-month) - net-worths (make-series-from-grouped-data (net-worths assets liabilities)) - net-worth-change (net-worth-change net-assets-per-month net-liabilities-per-month) - tfsa-contributions (tfsa-contributions data) - tfsa-contributions-per-year (->> tfsa-contributions - (tfsa-contributions-per-year) - (make-series-from-grouped-data) - (map-tfsa-yearly-limits)) - tfsa-contributions-over-lifetime (tfsa-contributions-over-lifetime tfsa-contributions) - fi-expense (fi-expense data) - fi-investments (map-fi-percentage fi-expense ( map-fi-withdrawals (make-series-from-grouped-data (fi-investments assets)) )) - investments (make-series-from-grouped-data (investments assets)) - investments-change (investments-change investments) - fi-investments-change (fi-investments-change fi-investments) - fi-monthly-withdrawal-change (fi-monthly-withdrawal-change fi-investments) - ] - {:sample sample - :income income - :expenses expenses - :emergency-fund-months emergency-fund-months - :emergency-fund-months-change emergency-fund-months-change - :net-worths net-worths - :net-worth net-worth - :net-worth-change net-worth-change - :net-assets net-assets-series - :net-liabilities net-liabilities-series - :tfsa-contributions-per-year tfsa-contributions-per-year - :tfsa-contributions-over-lifetime tfsa-contributions-over-lifetime - :fi-investments fi-investments - :fi-investments-change fi-investments-change - :investments investments - :investments-change investments-change - :fi-monthly-withdrawal-change fi-monthly-withdrawal-change})) - diff --git a/src/financial_health_dashboard/example.cljs b/src/financial_health_dashboard/example.cljs deleted file mode 100644 index 43d5427..0000000 --- a/src/financial_health_dashboard/example.cljs +++ /dev/null @@ -1,83 +0,0 @@ -(ns financial-health-dashboard.example - (:require [cljs-time.core :as time] - [clojure.string :as str])) - -(def now (time/now)) - -(def this-year (time/year now)) - -(def last-year (dec this-year)) - -(def date-of-birth - [["date-of-birth" 1985 11 6]]) - -(def year-goals - [["year-goal" this-year 15] - ["year-goal" this-year 13] - ["year-goal" this-year 11]]) - -(def income - [["income" "salary" this-year 1 20000] - ["income" "salary" this-year 2 18000] - ["income" "salary" this-year 3 22000] - ["income" "salary" this-year 4 19000] - ["income" "salary" this-year 5 28000]]) - -(def expense - [["expense" "day-to-day" this-year 1 18000] - ["expense" "recurring" this-year 1 2000] - ["expense" "day-to-day" this-year 2 19000] - ["expense" "day-to-day" this-year 3 21000] - ["expense" "day-to-day" this-year 4 19000] - ["expense" "day-to-day" this-year 5 21000]]) - -(def emergency-monthly-expense - [["emergency-monthly-expense" this-year 1 20000]]) - -(def emergency-fund - [["emergency-fund" this-year 3 50000] - ["emergency-fund" this-year 4 60000]]) - -(def example-comment - [["comment" "some random comment"]]) - -(def sample - [["sample" "yes"]]) - -(def assets - [["asset" "emergency-fund" this-year 1 10000] - ["asset" "emergency-fund" this-year 2 20000] - ["asset" "emergency-fund" this-year 3 30000] - ["asset" "TFSA" this-year 1 30000] - ["asset" "TFSA" this-year 2 40000] - ["asset" "TFSA" this-year 3 50000]]) - -(def liabilities - [["liability" "home-loan" this-year 1 8000] - ["liability" "home-loan" this-year 2 6000]]) - -(def tfsa-contributions - [["tfsa-contribution" 2016 3 0] - ["tfsa-contribution" this-year 2 6000] - ["tfsa-contribution" this-year 3 6000] - ["tfsa-contribution" this-year 4 6000]]) - -(def fi-expense - [["fi-expense" 10000]]) - -(def data-piped - (->> [sample - date-of-birth - year-goals - income - expense - emergency-monthly-expense - emergency-fund - assets - liabilities - tfsa-contributions - fi-expense] - (reduce into) - (map #(->> % (map str) (str/join "|"))) - (str/join "\n"))) - diff --git a/src/financial_health_dashboard/localstorage.cljs b/src/financial_health_dashboard/localstorage.cljs deleted file mode 100644 index 2f71fee..0000000 --- a/src/financial_health_dashboard/localstorage.cljs +++ /dev/null @@ -1,11 +0,0 @@ -(ns financial-health-dashboard.localstorage) - -(defn set-item! - "Set `key' in browser's localStorage to `val`." - [key val] - (.setItem (.-localStorage js/window) key val)) - -(defn get-item - "Returns value of `key' from browser's localStorage." - [key] - (.getItem (.-localStorage js/window) key)) diff --git a/src/financial_health_dashboard/parse.cljs b/src/financial_health_dashboard/parse.cljs deleted file mode 100644 index 826e940..0000000 --- a/src/financial_health_dashboard/parse.cljs +++ /dev/null @@ -1,78 +0,0 @@ -(ns financial-health-dashboard.parse - (:require - [financial-health-dashboard.domain :as d] - [cljs.spec.alpha :as s] - [clojure.string :as str] - [cljs.reader :as reader] - [testdouble.cljs.csv :as csv])) - -(def pipe "|") - -(defn- not-empty-row? [row] - (->> row - (filter (comp not empty?)) - count - (not= 0))) - -(defn- parse-field - [s] - (let [value (reader/read-string s)] - (if (symbol? value) s value))) - -(defn- parse-row [row] - (map - (fn [field] - (-> field - str/trim - parse-field)) - row)) - -(defn- validate-row-data [key data] - (let [specs (get d/data-types key)] - (->> specs - (map-indexed - (fn [i spec] - (let [field (nth data i)] - {:valid? (s/valid? spec field) - :spec spec - :field field})))))) - -(defn- validate-row [[key & data]] - (if-not (contains? d/data-types key) - {:valid? false :error (str key " is an invalid data type") :data data} - (let [validation (validate-row-data key data) - specs (->> (get d/data-types key))] - (if (empty? (->> validation (map :valid?) (filter false?))) - {:valid? true :specs specs :data data :key (keyword key)} - (let [failed-specs (->> validation - (filter (comp false? :valid?)) - (map :spec))] - {:valid false :data data - :specs specs - :key (keyword key) - :failed-specs failed-specs - :error (str key " has invalid values for " - (map name failed-specs) - ". Expected " (map name specs))}))))) - -(defn parse - [seperator data] - (->> (csv/read-csv data :separator seperator) - (filter not-empty-row?) - (map-indexed (fn [i r] - (-> r parse-row validate-row (assoc :i (inc i))))))) - - -(defn- as-domain-value [{:keys [specs key data]}] - (-> (zipmap - (map (comp keyword name) specs) - (take (count specs) data)) - (assoc :data-type key))) - -(defn as-domain-values - "Converts a collection of parsed and valid data rows into domain data." - [rows] - (->> rows - (filter :valid?) - (map as-domain-value))) - diff --git a/src/financial_health_dashboard/scratch.cljs b/src/financial_health_dashboard/scratch.cljs deleted file mode 100644 index c6f80cd..0000000 --- a/src/financial_health_dashboard/scratch.cljs +++ /dev/null @@ -1,7 +0,0 @@ -(ns financial-health-dashboard.scratch - (:require - [financial-health-dashboard.parse :as parse] - [financial-health-dashboard.example :as example])) - -(defn load-example-data [] - (parse/as-domain-values (parse/parse "|" example/data-piped))) diff --git a/test.cljs.edn b/test.cljs.edn deleted file mode 100644 index 6d2fbbf..0000000 --- a/test.cljs.edn +++ /dev/null @@ -1,10 +0,0 @@ -^{ - ;; use an alternative landing page for the tests so that we don't - ;; launch the application - :open-url "http://[[server-hostname]]:[[server-port]]/test.html" - - ;; uncomment to launch tests in a headless environment - ;; you will have to figure out the path to chrome on your system - ;; :launch-js ["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" "--headless" "--disable-gpu" "--repl" :open-url] - } -{:main financial-health-dashboard.test-runner} diff --git a/test/financial_health_dashboard/core_test.cljs b/test/financial_health_dashboard/core_test.cljs deleted file mode 100644 index 10ec82d..0000000 --- a/test/financial_health_dashboard/core_test.cljs +++ /dev/null @@ -1,10 +0,0 @@ -(ns financial-health-dashboard.core-test - (:require - [cljs.test :refer-macros [deftest is testing]] - [financial-health-dashboard.core :refer [multiply]])) - -(deftest multiply-test - (is (= (* 1 2) (multiply 1 2)))) - -(deftest multiply-test-2 - (is (= (* 75 10) (multiply 10 75)))) diff --git a/test/financial_health_dashboard/test_runner.cljs b/test/financial_health_dashboard/test_runner.cljs deleted file mode 100644 index 33f23bf..0000000 --- a/test/financial_health_dashboard/test_runner.cljs +++ /dev/null @@ -1,9 +0,0 @@ -;; This test runner is intended to be run from the command line -(ns financial-health-dashboard.test-runner - (:require - ;; require all the namespaces that you want to test - [financial-health-dashboard.core-test] - [figwheel.main.testing :refer [run-tests-async]])) - -(defn -main [& args] - (run-tests-async 5000)) From e912117ee4f64003451d8fff87ae8c7fc01d901c Mon Sep 17 00:00:00 2001 From: Rameez Khan Date: Tue, 9 Feb 2021 07:31:40 +0200 Subject: [PATCH 02/16] Add .gitignore --- .gitignore | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..295a9c8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,20 @@ +node_modules/ +public/js + +/target +/checkouts +/src/gen + +pom.xml +pom.xml.asc +*.iml +*.jar +*.log +.shadow-cljs +.idea +.lein-* +.nrepl-* +.DS_Store + +.hgignore +.hg/ From cd5350a98060fe66b29763c3c744161842e462a5 Mon Sep 17 00:00:00 2001 From: Rameez Khan Date: Tue, 9 Feb 2021 07:49:14 +0200 Subject: [PATCH 03/16] Add npm --- package.json | 18 ++ yarn.lock | 698 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 716 insertions(+) create mode 100644 package.json create mode 100644 yarn.lock diff --git a/package.json b/package.json new file mode 100644 index 0000000..3d8a65f --- /dev/null +++ b/package.json @@ -0,0 +1,18 @@ +{ + "name": "financial-health-dashboard", + "version": "2.0.0", + "main": "index.js", + "repository": "git@github.com:rameezk/financial-health-dashboard.git", + "author": "Rameez Khan", + "license": "MIT", + "dependencies": { + "react": "17.0.1", + "react-dom": "17.0.1" + }, + "devDependencies": { + "shadow-cljs": "^2.11.18" + }, + "scripts": { + "dev": "shadow-cljs watch app" + } +} diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..4a24e92 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,698 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +asn1.js@^5.2.0: + version "5.4.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" + integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA== + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + safer-buffer "^2.1.0" + +assert@^1.1.1: + version "1.5.0" + resolved "https://registry.yarnpkg.com/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb" + integrity sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA== + dependencies: + object-assign "^4.1.1" + util "0.10.3" + +async-limiter@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" + integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== + +base64-js@^1.0.2: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.9: + version "4.11.9" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.9.tgz#26d556829458f9d1e81fc48952493d0ba3507828" + integrity sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw== + +bn.js@^5.0.0, bn.js@^5.1.1: + version "5.1.3" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.1.3.tgz#beca005408f642ebebea80b042b4d18d2ac0ee6b" + integrity sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ== + +brorand@^1.0.1, brorand@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= + +browserify-aes@^1.0.0, browserify-aes@^1.0.4: + version "1.2.0" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== + dependencies: + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + +browserify-cipher@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" + integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" + integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +browserify-rsa@^4.0.0, browserify-rsa@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.1.0.tgz#b2fd06b5b75ae297f7ce2dc651f918f5be158c8d" + integrity sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog== + dependencies: + bn.js "^5.0.0" + randombytes "^2.0.1" + +browserify-sign@^4.0.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.1.tgz#eaf4add46dd54be3bb3b36c0cf15abbeba7956c3" + integrity sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg== + dependencies: + bn.js "^5.1.1" + browserify-rsa "^4.0.1" + create-hash "^1.2.0" + create-hmac "^1.1.7" + elliptic "^6.5.3" + inherits "^2.0.4" + parse-asn1 "^5.1.5" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + +browserify-zlib@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" + integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA== + dependencies: + pako "~1.0.5" + +buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= + +buffer@^4.3.0: + version "4.9.2" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8" + integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg== + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + isarray "^1.0.0" + +builtin-status-codes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" + integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug= + +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +console-browserify@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" + integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== + +constants-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" + integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= + +core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + +create-ecdh@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e" + integrity sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A== + dependencies: + bn.js "^4.1.0" + elliptic "^6.5.3" + +create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +crypto-browserify@^3.11.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" + integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== + dependencies: + browserify-cipher "^1.0.0" + browserify-sign "^4.0.0" + create-ecdh "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.0" + diffie-hellman "^5.0.0" + inherits "^2.0.1" + pbkdf2 "^3.0.3" + public-encrypt "^4.0.0" + randombytes "^2.0.0" + randomfill "^1.0.3" + +des.js@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" + integrity sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA== + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +diffie-hellman@^5.0.0: + version "5.0.3" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" + integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + +domain-browser@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" + integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== + +elliptic@^6.5.3: + version "6.5.4" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" + integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== + dependencies: + bn.js "^4.11.9" + brorand "^1.1.0" + hash.js "^1.0.0" + hmac-drbg "^1.0.1" + inherits "^2.0.4" + minimalistic-assert "^1.0.1" + minimalistic-crypto-utils "^1.0.1" + +events@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.2.0.tgz#93b87c18f8efcd4202a461aec4dfc0556b639379" + integrity sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg== + +evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + +hash-base@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" + integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== + dependencies: + inherits "^2.0.4" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + +hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +hmac-drbg@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +https-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" + integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= + +ieee754@^1.1.4: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + +inherits@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" + integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= + +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + +inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +isarray@^1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +"js-tokens@^3.0.0 || ^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +loose-envify@^1.1.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +md5.js@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +miller-rabin@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" + integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= + +node-libs-browser@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" + integrity sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q== + dependencies: + assert "^1.1.1" + browserify-zlib "^0.2.0" + buffer "^4.3.0" + console-browserify "^1.1.0" + constants-browserify "^1.0.0" + crypto-browserify "^3.11.0" + domain-browser "^1.1.1" + events "^3.0.0" + https-browserify "^1.0.0" + os-browserify "^0.3.0" + path-browserify "0.0.1" + process "^0.11.10" + punycode "^1.2.4" + querystring-es3 "^0.2.0" + readable-stream "^2.3.3" + stream-browserify "^2.0.1" + stream-http "^2.7.2" + string_decoder "^1.0.0" + timers-browserify "^2.0.4" + tty-browserify "0.0.0" + url "^0.11.0" + util "^0.11.0" + vm-browserify "^1.0.1" + +object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + +os-browserify@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" + integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= + +pako@~1.0.5: + version "1.0.11" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" + integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== + +parse-asn1@^5.0.0, parse-asn1@^5.1.5: + version "5.1.6" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4" + integrity sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw== + dependencies: + asn1.js "^5.2.0" + browserify-aes "^1.0.0" + evp_bytestokey "^1.0.0" + pbkdf2 "^3.0.3" + safe-buffer "^5.1.1" + +path-browserify@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a" + integrity sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ== + +pbkdf2@^3.0.3: + version "3.1.1" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.1.tgz#cb8724b0fada984596856d1a6ebafd3584654b94" + integrity sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg== + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= + +public-encrypt@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" + integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + safe-buffer "^5.1.2" + +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= + +punycode@^1.2.4: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= + +querystring-es3@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" + integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM= + +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= + +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +randomfill@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" + integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== + dependencies: + randombytes "^2.0.5" + safe-buffer "^5.1.0" + +react-dom@17.0.1: + version "17.0.1" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.1.tgz#1de2560474ec9f0e334285662ede52dbc5426fc6" + integrity sha512-6eV150oJZ9U2t9svnsspTMrWNyHc6chX0KzDeAOXftRa8bNeOKTTfCJ7KorIwenkHd2xqVTBTCZd79yk/lx/Ug== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + scheduler "^0.20.1" + +react@17.0.1: + version "17.0.1" + resolved "https://registry.yarnpkg.com/react/-/react-17.0.1.tgz#6e0600416bd57574e3f86d92edba3d9008726127" + integrity sha512-lG9c9UuMHdcAexXtigOZLX8exLWkW0Ku29qPRU8uhF2R9BN96dLCt0psvzPLlHc5OWkgymP3qwTRgbnw5BKx3w== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + +readable-stream@^2.0.2, readable-stream@^2.3.3, readable-stream@^2.3.6: + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readline-sync@^1.4.7: + version "1.4.10" + resolved "https://registry.yarnpkg.com/readline-sync/-/readline-sync-1.4.10.tgz#41df7fbb4b6312d673011594145705bf56d8873b" + integrity sha512-gNva8/6UAe8QYepIQH/jQ2qn91Qj0B9sYjMBBs3QOB8F2CXcKgLxQaJRP76sWVRQt+QU+8fAkCbCvjjMFu7Ycw== + +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safer-buffer@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +scheduler@^0.20.1: + version "0.20.1" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.1.tgz#da0b907e24026b01181ecbc75efdc7f27b5a000c" + integrity sha512-LKTe+2xNJBNxu/QhHvDR14wUXHRQbVY5ZOYpOGWRzhydZUqrLb2JBvLPY7cAqFmqrWuDED0Mjk7013SZiOz6Bw== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + +setimmediate@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= + +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +shadow-cljs-jar@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/shadow-cljs-jar/-/shadow-cljs-jar-1.3.2.tgz#97273afe1747b6a2311917c1c88d9e243c81957b" + integrity sha512-XmeffAZHv8z7451kzeq9oKh8fh278Ak+UIOGGrapyqrFBB773xN8vMQ3O7J7TYLnb9BUwcqadKkmgaq7q6fhZg== + +shadow-cljs@^2.11.18: + version "2.11.18" + resolved "https://registry.yarnpkg.com/shadow-cljs/-/shadow-cljs-2.11.18.tgz#f83fe776c9001afdf92611e6bef6da8aed926aab" + integrity sha512-7EAXl1xk2GjhViUeexn7cqAPx0lkEl2J40nAbPPCrAbfLfOWn5tjV4P3Be6IqTInSHMx04tFxDRV+0xFdIhl5A== + dependencies: + node-libs-browser "^2.2.1" + readline-sync "^1.4.7" + shadow-cljs-jar "1.3.2" + source-map-support "^0.4.15" + which "^1.3.1" + ws "^3.0.0" + +source-map-support@^0.4.15: + version "0.4.18" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" + integrity sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA== + dependencies: + source-map "^0.5.6" + +source-map@^0.5.6: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +stream-browserify@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b" + integrity sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg== + dependencies: + inherits "~2.0.1" + readable-stream "^2.0.2" + +stream-http@^2.7.2: + version "2.8.3" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc" + integrity sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw== + dependencies: + builtin-status-codes "^3.0.0" + inherits "^2.0.1" + readable-stream "^2.3.6" + to-arraybuffer "^1.0.0" + xtend "^4.0.0" + +string_decoder@^1.0.0, string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +timers-browserify@^2.0.4: + version "2.0.12" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.12.tgz#44a45c11fbf407f34f97bccd1577c652361b00ee" + integrity sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ== + dependencies: + setimmediate "^1.0.4" + +to-arraybuffer@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" + integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= + +tty-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" + integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY= + +ultron@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" + integrity sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og== + +url@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" + integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= + dependencies: + punycode "1.3.2" + querystring "0.2.0" + +util-deprecate@^1.0.1, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +util@0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" + integrity sha1-evsa/lCAUkZInj23/g7TeTNqwPk= + dependencies: + inherits "2.0.1" + +util@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/util/-/util-0.11.1.tgz#3236733720ec64bb27f6e26f421aaa2e1b588d61" + integrity sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ== + dependencies: + inherits "2.0.3" + +vm-browserify@^1.0.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" + integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== + +which@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +ws@^3.0.0: + version "3.3.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" + integrity sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA== + dependencies: + async-limiter "~1.0.0" + safe-buffer "~5.1.0" + ultron "~1.1.0" + +xtend@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== From c94de2335beaba47fd2ba75ae099e0d81386e0e1 Mon Sep 17 00:00:00 2001 From: Rameez Khan Date: Tue, 9 Feb 2021 07:49:22 +0200 Subject: [PATCH 04/16] Add shadow-cljs --- shadow-cljs.edn | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 shadow-cljs.edn diff --git a/shadow-cljs.edn b/shadow-cljs.edn new file mode 100644 index 0000000..d78741c --- /dev/null +++ b/shadow-cljs.edn @@ -0,0 +1,16 @@ +{:source-paths + ["src"] + + :nrepl {:port 9000} + + :dependencies + [[cider/cider-nrepl "0.25.8"] + [reagent "1.0.0"] + [re-frame "1.1.2"]] + + :builds {:app {:target :browser + :output-dir "public/js" + :modules {:main {:entries [financial_health_dashboard.core]}} + :devtools {:http-root "public" + :http-port 3000} + :release {:compiler-options {:optimizations :simple}}}}} From f3f7be32d7211f7537869b7b752ab5f109547e56 Mon Sep 17 00:00:00 2001 From: Rameez Khan Date: Tue, 9 Feb 2021 07:54:19 +0200 Subject: [PATCH 05/16] Add public resources --- public/android-chrome-192x192.png | Bin 0 -> 10725 bytes public/android-chrome-512x512.png | Bin 0 -> 35740 bytes public/apple-touch-icon.png | Bin 0 -> 9664 bytes public/css/style.css | 12 ++++++++ public/favicon-16x16.png | Bin 0 -> 636 bytes public/favicon-32x32.png | Bin 0 -> 1344 bytes public/index.html | 45 ++++++++++++++++++++++++++++++ public/site.webmanifest | 1 + 8 files changed, 58 insertions(+) create mode 100644 public/android-chrome-192x192.png create mode 100644 public/android-chrome-512x512.png create mode 100644 public/apple-touch-icon.png create mode 100644 public/css/style.css create mode 100644 public/favicon-16x16.png create mode 100644 public/favicon-32x32.png create mode 100644 public/index.html create mode 100644 public/site.webmanifest diff --git a/public/android-chrome-192x192.png b/public/android-chrome-192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..a1ce2919a134bfa98c832f339bced829ca521263 GIT binary patch literal 10725 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 XViNJ;8zF;h6VgM_M5r{ zftWz5igM5VO!wYn`_XOuz3V*MUo3Aui^%4k>nG6QD#%O*fk`0ed4xD!2oe=}H*9NS zH_R<;wuUh1gcXcUJbcVq0{SMq#^yWundy&xpXCeLgF%ikb9IS7i+`3zuB4vy&cFBF z6gpTO>9C1l(u6@XKnCf3B&k9Zb#8+BS{(9>{Eb%mu%TDx!6c{rR`lF2DiCQk+tf7T zp9ImijL%ONe{8&(7jOAMW=}?CLV&Hy#Zn?Ve@*|0^r-akP@8oZgjCq%d_%~!!bHkw z9`^=H2eoL$;*&D}!MA7l(&E$bm);7ycU`OMBF(WPXPok~{1WKKJVIfQm7t+>(3qs-v6}Zb)<1oOa#y8O3-J9JZgJ@ZV;vgeJ$4?a~;(Cdr@I$rD*KX$z z1q^C0z$`9bH*S}c@@T?th76y?Hc|V1kJ)Z2^ZPe~I5K`*^^7zqJmZsj2?`_@U+~0S zxpyRFR#lY-_ofyoC9LIs;@rU#~2D%j& zwxB{W(BK}h1trFTQCJ8%Mn)YYq(OkZy+nTVcJML%zto#=QNMPnq{tA*Zevr)`x^Y_ z*|N}&RxAFPCt?ri&wi%ElAOX3C9tCHw=8;_DxGsrkX!GRb3V1aD~tM)C6Y(LM2Q$; zl^j-Z=7EKLUb{@nsT=q%oxIyZWh&STY8g=(4&)|&-xvFQ%k6xbD5l90RMOu)R zX{Mt%n!ofyv8V5cA7K|OiXd$=LebKZm+IY{@pb{Xe?^%a$N=32#Lr6sr`I=9G$s}h zsDnKE9aQk-+p0QMVQL7hCi9c2bbE@=6h5*85eBgx`TJ5Kl;g>Jtj@vs4#|M)R7&ZC z59AR4jm7tLeKJI00!2e#WU{>-NTL2GV~*iIcit75)MeP?4AX7!*p_s1f0UZb+{SZk z(|*;qkeL?ia$~Y>e2#V0q7ADyEwKpy2dtG&E_Lm%Xw}w!-U<~`hzu(e7&%JEvXfD~ z(?X$N^~knr-|o}5zZ}i<-s}p^6zD-%t0W_0(SFc{Zi)%qe&kYWa-Ds-P=^HfWovAwxHJv zKTLX9tZ!r?GT6NcEDaD@!|2DkC>^|RN32_y`lHgE32yb2h>1bkKOcV^JQyRQ5*Jvs z!bR)bE?93&OKaae*fDm9S$G7MVud&Gk&oh2%H6V}p9{UEQ#VtM&%$*(z;~Dh^!!ql~l6tGmlT9J zsU0t!7I1V%H6AD-a!@BsQsw9b-GQRU@@Y;}=_4|mwd|sEI)07Al#$GYXW4e^V#t~# zk@h0i^XHX*-NxnnsRmjH)p9dPcT8~5T3X! zVgSxR5V&XGHK4ZpT8=6+HkNE*4PNuc!sl~Ep6)I2wR>wy&g0
jPrn5$&V?21vmkCd1okKSRQ9AnMhVek%tdJ}y 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 + + + + + + + + + + + + Financial Health Dashboard + + + + + + +
+ + + + + diff --git a/public/site.webmanifest b/public/site.webmanifest new file mode 100644 index 0000000..45dc8a2 --- /dev/null +++ b/public/site.webmanifest @@ -0,0 +1 @@ +{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} \ No newline at end of file From 2f2576680022a48d3597addc54f38150ebdbbf86 Mon Sep 17 00:00:00 2001 From: Rameez Khan Date: Tue, 9 Feb 2021 07:57:05 +0200 Subject: [PATCH 06/16] Add release target --- package.json | 3 ++- public/Makefile | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 public/Makefile diff --git a/package.json b/package.json index 3d8a65f..6cdb03a 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "shadow-cljs": "^2.11.18" }, "scripts": { - "dev": "shadow-cljs watch app" + "dev": "shadow-cljs watch app", + "release": "shadow-cljs release app" } } diff --git a/public/Makefile b/public/Makefile new file mode 100644 index 0000000..3f3b592 --- /dev/null +++ b/public/Makefile @@ -0,0 +1,7 @@ +.PHONY: build + +dev: + yarn dev + +release: + yarn release From 38569a26659ee2e81b1603f984533cb3353a473a Mon Sep 17 00:00:00 2001 From: Rameez Khan Date: Tue, 9 Feb 2021 08:30:27 +0200 Subject: [PATCH 07/16] Move Makefile --- public/Makefile => Makefile | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename public/Makefile => Makefile (100%) diff --git a/public/Makefile b/Makefile similarity index 100% rename from public/Makefile rename to Makefile From 8ca439c30d33971adb80ac67f492cee3bcc436a9 Mon Sep 17 00:00:00 2001 From: Rameez Khan Date: Tue, 9 Feb 2021 08:35:39 +0200 Subject: [PATCH 08/16] Fix Makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 3f3b592..a318e01 100644 --- a/Makefile +++ b/Makefile @@ -4,4 +4,4 @@ dev: yarn dev release: - yarn release + yarn release From 40512502cdc1d069b3581b921101719ab2274370 Mon Sep 17 00:00:00 2001 From: Rameez Khan Date: Fri, 5 Mar 2021 10:53:52 +0200 Subject: [PATCH 09/16] Update shadow-cljs --- public/index.html | 36 ++++++++++++------------ shadow-cljs.edn | 22 ++++++++++----- src/financial_health_dashboard/core.cljs | 18 ++++++++++++ 3 files changed, 51 insertions(+), 25 deletions(-) create mode 100644 src/financial_health_dashboard/core.cljs diff --git a/public/index.html b/public/index.html index 19fa812..9533da8 100644 --- a/public/index.html +++ b/public/index.html @@ -8,38 +8,38 @@ - + Financial Health Dashboard - - - -->
- - - + + + diff --git a/shadow-cljs.edn b/shadow-cljs.edn index d78741c..4f0fb4f 100644 --- a/shadow-cljs.edn +++ b/shadow-cljs.edn @@ -1,16 +1,24 @@ {:source-paths ["src"] - :nrepl {:port 9000} + ;; :nrepl {:port 9000} :dependencies [[cider/cider-nrepl "0.25.8"] [reagent "1.0.0"] [re-frame "1.1.2"]] - :builds {:app {:target :browser - :output-dir "public/js" - :modules {:main {:entries [financial_health_dashboard.core]}} - :devtools {:http-root "public" - :http-port 3000} - :release {:compiler-options {:optimizations :simple}}}}} + :builds + {:app {:target :browser + :output-dir "public/js" + :asset-path "/js" + + :modules + {:main + {:entries [financial_health_dashboard.core]}} + + :devtools + {:http-root "public" + :http-port 3001} + + :release {:compiler-options {:optimizations :simple}}}}} diff --git a/src/financial_health_dashboard/core.cljs b/src/financial_health_dashboard/core.cljs new file mode 100644 index 0000000..3217ac2 --- /dev/null +++ b/src/financial_health_dashboard/core.cljs @@ -0,0 +1,18 @@ +(ns financial-health-dashboard.core + (:require [reagent.dom :as rd])) + +(defn ^:dev/after-load start [] + (js/console.log "start")) + +(defn ^:export init [] + (js/console.log "init") + (start)) + +(defn ^:dev/before-load stop [] + (js/console.log "stop")) + + + + + + From ab16d70256cca646e12ba530eb33cb76acdcb729 Mon Sep 17 00:00:00 2001 From: Rameez Khan Date: Tue, 8 Jun 2021 08:38:40 +0200 Subject: [PATCH 10/16] Add nrepl makefile target --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index a318e01..9c4d722 100644 --- a/Makefile +++ b/Makefile @@ -5,3 +5,6 @@ dev: release: yarn release + +nrepl: + clj -M:nrepl From 2e33a888e2385e21c726da2e73e86e09e18536dc Mon Sep 17 00:00:00 2001 From: Rameez Khan Date: Tue, 8 Jun 2021 18:09:38 +0200 Subject: [PATCH 11/16] Nrepl port on 9000 --- shadow-cljs.edn | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shadow-cljs.edn b/shadow-cljs.edn index 4f0fb4f..32e53d0 100644 --- a/shadow-cljs.edn +++ b/shadow-cljs.edn @@ -1,7 +1,7 @@ {:source-paths ["src"] - ;; :nrepl {:port 9000} + :nrepl {:port 9000} :dependencies [[cider/cider-nrepl "0.25.8"] From cd392016028b5bb87f2aa285d6b051ae4007f337 Mon Sep 17 00:00:00 2001 From: Rameez Khan Date: Tue, 8 Jun 2021 18:09:53 +0200 Subject: [PATCH 12/16] Add nix shell --- .envrc | 1 + shell.nix | 11 +++++++++++ 2 files changed, 12 insertions(+) create mode 100644 .envrc create mode 100644 shell.nix diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..4a4726a --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use_nix diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..2c78ccd --- /dev/null +++ b/shell.nix @@ -0,0 +1,11 @@ +let pkgs = import { }; +in pkgs.mkShell rec { + name = "financial-health-dashboard"; + + buildInputs = with pkgs; [ + nodejs-14_x + (yarn.override { nodejs = nodejs-14_x; }) + clojure + jdk + ]; +} From 1546d0c60e5094dd3eb571491bbfefb56c7fdfab Mon Sep 17 00:00:00 2001 From: Rameez Khan Date: Tue, 8 Jun 2021 18:10:20 +0200 Subject: [PATCH 13/16] Add some domain functions for dealing with accounts and balances --- src/financial_health_dashboard/core.cljs | 6 --- src/financial_health_dashboard/domain.cljs | 57 ++++++++++++++++++++++ 2 files changed, 57 insertions(+), 6 deletions(-) create mode 100644 src/financial_health_dashboard/domain.cljs diff --git a/src/financial_health_dashboard/core.cljs b/src/financial_health_dashboard/core.cljs index 3217ac2..4d7dfba 100644 --- a/src/financial_health_dashboard/core.cljs +++ b/src/financial_health_dashboard/core.cljs @@ -10,9 +10,3 @@ (defn ^:dev/before-load stop [] (js/console.log "stop")) - - - - - - diff --git a/src/financial_health_dashboard/domain.cljs b/src/financial_health_dashboard/domain.cljs new file mode 100644 index 0000000..b903440 --- /dev/null +++ b/src/financial_health_dashboard/domain.cljs @@ -0,0 +1,57 @@ +(ns financial-health-dashboard.domain) + +(def data {:user/name "Bob" + :user/age 28 + :user/accounts [{:account/name "FNB Cheque Account" + :account/type :bank + :account/id 1} + {:account/name "Easy Equities TFSA" + :account/type :investment + :account/id 2}] + :user/account-balances [{:account/id 1 + :account-balance/year 2021 + :accound-balance/month 6 + :account-balance/amount 100} + {:account/id 2 + :account-balance/year 2021 + :account-balance/month 6 + :account-balance/amount 200} + {:account/id 2 + :account-balance/year 2021 + :account-balance/month 1 + :account-balance/amount 400}]}) + + +(defn user-name + "Return a user's name" + [{:user/keys [name]}] + name) + +(defn user-age + "Return a user's age" + [{:user/keys [age]}] + age) + +(defn user-accounts + "Return a user's accounts, filtered if account-type is provided" + ([{:user/keys [accounts]}] + accounts) + ([data account-type] + (filter #(= (:account/type %) account-type) (user-accounts data)))) + +(defn account + "Return an account by provided account-id" + [data account-id] + (let [accounts (user-accounts data)] + (first (filter #(= (:account/id %) account-id) accounts)))) + +(defn account-balances + "Returns all account balances, filtered if year and month are provided" + ([data] + (:user/account-balances data)) + + ([data year] + (filter #(= (:account-balance/year %) year) (account-balances data))) + + ([data year month] + (filter #(and (= (:account-balance/year %) year) (= (:account-balance/month %) month)) (account-balances data)))) From ea80841aabcd3bec2cc66f74990a9c3fa690cea9 Mon Sep 17 00:00:00 2001 From: Rameez Khan Date: Tue, 8 Jun 2021 18:11:07 +0200 Subject: [PATCH 14/16] Formatting --- src/financial_health_dashboard/domain.cljs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/financial_health_dashboard/domain.cljs b/src/financial_health_dashboard/domain.cljs index b903440..75b73bd 100644 --- a/src/financial_health_dashboard/domain.cljs +++ b/src/financial_health_dashboard/domain.cljs @@ -51,7 +51,11 @@ (:user/account-balances data)) ([data year] - (filter #(= (:account-balance/year %) year) (account-balances data))) + (filter #(= (:account-balance/year %) year) + (account-balances data))) ([data year month] - (filter #(and (= (:account-balance/year %) year) (= (:account-balance/month %) month)) (account-balances data)))) + (filter #(and + (= (:account-balance/year %) year) + (= (:account-balance/month %) month)) + (account-balances data)))) From 7478cfcb9ce5bb867d9e0f252a5cdb3f1a1c80ad Mon Sep 17 00:00:00 2001 From: Rameez Khan Date: Wed, 9 Jun 2021 08:32:39 +0200 Subject: [PATCH 15/16] Add more domain account functions --- src/financial_health_dashboard/domain.cljs | 69 ++++++++++++++-------- 1 file changed, 46 insertions(+), 23 deletions(-) diff --git a/src/financial_health_dashboard/domain.cljs b/src/financial_health_dashboard/domain.cljs index 75b73bd..e33ded2 100644 --- a/src/financial_health_dashboard/domain.cljs +++ b/src/financial_health_dashboard/domain.cljs @@ -1,24 +1,26 @@ (ns financial-health-dashboard.domain) -(def data {:user/name "Bob" - :user/age 28 - :user/accounts [{:account/name "FNB Cheque Account" - :account/type :bank - :account/id 1} - {:account/name "Easy Equities TFSA" - :account/type :investment - :account/id 2}] - :user/account-balances [{:account/id 1 - :account-balance/year 2021 - :accound-balance/month 6 +(def data {:user/name "Bob" + :user/age 28 + :user/accounts [{:account/name "FNB Cheque Account" + :account/type :bank + :account/id 1 + :account/active true} + {:account/name "Easy Equities TFSA" + :account/type :investment + :account/id 2 + :account/active true}] + :user/account-balances [{:account/id 1 + :account-balance/year 2021 + :account-balance/month 6 :account-balance/amount 100} - {:account/id 2 - :account-balance/year 2021 - :account-balance/month 6 + {:account/id 2 + :account-balance/year 2021 + :account-balance/month 6 :account-balance/amount 200} - {:account/id 2 - :account-balance/year 2021 - :account-balance/month 1 + {:account/id 2 + :account-balance/year 2021 + :account-balance/month 1 :account-balance/amount 400}]}) @@ -33,11 +35,13 @@ age) (defn user-accounts - "Return a user's accounts, filtered if account-type is provided" + "Return a user's active accounts, filtered if account-type is provided" ([{:user/keys [accounts]}] - accounts) + (filter #(:account/active %) accounts)) ([data account-type] - (filter #(= (:account/type %) account-type) (user-accounts data)))) + (filter + #(= (:account/type %) account-type) + (user-accounts data)))) (defn account "Return an account by provided account-id" @@ -46,7 +50,7 @@ (first (filter #(= (:account/id %) account-id) accounts)))) (defn account-balances - "Returns all account balances, filtered if year and month are provided" + "Returns all account balances, filtered if year or month are provided" ([data] (:user/account-balances data)) @@ -56,6 +60,25 @@ ([data year month] (filter #(and - (= (:account-balance/year %) year) - (= (:account-balance/month %) month)) + (= (:account-balance/year %) year) + (= (:account-balance/month %) month)) (account-balances data)))) + +(defn balance-exists-for-account? + "Check if balance exists for account" + [account-id year month] + (let [balances (account-balances data year month) + balances-for-account (filter #(= (:account/id %) account-id) balances)] + (pos? (count balances-for-account)))) + +(defn net-worth + "Calculate net worth for year and month" + [data year month] + (reduce + (fn [acc + {:account-balance/keys [amount]}] + (+ acc amount)) + 0 + (account-balances data year month))) + + From 16eba024e33d8f709a01ab44c678b7550cda84b9 Mon Sep 17 00:00:00 2001 From: Rameez Khan Date: Wed, 9 Jun 2021 16:43:38 +0200 Subject: [PATCH 16/16] Add a nice menu --- public/index.html | 57 +++++++------------ .../components.cljs | 8 +++ src/financial_health_dashboard/core.cljs | 17 +++++- src/financial_health_dashboard/domain.cljs | 1 - 4 files changed, 42 insertions(+), 41 deletions(-) create mode 100644 src/financial_health_dashboard/components.cljs diff --git a/public/index.html b/public/index.html index 9533da8..47f8495 100644 --- a/public/index.html +++ b/public/index.html @@ -1,45 +1,26 @@ - - - - - - - - - - Financial Health Dashboard - - - - + + + + + + + + + + Financial Health Dashboard + - +
- - - + "https://use.fontawesome.com/releases/v5.3.1/js/all.js" type= + "text/javascript"> + --> + + + diff --git a/src/financial_health_dashboard/components.cljs b/src/financial_health_dashboard/components.cljs new file mode 100644 index 0000000..159acc6 --- /dev/null +++ b/src/financial_health_dashboard/components.cljs @@ -0,0 +1,8 @@ +(ns financial-health-dashboard.components) + +(defn nav [] + [:nav.bg-purple-700.text-white.flex.items-center.justify-between.flex-wrap.p-6 + [:div.flex.items-center.flex-shrink-0.mr-6 + [:span "💰 Financial Health Dashboard"]] + [:div + [:a.inline-block.text-sm.px-4.py-2.leading-none.border.rounded.border-white.hover:border-transparent.hover:text-teal-500.hover:bg-purple-300.mt-4.lg:mt-0 {:href "https://www.google.com"} "Upload Data File"]]]) diff --git a/src/financial_health_dashboard/core.cljs b/src/financial_health_dashboard/core.cljs index 4d7dfba..a357d2e 100644 --- a/src/financial_health_dashboard/core.cljs +++ b/src/financial_health_dashboard/core.cljs @@ -1,8 +1,21 @@ (ns financial-health-dashboard.core - (:require [reagent.dom :as rd])) + (:require [reagent.dom :as rd] + [financial-health-dashboard.components :as c])) + +(defn app + "DOM entrypoint" + [] + [:div.section + [c/nav]]) + +(defn mount-reagent [] + (rd/render + app + (js/document.getElementById "app"))) (defn ^:dev/after-load start [] - (js/console.log "start")) + (js/console.log "start") + (mount-reagent)) (defn ^:export init [] (js/console.log "init") diff --git a/src/financial_health_dashboard/domain.cljs b/src/financial_health_dashboard/domain.cljs index e33ded2..9b8107e 100644 --- a/src/financial_health_dashboard/domain.cljs +++ b/src/financial_health_dashboard/domain.cljs @@ -81,4 +81,3 @@ 0 (account-balances data year month))) -