diff --git a/modules/webapp/src/main/elm/App/Data.elm b/modules/webapp/src/main/elm/App/Data.elm index 9abc609b..d165bd24 100644 --- a/modules/webapp/src/main/elm/App/Data.elm +++ b/modules/webapp/src/main/elm/App/Data.elm @@ -15,6 +15,7 @@ import Http import Page exposing (Page(..)) import Page.CollectiveSettings.Data import Page.Home.Data +import Page.ItemDetail.Data import Page.Login.Data import Page.ManageData.Data import Page.NewInvite.Data @@ -39,6 +40,7 @@ type alias Model = , registerModel : Page.Register.Data.Model , uploadModel : Page.Upload.Data.Model , newInviteModel : Page.NewInvite.Data.Model + , itemDetailModel : Page.ItemDetail.Data.Model , navMenuOpen : Bool , subs : Sub Msg } @@ -64,6 +66,7 @@ init key url flags = , registerModel = Page.Register.Data.emptyModel , uploadModel = Page.Upload.Data.emptyModel , newInviteModel = Page.NewInvite.Data.emptyModel + , itemDetailModel = Page.ItemDetail.Data.emptyModel , navMenuOpen = False , subs = Sub.none } @@ -82,6 +85,7 @@ type Msg | RegisterMsg Page.Register.Data.Msg | UploadMsg Page.Upload.Data.Msg | NewInviteMsg Page.NewInvite.Data.Msg + | ItemDetailMsg Page.ItemDetail.Data.Msg | Logout | LogoutResp (Result Http.Error ()) | SessionCheckResp (Result Http.Error AuthResult) diff --git a/modules/webapp/src/main/elm/App/Update.elm b/modules/webapp/src/main/elm/App/Update.elm index 86547b49..59d0169a 100644 --- a/modules/webapp/src/main/elm/App/Update.elm +++ b/modules/webapp/src/main/elm/App/Update.elm @@ -13,6 +13,8 @@ import Page.CollectiveSettings.Data import Page.CollectiveSettings.Update import Page.Home.Data import Page.Home.Update +import Page.ItemDetail.Data +import Page.ItemDetail.Update import Page.Login.Data import Page.Login.Update import Page.ManageData.Data @@ -71,6 +73,9 @@ updateWithSub msg model = NewInviteMsg m -> updateNewInvite m model |> noSub + ItemDetailMsg m -> + updateItemDetail m model |> noSub + VersionResp (Ok info) -> ( { model | version = info }, Cmd.none ) |> noSub @@ -170,6 +175,20 @@ updateWithSub msg model = ( { model | navMenuOpen = not model.navMenuOpen }, Cmd.none, Sub.none ) +updateItemDetail : Page.ItemDetail.Data.Msg -> Model -> ( Model, Cmd Msg ) +updateItemDetail lmsg model = + let + inav = + Page.Home.Data.itemNav model.itemDetailModel.detail.item.id model.homeModel + + ( lm, lc ) = + Page.ItemDetail.Update.update model.key model.flags inav.next lmsg model.itemDetailModel + in + ( { model | itemDetailModel = lm } + , Cmd.map ItemDetailMsg lc + ) + + updateNewInvite : Page.NewInvite.Data.Msg -> Model -> ( Model, Cmd Msg ) updateNewInvite lmsg model = let @@ -265,7 +284,7 @@ updateHome : Page.Home.Data.Msg -> Model -> ( Model, Cmd Msg ) updateHome lmsg model = let ( lm, lc ) = - Page.Home.Update.update model.flags lmsg model.homeModel + Page.Home.Update.update model.key model.flags lmsg model.homeModel in ( { model | homeModel = lm } , Cmd.map HomeMsg lc @@ -321,6 +340,9 @@ initPage model page = NewInvitePage -> updateQueue Page.Queue.Data.StopRefresh model + ItemDetailPage id -> + updateItemDetail (Page.ItemDetail.Data.Init id) model + noSub : ( Model, Cmd Msg ) -> ( Model, Cmd Msg, Sub Msg ) noSub ( m, c ) = diff --git a/modules/webapp/src/main/elm/App/View.elm b/modules/webapp/src/main/elm/App/View.elm index c2a5c05d..f3451644 100644 --- a/modules/webapp/src/main/elm/App/View.elm +++ b/modules/webapp/src/main/elm/App/View.elm @@ -6,7 +6,9 @@ import Html.Attributes exposing (..) import Html.Events exposing (onClick) import Page exposing (Page(..)) import Page.CollectiveSettings.View +import Page.Home.Data import Page.Home.View +import Page.ItemDetail.View import Page.Login.View import Page.ManageData.View import Page.NewInvite.View @@ -105,11 +107,23 @@ defaultLayout model = NewInvitePage -> viewNewInvite model + + ItemDetailPage id -> + viewItemDetail id model ] , footer model ] +viewItemDetail : String -> Model -> Html Msg +viewItemDetail id model = + let + inav = + Page.Home.Data.itemNav id model.homeModel + in + Html.map ItemDetailMsg (Page.ItemDetail.View.view inav model.itemDetailModel) + + viewNewInvite : Model -> Html Msg viewNewInvite model = Html.map NewInviteMsg (Page.NewInvite.View.view model.flags model.newInviteModel) diff --git a/modules/webapp/src/main/elm/Comp/ItemDetail.elm b/modules/webapp/src/main/elm/Comp/ItemDetail.elm index 665c7a20..478af071 100644 --- a/modules/webapp/src/main/elm/Comp/ItemDetail.elm +++ b/modules/webapp/src/main/elm/Comp/ItemDetail.elm @@ -1,7 +1,6 @@ module Comp.ItemDetail exposing ( Model , Msg(..) - , UserNav(..) , emptyModel , update , view @@ -20,6 +19,7 @@ import Api.Model.OptionalText exposing (OptionalText) import Api.Model.ReferenceList exposing (ReferenceList) import Api.Model.Tag exposing (Tag) import Api.Model.TagList exposing (TagList) +import Browser.Navigation as Nav import Comp.DatePicker import Comp.Dropdown exposing (isDropdownChangeMsg) import Comp.YesNoDimmer @@ -31,6 +31,7 @@ import Html.Attributes exposing (..) import Html.Events exposing (onClick, onInput) import Http import Markdown +import Page exposing (Page(..)) import Util.Maybe import Util.Size import Util.String @@ -49,6 +50,7 @@ type alias Model = , concEquipModel : Comp.Dropdown.Model IdName , nameModel : String , notesModel : Maybe String + , notesHidden : Bool , deleteConfirm : Comp.YesNoDimmer.Model , itemDatePicker : DatePicker , itemDate : Maybe Int @@ -76,7 +78,11 @@ emptyModel = } , directionModel = Comp.Dropdown.makeSingleList - { makeOption = \entry -> { value = Data.Direction.toString entry, text = Data.Direction.toString entry } + { makeOption = + \entry -> + { value = Data.Direction.toString entry + , text = Data.Direction.toString entry + } , options = Data.Direction.all , placeholder = "Choose a direction…" , selected = Nothing @@ -103,6 +109,7 @@ emptyModel = } , nameModel = "" , notesModel = Nothing + , notesHidden = False , deleteConfirm = Comp.YesNoDimmer.emptyModel , itemDatePicker = Comp.DatePicker.emptyModel , itemDate = Nothing @@ -112,26 +119,12 @@ emptyModel = } -type UserNav - = NavBack - | NavPrev - | NavNext - | NavNone - | NavNextOrBack - - -noNav : ( Model, Cmd Msg ) -> ( Model, Cmd Msg, UserNav ) -noNav ( model, cmd ) = - ( model, cmd, NavNone ) - - type Msg = ToggleMenu | ReloadItem | Init | SetItem ItemDetail | SetActiveAttachment Int - | NavClick UserNav | TagDropdownMsg (Comp.Dropdown.Msg Tag) | DirDropdownMsg (Comp.Dropdown.Msg Direction) | OrgDropdownMsg (Comp.Dropdown.Msg IdName) @@ -145,6 +138,7 @@ type Msg | SetName String | SaveName | SetNotes String + | ToggleNotes | SaveNotes | ConfirmItem | UnconfirmItem @@ -281,8 +275,8 @@ setDueDate flags model date = Api.setItemDueDate flags model.item.id (OptionalDate date) SaveResp -update : Flags -> Msg -> Model -> ( Model, Cmd Msg, UserNav ) -update flags msg model = +update : Nav.Key -> Flags -> Maybe String -> Msg -> Model -> ( Model, Cmd Msg ) +update key flags next msg model = case msg of Init -> let @@ -295,16 +289,17 @@ update flags msg model = , Cmd.map ItemDatePickerMsg dpc , Cmd.map DueDatePickerMsg dpc ] - , NavNone ) SetItem item -> let - ( m1, c1, _ ) = - update flags (TagDropdownMsg (Comp.Dropdown.SetSelection item.tags)) model + ( m1, c1 ) = + update key flags next (TagDropdownMsg (Comp.Dropdown.SetSelection item.tags)) model - ( m2, c2, _ ) = - update flags + ( m2, c2 ) = + update key + flags + next (DirDropdownMsg (Comp.Dropdown.SetSelection (Data.Direction.fromString item.direction @@ -315,8 +310,10 @@ update flags msg model = ) m1 - ( m3, c3, _ ) = - update flags + ( m3, c3 ) = + update key + flags + next (OrgDropdownMsg (Comp.Dropdown.SetSelection (item.corrOrg @@ -327,8 +324,10 @@ update flags msg model = ) m2 - ( m4, c4, _ ) = - update flags + ( m4, c4 ) = + update key + flags + next (CorrPersonMsg (Comp.Dropdown.SetSelection (item.corrPerson @@ -339,8 +338,10 @@ update flags msg model = ) m3 - ( m5, c5, _ ) = - update flags + ( m5, c5 ) = + update key + flags + next (ConcPersonMsg (Comp.Dropdown.SetSelection (item.concPerson @@ -358,26 +359,28 @@ update flags msg model = else Cmd.none in - ( { m5 | item = item, nameModel = item.name, notesModel = item.notes, itemDate = item.itemDate, dueDate = item.dueDate } + ( { m5 + | item = item + , nameModel = item.name + , notesModel = item.notes + , itemDate = item.itemDate + , dueDate = item.dueDate + } , Cmd.batch [ c1, c2, c3, c4, c5, getOptions flags, proposalCmd ] ) - |> noNav SetActiveAttachment pos -> - ( { model | visibleAttach = pos }, Cmd.none, NavNone ) - - NavClick nav -> - ( model, Cmd.none, nav ) + ( { model | visibleAttach = pos }, Cmd.none ) ToggleMenu -> - ( { model | menuOpen = not model.menuOpen }, Cmd.none, NavNone ) + ( { model | menuOpen = not model.menuOpen }, Cmd.none ) ReloadItem -> if model.item.id == "" then - ( model, Cmd.none, NavNone ) + ( model, Cmd.none ) else - ( model, Api.itemDetail flags model.item.id GetItemResp, NavNone ) + ( model, Api.itemDetail flags model.item.id GetItemResp ) TagDropdownMsg m -> let @@ -394,7 +397,7 @@ update flags msg model = else Cmd.none in - ( newModel, Cmd.batch [ save, Cmd.map TagDropdownMsg c2 ], NavNone ) + ( newModel, Cmd.batch [ save, Cmd.map TagDropdownMsg c2 ] ) DirDropdownMsg m -> let @@ -411,7 +414,7 @@ update flags msg model = else Cmd.none in - ( newModel, Cmd.batch [ save, Cmd.map DirDropdownMsg c2 ] ) |> noNav + ( newModel, Cmd.batch [ save, Cmd.map DirDropdownMsg c2 ] ) OrgDropdownMsg m -> let @@ -431,7 +434,7 @@ update flags msg model = else Cmd.none in - ( newModel, Cmd.batch [ save, Cmd.map OrgDropdownMsg c2 ] ) |> noNav + ( newModel, Cmd.batch [ save, Cmd.map OrgDropdownMsg c2 ] ) CorrPersonMsg m -> let @@ -451,7 +454,7 @@ update flags msg model = else Cmd.none in - ( newModel, Cmd.batch [ save, Cmd.map CorrPersonMsg c2 ] ) |> noNav + ( newModel, Cmd.batch [ save, Cmd.map CorrPersonMsg c2 ] ) ConcPersonMsg m -> let @@ -471,7 +474,7 @@ update flags msg model = else Cmd.none in - ( newModel, Cmd.batch [ save, Cmd.map ConcPersonMsg c2 ] ) |> noNav + ( newModel, Cmd.batch [ save, Cmd.map ConcPersonMsg c2 ] ) ConcEquipMsg m -> let @@ -491,13 +494,13 @@ update flags msg model = else Cmd.none in - ( newModel, Cmd.batch [ save, Cmd.map ConcEquipMsg c2 ] ) |> noNav + ( newModel, Cmd.batch [ save, Cmd.map ConcEquipMsg c2 ] ) SetName str -> - ( { model | nameModel = str }, Cmd.none ) |> noNav + ( { model | nameModel = str }, Cmd.none ) SaveName -> - ( model, setName flags model ) |> noNav + ( model, setName flags model ) SetNotes str -> ( { model @@ -510,16 +513,20 @@ update flags msg model = } , Cmd.none ) - |> noNav + + ToggleNotes -> + ( { model | notesHidden = not model.notesHidden } + , Cmd.none + ) SaveNotes -> - ( model, setNotes flags model ) |> noNav + ( model, setNotes flags model ) ConfirmItem -> - ( model, Api.setConfirmed flags model.item.id SaveResp ) |> noNav + ( model, Api.setConfirmed flags model.item.id SaveResp ) UnconfirmItem -> - ( model, Api.setUnconfirmed flags model.item.id SaveResp ) |> noNav + ( model, Api.setUnconfirmed flags model.item.id SaveResp ) ItemDatePickerMsg m -> let @@ -532,13 +539,13 @@ update flags msg model = newModel = { model | itemDatePicker = dp, itemDate = Just (Comp.DatePicker.midOfDay date) } in - ( newModel, setDate flags newModel newModel.itemDate ) |> noNav + ( newModel, setDate flags newModel newModel.itemDate ) _ -> - ( { model | itemDatePicker = dp }, Cmd.none ) |> noNav + ( { model | itemDatePicker = dp }, Cmd.none ) RemoveDate -> - ( { model | itemDate = Nothing }, setDate flags model Nothing ) |> noNav + ( { model | itemDate = Nothing }, setDate flags model Nothing ) DueDatePickerMsg m -> let @@ -551,13 +558,13 @@ update flags msg model = newModel = { model | dueDatePicker = dp, dueDate = Just (Comp.DatePicker.midOfDay date) } in - ( newModel, setDueDate flags newModel newModel.dueDate ) |> noNav + ( newModel, setDueDate flags newModel newModel.dueDate ) _ -> - ( { model | dueDatePicker = dp }, Cmd.none ) |> noNav + ( { model | dueDatePicker = dp }, Cmd.none ) RemoveDueDate -> - ( { model | dueDate = Nothing }, setDueDate flags model Nothing ) |> noNav + ( { model | dueDate = Nothing }, setDueDate flags model Nothing ) YesNoMsg m -> let @@ -571,67 +578,67 @@ update flags msg model = else Cmd.none in - ( { model | deleteConfirm = cm }, cmd ) |> noNav + ( { model | deleteConfirm = cm }, cmd ) RequestDelete -> - update flags (YesNoMsg Comp.YesNoDimmer.activate) model + update key flags next (YesNoMsg Comp.YesNoDimmer.activate) model SetCorrOrgSuggestion idname -> - ( model, setCorrOrg flags model (Just idname) ) |> noNav + ( model, setCorrOrg flags model (Just idname) ) SetCorrPersonSuggestion idname -> - ( model, setCorrPerson flags model (Just idname) ) |> noNav + ( model, setCorrPerson flags model (Just idname) ) SetConcPersonSuggestion idname -> - ( model, setConcPerson flags model (Just idname) ) |> noNav + ( model, setConcPerson flags model (Just idname) ) SetConcEquipSuggestion idname -> - ( model, setConcEquip flags model (Just idname) ) |> noNav + ( model, setConcEquip flags model (Just idname) ) SetItemDateSuggestion date -> - ( model, setDate flags model (Just date) ) |> noNav + ( model, setDate flags model (Just date) ) SetDueDateSuggestion date -> - ( model, setDueDate flags model (Just date) ) |> noNav + ( model, setDueDate flags model (Just date) ) GetTagsResp (Ok tags) -> let tagList = Comp.Dropdown.SetOptions tags.items - ( m1, c1, _ ) = - update flags (TagDropdownMsg tagList) model + ( m1, c1 ) = + update key flags next (TagDropdownMsg tagList) model in - ( m1, c1 ) |> noNav + ( m1, c1 ) GetTagsResp (Err _) -> - ( model, Cmd.none ) |> noNav + ( model, Cmd.none ) GetOrgResp (Ok orgs) -> let opts = Comp.Dropdown.SetOptions orgs.items in - update flags (OrgDropdownMsg opts) model + update key flags next (OrgDropdownMsg opts) model GetOrgResp (Err _) -> - ( model, Cmd.none ) |> noNav + ( model, Cmd.none ) GetPersonResp (Ok ps) -> let opts = Comp.Dropdown.SetOptions ps.items - ( m1, c1, _ ) = - update flags (CorrPersonMsg opts) model + ( m1, c1 ) = + update key flags next (CorrPersonMsg opts) model - ( m2, c2, _ ) = - update flags (ConcPersonMsg opts) m1 + ( m2, c2 ) = + update key flags next (ConcPersonMsg opts) m1 in - ( m2, Cmd.batch [ c1, c2 ] ) |> noNav + ( m2, Cmd.batch [ c1, c2 ] ) GetPersonResp (Err _) -> - ( model, Cmd.none ) |> noNav + ( model, Cmd.none ) GetEquipResp (Ok equips) -> let @@ -641,42 +648,47 @@ update flags msg model = equips.items ) in - update flags (ConcEquipMsg opts) model + update key flags next (ConcEquipMsg opts) model GetEquipResp (Err _) -> - ( model, Cmd.none ) |> noNav + ( model, Cmd.none ) SaveResp (Ok res) -> if res.success then - ( model, Api.itemDetail flags model.item.id GetItemResp ) |> noNav + ( model, Api.itemDetail flags model.item.id GetItemResp ) else - ( model, Cmd.none ) |> noNav + ( model, Cmd.none ) SaveResp (Err _) -> - ( model, Cmd.none ) |> noNav + ( model, Cmd.none ) DeleteResp (Ok res) -> if res.success then - ( model, Cmd.none, NavNextOrBack ) + case next of + Just id -> + ( model, Page.set key (ItemDetailPage id) ) + + Nothing -> + ( model, Page.set key HomePage ) else - ( model, Cmd.none ) |> noNav + ( model, Cmd.none ) DeleteResp (Err _) -> - ( model, Cmd.none ) |> noNav + ( model, Cmd.none ) GetItemResp (Ok item) -> - update flags (SetItem item) model + update key flags next (SetItem item) model GetItemResp (Err _) -> - ( model, Cmd.none ) |> noNav + ( model, Cmd.none ) GetProposalResp (Ok ip) -> - ( { model | itemProposals = ip }, Cmd.none ) |> noNav + ( { model | itemProposals = ip }, Cmd.none ) GetProposalResp (Err _) -> - ( model, Cmd.none ) |> noNav + ( model, Cmd.none ) @@ -692,21 +704,38 @@ actionInputDatePicker = { ds | containerClassList = [ ( "ui action input", True ) ] } -view : Model -> Html Msg -view model = +view : { prev : Maybe String, next : Maybe String } -> Model -> Html Msg +view inav model = div [] - [ div + [ renderItemInfo model + , div [ classList [ ( "ui ablue-comp menu", True ) ] ] - [ a [ class "item", href "", onClick (NavClick NavBack) ] + [ a [ class "item", Page.href HomePage ] [ i [ class "arrow left icon" ] [] ] - , a [ class "item", href "", onClick (NavClick NavPrev) ] + , a + [ classList + [ ( "item", True ) + , ( "disabled", inav.prev == Nothing ) + ] + , Maybe.map ItemDetailPage inav.prev + |> Maybe.map Page.href + |> Maybe.withDefault (href "#") + ] [ i [ class "caret square left outline icon" ] [] ] - , a [ class "item", href "", onClick (NavClick NavNext) ] + , a + [ classList + [ ( "item", True ) + , ( "disabled", inav.next == Nothing ) + ] + , Maybe.map ItemDetailPage inav.next + |> Maybe.map Page.href + |> Maybe.withDefault (href "#") + ] [ i [ class "caret square right outline icon" ] [] ] , a @@ -722,9 +751,10 @@ view model = ] ] , div [ class "ui grid" ] - [ div + [ Html.map YesNoMsg (Comp.YesNoDimmer.view model.deleteConfirm) + , div [ classList - [ ( "six wide column", True ) + [ ( "four wide column", True ) , ( "invisible", not model.menuOpen ) ] ] @@ -736,17 +766,17 @@ view model = ) , div [ classList - [ ( "ten", model.menuOpen ) + [ ( "twelve", model.menuOpen ) , ( "sixteen", not model.menuOpen ) , ( "wide column", True ) ] ] <| List.concat - [ [ renderItemInfo model ] - , [ renderAttachmentsTabMenu model ] + [ renderNotes model + , [ renderAttachmentsTabMenu model + ] , renderAttachmentsTabBody model - , renderNotes model , renderIdInfo model ] ] @@ -776,11 +806,31 @@ renderNotes model = [] Just str -> - [ h3 [ class "ui header" ] - [ text "Notes" + if model.notesHidden then + [ div [ class "ui segment" ] + [ a + [ class "ui top left attached label" + , onClick ToggleNotes + , href "#" + ] + [ i [ class "eye icon" ] [] + , text "Show notes…" + ] + ] + ] + + else + [ div [ class "ui segment" ] + [ Markdown.toHtml [ class "item-notes" ] str + , a + [ class "ui right corner label" + , onClick ToggleNotes + , href "#" + ] + [ i [ class "delete icon" ] [] + ] + ] ] - , Markdown.toHtml [ class "item-notes" ] str - ] renderAttachmentsTabMenu : Model -> Html Msg @@ -829,12 +879,6 @@ renderAttachmentsTabBody model = renderItemInfo : Model -> Html Msg renderItemInfo model = let - name = - div [ class "item" ] - [ i [ class (Data.Direction.iconFromString model.item.direction) ] [] - , text model.item.name - ] - date = div [ class "item" ] [ Maybe.withDefault model.item.created model.item.itemDate @@ -876,7 +920,7 @@ renderItemInfo model = ] in div [ class "ui fluid container" ] - ([ h2 [ class "ui header" ] + (h2 [ class "ui header" ] [ i [ class (Data.Direction.iconFromString model.item.direction) ] [] , div [ class "content" ] [ text model.item.name @@ -905,8 +949,7 @@ renderItemInfo model = ] ] ] - ] - ++ renderTags model + :: renderTags model ) @@ -973,8 +1016,7 @@ renderEditButtons model = renderEditForm : Model -> Html Msg renderEditForm model = div [ class "ui attached segment" ] - [ Html.map YesNoMsg (Comp.YesNoDimmer.view model.deleteConfirm) - , div [ class "ui form" ] + [ div [ class "ui form" ] [ div [ class "field" ] [ label [] [ i [ class "tags icon" ] [] @@ -986,7 +1028,12 @@ renderEditForm model = [ label [] [ text "Name" ] , div [ class "ui action input" ] [ input [ type_ "text", value model.nameModel, onInput SetName ] [] - , button [ class "ui icon button", onClick SaveName ] [ i [ class "save outline icon" ] [] ] + , button + [ class "ui icon button" + , onClick SaveName + ] + [ i [ class "save outline icon" ] [] + ] ] ] , div [ class "field" ] @@ -996,7 +1043,12 @@ renderEditForm model = , div [ class " field" ] [ label [] [ text "Date" ] , div [ class "ui action input" ] - [ Html.map ItemDatePickerMsg (Comp.DatePicker.viewTime model.itemDate actionInputDatePicker model.itemDatePicker) + [ Html.map ItemDatePickerMsg + (Comp.DatePicker.viewTime + model.itemDate + actionInputDatePicker + model.itemDatePicker + ) , a [ class "ui icon button", href "", onClick RemoveDate ] [ i [ class "trash alternate outline icon" ] [] ] @@ -1006,7 +1058,12 @@ renderEditForm model = , div [ class " field" ] [ label [] [ text "Due Date" ] , div [ class "ui action input" ] - [ Html.map DueDatePickerMsg (Comp.DatePicker.viewTime model.dueDate actionInputDatePicker model.dueDatePicker) + [ Html.map DueDatePickerMsg + (Comp.DatePicker.viewTime + model.dueDate + actionInputDatePicker + model.dueDatePicker + ) , a [ class "ui icon button", href "", onClick RemoveDueDate ] [ i [ class "trash alternate outline icon" ] [] ] ] diff --git a/modules/webapp/src/main/elm/Page.elm b/modules/webapp/src/main/elm/Page.elm index f4839b47..32355252 100644 --- a/modules/webapp/src/main/elm/Page.elm +++ b/modules/webapp/src/main/elm/Page.elm @@ -10,6 +10,7 @@ module Page exposing , pageFromString , pageName , pageToString + , set , uploadId ) @@ -31,6 +32,7 @@ type Page | RegisterPage | UploadPage (Maybe String) | NewInvitePage + | ItemDetailPage String isSecured : Page -> Bool @@ -63,6 +65,9 @@ isSecured page = UploadPage arg -> Util.Maybe.isEmpty arg + ItemDetailPage _ -> + True + isOpen : Page -> Bool isOpen page = @@ -114,6 +119,9 @@ pageName page = Nothing -> "Upload" + ItemDetailPage _ -> + "Item" + loginPageReferrer : Page -> Maybe Page loginPageReferrer page = @@ -169,6 +177,9 @@ pageToString page = NewInvitePage -> "/app/newinvite" + ItemDetailPage id -> + "/app/item/" ++ id + pageFromString : String -> Maybe Page pageFromString str = @@ -191,6 +202,11 @@ href page = Attr.href (pageToString page) +set : Nav.Key -> Page -> Cmd msg +set key page = + Nav.pushUrl key (pageToString page) + + goto : Page -> Cmd msg goto page = Nav.load (pageToString page) @@ -215,6 +231,7 @@ parser = , Parser.map (\s -> UploadPage (Just s)) (s pathPrefix s "upload" string) , Parser.map (UploadPage Nothing) (s pathPrefix s "upload") , Parser.map NewInvitePage (s pathPrefix s "newinvite") + , Parser.map ItemDetailPage (s pathPrefix s "item" string) ] diff --git a/modules/webapp/src/main/elm/Page/Home/Data.elm b/modules/webapp/src/main/elm/Page/Home/Data.elm index 7fbd38ae..a457db52 100644 --- a/modules/webapp/src/main/elm/Page/Home/Data.elm +++ b/modules/webapp/src/main/elm/Page/Home/Data.elm @@ -3,11 +3,11 @@ module Page.Home.Data exposing , Msg(..) , ViewMode(..) , emptyModel + , itemNav ) import Api.Model.ItemDetail exposing (ItemDetail) import Api.Model.ItemLightList exposing (ItemLightList) -import Comp.ItemDetail import Comp.ItemList import Comp.SearchMenu import Http @@ -17,7 +17,6 @@ type alias Model = { searchMenuModel : Comp.SearchMenu.Model , itemListModel : Comp.ItemList.Model , searchInProgress : Bool - , itemDetailModel : Comp.ItemDetail.Model , viewMode : ViewMode } @@ -26,7 +25,6 @@ emptyModel : Model emptyModel = { searchMenuModel = Comp.SearchMenu.emptyModel , itemListModel = Comp.ItemList.emptyModel - , itemDetailModel = Comp.ItemDetail.emptyModel , searchInProgress = False , viewMode = Listing } @@ -38,10 +36,22 @@ type Msg | ItemListMsg Comp.ItemList.Msg | ItemSearchResp (Result Http.Error ItemLightList) | DoSearch - | ItemDetailMsg Comp.ItemDetail.Msg - | ItemDetailResp (Result Http.Error ItemDetail) type ViewMode = Listing | Detail + + +itemNav : String -> Model -> { prev : Maybe String, next : Maybe String } +itemNav id model = + let + prev = + Comp.ItemList.prevItem model.itemListModel id + + next = + Comp.ItemList.nextItem model.itemListModel id + in + { prev = Maybe.map .id prev + , next = Maybe.map .id next + } diff --git a/modules/webapp/src/main/elm/Page/Home/Update.elm b/modules/webapp/src/main/elm/Page/Home/Update.elm index 01513a00..2c279e21 100644 --- a/modules/webapp/src/main/elm/Page/Home/Update.elm +++ b/modules/webapp/src/main/elm/Page/Home/Update.elm @@ -1,21 +1,22 @@ module Page.Home.Update exposing (update) import Api +import Browser.Navigation as Nav import Comp.ItemDetail import Comp.ItemList import Comp.SearchMenu import Data.Flags exposing (Flags) +import Page exposing (Page(..)) import Page.Home.Data exposing (..) import Util.Update -update : Flags -> Msg -> Model -> ( Model, Cmd Msg ) -update flags msg model = +update : Nav.Key -> Flags -> Msg -> Model -> ( Model, Cmd Msg ) +update key flags msg model = case msg of Init -> Util.Update.andThen1 - [ update flags (SearchMenuMsg Comp.SearchMenu.Init) - , update flags (ItemDetailMsg Comp.ItemDetail.Init) + [ update key flags (SearchMenuMsg Comp.SearchMenu.Init) , doSearch flags ] model @@ -45,7 +46,7 @@ update flags msg model = cmd = case mitem of Just item -> - Api.itemDetail flags item.id ItemDetailResp + Page.set key (ItemDetailPage item.id) Nothing -> Cmd.none @@ -57,7 +58,7 @@ update flags msg model = m = { model | searchInProgress = False, viewMode = Listing } in - update flags (ItemListMsg (Comp.ItemList.SetResults list)) m + update key flags (ItemListMsg (Comp.ItemList.SetResults list)) m ItemSearchResp (Err _) -> ( { model | searchInProgress = False }, Cmd.none ) @@ -65,58 +66,6 @@ update flags msg model = DoSearch -> doSearch flags model - ItemDetailMsg m -> - let - ( m2, c2, nav ) = - Comp.ItemDetail.update flags m model.itemDetailModel - - newModel = - { model | itemDetailModel = m2 } - - newCmd = - Cmd.map ItemDetailMsg c2 - in - case nav of - Comp.ItemDetail.NavBack -> - doSearch flags newModel - - Comp.ItemDetail.NavPrev -> - case Comp.ItemList.prevItem model.itemListModel m2.item.id of - Just n -> - ( newModel, Cmd.batch [ newCmd, Api.itemDetail flags n.id ItemDetailResp ] ) - - Nothing -> - ( newModel, newCmd ) - - Comp.ItemDetail.NavNext -> - case Comp.ItemList.nextItem model.itemListModel m2.item.id of - Just n -> - ( newModel, Cmd.batch [ newCmd, Api.itemDetail flags n.id ItemDetailResp ] ) - - Nothing -> - ( newModel, newCmd ) - - Comp.ItemDetail.NavNextOrBack -> - case Comp.ItemList.nextItem model.itemListModel m2.item.id of - Just n -> - ( newModel, Cmd.batch [ newCmd, Api.itemDetail flags n.id ItemDetailResp ] ) - - Nothing -> - doSearch flags newModel - - Comp.ItemDetail.NavNone -> - ( newModel, newCmd ) - - ItemDetailResp (Ok item) -> - let - m = - { model | viewMode = Detail } - in - update flags (ItemDetailMsg (Comp.ItemDetail.SetItem item)) m - - ItemDetailResp (Err _) -> - ( model, Cmd.none ) - doSearch : Flags -> Model -> ( Model, Cmd Msg ) doSearch flags model = diff --git a/modules/webapp/src/main/elm/Page/Home/View.elm b/modules/webapp/src/main/elm/Page/Home/View.elm index 046a511a..c9928db5 100644 --- a/modules/webapp/src/main/elm/Page/Home/View.elm +++ b/modules/webapp/src/main/elm/Page/Home/View.elm @@ -42,7 +42,7 @@ view model = Html.map ItemListMsg (Comp.ItemList.view model.itemListModel) Detail -> - Html.map ItemDetailMsg (Comp.ItemDetail.view model.itemDetailModel) + div [] [] ] ] diff --git a/modules/webapp/src/main/elm/Page/ItemDetail/Data.elm b/modules/webapp/src/main/elm/Page/ItemDetail/Data.elm new file mode 100644 index 00000000..b1f150d9 --- /dev/null +++ b/modules/webapp/src/main/elm/Page/ItemDetail/Data.elm @@ -0,0 +1,22 @@ +module Page.ItemDetail.Data exposing (Model, Msg(..), emptyModel) + +import Api.Model.ItemDetail exposing (ItemDetail) +import Comp.ItemDetail +import Http + + +type alias Model = + { detail : Comp.ItemDetail.Model + } + + +emptyModel : Model +emptyModel = + { detail = Comp.ItemDetail.emptyModel + } + + +type Msg + = Init String + | ItemDetailMsg Comp.ItemDetail.Msg + | ItemResp (Result Http.Error ItemDetail) diff --git a/modules/webapp/src/main/elm/Page/ItemDetail/Update.elm b/modules/webapp/src/main/elm/Page/ItemDetail/Update.elm new file mode 100644 index 00000000..c411e14d --- /dev/null +++ b/modules/webapp/src/main/elm/Page/ItemDetail/Update.elm @@ -0,0 +1,39 @@ +module Page.ItemDetail.Update exposing (update) + +import Api +import Browser.Navigation as Nav +import Comp.ItemDetail +import Data.Flags exposing (Flags) +import Page.ItemDetail.Data exposing (Model, Msg(..)) + + +update : Nav.Key -> Flags -> Maybe String -> Msg -> Model -> ( Model, Cmd Msg ) +update key flags next msg model = + case msg of + Init id -> + let + ( lm, lc ) = + Comp.ItemDetail.update key flags next Comp.ItemDetail.Init model.detail + in + ( { model | detail = lm } + , Cmd.batch [ Api.itemDetail flags id ItemResp, Cmd.map ItemDetailMsg lc ] + ) + + ItemDetailMsg lmsg -> + let + ( lm, lc ) = + Comp.ItemDetail.update key flags next lmsg model.detail + in + ( { model | detail = lm } + , Cmd.map ItemDetailMsg lc + ) + + ItemResp (Ok item) -> + let + lmsg = + Comp.ItemDetail.SetItem item + in + update key flags next (ItemDetailMsg lmsg) model + + ItemResp (Err err) -> + ( model, Cmd.none ) diff --git a/modules/webapp/src/main/elm/Page/ItemDetail/View.elm b/modules/webapp/src/main/elm/Page/ItemDetail/View.elm new file mode 100644 index 00000000..f86dd571 --- /dev/null +++ b/modules/webapp/src/main/elm/Page/ItemDetail/View.elm @@ -0,0 +1,19 @@ +module Page.ItemDetail.View exposing (view) + +import Comp.ItemDetail +import Html exposing (..) +import Html.Attributes exposing (..) +import Page.ItemDetail.Data exposing (Model, Msg(..)) + + +type alias ItemNav = + { prev : Maybe String + , next : Maybe String + } + + +view : ItemNav -> Model -> Html Msg +view inav model = + div [ class "ui fluid container item-detail-page" ] + [ Html.map ItemDetailMsg (Comp.ItemDetail.view inav model.detail) + ] diff --git a/modules/webapp/src/main/webjar/docspell.css b/modules/webapp/src/main/webjar/docspell.css index 9a57643d..24205b67 100644 --- a/modules/webapp/src/main/webjar/docspell.css +++ b/modules/webapp/src/main/webjar/docspell.css @@ -59,6 +59,12 @@ background: aliceblue; } +.default-layout .ui.fluid.container.item-detail-page { + padding-top: 1em; + padding-left: 1em; + padding-right: 1em; +} + .ui.search.dropdown.open { z-index: 20; }