import * as React from 'react' import { openAppLofter } from 'nw-app-lofter' import { isLofter } from 'nw-detect'; import { parse } from 'query-string-for-all'; import { callHandler } from 'nejsbridge/dist/bridge.lofter.es'; import safeAreaInsets from 'safe-area-insets'; import { Props, State, BlogInfo, } from './type' import { Popup } from '../common/popup'; import { Tabs, TabPane } from '../common/tabs'; import AddressModal from './address-modal'; import { MissionTitle, MissionList, MissionDesc, } from './missions'; import { AwardList, } from './awards' import { showMessage } from '../common/toast/toast' import { InfoIcon, MissionArrowIcon, MissionInfoIcon } from '../common/icons' import { goToLogin } from '../utils/login'; import { formatMonthDate, formatFullDate, formatAvatar } from '../utils/format'; import localParam from '../utils/localParam'; import log from '../utils/lofter-log' import { appNavigate } from '../utils/navigate' import { fetchTotalMission, convertSimplePrize } from './actions'; import { BaseComponent } from '../base-component'; import * as Styled from './index.style' const urlData = parse(location.search); const isDev = process.env.NODE_ENV === 'development'; const { rem } = Styled; interface InfoBlockProps { points: number, icon: string, color?: string, blogInfo: BlogInfo, } export class InfoBlock extends React.Component { render() { const { blogInfo, icon, points, color } = this.props; return ( 头像
{blogInfo.blogNickName}
活动积分:
图标 x{points}
) } } export class ActivityMission extends React.Component { constructor(props: Props) { super(props); const { isEdit, viewOutApp, alwaysPopup, activityCode } = props; if (!isLofter() && !isDev && !isEdit && !viewOutApp && alwaysPopup) { this.openApp(); return; } if (alwaysPopup) { if (urlData.show === 'award') { this.state.showAwardPopup = true; log.capture('cpnote-16', { category: 'cpnote', action: 100, scene: 'cpnote', activityId: 'cpnote-' + activityCode, }) } else { log.capture('cpnote-9', { category: 'cpnote', action: 100, scene: 'cpnote', activityId: 'cpnote-' + activityCode, }) this.state.showMissionPopup = true } } this.state.safeBottom = safeAreaInsets.bottom; document.body.style.backgroundColor = 'transparent' } static defaultProps = new Props() state = new State() missionScrollRef: HTMLElement | undefined; awardScrollRef: HTMLElement | undefined; awardAddressData: { activityCode: string, prizeActivityCode: string, prizeCode: string, } | undefined dataRequestTime: number = 0; getData = async ({ time, callback, } : { time?: number, callback?: () => void } = {}) => { try { const res = await fetchTotalMission(this.props.activityCode, time); if (res.code === 200) { this.setState({ isLogin: true, points: res.data.points, pointsIcon: res.data.pointsIcon, missionData: res.data.missionActivity, awardData: res.data.awardActivity, blogInfo: res.data.blogInfo, }, () => { this.setState({ showScrollTip: this.missionScrollRef ? ( this.missionScrollRef.scrollHeight > this.missionScrollRef.clientHeight ) : false }) callback && callback(); }) } else { if (res.code !== 401) { showMessage({ text: res.msg }) } } console.log('activity data', time, res); } catch (error) { console.log('Get data failed', error) showMessage('活动太火爆了,请稍后再来哦~') } } openApp = () => { openAppLofter({ path: 'webview', query: { url: location.href } }) } checkAppAndLogin = (type: 'mission' | 'award', callback: () => void) => { if (window.location.host.indexOf('cms-yaolu.hz.netease.com') >= 0){ callback(); return; } // 如果站外,并且不是允许站外浏览,直接唤起app才能做任务 if (!isLofter() && !this.props.viewOutApp && !this.props.isEdit) { this.openApp(); return; } if (type === 'mission') { if (this.state.missionData && this.state.missionData.activityStatus === -1) { showMessage('活动还没开始哦~') return; } if (this.state.missionData && this.state.missionData.activityStatus === 1) { showMessage('活动已经结束啦~') return; } } if (type === 'award') { if (this.state.awardData && this.state.awardData.status === -1) { showMessage('活动还没开始哦~') return; } if (this.state.awardData && this.state.awardData.status === 1) { showMessage('活动已经结束啦~') return; } } if (!this.state.isLogin) { goToLogin(() => { this.getData({ time: new Date().getTime(), callback }); }, 'card') return; } // 为了兼容5.1设备不支持visibility api,每次拉起弹窗都更新一次数据 this.getData({ time: new Date().getTime(), }); callback(); } missionMaskClick = () => { const { isEdit, alwaysPopup } = this.props; if (!alwaysPopup) { this.setState({ showMissionPopup: false, }) } if (isEdit) return; if (isLofter()){ callHandler('njb_closeCurrentWebview'); } else { history.back(); } } awardMaskClick = () => { const { isEdit, alwaysPopup } = this.props; if (!alwaysPopup) { this.setState({ showAwardPopup: false, }) } if (isEdit) return; if (isLofter()){ callHandler('njb_closeCurrentWebview'); } else { history.back(); } } showAddressModal = ({ activityCode, prizeActivityCode, prizeCode, } :{ activityCode: string, prizeActivityCode: string, prizeCode: string, }) => { this.awardAddressData = { activityCode, prizeActivityCode, prizeCode }; this.setState({ showAddressModal: true, }) } hideAddressModal = () => { this.awardAddressData = { activityCode: '', prizeActivityCode: '', prizeCode: '' }; this.setState({ showAddressModal: false, }) } submitAddressPrize = (data: any, callback?: () => void) => { console.log('submitAddressPrize', data); if (!this.awardAddressData || !this.awardAddressData.activityCode || !this.awardAddressData.prizeCode) { console.warn('No award adress data preset'); return; } convertSimplePrize({ addressId: data.addressId, activityCode: this.awardAddressData.activityCode, prizeActivityCode: this.awardAddressData.prizeActivityCode, prizeCode: this.awardAddressData.prizeCode, }).then(() => { this.hideAddressModal(); this.getData({ time: new Date().getTime(), }); callback && callback(); }) } monitorVisibility = () => { if (this.props.isEdit) return; const handleVisibilitychange = () => { if (!document.hidden) { console.log('monitorVisibility update', new Date().getTime()); this.getData({ time: new Date().getTime(), }); } }; document.addEventListener('visibilitychange', handleVisibilitychange); } // loadFont = () => { // const { point : { font } } = this.props // if (font) { // const style = document.createElement('style'); // style.innerText = `@font-face { // font-family: "Point Font"; // src: url("${font}") format("truetype"); // }`; // document.head.appendChild(style); // } // } componentDidMount() { // if (this.props.isEdit) { // this.watch() // } // this.loadFont(); this.monitorVisibility(); this.getData({ time: new Date().getTime(), }); safeAreaInsets.onChange((style: any) => { this.setState({ safeBottom: style.bottom, }) }) } watch = () => { let el = document.getElementById('viewport-left') let vwEl = document.getElementById('viewport') let left = vwEl!.getBoundingClientRect().left this.setState({ viewportLeft: left }) const config = { attributes: true, childList: true} const callback = (mutationList: any) => { mutationList.forEach((mutation: any) => { switch(mutation.type) { case 'childList': this.setState({ viewportLeft: vwEl!.getBoundingClientRect().left }) break; } }) } let observer = new MutationObserver(callback) observer.observe(el!, config) } goPointRule = () => { const { pointRuleUrl, isEdit } = this.props; if (pointRuleUrl && !isEdit) { appNavigate(pointRuleUrl); } } goExchangeRule = () => { const { exchangeRuleUrl, isEdit } = this.props; if (exchangeRuleUrl && !isEdit) { appNavigate(exchangeRuleUrl); } } goCreate = () => { if (!isLofter()) { this.openApp(); return; } const { isEdit, createBtn } = this.props; if (!isEdit) { window.location.href = `lofter://www.lofter.com/post/create/?publish=text&tag=${createBtn.tag}&content=${createBtn.content}` } } showMissionPopup = () => { const { activityCode } = this.props; log.capture('cpnote-16', { category: 'cpnote', action: 100, scene: 'cpnote', activityId: 'cpnote-' + activityCode, }) this.setState({ showMissionPopup: true }) } showAwardPopup = () => { const { activityCode } = this.props; log.capture('cpnote-9', { category: 'cpnote', action: 100, scene: 'cpnote', activityId: 'cpnote-' + activityCode, }) this.setState({ showAwardPopup: true }) } render() { const { activityCode, style, isEdit = false, createBtn, missionPanel, awardPanel, previewMission, previewAward, previewAddress, mainColor = '#000', addressModal, bgOutApp, alwaysPopup, mission, award, } = this.props const { viewportLeft, missionData, awardData, points, pointsIcon, blogInfo, safeBottom, } = this.state; let { showMissionPopup, showAwardPopup, showAddressModal, } = this.state; if (isEdit && previewMission) { showMissionPopup = true } if (isEdit && previewAward) { showAwardPopup = true } if (isEdit && previewAddress) { showAddressModal = true } const maskBg = !isLofter() && bgOutApp?.url ? bgOutApp.url : undefined return (
{!alwaysPopup &&
任务热区
兑换热区
} {missionPanel.titleImage && missionPanel.titleImage.url && } 积分规则 {(missionPanel.topGap && typeof missionPanel.topGap === 'number') ? : null} { this.missionScrollRef = ref }} color={mainColor}> { missionData && missionData.tabList ? missionData.tabList.map((tab, index) => { return ( { tab.tabDesc && ( {tab.tabDesc} ) } ) }) : null } 滚动查看更多 { createBtn.text && {createBtn.text} } {awardPanel.titleImage && awardPanel.titleImage.url && } 兑换规则 {(awardPanel.topGap && typeof awardPanel.topGap === 'number') ? : null} { if (!ref) return; this.awardScrollRef = ref }} > { awardData && } { awardData && }
) } }