Skip to content

Commit

Permalink
feat: create RowButtonBlock components (#120)
Browse files Browse the repository at this point in the history
  • Loading branch information
SeungJL authored May 7, 2024
2 parents cb29c64 + 120b16f commit 9aba4f0
Show file tree
Hide file tree
Showing 6 changed files with 317 additions and 2 deletions.
30 changes: 30 additions & 0 deletions components/atoms/blocks/RowButtonBlock.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import Link, { LinkProps } from "next/link";
import styled from "styled-components";

interface RowButtonBlockProps {
text: string;
url?: string;
func?: () => void;
}

function RowButtonBlock({ text, url, func }: RowButtonBlockProps) {
return (
<>{url ? <CustomLink href={url}>{text}</CustomLink> : <Button onClick={func}>{text}</Button>}</>
);
}

const Button = styled.button`
width: 100%;
padding: var(--gap-4) var(--gap-4);
text-align: start;
border-bottom: var(--border);
`;

const CustomLink = styled(Link)<LinkProps>`
display: block;
padding: var(--gap-4) var(--gap-4);
text-align: start;
border-bottom: var(--border);
`;

export default RowButtonBlock;
100 changes: 100 additions & 0 deletions design/attendance/AttendanceBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { Badge, Progress } from "@chakra-ui/react";
import { faQuestionCircle } from "@fortawesome/pro-light-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useState } from "react";
import styled from "styled-components";

import { BADGE_COLOR_MAPPINGS, BADGE_INFO } from "../../constants/serviceConstants/badgeConstants";
import { SCHEME_TO_COLOR } from "../../constants/styles";
import BadgeInfoModal from "../../modals/store/badgeInfoModal/BadgeInfoModal";

interface IAttendanceBar {
myScore: number;
hasQuestion?: boolean;
}

function AttendanceBar({ myScore, hasQuestion = true }: IAttendanceBar) {
const userBadge = { badge: "아메리카노", nextBadge: "망고" };

const [isBadgeModal, setIsBadgeModal] = useState(false);

const { badge, nextBadge } = userBadge;

const badgeColor = BADGE_COLOR_MAPPINGS[userBadge.badge];

const getBadgePoint = () => {
for (let i = 0; i < BADGE_INFO.length; i++) {
const badgeInfo = BADGE_INFO[i];
if (badgeInfo.badge === nextBadge) {
return {
nextBadgePoint: badgeInfo.minScore,
badgeGap: badgeInfo.minScore - BADGE_INFO[i - 1].minScore,
};
}
}
};
const { nextBadgePoint, badgeGap } = getBadgePoint() || {};

return (
<>
<Layout>
<Grade>
<div>
<Badge fontSize="14px" marginRight="var(--gap-2)" colorScheme={badgeColor}>
{badge}
</Badge>
<BadgeName color={SCHEME_TO_COLOR[badgeColor] || badgeColor}>{myScore}</BadgeName>
{hasQuestion && (
<IconWrapper onClick={() => setIsBadgeModal(true)}>
<FontAwesomeIcon icon={faQuestionCircle} size="sm" />
</IconWrapper>
)}
</div>
{nextBadge && (
<div>
<BadgeName color={BADGE_COLOR_MAPPINGS[nextBadge]}>{nextBadgePoint}</BadgeName>
<Badge fontSize="14px" colorScheme={BADGE_COLOR_MAPPINGS[nextBadge]} marginLeft="6px">
{nextBadge}
</Badge>
</div>
)}
</Grade>
<Progress
value={(1 - (nextBadgePoint - myScore) / badgeGap) * 100}
height="12px"
colorScheme="mintTheme"
hasStripe
/>
</Layout>

{isBadgeModal && <BadgeInfoModal setIsModal={setIsBadgeModal} />}
</>
);
}

const Layout = styled.div`
margin-bottom: var(--gap-3);
`;
const Grade = styled.div`
display: flex;
justify-content: space-between;
margin-bottom: var(--gap-3);
align-items: center;
> div {
display: flex;
align-items: center;
}
`;

const BadgeName = styled.span<{ color: string }>`
color: ${(props) => props.color};
font-weight: 600;
`;

const IconWrapper = styled.button`
color: var(--gray-2);
font-size: 14px;
margin-left: var(--gap-2);
`;

export default AttendanceBar;
159 changes: 159 additions & 0 deletions design/attendance/AttendanceModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
import dayjs from "dayjs";
import styled from "styled-components";

import Avatar from "../../components/atoms/Avatar";
import { PopOverIcon } from "../../components/atoms/Icons/PopOverIcon";
import { IFooterOptions, ModalLayout } from "../../modals/Modals";
import AttendanceBar from "./AttendanceBar";

function AttendanceModal({ type }: { type: 1 | 2 | 3 }) {
const today = dayjs();
const firstDayOfMonth = today.startOf("month");
const differenceInDays = today.diff(firstDayOfMonth, "day");
const weekNumber = Math.floor(differenceInDays / 7) + 1;

const footerOptions: IFooterOptions = {
main: {},
isFull: true,
};

return (
<>
<ModalLayout
title={`${dayjs().month() + 1}월 2주차 주간 체크`}
headerOptions={{}}
footerOptions={footerOptions}
setIsModal={() => {}}
>
<ScoreBarWrapper>
<AttendanceBar myScore={17} />
<span>임시 달성시 +10 포인트, 거북이 아바타 해금!</span>
</ScoreBarWrapper>
<ProfileWrapper>
<span>이승주 {type === 1 ? "(동아리원)" : "(수습멤버)"}</span>
<ImageWrapper>
<Avatar image="" size="md" />
</ImageWrapper>
</ProfileWrapper>
<Container>
<Info>
<Item>
<span>{weekNumber}주차 스터디 투표</span>
<span>2 회</span>
</Item>
<Item>
<span>{weekNumber}주차 스터디 출석</span>
<span>2 회</span>
</Item>
<Item>
<div style={{ display: "flex" }}>
<span>이번 달 스터디 점수</span>
<PopOverIcon
title="월간 스터디 점수"
text="최소 1점을 넘어야합니다. 출석을 기준으로 정규 스터디는 1회당 1점, 개인, FREE 스터디는 2회당 1점입니다."
/>
</div>
<span>40 점</span>
</Item>
<Item>
<span>다음 참여 정산일</span>
<span> {dayjs().add(1, "month").month() + 1}월 1일</span>
</Item>
<Item>
<span>보유 보증금</span>
<span>2000원</span>
</Item>
</Info>
</Container>
<Message>
{type === 2 ? (
<div>
🎉신규 가입을 환영해요🎉
<br />
앞으로 열심히 활동해봐요~!
</div>
) : type === 1 ? (
<div>
이번 달 스터디에 참여하지 않았어요.
<br /> {-dayjs().add(1, "month").date(1).diff(dayjs(), "day")}일 뒤에 경고를 받습니다.
</div>
) : (
<div>
🎉잘 하고 있어요🎉
<br />
이번주도 열심히 파이팅~!
</div>
)}
</Message>
</ModalLayout>
</>
);
}

const Message = styled.div`
padding: var(--gap-2) var(--gap-3);
color: var(--gray-2);
border-radius: var(--rounded);
background-color: var(--gray-8);
`;

const ProfileWrapper = styled.div`
padding: 8px 0;
display: flex;
align-items: center;
justify-content: space-between;
border-bottom: var(--border);
> span:first-child {
font-weight: 500;
font-size: 16px;
}
`;

const ScoreBarWrapper = styled.div`
padding: var(--gap-2) 0;
border-bottom: var(--border);
display: flex;
flex-direction: column;
> span {
font-size: 12px;
color: var(--gray-3);
margin-left: auto;
}
`;

const Container = styled.div`
padding: var(--gap-3) 0;
display: flex;
flex-direction: row;
height: 100%;
`;

const Info = styled.div`
width: 100%;
display: flex;
flex-direction: column;
`;

const ImageWrapper = styled.div`
margin-left: auto;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
> span {
display: inline-block;
margin-top: var(--gap-1);
}
`;

const Item = styled.div`
display: flex;
justify-content: space-between;
font-size: 14px;
padding: var(--gap-1) 0;
> span:last-child {
font-weight: 600;
}
`;

export default AttendanceModal;
2 changes: 1 addition & 1 deletion modals/pop-up/LastWeekAttendPopUp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ function LastWeekAttendPopUp({ setIsModal }: IModal) {
setIsModal={setIsModal}
>
<ScoreBarWrapper>
<PointScoreBar myScore={userInfo.score} hasQuestion={false} />
<PointScoreBar myScore={userInfo?.score} hasQuestion={false} />
{nextBadge ? (
<span>
{nextBadge} 달성시 +10 포인트, {nextAvatar[String(nextBadgePoint)]} 아바타 해금!
Expand Down
26 changes: 26 additions & 0 deletions stories/designs/attendanceModal.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type { Meta, StoryObj } from "@storybook/react";

import AttendanceModal from "../../design/attendance/AttendanceModal";

const meta = {
title: "DESIGNS/AttendanceModal",
component: AttendanceModal,
parameters: {},
tags: ["autodocs"],
argTypes: {},
args: {},
} satisfies Meta<typeof AttendanceModal>;

export default meta;
type Story = StoryObj<typeof meta>;

export const Primary: Story = {
args: {
type: 1,
},
};
export const Secondary: Story = {
args: {
type: 2,
},
};
2 changes: 1 addition & 1 deletion stories/molecules/Accordion.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Accordion from "../../components/molecules/Accordion";
import { ACCORDION_CONTENT_FEE } from "../../constants/contentsText/accordionContents";

const meta = {
title: "ATOMS/molecules/Accordion",
title: "MOLECULES/Accordion",
component: Accordion,
parameters: {},
tags: ["autodocs"],
Expand Down

0 comments on commit 9aba4f0

Please sign in to comment.