all repos

onasty @ 1994b67e32437e92e474da9b4e4002c28a9bdcd2

a one-time notes service

onasty/web/src/Shared.elm (view raw)

Smirnov Oleksandr Smirnov Oleksandr
ss2316544@gmail.com
web: create note page (#144)..., 11 months ago
1
module Shared exposing
2
    ( Flags, decoder
3
    , Model, Msg
4
    , init, update, subscriptions
5
    )
6
7
{-|
8
9
@docs Flags, decoder
10
@docs Model, Msg
11
@docs init, update, subscriptions
12
13
-}
14
15
import Api.Auth
16
import Auth.User
17
import Data.Credentials exposing (Credentials)
18
import Dict
19
import Effect exposing (Effect)
20
import Json.Decode
21
import JwtUtil
22
import Route exposing (Route)
23
import Route.Path
24
import Shared.Model
25
import Shared.Msg
26
import Task
27
import Time
28
29
30
31
-- FLAGS
32
33
34
type alias Flags =
35
    { accessToken : Maybe String
36
    , refreshToken : Maybe String
37
    , appUrl : String
38
    }
39
40
41
decoder : Json.Decode.Decoder Flags
42
decoder =
43
    Json.Decode.map3 Flags
44
        (Json.Decode.field "access_token" (Json.Decode.maybe Json.Decode.string))
45
        (Json.Decode.field "refresh_token" (Json.Decode.maybe Json.Decode.string))
46
        (Json.Decode.field "app_url" Json.Decode.string)
47
48
49
50
-- INIT
51
52
53
type alias Model =
54
    Shared.Model.Model
55
56
57
init : Result Json.Decode.Error Flags -> Route () -> ( Model, Effect Msg )
58
init flagsResult _ =
59
    let
60
        flags : Flags
61
        flags =
62
            flagsResult |> Result.withDefault { accessToken = Nothing, refreshToken = Nothing, appUrl = "" }
63
64
        maybeCredentials : Maybe Credentials
65
        maybeCredentials =
66
            Maybe.map2
67
                (\access refresh -> { accessToken = access, refreshToken = refresh })
68
                flags.accessToken
69
                flags.refreshToken
70
71
        user : Auth.User.SignInStatus
72
        user =
73
            case maybeCredentials of
74
                Just credentials ->
75
                    Auth.User.SignedIn credentials
76
77
                Nothing ->
78
                    Auth.User.NotSignedIn
79
80
        initModel : Model
81
        initModel =
82
            { user = user
83
            , timeZone = Time.utc
84
            , appURL = flags.appUrl
85
            }
86
    in
87
    ( initModel
88
    , Effect.batch
89
        [ Time.now |> Task.perform Shared.Msg.CheckTokenExpiration |> Effect.sendCmd
90
        , Time.here |> Task.perform Shared.Msg.GotZone |> Effect.sendCmd
91
        ]
92
    )
93
94
95
96
-- UPDATE
97
98
99
type alias Msg =
100
    Shared.Msg.Msg
101
102
103
update : Route () -> Msg -> Model -> ( Model, Effect Msg )
104
update _ msg model =
105
    case msg of
106
        Shared.Msg.GotZone timeZone ->
107
            ( { model | timeZone = timeZone }, Effect.none )
108
109
        Shared.Msg.Logout ->
110
            ( { model | user = Auth.User.NotSignedIn }, Effect.clearUser )
111
112
        Shared.Msg.SignedIn credentials ->
113
            ( { model | user = Auth.User.SignedIn credentials }
114
            , Effect.batch
115
                [ Effect.pushRoute
116
                    { path = Route.Path.Home_
117
                    , query = Dict.empty
118
                    , hash = Nothing
119
                    }
120
                , Effect.saveUser credentials.accessToken credentials.refreshToken
121
                ]
122
            )
123
124
        Shared.Msg.CheckTokenExpiration now ->
125
            case model.user of
126
                Auth.User.SignedIn credentials ->
127
                    if JwtUtil.isExpired now credentials.accessToken then
128
                        ( model, Effect.refreshTokens )
129
130
                    else
131
                        ( model, Effect.none )
132
133
                _ ->
134
                    ( model, Effect.none )
135
136
        Shared.Msg.TriggerTokenRefresh ->
137
            case model.user of
138
                Auth.User.SignedIn credentials ->
139
                    ( { model | user = Auth.User.RefreshingTokens }
140
                    , Api.Auth.refreshToken
141
                        { onResponse = Shared.Msg.ApiRefreshTokensResponded
142
                        , refreshToken = credentials.refreshToken
143
                        }
144
                    )
145
146
                _ ->
147
                    ( model, Effect.none )
148
149
        Shared.Msg.ApiRefreshTokensResponded (Ok credentials) ->
150
            ( { model | user = Auth.User.SignedIn credentials }
151
            , Effect.saveUser credentials.accessToken credentials.refreshToken
152
            )
153
154
        Shared.Msg.ApiRefreshTokensResponded (Err _) ->
155
            ( { model | user = Auth.User.NotSignedIn }, Effect.clearUser )
156
157
158
159
-- SUBSCRIPTIONS
160
161
162
subscriptions : Route () -> Model -> Sub Msg
163
subscriptions _ _ =
164
    Time.every (30 * 1000) Shared.Msg.CheckTokenExpiration