feat: Add prisma
This commit is contained in:
parent
e12a923186
commit
fcca20d14f
@ -2,4 +2,6 @@ NEXT_PUBLIC_TEST="테스트변수입니다. development"
|
|||||||
|
|
||||||
NEXT_PUBLIC_API_SERVER_PATH="http://localhost:8080"
|
NEXT_PUBLIC_API_SERVER_PATH="http://localhost:8080"
|
||||||
|
|
||||||
DATABASE_URL="sqlserver://mssql.devgrr.kr:1433;database=qcast;user=sa;password=Qwertqaz!@#45;trustServerCertificate=true"
|
DATABASE_URL="sqlserver://mssql.devgrr.kr:1433;database=qcast;user=qcast;password=Qwertqaz12345;trustServerCertificate=true"
|
||||||
|
|
||||||
|
SESSION_SECRET="i3iHH1yp2/2SpQSIySQ4bpyc4g0D+zCF9FAn5xUG0+Y="
|
||||||
@ -3,3 +3,5 @@ NEXT_PUBLIC_TEST="테스트변수입니다. production"
|
|||||||
NEXT_PUBLIC_API_SERVER_PATH="http://localhost:8080"
|
NEXT_PUBLIC_API_SERVER_PATH="http://localhost:8080"
|
||||||
|
|
||||||
DATABASE_URL=""
|
DATABASE_URL=""
|
||||||
|
|
||||||
|
SESSION_SECRET="i3iHH1yp2/2SpQSIySQ4bpyc4g0D+zCF9FAn5xUG0+Y="
|
||||||
@ -15,6 +15,7 @@
|
|||||||
"axios": "^1.7.3",
|
"axios": "^1.7.3",
|
||||||
"fabric": "^5.3.0",
|
"fabric": "^5.3.0",
|
||||||
"framer-motion": "^11.2.13",
|
"framer-motion": "^11.2.13",
|
||||||
|
"iron-session": "^8.0.2",
|
||||||
"mathjs": "^13.0.2",
|
"mathjs": "^13.0.2",
|
||||||
"mssql": "^11.0.1",
|
"mssql": "^11.0.1",
|
||||||
"next": "14.2.3",
|
"next": "14.2.3",
|
||||||
|
|||||||
@ -1,91 +1,9 @@
|
|||||||
export default function page() {
|
import Login from '@/components/auth/Login'
|
||||||
|
|
||||||
|
export default function LoginPage() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="flex flex-col align-center h-screen">
|
<Login />
|
||||||
<div className="flex min-h-full flex-1 flex-col justify-center px-6 py-12 lg:px-8">
|
|
||||||
<div className="sm:mx-auto sm:w-full sm:max-w-sm">
|
|
||||||
<img
|
|
||||||
alt="Your Company"
|
|
||||||
src="https://tailwindui.com/img/logos/mark.svg?color=indigo&shade=600"
|
|
||||||
className="mx-auto h-10 w-auto"
|
|
||||||
/>
|
|
||||||
<h2 className="mt-10 text-center text-2xl font-bold leading-9 tracking-tight text-gray-900">
|
|
||||||
Sign in to your account
|
|
||||||
</h2>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="mt-10 sm:mx-auto sm:w-full sm:max-w-sm">
|
|
||||||
<form action="#" method="POST" className="space-y-6">
|
|
||||||
<div>
|
|
||||||
<label
|
|
||||||
htmlFor="email"
|
|
||||||
className="block text-sm font-medium leading-6 text-gray-900"
|
|
||||||
>
|
|
||||||
Email address
|
|
||||||
</label>
|
|
||||||
<div className="mt-2">
|
|
||||||
<input
|
|
||||||
id="email"
|
|
||||||
name="email"
|
|
||||||
type="email"
|
|
||||||
required
|
|
||||||
autoComplete="email"
|
|
||||||
className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<label
|
|
||||||
htmlFor="password"
|
|
||||||
className="block text-sm font-medium leading-6 text-gray-900"
|
|
||||||
>
|
|
||||||
Password
|
|
||||||
</label>
|
|
||||||
<div className="text-sm">
|
|
||||||
<a
|
|
||||||
href="#"
|
|
||||||
className="font-semibold text-indigo-600 hover:text-indigo-500"
|
|
||||||
>
|
|
||||||
Forgot password?
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="mt-2">
|
|
||||||
<input
|
|
||||||
id="password"
|
|
||||||
name="password"
|
|
||||||
type="password"
|
|
||||||
required
|
|
||||||
autoComplete="current-password"
|
|
||||||
className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
className="flex w-full justify-center rounded-md bg-indigo-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
|
|
||||||
>
|
|
||||||
Sign in
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<p className="mt-10 text-center text-sm text-gray-500">
|
|
||||||
Not a member?{' '}
|
|
||||||
<a
|
|
||||||
href="#"
|
|
||||||
className="font-semibold leading-6 text-indigo-600 hover:text-indigo-500"
|
|
||||||
>
|
|
||||||
Start a 14 day free trial
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,15 @@
|
|||||||
import MainPage from '@/components/Main'
|
import MainPage from '@/components/Main'
|
||||||
|
import { getSession } from '@/lib/authActions'
|
||||||
import { getCurrentLocale } from '@/locales/server'
|
import { getCurrentLocale } from '@/locales/server'
|
||||||
|
|
||||||
export default function page() {
|
export default async function page() {
|
||||||
|
const session = await getSession()
|
||||||
|
|
||||||
const currentLocale = getCurrentLocale()
|
const currentLocale = getCurrentLocale()
|
||||||
|
|
||||||
const mainPageProps = {
|
const mainPageProps = {
|
||||||
currentLocale,
|
currentLocale,
|
||||||
|
isLoggedIn: session?.isLoggedIn,
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
|
import { logout } from '@/lib/authActions'
|
||||||
import { useChangeLocale, useI18n } from '@/locales/client'
|
import { useChangeLocale, useI18n } from '@/locales/client'
|
||||||
import { Button, Chip } from '@nextui-org/react'
|
import { Button, Chip } from '@nextui-org/react'
|
||||||
|
|
||||||
export default function MainPage(props) {
|
export default function MainPage(props) {
|
||||||
const { currentLocale } = props
|
const { currentLocale, isLoggedIn } = props
|
||||||
const t = useI18n()
|
const t = useI18n()
|
||||||
const changeLocale = useChangeLocale()
|
const changeLocale = useChangeLocale()
|
||||||
|
|
||||||
@ -12,7 +13,11 @@ export default function MainPage(props) {
|
|||||||
currentLocale === 'ja' ? changeLocale('ko') : changeLocale('ja')
|
currentLocale === 'ja' ? changeLocale('ko') : changeLocale('ja')
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('MainPage', currentLocale)
|
// console.log('MainPage', currentLocale)
|
||||||
|
|
||||||
|
const handleLogout = async () => {
|
||||||
|
await logout()
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -22,6 +27,13 @@ export default function MainPage(props) {
|
|||||||
<div>
|
<div>
|
||||||
<Button onClick={handleChangeLocale}>Change Locale</Button>
|
<Button onClick={handleChangeLocale}>Change Locale</Button>
|
||||||
</div>
|
</div>
|
||||||
|
{isLoggedIn && (
|
||||||
|
<div className="my-4">
|
||||||
|
<Button color="primary" onClick={handleLogout}>
|
||||||
|
로그아웃
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
75
src/components/auth/Login.jsx
Normal file
75
src/components/auth/Login.jsx
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import { login } from '@/lib/authActions'
|
||||||
|
|
||||||
|
export default function Login() {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col align-center h-screen">
|
||||||
|
<div className="flex min-h-full flex-1 flex-col justify-center px-6 py-12 lg:px-8">
|
||||||
|
<div className="sm:mx-auto sm:w-full sm:max-w-sm">
|
||||||
|
<img alt="Your Company" src="https://tailwindui.com/img/logos/mark.svg?color=indigo&shade=600" className="mx-auto h-10 w-auto" />
|
||||||
|
<h2 className="mt-10 text-center text-2xl font-bold leading-9 tracking-tight text-gray-900">Sign in to your account</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-10 sm:mx-auto sm:w-full sm:max-w-sm">
|
||||||
|
<form action={login} method="POST" className="space-y-6">
|
||||||
|
<div>
|
||||||
|
<label htmlFor="userId" className="block text-sm font-medium leading-6 text-gray-900">
|
||||||
|
User ID
|
||||||
|
</label>
|
||||||
|
<div className="mt-2">
|
||||||
|
<input
|
||||||
|
id="userId"
|
||||||
|
name="id"
|
||||||
|
type="text"
|
||||||
|
required
|
||||||
|
// autoComplete="email"
|
||||||
|
className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<label htmlFor="password" className="block text-sm font-medium leading-6 text-gray-900">
|
||||||
|
Password
|
||||||
|
</label>
|
||||||
|
<div className="text-sm">
|
||||||
|
<a href="#" className="font-semibold text-indigo-600 hover:text-indigo-500">
|
||||||
|
Forgot password?
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="mt-2">
|
||||||
|
<input
|
||||||
|
id="password"
|
||||||
|
name="password"
|
||||||
|
type="password"
|
||||||
|
required
|
||||||
|
autoComplete="current-password"
|
||||||
|
className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
className="flex w-full justify-center rounded-md bg-indigo-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
|
||||||
|
>
|
||||||
|
Sign in
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<p className="mt-10 text-center text-sm text-gray-500">
|
||||||
|
Not a member?{' '}
|
||||||
|
<a href="#" className="font-semibold leading-6 text-indigo-600 hover:text-indigo-500">
|
||||||
|
Start a 14 day free trial
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
61
src/lib/authActions.js
Normal file
61
src/lib/authActions.js
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
'use server'
|
||||||
|
|
||||||
|
import { cookies } from 'next/headers'
|
||||||
|
import { redirect } from 'next/navigation'
|
||||||
|
|
||||||
|
import { getIronSession } from 'iron-session'
|
||||||
|
|
||||||
|
import { getUserByIdAndPassword } from './user'
|
||||||
|
import { defaultSession, sessionOptions } from './session'
|
||||||
|
|
||||||
|
export async function logout() {
|
||||||
|
const session = await getSession()
|
||||||
|
session.destroy()
|
||||||
|
redirect('/login')
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getSession() {
|
||||||
|
let session
|
||||||
|
session = await getIronSession(cookies(), sessionOptions)
|
||||||
|
|
||||||
|
console.log('session:', session)
|
||||||
|
if (!session.isLoggedIn) {
|
||||||
|
session.isLoggedIn = defaultSession.isLoggedIn
|
||||||
|
}
|
||||||
|
|
||||||
|
return session
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function login(formData) {
|
||||||
|
const session = await getSession()
|
||||||
|
|
||||||
|
const userId = formData.get('id')
|
||||||
|
const password = formData.get('password')
|
||||||
|
|
||||||
|
console.log('id:', userId)
|
||||||
|
console.log('password:', password)
|
||||||
|
|
||||||
|
// const user = {
|
||||||
|
// id: 1,
|
||||||
|
// name: 'jinsoo Kim',
|
||||||
|
// email: 'jinsoo.kim@example.com',
|
||||||
|
// }
|
||||||
|
const loginUser = await getUserByIdAndPassword({ userId, password })
|
||||||
|
console.log('loginUser:', loginUser)
|
||||||
|
|
||||||
|
if (!loginUser) {
|
||||||
|
throw Error('Wrong Credentials!')
|
||||||
|
}
|
||||||
|
|
||||||
|
// session.id = user.id
|
||||||
|
// session.email = user.email
|
||||||
|
session.userId = loginUser.USER_ID
|
||||||
|
session.saleStoreId = loginUser.SALE_STORE_ID
|
||||||
|
session.name = loginUser.NAME
|
||||||
|
session.mail = loginUser.MAIL
|
||||||
|
session.isLoggedIn = true
|
||||||
|
console.log('session:', session)
|
||||||
|
|
||||||
|
await session.save()
|
||||||
|
redirect('/')
|
||||||
|
}
|
||||||
16
src/lib/session.js
Normal file
16
src/lib/session.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
export const defaultSession = {
|
||||||
|
userId: null,
|
||||||
|
saleStoreId: null,
|
||||||
|
name: null,
|
||||||
|
mail: null,
|
||||||
|
isLoggedIn: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const sessionOptions = {
|
||||||
|
password: process.env.SESSION_SECRET,
|
||||||
|
cookieName: 'lama-session',
|
||||||
|
cookieOptions: {
|
||||||
|
httpOnly: true,
|
||||||
|
secure: process.env.NODE_ENV === 'production',
|
||||||
|
},
|
||||||
|
}
|
||||||
@ -4,9 +4,9 @@ const { PrismaClient } = require('@prisma/client')
|
|||||||
|
|
||||||
const prisma = new PrismaClient()
|
const prisma = new PrismaClient()
|
||||||
|
|
||||||
export async function createUser({ userId, password }) {
|
export async function getUserByIdAndPassword({ userId, password }) {
|
||||||
return prisma.m_USER.create({
|
return prisma.m_USER.findFirst({
|
||||||
data: {
|
where: {
|
||||||
USER_ID: userId,
|
USER_ID: userId,
|
||||||
PASSWORD: password,
|
PASSWORD: password,
|
||||||
},
|
},
|
||||||
|
|||||||
24
yarn.lock
24
yarn.lock
@ -2645,6 +2645,11 @@ console-control-strings@^1.0.0, console-control-strings@^1.1.0:
|
|||||||
resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
|
resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
|
||||||
integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==
|
integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==
|
||||||
|
|
||||||
|
cookie@0.6.0:
|
||||||
|
version "0.6.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051"
|
||||||
|
integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==
|
||||||
|
|
||||||
cross-spawn@^7.0.0:
|
cross-spawn@^7.0.0:
|
||||||
version "7.0.3"
|
version "7.0.3"
|
||||||
resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz"
|
resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz"
|
||||||
@ -3091,6 +3096,20 @@ invariant@^2.2.4:
|
|||||||
dependencies:
|
dependencies:
|
||||||
loose-envify "^1.0.0"
|
loose-envify "^1.0.0"
|
||||||
|
|
||||||
|
iron-session@^8.0.2:
|
||||||
|
version "8.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/iron-session/-/iron-session-8.0.2.tgz#9802e080206a8ba41911b53d29ff7de11161d036"
|
||||||
|
integrity sha512-p4Yf1moQr6gnCcXu5vCaxVKRKDmR9PZcQDfp7ZOgbsSHUsgaNti6OgDB2BdgxC2aS6V/6Hu4O0wYlj92sbdIJg==
|
||||||
|
dependencies:
|
||||||
|
cookie "0.6.0"
|
||||||
|
iron-webcrypto "1.2.1"
|
||||||
|
uncrypto "0.1.3"
|
||||||
|
|
||||||
|
iron-webcrypto@1.2.1:
|
||||||
|
version "1.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/iron-webcrypto/-/iron-webcrypto-1.2.1.tgz#aa60ff2aa10550630f4c0b11fd2442becdb35a6f"
|
||||||
|
integrity sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==
|
||||||
|
|
||||||
is-arrayish@^0.3.1:
|
is-arrayish@^0.3.1:
|
||||||
version "0.3.2"
|
version "0.3.2"
|
||||||
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03"
|
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03"
|
||||||
@ -4288,6 +4307,11 @@ typed-function@^4.2.1:
|
|||||||
resolved "https://registry.yarnpkg.com/typed-function/-/typed-function-4.2.1.tgz#19aa51847aa2dea9ef5e7fb7641c060179a74426"
|
resolved "https://registry.yarnpkg.com/typed-function/-/typed-function-4.2.1.tgz#19aa51847aa2dea9ef5e7fb7641c060179a74426"
|
||||||
integrity sha512-EGjWssW7Tsk4DGfE+5yluuljS1OGYWiI1J6e8puZz9nTMM51Oug8CD5Zo4gWMsOhq5BI+1bF+rWTm4Vbj3ivRA==
|
integrity sha512-EGjWssW7Tsk4DGfE+5yluuljS1OGYWiI1J6e8puZz9nTMM51Oug8CD5Zo4gWMsOhq5BI+1bF+rWTm4Vbj3ivRA==
|
||||||
|
|
||||||
|
uncrypto@0.1.3:
|
||||||
|
version "0.1.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/uncrypto/-/uncrypto-0.1.3.tgz#e1288d609226f2d02d8d69ee861fa20d8348ef2b"
|
||||||
|
integrity sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==
|
||||||
|
|
||||||
undici-types@~6.13.0:
|
undici-types@~6.13.0:
|
||||||
version "6.13.0"
|
version "6.13.0"
|
||||||
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.13.0.tgz#e3e79220ab8c81ed1496b5812471afd7cf075ea5"
|
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.13.0.tgz#e3e79220ab8c81ed1496b5812471afd7cf075ea5"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user