boluo-app-main/src/pages/material-view/index.tsx
2025-05-15 01:02:00 +08:00

264 lines
9.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { Button } from '@tarojs/components';
import Taro, { useLoad, useShareAppMessage } from '@tarojs/taro';
import { useCallback, useEffect, useState } from 'react';
import CommonDialog from '@/components/common-dialog';
import PageLoading from '@/components/page-loading';
import SafeBottomPadding from '@/components/safe-bottom-padding';
import { EventName, OpenSource, PageUrl } from '@/constants/app';
import { CollectEventName } from '@/constants/event';
import { MaterialViewSource } from '@/constants/material';
import ProfileViewFragment from '@/fragments/profile/view';
import useInviteCode from '@/hooks/use-invite-code';
import { RESPONSE_ERROR_CODE } from '@/http/constant';
import { HttpError } from '@/http/error';
import { JobManageInfo } from '@/types/job';
import { MaterialProfile } from '@/types/material';
import { IJobMessage } from '@/types/message';
import { copy } from '@/utils/common';
import { collectEvent } from '@/utils/event';
import { requestHasPublishedJob, requestJobDetail } from '@/utils/job';
import { getMaterialShareMessage, requestReadProfile, requestShareProfile } from '@/utils/material';
import { isChatWithSelf, postCreateChat } from '@/utils/message';
import { getInviteCodeFromQueryAndUpdate } from '@/utils/partner';
import { getPageQuery, navigateBack, navigateTo, redirectTo } from '@/utils/route';
import Toast from '@/utils/toast';
import './index.less';
const PREFIX = 'page-material-view';
interface IViewContext {
resumeId: string;
source: MaterialViewSource.AnchorList | MaterialViewSource.Chat;
jobId?: string;
}
interface IShareContext {
resumeId: string;
source: MaterialViewSource.Share;
shareCode: string;
c?: string;
}
const isShareContext = (context: IViewContext | IShareContext): context is IShareContext => {
return !!(context as IShareContext).shareCode;
};
const requestProfile = async (context: IViewContext | IShareContext) => {
if (!context.resumeId) {
throw new Error('参数错误');
}
if (isShareContext(context)) {
const { resumeId, shareCode } = context;
const profileDetail = await requestShareProfile({ resumeId, shareCode });
return profileDetail;
} else {
const { resumeId, jobId } = context;
const profileDetail = await requestReadProfile({ resumeId, jobId });
return profileDetail;
}
};
export default function MaterialViewPage() {
const [contactEnable, setContactEnable] = useState(true);
const [profile, setProfile] = useState<MaterialProfile | null>(null);
const [jobId, setJobId] = useState<string>();
const [errorTips, setErrorTips] = useState<string>('');
const [publishDialogVisible, setPublishDialogVisible] = useState(false);
const [certificationDialogVisible, setCertificationDialogVisible] = useState(false);
const [noTimeDialogVisible, setNoTimeDialogVisible] = useState(false);
const [noVipLimitVisible, setNoVipLimitVisible] = useState(false);
const [vipExpiredVisible, setVipExpiredVisible] = useState(false);
const inviteCode = useInviteCode();
const onDev = useCallback(async () => profile && copy(profile.userId), [profile]);
const handleClickContact = useCallback(async () => {
if (!profile) {
return;
}
try {
if (jobId) {
const toUserId = profile.userId;
if (isChatWithSelf(toUserId)) {
Toast.error('不能与自己聊天');
return;
}
const jobDetail = await requestJobDetail(jobId);
const chat = await postCreateChat(toUserId);
const jobMessage: IJobMessage = {
id: jobDetail.id,
title: jobDetail.title,
employType: jobDetail.employType,
salary: jobDetail.salary,
lowPriceForFullTime: jobDetail.lowPriceForFullTime,
highPriceForFullTime: jobDetail.highPriceForFullTime,
lowPriceForPartyTime: jobDetail.lowPriceForPartyTime,
highPriceForPartyTime: jobDetail.highPriceForPartyTime,
};
navigateTo(PageUrl.MessageChat, { chatId: chat.chatId, job: jobMessage, jobId });
return;
}
if (!(await requestHasPublishedJob())) {
setPublishDialogVisible(true);
return;
}
navigateTo(PageUrl.JobSelectMyPublish, { source: OpenSource.MaterialViewPage });
} catch (error) {
const e = error as HttpError;
const errorCode = e.errorCode;
if (errorCode === RESPONSE_ERROR_CODE.INSUFFICIENT_BALANCE) {
setErrorTips('今日10次开聊次数已用完请明日再来');
} else {
Toast.error('请求失败请重试');
}
}
}, [profile, jobId]);
const handleClickNoViewTimes = useCallback(() => {
setNoTimeDialogVisible(false);
navigateBack();
}, []);
const handleClickGoPublish = useCallback(() => {
setPublishDialogVisible(false);
redirectTo(PageUrl.CertificationManage);
}, []);
const handleClickGoCertification = useCallback(() => {
setCertificationDialogVisible(false);
redirectTo(PageUrl.CertificationStart);
}, []);
useEffect(() => {
const callback = (select: JobManageInfo, source: OpenSource) =>
source === OpenSource.MaterialViewPage && setJobId(select.id);
Taro.eventCenter.on(EventName.SELECT_MY_PUBLISH_JOB, callback);
return () => {
Taro.eventCenter.off(EventName.SELECT_MY_PUBLISH_JOB, callback);
};
}, []);
useLoad(async () => {
const context = getPageQuery<IViewContext | IShareContext>();
getInviteCodeFromQueryAndUpdate(context as BL.Anything);
try {
const profileDetail = await requestProfile(context);
setProfile(profileDetail);
if (!isShareContext(context)) {
setJobId(context.jobId);
Taro.eventCenter.trigger(EventName.VIEW_MATERIAL_SUCCESS, profileDetail.id);
}
if (context.source === MaterialViewSource.Chat) {
setContactEnable(false);
}
Taro.setNavigationBarTitle({ title: profileDetail.name || '主播模卡' });
} catch (error) {
const e = error as HttpError;
const errorCode = e.errorCode;
collectEvent(CollectEventName.VIEW_MATERIAL_FAILED, { context, error: e.info?.() || e.message });
console.error(e);
if (errorCode === RESPONSE_ERROR_CODE.BOSS_NOT_AUTH) {
setCertificationDialogVisible(true);
} else if (errorCode === RESPONSE_ERROR_CODE.NO_PUBLISHED_JOB) {
setPublishDialogVisible(true);
} else if (errorCode === RESPONSE_ERROR_CODE.INSUFFICIENT_BALANCE) {
setNoTimeDialogVisible(true);
} else if (errorCode === RESPONSE_ERROR_CODE.INSUFFICIENT_FREE_BALANCE) {
setNoVipLimitVisible(true);
} else if (errorCode === RESPONSE_ERROR_CODE.BOSS_VIP_EXPIRED) {
setVipExpiredVisible(true);
} else {
Toast.error(e.message || '加载失败');
}
}
});
useShareAppMessage(async () => {
const shareMessage = await getMaterialShareMessage(profile, true, inviteCode);
return shareMessage as BL.Anything;
});
if (!profile) {
return (
<>
<PageLoading />
<CommonDialog
content="要查看主播详情,请先完成实人认证"
confirm="去认证"
visible={certificationDialogVisible}
onClose={() => setCertificationDialogVisible(false)}
onClick={handleClickGoCertification}
/>
<CommonDialog
content="请先发布一个认证通告"
confirm="去发布"
visible={publishDialogVisible}
onClose={() => setPublishDialogVisible(false)}
onClick={handleClickGoPublish}
/>
<CommonDialog
content="请先发布一个认证通告"
confirm="去发布"
visible={noVipLimitVisible}
onClose={() => setNoVipLimitVisible(false)}
onClick={handleClickGoPublish}
>
<div className={`${PREFIX}__no-time-tips`}></div>
</CommonDialog>
<CommonDialog
content="请先发布一个认证通告"
confirm="去发布"
visible={vipExpiredVisible}
onClose={() => setVipExpiredVisible(false)}
onClick={handleClickGoPublish}
/>
<CommonDialog
content="今日查看模卡详情次数已用完"
confirm="确定"
visible={noTimeDialogVisible}
onClick={handleClickNoViewTimes}
>
<div className={`${PREFIX}__no-time-tips`}> 20 </div>
</CommonDialog>
</>
);
}
return (
<div className={PREFIX}>
<ProfileViewFragment profile={profile} editable={false} onDev={onDev} />
<div className={`${PREFIX}__footer`}>
<div className={`${PREFIX}__footer__buttons`}>
<Button className={`${PREFIX}__footer__buttons__share`} openType="share">
</Button>
{contactEnable && (
<Button className={`${PREFIX}__footer__buttons__contact`} onClick={handleClickContact}>
</Button>
)}
</div>
<SafeBottomPadding />
</div>
<div>
<CommonDialog
content="请先发布一个认证通告"
confirm="去发布"
visible={publishDialogVisible}
onClose={() => setPublishDialogVisible(false)}
onClick={handleClickGoPublish}
/>
<CommonDialog
content={errorTips}
confirm="确定"
visible={!!errorTips}
onClose={() => setErrorTips('')}
onClick={() => setErrorTips('')}
/>
</div>
</div>
);
}