Skip to content

Commit 3869047

Browse files
committed
Add IconButton, user is signed out when token expires
1 parent 1084331 commit 3869047

File tree

12 files changed

+263
-37
lines changed

12 files changed

+263
-37
lines changed

src/Components/Button.elm

+15
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ module Components.Button exposing
22
( Button, new
33
, view
44
, withOnClick, withHref
5+
, withId
56
, withStyleSecondary
67
, withIcon
78
)
@@ -12,6 +13,7 @@ module Components.Button exposing
1213
@docs view
1314
1415
@docs withOnClick, withHref
16+
@docs withId
1517
@docs withStyleSecondary
1618
1719
-}
@@ -30,6 +32,7 @@ import Html.Events
3032
type Button msg
3133
= Button
3234
{ label : String
35+
, id : Maybe String
3336
, onClick : Maybe (Action msg)
3437
, style : Style
3538
, icon : Maybe Icon
@@ -55,6 +58,7 @@ new props =
5558
Button
5659
{ label = props.label
5760
, onClick = Nothing
61+
, id = Nothing
5862
, style = Primary
5963
, icon = Nothing
6064
}
@@ -79,6 +83,11 @@ withHref url (Button props) =
7983
Button { props | onClick = Just (OpenUrl url) }
8084

8185

86+
withId : String -> Button msg -> Button msg
87+
withId id (Button props) =
88+
Button { props | id = Just id }
89+
90+
8291
withIcon : Icon -> Button msg -> Button msg
8392
withIcon icon (Button props) =
8493
Button { props | icon = Just icon }
@@ -97,6 +106,12 @@ view (Button props) =
97106

98107
else
99108
Attr.classList []
109+
, case props.id of
110+
Just id ->
111+
Attr.id id
112+
113+
Nothing ->
114+
Attr.classList []
100115
]
101116
[ case props.icon of
102117
Just icon ->

src/Components/Dialog.elm

+8-10
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ module Components.Dialog exposing
1717

1818
import Components.Button
1919
import Components.Icon
20+
import Components.IconButton
2021
import Css
2122
import Html exposing (..)
2223
import Html.Attributes as Attr
@@ -94,16 +95,11 @@ view (Dialog props) =
9495
viewCloseButton : Html msg
9596
viewCloseButton =
9697
form [ Attr.method "dialog" ]
97-
[ button
98-
[ Css.pad_8
99-
, Css.border
100-
, Css.radius_8
101-
, Css.bg_background
102-
, Css.controls
103-
, Attr.attribute "aria-label" "Close dialog"
104-
]
105-
[ Components.Icon.view16 Components.Icon.Close
106-
]
98+
[ Components.IconButton.new
99+
{ label = "Close dialog"
100+
, icon = Components.Icon.Close
101+
}
102+
|> Components.IconButton.view
107103
]
108104
in
109105
node "dialog"
@@ -127,7 +123,9 @@ view (Dialog props) =
127123
, Css.border
128124
, Css.radius_16
129125
, Css.pad_32
126+
, Css.gap_32
130127
]
131128
[ viewHeader
129+
, div [ Css.fill ] props.content
132130
]
133131
]

src/Components/EmptyState.elm

+9-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import Svg.Attributes
88

99

1010
viewCreateYourFirstProject :
11-
{ onClick : msg
11+
{ id : String
12+
, onClick : msg
1213
}
1314
-> Html msg
1415
viewCreateYourFirstProject props =
@@ -18,6 +19,7 @@ viewCreateYourFirstProject props =
1819
, subtitle = "Welcome to Jangle! Let's get started by connecting to any existing GitHub repository."
1920
, button =
2021
{ label = "Create new project"
22+
, id = props.id
2123
, onClick = props.onClick
2224
}
2325
}
@@ -31,7 +33,11 @@ viewEmptyStateWithOptions :
3133
{ image : Html msg
3234
, title : String
3335
, subtitle : String
34-
, button : { label : String, onClick : msg }
36+
, button :
37+
{ id : String
38+
, label : String
39+
, onClick : msg
40+
}
3541
}
3642
-> Html msg
3743
viewEmptyStateWithOptions props =
@@ -58,6 +64,7 @@ viewEmptyStateWithOptions props =
5864
]
5965
, Components.Button.new { label = props.button.label }
6066
|> Components.Button.withOnClick props.button.onClick
67+
|> Components.Button.withId props.button.id
6168
|> Components.Button.view
6269
]
6370

src/Components/IconButton.elm

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
module Components.IconButton exposing
2+
( IconButton, new
3+
, withOnClick
4+
, view
5+
)
6+
7+
{-|
8+
9+
@docs IconButton, new
10+
@docs withOnClick
11+
12+
@docs view
13+
14+
-}
15+
16+
import Components.Icon exposing (Icon)
17+
import Css
18+
import Html exposing (..)
19+
import Html.Attributes as Attr
20+
import Html.Events
21+
22+
23+
type IconButton msg
24+
= IconButton
25+
{ label : String
26+
, icon : Icon
27+
, onClick : Maybe msg
28+
}
29+
30+
31+
new : { label : String, icon : Icon } -> IconButton msg
32+
new props =
33+
IconButton
34+
{ label = props.label
35+
, icon = props.icon
36+
, onClick = Nothing
37+
}
38+
39+
40+
withOnClick : msg -> IconButton msg -> IconButton msg
41+
withOnClick onClick (IconButton props) =
42+
IconButton { props | onClick = Just onClick }
43+
44+
45+
view : IconButton msg -> Html msg
46+
view (IconButton props) =
47+
button
48+
[ Css.pad_8
49+
, Css.border
50+
, Css.radius_8
51+
, Css.bg_background
52+
, Css.controls
53+
, Attr.attribute "aria-label" props.label
54+
, case props.onClick of
55+
Just onClick ->
56+
Html.Events.onClick onClick
57+
58+
Nothing ->
59+
Attr.classList []
60+
]
61+
[ Components.Icon.view16 props.icon
62+
]

src/Effect.elm

+10-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ port module Effect exposing
44
, sendCmd, sendMsg
55
, pushRoute, replaceRoute, loadExternalUrl
66
, map, toCmd
7-
, saveOAuthResponse
7+
, saveOAuthResponse, clearOAuthResponse
88
, fetchSupabaseUser
99
, showDialog
1010
)
@@ -21,7 +21,7 @@ port module Effect exposing
2121
2222
## Custom effects
2323
24-
@docs saveOAuthResponse
24+
@docs saveOAuthResponse, clearOAuthResponse
2525
@docs fetchSupabaseUser
2626
2727
-}
@@ -145,6 +145,14 @@ saveOAuthResponse oauthResponse =
145145
}
146146

147147

148+
clearOAuthResponse : Effect msg
149+
clearOAuthResponse =
150+
Save
151+
{ key = "oAuthResponse"
152+
, value = Json.Encode.null
153+
}
154+
155+
148156

149157
-- SUPABASE
150158

src/Pages/Home_.elm

+40-5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ module Pages.Home_ exposing (..)
22

33
import Auth
44
import Components.Button
5+
import Components.Dialog
56
import Components.EmptyState
67
import Components.Icon
78
import Components.Layout
@@ -24,7 +25,7 @@ page user shared route =
2425
{ init = init
2526
, update = update
2627
, subscriptions = subscriptions
27-
, view = view route.path
28+
, view = view user
2829
}
2930
|> Page.withLayout
3031
(\_ ->
@@ -64,7 +65,7 @@ update msg model =
6465
case msg of
6566
ClickedCreateFirstProject ->
6667
( { model | isDialogOpen = True }
67-
, Effect.none
68+
, Effect.showDialog { id = ids.createProjectDialog }
6869
)
6970

7071

@@ -81,15 +82,49 @@ subscriptions model =
8182
-- VIEW
8283

8384

84-
view : Path -> Model -> View Msg
85-
view path model =
85+
ids :
86+
{ createProjectDialog : String
87+
, createFirstProjectButton : String
88+
}
89+
ids =
90+
{ createProjectDialog = "dialog__create-project"
91+
, createFirstProjectButton = "button__create-first-project"
92+
}
93+
94+
95+
view : Auth.User -> Model -> View Msg
96+
view user model =
8697
{ title = "Jangle | Dashboard"
8798
, body =
8899
[ div [ Css.col, Css.fill, Css.align_center ]
89100
[ Components.EmptyState.viewCreateYourFirstProject
90-
{ onClick = ClickedCreateFirstProject
101+
{ id = ids.createFirstProjectButton
102+
, onClick = ClickedCreateFirstProject
91103
}
92104
, div [ Css.h_96 ] []
93105
]
106+
, Components.Dialog.new
107+
{ title = "Create a project"
108+
, content =
109+
[ div [ Css.col, Css.gap_12, Css.sidebar_link, Css.color_textSecondary ]
110+
[ p [ Css.line_140 ]
111+
[ text
112+
("Hey ${name}! 👋 This form isn't quite ready yet..."
113+
|> String.replace "${name}"
114+
(String.split " " user.name
115+
|> List.head
116+
|> Maybe.withDefault user.name
117+
)
118+
)
119+
]
120+
, p [ Css.line_140 ]
121+
[ text "Try hitting the ESC key or clicking the \"X\" icon in the top-right corner!"
122+
]
123+
]
124+
]
125+
}
126+
|> Components.Dialog.withSubtitle "Connect to an existing GitHub repository"
127+
|> Components.Dialog.withId ids.createProjectDialog
128+
|> Components.Dialog.view
94129
]
95130
}

src/Shared.elm

+2-2
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,8 @@ update : Route () -> Msg -> Model -> ( Model, Effect Msg )
100100
update route msg model =
101101
case msg of
102102
Shared.Msg.SupabaseUserApiResponded (Err httpError) ->
103-
( model
104-
, Effect.none
103+
( { model | user = Auth.User.NotSignedIn }
104+
, Effect.clearOAuthResponse
105105
-- |> Debug.log "TODO: Report this error to Sentry"
106106
)
107107

src/Stories/EmptyState.elm

+9-6
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,7 @@ decoder =
1919
{ id = "variant"
2020
, options =
2121
[ ( "CreateYourFirstProject"
22-
, Components.EmptyState.viewCreateYourFirstProject
23-
{ onClick = ClickedCreateNewProject
24-
}
22+
, viewCreateYourFirstProject
2523
)
2624
]
2725
}
@@ -50,6 +48,11 @@ view controls =
5048
viewSelectedEmptyState
5149

5250
Nothing ->
53-
Components.EmptyState.viewCreateYourFirstProject
54-
{ onClick = ClickedCreateNewProject
55-
}
51+
viewCreateYourFirstProject
52+
53+
54+
viewCreateYourFirstProject =
55+
Components.EmptyState.viewCreateYourFirstProject
56+
{ id = "button__create-first-project"
57+
, onClick = ClickedCreateNewProject
58+
}

0 commit comments

Comments
 (0)