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

Directly create a workspace and add the Edit Workspace page #4310

Merged
merged 17 commits into from
Aug 3, 2021
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
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
3 changes: 2 additions & 1 deletion src/ROUTES.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,11 @@ export default {
VALIDATE_LOGIN_WITH_VALIDATE_CODE_NEW_WORKSPACE: 'v/:accountID/:validateCode/new-workspace',
VALIDATE_LOGIN_WITH_VALIDATE_CODE_2FA_NEW_WORKSPACE: 'v/:accountID/:validateCode/2fa/new-workspace',
ENABLE_PAYMENTS: 'enable-payments',
WORKSPACE_NEW: 'workspace/new',
WORKSPACE: 'workspace',
WORKSPACE_EDIT: 'workspace/:policyID/edit',
WORKSPACE_CARD: ':policyID/card',
WORKSPACE_PEOPLE: ':policyID/people',
getWorkspaceEditRoute: policyID => `workspace/${policyID}/edit`,
getWorkspaceCardRoute: policyID => `workspace/${policyID}/card`,
getWorkspacePeopleRoute: policyID => `workspace/${policyID}/people`,
getWorkspaceInviteRoute: policyID => `workspace/${policyID}/invite`,
Expand Down
4 changes: 4 additions & 0 deletions src/languages/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,10 @@ export default {
genericFailureMessage: 'An error occurred inviting the user to the workspace, please try again.',
welcomeNote: ({workspaceName}) => `You have been invited to the ${workspaceName} Workspace! Download the Expensify mobile App to start tracking your expenses.`,
},
edit: {
editWorkspace: 'Edit Workspace',
growlMessageOnSave: 'Your workspace was successfully saved',
},
},
requestCallPage: {
requestACall: 'Request a Call',
Expand Down
10 changes: 7 additions & 3 deletions src/languages/es.js
Original file line number Diff line number Diff line change
Expand Up @@ -399,13 +399,13 @@ export default {
workspace: 'Espacio de trabajo',
},
new: {
newWorkspace: 'Nuevo Workspace',
newWorkspace: 'Nuevo espacio de trabajo',
getTheExpensifyCardAndMore: 'Consigue la Expensify Card y más',
welcome: 'Bienvenido/a',
chooseAName: 'Elige un nombre',
helpText: '¡Dale un nombre a tu Workspace antes de activar tus Expensify Cards!',
helpText: 'Elige un nombre para el espacio de trabajo antes de activar las tarjetas Expensify\n',
getStarted: '¡Empezar!',
genericFailureMessage: 'Se ha producido un error al intentar crear el Workspace. Por favor, inténtalo de nuevo.',
genericFailureMessage: 'Se ha producido un error al intentar crear el espacio de trabajo. Por favor, inténtalo de nuevo.',
},
people: {
assignee: 'Persona asignada',
Expand All @@ -432,6 +432,10 @@ export default {
genericFailureMessage: 'Se produjo un error al invitar al usuario al espacio de trabajo. Vuelva a intentarlo..',
welcomeNote: ({workspaceName}) => `¡Has sido invitado a la ${workspaceName} Espacio de trabajo! Descargue la aplicación móvil Expensify para comenzar a rastrear sus gastos.`,
},
edit: {
editWorkspace: 'Editar espacio de trabajo',
growlMessageOnSave: 'El espacio de trabajo se ha guardado correctamente',
},
},
companyStep: {
headerTitle: 'Información de la Empresa',
Expand Down
6 changes: 3 additions & 3 deletions src/libs/Navigation/AppNavigator/AuthScreens.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ import {
EnablePaymentsStackNavigator,
AddPersonalBankAccountModalStackNavigator,
ReimbursementAccountModalStackNavigator,
NewWorkspaceStackNavigator,
EditWorkspaceStackNavigator,
WorkspaceInviteModalStackNavigator,
RequestCallModalStackNavigator,
ReportDetailsModalStackNavigator,
Expand Down Expand Up @@ -378,9 +378,9 @@ class AuthScreens extends React.Component {
listeners={modalScreenListeners}
/>
<RootStack.Screen
name="NewWorkspace"
name="EditWorkspace"
options={modalScreenOptions}
component={NewWorkspaceStackNavigator}
component={EditWorkspaceStackNavigator}
listeners={modalScreenListeners}
/>
<RootStack.Screen
Expand Down
10 changes: 5 additions & 5 deletions src/libs/Navigation/AppNavigator/ModalStackNavigators.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import EnablePaymentsPage from '../../../pages/EnablePayments';
import AddPersonalBankAccountPage from '../../../pages/AddPersonalBankAccountPage';
import WorkspaceInvitePage from '../../../pages/workspace/WorkspaceInvitePage';
import ReimbursementAccountPage from '../../../pages/ReimbursementAccount/ReimbursementAccountPage';
import NewWorkspacePage from '../../../pages/workspace/NewWorkspacePage';
import EditWorkspacePage from '../../../pages/workspace/EditWorkspacePage';
import RequestCallPage from '../../../pages/RequestCallPage';
import ReportDetailsPage from '../../../pages/ReportDetailsPage';

Expand Down Expand Up @@ -182,9 +182,9 @@ const ReimbursementAccountModalStackNavigator = createModalStackNavigator([{
name: 'ReimbursementAccount_Root',
}]);

const NewWorkspaceStackNavigator = createModalStackNavigator([{
Component: NewWorkspacePage,
name: 'NewWorkspace_Root',
const EditWorkspaceStackNavigator = createModalStackNavigator([{
Component: EditWorkspacePage,
name: 'EditWorkspace_Root',
}]);

const WorkspaceInviteModalStackNavigator = createModalStackNavigator([{
Expand Down Expand Up @@ -212,7 +212,7 @@ export {
EnablePaymentsStackNavigator,
AddPersonalBankAccountModalStackNavigator,
ReimbursementAccountModalStackNavigator,
NewWorkspaceStackNavigator,
EditWorkspaceStackNavigator,
WorkspaceInviteModalStackNavigator,
RequestCallModalStackNavigator,
};
4 changes: 2 additions & 2 deletions src/libs/Navigation/linkingConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,9 @@ export default {
WorkspaceInvite_Root: ROUTES.WORKSPACE_INVITE,
},
},
NewWorkspace: {
EditWorkspace: {
screens: {
NewWorkspace_Root: ROUTES.WORKSPACE_NEW,
EditWorkspace_Root: ROUTES.WORKSPACE_EDIT,
},
},

Expand Down
22 changes: 20 additions & 2 deletions src/libs/actions/Policy.js
Original file line number Diff line number Diff line change
Expand Up @@ -182,9 +182,9 @@ function invite(logins, welcomeNote, policyID) {
/**
* Merges the passed in login into the specified policy
*
* @param {String} name
* @param {String} [name]
*/
function create(name) {
function create(name = '') {
API.Policy_Create({type: CONST.POLICY.TYPE.FREE, policyName: name})
.then((response) => {
if (response.jsonCode !== 200) {
Expand Down Expand Up @@ -223,6 +223,23 @@ function setAvatarURL(policyID, avatarURL = '') {
});
}

/**
* Sets the name of the policy.
* @param {String} policyID
* @param {String} name
*/
function setName(policyID, name) {
API.UpdatePolicy({policyID, value: JSON.stringify({name}), lastModified: null})
.then((policyResponse) => {
if (policyResponse.jsonCode !== 200) {
return;
}

Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {name});
Growl.success(translateLocal('workspace.edit.growlMessageOnSave'));
});
}

/**
* @param {String} policyID
* @param {Object} file
Expand All @@ -247,4 +264,5 @@ export {
create,
updateAvatar,
setAvatarURL,
setName,
};
3 changes: 2 additions & 1 deletion src/pages/home/sidebar/SidebarScreen.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
import Permissions from '../../../libs/Permissions';
import ONYXKEYS from '../../../ONYXKEYS';
import Firebase from '../../../libs/Firebase';
import {create} from '../../../libs/actions/Policy';

const propTypes = {
/** Beta features list */
Expand Down Expand Up @@ -147,7 +148,7 @@ class SidebarScreen extends Component {
iconHeight: 40,
text: this.props.translate('workspace.new.newWorkspace'),
description: this.props.translate('workspace.new.getTheExpensifyCardAndMore'),
onSelected: () => Navigation.navigate(ROUTES.WORKSPACE_NEW),
onSelected: () => create(),
},
] : []),
]}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,35 +12,55 @@ import styles from '../../styles/styles';
import WorkspaceDefaultAvatar from '../../../assets/images/workspace-default-avatar.svg';
import TextInputWithLabel from '../../components/TextInputWithLabel';
import Button from '../../components/Button';
import Text from '../../components/Text';
import compose from '../../libs/compose';
import {create} from '../../libs/actions/Policy';
import {setName, setAvatarURL, updateAvatar} from '../../libs/actions/Policy';
import defaultTheme from '../../styles/themes/default';
import AvatarWithImagePicker from '../../components/AvatarWithImagePicker';

const propTypes = {
/** List of betas */
betas: PropTypes.arrayOf(PropTypes.string),

...withLocalizePropTypes,

/** Policy being edited */
policy: PropTypes.shape({
/** ID of the policy */
id: PropTypes.string,

/** Name of the policy */
name: PropTypes.string,

/** Avatar url of the policy */
avatarURL: PropTypes.string,
}).isRequired,

/** URL Route params */
route: PropTypes.shape({
/** Params from the URL path */
params: PropTypes.shape({
/** policyID passed via route: /workspace/:policyID/edit */
policyID: PropTypes.string,
}),
}).isRequired,
};
const defaultProps = {
betas: [],
};

class NewWorkspacePage extends React.Component {
class EditWorkspacePage extends React.Component {
constructor(props) {
super(props);

this.state = {
name: '',
name: props.policy.name,
};

this.submit = this.submit.bind(this);
}

submit() {
const name = this.state.name.trim();
create(name);
setName(this.props.policy.id, name);
}

render() {
Expand All @@ -52,12 +72,21 @@ class NewWorkspacePage extends React.Component {
return (
<ScreenWrapper>
<HeaderWithCloseButton
title={this.props.translate('workspace.new.welcome')}
title={this.props.translate('workspace.edit.editWorkspace')}
onCloseButtonPress={Navigation.dismissModal}
/>

<View style={[styles.pageWrapper, styles.flex1]}>
<WorkspaceDefaultAvatar height={80} width={80} fill={defaultTheme.iconSuccessFill} />
<AvatarWithImagePicker
avatarURL={this.props.policy.avatarURL}
DefaultAvatar={() => <WorkspaceDefaultAvatar height={80} width={80} fill={defaultTheme.icon} />}
anchorPosition={{top: 176, right: 20}}
isUsingDefaultAvatar={!this.props.policy.avatarURL}
onImageSelected={(image) => {
updateAvatar(this.props.policy.id, image);
}}
onImageRemoved={() => setAvatarURL(this.props.policy.id)}
/>

<View style={[styles.mt6, styles.w100, styles.flex1]}>
<TextInputWithLabel
Expand All @@ -66,30 +95,34 @@ class NewWorkspacePage extends React.Component {
onChangeText={name => this.setState({name})}
onSubmitEditting={this.submit}
/>
<Text style={[styles.mt6]}>{this.props.translate('workspace.new.helpText')}</Text>
</View>

<Button
success
style={[styles.w100]}
text={this.props.translate('workspace.new.getStarted')}
text={this.props.translate('common.save')}
onPress={this.submit}
pressOnEnter
isDisabled={!this.state.name}
/>
</View>
</ScreenWrapper>
);
}
}

NewWorkspacePage.propTypes = propTypes;
NewWorkspacePage.defaultProps = defaultProps;
EditWorkspacePage.propTypes = propTypes;
EditWorkspacePage.defaultProps = defaultProps;
EditWorkspacePage.displayName = 'EditWorkspacePage';

export default compose(
withOnyx({
betas: {
key: ONYXKEYS.BETAS,
},
policy: {
key: ({route}) => `${ONYXKEYS.COLLECTION.POLICY}${route.params.policyID}`,
},
}),
withLocalize,
)(NewWorkspacePage);
)(EditWorkspacePage);
35 changes: 20 additions & 15 deletions src/pages/workspace/WorkspaceSidebar.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import _ from 'underscore';
import React from 'react';
import {View, ScrollView} from 'react-native';
import {View, ScrollView, Pressable} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
Expand All @@ -12,7 +12,7 @@ import Icon from '../../components/Icon';
import {
Users,
ExpensifyCard,
Workspace,
Workspace, Pencil,
} from '../../components/Icon/Expensicons';
import ScreenWrapper from '../../components/ScreenWrapper';
import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
Expand All @@ -22,8 +22,7 @@ import HeaderWithCloseButton from '../../components/HeaderWithCloseButton';
import withWindowDimensions, {windowDimensionsPropTypes} from '../../components/withWindowDimensions';
import compose from '../../libs/compose';
import ONYXKEYS from '../../ONYXKEYS';
import AvatarWithImagePicker from '../../components/AvatarWithImagePicker';
import {updateAvatar, setAvatarURL} from '../../libs/actions/Policy';
import Avatar from '../../components/Avatar';

const propTypes = {
/** Policy for the current route */
Expand Down Expand Up @@ -87,24 +86,30 @@ const WorkspaceSidebar = ({translate, isSmallScreenWidth, policy}) => {
)}
<View style={styles.pageWrapper}>
<View style={[styles.settingsPageBody, styles.alignItemsCenter]}>
<AvatarWithImagePicker
avatarURL={policy.avatarURL}
DefaultAvatar={() => (
<Pressable
style={[styles.alignItemsCenter, styles.mb3]}
onPress={() => Navigation.navigate(ROUTES.getWorkspaceEditRoute(policy.id))}
>
{policy.avatarURL ? (
<Avatar
containerStyles={styles.avatarLarge}
imageStyles={[styles.avatarLarge, styles.alignSelfCenter]}
source={policy.avatarURL}
/>
) : (
<Icon
src={Workspace}
height={80}
width={80}
fill={themedefault.icon}
/>
)}
style={[styles.mb3]}
anchorPosition={{top: 116, left: 20}}
isUsingDefaultAvatar={!policy.avatarURL}
onImageSelected={(image) => {
updateAvatar(policy.id, image);
}}
onImageRemoved={() => setAvatarURL(policy.id)}
/>
<View
style={[styles.smallEditIcon]}
>
<Icon src={Pencil} fill={themedefault.iconReversed} />
</View>
</Pressable>
<Text
numberOfLines={1}
style={[
Expand Down