* MM-26329 Fix Channel info guests info in landscape
* Channnel info refactor
* Rename canEditChannel to canEdit in connected component
(cherry picked from commit 55cfce9b89)
Co-authored-by: Elias Nahum <nahumhbl@gmail.com>
This commit is contained in:
parent
c4e23af279
commit
55511e1fdb
52 changed files with 3269 additions and 1120 deletions
|
|
@ -29,10 +29,9 @@ type BatchAction = {
|
|||
export type Action = GenericAction | Thunk | BatchAction | ActionFunc;
|
||||
|
||||
export type ActionResult = {
|
||||
data: any;
|
||||
} | {
|
||||
error: any;
|
||||
};
|
||||
data?: any;
|
||||
error?: any;
|
||||
}
|
||||
|
||||
export type DispatchFunc = (action: Action, getState?: GetStateFunc | null) => Promise<ActionResult>;
|
||||
export type ActionFunc = (dispatch: DispatchFunc, getState: GetStateFunc) => Promise<ActionResult|ActionResult[]> | ActionResult;
|
||||
|
|
|
|||
|
|
@ -13,3 +13,8 @@ export type GeneralState = {
|
|||
serverVersion: string;
|
||||
timezones: Array<string>;
|
||||
};
|
||||
|
||||
export type FormattedMsg = {
|
||||
id: string;
|
||||
defaultMessage: string;
|
||||
};
|
||||
|
|
|
|||
3
app/mm-redux/types/module.d.ts
vendored
3
app/mm-redux/types/module.d.ts
vendored
|
|
@ -2,4 +2,5 @@
|
|||
// See LICENSE.txt for license information.
|
||||
declare module 'gfycat-sdk';
|
||||
declare module 'remote-redux-devtools';
|
||||
declare module 'redux-action-buffer';
|
||||
declare module 'redux-action-buffer';
|
||||
declare module 'react-intl';
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`channel_info should match snapshot 1`] = `
|
||||
exports[`channelInfo should match snapshot 1`] = `
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
|
|
@ -75,15 +75,9 @@ exports[`channel_info should match snapshot 1`] = `
|
|||
}
|
||||
>
|
||||
<React.Fragment>
|
||||
<channelInfoRow
|
||||
action={[Function]}
|
||||
defaultMessage="Favorite"
|
||||
detail={false}
|
||||
icon="star-o"
|
||||
<Connect(Favorite)
|
||||
channelId="1234"
|
||||
isLandscape={false}
|
||||
rightArrow={true}
|
||||
shouldRender={true}
|
||||
textId="mobile.routes.channelInfo.favorite"
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
|
|
@ -113,26 +107,8 @@ exports[`channel_info should match snapshot 1`] = `
|
|||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
togglable={true}
|
||||
/>
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": undefined,
|
||||
"height": 1,
|
||||
"marginHorizontal": 15,
|
||||
}
|
||||
}
|
||||
/>
|
||||
<channelInfoRow
|
||||
action={[Function]}
|
||||
defaultMessage="Mute channel"
|
||||
detail={false}
|
||||
icon="bell-slash-o"
|
||||
isLandscape={false}
|
||||
rightArrow={true}
|
||||
shouldRender={true}
|
||||
textId="channel_notifications.muteChannel.settings"
|
||||
<Separator
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
|
|
@ -162,26 +138,10 @@ exports[`channel_info should match snapshot 1`] = `
|
|||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
togglable={true}
|
||||
/>
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": undefined,
|
||||
"height": 1,
|
||||
"marginHorizontal": 15,
|
||||
}
|
||||
}
|
||||
/>
|
||||
<channelInfoRow
|
||||
action={[Function]}
|
||||
defaultMessage="Ignore @channel, @here, @all"
|
||||
detail={false}
|
||||
icon="at"
|
||||
<Connect(Mute)
|
||||
channelId="1234"
|
||||
isLandscape={false}
|
||||
rightArrow={true}
|
||||
shouldRender={true}
|
||||
textId="channel_notifications.ignoreChannelMentions.settings"
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
|
|
@ -211,25 +171,9 @@ exports[`channel_info should match snapshot 1`] = `
|
|||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
togglable={true}
|
||||
userId="1234"
|
||||
/>
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": undefined,
|
||||
"height": 1,
|
||||
"marginHorizontal": 15,
|
||||
}
|
||||
}
|
||||
/>
|
||||
<channelInfoRow
|
||||
action={[Function]}
|
||||
defaultMessage="Pinned Posts"
|
||||
image={1}
|
||||
isLandscape={false}
|
||||
rightArrow={true}
|
||||
shouldRender={true}
|
||||
textId="channel_header.pinnedPosts"
|
||||
<Separator
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
|
|
@ -259,228 +203,202 @@ exports[`channel_info should match snapshot 1`] = `
|
|||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
togglable={false}
|
||||
/>
|
||||
<React.Fragment>
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": undefined,
|
||||
"height": 1,
|
||||
"marginHorizontal": 15,
|
||||
}
|
||||
}
|
||||
/>
|
||||
<channelInfoRow
|
||||
action={[Function]}
|
||||
defaultMessage="Manage Members"
|
||||
detail={2}
|
||||
icon="users"
|
||||
isLandscape={false}
|
||||
rightArrow={true}
|
||||
shouldRender={true}
|
||||
textId="channel_header.manageMembers"
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
togglable={false}
|
||||
/>
|
||||
</React.Fragment>
|
||||
<React.Fragment>
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": undefined,
|
||||
"height": 1,
|
||||
"marginHorizontal": 15,
|
||||
}
|
||||
}
|
||||
/>
|
||||
<channelInfoRow
|
||||
action={[Function]}
|
||||
defaultMessage="Add Members"
|
||||
icon="user-plus"
|
||||
isLandscape={false}
|
||||
rightArrow={true}
|
||||
shouldRender={true}
|
||||
textId="channel_header.addMembers"
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
togglable={false}
|
||||
/>
|
||||
</React.Fragment>
|
||||
<React.Fragment>
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": undefined,
|
||||
"height": 1,
|
||||
"marginHorizontal": 15,
|
||||
}
|
||||
}
|
||||
/>
|
||||
<channelInfoRow
|
||||
action={[Function]}
|
||||
defaultMessage="Convert to Private Channel"
|
||||
icon="lock"
|
||||
isLandscape={false}
|
||||
rightArrow={true}
|
||||
shouldRender={true}
|
||||
textId="mobile.channel_info.convert"
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
togglable={false}
|
||||
/>
|
||||
</React.Fragment>
|
||||
<React.Fragment>
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": undefined,
|
||||
"height": 1,
|
||||
"marginHorizontal": 15,
|
||||
}
|
||||
}
|
||||
/>
|
||||
<channelInfoRow
|
||||
action={[Function]}
|
||||
defaultMessage="Edit Channel"
|
||||
icon="edit"
|
||||
isLandscape={false}
|
||||
rightArrow={true}
|
||||
shouldRender={true}
|
||||
textId="mobile.channel_info.edit"
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
togglable={false}
|
||||
/>
|
||||
</React.Fragment>
|
||||
</React.Fragment>
|
||||
<React.Fragment>
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": undefined,
|
||||
"height": 1,
|
||||
"marginHorizontal": 15,
|
||||
}
|
||||
}
|
||||
/>
|
||||
<channelInfoRow
|
||||
action={[Function]}
|
||||
defaultMessage="Leave Channel"
|
||||
icon="sign-out"
|
||||
<Connect(IgnoreMentions)
|
||||
channelId="1234"
|
||||
isLandscape={false}
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<Separator
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<Connect(Pinned)
|
||||
channelId="1234"
|
||||
isLandscape={false}
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<Connect(ManageMembers)
|
||||
isLandscape={false}
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<Connect(AddMembers)
|
||||
isLandscape={false}
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<Connect(ConvertPrivate)
|
||||
isLandscape={false}
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<Connect(EditChannel)
|
||||
isLandscape={false}
|
||||
rightArrow={true}
|
||||
shouldRender={true}
|
||||
textId="navbar.leave"
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
|
|
@ -510,40 +428,52 @@ exports[`channel_info should match snapshot 1`] = `
|
|||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
togglable={false}
|
||||
/>
|
||||
</React.Fragment>
|
||||
</View>
|
||||
<View
|
||||
style={
|
||||
Array [
|
||||
Object {
|
||||
"backgroundColor": "#ffffff",
|
||||
"borderBottomColor": undefined,
|
||||
"borderBottomWidth": 1,
|
||||
"borderTopColor": undefined,
|
||||
"borderTopWidth": 1,
|
||||
},
|
||||
Object {
|
||||
"borderBottomColor": undefined,
|
||||
"borderBottomWidth": 1,
|
||||
"borderTopColor": undefined,
|
||||
"borderTopWidth": 1,
|
||||
"marginTop": 40,
|
||||
},
|
||||
]
|
||||
Object {
|
||||
"marginTop": 40,
|
||||
}
|
||||
}
|
||||
>
|
||||
<channelInfoRow
|
||||
action={[Function]}
|
||||
defaultMessage="Archive Channel"
|
||||
icon="archive"
|
||||
iconColor="#CA3B27"
|
||||
<Connect(Leave)
|
||||
close={[Function]}
|
||||
isLandscape={false}
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<Connect(Archive)
|
||||
close={[Function]}
|
||||
isLandscape={false}
|
||||
rightArrow={true}
|
||||
shouldRender={true}
|
||||
textColor="#CA3B27"
|
||||
textId="mobile.routes.channelInfo.delete_channel"
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
|
|
@ -573,7 +503,6 @@ exports[`channel_info should match snapshot 1`] = `
|
|||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
togglable={false}
|
||||
/>
|
||||
</View>
|
||||
</ScrollView>
|
||||
|
|
|
|||
|
|
@ -395,9 +395,12 @@ exports[`channel_info_header should match snapshot when DM and hasGuests and is
|
|||
</View>
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"marginTop": 15,
|
||||
}
|
||||
Array [
|
||||
Object {
|
||||
"marginTop": 15,
|
||||
},
|
||||
null,
|
||||
]
|
||||
}
|
||||
>
|
||||
<View
|
||||
|
|
@ -1045,9 +1048,12 @@ exports[`channel_info_header should match snapshot when GM and hasGuests 1`] = `
|
|||
</View>
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"marginTop": 15,
|
||||
}
|
||||
Array [
|
||||
Object {
|
||||
"marginTop": 15,
|
||||
},
|
||||
null,
|
||||
]
|
||||
}
|
||||
>
|
||||
<View
|
||||
|
|
@ -1717,9 +1723,12 @@ exports[`channel_info_header should match snapshot when public channel and hasGu
|
|||
</View>
|
||||
<View
|
||||
style={
|
||||
Object {
|
||||
"marginTop": 15,
|
||||
}
|
||||
Array [
|
||||
Object {
|
||||
"marginTop": 15,
|
||||
},
|
||||
null,
|
||||
]
|
||||
}
|
||||
>
|
||||
<View
|
||||
|
|
|
|||
|
|
@ -0,0 +1,76 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ChannelInfo -> Add Members should match snapshot 1`] = `
|
||||
<React.Fragment>
|
||||
<Separator
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<channelInfoRow
|
||||
action={[Function]}
|
||||
defaultMessage="Add Members"
|
||||
icon="user-plus"
|
||||
isLandscape={false}
|
||||
rightArrow={true}
|
||||
shouldRender={true}
|
||||
textId="channel_header.addMembers"
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
togglable={false}
|
||||
/>
|
||||
</React.Fragment>
|
||||
`;
|
||||
55
app/screens/channel_info/add_members/add_members.test.js
Normal file
55
app/screens/channel_info/add_members/add_members.test.js
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import {shallowWithIntl} from 'test/intl-test-helper';
|
||||
|
||||
import Preferences from '@mm-redux/constants/preferences';
|
||||
|
||||
import AddMembers from './add_members';
|
||||
|
||||
jest.mock('@utils/theme', () => {
|
||||
const original = jest.requireActual('../../../utils/theme');
|
||||
return {
|
||||
...original,
|
||||
changeOpacity: jest.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
describe('ChannelInfo -> Add Members', () => {
|
||||
const baseProps = {
|
||||
canManageUsers: true,
|
||||
groupConstrained: false,
|
||||
isLandscape: false,
|
||||
theme: Preferences.THEMES.default,
|
||||
};
|
||||
|
||||
test('should match snapshot', () => {
|
||||
const wrapper = shallowWithIntl(
|
||||
<AddMembers
|
||||
{...baseProps}
|
||||
/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should render null if cannot manage members', () => {
|
||||
const wrapper = shallowWithIntl(
|
||||
<AddMembers
|
||||
{...baseProps}
|
||||
canManageUsers={false}
|
||||
/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toBeNull();
|
||||
});
|
||||
|
||||
test('should render null if channel is constrained to groups', () => {
|
||||
const wrapper = shallowWithIntl(
|
||||
<AddMembers
|
||||
{...baseProps}
|
||||
groupConstrained={true}
|
||||
/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toBeNull();
|
||||
});
|
||||
});
|
||||
55
app/screens/channel_info/add_members/add_members.tsx
Normal file
55
app/screens/channel_info/add_members/add_members.tsx
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {PureComponent} from 'react';
|
||||
import {intlShape} from 'react-intl';
|
||||
|
||||
import {goToScreen} from '@actions/navigation';
|
||||
import {Theme} from '@mm-redux/types/preferences';
|
||||
import ChannelInfoRow from '@screens/channel_info/channel_info_row';
|
||||
import Separator from '@screens/channel_info/separator';
|
||||
import {t} from '@utils/i18n';
|
||||
import {preventDoubleTap} from '@utils/tap';
|
||||
|
||||
interface AddMembersProps {
|
||||
canManageUsers: boolean;
|
||||
groupConstrained: boolean;
|
||||
isLandscape: boolean;
|
||||
theme: Theme;
|
||||
}
|
||||
|
||||
export default class AddMembers extends PureComponent<AddMembersProps> {
|
||||
static contextTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
goToChannelAddMembers = preventDoubleTap(() => {
|
||||
const {intl} = this.context;
|
||||
const screen = 'ChannelAddMembers';
|
||||
const title = intl.formatMessage({id: 'channel_header.addMembers', defaultMessage: 'Add Members'});
|
||||
|
||||
goToScreen(screen, title);
|
||||
});
|
||||
|
||||
render() {
|
||||
const {canManageUsers, groupConstrained, isLandscape, theme} = this.props;
|
||||
|
||||
if (canManageUsers && !groupConstrained) {
|
||||
return (
|
||||
<>
|
||||
<Separator theme={theme}/>
|
||||
<ChannelInfoRow
|
||||
action={this.goToChannelAddMembers}
|
||||
defaultMessage='Add Members'
|
||||
icon='user-plus'
|
||||
textId={t('channel_header.addMembers')}
|
||||
theme={theme}
|
||||
isLandscape={isLandscape}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
22
app/screens/channel_info/add_members/index.js
Normal file
22
app/screens/channel_info/add_members/index.js
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
import {canManageChannelMembers, getCurrentChannel} from '@mm-redux/selectors/entities/channels';
|
||||
import AddMembers from './add_members';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
const currentChannel = getCurrentChannel(state);
|
||||
let canManageUsers = currentChannel?.id ? canManageChannelMembers(state) : false;
|
||||
if (currentChannel.group_constrained) {
|
||||
canManageUsers = false;
|
||||
}
|
||||
|
||||
return {
|
||||
canManageUsers,
|
||||
groupConstrained: currentChannel.group_constrained,
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(AddMembers);
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ChannelInfo -> Archive should match snapshot for Archive Channel 1`] = `
|
||||
<React.Fragment>
|
||||
<Separator
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<channelInfoRow
|
||||
action={[Function]}
|
||||
defaultMessage="Archive Channel"
|
||||
icon="archive"
|
||||
iconColor="#CA3B27"
|
||||
isLandscape={false}
|
||||
rightArrow={false}
|
||||
shouldRender={true}
|
||||
textColor="#CA3B27"
|
||||
textId="mobile.routes.channelInfo.delete_channel"
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
togglable={false}
|
||||
/>
|
||||
</React.Fragment>
|
||||
`;
|
||||
|
||||
exports[`ChannelInfo -> Archive should match snapshot for Unarchive Channel 1`] = `
|
||||
<React.Fragment>
|
||||
<Separator
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<channelInfoRow
|
||||
action={[Function]}
|
||||
defaultMessage="Unarchive Channel"
|
||||
icon="archive"
|
||||
iconColor="#CA3B27"
|
||||
isLandscape={false}
|
||||
rightArrow={false}
|
||||
shouldRender={true}
|
||||
textColor="#CA3B27"
|
||||
textId="mobile.routes.channelInfo.unarchive_channel"
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
togglable={false}
|
||||
/>
|
||||
</React.Fragment>
|
||||
`;
|
||||
67
app/screens/channel_info/archive/archive.test.js
Normal file
67
app/screens/channel_info/archive/archive.test.js
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import {shallowWithIntl} from 'test/intl-test-helper';
|
||||
|
||||
import Preferences from '@mm-redux/constants/preferences';
|
||||
|
||||
import Archive from './archive';
|
||||
|
||||
jest.mock('@utils/theme', () => {
|
||||
const original = jest.requireActual('../../../utils/theme');
|
||||
return {
|
||||
...original,
|
||||
changeOpacity: jest.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
describe('ChannelInfo -> Archive', () => {
|
||||
const baseProps = {
|
||||
canArchive: true,
|
||||
canUnarchive: false,
|
||||
channelId: '123',
|
||||
close: jest.fn(),
|
||||
deleteChannel: jest.fn(),
|
||||
displayName: 'Test Channel',
|
||||
getChannel: jest.fn(),
|
||||
handleSelectChannel: jest.fn(),
|
||||
isLandscape: false,
|
||||
isPublic: true,
|
||||
unarchiveChannel: jest.fn(),
|
||||
selectPenultimateChannel: jest.fn(),
|
||||
teamId: 'team-123',
|
||||
theme: Preferences.THEMES.default,
|
||||
viewArchivedChannels: true,
|
||||
};
|
||||
|
||||
test('should match snapshot for Archive Channel', () => {
|
||||
const wrapper = shallowWithIntl(
|
||||
<Archive
|
||||
{...baseProps}
|
||||
/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should match snapshot for Unarchive Channel', () => {
|
||||
const wrapper = shallowWithIntl(
|
||||
<Archive
|
||||
{...baseProps}
|
||||
canUnarchive={true}
|
||||
/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should match snapshot Not render Archive', () => {
|
||||
const wrapper = shallowWithIntl(
|
||||
<Archive
|
||||
{...baseProps}
|
||||
canArchive={false}
|
||||
canUnarchive={false}
|
||||
/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toBeNull();
|
||||
});
|
||||
});
|
||||
177
app/screens/channel_info/archive/archive.tsx
Normal file
177
app/screens/channel_info/archive/archive.tsx
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {PureComponent} from 'react';
|
||||
import {Alert} from 'react-native';
|
||||
import {intlShape} from 'react-intl';
|
||||
|
||||
import {ActionResult} from '@mm-redux/types/actions';
|
||||
import {FormattedMsg} from '@mm-redux/types/general';
|
||||
import {Theme} from '@mm-redux/types/preferences';
|
||||
import ChannelInfoRow from '@screens/channel_info/channel_info_row';
|
||||
import Separator from '@screens/channel_info/separator';
|
||||
import {alertErrorWithFallback} from '@utils/general';
|
||||
import {t} from '@utils/i18n';
|
||||
import {preventDoubleTap} from '@utils/tap';
|
||||
|
||||
interface ArchiveProps {
|
||||
canArchive: boolean;
|
||||
canUnarchive: boolean;
|
||||
channelId: string;
|
||||
close: (redirect: boolean) => void;
|
||||
deleteChannel: (channelId: string) => Promise<ActionResult>;
|
||||
displayName: string;
|
||||
getChannel: (channelId: string) => Promise<ActionResult>;
|
||||
handleSelectChannel: (channelId: string) => Promise<ActionResult>;
|
||||
isLandscape: boolean;
|
||||
isPublic: boolean;
|
||||
unarchiveChannel: (channelId: string) => Promise<ActionResult>;
|
||||
selectPenultimateChannel: (channelId: string) => Promise<ActionResult>;
|
||||
teamId: string;
|
||||
theme: Theme;
|
||||
viewArchivedChannels: boolean;
|
||||
}
|
||||
|
||||
export default class Archive extends PureComponent<ArchiveProps> {
|
||||
static contextTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
alertAndHandleYesAction = (title: FormattedMsg, message: FormattedMsg, onPressAction: () => void) => {
|
||||
const {formatMessage} = this.context.intl;
|
||||
const {displayName, isPublic} = this.props;
|
||||
|
||||
// eslint-disable-next-line multiline-ternary
|
||||
const term = isPublic ? formatMessage({id: 'mobile.channel_info.publicChannel', defaultMessage: 'Public Channel'}) :
|
||||
formatMessage({id: 'mobile.channel_info.privateChannel', defaultMessage: 'Private Channel'});
|
||||
|
||||
Alert.alert(
|
||||
formatMessage(title, {term}),
|
||||
formatMessage(
|
||||
message,
|
||||
{
|
||||
term: term.toLowerCase(),
|
||||
name: displayName,
|
||||
},
|
||||
),
|
||||
[{
|
||||
text: formatMessage({id: 'mobile.channel_info.alertNo', defaultMessage: 'No'}),
|
||||
}, {
|
||||
text: formatMessage({id: 'mobile.channel_info.alertYes', defaultMessage: 'Yes'}),
|
||||
onPress: onPressAction,
|
||||
}],
|
||||
);
|
||||
}
|
||||
|
||||
handleDelete = preventDoubleTap(() => {
|
||||
const {channelId, deleteChannel, displayName, teamId} = this.props;
|
||||
const title = {id: t('mobile.channel_info.alertTitleDeleteChannel'), defaultMessage: 'Archive {term}'};
|
||||
const message = {
|
||||
id: t('mobile.channel_info.alertMessageDeleteChannel'),
|
||||
defaultMessage: 'Are you sure you want to archive the {term} {name}?',
|
||||
};
|
||||
const onPressAction = async () => {
|
||||
const result = await deleteChannel(channelId);
|
||||
if (result.error) {
|
||||
alertErrorWithFallback(
|
||||
this.context.intl,
|
||||
result.error,
|
||||
{
|
||||
id: t('mobile.channel_info.delete_failed'),
|
||||
defaultMessage: "We couldn't archive the channel {displayName}. Please check your connection and try again.",
|
||||
},
|
||||
{
|
||||
displayName,
|
||||
},
|
||||
);
|
||||
if (result.error.server_error_id === 'api.channel.delete_channel.deleted.app_error') {
|
||||
this.props.getChannel(channelId);
|
||||
}
|
||||
} else if (this.props.viewArchivedChannels) {
|
||||
this.props.handleSelectChannel(channelId);
|
||||
this.props.close(false);
|
||||
} else {
|
||||
this.props.selectPenultimateChannel(teamId);
|
||||
this.props.close(false);
|
||||
}
|
||||
};
|
||||
this.alertAndHandleYesAction(title, message, onPressAction);
|
||||
});
|
||||
|
||||
handleUnarchive = preventDoubleTap(() => {
|
||||
const {channelId, displayName} = this.props;
|
||||
const title = {id: t('mobile.channel_info.alertTitleUnarchiveChannel'), defaultMessage: 'Unarchive {term}'};
|
||||
const message = {
|
||||
id: t('mobile.channel_info.alertMessageUnarchiveChannel'),
|
||||
defaultMessage: 'Are you sure you want to unarchive the {term} {name}?',
|
||||
};
|
||||
const onPressAction = async () => {
|
||||
const result = await this.props.unarchiveChannel(channelId);
|
||||
if (result.error) {
|
||||
alertErrorWithFallback(
|
||||
this.context.intl,
|
||||
result.error,
|
||||
{
|
||||
id: t('mobile.channel_info.unarchive_failed'),
|
||||
defaultMessage: "We couldn't unarchive the channel {displayName}. Please check your connection and try again.",
|
||||
},
|
||||
{
|
||||
displayName,
|
||||
},
|
||||
);
|
||||
if (result.error.server_error_id === 'api.channel.unarchive_channel.unarchive.app_error') {
|
||||
this.props.getChannel(channelId);
|
||||
}
|
||||
} else {
|
||||
this.props.close(false);
|
||||
}
|
||||
};
|
||||
this.alertAndHandleYesAction(title, message, onPressAction);
|
||||
});
|
||||
|
||||
render() {
|
||||
const {canArchive, canUnarchive, isLandscape, theme} = this.props;
|
||||
|
||||
if (!canArchive && !canUnarchive) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let element;
|
||||
if (canUnarchive) {
|
||||
element = (
|
||||
<ChannelInfoRow
|
||||
action={this.handleUnarchive}
|
||||
defaultMessage='Unarchive Channel'
|
||||
icon='archive'
|
||||
iconColor='#CA3B27'
|
||||
textColor='#CA3B27'
|
||||
textId={t('mobile.routes.channelInfo.unarchive_channel')}
|
||||
theme={theme}
|
||||
isLandscape={isLandscape}
|
||||
rightArrow={false}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
element = (
|
||||
<ChannelInfoRow
|
||||
action={this.handleDelete}
|
||||
defaultMessage='Archive Channel'
|
||||
iconColor='#CA3B27'
|
||||
icon='archive'
|
||||
textId={t('mobile.routes.channelInfo.delete_channel')}
|
||||
textColor='#CA3B27'
|
||||
theme={theme}
|
||||
isLandscape={isLandscape}
|
||||
rightArrow={false}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Separator theme={theme}/>
|
||||
{element}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
76
app/screens/channel_info/archive/index.js
Normal file
76
app/screens/channel_info/archive/index.js
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
import {
|
||||
handleSelectChannel,
|
||||
selectPenultimateChannel,
|
||||
} from '@actions/views/channel';
|
||||
import {deleteChannel, getChannel, unarchiveChannel} from '@mm-redux/actions/channels';
|
||||
import {General} from '@mm-redux/constants';
|
||||
import Permissions from '@mm-redux/constants/permissions';
|
||||
import {getCurrentChannel, isCurrentChannelReadOnly} from '@mm-redux/selectors/entities/channels';
|
||||
import {getConfig, getLicense, hasNewPermissions} from '@mm-redux/selectors/entities/general';
|
||||
import {haveITeamPermission} from '@mm-redux/selectors/entities/roles';
|
||||
import {getCurrentTeamId} from '@mm-redux/selectors/entities/teams';
|
||||
import {getCurrentUser, getCurrentUserRoles} from '@mm-redux/selectors/entities/users';
|
||||
import {showDeleteOption} from '@mm-redux/utils/channel_utils';
|
||||
import {isMinimumServerVersion} from '@mm-redux/utils/helpers';
|
||||
import {isAdmin as checkIsAdmin, isChannelAdmin as checkIsChannelAdmin, isSystemAdmin as checkIsSystemAdmin} from '@mm-redux/utils/user_utils';
|
||||
import {isGuest as isUserGuest} from '@utils/users';
|
||||
|
||||
import Archive from './archive';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
const config = getConfig(state);
|
||||
const license = getLicense(state);
|
||||
const currentChannel = getCurrentChannel(state);
|
||||
const currentUser = getCurrentUser(state);
|
||||
const roles = getCurrentUserRoles(state) || '';
|
||||
const isGuest = isUserGuest(currentUser);
|
||||
const isDefaultChannel = currentChannel.name === General.DEFAULT_CHANNEL;
|
||||
const isDirectMessage = currentChannel.type === General.DM_CHANNEL;
|
||||
const isGroupMessage = currentChannel.type === General.GM_CHANNEL;
|
||||
const isAdmin = checkIsAdmin(roles);
|
||||
const isChannelAdmin = checkIsChannelAdmin(roles);
|
||||
const isSystemAdmin = checkIsSystemAdmin(roles);
|
||||
const canLeave = (!isDefaultChannel && !isDirectMessage && !isGroupMessage) || (isDefaultChannel && isGuest);
|
||||
const canDelete = showDeleteOption(state, config, license, currentChannel, isAdmin, isSystemAdmin, isChannelAdmin);
|
||||
const canUnarchive = (currentChannel?.delete_at > 0 && !isDirectMessage && !isGroupMessage);
|
||||
const viewArchivedChannels = config.ExperimentalViewArchivedChannels === 'true';
|
||||
const {serverVersion} = state.entities.general;
|
||||
|
||||
let isReadOnly = false;
|
||||
if (currentUser?.id && currentChannel?.id) {
|
||||
isReadOnly = isCurrentChannelReadOnly(state) || false;
|
||||
}
|
||||
|
||||
let canUnarchiveChannel = false;
|
||||
if (hasNewPermissions(state) && isMinimumServerVersion(serverVersion, 5, 20)) {
|
||||
canUnarchiveChannel = haveITeamPermission(state, {
|
||||
team: getCurrentTeamId(state),
|
||||
permission: Permissions.MANAGE_TEAM,
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
canArchive: (canLeave && canDelete && !isReadOnly),
|
||||
canUnarchive: canUnarchive && canUnarchiveChannel,
|
||||
channelId: currentChannel?.id || '',
|
||||
displayName: (currentChannel?.display_name || '').trim(),
|
||||
isPublic: currentChannel?.type === General.OPEN_CHANNEL,
|
||||
teamId: currentChannel?.team_id || '',
|
||||
viewArchivedChannels,
|
||||
};
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
deleteChannel,
|
||||
getChannel,
|
||||
handleSelectChannel,
|
||||
unarchiveChannel,
|
||||
selectPenultimateChannel,
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Archive);
|
||||
|
|
@ -5,69 +5,47 @@ import React, {PureComponent} from 'react';
|
|||
import PropTypes from 'prop-types';
|
||||
import {intlShape} from 'react-intl';
|
||||
import {
|
||||
Alert,
|
||||
ScrollView,
|
||||
View,
|
||||
} from 'react-native';
|
||||
import {Navigation} from 'react-native-navigation';
|
||||
|
||||
import {dismissModal, goToScreen, showModalOverCurrentContext} from '@actions/navigation';
|
||||
import pinIcon from '@assets/images/channel_info/pin.png';
|
||||
import {dismissModal, showModalOverCurrentContext} from '@actions/navigation';
|
||||
import StatusBar from '@components/status_bar';
|
||||
import {General, Users} from '@mm-redux/constants';
|
||||
import {alertErrorWithFallback} from '@utils/general';
|
||||
import {t} from '@utils/i18n';
|
||||
import {preventDoubleTap} from '@utils/tap';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
|
||||
import AddMembers from './add_members';
|
||||
import Archive from './archive';
|
||||
import ChannelInfoHeader from './channel_info_header';
|
||||
import ChannelInfoRow from './channel_info_row';
|
||||
import ConvertPrivate from './convert_private';
|
||||
import EditChannel from './edit_channel';
|
||||
import Favorite from './favorite';
|
||||
import IgnoreMentions from './ignore_mentions';
|
||||
import Leave from './leave';
|
||||
import ManageMembers from './manage_members';
|
||||
import Mute from './mute';
|
||||
import Pinned from './pinned';
|
||||
import Separator from './separator';
|
||||
|
||||
export default class ChannelInfo extends PureComponent {
|
||||
static propTypes = {
|
||||
actions: PropTypes.shape({
|
||||
clearPinnedPosts: PropTypes.func.isRequired,
|
||||
closeDMChannel: PropTypes.func.isRequired,
|
||||
closeGMChannel: PropTypes.func.isRequired,
|
||||
convertChannelToPrivate: PropTypes.func.isRequired,
|
||||
deleteChannel: PropTypes.func.isRequired,
|
||||
unarchiveChannel: PropTypes.func.isRequired,
|
||||
getChannelStats: PropTypes.func.isRequired,
|
||||
getChannel: PropTypes.func.isRequired,
|
||||
leaveChannel: PropTypes.func.isRequired,
|
||||
loadChannelsByTeamName: PropTypes.func.isRequired,
|
||||
favoriteChannel: PropTypes.func.isRequired,
|
||||
unfavoriteChannel: PropTypes.func.isRequired,
|
||||
getCustomEmojisInText: PropTypes.func.isRequired,
|
||||
selectFocusedPostId: PropTypes.func.isRequired,
|
||||
updateChannelNotifyProps: PropTypes.func.isRequired,
|
||||
selectPenultimateChannel: PropTypes.func.isRequired,
|
||||
handleSelectChannel: PropTypes.func.isRequired,
|
||||
setChannelDisplayName: PropTypes.func.isRequired,
|
||||
}),
|
||||
componentId: PropTypes.string,
|
||||
viewArchivedChannels: PropTypes.bool.isRequired,
|
||||
canDeleteChannel: PropTypes.bool.isRequired,
|
||||
canUnarchiveChannel: PropTypes.bool.isRequired,
|
||||
currentChannel: PropTypes.object.isRequired,
|
||||
currentChannelCreatorName: PropTypes.string,
|
||||
currentChannelMemberCount: PropTypes.number,
|
||||
currentChannelGuestCount: PropTypes.number,
|
||||
currentChannelPinnedPostCount: PropTypes.number,
|
||||
currentChannelMemberCount: PropTypes.number,
|
||||
currentUserId: PropTypes.string,
|
||||
currentUserIsGuest: PropTypes.bool,
|
||||
isBot: PropTypes.bool.isRequired,
|
||||
isLandscape: PropTypes.bool.isRequired,
|
||||
isTeammateGuest: PropTypes.bool.isRequired,
|
||||
status: PropTypes.string,
|
||||
theme: PropTypes.object.isRequired,
|
||||
isChannelMuted: PropTypes.bool.isRequired,
|
||||
isCurrent: PropTypes.bool.isRequired,
|
||||
isFavorite: PropTypes.bool.isRequired,
|
||||
canConvertChannel: PropTypes.bool.isRequired,
|
||||
canManageUsers: PropTypes.bool.isRequired,
|
||||
canEditChannel: PropTypes.bool.isRequired,
|
||||
ignoreChannelMentions: PropTypes.bool.isRequired,
|
||||
isBot: PropTypes.bool.isRequired,
|
||||
isTeammateGuest: PropTypes.bool.isRequired,
|
||||
isLandscape: PropTypes.bool.isRequired,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
|
|
@ -78,30 +56,6 @@ export default class ChannelInfo extends PureComponent {
|
|||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
isFavorite: props.isFavorite,
|
||||
isMuted: props.isChannelMuted,
|
||||
ignoreChannelMentions: props.ignoreChannelMentions,
|
||||
};
|
||||
}
|
||||
|
||||
static getDerivedStateFromProps(nextProps, state) {
|
||||
if (state.isFavorite !== nextProps.isFavorite ||
|
||||
state.isMuted !== nextProps.isChannelMuted ||
|
||||
state.ignoreChannelMentions !== nextProps.ignoreChannelMentions) {
|
||||
return {
|
||||
isFavorite: nextProps.isFavorite,
|
||||
isMuted: nextProps.isChannelMuted,
|
||||
ignoreChannelMentions: nextProps.ignoreChannelMentions,
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.navigationEventListener = Navigation.events().bindComponent(this);
|
||||
this.props.actions.getChannelStats(this.props.currentChannel.id);
|
||||
|
|
@ -124,234 +78,6 @@ export default class ChannelInfo extends PureComponent {
|
|||
dismissModal();
|
||||
};
|
||||
|
||||
goToChannelAddMembers = preventDoubleTap(() => {
|
||||
const {intl} = this.context;
|
||||
const screen = 'ChannelAddMembers';
|
||||
const title = intl.formatMessage({id: 'channel_header.addMembers', defaultMessage: 'Add Members'});
|
||||
|
||||
goToScreen(screen, title);
|
||||
});
|
||||
|
||||
goToChannelMembers = preventDoubleTap(() => {
|
||||
const {canManageUsers} = this.props;
|
||||
const {intl} = this.context;
|
||||
const id = canManageUsers ? t('channel_header.manageMembers') : t('channel_header.viewMembers');
|
||||
const defaultMessage = canManageUsers ? 'Manage Members' : 'View Members';
|
||||
const screen = 'ChannelMembers';
|
||||
const title = intl.formatMessage({id, defaultMessage});
|
||||
|
||||
goToScreen(screen, title);
|
||||
});
|
||||
|
||||
goToPinnedPosts = preventDoubleTap(() => {
|
||||
const {currentChannel} = this.props;
|
||||
const {formatMessage} = this.context.intl;
|
||||
const id = t('channel_header.pinnedPosts');
|
||||
const defaultMessage = 'Pinned Posts';
|
||||
const screen = 'PinnedPosts';
|
||||
const title = formatMessage({id, defaultMessage});
|
||||
const passProps = {
|
||||
currentChannelId: currentChannel.id,
|
||||
};
|
||||
|
||||
goToScreen(screen, title, passProps);
|
||||
});
|
||||
|
||||
handleChannelEdit = preventDoubleTap(() => {
|
||||
const {intl} = this.context;
|
||||
const id = t('mobile.channel_info.edit');
|
||||
const defaultMessage = 'Edit Channel';
|
||||
const screen = 'EditChannel';
|
||||
const title = intl.formatMessage({id, defaultMessage});
|
||||
|
||||
goToScreen(screen, title);
|
||||
});
|
||||
|
||||
handleConfirmConvertToPrivate = preventDoubleTap(async () => {
|
||||
const {actions, currentChannel} = this.props;
|
||||
const result = await actions.convertChannelToPrivate(currentChannel.id);
|
||||
const displayName = {displayName: currentChannel.display_name.trim()};
|
||||
const {formatMessage} = this.context.intl;
|
||||
if (result.error) {
|
||||
alertErrorWithFallback(
|
||||
this.context.intl,
|
||||
result.error,
|
||||
{
|
||||
id: t('mobile.channel_info.convert_failed'),
|
||||
defaultMessage: 'We were unable to convert {displayName} to a private channel.',
|
||||
},
|
||||
{
|
||||
displayName,
|
||||
},
|
||||
[{
|
||||
text: formatMessage({id: 'mobile.share_extension.error_close', defaultMessage: 'Close'}),
|
||||
}, {
|
||||
text: formatMessage({id: 'mobile.terms_of_service.alert_retry', defaultMessage: 'Try Again'}),
|
||||
onPress: this.handleConfirmConvertToPrivate,
|
||||
}],
|
||||
);
|
||||
} else {
|
||||
Alert.alert(
|
||||
'',
|
||||
formatMessage({id: t('mobile.channel_info.convert_success'), defaultMessage: '{displayName} is now a private channel.'}, displayName),
|
||||
);
|
||||
}
|
||||
})
|
||||
|
||||
handleConvertToPrivate = preventDoubleTap(() => {
|
||||
const {currentChannel} = this.props;
|
||||
const {formatMessage} = this.context.intl;
|
||||
const displayName = {displayName: currentChannel.display_name.trim()};
|
||||
const title = {id: t('mobile.channel_info.alertTitleConvertChannel'), defaultMessage: 'Convert {displayName} to a private channel?'};
|
||||
const message = {
|
||||
id: t('mobile.channel_info.alertMessageConvertChannel'),
|
||||
defaultMessage: 'When you convert {displayName} to a private channel, history and membership are preserved. Publicly shared files remain accessible to anyone with the link. Membership in a private channel is by invitation only.\n\nThe change is permanent and cannot be undone.\n\nAre you sure you want to convert {displayName} to a private channel?',
|
||||
};
|
||||
|
||||
Alert.alert(
|
||||
formatMessage(title, displayName),
|
||||
formatMessage(message, displayName),
|
||||
[{
|
||||
text: formatMessage({id: 'mobile.channel_info.alertNo', defaultMessage: 'No'}),
|
||||
}, {
|
||||
text: formatMessage({id: 'mobile.channel_info.alertYes', defaultMessage: 'Yes'}),
|
||||
onPress: this.handleConfirmConvertToPrivate,
|
||||
}],
|
||||
);
|
||||
});
|
||||
|
||||
handleLeave = preventDoubleTap(() => {
|
||||
const title = {id: t('mobile.channel_info.alertTitleLeaveChannel'), defaultMessage: 'Leave {term}'};
|
||||
const message = {
|
||||
id: t('mobile.channel_info.alertMessageLeaveChannel'),
|
||||
defaultMessage: 'Are you sure you want to leave the {term} {name}?',
|
||||
};
|
||||
const onPressAction = () => {
|
||||
this.props.actions.leaveChannel(this.props.currentChannel, true).then(() => {
|
||||
this.close();
|
||||
});
|
||||
};
|
||||
this.alertAndHandleYesAction(title, message, onPressAction);
|
||||
});
|
||||
|
||||
handleDelete = preventDoubleTap(() => {
|
||||
const channel = this.props.currentChannel;
|
||||
const title = {id: t('mobile.channel_info.alertTitleDeleteChannel'), defaultMessage: 'Archive {term}'};
|
||||
const message = {
|
||||
id: t('mobile.channel_info.alertMessageDeleteChannel'),
|
||||
defaultMessage: 'Are you sure you want to archive the {term} {name}?',
|
||||
};
|
||||
const onPressAction = async () => {
|
||||
const result = await this.props.actions.deleteChannel(channel.id);
|
||||
if (result.error) {
|
||||
alertErrorWithFallback(
|
||||
this.context.intl,
|
||||
result.error,
|
||||
{
|
||||
id: t('mobile.channel_info.delete_failed'),
|
||||
defaultMessage: "We couldn't archive the channel {displayName}. Please check your connection and try again.",
|
||||
},
|
||||
{
|
||||
displayName: channel.display_name.trim(),
|
||||
},
|
||||
);
|
||||
if (result.error.server_error_id === 'api.channel.delete_channel.deleted.app_error') {
|
||||
this.props.actions.getChannel(channel.id);
|
||||
}
|
||||
} else if (this.props.viewArchivedChannels) {
|
||||
this.props.actions.handleSelectChannel(channel.id);
|
||||
this.close(false);
|
||||
} else {
|
||||
this.props.actions.selectPenultimateChannel(channel.team_id);
|
||||
this.close(false);
|
||||
}
|
||||
};
|
||||
this.alertAndHandleYesAction(title, message, onPressAction);
|
||||
});
|
||||
|
||||
handleUnarchive = preventDoubleTap(() => {
|
||||
const channel = this.props.currentChannel;
|
||||
const title = {id: t('mobile.channel_info.alertTitleUnarchiveChannel'), defaultMessage: 'Unarchive {term}'};
|
||||
const message = {
|
||||
id: t('mobile.channel_info.alertMessageUnarchiveChannel'),
|
||||
defaultMessage: 'Are you sure you want to unarchive the {term} {name}?',
|
||||
};
|
||||
const onPressAction = async () => {
|
||||
const result = await this.props.actions.unarchiveChannel(channel.id);
|
||||
if (result.error) {
|
||||
alertErrorWithFallback(
|
||||
this.context.intl,
|
||||
result.error,
|
||||
{
|
||||
id: t('mobile.channel_info.unarchive_failed'),
|
||||
defaultMessage: "We couldn't unarchive the channel {displayName}. Please check your connection and try again.",
|
||||
},
|
||||
{
|
||||
displayName: channel.display_name.trim(),
|
||||
},
|
||||
);
|
||||
if (result.error.server_error_id === 'api.channel.unarchive_channel.unarchive.app_error') {
|
||||
this.props.actions.getChannel(channel.id);
|
||||
}
|
||||
} else {
|
||||
this.close(false);
|
||||
}
|
||||
};
|
||||
this.alertAndHandleYesAction(title, message, onPressAction);
|
||||
});
|
||||
|
||||
alertAndHandleYesAction = (title, message, onPressAction) => {
|
||||
const {formatMessage} = this.context.intl;
|
||||
const channel = this.props.currentChannel;
|
||||
const term = channel.type === General.OPEN_CHANNEL ?
|
||||
formatMessage({id: 'mobile.channel_info.publicChannel', defaultMessage: 'Public Channel'}) :
|
||||
formatMessage({id: 'mobile.channel_info.privateChannel', defaultMessage: 'Private Channel'});
|
||||
|
||||
Alert.alert(
|
||||
formatMessage(title, {term}),
|
||||
formatMessage(
|
||||
message,
|
||||
{
|
||||
term: term.toLowerCase(),
|
||||
name: channel.display_name.trim(),
|
||||
},
|
||||
),
|
||||
[{
|
||||
text: formatMessage({id: 'mobile.channel_info.alertNo', defaultMessage: 'No'}),
|
||||
}, {
|
||||
text: formatMessage({id: 'mobile.channel_info.alertYes', defaultMessage: 'Yes'}),
|
||||
onPress: onPressAction,
|
||||
}],
|
||||
);
|
||||
}
|
||||
|
||||
handleClose = preventDoubleTap(() => {
|
||||
const {currentChannel, isCurrent, isFavorite} = this.props;
|
||||
const channel = Object.assign({}, currentChannel, {isCurrent}, {isFavorite});
|
||||
const {closeDMChannel, closeGMChannel} = this.props.actions;
|
||||
|
||||
switch (channel.type) {
|
||||
case General.DM_CHANNEL:
|
||||
closeDMChannel(channel).then(() => {
|
||||
this.close();
|
||||
});
|
||||
break;
|
||||
case General.GM_CHANNEL:
|
||||
closeGMChannel(channel).then(() => {
|
||||
this.close();
|
||||
});
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
handleFavorite = preventDoubleTap(() => {
|
||||
const {isFavorite, actions, currentChannel} = this.props;
|
||||
const {favoriteChannel, unfavoriteChannel} = actions;
|
||||
const toggleFavorite = isFavorite ? unfavoriteChannel : favoriteChannel;
|
||||
this.setState({isFavorite: !isFavorite});
|
||||
toggleFavorite(currentChannel.id);
|
||||
});
|
||||
|
||||
handleClosePermalink = () => {
|
||||
const {actions} = this.props;
|
||||
actions.selectFocusedPostId('');
|
||||
|
|
@ -363,29 +89,6 @@ export default class ChannelInfo extends PureComponent {
|
|||
this.showPermalinkView(postId);
|
||||
};
|
||||
|
||||
handleMuteChannel = preventDoubleTap(() => {
|
||||
const {actions, currentChannel, currentUserId, isChannelMuted} = this.props;
|
||||
const {updateChannelNotifyProps} = actions;
|
||||
const opts = {
|
||||
mark_unread: isChannelMuted ? 'all' : 'mention',
|
||||
};
|
||||
|
||||
this.setState({isMuted: !isChannelMuted});
|
||||
updateChannelNotifyProps(currentUserId, currentChannel.id, opts);
|
||||
});
|
||||
|
||||
handleIgnoreChannelMentions = preventDoubleTap(() => {
|
||||
const {actions, currentChannel, currentUserId, ignoreChannelMentions} = this.props;
|
||||
const {updateChannelNotifyProps} = actions;
|
||||
|
||||
const opts = {
|
||||
ignore_channel_mentions: ignoreChannelMentions ? Users.IGNORE_CHANNEL_MENTIONS_OFF : Users.IGNORE_CHANNEL_MENTIONS_ON,
|
||||
};
|
||||
|
||||
this.setState({ignoreChannelMentions: !ignoreChannelMentions});
|
||||
updateChannelNotifyProps(currentUserId, currentChannel.id, opts);
|
||||
});
|
||||
|
||||
showPermalinkView = (postId) => {
|
||||
const {actions} = this.props;
|
||||
const screen = 'Permalink';
|
||||
|
|
@ -405,194 +108,66 @@ export default class ChannelInfo extends PureComponent {
|
|||
showModalOverCurrentContext(screen, passProps, options);
|
||||
};
|
||||
|
||||
renderViewOrManageMembersRow = () => {
|
||||
const channel = this.props.currentChannel;
|
||||
const isDirectMessage = channel.type === General.DM_CHANNEL;
|
||||
|
||||
return !isDirectMessage;
|
||||
};
|
||||
|
||||
renderLeaveOrDeleteChannelRow = () => {
|
||||
const channel = this.props.currentChannel;
|
||||
const isGuest = this.props.currentUserIsGuest;
|
||||
const isDefaultChannel = channel.name === General.DEFAULT_CHANNEL;
|
||||
const isDirectMessage = channel.type === General.DM_CHANNEL;
|
||||
const isGroupMessage = channel.type === General.GM_CHANNEL;
|
||||
|
||||
return (!isDefaultChannel && !isDirectMessage && !isGroupMessage) || (isDefaultChannel && isGuest);
|
||||
};
|
||||
|
||||
renderCloseDirect = () => {
|
||||
const channel = this.props.currentChannel;
|
||||
const isDirectMessage = channel.type === General.DM_CHANNEL;
|
||||
const isGroupMessage = channel.type === General.GM_CHANNEL;
|
||||
|
||||
return isDirectMessage || isGroupMessage;
|
||||
};
|
||||
|
||||
renderUnarchiveChannel = () => {
|
||||
const {canUnarchiveChannel} = this.props;
|
||||
if (!canUnarchiveChannel) {
|
||||
return false;
|
||||
}
|
||||
const channel = this.props.currentChannel;
|
||||
const channelIsArchived = channel.delete_at !== 0;
|
||||
const isDirectMessage = channel.type === General.DM_CHANNEL;
|
||||
const isGroupMessage = channel.type === General.GM_CHANNEL;
|
||||
|
||||
return channelIsArchived && (!isDirectMessage && !isGroupMessage);
|
||||
};
|
||||
|
||||
renderConvertToPrivateRow = () => {
|
||||
const {currentChannel, canConvertChannel} = this.props;
|
||||
const isDefaultChannel = currentChannel.name === General.DEFAULT_CHANNEL;
|
||||
const isPublicChannel = currentChannel.type === General.OPEN_CHANNEL;
|
||||
return !isDefaultChannel && isPublicChannel && canConvertChannel;
|
||||
}
|
||||
|
||||
actionsRows = (style, channelIsArchived) => {
|
||||
const {
|
||||
currentChannelMemberCount,
|
||||
currentChannelPinnedPostCount,
|
||||
canManageUsers,
|
||||
canEditChannel,
|
||||
theme,
|
||||
currentChannel,
|
||||
isLandscape,
|
||||
} = this.props;
|
||||
const {currentChannel, currentUserId, isLandscape, theme} = this.props;
|
||||
|
||||
if (channelIsArchived) {
|
||||
return (this.renderViewOrManageMembersRow() &&
|
||||
<View>
|
||||
<ChannelInfoRow
|
||||
action={this.goToChannelMembers}
|
||||
defaultMessage={canManageUsers ? 'Manage Members' : 'View Members'}
|
||||
detail={currentChannelMemberCount}
|
||||
icon='users'
|
||||
textId={canManageUsers ? t('channel_header.manageMembers') : t('channel_header.viewMembers')}
|
||||
theme={theme}
|
||||
isLandscape={isLandscape}
|
||||
/>
|
||||
</View>);
|
||||
return (
|
||||
<ManageMembers
|
||||
isLandscape={isLandscape}
|
||||
theme={theme}
|
||||
separator={false}
|
||||
/>);
|
||||
}
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<ChannelInfoRow
|
||||
action={this.handleFavorite}
|
||||
defaultMessage='Favorite'
|
||||
detail={this.state.isFavorite}
|
||||
icon='star-o'
|
||||
textId={t('mobile.routes.channelInfo.favorite')}
|
||||
togglable={true}
|
||||
theme={theme}
|
||||
<>
|
||||
<Favorite
|
||||
channelId={currentChannel.id}
|
||||
isLandscape={isLandscape}
|
||||
/>
|
||||
<View style={style.separator}/>
|
||||
<ChannelInfoRow
|
||||
action={this.handleMuteChannel}
|
||||
defaultMessage='Mute channel'
|
||||
detail={this.state.isMuted}
|
||||
icon='bell-slash-o'
|
||||
textId={t('channel_notifications.muteChannel.settings')}
|
||||
togglable={true}
|
||||
theme={theme}
|
||||
isLandscape={isLandscape}
|
||||
/>
|
||||
<View style={style.separator}/>
|
||||
<ChannelInfoRow
|
||||
action={this.handleIgnoreChannelMentions}
|
||||
defaultMessage='Ignore @channel, @here, @all'
|
||||
detail={this.state.ignoreChannelMentions}
|
||||
icon='at'
|
||||
textId={t('channel_notifications.ignoreChannelMentions.settings')}
|
||||
togglable={true}
|
||||
<Separator theme={theme}/>
|
||||
<Mute
|
||||
channelId={currentChannel.id}
|
||||
isLandscape={isLandscape}
|
||||
userId={currentUserId}
|
||||
theme={theme}
|
||||
isLandscape={isLandscape}
|
||||
/>
|
||||
<View style={style.separator}/>
|
||||
<ChannelInfoRow
|
||||
action={this.goToPinnedPosts}
|
||||
defaultMessage='Pinned Posts'
|
||||
detail={currentChannelPinnedPostCount}
|
||||
image={pinIcon}
|
||||
textId={t('channel_header.pinnedPosts')}
|
||||
<Separator theme={theme}/>
|
||||
<IgnoreMentions
|
||||
channelId={currentChannel.id}
|
||||
isLandscape={isLandscape}
|
||||
theme={theme}
|
||||
isLandscape={isLandscape}
|
||||
/>
|
||||
{
|
||||
|
||||
/**
|
||||
<ChannelInfoRow
|
||||
action={() => true}
|
||||
defaultMessage='Notification Preferences'
|
||||
icon='bell-o'
|
||||
textId='channel_header.notificationPreferences'
|
||||
theme={theme}
|
||||
/>
|
||||
<View style={style.separator}/>
|
||||
**/
|
||||
}
|
||||
{this.renderViewOrManageMembersRow() &&
|
||||
<React.Fragment>
|
||||
<View style={style.separator}/>
|
||||
<ChannelInfoRow
|
||||
action={this.goToChannelMembers}
|
||||
defaultMessage={canManageUsers ? 'Manage Members' : 'View Members'}
|
||||
detail={currentChannelMemberCount}
|
||||
icon='users'
|
||||
textId={canManageUsers ? t('channel_header.manageMembers') : t('channel_header.viewMembers')}
|
||||
theme={theme}
|
||||
isLandscape={isLandscape}
|
||||
/>
|
||||
</React.Fragment>
|
||||
}
|
||||
{canManageUsers && !currentChannel.group_constrained &&
|
||||
<React.Fragment>
|
||||
<View style={style.separator}/>
|
||||
<ChannelInfoRow
|
||||
action={this.goToChannelAddMembers}
|
||||
defaultMessage='Add Members'
|
||||
icon='user-plus'
|
||||
textId={t('channel_header.addMembers')}
|
||||
theme={theme}
|
||||
isLandscape={isLandscape}
|
||||
/>
|
||||
</React.Fragment>
|
||||
}
|
||||
{this.renderConvertToPrivateRow() && (
|
||||
<React.Fragment>
|
||||
<View style={style.separator}/>
|
||||
<ChannelInfoRow
|
||||
action={this.handleConvertToPrivate}
|
||||
defaultMessage='Convert to Private Channel'
|
||||
icon='lock'
|
||||
textId={t('mobile.channel_info.convert')}
|
||||
theme={theme}
|
||||
isLandscape={isLandscape}
|
||||
/>
|
||||
</React.Fragment>
|
||||
)}
|
||||
{canEditChannel && (
|
||||
<React.Fragment>
|
||||
<View style={style.separator}/>
|
||||
<ChannelInfoRow
|
||||
action={this.handleChannelEdit}
|
||||
defaultMessage='Edit Channel'
|
||||
icon='edit'
|
||||
textId={t('mobile.channel_info.edit')}
|
||||
theme={theme}
|
||||
isLandscape={isLandscape}
|
||||
/>
|
||||
</React.Fragment>
|
||||
)}
|
||||
</React.Fragment>
|
||||
<Separator theme={theme}/>
|
||||
<Pinned
|
||||
channelId={currentChannel.id}
|
||||
isLandscape={isLandscape}
|
||||
theme={theme}
|
||||
/>
|
||||
<ManageMembers
|
||||
isLandscape={isLandscape}
|
||||
theme={theme}
|
||||
/>
|
||||
<AddMembers
|
||||
isLandscape={isLandscape}
|
||||
theme={theme}
|
||||
/>
|
||||
<ConvertPrivate
|
||||
isLandscape={isLandscape}
|
||||
theme={theme}
|
||||
/>
|
||||
<EditChannel
|
||||
isLandscape={isLandscape}
|
||||
theme={theme}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
canDeleteChannel,
|
||||
currentChannel,
|
||||
currentChannelCreatorName,
|
||||
currentChannelMemberCount,
|
||||
|
|
@ -607,26 +182,13 @@ export default class ChannelInfo extends PureComponent {
|
|||
const style = getStyleSheet(theme);
|
||||
const channelIsArchived = currentChannel.delete_at !== 0;
|
||||
|
||||
let i18nId;
|
||||
let defaultMessage;
|
||||
switch (currentChannel.type) {
|
||||
case General.DM_CHANNEL:
|
||||
i18nId = t('mobile.channel_list.closeDM');
|
||||
defaultMessage = 'Close Direct Message';
|
||||
break;
|
||||
case General.GM_CHANNEL:
|
||||
i18nId = t('mobile.channel_list.closeGM');
|
||||
defaultMessage = 'Close Group Message';
|
||||
break;
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={style.container}>
|
||||
<StatusBar/>
|
||||
<ScrollView
|
||||
style={style.scrollView}
|
||||
>
|
||||
{currentChannel.hasOwnProperty('id') &&
|
||||
{Boolean(currentChannel?.id) &&
|
||||
<ChannelInfoHeader
|
||||
createAt={currentChannel.create_at}
|
||||
creator={currentChannelCreatorName}
|
||||
|
|
@ -648,62 +210,19 @@ export default class ChannelInfo extends PureComponent {
|
|||
}
|
||||
<View style={style.rowsContainer}>
|
||||
{this.actionsRows(style, channelIsArchived)}
|
||||
{this.renderLeaveOrDeleteChannelRow() &&
|
||||
<React.Fragment>
|
||||
<View style={style.separator}/>
|
||||
<ChannelInfoRow
|
||||
action={this.handleLeave}
|
||||
defaultMessage='Leave Channel'
|
||||
icon='sign-out'
|
||||
textId={t('navbar.leave')}
|
||||
theme={theme}
|
||||
isLandscape={isLandscape}
|
||||
/>
|
||||
{this.renderUnarchiveChannel() &&
|
||||
<React.Fragment>
|
||||
<View style={style.separator}/>
|
||||
<ChannelInfoRow
|
||||
action={this.handleUnarchive}
|
||||
defaultMessage='Unarchive Channel'
|
||||
icon='archive' // might need to change the icon...
|
||||
textId={t('mobile.routes.channelInfo.unarchive_channel')}
|
||||
theme={theme}
|
||||
isLandscape={isLandscape}
|
||||
/>
|
||||
</React.Fragment>
|
||||
}
|
||||
</React.Fragment>
|
||||
}
|
||||
</View>
|
||||
{this.renderLeaveOrDeleteChannelRow() && canDeleteChannel && !channelIsArchived &&
|
||||
<View style={[style.rowsContainer, style.footer]}>
|
||||
<ChannelInfoRow
|
||||
action={this.handleDelete}
|
||||
defaultMessage='Archive Channel'
|
||||
iconColor='#CA3B27'
|
||||
icon='archive'
|
||||
textId={t('mobile.routes.channelInfo.delete_channel')}
|
||||
textColor='#CA3B27'
|
||||
theme={theme}
|
||||
<View style={style.footer}>
|
||||
<Leave
|
||||
close={this.close}
|
||||
isLandscape={isLandscape}
|
||||
theme={theme}
|
||||
/>
|
||||
<Archive
|
||||
close={this.close}
|
||||
isLandscape={isLandscape}
|
||||
theme={theme}
|
||||
/>
|
||||
</View>
|
||||
}
|
||||
{this.renderCloseDirect() &&
|
||||
<View style={[style.rowsContainer, style.footer]}>
|
||||
<ChannelInfoRow
|
||||
action={this.handleClose}
|
||||
defaultMessage={defaultMessage}
|
||||
icon='times'
|
||||
iconColor='#CA3B27'
|
||||
rightArrow={false}
|
||||
textId={i18nId}
|
||||
textColor='#CA3B27'
|
||||
theme={theme}
|
||||
isLandscape={isLandscape}
|
||||
/>
|
||||
</View>
|
||||
}
|
||||
</ScrollView>
|
||||
</View>
|
||||
);
|
||||
|
|
@ -721,10 +240,6 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => {
|
|||
},
|
||||
footer: {
|
||||
marginTop: 40,
|
||||
borderTopWidth: 1,
|
||||
borderBottomWidth: 1,
|
||||
borderTopColor: changeOpacity(theme.centerChannelColor, 0.1),
|
||||
borderBottomColor: changeOpacity(theme.centerChannelColor, 0.1),
|
||||
},
|
||||
rowsContainer: {
|
||||
borderTopWidth: 1,
|
||||
|
|
@ -733,10 +248,5 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => {
|
|||
borderBottomColor: changeOpacity(theme.centerChannelColor, 0.1),
|
||||
backgroundColor: theme.centerChannelBg,
|
||||
},
|
||||
separator: {
|
||||
marginHorizontal: 15,
|
||||
height: 1,
|
||||
backgroundColor: changeOpacity(theme.centerChannelColor, 0.1),
|
||||
},
|
||||
};
|
||||
});
|
||||
|
|
|
|||
|
|
@ -9,11 +9,6 @@ import {General} from '@mm-redux/constants';
|
|||
|
||||
import ChannelInfo from './channel_info';
|
||||
|
||||
// ChannelInfoRow expects to receive the pinIcon as a number
|
||||
jest.mock('@assets/images/channel_info/pin.png', () => {
|
||||
return 1;
|
||||
});
|
||||
|
||||
jest.mock('@utils/theme', () => {
|
||||
const original = jest.requireActual('../../utils/theme');
|
||||
return {
|
||||
|
|
@ -22,7 +17,7 @@ jest.mock('@utils/theme', () => {
|
|||
};
|
||||
});
|
||||
|
||||
describe('channel_info', () => {
|
||||
describe('channelInfo', () => {
|
||||
const intlMock = {
|
||||
formatMessage: jest.fn(),
|
||||
formatDate: jest.fn(),
|
||||
|
|
@ -34,12 +29,6 @@ describe('channel_info', () => {
|
|||
now: jest.fn(),
|
||||
};
|
||||
const baseProps = {
|
||||
canDeleteChannel: true,
|
||||
canUnarchiveChannel: false,
|
||||
canConvertChannel: true,
|
||||
canManageUsers: true,
|
||||
viewArchivedChannels: true,
|
||||
canEditChannel: true,
|
||||
currentChannel: {
|
||||
id: '1234',
|
||||
display_name: 'Channel Name',
|
||||
|
|
@ -54,35 +43,17 @@ describe('channel_info', () => {
|
|||
currentChannelMemberCount: 2,
|
||||
currentChannelGuestCount: 0,
|
||||
currentUserId: '1234',
|
||||
currentUserIsGuest: false,
|
||||
isChannelMuted: false,
|
||||
ignoreChannelMentions: false,
|
||||
isCurrent: true,
|
||||
isFavorite: false,
|
||||
status: 'status',
|
||||
theme: Preferences.THEMES.default,
|
||||
isBot: false,
|
||||
isTeammateGuest: false,
|
||||
isLandscape: false,
|
||||
actions: {
|
||||
clearPinnedPosts: jest.fn(),
|
||||
closeDMChannel: jest.fn(),
|
||||
closeGMChannel: jest.fn(),
|
||||
convertChannelToPrivate: jest.fn(),
|
||||
deleteChannel: jest.fn(),
|
||||
unarchiveChannel: jest.fn(),
|
||||
getChannelStats: jest.fn(),
|
||||
getChannel: jest.fn(),
|
||||
leaveChannel: jest.fn(),
|
||||
loadChannelsByTeamName: jest.fn(),
|
||||
favoriteChannel: jest.fn(),
|
||||
unfavoriteChannel: jest.fn(),
|
||||
getCustomEmojisInText: jest.fn(),
|
||||
selectFocusedPostId: jest.fn(),
|
||||
updateChannelNotifyProps: jest.fn(),
|
||||
selectPenultimateChannel: jest.fn(),
|
||||
setChannelDisplayName: jest.fn(),
|
||||
handleSelectChannel: jest.fn(),
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -96,63 +67,6 @@ describe('channel_info', () => {
|
|||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should render convert to private button when user has team admin permissions', async () => {
|
||||
const wrapper = shallow(
|
||||
<ChannelInfo
|
||||
{...baseProps}
|
||||
/>,
|
||||
{context: {intl: intlMock}},
|
||||
);
|
||||
|
||||
const instance = wrapper.instance();
|
||||
const render = instance.renderConvertToPrivateRow();
|
||||
expect(render).toBeTruthy();
|
||||
});
|
||||
|
||||
test('should not render convert to private button when user is not team admin or above', async () => {
|
||||
const wrapper = shallow(
|
||||
<ChannelInfo
|
||||
{...baseProps}
|
||||
canConvertChannel={false}
|
||||
/>,
|
||||
{context: {intl: intlMock}},
|
||||
);
|
||||
|
||||
const instance = wrapper.instance();
|
||||
const render = instance.renderConvertToPrivateRow();
|
||||
expect(render).toBeFalsy();
|
||||
});
|
||||
|
||||
test('should not render convert to private button currentChannel is already private', async () => {
|
||||
const props = Object.assign({}, baseProps);
|
||||
props.currentChannel.type = General.PRIVATE_CHANNEL;
|
||||
const wrapper = shallow(
|
||||
<ChannelInfo
|
||||
{...props}
|
||||
/>,
|
||||
{context: {intl: intlMock}},
|
||||
);
|
||||
|
||||
const instance = wrapper.instance();
|
||||
const render = instance.renderConvertToPrivateRow();
|
||||
expect(render).toBeFalsy();
|
||||
});
|
||||
|
||||
test('should not render convert to private button when currentChannel is a default channel', async () => {
|
||||
const props = Object.assign({}, baseProps);
|
||||
props.currentChannel.name = General.DEFAULT_CHANNEL;
|
||||
const wrapper = shallow(
|
||||
<ChannelInfo
|
||||
{...props}
|
||||
/>,
|
||||
{context: {intl: intlMock}},
|
||||
);
|
||||
|
||||
const instance = wrapper.instance();
|
||||
const render = instance.renderConvertToPrivateRow();
|
||||
expect(render).toBeFalsy();
|
||||
});
|
||||
|
||||
test('should dismiss modal on close', () => {
|
||||
const dismissModal = jest.spyOn(NavigationActions, 'dismissModal');
|
||||
const wrapper = shallow(
|
||||
|
|
@ -167,38 +81,4 @@ describe('channel_info', () => {
|
|||
instance.close();
|
||||
expect(dismissModal).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('should render unarchive channel button when currentChannel is an archived channel', async () => {
|
||||
const props = Object.assign({}, baseProps);
|
||||
props.canUnarchiveChannel = true;
|
||||
props.currentChannel.delete_at = 1234566;
|
||||
|
||||
const wrapper = shallow(
|
||||
<ChannelInfo
|
||||
{...props}
|
||||
/>,
|
||||
{context: {intl: intlMock}},
|
||||
);
|
||||
|
||||
const instance = wrapper.instance();
|
||||
const render = instance.renderUnarchiveChannel();
|
||||
expect(render).toBeTruthy();
|
||||
});
|
||||
|
||||
test('should not render unarchive channel button when currentChannel is an active channel', async () => {
|
||||
const props = Object.assign({}, baseProps);
|
||||
props.canUnarchiveChannel = false;
|
||||
props.currentChannel.delete_at = 0;
|
||||
|
||||
const wrapper = shallow(
|
||||
<ChannelInfo
|
||||
{...props}
|
||||
/>,
|
||||
{context: {intl: intlMock}},
|
||||
);
|
||||
|
||||
const instance = wrapper.instance();
|
||||
const render = instance.renderUnarchiveChannel();
|
||||
expect(render).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ export default class ChannelInfoHeader extends React.PureComponent {
|
|||
};
|
||||
|
||||
renderHasGuestText = (style) => {
|
||||
const {type, hasGuests, isTeammateGuest} = this.props;
|
||||
const {type, hasGuests, isLandscape, isTeammateGuest} = this.props;
|
||||
if (!hasGuests) {
|
||||
return null;
|
||||
}
|
||||
|
|
@ -74,7 +74,7 @@ export default class ChannelInfoHeader extends React.PureComponent {
|
|||
defaultMessage = 'This channel has guests';
|
||||
}
|
||||
return (
|
||||
<View style={style.section}>
|
||||
<View style={[style.section, padding(isLandscape, -15)]}>
|
||||
<View style={style.row}>
|
||||
<FormattedText
|
||||
style={style.header}
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ channelInfoRow.propTypes = {
|
|||
iconColor: PropTypes.string,
|
||||
image: PropTypes.number,
|
||||
imageTintColor: PropTypes.string,
|
||||
isLandscape: PropTypes.bool,
|
||||
rightArrow: PropTypes.bool,
|
||||
textId: PropTypes.string.isRequired,
|
||||
togglable: PropTypes.bool,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,76 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ChannelInfo -> ConvertPrivate should match snapshot for Convert to Private Channel 1`] = `
|
||||
<React.Fragment>
|
||||
<Separator
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<channelInfoRow
|
||||
action={[Function]}
|
||||
defaultMessage="Convert to Private Channel"
|
||||
icon="lock"
|
||||
isLandscape={false}
|
||||
rightArrow={false}
|
||||
shouldRender={true}
|
||||
textId="mobile.channel_info.convert"
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
togglable={false}
|
||||
/>
|
||||
</React.Fragment>
|
||||
`;
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import {shallowWithIntl} from 'test/intl-test-helper';
|
||||
|
||||
import Preferences from '@mm-redux/constants/preferences';
|
||||
|
||||
import ConvertPrivate from './convert_private';
|
||||
|
||||
jest.mock('@utils/theme', () => {
|
||||
const original = jest.requireActual('../../../utils/theme');
|
||||
return {
|
||||
...original,
|
||||
changeOpacity: jest.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
describe('ChannelInfo -> ConvertPrivate', () => {
|
||||
const baseProps = {
|
||||
canConvert: true,
|
||||
channelId: '123',
|
||||
convertChannelToPrivate: jest.fn(),
|
||||
displayName: 'Test Channel',
|
||||
isLandscape: false,
|
||||
theme: Preferences.THEMES.default,
|
||||
};
|
||||
|
||||
test('should match snapshot for Convert to Private Channel', () => {
|
||||
const wrapper = shallowWithIntl(
|
||||
<ConvertPrivate
|
||||
{...baseProps}
|
||||
/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should match snapshot Convert to Private Channel', () => {
|
||||
const wrapper = shallowWithIntl(
|
||||
<ConvertPrivate
|
||||
{...baseProps}
|
||||
canConvert={false}
|
||||
/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toBeNull();
|
||||
});
|
||||
});
|
||||
103
app/screens/channel_info/convert_private/convert_private.tsx
Normal file
103
app/screens/channel_info/convert_private/convert_private.tsx
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {PureComponent} from 'react';
|
||||
import {Alert} from 'react-native';
|
||||
import {intlShape} from 'react-intl';
|
||||
|
||||
import {ActionResult} from '@mm-redux/types/actions';
|
||||
import {Theme} from '@mm-redux/types/preferences';
|
||||
import ChannelInfoRow from '@screens/channel_info/channel_info_row';
|
||||
import Separator from '@screens/channel_info/separator';
|
||||
import {alertErrorWithFallback} from '@utils/general';
|
||||
import {t} from '@utils/i18n';
|
||||
import {preventDoubleTap} from '@utils/tap';
|
||||
|
||||
interface ConvertPrivateProps {
|
||||
canConvert: boolean;
|
||||
channelId: string;
|
||||
convertChannelToPrivate: (channelId: string) => Promise<ActionResult>;
|
||||
displayName: string;
|
||||
isLandscape: boolean;
|
||||
theme: Theme;
|
||||
}
|
||||
|
||||
export default class ConvertPrivate extends PureComponent<ConvertPrivateProps> {
|
||||
static contextTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
handleConfirmConvertToPrivate = preventDoubleTap(async () => {
|
||||
const {channelId, convertChannelToPrivate, displayName} = this.props;
|
||||
const result = await convertChannelToPrivate(channelId);
|
||||
const {formatMessage} = this.context.intl;
|
||||
if (result.error) {
|
||||
alertErrorWithFallback(
|
||||
this.context.intl,
|
||||
result.error,
|
||||
{
|
||||
id: t('mobile.channel_info.convert_failed'),
|
||||
defaultMessage: 'We were unable to convert {displayName} to a private channel.',
|
||||
},
|
||||
{
|
||||
displayName,
|
||||
},
|
||||
[{
|
||||
text: formatMessage({id: 'mobile.share_extension.error_close', defaultMessage: 'Close'}),
|
||||
}, {
|
||||
text: formatMessage({id: 'mobile.terms_of_service.alert_retry', defaultMessage: 'Try Again'}),
|
||||
onPress: this.handleConfirmConvertToPrivate,
|
||||
}],
|
||||
);
|
||||
} else {
|
||||
Alert.alert(
|
||||
'',
|
||||
formatMessage({id: t('mobile.channel_info.convert_success'), defaultMessage: '{displayName} is now a private channel.'}, displayName),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
handleConvertToPrivate = preventDoubleTap(() => {
|
||||
const {displayName} = this.props;
|
||||
const {formatMessage} = this.context.intl;
|
||||
const title = {id: t('mobile.channel_info.alertTitleConvertChannel'), defaultMessage: 'Convert {displayName} to a private channel?'};
|
||||
const message = {
|
||||
id: t('mobile.channel_info.alertMessageConvertChannel'),
|
||||
defaultMessage: 'When you convert {displayName} to a private channel, history and membership are preserved. Publicly shared files remain accessible to anyone with the link. Membership in a private channel is by invitation only.\n\nThe change is permanent and cannot be undone.\n\nAre you sure you want to convert {displayName} to a private channel?',
|
||||
};
|
||||
|
||||
Alert.alert(
|
||||
formatMessage(title, {displayName}),
|
||||
formatMessage(message, {displayName}),
|
||||
[{
|
||||
text: formatMessage({id: 'mobile.channel_info.alertNo', defaultMessage: 'No'}),
|
||||
}, {
|
||||
text: formatMessage({id: 'mobile.channel_info.alertYes', defaultMessage: 'Yes'}),
|
||||
onPress: this.handleConfirmConvertToPrivate,
|
||||
}],
|
||||
);
|
||||
});
|
||||
|
||||
render() {
|
||||
const {canConvert, isLandscape, theme} = this.props;
|
||||
|
||||
if (!canConvert) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Separator theme={theme}/>
|
||||
<ChannelInfoRow
|
||||
action={this.handleConvertToPrivate}
|
||||
defaultMessage='Convert to Private Channel'
|
||||
icon='lock'
|
||||
isLandscape={isLandscape}
|
||||
rightArrow={false}
|
||||
theme={theme}
|
||||
textId={t('mobile.channel_info.convert')}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
33
app/screens/channel_info/convert_private/index.js
Normal file
33
app/screens/channel_info/convert_private/index.js
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
import {convertChannelToPrivate} from '@mm-redux/actions/channels';
|
||||
import {General} from '@mm-redux/constants';
|
||||
import {getCurrentChannel} from '@mm-redux/selectors/entities/channels';
|
||||
import {getCurrentUserRoles} from '@mm-redux/selectors/entities/users';
|
||||
import {isAdmin as checkIsAdmin} from '@mm-redux/utils/user_utils';
|
||||
|
||||
import ConvertPrivate from './convert_private';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
const currentChannel = getCurrentChannel(state);
|
||||
const isDefaultChannel = currentChannel.name === General.DEFAULT_CHANNEL;
|
||||
const isPublicChannel = currentChannel.type === General.OPEN_CHANNEL;
|
||||
const roles = getCurrentUserRoles(state) || '';
|
||||
const isAdmin = checkIsAdmin(roles);
|
||||
const canConvert = !isDefaultChannel && isPublicChannel && isAdmin;
|
||||
|
||||
return {
|
||||
canConvert,
|
||||
channelId: currentChannel?.id || '',
|
||||
displayName: (currentChannel?.display_name || '').trim(),
|
||||
};
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
convertChannelToPrivate,
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ConvertPrivate);
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ChannelInfo -> EditChannel should match snapshot for Edit Channel 1`] = `
|
||||
<React.Fragment>
|
||||
<Separator
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<channelInfoRow
|
||||
action={[Function]}
|
||||
defaultMessage="Edit Channel"
|
||||
icon="edit"
|
||||
isLandscape={false}
|
||||
rightArrow={true}
|
||||
shouldRender={true}
|
||||
textId="mobile.channel_info.edit"
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
togglable={false}
|
||||
/>
|
||||
</React.Fragment>
|
||||
`;
|
||||
44
app/screens/channel_info/edit_channel/edit_channel.test.js
Normal file
44
app/screens/channel_info/edit_channel/edit_channel.test.js
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import {shallowWithIntl} from 'test/intl-test-helper';
|
||||
|
||||
import Preferences from '@mm-redux/constants/preferences';
|
||||
|
||||
import EditChannel from './edit_channel';
|
||||
|
||||
jest.mock('@utils/theme', () => {
|
||||
const original = jest.requireActual('../../../utils/theme');
|
||||
return {
|
||||
...original,
|
||||
changeOpacity: jest.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
describe('ChannelInfo -> EditChannel', () => {
|
||||
const baseProps = {
|
||||
canEdit: true,
|
||||
isLandscape: false,
|
||||
theme: Preferences.THEMES.default,
|
||||
};
|
||||
|
||||
test('should match snapshot for Edit Channel', () => {
|
||||
const wrapper = shallowWithIntl(
|
||||
<EditChannel
|
||||
{...baseProps}
|
||||
/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should match snapshot Not render EditChannel', () => {
|
||||
const wrapper = shallowWithIntl(
|
||||
<EditChannel
|
||||
{...baseProps}
|
||||
canEdit={false}
|
||||
/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toBeNull();
|
||||
});
|
||||
});
|
||||
56
app/screens/channel_info/edit_channel/edit_channel.tsx
Normal file
56
app/screens/channel_info/edit_channel/edit_channel.tsx
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {PureComponent} from 'react';
|
||||
import {intlShape} from 'react-intl';
|
||||
|
||||
import {goToScreen} from '@actions/navigation';
|
||||
import {Theme} from '@mm-redux/types/preferences';
|
||||
import ChannelInfoRow from '@screens/channel_info/channel_info_row';
|
||||
import Separator from '@screens/channel_info/separator';
|
||||
import {t} from '@utils/i18n';
|
||||
import {preventDoubleTap} from '@utils/tap';
|
||||
|
||||
interface EditChannelProps {
|
||||
canEdit: boolean;
|
||||
isLandscape: boolean;
|
||||
theme: Theme;
|
||||
}
|
||||
|
||||
export default class EditChannel extends PureComponent<EditChannelProps> {
|
||||
static contextTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
handleChannelEdit = preventDoubleTap(() => {
|
||||
const {intl} = this.context;
|
||||
const id = t('mobile.channel_info.edit');
|
||||
const defaultMessage = 'Edit Channel';
|
||||
const screen = 'EditChannel';
|
||||
const title = intl.formatMessage({id, defaultMessage});
|
||||
|
||||
goToScreen(screen, title);
|
||||
});
|
||||
|
||||
render() {
|
||||
const {canEdit, isLandscape, theme} = this.props;
|
||||
|
||||
if (!canEdit) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Separator theme={theme}/>
|
||||
<ChannelInfoRow
|
||||
action={this.handleChannelEdit}
|
||||
defaultMessage='Edit Channel'
|
||||
icon='edit'
|
||||
textId={t('mobile.channel_info.edit')}
|
||||
theme={theme}
|
||||
isLandscape={isLandscape}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
36
app/screens/channel_info/edit_channel/index.js
Normal file
36
app/screens/channel_info/edit_channel/index.js
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
import {getCurrentChannel, isCurrentChannelReadOnly} from '@mm-redux/selectors/entities/channels';
|
||||
import {getConfig, getLicense} from '@mm-redux/selectors/entities/general';
|
||||
import {getCurrentUserId, getCurrentUserRoles} from '@mm-redux/selectors/entities/users';
|
||||
import {showManagementOptions} from '@mm-redux/utils/channel_utils';
|
||||
import {isAdmin as checkIsAdmin, isChannelAdmin as checkIsChannelAdmin, isSystemAdmin as checkIsSystemAdmin} from '@mm-redux/utils/user_utils';
|
||||
|
||||
import EditChannel from './edit_channel';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
const config = getConfig(state);
|
||||
const license = getLicense(state);
|
||||
const currentChannel = getCurrentChannel(state);
|
||||
const currentUserId = getCurrentUserId(state);
|
||||
const roles = getCurrentUserRoles(state) || '';
|
||||
const isAdmin = checkIsAdmin(roles);
|
||||
const isChannelAdmin = checkIsChannelAdmin(roles);
|
||||
const isSystemAdmin = checkIsSystemAdmin(roles);
|
||||
|
||||
let channelIsReadOnly = false;
|
||||
if (currentUserId && currentChannel.id) {
|
||||
channelIsReadOnly = isCurrentChannelReadOnly(state) || false;
|
||||
}
|
||||
|
||||
const canEdit = !channelIsReadOnly && showManagementOptions(state, config, license, currentChannel, isAdmin, isSystemAdmin, isChannelAdmin);
|
||||
|
||||
return {
|
||||
canEdit,
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(EditChannel);
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ChannelInfo -> Favorite should match snapshot for Favorite Channel 1`] = `
|
||||
<channelInfoRow
|
||||
action={[Function]}
|
||||
defaultMessage="Favorite"
|
||||
detail={true}
|
||||
icon="star-o"
|
||||
isLandscape={false}
|
||||
rightArrow={true}
|
||||
shouldRender={true}
|
||||
textId="mobile.routes.channelInfo.favorite"
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
togglable={true}
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`ChannelInfo -> Favorite should match snapshot for Unfavorite Channel 1`] = `
|
||||
<channelInfoRow
|
||||
action={[Function]}
|
||||
defaultMessage="Favorite"
|
||||
detail={false}
|
||||
icon="star-o"
|
||||
isLandscape={false}
|
||||
rightArrow={true}
|
||||
shouldRender={true}
|
||||
textId="mobile.routes.channelInfo.favorite"
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
togglable={true}
|
||||
/>
|
||||
`;
|
||||
47
app/screens/channel_info/favorite/favorite.test.js
Normal file
47
app/screens/channel_info/favorite/favorite.test.js
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import {shallowWithIntl} from 'test/intl-test-helper';
|
||||
|
||||
import Preferences from '@mm-redux/constants/preferences';
|
||||
|
||||
import Favorite from './favorite';
|
||||
|
||||
jest.mock('@utils/theme', () => {
|
||||
const original = jest.requireActual('../../../utils/theme');
|
||||
return {
|
||||
...original,
|
||||
changeOpacity: jest.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
describe('ChannelInfo -> Favorite', () => {
|
||||
const baseProps = {
|
||||
channelId: '123',
|
||||
favoriteChannel: jest.fn(),
|
||||
isFavorite: false,
|
||||
isLandscape: false,
|
||||
unfavoriteChannel: jest.fn(),
|
||||
theme: Preferences.THEMES.default,
|
||||
};
|
||||
|
||||
test('should match snapshot for Favorite Channel', () => {
|
||||
const wrapper = shallowWithIntl(
|
||||
<Favorite
|
||||
{...baseProps}
|
||||
isFavorite={true}
|
||||
/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should match snapshot for Unfavorite Channel', () => {
|
||||
const wrapper = shallowWithIntl(
|
||||
<Favorite
|
||||
{...baseProps}
|
||||
/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
43
app/screens/channel_info/favorite/favorite.tsx
Normal file
43
app/screens/channel_info/favorite/favorite.tsx
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {memo, useState} from 'react';
|
||||
|
||||
import {Theme} from '@mm-redux/types/preferences';
|
||||
import ChannelInfoRow from '@screens/channel_info/channel_info_row';
|
||||
import {t} from '@utils/i18n';
|
||||
import {preventDoubleTap} from '@utils/tap';
|
||||
|
||||
interface FavoriteProps {
|
||||
channelId: string;
|
||||
favoriteChannel: (channelId: string) => void;
|
||||
isFavorite: boolean;
|
||||
isLandscape: boolean;
|
||||
unfavoriteChannel: (channelId: string) => void;
|
||||
theme: Theme;
|
||||
}
|
||||
|
||||
const Favorite = ({channelId, favoriteChannel, isLandscape, isFavorite, unfavoriteChannel, theme}: FavoriteProps) => {
|
||||
const [favorite, setFavorite] = useState(isFavorite);
|
||||
|
||||
const handleFavorite = preventDoubleTap(() => {
|
||||
const toggleFavorite = favorite ? unfavoriteChannel : favoriteChannel;
|
||||
setFavorite(!favorite);
|
||||
toggleFavorite(channelId);
|
||||
}, 500);
|
||||
|
||||
return (
|
||||
<ChannelInfoRow
|
||||
action={handleFavorite}
|
||||
defaultMessage='Favorite'
|
||||
detail={favorite}
|
||||
icon='star-o'
|
||||
textId={t('mobile.routes.channelInfo.favorite')}
|
||||
togglable={true}
|
||||
theme={theme}
|
||||
isLandscape={isLandscape}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(Favorite);
|
||||
26
app/screens/channel_info/favorite/index.js
Normal file
26
app/screens/channel_info/favorite/index.js
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
import {favoriteChannel, unfavoriteChannel} from '@mm-redux/actions/channels';
|
||||
import {getFavoritesPreferences} from '@mm-redux/selectors/entities/preferences';
|
||||
|
||||
import Favorite from './favorite';
|
||||
|
||||
function mapStateToProps(state, ownProps) {
|
||||
const {channelId} = ownProps;
|
||||
const favoriteChannels = getFavoritesPreferences(state) || [];
|
||||
|
||||
return {
|
||||
channelId,
|
||||
isFavorite: favoriteChannels.indexOf(channelId) > -1,
|
||||
};
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
favoriteChannel,
|
||||
unfavoriteChannel,
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Favorite);
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ChannelInfo -> IgnoreMentions should match snapshot for Ignore Mentions 1`] = `
|
||||
<channelInfoRow
|
||||
action={[Function]}
|
||||
defaultMessage="Ignore @channel, @here, @all"
|
||||
detail={true}
|
||||
icon="at"
|
||||
isLandscape={false}
|
||||
rightArrow={true}
|
||||
shouldRender={true}
|
||||
textId="channel_notifications.ignoreChannelMentions.settings"
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
togglable={true}
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`ChannelInfo -> IgnoreMentions should match snapshot for Not Ignore Mentions 1`] = `
|
||||
<channelInfoRow
|
||||
action={[Function]}
|
||||
defaultMessage="Ignore @channel, @here, @all"
|
||||
detail={false}
|
||||
icon="at"
|
||||
isLandscape={false}
|
||||
rightArrow={true}
|
||||
shouldRender={true}
|
||||
textId="channel_notifications.ignoreChannelMentions.settings"
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
togglable={true}
|
||||
/>
|
||||
`;
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import {shallowWithIntl} from 'test/intl-test-helper';
|
||||
|
||||
import Preferences from '@mm-redux/constants/preferences';
|
||||
|
||||
import IgnoreMentions from './ignore_mentions';
|
||||
|
||||
jest.mock('@utils/theme', () => {
|
||||
const original = jest.requireActual('../../../utils/theme');
|
||||
return {
|
||||
...original,
|
||||
changeOpacity: jest.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
describe('ChannelInfo -> IgnoreMentions', () => {
|
||||
const baseProps = {
|
||||
channelId: '123',
|
||||
ignore: false,
|
||||
isLandscape: false,
|
||||
theme: Preferences.THEMES.default,
|
||||
updateChannelNotifyProps: jest.fn(),
|
||||
userId: 'user-123',
|
||||
};
|
||||
|
||||
test('should match snapshot for Not Ignore Mentions', () => {
|
||||
const wrapper = shallowWithIntl(
|
||||
<IgnoreMentions
|
||||
{...baseProps}
|
||||
/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should match snapshot for Ignore Mentions', () => {
|
||||
const wrapper = shallowWithIntl(
|
||||
<IgnoreMentions
|
||||
{...baseProps}
|
||||
ignore={true}
|
||||
/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
47
app/screens/channel_info/ignore_mentions/ignore_mentions.tsx
Normal file
47
app/screens/channel_info/ignore_mentions/ignore_mentions.tsx
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {memo, useState} from 'react';
|
||||
|
||||
import {Users} from '@mm-redux/constants';
|
||||
import {Theme} from '@mm-redux/types/preferences';
|
||||
import ChannelInfoRow from '@screens/channel_info/channel_info_row';
|
||||
import {t} from '@utils/i18n';
|
||||
import {preventDoubleTap} from '@utils/tap';
|
||||
|
||||
interface IgnoreMentionsProps {
|
||||
channelId: string;
|
||||
ignore: boolean;
|
||||
isLandscape: boolean;
|
||||
theme: Theme;
|
||||
updateChannelNotifyProps: (userId: string, channelId: string, opts: {ignore_channel_mentions: string}) => void;
|
||||
userId: string;
|
||||
}
|
||||
|
||||
const IgnoreMentions = ({channelId, ignore, isLandscape, updateChannelNotifyProps, userId, theme}: IgnoreMentionsProps) => {
|
||||
const [mentions, setMentions] = useState(ignore);
|
||||
|
||||
const handleIgnoreChannelMentions = preventDoubleTap(() => {
|
||||
const opts = {
|
||||
ignore_channel_mentions: ignore ? Users.IGNORE_CHANNEL_MENTIONS_OFF : Users.IGNORE_CHANNEL_MENTIONS_ON,
|
||||
};
|
||||
|
||||
setMentions(!mentions);
|
||||
updateChannelNotifyProps(userId, channelId, opts);
|
||||
});
|
||||
|
||||
return (
|
||||
<ChannelInfoRow
|
||||
action={handleIgnoreChannelMentions}
|
||||
defaultMessage='Ignore @channel, @here, @all'
|
||||
detail={ignore}
|
||||
icon='at'
|
||||
textId={t('channel_notifications.ignoreChannelMentions.settings')}
|
||||
togglable={true}
|
||||
theme={theme}
|
||||
isLandscape={isLandscape}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(IgnoreMentions);
|
||||
27
app/screens/channel_info/ignore_mentions/index.js
Normal file
27
app/screens/channel_info/ignore_mentions/index.js
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
import {updateChannelNotifyProps} from '@mm-redux/actions/channels';
|
||||
import {getMyCurrentChannelMembership} from '@mm-redux/selectors/entities/channels';
|
||||
import {getCurrentUser} from '@mm-redux/selectors/entities/users';
|
||||
import {areChannelMentionsIgnored} from '@mm-redux/utils/channel_utils';
|
||||
|
||||
import IgnoreMentions from './ignore_mentions';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
const currentUser = getCurrentUser(state);
|
||||
const currentChannelMember = getMyCurrentChannelMembership(state);
|
||||
|
||||
return {
|
||||
ignore: areChannelMentionsIgnored(currentChannelMember && currentChannelMember.notify_props, currentUser.notify_props),
|
||||
userId: currentUser?.id || '',
|
||||
};
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
updateChannelNotifyProps,
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(IgnoreMentions);
|
||||
|
|
@ -4,77 +4,30 @@
|
|||
import {bindActionCreators} from 'redux';
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
import {
|
||||
convertChannelToPrivate,
|
||||
favoriteChannel,
|
||||
getChannelStats,
|
||||
getChannel,
|
||||
deleteChannel,
|
||||
unarchiveChannel,
|
||||
unfavoriteChannel,
|
||||
updateChannelNotifyProps,
|
||||
} from '@mm-redux/actions/channels';
|
||||
import {loadChannelsByTeamName, setChannelDisplayName} from '@actions/views/channel';
|
||||
import {getChannelStats} from '@mm-redux/actions/channels';
|
||||
import {getCustomEmojisInText} from '@mm-redux/actions/emojis';
|
||||
import {selectFocusedPostId} from '@mm-redux/actions/posts';
|
||||
import {clearPinnedPosts} from '@mm-redux/actions/search';
|
||||
import {General} from '@mm-redux/constants';
|
||||
import {getTheme} from '@mm-redux/selectors/entities/preferences';
|
||||
import {
|
||||
canManageChannelMembers,
|
||||
getCurrentChannel,
|
||||
getCurrentChannelStats,
|
||||
getSortedFavoriteChannelIds,
|
||||
getMyCurrentChannelMembership,
|
||||
isCurrentChannelReadOnly,
|
||||
} from '@mm-redux/selectors/entities/channels';
|
||||
import {getCurrentUserId, getUser, getStatusForUserId, getCurrentUserRoles} from '@mm-redux/selectors/entities/users';
|
||||
import {areChannelMentionsIgnored, getUserIdFromChannelName, isChannelMuted, showDeleteOption, showManagementOptions} from '@mm-redux/utils/channel_utils';
|
||||
import {isAdmin as checkIsAdmin, isChannelAdmin as checkIsChannelAdmin, isSystemAdmin as checkIsSystemAdmin} from '@mm-redux/utils/user_utils';
|
||||
import {getConfig, getLicense, hasNewPermissions} from '@mm-redux/selectors/entities/general';
|
||||
import {isTimezoneEnabled} from '@mm-redux/selectors/entities/timezone';
|
||||
import {getUserCurrentTimezone} from '@mm-redux/utils/timezone_utils';
|
||||
import Permissions from '@mm-redux/constants/permissions';
|
||||
import {haveITeamPermission} from '@mm-redux/selectors/entities/roles';
|
||||
import {getCurrentTeamId} from '@mm-redux/selectors/entities/teams';
|
||||
import {isMinimumServerVersion} from '@mm-redux/utils/helpers';
|
||||
|
||||
import {
|
||||
closeDMChannel,
|
||||
closeGMChannel,
|
||||
handleSelectChannel,
|
||||
leaveChannel,
|
||||
loadChannelsByTeamName,
|
||||
selectPenultimateChannel,
|
||||
setChannelDisplayName,
|
||||
} from 'app/actions/views/channel';
|
||||
import {isLandscape} from 'app/selectors/device';
|
||||
import {isGuest} from 'app/utils/users';
|
||||
import {getTeammateNameDisplaySetting, getTheme} from '@mm-redux/selectors/entities/preferences';
|
||||
import {getCurrentChannel, getCurrentChannelStats} from '@mm-redux/selectors/entities/channels';
|
||||
import {getCurrentUserId, getUser, getStatusForUserId} from '@mm-redux/selectors/entities/users';
|
||||
import {getUserIdFromChannelName} from '@mm-redux/utils/channel_utils';
|
||||
import {displayUsername} from '@mm-redux/utils/user_utils';
|
||||
import {isLandscape} from '@selectors/device';
|
||||
import {isGuest} from '@utils/users';
|
||||
|
||||
import ChannelInfo from './channel_info';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
const config = getConfig(state);
|
||||
const license = getLicense(state);
|
||||
const currentChannel = getCurrentChannel(state) || {};
|
||||
const currentChannelCreator = getUser(state, currentChannel.creator_id);
|
||||
const currentChannelCreatorName = currentChannelCreator && currentChannelCreator.username;
|
||||
const teammateNameDisplay = getTeammateNameDisplaySetting(state);
|
||||
const currentChannelCreatorName = displayUsername(currentChannelCreator, teammateNameDisplay);
|
||||
const currentChannelStats = getCurrentChannelStats(state);
|
||||
const currentChannelMemberCount = currentChannelStats && currentChannelStats.member_count;
|
||||
const currentChannelPinnedPostCount = currentChannelStats && currentChannelStats.pinnedpost_count;
|
||||
let currentChannelGuestCount = (currentChannelStats && currentChannelStats.guest_count) || 0;
|
||||
const currentChannelMember = getMyCurrentChannelMembership(state);
|
||||
const currentUserId = getCurrentUserId(state);
|
||||
const favoriteChannels = getSortedFavoriteChannelIds(state);
|
||||
const isCurrent = currentChannel.id === state.entities.channels.currentChannelId;
|
||||
const isFavorite = favoriteChannels && favoriteChannels.indexOf(currentChannel.id) > -1;
|
||||
const roles = getCurrentUserRoles(state) || '';
|
||||
const {serverVersion} = state.entities.general;
|
||||
let canManageUsers = currentChannel.id ? canManageChannelMembers(state) : false;
|
||||
if (currentChannel.group_constrained) {
|
||||
canManageUsers = false;
|
||||
}
|
||||
const currentUser = getUser(state, currentUserId);
|
||||
const currentUserIsGuest = isGuest(currentUser);
|
||||
|
||||
let status;
|
||||
let isBot = false;
|
||||
|
|
@ -92,80 +45,28 @@ function mapStateToProps(state) {
|
|||
}
|
||||
}
|
||||
|
||||
const isAdmin = checkIsAdmin(roles);
|
||||
const isChannelAdmin = checkIsChannelAdmin(roles);
|
||||
const isSystemAdmin = checkIsSystemAdmin(roles);
|
||||
|
||||
let channelIsReadOnly = false;
|
||||
if (currentUserId && currentChannel.id) {
|
||||
channelIsReadOnly = isCurrentChannelReadOnly(state) || false;
|
||||
}
|
||||
|
||||
const canEditChannel = !channelIsReadOnly && showManagementOptions(state, config, license, currentChannel, isAdmin, isSystemAdmin, isChannelAdmin);
|
||||
const viewArchivedChannels = config.ExperimentalViewArchivedChannels === 'true';
|
||||
|
||||
const enableTimezone = isTimezoneEnabled(state);
|
||||
let timeZone = null;
|
||||
if (enableTimezone) {
|
||||
timeZone = getUserCurrentTimezone(currentUser.timezone);
|
||||
}
|
||||
|
||||
let canUnarchiveChannel = false;
|
||||
if (hasNewPermissions(state) && isMinimumServerVersion(serverVersion, 5, 20)) {
|
||||
canUnarchiveChannel = haveITeamPermission(state, {
|
||||
team: getCurrentTeamId(state),
|
||||
permission: Permissions.MANAGE_TEAM,
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
canDeleteChannel: showDeleteOption(state, config, license, currentChannel, isAdmin, isSystemAdmin, isChannelAdmin),
|
||||
canUnarchiveChannel,
|
||||
canConvertChannel: isAdmin,
|
||||
viewArchivedChannels,
|
||||
canEditChannel,
|
||||
currentChannel,
|
||||
currentChannelCreatorName,
|
||||
currentChannelMemberCount,
|
||||
currentChannelGuestCount,
|
||||
currentChannelPinnedPostCount,
|
||||
currentChannelMemberCount,
|
||||
currentUserId,
|
||||
currentUserIsGuest,
|
||||
isChannelMuted: isChannelMuted(currentChannelMember),
|
||||
ignoreChannelMentions: areChannelMentionsIgnored(currentChannelMember && currentChannelMember.notify_props, currentUser.notify_props),
|
||||
isCurrent,
|
||||
isFavorite,
|
||||
isBot,
|
||||
isLandscape: isLandscape(state),
|
||||
isTeammateGuest,
|
||||
status,
|
||||
theme: getTheme(state),
|
||||
canManageUsers,
|
||||
isBot,
|
||||
isTeammateGuest,
|
||||
isLandscape: isLandscape(state),
|
||||
timeZone,
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators({
|
||||
clearPinnedPosts,
|
||||
closeDMChannel,
|
||||
closeGMChannel,
|
||||
convertChannelToPrivate,
|
||||
deleteChannel,
|
||||
unarchiveChannel,
|
||||
getChannelStats,
|
||||
getChannel,
|
||||
leaveChannel,
|
||||
loadChannelsByTeamName,
|
||||
favoriteChannel,
|
||||
unfavoriteChannel,
|
||||
getCustomEmojisInText,
|
||||
selectFocusedPostId,
|
||||
updateChannelNotifyProps,
|
||||
selectPenultimateChannel,
|
||||
setChannelDisplayName,
|
||||
handleSelectChannel,
|
||||
}, dispatch),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
309
app/screens/channel_info/leave/__snapshots__/leave.test.js.snap
Normal file
309
app/screens/channel_info/leave/__snapshots__/leave.test.js.snap
Normal file
|
|
@ -0,0 +1,309 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ChannelInfo -> Leave should match snapshot for Close DM 1`] = `
|
||||
<React.Fragment>
|
||||
<Separator
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<channelInfoRow
|
||||
action={[Function]}
|
||||
defaultMessage="Close Direct Message"
|
||||
icon="times"
|
||||
iconColor="#CA3B27"
|
||||
isLandscape={false}
|
||||
rightArrow={false}
|
||||
shouldRender={true}
|
||||
textColor="#CA3B27"
|
||||
textId="mobile.channel_list.closeDM"
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
togglable={false}
|
||||
/>
|
||||
</React.Fragment>
|
||||
`;
|
||||
|
||||
exports[`ChannelInfo -> Leave should match snapshot for Close GM 1`] = `
|
||||
<React.Fragment>
|
||||
<Separator
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<channelInfoRow
|
||||
action={[Function]}
|
||||
defaultMessage="Close Group Message"
|
||||
icon="times"
|
||||
iconColor="#CA3B27"
|
||||
isLandscape={false}
|
||||
rightArrow={false}
|
||||
shouldRender={true}
|
||||
textColor="#CA3B27"
|
||||
textId="mobile.channel_list.closeGM"
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
togglable={false}
|
||||
/>
|
||||
</React.Fragment>
|
||||
`;
|
||||
|
||||
exports[`ChannelInfo -> Leave should match snapshot for Leave Private Channel 1`] = `
|
||||
<React.Fragment>
|
||||
<Separator
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<channelInfoRow
|
||||
action={[Function]}
|
||||
defaultMessage="Leave Channel"
|
||||
icon="sign-out"
|
||||
iconColor="#CA3B27"
|
||||
isLandscape={false}
|
||||
rightArrow={false}
|
||||
shouldRender={true}
|
||||
textColor="#CA3B27"
|
||||
textId="navbar.leave"
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
togglable={false}
|
||||
/>
|
||||
</React.Fragment>
|
||||
`;
|
||||
|
||||
exports[`ChannelInfo -> Leave should match snapshot for Leave Public Channel 1`] = `
|
||||
<React.Fragment>
|
||||
<Separator
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<channelInfoRow
|
||||
action={[Function]}
|
||||
defaultMessage="Leave Channel"
|
||||
icon="sign-out"
|
||||
iconColor="#CA3B27"
|
||||
isLandscape={false}
|
||||
rightArrow={false}
|
||||
shouldRender={true}
|
||||
textColor="#CA3B27"
|
||||
textId="navbar.leave"
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
togglable={false}
|
||||
/>
|
||||
</React.Fragment>
|
||||
`;
|
||||
46
app/screens/channel_info/leave/index.js
Normal file
46
app/screens/channel_info/leave/index.js
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
import {
|
||||
closeDMChannel,
|
||||
closeGMChannel,
|
||||
leaveChannel,
|
||||
} from '@actions/views/channel';
|
||||
import {General} from '@mm-redux/constants';
|
||||
import {getCurrentChannel} from '@mm-redux/selectors/entities/channels';
|
||||
import {getFavoritesPreferences} from '@mm-redux/selectors/entities/preferences';
|
||||
import {getCurrentUser} from '@mm-redux/selectors/entities/users';
|
||||
import {isGuest as isUserGuest} from '@utils/users';
|
||||
|
||||
import Leave from './leave';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
const currentChannel = getCurrentChannel(state);
|
||||
const currentUser = getCurrentUser(state);
|
||||
const favoriteChannels = getFavoritesPreferences(state) || [];
|
||||
const isGuest = isUserGuest(currentUser);
|
||||
const isDefaultChannel = currentChannel.name === General.DEFAULT_CHANNEL;
|
||||
const isDirectMessage = currentChannel.type === General.DM_CHANNEL;
|
||||
const isGroupMessage = currentChannel.type === General.GM_CHANNEL;
|
||||
const canLeave = (!isDefaultChannel && !isDirectMessage && !isGroupMessage) || (isDefaultChannel && isGuest);
|
||||
|
||||
return {
|
||||
canLeave,
|
||||
currentChannel,
|
||||
displayName: (currentChannel?.display_name || '').trim(),
|
||||
isDirectMessage,
|
||||
isFavorite: favoriteChannels.indexOf(currentChannel?.id) > -1,
|
||||
isGroupMessage,
|
||||
isPublic: currentChannel?.type === General.OPEN_CHANNEL,
|
||||
};
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
closeDMChannel,
|
||||
closeGMChannel,
|
||||
leaveChannel,
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Leave);
|
||||
98
app/screens/channel_info/leave/leave.test.js
Normal file
98
app/screens/channel_info/leave/leave.test.js
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import {shallowWithIntl} from 'test/intl-test-helper';
|
||||
|
||||
import {General} from '@mm-redux/constants';
|
||||
import Preferences from '@mm-redux/constants/preferences';
|
||||
|
||||
import Leave from './leave';
|
||||
|
||||
jest.mock('@utils/theme', () => {
|
||||
const original = jest.requireActual('../../../utils/theme');
|
||||
return {
|
||||
...original,
|
||||
changeOpacity: jest.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
describe('ChannelInfo -> Leave', () => {
|
||||
const baseProps = {
|
||||
canLeave: true,
|
||||
currentChannel: {
|
||||
id: '1234',
|
||||
display_name: 'Channel Name',
|
||||
type: General.OPEN_CHANNEL,
|
||||
create_at: 123,
|
||||
delete_at: 0,
|
||||
header: '',
|
||||
purpose: 'Purpose',
|
||||
group_constrained: false,
|
||||
},
|
||||
close: jest.fn(),
|
||||
closeDMChannel: jest.fn(),
|
||||
closeGMChannel: jest.fn(),
|
||||
displayName: 'Channel Name',
|
||||
leaveChannel: jest.fn(),
|
||||
isDirectMessage: false,
|
||||
isFavorite: false,
|
||||
isGroupMessage: false,
|
||||
isLandscape: false,
|
||||
isPublic: true,
|
||||
theme: Preferences.THEMES.default,
|
||||
};
|
||||
|
||||
test('should match snapshot for Leave Public Channel', () => {
|
||||
const wrapper = shallowWithIntl(
|
||||
<Leave
|
||||
{...baseProps}
|
||||
/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should match snapshot for Leave Private Channel', () => {
|
||||
const wrapper = shallowWithIntl(
|
||||
<Leave
|
||||
{...baseProps}
|
||||
isPublic={false}
|
||||
/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should match snapshot for Close DM', () => {
|
||||
const wrapper = shallowWithIntl(
|
||||
<Leave
|
||||
{...baseProps}
|
||||
canLeave={false}
|
||||
isDirectMessage={true}
|
||||
isPublic={false}
|
||||
/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should match snapshot for Close GM', () => {
|
||||
const wrapper = shallowWithIntl(
|
||||
<Leave
|
||||
{...baseProps}
|
||||
canLeave={false}
|
||||
isGroupMessage={true}
|
||||
isPublic={false}
|
||||
/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should render null if cannot leave', () => {
|
||||
const wrapper = shallowWithIntl(
|
||||
<Leave
|
||||
{...baseProps}
|
||||
canLeave={false}
|
||||
/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toBeNull();
|
||||
});
|
||||
});
|
||||
149
app/screens/channel_info/leave/leave.tsx
Normal file
149
app/screens/channel_info/leave/leave.tsx
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {PureComponent} from 'react';
|
||||
import {Alert} from 'react-native';
|
||||
import {intlShape} from 'react-intl';
|
||||
|
||||
import {ActionResult} from '@mm-redux/types/actions';
|
||||
import {Channel} from '@mm-redux/types/channels';
|
||||
import {FormattedMsg} from '@mm-redux/types/general';
|
||||
import {Theme} from '@mm-redux/types/preferences';
|
||||
import ChannelInfoRow from '@screens/channel_info/channel_info_row';
|
||||
import Separator from '@screens/channel_info/separator';
|
||||
import {t} from '@utils/i18n';
|
||||
import {preventDoubleTap} from '@utils/tap';
|
||||
|
||||
interface LeaveProps {
|
||||
canLeave: boolean;
|
||||
currentChannel: Channel;
|
||||
close: (redirect: boolean) => void;
|
||||
closeDMChannel: (channel: Channel) => Promise<ActionResult>;
|
||||
closeGMChannel: (channel: Channel) => Promise<ActionResult>;
|
||||
displayName: string;
|
||||
leaveChannel: (channel: Channel, reset: boolean) => Promise<ActionResult>;
|
||||
isDirectMessage: boolean;
|
||||
isFavorite: boolean;
|
||||
isGroupMessage: boolean;
|
||||
isLandscape: boolean;
|
||||
isPublic: boolean;
|
||||
theme: Theme;
|
||||
}
|
||||
|
||||
export default class Leave extends PureComponent<LeaveProps> {
|
||||
static contextTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
alertAndHandleYesAction = (title: FormattedMsg, message: FormattedMsg, onPressAction: () => void) => {
|
||||
const {formatMessage} = this.context.intl;
|
||||
const {displayName, isPublic} = this.props;
|
||||
|
||||
// eslint-disable-next-line multiline-ternary
|
||||
const term = isPublic ? formatMessage({id: 'mobile.channel_info.publicChannel', defaultMessage: 'Public Channel'}) :
|
||||
formatMessage({id: 'mobile.channel_info.privateChannel', defaultMessage: 'Private Channel'});
|
||||
|
||||
Alert.alert(
|
||||
formatMessage(title, {term}),
|
||||
formatMessage(
|
||||
message,
|
||||
{
|
||||
term: term.toLowerCase(),
|
||||
name: displayName,
|
||||
},
|
||||
),
|
||||
[{
|
||||
text: formatMessage({id: 'mobile.channel_info.alertNo', defaultMessage: 'No'}),
|
||||
}, {
|
||||
text: formatMessage({id: 'mobile.channel_info.alertYes', defaultMessage: 'Yes'}),
|
||||
onPress: onPressAction,
|
||||
}],
|
||||
);
|
||||
}
|
||||
|
||||
handleClose = preventDoubleTap(() => {
|
||||
const {close, currentChannel, isDirectMessage, isFavorite} = this.props;
|
||||
const channel = Object.assign({}, currentChannel, {isCurrent: true}, {isFavorite});
|
||||
const {closeDMChannel, closeGMChannel} = this.props;
|
||||
|
||||
if (isDirectMessage) {
|
||||
closeDMChannel(channel).then(() => {
|
||||
close(true);
|
||||
});
|
||||
} else {
|
||||
closeGMChannel(channel).then(() => {
|
||||
close(true);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
handleLeave = preventDoubleTap(() => {
|
||||
const title = {id: t('mobile.channel_info.alertTitleLeaveChannel'), defaultMessage: 'Leave {term}'};
|
||||
const message = {
|
||||
id: t('mobile.channel_info.alertMessageLeaveChannel'),
|
||||
defaultMessage: 'Are you sure you want to leave the {term} {name}?',
|
||||
};
|
||||
const onPressAction = () => {
|
||||
this.props.leaveChannel(this.props.currentChannel, true).then(() => {
|
||||
this.props.close(true);
|
||||
});
|
||||
};
|
||||
this.alertAndHandleYesAction(title, message, onPressAction);
|
||||
});
|
||||
|
||||
render() {
|
||||
const {canLeave, isDirectMessage, isGroupMessage, isLandscape, theme} = this.props;
|
||||
|
||||
if (!canLeave && !isDirectMessage && !isGroupMessage) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let element;
|
||||
if (isDirectMessage || isGroupMessage) {
|
||||
let i18nId;
|
||||
let defaultMessage;
|
||||
if (isDirectMessage) {
|
||||
i18nId = t('mobile.channel_list.closeDM');
|
||||
defaultMessage = 'Close Direct Message';
|
||||
} else {
|
||||
i18nId = t('mobile.channel_list.closeGM');
|
||||
defaultMessage = 'Close Group Message';
|
||||
}
|
||||
|
||||
element = (
|
||||
<ChannelInfoRow
|
||||
action={this.handleClose}
|
||||
defaultMessage={defaultMessage}
|
||||
icon='times'
|
||||
iconColor='#CA3B27'
|
||||
textColor='#CA3B27'
|
||||
textId={i18nId}
|
||||
theme={theme}
|
||||
isLandscape={isLandscape}
|
||||
rightArrow={false}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
element = (
|
||||
<ChannelInfoRow
|
||||
action={this.handleLeave}
|
||||
defaultMessage='Leave Channel'
|
||||
icon='sign-out'
|
||||
iconColor='#CA3B27'
|
||||
textColor='#CA3B27'
|
||||
textId={t('navbar.leave')}
|
||||
theme={theme}
|
||||
isLandscape={isLandscape}
|
||||
rightArrow={false}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Separator theme={theme}/>
|
||||
{element}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,198 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ChannelInfo -> Manage Members should match snapshot for Manage Members 1`] = `
|
||||
<React.Fragment>
|
||||
<Separator
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<channelInfoRow
|
||||
action={[Function]}
|
||||
defaultMessage="Manage Members"
|
||||
detail={10}
|
||||
icon="users"
|
||||
isLandscape={false}
|
||||
rightArrow={true}
|
||||
shouldRender={true}
|
||||
textId="channel_header.manageMembers"
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
togglable={false}
|
||||
/>
|
||||
</React.Fragment>
|
||||
`;
|
||||
|
||||
exports[`ChannelInfo -> Manage Members should match snapshot for View Members 1`] = `
|
||||
<React.Fragment>
|
||||
<Separator
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<channelInfoRow
|
||||
action={[Function]}
|
||||
defaultMessage="View Members"
|
||||
detail={10}
|
||||
icon="users"
|
||||
isLandscape={false}
|
||||
rightArrow={true}
|
||||
shouldRender={true}
|
||||
textId="channel_header.viewMembers"
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
togglable={false}
|
||||
/>
|
||||
</React.Fragment>
|
||||
`;
|
||||
|
||||
exports[`ChannelInfo -> Manage Members should match snapshot without separator 1`] = `
|
||||
<React.Fragment>
|
||||
<channelInfoRow
|
||||
action={[Function]}
|
||||
defaultMessage="Manage Members"
|
||||
detail={10}
|
||||
icon="users"
|
||||
isLandscape={false}
|
||||
rightArrow={true}
|
||||
shouldRender={true}
|
||||
textId="channel_header.manageMembers"
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
togglable={false}
|
||||
/>
|
||||
</React.Fragment>
|
||||
`;
|
||||
26
app/screens/channel_info/manage_members/index.js
Normal file
26
app/screens/channel_info/manage_members/index.js
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
import {General} from '@mm-redux/constants';
|
||||
import {canManageChannelMembers, getCurrentChannel, getCurrentChannelStats} from '@mm-redux/selectors/entities/channels';
|
||||
import ManageMembers from './manage_members';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
const currentChannel = getCurrentChannel(state);
|
||||
const currentChannelStats = getCurrentChannelStats(state);
|
||||
const membersCount = currentChannelStats?.member_count || 0;
|
||||
let canManageUsers = currentChannel?.id ? canManageChannelMembers(state) : false;
|
||||
if (currentChannel.group_constrained) {
|
||||
canManageUsers = false;
|
||||
}
|
||||
|
||||
return {
|
||||
canManageUsers,
|
||||
isDirectMessage: currentChannel.type === General.DM_CHANNEL,
|
||||
membersCount,
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(ManageMembers);
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import {shallowWithIntl} from 'test/intl-test-helper';
|
||||
|
||||
import Preferences from '@mm-redux/constants/preferences';
|
||||
|
||||
import ManageMembers from './manage_members';
|
||||
|
||||
jest.mock('@utils/theme', () => {
|
||||
const original = jest.requireActual('../../../utils/theme');
|
||||
return {
|
||||
...original,
|
||||
changeOpacity: jest.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
describe('ChannelInfo -> Manage Members', () => {
|
||||
const baseProps = {
|
||||
canManageUsers: true,
|
||||
isDirectMessage: false,
|
||||
isLandscape: false,
|
||||
membersCount: 10,
|
||||
separator: true,
|
||||
theme: Preferences.THEMES.default,
|
||||
};
|
||||
|
||||
test('should match snapshot for Manage Members', () => {
|
||||
const wrapper = shallowWithIntl(
|
||||
<ManageMembers
|
||||
{...baseProps}
|
||||
/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should match snapshot without separator', () => {
|
||||
const wrapper = shallowWithIntl(
|
||||
<ManageMembers
|
||||
{...baseProps}
|
||||
separator={false}
|
||||
/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should match snapshot for View Members', () => {
|
||||
const wrapper = shallowWithIntl(
|
||||
<ManageMembers
|
||||
{...baseProps}
|
||||
canManageUsers={false}
|
||||
/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should render null if channel is DM', () => {
|
||||
const wrapper = shallowWithIntl(
|
||||
<ManageMembers
|
||||
{...baseProps}
|
||||
isDirectMessage={true}
|
||||
/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toBeNull();
|
||||
});
|
||||
});
|
||||
65
app/screens/channel_info/manage_members/manage_members.tsx
Normal file
65
app/screens/channel_info/manage_members/manage_members.tsx
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {PureComponent} from 'react';
|
||||
import {intlShape} from 'react-intl';
|
||||
|
||||
import {goToScreen} from '@actions/navigation';
|
||||
import {Theme} from '@mm-redux/types/preferences';
|
||||
import ChannelInfoRow from '@screens/channel_info/channel_info_row';
|
||||
import Separator from '@screens/channel_info/separator';
|
||||
import {t} from '@utils/i18n';
|
||||
import {preventDoubleTap} from '@utils/tap';
|
||||
|
||||
interface ManageMembersProps {
|
||||
canManageUsers: boolean;
|
||||
isDirectMessage: boolean;
|
||||
isLandscape: boolean;
|
||||
membersCount: number;
|
||||
separator: boolean;
|
||||
theme: Theme;
|
||||
}
|
||||
|
||||
export default class ManageMembers extends PureComponent<ManageMembersProps> {
|
||||
static contextTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
separator: true,
|
||||
};
|
||||
|
||||
goToChannelMembers = preventDoubleTap(() => {
|
||||
const {canManageUsers} = this.props;
|
||||
const {intl} = this.context;
|
||||
const id = canManageUsers ? t('channel_header.manageMembers') : t('channel_header.viewMembers');
|
||||
const defaultMessage = canManageUsers ? 'Manage Members' : 'View Members';
|
||||
const screen = 'ChannelMembers';
|
||||
const title = intl.formatMessage({id, defaultMessage});
|
||||
|
||||
goToScreen(screen, title);
|
||||
});
|
||||
|
||||
render() {
|
||||
const {isDirectMessage, canManageUsers, isLandscape, membersCount, separator, theme} = this.props;
|
||||
|
||||
if (isDirectMessage) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{separator && <Separator theme={theme}/>}
|
||||
<ChannelInfoRow
|
||||
action={this.goToChannelMembers}
|
||||
defaultMessage={canManageUsers ? 'Manage Members' : 'View Members'}
|
||||
detail={membersCount}
|
||||
icon='users'
|
||||
textId={canManageUsers ? t('channel_header.manageMembers') : t('channel_header.viewMembers')}
|
||||
theme={theme}
|
||||
isLandscape={isLandscape}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ChannelInfo -> Mute should match snapshot for Muted 1`] = `
|
||||
<channelInfoRow
|
||||
action={[Function]}
|
||||
defaultMessage="Mute channel"
|
||||
detail={true}
|
||||
icon="bell-slash-o"
|
||||
isLandscape={false}
|
||||
rightArrow={true}
|
||||
shouldRender={true}
|
||||
textId="channel_notifications.muteChannel.settings"
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
togglable={true}
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`ChannelInfo -> Mute should match snapshot for Not Muted 1`] = `
|
||||
<channelInfoRow
|
||||
action={[Function]}
|
||||
defaultMessage="Mute channel"
|
||||
detail={false}
|
||||
icon="bell-slash-o"
|
||||
isLandscape={false}
|
||||
rightArrow={true}
|
||||
shouldRender={true}
|
||||
textId="channel_notifications.muteChannel.settings"
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
togglable={true}
|
||||
/>
|
||||
`;
|
||||
24
app/screens/channel_info/mute/index.js
Normal file
24
app/screens/channel_info/mute/index.js
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
import {updateChannelNotifyProps} from '@mm-redux/actions/channels';
|
||||
import {getMyCurrentChannelMembership} from '@mm-redux/selectors/entities/channels';
|
||||
import {isChannelMuted} from '@mm-redux/utils/channel_utils';
|
||||
|
||||
import Mute from './mute';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
const currentChannelMember = getMyCurrentChannelMembership(state);
|
||||
|
||||
return {
|
||||
isChannelMuted: isChannelMuted(currentChannelMember),
|
||||
};
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
updateChannelNotifyProps,
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Mute);
|
||||
47
app/screens/channel_info/mute/mute.test.js
Normal file
47
app/screens/channel_info/mute/mute.test.js
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import {shallowWithIntl} from 'test/intl-test-helper';
|
||||
|
||||
import Preferences from '@mm-redux/constants/preferences';
|
||||
|
||||
import Mute from './mute';
|
||||
|
||||
jest.mock('@utils/theme', () => {
|
||||
const original = jest.requireActual('../../../utils/theme');
|
||||
return {
|
||||
...original,
|
||||
changeOpacity: jest.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
describe('ChannelInfo -> Mute', () => {
|
||||
const baseProps = {
|
||||
channelId: '123',
|
||||
isChannelMuted: false,
|
||||
isLandscape: false,
|
||||
theme: Preferences.THEMES.default,
|
||||
updateChannelNotifyProps: jest.fn(),
|
||||
userId: 'user-123',
|
||||
};
|
||||
|
||||
test('should match snapshot for Not Muted', () => {
|
||||
const wrapper = shallowWithIntl(
|
||||
<Mute
|
||||
{...baseProps}
|
||||
/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should match snapshot for Muted', () => {
|
||||
const wrapper = shallowWithIntl(
|
||||
<Mute
|
||||
{...baseProps}
|
||||
isChannelMuted={true}
|
||||
/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
46
app/screens/channel_info/mute/mute.tsx
Normal file
46
app/screens/channel_info/mute/mute.tsx
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {memo, useState} from 'react';
|
||||
|
||||
import {Theme} from '@mm-redux/types/preferences';
|
||||
import ChannelInfoRow from '@screens/channel_info/channel_info_row';
|
||||
import {t} from '@utils/i18n';
|
||||
import {preventDoubleTap} from '@utils/tap';
|
||||
|
||||
interface MuteProps {
|
||||
channelId: string;
|
||||
isChannelMuted: boolean;
|
||||
isLandscape: boolean;
|
||||
theme: Theme;
|
||||
updateChannelNotifyProps: (userId: string, channelId: string, opts: {mark_unread: string}) => void;
|
||||
userId: string;
|
||||
}
|
||||
|
||||
const Mute = ({channelId, isChannelMuted, isLandscape, updateChannelNotifyProps, userId, theme}: MuteProps) => {
|
||||
const [muted, setMuted] = useState(isChannelMuted);
|
||||
|
||||
const handleMuteChannel = preventDoubleTap(() => {
|
||||
const opts = {
|
||||
mark_unread: muted ? 'all' : 'mention',
|
||||
};
|
||||
|
||||
setMuted(!muted);
|
||||
updateChannelNotifyProps(userId, channelId, opts);
|
||||
});
|
||||
|
||||
return (
|
||||
<ChannelInfoRow
|
||||
action={handleMuteChannel}
|
||||
defaultMessage='Mute channel'
|
||||
detail={muted}
|
||||
icon='bell-slash-o'
|
||||
textId={t('channel_notifications.muteChannel.settings')}
|
||||
togglable={true}
|
||||
theme={theme}
|
||||
isLandscape={isLandscape}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(Mute);
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ChannelInfo -> Pinned should match snapshot 1`] = `
|
||||
<channelInfoRow
|
||||
action={[Function]}
|
||||
defaultMessage="Pinned Posts"
|
||||
detail={0}
|
||||
image={1}
|
||||
isLandscape={false}
|
||||
rightArrow={true}
|
||||
shouldRender={true}
|
||||
textId="channel_header.pinnedPosts"
|
||||
theme={
|
||||
Object {
|
||||
"awayIndicator": "#ffbc42",
|
||||
"buttonBg": "#166de0",
|
||||
"buttonColor": "#ffffff",
|
||||
"centerChannelBg": "#ffffff",
|
||||
"centerChannelColor": "#3d3c40",
|
||||
"codeTheme": "github",
|
||||
"dndIndicator": "#f74343",
|
||||
"errorTextColor": "#fd5960",
|
||||
"linkColor": "#2389d7",
|
||||
"mentionBg": "#ffffff",
|
||||
"mentionBj": "#ffffff",
|
||||
"mentionColor": "#145dbf",
|
||||
"mentionHighlightBg": "#ffe577",
|
||||
"mentionHighlightLink": "#166de0",
|
||||
"newMessageSeparator": "#ff8800",
|
||||
"onlineIndicator": "#06d6a0",
|
||||
"sidebarBg": "#145dbf",
|
||||
"sidebarHeaderBg": "#1153ab",
|
||||
"sidebarHeaderTextColor": "#ffffff",
|
||||
"sidebarText": "#ffffff",
|
||||
"sidebarTextActiveBorder": "#579eff",
|
||||
"sidebarTextActiveColor": "#ffffff",
|
||||
"sidebarTextHoverBg": "#4578bf",
|
||||
"sidebarUnreadText": "#ffffff",
|
||||
"type": "Mattermost",
|
||||
}
|
||||
}
|
||||
togglable={false}
|
||||
/>
|
||||
`;
|
||||
19
app/screens/channel_info/pinned/index.js
Normal file
19
app/screens/channel_info/pinned/index.js
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
import {getCurrentChannelStats} from '@mm-redux/selectors/entities/channels';
|
||||
|
||||
import Pinned from './pinned';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
const currentChannelStats = getCurrentChannelStats(state);
|
||||
const pinnedCount = currentChannelStats?.pinnedpost_count || 0;
|
||||
|
||||
return {
|
||||
pinnedCount,
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(Pinned);
|
||||
41
app/screens/channel_info/pinned/pinned.test.js
Normal file
41
app/screens/channel_info/pinned/pinned.test.js
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import {shallowWithIntl} from 'test/intl-test-helper';
|
||||
|
||||
import Preferences from '@mm-redux/constants/preferences';
|
||||
|
||||
import Pinned from './pinned';
|
||||
|
||||
// Pinned expects to receive the pinIcon as a number
|
||||
jest.mock('@assets/images/channel_info/pin.png', () => {
|
||||
return 1;
|
||||
});
|
||||
|
||||
jest.mock('@utils/theme', () => {
|
||||
const original = jest.requireActual('../../../utils/theme');
|
||||
return {
|
||||
...original,
|
||||
changeOpacity: jest.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
describe('ChannelInfo -> Pinned', () => {
|
||||
const baseProps = {
|
||||
channelId: '123',
|
||||
pinnedCount: 0,
|
||||
isLandscape: false,
|
||||
theme: Preferences.THEMES.default,
|
||||
userId: 'user-123',
|
||||
};
|
||||
|
||||
test('should match snapshot', () => {
|
||||
const wrapper = shallowWithIntl(
|
||||
<Pinned
|
||||
{...baseProps}
|
||||
/>,
|
||||
);
|
||||
expect(wrapper.getElement()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
54
app/screens/channel_info/pinned/pinned.tsx
Normal file
54
app/screens/channel_info/pinned/pinned.tsx
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {PureComponent} from 'react';
|
||||
import {intlShape} from 'react-intl';
|
||||
|
||||
import {goToScreen} from '@actions/navigation';
|
||||
import {Theme} from '@mm-redux/types/preferences';
|
||||
import ChannelInfoRow from '@screens/channel_info/channel_info_row';
|
||||
import {t} from '@utils/i18n';
|
||||
import {preventDoubleTap} from '@utils/tap';
|
||||
|
||||
interface PinnedProps {
|
||||
channelId: string;
|
||||
pinnedCount: number;
|
||||
isLandscape: boolean;
|
||||
theme: Theme;
|
||||
userId: string;
|
||||
}
|
||||
|
||||
export default class Pinned extends PureComponent<PinnedProps> {
|
||||
static contextTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
goToPinnedPosts = preventDoubleTap(() => {
|
||||
const {channelId} = this.props;
|
||||
const {formatMessage} = this.context.intl;
|
||||
const id = t('channel_header.pinnedPosts');
|
||||
const defaultMessage = 'Pinned Posts';
|
||||
const screen = 'PinnedPosts';
|
||||
const title = formatMessage({id, defaultMessage});
|
||||
const passProps = {
|
||||
currentChannelId: channelId,
|
||||
};
|
||||
|
||||
goToScreen(screen, title, passProps);
|
||||
});
|
||||
|
||||
render() {
|
||||
const {pinnedCount, isLandscape, theme} = this.props;
|
||||
return (
|
||||
<ChannelInfoRow
|
||||
action={this.goToPinnedPosts}
|
||||
defaultMessage='Pinned Posts'
|
||||
detail={pinnedCount}
|
||||
image={require('@assets/images/channel_info/pin.png')}
|
||||
textId={t('channel_header.pinnedPosts')}
|
||||
theme={theme}
|
||||
isLandscape={isLandscape}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
28
app/screens/channel_info/separator.tsx
Normal file
28
app/screens/channel_info/separator.tsx
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import {View} from 'react-native';
|
||||
|
||||
import {Theme} from '@mm-redux/types/preferences';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
|
||||
interface SeparatorProps {
|
||||
theme: Theme;
|
||||
}
|
||||
|
||||
const Separator = ({theme}: SeparatorProps) => {
|
||||
const style = getStyleSheet(theme);
|
||||
|
||||
return <View style={style.separator}/>;
|
||||
};
|
||||
|
||||
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
||||
separator: {
|
||||
marginHorizontal: 15,
|
||||
height: 1,
|
||||
backgroundColor: changeOpacity(theme.centerChannelColor, 0.1),
|
||||
},
|
||||
}));
|
||||
|
||||
export default Separator;
|
||||
|
|
@ -39,6 +39,7 @@
|
|||
"@i18n": ["app/i18n/index"],
|
||||
"@init/*": ["app/init/*"],
|
||||
"@mm-redux/*": ["app/mm-redux/*"],
|
||||
"@screens/*": ["app/screens/*"],
|
||||
"@selectors/*": ["app/selectors/*"],
|
||||
"@store/*": ["app/store"],
|
||||
"@telemetry/*": ["/app/telemetry/*"],
|
||||
|
|
|
|||
Loading…
Reference in a new issue