diff --git a/src/components/CommunityStatesPad/SubscribedTitle.js b/src/components/CommunityStatesPad/SubscribedTitle.js index 00ef240c4..79d2f1c5f 100755 --- a/src/components/CommunityStatesPad/SubscribedTitle.js +++ b/src/components/CommunityStatesPad/SubscribedTitle.js @@ -1,55 +1,15 @@ import React from 'react' -// import { ICON_CMD } from '@/config' -// import { Wrapper } from './styles' -import Tooltip from '@/components/Tooltip' import { NumberTitle } from './styles' -import { PopoverInfo, PopTitle, PopDesc } from './styles/subscribed_title' -const SubscribedBtn = ({ community, onUndoSubscribe }) => { - if (community.raw === 'home') { - return ( - - 已加入 - - ) - } - - return ( - - 点击可退出 - 退出后该社区将不会出现在你的左侧列表中 - - } - > - onUndoSubscribe(community)} small> - 已加入 - - - ) -} - -const SubscribedTitle = ({ community, onSubscribe, onUndoSubscribe }) => ( - <> - {community.viewerHasSubscribed ? ( - +const SubscribedTitle = ({ viewerHasSubscribed }) => ( + + {viewerHasSubscribed ? ( + 已加入 ) : ( - - 点击加入 - 加入后该社区将会出现在你的左侧列表中 - - } - > - onSubscribe(community)}>加入 - + 加入 )} - + ) export default React.memo(SubscribedTitle) diff --git a/src/components/CommunityStatesPad/index.js b/src/components/CommunityStatesPad/index.js index 4ae7655ec..e4507e2cf 100755 --- a/src/components/CommunityStatesPad/index.js +++ b/src/components/CommunityStatesPad/index.js @@ -29,8 +29,6 @@ const log = buildLog('c:CommunityStatesPad:index') const CommunityStatesPad = ({ community, - onSubscribe, - onUndoSubscribe, onShowEditorList, onShowSubscriberList, withoutFounding, @@ -52,11 +50,7 @@ const CommunityStatesPad = ({ {!isMobile && ( - + )} @@ -116,6 +114,10 @@ const ColumnView = ({ + setViewport(true)} + onLeave={() => setViewport(false)} + /> ) } diff --git a/src/containers/digest/CommunityDigest/DigestView/RowView/index.js b/src/containers/digest/CommunityDigest/DigestView/RowView/index.js index 1627f6a52..aa7fc29e8 100644 --- a/src/containers/digest/CommunityDigest/DigestView/RowView/index.js +++ b/src/containers/digest/CommunityDigest/DigestView/RowView/index.js @@ -40,8 +40,6 @@ import { import { tabOnChange } from '../../logic' // import { -// onSubscribe, -// onUndoSubscribe, // onShowEditorList, // onShowSubscriberList, // } from '../../logic' diff --git a/src/containers/digest/CommunityDigest/logic.js b/src/containers/digest/CommunityDigest/logic.js index 7a7be7674..1a59c69a1 100755 --- a/src/containers/digest/CommunityDigest/logic.js +++ b/src/containers/digest/CommunityDigest/logic.js @@ -41,24 +41,6 @@ export const tabOnChange = (activeThread) => { send(EVENT.THREAD_CHANGE, { data: { activeThread, topic: subPath } }) } -export const onSubscribe = (community) => { - if (!store.isLogin) return store.authWarning() - if (store.subscribeLoading) return false - - // log('onSubscribe: ', community) - store.mark({ subscribeLoading: true }) - sr71$.mutate(S.subscribeCommunity, { communityId: community.id }) -} - -export const onUndoSubscribe = (community) => { - if (!store.isLogin) return store.authWarning() - if (store.subscribeLoading) return false - - // log('onUndoSubscribe: ', community) - store.mark({ subscribeLoading: true }) - sr71$.mutate(S.unsubscribeCommunity, { communityId: community.id }) -} - export const onShowEditorList = () => { const type = TYPE.USER_LISTER_COMMUNITY_EDITORS const data = { @@ -85,8 +67,15 @@ export const toggleDescExpand = () => { store.mark({ descExpand: !descExpand }) } -const markLoading = (maybe = true) => - store.mark({ loading: maybe, subscribeLoading: maybe }) +const markLoading = (maybe = true) => store.mark({ loading: maybe }) + +/** + * set digest visiable in current viewport + * @param {Boolean} inView + */ +export const setViewport = (inViewport) => { + store.mark({ inViewport }) +} // ############################### // Data & Error handlers diff --git a/src/containers/digest/CommunityDigest/schema.js b/src/containers/digest/CommunityDigest/schema.js index b26ec3978..d92f97035 100755 --- a/src/containers/digest/CommunityDigest/schema.js +++ b/src/containers/digest/CommunityDigest/schema.js @@ -1,34 +1,12 @@ import gql from 'graphql-tag' -import { P, F } from '@/schemas' +import { P } from '@/schemas' const community = gql` ${P.community} ` -const subscribeCommunity = gql` - mutation subscribeCommunity($communityId: ID!) { - subscribeCommunity(communityId: $communityId) { - ${F.community} - contributesDigest - threads { - title - raw - } - } - } -` -const unsubscribeCommunity = gql` - mutation unsubscribeCommunity($communityId: ID!) { - unsubscribeCommunity(communityId: $communityId) { - id - } - } -` - const schema = { community, - subscribeCommunity, - unsubscribeCommunity, } export default schema diff --git a/src/containers/digest/CommunityDigest/store.js b/src/containers/digest/CommunityDigest/store.js index 1bc96504d..d5ff8ec65 100755 --- a/src/containers/digest/CommunityDigest/store.js +++ b/src/containers/digest/CommunityDigest/store.js @@ -13,7 +13,8 @@ const log = buildLog('S:CommunityDigest') const CommunityDigest = T.model('CommunityDigest', { loading: T.optional(T.boolean, false), descExpand: T.optional(T.boolean, false), - subscribeLoading: T.optional(T.boolean, false), + + inViewport: T.optional(T.boolean, true), }) .views((self) => ({ get root() { diff --git a/src/containers/thread/PostsThread/index.js b/src/containers/thread/PostsThread/index.js index d6a6ef593..7fcf59777 100755 --- a/src/containers/thread/PostsThread/index.js +++ b/src/containers/thread/PostsThread/index.js @@ -12,6 +12,7 @@ import { ICON } from '@/config' import { C11N, THREAD, ROUTE } from '@/constant' import { pluggedIn, buildLog } from '@/utils' +import CommunityJoinBadge from '@/containers/tool/CommunityJoinBadge' import TagsBar from '@/containers/unit/TagsBar' import Sticky from '@/components/Sticky' @@ -30,6 +31,7 @@ import { LeftPart, RightPart, FilterWrapper, + BadgeWrapper, PublisherWrapper, StickyHolder, } from './styles' @@ -97,6 +99,7 @@ const PostsThreadContainer = ({ postsThread: store }) => { accountInfo: { customization: { bannerLayout }, }, + isCommunityDigestInViewport, } = store const { subPath } = curRoute @@ -147,7 +150,7 @@ const PostsThreadContainer = ({ postsThread: store }) => { {bannerLayout === C11N.DIGEST && ( - + { > {LabelText[subPath] || '发布帖子'} - - {/* */} - + + + + ({ toastInfo(options) { diff --git a/src/containers/thread/PostsThread/styles/index.js b/src/containers/thread/PostsThread/styles/index.js index f1ce5b635..d9163c2ee 100755 --- a/src/containers/thread/PostsThread/styles/index.js +++ b/src/containers/thread/PostsThread/styles/index.js @@ -18,15 +18,21 @@ export const LeftPart = styled.div` ` export const RightPart = styled.div` min-width: 200px; + max-width: 200px; padding-top: 20px; margin-left: 40px; ${css.media.tablet`display: none;`}; ` export const PublisherWrapper = styled.div` + display: ${({ show }) => (show ? 'block' : 'none')}; width: 160px; max-width: 180px; - margin-left: 8%; + margin-left: 16px; +` +export const BadgeWrapper = styled.div` + display: ${({ show }) => (show ? 'block' : 'none')}; + margin-left: 18px; ` export const FilterWrapper = styled.div` ${css.flex('align-center')}; diff --git a/src/containers/tool/CommunityJoinBadge/SubscribeBtn.js b/src/containers/tool/CommunityJoinBadge/SubscribeBtn.js new file mode 100644 index 000000000..73f390a62 --- /dev/null +++ b/src/containers/tool/CommunityJoinBadge/SubscribeBtn.js @@ -0,0 +1,53 @@ +import React from 'react' + +import Button from '@/components/Buttons/Button' + +import { Wrapper, Text } from './styles/subscribe_btn' +import { onSubscribe, onCancleSubscribe } from './logic' + +const SubscribeButton = ({ community, subscribeLoading }) => { + const { viewerHasSubscribed } = community + + if (community.raw === 'home') { + return ( + + + + ) + } + + return ( + + {viewerHasSubscribed ? ( + + ) : ( + + )} + + ) +} + +export default SubscribeButton diff --git a/src/containers/tool/CommunityJoinBadge/index.js b/src/containers/tool/CommunityJoinBadge/index.js new file mode 100755 index 000000000..3d747fdb5 --- /dev/null +++ b/src/containers/tool/CommunityJoinBadge/index.js @@ -0,0 +1,52 @@ +// + +/* + * + * CommunityJoinBadge + * + */ + +import React from 'react' +import T from 'prop-types' + +import { pluggedIn, buildLog } from '@/utils' + +import SubscribeBtn from './SubscribeBtn' + +import { Wrapper, Title, Desc, BottomLine } from './styles' +import { useInit } from './logic' + +/* eslint-disable-next-line */ +const log = buildLog('C:CommunityJoinBadge') + +const CommunityJoinBadgeContainer = ({ communityJoinBadge: store, testId }) => { + useInit(store) + + const { curCommunity, subscribeLoading } = store + const { title, desc } = curCommunity + + return ( + + {title} + {desc} + + + + + + ) +} + +CommunityJoinBadgeContainer.propTypes = { + communityJoinBadge: T.any.isRequired, + testId: T.string, +} + +CommunityJoinBadgeContainer.defaultProps = { + testId: 'community-join-badge', +} + +export default pluggedIn(CommunityJoinBadgeContainer) diff --git a/src/containers/tool/CommunityJoinBadge/logic.js b/src/containers/tool/CommunityJoinBadge/logic.js new file mode 100755 index 000000000..2e72b54aa --- /dev/null +++ b/src/containers/tool/CommunityJoinBadge/logic.js @@ -0,0 +1,120 @@ +import { useEffect } from 'react' + +import { EVENT, ERR } from '@/constant' +import { asyncSuit, buildLog, subPath2Thread, errRescue } from '@/utils' + +import S from './schema' + +/* eslint-disable-next-line */ +const log = buildLog('L:CommunityJoinBadge') + +const { SR71, $solver, asyncRes, asyncErr } = asyncSuit +const sr71$ = new SR71({ receive: [EVENT.COMMUNITY_CHANGE] }) + +let sub$ = null +let store = null + +const loadCommunity = () => { + const userHasLogin = store.isLogin + const { raw } = store.curCommunity + + markLoading(true) + + sr71$.query(S.community, { raw, userHasLogin }) +} + +export const onSubscribe = (community) => { + if (!store.isLogin) return store.authWarning() + if (store.subscribeLoading) return false + + // log('onSubscribe: ', community) + store.mark({ subscribeLoading: true }) + sr71$.mutate(S.subscribeCommunity, { communityId: community.id }) +} + +export const onCancleSubscribe = (community) => { + if (!store.isLogin) return store.authWarning() + if (store.subscribeLoading) return false + + store.mark({ subscribeLoading: true }) + sr71$.mutate(S.unsubscribeCommunity, { communityId: community.id }) +} + +const markLoading = (maybe = true) => + store.mark({ loading: maybe, subscribeLoading: maybe }) + +// ############################### +// Data & Error handlers +// ############################### + +const DataSolver = [ + { + match: asyncRes('community'), + action: ({ community }) => { + markLoading(false) + const { subPath } = store.curRoute + log('community: ', community) + store.setViewing({ + community, + activeThread: subPath2Thread(subPath), + }) + }, + }, + { + match: asyncRes('subscribeCommunity'), + action: ({ subscribeCommunity }) => { + store.addSubscribedCommunity(subscribeCommunity) + loadCommunity() + }, + }, + { + match: asyncRes('unsubscribeCommunity'), + action: ({ unsubscribeCommunity }) => { + store.removeSubscribedCommunity(unsubscribeCommunity) + loadCommunity() + }, + }, + { + match: asyncRes(EVENT.COMMUNITY_CHANGE), + action: () => loadCommunity(), + }, +] +const ErrSolver = [ + { + match: asyncErr(ERR.GRAPHQL), + action: () => markLoading(false), + }, + { + match: asyncErr(ERR.TIMEOUT), + action: ({ details }) => { + markLoading(false) + errRescue({ type: ERR.TIMEOUT, details, path: 'AccountEditor' }) + }, + }, + { + match: asyncErr(ERR.NETWORK), + action: () => { + markLoading(false) + errRescue({ type: ERR.NETWORK, path: 'CommunityDigest' }) + }, + }, +] + +// ############################### +// init & uninit +// ############################### +export const useInit = (_store) => { + useEffect(() => { + store = _store + // log('effect init') + sub$ = sr71$.data().subscribe($solver(DataSolver, ErrSolver)) + + return () => { + if (sub$ && !store.loading) { + sr71$.stop() + sub$.unsubscribe() + } + // log('effect uninit') + } + }, [_store]) +} diff --git a/src/containers/tool/CommunityJoinBadge/schema.js b/src/containers/tool/CommunityJoinBadge/schema.js new file mode 100755 index 000000000..b26ec3978 --- /dev/null +++ b/src/containers/tool/CommunityJoinBadge/schema.js @@ -0,0 +1,34 @@ +import gql from 'graphql-tag' +import { P, F } from '@/schemas' + +const community = gql` + ${P.community} +` + +const subscribeCommunity = gql` + mutation subscribeCommunity($communityId: ID!) { + subscribeCommunity(communityId: $communityId) { + ${F.community} + contributesDigest + threads { + title + raw + } + } + } +` +const unsubscribeCommunity = gql` + mutation unsubscribeCommunity($communityId: ID!) { + unsubscribeCommunity(communityId: $communityId) { + id + } + } +` + +const schema = { + community, + subscribeCommunity, + unsubscribeCommunity, +} + +export default schema diff --git a/src/containers/tool/CommunityJoinBadge/store.js b/src/containers/tool/CommunityJoinBadge/store.js new file mode 100755 index 000000000..c7114fa66 --- /dev/null +++ b/src/containers/tool/CommunityJoinBadge/store.js @@ -0,0 +1,33 @@ +/* + * CommunityJoinBadge store + * + */ + +import { types as T, getParent } from 'mobx-state-tree' +// import {} from 'ramda' + +import { markStates, buildLog, stripMobx } from '@/utils' +/* eslint-disable-next-line */ +const log = buildLog('S:CommunityJoinBadge') + +const CommunityJoinBadge = T.model('CommunityJoinBadge', { + subscribeLoading: T.optional(T.boolean, false), +}) + .views((self) => ({ + get root() { + return getParent(self) + }, + get curCommunity() { + return stripMobx(self.root.viewing.community) + }, + })) + .actions((self) => ({ + authWarning(options) { + self.root.authWarning(options) + }, + mark(sobj) { + markStates(sobj, self) + }, + })) + +export default CommunityJoinBadge diff --git a/src/containers/tool/CommunityJoinBadge/styles/index.js b/src/containers/tool/CommunityJoinBadge/styles/index.js new file mode 100755 index 000000000..ab12e0d24 --- /dev/null +++ b/src/containers/tool/CommunityJoinBadge/styles/index.js @@ -0,0 +1,37 @@ +import styled from 'styled-components' + +// import Img from '@/Img' +import { theme } from '@/utils' + +export const Wrapper = styled.div.attrs((props) => ({ + 'data-test-id': props.testId, +}))` + position: relative; + padding-bottom: 20px; + padding-left: 3px; +` +export const BottomLine = styled.div` + position: absolute; + bottom: 0; + left: 0; + width: 65%; + height: 1px; + background: #014454; +` +export const Title = styled.div` + font-size: 16px; + font-weight: bold; + color: ${theme('thread.articleTitle')}; +` +export const Desc = styled.div` + font-size: 12px; + color: ${theme('thread.articleDigest')}; + margin-top: 5px; +` +export const BtnWrapper = styled.div` + margin-top: 12px; + margin-bottom: 5px; +` +export const BtnText = styled.div` + padding: 2px 5px; +` diff --git a/src/containers/tool/CommunityJoinBadge/styles/subscribe_btn.js b/src/containers/tool/CommunityJoinBadge/styles/subscribe_btn.js new file mode 100644 index 000000000..bb2f40afa --- /dev/null +++ b/src/containers/tool/CommunityJoinBadge/styles/subscribe_btn.js @@ -0,0 +1,11 @@ +import styled from 'styled-components' + +// import Img from '@/Img' + +export const Wrapper = styled.div` + margin-top: 12px; + margin-bottom: 5px; +` +export const Text = styled.div` + padding: 2px 5px; +` diff --git a/src/containers/tool/CommunityJoinBadge/tests/index.test.js b/src/containers/tool/CommunityJoinBadge/tests/index.test.js new file mode 100755 index 000000000..df29e5696 --- /dev/null +++ b/src/containers/tool/CommunityJoinBadge/tests/index.test.js @@ -0,0 +1,10 @@ +// import React from 'react' +// import { shallow } from 'enzyme' + +// import CommunityJoinBadge from '../index' + +describe('TODO ', () => { + it('Expect to have unit tests specified', () => { + expect(true).toEqual(true) + }) +}) diff --git a/src/containers/tool/CommunityJoinBadge/tests/store.test.js b/src/containers/tool/CommunityJoinBadge/tests/store.test.js new file mode 100755 index 000000000..38835eca4 --- /dev/null +++ b/src/containers/tool/CommunityJoinBadge/tests/store.test.js @@ -0,0 +1,10 @@ +/* + * CommunityJoinBadge store test + * + */ + +// import CommunityJoinBadge from '../index' + +it('TODO: store test CommunityJoinBadge', () => { + expect(1 + 1).toBe(2) +}) diff --git a/src/stores/RootStore/index.js b/src/stores/RootStore/index.js index 0edbe87d4..cc1a62ab5 100755 --- a/src/stores/RootStore/index.js +++ b/src/stores/RootStore/index.js @@ -94,6 +94,7 @@ import { CoolGuideContentStore, // GEN: IMPORT SUBSTORE + CommunityJoinBadgeStore, ArticleEditorStore, WorksEditorStore, UserProfileStore, @@ -210,6 +211,7 @@ const rootStore = T.model({ coolGuideContent: T.optional(CoolGuideContentStore, {}), // GEN: PLUG SUBSTORE TO ROOTSTORE + communityJoinBadge: T.optional(CommunityJoinBadgeStore, {}), articleEditor: T.optional(ArticleEditorStore, {}), worksEditor: T.optional(WorksEditorStore, {}), userProfile: T.optional(UserProfileStore, {}), diff --git a/src/stores/index.js b/src/stores/index.js index 3454e6bdc..353a9af91 100755 --- a/src/stores/index.js +++ b/src/stores/index.js @@ -96,6 +96,7 @@ export { default as CommunityEditorStore } from '@/containers/editor/CommunityEd export { default as WorksEditorStore } from '@/containers/editor/WorksEditor/store' // GEN: EXPORT CONTAINERS STORE HERE +export { default as CommunityJoinBadgeStore } from '@/containers/tool/CommunityJoinBadge/store' export { default as ArticleEditorStore } from '@/containers/editor/ArticleEditor/store' export { default as UserProfileStore } from '@/containers/user/UserProfile/store' export { default as MembershipContentStore } from '@/containers/content/MembershipContent/store'