Skip to content

Commit 531efe1

Browse files
authored
Merge pull request #43 from CodeitPart3/COMPONENT-31-HONG
[feat] PostCard 컴포넌트 생성
2 parents 26b3806 + cf8d6ed commit 531efe1

File tree

5 files changed

+132
-23
lines changed

5 files changed

+132
-23
lines changed

src/assets/icon/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import Active from "./active.svg?react";
22
import ArrowLeft from "./arrow-left.svg?react";
33
import ArrowRight from "./arrow-right.svg?react";
44
import ArrowUp from "./arrow-up.svg?react";
5+
import ArrowUpBold from "./arrow-up-bold.svg?react";
56
import Camera from "./camera.svg?react";
67
import Check from "./check.svg?react";
78
import Close from "./close.svg?react";
@@ -16,6 +17,7 @@ import Time from "./time.svg?react";
1617

1718
export {
1819
ArrowUp,
20+
ArrowUpBold,
1921
ArrowLeft,
2022
ArrowRight,
2123
Close,

src/components/Post/Post.tsx

Lines changed: 6 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,8 @@
11
import { cn } from "@/utils/cn";
22
import { Link } from "react-router-dom";
33
import { formatTimeRange, isPastDate } from "@/utils/datetime";
4-
import IconTime from "@/assets/icon/time.svg?react";
5-
import IconLocation from "@/assets/icon/location.svg?react";
6-
import IconArrow from "@/assets/icon/arrow-up.svg?react";
7-
import IconArrowBold from "@/assets/icon/arrow-up-bold.svg?react";
8-
9-
const getPayRateText = (
10-
hourlyPay: number,
11-
originalPay: number,
12-
): {
13-
rawRate: number;
14-
displayRate: number;
15-
rateText: string;
16-
} => {
17-
const rawRate = ((hourlyPay - originalPay) / originalPay) * 100;
18-
const displayRate = Math.min(Math.round(rawRate), 100);
19-
const rateText = `기존 시급보다 ${displayRate}%`;
20-
21-
return { rawRate, displayRate, rateText };
22-
};
4+
import { getPayRateText } from "@/utils/payRate";
5+
import { Location, Time, ArrowUp, ArrowUpBold } from "@/assets/icon";
236

247
interface PostProps {
258
name: string;
@@ -76,11 +59,11 @@ export default function Post({
7659
<div className="mt-3 flex flex-col gap-2 md:mt-5">
7760
<h3 className="text-base md:text-xl">{name}</h3>
7861
<p className="flex items-start gap-[6px] text-xs font-normal text-gray-50 md:text-[14px] md:leading-[22px]">
79-
<IconTime className="h-4 w-4 md:h-5 md:w-5" />
62+
<Time className="h-4 w-4 md:h-5 md:w-5" />
8063
{timeRange}
8164
</p>
8265
<p className="flex items-start gap-[6px] text-xs font-normal text-gray-50 md:text-[14px] md:leading-[22px]">
83-
<IconLocation className="h-4 w-4 md:h-5 md:w-5" />
66+
<Location className="h-4 w-4 md:h-5 md:w-5" />
8467
{address1}
8568
</p>
8669
</div>
@@ -102,8 +85,8 @@ export default function Post({
10285
)}
10386
>
10487
{rateText}
105-
<IconArrow className="hidden h-5 w-5 md:block" />
106-
<IconArrowBold className="h-4 w-4 md:hidden" />
88+
<ArrowUp className="hidden h-5 w-5 md:block" />
89+
<ArrowUpBold className="h-4 w-4 md:hidden" />
10790
</span>
10891
)}
10992
</div>

src/components/Post/PostCard.tsx

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import { cn } from "@/utils/cn";
2+
import { formatTimeRange } from "@/utils/datetime";
3+
import { getPayRateText } from "@/utils/payRate";
4+
import { Location, Time, ArrowUp } from "@/assets/icon";
5+
6+
interface PostCardProps {
7+
name: string;
8+
imageUrl: string;
9+
address1: string;
10+
description: string;
11+
originalHourlyPay?: number;
12+
hourlyPay?: number;
13+
startsAt?: string;
14+
workhour?: number;
15+
isShopInfo?: boolean;
16+
backgroundColor?: string;
17+
buttons?: React.ReactNode;
18+
}
19+
20+
export default function PostCard({
21+
name,
22+
imageUrl,
23+
address1,
24+
description,
25+
hourlyPay,
26+
originalHourlyPay,
27+
startsAt,
28+
workhour,
29+
isShopInfo = false,
30+
backgroundColor = "#ffffff",
31+
buttons = null,
32+
}: PostCardProps) {
33+
const { rateText } = getPayRateText(hourlyPay, originalHourlyPay);
34+
35+
const timeRange =
36+
startsAt && workhour !== undefined
37+
? formatTimeRange(startsAt, workhour)
38+
: "";
39+
40+
return (
41+
<article
42+
className={cn(
43+
"grid p-5 md:p-6 lg:grid-cols-[1fr_346px] lg:gap-[31px] rounded-2xl",
44+
backgroundColor,
45+
backgroundColor === "#ffffff" && "border border-gray-20 shadow-sm",
46+
)}
47+
>
48+
<div className="w-full overflow-hidden rounded-xl">
49+
<img
50+
src={imageUrl}
51+
alt={name}
52+
className="w-full h-[180px] object-cover md:h-[360px] lg:h-[308px]"
53+
/>
54+
</div>
55+
<div className="flex flex-col justify-between mt-3 h-[251px] md:mt-4 md:h-[252px] lg:h-[292px]">
56+
<div className="space-y-2 md:space-y-3">
57+
{!isShopInfo ? (
58+
<>
59+
<div className="flex flex-col gap-[2px]">
60+
<p className="text-primary body2-bold md:body1-bold">시급</p>
61+
<div className="flex items-center gap-2">
62+
<h2 className="text-[20px] font-bold md:text-[28px]">
63+
{hourlyPay?.toLocaleString()}
64+
</h2>
65+
<span className="inline-flex items-center gap-[2px] rounded-[20px] bg-primary px-3 py-1 text-[12px] font-normal leading-[16px] text-white md:body2-bold">
66+
{rateText}
67+
<ArrowUp className="w-4 h-4 md:w-5 md:h-5" />
68+
</span>
69+
</div>
70+
</div>
71+
<div className="flex items-center gap-[6px] text-gray-50 body2-regular md:body1-regular">
72+
<Time className="w-4 h-4 md:w-5 md:h-5" />
73+
{timeRange}
74+
</div>
75+
</>
76+
) : (
77+
<p className="text-primary body2-bold md:body1-bold">식당</p>
78+
)}
79+
{isShopInfo && <h2 className="text-[28px] font-bold">{name}</h2>}
80+
<div className="flex items-center gap-[6px] text-gray-50 body2-regular md:body1-regular">
81+
<Location className="w-4 h-4 md:w-5 md:h-5" />
82+
{address1}
83+
</div>
84+
<p className="text-black body2-regular md:body1-regular">
85+
{description}
86+
</p>
87+
</div>
88+
{buttons && <div className="flex gap-2 mt-3">{buttons}</div>}
89+
</div>
90+
</article>
91+
);
92+
}

src/styles/theme.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,9 @@
2323
--color-green-10: #d4f7d4;
2424
--color-green-20: #20a81e;
2525

26+
--color-violet: #5534da;
27+
28+
--color-primary: #ea3c12;
29+
2630
--color-kakao: #fee500;
2731
}

src/utils/payRate.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/**
2+
* 시급 인상률 계산 유틸리티
3+
* @param hourlyPay 현재 시급
4+
* @param originalPay 기존 시급
5+
* @returns { rawRate, displayRate, rateText }
6+
*/
7+
export const getPayRateText = (
8+
hourlyPay?: number,
9+
originalPay?: number,
10+
): {
11+
rawRate: number;
12+
displayRate: number;
13+
rateText: string;
14+
} => {
15+
if (hourlyPay === undefined || originalPay === undefined) {
16+
return {
17+
rawRate: 0,
18+
displayRate: 0,
19+
rateText: "",
20+
};
21+
}
22+
23+
const rawRate = ((hourlyPay - originalPay) / originalPay) * 100;
24+
const displayRate = Math.min(Math.round(rawRate), 100);
25+
const rateText = `기존 시급보다 ${displayRate}%`;
26+
27+
return { rawRate, displayRate, rateText };
28+
};

0 commit comments

Comments
 (0)