Skip to content

Commit

Permalink
feat: 멤버 탭 변경사항 및 mds 반영 (#1705)
Browse files Browse the repository at this point in the history
* feat: 참여한 프로젝트, 모임이 없는 경우 해당 항목 전부 비노출

* feat: 본인 프로필에 커피챗 오픈 버튼 추가

* chore: makers-ui 버전 업

* feat: 개선된 Select에 맞추어 레이아웃 변경

* feat: 멤버 정렬 Select를 mds로 교체

현재 Select의 오픈 상태에 따른 스타일링을 반영할 수 없어, mds 수정 사항 요청 상태

* feat: ProfileSection mds 반영

* feat: 활동 팀 mds Tag로 변경

* feat: soptActivitySection 모바일 레이아웃 변경

* feat: 본인 프로필이면서 활동 내역에 등록된 프로젝트가 없을 경우 프로젝트 등록 페이지로 이동하는 버튼 추가

* refactor: activity 필드 내부 값에 대한 가드

* feat: 멤버 순서 정렬 Select mds 수정사항 반영하여 교체

* fix: 프로필 기본정보 gap 수정

* feat: BottomSheetSelect 수정

* feat: 멤버탭 모바일 Select를 BottomSheetSelect로 교체

* feat: BottomSheetSelect에서 icon prop과 스타일 커스텀 추가

* feat: 멤버 탭에서 모바일 정렬 Select를 BottomSheetSelect로 교체

* fix: coffeechatform의 career 항목에 대해 string[] 타입 비허용

* feat: 쪽지 보내기에 커피챗 뱃지 추가

* fix: 멤버 상세 activity section에서 프로젝트가 없을 경우 내용을 세로 가운데 정렬

* fix: 멤버 상세 activity section 내 간격 조정

* fix: 멤버 상세 career section 커리어-스킬 사이 마진 수정

* fix: 멤버 상세 페이지 하단 마진값 수정

* fix: 멤버 상세 연락처 정보 마진 수정

* feat: BottomSheetSelect width 정의 방식 변경

* feat: mds ui 버전업
  • Loading branch information
simeunseo authored Jan 14, 2025
1 parent 934e9fa commit adb1f76
Show file tree
Hide file tree
Showing 18 changed files with 585 additions and 1,104 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@
"@radix-ui/react-tooltip": "^1.0.5",
"@sopt-makers/colors": "^3.0.2",
"@sopt-makers/fonts": "^1.0.0",
"@sopt-makers/icons": "^1.0.5",
"@sopt-makers/ui": "^2.7.6",
"@sopt-makers/icons": "^1.1.0",
"@sopt-makers/ui": "^2.8.6",
"@tanstack/react-query": "^5.4.3",
"@toss/emotion-utils": "^1.1.10",
"@toss/error-boundary": "^1.4.6",
Expand Down
2 changes: 1 addition & 1 deletion src/components/coffeechat/detail/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export default function CoffeechatDetail({ memberId }: CoffeechatDetailProp) {
isMine={profile.isMine}
isCoffeechatTap
/>
<DetailInfoSection profile={profile} isCoffeechat />
<DetailInfoSection profile={profile} />
</ProfileContents>
<SoptActivityTitle>SOPT 활동 정보</SoptActivityTitle>
<SoptActivitySection soptActivities={sortedSoptActivities} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { colors } from '@sopt-makers/colors';
import { fonts } from '@sopt-makers/fonts';
import { IconCheck, IconChevronDown } from '@sopt-makers/icons';
import { Button } from '@sopt-makers/ui';
import { useEffect, useState } from 'react';
import { ReactNode, useEffect, useState } from 'react';

import { zIndex } from '@/styles/zIndex';

Expand All @@ -14,11 +14,23 @@ interface Option {

interface BottomSheetSelectProps {
options: Option[];
value: string | string[] | null | undefined;
defaultOption?: Option;
value: string | null | undefined;
placeholder: string;
onChange: (value: string) => void;
icon?: ReactNode;
className?: string;
}
const BottomSheetSelect = ({ options, value, placeholder, onChange }: BottomSheetSelectProps) => {

const BottomSheetSelect = ({
options,
defaultOption,
value,
placeholder,
onChange,
icon,
className,
}: BottomSheetSelectProps) => {
const [open, setOpen] = useState(false);
const [selectedValue, setSelectedValue] = useState(value);
const [temporaryValue, setTemporaryValue] = useState(value);
Expand All @@ -32,7 +44,7 @@ const BottomSheetSelect = ({ options, value, placeholder, onChange }: BottomShee

const handleConfirm = () => {
setSelectedValue(temporaryValue);
if (temporaryValue !== '') onChange(temporaryValue as string);
onChange(temporaryValue as string);

handleClose();
};
Expand All @@ -49,25 +61,37 @@ const BottomSheetSelect = ({ options, value, placeholder, onChange }: BottomShee
};
}, [open]);

const getSelectedLabel = (value: string) => {
return options.find((option) => option.value === value)?.label;
};

return (
<Container>
<InputField onClick={handleOpen}>
{selectedValue !== null ? <p>{selectedValue}</p> : <p style={{ color: '#808087' }}>{placeholder}</p>}
<IconChevronDown
style={{
width: 20,
height: 20,
transform: open ? 'rotate(-180deg)' : '',
transition: 'all 0.5s',
}}
/>
<InputField onClick={handleOpen} className={className}>
{selectedValue ? <p>{getSelectedLabel(selectedValue)}</p> : <p style={{ color: '#808087' }}>{placeholder}</p>}
{icon || (
<IconChevronDown
style={{
width: 20,
height: 20,
transform: open ? 'rotate(-180deg)' : '',
transition: 'all 0.5s',
}}
/>
)}
</InputField>

{open && (
<>
<Overlay onClick={handleClose} />
<BottomSheet>
<OptionList>
{defaultOption && (
<OptionItem onClick={() => handleOptionSelect(defaultOption.value)}>
{defaultOption.label}
{temporaryValue === defaultOption.value && <CheckedIcon />}
</OptionItem>
)}
{options.map((option) => (
<OptionItem key={option.value} onClick={() => handleOptionSelect(option.value)}>
{option.label}
Expand All @@ -88,18 +112,20 @@ export default BottomSheetSelect;

const Container = styled.div`
position: relative;
width: 100%;
`;

const InputField = styled.div`
display: flex;
gap: 12px;
align-items: center;
justify-content: space-between;
border-radius: 10px;
background-color: ${colors.gray800};
cursor: pointer;
padding: 11px 16px;
${fonts.BODY_16_M};
width: 100%;
`;

const Overlay = styled.div`
Expand All @@ -115,6 +141,7 @@ const Overlay = styled.div`
const BottomSheet = styled.section`
position: fixed;
bottom: 0;
left: 20px;
z-index: ${zIndex.헤더};
margin-bottom: 12px;
border-radius: 16px;
Expand Down
31 changes: 22 additions & 9 deletions src/components/members/detail/ActivityBadge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,29 @@ import styled from '@emotion/styled';
import { colors } from '@sopt-makers/colors';
import { FC } from 'react';

import Text from '@/components/common/Text';
import { MOBILE_MEDIA_QUERY } from '@/styles/mediaQuery';
import { textStyles } from '@/styles/typography';

interface ActivityBadgeProps {
category?: string;
name: string;
}

const ActivityBadge: FC<ActivityBadgeProps> = ({ category, name }) => {
return <Container>{`${category} ${name}`}</Container>;
return (
<Container>
<Category typography='SUIT_13_M'>{category}</Category>
<Text typography='SUIT_13_M'>{name}</Text>
</Container>
);
};

const Container = styled.div`
display: flex;
align-items: center;
transition: background-color 0.2s;
border-radius: 13px;
border-radius: 28px;
background-color: ${colors.gray700};
padding: 6px 14px;
line-height: 100%;
letter-spacing: -0.01em;
color: ${colors.gray10};
${textStyles.SUIT_14_M}
&:hover {
background-color: ${colors.gray600};
Expand All @@ -38,4 +37,18 @@ const Container = styled.div`
}
`;

const Category = styled(Text)`
display: flex;
align-items: center;
::after {
display: inline-block;
margin: 0 10px;
background-color: ${colors.gray400};
width: 1px;
height: 14px;
content: '';
}
`;

export default ActivityBadge;
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ const MemberDetail: FC<MemberDetailProps> = ({ memberId }) => {
<Container>
<Wrapper>
<ProfileSection profile={profile} memberId={memberId} />
{!profile.isMine && <MessageSection profile={profile} memberId={memberId} />}
<MessageSection profile={profile} memberId={memberId} />
<DetailInfoSection profile={profile} />
<SoptActivitySection soptActivities={sortedSoptActivities} />
<SoptActivitySection soptActivities={sortedSoptActivities} isMine={profile.isMine} />
<CareerSection
careers={profile.careers}
links={profile.links}
Expand Down Expand Up @@ -119,7 +119,7 @@ const Container = styled.div`
display: flex;
flex-direction: column;
align-items: center;
padding: 123px 0;
padding: 120px 0 200px;
@media ${MOBILE_MEDIA_QUERY} {
padding: 16px 20px;
padding-bottom: 100px;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ import { MOBILE_MEDIA_QUERY } from '@/styles/mediaQuery';
export const MemberDetailSection = styled.section`
display: flex;
flex-direction: column;
gap: 32px;
border-radius: 20px;
background: ${colors.gray900};
padding: 40px;
width: 100%;
@media ${MOBILE_MEDIA_QUERY} {
gap: 30px;
border-radius: 18px;
padding: 30px 20px;
}
Expand Down
48 changes: 16 additions & 32 deletions src/components/members/detail/DetailinfoSection/index.tsx
Original file line number Diff line number Diff line change
@@ -1,46 +1,29 @@
import styled from '@emotion/styled';
import { colors } from '@sopt-makers/colors';
import dayjs from 'dayjs';

import { ProfileDetail } from '@/api/endpoint_LEGACY/members/type';
import Text from '@/components/common/Text';
import MemberDetailSection from '@/components/members/detail/ActivitySection/MemberDetailSection';
import InfoItem from '@/components/members/detail/InfoItem';
import { DEFAULT_DATE } from '@/components/members/upload/constants';
import { MOBILE_MEDIA_QUERY } from '@/styles/mediaQuery';

interface DetailInfoSectionProps {
profile: ProfileDetail;
isCoffeechat?: boolean;
}

const convertBirthdayFormat = (birthday?: string) => {
// FIXME: 서버쪽에 YYYY-MM-DD 형태로 무조건 업로드시 전송해줘야 하는 이슈가 있어서,
// 생년월일을 보내지 않았을 경우에 DEFAULT_DATE를 전송하도록 임시처리 해 두었습니다. 이를 클라에서 보여주기 위해 대응합니다.
if (birthday) {
const isDefaultDay = dayjs(birthday).isSame(dayjs(DEFAULT_DATE));
return isDefaultDay ? '' : dayjs(birthday).format('YYYY-MM-DD');
}
return '';
};

const DetailInfoSection = ({ profile, isCoffeechat = false }: DetailInfoSectionProps) => {
const DetailInfoSection = ({ profile }: DetailInfoSectionProps) => {
const hasProfileInfo = profile.birthday || profile.university || profile.major || profile.address;

return hasProfileInfo ? (
<MemberDetailSection style={{ gap: '30px' }}>
{!isCoffeechat && profile.birthday && (
<InfoItem label='생년월일' content={convertBirthdayFormat(profile.birthday)} />
)}
{profile.university && <InfoItem label='학교'>{profile.university}</InfoItem>}
{profile.major && <InfoItem label='전공'>{profile.major}</InfoItem>}
{profile.address && (
<InfoItem label='활동 지역'>
<StyledAddressBadgeWrapper>
{profile.address.split(',').map((address) => (
<AddressBadge key={address}>
<Text typography='SUIT_14_M'>{address}</Text>
</AddressBadge>
<AddressItem key={address}>
<Text typography='SUIT_18_M'>{address}</Text>
</AddressItem>
))}
</StyledAddressBadgeWrapper>
</InfoItem>
Expand All @@ -54,18 +37,19 @@ export default DetailInfoSection;
const StyledAddressBadgeWrapper = styled.div`
display: flex;
flex-wrap: wrap;
gap: 8px;
align-items: center;
@media ${MOBILE_MEDIA_QUERY} {
gap: 10px;
}
`;

const AddressBadge = styled.div`
border-radius: 13px;
background-color: ${colors.gray700};
padding: 6px 14px;
line-height: 16px;
color: ${colors.gray10};
const AddressItem = styled.div`
display: flex;
align-items: center;
&:not(:last-child)::after {
display: inline-block;
margin: 0 10px;
background-color: ${colors.gray600};
width: 1px;
height: 16px;
content: '';
}
`;
18 changes: 8 additions & 10 deletions src/components/members/detail/GroupSection/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import styled from '@emotion/styled';
import { colors } from '@sopt-makers/colors';
import { fonts } from '@sopt-makers/fonts';
import axios from 'axios';
import Link from 'next/link';

Expand All @@ -13,7 +14,6 @@ import { playgroundLink } from '@/constants/links';
import useEnterScreen from '@/hooks/useEnterScreen';
import { MOBILE_MEDIA_QUERY } from '@/styles/mediaQuery';
import { safeParseInt } from '@/utils';
import { fonts } from '@sopt-makers/fonts';

interface GroupSectionProps {
profile: ProfileDetail;
Expand All @@ -40,9 +40,9 @@ const GroupSection = ({ profile, meId, memberId }: GroupSectionProps) => {
}

return (
<Container>
<>
{meetingList.length > 0 ? (
<>
<Container>
<ActivityTitle>
{profile.name}님이 참여한 {meetingList.length}개의 모임이에요!
</ActivityTitle>
Expand All @@ -56,11 +56,11 @@ const GroupSection = ({ profile, meId, memberId }: GroupSectionProps) => {
))}
</ActivityDisplay>
<Target ref={ref} />
</>
</Container>
) : (
<>
{String(meId) === memberId ? (
<>
{String(meId) === memberId && (
<Container>
<ActivityTitle>아직 참여한 모임이 없어요</ActivityTitle>
<ActivityUploadNudge>
<NudgeSubText typography='SUIT_16_M' style={{ textAlign: 'center', lineHeight: '24px' }}>
Expand All @@ -72,13 +72,11 @@ const GroupSection = ({ profile, meId, memberId }: GroupSectionProps) => {
</ActivityUploadButton>
<ActivityUploadMaskImg src='/icons/img/meeting-mask.png' alt='meeting-mask-image' height={134} />
</ActivityUploadNudge>
</>
) : (
<ActivityTitle>아직 {profile.name}님이 참여한 모임이 없어요</ActivityTitle>
</Container>
)}
</>
)}
</Container>
</>
);
};

Expand Down
Loading

0 comments on commit adb1f76

Please sign in to comment.