Skip to content

Instantly share code, notes, and snippets.

@reshmee011
Last active January 1, 2016 13:09
Show Gist options
  • Save reshmee011/1f71c06f23d530c5de07 to your computer and use it in GitHub Desktop.
Save reshmee011/1f71c06f23d530c5de07 to your computer and use it in GitHub Desktop.
(ns simplecalculator.core
(:require [reagent.core :as r :refer [atom]]
[reagent.session :as session]
[secretary.core :as secretary :include-macros true]
[accountant.core :as accountant]
))
(enable-console-print!)
;;pension age calculator implementation
;;atom to store the state data for the pension age component
;;defonce is used instead of def to prevent the atom from resetting on each save of the file. Only on refresh of the page, the atom is reset.
(defonce pension-age (r/atom {:dob nil :pensiondate 0 :age 0}))
;;JavaScript objects can be referenced using the js prefix
;;function to check whether object is a JavaScript date
(defn date? [x]
(= (type x) js/Date))
;; using Javascript date function toLocaleDateString to convert date into local date format if date object is provided else return "unselected"
(defn get-date! [date]
(if (date? date)
(.toLocaleDateString date "en" "%d-%b-%Y")
"unselected"))
;;function to calculate pension age based on date of birth entered from the UI
;;destructuring is used on the pension-age atom object to map each value (dob, pensiondate and age) to a variable which can be used for manipulation
(defn calc-pensionage []
(let [{:keys [dob pensiondate age]} @pension-age ]
;;js/Date. is used to get a date object from string
;;if dob is between "1950-04-06" and "1953-04-05" then state pension age is 63
(if(and (<(js/Date. "1950-04-06") dob) (> (js/Date. "1953-04-05") dob))
;;age to get state pension is 63
((swap! pension-age assoc :age 63)
;;add 63 years to dob
;;JavaScript Date function getFullYear is used to get the year from dob date object and then add the number of years
(swap! pension-age assoc :pensiondate (js/Date. (+ (.getFullYear dob) 63) (.getMonth dob) (.getDate dob)))))
;;if dob is between "1953-04-06" and "1953-12-05" then state pension age is 65
(if(and (<(js/Date. "1953-04-06") dob ) (>(js/Date. "1953-12-05") dob))
;;age to get state pension is 65
((swap! pension-age assoc :age 65)
;;add 65 to dob
(swap! pension-age assoc :pensiondate (js/Date. (+ (.getFullYear dob) 65) (.getMonth dob) (.getDate dob)))))
;;if dob is between "1953-12-06" and "1960-04-05" then state pension age is 66
(if(and (<(js/Date. "1953-12-06") dob ) (>(js/Date. "1960-04-05") dob))
;;age to get state pension is 66
((swap! pension-age assoc :age 66)
;;add 66 to dob
(swap! pension-age assoc :pensiondate (js/Date. (+ (.getFullYear dob) 66) (.getMonth dob) (.getDate dob))))
)
;;if dob is between "1960-04-06" and "1977-04-05" then state pension age is 67
(if(and (<(js/Date. "1960-04-06") dob ) (>(js/Date. "1977-04-05") dob))
;;age to get state pension is 67
((swap! pension-age assoc :age 67)
;;add 67 to dob
(swap! pension-age assoc :pensiondate (js/Date. (+ (.getFullYear dob) 67) (.getMonth dob) (.getDate dob))))
)
;;if dob is greater than "1977-04-06", then state pension age is 68
(if(<(js/Date. "1977-04-06") dob )
;;age to get state pension is 68
((swap! pension-age assoc :age 68)
;;add 68 to dob
(swap! pension-age assoc :pensiondate (js/Date. (+ (.getFullYear dob) 68) (.getMonth dob) (.getDate dob))))
)
)
)
;;maths calculator component
;;atom storing the data state of the maths calc component
(defonce result-data (r/atom {:number 0 :result nil :operator nil}))
;;function to calculate result based on operator and number
;;using destructuring to map each value from the atom to a variable
(defn calc-result []
(let [{:keys [number result operator]} @result-data]
;; multiplying the result and number by 1 to force cast to number before adding the numbers, otherwise the numbers were concatenated
(if (= operator "+") (swap! result-data assoc :result (+ (* 1 result) (* 1 number))))
;;if substract sign is selected, the number is substracted from the result
(if (= operator "-") (swap! result-data assoc :result (- result number )))
;;if multiply sign is selected, the number is multipled with the result
(if (= operator "*") (swap! result-data assoc :result (* result number )))
;;if divide sign is selected, the result is divided with the number
(if (= operator "/") (swap! result-data assoc :result (/ result number )))
(swap! result-data assoc :number 0)
))
;;BMI Calculator components
(defonce bmi-data (r/atom {:height 180 :weight 80}))
;;function to calculate the bmi
;;destructuring used to map each atom value to a variable
;;in addition, the variable h is set to height/100
(defn calc-bmi []
(let [{:keys [height weight bmi] :as data} @bmi-data
h (/ height 100)]
(if (nil? bmi)
;;update the key bmi value with weight/ (h*h) is bmi is nil
(assoc data :bmi (/ weight (* h h)))
;;if bmi is not nil, update the key weight with bmi * h * h
(assoc data :weight (* bmi h h)))))
;;slider child component which can be referenced in other components
(defn slider [param value min max]
[:input {:type "range" :value value :min min :max max
:style {:width "100%"}
:on-change (fn [e]
;;swap! is used to update the atom object
(swap! bmi-data assoc param (.-target.value e))
;;if bmi has not been updated set it to nil in the atom object
(when (not= param :bmi)
(swap! bmi-data assoc :bmi nil)))}])
;; -------------------------
;; Views
;;navigation view
;;navigation-view will be shared by three calculator components; Maths, BMI and Pension Age
(defn navigation-view []
[:div
[:a {:href "/"} "Maths "]
[:a {:href "/BMI"} " BMI"]
[:a {:href "/Pensionage"} " PensionAge"]
])
;;Home Page is the Maths Calculator
;; using the atom object to display the data on the UI
(defn home-page []
(let [{:keys [number result operator]} @result-data]
;;Reagent uses the hiccup style to write the virtual DOM
[:div
;;navigation component
[navigation-view]
[:h4 "Maths Calculator"]
;;input control allowing only numbers to be typed in
[:input {:type "number"
:value number
:on-change (fn [e]
(swap! result-data assoc :number (.-target.value e))
)
}]
[:div
[:input {:type "button"
:value "+"
:on-click (fn [e]
(swap! result-data assoc :operator (.-target.value e))
(if(nil? result)
((swap! result-data assoc :result number)
(swap! result-data assoc :number 0)))
)
}]
[:input {:type "button"
:value "-"
:on-click (fn [e]
(swap! result-data assoc :operator (.-target.value e))
(if(nil? result)
((swap! result-data assoc :result number)
(swap! result-data assoc :number 0)))
)
}]
[:input {:type "button"
:value "/"
:on-click (fn [e]
(swap! result-data assoc :operator (.-target.value e))
(if(nil? result)
((swap! result-data assoc :result number)
(swap! result-data assoc :number 0)))
)
}]
[:input {:type "button"
:value "*"
:on-click (fn [e]
(swap! result-data assoc :operator (.-target.value e))
(if(nil? result)
((swap! result-data assoc :result number)
(swap! result-data assoc :number 0)))
)
}]
[:input {:type "button"
:value "="
:on-click calc-result
}]
]
[:p result]]))
;;BMI page component
;;the data of the component is provided by function calc-bmi. Futhermore depending on the BMI value, the color and diagnose variables are set
(defn bmi-page []
(let [{:keys [weight height bmi]} (calc-bmi)
[color diagnose] (cond
(< bmi 18.5) ["orange" "underweight"]
(< bmi 25) ["inherit" "normal"]
(< bmi 30) ["orange" "overweight"]
:else ["red" "obese"])]
[:div
;;instantiate navigation-view
[navigation-view]
[:h4 "BMI calculator"]
[:div
"Height: " (int height) "cm"
;;instantiate slider component with properties :height height 100 220
[slider :height height 100 220]]
[:div
"Weight: " (int weight) "kg"
;;instantiate slider component with properties :weight weight 30 150
[slider :weight weight 30 150]]
[:div
"BMI: " (int bmi) " "
[:span {:style {:color color}} diagnose]
;;instantiate slider component with properties :bmi bmi 10 50
[slider :bmi bmi 10 50]]]))
;;pension-page component
(defn pension-page []
(let [{:keys [dob pensiondate age]} @pension-age]
[:div
[navigation-view]
[:div [:h4 "State Pension Age Calculator"]
[:p "Enter Date Of Birth"]
;;using input control of type date to allow a date to be picked
[:input {:type "date"
:on-change (fn [e] (swap! pension-age assoc :dob (js/Date. (.-target.value e))))
}]
;; button to cal pension age
[:input {:type "button"
:value "Pension Age"
:on-click calc-pensionage
}]
[:p "You will reach pension age at " age " as from " (get-date! pensiondate) ]]]))
;;using session from reagent to store session of the page
(defn current-page []
[:div [(session/get :current-page)]])
;; -------------------------
;; Routes with secretary library
(secretary/defroute "/" []
(session/put! :current-page #'home-page))
(secretary/defroute "/BMI" []
(session/put! :current-page #'bmi-page))
(secretary/defroute "/Pensionage" []
(session/put! :current-page #'pension-page))
;; -------------------------
;; Initialize app
(defn mount-root []
;;render from Reagent
(r/render [current-page] (.getElementById js/document "app")))
;;accountant library used together with secretary to make navigation easier
(accountant/configure-navigation!)
(accountant/dispatch-current!)
(mount-root)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment