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

[FE] 이벤트 페이지 프로필 표시(로그인 유지) 및 이벤트 페이지 로딩 화면 설정 #853

Merged
merged 11 commits into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
11 changes: 11 additions & 0 deletions client/src/apis/request/user.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import {User} from 'types/serviceType';

import {BASE_URL} from '@apis/baseUrl';
import {requestGet} from '@apis/fetcher';

export const requestGetUserInfo = async () => {
return await requestGet<User>({
baseUrl: BASE_URL.HD,
endpoint: `/api/users/mine`,
});
};
Comment on lines +1 to +11
Copy link
Contributor

Choose a reason for hiding this comment

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

피드백은 아니지만, 이번에 merge할 때 저랑 겹치는 부분이라 유의해서 merge해봅시댱!

3 changes: 2 additions & 1 deletion client/src/components/Design/components/Image/Image.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
type ImageProps = React.ComponentProps<'img'> & {
/** @jsxImportSource @emotion/react */
export type ImageProps = React.ComponentProps<'img'> & {
src: string;
fallbackSrc?: string;
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/** @jsxImportSource @emotion/react */
import type {Meta, StoryObj} from '@storybook/react';

import {Profile} from './Profile';

const meta: Meta<typeof Profile> = {
title: 'Components/Profile',
component: Profile,
tags: ['autodocs'],
parameters: {
layout: 'centered',
},
decorators: [
Story => (
<div style={{width: '200px', height: '200px', padding: '1rem'}}>
<Story />
</div>
),
],
args: {
src: 'https://wooteco-crew-wiki.s3.ap-northeast-2.amazonaws.com/%EC%9B%A8%EB%94%94%286%EA%B8%B0%29/g583lirp8yg.jpg',
size: 'large',
},
};

export default meta;

type Story = StoryObj<typeof meta>;

// Playground 스토리
export const Playground: Story = {};
26 changes: 26 additions & 0 deletions client/src/components/Design/components/Profile/Profile.style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import {css} from '@emotion/react';

import {Theme} from '@components/Design/theme/theme.type';

import {ProfileSize} from './Profile.type';

const SEMANTIC_SIZE: Record<ProfileSize, string> = {
small: '1rem',
medium: '1.75rem',
large: '3rem',
};

export const profileContainerStyle = (theme: Theme, size: ProfileSize) => {
return css({
display: 'flex',

width: SEMANTIC_SIZE[size],
height: SEMANTIC_SIZE[size],

borderRadius: '50%',

backgroundColor: theme.colors.white,

objectFit: 'cover',
});
};
13 changes: 13 additions & 0 deletions client/src/components/Design/components/Profile/Profile.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/** @jsxImportSource @emotion/react */
import {useTheme} from '@components/Design/theme/HDesignProvider';

import Image from '../Image/Image';

import {profileContainerStyle} from './Profile.style';
import {ProfileProps} from './Profile.type';

export const Profile = ({size = 'medium', ...profileProps}: ProfileProps) => {
const {theme} = useTheme();

return <Image aria-label="프로필 이미지" {...profileProps} css={profileContainerStyle(theme, size)} />;
Copy link
Contributor

Choose a reason for hiding this comment

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

aria-label까지 챙기는 것 👍

};
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import {ImageProps} from '../Image/Image';

export type ProfileSize = 'small' | 'medium' | 'large';

export type ProfileProps = ImageProps & {
size?: ProfileSize;
};
8 changes: 3 additions & 5 deletions client/src/components/Loader/EventLoader.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {useQueries} from '@tanstack/react-query';
import {useSuspenseQueries} from '@tanstack/react-query';
import {useEffect} from 'react';

import {requestGetEvent} from '@apis/request/event';
Expand All @@ -16,7 +16,7 @@ import QUERY_KEYS from '@constants/queryKeys';
const EventLoader = ({children, ...props}: React.PropsWithChildren<WithErrorHandlingStrategy | null> = {}) => {
const eventId = getEventIdByUrl();

const queries = useQueries({
const queries = useSuspenseQueries({
queries: [
{queryKey: [QUERY_KEYS.event], queryFn: () => requestGetEvent({eventId, ...props})},
{
Expand Down Expand Up @@ -44,9 +44,7 @@ const EventLoader = ({children, ...props}: React.PropsWithChildren<WithErrorHand
}
}, [stepsData.data, stepsData.isSuccess, updateTotalExpenseAmount]);

const isLoading = queries.some(query => query.isLoading === true);

return !isLoading && children;
return children;
};

export default EventLoader;
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,10 @@ const DesktopShareEventButton = ({onCopy}: DesktopShareEventButtonProps) => {
};

return (
<div style={{marginRight: '1rem'}}>
Copy link
Contributor

Choose a reason for hiding this comment

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

여기 div 삭제도 마찬가지입니댜!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

여기도 위와 마찬가지 이유입니다~

<Dropdown base="button" baseButtonText="정산 초대하기">
<DropdownButton text="링크 복사하기" onClick={copyAndToast} />
<DropdownButton text="QR코드로 초대하기" onClick={navigateQRPage} />
</Dropdown>
</div>
<Dropdown base="button" baseButtonText="정산 초대하기">
<DropdownButton text="링크 복사하기" onClick={copyAndToast} />
<DropdownButton text="QR코드로 초대하기" onClick={navigateQRPage} />
</Dropdown>
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,11 @@ const MobileShareEventButton = ({copyShare, kakaoShare}: MobileShareEventButtonP
};

return (
<div style={{marginRight: '1rem'}}>
Copy link
Contributor

Choose a reason for hiding this comment

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

div 태그를 제거하게 된 이유가 있을까요?
이 부분 제가 추가했었는데, div 태그로 감싸고 1rem을 marginRight로 줬던 이유가, header 디자인이 통일되지 않아서였던 걸로 기억해요!
혹시 그 부분을 수정해주셔서 코드를 삭제하신건지 궁금해서 남겨욧!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

대신에 이 상위 컴포넌트에서 마진을 주었어요! 상위에서 공유 버튼 이외에 추가로 프로필 컴포넌트가 생겨서 두 개를 감싸는 Flex 컴포넌트에 마진을 주었습니다

<Flex alignItems="center" gap="0.75rem" margin="0 1rem 0 0">
  {isMobile ? (
    <MobileShareEventButton copyShare={trackLinkShare} kakaoShare={trackKakaoShare} />
   ) : (
    <DesktopShareEventButton onCopy={trackLinkShare} />
   )}
   {isKakaoUser && (
     <Link to={ROUTER_URLS.myPage}>
       <Profile src={event.userInfo.profileImage ?? getImageUrl('runningDog', 'png')} size="medium" />
     </Link>
   )}
</Flex>

<Dropdown base="button" baseButtonText="정산 초대하기" onBaseButtonClick={initKakao}>
<DropdownButton text="링크 복사하기" onClick={copyAndToast} />
<DropdownButton text="QR코드로 초대하기" onClick={navigateQRPage} />
<DropdownButton text="카카오톡으로 초대하기" onClick={kakaoShare} />
</Dropdown>
</div>
<Dropdown base="button" baseButtonText="정산 초대하기" onBaseButtonClick={initKakao}>
<DropdownButton text="링크 복사하기" onClick={copyAndToast} />
<DropdownButton text="QR코드로 초대하기" onClick={navigateQRPage} />
<DropdownButton text="카카오톡으로 초대하기" onClick={kakaoShare} />
</Dropdown>
);
};

Expand Down
1 change: 1 addition & 0 deletions client/src/constants/queryKeys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const QUERY_KEYS = {
images: 'images',
kakaoClientId: 'kakao-client-id',
kakaoLogin: 'kakao-login',
userInfo: 'userinfo',
Copy link
Contributor

Choose a reason for hiding this comment

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

매우매우 사소하지만, pascalCase로 작성하는게 좋지 않을까 싶어요!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

여기 쿼리키들 말씀하시는거죠? 바꾼다고 해서 큰 상관은 없는 내용이라 바꿔도 좋을 것 같아요. 리팩토링할 때 바꿔봅시다

Copy link
Contributor

Choose a reason for hiding this comment

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

사실 뭐든 상관없는데 통일만 되면 될 것 같아요 ㅋㅋㅋㅋㅋ

};

export default QUERY_KEYS;
16 changes: 16 additions & 0 deletions client/src/hooks/queries/user/useRequestGetUserInfo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import {useSuspenseQuery} from '@tanstack/react-query';

import {requestGetUserInfo} from '@apis/request/user';

import QUERY_KEYS from '@constants/queryKeys';

const useRequestGetUserInfo = () => {
const {data} = useSuspenseQuery({
queryKey: [QUERY_KEYS.userInfo],
queryFn: requestGetUserInfo,
});

return {userInfo: data};
};

export default useRequestGetUserInfo;
3 changes: 3 additions & 0 deletions client/src/hooks/useEventPageLayout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import getEventIdByUrl from '@utils/getEventIdByUrl';
import useRequestGetEvent from './queries/event/useRequestGetEvent';
import useRequestGetAllMembers from './queries/member/useRequestGetAllMembers';
import useRequestGetSteps from './queries/step/useRequestGetSteps';
import useRequestGetUserInfo from './queries/user/useRequestGetUserInfo';

const useEventPageLayout = () => {
const eventId = getEventIdByUrl();
Expand All @@ -14,13 +15,15 @@ const useEventPageLayout = () => {
const {totalExpenseAmount} = useTotalExpenseAmountStore();
const {members} = useRequestGetAllMembers();
const {steps} = useRequestGetSteps();
const {userInfo} = useRequestGetUserInfo();
const billsCount = steps.flatMap(step => [...step.bills]).length;

const event = {
eventName,
bankName,
accountNumber,
createdByGuest,
userInfo,
};

const eventSummary = {
Expand Down
23 changes: 23 additions & 0 deletions client/src/pages/EventPage/EventPageFallback/EventPageLoading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import {Flex, Icon, IconButton, MainLayout, TopNav} from '@components/Design';
import {Footer} from '@components/Footer';

const EventPageLoading = () => {
return (
<MainLayout backgroundColor="gray">
<Flex justifyContent="spaceBetween" alignItems="center">
<TopNav>
<TopNav.Item routePath="/">
<IconButton variants="none">
<Icon iconType="heundeut" />
</IconButton>
</TopNav.Item>
<TopNav.Item displayName="홈" routePath="/home" />
<TopNav.Item displayName="관리" routePath="/admin" />
</TopNav>
Copy link
Contributor

Choose a reason for hiding this comment

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

로딩중일때, 로딩중이라는 이미지나 문구가 있으면 더 좋을 것 같긴해요!
그냥 TopNav만 띄워지면 어떤 상황인지 유저가 인지하기 어려울 것 같아서용

Copy link
Contributor Author

Choose a reason for hiding this comment

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

그 부분이 살짝 우려가 되긴 했어요.. 어떤 내용이 들어오면 좋을지 이건 이따가 회의 때 이야기해보면 좋을 것 같아요!

Copy link
Contributor

@pakxe pakxe Dec 18, 2024

Choose a reason for hiding this comment

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

이미지같이 덩치가 크면 로딩 페이지 -> 가려는 페이지 사이에서 깜빡이는게 크게 체감될 것 같단 생각이 들어용.. 그래서 스켈레톤이나 작은 로딩 아이콘을 두는게 어떨까 싶습니다!

</Flex>
<Footer />
</MainLayout>
);
};

export default EventPageLoading;
26 changes: 20 additions & 6 deletions client/src/pages/EventPage/EventPageLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import type {Event} from 'types/serviceType';

import {Outlet} from 'react-router-dom';
import {Link, Outlet} from 'react-router-dom';
import {useEffect} from 'react';

import {Profile} from '@components/Design/components/Profile/Profile';

import useEventPageLayout from '@hooks/useEventPageLayout';
import useShareEvent from '@hooks/useShareEvent';
import useAmplitude from '@hooks/useAmplitude';
Expand All @@ -14,6 +16,9 @@ import {Flex, Icon, IconButton, MainLayout, TopNav} from '@HDesign/index';

import {isMobileDevice} from '@utils/detectDevice';
import {updateMetaTag} from '@utils/udpateMetaTag';
import getImageUrl from '@utils/getImageUrl';

import {ROUTER_URLS} from '@constants/routerUrls';

export type EventPageContextProps = Event & {
isAdmin: boolean;
Expand Down Expand Up @@ -50,6 +55,8 @@ const EventPageLayout = () => {
};
}, []);

const isKakaoUser = event.userInfo && event.userInfo.isGuest === false;

return (
<MainLayout backgroundColor="gray">
<Flex justifyContent="spaceBetween" alignItems="center">
Expand All @@ -62,11 +69,18 @@ const EventPageLayout = () => {
<TopNav.Item displayName="홈" routePath="/home" />
<TopNav.Item displayName="관리" routePath="/admin" />
</TopNav>
{isMobile ? (
<MobileShareEventButton copyShare={trackLinkShare} kakaoShare={trackKakaoShare} />
) : (
<DesktopShareEventButton onCopy={trackLinkShare} />
)}
<Flex alignItems="center" gap="0.75rem" margin="0 1rem 0 0">
{isMobile ? (
<MobileShareEventButton copyShare={trackLinkShare} kakaoShare={trackKakaoShare} />
) : (
<DesktopShareEventButton onCopy={trackLinkShare} />
)}
{isKakaoUser && (
<Link to={ROUTER_URLS.myPage}>
Copy link
Contributor

Choose a reason for hiding this comment

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

useNavigate가 아닌 Link 사용하신 이유가 있을까요?? 단순히 궁금해서 여쭤봐요! 웹 접근성 때문에 Link를 사용하신 건지..🧐

Copy link
Contributor Author

Choose a reason for hiding this comment

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

프로필을 클릭했을 때 단순히 경로만 바뀌는 역할만해서 Link를 사용했던 것 같아요! 접근성은 생각하지 못 했는데 접근성의 이유가 될 수도 있을 것 같아요. button이 아닌데 onClick을 주는 것도 어색하다고 생각할 수 있을 것 같기도 해요

<Profile src={event.userInfo.profileImage ?? getImageUrl('runningDog', 'png')} size="medium" />
</Link>
)}
</Flex>
</Flex>
<Outlet context={outletContext} />
<Footer />
Expand Down
9 changes: 6 additions & 3 deletions client/src/router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const LoginPage = lazy(() => import('@pages/LoginPage'));
const MyPage = lazy(() => import('@pages/MyPage'));
const LoginRedirectPage = lazy(() => import('@pages/LoginPage/LoginRedirectPage'));
const LoginFailFallback = lazy(() => import('@pages/LoginPage/LoginFailFallback'));
const EventPageLoading = lazy(() => import('@pages/EventPage/EventPageFallback/EventPageLoading'));

const router = createBrowserRouter([
{
Expand Down Expand Up @@ -75,9 +76,11 @@ const router = createBrowserRouter([
{
path: ROUTER_URLS.event,
element: (
<EventLoader>
<EventPage />
</EventLoader>
<Suspense fallback={<EventPageLoading />}>
<EventLoader>
<EventPage />
</EventLoader>
</Suspense>
),
children: [
{
Expand Down
2 changes: 2 additions & 0 deletions client/src/types/serviceType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ export type Event = BankAccount & {

export type User = BankAccount & {
nickname: Nickname;
isGuest: boolean;
profileImage: string | null;
};

export interface Report {
Expand Down
Loading