about summary refs log tree commit diff stats
path: root/elm/cost-of-meeting/src/Main.elm
diff options
context:
space:
mode:
Diffstat (limited to 'elm/cost-of-meeting/src/Main.elm')
-rw-r--r--elm/cost-of-meeting/src/Main.elm217
1 files changed, 217 insertions, 0 deletions
diff --git a/elm/cost-of-meeting/src/Main.elm b/elm/cost-of-meeting/src/Main.elm
new file mode 100644
index 0000000..fdc16d5
--- /dev/null
+++ b/elm/cost-of-meeting/src/Main.elm
@@ -0,0 +1,217 @@
+module Main exposing (main)
+
+import Browser
+import Html exposing (..)
+import Html.Attributes as Attr
+import Html.Events exposing (onInput)
+import String
+
+-- MODEL
+
+type alias Model =
+    { participants : String
+    , salary : String
+    , minutes : String
+    , errors : List String
+    }
+
+
+init : Model
+init =
+    { participants = ""
+    , salary = ""
+    , minutes = ""
+    , errors = []
+    }
+
+
+-- UPDATE
+
+type Msg
+    = UpdateParticipants String
+    | UpdateSalary String
+    | UpdateMinutes String
+
+
+update : Msg -> Model -> Model
+update msg model =
+    case msg of
+        UpdateParticipants value ->
+            { model | participants = value, errors = validateInputs { model | participants = value } }
+
+        UpdateSalary value ->
+            { model | salary = value, errors = validateInputs { model | salary = value } }
+
+        UpdateMinutes value ->
+            { model | minutes = value, errors = validateInputs { model | minutes = value } }
+
+
+-- VALIDATION
+
+validateInputs : Model -> List String
+validateInputs model =
+    let
+        validateParticipants value =
+            case String.toFloat (String.replace "," "" value) of
+                Just num ->
+                    if num <= 0 then
+                        [ "Number of participants must be greater than 0" ]
+                    else if num > 1000 then
+                        [ "Number of participants seems unusually high" ]
+                    else if num /= toFloat (round num) then
+                        [ "Number of participants must be a whole number" ]
+                    else
+                        []
+
+                Nothing ->
+                    if String.isEmpty value then
+                        []
+                    else
+                        [ "Number of participants must be a valid number" ]
+
+        validateSalary value =
+            case String.toFloat (String.replace "," "" value) of
+                Just num ->
+                    if num <= 0 then
+                        [ "Salary must be greater than 0" ]
+                    else if num < 10 then
+                        [ "Salary seems unusually low" ]
+                    else if num > 1000000 then
+                        [ "Salary seems unusually high" ]
+                    else
+                        []
+
+                Nothing ->
+                    if String.isEmpty value then
+                        []
+                    else
+                        [ "Salary must be a valid number" ]
+
+        validateMinutes value =
+            case String.toFloat (String.replace "," "" value) of
+                Just num ->
+                    if num <= 0 then
+                        [ "Meeting length must be greater than 0" ]
+                    else if num > 480 then
+                        [ "Meeting length seems unusually long (over 8 hours)" ]
+                    else if num /= toFloat (round num) then
+                        [ "Meeting length must be a whole number" ]
+                    else
+                        []
+
+                Nothing ->
+                    if String.isEmpty value then
+                        []
+                    else
+                        [ "Meeting length must be a valid number" ]
+    in
+    validateParticipants model.participants
+        ++ validateSalary model.salary
+        ++ validateMinutes model.minutes
+
+
+-- VIEW
+
+view : Model -> Html Msg
+view model =
+    div [ Attr.class "container" ]
+        [ h1 [] [ text "Meeting Cost Calculator" ]
+        , div [ Attr.class "input-group" ]
+            [ label [] [ text "Number of Participants" ]
+            , input 
+                [ Attr.type_ "number"
+                , Attr.value model.participants
+                , onInput UpdateParticipants
+                , Attr.placeholder "Enter number of participants"
+                , Attr.min "1"
+                , Attr.max "1000"
+                ] []
+            ]
+        , div [ Attr.class "input-group" ]
+            [ label [] [ text "Average Annual Salary ($)" ]
+            , input 
+                [ Attr.type_ "text"
+                , Attr.value model.salary
+                , onInput UpdateSalary
+                , Attr.placeholder "Enter average annual salary"
+                ] []
+            ]
+        , div [ Attr.class "input-group" ]
+            [ label [] [ text "Meeting Length (minutes)" ]
+            , input 
+                [ Attr.type_ "number"
+                , Attr.value model.minutes
+                , onInput UpdateMinutes
+                , Attr.placeholder "Enter meeting length in minutes"
+                , Attr.min "1"
+                , Attr.max "480"
+                ] []
+            ]
+        , viewErrors model.errors
+        , div [ Attr.class "results" ]
+            [ viewResults model ]
+        ]
+
+
+viewErrors : List String -> Html msg
+viewErrors errors =
+    if List.isEmpty errors then
+        div [] []
+    else
+        div [ Attr.class "errors" ]
+            (List.map (\error -> p [] [ text error ]) errors)
+
+
+viewResults : Model -> Html msg
+viewResults model =
+    let
+        participants =
+            String.toFloat (String.replace "," "" model.participants) |> Maybe.withDefault 0
+
+        salary =
+            String.toFloat (String.replace "," "" model.salary) |> Maybe.withDefault 0
+
+        minutes =
+            String.toFloat (String.replace "," "" model.minutes) |> Maybe.withDefault 0
+
+        -- Calculate working hours per year (50 weeks * 5 days * 8 hours)
+        workingHoursPerYear =
+            50 * 5 * 8
+
+        -- Calculate hourly rate
+        hourlyRate =
+            salary / workingHoursPerYear
+
+        -- Calculate cost per minute
+        costPerMinute =
+            hourlyRate / 60
+
+        -- Calculate total meeting cost
+        totalCost =
+            costPerMinute * minutes * participants
+    in
+    if participants > 0 && salary > 0 && minutes > 0 && List.isEmpty model.errors then
+        div []
+            [ h2 [] [ text "Approximate Meeting Cost" ]
+            , p [] 
+                [ span [] [ text "Total Meeting Cost: " ]
+                , strong [] [ text ("$" ++ String.fromFloat (toFloat (round (totalCost * 100)) / 100)) ]
+                ]
+            , p [] 
+                [ span [] [ text "Cost per Minute: " ]
+                , strong [] [ text ("$" ++ String.fromFloat (toFloat (round (costPerMinute * 100)) / 100)) ]
+                ]
+            ]
+    else
+        div [] []
+
+
+-- MAIN
+
+main : Program () Model Msg
+main =
+    Browser.sandbox
+        { init = init
+        , update = update
+        , view = view
+        } 
\ No newline at end of file