feat: add pdf generation

This commit is contained in:
Patryk Hegenberg 2025-11-08 12:07:29 +01:00
parent bb891aea0b
commit d4265cc046
7 changed files with 245 additions and 5 deletions

View file

@ -1,19 +1,21 @@
{
"type": "application",
"source-directories": ["src"],
"source-directories": [
"src"
],
"elm-version": "0.19.1",
"dependencies": {
"direct": {
"elm/browser": "1.0.2",
"elm/bytes": "1.0.8",
"elm/core": "1.0.5",
"elm/file": "1.0.5",
"elm/html": "1.0.0",
"elm/http": "2.0.0",
"elm/json": "1.1.3",
"elm/time": "1.0.0"
},
"indirect": {
"elm/bytes": "1.0.8",
"elm/file": "1.0.5",
"elm/url": "1.0.0",
"elm/virtual-dom": "1.0.3"
}

View file

@ -1,7 +1,9 @@
port module Main exposing (..)
import Browser
import Bytes exposing (Bytes)
import Dict exposing (Dict)
import File.Download
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (..)
@ -430,6 +432,8 @@ type Msg
| SchoolYearActivated (Result Http.Error ())
| DeleteSchoolYear Int
| SchoolYearDeleted (Result Http.Error ())
| DownloadYearlySummaryPDF
| YearlySummaryPDFReceived (Result Http.Error Bytes.Bytes)
update : Msg -> Model -> ( Model, Cmd Msg )
@ -1631,6 +1635,29 @@ update msg model =
SchoolYearDeleted (Err _) ->
( { model | error = Just "Fehler beim Löschen" }, Cmd.none )
DownloadYearlySummaryPDF ->
case model.token of
Just token ->
( { model | isProcessing = True }, downloadYearlySummaryPDF token )
Nothing ->
( model, Cmd.none )
YearlySummaryPDFReceived (Ok pdfBytes) ->
let
filename =
"Jahresuebersicht_" ++ String.fromInt model.currentYear ++ ".pdf"
in
( { model | isProcessing = False }, File.Download.bytes filename "application/pdf" pdfBytes )
YearlySummaryPDFReceived (Err _) ->
( { model
| error = Just "Fehler beim Herunterladen der PDF"
, isProcessing = False
}
, Cmd.none
)
-- SUBSCRIPTIONS
@ -2606,7 +2633,35 @@ viewTimeEntriesTab model =
viewYearlyHoursSummary : Model -> Html Msg
viewYearlyHoursSummary model =
div [ class "box" ]
[ if List.isEmpty model.yearlyHoursSummary then
[ div [ class "level mb-4" ]
[ div [ class "level-left" ]
[ div [ class "level-item" ]
[ h3 [ class "subtitle is-5 mb-0" ] [ text "Jahresübersicht" ]
]
]
, div [ class "level-right" ]
[ div [ class "level-item" ]
[ a
[ class "button is-info"
, onClick DownloadYearlySummaryPDF
, disabled model.isProcessing
]
[ span [ class "icon" ]
[ i [ class "fas fa-file-pdf" ] [] ]
, span []
[ text
(if model.isProcessing then
"Wird erstellt..."
else
"PDF exportieren"
)
]
]
]
]
]
, if List.isEmpty model.yearlyHoursSummary then
p [ class "has-text-centered" ] [ text "Keine Daten vorhanden" ]
else
@ -2950,7 +3005,7 @@ viewWeekNavigation model =
, style "flex-direction" "column"
, style "align-items" "center"
, style "gap" "0.5rem"
, style "min-width" "250px" -- Verhindert Kompression
, style "min-width" "250px"
]
[ p
[ class "heading"
@ -4225,3 +4280,34 @@ schoolYearDecoder =
(field "start_date" string)
(field "end_date" string)
(field "is_active" bool)
downloadYearlySummaryPDF : String -> Cmd Msg
downloadYearlySummaryPDF token =
Http.request
{ method = "GET"
, headers = [ Http.header "Authorization" ("Bearer " ++ token) ]
, url = "/api/admin/yearly-summary/pdf"
, body = Http.emptyBody
, expect =
Http.expectBytesResponse YearlySummaryPDFReceived
(\response ->
case response of
Http.GoodStatus_ _ body ->
Ok body
Http.BadUrl_ url ->
Err (Http.BadUrl url)
Http.Timeout_ ->
Err Http.Timeout
Http.NetworkError_ ->
Err Http.NetworkError
Http.BadStatus_ metadata _ ->
Err (Http.BadStatus metadata.statusCode)
)
, timeout = Nothing
, tracker = Nothing
}