Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Invite user to workspace via invite link #37525

Merged
merged 37 commits into from
Mar 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
8098418
Invite user to workspace via invite link
narefyev91 Feb 29, 2024
e7dea09
Merge branch 'main' into invite-member-with-join-link
narefyev91 Feb 29, 2024
21aef54
fix first part of ts
narefyev91 Feb 29, 2024
ea7e586
fix last part of ts
narefyev91 Feb 29, 2024
a88c6d2
Merge branch 'main' into invite-member-with-join-link
narefyev91 Feb 29, 2024
a0c5d5e
Updates based on comments
narefyev91 Mar 1, 2024
290197f
clean up
narefyev91 Mar 1, 2024
0a13a32
update ui for list
narefyev91 Mar 1, 2024
a695178
pod lock
narefyev91 Mar 1, 2024
c2b3da7
fix lint
narefyev91 Mar 1, 2024
3d28863
fix lint
narefyev91 Mar 1, 2024
510c1ba
fix prettier
narefyev91 Mar 1, 2024
67ed8bf
add correct types for message
narefyev91 Mar 1, 2024
3ed4d69
Merge branch 'main' into invite-member-with-join-link
narefyev91 Mar 1, 2024
4fde655
resolve correct naming for inviter email
narefyev91 Mar 1, 2024
7945f9d
Hide action and not show message if invite action is resolved
narefyev91 Mar 4, 2024
c28a204
Merge branch 'main' into invite-member-with-join-link
narefyev91 Mar 4, 2024
5b41738
add correct navigation
narefyev91 Mar 4, 2024
a205cb4
add correct payload for accept/reject
narefyev91 Mar 4, 2024
420d0cc
Merge branch 'main' into invite-member-with-join-link
narefyev91 Mar 4, 2024
33ad6bd
Merge branch 'main' into invite-member-with-join-link
narefyev91 Mar 5, 2024
f42431c
Move admin room in left panel to pin with green dot
narefyev91 Mar 5, 2024
7387694
Merge branch 'main' into invite-member-with-join-link
narefyev91 Mar 6, 2024
4111657
add muted style
narefyev91 Mar 6, 2024
d59715c
use correct redirects, fix native ui issue
narefyev91 Mar 6, 2024
942e296
prettier
narefyev91 Mar 6, 2024
451b211
Merge branch 'main' into invite-member-with-join-link
narefyev91 Mar 7, 2024
65b1923
resolve comments
narefyev91 Mar 7, 2024
e63978a
support icon inside badge
narefyev91 Mar 7, 2024
6bfaf96
fix lint
narefyev91 Mar 7, 2024
d2cae9b
Merge branch 'main' into invite-member-with-join-link
narefyev91 Mar 7, 2024
4a1ca6d
resolve comments
narefyev91 Mar 7, 2024
7c97020
fix single request execution
narefyev91 Mar 7, 2024
862e897
fix icon + prettier
narefyev91 Mar 7, 2024
e148429
resolve spacing
narefyev91 Mar 7, 2024
1c6307f
Merge branch 'main' into invite-member-with-join-link
narefyev91 Mar 7, 2024
9997e2f
resolve merge conflicts
narefyev91 Mar 7, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,7 @@ const CONST = {
LIMIT: 50,
TYPE: {
ADDCOMMENT: 'ADDCOMMENT',
ACTIONABLEJOINREQUEST: 'ACTIONABLEJOINREQUEST',
APPROVED: 'APPROVED',
CHRONOSOOOLIST: 'CHRONOSOOOLIST',
CLOSED: 'CLOSED',
Expand Down Expand Up @@ -678,6 +679,10 @@ const CONST = {
INVITE: 'invited',
NOTHING: 'nothing',
},
ACTIONABLE_MENTION_JOIN_WORKSPACE_RESOLUTION: {
ACCEPT: 'accept',
DECLINE: 'decline',
},
ARCHIVE_REASON: {
DEFAULT: 'default',
ACCOUNT_CLOSED: 'accountClosed',
Expand Down
2 changes: 2 additions & 0 deletions src/ONYXKEYS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@ const ONYXKEYS = {
POLICY_MEMBERS: 'policyMembers_',
POLICY_DRAFTS: 'policyDrafts_',
POLICY_MEMBERS_DRAFTS: 'policyMembersDrafts_',
POLICY_JOIN_MEMBER: 'policyJoinMember_',
POLICY_CATEGORIES: 'policyCategories_',
POLICY_RECENTLY_USED_CATEGORIES: 'policyRecentlyUsedCategories_',
POLICY_TAGS: 'policyTags_',
Expand Down Expand Up @@ -487,6 +488,7 @@ type OnyxCollectionValuesMapping = {
[ONYXKEYS.COLLECTION.SELECTED_TAB]: string;
[ONYXKEYS.COLLECTION.PRIVATE_NOTES_DRAFT]: string;
[ONYXKEYS.COLLECTION.NEXT_STEP]: OnyxTypes.ReportNextStep;
[ONYXKEYS.COLLECTION.POLICY_JOIN_MEMBER]: OnyxTypes.PolicyJoinMember;
};

type OnyxValuesMapping = {
Expand Down
4 changes: 4 additions & 0 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,10 @@ const ROUTES = {
route: 'workspace/:policyID/avatar',
getRoute: (policyID: string) => `workspace/${policyID}/avatar` as const,
},
WORKSPACE_JOIN_USER: {
route: 'workspace/:policyID/join',
getRoute: (policyID: string, inviterEmail: string) => `workspace/${policyID}/join?email=${inviterEmail}` as const,
},
WORKSPACE_SETTINGS_CURRENCY: {
route: 'workspace/:policyID/settings/currency',
getRoute: (policyID: string) => `workspace/${policyID}/settings/currency` as const,
Expand Down
1 change: 1 addition & 0 deletions src/SCREENS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ const SCREENS = {
SIGN_IN_WITH_GOOGLE_DESKTOP: 'GoogleSignInDesktop',
DESKTOP_SIGN_IN_REDIRECT: 'DesktopSignInRedirect',
SAML_SIGN_IN: 'SAMLSignIn',
WORKSPACE_JOIN_USER: 'WorkspaceJoinUser',

MONEY_REQUEST: {
MANUAL_TAB: 'manual',
Expand Down
34 changes: 33 additions & 1 deletion src/components/Badge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@ import React, {useCallback} from 'react';
import type {GestureResponderEvent, PressableStateCallbackType, StyleProp, TextStyle, ViewStyle} from 'react-native';
import {View} from 'react-native';
import useStyleUtils from '@hooks/useStyleUtils';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import variables from '@styles/variables';
import CONST from '@src/CONST';
import type IconAsset from '@src/types/utils/IconAsset';
import Icon from './Icon';
import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback';
import Text from './Text';

Expand Down Expand Up @@ -31,11 +35,29 @@ type BadgeProps = {

/** Callback to be called on onPress */
onPress?: (event?: GestureResponderEvent | KeyboardEvent) => void;

/** The icon asset to display to the left of the text */
icon?: IconAsset | null;

/** Any additional styles to pass to the left icon container. */
iconStyles?: StyleProp<ViewStyle>;
};

function Badge({success = false, error = false, pressable = false, text, environment = CONST.ENVIRONMENT.DEV, badgeStyles, textStyles, onPress = () => {}}: BadgeProps) {
function Badge({
success = false,
error = false,
pressable = false,
text,
environment = CONST.ENVIRONMENT.DEV,
badgeStyles,
textStyles,
onPress = () => {},
icon,
iconStyles = [],
}: BadgeProps) {
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
const theme = useTheme();
const textColorStyles = success || error ? styles.textWhite : undefined;
const Wrapper = pressable ? PressableWithoutFeedback : View;

Expand All @@ -53,6 +75,16 @@ function Badge({success = false, error = false, pressable = false, text, environ
aria-label={!pressable ? text : undefined}
accessible={false}
>
{icon && (
<View style={[styles.mr2, iconStyles]}>
<Icon
width={variables.iconSizeExtraSmall}
height={variables.iconSizeExtraSmall}
src={icon}
fill={theme.icon}
/>
</View>
)}
<Text
style={[styles.badgeText, textColorStyles, textStyles]}
numberOfLines={1}
Expand Down
5 changes: 5 additions & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1754,6 +1754,7 @@ export default {
workspaceType: 'Workspace type',
workspaceAvatar: 'Workspace avatar',
mustBeOnlineToViewMembers: 'You must be online in order to view members of this workspace.',
requested: 'Requested',
},
type: {
free: 'Free',
Expand Down Expand Up @@ -2243,6 +2244,10 @@ export default {
invite: 'Invite them',
nothing: 'Do nothing',
},
actionableMentionJoinWorkspaceOptions: {
accept: 'Accept',
decline: 'Decline',
},
teachersUnitePage: {
teachersUnite: 'Teachers Unite',
joinExpensifyOrg: 'Join Expensify.org in eliminating injustice around the world and help teachers split their expenses for classrooms in need!',
Expand Down
5 changes: 5 additions & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1778,6 +1778,7 @@ export default {
workspaceType: 'Tipo de espacio de trabajo',
workspaceAvatar: 'Espacio de trabajo avatar',
mustBeOnlineToViewMembers: 'Debes estar en línea para poder ver los miembros de este espacio de trabajo.',
requested: 'Solicitado',
},
type: {
free: 'Gratis',
Expand Down Expand Up @@ -2709,6 +2710,10 @@ export default {
invite: 'Invitar',
nothing: 'No hacer nada',
},
actionableMentionJoinWorkspaceOptions: {
accept: 'Aceptar',
decline: 'Rechazar',
},
moderation: {
flagDescription: 'Todos los mensajes marcados se enviarán a un moderador para su revisión.',
chooseAReason: 'Elige abajo un motivo para reportarlo:',
Expand Down
5 changes: 5 additions & 0 deletions src/libs/API/parameters/AcceptJoinRequest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
type AcceptJoinRequestParams = {
requests: string;
};

export default AcceptJoinRequestParams;
5 changes: 5 additions & 0 deletions src/libs/API/parameters/DeclineJoinRequest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
type DeclineJoinRequestParams = {
requests: string;
};

export default DeclineJoinRequestParams;
6 changes: 6 additions & 0 deletions src/libs/API/parameters/JoinPolicyInviteLink.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
type JoinPolicyInviteLinkParams = {
policyID: string;
inviterEmail: string;
};

export default JoinPolicyInviteLinkParams;
3 changes: 3 additions & 0 deletions src/libs/API/parameters/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,3 +156,6 @@ export type {default as SetWorkspaceAutoReportingFrequencyParams} from './SetWor
export type {default as SetWorkspaceAutoReportingMonthlyOffsetParams} from './SetWorkspaceAutoReportingMonthlyOffsetParams';
export type {default as SetWorkspaceApprovalModeParams} from './SetWorkspaceApprovalModeParams';
export type {default as SwitchToOldDotParams} from './SwitchToOldDotParams';
export type {default as AcceptJoinRequestParams} from './AcceptJoinRequest';
export type {default as DeclineJoinRequestParams} from './DeclineJoinRequest';
export type {default as JoinPolicyInviteLinkParams} from './JoinPolicyInviteLink';
8 changes: 8 additions & 0 deletions src/libs/API/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,9 @@ const WRITE_COMMANDS = {
CANCEL_PAYMENT: 'CancelPayment',
ACCEPT_ACH_CONTRACT_FOR_BANK_ACCOUNT: 'AcceptACHContractForBankAccount',
SWITCH_TO_OLD_DOT: 'SwitchToOldDot',
JOIN_POLICY_VIA_INVITE_LINK: 'JoinWorkspaceViaInviteLink',
ACCEPT_JOIN_REQUEST: 'AcceptJoinRequest',
DECLINE_JOIN_REQUEST: 'DeclineJoinRequest',
} as const;

type WriteCommand = ValueOf<typeof WRITE_COMMANDS>;
Expand Down Expand Up @@ -312,6 +315,9 @@ type WriteCommandParameters = {
[WRITE_COMMANDS.SET_WORKSPACE_AUTO_REPORTING_MONTHLY_OFFSET]: Parameters.SetWorkspaceAutoReportingMonthlyOffsetParams;
[WRITE_COMMANDS.SET_WORKSPACE_APPROVAL_MODE]: Parameters.SetWorkspaceApprovalModeParams;
[WRITE_COMMANDS.SWITCH_TO_OLD_DOT]: Parameters.SwitchToOldDotParams;
[WRITE_COMMANDS.JOIN_POLICY_VIA_INVITE_LINK]: Parameters.JoinPolicyInviteLinkParams;
[WRITE_COMMANDS.ACCEPT_JOIN_REQUEST]: Parameters.AcceptJoinRequestParams;
[WRITE_COMMANDS.DECLINE_JOIN_REQUEST]: Parameters.DeclineJoinRequestParams;
};

const READ_COMMANDS = {
Expand Down Expand Up @@ -388,6 +394,7 @@ const SIDE_EFFECT_REQUEST_COMMANDS = {
OPEN_OLD_DOT_LINK: 'OpenOldDotLink',
REVEAL_EXPENSIFY_CARD_DETAILS: 'RevealExpensifyCardDetails',
GET_MISSING_ONYX_MESSAGES: 'GetMissingOnyxMessages',
JOIN_POLICY_VIA_INVITE_LINK: 'JoinWorkspaceViaInviteLink',
RECONNECT_APP: 'ReconnectApp',
} as const;

Expand All @@ -399,6 +406,7 @@ type SideEffectRequestCommandParameters = {
[SIDE_EFFECT_REQUEST_COMMANDS.OPEN_OLD_DOT_LINK]: Parameters.OpenOldDotLinkParams;
[SIDE_EFFECT_REQUEST_COMMANDS.REVEAL_EXPENSIFY_CARD_DETAILS]: Parameters.RevealExpensifyCardDetailsParams;
[SIDE_EFFECT_REQUEST_COMMANDS.GET_MISSING_ONYX_MESSAGES]: Parameters.GetMissingOnyxMessagesParams;
[SIDE_EFFECT_REQUEST_COMMANDS.JOIN_POLICY_VIA_INVITE_LINK]: Parameters.JoinPolicyInviteLinkParams;
[SIDE_EFFECT_REQUEST_COMMANDS.RECONNECT_APP]: Parameters.ReconnectAppParams;
};

Expand Down
9 changes: 9 additions & 0 deletions src/libs/Navigation/AppNavigator/AuthScreens.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ const loadConciergePage = () => require('../../../pages/ConciergePage').default
const loadProfileAvatar = () => require('../../../pages/settings/Profile/ProfileAvatar').default as React.ComponentType;
const loadWorkspaceAvatar = () => require('../../../pages/workspace/WorkspaceAvatar').default as React.ComponentType;
const loadReportAvatar = () => require('../../../pages/ReportAvatar').default as React.ComponentType;
const loadWorkspaceJoinUser = () => require('@pages/workspace/WorkspaceJoinUserPage').default as React.ComponentType;

let timezone: Timezone | null;
let currentAccountID = -1;
Expand Down Expand Up @@ -356,6 +357,14 @@ function AuthScreens({session, lastOpenedPublicRoomID, isUsingMemoryOnlyKeys = f
options={screenOptions.fullScreen}
component={DesktopSignInRedirectPage}
/>
<RootStack.Screen
name={SCREENS.WORKSPACE_JOIN_USER}
options={{
headerShown: false,
presentation: 'transparentModal',
}}
getComponent={loadWorkspaceJoinUser}
/>
</RootStack.Navigator>
</View>
);
Expand Down
1 change: 1 addition & 0 deletions src/libs/Navigation/linkingConfig/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const config: LinkingOptions<RootStackParamList>['config'] = {
[SCREENS.PROFILE_AVATAR]: ROUTES.PROFILE_AVATAR.route,
[SCREENS.WORKSPACE_AVATAR]: ROUTES.WORKSPACE_AVATAR.route,
[SCREENS.REPORT_AVATAR]: ROUTES.REPORT_AVATAR.route,
[SCREENS.WORKSPACE_JOIN_USER]: ROUTES.WORKSPACE_JOIN_USER.route,

// Sidebar
[NAVIGATORS.BOTTOM_TAB_NAVIGATOR]: {
Expand Down
4 changes: 4 additions & 0 deletions src/libs/Navigation/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,10 @@ type AuthScreensParamList = SharedScreensParamList & {
[SCREENS.WORKSPACE_AVATAR]: {
policyID: string;
};
[SCREENS.WORKSPACE_JOIN_USER]: {
policyID: string;
email: string;
};
[SCREENS.REPORT_AVATAR]: {
reportID: string;
};
Expand Down
4 changes: 3 additions & 1 deletion src/libs/PolicyUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,9 @@ function getPolicyBrickRoadIndicatorStatus(policy: OnyxEntry<Policy>, policyMemb
*/
function shouldShowPolicy(policy: OnyxEntry<Policy>, isOffline: boolean): boolean {
return (
!!policy && policy?.isPolicyExpenseChatEnabled && (isOffline || policy?.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE || Object.keys(policy.errors ?? {}).length > 0)
!!policy &&
(policy?.isPolicyExpenseChatEnabled || Boolean(policy?.isJoinRequestPending)) &&
(isOffline || policy?.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE || Object.keys(policy.errors ?? {}).length > 0)
);
}

Expand Down
32 changes: 31 additions & 1 deletion src/libs/ReportActionsUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,15 @@ import Onyx from 'react-native-onyx';
import type {ValueOf} from 'type-fest';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {ActionName, ChangeLog, IOUMessage, OriginalMessageActionableMentionWhisper, OriginalMessageIOU, OriginalMessageReimbursementDequeued} from '@src/types/onyx/OriginalMessage';
import type {
ActionName,
ChangeLog,
IOUMessage,
OriginalMessageActionableMentionWhisper,
OriginalMessageIOU,
OriginalMessageJoinPolicyChangeLog,
OriginalMessageReimbursementDequeued,
} from '@src/types/onyx/OriginalMessage';
import type Report from '@src/types/onyx/Report';
import type {Message, ReportActionBase, ReportActions} from '@src/types/onyx/ReportAction';
import type ReportAction from '@src/types/onyx/ReportAction';
Expand Down Expand Up @@ -881,6 +889,26 @@ function isCurrentActionUnread(report: Report | EmptyObject, reportAction: Repor
return isReportActionUnread(reportAction, lastReadTime) && (!prevReportAction || !isReportActionUnread(prevReportAction, lastReadTime));
}

/**
* Checks if a given report action corresponds to a join request action.
* @param reportAction
*/
function isActionableJoinRequest(reportAction: OnyxEntry<ReportAction>): boolean {
return reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.ACTIONABLEJOINREQUEST;
}

/**
* Checks if any report actions correspond to a join request action that is still pending.
* @param reportID
*/
function isActionableJoinRequestPending(reportID: string): boolean {
const sortedReportActions = getSortedReportActions(Object.values(getAllReportActions(reportID)));
const findPendingRequest = sortedReportActions.find(
(reportActionItem) => isActionableJoinRequest(reportActionItem) && (reportActionItem as OriginalMessageJoinPolicyChangeLog)?.originalMessage?.choice === '',
);
return !!findPendingRequest;
}

function isApprovedOrSubmittedReportAction(action: OnyxEntry<ReportAction> | EmptyObject) {
return [CONST.REPORT.ACTIONS.TYPE.APPROVED, CONST.REPORT.ACTIONS.TYPE.SUBMITTED].some((type) => type === action?.actionName);
}
Expand Down Expand Up @@ -946,6 +974,8 @@ export {
isActionableMentionWhisper,
getActionableMentionWhisperMessage,
isCurrentActionUnread,
isActionableJoinRequest,
isActionableJoinRequestPending,
};

export type {LastVisibleMessage};
15 changes: 15 additions & 0 deletions src/libs/ReportUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1083,6 +1083,16 @@ function isArchivedRoom(report: OnyxEntry<Report> | EmptyObject): boolean {
return report?.statusNum === CONST.REPORT.STATUS_NUM.CLOSED && report?.stateNum === CONST.REPORT.STATE_NUM.APPROVED;
}

/**
* Whether the provided report is the admin's room
*/
function isJoinRequestInAdminRoom(report: OnyxEntry<Report>): boolean {
if (!report) {
return false;
}
return ReportActionsUtils.isActionableJoinRequestPending(report.reportID);
}

/**
* Checks if the current user is allowed to comment on the given report.
*/
Expand Down Expand Up @@ -1910,6 +1920,10 @@ function requiresAttentionFromCurrentUser(optionOrReport: OnyxEntry<Report> | Op
return false;
}

if (isJoinRequestInAdminRoom(optionOrReport)) {
return true;
}

if (isArchivedRoom(optionOrReport) || isArchivedRoom(getReport(optionOrReport.parentReportID))) {
return false;
}
Expand Down Expand Up @@ -5358,6 +5372,7 @@ export {
canEditRoomVisibility,
canEditPolicyDescription,
getPolicyDescriptionText,
isJoinRequestInAdminRoom,
canAddOrDeleteTransactions,
shouldCreateNewMoneyRequestReport,
};
Expand Down
6 changes: 6 additions & 0 deletions src/libs/SidebarUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,12 @@ function getOptionData({

result.isIOUReportOwner = ReportUtils.isIOUOwnedByCurrentUser(result as Report);

if (ReportActionsUtils.isActionableJoinRequestPending(report.reportID)) {
result.isPinned = true;
result.isUnread = true;
result.brickRoadIndicator = CONST.BRICK_ROAD_INDICATOR_STATUS.INFO;
}

if (!hasMultipleParticipants) {
result.accountID = personalDetail?.accountID;
result.login = personalDetail?.login;
Expand Down
Loading
Loading