Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Close groups #126

Merged
merged 8 commits into from
Nov 4, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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