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

feat: add guest-book banner #37

Merged
merged 3 commits into from
Aug 15, 2023
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
7 changes: 7 additions & 0 deletions src/assets/icons/guest_book.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/assets/icons/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ export { default as Camera } from './camera.svg';
export { default as ArrowDown } from './arrow-down.svg';
export { default as Pencil } from './pencil.svg';
export { default as Close } from './close.svg';
export { default as GuestBook } from './guest_book.svg';
106 changes: 106 additions & 0 deletions src/components/user/guest-book/GuestBookBanner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import { useEffect, useState } from 'react';
import { Icon } from '@/components/shared';
import { useLogin } from '@/hooks/useLogin';

interface GuestBookBannerProps {
visitLogs?: VisitLog[];
ownerName: string;
}

interface VisitLog {
name: string;
text: string;
log_id: number;
created_at: string;
user_id: string;
}

const Log = ({ text, name }: Pick<VisitLog, 'name' | 'text'>) => {
return (
<div className='tw-relative tw-flex tw-h-9 tw-flex-row tw-justify-between tw-py-1.5'>
<div className='tw-flex tw-flex-row tw-gap-2'>
<Icon iconType='GuestBook' />
<p>{text}</p>
</div>
<button className='tw-text-grayscale-300'>{`- ${name}`}</button>
</div>
);
};

export const GuestBookBanner = ({
visitLogs,
ownerName,
}: GuestBookBannerProps) => {
const { login } = useLogin();
const [activeIndex, setActiveIndex] = useState(0);
const [isTransitioning, setIsTransitioning] = useState(false);
const translateY = -activeIndex * 36;

useEffect(() => {
if (visitLogs && isTransitioning) {
const id = setTimeout(() => {
setIsTransitioning(false);
if (activeIndex === visitLogs.length) {
setActiveIndex(0);
}
}, 300);

return () => clearTimeout(id);
}
}, [activeIndex, isTransitioning, visitLogs]);

const nextItem = () => {
setIsTransitioning(true);
if (visitLogs && visitLogs.length) {
setActiveIndex((prevIndex) => (prevIndex + 1) % (visitLogs.length + 1));
}
};

useEffect(() => {
const id = setInterval(() => {
nextItem();
}, 2500);

return () => clearInterval(id);
}, []);

if (!visitLogs || !visitLogs.length) {
return (
<div className='tw-mx-5 tw-mb-5 tw-mt-3 tw-bg-grayscale-700 tw-px-3.5 tw-py-1.5 tw-text-white'>
{login ? (
<div className='tw-flex tw-flex-row tw-gap-2'>
<Icon iconType='GuestBook' />
<p className='tw-text-grayscale-300'>
아직 작성된 방명록이 없습니다
</p>
</div>
) : (
<>
<div className='tw-flex tw-flex-row tw-gap-2'>
<Icon iconType='GuestBook' />
<p>{`${ownerName}님께 방명록을 남겨주세요`}</p>
</div>
<button className='tw-text-grayscale-300'>작성하기</button>
</>
)}
</div>
);
}

return (
<div className='tw-mx-5 tw-mb-5 tw-mt-3 tw-h-9 tw-overflow-hidden tw-bg-grayscale-700 tw-px-3.5 tw-text-white'>
<div
className={`${
isTransitioning
? 'tw-ease tw-transition-transform tw-duration-500'
: ''
}`}
style={{ transform: `translateY(${translateY}px)` }}
>
{visitLogs.map(({ log_id, name, text }) => (
<Log key={log_id} name={name} text={text} />
))}
</div>
</div>
);
};
2 changes: 1 addition & 1 deletion src/hooks/useLogin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useState } from 'react';
import { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect';

export function useLogin() {
const [login, setLogin] = useState<boolean | null>(null);
const [login, setLogin] = useState<boolean>(false);

useIsomorphicLayoutEffect(() => {
const user_id = localStorage.getItem('userId');
Expand Down
14 changes: 9 additions & 5 deletions src/pages/user/[id]/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { ModalContext } from '@/providers';
import { useGetFilms } from '@/query-hooks/useFilms';
import filmsApis from '@/query-hooks/useFilms/api';
import filmsKeys from '@/query-hooks/useFilms/keys';
import { useGetUser } from '@/query-hooks/useUsers';
import { useGetUser, useGetUserVisitLogs } from '@/query-hooks/useUsers';
import usersApis from '@/query-hooks/useUsers/apis';
import usersKeys from '@/query-hooks/useUsers/keys';
import { Avatar, Button, Icon, Tooltip } from '@/components/shared';
Expand All @@ -20,6 +20,7 @@ import {
FilmTitleModal,
ProfileModal,
} from '@/components/user';
import { GuestBookBanner } from '@/components/user/guest-book/GuestBookBanner';
import { useLogin } from '@/hooks/useLogin';

export interface Profile {
Expand All @@ -39,6 +40,7 @@ export default function User({
const { login: isLogin } = useLogin();
const { isLoading, data: filmList, isError } = useGetFilms(userId);
const { data: userData } = useGetUser(userId);
const { data: visitLogData } = useGetUserVisitLogs(userId);

const { status, dispatch } = useSafeContext(ModalContext);

Expand Down Expand Up @@ -68,7 +70,6 @@ export default function User({
dispatch({ type: 'OPEN_PROFILE_MODAL' });
};

if (isLogin === null) return null;
if (isLoading) return <div>로딩중...</div>;
if (isError) return <div>에러 ㅋ</div>;

Expand All @@ -85,9 +86,9 @@ export default function User({
onEditProfile={handleEditProfile}
/>
)}
<div className='tw-mx-5 tw-mb-5 tw-mt-3 tw-bg-grayscale-700 tw-px-3.5 tw-py-1.5 tw-text-white'>
방명록 기능이 추가될 공간입니다 ㅎ
</div>
{userData && (
<GuestBookBanner ownerName={userData.name} visitLogs={visitLogData} />
)}
<div className='tw-flex tw-flex-col tw-gap-4'>
{filmList?.map(({ film_id, photo_cuts, title }) => (
<CameraRoll
Expand Down Expand Up @@ -197,6 +198,9 @@ export const getServerSideProps: GetServerSideProps<{
queryClient.prefetchQuery(usersKeys.item(userId), () =>
usersApis.getUser(userId),
),
queryClient.prefetchQuery(usersKeys.visitLogs(userId), () =>
usersApis.getUserVisitLogs(userId),
),
]);

return {
Expand Down