Files
mini-programs/src/pages/detail/index.tsx

1115 lines
33 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 React, {
useState,
useEffect,
useRef,
useImperativeHandle,
forwardRef,
} from "react";
import { View, Text, Image, Map, ScrollView } from "@tarojs/components";
import { Avatar } from "@nutui/nutui-react-taro";
import Taro, {
useRouter,
useShareAppMessage,
useShareTimeline,
useDidShow,
} from "@tarojs/taro";
import dayjs from "dayjs";
import "dayjs/locale/zh-cn";
// 导入API服务
import { CommonPopup, withAuth, NTRPEvaluatePopup } from "@/components";
import {
EvaluateType,
SceneType,
DisplayConditionType,
} from "@/components/NTRPEvaluatePopup";
import DetailService, { MATCH_STATUS } from "@/services/detailService";
import * as LoginService from "@/services/loginService";
import OrderService from "@/services/orderService";
import { getCurrentLocation, calculateDistance } from "@/utils/locationUtils";
import { useUserInfo, useUserActions } from "@/store/userStore";
import img from "@/config/images";
import "./index.scss";
dayjs.locale("zh-cn");
// 将·作为连接符插入到标签文本之间
function insertDotInTags(tags: string[]) {
return tags.join("-·-").split("-");
}
function GameTags(props) {
const { detail } = props;
const tags = [
{
name: "🕙 急招",
icon: "",
},
{
name: "🔥 本周热门",
icon: "",
},
{
name: "🎉 新活动",
icon: "",
},
{
name: "官方组织",
icon: "",
},
];
return (
<View className="detail-page-content-avatar-tags">
<View className="detail-page-content-avatar-tags-avatar">
{/* network image mock */}
<Image
className="detail-page-content-avatar-tags-avatar-image"
src="https://img.yzcdn.cn/vant/cat.jpeg"
/>
</View>
<View className="detail-page-content-avatar-tags-tags">
{tags.map((tag, index) => (
<View
key={index}
className="detail-page-content-avatar-tags-tags-tag"
>
{tag.icon && <Image src={tag.icon} />}
<Text>{tag.name}</Text>
</View>
))}
</View>
</View>
);
}
type CourselItemType = {
url: string;
width: number;
height: number;
};
function Coursel(props) {
const { detail } = props;
const [list, setList] = useState<CourselItemType[]>([]);
const [listWidth, setListWidth] = useState(0);
const { image_list } = detail;
async function getImagesMsg(imageList) {
const latest_list: CourselItemType[] = [];
const sys_info = await Taro.getSystemInfo();
console.log(sys_info, "info");
const max_width = sys_info.screenWidth - 30;
const max_height = 240;
const current_aspect_ratio = max_width / max_height;
let container_width = 0;
for (const imageUrl of imageList) {
const { width, height } = await Taro.getImageInfo({ src: imageUrl });
if (width && height) {
const aspect_ratio = width / height;
const latest_w_h = { width, height };
if (aspect_ratio < current_aspect_ratio) {
latest_w_h.width = max_height * aspect_ratio;
latest_w_h.height = max_height;
} else {
latest_w_h.width = max_width;
latest_w_h.height = max_width / aspect_ratio;
}
container_width += latest_w_h.width + 12;
latest_list.push({
url: imageUrl,
width: latest_w_h.width,
height: latest_w_h.height,
});
}
}
setList(latest_list);
setListWidth(container_width);
}
useEffect(() => {
getImagesMsg(image_list || []);
}, [image_list]);
return (
<View className="detail-swiper-container">
<View
className="detail-swiper-scroll-container"
style={{ width: listWidth + "px" }}
>
{list.map((item, index) => {
return (
<View className="detail-swiper-item" key={index}>
<Image
src={item.url}
mode="aspectFill"
className="detail-swiper-item-image"
style={{ width: item.width + "px", height: item.height + "px" }}
/>
</View>
);
})}
</View>
</View>
);
}
// 分享弹窗
const SharePopup = forwardRef(
({ id, from }: { id: string; from: string }, ref) => {
const [visible, setVisible] = useState(false);
useImperativeHandle(ref, () => ({
show: () => {
setVisible(true);
},
}));
// function handleShareToWechat() {
// useShareAppMessage(() => {
// return {
// title: '分享',
// path: `/pages/detail/index?id=${id}&from=share`,
// }
// })
// }
// function handleShareToWechatMoments() {
// useShareTimeline(() => {
// return {
// title: '分享',
// path: `/pages/detail/index?id=${id}&from=share`,
// }
// })
// }
// function handleSaveToLocal() {
// Taro.saveImageToPhotosAlbum({
// filePath: images[0],
// success: () => {
// Taro.showToast({ title: '保存成功', icon: 'success' })
// },
// fail: () => {
// Taro.showToast({ title: '保存失败', icon: 'none' })
// },
// })
// }
return (
<CommonPopup
title="分享"
visible={visible}
onClose={() => {
setVisible(false);
}}
hideFooter
style={{ minHeight: "100px" }}
>
<View catchMove className="share-popup-content">
</View>
</CommonPopup>
);
},
);
function navto(url) {
Taro.navigateTo({
url: url,
});
}
// 底部操作栏
function StickyButton(props) {
const { handleShare, handleJoinGame, detail } = props;
const ntrpRef = useRef(null);
// const userInfo = useUserInfo();
// const { id } = userInfo;
const {
id,
publisher_id,
match_status,
price,
user_action_status,
end_time,
} = detail || {};
function handleSelfEvaluate() {
// TODO: 打开自评弹窗
ntrpRef?.current?.show();
}
function generateTextAndAction(
user_action_status: null | { [key: string]: boolean },
): undefined | { text: string | React.FC; action: () => void } {
if (!user_action_status) {
return;
}
// user_action_status.can_assess = true;
user_action_status.can_join = true;
const {
can_assess,
can_join,
can_substitute,
can_pay,
is_substituting,
waiting_start,
} = user_action_status || {};
if (
Object.values(user_action_status).every((value) => !value) &&
dayjs(end_time).isBefore(dayjs())
) {
return {
text: "球局已结束,查看其他球局",
action: navto.bind(null, "/pages/list/index"),
};
}
if (waiting_start) {
return {
text: "等待开始, 查看更多球局",
action: navto.bind(null, "/pages/list/index"),
};
} else if (is_substituting) {
return {
text: "候补中,查看其他球局",
action: navto.bind(null, "/pages/list/index"),
};
} else if (can_pay) {
return {
text: "继续支付",
action: async () => {
const res = await OrderService.getUnpaidOrder(id);
if (res.code === 0) {
Taro.navigateTo({
url: `/mod_user/orderDetail/index?id=${res.data.order_info.order_id}`,
});
}
},
};
} else if (can_substitute) {
return {
text: "立即候补",
action: handleJoinGame,
};
} else if (can_join) {
return {
text: () => {
return (
<>
<Text>🎾</Text>
<Text></Text>
<View className="game-price">
<Text>¥ {price}</Text>
</View>
</>
);
},
action: handleJoinGame,
};
} else if (can_assess) {
return {
text: () => (
<NTRPEvaluatePopup
ref={ntrpRef}
types={[EvaluateType.EDIT, EvaluateType.EVALUATE]}
scene={SceneType.DETAIL}
displayCondition={DisplayConditionType.AUTO}
>
<Text>NTRP自评</Text>
</NTRPEvaluatePopup>
),
action: handleSelfEvaluate,
};
}
return {
text: "球局无法加入",
action: () => {},
};
}
if (!user_action_status) {
return "";
}
const { text, action } = generateTextAndAction(user_action_status)!;
let ActionText: React.FC | string = text;
if (typeof ActionText === "string") {
ActionText = () => {
return <Text>{text as string}</Text>;
};
}
// const role = Number(publisher_id) === id ? "ownner" : "visitor";
return (
<View className="sticky-bottom-bar">
<View className="sticky-bottom-bar-share-and-comment">
<View className="sticky-bottom-bar-share" onClick={handleShare}>
<Image
className="sticky-bottom-bar-share-icon"
src={img.ICON_DETAIL_SHARE}
/>
<Text className="sticky-bottom-bar-share-text"></Text>
</View>
<View className="sticky-bottom-bar-share-and-comment-separator" />
<View
className="sticky-bottom-bar-comment"
onClick={() => {
Taro.showToast({ title: "To be continued", icon: "none" });
}}
>
<Image
className="sticky-bottom-bar-comment-icon"
src={img.ICON_DETAIL_COMMENT_DARK}
/>
<Text className="sticky-bottom-bar-comment-text">32</Text>
</View>
</View>
<View className="sticky-bottom-bar-join-game" onClick={action}>
<ActionText />
</View>
</View>
);
}
// 球局信息
function GameInfo(props) {
const { detail, currentLocation } = props;
const {
latitude,
longitude,
location,
location_name,
start_time,
end_time,
weather = [{}],
} = detail || {};
const [{ iconDay, tempMax, tempMin }] = weather;
const openMap = () => {
Taro.openLocation({
latitude, // 纬度(必填)
longitude, // 经度(必填)
name: location_name, // 位置名(可选)
address: location, // 地址详情(可选)
scale: 15, // 地图缩放级别1-28
});
};
const [c_latitude, c_longitude] = currentLocation;
const distance =
latitude && longitude
? calculateDistance(c_latitude, c_longitude, latitude, longitude) / 1000
: 0;
const startTime = dayjs(start_time);
const endTime = dayjs(end_time);
const game_length = endTime.diff(startTime, "minutes") / 60;
const startMonth = startTime.format("M");
const startDay = startTime.format("D");
const theDayOfWeek = startTime.format("dddd");
const startDate = `${startMonth}${startDay}${theDayOfWeek}`;
const gameRange = `${startTime.format("HH:mm")} - ${endTime.format("HH:mm")}`;
return (
<View className="detail-page-content-game-info">
{/* Date and Weather */}
<View className="detail-page-content-game-info-date-weather">
{/* Calendar and Date time */}
<View className="detail-page-content-game-info-date-weather-calendar-date">
{/* Calendar */}
<View className="detail-page-content-game-info-date-weather-calendar-date-calendar">
<View className="month">{startMonth}</View>
<View className="day">{startDay}</View>
</View>
{/* Date time */}
<View className="detail-page-content-game-info-date-weather-calendar-date-date">
<View className="date">{startDate}</View>
<View className="venue-time">
{gameRange} {game_length}
</View>
</View>
</View>
{/* Weather */}
<View className="detail-page-content-game-info-date-weather-weather">
{/* Weather icon */}
<View className="detail-page-content-game-info-date-weather-weather-icon">
{/*<Image className="weather-icon" src={img.ICON_WEATHER_SUN} />*/}
<i className={`qi-${iconDay}`}></i>
</View>
{/* Weather text and temperature */}
<View className="detail-page-content-game-info-date-weather-weather-text-temperature">
{tempMin && tempMax && (
<Text>
{tempMin} - {tempMax}
</Text>
)}
</View>
</View>
</View>
{/* Place */}
<View className="detail-page-content-game-info-place">
{/* venue location message */}
<View className="location-message">
{/* location icon */}
<View className="location-message-icon">
<Image
className="location-message-icon-image"
src={img.ICON_DETAIL_MAP}
/>
</View>
{/* location message */}
<View className="location-message-text">
{/* venue name and distance */}
{distance ? (
<View
className="location-message-text-name-distance"
onClick={openMap}
>
<Text>{location_name || "-"}</Text>
<Text>·</Text>
<Text>{distance.toFixed(1)}km</Text>
<Image
className="location-message-text-name-distance-arrow"
src={img.ICON_DETAIL_ARROW_RIGHT}
/>
</View>
) : (
""
)}
{/* venue address */}
<View className="location-message-text-address">
<Text>{location || "-"}</Text>
</View>
</View>
</View>
{/* venue map */}
<View className="location-map">
{longitude && latitude && (
<Map
className="location-map-map"
longitude={c_longitude}
latitude={c_latitude}
markers={[
{
id: 1,
latitude,
longitude,
iconPath: require("@/static/detail/icon-stark.svg"),
width: 16,
height: 16,
},
]}
includePoints={[
{ latitude, longitude },
{ latitude: c_latitude, longitude: c_longitude },
]}
includePadding={{ left: 50, right: 50, top: 50, bottom: 50 }}
onError={() => {}}
// hide business msg
showLocation
theme="dark"
/>
)}
</View>
</View>
</View>
);
}
// 场馆信息
function VenueInfo(props) {
const { detail } = props;
const [visible, setVisible] = useState(false);
const {
venue_description,
venue_description_tag = [],
venue_image_list = [],
} = detail;
function showScreenShot() {
setVisible(true);
}
function onClose() {
setVisible(false);
}
function previewImage(current_url) {
Taro.previewImage({
current: current_url,
urls: venue_image_list.map((c) => c.url),
});
}
return (
<View className="detail-page-content-venue">
{/* venue detail title and venue ordered status */}
<View className="venue-detail-title">
<Text></Text>
{venue_image_list?.length > 0 ? (
<>
<Text>·</Text>
<View className="venue-reserve-status" onClick={showScreenShot}>
<Text></Text>
<Image
className="venue-reserve-screenshot"
src={img.ICON_DETAIL_ARROW_RIGHT}
/>
</View>
</>
) : (
""
)}
</View>
{/* venue detail content */}
<View className="venue-detail-content">
{/* venue detail tags */}
<View className="venue-detail-content-tags">
{insertDotInTags(venue_description_tag).map((tag, index) => (
<View key={index} className="venue-detail-content-tags-tag">
<Text>{tag}</Text>
</View>
))}
</View>
{/* venue remarks */}
<View className="venue-detail-content-remarks">
<Text>{venue_description}</Text>
</View>
</View>
<CommonPopup
visible={visible}
onClose={onClose}
round
hideFooter
position="bottom"
zIndex={1001}
>
<View className="venue-screenshot-title"></View>
<ScrollView scrollY className="venue-screenshot-scroll-view">
<View className="venue-screenshot-image-list">
{venue_image_list.map((item) => {
return (
<View
className="venue-screenshot-image-item"
onClick={previewImage.bind(null, item.url)}
>
<Image
className="venue-screenshot-image-item-image"
src={item.url}
/>
</View>
);
})}
</View>
</ScrollView>
</CommonPopup>
</View>
);
}
function genNTRPRequirementText(min, max) {
if (min && max && min !== max) {
return `${min} - ${max} 之间`;
} else if (max === 1) {
return "没有要求";
} else if (max) {
return `${max} 以上`;
}
return "-";
}
// 玩法要求
function GamePlayAndRequirement(props) {
const {
detail: { skill_level_min, skill_level_max, play_type, game_type },
} = props;
const requirements = [
{
title: "NTRP水平要求",
desc: genNTRPRequirementText(skill_level_min, skill_level_max),
},
{
title: "活动玩法",
desc: play_type || "-",
},
{
title: "人员构成",
desc: game_type || "-",
},
];
return (
<View className="detail-page-content-gameplay-requirements">
{/* title */}
<View className="gameplay-requirements-title">
<Text></Text>
</View>
{/* requirements */}
<View className="gameplay-requirements">
{requirements.map((item, index) => (
<View key={index} className="gameplay-requirements-item">
<Text className="gameplay-requirements-item-title">
{item.title}
</Text>
<Text className="gameplay-requirements-item-desc">{item.desc}</Text>
</View>
))}
</View>
</View>
);
}
// 参与者
function Participants(props) {
const { detail = {}, handleJoinGame } = props;
const participants = detail.participants || [];
const {
participant_count,
max_participants,
user_action_status = {},
} = detail;
const { can_join, can_pay, can_substitute, is_substituting, waiting_start } =
user_action_status;
const showApplicationEntry =
[can_pay, can_substitute, is_substituting, waiting_start].every(
(item) => !item,
) && can_join;
const leftCount = max_participants - participant_count;
const organizer_id = Number(detail.publisher_id);
return (
<View className="detail-page-content-participants">
<View className="participants-title">
<Text></Text>
<Text>·</Text>
<Text>{leftCount > 0 ? `剩余空位 ${leftCount}` : "已满员"}</Text>
</View>
{participant_count > 0 || showApplicationEntry ? (
<View className="participants-list">
{/* application */}
{showApplicationEntry && (
<View
className="participants-list-application"
onClick={() => {
handleJoinGame();
// Taro.showToast({ title: "To be continued", icon: "none" });
}}
>
<Image
className="participants-list-application-icon"
src={img.ICON_DETAIL_APPLICATION_ADD}
/>
<Text className="participants-list-application-text">
</Text>
</View>
)}
{/* participants list */}
<ScrollView className="participants-list-scroll" scrollX>
<View
className="participants-list-scroll-content"
style={{
width: `${participants.length * 103 + (participants.length - 1) * 8}px`,
}}
>
{participants.map((participant) => {
const {
user: {
avatar_url,
nickname,
level,
id: participant_user_id,
},
} = participant;
const role =
participant_user_id === organizer_id ? "组织者" : "参与者";
return (
<View key={participant.id} className="participants-list-item">
<Avatar
className="participants-list-item-avatar"
src={avatar_url}
/>
<Text className="participants-list-item-name">
{nickname || "未知"}
</Text>
<Text className="participants-list-item-level">
{level || "未知"}
</Text>
<Text className="participants-list-item-role">{role}</Text>
</View>
);
})}
</View>
</ScrollView>
</View>
) : (
""
)}
</View>
);
}
function SupplementalNotes(props) {
const {
detail: { description, description_tag = [] },
} = props;
return (
<View className="detail-page-content-supplemental-notes">
<View className="supplemental-notes-title">
<Text></Text>
</View>
<View className="supplemental-notes-content">
{/* supplemental notes tags */}
<View className="supplemental-notes-content-tags">
{insertDotInTags(description_tag).map((tag, index) => (
<View key={index} className="supplemental-notes-content-tags-tag">
<Text>{tag}</Text>
</View>
))}
</View>
{/* supplemental notes content */}
<View className="supplemental-notes-content-text">
<Text>{description}</Text>
</View>
</View>
</View>
);
}
function genRecommendGames(games, location, avatar) {
return games.map((item) => {
const {
id,
title,
start_time,
end_time,
court_type,
location_name,
current_players,
max_players,
latitude,
longitude,
skill_level_max,
skill_level_min,
play_type,
} = item;
const [c_latitude, c_longitude] = location;
const distance =
calculateDistance(c_latitude, c_longitude, latitude, longitude) / 1000;
const startTime = dayjs(start_time);
const endTime = dayjs(end_time);
return {
id,
title,
time: startTime.format("YYYY-MM-DD HH:MM"),
timeLength: endTime.diff(startTime, "hour"),
venue: location_name,
venueType: court_type,
distance: `${distance.toFixed(2)}km`,
avatar,
applications: max_players,
checkedApplications: current_players,
levelRequirements: `NTRP ${genNTRPRequirementText(skill_level_min, skill_level_max)}`,
playType: play_type,
};
});
}
function OrganizerInfo(props) {
const {
userInfo,
currentLocation: location,
onUpdateUserInfo = () => {},
} = props;
const {
id,
nickname,
avatar_url,
is_following,
ntrp_level,
stats: { hosted_games_count } = {},
ongoing_games = [],
} = userInfo;
const myInfo = useUserInfo();
const { id: my_id } = myInfo as LoginService.UserInfoType;
const recommendGames = genRecommendGames(ongoing_games, location, avatar_url);
const toggleFollow = async (follow) => {
try {
if (follow) {
await LoginService.unFollowUser(id);
} else {
await LoginService.followUser(id);
}
onUpdateUserInfo();
Taro.showToast({
title: `${nickname} ${follow ? "已取消关注" : "已关注"}`,
icon: "success",
});
} catch (e) {
Taro.showToast({
title: `${nickname} ${follow ? "取消关注失败" : "关注失败"}`,
icon: "error",
});
}
};
return (
<View className="detail-page-content-organizer-recommend-games">
{/* orgnizer title */}
<View className="organizer-title">
<Text></Text>
</View>
{/* organizer avatar and name */}
<View className="organizer-avatar-name">
<Avatar className="organizer-avatar-name-avatar" src={avatar_url} />
<View className="organizer-avatar-name-message">
<Text className="organizer-avatar-name-message-name">{nickname}</Text>
<View className="organizer-avatar-name-message-stats">
<Text> {hosted_games_count} </Text>
<View className="organizer-avatar-name-message-stats-separator" />
<Text>NTRP {ntrp_level || "初学者"}</Text>
</View>
</View>
<View className="organizer-actions">
{my_id === id ? (
""
) : (
<View
className="organizer-actions-follow"
onClick={toggleFollow.bind(null, is_following)}
>
{is_following ? (
<Text className="organizer-actions-follow-text"></Text>
) : (
<>
<Image
className="organizer-actions-follow-icon"
src={img.ICON_DETAIL_APPLICATION_ADD}
/>
<Text className="organizer-actions-follow-text"></Text>
</>
)}
</View>
)}
<View className="organizer-actions-comment">
<Image
className="organizer-actions-comment-icon"
src={img.ICON_DETAIL_COMMENT}
/>
</View>
</View>
</View>
{/* recommend games by organizer */}
<View className="organizer-recommend-games">
<View className="organizer-recommend-games-title" onClick={() => {}}>
<Text>TA的更多活动</Text>
<Image
className="organizer-recommend-games-title-arrow"
src={img.ICON_DETAIL_ARROW_RIGHT}
/>
</View>
<ScrollView className="recommend-games-list" scrollX>
<View className="recommend-games-list-content">
{recommendGames.map((game, index) => (
<View key={index} className="recommend-games-list-item">
{/* game title */}
<View className="recommend-games-list-item-title">
<Text>{game.title}</Text>
<Image
className="recommend-games-list-item-title-arrow"
src={img.ICON_DETAIL_ARROW_RIGHT}
/>
</View>
{/* game time and range */}
<View className="recommend-games-list-item-time-range">
<Text>{game.time}</Text>
<Text>{game.timeLength}</Text>
</View>
{/* game location、vunue、distance */}
<View className="recommend-games-list-item-location-venue-distance">
<Text>{game.venue}</Text>
<Text>·</Text>
<Text>{game.venueType}</Text>
<Text>·</Text>
<Text>{game.distance}</Text>
</View>
{/* organizer avatar、applications、level requirements、play type */}
<View className="recommend-games-list-item-addon">
<Avatar
className="recommend-games-list-item-addon-avatar"
src={game.avatar}
/>
<View className="recommend-games-list-item-addon-message">
<View className="recommend-games-list-item-addon-message-applications">
<Text>
{game.checkedApplications}/{game.applications}
</Text>
</View>
<View className="recommend-games-list-item-addon-message-level-requirements">
<Text>{game.levelRequirements}</Text>
</View>
<View className="recommend-games-list-item-addon-message-play-type">
<Text>{game.playType}</Text>
</View>
</View>
</View>
</View>
))}
</View>
</ScrollView>
</View>
</View>
);
}
function Index() {
const [detail, setDetail] = useState<any>({});
const { params } = useRouter();
const [currentLocation, setCurrentLocation] = useState<[number, number]>([
0, 0,
]);
const { id, from } = params;
const [userInfo, setUserInfo] = useState({}); // 组织者的userInfo
const { fetchUserInfo } = useUserActions(); // 获取登录用户的userInfo
const sharePopupRef = useRef<any>(null);
useDidShow(async () => {
await updateLocation();
await fetchUserInfo();
// await fetchDetail();
});
const updateLocation = async () => {
try {
const { address, ...location } = await getCurrentLocation();
setCurrentLocation([location.latitude, location.longitude]);
// 使用 userStore 中的统一位置更新方法
// await updateUserInfo({ latitude: location.latitude, longitude: location.longitude })
await DetailService.updateLocation({
latitude: Number(location.latitude),
longitude: Number(location.longitude),
});
// 位置更新后,重新获取详情页数据(因为距离等信息可能发生变化)
await fetchDetail();
} catch (error) {
console.error("用户位置更新失败", error);
}
};
const fetchDetail = async () => {
if (!id) return;
const res = await DetailService.getDetail(Number(id));
if (res.code === 0) {
setDetail(res.data);
fetchUserInfoById(res.data.publisher_id);
}
};
const onUpdateUserInfo = () => {
fetchUserInfoById(detail.publisher_id);
};
async function fetchUserInfoById(user_id) {
const userDetailInfo = await LoginService.getUserInfoById(Number(user_id));
if (userDetailInfo.code === 0) {
// console.log(userDetailInfo.data);
setUserInfo(userDetailInfo.data);
}
}
function handleShare() {
sharePopupRef.current.show();
}
const handleJoinGame = () => {
Taro.navigateTo({
url: `/mod_user/orderDetail/index?gameId=${id}`,
});
};
function handleBack() {
const pages = Taro.getCurrentPages();
if (pages.length <= 1) {
Taro.redirectTo({
url: "/pages/list/index",
});
} else {
Taro.navigateBack();
}
}
console.log("detail", detail);
const backgroundImage = detail?.image_list?.[0]
? { backgroundImage: `url(${detail?.image_list?.[0]})` }
: {};
return (
<View className="detail-page">
{/* custom navbar */}
<view className="custom-navbar">
<View className="detail-navigator">
<View className="detail-navigator-back" onClick={handleBack}>
<Image
className="detail-navigator-back-icon"
src={img.ICON_ARROW_LEFT}
/>
</View>
<View className="detail-navigator-icon">
<Image
className="detail-navigator-logo-icon"
src={img.ICON_LOGO_GO}
/>
</View>
</View>
</view>
<View className="detail-page-bg" style={backgroundImage} />
{/* swiper */}
<Coursel detail={detail} />
{/* content */}
<View className="detail-page-content">
{/* avatar and tags */}
<GameTags detail={detail} />
{/* title */}
<View className="detail-page-content-title">
<Text className="detail-page-content-title-text">{detail.title}</Text>
</View>
{/* Date and Place and weather */}
<GameInfo detail={detail} currentLocation={currentLocation} />
{/* detail */}
<VenueInfo detail={detail} />
{/* gameplay requirements */}
<GamePlayAndRequirement detail={detail} />
{/* participants */}
<Participants detail={detail} handleJoinGame={handleJoinGame} />
{/* supplemental notes */}
<SupplementalNotes detail={detail} />
{/* organizer and recommend games by organizer */}
<OrganizerInfo
detail={detail}
userInfo={userInfo}
currentLocation={currentLocation}
onUpdateUserInfo={onUpdateUserInfo}
/>
{/* sticky bottom action bar */}
<StickyButton
handleShare={handleShare}
handleJoinGame={handleJoinGame}
detail={detail}
/>
{/* share popup */}
<SharePopup
ref={sharePopupRef}
id={id as string}
from={from as string}
/>
</View>
</View>
);
}
export default withAuth(Index);