Skip to content

Commit

Permalink
Merge pull request #48442 from callstack-internal/pac-guerreiro/featu…
Browse files Browse the repository at this point in the history
…re/46992-add-lhn-debugging-to-debug-mode

Add LHN debugging to Debug Mode
  • Loading branch information
neil-marcellini authored Oct 7, 2024
2 parents 8f86ee2 + 8c48c05 commit 0c4b2d1
Show file tree
Hide file tree
Showing 18 changed files with 1,226 additions and 159 deletions.
21 changes: 21 additions & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5798,6 +5798,27 @@ const CONST = {
REPORT_ACTIONS: 'actions',
REPORT_ACTION_PREVIEW: 'preview',
},

REPORT_IN_LHN_REASONS: {
HAS_DRAFT_COMMENT: 'hasDraftComment',
HAS_GBR: 'hasGBR',
PINNED_BY_USER: 'pinnedByUser',
HAS_IOU_VIOLATIONS: 'hasIOUViolations',
HAS_ADD_WORKSPACE_ROOM_ERRORS: 'hasAddWorkspaceRoomErrors',
IS_UNREAD: 'isUnread',
IS_ARCHIVED: 'isArchived',
IS_SELF_DM: 'isSelfDM',
IS_FOCUSED: 'isFocused',
DEFAULT: 'default',
},

REQUIRES_ATTENTION_REASONS: {
HAS_JOIN_REQUEST: 'hasJoinRequest',
IS_UNREAD_WITH_MENTION: 'isUnreadWithMention',
IS_WAITING_FOR_ASSIGNEE_TO_COMPLETE_ACTION: 'isWaitingForAssigneeToCompleteAction',
HAS_CHILD_REPORT_AWAITING_ACTION: 'hasChildReportAwaitingAction',
HAS_MISSING_INVOICE_BANK_ACCOUNT: 'hasMissingInvoiceBankAccount',
},
} as const;

type Country = keyof typeof CONST.ALL_COUNTRIES;
Expand Down
34 changes: 17 additions & 17 deletions src/components/TimePicker/TimePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ type TimePickerProps = {
/** Whether the time value should be validated */
shouldValidate?: boolean;

/** Whether the picker shows hours, minutes, seconds and miliseconds */
/** Whether the picker shows hours, minutes, seconds and milliseconds */
showFullFormat?: boolean;
};

Expand Down Expand Up @@ -88,7 +88,7 @@ function replaceRangeWithZeros(originalString: string, from: number, to: number,
}

/**
* Clear the value under selection of an input (either hours, minutes, seconds or miliseconds) by replacing it with zeros
* Clear the value under selection of an input (either hours, minutes, seconds or milliseconds) by replacing it with zeros
*
* @param value - current value of the input
* @param selection - current selection of the input
Expand Down Expand Up @@ -135,7 +135,7 @@ function TimePicker({defaultValue = '', onSubmit, onInputChange = () => {}, shou
const [hours, setHours] = useState(() => DateUtils.get12HourTimeObjectFromDate(value, showFullFormat).hour);
const [minutes, setMinutes] = useState(() => DateUtils.get12HourTimeObjectFromDate(value, showFullFormat).minute);
const [seconds, setSeconds] = useState(() => DateUtils.get12HourTimeObjectFromDate(value, showFullFormat).seconds);
const [miliseconds, setMiliseconds] = useState(() => DateUtils.get12HourTimeObjectFromDate(value, showFullFormat).miliseconds);
const [milliseconds, setMilliseconds] = useState(() => DateUtils.get12HourTimeObjectFromDate(value, showFullFormat).milliseconds);
const [amPmValue, setAmPmValue] = useState(() => DateUtils.get12HourTimeObjectFromDate(value, showFullFormat).period);

const lastPressedKey = useRef('');
Expand Down Expand Up @@ -189,7 +189,7 @@ function TimePicker({defaultValue = '', onSubmit, onInputChange = () => {}, shou
setSelectionSecond({start: 0, end: 0});
};

const resetMiliseconds = () => {
const resetMilliseconds = () => {
setMinutes('000');
setSelectionMilisecond({start: 0, end: 0});
};
Expand Down Expand Up @@ -440,14 +440,14 @@ function TimePicker({defaultValue = '', onSubmit, onInputChange = () => {}, shou
};

/*
This function receives value from the miliseconds input and validates it.
This function receives value from the milliseconds input and validates it.
The valid format is SSS(from 000 to 999). If the user enters 9, it will be prepended to 009. If the user tries to change 999 to 9999, it would skip the character
*/
const handleMilisecondsChange = (text: string) => {
const handleMillisecondsChange = (text: string) => {
// Replace spaces with 0 to implement the following digit removal by pressing space
const trimmedText = text.replace(/ /g, '0');
if (!trimmedText) {
resetMiliseconds();
resetMilliseconds();
return;
}

Expand All @@ -460,7 +460,7 @@ function TimePicker({defaultValue = '', onSubmit, onInputChange = () => {}, shou
let newSelection;

if (selectionMilisecond.start === 0 && selectionMilisecond.end === 0) {
// The cursor is at the start of miliseconds
// The cursor is at the start of milliseconds
const firstDigit = trimmedText[0];
const secondDigit = trimmedText[2] || '0';
const thirdDigit = trimmedText[3] || '0';
Expand Down Expand Up @@ -514,10 +514,10 @@ function TimePicker({defaultValue = '', onSubmit, onInputChange = () => {}, shou
}

if (Number(newMilisecond) > 999) {
newMilisecond = miliseconds;
newMilisecond = milliseconds;
}

setMiliseconds(newMilisecond);
setMilliseconds(newMilisecond);
setSelectionMilisecond({start: newSelection, end: newSelection});
};

Expand Down Expand Up @@ -563,7 +563,7 @@ function TimePicker({defaultValue = '', onSubmit, onInputChange = () => {}, shou
return;
}

clearSelectedValue(miliseconds, selectionMilisecond, setMiliseconds, setSelectionMilisecond, 3);
clearSelectedValue(milliseconds, selectionMilisecond, setMilliseconds, setSelectionMilisecond, 3);
}
return;
}
Expand All @@ -576,11 +576,11 @@ function TimePicker({defaultValue = '', onSubmit, onInputChange = () => {}, shou
} else if (isSecondFocused) {
handleSecondsChange(insertAtPosition(seconds, trimmedKey, selectionSecond.start, selectionSecond.end));
} else if (isMilisecondFocused) {
handleMilisecondsChange(insertAtPosition(miliseconds, trimmedKey, selectionMilisecond.start, selectionMilisecond.end));
handleMillisecondsChange(insertAtPosition(milliseconds, trimmedKey, selectionMilisecond.start, selectionMilisecond.end));
}
},
// eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps
[minutes, hours, seconds, miliseconds, selectionMinute, selectionHour, selectionSecond, selectionMilisecond],
[minutes, hours, seconds, milliseconds, selectionMinute, selectionHour, selectionSecond, selectionMilisecond],
);

useEffect(() => {
Expand Down Expand Up @@ -690,12 +690,12 @@ function TimePicker({defaultValue = '', onSubmit, onInputChange = () => {}, shou
}, [canUseTouchScreen, updateAmountNumberPad]);

useEffect(() => {
onInputChange(showFullFormat ? `${hours}:${minutes}:${seconds}.${miliseconds} ${amPmValue}` : `${hours}:${minutes} ${amPmValue}`);
onInputChange(showFullFormat ? `${hours}:${minutes}:${seconds}.${milliseconds} ${amPmValue}` : `${hours}:${minutes} ${amPmValue}`);
// eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps
}, [hours, minutes, amPmValue]);

const handleSubmit = () => {
const time = showFullFormat ? `${hours}:${minutes}:${seconds}.${miliseconds}` : `${hours}:${minutes} ${amPmValue}`;
const time = showFullFormat ? `${hours}:${minutes}:${seconds}.${milliseconds}` : `${hours}:${minutes} ${amPmValue}`;
const isValid = validate(time);

if (isValid) {
Expand Down Expand Up @@ -796,12 +796,12 @@ function TimePicker({defaultValue = '', onSubmit, onInputChange = () => {}, shou
<Text style={[styles.timePickerSemiDot, showFullFormat && [styles.textXXLarge, {height: undefined}]]}>{CONST.COLON}</Text>
<AmountTextInput
placeholder={numberFormat(0)}
formattedAmount={miliseconds}
formattedAmount={milliseconds}
onKeyPress={(e) => {
lastPressedKey.current = e.nativeEvent.key;
handleFocusOnBackspace(e);
}}
onChangeAmount={handleMilisecondsChange}
onChangeAmount={handleMillisecondsChange}
ref={(textInputRef) => {
updateRefs('milisecondRef', textInputRef);
milisecondInputRef.current = textInputRef as TextInput | null;
Expand Down
23 changes: 23 additions & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4917,6 +4917,29 @@ const translations = {
date: 'Date',
time: 'Time',
none: 'None',
visibleInLHN: 'Visible in LHN',
GBR: 'GBR',
RBR: 'RBR',
true: 'true',
false: 'false',
reasonVisibleInLHN: {
hasDraftComment: 'Has draft comment',
hasGBR: 'Has GBR',
pinnedByUser: 'Pinned by user',
hasIOUViolations: 'Has IOU violations',
hasAddWorkspaceRoomErrors: 'Has add workspace room errors',
isUnread: 'Is unread (focus mode)',
isArchived: 'Is archived (most recent mode)',
isSelfDM: 'Is self DM',
isFocused: 'Is temporarily focused',
},
reasonGBR: {
hasJoinRequest: 'Has join request (admin room)',
isUnreadWithMention: 'Is unread with mention',
isWaitingForAssigneeToCompleteAction: 'Is waiting for assignee to complete action',
hasChildReportAwaitingAction: 'Has child report awaiting action',
hasMissingInvoiceBankAccount: 'Has missing invoice bank account',
},
},
};

Expand Down
23 changes: 23 additions & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5429,6 +5429,29 @@ const translations = {
date: 'Fecha',
time: 'Hora',
none: 'Ninguno',
visibleInLHN: 'Visible en LHN',
GBR: 'GBR',
RBR: 'RBR',
true: 'verdadero',
false: 'falso',
reasonVisibleInLHN: {
hasDraftComment: 'Tiene comentario en borrador',
hasGBR: 'Tiene GBR',
pinnedByUser: 'Fijado por el usuario',
hasIOUViolations: 'Tiene violaciones de IOU',
hasAddWorkspaceRoomErrors: 'Tiene errores al agregar sala de espacio de trabajo',
isUnread: 'No leído (modo de enfoque)',
isArchived: 'Archivado (modo más reciente)',
isSelfDM: 'Es un mensaje directo propio',
isFocused: 'Está temporalmente enfocado',
},
reasonGBR: {
hasJoinRequest: 'Tiene solicitud de unión (sala de administrador)',
isUnreadWithMention: 'No leído con mención',
isWaitingForAssigneeToCompleteAction: 'Esperando a que el asignado complete la acción',
hasChildReportAwaitingAction: 'Informe secundario pendiente de acción',
hasMissingInvoiceBankAccount: 'Falta la cuenta bancaria de la factura',
},
},
};

Expand Down
8 changes: 4 additions & 4 deletions src/libs/DateUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -616,15 +616,15 @@ const combineDateAndTime = (updatedTime: string, inputDateTime: string): string
/**
* param {String} dateTime in 'HH:mm:ss.SSS a' format
* returns {Object}
* example {hour: '11', minute: '10', seconds: '10', miliseconds: '123', period: 'AM'}
* example {hour: '11', minute: '10', seconds: '10', milliseconds: '123', period: 'AM'}
*/
function get12HourTimeObjectFromDate(dateTime: string, isFullFormat = false): {hour: string; minute: string; seconds: string; miliseconds: string; period: string} {
function get12HourTimeObjectFromDate(dateTime: string, isFullFormat = false): {hour: string; minute: string; seconds: string; milliseconds: string; period: string} {
if (!dateTime) {
return {
hour: '12',
minute: '00',
seconds: '00',
miliseconds: '000',
milliseconds: '000',
period: 'PM',
};
}
Expand All @@ -633,7 +633,7 @@ function get12HourTimeObjectFromDate(dateTime: string, isFullFormat = false): {h
hour: format(parsedTime, 'hh'),
minute: format(parsedTime, 'mm'),
seconds: isFullFormat ? format(parsedTime, 'ss') : '00',
miliseconds: isFullFormat ? format(parsedTime, 'SSS') : '000',
milliseconds: isFullFormat ? format(parsedTime, 'SSS') : '000',
period: format(parsedTime, 'a').toUpperCase(),
};
}
Expand Down
107 changes: 105 additions & 2 deletions src/libs/DebugUtils.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
/* eslint-disable max-classes-per-file */
import {isMatch} from 'date-fns';
import isValid from 'date-fns/isValid';
import type {OnyxEntry} from 'react-native-onyx';
import type {OnyxCollection, OnyxEntry} from 'react-native-onyx';
import Onyx from 'react-native-onyx';
import CONST from '@src/CONST';
import type {Report, ReportAction} from '@src/types/onyx';
import type {TranslationPaths} from '@src/languages/types';
import ONYXKEYS from '@src/ONYXKEYS';
import type {Beta, Policy, Report, ReportAction, ReportActions, TransactionViolation} from '@src/types/onyx';
import * as OptionsListUtils from './OptionsListUtils';
import * as ReportUtils from './ReportUtils';

class NumberError extends SyntaxError {
constructor() {
Expand Down Expand Up @@ -107,6 +112,40 @@ const REPORT_ACTION_BOOLEAN_PROPERTIES: Array<keyof ReportAction> = [

const REPORT_ACTION_DATE_PROPERTIES: Array<keyof ReportAction> = ['created', 'lastModified'] satisfies Array<keyof ReportAction>;

let isInFocusMode: OnyxEntry<boolean>;
Onyx.connect({
key: ONYXKEYS.NVP_PRIORITY_MODE,
callback: (priorityMode) => {
isInFocusMode = priorityMode === CONST.PRIORITY_MODE.GSD;
},
});

let policies: OnyxCollection<Policy>;
Onyx.connect({
key: ONYXKEYS.COLLECTION.POLICY,
waitForCollectionCallback: true,
callback: (value) => {
policies = value;
},
});

let transactionViolations: OnyxCollection<TransactionViolation[]>;
Onyx.connect({
key: ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS,
waitForCollectionCallback: true,
callback: (value) => {
transactionViolations = value;
},
});

let betas: OnyxEntry<Beta[]>;
Onyx.connect({
key: ONYXKEYS.BETAS,
callback: (value) => {
betas = value;
},
});

function stringifyJSON(data: Record<string, unknown>) {
return JSON.stringify(data, null, 6);
}
Expand Down Expand Up @@ -551,6 +590,67 @@ function validateReportActionJSON(json: string) {
});
}

/**
* Gets the reason for showing LHN row
*/
function getReasonForShowingRowInLHN(report: OnyxEntry<Report>): TranslationPaths | null {
if (!report) {
return null;
}

const doesReportHaveViolations = OptionsListUtils.shouldShowViolations(report, transactionViolations);

const reason = ReportUtils.reasonForReportToBeInOptionList({
report,
// We can't pass report.reportID because it will cause reason to always be isFocused
currentReportId: '-1',
isInFocusMode: !!isInFocusMode,
betas,
policies,
excludeEmptyChats: true,
doesReportHaveViolations,
includeSelfDM: true,
});

// When there's no specific reason, we default to isFocused since the report is only showing because we're viewing it
if (reason === null || reason === CONST.REPORT_IN_LHN_REASONS.DEFAULT) {
return 'debug.reasonVisibleInLHN.isFocused';
}

return `debug.reasonVisibleInLHN.${reason}`;
}

type GBRReasonAndReportAction = {
reason: TranslationPaths;
reportAction: OnyxEntry<ReportAction>;
};

/**
* Gets the reason and report action that is causing the GBR to show up in LHN row
*/
function getReasonAndReportActionForGBRInLHNRow(report: OnyxEntry<Report>): GBRReasonAndReportAction | null {
if (!report) {
return null;
}

const {reason, reportAction} = ReportUtils.getReasonAndReportActionThatRequiresAttention(report) ?? {};

if (reason) {
return {reason: `debug.reasonGBR.${reason}`, reportAction};
}

return null;
}

/**
* Gets the report action that is causing the RBR to show up in LHN
*/
function getRBRReportAction(report: OnyxEntry<Report>, reportActions: OnyxEntry<ReportActions>): OnyxEntry<ReportAction> {
const {reportAction} = OptionsListUtils.getAllReportActionsErrorsAndReportActionThatRequiresAttention(report, reportActions);

return reportAction;
}

const DebugUtils = {
stringifyJSON,
onyxDataToDraftData,
Expand All @@ -568,6 +668,9 @@ const DebugUtils = {
validateReportDraftProperty,
validateReportActionDraftProperty,
validateReportActionJSON,
getReasonForShowingRowInLHN,
getReasonAndReportActionForGBRInLHNRow,
getRBRReportAction,
REPORT_ACTION_REQUIRED_PROPERTIES,
REPORT_REQUIRED_PROPERTIES,
};
Expand Down
Loading

0 comments on commit 0c4b2d1

Please sign in to comment.