Skip to content

Commit ec39eb0

Browse files
committed
πŸ’„ design(#170): νšŒμ›κ°€μž… BottomSheet UI μΆ”κ°€
- νŽΈμ§€ 전솑 ν›„ νšŒμ›κ°€μž… μœ λ„ BottomSheet μΆ”κ°€ - OauthButton shape props μΆ”κ°€ 및 list 버전 λ²„νŠΌ μ œμž‘
1 parent 3cba0be commit ec39eb0

3 files changed

Lines changed: 146 additions & 43 deletions

File tree

β€Žsrc/app/send/complete/page.tsxβ€Ž

Lines changed: 102 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
'use client';
22

3+
import BottomSheet from '@/components/common/BottomSheet';
34
import Button from '@/components/common/Button';
5+
import OauthButton from '@/components/signup/OauthButton';
6+
import { OAUTH } from '@/constants/oauth';
47
import { SEND_COMPLETE_SUBTEXT } from '@/constants/send/message';
58
import { sendLetterState } from '@/recoil/letterStore';
69
import { theme } from '@/styles/theme';
10+
import { OAuthType } from '@/types/login';
711
import Image from 'next/image';
812
import { useRouter, useSearchParams } from 'next/navigation';
9-
import React, { useState } from 'react';
13+
import React, { useEffect, useState } from 'react';
1014
import { useRecoilValue } from 'recoil';
1115
import styled from 'styled-components';
1216

@@ -15,41 +19,84 @@ const SendCompletePage = () => {
1519
const searchParams = useSearchParams();
1620
const isGuest = searchParams.get('guest') === 'true';
1721
const { receiverName } = useRecoilValue(sendLetterState);
22+
const [isDisplayed, setIsDisplayed] = useState<boolean>(false);
23+
const [isBottomUp, setIsBottomUp] = useState<boolean>(false);
1824

1925
const subText = isGuest
2026
? SEND_COMPLETE_SUBTEXT.guest
2127
: SEND_COMPLETE_SUBTEXT.member;
2228

29+
const handleBottomUpChange = (state: boolean) => {
30+
setIsBottomUp(state);
31+
};
32+
33+
useEffect(() => {
34+
if (isBottomUp) {
35+
setIsDisplayed(true);
36+
} else {
37+
setTimeout(() => {
38+
setIsDisplayed(false);
39+
}, 490);
40+
}
41+
}, [isBottomUp]);
42+
2343
const handleComplete = () => {
2444
if (isGuest) {
45+
setIsBottomUp(true);
2546
} else {
2647
router.push('/planet');
2748
}
2849
};
2950

3051
return (
31-
<Layout>
32-
<Container>
33-
<Title>
34-
{receiverName}μ—κ²Œ
35-
<br />
36-
νŽΈμ§€λ₯Ό μ „λ‹¬ν–ˆμ–΄μš”!
37-
<Sub>{subText}</Sub>
38-
</Title>
39-
<ImageWrapper>
40-
<Image src="/assets/send/send_complete.png" fill alt="νŽΈμ§€" />
41-
</ImageWrapper>
42-
</Container>
43-
<ButtonWrapper>
44-
<Button
45-
buttonType="primary"
46-
text={
47-
isGuest ? 'νšŒμ›κ°€μž…ν•˜κ³  더 λ§Žμ€ κΈ°λŠ₯ μ΄μš©ν•˜κΈ°' : 'ν™ˆμœΌλ‘œ λŒμ•„κ°€κΈ°'
48-
}
49-
onClick={handleComplete}
50-
/>
51-
</ButtonWrapper>
52-
</Layout>
52+
<>
53+
<Layout>
54+
<Container>
55+
<Title>
56+
{receiverName}μ—κ²Œ
57+
<br />
58+
νŽΈμ§€λ₯Ό μ „λ‹¬ν–ˆμ–΄μš”!
59+
<Sub>{subText}</Sub>
60+
</Title>
61+
<ImageWrapper>
62+
<Image src="/assets/send/send_complete.png" fill alt="νŽΈμ§€" />
63+
</ImageWrapper>
64+
</Container>
65+
<ButtonWrapper>
66+
<Button
67+
buttonType="primary"
68+
text={
69+
isGuest ? 'νšŒμ›κ°€μž…ν•˜κ³  더 λ§Žμ€ κΈ°λŠ₯ μ΄μš©ν•˜κΈ°' : 'ν™ˆμœΌλ‘œ λŒμ•„κ°€κΈ°'
70+
}
71+
onClick={handleComplete}
72+
/>
73+
</ButtonWrapper>
74+
{isDisplayed && (
75+
<BottomSheet
76+
height={290}
77+
isOpen={isBottomUp}
78+
handleOpen={handleBottomUpChange}
79+
>
80+
<BottomWrapper>
81+
<SocialTitle>μ†Œμ…œλ‘œκ·ΈμΈ 선택</SocialTitle>
82+
<LoginList>
83+
{OAUTH.map((item) => (
84+
<OauthButton
85+
key={item.key}
86+
shape="list"
87+
loginType={item.key as OAuthType}
88+
bgColor={item.bgColor}
89+
icon={item.icon}
90+
size={item.miniSize}
91+
label={item.label}
92+
/>
93+
))}
94+
</LoginList>
95+
</BottomWrapper>
96+
</BottomSheet>
97+
)}
98+
</Layout>
99+
</>
53100
);
54101
};
55102

@@ -62,21 +109,23 @@ const Layout = styled.div`
62109
width: 100%;
63110
height: 100%;
64111
color: ${theme.colors.white};
65-
padding: 76px 24px 54px 24px;
66112
overflow-x: hidden;
67-
padding-bottom: 40px;
113+
overflow-y: hidden;
68114
background: ${(props) => props.theme.colors.bg};
69115
background-image: url('/assets/send/img_send_background.png');
70116
background-size: cover;
71117
background-position: bottom 80px center;
72118
background-repeat: no-repeat;
73119
position: relative;
120+
z-index: 0;
74121
`;
75122

76123
const Container = styled.div`
77124
width: 100%;
125+
height: 100%;
78126
display: flex;
79127
flex-direction: column;
128+
padding: 76px 24px 54px 24px;
80129
gap: 80px;
81130
`;
82131

@@ -105,16 +154,22 @@ const ImageWrapper = styled.div`
105154
align-items: center;
106155
justify-content: center;
107156
157+
@media (max-height: 680px) {
158+
width: 400px;
159+
height: 380px;
160+
top: 55%;
161+
}
162+
108163
@media (max-height: 580px) {
109164
width: 350px;
110165
height: 340px;
111-
top: 55%;
166+
top: 58%;
112167
}
113168
114169
@media (max-height: 550px) {
115170
width: 300px;
116171
height: 290px;
117-
top: 55%;
172+
top: 58%;
118173
}
119174
`;
120175

@@ -128,3 +183,23 @@ const ButtonWrapper = styled.div`
128183
bottom: 54px;
129184
left: 0;
130185
`;
186+
187+
const BottomWrapper = styled.div`
188+
display: flex;
189+
flex-direction: column;
190+
align-items: flex-start;
191+
gap: 26px;
192+
`;
193+
194+
const SocialTitle = styled.p`
195+
color: ${theme.colors.gray100};
196+
${theme.fonts.title02};
197+
`;
198+
199+
const LoginList = styled.div`
200+
display: flex;
201+
flex-direction: column;
202+
align-items: flex-start;
203+
padding: 0 14px;
204+
gap: 24px;
205+
`;

β€Žsrc/components/signup/OauthButton.tsxβ€Ž

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@ import { float } from '@/styles/animation';
99

1010
interface OauthButtonProps {
1111
loginType: OAuthType;
12+
shape?: 'circle' | 'list';
1213
bgColor: string;
1314
icon: string;
1415
size: number;
16+
label?: string;
1517
}
1618
const OauthButton = (props: OauthButtonProps) => {
17-
const { loginType, bgColor, icon, size } = props;
19+
const { loginType, shape = 'circle', bgColor, icon, size, label } = props;
1820

1921
const searchParams = useSearchParams();
2022
const url = searchParams.get('url');
@@ -87,28 +89,43 @@ const OauthButton = (props: OauthButtonProps) => {
8789

8890
return (
8991
<Wrapper>
90-
{recentLogin === loginType && <Bubble>μ΅œκ·Όμ— λ‘œκ·ΈμΈν–ˆμ–΄μš”</Bubble>}
91-
<SocialButton $bgColor={bgColor} onClick={handleLogin}>
92-
<SocialIcon src={icon} width={size} height={size} alt={loginType} />
93-
</SocialButton>
92+
{shape === 'circle' && recentLogin === loginType && (
93+
<Bubble>μ΅œκ·Όμ— λ‘œκ·ΈμΈν–ˆμ–΄μš”</Bubble>
94+
)}
95+
<Box onClick={handleLogin}>
96+
<SocialButton $bgColor={bgColor} $shape={shape}>
97+
<SocialIcon
98+
src={icon}
99+
width={size}
100+
height={size}
101+
$size={size}
102+
alt={loginType}
103+
/>
104+
</SocialButton>
105+
{shape === 'list' && <ButtonLabel>{label}</ButtonLabel>}
106+
</Box>
94107
</Wrapper>
95108
);
96109
};
97110

98111
export default OauthButton;
99112

100113
const Wrapper = styled.div`
101-
width: 69px;
102-
height: 69px;
103114
position: relative;
104115
display: flex;
105116
flex-direction: column;
106117
align-items: center;
107118
`;
108119

109-
const SocialButton = styled.button<{ $bgColor: string }>`
110-
width: 69px;
111-
height: 69px;
120+
const Box = styled.button`
121+
display: flex;
122+
align-items: center;
123+
gap: 20px;
124+
`;
125+
126+
const SocialButton = styled.div<{ $bgColor: string; $shape?: string }>`
127+
width: ${({ $shape }) => ($shape === 'list' ? '31px' : '69px')};
128+
height: ${({ $shape }) => ($shape === 'list' ? '31px' : '69px')};
112129
display: flex;
113130
justify-content: center;
114131
align-items: center;
@@ -119,10 +136,9 @@ const SocialButton = styled.button<{ $bgColor: string }>`
119136
transition: background-color 0.3s;
120137
`;
121138

122-
const SocialIcon = styled(Image)`
123-
width: 100%;
124-
height: 100%;
125-
padding: 0 16px;
139+
const SocialIcon = styled(Image)<{ $size: number }>`
140+
width: ${({ $size }) => $size}px;
141+
height: ${({ $size }) => $size}px;
126142
object-fit: contain;
127143
`;
128144

@@ -153,3 +169,9 @@ const Bubble = styled.div`
153169
border-color: ${theme.colors.blue} transparent transparent transparent;
154170
}
155171
`;
172+
173+
const ButtonLabel = styled.span`
174+
margin-left: 12px;
175+
color: ${theme.colors.white};
176+
${theme.fonts.body02};
177+
`;

β€Žsrc/constants/oauth.tsβ€Ž

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,26 @@ export const OAUTH = [
44
bgColor: '#03CF5D',
55
icon: '/assets/icons/ic_naver.svg',
66
size: 26,
7-
profile: "/assets/icons/ic_naver.svg"
7+
miniSize: 13,
8+
profile: '/assets/icons/ic_naver.svg',
9+
label: 'λ„€μ΄λ²„λ‘œ μ‹œμž‘ν•˜κΈ°'
810
},
911
{
1012
key: 'google',
1113
bgColor: '#FFFFFF',
1214
icon: '/assets/icons/ic_google.svg',
1315
size: 32,
14-
profile: "/assets/icons/ic_googler.svg"
16+
miniSize: 16,
17+
profile: '/assets/icons/ic_googler.svg',
18+
label: 'κ΅¬κΈ€λ‘œ μ‹œμž‘ν•˜κΈ°'
1519
},
1620
{
1721
key: 'kakao',
1822
bgColor: '#FEE500',
1923
icon: '/assets/icons/ic_kakaotalk.svg',
2024
size: 38,
25+
miniSize: 18,
2126
profile: '/assets/icons/ic_kakao_profile.svg',
27+
label: '카카였둜 μ‹œμž‘ν•˜κΈ°'
2228
}
2329
];

0 commit comments

Comments
Β (0)