all repos

onasty @ 6e28490

a one-time notes service

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

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