mirror of
https://github.com/jhillyerd/inbucket.git
synced 2025-12-17 09:37:02 +00:00
ui: Refactor mailbox header list into State
This commit is contained in:
@@ -243,7 +243,7 @@ view model =
|
|||||||
mailbox =
|
mailbox =
|
||||||
case model.page of
|
case model.page of
|
||||||
Mailbox subModel ->
|
Mailbox subModel ->
|
||||||
subModel.name
|
subModel.mailboxName
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
""
|
""
|
||||||
|
|||||||
@@ -25,45 +25,40 @@ type Body
|
|||||||
|
|
||||||
|
|
||||||
type State
|
type State
|
||||||
= NoSelection
|
= LoadingList (Maybe MessageID)
|
||||||
| Selected MessageID
|
| ShowingList (List MessageHeader) (Maybe MessageID)
|
||||||
| Viewing Visible
|
| LoadingMessage (List MessageHeader) MessageID
|
||||||
| Transitioning Visible MessageID
|
| ShowingMessage (List MessageHeader) VisibleMessage
|
||||||
|
| Transitioning (List MessageHeader) VisibleMessage MessageID
|
||||||
|
|
||||||
|
|
||||||
type alias MessageID =
|
type alias MessageID =
|
||||||
String
|
String
|
||||||
|
|
||||||
|
|
||||||
type alias Visible =
|
type alias VisibleMessage =
|
||||||
{ message : Message
|
{ message : Message
|
||||||
, markSeenAt : Maybe Time
|
, markSeenAt : Maybe Time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type alias Model =
|
type alias Model =
|
||||||
{ name : String
|
{ mailboxName : String
|
||||||
, state : State
|
, state : State
|
||||||
, headers : List MessageHeader
|
|
||||||
, bodyMode : Body
|
, bodyMode : Body
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
init : String -> Maybe MessageID -> Model
|
init : String -> Maybe MessageID -> Model
|
||||||
init name selection =
|
init mailboxName selection =
|
||||||
case selection of
|
Model mailboxName (LoadingList selection) SafeHtmlBody
|
||||||
Just id ->
|
|
||||||
Model name (Selected id) [] SafeHtmlBody
|
|
||||||
|
|
||||||
Nothing ->
|
|
||||||
Model name NoSelection [] SafeHtmlBody
|
|
||||||
|
|
||||||
|
|
||||||
load : String -> Cmd Msg
|
load : String -> Cmd Msg
|
||||||
load name =
|
load mailboxName =
|
||||||
Cmd.batch
|
Cmd.batch
|
||||||
[ Ports.windowTitle (name ++ " - Inbucket")
|
[ Ports.windowTitle (mailboxName ++ " - Inbucket")
|
||||||
, getMailbox name
|
, getList mailboxName
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@@ -74,7 +69,7 @@ load name =
|
|||||||
subscriptions : Model -> Sub Msg
|
subscriptions : Model -> Sub Msg
|
||||||
subscriptions model =
|
subscriptions model =
|
||||||
case model.state of
|
case model.state of
|
||||||
Viewing { message } ->
|
ShowingMessage _ { message } ->
|
||||||
if message.seen then
|
if message.seen then
|
||||||
Sub.none
|
Sub.none
|
||||||
else
|
else
|
||||||
@@ -93,7 +88,7 @@ type Msg
|
|||||||
| ViewMessage MessageID
|
| ViewMessage MessageID
|
||||||
| DeleteMessage Message
|
| DeleteMessage Message
|
||||||
| DeleteMessageResult (Result Http.Error ())
|
| DeleteMessageResult (Result Http.Error ())
|
||||||
| MailboxResult (Result Http.Error (List MessageHeader))
|
| ListResult (Result Http.Error (List MessageHeader))
|
||||||
| MarkSeenResult (Result Http.Error ())
|
| MarkSeenResult (Result Http.Error ())
|
||||||
| MessageResult (Result Http.Error Message)
|
| MessageResult (Result Http.Error Message)
|
||||||
| MessageBody Body
|
| MessageBody Body
|
||||||
@@ -107,16 +102,16 @@ update session msg model =
|
|||||||
ClickMessage id ->
|
ClickMessage id ->
|
||||||
( updateSelected model id
|
( updateSelected model id
|
||||||
, Cmd.batch
|
, Cmd.batch
|
||||||
[ Route.newUrl (Route.Message model.name id)
|
[ Route.newUrl (Route.Message model.mailboxName id)
|
||||||
, getMessage model.name id
|
, getMessage model.mailboxName id
|
||||||
]
|
]
|
||||||
, Session.DisableRouting
|
, Session.DisableRouting
|
||||||
)
|
)
|
||||||
|
|
||||||
ViewMessage id ->
|
ViewMessage id ->
|
||||||
( updateSelected model id
|
( updateSelected model id
|
||||||
, getMessage model.name id
|
, getMessage model.mailboxName id
|
||||||
, Session.AddRecent model.name
|
, Session.AddRecent model.mailboxName
|
||||||
)
|
)
|
||||||
|
|
||||||
DeleteMessage msg ->
|
DeleteMessage msg ->
|
||||||
@@ -128,20 +123,25 @@ update session msg model =
|
|||||||
DeleteMessageResult (Err err) ->
|
DeleteMessageResult (Err err) ->
|
||||||
( model, Cmd.none, Session.SetFlash (HttpUtil.errorString err) )
|
( model, Cmd.none, Session.SetFlash (HttpUtil.errorString err) )
|
||||||
|
|
||||||
MailboxResult (Ok headers) ->
|
ListResult (Ok headers) ->
|
||||||
let
|
case model.state of
|
||||||
newModel =
|
LoadingList selection ->
|
||||||
{ model | headers = headers }
|
let
|
||||||
in
|
newModel =
|
||||||
case model.state of
|
{ model | state = ShowingList headers selection }
|
||||||
Selected id ->
|
in
|
||||||
-- Recurse to select message id.
|
case selection of
|
||||||
update session (ViewMessage id) newModel
|
Just id ->
|
||||||
|
-- Recurse to select message id.
|
||||||
|
update session (ViewMessage id) newModel
|
||||||
|
|
||||||
_ ->
|
Nothing ->
|
||||||
( newModel, Cmd.none, Session.AddRecent model.name )
|
( newModel, Cmd.none, Session.AddRecent model.mailboxName )
|
||||||
|
|
||||||
MailboxResult (Err err) ->
|
_ ->
|
||||||
|
( model, Cmd.none, Session.none )
|
||||||
|
|
||||||
|
ListResult (Err err) ->
|
||||||
( model, Cmd.none, Session.SetFlash (HttpUtil.errorString err) )
|
( model, Cmd.none, Session.SetFlash (HttpUtil.errorString err) )
|
||||||
|
|
||||||
MarkSeenResult (Ok _) ->
|
MarkSeenResult (Ok _) ->
|
||||||
@@ -157,14 +157,31 @@ update session msg model =
|
|||||||
TextBody
|
TextBody
|
||||||
else
|
else
|
||||||
model.bodyMode
|
model.bodyMode
|
||||||
|
|
||||||
|
updateMessage list message =
|
||||||
|
( { model
|
||||||
|
| state = ShowingMessage list { message = message, markSeenAt = Nothing }
|
||||||
|
, bodyMode = bodyMode
|
||||||
|
}
|
||||||
|
, Task.perform OpenedTime Time.now
|
||||||
|
, Session.none
|
||||||
|
)
|
||||||
in
|
in
|
||||||
( { model
|
case model.state of
|
||||||
| state = Viewing { message = msg, markSeenAt = Nothing }
|
LoadingList _ ->
|
||||||
, bodyMode = bodyMode
|
( model, Cmd.none, Session.none )
|
||||||
}
|
|
||||||
, Task.perform OpenedTime Time.now
|
ShowingList list _ ->
|
||||||
, Session.none
|
updateMessage list msg
|
||||||
)
|
|
||||||
|
LoadingMessage list _ ->
|
||||||
|
updateMessage list msg
|
||||||
|
|
||||||
|
ShowingMessage list _ ->
|
||||||
|
updateMessage list msg
|
||||||
|
|
||||||
|
Transitioning list _ _ ->
|
||||||
|
updateMessage list msg
|
||||||
|
|
||||||
MessageResult (Err err) ->
|
MessageResult (Err err) ->
|
||||||
( model, Cmd.none, Session.SetFlash (HttpUtil.errorString err) )
|
( model, Cmd.none, Session.SetFlash (HttpUtil.errorString err) )
|
||||||
@@ -174,14 +191,14 @@ update session msg model =
|
|||||||
|
|
||||||
OpenedTime time ->
|
OpenedTime time ->
|
||||||
case model.state of
|
case model.state of
|
||||||
Viewing visible ->
|
ShowingMessage list visible ->
|
||||||
if visible.message.seen then
|
if visible.message.seen then
|
||||||
( model, Cmd.none, Session.none )
|
( model, Cmd.none, Session.none )
|
||||||
else
|
else
|
||||||
-- Set delay to report message as seen to backend.
|
-- Set delay to report message as seen to backend.
|
||||||
( { model
|
( { model
|
||||||
| state =
|
| state =
|
||||||
Viewing
|
ShowingMessage list
|
||||||
{ visible
|
{ visible
|
||||||
| markSeenAt = Just (time + (1.5 * Time.second))
|
| markSeenAt = Just (time + (1.5 * Time.second))
|
||||||
}
|
}
|
||||||
@@ -195,7 +212,7 @@ update session msg model =
|
|||||||
|
|
||||||
Tick now ->
|
Tick now ->
|
||||||
case model.state of
|
case model.state of
|
||||||
Viewing { message, markSeenAt } ->
|
ShowingMessage _ { message, markSeenAt } ->
|
||||||
case markSeenAt of
|
case markSeenAt of
|
||||||
Just deadline ->
|
Just deadline ->
|
||||||
if now >= deadline then
|
if now >= deadline then
|
||||||
@@ -213,22 +230,28 @@ update session msg model =
|
|||||||
updateSelected : Model -> MessageID -> Model
|
updateSelected : Model -> MessageID -> Model
|
||||||
updateSelected model id =
|
updateSelected model id =
|
||||||
case model.state of
|
case model.state of
|
||||||
Viewing visible ->
|
ShowingList list _ ->
|
||||||
|
{ model | state = LoadingMessage list id }
|
||||||
|
|
||||||
|
ShowingMessage list visible ->
|
||||||
-- Use Transitioning state to prevent message flicker.
|
-- Use Transitioning state to prevent message flicker.
|
||||||
{ model | state = Transitioning visible id }
|
{ model | state = Transitioning list visible id }
|
||||||
|
|
||||||
|
Transitioning list visible _ ->
|
||||||
|
{ model | state = Transitioning list visible id }
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
{ model | state = Selected id }
|
model
|
||||||
|
|
||||||
|
|
||||||
getMailbox : String -> Cmd Msg
|
getList : String -> Cmd Msg
|
||||||
getMailbox name =
|
getList mailboxName =
|
||||||
let
|
let
|
||||||
url =
|
url =
|
||||||
"/api/v1/mailbox/" ++ name
|
"/api/v1/mailbox/" ++ mailboxName
|
||||||
in
|
in
|
||||||
Http.get url (Decode.list MessageHeader.decoder)
|
Http.get url (Decode.list MessageHeader.decoder)
|
||||||
|> Http.send MailboxResult
|
|> Http.send ListResult
|
||||||
|
|
||||||
|
|
||||||
deleteMessage : Model -> Message -> ( Model, Cmd Msg, Session.Msg )
|
deleteMessage : Model -> Message -> ( Model, Cmd Msg, Session.Msg )
|
||||||
@@ -241,20 +264,22 @@ deleteMessage model msg =
|
|||||||
HttpUtil.delete url
|
HttpUtil.delete url
|
||||||
|> Http.send DeleteMessageResult
|
|> Http.send DeleteMessageResult
|
||||||
in
|
in
|
||||||
( { model
|
case model.state of
|
||||||
| state = NoSelection
|
ShowingMessage list _ ->
|
||||||
, headers = List.filter (\x -> x.id /= msg.id) model.headers
|
( { model | state = ShowingList (List.filter (\x -> x.id /= msg.id) list) Nothing }
|
||||||
}
|
, cmd
|
||||||
, cmd
|
, Session.none
|
||||||
, Session.none
|
)
|
||||||
)
|
|
||||||
|
_ ->
|
||||||
|
( model, cmd, Session.none )
|
||||||
|
|
||||||
|
|
||||||
getMessage : String -> MessageID -> Cmd Msg
|
getMessage : String -> MessageID -> Cmd Msg
|
||||||
getMessage mailbox id =
|
getMessage mailboxName id =
|
||||||
let
|
let
|
||||||
url =
|
url =
|
||||||
"/serve/m/" ++ mailbox ++ "/" ++ id
|
"/serve/m/" ++ mailboxName ++ "/" ++ id
|
||||||
in
|
in
|
||||||
Http.get url Message.decoder
|
Http.get url Message.decoder
|
||||||
|> Http.send MessageResult
|
|> Http.send MessageResult
|
||||||
@@ -263,7 +288,7 @@ getMessage mailbox id =
|
|||||||
markMessageSeen : Model -> Message -> ( Model, Cmd Msg, Session.Msg )
|
markMessageSeen : Model -> Message -> ( Model, Cmd Msg, Session.Msg )
|
||||||
markMessageSeen model message =
|
markMessageSeen model message =
|
||||||
case model.state of
|
case model.state of
|
||||||
Viewing visible ->
|
ShowingMessage list visible ->
|
||||||
let
|
let
|
||||||
message =
|
message =
|
||||||
visible.message
|
visible.message
|
||||||
@@ -287,12 +312,11 @@ markMessageSeen model message =
|
|||||||
in
|
in
|
||||||
( { model
|
( { model
|
||||||
| state =
|
| state =
|
||||||
Viewing
|
ShowingMessage (List.map updateSeen list)
|
||||||
{ visible
|
{ visible
|
||||||
| message = { message | seen = True }
|
| message = { message | seen = True }
|
||||||
, markSeenAt = Nothing
|
, markSeenAt = Nothing
|
||||||
}
|
}
|
||||||
, headers = List.map updateSeen model.headers
|
|
||||||
}
|
}
|
||||||
, command
|
, command
|
||||||
, Session.None
|
, Session.None
|
||||||
@@ -309,20 +333,36 @@ markMessageSeen model message =
|
|||||||
view : Session -> Model -> Html Msg
|
view : Session -> Model -> Html Msg
|
||||||
view session model =
|
view session model =
|
||||||
div [ id "page", class "mailbox" ]
|
div [ id "page", class "mailbox" ]
|
||||||
[ aside [ id "message-list" ] [ messageList model ]
|
[ aside [ id "message-list" ]
|
||||||
|
[ case model.state of
|
||||||
|
LoadingList _ ->
|
||||||
|
messageList [] Nothing
|
||||||
|
|
||||||
|
ShowingList list selection ->
|
||||||
|
messageList list selection
|
||||||
|
|
||||||
|
LoadingMessage list selection ->
|
||||||
|
messageList list (Just selection)
|
||||||
|
|
||||||
|
ShowingMessage list visible ->
|
||||||
|
messageList list (Just visible.message.id)
|
||||||
|
|
||||||
|
Transitioning list _ selection ->
|
||||||
|
messageList list (Just selection)
|
||||||
|
]
|
||||||
, main_
|
, main_
|
||||||
[ id "message" ]
|
[ id "message" ]
|
||||||
[ case model.state of
|
[ case model.state of
|
||||||
NoSelection ->
|
ShowingList _ _ ->
|
||||||
text
|
text
|
||||||
("Select a message on the left,"
|
("Select a message on the left,"
|
||||||
++ " or enter a different username into the box on upper right."
|
++ " or enter a different username into the box on upper right."
|
||||||
)
|
)
|
||||||
|
|
||||||
Viewing { message } ->
|
ShowingMessage _ { message } ->
|
||||||
viewMessage message model.bodyMode
|
viewMessage message model.bodyMode
|
||||||
|
|
||||||
Transitioning { message } _ ->
|
Transitioning _ { message } _ ->
|
||||||
viewMessage message model.bodyMode
|
viewMessage message model.bodyMode
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
@@ -331,21 +371,9 @@ view session model =
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
messageList : Model -> Html Msg
|
messageList : List MessageHeader -> Maybe MessageID -> Html Msg
|
||||||
messageList model =
|
messageList list selected =
|
||||||
let
|
div [] (List.map (messageChip selected) (List.reverse list))
|
||||||
selected =
|
|
||||||
case model.state of
|
|
||||||
Selected id ->
|
|
||||||
Just id
|
|
||||||
|
|
||||||
Viewing { message } ->
|
|
||||||
Just message.id
|
|
||||||
|
|
||||||
_ ->
|
|
||||||
Nothing
|
|
||||||
in
|
|
||||||
div [] (List.map (messageChip selected) (List.reverse model.headers))
|
|
||||||
|
|
||||||
|
|
||||||
messageChip : Maybe MessageID -> MessageHeader -> Html Msg
|
messageChip : Maybe MessageID -> MessageHeader -> Html Msg
|
||||||
|
|||||||
Reference in New Issue
Block a user