Show item detail for a shared item

This commit is contained in:
eikek
2021-10-07 22:02:31 +02:00
parent 006791deb4
commit 7cbdf919f4
18 changed files with 458 additions and 57 deletions

View File

@ -5,7 +5,7 @@
-}
module Page.Share.Data exposing (Mode(..), Model, Msg(..), PageError(..), init)
module Page.Share.Data exposing (Mode(..), Model, Msg(..), PageError(..), init, initCmd)
import Api
import Api.Model.ItemLightList exposing (ItemLightList)
@ -41,6 +41,7 @@ type alias Model =
, powerSearchInput : Comp.PowerSearchInput.Model
, searchInProgress : Bool
, itemListModel : Comp.ItemCardList.Model
, initialized : Bool
}
@ -54,17 +55,27 @@ emptyModel flags =
, powerSearchInput = Comp.PowerSearchInput.init
, searchInProgress = False
, itemListModel = Comp.ItemCardList.init
, initialized = False
}
init : Maybe String -> Flags -> ( Model, Cmd Msg )
init shareId flags =
let
em =
emptyModel flags
in
case shareId of
Just id ->
( emptyModel flags, Api.verifyShare flags (ShareSecret id Nothing) VerifyResp )
( { em | initialized = True }, Api.verifyShare flags (ShareSecret id Nothing) VerifyResp )
Nothing ->
( emptyModel flags, Cmd.none )
( em, Cmd.none )
initCmd : String -> Flags -> Cmd Msg
initCmd shareId flags =
Api.verifyShare flags (ShareSecret shareId Nothing) VerifyResp
type Msg

View File

@ -42,13 +42,18 @@ viewContent texts flags versionInfo uiSettings shareId model =
ModeInitial ->
div
[ id "content"
, class "h-full w-full flex flex-col text-5xl"
, class "h-full w-full flex flex-col"
, class S.content
]
[ B.loadingDimmer
{ active = model.pageError == PageErrorNone
, label = ""
}
[ div [ class " text-5xl" ]
[ B.loadingDimmer
{ active = model.pageError == PageErrorNone
, label = ""
}
]
, div [ class "my-4 text-lg" ]
[ errorMessage texts model
]
]
ModePassword ->
@ -76,10 +81,28 @@ mainContent texts flags settings shareId model =
[ text <| Maybe.withDefault "" model.verifyResult.name
]
, Menubar.view texts model
, errorMessage texts model
, Results.view texts settings flags shareId model
]
errorMessage : Texts -> Model -> Html Msg
errorMessage texts model =
case model.pageError of
PageErrorNone ->
span [ class "hidden" ] []
PageErrorAuthFail ->
div [ class S.errorMessage ]
[ text texts.authFailed
]
PageErrorHttp err ->
div [ class S.errorMessage ]
[ text (texts.httpError err)
]
passwordContent : Texts -> Flags -> VersionInfo -> Model -> Html Msg
passwordContent texts flags versionInfo model =
div

View File

@ -5,6 +5,7 @@ import Api.Model.ItemDetail exposing (ItemDetail)
import Api.Model.ShareSecret exposing (ShareSecret)
import Api.Model.ShareVerifyResult exposing (ShareVerifyResult)
import Comp.SharePasswordForm
import Comp.UrlCopy
import Data.Flags exposing (Flags)
import Http
@ -27,6 +28,8 @@ type alias Model =
, passwordModel : Comp.SharePasswordForm.Model
, viewMode : ViewMode
, pageError : PageError
, attachMenuOpen : Bool
, visibleAttach : Int
}
@ -34,6 +37,9 @@ type Msg
= VerifyResp (Result Http.Error ShareVerifyResult)
| GetItemResp (Result Http.Error ItemDetail)
| PasswordMsg Comp.SharePasswordForm.Msg
| SelectActiveAttachment Int
| ToggleSelectAttach
| UrlCopyMsg Comp.UrlCopy.Msg
emptyModel : ViewMode -> Model
@ -43,14 +49,18 @@ emptyModel vm =
, passwordModel = Comp.SharePasswordForm.init
, viewMode = vm
, pageError = PageErrorNone
, attachMenuOpen = False
, visibleAttach = 0
}
init : Maybe ( String, String ) -> Flags -> ( Model, Cmd Msg )
init mids flags =
case mids of
Just ( shareId, _ ) ->
( emptyModel ViewLoading, Api.verifyShare flags (ShareSecret shareId Nothing) VerifyResp )
Just ( shareId, itemId ) ->
( emptyModel ViewLoading
, Api.verifyShare flags (ShareSecret shareId Nothing) VerifyResp
)
Nothing ->
( emptyModel ViewLoading, Cmd.none )

View File

@ -2,7 +2,9 @@ module Page.ShareDetail.Update exposing (update)
import Api
import Comp.SharePasswordForm
import Comp.UrlCopy
import Data.Flags exposing (Flags)
import Page exposing (Page(..))
import Page.ShareDetail.Data exposing (..)
@ -36,12 +38,16 @@ update shareId itemId flags msg model =
( { model | pageError = PageErrorHttp err }, Cmd.none )
GetItemResp (Ok item) ->
let
url =
Page.pageToString (ShareDetailPage shareId itemId)
in
( { model
| item = item
, viewMode = ViewNormal
, pageError = PageErrorNone
}
, Cmd.none
, Comp.UrlCopy.initCopy url
)
GetItemResp (Err err) ->
@ -62,3 +68,21 @@ update shareId itemId flags msg model =
Nothing ->
( { model | passwordModel = m }, Cmd.map PasswordMsg c )
SelectActiveAttachment pos ->
( { model
| visibleAttach = pos
, attachMenuOpen = False
}
, Cmd.none
)
ToggleSelectAttach ->
( { model | attachMenuOpen = not model.attachMenuOpen }, Cmd.none )
UrlCopyMsg lm ->
let
cmd =
Comp.UrlCopy.update lm
in
( model, cmd )

View File

@ -1,30 +1,41 @@
module Page.ShareDetail.View exposing (viewContent, viewSidebar)
import Api
import Api.Model.Attachment exposing (Attachment)
import Api.Model.VersionInfo exposing (VersionInfo)
import Comp.Basic as B
import Comp.SharePasswordForm
import Comp.UrlCopy
import Data.Fields
import Data.Flags exposing (Flags)
import Data.Icons as Icons
import Data.ItemTemplate as IT exposing (ItemTemplate)
import Data.UiSettings exposing (UiSettings)
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (onClick)
import Messages.Page.ShareDetail exposing (Texts)
import Page exposing (Page(..))
import Page.ShareDetail.Data exposing (..)
import Styles as S
import Util.CustomField
import Util.Item
import Util.List
import Util.Size
import Util.String
viewSidebar : Texts -> Bool -> Flags -> UiSettings -> Model -> Html Msg
viewSidebar texts visible flags settings model =
viewSidebar : Texts -> Bool -> Flags -> UiSettings -> String -> String -> Model -> Html Msg
viewSidebar texts visible flags settings shareId itemId model =
div
[ id "sidebar"
, class "hidden"
, classList [ ( "hidden", not visible ) ]
, class S.sidebar
]
[ div [ class "pt-2" ]
[ itemData texts flags model shareId itemId
]
]
[]
viewContent : Texts -> Flags -> UiSettings -> VersionInfo -> String -> String -> Model -> Html Msg
@ -36,10 +47,15 @@ viewContent texts flags uiSettings versionInfo shareId itemId model =
, class "h-full w-full flex flex-col text-5xl"
, class S.content
]
[ B.loadingDimmer
{ active = model.pageError == PageErrorNone
, label = ""
}
[ div [ class "text-5xl" ]
[ B.loadingDimmer
{ active = model.pageError == PageErrorNone
, label = ""
}
]
, div [ class "my-4 text-lg" ]
[ errorMessage texts model
]
]
ViewPassword ->
@ -60,18 +76,18 @@ mainContent texts flags settings shareId model =
, class S.content
]
[ itemHead texts shareId model
, div [ class "flex flex-col sm:flex-row sm:space-x-4 relative h-full" ]
[ itemData texts model
, itemPreview texts flags settings model
, errorMessage texts model
, div [ class "relative h-full" ]
[ itemPreview texts flags settings model
]
]
itemData : Texts -> Model -> Html Msg
itemData texts model =
itemData : Texts -> Flags -> Model -> String -> String -> Html Msg
itemData texts flags model shareId itemId =
let
boxStyle =
"mb-4 sm:mb-6 max-w-sm"
"mb-4 sm:mb-6"
headerStyle =
"py-2 bg-blue-50 hover:bg-blue-100 dark:bg-bluegray-700 dark:hover:bg-opacity-100 dark:hover:bg-bluegray-600 text-lg font-medium rounded-lg"
@ -92,11 +108,11 @@ itemData texts model =
]
Nothing
in
div [ class "flex flex-col pr-2 sm:w-1/3" ]
div [ class "flex flex-col" ]
[ div [ class boxStyle ]
[ div [ class headerStyle ]
[ Icons.dateIcon2 "mr-2 ml-2"
, text "Date"
, text (texts.field Data.Fields.Date)
]
, div [ class "text-lg ml-2" ]
[ Util.Item.toItemLight model.item
@ -104,10 +120,24 @@ itemData texts model =
|> text
]
]
, div
[ class boxStyle
, classList [ ( "hidden", model.item.dueDate == Nothing ) ]
]
[ div [ class headerStyle ]
[ Icons.dueDateIcon2 "mr-2 ml-2"
, text (texts.field Data.Fields.DueDate)
]
, div [ class "text-lg ml-2" ]
[ Util.Item.toItemLight model.item
|> IT.render IT.dueDateLong (templateCtx texts)
|> text
]
]
, div [ class boxStyle ]
[ div [ class headerStyle ]
[ Icons.tagsIcon2 "mr-2 ml-2"
, text "Tags & Fields"
, text texts.tagsAndFields
]
, div [ class "flex flex-row items-center flex-wrap font-medium my-1" ]
(List.map showTag model.item.tags ++ List.map showField model.item.customfields)
@ -115,7 +145,7 @@ itemData texts model =
, div [ class boxStyle ]
[ div [ class headerStyle ]
[ Icons.correspondentIcon2 "mr-2 ml-2"
, text "Correspondent"
, text texts.basics.correspondent
]
, div [ class "text-lg ml-2" ]
[ Util.Item.toItemLight model.item
@ -126,7 +156,7 @@ itemData texts model =
, div [ class boxStyle ]
[ div [ class headerStyle ]
[ Icons.concernedIcon2 "mr-2 ml-2"
, text "Concerning"
, text texts.basics.concerning
]
, div [ class "text-lg ml-2" ]
[ Util.Item.toItemLight model.item
@ -134,40 +164,110 @@ itemData texts model =
|> text
]
]
, div [ class boxStyle ]
[ div [ class headerStyle ]
[ i [ class "fa fa-copy mr-2 ml-2" ] []
, text "Copy URL"
]
, div [ class "flex flex-col items-center py-2" ]
[ Html.map UrlCopyMsg
(Comp.UrlCopy.view
(flags.config.baseUrl
++ Page.pageToString
(ShareDetailPage shareId itemId)
)
)
]
]
]
itemPreview : Texts -> Flags -> UiSettings -> Model -> Html Msg
itemPreview texts flags settings model =
let
id =
List.head model.item.attachments
|> Maybe.map .id
|> Maybe.withDefault ""
attach =
Util.List.get model.item.attachments model.visibleAttach
|> Maybe.withDefault Api.Model.Attachment.empty
attachName =
Maybe.withDefault (texts.noName ++ ".pdf") attach.name
in
div
[ class "flex flex-grow"
, style "min-height" "500px"
[ class "flex flex-grow flex-col h-full border-t dark:border-bluegray-600"
]
[ embed
[ src (Data.UiSettings.pdfUrl settings flags (Api.shareFileURL id))
, class " h-full w-full mx-0 py-0"
[ div [ class "flex flex-col sm:flex-row items-center py-1 px-1 border-l border-r dark:border-bluegray-600" ]
[ div [ class "text-base font-bold flex-grow w-full text-center sm:text-left break-all" ]
[ text attachName
, text " ("
, text (Util.Size.bytesReadable Util.Size.B (toFloat attach.size))
, text ")"
]
, div [ class "flex flex-row space-x-2" ]
[ B.secondaryBasicButton
{ label = ""
, icon = "fa fa-eye"
, disabled = False
, handler = href (Api.shareFileURL attach.id)
, attrs =
[ target "_new"
]
}
, B.secondaryBasicButton
{ label = ""
, icon = "fa fa-download"
, disabled = False
, handler = href (Api.shareFileURL attach.id)
, attrs =
[ download attachName
]
}
, B.secondaryBasicButton
{ label = ""
, icon = "fa fa-ellipsis-v"
, disabled = False
, handler = onClick ToggleSelectAttach
, attrs =
[ href "#"
, classList [ ( "hidden", List.length model.item.attachments <= 1 ) ]
]
}
]
]
, attachmentSelect texts model
, div
[ class "flex w-full h-full mb-4 border-b border-l border-r dark:border-bluegray-600"
, style "min-height" "500px"
]
[ embed
[ src (Data.UiSettings.pdfUrl settings flags (Api.shareFileURL attach.id))
, class " h-full w-full mx-0 py-0"
]
[]
]
[]
]
itemHead : Texts -> String -> Model -> Html Msg
itemHead texts shareId model =
div [ class "flex flex-col sm:flex-row" ]
div [ class "flex flex-col sm:flex-row mt-1" ]
[ div [ class "flex flex-grow items-center" ]
[ h1 [ class S.header1 ]
[ h1
[ class S.header1
, class "items-center flex flex-row"
]
[ text model.item.name
, span
[ classList [ ( "hidden", model.item.state /= "created" ) ]
, class S.blueBasicLabel
, class "inline ml-4 text-sm"
]
[ text texts.unconfirmed
]
]
]
, div [ class "flex flex-row items-center justify-end mb-2 sm:mb-0" ]
[ B.secondaryBasicButton
{ label = "Close"
{ label = texts.basics.back
, icon = "fa fa-times"
, disabled = False
, handler = Page.href (SharePage shareId)
@ -189,6 +289,83 @@ passwordContent texts flags versionInfo model =
]
attachmentSelect : Texts -> Model -> Html Msg
attachmentSelect texts model =
div
[ class "flex flex-row border-l border-t border-r px-2 py-2 dark:border-bluegray-600 "
, class "overflow-x-auto overflow-y-none"
, classList
[ ( "hidden", not model.attachMenuOpen )
]
]
(List.indexedMap (menuItem texts model) model.item.attachments)
menuItem : Texts -> Model -> Int -> Attachment -> Html Msg
menuItem texts model pos attach =
let
iconClass =
"fa fa-circle ml-1"
visible =
model.visibleAttach == pos
in
a
[ classList <|
[ ( "border-blue-500 dark:border-lightblue-500", pos == 0 )
, ( "dark:border-bluegray-600", pos /= 0 )
]
, class "flex flex-col relative border rounded px-1 py-1 mr-2"
, class " hover:shadow dark:hover:border-bluegray-500"
, href "#"
, onClick (SelectActiveAttachment pos)
]
[ div
[ classList
[ ( "hidden", not visible )
]
, class "absolute right-1 top-1 text-blue-400 dark:text-lightblue-400 text-xl"
]
[ i [ class iconClass ] []
]
, div [ class "flex-grow" ]
[ img
[ src (Api.shareAttachmentPreviewURL attach.id)
, class "block w-20 mx-auto"
]
[]
]
, div [ class "mt-1 text-sm break-all w-28 text-center" ]
[ Maybe.map (Util.String.ellipsis 36) attach.name
|> Maybe.withDefault texts.noName
|> text
]
]
errorMessage : Texts -> Model -> Html Msg
errorMessage texts model =
case model.pageError of
PageErrorNone ->
span [ class "hidden" ] []
PageErrorAuthFail ->
div
[ class S.errorMessage
, class "my-4"
]
[ text texts.authFailed
]
PageErrorHttp err ->
div
[ class S.errorMessage
, class "my-4"
]
[ text (texts.httpError err)
]
templateCtx : Texts -> IT.TemplateContext
templateCtx texts =
{ dateFormatLong = texts.formatDateLong