239 lines
8.8 KiB
TypeScript
239 lines
8.8 KiB
TypeScript
import { Image } from '@tarojs/components';
|
|
import Taro, { NodesRef, useDidShow, useLoad, useShareAppMessage } from '@tarojs/taro';
|
|
|
|
import { ArrowUp, ArrowDown } from '@taroify/icons';
|
|
import classNames from 'classnames';
|
|
import { isEqual } from 'lodash-es';
|
|
import { useCallback, useEffect, useState } from 'react';
|
|
|
|
import AnchorList, { IAnchorListProps } from '@/components/anchor-list';
|
|
import AnchorPicker from '@/components/anchor-picker';
|
|
import CustomNavigationBar from '@/components/custom-navigation-bar';
|
|
import HomePage from '@/components/home-page';
|
|
import Overlay from '@/components/overlay';
|
|
import PageLoading from '@/components/page-loading';
|
|
import PartnerBanner from '@/components/partner-banner';
|
|
import SwitchBar from '@/components/switch-bar';
|
|
import { APP_TAB_BAR_ID, EventName, OpenSource, PageUrl } from '@/constants/app';
|
|
import { EmployType, JobManageStatus } from '@/constants/job';
|
|
import { ALL_ANCHOR_SORT_TYPES, ANCHOR_SORT_TYPE_TITLE_MAP, AnchorSortType } from '@/constants/material';
|
|
import useInviteCode from '@/hooks/use-invite-code';
|
|
import useListHeight, { IUseListHeightProps } from '@/hooks/use-list-height';
|
|
import useLocation from '@/hooks/use-location';
|
|
import { JobManageInfo } from '@/types/job';
|
|
import { Coordinate } from '@/types/location';
|
|
import { IAnchorFilters } from '@/types/material';
|
|
import { logWithPrefix } from '@/utils/common';
|
|
import { getLastSelectMyJobId, requestJobManageList, setLastSelectMyJobId } from '@/utils/job';
|
|
import { getWxLocation } from '@/utils/location';
|
|
import { requestUnreadMessageCount } from '@/utils/message';
|
|
import { navigateTo } from '@/utils/route';
|
|
import { getCommonShareMessage } from '@/utils/share';
|
|
import Toast from '@/utils/toast';
|
|
import './index.less';
|
|
|
|
const PREFIX = 'page-anchor';
|
|
const LIST_CONTAINER_CLASS = `${PREFIX}__list-container`;
|
|
const CALC_LIST_PROPS: IUseListHeightProps = {
|
|
selectors: [`.${LIST_CONTAINER_CLASS}`, `#${APP_TAB_BAR_ID}`],
|
|
calc: (rects: [NodesRef.BoundingClientRectCallbackResult, NodesRef.BoundingClientRectCallbackResult]) => {
|
|
const [rect, diffRect] = rects;
|
|
return diffRect.top - rect.top;
|
|
},
|
|
};
|
|
const log = logWithPrefix(PREFIX);
|
|
|
|
const EmptyTips = (props: { className?: string; height?: number }) => {
|
|
const { className, height } = props;
|
|
return (
|
|
<div className={classNames(`${PREFIX}__tips-container`, className)} style={height ? { height } : undefined}>
|
|
<Image className={`${PREFIX}__empty-box`} src={require('@/statics/svg/empty-box.svg')} mode="aspectFit" />
|
|
<div className={`${PREFIX}__tips-title`}>该条件下还没有主播</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
function ListWrapper(props: IAnchorListProps) {
|
|
const { className, jobId, filters, cityCode, sortType, latitude, longitude } = props;
|
|
const listHeight = useListHeight(CALC_LIST_PROPS);
|
|
const [isEmpty, setIsEmpty] = useState(false);
|
|
|
|
const handleListEmpty = useCallback(() => {
|
|
setIsEmpty(true);
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
setIsEmpty(false);
|
|
}, [jobId, filters, cityCode, sortType, latitude, longitude]);
|
|
|
|
if (isEmpty) {
|
|
return <EmptyTips className={className} height={listHeight} />;
|
|
}
|
|
|
|
return <AnchorList listHeight={listHeight} {...props} onListEmpty={handleListEmpty} />;
|
|
}
|
|
|
|
export default function AnchorPage() {
|
|
const location = useLocation();
|
|
const [loading, setLoading] = useState(true);
|
|
const [selectJob, setSelectJob] = useState<JobManageInfo | undefined>();
|
|
const [filters, setFilters] = useState<IAnchorFilters>({ employType: EmployType.All });
|
|
const [showFilter, setShowFilter] = useState<boolean>(false);
|
|
const [sortType, setSortType] = useState<AnchorSortType>(AnchorSortType.Active);
|
|
const [coordinate, setCoordinate] = useState<Coordinate>({
|
|
latitude: location.latitude,
|
|
longitude: location.longitude,
|
|
});
|
|
const inviteCode = useInviteCode();
|
|
log('jobId', selectJob);
|
|
|
|
const handleChangeSelectJob = useCallback((select?: JobManageInfo) => {
|
|
log('select job change', select);
|
|
setSelectJob(select);
|
|
setLastSelectMyJobId(select?.id || '');
|
|
}, []);
|
|
|
|
const handleClickSwitch = useCallback(
|
|
() => navigateTo(PageUrl.JobSelectMyPublish, { id: selectJob?.id, source: OpenSource.AnchorPage }),
|
|
[selectJob]
|
|
);
|
|
|
|
const handleClickSalarySelect = useCallback(() => {
|
|
setShowFilter(!showFilter);
|
|
}, [showFilter]);
|
|
|
|
const handleHideFilter = useCallback(() => setShowFilter(false), []);
|
|
|
|
const handleFilterChange = useCallback(
|
|
(newFilters: IAnchorFilters) => {
|
|
!isEqual(newFilters, filters) && setFilters(newFilters);
|
|
setShowFilter(false);
|
|
},
|
|
[filters]
|
|
);
|
|
|
|
const handleClickSortType = useCallback(async (type: AnchorSortType) => setSortType(type), []);
|
|
|
|
const handleJobChange = useCallback(
|
|
(select: JobManageInfo, source: OpenSource) => {
|
|
log('handleJobChange', select, source);
|
|
source === OpenSource.AnchorPage && handleChangeSelectJob(select);
|
|
},
|
|
[handleChangeSelectJob]
|
|
);
|
|
|
|
const handlePublishJobChange = useCallback(async () => {
|
|
const { jobResults = [] } = await requestJobManageList({ status: JobManageStatus.Open });
|
|
if (!selectJob) {
|
|
// 之前没有开发中的通告,自动选中第一个开放中的通告
|
|
handleChangeSelectJob(jobResults[0]);
|
|
return;
|
|
}
|
|
const curJob = jobResults.find(j => j.id === selectJob.id);
|
|
if (!curJob) {
|
|
// 之前选中的通告不再开放了,自动切到第一个开放中的通告
|
|
handleChangeSelectJob(jobResults[0]);
|
|
} else if (!isEqual(curJob, selectJob)) {
|
|
// 之前选中的通告发生了变化,尝试更新
|
|
handleChangeSelectJob(curJob);
|
|
}
|
|
}, [selectJob, handleChangeSelectJob]);
|
|
|
|
useEffect(() => {
|
|
Taro.eventCenter.on(EventName.SELECT_MY_PUBLISH_JOB, handleJobChange);
|
|
Taro.eventCenter.on(EventName.COMPANY_JOB_PUBLISH_CHANGED, handlePublishJobChange);
|
|
return () => {
|
|
Taro.eventCenter.off(EventName.SELECT_MY_PUBLISH_JOB, handleJobChange);
|
|
Taro.eventCenter.off(EventName.COMPANY_JOB_PUBLISH_CHANGED, handlePublishJobChange);
|
|
};
|
|
}, [handleJobChange, handlePublishJobChange]);
|
|
|
|
useEffect(() => {
|
|
const ensureLocation = async () => {
|
|
if (location.latitude || !location.longitude) {
|
|
const res = await getWxLocation();
|
|
if (!res) {
|
|
Toast.info('获取位置信息失败,请重试');
|
|
return;
|
|
}
|
|
const { latitude, longitude } = res;
|
|
setCoordinate({ latitude, longitude });
|
|
}
|
|
};
|
|
ensureLocation();
|
|
}, [location]);
|
|
|
|
useLoad(async () => {
|
|
try {
|
|
const { jobResults = [] } = await requestJobManageList({ status: JobManageStatus.Open });
|
|
if (!jobResults.length) {
|
|
Toast.info('当前是根据定位为您展示主播');
|
|
return;
|
|
}
|
|
const lastSelectJobId = getLastSelectMyJobId();
|
|
const lastJob = jobResults.find(job => job.id === lastSelectJobId) || jobResults[0];
|
|
log('lastJob', lastSelectJobId, lastJob);
|
|
handleChangeSelectJob(lastJob);
|
|
} catch (e) {
|
|
console.error(e);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
});
|
|
|
|
useShareAppMessage(() => {
|
|
return getCommonShareMessage(true, inviteCode);
|
|
});
|
|
|
|
useDidShow(() => requestUnreadMessageCount());
|
|
|
|
return (
|
|
<HomePage>
|
|
{!!loading && <PageLoading className={`${PREFIX}__loading`} />}
|
|
<CustomNavigationBar className={`${PREFIX}__navigation-bar`}>
|
|
{selectJob && <SwitchBar title={selectJob.title.substring(0, 4)} onClick={handleClickSwitch} />}
|
|
</CustomNavigationBar>
|
|
<div className={PREFIX}>
|
|
<div className={`${PREFIX}__top-search-bar`}>
|
|
<div className={classNames(`${PREFIX}__sort-type`)}>
|
|
{ALL_ANCHOR_SORT_TYPES.map(type => (
|
|
<div
|
|
key={type}
|
|
className={classNames(`${PREFIX}__sort-item`, { selected: sortType === type })}
|
|
onClick={() => handleClickSortType(type)}
|
|
>
|
|
{ANCHOR_SORT_TYPE_TITLE_MAP[type]}
|
|
</div>
|
|
))}
|
|
</div>
|
|
<div className={classNames(`${PREFIX}__filter`)} onClick={handleClickSalarySelect}>
|
|
<div className="title">筛选</div>
|
|
{showFilter ? <ArrowUp /> : <ArrowDown />}
|
|
</div>
|
|
</div>
|
|
<div className={`${PREFIX}__banner`}>
|
|
<PartnerBanner />
|
|
</div>
|
|
<ListWrapper
|
|
filters={filters}
|
|
ready={!loading}
|
|
sortType={sortType}
|
|
jobId={selectJob?.id}
|
|
cityCode={selectJob?.cityCode ?? location.cityCode}
|
|
latitude={coordinate.latitude}
|
|
longitude={coordinate.longitude}
|
|
className={LIST_CONTAINER_CLASS}
|
|
/>
|
|
<Overlay
|
|
visible={showFilter}
|
|
onClickOuter={handleHideFilter}
|
|
outerClassName={`${PREFIX}__overlay-outer`}
|
|
innerClassName={`${PREFIX}__overlay-inner`}
|
|
>
|
|
<AnchorPicker value={filters} onConfirm={handleFilterChange} />
|
|
</Overlay>
|
|
</div>
|
|
</HomePage>
|
|
);
|
|
}
|