diff options
Diffstat (limited to 'elm/cost-of-meeting/src/Main.elm')
-rw-r--r-- | elm/cost-of-meeting/src/Main.elm | 217 |
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 |