diff --git a/src/api/meeting.ts b/src/api/meeting.ts index 3ab3c795..bfc028f4 100644 --- a/src/api/meeting.ts +++ b/src/api/meeting.ts @@ -22,6 +22,17 @@ export const getMeetingDetail = async ( } }; +export const increaseMeetingEnterUserCount = async ( + id: string, +): Promise => { + try { + await customAxios().post(`/meetings/${id}/enter`); + return { success: true }; + } catch (e) { + return { success: false }; + } +}; + interface getMeetingsRes { success: boolean; data?: MeetingList[]; @@ -31,3 +42,7 @@ interface getMeetingDetailRes { success: boolean; data?: MeetingDetail; } + +interface increaseMeetingEnterUserCountRes { + success: boolean; +} diff --git a/src/assets/icon/person.svg b/src/assets/icon/person.svg new file mode 100644 index 00000000..35c766ea --- /dev/null +++ b/src/assets/icon/person.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/LandingPage/components/MeetingCard/CurrMeetingCard.tsx b/src/components/LandingPage/components/MeetingCard/CurrMeetingCard.tsx index edcdba38..3cfd5ace 100644 --- a/src/components/LandingPage/components/MeetingCard/CurrMeetingCard.tsx +++ b/src/components/LandingPage/components/MeetingCard/CurrMeetingCard.tsx @@ -6,6 +6,7 @@ import { MeetingList } from 'meeting'; import { COLOR } from '../../../../constant/color'; import CurrMeetingTimer from '../CurrMeetingTimer'; +import ParticipantNum from '../ParticipantNum'; interface Props { data: MeetingList; @@ -43,6 +44,9 @@ function CurrMeetingCard({ idx, data }: Props): ReactElement { end_time={data.end_time} /> {data.title} + {data.user_enter_cnt !== 0 && ( + + )} @@ -117,7 +121,7 @@ const Title = styled.div` line-height: 2.6rem; letter-spacing: -0.04rem; color: ${COLOR.TEXT_BLACK}; - margin-bottom: 1.4rem; + margin-bottom: 0.4rem; overflow: hidden; text-overflow: ellipsis; -webkit-line-clamp: 2; @@ -127,6 +131,7 @@ const Title = styled.div` display: -ms-flexbox; display: box; `; + const Button = styled.div` width: 100%; height: 4rem; diff --git a/src/components/LandingPage/components/ParticipantNum.tsx b/src/components/LandingPage/components/ParticipantNum.tsx new file mode 100644 index 00000000..baba302d --- /dev/null +++ b/src/components/LandingPage/components/ParticipantNum.tsx @@ -0,0 +1,38 @@ +import React, { ReactElement } from 'react'; + +import styled from '@emotion/styled'; + +import person from '../../../assets/icon/person.svg'; +import { COLOR } from '../../../constant/color'; + +interface Props { + userMeetingNum: number; +} + +function ParticipantNum({ userMeetingNum }: Props): ReactElement { + return ( + + + + 누적 참여자 {userMeetingNum}명 + + + ); +} + +const ParticipantNumWrapper = styled.div` + display: flex; + flex-direction: row; + align-items: center; + margin-bottom: 1.4rem; +`; + +const ParticipantIcon = styled.img` + margin-right: 0.4rem; +`; + +const Participant = styled.div` + color: ${COLOR.TEXT_GRAY}; +`; + +export default ParticipantNum; diff --git a/src/components/MeetingDetailPage/components/ZoomBottomSheet.tsx b/src/components/MeetingDetailPage/components/ZoomBottomSheet.tsx index 73b1cd59..5ad21292 100644 --- a/src/components/MeetingDetailPage/components/ZoomBottomSheet.tsx +++ b/src/components/MeetingDetailPage/components/ZoomBottomSheet.tsx @@ -4,6 +4,7 @@ import styled from '@emotion/styled'; import { logEvent } from '@firebase/analytics'; import { useRecoilValue } from 'recoil'; +import { increaseMeetingEnterUserCount } from '../../../api/meeting'; import { analytics } from '../../../App'; import arrow_iOS_xsmall_green from '../../../assets/icon/arrow_iOS_xsmall_green.svg'; import cam from '../../../assets/icon/cam.svg'; @@ -20,9 +21,9 @@ interface Props { onClose: () => void; onClickJoin?: () => void; zoomGuideHandler?: () => void; - meetingId?: string; - meetingTitle?: string; - url?: string; + meetingId: string; + meetingTitle: string; + url: string; } function ZoomBottomSheet({ @@ -48,7 +49,10 @@ function ZoomBottomSheet({ closeHandler(); }; - const onClickJoinHandler = () => { + const onClickJoinHandler = async () => { + const redirectWindow = window.open(url, '_blank'); + await increaseMeetingEnterUserCount(meetingId); + redirectWindow && redirectWindow.location; logEvent(analytics, 'zoom_bottom_sheet_join__click', { location: 'zoom_bottom_sheet', meeting_id: meetingId, @@ -56,7 +60,6 @@ function ZoomBottomSheet({ userNickname: userInfo?.nickname, userRegion: userInfo?.region, }); - window.open(url, '', '_blank'); onClickJoin && onClickJoin(); }; @@ -95,7 +98,6 @@ function ZoomBottomSheet({ - ); @@ -179,9 +181,10 @@ const ZoomGuide = styled.div` const JoinBtnBlue = styled.img` width: auto; height: 4.4rem; + margin: 0 2rem 1.8rem 2rem; text-decoration: none; outline: none; - margin: 0 2rem 1.8rem 2rem; + box-sizing: border-box; `; export default ZoomBottomSheet; diff --git a/src/hoc/Auth.tsx b/src/hoc/Auth.tsx index 868a2e04..8448f28a 100644 --- a/src/hoc/Auth.tsx +++ b/src/hoc/Auth.tsx @@ -1,9 +1,11 @@ import React, { useCallback, useEffect, useState } from 'react'; +import { logEvent } from '@firebase/analytics'; import jwt_decode, { JwtPayload } from 'jwt-decode'; import { useRecoilState } from 'recoil'; import { login } from '../api/user'; +import { analytics } from '../App'; import { codeAtom, userInfoAtom } from '../store/user'; import mini from '../util/mini'; import { getRegionId } from '../util/utils'; @@ -86,12 +88,18 @@ const Auth = (SpecialComponent: React.FC) => { }, [code, setUserNewInfoHandler, setUserInfo]); useEffect(() => { - if (!code) getCodeHandler(); + if (!code) { + logEvent(analytics, 'new_user_enter'); + getCodeHandler(); + } if (code && !userInfo) checkAuth(); }, [checkAuth, code, getCodeHandler, userInfo]); useEffect(() => { - if (presetClosed && !code) mini.close(); + if (presetClosed && !code) { + logEvent(analytics, 'close_preset'); + mini.close(); + } }, [code, presetClosed]); return ; diff --git a/src/types/meeting.d.ts b/src/types/meeting.d.ts index bd0d65d4..4414e1c0 100644 --- a/src/types/meeting.d.ts +++ b/src/types/meeting.d.ts @@ -7,6 +7,7 @@ declare module 'meeting' { end_time: string; date: string; alarm_id: number | undefined; + user_enter_cnt: number; live_status: 'live' | 'tomorrow' | 'upcoming' | 'finish'; };