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

[#301] 프로필 공유 모달 제작 #317

Merged
merged 20 commits into from
Jun 16, 2024
Merged
Show file tree
Hide file tree
Changes from 14 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import React from 'react'
import createShareProfilService from '@features/student/service/createShareProfilService'
import * as S from './style'

interface Props {
isLinkCreated: boolean
setIsLinkCreated: (value: boolean) => void
periodDay: number
toggleModal: () => void
studentId: string
setProfileShareData: React.Dispatch<React.SetStateAction<ProfileShareData[]>>
}

interface ProfileShareData {
token: string
}

const ProfileShareModalFooter = ({
isLinkCreated,
setIsLinkCreated,
periodDay,
toggleModal,
studentId,
setProfileShareData,
}: Props) => {
const handleCreateLinkButtonClick = async () => {
if (isLinkCreated) {
toggleModal()
} else {
setIsLinkCreated(true)
const res = await createShareProfilService(studentId, periodDay)
if (res) {
setProfileShareData([res]) // 배열로 설정
}
}
}

const buttonText = isLinkCreated ? '확인' : '링크 생성'
const beforeText = !isLinkCreated && (
<S.BeforeText onClick={toggleModal}>이전으로</S.BeforeText>
)

return (
<S.FooterContainer>
<S.ButtonContainr>
{beforeText}
<S.CreateLinkButton onClick={handleCreateLinkButtonClick}>
{buttonText}
</S.CreateLinkButton>
</S.ButtonContainr>
</S.FooterContainer>
)
}

export default ProfileShareModalFooter
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import styled from '@emotion/styled'

export const FooterContainer = styled.div`
width: 100%;
height: 3rem;
display: flex;
align-items: center;
box-sizing: border-box;
justify-content: flex-end;
`

export const ButtonContainr = styled.div`
display: flex;
gap: 2.875rem;
`

export const BeforeText = styled.p`
color: var(--N30);
font-family: Pretendard;
font-size: 1.0625rem;
font-weight: 700;
line-height: 1.3125rem;
letter-spacing: -0.002em;
align-self: center;
cursor: pointer;
`

export const CreateLinkButton = styled.button`
width: 11.4375rem;
height: 3rem;
padding: 0.75rem;
border-radius: 0.5rem;
background: var(--P2);

font-family: Pretendard;
font-size: 1.0625rem;
font-weight: 700;
line-height: 1.3125rem;
letter-spacing: -0.002em;
display: flex;
justify-content: center;
align-items: center;
border: none;

color: var(--WHITE);
cursor: pointer;
`
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from 'react'
import * as S from './style'

interface Props {
isLinkCreated: boolean
}

const ProfileShareModalHeader = ({ isLinkCreated }: Props) => {
const modalHeaderTitle = isLinkCreated ? '링크 복사' : '만료 시간 선택'

return (
<S.ModalHeaderContainer>
<S.ModalHeaderTitle>{modalHeaderTitle}</S.ModalHeaderTitle>
</S.ModalHeaderContainer>
)
}

export default ProfileShareModalHeader
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import styled from '@emotion/styled'

export const ModalHeaderContainer = styled.div`
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
`

export const ModalExpirationContainer = styled.div`
width: 100%;
display: flex;
flex-direction: column;
gap: 1rem;
`

export const ModalHeaderTitle = styled.p`
font-family: Pretendard;
font-size: 1.0625rem;
font-weight: 700;
line-height: 1.3125rem;
letter-spacing: -0.002em;
margin: 0;
`

export const ModalExitSvgContainer = styled.div`
cursor: pointer;
`
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { Radio } from '@sms/shared'
import { useRef } from 'react'
import * as S from './style'

interface ProfileShareData {
token: string
}

interface Props {
isLinkCreated: boolean
setPeriodDay: React.Dispatch<React.SetStateAction<number>>
periodDay: number
profileShareData: ProfileShareData[]
}

const ProfileShareModalSection = ({
isLinkCreated,
setPeriodDay,
periodDay,
profileShareData,
}: Props) => {
const linkUrl =
profileShareData.length > 0
? `https://sms.msg-team.com/student/link?token=${profileShareData[0].token}`
: ''
const linkRef = useRef<HTMLDivElement>(null)

const copyLinkToClipboard = async () => {
if (linkRef.current) {
chanwoo00106 marked this conversation as resolved.
Show resolved Hide resolved
await navigator.clipboard.writeText(linkUrl)
}
}

const handleRadioChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setPeriodDay(parseInt(event.target.value))
}

const expirationOptions = [
{ value: '5', label: '5일' },
{ value: '10', label: '10일' },
{ value: '15', label: '15일' },
{ value: '20', label: '20일' },
{ value: '25', label: '25일' },
{ value: '30', label: '30일' },
]
chanwoo00106 marked this conversation as resolved.
Show resolved Hide resolved

return (
<S.ModalSectionContainer>
<S.ModalExpirationContainer>
{isLinkCreated && profileShareData.length > 0 ? (
<S.ModalViewLinkContainer>
<S.ModalViewLinkText ref={linkRef}>{linkUrl}</S.ModalViewLinkText>
<S.ModalViewLinkCopy onClick={copyLinkToClipboard}>
복사
</S.ModalViewLinkCopy>
</S.ModalViewLinkContainer>
) : (
expirationOptions.map((option) => (
<Radio
key={option.value}
value={option.value}
label={option.label}
checked={periodDay === parseInt(option.value)}
onChange={handleRadioChange}
/>
))
)}
</S.ModalExpirationContainer>
</S.ModalSectionContainer>
)
}

export default ProfileShareModalSection
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import styled from '@emotion/styled'

export const ModalSectionContainer = styled.div`
display: flex;
width: 100%;
flex-direction: column;
gap: 2.5rem;
box-sizing: border-box;
`

export const ModalExpirationContainer = styled.div`
width: 100%;
display: flex;
justify-content: center;
gap: 1.4563rem;

@media (max-width: 544px) {
gap: 16px;
}
`

export const ModalViewLinkContainer = styled.div`
width: 100%;
background: var(--N10);
padding: 0.75rem;
border-radius: 0.5rem;
border: 0.0625rem solid var(--N20);
display: flex;
align-items: center;
justify-content: space-between;
`

export const ModalViewLinkText = styled.p`
font-family: Pretendard;
font-size: 0.9375rem;
font-weight: 400;
line-height: 1.3125rem;
letter-spacing: -0.002em;
color: var(--N50);
max-width: calc(100% - 100px);
`

export const ModalViewLinkCopy = styled.button`
display: flex;
align-items: center;
justify-content: center;
padding: 0.3125rem 1.25rem;
border-radius: 3.5rem;
border: 0.0625rem solid #2260ff;
background-color: var(--WHITE);
color: #2260ff;
overflow: hidden;

font-family: Pretendard;
font-size: 0.9375rem;
font-weight: 400;
line-height: 1.3125rem;
letter-spacing: -0.002em;

cursor: pointer;
`
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export const Wrapper = styled.div`
display: flex;
flex-direction: column;
gap: 1rem;
overflow: hidden;

@media (max-width: 34rem) {
padding: 1.25rem 1.5rem;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React, { useState } from 'react'
import ProfileShareModalHeader from '@features/student/atoms/ProfileShareModalHeader'
import ProfileShareModalSection from '@features/student/atoms/ProfileShareModalSection'
import ProfileShareModalFooter from '@features/student/atoms/ProfileShareModalFooter'
import * as S from './style'

interface Props {
toggleModal: () => void
studentId: string
}

interface ProfileShareData {
token: string
}

const ProfileSharingModal = ({ toggleModal, studentId }: Props) => {
const [periodDay, setPeriodDay] = useState<number>(5)
const [isLinkCreated, setIsLinkCreated] = useState(false)
const [profileShareData, setProfileShareData] = useState<ProfileShareData[]>(
[]
)
const handleBackgroundClick = (e: React.MouseEvent) => {
e.stopPropagation()
toggleModal()
}

return (
<S.ModalBackground onClick={handleBackgroundClick}>
<S.ModalContainer onClick={(e) => e.stopPropagation()}>
<S.ModalContainerResponce>
<S.ModalMainContainer>
<ProfileShareModalHeader isLinkCreated={isLinkCreated} />
<ProfileShareModalSection
isLinkCreated={isLinkCreated}
periodDay={periodDay}
setPeriodDay={setPeriodDay}
profileShareData={profileShareData}
/>
</S.ModalMainContainer>
<ProfileShareModalFooter
isLinkCreated={isLinkCreated}
setIsLinkCreated={setIsLinkCreated}
periodDay={periodDay}
toggleModal={toggleModal}
studentId={studentId}
setProfileShareData={setProfileShareData}
/>
</S.ModalContainerResponce>
</S.ModalContainer>
</S.ModalBackground>
)
}

export default ProfileSharingModal
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import styled from '@emotion/styled'

export const ModalBackground = styled.div`
width: 100vw;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
`

export const ModalContainer = styled.div`
width: 31.625rem;
height: 14.3125rem;
background-color: var(--WHITE);
border-radius: 1rem;
`

export const ModalContainerResponce = styled.div`
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
padding: 1.5rem;
`

export const ModalMainContainer = styled.div`
width: 100%;
display: flex;
flex-direction: column;
gap: 1.5rem;
align-items: center;
`
Loading
Loading