Page MenuHomePhorge

D8156.1765098902.diff
No OneTemporary

Size
7 KB
Referenced Files
None
Subscribers
None

D8156.1765098902.diff

diff --git a/native/chat/chat.react.js b/native/chat/chat.react.js
--- a/native/chat/chat.react.js
+++ b/native/chat/chat.react.js
@@ -69,7 +69,9 @@
type ChatParamList,
type ChatTopTabsParamList,
MessageSearchRouteName,
+ ChangeRolesScreenRouteName,
} from '../navigation/route-names.js';
+import ChangeRolesScreen from '../roles/change-roles-screen.react.js';
import MessageSearch from '../search/message-search.react.js';
import SearchHeader from '../search/search-header.react.js';
import SearchMessagesButton from '../search/search-messages-button.react.js';
@@ -293,6 +295,10 @@
headerTitle: 'Pinned Messages',
headerBackTitleVisible: false,
};
+const changeRolesScreenOptions = {
+ headerTitle: 'Change Role',
+ presentation: 'modal',
+};
export type ChatNavigationProp<
RouteName: $Keys<ChatParamList> = $Keys<ChatParamList>,
@@ -411,6 +417,11 @@
component={MessageSearch}
options={messageSearchOptions}
/>
+ <Chat.Screen
+ name={ChangeRolesScreenRouteName}
+ component={ChangeRolesScreen}
+ options={changeRolesScreenOptions}
+ />
</Chat.Navigator>
<MessageStorePruner />
<ThreadScreenPruner />
diff --git a/native/navigation/route-names.js b/native/navigation/route-names.js
--- a/native/navigation/route-names.js
+++ b/native/navigation/route-names.js
@@ -42,6 +42,7 @@
import type { VideoPlaybackModalParams } from '../media/video-playback-modal.react.js';
import type { CustomServerModalParams } from '../profile/custom-server-modal.react.js';
import type { RelationshipListItemTooltipModalParams } from '../profile/relationship-list-item-tooltip-modal.react.js';
+import type { ChangeRolesScreenParams } from '../roles/change-roles-screen.react.js';
import type { MessageSearchParams } from '../search/message-search.react.js';
export const ActionResultModalRouteName = 'ActionResultModal';
@@ -53,6 +54,7 @@
export const BlockListRouteName = 'BlockList';
export const BuildInfoRouteName = 'BuildInfo';
export const CalendarRouteName = 'Calendar';
+export const ChangeRolesScreenRouteName = 'ChangeRolesScreen';
export const ChatCameraModalRouteName = 'ChatCameraModal';
export const ChatRouteName = 'Chat';
export const ChatThreadListRouteName = 'ChatThreadList';
@@ -187,6 +189,7 @@
+FullScreenThreadMediaGallery: FullScreenThreadMediaGalleryParams,
+MessageResultsScreen: MessageResultsScreenParams,
+MessageSearch: MessageSearchParams,
+ +ChangeRolesScreen: ChangeRolesScreenParams,
};
export type ChatTopTabsParamList = {
diff --git a/native/roles/change-roles-screen.react.js b/native/roles/change-roles-screen.react.js
new file mode 100644
--- /dev/null
+++ b/native/roles/change-roles-screen.react.js
@@ -0,0 +1,177 @@
+// @flow
+
+import { useActionSheet } from '@expo/react-native-action-sheet';
+import invariant from 'invariant';
+import * as React from 'react';
+import { View, Text, Platform } from 'react-native';
+import { TouchableOpacity } from 'react-native-gesture-handler';
+import { useSafeAreaInsets } from 'react-native-safe-area-context';
+
+import type { RelativeMemberInfo, ThreadInfo } from 'lib/types/thread-types.js';
+import { values } from 'lib/utils/objects.js';
+
+import UserAvatar from '../avatars/user-avatar.react.js';
+import type { ChatNavigationProp } from '../chat/chat.react';
+import SWMansionIcon from '../components/swmansion-icon.react.js';
+import type { NavigationRoute } from '../navigation/route-names.js';
+import { useSelector } from '../redux/redux-utils.js';
+import { useStyles } from '../themes/colors.js';
+
+export type ChangeRolesScreenParams = {
+ +threadInfo: ThreadInfo,
+ +memberInfo: RelativeMemberInfo,
+ +role: ?string,
+};
+
+type Props = {
+ +navigation: ChatNavigationProp<'ChangeRolesScreen'>,
+ +route: NavigationRoute<'ChangeRolesScreen'>,
+};
+
+function ChangeRolesScreen(props: Props): React.Node {
+ const { navigation } = props;
+ const { threadInfo, memberInfo, role } = props.route.params;
+ invariant(role, 'Role must be defined');
+
+ const styles = useStyles(unboundStyles);
+
+ const [selectedRole, setSelectedRole] = React.useState<string>(role);
+ const roleOptions = React.useMemo(
+ () =>
+ values(threadInfo.roles).map(threadRole => ({
+ id: threadRole.id,
+ name: threadRole.name,
+ })),
+ [threadInfo.roles],
+ );
+ const selectedRoleName = React.useMemo(
+ () => roleOptions.find(roleOption => roleOption.id === selectedRole)?.name,
+ [roleOptions, selectedRole],
+ );
+
+ const onRoleChange = React.useCallback(
+ (selectedIndex: ?number) => {
+ if (
+ selectedIndex === undefined ||
+ selectedIndex === null ||
+ selectedIndex === roleOptions.length
+ ) {
+ return;
+ }
+
+ const newRole = roleOptions[selectedIndex].id;
+
+ setSelectedRole(newRole);
+ navigation.setParams({
+ threadInfo,
+ memberInfo,
+ role: newRole,
+ });
+ },
+ [navigation, setSelectedRole, roleOptions, memberInfo, threadInfo],
+ );
+
+ const activeTheme = useSelector(state => state.globalThemeInfo.activeTheme);
+ const { showActionSheetWithOptions } = useActionSheet();
+ const insets = useSafeAreaInsets();
+
+ const showActionSheet = React.useCallback(() => {
+ const options =
+ Platform.OS === 'ios'
+ ? [...roleOptions.map(roleOption => roleOption.name), 'Cancel']
+ : [...roleOptions.map(roleOption => roleOption.name)];
+
+ const cancelButtonIndex = Platform.OS === 'ios' ? options.length - 1 : -1;
+
+ const containerStyle = {
+ paddingBottom: insets.bottom,
+ };
+
+ showActionSheetWithOptions(
+ {
+ options,
+ cancelButtonIndex,
+ containerStyle,
+ userInterfaceStyle: activeTheme ?? 'dark',
+ },
+ onRoleChange,
+ );
+ }, [
+ roleOptions,
+ onRoleChange,
+ insets.bottom,
+ activeTheme,
+ showActionSheetWithOptions,
+ ]);
+
+ return (
+ <View>
+ <View style={styles.descriptionBackground}>
+ <Text style={styles.descriptionText}>
+ Members can only be assigned one role at a time. Changing a
+ member&rsquo;s role will replace their previously assigned role.
+ </Text>
+ </View>
+ <View style={styles.memberInfo}>
+ <UserAvatar userID={memberInfo.id} size="profile" />
+ <Text style={styles.memberInfoUsername}>{memberInfo.username}</Text>
+ </View>
+ <View>
+ <Text style={styles.roleSelectorLabel}>ROLE</Text>
+ <TouchableOpacity onPress={showActionSheet} style={styles.roleSelector}>
+ <Text style={styles.currentRole}>{selectedRoleName}</Text>
+ <SWMansionIcon name="edit-1" size={20} style={styles.pencilIcon} />
+ </TouchableOpacity>
+ </View>
+ </View>
+ );
+}
+
+const unboundStyles = {
+ descriptionBackground: {
+ backgroundColor: 'panelForeground',
+ marginBottom: 20,
+ },
+ descriptionText: {
+ color: 'panelBackgroundLabel',
+ padding: 16,
+ fontSize: 14,
+ },
+ memberInfo: {
+ backgroundColor: 'panelForeground',
+ padding: 16,
+ marginBottom: 30,
+ display: 'flex',
+ flexDirection: 'column',
+ alignItems: 'center',
+ },
+ memberInfoUsername: {
+ color: 'panelForegroundLabel',
+ marginTop: 8,
+ fontSize: 18,
+ fontWeight: '500',
+ },
+ roleSelectorLabel: {
+ color: 'panelForegroundSecondaryLabel',
+ marginLeft: 8,
+ fontSize: 12,
+ },
+ roleSelector: {
+ backgroundColor: 'panelForeground',
+ marginTop: 8,
+ padding: 16,
+ display: 'flex',
+ alignItems: 'center',
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ },
+ currentRole: {
+ color: 'panelForegroundSecondaryLabel',
+ fontSize: 16,
+ },
+ pencilIcon: {
+ color: 'panelInputSecondaryForeground',
+ },
+};
+
+export default ChangeRolesScreen;

File Metadata

Mime Type
text/plain
Expires
Sun, Dec 7, 9:15 AM (4 h, 49 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5837950
Default Alt Text
D8156.1765098902.diff (7 KB)

Event Timeline