1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
module UVNList.Vote exposing (main)
-- XXX: There's some unobvious and unintuitive behavior when removing a vote:
-- If the VN isn't also in the user's 'vnlist', then the VN entry will be
-- removed from the user's list and this is only visible on a page refresh. A
-- clean solution to this is to merge the 'votes' and 'vnlist' tables so that
-- there's always a 'vnlist' entry that remains. This is best done after VNDBv2
-- has been decommissioned.
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (..)
import Json.Encode as JE
import Browser
import Regex
import Lib.Api as Api
import Lib.Gen as Gen
main : Program Flags Model Msg
main = Browser.element
{ init = \f -> (init f, Cmd.none)
, subscriptions = always Sub.none
, view = view
, update = update
}
type alias Flags =
{ uid : Int
, vid : Int
, vote : String
}
type alias Model =
{ state : Api.State
, flags : Flags
, text : String
, valid : Bool
}
init : Flags -> Model
init f =
{ state = Api.Normal
, flags = f
, text = f.vote
, valid = True
}
encodeForm : Model -> JE.Value
encodeForm o = JE.object
[ ("uid", JE.int o.flags.uid)
, ("vid", JE.int o.flags.vid)
, ("vote", JE.string o.text) ]
type Msg
= Input String
| Save
| Saved Api.Response
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
Input s ->
( { model | text = s
, valid = Regex.contains (Maybe.withDefault Regex.never <| Regex.fromString Gen.vnvotePattern) s
}
, Cmd.none
)
Save ->
if model.valid && model.text /= model.flags.vote
then ( { model | state = Api.Loading }
, Api.post "/u/setvote" (encodeForm model) Saved )
else (model, Cmd.none)
Saved Gen.Success ->
let flags = model.flags
nflags = { flags | vote = model.text }
in ({ model | flags = nflags, state = Api.Normal }, Cmd.none)
Saved e -> ({ model | state = Api.Error e }, Cmd.none)
view : Model -> Html Msg
view model =
-- TODO: Display error somewhere
-- TODO: Save when pressing enter
if model.state == Api.Loading
then
div [ class "spinner spinner--md" ] []
else
input
[ type_ "text"
, pattern Gen.vnvotePattern
, class "form-control form-control--table-edit form-control--stealth"
, classList [("is-invalid", not model.valid)]
, value model.text
, onInput Input
, onBlur Save
] []
|