diff --git a/src/status_im/utils/number.cljs b/src/status_im/utils/number.cljs index 4b268fca7e..b160f3b7c2 100644 --- a/src/status_im/utils/number.cljs +++ b/src/status_im/utils/number.cljs @@ -1,4 +1,6 @@ -(ns status-im.utils.number) +(ns status-im.utils.number + (:require [goog.string :as gstring] + [goog.string.format])) (defn naive-round "Quickly and naively round number `n` up to `decimal-places`. @@ -13,3 +15,61 @@ (let [scale (Math/pow 10 decimal-places)] (/ (Math/round (* n scale)) scale))) + +(defn- caught-invalid-number [] + (throw (js/Error "Invalid Number"))) + +(defn- with-precision [precision input-number] + (gstring/format (str "%." precision "f") input-number)) + +(defn- is-bad-number [number-string] + (nil? (re-find #"^\d+(\.\d{1,9})?$" number-string))) + +(defn- with-precision-division [numerator-num denominator-num precision] + (->> (/ numerator-num denominator-num) + (with-precision precision))) + +(defn- number->formatted-number [number-string precision] + (let [parsed-number (js/parseInt number-string 10) + numeric-value (if (or (neg? number-string) + (is-bad-number (str number-string))) + (caught-invalid-number) + parsed-number) + million 1000000 + billion 1000000000 + >=-and-< #(and + (>= %1 %2) + (< %1 %3)) + unit (cond + (>=-and-< parsed-number billion js/Number.MAX_SAFE_INTEGER) "b" + (>=-and-< parsed-number million billion) "m" + :else + "k") + denominator (cond + (= unit "m") million + (= unit "b") billion + :else 1000)] + (if (js/isNaN numeric-value) + (caught-invalid-number) + (if (>= numeric-value 1000) + (str (with-precision-division numeric-value denominator precision) + unit) + (str numeric-value))))) + +(defn format-number + "Returns the thousands in a number in kilo format + + Arguments: + + number-string (or string int) The input of value of the number + + Examples: + [1000 0] -> 1k + [1001 0] -> 1k + [10000 0] -> 10k + [5000 0] -> 5k + [5000 0] -> 5k + [5000000 0] -> 5m + [5000 0] -> 5k" + [number-string precision] + (number->formatted-number number-string precision)) diff --git a/src/status_im/utils/number_test.cljs b/src/status_im/utils/number_test.cljs new file mode 100644 index 0000000000..c50480d725 --- /dev/null +++ b/src/status_im/utils/number_test.cljs @@ -0,0 +1,27 @@ +(ns status-im.utils.number-test + (:require [cljs.test :refer-macros [deftest testing are]] + [status-im.utils.number :as number])) + +(deftest format-number-test + (testing "Positive cases" + (are [input-number precision expected] (= (number/format-number input-number precision) expected) + "100" 0 "100" + "1000" 0 "1k" + "10000" 0 "10k" + "11000" 1 "11.0k" + "11000" 0 "11k" + "11010" 3 "11.010k" + "5200000" 3 "5.200m" + "1000000000" 0 "1b" + "1110000000" 2 "1.11b" + "9000000" 0 "9m")) + (testing "Negative cases" + (are [input-number precision] (thrown-with-msg? js/Error #"Invalid Number" (number/format-number input-number precision)) + js/undefined 0 + nil 0 + "-1" 0 + "" 0 + js/NaN 0 + "1e3" 0 + "10,2" 0 + "6hello" 0)))