Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEAT] 상세페이지 신청하기 섹션 구현 #52

Merged
merged 13 commits into from
May 22, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/components/ExperienceDetailPage/BubbleSection.tsx
AAminha marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const BubbleSection = () => {
return <div>여긴 버블버블</div>;
};
176 changes: 176 additions & 0 deletions src/components/ExperienceDetailPage/DetailSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
import { useState } from 'react';

import { styled } from 'styled-components';

import TestImage from '@/assets/test1.png';
import { PlainButton } from '@/components/common/Button/PlainButton';
import { PlainChip } from '@/components/common/Chip/PlainChip';
import { Modal } from '@/components/common/Modal/modal';

export const DetailSection = () => {
const [isModalOpen, setModalOpen] = useState(false);
const [participants, setParticipants] = useState(Dummy1.participants);
const [isButtonDisabled, setButtonDisabled] = useState(false);

const handleOpenModal = () => {
setModalOpen(true);
};

const handleCloseModal = () => {
setModalOpen(false);
};

const handleIncreaseParticipants = () => {
setParticipants((prevParticipants) => prevParticipants + 1);
setButtonDisabled(true);
setModalOpen(false);
Comment on lines +24 to +26
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이거 API 연동할 때 post 성공하면 실행되는 걸로 하면 될 것 같아요

};
AAminha marked this conversation as resolved.
Show resolved Hide resolved
return (
<StyledContainer>
<ImageContainer>
<img src={Dummy1.imageURL} alt="Detail" />
</ImageContainer>
<DetailContainer>
<TextContainer>
<PlainChip>{participants}명 참여 중!</PlainChip>
AAminha marked this conversation as resolved.
Show resolved Hide resolved
<TitleContainer>{Dummy1.title}</TitleContainer>
<SubTitleContainer>{Dummy1.subtitle}</SubTitleContainer>
</TextContainer>
<ProfileContainer>
<ProfileImageContainer>
<img src={Dummy1.profileImageURL} alt="profile" />
</ProfileImageContainer>
<ProfileTextContainer>
<ProfileTitleContainer>{Dummy1.profileTitle}</ProfileTitleContainer>
<ProfileSubTitleContainer>{Dummy1.profileSubtitle}</ProfileSubTitleContainer>
</ProfileTextContainer>
</ProfileContainer>
<PlainButton
variant="gray"
height="48px"
onClick={handleOpenModal}
disabled={isButtonDisabled}
>
신청하기
</PlainButton>
</DetailContainer>
<Modal
isOpen={isModalOpen}
onClose={handleCloseModal}
onConfirm={handleIncreaseParticipants}
/>
</StyledContainer>
);
};

const StyledContainer = styled.div`
width: 100%;
height: 100%;
justify-content: flex-start;
align-items: flex-start;
gap: 32px;
display: inline-flex;
`;

const ImageContainer = styled.div`
width: 597px;
height: 373px;
position: relative;
border-radius: 8px;
overflow: hidden;

img {
width: 100%;
height: 100%;
object-fit: cover;
border-radius: 8px;
}
`;

const DetailContainer = styled.div`
flex: 1 1 0;
align-self: stretch;
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
gap: 16px;
display: inline-flex;
`;

const TextContainer = styled.div`
align-self: stretch;
flex: 1 1 0;
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
gap: 10px;
display: flex;
`;

const TitleContainer = styled.div`
align-self: stretch;
color: ${({ theme }) => `${theme.color.gray700}`};
${({ theme }) => theme.font.desktop.title1};
`;

const SubTitleContainer = styled.div`
align-self: stretch;
color: ${({ theme }) => `${theme.color.gray500}`};
${({ theme }) => theme.font.desktop.body2m};
`;

const ProfileContainer = styled.div`
align-self: stretch;
padding: 16px;
background-color: ${({ theme }) => `${theme.color.white}`};
border-radius: 8px;
overflow: hidden;
border: 2px solid ${({ theme }) => `${theme.color.gray150}`};
justify-content: flex-start;
align-items: center;
gap: 16px;
display: inline-flex;
`;

const ProfileImageContainer = styled.div`
width: 56px;
height: 56px;
background: linear-gradient(0deg, #f4efff 0%, #f4efff 100%);
border-radius: 8px;
overflow: hidden;

img {
width: 100%;
height: 100%;
object-fit: cover;
}
`;

const ProfileTextContainer = styled.div`
flex-direction: column;
justify-content: center;
align-items: flex-start;
gap: 4px;
display: inline-flex;
`;

const ProfileTitleContainer = styled.div`
color: ${({ theme }) => `${theme.color.gray700}`};
${({ theme }) => theme.font.desktop.body1m};
`;

const ProfileSubTitleContainer = styled.div`
color: ${({ theme }) => `${theme.color.gray700}`};
${({ theme }) => theme.font.desktop.body2m};
`;

const Dummy1 = {
imageURL: TestImage,
profileImageURL: TestImage,
participants: 28,
title: '퍼스널 브랜딩, ‘나’를 기획, 디자인하기',
subtitle:
'대한민국은 국제평화의 유지에 노력하고 침략적 전쟁을 부인한다. 국민의 모든 자유와 권리는 국가안전보장·질서유지 또는 공공복리를 위하여 필요한 경우에 한하여 법률로써 제한할 수 있으며.대한민국은 국제평화의 유지에 노력하고 침략적 전쟁을 부인한다.',
profileTitle: '신민선',
profileSubtitle: '콘텐츠 마케터 | 퍼스널브랜딩 | 어쩌구',
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

더미 구성 괜찮은 것 같은데, 상세 소개 이미지랑, 이미지 키워드(방울방울)도 있다는 걸 생각하면 좋을 것 같아요. 그래서 더미를 여기에 두면 안되고, ExperienceDetailPage에서 여기로 props로 넘기는 방식을 선택하면 좋을 것 같습니다.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아 근데 profileSubtitle 저렇게 받기로 백엔드랑 협의 됐나요? 저번에 들었을 때는 다 쪼개서 받는다고 했었던 것 같아서요

Copy link
Collaborator Author

@mungjin01 mungjin01 May 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

더미데이터 위치 옮겨야 된다고 생각만 하고 고치지는 않았었네요.. 근데 profileSubtitle 리스트로 넘겨주기로 했는지 한번에 넘겨주기로 했는지 정확히 기억이 안 나서 api 구현된 거 보고 고칠 예정이였습니다..!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오호 일단 알겠습니다

46 changes: 46 additions & 0 deletions src/components/ExperienceDetailPage/ImageSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { styled } from 'styled-components';

export const ImageSection = () => {
return (
<StyledContainer>
<TitleContainer>프로그램 소개</TitleContainer>
<ImageBorderContainer>
<ImageContainer>기ㅣㅣㅣㅣㅣㅣㅣㅣㅣㅣㅣㅣㅣㅣㅣㅣㅣㅣㅣㅣㅣㅣ다란 이미지</ImageContainer>
</ImageBorderContainer>
</StyledContainer>
);
};

const StyledContainer = styled.div`
width: 100%;
height: 100%;
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
gap: 24px;
display: inline-flex;
`;

const TitleContainer = styled.div`
text-align: center;
color: ${({ theme }) => `${theme.color.gray900}`};
${({ theme }) => theme.font.desktop.title1};
`;

const ImageBorderContainer = styled.div`
align-self: stretch;
padding: 32px;
background-color: ${({ theme }) => `${theme.color.white}`};
border-radius: 8px;
overflow: hidden;
border: 2px solid ${({ theme }) => `${theme.color.gray150}`};
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
gap: 20px;
display: flex;
`;

const ImageContainer = styled.div`
align-self: stretch;
`;
90 changes: 90 additions & 0 deletions src/components/common/Modal/modal.tsx
AAminha marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import styled from 'styled-components';

import { PlainButton } from '@/components/common/Button/PlainButton';

interface ModalProps {
isOpen: boolean;
onClose: () => void;
onConfirm: () => void;
}
export const Modal = ({ isOpen, onClose, onConfirm }: ModalProps) => {
if (!isOpen) return null;

return (
<ModalOverlay>
<ModalContent>
<TitleContainer>금액 선택</TitleContainer>
<ContentContainer>
해당 프로그램을 <Highlight>신청</Highlight>하시겠습니까?
</ContentContainer>
<ButtonContainer>
<StyledButton height="48px" onClick={onClose}>
취소하기
</StyledButton>
<PlainButton variant="gray" height="48px" onClick={onConfirm}>
신청하기
</PlainButton>
</ButtonContainer>
</ModalContent>
</ModalOverlay>
);
};

const ModalOverlay = styled.div`
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(17.85, 17.85, 17.85, 0.36);
backdrop-filter: blur(10px);
display: flex;
justify-content: center;
align-items: center;
`;

const ModalContent = styled.div`
width: 618px;
height: 338px;
background: white;
padding: 24px;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.25);
border-radius: 16px;
overflow: hidden;
backdrop-filter: blur(8px);
flex-direction: column;
justify-content: space-between;
align-items: center;
display: inline-flex;
`;

const TitleContainer = styled.div`
align-self: stretch;
text-align: center;
color: ${({ theme }) => `${theme.color.gray800}`};
${({ theme }) => theme.font.desktop.body1b};
`;

const ContentContainer = styled.div`
color: ${({ theme }) => `${theme.color.gray700}`};
${({ theme }) => theme.font.desktop.title2};
`;

const ButtonContainer = styled.div`
align-self: stretch;
justify-content: flex-start;
gap: 8px;
display: inline-flex;
`;

const StyledButton = styled(PlainButton)`
background: ${({ theme }) => `${theme.color.gray200}`};
&:hover {
background: ${({ theme }) => `${theme.color.gray200}`};
}
color: inherit;
`;

const Highlight = styled.span`
color: ${({ theme }) => theme.color.primary500};
`;
27 changes: 27 additions & 0 deletions src/pages/ExperienceDetailPage.tsx
AAminha marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { styled } from 'styled-components';

import { BubbleSection } from '@/components/ExperienceDetailPage/BubbleSection';
import { DetailSection } from '@/components/ExperienceDetailPage/DetailSection';
import { ImageSection } from '@/components/ExperienceDetailPage/ImageSection';

export const ExperienceDetailPage = () => {
return (
<StyledContainer>
<DetailSection />
<BubbleSection />
<ImageSection />
</StyledContainer>
);
};

const StyledContainer = styled.div`
width: 100%;
height: 100%;
padding: 64px 56px;
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
gap: 72px;
display: inline-flex;
padding-top: 142px;
`;
Loading