Search

Vantech Event Finder - 로컬 IT 이벤트 탐색기

Tags
Typescript
NextJS
Prisma
Created
2023.05 - 2023.08

프로젝트명

Vantech Event Finder

제작기간

2023.05.16 - 2023.08.30

개발스택

프론트엔드 : Nextjs 13 / T3 / Typescript / Mantine
백엔드 : Postgres, Prisma, TRPC

프로젝트 기획 및 소개

Vantech Event Finder 프로젝트는 밴쿠버에서 열리는 다양한 IT 이벤트를 쉽게 찾을 수 있도록 돕기 위해 기획되었습니다. 밴쿠버는 각종 취미 소모임과 다양한 네트워킹 이벤트가 매달 개최됩니다. 그에 맞게 Meet Up 어플이나 Eventbrite 등 모임을 찾을 수 있는 어플도 다양합니다. 그 중에도 IT 에 관련된 이벤트를 한 곳에 모아 쉽게 검색하고 관리할 수 있는 도구를 만들어 보자는 생각으로 프로젝트가 시작되었습니다

프로젝트 주요 기능

1. Google Map API

날짜, 위치, 카테고리 등 다양한 필터링 옵션을 제공하여 사용자가 원하는 이벤트를 빠르게 찾을 수 있도록 합니다. 주요 기능은 다음과 같습니다:
위치 기반 검색: 사용자가 현재 위치를 기준으로 주변 이벤트를 검색할 수 있습니다.
날짜별 검색: 특정 날짜나 기간 동안 열리는 이벤트를 검색할 수 있습니다.
이벤트 핀: 각 이벤트 위치에 핀을 표시하여 지도를 통해 이벤트 위치를 직관적으로 확인할 수 있습니다.
코드 예시
import { useState, useEffect } from "react"; import { useMantineColorScheme } from "@mantine/core"; import { mapTheme, loader } from "~/utils"; export const GoogleMaps = () => { const [map, setMap] = useState<google.maps.Map>(); const { colorScheme } = useMantineColorScheme(); useEffect(() => { const fetchMap = async () => { await loader.load().then(() => { navigator.geolocation.getCurrentPosition( (position) => { const { latitude, longitude } = position.coords; const mapOptions = { center: { lat: latitude, lng: longitude }, zoom: 16, styles: colorScheme === "dark" ? mapTheme.dark : mapTheme.light, }; const newMap = new window.google.maps.Map( document.getElementById("map") as HTMLElement, mapOptions ); const marker = new window.google.maps.Marker({ position: { lat: latitude, lng: longitude }, map: newMap, }); setMap(newMap); } }); }); }; void fetchMap(); }, [colorScheme]); return <div id="map" style={{ height: "100%", width: "100%" }}></div>; };
TypeScript
복사

2. next-auth 로 login & signup 기능 구현

로그인 기능은 next-auth를 사용하여 구현되었습니다. 사용자는 이메일과 비밀번호를 입력하여 로그인할 수 있으며 로그인 성공 시 홈 페이지로 리디렉션됩니다. 폼 유효성 검사 및 상태 관리를 위해 Mantine의 useForm 훅을 사용합니다. 로그인 요청은 signIn 함수를 통해 처리됩니다.
코드 예제
1.
next-auth 설정 파일 (app/api/auth/[...nextauth].ts)
import NextAuth from 'next-auth'; import Providers from 'next-auth/providers'; export default NextAuth({ providers: [ Providers.Credentials({ name: 'Credentials', credentials: { email: { label: "Email", type: "email" }, password: { label: "Password", type: "password" } }, async authorize(crd) { const user = await yourUserLoginFunction(crd.email, crd.password); return user || null ; } }) ], session: { jwt: true }, // ... });
TypeScript
복사
2.
로그인 페이지 (app/(auth)/login/page.tsx)
const LogIn: React.FC = () => { const { data: session } = useSession(); const router = useRouter(); const [error, setError] = useState(''); const theme = useMantineTheme(); const form = useForm({ initialValues: { email: '', password: '', rememberPassword: false, }, validateInputOnChange: true, validate: { password: (value) => (value.length < 1 ? 'Please input Password' : null), email: (value) => (value.length < 1 ? 'Please input email address' : null), }, }); const isDisabled = Object.keys(form.errors).length !== 0; const handleSubmit = async (values: { email: string; password: string; rememberPassword: boolean }) => { try { const result = await signIn('credentials', { redirect: false, email: values.email, password: values.password, }); if (!result?.error) { if (!session) { await signIn('credentials', { redirect: false, email: values.email, password: values.password, }); } form.reset(); router.push('/'); } else { form.reset(); throw new Error(); } } catch (error) { setError('Failed to login!'); } }; if (session) router.push('/'); }; export default LogIn;
TypeScript
복사

3. Prisma를 사용한 Postgres 데이터베이스 설정

Prisma를 사용하여 Postgres 데이터베이스를 설정하고, 데이터베이스와의 상호작용을 단순화하였습니다.
이 프로젝트의 데이터베이스 관리에는 Prisma가 사용되었습니다. Prisma를 사용하여 Postgres 데이터베이스를 설정하고 사용자, 세션, 계정 및 관련된 인증 토큰에 타입을 부여해서 개발 생산성을 높였습니다.
코드 예시
// This is your Prisma schema file, generator client { provider = "prisma-client-js" } datasource db { provider = "postgresql" url = env("DATABASE_URL") } // ----- App Schema ------ // model FavEvent { id String @id @default(cuid()) userId String date DateTime @default(now()) } model User { id String @id @default(cuid()) name String? email String? @unique password String emailVerified DateTime? image String? accounts Account[] sessions Session[] } // ...
TypeScript
복사
메인으로 돌아가기