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

Feature : Pick, Talk페이지 애니메이션 구현 #20

Merged
merged 5 commits into from
Aug 20, 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
856 changes: 856 additions & 0 deletions public/lotties/pick.json

Large diffs are not rendered by default.

1,681 changes: 0 additions & 1,681 deletions public/lotties/posepicker.json

This file was deleted.

537 changes: 537 additions & 0 deletions public/lotties/talk_after_click.json

Large diffs are not rendered by default.

Binary file added public/lotties/talk_after_loading.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1,540 changes: 1,540 additions & 0 deletions public/lotties/talk_before_click.json

Large diffs are not rendered by default.

32 changes: 4 additions & 28 deletions src/apis/apis.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,11 @@
import { UseQueryOptions, useQuery } from '@tanstack/react-query';

import { PosePickResponse, PoseTalkResponse } from '.';
import publicApi from './config/publicApi';

export const getPoseTalk = () => publicApi.get('/pose/talk');
export const usePoseTalkQuery = () =>
useQuery(['poseTalk'], getPoseTalk, {
enabled: false,
});

export const getPoseDetail = (poseId: number) => publicApi.get(`/pose/${poseId}`);
export const usePoseDetailQuery = (poseId: number) =>
useQuery(['poseId', poseId], () => getPoseDetail(poseId));

export interface PosePickResponse {
poseInfo: {
createdAt: string;
frameCount: number;
imageKey: string;
peopleCount: number;
poseId: number;
source: string;
sourceUrl: string;
tagAttributes: string;
updatedAt: string;
};
}

export const getPosePick = (peopleCount: number) =>
publicApi.get<PosePickResponse>(`/pose/pick/${peopleCount}`);

export const usePosePickQuery = (
peopleCount: number,
options?: UseQueryOptions<PosePickResponse>
) => useQuery<PosePickResponse>(['posePick', peopleCount], () => getPosePick(peopleCount), options);
export const getPoseDetail = (poseId: number) => publicApi.get(`/pose/${poseId}`);

export const getPoseTalk = () => publicApi.get<PoseTalkResponse>('/pose/talk');
3 changes: 3 additions & 0 deletions src/apis/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './apis';
export * from './queries';
export * from './type';
24 changes: 24 additions & 0 deletions src/apis/queries.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { UseQueryOptions, useQuery } from '@tanstack/react-query';

import {
type PosePickResponse,
type PoseTalkResponse,
getPoseDetail,
getPosePick,
getPoseTalk,
} from '.';

export const usePoseDetailQuery = (poseId: number) =>
useQuery(['poseId', poseId], () => getPoseDetail(poseId));

export const usePosePickQuery = (
peopleCount: number,
options?: UseQueryOptions<PosePickResponse>
) =>
useQuery<PosePickResponse>(['posePick', peopleCount], () => getPosePick(peopleCount), {
enabled: false,
...options,
});

export const usePoseTalkQuery = (options?: UseQueryOptions<PoseTalkResponse>) =>
useQuery<PoseTalkResponse>(['poseTalk'], getPoseTalk, { enabled: false, ...options });
22 changes: 22 additions & 0 deletions src/apis/type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
export interface PosePickResponse {
poseInfo: {
createdAt: string;
frameCount: number;
imageKey: string;
peopleCount: number;
poseId: number;
source: string;
sourceUrl: string;
tagAttributes: string;
updatedAt: string;
};
}

export interface PoseTalkResponse {
poseWord: {
content: string;
createdAt: string;
updateAt: string;
wordId: number;
};
}
13 changes: 6 additions & 7 deletions src/app/(Main)/components/MainHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@ import { Header } from '@/components/Header';

export default function MainHeader() {
return (
<div>
<Header
leftNode={<h4>PosePicker</h4>}
rightNode={<Image src="/icons/menu.svg" width={24} height={24} alt="24" />}
headerDownNode={<Tab />}
/>
</div>
<Header
leftNode={<h4>PosePicker</h4>}
rightNode={<Image src="/icons/menu.svg" width={24} height={24} alt="24" />}
headerDownNode={<Tab />}
className="px-20"
/>
);
}
28 changes: 16 additions & 12 deletions src/app/(Main)/pick/components/PickSection.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,38 @@
'use client';

import Image from 'next/image';
import { useState } from 'react';
import { useEffect, useState } from 'react';
import Lottie from 'react-lottie-player';

import lottieJson from '../../../../../public/lotties/posepicker.json';
import { usePosePickQuery } from '@/apis/apis';
import { usePosePickQuery } from '@/apis';
import { BottomFixedButton } from '@/components/Button';
import { Spacing } from '@/components/Spacing';

import lottiePick from '#/lotties/pick.json';

const countList = ['1인', '2인', '3인', '4인', '5인+'];

export default function PickSection() {
const [countState, setCountState] = useState<string>('1인');
const [isLoading, setIsLoading] = useState<boolean>(false);
const [isLoading, setIsLoading] = useState<boolean>(true);
const [image, setImage] = useState<string>('');
const { refetch, data } = usePosePickQuery(+countState[0], {
enabled: false,
const { refetch } = usePosePickQuery(+countState[0], {
onSuccess: (data) => {
if (!data) return;
setImage(data.poseInfo.imageKey);
},
});

const handlePickClick = () => {
setIsLoading(true);
refetch();
useEffect(() => {
if (!isLoading) return;
setTimeout(() => {
setIsLoading(false);
}, 3000);
}, [isLoading]);

const handlePickClick = () => {
setIsLoading(true);
refetch();
};

return (
Expand All @@ -37,7 +41,7 @@ export default function PickSection() {
{countList.map((count) => (
<CountItem
key={count}
onClick={() => setCountState(count)}
onClick={() => !isLoading && setCountState(count)}
isSelected={count === countState}
count={count}
/>
Expand All @@ -47,9 +51,9 @@ export default function PickSection() {
<Spacing size={13} />
<div className="relative h-520">
{isLoading ? (
<Lottie loop animationData={lottieJson} play style={{ width: '100%', height: '100%' }} />
<Lottie loop animationData={lottiePick} play style={{ width: '100%', height: '100%' }} />
) : (
<Image src={image || '/images/sample.png'} fill priority alt="image" />
<Image src={image || '/images/sample.png'} fill priority alt="sample" />
)}
</div>
<BottomFixedButton className="bg-main-violet text-white" onClick={handlePickClick}>
Expand Down
54 changes: 53 additions & 1 deletion src/app/(Main)/talk/components/TalkSection.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,60 @@
'use client';

import Image from 'next/image';
import { useEffect, useRef, useState } from 'react';
import Lottie from 'react-lottie-player';

import { usePoseTalkQuery } from '@/apis';
import { BottomFixedButton } from '@/components/Button';

import lottieTalkAfterClick from '#/lotties/talk_after_click.json';
import lottieTalkBeforeClick from '#/lotties/talk_before_click.json';

interface TalkSectionProps {}
export default function TalkSection() {
return <section></section>;
const [isFirstLoading, setIsFirstLoading] = useState<boolean>(true);
const [isLoading, setIsLoading] = useState<boolean>(false);
const [talkWord, setTalkWord] = useState<string>('포즈로 말해요');
const { refetch } = usePoseTalkQuery({
onSuccess: (data) => {
setIsFirstLoading(false);
setIsLoading(true);
setTimeout(() => {
setIsLoading(false);
setTalkWord(data.poseWord.content);
}, 3000);
},
});

const handleTalkClick = () => {
refetch();
};

return (
<section className="flex flex-col items-center">
<h1>{talkWord}</h1>
{isFirstLoading && (
<Lottie
loop
animationData={lottieTalkBeforeClick}
play
style={{ width: '100%', height: '100%' }}
/>
)}
{isLoading && (
<Lottie
loop
animationData={lottieTalkAfterClick}
play
style={{ width: '100%', height: '100%' }}
/>
)}
{!isFirstLoading && !isLoading && (
<Image src="/lotties/talk_after_loading.png" width={360} height={10} alt="lottie" />
)}
<BottomFixedButton className="bg-main-violet text-white" onClick={handleTalkClick}>
제시어 뽑기
</BottomFixedButton>
</section>
);
}
4 changes: 2 additions & 2 deletions src/app/(Main)/talk/components/TitleSection.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
'use client';
import { Spacing } from '@/components/Spacing';
import Image from 'next/image';
import { useState } from 'react';
import { Tooltip } from 'react-tooltip';

import { Spacing } from '@/components/Spacing';

export default function TitleSection() {
const [tooltipOpened, setTooltipOpened] = useState<boolean>(false);
console.log(tooltipOpened);
Expand All @@ -24,7 +25,6 @@ export default function TitleSection() {
</div>
<Tooltip id="my-tooltip" style={{ fontSize: '1rem', fontWeight: 400 }} />
<Spacing size={8} />
<h1>포즈로 말해요</h1>
</section>
);
}
5 changes: 3 additions & 2 deletions src/app/(Sub)/menu/components/MakerSection.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import BottomFixedDiv from '@/components/BottomFixedDiv';
import { Spacing } from '@/components/Spacing';
import Image from 'next/image';
import Link from 'next/link';

import BottomFixedDiv from '@/components/BottomFixedDiv';
import { Spacing } from '@/components/Spacing';

export default function MakerSection() {
return (
<BottomFixedDiv>
Expand Down
3 changes: 2 additions & 1 deletion src/app/(Sub)/menu/components/MenuListSection.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Image from 'next/image';

import { Header } from '@/components/Header';
import { Spacing } from '@/components/Spacing';
import Image from 'next/image';

export default function MenuHeader() {
const LeftNode = (
Expand Down
13 changes: 6 additions & 7 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { Header } from '@/components/Header';
import './globals.css';
import '../../styles/font.css';
import '../../styles/typography.css';
import './globals.css';

import type { Metadata } from 'next';
import QueryProvider from './QueryProvider';
import { OverlayProvider } from '@/components/Overlay/OverlayProvider';

import QueryProvider from './QueryProvider';
import type { Metadata } from 'next';

export const metadata: Metadata = {
title: 'PosePicker',
Expand Down Expand Up @@ -51,9 +50,9 @@ export default function RootLayout({ children }: { children: React.ReactNode })
<html lang="ko">
<body className="flex h-[100dvh] w-screen touch-none justify-center bg-slate-100 py-px">
<div className="h-full w-full max-w-440 bg-white text-primary drop-shadow-2xl">
<QueryProvider>
<OverlayProvider>{children}</OverlayProvider>
</QueryProvider>
<QueryProvider>
<OverlayProvider>{children}</OverlayProvider>
</QueryProvider>
<div id="portal" />
</div>
</body>
Expand Down
2 changes: 1 addition & 1 deletion src/components/Button/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { StrictPropsWithChildren } from '@/types';

import type { ButtonHTMLAttributes, HTMLAttributes, PropsWithChildren } from 'react';
import type { ButtonHTMLAttributes } from 'react';

export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
className?: string;
Expand Down
2 changes: 1 addition & 1 deletion src/components/Header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export default function Header({
...props
}: HeaderProps) {
return (
<div className="fixed inset-x-0 top-8 bg-white px-20">
<div className="fixed inset-x-0 top-8 bg-white">
<header
className={`flex h-48 items-center justify-between ${className ? className : ''}`}
{...props}
Expand Down
2 changes: 1 addition & 1 deletion src/components/Modal/Popup.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { StrictPropsWithChildren } from '@/types';
import ModalWrapper from './ModalWrapper';
import { StrictPropsWithChildren } from '@/types';

interface PopupProps {
className?: string;
Expand Down
3 changes: 1 addition & 2 deletions src/components/Overlay/OverlayController.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
/** @tossdocs-ignore */
import { Ref, useImperativeHandle, forwardRef, useEffect, useState, useCallback } from 'react';
import { Ref, forwardRef, useCallback, useEffect, useImperativeHandle, useState } from 'react';

import { CreateOverlayElement } from './type';

Expand Down
4 changes: 2 additions & 2 deletions src/components/Overlay/OverlayProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
'use client';

import React, {
createContext,
PropsWithChildren,
ReactNode,
createContext,
useCallback,
useMemo,
useState,
Expand Down Expand Up @@ -41,7 +41,7 @@ export function OverlayProvider({ children }: PropsWithChildren) {
return (
<OverlayContext.Provider value={context}>
{children}
{[...overlayById.entries()].map(([id, element]) => (
{Array.from(overlayById.entries()).map(([id, element]) => (
<React.Fragment key={id}>{element}</React.Fragment>
))}
</OverlayContext.Provider>
Expand Down
3 changes: 2 additions & 1 deletion src/components/Overlay/useOverlay.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useContext, useEffect, useMemo, useRef, useState } from 'react';

import { OverlayControlRef, OverlayController } from './OverlayController';
import { OverlayContext } from './OverlayProvider';
import { OverlayController, OverlayControlRef } from './OverlayController';
import { CreateOverlayElement } from './type';

let elementId = 1;
Expand Down
3 changes: 2 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
"jsx": "preserve",
"incremental": true,
"paths": {
"@/*": ["./src/*"]
"@/*": ["./src/*"],
"#/*": ["./public/*"]
},
"plugins": [
{
Expand Down