Card.tsx 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. "use client";
  2. import { Category, GameListRep, GameRequest, toggleFavorite } from "@/api/home";
  3. import { userInfoApi } from "@/api/login";
  4. import useGame from "@/hooks/useGame";
  5. import { useRouter } from "@/i18n/routing";
  6. import { useWalletStore } from "@/stores/useWalletStore";
  7. import { getToken } from "@/utils/Cookies";
  8. import { Button, Image, Popup, Toast } from "antd-mobile";
  9. import clsx from "clsx";
  10. import { useTranslations } from "next-intl";
  11. import { FC, PropsWithChildren, ReactNode, useEffect, useRef, useState } from "react";
  12. import { shallow } from "zustand/shallow";
  13. import TipsModal, { ModalProps } from "../TipsModal";
  14. import styles from "./style.module.scss";
  15. export interface CardProps {
  16. item?: GameListRep;
  17. render?: (value: GameListRep) => ReactNode;
  18. groupType?: Category["bet_type"];
  19. isShowOnline?: boolean;
  20. isShowFavorite?: boolean;
  21. className?: string;
  22. }
  23. const Card: FC<PropsWithChildren<CardProps>> = (props) => {
  24. const { render, item, groupType, className } = props;
  25. const { getGameUrl, getCoinType } = useGame();
  26. const t = useTranslations("Game");
  27. const brandRef = useRef<GameListRep | null>(null);
  28. const [isFavorite, setIsFavorite] = useState(item?.is_favorite === 1 || false);
  29. const wallet = useWalletStore((state) => {
  30. return {
  31. score: state.wallet?.score,
  32. point: state.wallet?.point,
  33. free_score: state.wallet?.free_score,
  34. lose_score: state.wallet?.lose_score,
  35. };
  36. }, shallow);
  37. // 判断是否有未结算的对局
  38. const gameModelRef = useRef<ModalProps>(null);
  39. const gameRef = useRef<(GameListRep & { mode: GameRequest["mode"] }) | null>(null);
  40. const [visible, setVisible] = useState(false);
  41. const element = useRef<HTMLElement | null>(null);
  42. const router = useRouter();
  43. const token = getToken();
  44. const handler = (game: GameListRep) => {
  45. setVisible(true);
  46. brandRef.current = game;
  47. };
  48. useEffect(() => {
  49. element.current = document.getElementById("app");
  50. }, []);
  51. const playGameHandler = async (game: GameListRep) => {
  52. const type = getCoinType(game, groupType!);
  53. if (!token) {
  54. router.push("/login?redirect=/");
  55. return;
  56. }
  57. // 现金游戏
  58. if (type === 1 && Number(wallet.score) + wallet.point <= 0) {
  59. router.push("/deposit");
  60. return;
  61. }
  62. // 免费游戏
  63. if (type === 2 && Number(wallet.free_score) <= 0) {
  64. // router.push("/deposit");
  65. Toast.show({
  66. icon: "fail",
  67. content: "No free coins",
  68. maskClickable: false,
  69. });
  70. return;
  71. }
  72. // 重玩游戏
  73. if (type === 3 && Number(wallet.lose_score) <= 0) {
  74. Toast.show({
  75. icon: "fail",
  76. content: "No replay coins",
  77. maskClickable: false,
  78. });
  79. return;
  80. }
  81. let params: any = {
  82. id: game.id + "",
  83. mode: type!,
  84. };
  85. // 判断是否有未结算的游戏
  86. const { data }: any = await userInfoApi();
  87. const play_list = data?.play_list.map((item: any) => {
  88. return {
  89. ...item,
  90. mode: 1,
  91. };
  92. });
  93. const free_game_list = data?.free_game_list.map((item: any) => {
  94. return {
  95. ...item,
  96. mode: 2,
  97. };
  98. });
  99. const lose_game_list = data?.lose_game_list.map((item: any) => {
  100. return {
  101. ...item,
  102. mode: 3,
  103. };
  104. });
  105. let gameList = [...free_game_list, ...lose_game_list];
  106. if (type === 2) {
  107. gameList = [...play_list, ...lose_game_list];
  108. }
  109. if (type === 3) {
  110. gameList = [...play_list, ...free_game_list];
  111. }
  112. let unfinishedGame = gameList.find((item: { id: number }) => item?.id === game.id);
  113. if (unfinishedGame) {
  114. gameRef.current = unfinishedGame;
  115. setVisible(false);
  116. gameModelRef.current?.onOpen();
  117. return;
  118. }
  119. getGameUrl(brandRef.current!, params);
  120. };
  121. const goGame = () => {
  122. getGameUrl(gameRef.current!, {
  123. id: gameRef.current?.id + "",
  124. mode: gameRef.current?.mode!,
  125. });
  126. };
  127. const demoPlayGameHandler = (game: GameListRep) => {
  128. const params = {
  129. id: game.id + "",
  130. demo: game.demo,
  131. };
  132. getGameUrl(game, params);
  133. };
  134. const doFavorite = async (evt: React.MouseEvent) => {
  135. evt.stopPropagation();
  136. if (!getToken) {
  137. router.push("/login");
  138. }
  139. if (!item?.id) return;
  140. const params = {
  141. game_id: item?.id,
  142. };
  143. let res = null;
  144. res = await toggleFavorite(params);
  145. if (res.code === 200) {
  146. setIsFavorite(!isFavorite);
  147. // Toast.show({
  148. // icon: "success",
  149. // content: isFavorite ? "Cancelar favoritos com sucesso" : "Sucesso na coleção",
  150. // maskClickable: false,
  151. // });
  152. }
  153. };
  154. return (
  155. <>
  156. {render ? (
  157. render(item!)
  158. ) : (
  159. <div
  160. className={clsx(styles.cardWrap, className, "overflow-hidden")}
  161. onClick={() => handler(item!)}
  162. >
  163. <Image
  164. lazy={true}
  165. src={item?.game_icon}
  166. alt={item?.game_name_cn}
  167. width={"100%"}
  168. height={"1.54rem"}
  169. className={"h-[100%] w-[100%]"}
  170. />
  171. {props.isShowOnline && item?.online_user && (
  172. <div className={styles.cardOnline}>{item?.online_user} On-Line</div>
  173. )}
  174. {props.isShowFavorite && (
  175. <div
  176. className={clsx(styles.favorite, { [styles.active]: isFavorite })}
  177. onClick={doFavorite}
  178. >
  179. {isFavorite && (
  180. <i className="iconfont icon-ertong21 text-[#f6cf1e]"></i>
  181. )}
  182. {!isFavorite && <i className="iconfont icon-ertong"></i>}
  183. </div>
  184. )}
  185. </div>
  186. )}
  187. <Popup
  188. visible={visible}
  189. onMaskClick={() => {
  190. setVisible(false);
  191. }}
  192. onClose={() => {
  193. setVisible(false);
  194. }}
  195. style={{ "--adm-color-weak": "#fff" } as any}
  196. showCloseButton={true}
  197. getContainer={() => document.querySelector("#app")!}
  198. bodyStyle={{
  199. background: "#1f2830",
  200. // borderRadius: ".1rem .1rem 0 0",
  201. // border: "1px solid #e53fff",
  202. // boxShadow: "0rem -.06rem 20px 0.0rem #e53fff inset",
  203. padding: ".06rem .02rem",
  204. }}
  205. >
  206. <div className={"w-1/1 flex w-[4.02rem] flex-1 px-spacing-x py-spacing-y"}>
  207. <div className={styles.cardWrap} style={{ width: "1.1rem" }}>
  208. <Image
  209. src={item?.game_icon}
  210. alt={item?.game_name + "-" + item?.category_name}
  211. className={"h-[100%] w-[100%]"}
  212. height={"1.54rem"}
  213. />
  214. </div>
  215. <div className={styles.cardWrapGmeInfo}>
  216. <p className={"h-[0.6rem] text-[.18rem]"}>{item?.game_name}</p>
  217. <div className={"flex w-[2.2rem] justify-start"}>
  218. {/* 只是PG游戏展示demo试玩按钮 */}
  219. {/*{(item?.category_name === "Pragmaticplay" ||*/}
  220. {/* item?.category_name === "PP") && (*/}
  221. {/* <div*/}
  222. {/* onClick={() => demoPlayGameHandler({ ...item!, demo: 1 })}*/}
  223. {/* className={`flex h-[0.46rem] w-[1rem] items-center justify-center rounded-[.24rem] bg-[#11de68] text-[0.15rem] font-bold`}*/}
  224. {/* >*/}
  225. {/* {t("demo")}*/}
  226. {/* </div>*/}
  227. {/*)}*/}
  228. <div
  229. onClick={() => playGameHandler(item!)}
  230. // style={{
  231. // "--background-color": "#009d80",
  232. // "--border-color": "#009d80",
  233. // }}
  234. className={`flex h-[0.46rem] w-[1rem] items-center justify-center rounded-[.24rem] bg-[#11de68] text-[0.15rem] font-bold`}
  235. >
  236. {t("join")}
  237. </div>
  238. </div>
  239. </div>
  240. </div>
  241. </Popup>
  242. <TipsModal title={"Tips"} ref={gameModelRef} getContainer={element.current}>
  243. <p className={"text-left text-[0.12rem] font-medium text-[#666]"}>
  244. Há jogos inconclusos continuar o jogo
  245. </p>
  246. <div className={"mt-[0.0694rem] flex justify-center"}>
  247. <Button
  248. color={"primary"}
  249. className={"mx-auto"}
  250. style={{
  251. "--background-color": "var(--primary-color)",
  252. "--border-color": "var(--primary-color)",
  253. }}
  254. onClick={goGame}
  255. >
  256. para jogos
  257. </Button>
  258. </div>
  259. </TipsModal>
  260. </>
  261. );
  262. };
  263. export default Card;