lue-bird/elm-state-interface/2.0.2

NOTE: the latest version is 2.0.4

Web.Notification

Give important notices to the user as push notifications. Consider this a convenience feature, not something users have to rely upon. Always offer users alternative methods to view messages or initiate actions and allow users to opt out of getting more in the future.

askForPermission : Interface future_

Ask the user to consent to receiving notifications, if they haven't already.

For security reasons, browsers require some kind of user interaction like a button click first. So you could for example add a toggle to send notifications and ask only for permission when the toggle is set.

{ message : String
, details : String
, id : String
}
-> Interface NotificationClicked

An Interface for pushing a notification to the user. Users can in the future respond to it by clicking it.

To not notify users multiple times for multiple messages of the same kind, choose an id with a description for this kind so that the notification with the same kind gets silently replaced if it exists.

case messagesFromOpponent of
    [] ->
        Web.interfaceNone


    [ onlyMessage ] ->
        Web.Notification.show
            { id = "opponent messages"
            , message = "Your opponent left a message"
            , details = "\"" ++ onlyMessage ++ "\""
            }


    _ :: _ :: message2Up ->
        Web.Notification.show
            { id = "opponent messages"
            , message =
                [ "Your opponent left "
                , 2 + (message2Up |> List.length) |> String.fromInt
                , " messages"
                ]
                    |> String.join
            , details = ""
            }

Another example of a reminder shown in advance

let
    untilMeeting : Duration
    untilMeeting =
        Duration.from meetingTime currentTime
in
if untilMeeting |> Quantity.isLessThan (Duration.minutes 10) then
    Web.Notification.show
        { id = "time until meeting"
        , message =
            [ "the meeting starts in "
            , untilMeeting |> Duration.inMinutes |> Basics.ceiling |> String.fromInt)
            , " minutes"
            ]
                |> String.concat
        , details = ""
        }


else
    Web.interfaceNone

Note: If you haven't previously used askForPermission it will request this permission now.

You can combine it with Web.Window.visibilityChangeListen to only notify users when they're on a different page

import Web


type State
    = State
        { windowVisibility : Web.WindowVisibility
        , whoseMove : Player
        , mode : Mode
        , notificationPermissionToggle : Permission
        }


type Permission
    = Rejected
    | Accepted


type Mode
    = LongGameBoardMode
    | SettingsPage


type Player
    = You
    | Opponent


interface : State -> Web.Interface State
interface =
    \(State state) ->
        [ case state.notificationPermissionToggle of
            Accepted ->
                Web.Notification.askForPermission


            Rejected ->
                Web.interfaceNone
        , case state.windowVisibility of
            Web.WindowShown ->
                Web.interfaceNone


            Web.WindowHidden ->
                case state.whoseTurn of
                    Opponent ->
                        Web.interfaceNone


                    You ->
                        Web.Notification.show
                            { message = "opponent moved", ... }
                            |> Web.interfaceFutureMap
                                (\Web.NotificationClicked ->
                                    -- return to the game if previously in settings
                                    State { state | mode = LongGameBoardMode }
                                )


        , case state.mode of
            LongGameBoardMode ->
                ..listen for opponent move from server..
                    |> Web.interfaceFutureMap
                        (\... -> State { state | whoseMove = You })


            SettingsPage ->
                ..toggle for accepting/rejecting notifications..
                    |> Web.interfaceFutureMap
                        (\... -> State { state | notificationPermissionToggle = ..opposite.. })
        ]
            |> Web.interfaceBatch