Skip to content

Commit

Permalink
Merge pull request #123 from naya-h2/feat/metaTag
Browse files Browse the repository at this point in the history
✨ feat: 페이지별 메타태그 설정
  • Loading branch information
han-kimm authored Feb 20, 2024
2 parents 11c92fd + 87f4a93 commit 282a381
Show file tree
Hide file tree
Showing 19 changed files with 596 additions and 440 deletions.
27 changes: 16 additions & 11 deletions app/(route)/(bottom-nav)/mypage/page.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
"use client";

import MetaTag from "@/components/MetaTag";
import Tabs from "@/components/Tabs";
import DottedLayout from "@/components/layout/DottedLayout";
import { getSession } from "@/store/session/cookies";
import { META_TAG } from "@/constants/metaTag";
import UserProfile from "./_components/UserProfile";
import MyArtistTab from "./_components/tab/MyArtistTab";
import MyEventTab from "./_components/tab/MyEventTab";
Expand All @@ -12,18 +14,21 @@ const MyPage = () => {
const session = getSession();

return (
<DottedLayout size="extrawide">
<div className="flex h-screen w-full flex-col gap-24 pb-72 pc:h-[calc(100vh-7.2rem)] pc:flex-row pc:items-start pc:pb-0 pc:pt-48">
<UserProfile />
<div className="h-full pc:w-[83.4rem]">
<Tabs names={["행사", "아티스트", "후기"]} isNarrow>
<MyEventTab userId={session?.user?.userId ?? ""} />
<MyArtistTab userId={session?.user?.userId ?? ""} />
<MyReviewTab userId={session?.user?.userId ?? ""} />
</Tabs>
<>
<MetaTag title={META_TAG.mypage["title"]} description={META_TAG.mypage["description"]} />
<DottedLayout size="extrawide">
<div className="flex h-screen w-full flex-col gap-24 pb-72 pc:h-[calc(100vh-7.2rem)] pc:flex-row pc:items-start pc:pb-0 pc:pt-48">
<UserProfile />
<div className="h-full pc:w-[83.4rem]">
<Tabs names={["행사", "아티스트", "후기"]} isNarrow>
<MyEventTab userId={session?.user?.userId ?? ""} />
<MyArtistTab userId={session?.user?.userId ?? ""} />
<MyReviewTab userId={session?.user?.userId ?? ""} />
</Tabs>
</div>
</div>
</div>
</DottedLayout>
</DottedLayout>
</>
);
};

Expand Down
36 changes: 19 additions & 17 deletions app/(route)/(bottom-nav)/page.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import ArtistList from "@/(route)/_components/artist-list/ArtistList";
import { Session } from "inspector";
import { cookies } from "next/headers";
import MetaTag from "@/components/MetaTag";
import DottedLayout from "@/components/layout/DottedLayout";
import { getSession } from "@/store/session/cookies";
import { META_TAG } from "@/constants/metaTag";
import Logo from "@/public/icon/logo.svg";
import Footer from "../_components/Footer";
import FavArtistEventsCarousel from "../_components/carousel/FavArtistEventsCarousel";
Expand All @@ -11,20 +10,23 @@ import PopularEventsCarousel from "../_components/carousel/PopularEventsCarousel

const Home = () => {
return (
<DottedLayout size="wide">
<header className="sticky left-0 top-0 z-nav h-88 w-full bg-white-black px-20 pb-16 pt-48 pc:hidden">
<Logo />
</header>
<div className="flex flex-col gap-40 pb-72 pc:items-center pc:pb-0 pc:pt-52">
<main className="flex flex-col gap-40 overflow-hidden pc:w-[112rem]">
<FavArtistEventsCarousel />
<PopularEventsCarousel />
<NewestEventsCarousel />
<ArtistList />
</main>
</div>
<Footer />
</DottedLayout>
<>
<MetaTag title={META_TAG.landing["title"]} />
<DottedLayout size="wide">
<header className="sticky left-0 top-0 z-nav h-88 w-full bg-white-black px-20 pb-16 pt-48 pc:hidden">
<Logo />
</header>
<div className="flex flex-col gap-40 pb-72 pc:items-center pc:pb-0 pc:pt-52">
<main className="flex flex-col gap-40 overflow-hidden pc:w-[112rem]">
<FavArtistEventsCarousel />
<PopularEventsCarousel />
<NewestEventsCarousel />
<ArtistList />
</main>
</div>
<Footer />
</DottedLayout>
</>
);
};
export default Home;
127 changes: 67 additions & 60 deletions app/(route)/(bottom-nav)/search/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { keepPreviousData, useInfiniteQuery, useQueryClient } from "@tanstack/re
import dynamic from "next/dynamic";
import { ReadonlyURLSearchParams, usePathname, useRouter, useSearchParams } from "next/navigation";
import { Suspense, useCallback, useEffect, useState } from "react";
import MetaTag from "@/components/MetaTag";
import HorizontalEventCard from "@/components/card/HorizontalEventCard";
import SearchInput from "@/components/input/SearchInput";
import DottedLayout from "@/components/layout/DottedLayout";
Expand Down Expand Up @@ -178,68 +179,74 @@ const SearchPage = () => {
}, [position]);

return (
<DottedLayout size="wide">
<main className="relative w-full px-20 pb-84 pt-160 pc:p-0 pc:pb-84">
<section className="fixed left-0 right-0 top-0 z-nav flex w-full flex-col bg-white-black text-14 text-gray-500 shadow-top pc:static pc:shadow-none">
<div className="bg-white-black px-20 pb-8 pt-40 pc:px-0 pc:pb-20 pc:pt-[7rem]">
<SearchInput keyword={keyword} setKeyword={setKeyword} initialKeyword={initialKeyword} placeholder="최애의 이름으로 행사를 찾아보세요!" />
</div>
<div className={`animate-fadeIn px-20 pb-8 pc:p-0 ${visible ? "block" : "hidden pc:block"}`}>
<div className="flex gap-4 pb-12 pc:pb-32">
<FilterButton onClick={() => openBottomSheet(BOTTOM_SHEET.bigRegion)} selected={Boolean(filter.bigRegion)}>
{filter.bigRegion || "시/도"}
</FilterButton>
{filter.bigRegion && (
<FilterButton onClick={() => openBottomSheet(BOTTOM_SHEET.smallRegion)} selected={Boolean(filter.smallRegion)}>
{filter.smallRegion}
</FilterButton>
)}
<FilterButton onClick={() => openBottomSheet(BOTTOM_SHEET.calender)} selected={Boolean(filter.startDate)}>
{formattedDate ?? "기간"}
</FilterButton>
<FilterButton onClick={() => openBottomSheet(BOTTOM_SHEET.gift)} selected={Boolean(filter.gifts.length)}>
{formattedGift ?? "특전"}
</FilterButton>
<>
<MetaTag
title={keyword ? `${keyword}: 검색 결과` : "행사 둘러보기"}
description={keyword ? `${keyword}의 Opener 행사 검색 결과입니다.` : "Opener에 등록된 각종 오프라인 행사들을 구경해 보세요."}
/>
<DottedLayout size="wide">
<main className="relative w-full px-20 pb-84 pt-160 pc:p-0 pc:pb-84">
<section className="fixed left-0 right-0 top-0 z-nav flex w-full flex-col bg-white-black text-14 text-gray-500 shadow-top pc:static pc:shadow-none">
<div className="bg-white-black px-20 pb-8 pt-40 pc:px-0 pc:pb-20 pc:pt-[7rem]">
<SearchInput keyword={keyword} setKeyword={setKeyword} initialKeyword={initialKeyword} placeholder="최애의 이름으로 행사를 찾아보세요!" />
</div>
<div className="flex items-center gap-8">
<SortIcon />
<SortButton onClick={() => setSort("최신순")} selected={sort === "최신순"}>
최신순
</SortButton>
<SortButton onClick={() => setSort("인기순")} selected={sort === "인기순"}>
인기순
</SortButton>
<button onClick={resetFilter} type="button" className="ml-auto flex gap-[0.3rem] text-14 text-gray-400">
초기화
<ResetIcon />
</button>
<div className={`animate-fadeIn px-20 pb-8 pc:p-0 ${visible ? "block" : "hidden pc:block"}`}>
<div className="flex gap-4 pb-12 pc:pb-32">
<FilterButton onClick={() => openBottomSheet(BOTTOM_SHEET.bigRegion)} selected={Boolean(filter.bigRegion)}>
{filter.bigRegion || "시/도"}
</FilterButton>
{filter.bigRegion && (
<FilterButton onClick={() => openBottomSheet(BOTTOM_SHEET.smallRegion)} selected={Boolean(filter.smallRegion)}>
{filter.smallRegion}
</FilterButton>
)}
<FilterButton onClick={() => openBottomSheet(BOTTOM_SHEET.calender)} selected={Boolean(filter.startDate)}>
{formattedDate ?? "기간"}
</FilterButton>
<FilterButton onClick={() => openBottomSheet(BOTTOM_SHEET.gift)} selected={Boolean(filter.gifts.length)}>
{formattedGift ?? "특전"}
</FilterButton>
</div>
<div className="flex items-center gap-8">
<SortIcon />
<SortButton onClick={() => setSort("최신순")} selected={sort === "최신순"}>
최신순
</SortButton>
<SortButton onClick={() => setSort("인기순")} selected={sort === "인기순"}>
인기순
</SortButton>
<button onClick={resetFilter} type="button" className="ml-auto flex gap-[0.3rem] text-14 text-gray-400">
초기화
<ResetIcon />
</button>
</div>
</div>
</div>
</section>
<section className="flex flex-wrap items-center gap-x-24">
{isEmpty ? (
<div className="pt-36 text-14 font-500 text-gray-500">검색 결과가 없습니다.</div>
) : (
events?.pages.map((page) => page.eventList.map((event) => <HorizontalEventCard key={event.id} data={event} />))
)}
<DeferredSuspense fallback={<HorizontalEventCardSkeleton />} isFetching={isFetching} />
<div ref={containerRef} className="h-20 w-full" />
</section>
</main>
{bottomSheet === BOTTOM_SHEET.bigRegion && <BigRegionBottomSheet closeBottomSheet={closeBottomSheet} refs={refs} setBigRegionFilter={setBigRegionFilter} />}
{bottomSheet === BOTTOM_SHEET.smallRegion && (
<SmallRegionBottomSheet
closeBottomSheet={closeBottomSheet}
refs={refs}
bigRegion={filter.bigRegion as (typeof BIG_REGIONS)[number]}
setSmallRegionFilter={setSmallRegionFilter}
/>
)}
{bottomSheet === BOTTOM_SHEET.calender && (
<CalenderBottomSheet closeBottomSheet={closeBottomSheet} refs={refs} setStartDateFilter={setStartDateFilter} setEndDateFilter={setEndDateFilter} />
)}
{bottomSheet === BOTTOM_SHEET.gift && <GiftBottomSheet refs={refs} closeBottomSheet={closeBottomSheet} setGiftsFilter={setGiftsFilter} selected={filter.gifts} />}
</DottedLayout>
</section>
<section className="flex flex-wrap items-center gap-x-24">
{isEmpty ? (
<div className="pt-36 text-14 font-500 text-gray-500">검색 결과가 없습니다.</div>
) : (
events?.pages.map((page) => page.eventList.map((event) => <HorizontalEventCard key={event.id} data={event} />))
)}
<DeferredSuspense fallback={<HorizontalEventCardSkeleton />} isFetching={isFetching} />
<div ref={containerRef} className="h-20 w-full" />
</section>
</main>
{bottomSheet === BOTTOM_SHEET.bigRegion && <BigRegionBottomSheet closeBottomSheet={closeBottomSheet} refs={refs} setBigRegionFilter={setBigRegionFilter} />}
{bottomSheet === BOTTOM_SHEET.smallRegion && (
<SmallRegionBottomSheet
closeBottomSheet={closeBottomSheet}
refs={refs}
bigRegion={filter.bigRegion as (typeof BIG_REGIONS)[number]}
setSmallRegionFilter={setSmallRegionFilter}
/>
)}
{bottomSheet === BOTTOM_SHEET.calender && (
<CalenderBottomSheet closeBottomSheet={closeBottomSheet} refs={refs} setStartDateFilter={setStartDateFilter} setEndDateFilter={setEndDateFilter} />
)}
{bottomSheet === BOTTOM_SHEET.gift && <GiftBottomSheet refs={refs} closeBottomSheet={closeBottomSheet} setGiftsFilter={setGiftsFilter} selected={filter.gifts} />}
</DottedLayout>
</>
);
};

Expand Down
137 changes: 71 additions & 66 deletions app/(route)/(bottom-nav)/signin/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ import { usePathname, useRouter } from "next/navigation";
import { useState } from "react";
import { SubmitHandler, useForm } from "react-hook-form";
import toast from "react-hot-toast";
import MetaTag from "@/components/MetaTag";
import Button from "@/components/button";
import InputText from "@/components/input/InputText";
import PinkLayout from "@/components/layout/PinkLayout";
import useEnterNext from "@/hooks/useEnterNext";
import { deleteCookies, setCookies, setSession } from "@/store/session/cookies";
import { ERROR_MESSAGES, REG_EXP } from "@/utils/signupValidation";
import { SHOT_SIGNIN } from "@/constants/confetti";
import { META_TAG } from "@/constants/metaTag";
import { OAUTH } from "@/constants/oauth";
import ArrowLeft from "@/public/icon/arrow-left_lg.svg";
import Logo from "@/public/icon/logo.svg";
Expand Down Expand Up @@ -93,74 +95,77 @@ const SignInPage = () => {
};

return (
<PinkLayout size="narrow">
<header className="flex h-72 w-full justify-between bg-white-white px-20 pb-12 pt-36">
<button onClick={() => router.back()}>
<ArrowLeft />
</button>
</header>
<div className="flex-center flex-col px-20 pt-80 pc:pb-20">
<Link href="/">
<Logo />
</Link>
<form ref={formSection} onSubmit={handleSubmit(handleSignin)} className="flex-center mt-40 w-full flex-col pb-16">
<InputText
name="email"
placeholder="[email protected]"
control={control}
onKeyDown={handleEnterNext}
rules={{ required: ERROR_MESSAGES.email.emailField, pattern: { value: REG_EXP.CHECK_EMAIL, message: ERROR_MESSAGES.email.emailPattern } }}
noButton
/>
<InputText
name="password"
type="password"
placeholder="8자 이상 입력해주세요."
control={control}
rules={{ required: ERROR_MESSAGES.password.passwordField, pattern: { value: REG_EXP.CHECK_PASSWORD, message: ERROR_MESSAGES.password.passwordPattern } }}
onKeyDown={handleEnterNext}
/>
<div className={`mt-16 overflow-hidden transition-all ${submitState.isLoading ? "w-4/5" : "w-full"} ${submitState.isError ? "animate-[brrr_0.2s_0.2s]" : ""}`}>
<Button isSubmit isDisabled={!formState.isValid || !!formState.errors.email || !!formState.errors.password || submitState.isLoading}>
<div className="relative h-full w-full">
<span className={`absolute w-max transition-all ${formState.isSubmitted ? "top-48" : "absolute-center"}`}>로그인</span>
<span className={`absolute w-max transition-all ${submitState.isLoading ? "absolute-center" : "-top-48"}`}>
<LoadingDot />
</span>
<span className={`absolute w-max transition-all ${submitState.isLoading ? "top-48" : formState.isSubmitted ? "absolute-center" : "top-48"}`}>
{submitState.isError ? "다시 로그인하기" : "성공!"}
</span>
</div>
</Button>
</div>
</form>
<div className="flex-center mb-56 gap-20 text-14 font-500 text-gray-500">
<Link href={`/signup?email=${watch("email")}`} scroll={false}>
회원가입
</Link>
<div className="h-16 border" />
<Link href="">비밀번호 찾기</Link>
</div>
<div className="flex w-full flex-col gap-20">
<Link
href={OAUTH.kakao()}
onClick={() => setCookies("pathname", pathname, { path: "/" })}
className="flex-center w-full gap-8 rounded-sm bg-[#FEE500] py-16 text-16 font-500"
>
<KakaoLogo />
<p>카카오 계정으로 로그인</p>
</Link>
<Link
href={OAUTH.naver()}
onClick={() => setCookies("pathname", pathname, { path: "/" })}
className="flex-center w-full gap-8 rounded-sm bg-[#03CF5D] py-16 text-16 font-500 text-white-white"
>
<NaverLogo fill="white" />
<p>네이버 계정으로 로그인</p>
<>
<MetaTag title={META_TAG.signin["title"]} description={META_TAG.signin["description"]} />
<PinkLayout size="narrow">
<header className="flex h-72 w-full justify-between bg-white-white px-20 pb-12 pt-36">
<button onClick={() => router.back()}>
<ArrowLeft />
</button>
</header>
<div className="flex-center flex-col px-20 pt-80 pc:pb-20">
<Link href="/">
<Logo />
</Link>
<form ref={formSection} onSubmit={handleSubmit(handleSignin)} className="flex-center mt-40 w-full flex-col pb-16">
<InputText
name="email"
placeholder="[email protected]"
control={control}
onKeyDown={handleEnterNext}
rules={{ required: ERROR_MESSAGES.email.emailField, pattern: { value: REG_EXP.CHECK_EMAIL, message: ERROR_MESSAGES.email.emailPattern } }}
noButton
/>
<InputText
name="password"
type="password"
placeholder="8자 이상 입력해주세요."
control={control}
rules={{ required: ERROR_MESSAGES.password.passwordField, pattern: { value: REG_EXP.CHECK_PASSWORD, message: ERROR_MESSAGES.password.passwordPattern } }}
onKeyDown={handleEnterNext}
/>
<div className={`mt-16 overflow-hidden transition-all ${submitState.isLoading ? "w-4/5" : "w-full"} ${submitState.isError ? "animate-[brrr_0.2s_0.2s]" : ""}`}>
<Button isSubmit isDisabled={!formState.isValid || !!formState.errors.email || !!formState.errors.password || submitState.isLoading}>
<div className="relative h-full w-full">
<span className={`absolute w-max transition-all ${formState.isSubmitted ? "top-48" : "absolute-center"}`}>로그인</span>
<span className={`absolute w-max transition-all ${submitState.isLoading ? "absolute-center" : "-top-48"}`}>
<LoadingDot />
</span>
<span className={`absolute w-max transition-all ${submitState.isLoading ? "top-48" : formState.isSubmitted ? "absolute-center" : "top-48"}`}>
{submitState.isError ? "다시 로그인하기" : "성공!"}
</span>
</div>
</Button>
</div>
</form>
<div className="flex-center mb-56 gap-20 text-14 font-500 text-gray-500">
<Link href={`/signup?email=${watch("email")}`} scroll={false}>
회원가입
</Link>
<div className="h-16 border" />
<Link href="">비밀번호 찾기</Link>
</div>
<div className="flex w-full flex-col gap-20">
<Link
href={OAUTH.kakao()}
onClick={() => setCookies("pathname", pathname, { path: "/" })}
className="flex-center w-full gap-8 rounded-sm bg-[#FEE500] py-16 text-16 font-500"
>
<KakaoLogo />
<p>카카오 계정으로 로그인</p>
</Link>
<Link
href={OAUTH.naver()}
onClick={() => setCookies("pathname", pathname, { path: "/" })}
className="flex-center w-full gap-8 rounded-sm bg-[#03CF5D] py-16 text-16 font-500 text-white-white"
>
<NaverLogo fill="white" />
<p>네이버 계정으로 로그인</p>
</Link>
</div>
</div>
</div>
</PinkLayout>
</PinkLayout>
</>
);
};
export default SignInPage;
Loading

0 comments on commit 282a381

Please sign in to comment.