Skip to content

Commit

Permalink
Merge branch 'main' into expo-image
Browse files Browse the repository at this point in the history
  • Loading branch information
WojtekBoman committed Dec 20, 2023
2 parents dcc4994 + bd852c5 commit b856010
Show file tree
Hide file tree
Showing 16 changed files with 281 additions and 233 deletions.
3 changes: 2 additions & 1 deletion docs/TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ What options does a user have then interacting with this feature?
What elements of this feature are pay-walled vs. free?
-->

# FAQ
{% include faq-begin.md %}
<!--
This section covers the useful but not as vital information, it should capture commonly queried elements which do not organically form part of the About or How-to sections.
Expand All @@ -32,6 +32,7 @@ This section covers the useful but not as vital information, it should capture c
- Is there any general troubleshooting for this feature?
- Note: troubleshooting should generally go in the FAQ, but if there is extensive troubleshooting, such as with integrations, that will be housed in a separate page, stored with and linked from the main page for that feature.
-->
{% include faq-end.md %}

# Deep Dive
<!--
Expand Down
4 changes: 4 additions & 0 deletions docs/_includes/faq-begin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{::options parse_block_html="true" /}
<details>
{::options parse_block_html="false" /}
<summary>FAQ</summary> {: #faq}
1 change: 1 addition & 0 deletions docs/_includes/faq-end.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
</details>
29 changes: 23 additions & 6 deletions docs/_sass/_main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ blockquote {

article,
aside,
details,
figcaption,
figure,
footer,
Expand All @@ -55,8 +54,7 @@ hgroup,
main,
menu,
nav,
section,
summary {
section {
display: block;
}

Expand Down Expand Up @@ -99,7 +97,8 @@ h2,
h3,
h4,
h5,
h6 {
h6,
summary {
color: $color-text;
font-weight: bold;
padding-bottom: 12px;
Expand All @@ -113,7 +112,25 @@ h6 {
margin-top: 20px;
}

h1 {
#faq::marker {
font-size: 1.5em;
}

details summary {
cursor: pointer;
user-select: none;
}

details > summary {
list-style-image: url("/assets/images/arrow-right.svg");
}

details[open] > summary {
list-style-image: url("/assets/images/down.svg");
}

h1,
summary {
font-family: "ExpensifyNewKansas", "Helvetica Neue", "Helvetica", Arial, sans-serif;
font-weight: 500;
font-size: larger;
Expand Down Expand Up @@ -398,7 +415,7 @@ button {
flex-wrap: wrap;
}

h1 {
h1, summary {
font-size: 1.5em;
padding: 20px 0 12px 0;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ SmartScan's performance can vary depending on factors such as receipt quality, l
**Receipt quality**: The clarity and condition of a receipt can impact SmartScan's accuracy. For best results, ensure your environment is well-lit and the receipt is straight and free of obstructions.
**Language support**: While SmartScan supports multiple languages, its accuracy may differ from one language to another. Users dealing with non-English receipts should be aware of potential variations in data extraction.
**Handwriting recognition**: Handwritten receipts might pose challenges for SmartScan. In such cases, manual verification may be necessary to ensure accurate data entry.
# FAQ

{% include faq-begin.md %}

## Can I use the mobile app for both personal and business expenses?
Yes, you can use Expensify for personal and business expenses. It's versatile and suitable for both individual and corporate use. Check out our personal and business plans [here](https://www.expensify.com/pricing) to see what might be right for you.
## Is it possible to categorize and tag expenses on the mobile app?
Expand All @@ -50,3 +52,5 @@ If you experience issues, first make sure you’re using the most recent version
Expensify takes security seriously and employs encryption and other security measures to protect your data. It's important to use strong, unique passwords and enable device security features like biometric authentication.
## Can I use the mobile app offline, and will my data sync when I'm back online?
Yes, you can use the mobile app offline to capture receipts and create expenses. The app will sync your data once you have an internet connection.

{% include faq-end.md %}
1 change: 1 addition & 0 deletions docs/assets/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ window.addEventListener('DOMContentLoaded', () => {
// Disable the collapsible functionality of the library by
// setting the maximum number of heading levels (6)
collapseDepth: 6,
headingSelector: 'h1, h2, h3, summary',

// Main class to add to lists.
listClass: 'lhn-items',
Expand Down
1 change: 1 addition & 0 deletions src/ONYXKEYS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,7 @@ type OnyxValues = {
[ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS]: OnyxTypes.RecentlyUsedTags;
[ONYXKEYS.COLLECTION.SELECTED_TAB]: string;
[ONYXKEYS.COLLECTION.PRIVATE_NOTES_DRAFT]: string;
[ONYXKEYS.COLLECTION.NEXT_STEP]: OnyxTypes.ReportNextStep;

// Forms
[ONYXKEYS.FORMS.ADD_DEBIT_CARD_FORM]: OnyxTypes.AddDebitCardForm;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,16 @@ import {Text, View} from 'react-native';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import * as NextStepUtils from '@libs/NextStepUtils';
import nextStepPropTypes from '@pages/nextStepPropTypes';
import CONST from '@src/CONST';
import ReportNextStep from '@src/types/onyx/ReportNextStep';
import RenderHTML from './RenderHTML';

const propTypes = {
type MoneyReportHeaderStatusBarProps = {
/** The next step for the report */
nextStep: nextStepPropTypes,
nextStep: ReportNextStep;
};

const defaultProps = {
nextStep: {},
};

function MoneyReportHeaderStatusBar({nextStep}) {
function MoneyReportHeaderStatusBar({nextStep}: MoneyReportHeaderStatusBarProps) {
const styles = useThemeStyles();
const {translate} = useLocalize();

Expand All @@ -38,7 +34,5 @@ function MoneyReportHeaderStatusBar({nextStep}) {
}

MoneyReportHeaderStatusBar.displayName = 'MoneyReportHeaderStatusBar';
MoneyReportHeaderStatusBar.propTypes = propTypes;
MoneyReportHeaderStatusBar.defaultProps = defaultProps;

export default MoneyReportHeaderStatusBar;
6 changes: 1 addition & 5 deletions src/libs/NextStepUtils.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
import Str from 'expensify-common/lib/str';
import type {Message} from '@src/types/onyx/ReportNextStep';
import EmailUtils from './EmailUtils';

type Message = {
text: string;
type?: string;
};

function parseMessage(messages: Message[] | undefined) {
let nextStepHTML = '';

Expand Down
2 changes: 1 addition & 1 deletion src/libs/ReportUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1956,7 +1956,7 @@ function getTransactionReportName(reportAction: OnyxEntry<ReportAction>): string
* @param [reportAction] This can be either a report preview action or the IOU action
*/
function getReportPreviewMessage(
report: OnyxEntry<Report>,
report: OnyxEntry<Report> | EmptyObject,
reportAction: OnyxEntry<ReportAction> | EmptyObject = {},
shouldConsiderReceiptBeingScanned = false,
isPreviewMessageForParentChatReport = false,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,88 +1,83 @@
import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
import React from 'react';
import {Text, View} from 'react-native';
import _ from 'underscore';
import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
import React, {ReactElement} from 'react';
import {StyleProp, Text, View, ViewStyle} from 'react-native';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import * as ReportActionsUtils from '@libs/ReportActionsUtils';
import * as ReportUtils from '@libs/ReportUtils';
import CONST from '@src/CONST';
import type {ReportAction} from '@src/types/onyx';
import type {OriginalMessageAddComment} from '@src/types/onyx/OriginalMessage';
import TextCommentFragment from './comment/TextCommentFragment';
import ReportActionItemFragment from './ReportActionItemFragment';
import reportActionPropTypes from './reportActionPropTypes';

const propTypes = {
type ReportActionItemMessageProps = {
/** The report action */
action: PropTypes.shape(reportActionPropTypes).isRequired,
action: ReportAction;

/** Should the comment have the appearance of being grouped with the previous comment? */
displayAsGroup: PropTypes.bool.isRequired,
displayAsGroup: boolean;

/** Additional styles to add after local styles. */
style: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]),
style?: StyleProp<ViewStyle>;

/** Whether or not the message is hidden by moderation */
isHidden: PropTypes.bool,
isHidden?: boolean;

/** The ID of the report */
reportID: PropTypes.string.isRequired,

/** localization props */
...withLocalizePropTypes,
};

const defaultProps = {
style: [],
isHidden: false,
reportID: string;
};

function ReportActionItemMessage(props) {
function ReportActionItemMessage({action, displayAsGroup, reportID, style, isHidden = false}: ReportActionItemMessageProps) {
const styles = useThemeStyles();
const fragments = _.compact(props.action.previousMessage || props.action.message);
const isIOUReport = ReportActionsUtils.isMoneyRequestAction(props.action);
if (ReportActionsUtils.isMemberChangeAction(props.action)) {
const fragment = ReportActionsUtils.getMemberChangeMessageFragment(props.action);
const {translate} = useLocalize();

const fragments = (action.previousMessage ?? action.message ?? []).filter((item) => !!item);
const isIOUReport = ReportActionsUtils.isMoneyRequestAction(action);

if (ReportActionsUtils.isMemberChangeAction(action)) {
const fragment = ReportActionsUtils.getMemberChangeMessageFragment(action);

return (
<TextCommentFragment
fragment={fragment}
displayAsGroup={props.displayAsGroup}
style={props.style}
displayAsGroup={displayAsGroup}
style={style}
source=""
styleAsDeleted={false}
/>
);
}

let iouMessage;
let iouMessage: string | undefined;
if (isIOUReport) {
const iouReportID = lodashGet(props.action, 'originalMessage.IOUReportID');
const originalMessage = action.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? action.originalMessage : null;
const iouReportID = originalMessage?.IOUReportID;
if (iouReportID) {
iouMessage = ReportUtils.getReportPreviewMessage(ReportUtils.getReport(iouReportID), props.action);
iouMessage = ReportUtils.getReportPreviewMessage(ReportUtils.getReport(iouReportID), action);
}
}

const isApprovedOrSubmittedReportAction = _.contains([CONST.REPORT.ACTIONS.TYPE.APPROVED, CONST.REPORT.ACTIONS.TYPE.SUBMITTED], props.action.actionName);
const isApprovedOrSubmittedReportAction = [CONST.REPORT.ACTIONS.TYPE.APPROVED, CONST.REPORT.ACTIONS.TYPE.SUBMITTED].some((type) => type === action.actionName);

/**
* Get the ReportActionItemFragments
* @param {Boolean} shouldWrapInText determines whether the fragments are wrapped in a Text component
* @returns {Object} report action item fragments
* @param shouldWrapInText determines whether the fragments are wrapped in a Text component
* @returns report action item fragments
*/
const renderReportActionItemFragments = (shouldWrapInText) => {
const reportActionItemFragments = _.map(fragments, (fragment, index) => (
const renderReportActionItemFragments = (shouldWrapInText: boolean): ReactElement | ReactElement[] => {
const reportActionItemFragments = fragments.map((fragment, index) => (
<ReportActionItemFragment
key={`actionFragment-${props.action.reportActionID}-${index}`}
/* eslint-disable-next-line react/no-array-index-key */
key={`actionFragment-${action.reportActionID}-${index}`}
fragment={fragment}
iouMessage={iouMessage}
isThreadParentMessage={ReportActionsUtils.isThreadParentMessage(props.action, props.reportID)}
attachmentInfo={props.action.attachmentInfo}
pendingAction={props.action.pendingAction}
source={lodashGet(props.action, 'originalMessage.source')}
accountID={props.action.actorAccountID}
style={props.style}
displayAsGroup={props.displayAsGroup}
isThreadParentMessage={ReportActionsUtils.isThreadParentMessage(action, reportID)}
attachmentInfo={action.attachmentInfo}
pendingAction={action.pendingAction}
source={(action.originalMessage as OriginalMessageAddComment['originalMessage'])?.source}
accountID={action.actorAccountID}
style={style}
displayAsGroup={displayAsGroup}
isApprovedOrSubmittedReportAction={isApprovedOrSubmittedReportAction}
// Since system messages from Old Dot begin with the person who performed the action,
// the first fragment will contain the person's display name and their email. We'll use this
Expand All @@ -99,18 +94,16 @@ function ReportActionItemMessage(props) {
};

return (
<View style={[styles.chatItemMessage, ...props.style]}>
{!props.isHidden ? (
<View style={[styles.chatItemMessage, style]}>
{!isHidden ? (
renderReportActionItemFragments(isApprovedOrSubmittedReportAction)
) : (
<Text style={[styles.textLabelSupporting, styles.lh20]}>{props.translate('moderation.flaggedContent')}</Text>
<Text style={[styles.textLabelSupporting, styles.lh20]}>{translate('moderation.flaggedContent')}</Text>
)}
</View>
);
}

ReportActionItemMessage.propTypes = propTypes;
ReportActionItemMessage.defaultProps = defaultProps;
ReportActionItemMessage.displayName = 'ReportActionItemMessage';

export default withLocalize(ReportActionItemMessage);
export default ReportActionItemMessage;
Loading

0 comments on commit b856010

Please sign in to comment.