Skip to content

Commit

Permalink
[Feat] 배지 페이지 UI (#19)
Browse files Browse the repository at this point in the history
* feat: 홈 화면 Home 컴포넌트 추가

* feat: 홈 화면 운전하기 버튼 추가

* feat: 주행 중, 주행 후 화면 컴포넌트 추가

* feat: 주행 중 페이지 UI 구현

* feat: 주행 후 리포트 UI

* feat: 배지 페이지 Header

* feat: 배지 목록 UI

* feat: 배지 정보 바텀 시트 UI

* feat: 배지 목록 UI 수정

* feat: 배지 바텀시트 UI
  • Loading branch information
jwo0o0 authored Feb 19, 2024
1 parent ff7cb31 commit 26b7ad4
Show file tree
Hide file tree
Showing 8 changed files with 282 additions and 1 deletion.
Binary file added public/images/badge_1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/badge_1_complete.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
60 changes: 60 additions & 0 deletions src/components/Badge/BadgeContents/Badge.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import styled from "styled-components";
import { BadgeType } from "src/types/badge";

interface BadgeProps {
badgeData: BadgeType;
setOpen: React.Dispatch<React.SetStateAction<Boolean>>;
setCurrent: React.Dispatch<React.SetStateAction<BadgeType | undefined>>;
}
export const Badge = ({ badgeData, setOpen, setCurrent }: BadgeProps) => {
const handleClickBadge = () => {
setOpen(true);
setCurrent(badgeData);
};
return (
<BadgeContainer>
<BadgeImage done={badgeData.status} onClick={handleClickBadge}>
<img
src={`/images/badge_${badgeData.badgeId}${
badgeData.status === 1 ? "_complete" : ""
}.png`}
alt={badgeData.name}
/>
</BadgeImage>
<BadgeName>{badgeData.name}</BadgeName>
</BadgeContainer>
);
};

const BadgeContainer = styled.div`
display: flex;
flex-direction: column;
align-items: center;
width: 124px;
margin: 10px 0;
`;

const BadgeImage = styled.button<{ done: number }>`
width: 85px;
height: 85px;
border-radius: 50%;
border: none;
background-color: ${(props) => (props.done === 0 ? "#F6F8FA" : "#5F81FF")};
img {
width: 75px;
}
display: flex;
align-items: center;
justify-content: center;
`;

const BadgeName = styled.div`
font-weight: 600;
font-size: 14px;
color: ${({ theme }) => theme.colors.blue900};
margin: 12px 0;
`;
82 changes: 82 additions & 0 deletions src/components/Badge/BadgeContents/BottomSheet.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { BadgeType } from "src/types/badge";
import styled from "styled-components";

interface BottomSheetProps {
setOpen: React.Dispatch<React.SetStateAction<Boolean>>;
current: BadgeType | undefined;
}
export const BottomSheet = ({ setOpen, current }: BottomSheetProps) => {
const handleClickBottomSheet = () => {
setOpen(false);
};
return (
<BottomSheetContainer onClick={handleClickBottomSheet}>
<BottomContent onClick={(event) => event.stopPropagation()}>
<img
src={`/images/badge_${current?.badgeId}_complete.png`}
alt="배지"
/>
<BadgeName>{current?.name}</BadgeName>
<BadgeCaption>{current?.caption}</BadgeCaption>
</BottomContent>
</BottomSheetContainer>
);
};

const BottomSheetContainer = styled.div`
width: 100%;
max-width: 460px;
position: fixed;
top: 0;
bottom: 0;
background-color: rgba(87, 96, 106, 0.5);
border: 1px solid #eaeef2;
z-index: 500;
`;

const BottomContent = styled.div`
width: 100%;
max-width: 460px;
height: 200px;
background-color: white;
border-radius: 16px 16px 0 0;
opacity: 1;
position: absolute;
bottom: 0;
z-index: 600;
@keyframes fadeInUp {
0% {
transform: translate3d(0, 100%, 0);
}
to {
transform: translateZ(0);
}
}
animation: fadeInUp 0.5s;
img {
width: 110px;
height: 110px;
}
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
`;

const BadgeName = styled.div`
color: ${({ theme }) => theme.colors.blue900};
font-weight: 600;
font-size: 18px;
`;

const BadgeCaption = styled.div`
color: ${({ theme }) => theme.colors.gray6};
font-weight: 500;
font-size: 14px;
margin: 12px 0;
`;
85 changes: 85 additions & 0 deletions src/components/Badge/BadgeContents/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { useEffect, useState } from "react";
import styled from "styled-components";
import { BadgeType } from "src/types/badge";
import { Badge } from "./Badge";
import { BottomSheet } from "./BottomSheet";

const data = [
{
badgeId: 1,
status: 0,
name: "귀향길 운전왕",
caption: "시작이 반이다! 벌써 베스트 드라이버에 가까워지고 있어요.",
},
{
badgeId: 2,
status: 1,
name: "베스트 드라이버",
caption: "시작이 반이다! 벌써 베스트 드라이버에 가까워지고 있어요.",
},
{
badgeId: 3,
status: 0,
name: "피드백 만점",
caption: "시작이 반이다! 벌써 베스트 드라이버에 가까워지고 있어요.",
},
{
badgeId: 4,
status: 0,
name: "귀향길 운전왕",
caption: "시작이 반이다! 벌써 베스트 드라이버에 가까워지고 있어요.",
},
{
badgeId: 5,
status: 1,
name: "베스트 드라이버",
caption: "시작이 반이다! 벌써 베스트 드라이버에 가까워지고 있어요.",
},
];

export const BadgeContents = () => {
const [badges, setBadges] = useState<BadgeType[]>([]);
const [open, setOpen] = useState<Boolean>(false);
const [current, setCurrent] = useState<BadgeType>();

useEffect(() => {
setBadges(data);
}, []);

return (
<BadgeContentsContainer>
<Badges>
{badges.map((el) => {
return (
<Badge
key={el.badgeId}
badgeData={el}
setOpen={setOpen}
setCurrent={setCurrent}
/>
);
})}
</Badges>
{open ? <BottomSheet setOpen={setOpen} current={current} /> : null}
</BadgeContentsContainer>
);
};

const BadgeContentsContainer = styled.div`
width: 100%;
height: 100%;
margin-top: 106px;
background-color: white;
display: flex;
justify-content: center;
`;

const Badges = styled.div`
display: flex;
align-content: flex-start;
flex-wrap: wrap;
width: 372px;
padding-top: 20px;
`;
42 changes: 42 additions & 0 deletions src/components/Badge/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import styled from "styled-components";
import { PageHeader } from "@components/common/PageHeader";
import { BadgeContents } from "./BadgeContents";

export const Badge = () => {
return (
<BadgeContainer>
<PageHeader name="나의 배지" height="100px">
<SubHeader>
<div>김모비님이 지금까지 획득하신 배지입니다.</div>
<div>
<span>주행 피드백</span>을 통한 <span>안전 운전</span>으로 더 많은
배지를 모아보세요.
</div>
</SubHeader>
</PageHeader>
<BadgeContents></BadgeContents>
</BadgeContainer>
);
};

const BadgeContainer = styled.div`
position: relative;
height: 100%;
display: flex;
flex-direction: column;
`;

const SubHeader = styled.div`
width: 360px;
margin-top: 7px;
color: ${({ theme }) => theme.colors.gray6};
font-weight: 500;
font-size: 12px;
span {
color: ${({ theme }) => theme.colors.blue900};
}
div {
margin: 4px 0;
}
`;
3 changes: 2 additions & 1 deletion src/pages/Badge/index.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { Layout } from "@components/common/Layout";
import { Badge } from "@components/Badge";

export const BadgePage = () => {
return (
<Layout navbar>
<div>배지</div>
<Badge />
</Layout>
);
};
11 changes: 11 additions & 0 deletions src/types/badge.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* 배지 전체 조회
* /badge
*/

export interface BadgeType {
badgeId: number;
status: number;
name: string;
caption: string;
}

0 comments on commit 26b7ad4

Please sign in to comment.