通讯录/新朋友/黑名单列表区分"加载失败"与"真的是空"
三处都用 .catch(() => {}) 吞掉网络错误,loading 结束后空数组直接落到
"暂无好友"/"暂无新朋友申请"/"黑名单为空",加载失败和真的没数据在界面
上无法区分。改成 group-management-view.jsx 里 11 处同类组件已经在用
的 loadError 状态模式。
第十轮最小粒度测试 Ch5-6 发现。
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
4dbe76f2bd
commit
89fdd31cd4
@@ -106,6 +106,7 @@ function AddressBook({myUserId, onTopicSelected}) {
|
|||||||
const [friends, setFriends] = React.useState(() => (friendsCacheKey && readCachedData(friendsCacheKey)) || []);
|
const [friends, setFriends] = React.useState(() => (friendsCacheKey && readCachedData(friendsCacheKey)) || []);
|
||||||
const [pendingCount, setPendingCount] = React.useState(0);
|
const [pendingCount, setPendingCount] = React.useState(0);
|
||||||
const [loading, setLoading] = React.useState(() => !(friendsCacheKey && readCachedData(friendsCacheKey)));
|
const [loading, setLoading] = React.useState(() => !(friendsCacheKey && readCachedData(friendsCacheKey)));
|
||||||
|
const [loadError, setLoadError] = React.useState(false);
|
||||||
// Same bootstrap the message center already fetches (and caches under the same key) -- only need
|
// Same bootstrap the message center already fetches (and caches under the same key) -- only need
|
||||||
// it here for the file assistant's real topic, so a plain read of the shared cache is enough.
|
// it here for the file assistant's real topic, so a plain read of the shared cache is enough.
|
||||||
const [bootstrap] = useCachedData(myUserId ? 'bootstrap:' + myUserId : null, getBootstrap, [myUserId]);
|
const [bootstrap] = useCachedData(myUserId ? 'bootstrap:' + myUserId : null, getBootstrap, [myUserId]);
|
||||||
@@ -117,7 +118,7 @@ function AddressBook({myUserId, onTopicSelected}) {
|
|||||||
fetchAllPages(cursor => getFriends('', cursor)).then(list => {
|
fetchAllPages(cursor => getFriends('', cursor)).then(list => {
|
||||||
if (friendsCacheKey) { writeCachedData(friendsCacheKey, list); }
|
if (friendsCacheKey) { writeCachedData(friendsCacheKey, list); }
|
||||||
setFriends(list);
|
setFriends(list);
|
||||||
}).catch(() => {}).finally(() => setLoading(false));
|
}).catch(() => setLoadError(true)).finally(() => setLoading(false));
|
||||||
fetchAllPages(cursor => getFriendRequests('inbound', 'pending', cursor))
|
fetchAllPages(cursor => getFriendRequests('inbound', 'pending', cursor))
|
||||||
.then(list => setPendingCount(list.length)).catch(() => {});
|
.then(list => setPendingCount(list.length)).catch(() => {});
|
||||||
}, []);
|
}, []);
|
||||||
@@ -148,7 +149,7 @@ function AddressBook({myUserId, onTopicSelected}) {
|
|||||||
<main className="people-scroll">
|
<main className="people-scroll">
|
||||||
<section className="people-entry-list">{entries.map(item => <button type="button" key={item.label} onClick={() => openEntry(item)}><Avatar icon={item.icon} /><strong>{item.label}</strong>{item.badge ? <em>{item.badge}</em> : null}<Icon>chevron_right</Icon></button>)}</section>
|
<section className="people-entry-list">{entries.map(item => <button type="button" key={item.label} onClick={() => openEntry(item)}><Avatar icon={item.icon} /><strong>{item.label}</strong>{item.badge ? <em>{item.badge}</em> : null}<Icon>chevron_right</Icon></button>)}</section>
|
||||||
<h3 className="people-section-title">好友通讯录</h3>
|
<h3 className="people-section-title">好友通讯录</h3>
|
||||||
{loading ? <p className="people-empty-hint">加载中…</p> : sortedKeys.length === 0 ? <p className="people-empty-hint">暂无好友</p> : null}
|
{loading ? <p className="people-empty-hint">加载中…</p> : sortedKeys.length === 0 ? <p className="people-empty-hint">{loadError ? '通讯录加载失败' : '暂无好友'}</p> : null}
|
||||||
{sortedKeys.map(initial => <section className="people-group" id={'people-group-' + initial} key={initial}><h2>{initial}</h2>
|
{sortedKeys.map(initial => <section className="people-group" id={'people-group-' + initial} key={initial}><h2>{initial}</h2>
|
||||||
{groups[initial].map(person => <button type="button" key={person.user_id} onClick={() => { seedProfile(person); navigate('friend-profile', person.user_id); }}>
|
{groups[initial].map(person => <button type="button" key={person.user_id} onClick={() => { seedProfile(person); navigate('friend-profile', person.user_id); }}>
|
||||||
{/* 副行只在确实是另一个名字时才显示。后端在有备注时会把 display_name 也设成备注
|
{/* 副行只在确实是另一个名字时才显示。后端在有备注时会把 display_name 也设成备注
|
||||||
@@ -174,9 +175,10 @@ function requestStatusLabel(item) {
|
|||||||
function FriendRequests({onToast}) {
|
function FriendRequests({onToast}) {
|
||||||
const [items, setItems] = React.useState([]);
|
const [items, setItems] = React.useState([]);
|
||||||
const [loading, setLoading] = React.useState(true);
|
const [loading, setLoading] = React.useState(true);
|
||||||
|
const [loadError, setLoadError] = React.useState(false);
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
fetchAllPages(cursor => getFriendRequests('all', 'all', cursor))
|
fetchAllPages(cursor => getFriendRequests('all', 'all', cursor))
|
||||||
.then(setItems).catch(() => {}).finally(() => setLoading(false));
|
.then(setItems).catch(() => setLoadError(true)).finally(() => setLoading(false));
|
||||||
}, []);
|
}, []);
|
||||||
const handle = (item, accept) => {
|
const handle = (item, accept) => {
|
||||||
const nextStatus = accept ? 'accepted' : 'rejected';
|
const nextStatus = accept ? 'accepted' : 'rejected';
|
||||||
@@ -188,7 +190,7 @@ function FriendRequests({onToast}) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
return <div className="people-page"><Header title="新朋友" back="address-book" /><main className="people-request-list">
|
return <div className="people-page"><Header title="新朋友" back="address-book" /><main className="people-request-list">
|
||||||
{loading ? <p className="people-empty-hint">加载中…</p> : items.length === 0 ? <p className="people-empty-hint">暂无新朋友申请</p> : null}
|
{loading ? <p className="people-empty-hint">加载中…</p> : items.length === 0 ? <p className="people-empty-hint">{loadError ? '加载失败,请重试' : '暂无新朋友申请'}</p> : null}
|
||||||
{items.map(item => <article key={item.request_id}>
|
{items.map(item => <article key={item.request_id}>
|
||||||
<Avatar person={item.peer} />
|
<Avatar person={item.peer} />
|
||||||
<div><strong>{(item.peer && item.peer.display_name) || item.applicant_id}</strong><p>{item.message || '请求添加您为好友'}</p><small>{new Date(item.created_at).toLocaleString()}</small></div>
|
<div><strong>{(item.peer && item.peer.display_name) || item.applicant_id}</strong><p>{item.message || '请求添加您为好友'}</p><small>{new Date(item.created_at).toLocaleString()}</small></div>
|
||||||
@@ -574,8 +576,9 @@ function Settings({uid, initialBlocked, pinBlocked, onToast}) {
|
|||||||
function BlockList({onToast}) {
|
function BlockList({onToast}) {
|
||||||
const [people, setPeople] = React.useState([]);
|
const [people, setPeople] = React.useState([]);
|
||||||
const [loading, setLoading] = React.useState(true);
|
const [loading, setLoading] = React.useState(true);
|
||||||
|
const [loadError, setLoadError] = React.useState(false);
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
fetchAllPages(cursor => getBlocks(cursor)).then(setPeople).catch(() => {}).finally(() => setLoading(false));
|
fetchAllPages(cursor => getBlocks(cursor)).then(setPeople).catch(() => setLoadError(true)).finally(() => setLoading(false));
|
||||||
}, []);
|
}, []);
|
||||||
const remove = userId => {
|
const remove = userId => {
|
||||||
unblockUser(userId).then(() => { setPeople(items => items.filter(item => item.user_id !== userId)); onToast('已移出黑名单'); })
|
unblockUser(userId).then(() => { setPeople(items => items.filter(item => item.user_id !== userId)); onToast('已移出黑名单'); })
|
||||||
@@ -586,7 +589,7 @@ function BlockList({onToast}) {
|
|||||||
return <div className="people-page"><Header title="黑名单" back="android-settings" /><main className="people-block-list">
|
return <div className="people-page"><Header title="黑名单" back="android-settings" /><main className="people-block-list">
|
||||||
{loading ? <p className="people-empty-hint">加载中…</p> : people.length ?
|
{loading ? <p className="people-empty-hint">加载中…</p> : people.length ?
|
||||||
people.map(item => <article key={item.user_id}><Avatar person={item.user} /><span><strong>{(item.user && item.user.display_name) || item.user_id}</strong><small>已阻止消息和通话</small></span><button type="button" onClick={() => remove(item.user_id)}>移出</button></article>) :
|
people.map(item => <article key={item.user_id}><Avatar person={item.user} /><span><strong>{(item.user && item.user.display_name) || item.user_id}</strong><small>已阻止消息和通话</small></span><button type="button" onClick={() => remove(item.user_id)}>移出</button></article>) :
|
||||||
<div className="people-empty"><Icon>person_off</Icon><strong>黑名单为空</strong></div>}
|
<div className="people-empty"><Icon>person_off</Icon><strong>{loadError ? '黑名单加载失败' : '黑名单为空'}</strong></div>}
|
||||||
</main></div>;
|
</main></div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+9
-6
@@ -7668,6 +7668,7 @@ function AddressBook({
|
|||||||
const [friends, setFriends] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => friendsCacheKey && (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.readCachedData)(friendsCacheKey) || []);
|
const [friends, setFriends] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => friendsCacheKey && (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.readCachedData)(friendsCacheKey) || []);
|
||||||
const [pendingCount, setPendingCount] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(0);
|
const [pendingCount, setPendingCount] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(0);
|
||||||
const [loading, setLoading] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => !(friendsCacheKey && (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.readCachedData)(friendsCacheKey)));
|
const [loading, setLoading] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(() => !(friendsCacheKey && (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.readCachedData)(friendsCacheKey)));
|
||||||
|
const [loadError, setLoadError] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false);
|
||||||
const [bootstrap] = (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.useCachedData)(myUserId ? 'bootstrap:' + myUserId : null, _lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getBootstrap, [myUserId]);
|
const [bootstrap] = (0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.useCachedData)(myUserId ? 'bootstrap:' + myUserId : null, _lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getBootstrap, [myUserId]);
|
||||||
const fileAssistantTopic = bootstrap && bootstrap.entries && bootstrap.entries.file_assistant && bootstrap.entries.file_assistant.topic;
|
const fileAssistantTopic = bootstrap && bootstrap.entries && bootstrap.entries.file_assistant && bootstrap.entries.file_assistant.topic;
|
||||||
react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => {
|
react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => {
|
||||||
@@ -7676,7 +7677,7 @@ function AddressBook({
|
|||||||
(0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.writeCachedData)(friendsCacheKey, list);
|
(0,_lib_use_cached_data_js__WEBPACK_IMPORTED_MODULE_5__.writeCachedData)(friendsCacheKey, list);
|
||||||
}
|
}
|
||||||
setFriends(list);
|
setFriends(list);
|
||||||
}).catch(() => {}).finally(() => setLoading(false));
|
}).catch(() => setLoadError(true)).finally(() => setLoading(false));
|
||||||
(0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.fetchAllPages)(cursor => (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getFriendRequests)('inbound', 'pending', cursor)).then(list => setPendingCount(list.length)).catch(() => {});
|
(0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.fetchAllPages)(cursor => (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getFriendRequests)('inbound', 'pending', cursor)).then(list => setPendingCount(list.length)).catch(() => {});
|
||||||
}, []);
|
}, []);
|
||||||
const visible = friends.filter(item => `${item.display_name}${item.remark || ''}`.toLowerCase().includes(query.toLowerCase()));
|
const visible = friends.filter(item => `${item.display_name}${item.remark || ''}`.toLowerCase().includes(query.toLowerCase()));
|
||||||
@@ -7756,7 +7757,7 @@ function AddressBook({
|
|||||||
children: "加载中…"
|
children: "加载中…"
|
||||||
}, void 0, false) : sortedKeys.length === 0 ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", {
|
}, void 0, false) : sortedKeys.length === 0 ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", {
|
||||||
className: "people-empty-hint",
|
className: "people-empty-hint",
|
||||||
children: "暂无好友"
|
children: loadError ? '通讯录加载失败' : '暂无好友'
|
||||||
}, void 0, false) : null, sortedKeys.map(initial => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("section", {
|
}, void 0, false) : null, sortedKeys.map(initial => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("section", {
|
||||||
className: "people-group",
|
className: "people-group",
|
||||||
id: 'people-group-' + initial,
|
id: 'people-group-' + initial,
|
||||||
@@ -7804,8 +7805,9 @@ function FriendRequests({
|
|||||||
}) {
|
}) {
|
||||||
const [items, setItems] = react__WEBPACK_IMPORTED_MODULE_0___default().useState([]);
|
const [items, setItems] = react__WEBPACK_IMPORTED_MODULE_0___default().useState([]);
|
||||||
const [loading, setLoading] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(true);
|
const [loading, setLoading] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(true);
|
||||||
|
const [loadError, setLoadError] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false);
|
||||||
react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => {
|
react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => {
|
||||||
(0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.fetchAllPages)(cursor => (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getFriendRequests)('all', 'all', cursor)).then(setItems).catch(() => {}).finally(() => setLoading(false));
|
(0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.fetchAllPages)(cursor => (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getFriendRequests)('all', 'all', cursor)).then(setItems).catch(() => setLoadError(true)).finally(() => setLoading(false));
|
||||||
}, []);
|
}, []);
|
||||||
const handle = (item, accept) => {
|
const handle = (item, accept) => {
|
||||||
const nextStatus = accept ? 'accepted' : 'rejected';
|
const nextStatus = accept ? 'accepted' : 'rejected';
|
||||||
@@ -7834,7 +7836,7 @@ function FriendRequests({
|
|||||||
children: "加载中…"
|
children: "加载中…"
|
||||||
}, void 0, false) : items.length === 0 ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", {
|
}, void 0, false) : items.length === 0 ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("p", {
|
||||||
className: "people-empty-hint",
|
className: "people-empty-hint",
|
||||||
children: "暂无新朋友申请"
|
children: loadError ? '加载失败,请重试' : '暂无新朋友申请'
|
||||||
}, void 0, false) : null, items.map(item => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("article", {
|
}, void 0, false) : null, items.map(item => (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("article", {
|
||||||
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Avatar, {
|
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Avatar, {
|
||||||
person: item.peer
|
person: item.peer
|
||||||
@@ -8567,8 +8569,9 @@ function BlockList({
|
|||||||
}) {
|
}) {
|
||||||
const [people, setPeople] = react__WEBPACK_IMPORTED_MODULE_0___default().useState([]);
|
const [people, setPeople] = react__WEBPACK_IMPORTED_MODULE_0___default().useState([]);
|
||||||
const [loading, setLoading] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(true);
|
const [loading, setLoading] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(true);
|
||||||
|
const [loadError, setLoadError] = react__WEBPACK_IMPORTED_MODULE_0___default().useState(false);
|
||||||
react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => {
|
react__WEBPACK_IMPORTED_MODULE_0___default().useEffect(() => {
|
||||||
(0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.fetchAllPages)(cursor => (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getBlocks)(cursor)).then(setPeople).catch(() => {}).finally(() => setLoading(false));
|
(0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.fetchAllPages)(cursor => (0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.getBlocks)(cursor)).then(setPeople).catch(() => setLoadError(true)).finally(() => setLoading(false));
|
||||||
}, []);
|
}, []);
|
||||||
const remove = userId => {
|
const remove = userId => {
|
||||||
(0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.unblockUser)(userId).then(() => {
|
(0,_lib_im_api_js__WEBPACK_IMPORTED_MODULE_4__.unblockUser)(userId).then(() => {
|
||||||
@@ -8605,7 +8608,7 @@ function BlockList({
|
|||||||
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, {
|
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)(Icon, {
|
||||||
children: "person_off"
|
children: "person_off"
|
||||||
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("strong", {
|
}, void 0, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxDEV)("strong", {
|
||||||
children: "黑名单为空"
|
children: loadError ? '黑名单加载失败' : '黑名单为空'
|
||||||
}, void 0, false)]
|
}, void 0, false)]
|
||||||
}, void 0, true)
|
}, void 0, true)
|
||||||
}, void 0, false)]
|
}, void 0, false)]
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user