-
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
-
104
-
105
-
106
-
107
-
108
-
109
-
110
-
111
-
112
-
113
-
114
-
115
-
116
-
117
-
118
-
119
-
120
-
121
-
122
-
123
-
124
-
125
-
126
-
127
-
128
-
129
-
130
-
131
-
132
-
133
-
134
-
135
-
136
-
137
-
138
-
139
-
140
-
141
-
142
-
143
-
144
-
145
-
146
-
147
-
148
-
149
-
150
-
151
-
152
-
153
-
154
-
155
-
156
-
157
-
158
-
159
-
160
-
161
-
162
-
163
-
164
-
165
-
166
-
167
-
168
-
169
-
170
-
171
-
172
-
173
-
174
-
175
-
176
-
177
-
178
-
179
-
180
-
181
-
182
-
183
-
184
-
185
-
186
-
187
-
188
-
189
-
190
-
191
-
192
-
193
-
194
-
195
-
196
-
197
-
198
-
199
-
200
-
201
-
202
-
203
-
204
-
205
-
206
-
207
-
208
-
209
-
210
-
211
-
212
-
213
-
214
-
215
-
216
-
217
-
218
-
219
-
220
-
221
-
222
-
223
-
224
-
225
-
226
-
227
-
228
-
229
-
230
-
231
-
232
-
233
-
234
-
235
-
236
-- SPDX-License-Identifier: AGPL-3.0-only
-- Copyright 2026 Shota FUJI
--
-- This program is free software: you can redistribute it and/or modify it under the terms
-- of the GNU Affero General Public License as published by the Free Software Foundation,
-- either version 3 of the License, or (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful, but WITHOUT ANY
-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-- PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
--
-- You should have received a copy of the GNU Affero General Public License along
-- with this program. If not, see <http://www.gnu.org/licenses/>.
module Main exposing (main)
import Browser
import Browser.Navigation
import Html exposing (text)
import Html.Attributes exposing (href, style)
import Url
import Url.Parser
main : Program Flags Model Msg
main =
Browser.application
{ init = init
, view = view
, update = update
, subscriptions = subscriptions
, onUrlChange = OnUrlChange
, onUrlRequest = OnUrlRequest
}
-- FLAGS
type alias Flags =
()
-- MODEL
type Editability
= Readonly
| ReadWrite
type EmployerRole
= RegularEmployer
| Admin
type Route
= DemoIndex
| WorkerHome Editability
| EmployerHome EmployerRole
| NotFound
routeParser : Url.Parser.Parser (Route -> a) a
routeParser =
Url.Parser.oneOf
[ Url.Parser.map DemoIndex Url.Parser.top
, Url.Parser.map (WorkerHome Readonly) (Url.Parser.s "worker")
, Url.Parser.map (WorkerHome ReadWrite) (Url.Parser.s "worker-mutable")
, Url.Parser.map (EmployerHome RegularEmployer) (Url.Parser.s "employer")
, Url.Parser.map (EmployerHome Admin) (Url.Parser.s "admin")
]
type alias Model =
{ route : Route
, key : Browser.Navigation.Key
}
init : Flags -> Url.Url -> Browser.Navigation.Key -> ( Model, Cmd Msg )
init _ url key =
( { route = Url.Parser.parse routeParser url |> Maybe.withDefault NotFound
, key = key
}
, Cmd.none
)
-- UPDATE
type Msg
= NoOp
| OnUrlChange Url.Url
| OnUrlRequest Browser.UrlRequest
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
OnUrlChange url ->
( { model
| route = Url.Parser.parse routeParser url |> Maybe.withDefault NotFound
}
, Cmd.none
)
OnUrlRequest (Browser.Internal url) ->
( model, Browser.Navigation.pushUrl model.key (Url.toString url) )
OnUrlRequest (Browser.External href) ->
( model, Browser.Navigation.load href )
NoOp ->
( model, Cmd.none )
-- VIEW
view : Model -> Browser.Document Msg
view model =
case model.route of
NotFound ->
{ title = "404 | Yamori デモ"
, body = [ Html.p [] [ text "存在しないページです" ] ]
}
WorkerHome editability ->
{ title = "労働者ホーム | Yamori デモ"
, body =
[ Html.h1 [] [ text "ようこそ、田中 太郎さん。" ]
, Html.p []
[ text "残り"
, Html.strong [ style "font-size" "1.5em" ] [ text "10" ]
, text "日の有給休暇が利用可能です。"
]
, Html.p []
[ text "労働基準法により、"
, Html.strong [] [ text "2026/02/01" ]
, text "までに"
, Html.strong [ style "font-size" "1.5em" ] [ text "3" ]
, text "日の有給休暇を"
, Html.mark [] [ text "利用する必要" ]
, text "があります。"
]
, Html.hr [] []
, Html.dl []
(case editability of
Readonly ->
[ Html.dt []
[ Html.a [ href "#" ] [ text "予定を確認する" ] ]
, Html.dd []
[ text "有給休暇の利用予定と実績を閲覧する画面に移動します。" ]
]
ReadWrite ->
[ Html.dt []
[ Html.a [ href "#" ] [ text "予定を確認する" ] ]
, Html.dd []
[ text "有給休暇の利用予定と実績の閲覧・編集画面に移動します。" ]
]
)
]
}
EmployerHome role ->
{ title =
(case role of
RegularEmployer ->
"使用者"
Admin ->
"管理者"
)
++ "ホーム | Yamori デモ"
, body =
let
baseMenus : List (Html.Html msg)
baseMenus =
[ Html.dt []
[ Html.a [ href "#" ] [ text "労働者の一覧を見る" ] ]
, Html.dd []
[ text "システムに登録されている労働者の閲覧や変更を行う画面に移動します。" ]
, Html.dt []
[ Html.a [ href "#" ] [ text "全体の予定と実績を確認する" ] ]
, Html.dd []
[ text "すべての労働者の予定と実績をまとめて確認できる画面に移動します。" ]
]
adminMenus : List (Html.Html msg)
adminMenus =
[ Html.dt []
[ Html.a [ href "#" ] [ text "カレンダーを読み込む" ] ]
, Html.dd []
[ text "スプレッドシート形式の勤怠データをシステムに反映します。" ]
]
in
[ Html.h1 [] [ text "株式会社XXX 有給休暇管理システム" ]
, Html.dl []
(case role of
Admin ->
baseMenus ++ adminMenus
_ ->
baseMenus
)
]
}
DemoIndex ->
{ title = "Yamori デモ 画面選択"
, body =
[ Html.ul []
[ Html.li [] [ Html.a [ href "/worker" ] [ text "労働者ホーム" ] ]
, Html.li [] [ Html.a [ href "/worker-mutable" ] [ text "労働者ホーム (編集権限あり)" ] ]
, Html.li [] [ Html.a [ href "/employer" ] [ text "使用者ホーム" ] ]
, Html.li [] [ Html.a [ href "/admin" ] [ text "管理者ホーム" ] ]
]
]
}
-- SUBSCRIPTIONS
subscriptions : Model -> Sub Msg
subscriptions _ =
Sub.none