featL
This commit is contained in:
@ -1,106 +0,0 @@
|
||||
import Taro from '@tarojs/taro';
|
||||
|
||||
import { Dialog } from '@taroify/core';
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
|
||||
import { DialogStatus, PREFIX } from '@/components/product-dialog/const';
|
||||
import ContactCustomerService from '@/components/product-dialog/steps-ui/job-contact-customer';
|
||||
import ContactDirect from '@/components/product-dialog/steps-ui/job-contact-direct';
|
||||
import UnableUnlockContent from '@/components/product-dialog/steps-ui/job-unable';
|
||||
import { EventName } from '@/constants/app';
|
||||
import { DeclarationType, ProductType } from '@/constants/product';
|
||||
import { JobDetails } from '@/types/job';
|
||||
import { GetProductIsUnlockResponse, ProductInfo } from '@/types/product';
|
||||
import { logWithPrefix } from '@/utils/common';
|
||||
import { requestUseProduct } from '@/utils/product';
|
||||
import Toast from '@/utils/toast';
|
||||
|
||||
import '../index.less';
|
||||
|
||||
interface IProps {
|
||||
data: JobDetails;
|
||||
productRecord?: GetProductIsUnlockResponse;
|
||||
productInfo?: ProductInfo;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
const PRODUCT_CODE = ProductType.VIP;
|
||||
const log = logWithPrefix('product-contact-dialog');
|
||||
|
||||
function ProductContactDialog(props: Omit<IProps, 'visible'>) {
|
||||
const { data, productInfo: productInfoProps, productRecord, onClose } = props;
|
||||
const [status, setStatus] = useState<DialogStatus>(DialogStatus.LOADING);
|
||||
const [publisherAcctNo, setPublisherAcctNo] = useState<string>('');
|
||||
const initRef = useRef(() => {});
|
||||
|
||||
const handleCloseDialog = useCallback(() => {
|
||||
onClose();
|
||||
}, [onClose]);
|
||||
|
||||
const handleReport = useCallback(() => {
|
||||
log('report', data.id);
|
||||
}, [data]);
|
||||
|
||||
useEffect(() => {
|
||||
initRef.current = async () => {
|
||||
const handleContact = (declarationTypeResult?: ProductInfo['declarationTypeResult']) => {
|
||||
if (declarationTypeResult?.type === DeclarationType.Direct && declarationTypeResult.publisherAcctNo) {
|
||||
console.log('set JOB_CONTACT_DIRECT', declarationTypeResult.publisherAcctNo)
|
||||
setStatus(DialogStatus.JOB_CONTACT_DIRECT);
|
||||
setPublisherAcctNo(declarationTypeResult.publisherAcctNo);
|
||||
} else {
|
||||
console.log('set JOB_CONTACT_CS')
|
||||
setStatus(DialogStatus.JOB_CONTACT_CS);
|
||||
}
|
||||
};
|
||||
try {
|
||||
Taro.showLoading();
|
||||
// if (1 < 2) {
|
||||
// setStatus(DialogStatus.JOB_CONTACT_CS);
|
||||
// return;
|
||||
// }
|
||||
log('requestProductUseRecord result', productRecord);
|
||||
if (productRecord) {
|
||||
handleContact(productRecord.declarationTypeResult);
|
||||
return;
|
||||
}
|
||||
if (!productInfoProps?.balance) {
|
||||
setStatus(DialogStatus.JOB_UNABLE_UNLOCK);
|
||||
return;
|
||||
}
|
||||
const productInfo = await requestUseProduct(PRODUCT_CODE, { jobId: data.id });
|
||||
Taro.eventCenter.trigger(EventName.READ_CONTACT);
|
||||
console.log('开始报单', productInfo);
|
||||
handleContact(productInfo ? productInfo.declarationTypeResult : undefined);
|
||||
} catch (e) {
|
||||
Toast.error('出错了,请重试');
|
||||
console.log(e);
|
||||
handleCloseDialog();
|
||||
} finally {
|
||||
Taro.hideLoading();
|
||||
}
|
||||
};
|
||||
}, [data, handleCloseDialog, productRecord, productInfoProps?.balance]);
|
||||
|
||||
useEffect(() => {
|
||||
initRef.current();
|
||||
}, []);
|
||||
|
||||
if (status === DialogStatus.LOADING) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog className={PREFIX} onClose={onClose} open>
|
||||
<Dialog.Content>
|
||||
{status === DialogStatus.JOB_CONTACT_CS && <ContactCustomerService onAfterConfirm={handleCloseDialog} />}
|
||||
{status === DialogStatus.JOB_CONTACT_DIRECT && (
|
||||
<ContactDirect publisherAcctNo={publisherAcctNo} onAfterConfirm={handleCloseDialog} onReport={handleReport} />
|
||||
)}
|
||||
{status === DialogStatus.JOB_UNABLE_UNLOCK && <UnableUnlockContent onConfirm={handleCloseDialog} />}
|
||||
</Dialog.Content>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
export default ProductContactDialog;
|
||||
175
src/components/product-dialog/job-contact/index.tsx
Normal file
175
src/components/product-dialog/job-contact/index.tsx
Normal file
@ -0,0 +1,175 @@
|
||||
import Taro from '@tarojs/taro';
|
||||
|
||||
import { Dialog } from '@taroify/core';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
|
||||
import { DialogStatus, PREFIX } from '@/components/product-dialog/const';
|
||||
import JobBuy from '@/components/product-dialog/steps-ui/job-buy';
|
||||
import ContactCustomerService from '@/components/product-dialog/steps-ui/job-contact-customer';
|
||||
import ContactDirect from '@/components/product-dialog/steps-ui/job-contact-direct';
|
||||
import UnableUnlockContent from '@/components/product-dialog/steps-ui/job-unable';
|
||||
import { DeclarationType, ProductType } from '@/constants/product';
|
||||
import { JobDetails } from '@/types/job';
|
||||
import { GetProductIsUnlockResponse, ProductInfo } from '@/types/product';
|
||||
import { logWithPrefix } from '@/utils/common';
|
||||
import { requestUseProduct } from '@/utils/product';
|
||||
import Toast from '@/utils/toast';
|
||||
|
||||
import '../index.less';
|
||||
|
||||
interface IProps {
|
||||
data: JobDetails;
|
||||
/** Product use record from parent - if exists, user has already unlocked this job */
|
||||
productRecord?: GetProductIsUnlockResponse | null;
|
||||
/** Product balance info from parent */
|
||||
productInfo?: ProductInfo;
|
||||
/** Callback to refresh product balance in parent after purchase */
|
||||
onRefreshBalance?: () => Promise<ProductInfo | undefined>;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
const PRODUCT_CODE = ProductType.VIP;
|
||||
const log = logWithPrefix('product-job-contact-dialog');
|
||||
|
||||
/**
|
||||
* Integrated dialog component for job contact flow
|
||||
* Handles: balance check -> buy if needed -> use product -> show contact info
|
||||
*
|
||||
* @param productRecord - Pass from parent to avoid duplicate API calls
|
||||
* @param productInfo - Pass from parent to avoid duplicate API calls
|
||||
* @param onRefreshBalance - Callback to refresh balance in parent after purchase
|
||||
*/
|
||||
function ProductJobContactDialog(props: IProps) {
|
||||
const { data, productRecord, productInfo, onRefreshBalance, onClose } = props;
|
||||
const [status, setStatus] = useState<DialogStatus>(DialogStatus.LOADING);
|
||||
const [publisherAcctNo, setPublisherAcctNo] = useState<string>('');
|
||||
|
||||
/**
|
||||
* Handle contact display based on declaration type
|
||||
*/
|
||||
const showContactResult = useCallback((declarationTypeResult?: ProductInfo['declarationTypeResult']) => {
|
||||
if (declarationTypeResult?.type === DeclarationType.Direct && declarationTypeResult.publisherAcctNo) {
|
||||
log('show JOB_CONTACT_DIRECT', declarationTypeResult.publisherAcctNo);
|
||||
setPublisherAcctNo(declarationTypeResult.publisherAcctNo);
|
||||
setStatus(DialogStatus.JOB_CONTACT_DIRECT);
|
||||
} else {
|
||||
log('show JOB_CONTACT_CS');
|
||||
setStatus(DialogStatus.JOB_CONTACT_CS);
|
||||
}
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Use product and show contact info
|
||||
*/
|
||||
const consumeProductAndShowContact = useCallback(async () => {
|
||||
const productResult = await requestUseProduct(PRODUCT_CODE, { jobId: data.id });
|
||||
log('consumeProductAndShowContact result', productResult);
|
||||
// Refresh balance in parent after consuming product
|
||||
await onRefreshBalance?.();
|
||||
showContactResult(productResult?.declarationTypeResult);
|
||||
}, [data.id, showContactResult, onRefreshBalance]);
|
||||
|
||||
/**
|
||||
* Callback after successful purchase
|
||||
* Refresh balance via parent callback and use product to show contact info
|
||||
*/
|
||||
const handleAfterBuy = useCallback(async () => {
|
||||
log('handleAfterBuy - start');
|
||||
try {
|
||||
Taro.showLoading({ mask: true, title: '加载中...' });
|
||||
|
||||
// Refresh balance via parent callback
|
||||
await onRefreshBalance?.();
|
||||
|
||||
// Use product and show contact info after purchase
|
||||
await consumeProductAndShowContact();
|
||||
} catch (e) {
|
||||
log('handleAfterBuy error', e);
|
||||
Toast.error('出错了,请重试');
|
||||
onClose();
|
||||
} finally {
|
||||
Taro.hideLoading();
|
||||
}
|
||||
}, [consumeProductAndShowContact, onRefreshBalance, onClose]);
|
||||
|
||||
const handleReport = useCallback(() => {
|
||||
log('report', data.id);
|
||||
}, [data.id]);
|
||||
|
||||
/**
|
||||
* Initialize dialog on mount
|
||||
*/
|
||||
useEffect(() => {
|
||||
let isMounted = true;
|
||||
|
||||
const init = async () => {
|
||||
try {
|
||||
Taro.showLoading({ mask: true, title: '加载中...' });
|
||||
|
||||
log('init with productRecord', productRecord);
|
||||
log('init with productInfo', productInfo);
|
||||
|
||||
// Step 1: Already unlocked - show contact directly
|
||||
if (productRecord) {
|
||||
log('show JOB_CONTACT_DIRECT from productRecord', productRecord.declarationTypeResult);
|
||||
showContactResult(productRecord.declarationTypeResult);
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 2: No productInfo - error state
|
||||
if (!productInfo) {
|
||||
log('no productInfo provided, closing');
|
||||
Toast.error('出错了,请重试');
|
||||
onClose();
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 3: Determine status based on balance
|
||||
if (!productInfo.isPaidVip && !productInfo.freeBalance) {
|
||||
log('show JOB_BUY');
|
||||
if (isMounted) setStatus(DialogStatus.JOB_BUY);
|
||||
} else if (!productInfo.balance) {
|
||||
log('show JOB_UNABLE_UNLOCK');
|
||||
if (isMounted) setStatus(DialogStatus.JOB_UNABLE_UNLOCK);
|
||||
} else {
|
||||
await consumeProductAndShowContact();
|
||||
}
|
||||
} catch (e) {
|
||||
log('init error', e);
|
||||
Toast.error('出错了,请重试');
|
||||
onClose();
|
||||
} finally {
|
||||
Taro.hideLoading();
|
||||
}
|
||||
};
|
||||
|
||||
init();
|
||||
|
||||
return () => {
|
||||
isMounted = false;
|
||||
};
|
||||
// Only run on mount - props are captured at dialog open time
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
if (status === DialogStatus.LOADING) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog className={PREFIX} onClose={onClose} open>
|
||||
<Dialog.Content>
|
||||
{status === DialogStatus.JOB_CONTACT_CS && <ContactCustomerService onAfterConfirm={onClose} />}
|
||||
{status === DialogStatus.JOB_CONTACT_DIRECT && (
|
||||
<ContactDirect publisherAcctNo={publisherAcctNo} onAfterConfirm={onClose} onReport={handleReport} />
|
||||
)}
|
||||
{status === DialogStatus.JOB_BUY && (
|
||||
<JobBuy onConfirm={handleAfterBuy} isCreateResume={productInfo?.isCreateResume} />
|
||||
)}
|
||||
{status === DialogStatus.JOB_UNABLE_UNLOCK && <UnableUnlockContent onConfirm={onClose} />}
|
||||
</Dialog.Content>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
export default ProductJobContactDialog;
|
||||
Reference in New Issue
Block a user