Skip to content

Commit

Permalink
Refactor: Event2023FallLeaderboard
Browse files Browse the repository at this point in the history
  • Loading branch information
14KGun committed Sep 20, 2023
1 parent 365e4c1 commit 2fa4d81
Show file tree
Hide file tree
Showing 10 changed files with 137 additions and 130 deletions.
27 changes: 14 additions & 13 deletions src/components/Empty.tsx
Original file line number Diff line number Diff line change
@@ -1,40 +1,41 @@
import { ReactNode } from "react";
import { HTMLProps, ReactNode } from "react";

import theme from "tools/theme";

import NotInterestedIcon from "@material-ui/icons/NotInterested";

type ScreenType = "mobile" | "pc";

type EmptyProps = {
screen: ScreenType;
children: ReactNode;
marginBottom?: PixelValue;
};
type: "mobile" | "pc";
children?: ReactNode;
className?: string;
} & HTMLProps<HTMLDivElement>;

const Empty = ({ screen, children, marginBottom }: EmptyProps) => {
const styleCommon: CSS = {
const Empty = ({ type, children, className, ...divProps }: EmptyProps) => {
const styleCommon = {
display: "flex",
justifyContent: "center",
...theme.font14_bold,
color: theme.gray_text,
columnGap: "6px",
marginBottom: marginBottom,
};
const styleMobile: CSS = {
const styleMobile = {
...styleCommon,
padding: "24px 0",
borderRadius: "12px",
backgroundColor: theme.gray_background,
border: "0.25px solid " + theme.gray_line,
};
const stylePC: CSS = {
const stylePC = {
...styleCommon,
padding: "48px 0 26px",
};

return (
<div style={screen === "pc" ? stylePC : styleMobile}>
<div
css={type === "pc" ? stylePC : styleMobile}
className={className}
{...divProps}
>
<NotInterestedIcon style={{ fontSize: "16px" }} />
{children}
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/components/ModalPopup/Body/BodyReport.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ const ReportList = (props: BodyReportProps) => {
};
if (!props.selectedReportHistory?.length) {
return (
<Empty screen="mobile">
<Empty type="mobile">
{props.option === "Reporting"
? t("page_report.empty_reported")
: t("page_report.empty_received")}
Expand Down
18 changes: 6 additions & 12 deletions src/hooks/useTaxiAPI/useQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,10 @@ import useAxios from "./useAxios";
type Method = "get" | "post";

const wrapUseQuery =
<ResponseType = any>(method: Method) =>
(
url: string,
data?: any,
dep?: [any]
): [any, ResponseType | null, boolean] => {
(method: Method) =>
(url: string, data?: any, dep?: [any]): [any, any, boolean] => {
const axios = useAxios();
const [res, setRes] = useState<{ error: any; data: ResponseType | null }>({
const [res, setRes] = useState<{ error: any; data: any }>({
error: null,
data: null,
});
Expand All @@ -28,7 +24,7 @@ const wrapUseQuery =
data,
onSuccess: (res) => {
if (isUnmounted || currentReqID !== latestReqID.current) return;
setRes({ error: null, data: res as ResponseType });
setRes({ error: null, data: res });
setLoading(false);
},
onError: (e) => {
Expand All @@ -46,8 +42,6 @@ const wrapUseQuery =
};

export default {
get: <ResponseType = any>(url: string, data?: any, dep?: [any]) =>
wrapUseQuery<ResponseType>("get")(url, data, dep),
post: <ResponseType = any>(url: string, data?: any, dep?: [any]) =>
wrapUseQuery<ResponseType>("post")(url, data, dep),
get: wrapUseQuery("get"),
post: wrapUseQuery("post"),
};
192 changes: 109 additions & 83 deletions src/pages/Event/Event2023FallLeaderboard.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { useMemo } from "react";

import type { Leader } from "types/event2023fall";

import { useValueRecoilState } from "hooks/useFetchRecoilState";
import useQuery from "hooks/useTaxiAPI";

import AdaptiveDiv from "components/AdaptiveDiv";
import Empty from "components/Empty";
import Footer from "components/Footer";
import HeaderWithLeftNav from "components/Header/HeaderWithLeftNav";
import Title from "components/Title";
import ProfileImage from "components/User/ProfileImage";
Expand All @@ -16,53 +16,62 @@ import theme from "tools/theme";
import { ReactComponent as Ticket1Icon } from "static/events/2023fallTicket1.svg";
import { ReactComponent as Ticket2Icon } from "static/events/2023fallTicket2.svg";

const LeaderboardTopBar = () => {
return (
<div
const LeaderboardTopBar = () => (
<div
css={{
display: "flex",
alignItems: "center",
padding: "8px 12px",
gap: "8px",
...theme.font12,
color: theme.purple_disabled,
marginTop: "-10px",
}}
>
<span>순위</span>
<span css={{ marginLeft: "16px" }}>플레이어</span>
<Ticket1Icon
css={{
display: "flex",
alignItems: "center",
padding: "8px 12px",
gap: "8px",
...theme.font12,
color: theme.purple_disabled,
marginLeft: "auto",
width: "30px",
height: "27px",
marginTop: "-4px",
marginBottom: "-4px",
flexShrink: 0,
}}
>
<span>순위</span>
<span css={{ marginLeft: "16px" }}>플레이어</span>
<Ticket1Icon
css={{
marginLeft: "auto",
width: "30px",
height: "27px",
marginTop: "-4px",
marginBottom: "-4px",
flexShrink: 0,
}}
/>
<Ticket2Icon
css={{
width: "30px",
height: "27px",
marginTop: "-4px",
marginBottom: "-4px",
flexShrink: 0,
}}
/>
<span css={{ width: "56px" }}>상품 확률</span>
</div>
);
/>
<Ticket2Icon
css={{
width: "30px",
height: "27px",
marginTop: "-4px",
marginBottom: "-4px",
flexShrink: 0,
}}
/>
<span css={{ width: "56px" }}>상품 확률</span>
</div>
);

type LeaderboardElem = {
nickname: string;
profileImageUrl: string;
ticket1Amount: number;
ticket2Amount: number;
probability: number;
};

type LeaderboardItemProps = {
value: LeaderboardElem;
rank: number;
isMe?: boolean;
};

const LeaderboardItem = ({
index,
nickname,
profileImageUrl,
ticket1Amount,
ticket2Amount,
probability,
isMe,
}: Leader & { index: number; isMe: boolean }) => {
value,
rank,
isMe = false,
}: LeaderboardItemProps) => {
const styleContainer = (index: number) => {
switch (index) {
case 0:
Expand All @@ -71,23 +80,26 @@ const LeaderboardItem = ({
border: "0.5px solid #E4CD00",
background: "#FFEE5A",
boxShadow: "0px 1px 5px 0px #E4CD00",
...theme.font24,
...theme.font20,
fontSize: "24px",
};
case 1:
return {
color: "#96BCC6",
border: "0.5px solid #BBD4DA",
background: "#EEF6F8",
boxShadow: "0px 1px 5px 0px #BBD4DA",
...theme.font24,
...theme.font20,
fontSize: "24px",
};
case 2:
return {
color: "#CD6830",
border: "0.5px solid #DE8C5D",
background: "#FFC5A4",
boxShadow: "0px 1px 5px 0px #DE8C5D",
...theme.font24,
...theme.font20,
fontSize: "24px",
};
case -1:
return {
Expand Down Expand Up @@ -129,8 +141,11 @@ const LeaderboardItem = ({
} as CSS;

const realProbability = useMemo(
() => 1 - (1 - probability) ** (ticket1Amount * 1 + ticket2Amount * 5),
[probability, ticket1Amount, ticket2Amount]
() =>
1 -
(1 - value.probability) **
(value.ticket1Amount * 1 + value.ticket2Amount * 5),
[value]
);

return (
Expand All @@ -141,10 +156,10 @@ const LeaderboardItem = ({
padding: "8px 15px",
marginBottom: "8px",
gap: "8px",
...styleContainer(isMe ? -1 : index),
...styleContainer(isMe ? -1 : rank),
}}
>
{index + 1}
{rank + 1}
<div
css={{
width: "30px",
Expand All @@ -156,7 +171,7 @@ const LeaderboardItem = ({
marginLeft: "5px",
}}
>
<ProfileImage url={profileImageUrl} />
<ProfileImage url={value.profileImageUrl} />
</div>
{isMe && (
<div
Expand All @@ -182,15 +197,15 @@ const LeaderboardItem = ({
color: isMe ? theme.white : theme.black,
}}
>
{nickname}
{value.nickname}
</div>
<span css={{ marginLeft: "auto", ...styleTicketText }}>
{ticket1Amount || 0}
{value.ticket1Amount || 0}
</span>
<span css={{ ...styleTicketText }}>{ticket2Amount || 0}</span>
<span css={{ ...styleTicketText }}>{value.ticket2Amount || 0}</span>
<div
css={{
color: styleText(isMe ? -1 : index),
color: styleText(isMe ? -1 : rank),
...theme.font16_bold,
width: "56px",
flexShrink: 0,
Expand All @@ -208,15 +223,25 @@ const LeaderboardItem = ({
};

const Event2023FallLeaderboard = () => {
const [, leaderboardResponse] = useQuery.get(
const { leaderboard, rank, probability } = useQuery.get(
"/events/2023fall/public-notice/leaderboard"
);
)[1] || { leaderboard: [], rank: 0 };
const { ticket1Amount, ticket2Amount } =
useValueRecoilState("event2023FallInfo") || {};
const { nickname, profileImgUrl } = useValueRecoilState("loginInfo") || {};
const myLeaderboardInfo = useMemo<Nullable<LeaderboardElem>>(() => {
if (!nickname || !profileImgUrl || !probability) return null;
return {
nickname,
profileImageUrl: profileImgUrl,
ticket1Amount: ticket1Amount || 0,
ticket2Amount: ticket2Amount || 0,
probability,
};
}, [nickname, profileImgUrl, ticket1Amount, ticket2Amount, probability]);

return (
<AdaptiveDiv type="center">
<>
<HeaderWithLeftNav
value="leaderboard"
options={[
Expand All @@ -233,30 +258,31 @@ const Event2023FallLeaderboard = () => {
},
]}
/>
<Title icon="leaderboard" isHeader>
리더보드
</Title>
<LeaderboardTopBar />
{leaderboardResponse?.leaderboard.map((item: Leader, index: number) => (
<LeaderboardItem
key={index}
index={index}
isMe={index == leaderboardResponse?.rank - 1}
{...item}
/>
))}
{leaderboardResponse?.rank > 20 && (
<LeaderboardItem
index={leaderboardResponse?.rank - 1}
isMe={true}
nickname={nickname ?? ""}
profileImageUrl={profileImgUrl ?? ""}
ticket1Amount={ticket1Amount ?? 0}
ticket2Amount={ticket2Amount ?? 0}
probability={leaderboardResponse?.probability}
/>
)}
</AdaptiveDiv>
<AdaptiveDiv type="center">
<Title icon="leaderboard" isHeader>
리더보드
</Title>
{leaderboard.length > 0 ? (
<>
<LeaderboardTopBar />
{leaderboard.map((elem: LeaderboardElem, index: number) => (
<LeaderboardItem
key={index}
rank={index}
value={elem}
isMe={index === rank - 1}
/>
))}
{rank > 20 && myLeaderboardInfo && (
<LeaderboardItem rank={rank - 1} value={myLeaderboardInfo} isMe />
)}
</>
) : (
<Empty type="mobile">리더보드가 비어있습니다.</Empty>
)}
</AdaptiveDiv>
<Footer type="event-2023fall" />
</>
);
};

Expand Down
Loading

0 comments on commit 2fa4d81

Please sign in to comment.