From fcc9d9fd784c36d68af2dd13630d9862e2db539d Mon Sep 17 00:00:00 2001 From: mydearxym Date: Tue, 30 Nov 2021 18:05:16 +0800 Subject: [PATCH 1/2] chore(cpers-map): adjust ranking & bottom note for laptop --- src/containers/thread/CperMapThread/styles/index.ts | 4 ++-- src/containers/thread/CperMapThread/styles/raning_board.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/containers/thread/CperMapThread/styles/index.ts b/src/containers/thread/CperMapThread/styles/index.ts index 0bb8f23d0..1c50d2e30 100755 --- a/src/containers/thread/CperMapThread/styles/index.ts +++ b/src/containers/thread/CperMapThread/styles/index.ts @@ -20,8 +20,8 @@ export const MapWrapper = styled.div` /* * magic number, if set 100% the map will jump in laptop screen */ - width: 1000px; - height: 625px; + width: 100%; + height: 100%; min-height: 620px; ${css.media.mobile`width: 250%;`}; ` diff --git a/src/containers/thread/CperMapThread/styles/raning_board.ts b/src/containers/thread/CperMapThread/styles/raning_board.ts index adccc2e30..2981cecd9 100644 --- a/src/containers/thread/CperMapThread/styles/raning_board.ts +++ b/src/containers/thread/CperMapThread/styles/raning_board.ts @@ -11,7 +11,7 @@ export const Wrapper = styled.div` position: absolute; z-index: 1; left: 37px; - bottom: 60px; + bottom: 100px; border-radius: 5px; width: 150px; transition: width 0.2s linear; From e0699a230e54388b8dc6e0d78b1eba2f2802d2ae Mon Sep 17 00:00:00 2001 From: mydearxym Date: Tue, 30 Nov 2021 23:36:31 +0800 Subject: [PATCH 2/2] refactor(user-lister): re-org with drawer style --- .../digest/CommunityDigest/logic.ts | 26 ++-- .../tool/Drawer/Content/DesktopView.tsx | 5 +- .../tool/Drawer/Content/renderContent.tsx | 14 +- src/containers/tool/Drawer/dynamics.tsx | 6 + src/containers/tool/Drawer/index.tsx | 2 + src/containers/tool/Drawer/store.ts | 5 + .../{HeaderInfo.js => HeaderInfo.tsx} | 52 +++++--- .../user/UserLister/List/EditorLayout.tsx | 68 ++++++++++ .../user/UserLister/List/NormalLayout.tsx | 66 ++++++++++ src/containers/user/UserLister/List/index.tsx | 51 ++++++++ src/containers/user/UserLister/UserList.js | 106 --------------- src/containers/user/UserLister/index.js | 82 ------------ src/containers/user/UserLister/index.tsx | 70 ++++++++++ .../user/UserLister/{logic.js => logic.ts} | 121 +++++++++--------- src/containers/user/UserLister/schema.ts | 32 +---- .../user/UserLister/{store.js => store.ts} | 42 +++--- .../user/UserLister/styles/header_info.ts | 17 +-- .../UserLister/styles/list/editor_layout.ts | 97 ++++++++++++++ .../UserLister/styles/list/normal_layout.ts | 79 ++++++++++++ src/spec/account.ts | 2 + .../Buttons/styles/follow_button/index.ts | 1 + .../CommunityStatesPad/SubscribeStatus.tsx | 24 +++- src/widgets/CommunityStatesPad/index.tsx | 22 +--- .../CommunityStatesPad/styles/index.ts | 4 - .../styles/subscribe_status.ts | 4 + utils/constant/type.ts | 3 + utils/helper.ts | 5 + 27 files changed, 637 insertions(+), 369 deletions(-) rename src/containers/user/UserLister/{HeaderInfo.js => HeaderInfo.tsx} (51%) mode change 100755 => 100644 create mode 100644 src/containers/user/UserLister/List/EditorLayout.tsx create mode 100644 src/containers/user/UserLister/List/NormalLayout.tsx create mode 100644 src/containers/user/UserLister/List/index.tsx delete mode 100755 src/containers/user/UserLister/UserList.js delete mode 100755 src/containers/user/UserLister/index.js create mode 100644 src/containers/user/UserLister/index.tsx rename src/containers/user/UserLister/{logic.js => logic.ts} (56%) mode change 100755 => 100644 rename src/containers/user/UserLister/{store.js => store.ts} (55%) mode change 100755 => 100644 create mode 100644 src/containers/user/UserLister/styles/list/editor_layout.ts create mode 100644 src/containers/user/UserLister/styles/list/normal_layout.ts diff --git a/src/containers/digest/CommunityDigest/logic.ts b/src/containers/digest/CommunityDigest/logic.ts index 2e42f06f8..0a83316d6 100755 --- a/src/containers/digest/CommunityDigest/logic.ts +++ b/src/containers/digest/CommunityDigest/logic.ts @@ -3,7 +3,7 @@ import { useEffect } from 'react' import { TYPE, EVENT, ERR } from '@/constant' import asyncSuit from '@/utils/async' -import { send, errRescue, singular } from '@/utils/helper' +import { send, errRescue, singular, listUsers } from '@/utils/helper' import { buildLog } from '@/utils/logger' import type { TStore } from './store' @@ -28,24 +28,20 @@ const loadCommunity = (): void => { sr71$.query(S.community, { raw, userHasLogin }) } +// 查看当前社区志愿者列表 export const onShowEditorList = (): void => { - const type = TYPE.USER_LISTER_COMMUNITY_EDITORS - const data = { - id: store.curCommunity.id, - brief: store.curCommunity.title, - } - - send(EVENT.USER_LISTER_OPEN, { type, data }) + listUsers(TYPE.USER_LISTER_COMMUNITY_EDITORS) } export const onShowSubscriberList = (): void => { - const type = TYPE.USER_LISTER_COMMUNITY_SUBSCRIBERS - const data = { - id: store.curCommunity.id, - brief: store.curCommunity.title, - } - - send(EVENT.USER_LISTER_OPEN, { type, data }) + // const type = TYPE.USER_LISTER_COMMUNITY_SUBSCRIBERS + // const data = { + // id: store.curCommunity.id, + // brief: store.curCommunity.title, + // } + // send(EVENT.USER_LISTER_OPEN, { type, data }) + + listUsers(TYPE.USER_LISTER_COMMUNITY_SUBSCRIBERS) } export const toggleDescExpand = (): void => { diff --git a/src/containers/tool/Drawer/Content/DesktopView.tsx b/src/containers/tool/Drawer/Content/DesktopView.tsx index 249348f6e..f872822e2 100644 --- a/src/containers/tool/Drawer/Content/DesktopView.tsx +++ b/src/containers/tool/Drawer/Content/DesktopView.tsx @@ -10,9 +10,10 @@ type TProps = { visible: boolean type: string // TODO: attUser: any // TODO: + userListerType: string } -const Content: FC = ({ visible, type, attUser }) => { +const Content: FC = ({ visible, type, attUser, userListerType }) => { const ref = useRef(null) /* @@ -34,7 +35,7 @@ const Content: FC = ({ visible, type, attUser }) => { shadowSize="small" showShadow={false} > - {renderContent(type, attUser)} + {renderContent(type, attUser, userListerType)} ) diff --git a/src/containers/tool/Drawer/Content/renderContent.tsx b/src/containers/tool/Drawer/Content/renderContent.tsx index 8e34a91bc..3bd1fa46e 100644 --- a/src/containers/tool/Drawer/Content/renderContent.tsx +++ b/src/containers/tool/Drawer/Content/renderContent.tsx @@ -1,3 +1,4 @@ +import { FC } from 'react' import { TYPE } from '@/constant' import ModeLineMenu from '@/containers/unit/ModeLineMenu' import type { TUser } from '@/spec' @@ -11,9 +12,16 @@ import { AccountEditor, // utils C11NSettingPanel, + // userlister + UserLister, } from '../dynamics' -const renderContent = (type: string, attUser: TUser, mmType?) => { +const renderContent = ( + type: string, + attUser: TUser, + userListerType: string, + mmType?, +) => { if (!type) return
switch (type) { @@ -33,6 +41,10 @@ const renderContent = (type: string, attUser: TUser, mmType?) => { // @ts-ignore return + case TYPE.DRAWER.USER_LISTER: { + return + } + default: // TYPE.DRAWER.[ARTICLE]_VIEW: return diff --git a/src/containers/tool/Drawer/dynamics.tsx b/src/containers/tool/Drawer/dynamics.tsx index 92f55f08f..9a67d60ad 100755 --- a/src/containers/tool/Drawer/dynamics.tsx +++ b/src/containers/tool/Drawer/dynamics.tsx @@ -49,6 +49,12 @@ export const AccountEditor = dynamic( commonConfig, ) +// user lister +export const UserLister = dynamic( + () => import('@/containers/user/UserLister'), + commonConfig, +) + // export const RepoEditor = dynamic( // () => import('@/containers/editor/RepoEditor'), // editorConfig, diff --git a/src/containers/tool/Drawer/index.tsx b/src/containers/tool/Drawer/index.tsx index d4ff5667c..e755fd42c 100755 --- a/src/containers/tool/Drawer/index.tsx +++ b/src/containers/tool/Drawer/index.tsx @@ -33,6 +33,7 @@ const DrawerContainer: FC = ({ drawer: store }) => { slideVisible, type, attUserData, + userListerType, mmType, rightOffset, optionsData, @@ -60,6 +61,7 @@ const DrawerContainer: FC = ({ drawer: store }) => { visible={slideVisible} options={optionsData} attUser={attUserData} + userListerType={userListerType} mmType={mmType} /> diff --git a/src/containers/tool/Drawer/store.ts b/src/containers/tool/Drawer/store.ts index 3d1c74e3d..4a338fcf2 100755 --- a/src/containers/tool/Drawer/store.ts +++ b/src/containers/tool/Drawer/store.ts @@ -53,10 +53,12 @@ const DrawerStore = T.model('DrawerStore', { // TYPE.DRAWER.C11N_SETTINGS, TYPE.DRAWER.MODELINE_MENU, + TYPE.DRAWER.USER_LISTER, ...ARTICLE_THREAD_CURD_TYPES, ]), ), attUser: T.maybeNull(User), + userListerType: T.optional(T.string, ''), // shortcut for modelineMenuType mmType: T.optional( @@ -154,6 +156,9 @@ const DrawerStore = T.model('DrawerStore', { if (type === TYPE.DRAWER.MODELINE_MENU) { slf.mmType = data } + if (type === TYPE.DRAWER.USER_LISTER) { + slf.userListerType = data + } if (contains(thread, values(ARTICLE_THREAD))) { // article diff --git a/src/containers/user/UserLister/HeaderInfo.js b/src/containers/user/UserLister/HeaderInfo.tsx old mode 100755 new mode 100644 similarity index 51% rename from src/containers/user/UserLister/HeaderInfo.js rename to src/containers/user/UserLister/HeaderInfo.tsx index 72bdd64d3..7ac98aae5 --- a/src/containers/user/UserLister/HeaderInfo.js +++ b/src/containers/user/UserLister/HeaderInfo.tsx @@ -1,19 +1,27 @@ -import React from 'react' +import { FC, memo } from 'react' +import type { TCommunity } from '@/spec' import { ICON_CMD, EMAIL_SUPPORT } from '@/config' import { TYPE } from '@/constant' +import NoticeBar from '@/widgets/NoticeBar' + import { Wrapper, Title, DescLabel, DescIcon, - EditorIcon, DescText, DescLink, } from './styles/header_info' -const HeaderInfo = ({ type, totalCount, brief, curCommunity }) => { +type TProps = { + type: string + totalCount: number + curCommunity: TCommunity +} + +const HeaderInfo: FC = ({ type, totalCount, curCommunity }) => { switch (type) { case TYPE.USER_LISTER_FAVORITES: return ( @@ -24,7 +32,7 @@ const HeaderInfo = ({ type, totalCount, brief, curCommunity }) => { - {brief} + -- ) @@ -38,7 +46,7 @@ const HeaderInfo = ({ type, totalCount, brief, curCommunity }) => { - {brief} + -- ) @@ -51,7 +59,7 @@ const HeaderInfo = ({ type, totalCount, brief, curCommunity }) => { 人) - 关注 {brief} 的人 + 关注 -- 的人 ) @@ -64,7 +72,7 @@ const HeaderInfo = ({ type, totalCount, brief, curCommunity }) => { 人) - {brief} 关注的人 + -- 关注的人 ) @@ -73,11 +81,11 @@ const HeaderInfo = ({ type, totalCount, brief, curCommunity }) => { return ( - 关注中 ({totalCount} + 已加入 ({totalCount} 人) - 关注 {brief} 社区的人 + 他们加入了 {curCommunity.title} 社区 ) @@ -86,20 +94,22 @@ const HeaderInfo = ({ type, totalCount, brief, curCommunity }) => { return ( - {brief} 社区编辑 ({totalCount} + {curCommunity.title} 社区志愿者 ({totalCount} 人) + - - - {brief} 社区编辑面向所有用户开放, - - 申请成为社区编辑 - - 。 - + + 申请成为社区志愿者 + ) @@ -109,4 +119,4 @@ const HeaderInfo = ({ type, totalCount, brief, curCommunity }) => { } } -export default React.memo(HeaderInfo) +export default memo(HeaderInfo) diff --git a/src/containers/user/UserLister/List/EditorLayout.tsx b/src/containers/user/UserLister/List/EditorLayout.tsx new file mode 100644 index 000000000..8ade76f14 --- /dev/null +++ b/src/containers/user/UserLister/List/EditorLayout.tsx @@ -0,0 +1,68 @@ +import { FC, memo } from 'react' + +import type { TUser } from '@/spec' +import Link from 'next/link' + +import { useAccount } from '@/hooks' +import FollowButton from '@/widgets/Buttons/FollowButton' + +import { + Wrapper, + UserWrapper, + UserAvatar, + UserBrief, + Title, + Desc, + Nickname, + Location, + CityIcon, + City, + Action, +} from '../styles/list/editor_layout' +import { onFollow, undoFollow } from '../logic' + +type TProps = { + users: TUser[] +} + +const EditorLayout: FC = ({ users }) => { + const { c11n, user: account } = useAccount() + const { isLogin } = c11n + + return ( + + {users.map((user) => ( + + + + + <Link href={`/u/${user.login}`} passHref> + <Nickname>{user.nickname}</Nickname> + </Link> + <Location> + <CityIcon /> + <City>{user.location || user.geoCity || '--'}</City> + </Location> + + {user.bio} + + {isLogin && account.id === user.id ? ( +
(本尊)
+ ) : ( + + )} +
+
+
+ ))} +
+ ) +} + +export default memo(EditorLayout) diff --git a/src/containers/user/UserLister/List/NormalLayout.tsx b/src/containers/user/UserLister/List/NormalLayout.tsx new file mode 100644 index 000000000..c6e3aa0f9 --- /dev/null +++ b/src/containers/user/UserLister/List/NormalLayout.tsx @@ -0,0 +1,66 @@ +import { FC, memo } from 'react' + +import type { TUser } from '@/spec' +import Link from 'next/link' + +import { useAccount } from '@/hooks' +import FollowButton from '@/widgets/Buttons/FollowButton' + +import { + Wrapper, + UserWrapper, + UserAvatar, + UserBrief, + Title, + Nickname, + Location, + City, + CityIcon, + Action, +} from '../styles/list/normal_layout' +import { onFollow, undoFollow } from '../logic' + +type TProps = { + users: TUser[] +} + +const NormalLayout: FC = ({ users }) => { + const { c11n, user: account } = useAccount() + const { isLogin } = c11n + + return ( + + {users.map((user) => ( + + + + + <Link href={`/u/${user.login}`} passHref> + <Nickname>{user.nickname}</Nickname> + </Link> + <Location> + <CityIcon /> + <City>{user.location || user.geoCity || '--'}</City> + </Location> + + + {isLogin && account.id === user.id ? ( +
(本尊)
+ ) : ( + + )} +
+
+
+ ))} +
+ ) +} + +export default memo(NormalLayout) diff --git a/src/containers/user/UserLister/List/index.tsx b/src/containers/user/UserLister/List/index.tsx new file mode 100644 index 000000000..65d80aa3a --- /dev/null +++ b/src/containers/user/UserLister/List/index.tsx @@ -0,0 +1,51 @@ +/* + * + * UserList + * + */ + +import { FC, memo } from 'react' + +import type { TPagedUsers } from '@/spec' +import { TYPE } from '@/constant' + +import { buildLog } from '@/utils/logger' + +import Pagi from '@/widgets/Pagi' +import EditorLayout from './EditorLayout' +import NormalLayout from './NormalLayout' + +import { onPageChange } from '../logic' + +/* eslint-disable-next-line */ +const log = buildLog('c:UserList:index') + +type TProps = { + type: string + data: TPagedUsers +} + +const UserList: FC = ({ + type, + data: { entries, pageNumber, pageSize, totalCount }, +}) => ( + <> + {type === TYPE.USER_LISTER_COMMUNITY_EDITORS ? ( + + ) : ( + + )} + +
+ +
+
+ +) + +export default memo(UserList) diff --git a/src/containers/user/UserLister/UserList.js b/src/containers/user/UserLister/UserList.js deleted file mode 100755 index cb42ecd43..000000000 --- a/src/containers/user/UserLister/UserList.js +++ /dev/null @@ -1,106 +0,0 @@ -/* - * - * UserList - * - */ - -import React from 'react' -import T from 'prop-types' - -import { ICON_CMD } from '@/config' -import { cutRest } from '@/utils/helper' -import { buildLog } from '@/utils/logger' - -import Pagi from '@/widgets/Pagi' -import FollowButton from '@/widgets/Buttons/FollowButton' - -import { - TableWrapper, - UserWrapper, - UserAvatar, - UserBrief, - Title, - Nickname, - Location, - GeoIcon, - Action, -} from './styles/user_list' - -import { onFollow, undoFollow } from './logic' - -/* eslint-disable-next-line */ -const log = buildLog('c:UserList:index') - -const UsersTable = ({ entries, accountId }) => ( - - {entries.map((user) => ( - - - - - <Nickname>{user.nickname}</Nickname> - <Location> - <GeoIcon src={`${ICON_CMD}/city_map.svg`} /> - {cutRest(user.location || user.geoCity || '--', 16)} - </Location> - - - {accountId !== user.id ? ( - - ) : ( -
(本尊)
- )} -
-
-
- ))} -
-) - -const UserList = ({ - accountInfo, - data: { entries, pageNumber, pageSize, totalCount }, - onPageChange, -}) => ( - <> - - - -) - -UserList.propTypes = { - // https://www.npmjs.com/package/prop-types - data: T.shape({ - entries: T.array, - pageNumber: T.number, - pageSize: T.number, - totalCount: T.number, - totalPages: T.number, - }), - onPageChange: T.func, - accountInfo: T.object.isRequired, -} - -UserList.defaultProps = { - data: { - entries: [], - pageNumber: 1, - pageSize: 20, - totalCount: 0, - totalPages: 0, - }, - onPageChange: log, -} - -export default UserList diff --git a/src/containers/user/UserLister/index.js b/src/containers/user/UserLister/index.js deleted file mode 100755 index 502d81bfb..000000000 --- a/src/containers/user/UserLister/index.js +++ /dev/null @@ -1,82 +0,0 @@ -/* - * - * UserLister - * - */ - -import React from 'react' - -import { TYPE } from '@/constant' -import { buildLog } from '@/utils/logger' -import { pluggedIn } from '@/utils/mobx' - -import EmptyLabel from '@/widgets/EmptyLabel' -import Modal from '@/widgets/Modal' -import SearchingLabel from '@/widgets/SearchingLabel' - -import HeaderInfo from './HeaderInfo' -import UserList from './UserList' - -import { Wrapper, MsgWrapper } from './styles' -import { useInit, onClose, onPageChange } from './logic' - -/* eslint-disable-next-line */ -const log = buildLog('C:UserLister') - -const renderContent = (curView, pagedUsersData, accountInfo) => { - switch (curView) { - case TYPE.LOADING: - return ( - - - - ) - - case TYPE.RESULT_EMPTY: - return ( - - - - ) - - default: - return ( - - ) - } -} - -const UserListerContainer = ({ userLister: store }) => { - useInit(store) - - const { - curView, - show, - type, - brief, - pagedUsersData, - accountInfo, - curCommunity, - } = store - - return ( - - - - - {renderContent(curView, pagedUsersData, accountInfo)} - - - ) -} - -export default pluggedIn(UserListerContainer) diff --git a/src/containers/user/UserLister/index.tsx b/src/containers/user/UserLister/index.tsx new file mode 100644 index 000000000..c673680ad --- /dev/null +++ b/src/containers/user/UserLister/index.tsx @@ -0,0 +1,70 @@ +/* + * + * UserLister + * + */ + +import { FC } from 'react' + +import { TYPE } from '@/constant' +import { buildLog } from '@/utils/logger' +import { pluggedIn } from '@/utils/mobx' + +import EmptyLabel from '@/widgets/EmptyLabel' +import { LavaLampLoading } from '@/widgets/dynamic' + +import type { TStore } from './store' +import HeaderInfo from './HeaderInfo' +import List from './List' + +import { Wrapper, MsgWrapper } from './styles' +import { useInit } from './logic' + +/* eslint-disable-next-line */ +const log = buildLog('C:UserLister') + +const renderContent = (type, curView, pagedUsersData) => { + switch (curView) { + case TYPE.LOADING: + return ( + + + + ) + + case TYPE.RESULT_EMPTY: + return ( + + + + ) + + default: + return + } +} + +type TProps = { + userLister?: TStore + type: string +} + +const UserListerContainer: FC = ({ userLister: store, type }) => { + useInit(store, type) + + const { curView, pagedUsersData, curCommunity } = store + + return ( + + + + {renderContent(type, curView, pagedUsersData)} + + ) +} + +export default pluggedIn(UserListerContainer) as FC diff --git a/src/containers/user/UserLister/logic.js b/src/containers/user/UserLister/logic.ts old mode 100755 new mode 100644 similarity index 56% rename from src/containers/user/UserLister/logic.js rename to src/containers/user/UserLister/logic.ts index 629177250..8cbe643a8 --- a/src/containers/user/UserLister/logic.js +++ b/src/containers/user/UserLister/logic.ts @@ -1,10 +1,11 @@ import { useEffect } from 'react' -import { merge, toUpper } from 'ramda' +import type { TID } from '@/spec' import { PAGE_SIZE } from '@/config' import { TYPE, EVENT, ERR } from '@/constant' -import { asyncSuit, buildLog, lockPage, unlockPage, errRescue } from '@/utils' +import { asyncSuit, buildLog, errRescue } from '@/utils' +import type { TStore } from './store' import S from './schema' /* eslint-disable-next-line */ @@ -12,71 +13,72 @@ const log = buildLog('L:UserLister') const { SR71, $solver, asyncRes, asyncErr } = asyncSuit const sr71$ = new SR71({ + // @ts-ignore receive: [EVENT.USER_LISTER_OPEN], }) let sub$ = null let store = null -export const onClose = () => { - store.mark({ show: false }) - unlockPage() -} - -export const onFollow = (userId) => sr71$.mutate(S.follow, { userId }) -export const undoFollow = (userId) => sr71$.mutate(S.undoFollow, { userId }) +export const onFollow = (userId: TID): void => + sr71$.mutate(S.follow, { userId }) +export const undoFollow = (userId: TID): void => + sr71$.mutate(S.undoFollow, { userId }) -const loadUsers = (type, data, page = 1) => { +const loadUsers = (type, page = 1): void => { // log('loadUsers type: ', type) + // TODO: use simple loading store.mark({ curView: TYPE.LOADING }) switch (type) { - case TYPE.USER_LISTER_FAVORITES: - case TYPE.USER_LISTER_STARS: { - const args = merge( - { ...data }, - { - thread: toUpper(data.thread), - filter: { page, size: PAGE_SIZE.D }, - userHasLogin: store.isLogin, - }, - ) - - return sr71$.query(S.reactionUsers, args) - } - case TYPE.USER_LISTER_FOLLOWINGS: { - const args = { - userId: data.id, - filter: { page, size: PAGE_SIZE.D }, - userHasLogin: store.isLogin, - } - return sr71$.query(S.pagedFollowings, args) - } - case TYPE.USER_LISTER_FOLLOWERS: { - const args = { - userId: data.id, - filter: { page, size: PAGE_SIZE.D }, - userHasLogin: store.isLogin, - } - return sr71$.query(S.pagedFollowers, args) - } + // case TYPE.USER_LISTER_FAVORITES: + // case TYPE.USER_LISTER_STARS: { + // const args = merge( + // { ...data }, + // { + // thread: toUpper(data.thread), + // filter: { page, size: PAGE_SIZE.D }, + // userHasLogin: store.isLogin, + // }, + // ) + + // return sr71$.query(S.reactionUsers, args) + // } + // case TYPE.USER_LISTER_FOLLOWINGS: { + // const args = { + // userId: data.id, + // filter: { page, size: PAGE_SIZE.D }, + // userHasLogin: store.isLogin, + // } + // return sr71$.query(S.pagedFollowings, args) + // } + // case TYPE.USER_LISTER_FOLLOWERS: { + // const args = { + // userId: data.id, + // filter: { page, size: PAGE_SIZE.D }, + // userHasLogin: store.isLogin, + // } + // return sr71$.query(S.pagedFollowers, args) + // } case TYPE.USER_LISTER_COMMUNITY_EDITORS: { + const { id } = store.curCommunity const args = { - ...data, + id, filter: { page, size: PAGE_SIZE.D }, userHasLogin: store.isLogin, } - return sr71$.query(S.communityEditors, args) + return sr71$.query(S.pagedCommunityEditors, args) } case TYPE.USER_LISTER_COMMUNITY_SUBSCRIBERS: { + const { id } = store.curCommunity const args = { - ...data, + id, filter: { page, size: PAGE_SIZE.D }, userHasLogin: store.isLogin, } - return sr71$.query(S.communitySubscribers, args) + return sr71$.query(S.pagedCommunitySubscribers, args) } default: { return sr71$.query(S.pagedUsers, { @@ -86,9 +88,9 @@ const loadUsers = (type, data, page = 1) => { } } -export const onPageChange = (page) => { - const { type, id, action, thread } = store - loadUsers(type, { id, action, thread }, page) +export const onPageChange = (page = 1): void => { + const { type } = store + loadUsers(type, page) } const handleUsersRes = (pagedUsers) => { @@ -99,15 +101,6 @@ const handleUsersRes = (pagedUsers) => { // Data & Error handlers // ############################### const DataSolver = [ - { - match: asyncRes(EVENT.USER_LISTER_OPEN), - action: (res) => { - const { type, data } = res.USER_LISTER_OPEN - store.mark({ show: true, type, ...data }) - loadUsers(type, data) - lockPage() - }, - }, { match: asyncRes('reactionUsers'), action: ({ reactionUsers: pagedUsers }) => handleUsersRes(pagedUsers), @@ -121,12 +114,13 @@ const DataSolver = [ action: ({ pagedFollowers: pagedUsers }) => handleUsersRes(pagedUsers), }, { - match: asyncRes('communityEditors'), - action: ({ communityEditors: pagedUsers }) => handleUsersRes(pagedUsers), + match: asyncRes('pagedCommunityEditors'), + action: ({ pagedCommunityEditors: pagedUsers }) => + handleUsersRes(pagedUsers), }, { - match: asyncRes('communitySubscribers'), - action: ({ communitySubscribers: pagedUsers }) => + match: asyncRes('pagedCommunitySubscribers'), + action: ({ pagedCommunitySubscribers: pagedUsers }) => handleUsersRes(pagedUsers), }, { @@ -145,7 +139,9 @@ const DataSolver = [ const ErrSolver = [ { match: asyncErr(ERR.GRAPHQL), - action: () => {}, + action: () => { + // + }, }, { match: asyncErr(ERR.TIMEOUT), @@ -161,16 +157,17 @@ const ErrSolver = [ // ############################### // init & uninit // ############################### -export const useInit = (_store) => { +export const useInit = (_store: TStore, type: string): void => { useEffect(() => { store = _store // log('effect init') sub$ = sr71$.data().subscribe($solver(DataSolver, ErrSolver)) + loadUsers(type) return () => { // log('effect uninit') sr71$.stop() sub$.unsubscribe() } - }, [_store]) + }, [_store, type]) } diff --git a/src/containers/user/UserLister/schema.ts b/src/containers/user/UserLister/schema.ts index b24a8df8a..8b1427125 100755 --- a/src/containers/user/UserLister/schema.ts +++ b/src/containers/user/UserLister/schema.ts @@ -13,9 +13,9 @@ const pagedUsers = gql` } ` -const communitySubscribers = gql` +const pagedCommunitySubscribers = gql` query($id: ID, $community: String, $filter: PagedFilter!, $userHasLogin: Boolean!) { - communitySubscribers(id: $id, community: $community, filter: $filter) { + pagedCommunitySubscribers(id: $id, community: $community, filter: $filter) { entries { ${F.author} location @@ -51,9 +51,9 @@ const pagedFollowings = gql` } } ` -const communityEditors = gql` +const pagedCommunityEditors = gql` query($id: ID!, $filter: PagedFilter!, $userHasLogin: Boolean!) { - communityEditors(id: $id, filter: $filter) { + pagedCommunityEditors(id: $id, filter: $filter) { entries { ${F.author} location @@ -63,25 +63,6 @@ const communityEditors = gql` } } ` -const reactionUsers = gql` - query( - $id: ID! - $thread: ReactThread - $action: ReactAction! - $filter: PagedFilter! - $userHasLogin: Boolean! - ) { - reactionUsers(id: $id, thread: $thread, action: $action, filter: $filter) { - entries { - ${F.author} - location - geoCity - viewerHasFollowed @include(if: $userHasLogin) - } - ${F.pagi} - } - } -` const follow = gql` ${P.follow} @@ -93,11 +74,10 @@ const undoFollow = gql` const schema = { pagedUsers, - communitySubscribers, - reactionUsers, + pagedCommunitySubscribers, pagedFollowers, pagedFollowings, - communityEditors, + pagedCommunityEditors, follow, undoFollow, diff --git a/src/containers/user/UserLister/store.js b/src/containers/user/UserLister/store.ts old mode 100755 new mode 100644 similarity index 55% rename from src/containers/user/UserLister/store.js rename to src/containers/user/UserLister/store.ts index de7a10c4d..e2a400ece --- a/src/containers/user/UserLister/store.js +++ b/src/containers/user/UserLister/store.ts @@ -3,15 +3,16 @@ * */ -import { types as T, getParent } from 'mobx-state-tree' +import { types as T, getParent, Instance } from 'mobx-state-tree' import { findIndex, propEq } from 'ramda' +import type { TRootStore, TID, TCommunity, TPagedUsers, TAccount } from '@/spec' import { TYPE } from '@/constant' import { markStates, toJS } from '@/utils/mobx' import { PagedUsers, emptyPagi } from '@/model' const UserLister = T.model('UserLister', { - show: T.optional(T.boolean, false), + loading: T.optional(T.boolean, false), curView: T.optional( T.enumeration('curView', [TYPE.RESULT, TYPE.LOADING, TYPE.RESULT_EMPTY]), TYPE.LOADING, @@ -34,35 +35,40 @@ const UserLister = T.model('UserLister', { brief: T.optional(T.string, ''), }) .views((self) => ({ - get root() { - return getParent(self) + get isLogin(): boolean { + const root = getParent(self) as TRootStore + return root.account.isLogin }, - get isLogin() { - return self.root.account.isLogin + get accountInfo(): TAccount { + const root = getParent(self) as TRootStore + return root.accountInfo }, - get accountInfo() { - return self.root.accountInfo - }, - get pagedUsersData() { + get pagedUsersData(): TPagedUsers { return toJS(self.pagedUsers) }, - get curCommunity() { - return toJS(self.root.viewing.community) + get curCommunity(): TCommunity { + const root = getParent(self) as TRootStore + return toJS(root.viewing.community) }, })) .actions((self) => ({ - toggleHasFollow(userId) { + reset(): void { + // + }, + toggleHasFollow(userId: TID): void { const { entries } = self.pagedUsersData + // @ts-ignore const index = findIndex(propEq('id', userId), entries) - if (index >= 0) { - const curIsFollow = self.pagedUsers.entries[index].viewerHasFollowed - self.pagedUsers.entries[index].viewerHasFollowed = !curIsFollow - } + if (index < 0) return + + const curIsFollow = self.pagedUsers.entries[index].viewerHasFollowed + self.pagedUsers.entries[index].viewerHasFollowed = !curIsFollow }, - mark(sobj) { + mark(sobj: Record): void { markStates(sobj, self) }, })) +export type TStore = Instance export default UserLister diff --git a/src/containers/user/UserLister/styles/header_info.ts b/src/containers/user/UserLister/styles/header_info.ts index 067d2d767..fb88e5389 100755 --- a/src/containers/user/UserLister/styles/header_info.ts +++ b/src/containers/user/UserLister/styles/header_info.ts @@ -6,7 +6,8 @@ import css from '@/utils/css' export const Wrapper = styled.div` ${css.flexColumn()}; - margin-bottom: 8px; + margin-bottom: 12px; + margin-left: 4px; ` export const Title = styled.div` color: ${theme('thread.articleTitle')}; @@ -22,21 +23,17 @@ export const DescIcon = styled(Img)` margin-right: 5px; ` export const DescLink = styled.a` - color: ${theme('thread.articleTitle')}; - text-decoration: underline; + color: #139c9e; + text-decoration: none; + margin-left: 25px; &:hover { - color: ${theme('banner.title')}; + color: #139c9e; cursor: pointer; text-decoration: underline; } - transition: color 0.3s; -` -export const EditorIcon = styled(DescIcon)` - ${css.size(15)}; - fill: ${theme('thread.articleTitle')}; + transition: color 0.2s; ` - export const DescText = styled.div` color: ${theme('thread.articleDigest')}; font-size: 0.9rem; diff --git a/src/containers/user/UserLister/styles/list/editor_layout.ts b/src/containers/user/UserLister/styles/list/editor_layout.ts new file mode 100644 index 000000000..4b583f059 --- /dev/null +++ b/src/containers/user/UserLister/styles/list/editor_layout.ts @@ -0,0 +1,97 @@ +import styled from 'styled-components' + +import Img from '@/Img' +import { theme } from '@/utils/themes' +import css from '@/utils/css' +import CitySVG from '@/icons/City' + +export const Wrapper = styled.div`` + +export const UserWrapper = styled.div` + ${css.flex()}; + width: 100%; + margin-bottom: 10px; + margin-right: 5px; + padding: 20px 10px; + border-bottom: 1px solid; + border-bottom-color: ${theme('drawer.divider')}; +` +export const UserAvatar = styled(Img)` + ${css.size(55)}; + border-radius: 42%; + margin-top: 5px; + + ${css.media.mobile` + ${css.size(30)}; +`}; +` +export const UserBrief = styled.div` + ${css.flexColumnGrow('justify-between')}; + margin-left: 24px; +` +export const Title = styled.div` + ${css.flex('align-center')}; + color: ${theme('thread.articleTitle')}; + + ${css.media.tablet` + ${css.flexColumn('align-start')}; + `}; +` +export const Desc = styled.div` + font-size: 15px; + margin-top: 2px; + margin-bottom: 5px; + color: ${theme('thread.articleDigest')}; +` +export const Nickname = styled.a` + color: ${theme('thread.articleTitle')}; + text-decoration: none; + font-size: 16px; + + &:hover { + color: ${theme('thread.articleTitle')}; + text-decoration: underline; + } +` +export const Location = styled.div` + ${css.flex('align-center')}; + color: ${theme('thread.articleDigest')}; + margin-left: 10px; + opacity: 0.8; + + ${css.media.tablet` + ${css.cutRest('80px')}; + margin-left: 0; + margin-bottom: 3px; + `}; + + ${css.media.mobile` + ${css.cutRest('60px')}; + margin-left: 0; + margin-bottom: 3px; + `}; +` +export const City = styled.div` + ${css.cutRest('200px')}; + ${css.media.tablet` + ${css.cutRest('80px')}; + margin-left: 0; + margin-bottom: 3px; + `}; + + ${css.media.mobile` + ${css.cutRest('60px')}; + margin-left: 0; + margin-bottom: 3px; + `}; +` +export const CityIcon = styled(CitySVG)` + fill: ${theme('thread.articleDigest')}; + ${css.size(13)}; + margin-right: 2px; +` +export const Action = styled.div` + color: ${theme('thread.articleDigest')}; + width: 100px; + margin-top: 5px; +` diff --git a/src/containers/user/UserLister/styles/list/normal_layout.ts b/src/containers/user/UserLister/styles/list/normal_layout.ts new file mode 100644 index 000000000..2036564d1 --- /dev/null +++ b/src/containers/user/UserLister/styles/list/normal_layout.ts @@ -0,0 +1,79 @@ +import styled from 'styled-components' + +import Img from '@/Img' +import { theme } from '@/utils/themes' +import css from '@/utils/css' +import CitySVG from '@/icons/City' + +export const Wrapper = styled.div` + ${css.flex()}; + flex-wrap: wrap; +` + +export const UserWrapper = styled.div` + ${css.flex()}; + width: 48%; + margin-bottom: 10px; + margin-right: 5px; + padding-top: 10px; + padding-bottom: 10px; + border-bottom: 1px solid; + border-bottom-color: ${theme('drawer.divider')}; +` +export const UserAvatar = styled(Img)` + ${css.size(42)}; + border-radius: 42%; + margin-top: 4px; + + ${css.media.mobile` + ${css.size(30)}; +`}; +` +export const UserBrief = styled.div` + ${css.flexColumnGrow('justify-between')}; + margin-left: 18px; +` +export const Title = styled.div` + ${css.media.tablet` + ${css.flexColumn('align-start')}; + `}; +` +export const Nickname = styled.a` + color: ${theme('thread.articleTitle')}; + text-decoration: none; + font-size: 16px; + + &:hover { + color: ${theme('thread.articleTitle')}; + text-decoration: underline; + } +` +export const Location = styled.div` + ${css.flex('align-center')}; + color: ${theme('thread.articleDigest')}; +` +export const City = styled.div` + ${css.cutRest('150px')}; + ${css.media.tablet` + ${css.cutRest('80px')}; + margin-left: 0; + margin-bottom: 3px; + `}; + + ${css.media.mobile` + ${css.cutRest('60px')}; + margin-left: 0; + margin-bottom: 3px; + `}; +` +export const CityIcon = styled(CitySVG)` + fill: ${theme('thread.articleDigest')}; + ${css.size(13)}; + margin-right: 2px; +` +export const Action = styled.div` + color: ${theme('thread.articleDigest')}; + width: 100px; + margin-top: 10px; + margin-bottom: 10px; +` diff --git a/src/spec/account.ts b/src/spec/account.ts index 350becb9a..190bef524 100644 --- a/src/spec/account.ts +++ b/src/spec/account.ts @@ -34,6 +34,8 @@ export type TUser = TSimpleUser & { editableCommunities?: TPagedCommunities sex?: string location?: string + geoCity?: string + viewerHasFollowed?: boolean social?: TSocial email?: string contributes?: TContributes diff --git a/src/widgets/Buttons/styles/follow_button/index.ts b/src/widgets/Buttons/styles/follow_button/index.ts index 17dcedb54..85d86963c 100644 --- a/src/widgets/Buttons/styles/follow_button/index.ts +++ b/src/widgets/Buttons/styles/follow_button/index.ts @@ -46,6 +46,7 @@ export const FollowingIcon = styled(JoinEyeSVG)` ` export const FollowedButton = styled(Button)` border-radius: 10px; + padding-top: 3px; ` export const FollowingButton = styled(Button)<{ followingOffset: number }>` color: ${theme('baseColor.green')}; diff --git a/src/widgets/CommunityStatesPad/SubscribeStatus.tsx b/src/widgets/CommunityStatesPad/SubscribeStatus.tsx index 806ecbdc7..ab61f4047 100644 --- a/src/widgets/CommunityStatesPad/SubscribeStatus.tsx +++ b/src/widgets/CommunityStatesPad/SubscribeStatus.tsx @@ -2,7 +2,9 @@ import { FC, memo } from 'react' import { prettyNum } from '@/utils/helper' import { buildLog } from '@/utils/logger' + import AnimatedCount from '@/widgets/AnimatedCount' +import Tooltip from '@/widgets/Tooltip' import { Wrapper, @@ -10,6 +12,7 @@ import { SubNumberWrapper, SubNum, GreenDot, + PopHint, } from './styles/subscribe_status' /* eslint-disable-next-line */ @@ -32,12 +35,21 @@ const SubscribeStatus: FC = ({ {prettyNum(count)} - - - - - - + + 实时在线人数,后续会单独统计每个子社区的实时在线人数。 + + } + placement="bottom" + > + + + + + + + ) } diff --git a/src/widgets/CommunityStatesPad/index.tsx b/src/widgets/CommunityStatesPad/index.tsx index bb585eb42..d41209ce1 100755 --- a/src/widgets/CommunityStatesPad/index.tsx +++ b/src/widgets/CommunityStatesPad/index.tsx @@ -9,7 +9,6 @@ import { FC, memo } from 'react' import type { TCommunity } from '@/spec' import usePlatform from '@/hooks/usePlatform' import { buildLog } from '@/utils/logger' -import Tooltip from '@/widgets/Tooltip' import Charger from '@/widgets/Charger' @@ -25,7 +24,6 @@ import { ChargeSection, NumberDivider, NumberTitle, - PopHint, } from './styles' /* eslint-disable-next-line */ @@ -54,20 +52,12 @@ const CommunityStatesPad: FC = ({ {!isMobile && 成员} - - 实时在线人数,后续会单独统计每个子社区的实时在线人数。 - - } - placement="bottom" - > - - + + diff --git a/src/widgets/CommunityStatesPad/styles/index.ts b/src/widgets/CommunityStatesPad/styles/index.ts index f621b0e5b..20879a27f 100755 --- a/src/widgets/CommunityStatesPad/styles/index.ts +++ b/src/widgets/CommunityStatesPad/styles/index.ts @@ -54,7 +54,3 @@ export const NumberDivider = styled.div` `}; ${css.media.mobile`display: none`}; ` - -export const PopHint = styled.div` - width: 200px; -` diff --git a/src/widgets/CommunityStatesPad/styles/subscribe_status.ts b/src/widgets/CommunityStatesPad/styles/subscribe_status.ts index fae3e4d4a..3c1f4a1ce 100644 --- a/src/widgets/CommunityStatesPad/styles/subscribe_status.ts +++ b/src/widgets/CommunityStatesPad/styles/subscribe_status.ts @@ -46,3 +46,7 @@ export const NumberItem = styled.div<{ readOnly: boolean }>` margin-bottom: 2px; `}; ` + +export const PopHint = styled.div` + width: 200px; +` diff --git a/utils/constant/type.ts b/utils/constant/type.ts index 3697a0eee..c555c9272 100755 --- a/utils/constant/type.ts +++ b/utils/constant/type.ts @@ -47,6 +47,9 @@ const TYPE = { // c11n settings C11N_SETTINGS: 'C11N_SETTINGS', + // user lister + USER_LISTER: 'USER_LISTER', + // modeline MODELINE_MENU: 'MODELINE_MENU', }, diff --git a/utils/helper.ts b/utils/helper.ts index 5aceaad70..8f1fe167c 100755 --- a/utils/helper.ts +++ b/utils/helper.ts @@ -207,6 +207,11 @@ export const setTag = (): void => { send(EVENT.SET_TAG, {}) } +export const listUsers = (data): void => { + const type = TYPE.DRAWER.USER_LISTER + send(EVENT.DRAWER.OPEN, { type, data }) +} + export const upvoteOnArticleList = ( article: TArticle, viewerHasUpvoted: boolean,