Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
10
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Open sidebar
gab
social
gab-social
Commits
1fabd284
Commit
1fabd284
authored
Jul 15, 2019
by
2458773093
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
New groups
parent
fd50f033
Changes
30
Hide whitespace changes
Inline
Side-by-side
Showing
30 changed files
with
816 additions
and
292 deletions
+816
-292
app/controllers/api/v1/groups/accounts_controller.rb
app/controllers/api/v1/groups/accounts_controller.rb
+1
-1
app/controllers/api/v1/groups_controller.rb
app/controllers/api/v1/groups_controller.rb
+15
-1
app/controllers/api/v1/timelines/group_controller.rb
app/controllers/api/v1/timelines/group_controller.rb
+2
-2
app/javascript/gabsocial/actions/compose.js
app/javascript/gabsocial/actions/compose.js
+2
-1
app/javascript/gabsocial/actions/groups.js
app/javascript/gabsocial/actions/groups.js
+109
-5
app/javascript/gabsocial/features/compose/components/compose_form.js
...ipt/gabsocial/features/compose/components/compose_form.js
+2
-1
app/javascript/gabsocial/features/compose/containers/compose_form_container.js
...ial/features/compose/containers/compose_form_container.js
+2
-2
app/javascript/gabsocial/features/groups/index/card.js
app/javascript/gabsocial/features/groups/index/card.js
+54
-0
app/javascript/gabsocial/features/groups/index/index.js
app/javascript/gabsocial/features/groups/index/index.js
+58
-63
app/javascript/gabsocial/features/groups/members/index.js
app/javascript/gabsocial/features/groups/members/index.js
+73
-0
app/javascript/gabsocial/features/groups/timeline/components/header.js
...t/gabsocial/features/groups/timeline/components/header.js
+55
-37
app/javascript/gabsocial/features/groups/timeline/components/inner_header.js
...ocial/features/groups/timeline/components/inner_header.js
+0
-96
app/javascript/gabsocial/features/groups/timeline/components/panel.js
...pt/gabsocial/features/groups/timeline/components/panel.js
+34
-0
app/javascript/gabsocial/features/groups/timeline/index.js
app/javascript/gabsocial/features/groups/timeline/index.js
+73
-77
app/javascript/gabsocial/features/ui/components/tabs_bar.js
app/javascript/gabsocial/features/ui/components/tabs_bar.js
+3
-0
app/javascript/gabsocial/features/ui/index.js
app/javascript/gabsocial/features/ui/index.js
+8
-2
app/javascript/gabsocial/features/ui/util/async-components.js
...javascript/gabsocial/features/ui/util/async-components.js
+4
-0
app/javascript/gabsocial/locales/en.json
app/javascript/gabsocial/locales/en.json
+1
-0
app/javascript/gabsocial/pages/group_page.js
app/javascript/gabsocial/pages/group_page.js
+71
-0
app/javascript/gabsocial/pages/groups_page.js
app/javascript/gabsocial/pages/groups_page.js
+53
-0
app/javascript/gabsocial/reducers/group_lists.js
app/javascript/gabsocial/reducers/group_lists.js
+21
-0
app/javascript/gabsocial/reducers/index.js
app/javascript/gabsocial/reducers/index.js
+2
-0
app/javascript/gabsocial/reducers/user_lists.js
app/javascript/gabsocial/reducers/user_lists.js
+9
-0
app/javascript/styles/application.scss
app/javascript/styles/application.scss
+2
-0
app/javascript/styles/gabsocial/components/group-card.scss
app/javascript/styles/gabsocial/components/group-card.scss
+71
-0
app/javascript/styles/gabsocial/components/group-detail.scss
app/javascript/styles/gabsocial/components/group-detail.scss
+72
-0
app/javascript/styles/gabsocial/components/tabs-bar.scss
app/javascript/styles/gabsocial/components/tabs-bar.scss
+2
-0
app/serializers/rest/group_serializer.rb
app/serializers/rest/group_serializer.rb
+15
-1
app/services/fan_out_on_write_service.rb
app/services/fan_out_on_write_service.rb
+1
-1
app/services/group_query_service.rb
app/services/group_query_service.rb
+1
-2
No files found.
app/controllers/api/v1/groups/accounts_controller.rb
View file @
1fabd284
...
...
@@ -9,7 +9,7 @@ class Api::V1::Groups::AccountsController < Api::BaseController
before_action
:require_user!
before_action
:set_group
after_action
:insert_pagination_headers
,
only: :
index
after_action
:insert_pagination_headers
,
only: :
show
def
show
@accounts
=
load_accounts
...
...
app/controllers/api/v1/groups_controller.rb
View file @
1fabd284
...
...
@@ -10,10 +10,24 @@ class Api::V1::GroupsController < Api::BaseController
before_action
:set_group
,
except:
[
:index
,
:create
]
def
index
@groups
=
Group
.
joins
(
:group_accounts
).
where
(
is_archived:
false
,
group_accounts:
{
account:
current_account
}).
all
case
current_tab
when
'featured'
@groups
=
Group
.
where
(
is_featured:
true
).
limit
(
25
).
all
when
'member'
@groups
=
Group
.
joins
(
:group_accounts
).
where
(
is_archived:
false
,
group_accounts:
{
account:
current_account
}).
all
when
'admin'
@groups
=
Group
.
joins
(
:group_accounts
).
where
(
is_archived:
false
,
group_accounts:
{
account:
current_account
,
write_permissions:
true
}).
all
end
render
json:
@groups
,
each_serializer:
REST
::
GroupSerializer
end
def
current_tab
tab
=
'featured'
tab
=
params
[
:tab
]
if
[
'featured'
,
'member'
,
'admin'
].
include?
params
[
:tab
]
return
tab
end
def
show
render
json:
@group
,
serializer:
REST
::
GroupSerializer
end
...
...
app/controllers/api/v1/timelines/group_controller.rb
View file @
1fabd284
...
...
@@ -29,7 +29,7 @@ class Api::V1::Timelines::GroupController < Api::BaseController
end
def
group_statuses
statuses
=
tag
_timeline_statuses
.
paginate_by_id
(
statuses
=
group
_timeline_statuses
.
paginate_by_id
(
limit_param
(
DEFAULT_STATUSES_LIMIT
),
params_slice
(
:max_id
,
:since_id
,
:min_id
)
)
...
...
@@ -43,7 +43,7 @@ class Api::V1::Timelines::GroupController < Api::BaseController
end
end
def
group_statuses
def
group_
timeline_
statuses
GroupQueryService
.
new
.
call
(
@group
)
end
...
...
app/javascript/gabsocial/actions/compose.js
View file @
1fabd284
...
...
@@ -125,7 +125,7 @@ export function directCompose(account, routerHistory) {
};
};
export
function
submitCompose
(
routerHistory
)
{
export
function
submitCompose
(
routerHistory
,
group
)
{
return
function
(
dispatch
,
getState
)
{
if
(
!
me
)
return
;
...
...
@@ -147,6 +147,7 @@ export function submitCompose(routerHistory) {
spoiler_text
:
getState
().
getIn
([
'
compose
'
,
'
spoiler_text
'
],
''
),
visibility
:
getState
().
getIn
([
'
compose
'
,
'
privacy
'
]),
poll
:
getState
().
getIn
([
'
compose
'
,
'
poll
'
],
null
),
group_id
:
group
?
group
.
get
(
'
id
'
)
:
null
,
},
{
headers
:
{
'
Idempotency-Key
'
:
getState
().
getIn
([
'
compose
'
,
'
idempotencyKey
'
]),
...
...
app/javascript/gabsocial/actions/groups.js
View file @
1fabd284
import
api
from
'
../api
'
;
import
api
,
{
getLinks
}
from
'
../api
'
;
import
{
me
}
from
'
gabsocial/initial_state
'
;
import
{
importFetchedAccounts
}
from
'
./importer
'
;
import
{
fetchRelationships
}
from
'
./accounts
'
;
export
const
GROUP_FETCH_REQUEST
=
'
GROUP_FETCH_REQUEST
'
;
export
const
GROUP_FETCH_SUCCESS
=
'
GROUP_FETCH_SUCCESS
'
;
...
...
@@ -21,6 +23,14 @@ export const GROUP_LEAVE_REQUEST = 'GROUP_LEAVE_REQUEST';
export
const
GROUP_LEAVE_SUCCESS
=
'
GROUP_LEAVE_SUCCESS
'
;
export
const
GROUP_LEAVE_FAIL
=
'
GROUP_LEAVE_FAIL
'
;
export
const
GROUP_MEMBERS_FETCH_REQUEST
=
'
GROUP_MEMBERS_FETCH_REQUEST
'
;
export
const
GROUP_MEMBERS_FETCH_SUCCESS
=
'
GROUP_MEMBERS_FETCH_SUCCESS
'
;
export
const
GROUP_MEMBERS_FETCH_FAIL
=
'
GROUP_MEMBERS_FETCH_FAIL
'
;
export
const
GROUP_MEMBERS_EXPAND_REQUEST
=
'
GROUP_MEMBERS_EXPAND_REQUEST
'
;
export
const
GROUP_MEMBERS_EXPAND_SUCCESS
=
'
GROUP_MEMBERS_EXPAND_SUCCESS
'
;
export
const
GROUP_MEMBERS_EXPAND_FAIL
=
'
GROUP_MEMBERS_EXPAND_FAIL
'
;
export
const
fetchGroup
=
id
=>
(
dispatch
,
getState
)
=>
{
if
(
!
me
)
return
;
...
...
@@ -98,13 +108,16 @@ export function fetchGroupRelationshipsFail(error) {
};
};
export
const
fetchGroups
=
()
=>
(
dispatch
,
getState
)
=>
{
export
const
fetchGroups
=
(
tab
)
=>
(
dispatch
,
getState
)
=>
{
if
(
!
me
)
return
;
dispatch
(
fetchGroupsRequest
());
api
(
getState
).
get
(
'
/api/v1/groups
'
)
.
then
(({
data
})
=>
dispatch
(
fetchGroupsSuccess
(
data
)))
api
(
getState
).
get
(
'
/api/v1/groups?tab=
'
+
tab
)
.
then
(({
data
})
=>
{
dispatch
(
fetchGroupsSuccess
(
data
,
tab
));
dispatch
(
fetchGroupRelationships
(
data
.
map
(
item
=>
item
.
id
)));
})
.
catch
(
err
=>
dispatch
(
fetchGroupsFail
(
err
)));
};
...
...
@@ -112,9 +125,10 @@ export const fetchGroupsRequest = () => ({
type
:
GROUPS_FETCH_REQUEST
,
});
export
const
fetchGroupsSuccess
=
groups
=>
({
export
const
fetchGroupsSuccess
=
(
groups
,
tab
)
=>
({
type
:
GROUPS_FETCH_SUCCESS
,
groups
,
tab
,
});
export
const
fetchGroupsFail
=
error
=>
({
...
...
@@ -191,3 +205,93 @@ export function leaveGroupFail(error) {
error
,
};
};
export
function
fetchMembers
(
id
)
{
return
(
dispatch
,
getState
)
=>
{
if
(
!
me
)
return
;
dispatch
(
fetchMembersRequest
(
id
));
api
(
getState
).
get
(
`/api/v1/groups/
${
id
}
/accounts`
).
then
(
response
=>
{
const
next
=
getLinks
(
response
).
refs
.
find
(
link
=>
link
.
rel
===
'
next
'
);
dispatch
(
importFetchedAccounts
(
response
.
data
));
dispatch
(
fetchMembersSuccess
(
id
,
response
.
data
,
next
?
next
.
uri
:
null
));
dispatch
(
fetchRelationships
(
response
.
data
.
map
(
item
=>
item
.
id
)));
}).
catch
(
error
=>
{
dispatch
(
fetchMembersFail
(
id
,
error
));
});
};
};
export
function
fetchMembersRequest
(
id
)
{
return
{
type
:
GROUP_MEMBERS_FETCH_REQUEST
,
id
,
};
};
export
function
fetchMembersSuccess
(
id
,
accounts
,
next
)
{
return
{
type
:
GROUP_MEMBERS_FETCH_SUCCESS
,
id
,
accounts
,
next
,
};
};
export
function
fetchMembersFail
(
id
,
error
)
{
return
{
type
:
GROUP_MEMBERS_FETCH_FAIL
,
id
,
error
,
};
};
export
function
expandMembers
(
id
)
{
return
(
dispatch
,
getState
)
=>
{
if
(
!
me
)
return
;
const
url
=
getState
().
getIn
([
'
user_lists
'
,
'
groups
'
,
id
,
'
next
'
]);
if
(
url
===
null
)
{
return
;
}
dispatch
(
expandMembersRequest
(
id
));
api
(
getState
).
get
(
url
).
then
(
response
=>
{
const
next
=
getLinks
(
response
).
refs
.
find
(
link
=>
link
.
rel
===
'
next
'
);
dispatch
(
importFetchedAccounts
(
response
.
data
));
dispatch
(
expandMembersSuccess
(
id
,
response
.
data
,
next
?
next
.
uri
:
null
));
dispatch
(
fetchRelationships
(
response
.
data
.
map
(
item
=>
item
.
id
)));
}).
catch
(
error
=>
{
dispatch
(
expandMembersFail
(
id
,
error
));
});
};
};
export
function
expandMembersRequest
(
id
)
{
return
{
type
:
GROUP_MEMBERS_EXPAND_REQUEST
,
id
,
};
};
export
function
expandMembersSuccess
(
id
,
accounts
,
next
)
{
return
{
type
:
GROUP_MEMBERS_EXPAND_SUCCESS
,
id
,
accounts
,
next
,
};
};
export
function
expandMembersFail
(
id
,
error
)
{
return
{
type
:
GROUP_MEMBERS_EXPAND_FAIL
,
id
,
error
,
};
};
\ No newline at end of file
app/javascript/gabsocial/features/compose/components/compose_form.js
View file @
1fabd284
...
...
@@ -68,6 +68,7 @@ class ComposeForm extends ImmutablePureComponent {
anyMedia
:
PropTypes
.
bool
,
shouldCondense
:
PropTypes
.
bool
,
autoFocus
:
PropTypes
.
bool
,
group
:
ImmutablePropTypes
.
map
,
};
static
defaultProps
=
{
...
...
@@ -118,7 +119,7 @@ class ComposeForm extends ImmutablePureComponent {
return
;
}
this
.
props
.
onSubmit
(
this
.
context
.
router
?
this
.
context
.
router
.
history
:
null
);
this
.
props
.
onSubmit
(
this
.
context
.
router
?
this
.
context
.
router
.
history
:
null
,
this
.
props
.
group
);
}
onSuggestionsClearRequested
=
()
=>
{
...
...
app/javascript/gabsocial/features/compose/containers/compose_form_container.js
View file @
1fabd284
...
...
@@ -33,8 +33,8 @@ const mapDispatchToProps = (dispatch) => ({
dispatch
(
changeCompose
(
text
));
},
onSubmit
(
router
)
{
dispatch
(
submitCompose
(
router
));
onSubmit
(
router
,
group
)
{
dispatch
(
submitCompose
(
router
,
group
));
},
onClearSuggestions
()
{
...
...
app/javascript/gabsocial/features/groups/index/card.js
0 → 100644
View file @
1fabd284
import
React
from
'
react
'
;
import
ImmutablePropTypes
from
'
react-immutable-proptypes
'
;
import
ImmutablePureComponent
from
'
react-immutable-pure-component
'
;
import
{
defineMessages
,
injectIntl
}
from
'
react-intl
'
;
import
{
Link
}
from
'
react-router-dom
'
;
import
{
shortNumberFormat
}
from
'
../../../utils/numbers
'
;
import
{
connect
}
from
'
react-redux
'
;
const
messages
=
defineMessages
({
members
:
{
id
:
'
groups.card.members
'
,
defaultMessage
:
'
Members
'
},
view
:
{
id
:
'
groups.card.view
'
,
defaultMessage
:
'
View
'
},
join
:
{
id
:
'
groups.card.join
'
,
defaultMessage
:
'
Join
'
},
role_member
:
{
id
:
'
groups.card.roles.member
'
,
defaultMessage
:
'
You
\'
re a member
'
},
role_admin
:
{
id
:
'
groups.card.roles.admin
'
,
defaultMessage
:
'
You
\'
re an admin
'
},
});
const
mapStateToProps
=
(
state
,
{
id
})
=>
({
group
:
state
.
getIn
([
'
groups
'
,
id
]),
relationships
:
state
.
getIn
([
'
group_relationships
'
,
id
]),
});
export
default
@
connect
(
mapStateToProps
)
@
injectIntl
class
GroupCard
extends
ImmutablePureComponent
{
static
propTypes
=
{
group
:
ImmutablePropTypes
.
map
,
relationships
:
ImmutablePropTypes
.
map
,
}
getRole
()
{
const
{
intl
,
relationships
}
=
this
.
props
;
if
(
!
relationships
)
return
null
;
if
(
relationships
.
get
(
'
admin
'
))
return
intl
.
formatMessage
(
messages
.
role_admin
);
if
(
relationships
.
get
(
'
member
'
))
return
intl
.
formatMessage
(
messages
.
role_member
);
}
render
()
{
const
{
intl
,
group
}
=
this
.
props
;
const
coverImageUrl
=
group
.
get
(
'
cover_image_url
'
);
const
role
=
this
.
getRole
();
return
(
<
Link
to
=
{
`/groups/
${
group
.
get
(
'
id
'
)}
`
}
className
=
"
group-card
"
>
<
div
className
=
"
group-card__header
"
>
{
coverImageUrl
&&
<
img
alt
=
""
src
=
{
coverImageUrl
}
/>}</
div
>
<
div
className
=
"
group-card__content
"
>
<
div
className
=
"
group-card__title
"
>
{
group
.
get
(
'
title
'
)}
<
/div
>
<
div
className
=
"
group-card__meta
"
><
strong
>
{
shortNumberFormat
(
group
.
get
(
'
member_count
'
))}
<
/strong> {intl.formatMessage
(
messages.members
)
}{role && <span> · {role}</
span
>
}
<
/div
>
<
div
className
=
"
group-card__description
"
>
{
group
.
get
(
'
description
'
)}
<
/div
>
<
/div
>
<
/Link
>
);
}
}
\ No newline at end of file
app/javascript/gabsocial/features/groups/index/index.js
View file @
1fabd284
...
...
@@ -2,80 +2,75 @@ import React from 'react';
import
{
connect
}
from
'
react-redux
'
;
import
PropTypes
from
'
prop-types
'
;
import
ImmutablePropTypes
from
'
react-immutable-proptypes
'
;
import
LoadingIndicator
from
'
../../../components/loading_indicator
'
;
import
Column
from
'
../../ui/components/column
'
;
import
ColumnBackButtonSlim
from
'
../../../components/column_back_button_slim
'
;
import
{
fetchGroups
}
from
'
../../../actions/groups
'
;
import
{
defineMessages
,
injectIntl
,
FormattedMessage
}
from
'
react-intl
'
;
import
{
defineMessages
,
injectIntl
}
from
'
react-intl
'
;
import
ImmutablePureComponent
from
'
react-immutable-pure-component
'
;
import
ColumnLink
from
'
../../ui/components/column_link
'
;
import
ColumnSubheading
from
'
../../ui/components/column_subheading
'
;
import
NewGroupForm
from
'
../create
'
;
import
{
createSelector
}
from
'
reselect
'
;
import
ScrollableList
from
'
../../../components/scrollable_list
'
;
import
{
Link
}
from
'
react-router-dom
'
;
import
classNames
from
'
classnames
'
;
import
GroupCard
from
'
./card
'
;
const
messages
=
defineMessages
({
heading
:
{
id
:
'
column.groups
'
,
defaultMessage
:
'
Groups
'
},
subheading
:
{
id
:
'
groups.subheading
'
,
defaultMessage
:
'
Your groups
'
},
heading
:
{
id
:
'
column.groups
'
,
defaultMessage
:
'
Groups
'
},
tab_featured
:
{
id
:
'
column.groups_tab_featured
'
,
defaultMessage
:
'
Featured
'
},
tab_member
:
{
id
:
'
column.groups_tab_member
'
,
defaultMessage
:
'
Groups you
\'
re in
'
},
tab_admin
:
{
id
:
'
column.groups_tab_admin
'
,
defaultMessage
:
'
Groups you manage
'
},
});
const
getOrderedGroups
=
createSelector
([
state
=>
state
.
get
(
'
groups
'
)],
groups
=>
{
if
(
!
groups
)
{
return
groups
;
}
return
groups
.
toList
().
filter
(
item
=>
!!
item
);
});
const
mapStateToProps
=
state
=>
({
groups
:
getOrderedGroups
(
state
),
const
mapStateToProps
=
(
state
,
{
activeTab
})
=>
({
groupIds
:
state
.
getIn
([
'
group_lists
'
,
activeTab
]),
});
export
default
@
connect
(
mapStateToProps
)
@
injectIntl
class
Groups
extends
ImmutablePureComponent
{
static
propTypes
=
{
params
:
PropTypes
.
object
.
isRequired
,
activeTab
:
PropTypes
.
string
.
isRequired
,
dispatch
:
PropTypes
.
func
.
isRequired
,
groups
:
ImmutablePropTypes
.
map
,
groupIds
:
ImmutablePropTypes
.
list
,
intl
:
PropTypes
.
object
.
isRequired
,
};
static
propTypes
=
{
params
:
PropTypes
.
object
.
isRequired
,
dispatch
:
PropTypes
.
func
.
isRequired
,
groups
:
ImmutablePropTypes
.
list
,
intl
:
PropTypes
.
object
.
isRequired
,
};
componentWillMount
()
{
this
.
props
.
dispatch
(
fetchGroups
());
}
render
()
{
const
{
intl
,
groups
}
=
this
.
props
;
if
(
!
groups
)
{
return
(
<
Column
>
<
LoadingIndicator
/>
<
/Column
>
);
}
const
emptyMessage
=
<
FormattedMessage
id
=
'
empty_column.groups
'
defaultMessage
=
"
No groups.
"
/>
;
return
(
<
Column
icon
=
'
list-ul
'
heading
=
{
intl
.
formatMessage
(
messages
.
heading
)}
>
<
ColumnBackButtonSlim
/>
<
NewGroupForm
/>
componentWillMount
()
{
this
.
props
.
dispatch
(
fetchGroups
(
this
.
props
.
activeTab
));
}
<
ColumnSubheading
text
=
{
intl
.
formatMessage
(
messages
.
subheading
)}
/
>
<
ScrollableList
scrollKey
=
'
lists
'
emptyMessage
=
{
emptyMessage
}
>
{
groups
.
map
(
group
=>
<
ColumnLink
key
=
{
group
.
get
(
'
id
'
)}
to
=
{
`/groups/
${
group
.
get
(
'
id
'
)}
`
}
icon
=
'
list-ul
'
text
=
{
group
.
get
(
'
title
'
)}
/
>
)}
<
/ScrollableList
>
<
/Column
>
);
}
componentDidUpdate
(
oldProps
)
{
if
(
this
.
props
.
activeTab
&&
this
.
props
.
activeTab
!==
oldProps
.
activeTab
)
{
this
.
props
.
dispatch
(
fetchGroups
(
this
.
props
.
activeTab
));
}
}
}
render
()
{
const
{
intl
,
groupIds
,
activeTab
}
=
this
.
props
;
return
(
<
div
>
<
div
className
=
"
group-column-header
"
>
<
div
className
=
"
group-column-header__title
"
>
{
intl
.
formatMessage
(
messages
.
heading
)}
<
/div
>
<
div
className
=
"
column-header__wrapper
"
>
<
h1
className
=
"
column-header
"
>
<
Link
to
=
'
/groups
'
className
=
{
classNames
(
'
btn grouped
'
,
{
'
active
'
:
'
featured
'
===
activeTab
})}
>
{
intl
.
formatMessage
(
messages
.
tab_featured
)}
<
/Link
>
<
Link
to
=
'
/groups/browse/member
'
className
=
{
classNames
(
'
btn grouped
'
,
{
'
active
'
:
'
member
'
===
activeTab
})}
>
{
intl
.
formatMessage
(
messages
.
tab_member
)}
<
/Link
>
<
Link
to
=
'
/groups/browse/admin
'
className
=
{
classNames
(
'
btn grouped
'
,
{
'
active
'
:
'
admin
'
===
activeTab
})}
>
{
intl
.
formatMessage
(
messages
.
tab_admin
)}
<
/Link
>
<
/h1
>
<
/div
>
<
/div
>
<
div
className
=
"
group-card-list
"
>
{
groupIds
.
map
(
id
=>
<
GroupCard
key
=
{
id
}
id
=
{
id
}
/>
)
}
<
/div
>
<
/div
>
);
}
}
\ No newline at end of file
app/javascript/gabsocial/features/groups/members/index.js
0 → 100644
View file @
1fabd284
import
React
from
'
react
'
;
import
{
connect
}
from
'
react-redux
'
;
import
ImmutablePureComponent
from
'
react-immutable-pure-component
'
;
import
PropTypes
from
'
prop-types
'
;
import
ImmutablePropTypes
from
'
react-immutable-proptypes
'
;
import
{
debounce
}
from
'
lodash
'
;
import
LoadingIndicator
from
'
../../../components/loading_indicator
'
;
import
{
fetchMembers
,
expandMembers
,
}
from
'
../../../actions/groups
'
;
import
{
FormattedMessage
}
from
'
react-intl
'
;
import
AccountContainer
from
'
../../../containers/account_container
'
;
import
Column
from
'
../../ui/components/column
'
;
import
ScrollableList
from
'
../../../components/scrollable_list
'
;
const
mapStateToProps
=
(
state
,
{
params
:
{
id
}
})
=>
({
group
:
state
.
getIn
([
'
groups
'
,
id
]),
accountIds
:
state
.
getIn
([
'
user_lists
'
,
'
groups
'
,
id
,
'
items
'
]),
hasMore
:
!!
state
.
getIn
([
'
user_lists
'
,
'
groups
'
,
id
,
'
next
'
]),
});
export
default
@
connect
(
mapStateToProps
)
class
GroupMembers
extends
ImmutablePureComponent
{
static
propTypes
=
{
params
:
PropTypes
.
object
.
isRequired
,
dispatch
:
PropTypes
.
func
.
isRequired
,
accountIds
:
ImmutablePropTypes
.
list
,
hasMore
:
PropTypes
.
bool
,
};
componentWillMount
()
{
const
{
params
:
{
id
}
}
=
this
.
props
;
this
.
props
.
dispatch
(
fetchMembers
(
id
));
}
componentWillReceiveProps
(
nextProps
)
{
if
(
nextProps
.
params
.
id
!==
this
.
props
.
params
.
id
)
{
this
.
props
.
dispatch
(
fetchMembers
(
nextProps
.
params
.
id
));
}
}
handleLoadMore
=
debounce
(()
=>
{
this
.
props
.
dispatch
(
expandMembers
(
this
.
props
.
params
.
id
));
},
300
,
{
leading
:
true
});
render
()
{
const
{
accountIds
,
hasMore
,
group
}
=
this
.
props
;
if
(
!
group
||
!
accountIds
)
{
return
(
<
Column
>
<
LoadingIndicator
/>
<
/Column
>
);
}
return
(
<
Column
>
<
ScrollableList
scrollKey
=
'
members
'
hasMore
=
{
hasMore
}
onLoadMore
=
{
this
.
handleLoadMore
}
emptyMessage
=
{
<
FormattedMessage
id
=
'
group.members.empty
'
defaultMessage
=
'
This group does not has any members.
'
/>
}
>
{
accountIds
.
map
(
id
=>
<
AccountContainer
key
=
{
id
}
id
=
{
id
}
withNote
=
{
false
}
/>
)
}
<
/ScrollableList
>
<
/Column
>
);
}
}
app/javascript/gabsocial/features/groups/timeline/components/header.js
View file @
1fabd284
import
React
from
'
react
'
;
import
ImmutablePropTypes
from
'
react-immutable-proptypes
'
;
import
PropTypes
from
'
prop-types
'
;
import
InnerHeader
from
'
./inner_header
'
;
import
Button
from
'
gabsocial/components/button
'
;
import
ImmutablePureComponent
from
'
react-immutable-pure-component
'
;
import
{
FormattedMessage
}
from
'
react-intl
'
;
import
{
defineMessages
,
injectIntl
}
from
'
react-intl
'
;
import
{
NavLink
}
from
'
react-router-dom
'
;
export
default
class
Header
extends
ImmutablePureComponent
{
static
propTypes
=
{
group
:
ImmutablePropTypes
.
map
,
relationships
:
ImmutablePropTypes
.
map
,
toggleMembership
:
PropTypes
.
func
.
isRequired
,
};
static
contextTypes
=
{
router
:
PropTypes
.
object
,
};
render
()
{
const
{
group
,
relationships
,
toggleMembership
}
=
this
.
props
;
if
(
group
===
null
)
{
return
null
;
}
return
(
<
div
className
=
'
account-timeline__header
'
>
<
InnerHeader
group
=
{
group
}
relationships
=
{
relationships
}
toggleMembership
=
{
toggleMembership
}
/
>
<
div
className
=
'
account__section-headline
'
>
<
NavLink
exact
to
=
{
`/groups/
${
group
.
get
(
'
id
'
)}
`
}
><
FormattedMessage
id
=
'
groups.posts
'
defaultMessage
=
'
Posts
'
/><
/NavLink
>
<
NavLink
exact
to
=
{
`/groups/
${
group
.
get
(
'
id
'
)}
/accounts`
}
><
FormattedMessage
id
=
'
group.accounts
'
defaultMessage
=
'
Members
'
/><
/NavLink
>
<
/div
>
<
/div
>
);
}
const
messages
=
defineMessages
({
join
:
{
id
:
'
groups.join
'
,
defaultMessage
:
'
Join group
'
},
leave
:
{
id
:
'
groups.leave
'
,
defaultMessage
:
'
Leave group
'
},
});
export
default
@
injectIntl
class
Header
extends
ImmutablePureComponent
{
static
propTypes
=
{
group
:
ImmutablePropTypes
.
map
,
relationships
:
ImmutablePropTypes
.
map
,
toggleMembership
:
PropTypes
.
func
.
isRequired
,