Skip to content

Commit

Permalink
Merge pull request #126 from levelhq/close-groups
Browse files Browse the repository at this point in the history
Close groups
  • Loading branch information
derrickreimer committed Nov 4, 2018
2 parents 43462e2 + 4eddfe2 commit 32dfd2f
Show file tree
Hide file tree
Showing 23 changed files with 779 additions and 34 deletions.
41 changes: 36 additions & 5 deletions assets/elm/src/Group.elm
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
module Group exposing (Group, decoder, fragment, id, isBookmarked, isPrivate, membershipState, name)
module Group exposing (Group, State(..), decoder, fragment, id, isBookmarked, isPrivate, membershipState, name, state)

import GraphQL exposing (Fragment)
import GroupMembership exposing (GroupMembershipState(..))
import Id exposing (Id)
import Json.Decode as Decode exposing (Decoder, bool, field, int, string)
import Json.Decode as Decode exposing (Decoder, bool, fail, field, int, string, succeed)



Expand All @@ -14,8 +14,14 @@ type Group
= Group Data


type State
= Open
| Closed


type alias Data =
{ id : Id
, state : State
, name : String
, isPrivate : Bool
, isBookmarked : Bool
Expand All @@ -30,6 +36,7 @@ fragment =
"""
fragment GroupFields on Group {
id
state
name
isPrivate
isBookmarked
Expand All @@ -51,6 +58,11 @@ id (Group data) =
data.id


state : Group -> State
state (Group data) =
data.state


name : Group -> String
name (Group data) =
data.name
Expand Down Expand Up @@ -78,17 +90,36 @@ membershipState (Group data) =
decoder : Decoder Group
decoder =
Decode.map Group <|
Decode.map6 Data
Decode.map7 Data
(field "id" Id.decoder)
(field "state" stateDecoder)
(field "name" string)
(field "isPrivate" bool)
(field "isBookmarked" bool)
stateDecoder
membershipStateDecoder
(field "fetchedAt" int)


stateDecoder : Decoder GroupMembershipState
stateDecoder : Decoder State
stateDecoder =
let
convert : String -> Decoder State
convert raw =
case raw of
"OPEN" ->
succeed Open

"CLOSED" ->
succeed Closed

_ ->
fail "State not valid"
in
Decode.andThen convert string


membershipStateDecoder : Decoder GroupMembershipState
membershipStateDecoder =
Decode.oneOf
[ Decode.at [ "membership", "state" ] GroupMembership.stateDecoder
, Decode.succeed NotSubscribed
Expand Down
56 changes: 56 additions & 0 deletions assets/elm/src/Mutation/CloseGroup.elm
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
module Mutation.CloseGroup exposing (Response(..), request)

import GraphQL exposing (Document)
import Group exposing (Group)
import Json.Decode as Decode exposing (Decoder)
import Json.Encode as Encode
import Session exposing (Session)
import Task exposing (Task)


type Response
= Success Group


document : Document
document =
GraphQL.toDocument
"""
mutation CloseGroup(
$spaceId: ID!,
$groupId: ID!
) {
closeGroup(
spaceId: $spaceId,
groupId: $groupId
) {
group {
...GroupFields
}
}
}
"""
[ Group.fragment
]


variables : String -> String -> Maybe Encode.Value
variables spaceId groupId =
Just <|
Encode.object
[ ( "spaceId", Encode.string spaceId )
, ( "groupId", Encode.string groupId )
]


decoder : Decoder Response
decoder =
Decode.map Success <|
Decode.at [ "data", "closeGroup", "group" ]
Group.decoder


request : String -> String -> Session -> Task Session.Error ( Session, Response )
request spaceId groupId session =
Session.request session <|
GraphQL.request document (variables spaceId groupId) decoder
56 changes: 56 additions & 0 deletions assets/elm/src/Mutation/ReopenGroup.elm
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
module Mutation.ReopenGroup exposing (Response(..), request)

import GraphQL exposing (Document)
import Group exposing (Group)
import Json.Decode as Decode exposing (Decoder)
import Json.Encode as Encode
import Session exposing (Session)
import Task exposing (Task)


type Response
= Success Group


document : Document
document =
GraphQL.toDocument
"""
mutation ReopenGroup(
$spaceId: ID!,
$groupId: ID!
) {
reopenGroup(
spaceId: $spaceId,
groupId: $groupId
) {
group {
...GroupFields
}
}
}
"""
[ Group.fragment
]


variables : String -> String -> Maybe Encode.Value
variables spaceId groupId =
Just <|
Encode.object
[ ( "spaceId", Encode.string spaceId )
, ( "groupId", Encode.string groupId )
]


decoder : Decoder Response
decoder =
Decode.map Success <|
Decode.at [ "data", "reopenGroup", "group" ]
Group.decoder


request : String -> String -> Session -> Task Session.Error ( Session, Response )
request spaceId groupId session =
Session.request session <|
GraphQL.request document (variables spaceId groupId) decoder
70 changes: 69 additions & 1 deletion assets/elm/src/Page/Group.elm
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ import Json.Decode as Decode
import KeyboardShortcuts
import ListHelpers exposing (insertUniqueBy, removeBy)
import Mutation.BookmarkGroup as BookmarkGroup
import Mutation.CloseGroup as CloseGroup
import Mutation.CreatePost as CreatePost
import Mutation.ReopenGroup as ReopenGroup
import Mutation.SubscribeToGroup as SubscribeToGroup
import Mutation.UnbookmarkGroup as UnbookmarkGroup
import Mutation.UnsubscribeFromGroup as UnsubscribeFromGroup
Expand Down Expand Up @@ -228,6 +230,10 @@ type Msg
| CollapseSearchEditor
| SearchEditorChanged String
| SearchSubmitted
| CloseClicked
| Closed (Result Session.Error ( Session, CloseGroup.Response ))
| ReopenClicked
| Reopened (Result Session.Error ( Session, ReopenGroup.Response ))


update : Msg -> Globals -> Model -> ( ( Model, Cmd Msg ), Globals )
Expand Down Expand Up @@ -596,6 +602,52 @@ update msg globals model =
in
( ( { model | searchEditor = newSearchEditor }, cmd ), globals )

CloseClicked ->
let
cmd =
globals.session
|> CloseGroup.request model.spaceId model.groupId
|> Task.attempt Closed
in
( ( model, cmd ), globals )

Closed (Ok ( newSession, CloseGroup.Success newGroup )) ->
let
newRepo =
globals.repo
|> Repo.setGroup newGroup
in
noCmd { globals | session = newSession, repo = newRepo } model

Closed (Err Session.Expired) ->
redirectToLogin globals model

Closed (Err _) ->
noCmd globals model

ReopenClicked ->
let
cmd =
globals.session
|> ReopenGroup.request model.spaceId model.groupId
|> Task.attempt Reopened
in
( ( model, cmd ), globals )

Reopened (Ok ( newSession, ReopenGroup.Success newGroup )) ->
let
newRepo =
globals.repo
|> Repo.setGroup newGroup
in
noCmd { globals | session = newSession, repo = newRepo } model

Reopened (Err Session.Expired) ->
redirectToLogin globals model

Reopened (Err _) ->
noCmd globals model


noCmd : Globals -> Model -> ( ( Model, Cmd Msg ), Globals )
noCmd globals model =
Expand Down Expand Up @@ -733,7 +785,15 @@ resolvedView repo maybeCurrentRoute spaceUsers model data =
, controlsView model
]
]
, newPostView model.spaceId model.postComposer data.viewer spaceUsers
, viewIf (Group.state data.group == Group.Open) <|
newPostView model.spaceId model.postComposer data.viewer spaceUsers
, viewIf (Group.state data.group == Group.Closed) <|
p [ class "flex items-center px-4 py-3 mb-4 bg-red-lightest border-b-2 border-red text-red font-extrabold" ]
[ div [ class "flex-grow" ] [ text "This group is closed." ]
, div [ class "flex-no-shrink" ]
[ button [ class "btn btn-blue btn-sm", onClick ReopenClicked ] [ text "Reopen this group" ]
]
]
, div [ class "sticky flex items-baseline mx-4 mb-4 border-b" ]
[ filterTab "Open" Route.Group.Open (openParams model.params) model.params
, filterTab "Closed" Route.Group.Closed (closedParams model.params) model.params
Expand Down Expand Up @@ -961,6 +1021,14 @@ sidebarView params group featuredMembers =
, li []
[ subscribeButtonView (Group.membershipState group)
]
, viewIf (Group.state group == Group.Open) <|
li []
[ button
[ class "text-md text-dusty-blue no-underline font-bold"
, onClick CloseClicked
]
[ text "Close this group" ]
]
]
]

Expand Down
43 changes: 36 additions & 7 deletions assets/elm/src/Page/Groups.elm
Original file line number Diff line number Diff line change
Expand Up @@ -159,23 +159,38 @@ resolvedView repo maybeCurrentRoute model data =
data.bookmarks
maybeCurrentRoute
[ div [ class "mx-auto max-w-sm leading-normal p-8" ]
[ div [ class "flex items-center pb-5" ]
[ h1 [ class "flex-1 ml-4 mr-4 font-extrabold text-3xl" ] [ text "Groups" ]
[ div [ class "flex items-center pb-4" ]
[ h1 [ class "flex-1 mx-4 font-extrabold text-3xl" ] [ text "Groups" ]
, div [ class "flex-0 flex-no-shrink" ]
[ a [ Route.href (Route.NewGroup (Space.slug data.space)), class "btn btn-blue btn-md no-underline" ] [ text "New group" ]
]
]
, div [ class "pb-8" ]
[ label [ class "flex items-center p-4 w-full rounded bg-grey-light" ]
[ div [ class "flex-0 flex-no-shrink pr-3" ] [ Icons.search ]
, input [ id "search-input", type_ "text", class "flex-1 bg-transparent no-outline", placeholder "Type to search" ] []
]
, div [ class "flex items-baseline mx-4 mb-4 border-b" ]
[ filterTab "Open" Route.Groups.Open (openParams model.params) model.params
, filterTab "Closed" Route.Groups.Closed (closedParams model.params) model.params
]
, groupsView repo model.params data.space model.groupIds
]
]


filterTab : String -> Route.Groups.State -> Params -> Params -> Html Msg
filterTab label state linkParams currentParams =
let
isCurrent =
Route.Groups.getState currentParams == state
in
a
[ Route.href (Route.Groups linkParams)
, classList
[ ( "block text-sm mr-4 py-2 border-b-3 border-transparent no-underline font-bold", True )
, ( "text-dusty-blue", not isCurrent )
, ( "border-turquoise text-dusty-blue-darker", isCurrent )
]
]
[ text label ]


groupsView : Repo -> Params -> Space -> Connection Id -> Html Msg
groupsView repo params space groupIds =
let
Expand Down Expand Up @@ -268,3 +283,17 @@ startsWith letter ( _, group ) =
isEven : Int -> Bool
isEven number =
remainderBy 2 number == 0


openParams : Params -> Params
openParams params =
params
|> Route.Groups.setCursors Nothing Nothing
|> Route.Groups.setState Route.Groups.Open


closedParams : Params -> Params
closedParams params =
params
|> Route.Groups.setCursors Nothing Nothing
|> Route.Groups.setState Route.Groups.Closed
Loading

0 comments on commit 32dfd2f

Please sign in to comment.