Skip to content

Commit

Permalink
Merge pull request #25761 from Expensify/techievivek_private_notes_fe…
Browse files Browse the repository at this point in the history
…ature

Add private notes feature to newDot
  • Loading branch information
Julesssss authored Sep 15, 2023
2 parents 144e932 + 4b29f85 commit 1862aff
Show file tree
Hide file tree
Showing 16 changed files with 655 additions and 3 deletions.
1 change: 1 addition & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1342,6 +1342,7 @@ const CONST = {
SETTINGS: 'settings',
LEAVE_ROOM: 'leaveRoom',
WELCOME_MESSAGE: 'welcomeMessage',
PRIVATE_NOTES: 'privateNotes',
},
EDIT_REQUEST_FIELD: {
AMOUNT: 'amount',
Expand Down
1 change: 1 addition & 0 deletions src/ONYXKEYS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ const ONYXKEYS = {
SETTINGS_STATUS_SET_FORM: 'settingsStatusSetForm',
SETTINGS_STATUS_CLEAR_AFTER_FORM: 'settingsStatusClearAfterForm',
SETTINGS_STATUS_SET_CLEAR_AFTER_FORM: 'settingsStatusSetClearAfterForm',
PRIVATE_NOTES_FORM: 'privateNotesForm',
I_KNOW_A_TEACHER_FORM: 'iKnowTeacherForm',
INTRO_SCHOOL_PRINCIPAL_FORM: 'introSchoolPrincipalForm',
},
Expand Down
8 changes: 8 additions & 0 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,14 @@ export default {
GOOGLE_SIGN_IN: 'sign-in-with-google',
DESKTOP_SIGN_IN_REDIRECT: 'desktop-signin-redirect',

// Routes related to private notes added to the report
PRIVATE_NOTES_VIEW: 'r/:reportID/notes/:accountID',
getPrivateNotesViewRoute: (reportID: string, accountID: string | number) => `r/${reportID}/notes/${accountID}`,
PRIVATE_NOTES_LIST: 'r/:reportID/notes',
getPrivateNotesListRoute: (reportID: string) => `r/${reportID}/notes`,
PRIVATE_NOTES_EDIT: 'r/:reportID/notes/:accountID/edit',
getPrivateNotesEditRoute: (reportID: string, accountID: string | number) => `r/${reportID}/notes/${accountID}/edit`,

// This is a special validation URL that will take the user to /workspace/new after validation. This is used
// when linking users from e.com in order to share a session in this app.
ENABLE_PAYMENTS: 'enable-payments',
Expand Down
6 changes: 5 additions & 1 deletion src/components/MenuItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import variables from '../styles/variables';
import * as Session from '../libs/actions/Session';
import Hoverable from './Hoverable';
import useWindowDimensions from '../hooks/useWindowDimensions';
import RenderHTML from './RenderHTML';

const propTypes = menuItemPropTypes;

Expand Down Expand Up @@ -73,6 +74,7 @@ const defaultProps = {
title: '',
numberOfLinesTitle: 1,
shouldGreyOutWhenDisabled: true,
shouldRenderAsHTML: false,
};

const MenuItem = React.forwardRef((props, ref) => {
Expand Down Expand Up @@ -220,7 +222,9 @@ const MenuItem = React.forwardRef((props, ref) => {
</Text>
)}
<View style={[styles.flexRow, styles.alignItemsCenter]}>
{Boolean(props.title) && (
{Boolean(props.title) && Boolean(props.shouldRenderAsHTML) && <RenderHTML html={convertToLTR(props.title)} />}

{Boolean(props.title) && !props.shouldRenderAsHTML && (
<Text
style={titleTextStyle}
numberOfLines={props.numberOfLinesTitle || undefined}
Expand Down
3 changes: 3 additions & 0 deletions src/components/menuItemPropTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,9 @@ const propTypes = {

/** Should we grey out the menu item when it is disabled? */
shouldGreyOutWhenDisabled: PropTypes.bool,

/** Should render the content in HTML format */
shouldRenderAsHTML: PropTypes.bool,
};

export default propTypes;
7 changes: 7 additions & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,13 @@ export default {
passwordUpdated: 'Password updated!',
allSet: 'You’re all set. Keep your new password safe.',
},
privateNotes: {
title: 'Private notes',
personalNoteMessage: 'Keep notes about this chat here. You are the only person who can add, edit or view these notes.',
sharedNoteMessage: 'Keep notes about this chat here. Expensify employees and other users on the team.expensify.com domain can view these notes.',
notesUnavailable: 'No notes found for the user',
composerLabel: 'Notes',
},
addPayPalMePage: {
enterYourUsernameToGetPaidViaPayPal: 'Get paid back via PayPal.',
payPalMe: 'PayPal.me/',
Expand Down
7 changes: 7 additions & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -749,6 +749,13 @@ export default {
passwordUpdated: 'Contraseña actualizada!',
allSet: 'Todo está listo. Guarda tu contraseña en un lugar seguro.',
},
privateNotes: {
title: 'Notas privadas',
personalNoteMessage: 'Guarda notas sobre este chat aquí. Usted es la única persona que puede añadir, editar o ver estas notas.',
sharedNoteMessage: 'Guarda notas sobre este chat aquí. Los empleados de Expensify y otros usuarios del dominio team.expensify.com pueden ver estas notas.',
notesUnavailable: 'No se han encontrado notas para el usuario',
composerLabel: 'Notas',
},
addPayPalMePage: {
enterYourUsernameToGetPaidViaPayPal: 'Recibe pagos vía PayPal.',
payPalMe: 'PayPal.me/',
Expand Down
25 changes: 25 additions & 0 deletions src/libs/Navigation/AppNavigator/ModalStackNavigators.js
Original file line number Diff line number Diff line change
Expand Up @@ -760,6 +760,30 @@ const EditRequestStackNavigator = createModalStackNavigator([
},
]);

const PrivateNotesModalStackNavigator = createModalStackNavigator([
{
getComponent: () => {
const PrivateNotesPage = require('../../../pages/PrivateNotes/PrivateNotesViewPage').default;
return PrivateNotesPage;
},
name: 'PrivateNotes_View',
},
{
getComponent: () => {
const PrivateNotesListPage = require('../../../pages/PrivateNotes/PrivateNotesListPage').default;
return PrivateNotesListPage;
},
name: 'PrivateNotes_List',
},
{
getComponent: () => {
const PrivateNotesEditPage = require('../../../pages/PrivateNotes/PrivateNotesEditPage').default;
return PrivateNotesEditPage;
},
name: 'PrivateNotes_Edit',
},
]);

const SignInModalStackNavigator = createModalStackNavigator([
{
getComponent: () => {
Expand Down Expand Up @@ -790,6 +814,7 @@ export {
WalletStatementStackNavigator,
FlagCommentStackNavigator,
EditRequestStackNavigator,
PrivateNotesModalStackNavigator,
NewTeachersUniteNavigator,
SignInModalStackNavigator,
};
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@ function RightModalNavigator(props) {
name="SignIn"
component={ModalStackNavigators.SignInModalStackNavigator}
/>
<Stack.Screen
name="Private_Notes"
component={ModalStackNavigators.PrivateNotesModalStackNavigator}
/>
</Stack.Navigator>
</View>
</NoDropZone>
Expand Down
7 changes: 7 additions & 0 deletions src/libs/Navigation/linkingConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,13 @@ export default {
},
},
},
Private_Notes: {
screens: {
PrivateNotes_View: ROUTES.PRIVATE_NOTES_VIEW,
PrivateNotes_List: ROUTES.PRIVATE_NOTES_LIST,
PrivateNotes_Edit: ROUTES.PRIVATE_NOTES_EDIT,
},
},
Report_Details: {
screens: {
Report_Details_Root: ROUTES.REPORT_WITH_ID_DETAILS,
Expand Down
134 changes: 134 additions & 0 deletions src/libs/actions/Report.js
Original file line number Diff line number Diff line change
Expand Up @@ -1933,6 +1933,136 @@ function flagComment(reportID, reportAction, severity) {
API.write('FlagComment', parameters, {optimisticData, successData, failureData});
}

/**
* Updates a given user's private notes on a report
*
* @param {String} reportID
* @param {Number} accountID
* @param {String} note
*/
const updatePrivateNotes = (reportID, accountID, note) => {
const optimisticData = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`,
value: {
privateNotes: {
[accountID]: {
pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE,
errors: null,
note,
},
},
},
},
];

const successData = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`,
value: {
privateNotes: {
[accountID]: {
pendingAction: null,
errors: null,
},
},
},
},
];

const failureData = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`,
value: {
privateNotes: {
[accountID]: {
errors: ErrorUtils.getMicroSecondOnyxError("Private notes couldn't be saved"),
},
},
},
},
];

API.write(
'UpdateReportPrivateNote',
{
reportID,
privateNotes: note,
},
{optimisticData, successData, failureData},
);
};

/**
* Fetches all the private notes for a given report
*
* @param {String} reportID
*/
function getReportPrivateNote(reportID) {
if (_.isEmpty(reportID)) {
return;
}
API.read(
'GetReportPrivateNote',
{
reportID,
},
{
optimisticData: [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`,
value: {
isLoadingPrivateNotes: true,
},
},
],
successData: [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`,
value: {
isLoadingPrivateNotes: false,
},
},
],
failureData: [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`,
value: {
isLoadingPrivateNotes: false,
},
},
],
},
);
}

/**
* Checks if there are any errors in the private notes for a given report
*
* @param {Object} report
* @returns {Boolean} Returns true if there are errors in any of the private notes on the report
*/
function hasErrorInPrivateNotes(report) {
const privateNotes = lodashGet(report, 'privateNotes', {});
return _.some(privateNotes, (privateNote) => !_.isEmpty(privateNote.errors));
}

/**
* Clears all errors associated with a given private note
*
* @param {String} reportID
* @param {Number} accountID
*/
function clearPrivateNotesError(reportID, accountID) {
Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, {privateNotes: {[accountID]: {errors: null}}});
}

export {
addComment,
addAttachment,
Expand Down Expand Up @@ -1980,4 +2110,8 @@ export {
setLastOpenedPublicRoom,
flagComment,
openLastOpenedPublicRoom,
updatePrivateNotes,
getReportPrivateNote,
clearPrivateNotesError,
hasErrorInPrivateNotes,
};
Loading

0 comments on commit 1862aff

Please sign in to comment.