diff --git a/src/account-info/AccountDetails.js b/src/account-info/AccountDetails.js index ba8ca126905..edf11a35565 100644 --- a/src/account-info/AccountDetails.js +++ b/src/account-info/AccountDetails.js @@ -16,6 +16,7 @@ import { getUserStatus } from '../user-statuses/userStatusesModel'; import PresenceStatusIndicator from '../common/PresenceStatusIndicator'; import ActivityText from '../title/ActivityText'; import { nowInTimeZone } from '../utils/date'; +import CustomProfileFields from './CustomProfileFields'; const componentStyles = createStyleSheet({ componentListItem: { @@ -96,6 +97,9 @@ export default function AccountDetails(props: Props): Node { /> )} + {/* TODO: It's weird to omit fields on `isSelf` like this, so you can't + see how your profile looks to other people. Make this condition + its own prop, passed by ProfileScreen… or cut the condition entirely. */} {!isSelf && ( @@ -106,6 +110,7 @@ export default function AccountDetails(props: Props): Node { )} + ); } diff --git a/src/account-info/CustomProfileFields.js b/src/account-info/CustomProfileFields.js new file mode 100644 index 00000000000..6970300f12d --- /dev/null +++ b/src/account-info/CustomProfileFields.js @@ -0,0 +1,132 @@ +// @flow strict-local +import * as React from 'react'; +import { View } from 'react-native'; + +import { type UserOrBot, type UserId } from '../api/modelTypes'; +import WebLink from '../common/WebLink'; +import ZulipText from '../common/ZulipText'; +import ZulipTextIntl from '../common/ZulipTextIntl'; +import { ensureUnreachable } from '../generics'; +import { useSelector } from '../react-redux'; +import { tryGetUserForId } from '../selectors'; +import { + type CustomProfileFieldValue, + getCustomProfileFieldsForUser, +} from '../users/userSelectors'; +import UserAvatar from '../common/UserAvatar'; + +type Props = {| + +user: UserOrBot, +|}; + +function CustomProfileFieldUser(props: {| +userId: UserId |}): React.Node { + const { userId } = props; + const user = useSelector(state => tryGetUserForId(state, userId)); + + const styles = React.useMemo( + () => ({ + text: { marginStart: 8 }, + row: { flexDirection: 'row', marginVertical: 4 }, + }), + [], + ); + + if (!user) { + return ; + } + + return ( + + + + + ); +} + +function CustomProfileFieldRow(props: {| + +name: string, + +value: CustomProfileFieldValue, + +first: boolean, +|}): React.Node { + const { first, name, value } = props; + + const styles = React.useMemo( + () => ({ + row: { marginTop: first ? 0 : 8, flexDirection: 'row' }, + label: { width: 96, marginEnd: 8, fontWeight: 'bold' }, + valueView: { flex: 1 }, + valueText: { flex: 1 }, + }), + [first], + ); + + let valueElement = undefined; + switch (value.displayType) { + case 'text': + valueElement = ; + break; + + case 'link': + valueElement = ( + + {value.url ? ( + + ) : ( + + )} + + ); + break; + + case 'users': + valueElement = ( + + {value.userIds.map(userId => ( + + ))} + + ); + break; + + default: + ensureUnreachable(value.displayType); + return null; + } + + return ( + + + {valueElement} + + ); +} + +export default function CustomProfileFields(props: Props): React.Node { + const { user } = props; + const realm = useSelector(state => state.realm); + + const fields = React.useMemo(() => getCustomProfileFieldsForUser(realm, user), [realm, user]); + + const styles = React.useMemo( + () => ({ + outer: { flexDirection: 'row', justifyContent: 'center' }, + inner: { flexBasis: 400, flexShrink: 1 }, + }), + [], + ); + + return ( + + + {fields.map((field, i) => ( + + ))} + + + ); +} diff --git a/static/translations/messages_en.json b/static/translations/messages_en.json index f7529e1bb3d..96e4a585bf2 100644 --- a/static/translations/messages_en.json +++ b/static/translations/messages_en.json @@ -186,6 +186,7 @@ "Send private message": "Send private message", "View private messages": "View private messages", "(This user has been deactivated)": "(This user has been deactivated)", + "(unknown user)": "(unknown user)", "Forgot password?": "Forgot password?", "Members": "Members", "Recipients": "Recipients",