diff --git a/package.json b/package.json index 19d87961..784fa8b3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { - "name": "soma", - "version": "0.1.0", + "name": "inforum", + "version": "1.0.0", "private": true, "scripts": { "dev": "next dev", diff --git a/public/img/profile.png b/public/img/profile.png deleted file mode 100644 index b398aa2a..00000000 Binary files a/public/img/profile.png and /dev/null differ diff --git a/public/next.svg b/public/next.svg deleted file mode 100644 index 5174b28c..00000000 --- a/public/next.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/vercel.svg b/public/vercel.svg deleted file mode 100644 index d2f84222..00000000 --- a/public/vercel.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx index 192f5760..fd9e8e91 100644 --- a/src/app/login/page.tsx +++ b/src/app/login/page.tsx @@ -1,3 +1,4 @@ +import GoogleLoginBtn from '@/components/GoogleLoginBtn'; import LoginForm from '@/components/LoginForm'; import { Metadata } from 'next'; import Link from 'next/link'; @@ -18,7 +19,8 @@ export default function LoginPage() {

Inforum

-
+ +

계정이 없으신가요?

diff --git a/src/app/page.tsx b/src/app/page.tsx index 6fd11c8f..c6c38a6e 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,44 +1,103 @@ 'use client'; +import Image from 'next/image'; import Link from 'next/link'; -import { useState } from 'react'; +import { useRef, useState } from 'react'; import TypeIt from 'typeit-react'; +import landing from '@/assets/landing.gif'; +import { + BsFillArrowDownCircleFill, + BsFillArrowUpCircleFill, +} from 'react-icons/bs'; export default function LandingPage() { - const [state, setState] = useState(false); + const [readyState, setReadyState] = useState(false); + const firstScreenRef = useRef(null); + + const scrolltoTop = () => { + if (firstScreenRef.current) { + firstScreenRef.current.scrollIntoView({ behavior: 'smooth' }); + } + }; + return ( -
-

- { - setState(true); - }, - }} - > - 개발 기록을 쉽고 즐겁게, 인포럼 - -

+
-

- 자동 텍스트 생성 기능을 통해 글을 쉽고 빠르게 작성하세요 -
- 파스텔톤 메모에 개발 기록을 간단하게 작성해보세요 +

+ { + setReadyState(true); + }, + }} + > + 개발 기록을 쉽고 즐겁게, 인포럼 + +

+
+

+ 자동 텍스트 생성 기능을 통해 글을 쉽고 빠르게 작성하세요 +
+ 파스텔톤 메모에 개발 기록을 간단하게 작성해보세요 +

+ + + +
+ +
+
+

+ 질문을 작성 후 ++를 입력해 text를 자동 생성해보세요!

- - - +
+ landing +
+
+

지원 예정

+
+
    +
  • + story 기능 +
  • +
  • + 질문 서비스 +
  • +
  • + 등급 제도 +
  • +
  • + 사용자 log 기반
    + 나만의 포트폴리오 +
  • +
+
); diff --git a/src/app/signup/nickname/[slug]/page.tsx b/src/app/signup/nickname/[slug]/page.tsx new file mode 100644 index 00000000..03bec0db --- /dev/null +++ b/src/app/signup/nickname/[slug]/page.tsx @@ -0,0 +1,92 @@ +'use client'; + +import BlueBtn from '@/components/shared/BlueBtn'; +import IsValidBtn from '@/components/shared/IsValidBtn'; +import PromptgMessage from '@/components/shared/PromptMessage'; +import { checkNickname, registerNickname } from '@/service/auth'; +import { validateNickname } from '@/service/validation'; +import { useRouter } from 'next/navigation'; +import { useState } from 'react'; + +type Props = { + params: { + slug: number; + }; +}; + +export default function SignupNicknameSettingPage({ params: { slug } }: Props) { + const router = useRouter(); + const [nickname, setNickname] = useState(''); + const [isValidNickname, setIsValidNickname] = useState(false); + + const [messageText, setMessageText] = useState(''); + const [messageType, setMessageType] = useState(false); // true : 성공 메시지 false : 경고 메시지 + const [isMessageVisible, setIsMessageVisible] = useState(false); + + const handleIsValidNickname = () => { + if (!validateNickname(nickname)) { + showMessage('닉네임 형식에 맞지 않습니다.', false); + setIsValidNickname(false); + return; + } + + checkNickname(nickname).then((data) => { + showMessage(data.message, data.valid); + setIsValidNickname(data.valid ? true : false); + }); + }; + + const handleClick = () => { + if (!isValidNickname) { + showMessage('닉네임 설정에 문제가 있습니다.', false); + return; + } + + registerNickname(nickname, slug).then(() => { + router.push(`/signup/setting/${slug}`); + }); + }; + + const showMessage = (text: string, type: boolean) => { + setMessageText(text); + setMessageType(type); + setIsMessageVisible(true); + setTimeout(() => { + setIsMessageVisible(false); + }, 2000); + }; + + return ( +
+

Inforum

+ +
+ +
+ setNickname(e.target.value)} + required + placeholder="4~14자리 (영어, 숫자 : 1자, 한글 : 2자)" + /> + +
+
+ +
+ ); +} diff --git a/src/assets/icons/google_icon.svg b/src/assets/icons/google_icon.svg new file mode 100644 index 00000000..c5fa0b66 --- /dev/null +++ b/src/assets/icons/google_icon.svg @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/landing.gif b/src/assets/landing.gif new file mode 100644 index 00000000..ca25c8b2 Binary files /dev/null and b/src/assets/landing.gif differ diff --git a/src/components/GoogleLoginBtn.tsx b/src/components/GoogleLoginBtn.tsx new file mode 100644 index 00000000..9ab11307 --- /dev/null +++ b/src/components/GoogleLoginBtn.tsx @@ -0,0 +1,21 @@ +'use client'; + +import Link from 'next/link'; +import googleIcon from '../assets/icons/google_icon.svg'; + +import Image from 'next/image'; + +export default function GoogleLoginBtn() { + return ( + + + + ); +} diff --git a/src/components/LoginForm.tsx b/src/components/LoginForm.tsx index 3ba8a0d9..de1262a3 100644 --- a/src/components/LoginForm.tsx +++ b/src/components/LoginForm.tsx @@ -75,7 +75,7 @@ export default function LoginForm() { required placeholder="비밀번호" /> - {}} extraStyle="my-5" /> + {}} extraStyle="my-2" /> ); } diff --git a/src/components/MyInfoForm.tsx b/src/components/MyInfoForm.tsx index 482653c1..7d76f68a 100644 --- a/src/components/MyInfoForm.tsx +++ b/src/components/MyInfoForm.tsx @@ -15,7 +15,7 @@ import BlueBtn from './shared/BlueBtn'; import BlueBtn2 from './shared/BlueBtn2'; import { useRouter } from 'next/navigation'; import Link from 'next/link'; -import { registerUserInfo, updateUserInfo } from '@/service/auth'; +import { checkUser, registerUserInfo, updateUserInfo } from '@/service/auth'; import { UserInfo2 } from '@/types'; type Props = { @@ -55,7 +55,9 @@ export default function MyInfoForm({ userId, userInfo, isSignup }: Props) { tags, imageUrl === '' && imageFile === null ? 'true' : 'false' ).then(() => { - router.push('/login'); + checkUser().then((data) => { + router.push(data.isLogin ? '/memos' : '/login'); + }); }) : updateUserInfo( userId, diff --git a/src/components/memo/MemoCard.tsx b/src/components/memo/MemoCard.tsx index 0ba32612..c2e48924 100644 --- a/src/components/memo/MemoCard.tsx +++ b/src/components/memo/MemoCard.tsx @@ -13,38 +13,39 @@ export default function MemoCard({ memoDescription, memoColor, createdDate, + authorId, authorName, authorProfileImagePath, likes, }, }: Props) { return ( - -
- - +
+ +

{memoTitle}

{memoDescription}

-
- + +
); } diff --git a/src/components/memo/MemoCardHeader.tsx b/src/components/memo/MemoCardHeader.tsx index 95fe7c82..68ba5de6 100644 --- a/src/components/memo/MemoCardHeader.tsx +++ b/src/components/memo/MemoCardHeader.tsx @@ -1,12 +1,14 @@ import Image from 'next/image'; -import exampleImg from '../../../public/img/profile.png'; +import basicProfileImg from '@/assets/profile.svg'; import fillHeart from '../../assets/icons/heart_fill.svg'; +import Link from 'next/link'; type Props = { createDate: string; authorName: string; likes: number; imagePath: string; + authorId: number; }; export default function MemoCardHeader({ @@ -14,17 +16,20 @@ export default function MemoCardHeader({ authorName, likes, imagePath, + authorId, }: Props) { return (
- exampleImg + + profileImg +

{authorName}

{createDate}

diff --git a/src/service/auth.ts b/src/service/auth.ts index db599212..659c9155 100644 --- a/src/service/auth.ts +++ b/src/service/auth.ts @@ -181,3 +181,16 @@ export async function getUserInfo2(userId: number): Promise { }) .catch(console.error); } + +export async function registerNickname(nickname: string, userId: number) { + return fetch( + `${process.env.NEXT_PUBLIC_SERVER_IP_ADDRESS_SECURE}/users/nickname/${userId}`, + { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ nickname }), + } + ) + .then((res) => res.json()) + .catch(console.error); +}