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

feat: Added Skeleton UI to chats #8042

Merged
merged 59 commits into from
Jul 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
8bddc65
feat: Added react-content-loader dependency
mananjadhav Feb 6, 2022
416bc77
feat: Basic setup of content loader added
mananjadhav Feb 6, 2022
851952b
feat: Added content loaders with svgs
mananjadhav Feb 7, 2022
d98a67c
feat: Updated chat ghost ui with dynamic loaders
mananjadhav Feb 7, 2022
92dd9a1
feat: Added native files for content loading elements
mananjadhav Feb 7, 2022
4060abc
feat: Added isLoadingReportData flag for loader on Report
mananjadhav Feb 7, 2022
01af67a
Merge branch 'main' of https://github.com/mananjadhav/App into feat/g…
mananjadhav Feb 21, 2022
afaac18
Merge branch 'main' of https://github.com/mananjadhav/App into feat/g…
mananjadhav Mar 7, 2022
2004e68
Merge branch 'main' of https://github.com/mananjadhav/App into feat/g…
mananjadhav Mar 8, 2022
cb9b0eb
fix: added state variable for ghostscreen
mananjadhav Mar 8, 2022
b96aa5b
fix: added derivedstatefromprops function to update state one time
mananjadhav Mar 8, 2022
0c60227
fix: removed props check from loader
mananjadhav Mar 8, 2022
8665824
fix: changed width for native devices
mananjadhav Mar 8, 2022
95d1130
fix: code cleanup with style guidelines
mananjadhav Mar 8, 2022
7229d3d
fix: added _.map for _.keys
mananjadhav Mar 8, 2022
ed69116
Merge branch 'main' of https://github.com/mananjadhav/App into feat/g…
mananjadhav Mar 24, 2022
8fce186
fix: reusing shapes from rn-svg and replacing content-loader wrapper
mananjadhav Mar 25, 2022
6bb0c36
fix: moved setstate to componentDidUpdate
mananjadhav Mar 25, 2022
f9d02b2
fix: remove full screen loader
mananjadhav Mar 25, 2022
c2270ff
fix: add delay in render
mananjadhav Mar 25, 2022
8b7d569
Merge branch 'main' of https://github.com/mananjadhav/App into feat/g…
mananjadhav Apr 12, 2022
3ae559c
fix: added flag check to function
mananjadhav Apr 12, 2022
17177d6
Merge branch 'main' of https://github.com/mananjadhav/App into feat/g…
mananjadhav May 1, 2022
a6128c0
Merge branch 'main' of https://github.com/mananjadhav/App into feat/g…
mananjadhav May 2, 2022
0bfe1ba
feat: updated component structure for skeleton views
mananjadhav May 2, 2022
9140ea1
fix: removed old code
mananjadhav May 2, 2022
abdb0a9
fix: updated conditions for showing loader
mananjadhav May 2, 2022
2052ba0
fix: removed "ghost" word references
mananjadhav May 2, 2022
428e545
fix: cleanup skeleton ui logic
mananjadhav May 2, 2022
22ba08d
fix: change condition for loader screen
mananjadhav May 2, 2022
fcabd27
fix: added alias to webpack for react-content-loader
mananjadhav May 2, 2022
14e230c
fix: moved heights to const and cleanup code
mananjadhav May 2, 2022
a021c5e
fix: updated num row logic
mananjadhav May 2, 2022
a277fc2
style: fixed linting and added jsdoc
mananjadhav May 2, 2022
bb5b935
fix: wrapped render component with fragment
mananjadhav May 8, 2022
ddd0def
fix: switched to container height from window height to set the heigh…
mananjadhav May 8, 2022
9417fee
Merge branch 'main' of https://github.com/mananjadhav/App into feat/g…
mananjadhav May 12, 2022
6431e4b
Merge branch 'main' of https://github.com/mananjadhav/App into feat/g…
mananjadhav Jun 14, 2022
d0f52f2
feat: merge report fetch action methods
mananjadhav Jun 14, 2022
6567615
feat: update loader logic for skeleton view
mananjadhav Jun 14, 2022
662409e
feat: update references for isloading flags
mananjadhav Jun 14, 2022
5a8c3e5
fix: report actions loader
mananjadhav Jun 14, 2022
b5c10e6
fix: split functions for initial load and pagination
mananjadhav Jun 14, 2022
479e056
fix: alignment of skeleton view
mananjadhav Jun 14, 2022
e468cbc
fix: update checks for shouldComponentUpdate
mananjadhav Jun 14, 2022
8d9e5bb
feat: added animation transition to skeleton ui
mananjadhav Jun 14, 2022
7f8d26f
Merge branch 'main' of github.com:mananjadhav/App into feat/ghost-screen
mananjadhav Jul 22, 2022
cc66043
refactor: chnged the latest version of skeleton ui code
mananjadhav Jul 22, 2022
aaa6806
chore: package-lock changes
mananjadhav Jul 22, 2022
fb56647
refactor: retain the latest changes ReportScreen
mananjadhav Jul 22, 2022
2c35e7a
refactor: change the flags for isLoadingMoreActions
mananjadhav Jul 22, 2022
2efc337
feat: changed flags for loading actions with new format
mananjadhav Jul 22, 2022
d4cbe16
style: lint fixes
mananjadhav Jul 22, 2022
8f09ac6
fix: updated the flag with reportId
mananjadhav Jul 22, 2022
80671e6
Merge branch 'main' of github.com:mananjadhav/App into feat/ghost-screen
mananjadhav Jul 26, 2022
719a477
Merge branch 'main' of github.com:mananjadhav/App into feat/ghost-screen
mananjadhav Jul 28, 2022
0352b63
refactor: remove unwanted pagination method
mananjadhav Jul 28, 2022
862557b
Merge branch 'main' of github.com:mananjadhav/App into feat/ghost-screen
mananjadhav Jul 29, 2022
ab2189f
style: corrected comment
mananjadhav Jul 29, 2022
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
1 change: 1 addition & 0 deletions config/webpack/webpack.common.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ const webpackConfig = ({envFile = '.env', platform = 'web'}) => ({
alias: {
'react-native-config': 'react-web-config',
'react-native$': 'react-native-web',
'react-content-loader/native': 'react-content-loader',
mananjadhav marked this conversation as resolved.
Show resolved Hide resolved
},

// React Native libraries may have web-specific module implementations that appear with the extension `.web.js`
Expand Down
145 changes: 75 additions & 70 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
"pusher-js": "^7.0.6",
"react": "^17.0.2",
"react-collapse": "^5.1.0",
"react-content-loader": "^6.1.0",
"react-dom": "^17.0.2",
"react-native": "0.66.4",
"react-native-collapsible": "^1.6.0",
Expand Down
10 changes: 8 additions & 2 deletions src/CONST.js
Original file line number Diff line number Diff line change
Expand Up @@ -476,9 +476,15 @@ const CONST = {
NON_NATIVE_EMOJI_PICKER_LIST_HEIGHT: 300,
EMOJI_PICKER_ITEM_HEIGHT: 40,
EMOJI_PICKER_HEADER_HEIGHT: 38,

COMPOSER_MAX_HEIGHT: 125,

CHAT_SKELETON_VIEW: {
AVERAGE_ROW_HEIGHT: 80,
HEIGHT_FOR_ROW_COUNT: {
1: 60,
2: 80,
3: 100,
},
},
EMAIL: {
CONCIERGE: 'concierge@expensify.com',
HELP: 'help@expensify.com',
Expand Down
3 changes: 2 additions & 1 deletion src/ONYXKEYS.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ export default {
POLICY: 'policy_',
REPORTS_WITH_DRAFT: 'reportWithDraft_',
REPORT_IS_COMPOSER_FULL_SIZE: 'reportIsComposerFullSize_',
IS_LOADING_REPORT_ACTIONS: 'isLoadingReportActions_',
IS_LOADING_INITIAL_REPORT_ACTIONS: 'isLoadingInitialReportActions_',
IS_LOADING_MORE_REPORT_ACTIONS: 'isLoadingMoreReportActions_',
POLICY_MEMBER_LIST: 'policyMemberList_',
},

Expand Down
26 changes: 26 additions & 0 deletions src/components/ReportActionsSkeletonView/SkeletonViewLines.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from 'react';
import PropTypes from 'prop-types';
import {Rect, Circle} from 'react-native-svg';
import SkeletonViewContentLoader from 'react-content-loader/native';
import CONST from '../../CONST';

const propTypes = {
/** Number of rows to show in Skeleton UI block */
numberOfRows: PropTypes.number.isRequired,
mananjadhav marked this conversation as resolved.
Show resolved Hide resolved
};

const SkeletonViewLines = props => (
<SkeletonViewContentLoader
height={CONST.CHAT_SKELETON_VIEW.HEIGHT_FOR_ROW_COUNT[props.numberOfRows]}
>
<Circle cx="40" cy="26" r="20" />
<Rect x="67" y="11" width="20%" height="8" />
<Rect x="67" y="31" width="90%" height="8" />
{props.numberOfRows > 1 && <Rect x="67" y="51" width="50%" height="8" />}
{props.numberOfRows > 2 && <Rect x="67" y="71" width="50%" height="8" />}
</SkeletonViewContentLoader>
);

SkeletonViewLines.displayName = 'SkeletonViewLines';
SkeletonViewLines.propTypes = propTypes;
export default SkeletonViewLines;
33 changes: 33 additions & 0 deletions src/components/ReportActionsSkeletonView/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React from 'react';
import PropTypes from 'prop-types';
import SkeletonViewLines from './SkeletonViewLines';
import CONST from '../../CONST';

const propTypes = {
/** Height of the container component */
containerHeight: PropTypes.number.isRequired,
};

const ReportActionsSkeletonView = (props) => {
// Determines the number of content items based on container height
const possibleVisibleContentItems = Math.floor(props.containerHeight / CONST.CHAT_SKELETON_VIEW.AVERAGE_ROW_HEIGHT);
const skeletonViewLines = [];
for (let index = 0; index < possibleVisibleContentItems; index++) {
const iconIndex = (index + 1) % 4;
switch (iconIndex) {
case 2:
skeletonViewLines.push(<SkeletonViewLines numberOfRows={2} key={`skeletonViewLines${index}`} />);
break;
case 0:
skeletonViewLines.push(<SkeletonViewLines numberOfRows={3} key={`skeletonViewLines${index}`} />);
break;
default:
skeletonViewLines.push(<SkeletonViewLines numberOfRows={1} key={`skeletonViewLines${index}`} />);
}
}
return <>{skeletonViewLines}</>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should have been wrapped within a View. Otherwise the skeleton lines may shrink if the outer view height is not enough.

(Coming from a regression #19442)

Copy link
Member

@parasharrajat parasharrajat May 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, this was not needed at the time we built it so this can't be a regression from this PR. Later when the payment page was added it should have been adjusted to that case as well thus that PR should be linked as regression PR.

};

ReportActionsSkeletonView.displayName = 'ReportActionsSkeletonView';
ReportActionsSkeletonView.propTypes = propTypes;
export default ReportActionsSkeletonView;
2 changes: 1 addition & 1 deletion src/libs/actions/Policy.js
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,7 @@ function subscribeToPolicyEvents() {
if (!_.isEmpty(policyExpenseChatIDs)) {
Report.fetchChatReportsByIDs(policyExpenseChatIDs);
_.each(policyExpenseChatIDs, (reportID) => {
Report.fetchActions(reportID);
Report.fetchInitialActions(reportID);
});
}

Expand Down
19 changes: 15 additions & 4 deletions src/libs/actions/Report.js
Original file line number Diff line number Diff line change
Expand Up @@ -672,6 +672,17 @@ function fetchActions(reportID) {
});
}

/**
* Get the initial actions of a report
*
* @param {Number} reportID
*/
function fetchInitialActions(reportID) {
Onyx.set(`${ONYXKEYS.COLLECTION.IS_LOADING_INITIAL_REPORT_ACTIONS}${reportID}`, true);
fetchActions(reportID)
.finally(() => Onyx.set(`${ONYXKEYS.COLLECTION.IS_LOADING_INITIAL_REPORT_ACTIONS}${reportID}`, false));
}

/**
* Get all of our reports
*
Expand Down Expand Up @@ -1073,17 +1084,17 @@ function readOldestAction(reportID, oldestActionSequenceNumber) {
{
optimisticData: [{
onyxMethod: CONST.ONYX.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.IS_LOADING_REPORT_ACTIONS}${reportID}`,
key: `${ONYXKEYS.COLLECTION.IS_LOADING_MORE_REPORT_ACTIONS}${reportID}`,
value: true,
}],
successData: [{
onyxMethod: CONST.ONYX.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.IS_LOADING_REPORT_ACTIONS}${reportID}`,
key: `${ONYXKEYS.COLLECTION.IS_LOADING_MORE_REPORT_ACTIONS}${reportID}`,
value: false,
}],
failureData: [{
onyxMethod: CONST.ONYX.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.IS_LOADING_REPORT_ACTIONS}${reportID}`,
key: `${ONYXKEYS.COLLECTION.IS_LOADING_MORE_REPORT_ACTIONS}${reportID}`,
value: false,
}],
});
Expand Down Expand Up @@ -1574,7 +1585,6 @@ Onyx.connect({

export {
fetchAllReports,
fetchActions,
fetchOrCreateChatReport,
fetchChatReportsByIDs,
fetchIOUReportByID,
Expand All @@ -1598,6 +1608,7 @@ export {
navigateToConciergeChat,
handleInaccessibleReport,
setReportWithDraft,
fetchInitialActions,
createPolicyRoom,
renameReport,
setIsComposerFullSize,
Expand Down
53 changes: 27 additions & 26 deletions src/pages/home/ReportScreen.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import ReportActionCompose from './report/ReportActionCompose';
import KeyboardAvoidingView from '../../components/KeyboardAvoidingView';
import SwipeableView from '../../components/SwipeableView';
import CONST from '../../CONST';
import FullScreenLoadingIndicator from '../../components/FullscreenLoadingIndicator';
import ReportActionsSkeletonView from '../../components/ReportActionsSkeletonView';
import reportActionPropTypes from './report/reportActionPropTypes';
import ArchivedReportFooter from '../../components/ArchivedReportFooter';
import toggleReportActionComposeView from '../../libs/toggleReportActionComposeView';
Expand Down Expand Up @@ -66,6 +66,9 @@ const propTypes = {
/** Beta features list */
betas: PropTypes.arrayOf(PropTypes.string),

/** Flag to check if the initial report actions data are loading */
isLoadingInitialReportActions: PropTypes.bool,

/** The policies which the user has access to */
policies: PropTypes.objectOf(PropTypes.shape({
/** The policy name */
Expand All @@ -89,6 +92,7 @@ const defaultProps = {
},
isComposerFullSize: false,
betas: [],
isLoadingInitialReportActions: false,
};

/**
Expand All @@ -112,13 +116,12 @@ class ReportScreen extends React.Component {
this.viewportOffsetTop = this.updateViewportOffsetTop.bind(this);

this.state = {
isLoading: true,
skeletonViewContainerHeight: 0,
viewportOffsetTop: 0,
};
}

componentDidMount() {
this.prepareTransition();
this.storeCurrentlyViewedReport();
if (window.visualViewport) {
window.visualViewport.addEventListener('resize', this.viewportOffsetTop);
Expand All @@ -129,8 +132,6 @@ class ReportScreen extends React.Component {
if (this.props.route.params.reportID === prevProps.route.params.reportID) {
return;
}

this.prepareTransition();
this.storeCurrentlyViewedReport();
}

Expand Down Expand Up @@ -162,16 +163,7 @@ class ReportScreen extends React.Component {
* @returns {Boolean}
*/
shouldShowLoader() {
return this.state.isLoading || !getReportID(this.props.route);
}

/**
* Configures a small loading transition and proceeds with rendering available data
*/
prepareTransition() {
this.setState({isLoading: true});
clearTimeout(this.loadingTimerId);
this.loadingTimerId = setTimeout(() => this.setState({isLoading: false}), 0);
return !getReportID(this.props.route) || (_.isEmpty(this.props.reportActions) && this.props.isLoadingInitialReportActions);
}

/**
Expand Down Expand Up @@ -212,7 +204,6 @@ class ReportScreen extends React.Component {
if (isArchivedRoom) {
reportClosedAction = lodashFindLast(this.props.reportActions, action => action.actionName === CONST.REPORT.ACTIONS.TYPE.CLOSED);
}

return (
<ScreenWrapper style={[styles.appContent, styles.flex1, {marginTop: this.state.viewportOffsetTop}]}>
<KeyboardAvoidingView>
Expand All @@ -224,17 +215,23 @@ class ReportScreen extends React.Component {
<View
nativeID={CONST.REPORT.DROP_NATIVE_ID}
style={[styles.flex1, styles.justifyContentEnd, styles.overflowHidden]}
onLayout={event => this.setState({skeletonViewContainerHeight: event.nativeEvent.layout.height})}
mananjadhav marked this conversation as resolved.
Show resolved Hide resolved
>
{this.shouldShowLoader() && <FullScreenLoadingIndicator />}
{!this.shouldShowLoader() && (
<ReportActionsView
reportID={reportID}
reportActions={this.props.reportActions}
report={this.props.report}
session={this.props.session}
isComposerFullSize={this.props.isComposerFullSize}
/>
)}
{this.shouldShowLoader()
? (
<ReportActionsSkeletonView
containerHeight={this.state.skeletonViewContainerHeight}
/>
)
: (
<ReportActionsView
reportID={reportID}
reportActions={this.props.reportActions}
report={this.props.report}
session={this.props.session}
isComposerFullSize={this.props.isComposerFullSize}
/>
)}
{(isArchivedRoom || this.props.session.shouldShowComposeInput) && (
<View style={[styles.chatFooter, this.props.isComposerFullSize && styles.chatFooterFullCompose]}>
{
Expand Down Expand Up @@ -288,6 +285,10 @@ export default withOnyx({
betas: {
key: ONYXKEYS.BETAS,
},
isLoadingInitialReportActions: {
key: ({route}) => `${ONYXKEYS.COLLECTION.IS_LOADING_INITIAL_REPORT_ACTIONS}${getReportID(route)}`,
initWithStoredValues: false,
},
policies: {
key: ONYXKEYS.COLLECTION.POLICY,
},
Expand Down
Loading