forked from Ivasoft/mattermost-mobile
MM-42835_Invite People - add email+user invites
This commit is contained in:
@@ -508,19 +508,13 @@ export async function getTeamMembersByIds(serverUrl: string, teamId: string, use
|
||||
if (!fetchOnly) {
|
||||
setTeamLoading(serverUrl, true);
|
||||
|
||||
const teamMemberships: TeamMembership[] = [];
|
||||
const roles: Record<string, boolean> = {};
|
||||
const roles = [];
|
||||
|
||||
for (const member of members) {
|
||||
teamMemberships.push(member);
|
||||
member.roles.split(' ').forEach((role) => {
|
||||
if (!roles[role]) {
|
||||
roles[role] = true;
|
||||
}
|
||||
});
|
||||
for (const {roles: memberRoles} of members) {
|
||||
roles.push(...memberRoles.split(' '));
|
||||
}
|
||||
|
||||
fetchRolesIfNeeded(serverUrl, Object.getOwnPropertyNames(roles));
|
||||
fetchRolesIfNeeded(serverUrl, Array.from(new Set(roles)));
|
||||
|
||||
const operator = DatabaseManager.serverDatabases[serverUrl]?.operator;
|
||||
|
||||
@@ -529,7 +523,7 @@ export async function getTeamMembersByIds(serverUrl: string, teamId: string, use
|
||||
|
||||
const models: Model[] = (await Promise.all([
|
||||
operator.handleTeam({teams: [team], prepareRecordsOnly: true}),
|
||||
operator.handleTeamMemberships({teamMemberships, prepareRecordsOnly: true}),
|
||||
operator.handleTeamMemberships({teamMemberships: members, prepareRecordsOnly: true}),
|
||||
])).flat();
|
||||
|
||||
await operator.batchRecords(models);
|
||||
|
||||
@@ -115,6 +115,7 @@ export default function Invite({
|
||||
const modalPosition = useModalPosition(mainView);
|
||||
|
||||
const searchTimeoutId = useRef<NodeJS.Timeout | null>(null);
|
||||
const retryTimeoutId = useRef<NodeJS.Timeout | null>(null);
|
||||
|
||||
const [term, setTerm] = useState('');
|
||||
const [searchResults, setSearchResults] = useState<SearchResult[]>([]);
|
||||
@@ -137,7 +138,7 @@ export default function Invite({
|
||||
return;
|
||||
}
|
||||
|
||||
const {data} = await searchProfiles(serverUrl, searchTerm.toLowerCase(), {allow_inactive: true});
|
||||
const {data} = await searchProfiles(serverUrl, searchTerm.toLowerCase());
|
||||
const results: SearchResult[] = data ?? [];
|
||||
|
||||
if (!results.length && isEmail(searchTerm.trim())) {
|
||||
@@ -193,7 +194,7 @@ export default function Invite({
|
||||
setSendError('');
|
||||
setStage(Stage.LOADING);
|
||||
|
||||
setTimeout(() => {
|
||||
retryTimeoutId.current = setTimeout(() => {
|
||||
handleSend();
|
||||
}, TIMEOUT_MILLISECONDS);
|
||||
};
|
||||
@@ -243,9 +244,9 @@ export default function Invite({
|
||||
|
||||
for (const userId of userIds) {
|
||||
if (isGuest((selectedIds[userId] as UserProfile).roles)) {
|
||||
notSent.push({userId, reason: formatMessage({id: 'invite.members.user-is-guest', defaultMessage: 'Contact your admin to make this guest a full member'})});
|
||||
notSent.push({userId, reason: formatMessage({id: 'invite.members.user_is_guest', defaultMessage: 'Contact your admin to make this guest a full member'})});
|
||||
} else if (currentMemberIds[userId]) {
|
||||
notSent.push({userId, reason: formatMessage({id: 'invite.members.already-member', defaultMessage: 'This person is already a team member'})});
|
||||
notSent.push({userId, reason: formatMessage({id: 'invite.members.already_member', defaultMessage: 'This person is already a team member'})});
|
||||
} else {
|
||||
usersToAdd.push(userId);
|
||||
}
|
||||
@@ -338,6 +339,18 @@ export default function Invite({
|
||||
});
|
||||
}, [componentId, locale, theme, stage]);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (searchTimeoutId.current) {
|
||||
clearTimeout(searchTimeoutId.current);
|
||||
}
|
||||
|
||||
if (retryTimeoutId.current) {
|
||||
clearTimeout(retryTimeoutId.current);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
const handleRemoveItem = useCallback((id: string) => {
|
||||
const newSelectedIds = Object.assign({}, selectedIds);
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@ import {useTheme} from '@context/theme';
|
||||
import {useAutocompleteDefaultAnimatedValues} from '@hooks/autocomplete';
|
||||
import {useIsTablet, useKeyboardHeight} from '@hooks/device';
|
||||
import {makeStyleSheetFromTheme, changeOpacity} from '@utils/theme';
|
||||
import {typography} from '@utils/typography';
|
||||
|
||||
import {SearchResult} from './invite';
|
||||
import SelectedEmail from './selected_email';
|
||||
@@ -56,54 +55,6 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
||||
display: 'flex',
|
||||
flex: 1,
|
||||
},
|
||||
teamContainer: {
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
width: '100%',
|
||||
paddingVertical: 16,
|
||||
paddingHorizontal: 20,
|
||||
backgroundColor: changeOpacity(theme.centerChannelColor, 0.04),
|
||||
},
|
||||
iconContainer: {
|
||||
width: 40,
|
||||
height: 40,
|
||||
},
|
||||
textContainer: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
},
|
||||
teamText: {
|
||||
color: theme.centerChannelColor,
|
||||
marginLeft: 12,
|
||||
...typography('Body', 200, 'SemiBold'),
|
||||
},
|
||||
serverText: {
|
||||
color: changeOpacity(theme.centerChannelColor, 0.72),
|
||||
marginLeft: 12,
|
||||
...typography('Body', 75, 'Regular'),
|
||||
},
|
||||
shareLink: {
|
||||
display: 'flex',
|
||||
marginLeft: 'auto',
|
||||
},
|
||||
shareLinkButton: {
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
height: 40,
|
||||
paddingHorizontal: 20,
|
||||
backgroundColor: changeOpacity(theme.buttonBg, 0.08),
|
||||
borderRadius: 4,
|
||||
},
|
||||
shareLinkText: {
|
||||
color: theme.buttonBg,
|
||||
...typography('Body', 100, 'SemiBold'),
|
||||
paddingLeft: 7,
|
||||
},
|
||||
shareLinkIcon: {
|
||||
color: theme.buttonBg,
|
||||
},
|
||||
searchList: {
|
||||
left: 20,
|
||||
right: 20,
|
||||
|
||||
@@ -262,18 +262,22 @@ export default function Summary({
|
||||
</Text>
|
||||
) : (
|
||||
<>
|
||||
<SummaryReport
|
||||
type={SummaryReportType.NOT_SENT}
|
||||
invites={notSent}
|
||||
selectedIds={selectedIds}
|
||||
testID='invite.summary_report'
|
||||
/>
|
||||
<SummaryReport
|
||||
type={SummaryReportType.SENT}
|
||||
invites={sent}
|
||||
selectedIds={selectedIds}
|
||||
testID='invite.summary_report'
|
||||
/>
|
||||
{notSent.length > 0 && (
|
||||
<SummaryReport
|
||||
type={SummaryReportType.NOT_SENT}
|
||||
invites={notSent}
|
||||
selectedIds={selectedIds}
|
||||
testID='invite.summary_report'
|
||||
/>
|
||||
)}
|
||||
{sent.length > 0 && (
|
||||
<SummaryReport
|
||||
type={SummaryReportType.SENT}
|
||||
invites={sent}
|
||||
selectedIds={selectedIds}
|
||||
testID='invite.summary_report'
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
|
||||
@@ -14,9 +14,12 @@ import {typography} from '@utils/typography';
|
||||
import {SearchResult, InviteResult} from './invite';
|
||||
import TextItem, {TextItemType} from './text_item';
|
||||
|
||||
const COLOR_SUCCESS = '#3db887';
|
||||
const COLOR_ERROR = '#d24b4e';
|
||||
|
||||
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
||||
return {
|
||||
summaryInvitationsContainer: {
|
||||
container: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
borderWidth: 1,
|
||||
@@ -25,29 +28,29 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
||||
marginBottom: 16,
|
||||
paddingVertical: 8,
|
||||
},
|
||||
summaryInvitationsTitle: {
|
||||
title: {
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
paddingHorizontal: 20,
|
||||
paddingVertical: 12,
|
||||
},
|
||||
summaryInvitationsTitleText: {
|
||||
titleText: {
|
||||
marginLeft: 12,
|
||||
...typography('Heading', 300, 'SemiBold'),
|
||||
color: theme.centerChannelColor,
|
||||
},
|
||||
summaryInvitationsItem: {
|
||||
item: {
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
paddingVertical: 12,
|
||||
},
|
||||
summaryInvitationsUser: {
|
||||
user: {
|
||||
paddingTop: 0,
|
||||
paddingBottom: 0,
|
||||
height: 'auto',
|
||||
},
|
||||
summaryInvitationsReason: {
|
||||
reason: {
|
||||
paddingLeft: 56,
|
||||
paddingRight: 20,
|
||||
...typography('Body', 75, 'Regular'),
|
||||
@@ -80,10 +83,6 @@ export default function SummaryReport({
|
||||
|
||||
const count = invites.length;
|
||||
|
||||
if (!count) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const sent = type === SummaryReportType.SENT;
|
||||
const message = sent ? (
|
||||
formatMessage(
|
||||
@@ -105,16 +104,16 @@ export default function SummaryReport({
|
||||
|
||||
return (
|
||||
<View
|
||||
style={styles.summaryInvitationsContainer}
|
||||
style={styles.container}
|
||||
testID={`${testID}.${type}`}
|
||||
>
|
||||
<View style={styles.summaryInvitationsTitle}>
|
||||
<View style={styles.title}>
|
||||
<CompassIcon
|
||||
name={sent ? 'check-circle' : 'close-circle'}
|
||||
size={24}
|
||||
style={{color: sent ? '#3db887' : '#d24b4e'}}
|
||||
style={{color: sent ? COLOR_SUCCESS : COLOR_ERROR}}
|
||||
/>
|
||||
<Text style={styles.summaryInvitationsTitleText}>
|
||||
<Text style={styles.titleText}>
|
||||
{message}
|
||||
</Text>
|
||||
</View>
|
||||
@@ -124,7 +123,7 @@ export default function SummaryReport({
|
||||
return (
|
||||
<View
|
||||
key={userId}
|
||||
style={styles.summaryInvitationsItem}
|
||||
style={styles.item}
|
||||
>
|
||||
{typeof item === 'string' ? (
|
||||
<TextItem
|
||||
@@ -135,11 +134,11 @@ export default function SummaryReport({
|
||||
) : (
|
||||
<UserItem
|
||||
user={item}
|
||||
containerStyle={styles.summaryInvitationsUser}
|
||||
containerStyle={styles.user}
|
||||
testID={`${testID}.user_item`}
|
||||
/>
|
||||
)}
|
||||
<Text style={styles.summaryInvitationsReason}>
|
||||
<Text style={styles.reason}>
|
||||
{reason}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
@@ -703,7 +703,7 @@ export function setButtons(componentId: string, buttons: NavButtons = {leftButto
|
||||
mergeNavigationOptions(componentId, options);
|
||||
}
|
||||
|
||||
export function showOverlay(name: string, passProps = {}, options = {}) {
|
||||
export function showOverlay(name: string, passProps = {}, options: Options = {}) {
|
||||
if (!isScreenRegistered(name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -327,8 +327,8 @@
|
||||
"intro.welcome.public": "Add some more team members to the channel or start a conversation below.",
|
||||
"invite_people_to_team.message": "Here’s a link to collaborate and communicate with us on Mattermost.",
|
||||
"invite_people_to_team.title": "Join the {team} team",
|
||||
"invite.members.already-member": "This person is already a team member",
|
||||
"invite.members.user-is-guest": "Contact your admin to make this guest a full member",
|
||||
"invite.members.already_member": "This person is already a team member",
|
||||
"invite.members.user_is_guest": "Contact your admin to make this guest a full member",
|
||||
"invite.search.email_invite": "invite",
|
||||
"invite.search.no_results": "No one found matching",
|
||||
"invite.searchPlaceholder": "Type a name or email address…",
|
||||
|
||||
Reference in New Issue
Block a user