diff --git a/package-lock.json b/package-lock.json index eee04dc..b0ae7f9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "@mui/material": "^5.14.18", "axios": "^1.6.2", "next": "14.0.3", + "next-auth": "^4.24.5", "react": "^18", "react-dom": "^18", "recoil": "^0.7.7", @@ -999,6 +1000,14 @@ "node": ">= 8" } }, + "node_modules/@panva/hkdf": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@panva/hkdf/-/hkdf-1.1.1.tgz", + "integrity": "sha512-dhPeilub1NuIG0X5Kvhh9lH4iW3ZsHlnzwgwbOlgwQ2wG1IqFzsgHqmKPk3WzsdWAeaxKJxgM0+W433RmN45GA==", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/@popperjs/core": { "version": "2.11.8", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", @@ -1771,6 +1780,14 @@ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/cosmiconfig": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", @@ -3426,6 +3443,14 @@ "jiti": "bin/jiti.js" } }, + "node_modules/jose": { + "version": "4.15.4", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.4.tgz", + "integrity": "sha512-W+oqK4H+r5sITxfxpSU+MMdr/YSWGvgZMQDIsNoBDGGy4i7GBPTtvFKibQzW06n3U3TqHjhvBJsirShsEJ6eeQ==", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -3583,7 +3608,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, "dependencies": { "yallist": "^4.0.0" }, @@ -3738,6 +3762,33 @@ } } }, + "node_modules/next-auth": { + "version": "4.24.5", + "resolved": "https://registry.npmjs.org/next-auth/-/next-auth-4.24.5.tgz", + "integrity": "sha512-3RafV3XbfIKk6rF6GlLE4/KxjTcuMCifqrmD+98ejFq73SRoj2rmzoca8u764977lH/Q7jo6Xu6yM+Re1Mz/Og==", + "dependencies": { + "@babel/runtime": "^7.20.13", + "@panva/hkdf": "^1.0.2", + "cookie": "^0.5.0", + "jose": "^4.11.4", + "oauth": "^0.9.15", + "openid-client": "^5.4.0", + "preact": "^10.6.3", + "preact-render-to-string": "^5.1.19", + "uuid": "^8.3.2" + }, + "peerDependencies": { + "next": "^12.2.5 || ^13 || ^14", + "nodemailer": "^6.6.5", + "react": "^17.0.2 || ^18", + "react-dom": "^17.0.2 || ^18" + }, + "peerDependenciesMeta": { + "nodemailer": { + "optional": true + } + } + }, "node_modules/node-releases": { "version": "2.0.13", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", @@ -3761,6 +3812,11 @@ "node": ">=0.10.0" } }, + "node_modules/oauth": { + "version": "0.9.15", + "resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz", + "integrity": "sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA==" + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -3887,6 +3943,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/oidc-token-hash": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-5.0.3.tgz", + "integrity": "sha512-IF4PcGgzAr6XXSff26Sk/+P4KZFJVuHAJZj3wgO3vX2bMdNVp/QXTP3P7CEm9V1IdG8lDLY3HhiqpsE/nOwpPw==", + "engines": { + "node": "^10.13.0 || >=12.0.0" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -3896,6 +3960,28 @@ "wrappy": "1" } }, + "node_modules/openid-client": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-5.6.1.tgz", + "integrity": "sha512-PtrWsY+dXg6y8mtMPyL/namZSYVz8pjXz3yJiBNZsEdCnu9miHLB4ELVC85WvneMKo2Rg62Ay7NkuCpM0bgiLQ==", + "dependencies": { + "jose": "^4.15.1", + "lru-cache": "^6.0.0", + "object-hash": "^2.2.0", + "oidc-token-hash": "^5.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/openid-client/node_modules/object-hash": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz", + "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==", + "engines": { + "node": ">= 6" + } + }, "node_modules/optionator": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", @@ -4175,6 +4261,26 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "dev": true }, + "node_modules/preact": { + "version": "10.19.2", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.19.2.tgz", + "integrity": "sha512-UA9DX/OJwv6YwP9Vn7Ti/vF80XL+YA5H2l7BpCtUr3ya8LWHFzpiO5R+N7dN16ujpIxhekRFuOOF82bXX7K/lg==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, + "node_modules/preact-render-to-string": { + "version": "5.2.6", + "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-5.2.6.tgz", + "integrity": "sha512-JyhErpYOvBV1hEPwIxc/fHWXPfnEGdRKxc8gFdAZ7XV4tlzyzG847XAyEZqoDnynP88akM4eaHcSOzNcLWFguw==", + "dependencies": { + "pretty-format": "^3.8.0" + }, + "peerDependencies": { + "preact": ">=10" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -4184,6 +4290,11 @@ "node": ">= 0.8.0" } }, + "node_modules/pretty-format": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-3.8.0.tgz", + "integrity": "sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==" + }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -5086,6 +5197,14 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/watchpack": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", @@ -5198,8 +5317,7 @@ "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/yaml": { "version": "2.3.4", diff --git a/package.json b/package.json index 373a9e2..992a2e4 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "@mui/material": "^5.14.18", "axios": "^1.6.2", "next": "14.0.3", + "next-auth": "^4.24.5", "react": "^18", "react-dom": "^18", "recoil": "^0.7.7", diff --git a/src/app/detail/page.tsx b/src/app/detail/page.tsx new file mode 100644 index 0000000..807196a --- /dev/null +++ b/src/app/detail/page.tsx @@ -0,0 +1,17 @@ +"use client"; + +import WeatherBar from "@/component/WeatherBar"; +import Image from "next/image"; + +export default function Detail(): JSX.Element { + return ( +
+
+ back +
+
+ +
+
+ ); +} diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx index 021bb22..93f88bf 100644 --- a/src/app/login/page.tsx +++ b/src/app/login/page.tsx @@ -1,17 +1,32 @@ "use client"; -import { Link } from "@mui/icons-material"; import "../../style/login.scss"; import CloseIcon from "@mui/icons-material/Close"; import Menubar from "../../component/MenuBar"; import { useState, ChangeEvent, FormEvent, useEffect } from "react"; import axios from "axios"; -import { useRouter } from "next/navigation"; export default function Login() { - const router = useRouter(); const [email, setEmail] = useState(""); const [pw, setPw] = useState(""); + useEffect(() => { + // 페이지 로드 시 URL에서 access_token 파싱 + const urlParams = new URLSearchParams(window.location.hash.substring(1)); + const accessToken = urlParams.get("access_token"); + + // accessToken을 로컬 스토리지에 저장 또는 백엔드로 전송 + if (accessToken) { + localStorage.setItem("accessToken", accessToken); + } + }, []); + + const onGoogleSocialLogin = async () => { + window.location.href = + "https://accounts.google.com/o/oauth2/v2/auth/oauthchooseaccount?scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive.metadata.readonly&include_granted_scopes=true&response_type=token&redirect_uri=https%3A%2F%2Fwww.jerneithe.site%2Fuser%2Flogin%2Foauth2%2Fcode%2Fgoogle&client_id=453423602833-7db2b1dbicre47rkcrpfgn20nd16l9rs.apps.googleusercontent.com&service=lso&o2v=2&theme=glif&flowName=GeneralOAuthFlow"; + }; + + // 일반 로그인 + const handleLogin = async (e: FormEvent) => { e.preventDefault(); @@ -27,13 +42,13 @@ export default function Login() { } catch (error) { console.error("login error: ", error); } - }; const handleInputChange = (setState: React.Dispatch>) => - (e: ChangeEvent) => + (e: ChangeEvent) => { setState(e.target.value); + }; return (
@@ -75,7 +90,12 @@ export default function Login() {

-
간편 로그인
+
+
간편 로그인
+
+
diff --git a/src/app/register/page.tsx b/src/app/register/page.tsx index 9118b94..2f9ac27 100644 --- a/src/app/register/page.tsx +++ b/src/app/register/page.tsx @@ -4,16 +4,15 @@ import "../../style/register.scss"; import { useState } from "react"; import InputBar from "@/component/InputBar"; import Menubar from "@/component/MenuBar"; - import axios from "axios"; ///////////////////////////해야하는 작업///////////////////////////// // 희성이형하고 같이해야함 -//1. 비밀번호 확인 기능 -//2. 이메일 인증 전에는 데이터 전송을 해주지 않고, 이메일 전송을 통해 토큰을 받았을때만 +//1. 비밀번호 확인 기능 +//2. 이메일 인증 전에는 데이터 전송을 해주지 않고, 이메일 전송을 통해 토큰을 받았을때만 // 회원가입 데이터를 전송해주는 기능 -//3. 소셜데이터 로그인 버튼과 소셜 로그인 기능 +//3. 소셜데이터 로그인 버튼과 소셜 로그인 기능 /////////////////////////////////////////////////////////////////// export default function Register(): JSX.Element { @@ -44,40 +43,34 @@ export default function Register(): JSX.Element { return inputValue === password; }; - const verify_btn = async() => { + const verify_btn = async () => { console.log("Verify 버튼이 클릭되었습니다."); - const verify_email = await axios({ - method : "POST", - url : "https://www.jerneithe.site/user/profile", - data : email + const verify_email = await axios({ + method: "POST", + url: "https://www.jerneithe.site/user/profile", + data: email, }); + }; - - } - - const caster_register = async() => { + const caster_register = async () => { const req_regdata = { email, name, nickname, password, - repassword, - } + repassword, + }; console.log(req_regdata); - const register_data = await axios({ - method : "POST", - url : "https://www.jerneithe.site/user/signup", - data : req_regdata + const register_data = await axios({ + method: "POST", + url: "https://www.jerneithe.site/user/signup", + data: req_regdata, }); - - - }; - return (
diff --git a/src/app/socialregister/page.tsx b/src/app/socialregister/page.tsx new file mode 100644 index 0000000..e99a2b9 --- /dev/null +++ b/src/app/socialregister/page.tsx @@ -0,0 +1,48 @@ +"use client"; +import { useState } from "react"; +import { useRouter } from "next/navigation"; +import axios from "axios"; + +export default function CompleteProfile() { + const [name, setName] = useState(""); + const [nickname, setNickname] = useState(""); + const router = useRouter(); + + const handleNicknameSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + try { + const response = await axios({ + method: "POST", + url: "", + data: { + name, + nickname, + }, + }); + router.push("/"); + } catch (error) { + console.error("닉네임 저장 오류:", error); + } + }; + + return ( +
+

닉네임 설정

+
+ setName(e.target.value)} + /> + setNickname(e.target.value)} + /> + +
+
+ ); +} diff --git a/src/app/upload/page.tsx b/src/app/upload/page.tsx index c8ddf30..24fb701 100644 --- a/src/app/upload/page.tsx +++ b/src/app/upload/page.tsx @@ -6,7 +6,7 @@ import "../../style/upload.scss"; import ImageUpload from "@/component/ImageUpload"; import TextArea from "@/component/TextArea"; import SelectCategory from "@/component/SelectCategory"; -import { useCallback, useEffect, useState } from "react"; +import { useCallback, useState } from "react"; import axios from "axios"; export default function Upload(): JSX.Element { @@ -18,9 +18,7 @@ export default function Upload(): JSX.Element { >({}); const handleImagesSelected = useCallback((files: File[] | null) => { - // if (files) { setSelectedImages(files ? Array.from(files) : []); - // } }, []); const handleContent = (text: string) => { diff --git a/src/component/TextArea.tsx b/src/component/TextArea.tsx index b0415dc..8330120 100644 --- a/src/component/TextArea.tsx +++ b/src/component/TextArea.tsx @@ -37,6 +37,7 @@ const TextArea: React.FC = ({ } return []; }; + // 엔터키 인식해서 줄바꿈 가능하게 const handleKeyDown = (event: React.KeyboardEvent) => { if (event.key === "Enter") { diff --git a/src/component/WeatherBar.tsx b/src/component/WeatherBar.tsx index 7783809..df6422d 100644 --- a/src/component/WeatherBar.tsx +++ b/src/component/WeatherBar.tsx @@ -3,13 +3,12 @@ import Image from "next/image"; import "../style/weatherBar.scss"; import React from "react"; - const WeatherBar:React.FC = () => { const API_KEY = "fa3eba61f243af3e8e69086462763172"; const kakao_API_KEY = "3a6c3035c801405eaa71ebb9dc7f474b"; let temp: string | undefined; const [usetemp, setTemp] = useState(); - + const [max, setMax] = useState(); const [min, setMin] = useState(); const [weat, setWeat] = useState(); @@ -18,12 +17,12 @@ const WeatherBar:React.FC = () => { useEffect(() => { // 위치 정보를 비동기적으로 가져오는 함수 const getLocation = async () => { - try { - const position = await new Promise( - (resolve, reject) => { - navigator.geolocation.getCurrentPosition(resolve, reject); - } - ); + try { + const position = await new Promise( + (resolve, reject) => { + navigator.geolocation.getCurrentPosition(resolve, reject); + }, + ); const latitude = position.coords.latitude; console.log("위도", latitude); @@ -35,7 +34,7 @@ const WeatherBar:React.FC = () => { ); const weatherData = await weatherResponse.json(); temp = weatherData.main.temp.toFixed(1); - setTemp(temp); + setTemp(temp + "℃"); // max = weatherData.main.temp_max.toFixed(1); setMax(weatherData.main.temp_max.toFixed(1)); setMin(weatherData.main.temp_min.toFixed(1)); @@ -43,29 +42,29 @@ const WeatherBar:React.FC = () => { console.log(weatherData) // console.log(`온도 : ${temp} ,최고온도 ${max},최저온도 ${min}, 날씨 : ${weat}`); - const addressResponse = await fetch( - `https://dapi.kakao.com/v2/local/geo/coord2address.json?x=${longitude}&y=${latitude}`, - { - method: "GET", - headers: { Authorization: `KakaoAK ${kakao_API_KEY}` }, - } - ); - const addressData = await addressResponse.json(); - setAddress( - addressData.documents[0].address.region_1depth_name + + const addressResponse = await fetch( + `https://dapi.kakao.com/v2/local/geo/coord2address.json?x=${longitude}&y=${latitude}`, + { + method: "GET", + headers: { Authorization: `KakaoAK ${kakao_API_KEY}` }, + }, + ); + const addressData = await addressResponse.json(); + setAddress( + addressData.documents[0].address.region_1depth_name + " " + - addressData.documents[0].address.region_2depth_name - ); + addressData.documents[0].address.region_2depth_name, + ); + + console.log(address); + } catch (error) { + console.error("Error getting location:", error); + } + }; - console.log(address); - } catch (error) { - console.error("Error getting location:", error); - } - }; + getLocation(); // getLocation 함수 실행 + }, []); - getLocation(); // getLocation 함수 실행 - }, []); - return (
@@ -77,7 +76,7 @@ const WeatherBar:React.FC = () => { height={24} priority /> - {usetemp} ℃ + {usetemp}
최고 {max}℃  @@ -86,6 +85,6 @@ const WeatherBar:React.FC = () => {
); -} +}; export default WeatherBar; diff --git a/src/style/detail.scss b/src/style/detail.scss new file mode 100644 index 0000000..3b8c4e1 --- /dev/null +++ b/src/style/detail.scss @@ -0,0 +1,28 @@ +@import "_util.scss"; +.container { + font-family: "EASTARJET-Medium"; + font-weight: 600; + display: flex; + flex-direction: column; + justify-content: space-between; + align-items: center; +} +header { + width: 100%; +} + +hr { + background-color: #252525; +} + +@media only screen and (min-width: 320px) and (max-width: 768px) { + .container { + width: 100%; + } +} + +@media only screen and (min-width: 768px) and (max-width: 1024px) { +} + +@media only screen and (min-width: 1024px) { +} diff --git a/src/style/login.scss b/src/style/login.scss index e25c92a..c182c90 100644 --- a/src/style/login.scss +++ b/src/style/login.scss @@ -56,7 +56,13 @@ } .login_easy { + div { + display: flex; + justify-content: center; + width: 100%; + } display: flex; + flex-direction: column; align-items: center; justify-content: center; color: #d0dbff; diff --git a/tailwind.config.ts b/tailwind.config.ts index 1af3b8f..3b45132 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -1,20 +1,22 @@ -import type { Config } from 'tailwindcss' +import type { Config } from "tailwindcss"; const config: Config = { content: [ - './src/pages/**/*.{js,ts,jsx,tsx,mdx}', - './src/components/**/*.{js,ts,jsx,tsx,mdx}', - './src/app/**/*.{js,ts,jsx,tsx,mdx}', + // './src/pages/**/*.{js,ts,jsx,tsx,mdx}', + // './src/components/**/*.{js,ts,jsx,tsx,mdx}', + // './src/app/**/*.{js,ts,jsx,tsx,mdx}', + "./src/app/detail/*.{tsx, ts}", + "./src/app/*.{tsx,ts}", ], theme: { extend: { backgroundImage: { - 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))', - 'gradient-conic': - 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))', + "gradient-radial": "radial-gradient(var(--tw-gradient-stops))", + "gradient-conic": + "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))", }, }, }, plugins: [], -} -export default config +}; +export default config;