xxxxxxxxxx
-- this gives you a function to send a message to JavaScript
reportEvent : { title : String, message : String, kind : String } -> Cmd msg
-- this gives you a subscription to listen for messages from JavaScript
gotLocalStorage : ( { key : String, value : Json.Decode.Value } -> msg ) -> Sub msg
xxxxxxxxxx
reportEvent
{ title = "Could not find that discount code"
, message = "Could not found discount code " ++ discountCode ++ "."
, kind = "Warning"
}
xxxxxxxxxx
const app = Elm.Main.init({ flags: flagData });
app.ports.reportEvent.subscribe(function (data) {
// report event based on `data` we got from Elm
});
xxxxxxxxxx
reportEvent
{ title = "Could not find that discount code"
, message =
"Could not found discount code "
++ discountCode
++ ". Please try again."
, kind = "Warning"
}
xxxxxxxxxx
type Error
= FatalError ErrorCode
| Warning { title : String, message : String }
xxxxxxxxxx
reportElmErrorType : Error -> Cmd msg
reportElmErrorType error =
case error of
FatalError errorCode ->
reportEvent
{ title = "Internal Error"
, message =
"Please contact support with code "
++ errorCodeToString errorCode
, kind = "Error"
}
xxxxxxxxxx
type Event = Error | PageNavigation;
type Error = {
kind: "Error";
errorId?: string;
message: string;
context?: string;
};
type PageNavigation = {
kind: "PageNavigation";
path: string;
};
xxxxxxxxxx
import Json.Encode as JE
import TsJson.Encode as TsEncode exposing (Encoder)
type Event
= ErrorEvent Error
| PageNavigationEvent Url
type alias Url =
{ path : String }
eventEncoder : Encoder Event
eventEncoder =
TsEncode.union
(\vPageNavigation vError value ->
case value of
PageNavigationEvent url ->
vPageNavigation url
ErrorEvent errorData ->
vError errorData
)
|> TsEncode.variant pageNavigationEncoder
|> TsEncode.variant errorEncoder
|> TsEncode.buildUnion
pageNavigationEncoder : Encoder Url
pageNavigationEncoder =
TsEncode.object
[ TsEncode.required "kind" identity (TsEncode.literal <| JE.string "PageNavigation")
, Encode.required "path" .path Encode.string
]
errorEncoder : Encoder Error
errorEncoder =
rawErrorEncoder
|> TsEncode.map
(\value ->
case value of
FatalError errorCode ->
{ errorId = Just (errorCodeToString errorCode)
, message = "Fatal error."
, context = Nothing
}
Warning details ->
{ errorId = Nothing
, message = details.message
, context = Nothing
}
)
rawErrorEncoder :
Encoder
{ errorId : Maybe String
, message : String
, context : Maybe String
}
rawErrorEncoder =
TsEncode.object
[ TsEncode.optional "errorId" .errorId TsEncode.string
, TsEncode.required "message" .message TsEncode.string
, TsEncode.optional "context" .context TsEncode.string
, TsEncode.required "kind" identity (TsEncode.literal <| JE.string "Error")
]
xxxxxxxxxx
app.ports.fromElm.subscribe((fromElm) => {
switch (fromElm.tag) {
case "reportEvent":
AnalyticsService.notify(fromElm.data);
break;
case "scrollIntoView":
document.getElementById(fromElm.id)?.scrollIntoView(fromElm.data);
break;
// exhaustive check will fail if there are unhandled cases
}
});