tiefen_space_h5/components/PostItem/index.js

458 lines
16 KiB
JavaScript
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.

"use client";
import React, { useEffect, useState, useMemo, useCallback } from "react";
import Photos from "../Photos";
import { useRouter } from "next/navigation";
import PaySpacePost from "../PaySpacePost";
import { Image, Popover, Divider, Toast } from "antd-mobile";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faAngleRight } from "@fortawesome/free-solid-svg-icons";
import { handleFollow, thumbsUp, handleBlock } from "@/api/public";
import { get } from "@/utils/storeInfo";
import { Inter } from "next/font/google";
import requireAPI from "@/utils/requireAPI";
const inter = Inter({ subsets: ["latin"] });
export default function PostItem({
type,
follow,
date = new Date(),
data = {},
}) {
const router = useRouter();
const [isOpenText, setIsOpenText] = useState(false);
const [popoverVisible, setPopoverVisible] = useState(false);
const [isFollow, setIsFollow] = useState(data.is_followed);
const [isThumbsUp, setIsThumbsUp] = useState(
data?.is_thumbed_up || data?.is_zone_moment_thumbed_up
);
const [account, setAccount] = useState(
data?.is_thumbed_up || data?.is_zone_moment_thumbed_up
);
//判断是否是发帖人
const [isCreator, setIsCreator] = useState(false);
useEffect(() => {
const currentAccount = get("account");
setAccount(currentAccount);
if (currentAccount?.mid === data.mid) setIsCreator(true);
return () => {
router.prefetch("/profile/" + data.mid);
};
}, []);
const getDays = useMemo(() => {
const today = new Date();
const days = Math.floor((today - data.ct) / (1000 * 60 * 60 * 24));
return days;
}, []);
function findLinksInText(text) {
// 定义一个正则表达式来匹配URL
// 注意这个正则表达式可能无法匹配所有可能的URL但可以匹配大部分常见的格式
var urlPattern = /https?:\/\/[^\s\/$.?#].[^\s]*/g;
// 使用正则表达式的exec或match方法查找匹配项
// exec在全局搜索中需要循环调用而match在全局模式下直接返回所有匹配项
var matches = text?.match(urlPattern);
// // 如果没有找到匹配项,返回空数组
// if (!matches) {
// return text;
// }
if (matches) {
matches?.forEach((el) => {
// console.log("index", text.indexOf(el));
text = text.replace(
el,
`<a className="text-btn" href="${el}" target="_blank">#网页链接</a>`
);
});
// console.log("matches", matches);
// console.log("text", text);
}
// 返回找到的链接数组
return text;
}
const formatZoneUpdateTime = useCallback((time) => {
if (time === 0) return "今日";
if (time === 1) return "昨日";
return `${time}日前`;
}, []);
const handleDelete = async () => {
try {
const _data = await requireAPI("POST", "/api/zone_moment/delete", {
body: {
id: data?.id,
},
});
if (_data.ret === -1) {
Toast.show({
icon: "fail",
content: _data.msg,
position: "top",
});
return;
}
Toast.show({
icon: "success",
content: "删除成功,请刷新页面",
position: "top",
});
return;
} catch (error) {
console.error(error);
} finally {
setPopoverVisible(false);
}
};
//置顶
const handleTop = async () => {
try {
const body = {
zone_moment_ids: [data.id],
op_type: data.is_headed ? 0 : 1,
};
const _data = await requireAPI("POST", "/api/zone_moment/head", {
body,
});
if (_data.ret === -1) {
Toast.show({
icon: "fail",
content: _data.msg,
position: "top",
});
return;
}
Toast.show({
icon: "success",
content: "操作成功,请刷新页面查看",
position: "top",
});
return;
} catch (error) {
console.error(error);
} finally {
setPopoverVisible(false);
}
};
return (
<div>
{type == "space" && data?.is_headed === 1 && (
<Image
src={process.env.NEXT_PUBLIC_WEB_ASSETS_URL + "/images/top_post.png"}
width={76}
className="mb-2"
/>
)}
<div className="flex">
<div
className="h-max"
onClick={() => {
router.push("/profile/" + data.mid);
}}
>
<Image
className="flex-none w-8 h-8 rounded-full mr-2"
fit="cover"
width={"2rem"}
height={"2rem"}
src={data.streamer_ext?.avatar.images[0].urls[0]}
alt=""
/>
</div>
<div className="flex-1">
<div className="flex justify-between items-center ">
<span className="text-md">{data.streamer_ext?.name}</span>
{type == "post" && (
<span
onClick={() => handleFollow(isFollow, data?.mid, setIsFollow)}
className="rounded-full bg-[#FFFFFF1A] px-2 py-1 text-xs text-white font-medium"
>
{isFollow ? "已关注" : "关注"}
</span>
)}
</div>
{(data?.status === 0 || data?.status === 1) && (
<div className="flex flex-col items-start mt-2">
<div className="py-1 px-2 rounded bg-[#3B69B8]">
<span className="text-sm">审核中</span>
</div>
</div>
)}
{data?.status === 3 &&
(type == "space" ? (
<p
className="py-1 px-2 inline-block bg-[#F53030] rounded"
onClick={() => {
router.push(
`/space/editSpacePost?data=${encodeURIComponent(
JSON.stringify(data)
)}`
);
}}
>
<span className="text-sm">
审核未通过<span className="underline">重新编辑</span>
</span>
</p>
) : (
<p className="py-1 px-2 inline-block bg-[#F53030] rounded">
<span className="text-sm">
审核未通过请删除后重新提交{type}
</span>
</p>
))}
<div>
{!data?.is_zone_moment_unlocked ? (
<span
dangerouslySetInnerHTML={{
__html: findLinksInText(data.text),
}}
className={`mb-2 mt-2 whitespace-pre-wrap ${
!isOpenText ? "text-ellipsis-7" : ""
} ${inter.className}`}
// style={{
// WebkitLineClamp: data?.text_visible_range < 999?data?.text_visible_range:7,
// }}
></span>
) : (
<div>
<span
className={`mb-2 mt-2 whitespace-pre-wrap ${
!isOpenText ? "text-ellipsis-7" : ""
} ${inter.className}`}
dangerouslySetInnerHTML={{
__html: findLinksInText(data.text),
}}
style={{
WebkitLineClamp:
data?.text_visible_range < 999
? data?.text_visible_range
: 7,
}}
></span>
</div>
)}
{!(
!data?.is_zone_moment_unlocked && data?.text_visible_range < 999
) &&
data.text?.length > 140 && (
<div
className="font-bold text-btn my-4 text-base"
onClick={() => setIsOpenText(!isOpenText)}
>
{isOpenText ? "收起" : "全文"}
</div>
)}
</div>
<div className="mr-8 rounded-md">
{data.media_component && (
<Photos
data={data}
media={data.media_component}
isUnlocked={data.is_zone_moment_unlocked}
mediaAmount={data.media_amount}
mediaVisibleRange={data.media_visible_range}
type={type}
isCreator={isCreator}
/>
)}
{type == "space" && !!data.c_type && (
<PaySpacePost
type={data.is_ironfan_visible ? "ironFan" : "superFan"}
price={data.price / 100}
status={data.is_ironfanship_unlocked}
is_ironfan_visible={data.is_ironfan_visible == 1}
ironfanship_price={data.ironfanship_price / 100}
is_zone_moment_unlocked={data.is_zone_moment_unlocked}
data={data}
isCreator={isCreator}
/>
)}
</div>
<div className="flex justify-between items-center mt-2">
{type == "post" ? (
<div
className="flex items-center"
onClick={() =>
router.push("/space/person_space_introduce/" + data.mid)
}
>
{data.streamer_ext.is_active_within_a_week ? (
<>
<Image
src={
process.env.NEXT_PUBLIC_WEB_ASSETS_URL +
"/icons/space_new_post.png"
}
width={18}
className="w-4 h-full mr-1"
placeholder=""
/>
<span className="mr-1 text-primary text-xs">
{/* {data.streamer_ext.days_elapsed_since_the_last_zones_update < 7 &&
`空间${
data.streamer_ext.days_elapsed_since_the_last_zones_update === 0
? "今日"
: "new" === 1
? "昨日"
: "new" === 2
? "前天"
: data.streamer_ext.days_elapsed_since_the_last_zones_update +
"天前"
}有更新`}
空间 */}
空间
{formatZoneUpdateTime(
data?.streamer_ext
?.days_elapsed_since_the_last_zones_update
)}
有更新
</span>
<FontAwesomeIcon
icon={faAngleRight}
style={{ maxWidth: "12px" }}
color="#FF669E"
size="sm"
/>
</>
) : (
data?.streamer_ext?.zones?.length !== 0 && (
<div className="text-[#FFFFFFB2] font-medium text-xs flex items-center">
<span className="mr-1">查看TA的空间</span>
<FontAwesomeIcon
icon={faAngleRight}
size="sm"
style={{ maxWidth: "12px" }}
/>
</div>
)
)}
</div>
) : (
<div className="text-[#ffffff88] text-xs">
<span className="mr-2">
{getDays < 3
? `${
getDays === 0 ? "今日" : "new" === 1 ? "昨日" : "前天"
}`
: date.getMonth() + 1 + "-" + date.getDate()}
</span>
<span>
{(date.getHours() > 9
? date.getHours()
: "0" + date.getHours()) +
":" +
(date.getMinutes() > 9
? date.getMinutes()
: "0" + date.getMinutes())}
</span>
</div>
)}
<div className="flex items-center">
<div
className="flex items-center mr-4 h-[32px]"
onClick={() =>
thumbsUp(data.id, isThumbsUp, setIsThumbsUp, type == "space")
}
>
<Image
src={
process.env.NEXT_PUBLIC_WEB_ASSETS_URL +
(isThumbsUp == 1
? "/icons/thumbup.png"
: "/icons/notthumbup.png")
}
width={32}
className="w-4 h-full"
placeholder=""
/>
<span
className={`text-xs ${
isThumbsUp == 1 ? "text-[#FF669E]" : "text-[#FFFFFF80]"
}`}
>
{isThumbsUp == 1 ? "已赞" : "点赞"}
</span>
</div>
<Popover
visible={popoverVisible}
// stopPropagation={["click", "touchstart"]}
destroyOnHide={true}
style={{ "--background": "#1E1C29" }}
content={
<ul>
{type == "space" && account?.mid == data?.mid ? (
<>
<li className="py-1 px-4" onClick={handleTop}>
{data.is_headed ? "取消置顶" : "置顶"}
</li>
<hr className="border-[#ffffff2b] my-1" />
<li
className="py-1 px-4"
onClick={() => {
router.push(
`/space/editSpacePost?data=${encodeURIComponent(
JSON.stringify(data)
)}`
);
}}
>
编辑
</li>
<hr className="border-[#ffffff2b] my-1" />
<li className="py-1 px-4" onClick={handleDelete}>
删除
</li>
</>
) : type == "post" && account?.mid == data?.mid ? (
<>
<li className="py-1 px-4" onClick={handleDelete}>
删除
</li>
</>
) : (
<>
<li
className="py-1 px-4"
onClick={() => {
router.push("/messageDetail");
}}
>
举报
</li>
<hr className="border-[#ffffff2b] my-1" />
<li
className="py-1 px-4"
onClick={async () => {
const subMid = account.mid;
const objMid = data.mid;
await handleBlock(subMid, objMid);
setPopoverVisible(false);
}}
>
拉黑
</li>
</>
)}
</ul>
}
trigger="click"
placement="left"
>
<span
className="mr-2"
onClick={() => setPopoverVisible(!popoverVisible)}
>
···
</span>
</Popover>
</div>
</div>
{/* <div className="rounded-full h-px bg-gray-200 mt-2"></div> */}
</div>
</div>
</div>
);
}