diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml
index da4a3f68..fb561511 100644
--- a/.github/workflows/pull-request.yml
+++ b/.github/workflows/pull-request.yml
@@ -32,15 +32,17 @@ jobs:
run: npm install
# 아래 단계에서 .env 파일을 생성하고 시크릿 값을 설정합니다.
- # - name: Set Environment Variables
- # env:
- # NEXT_PUBLIC_API_ADDRESS: ${{ secrets.NEXT_PUBLIC_API_ADDRESS }}
- # NEXT_PUBLIC_CHANNEL_ID: ${{ secrets.NEXT_PUBLIC_CHANNEL_ID }}
- # NEXT_PUBLIC_DISLIKE_CHANNEL_ID: ${{ secrets.NEXT_PUBLIC_DISLIKE_CHANNEL_ID }}
- # run: |
- # echo "NEXT_PUBLIC_API_ADDRESS=$NEXT_PUBLIC_API_ADDRESS" >> .env
- # echo "NEXT_PUBLIC_CHANNEL_ID=$NEXT_PUBLIC_CHANNEL_ID" >> .env
- # echo "NEXT_PUBLIC_DISLIKE_CHANNEL_ID=$NEXT_PUBLIC_DISLIKE_CHANNEL_ID" >> .env
+ - name: Set Environment Variables
+ env:
+ NEXT_PUBLIC_API_ADDRESS: ${{ secrets.NEXT_PUBLIC_API_ADDRESS }}
+ NEXT_PUBLIC_API_MOCKING: ${{ secrets.NEXT_PUBLIC_API_MOCKING }}
+ NEXT_PUBLIC_API_MOCKING_ADDRESS: ${{ secrets.NEXT_PUBLIC_API_MOCKING_ADDRESS }}
+ CHROMATIC_TOKEN: ${{ secrets.CHROMATIC_TOKEN }}
+ run: |
+ echo "NEXT_PUBLIC_API_ADDRESS=$NEXT_PUBLIC_API_ADDRESS" >> .env
+ echo "NEXT_PUBLIC_API_MOCKING=$NEXT_PUBLIC_API_MOCKING" >> .env
+ echo "NEXT_PUBLIC_API_MOCKING_ADDRESS=$NEXT_PUBLIC_API_MOCKING_ADDRESS" >> .env
+ echo "CHROMATIC_TOKEN=$CHROMATIC_TOKEN" >> .env
# 빌드를 수행합니다.
- name: Build
@@ -61,12 +63,7 @@ jobs:
await github.pulls.createReview({
...context.repo,
pull_number,
- body : "테스트코드를 다시 확인해주세요. ",
+ body : "actions 결과를 다시 확인해주세요. -자동으로 작성됨-",
event : "REQUEST_CHANGES"
})
- await github.pulls.update({
- ...context.repo,
- pull_number,
- state: "closed"
- })
if: failure()
diff --git a/package.json b/package.json
index a2c67fdc..2d9b1989 100644
--- a/package.json
+++ b/package.json
@@ -19,6 +19,7 @@
"@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-label": "^2.0.2",
+ "@radix-ui/react-select": "^2.0.0",
"@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-switch": "^1.0.3",
"@radix-ui/react-tabs": "^1.0.4",
@@ -27,6 +28,7 @@
"class-variance-authority": "^0.7.0",
"classnames": "^2.3.2",
"clsx": "^2.0.0",
+ "lucide-react": "^0.291.0",
"date-fns": "^2.30.0",
"next": "13.5.6",
"next-themes": "^0.2.1",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index f7a9fe24..cd99f8b8 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -19,6 +19,9 @@ dependencies:
version: 1.3.0(react@18.0.0)
'@radix-ui/react-label':
specifier: ^2.0.2
+ version: 2.0.2(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.0.0)(react@18.0.0)
+ '@radix-ui/react-select':
+ specifier: ^2.0.0
version: 2.0.2(@types/react-dom@18.0.0)(@types/react@18.2.33)(react-dom@18.0.0)(react@18.0.0)
'@radix-ui/react-slot':
specifier: ^1.0.2
@@ -44,6 +47,9 @@ dependencies:
clsx:
specifier: ^2.0.0
version: 2.0.0
+ lucide-react:
+ specifier: ^0.291.0
+ version: 0.291.0(react@18.0.0)
date-fns:
specifier: ^2.30.0
version: 2.30.0
@@ -2186,7 +2192,6 @@ packages:
resolution: {integrity: sha512-T5gIdVO2mmPW3NNhjNgEP3cqMXjXL9UbO0BzWcXfvdBs+BohbQxvd/K5hSVKmn9/lbTdsQVKbUcP5WLCwvUbBg==}
dependencies:
'@babel/runtime': 7.23.2
- dev: true
/@radix-ui/primitive@1.0.1:
resolution: {integrity: sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==}
@@ -2763,6 +2768,46 @@ packages:
react-remove-scroll: 2.5.5(@types/react@18.2.33)(react@18.0.0)
dev: true
+ /@radix-ui/react-select@2.0.0(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.0.0)(react@18.0.0):
+ resolution: {integrity: sha512-RH5b7af4oHtkcHS7pG6Sgv5rk5Wxa7XI8W5gvB1N/yiuDGZxko1ynvOiVhFM7Cis2A8zxF9bTOUVbRDzPepe6w==}
+ peerDependencies:
+ '@types/react': '*'
+ '@types/react-dom': '*'
+ react: ^16.8 || ^17.0 || ^18.0
+ react-dom: ^16.8 || ^17.0 || ^18.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ '@types/react-dom':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.23.2
+ '@radix-ui/number': 1.0.1
+ '@radix-ui/primitive': 1.0.1
+ '@radix-ui/react-collection': 1.0.3(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.0.0)(react@18.0.0)
+ '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.0.0)(react@18.0.0)
+ '@radix-ui/react-context': 1.0.1(@types/react@18.0.0)(react@18.0.0)
+ '@radix-ui/react-direction': 1.0.1(@types/react@18.0.0)(react@18.0.0)
+ '@radix-ui/react-dismissable-layer': 1.0.5(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.0.0)(react@18.0.0)
+ '@radix-ui/react-focus-guards': 1.0.1(@types/react@18.0.0)(react@18.0.0)
+ '@radix-ui/react-focus-scope': 1.0.4(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.0.0)(react@18.0.0)
+ '@radix-ui/react-id': 1.0.1(@types/react@18.0.0)(react@18.0.0)
+ '@radix-ui/react-popper': 1.1.3(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.0.0)(react@18.0.0)
+ '@radix-ui/react-portal': 1.0.4(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.0.0)(react@18.0.0)
+ '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.0.0)(react@18.0.0)
+ '@radix-ui/react-slot': 1.0.2(@types/react@18.0.0)(react@18.0.0)
+ '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.0.0)(react@18.0.0)
+ '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.0.0)(react@18.0.0)
+ '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.0.0)(react@18.0.0)
+ '@radix-ui/react-use-previous': 1.0.1(@types/react@18.0.0)(react@18.0.0)
+ '@radix-ui/react-visually-hidden': 1.0.3(@types/react-dom@18.0.0)(@types/react@18.0.0)(react-dom@18.0.0)(react@18.0.0)
+ '@types/react': 18.0.0
+ '@types/react-dom': 18.0.0
+ aria-hidden: 1.2.3
+ react: 18.0.0
+ react-dom: 18.0.0(react@18.0.0)
+ react-remove-scroll: 2.5.5(@types/react@18.0.0)(react@18.0.0)
+ dev: false
/@radix-ui/react-separator@1.0.3(@types/react-dom@18.0.0)(@types/react@18.2.33)(react-dom@18.0.0)(react@18.0.0):
resolution: {integrity: sha512-itYmTy/kokS21aiV5+Z56MZB54KrhPgn6eHDKkFeOLR34HMN2s8PaN47qZZAGnvupcjxHaFZnW4pQEh0BvvVuw==}
peerDependencies:
@@ -3044,7 +3089,6 @@ packages:
'@types/react-dom': 18.0.0
react: 18.0.0
react-dom: 18.0.0(react@18.0.0)
- dev: true
/@radix-ui/rect@1.0.1:
resolution: {integrity: sha512-fyrgCaedtvMg9NK3en0pnOYJdtfwxUcNolezkNPUsoX57X8oQk+NkqcvzHXD2uKNij6GXmWU9NDru2IWjrO4BQ==}
@@ -9221,6 +9265,14 @@ packages:
yallist: 4.0.0
dev: true
+ /lucide-react@0.291.0(react@18.0.0):
+ resolution: {integrity: sha512-79jHlT9Je2PXSvXIBGDkItCK7In2O9iKnnSJ/bJxvIBOFaX2Ex0xEcC4fRS/g0F2uQGFejjmn2qWhwdc5wicMQ==}
+ peerDependencies:
+ react: ^16.5.1 || ^17.0.0 || ^18.0.0
+ dependencies:
+ react: 18.0.0
+ dev: false
+
/lz-string@1.5.0:
resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==}
hasBin: true
diff --git a/src/app/(root)/(routes)/(home)/components/TestBlock.tsx b/src/app/(root)/(routes)/(home)/components/TestBlock.tsx
index cb336899..431a4e03 100644
--- a/src/app/(root)/(routes)/(home)/components/TestBlock.tsx
+++ b/src/app/(root)/(routes)/(home)/components/TestBlock.tsx
@@ -1,25 +1,28 @@
-'use client'
-
-import React, { useEffect } from 'react'
+// 'use client'
+import React from 'react'
import { getTest } from '@/services/test/test'
-// async function getTestValue() {
-// const res = await getTest()
-// const data = await res.json()
-// return data
-// }
+async function getTestValue(): Promise<{ message: string } | null> {
+ try {
+ const res = await getTest()
+ const data = await res.json()
+ return data
+ } catch (e) {
+ console.log(e)
+ return null
+ }
+}
-export default function TestBlock() {
- // const data = await getTestValue()
- // console.log(data.message)
+export default async function TestBlock() {
+ const data = await getTestValue()
- useEffect(() => {
- async function fetchData() {
- const data = await getTest()
- console.log(await data.json())
- }
- fetchData()
- }, [])
+ // useEffect(() => {
+ // async function fetchData() {
+ // const data = await getTest()
+ // console.log(await data.json())
+ // }
+ // fetchData()
+ // }, [])
- return
{'index '}
+ return {'index ' + data?.message}
}
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index c0add4dc..6f9dd813 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -1,9 +1,11 @@
import { Suspense } from 'react'
import type { Metadata } from 'next'
import Header from '@/components/domain/Header'
+import { Environment } from '@/config/environment'
import MSWWrapper from '@/contexts/MSWWrapper'
import TanstackQueryContext from '@/contexts/TanstackQueryContext'
import ThemeProviderContext from '@/contexts/ThemeProviderContext'
+import { initMockApi } from '@/lib/msw/initMockApi'
import '@/styles/globals.css'
export const metadata: Metadata = {
@@ -12,6 +14,11 @@ export const metadata: Metadata = {
viewport: 'width=device-width, initial-scale=1.0',
}
+if (Environment.apiMocking() === 'enabled') {
+ console.log('Mocking enabled')
+ initMockApi()
+}
+
export default function RootLayout({
children,
authModal,
diff --git a/src/components/domain/Header/Header.tsx b/src/components/domain/Header/Header.tsx
index e0848a85..0961432c 100644
--- a/src/components/domain/Header/Header.tsx
+++ b/src/components/domain/Header/Header.tsx
@@ -37,11 +37,11 @@ const Header = ({ isLogin = false }: HeaderProps) => {
{/** TODO: 아바타 컴포넌트로 변경 */}
>
) : (
- <>
-
- >
+
)}
diff --git a/src/components/domain/LoginForm/LoginForm.stories.tsx b/src/components/domain/LoginForm/LoginForm.stories.tsx
deleted file mode 100644
index 4a67a72d..00000000
--- a/src/components/domain/LoginForm/LoginForm.stories.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import type { Meta, StoryObj } from '@storybook/react'
-import LoginForm from './LoginForm'
-
-const meta = {
- title: 'DOMAIN/LoginForm',
- component: LoginForm,
- tags: ['autodocs'],
- argTypes: {},
-} satisfies Meta
-
-export default meta
-type Story = StoryObj
-
-export const Normal: Story = {
- args: {},
-}
diff --git a/src/components/domain/LoginForm/LoginForm.tsx b/src/components/domain/LoginForm/LoginForm.tsx
index 4e47338c..b8e6aa44 100644
--- a/src/components/domain/LoginForm/LoginForm.tsx
+++ b/src/components/domain/LoginForm/LoginForm.tsx
@@ -1,12 +1,50 @@
+'use client'
+
import Image from 'next/image'
+import { useRouter } from 'next/navigation'
+import AppPath from '@/config/appPath'
import Assets from '@/config/assets'
+import { getGoogleLogin, getKakaoLogin } from '@/services/auth/auth'
import LoginButtons from './section/LoginButtons'
const LoginForm = () => {
+ const router = useRouter()
+ const kakaoLoginHandler = async () => {
+ try {
+ await getKakaoLogin()
+ const res = await getKakaoLogin()
+ const data = await res.json()
+ console.log(data)
+ alert('로그인 성공')
+ router.back()
+ } catch (e) {
+ console.log(e)
+ alert('로그인 실패')
+ router.push(AppPath.login(), { scroll: false })
+ }
+ }
+ const googleLoginHandler = async () => {
+ try {
+ await getKakaoLogin()
+ const res = await getGoogleLogin()
+ const data = await res.json()
+ console.log(data)
+ alert('로그인 성공')
+ router.back()
+ } catch (e) {
+ console.log(e)
+ alert('로그인 실패')
+ router.push(AppPath.login(), { scroll: false })
+ }
+ }
+
return (
)
}
diff --git a/src/components/domain/LoginForm/section/LoginButtons.tsx b/src/components/domain/LoginForm/section/LoginButtons.tsx
index 5b80d764..e11f9ede 100644
--- a/src/components/domain/LoginForm/section/LoginButtons.tsx
+++ b/src/components/domain/LoginForm/section/LoginButtons.tsx
@@ -3,11 +3,19 @@
import React from 'react'
import { KakaoLoginButton, GoogleLoginButton } from '../../buttons/LoginButtons'
-const LoginButtons = () => {
+type LoginButtonsProps = {
+ kakaoLoginHandler: () => void
+ googleLoginHandler: () => void
+}
+
+const LoginButtons = ({
+ kakaoLoginHandler,
+ googleLoginHandler,
+}: LoginButtonsProps) => {
return (
- alert('k')} />
- alert('g')} />
+
+
)
}
diff --git a/src/components/ui/Select/Select.stories.tsx b/src/components/ui/Select/Select.stories.tsx
new file mode 100644
index 00000000..dad27c12
--- /dev/null
+++ b/src/components/ui/Select/Select.stories.tsx
@@ -0,0 +1,41 @@
+import type { Meta, StoryObj } from '@storybook/react'
+import {
+ Select,
+ SelectContent,
+ SelectGroup,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from './Select'
+
+const meta = {
+ title: 'UI/Select',
+ component: Select,
+ tags: ['autodocs'],
+ argTypes: {},
+} satisfies Meta
+
+export default meta
+type Story = StoryObj
+
+export const Normal: Story = {
+ args: {},
+ render: () => {
+ return (
+
+ )
+ },
+}
diff --git a/src/components/ui/Select/Select.tsx b/src/components/ui/Select/Select.tsx
new file mode 100644
index 00000000..81eea9c8
--- /dev/null
+++ b/src/components/ui/Select/Select.tsx
@@ -0,0 +1,94 @@
+'use client'
+
+import * as React from 'react'
+import * as SelectPrimitive from '@radix-ui/react-select'
+import { Check, ChevronDown } from 'lucide-react'
+import { cn } from '@/utils'
+
+const Select = SelectPrimitive.Root
+
+const SelectGroup = SelectPrimitive.Group
+
+const SelectValue = SelectPrimitive.Value
+
+const SelectTrigger = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, children, ...props }, ref) => (
+
+ {children}
+
+
+
+
+))
+SelectTrigger.displayName = SelectPrimitive.Trigger.displayName
+
+const SelectContent = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, children, position = 'popper', ...props }, ref) => (
+
+
+
+ {children}
+
+
+
+))
+SelectContent.displayName = SelectPrimitive.Content.displayName
+
+const SelectItem = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, children, ...props }, ref) => (
+
+
+
+
+
+
+
+ {children}
+
+))
+SelectItem.displayName = SelectPrimitive.Item.displayName
+
+export {
+ Select,
+ SelectGroup,
+ SelectValue,
+ SelectTrigger,
+ SelectContent,
+ SelectItem,
+}
diff --git a/src/components/ui/Select/index.tsx b/src/components/ui/Select/index.tsx
new file mode 100644
index 00000000..da0623d8
--- /dev/null
+++ b/src/components/ui/Select/index.tsx
@@ -0,0 +1,3 @@
+import { Select } from './Select'
+
+export default Select
diff --git a/src/config/apiEndPoint.ts b/src/config/apiEndPoint.ts
index 65357596..852201fe 100644
--- a/src/config/apiEndPoint.ts
+++ b/src/config/apiEndPoint.ts
@@ -1,7 +1,8 @@
import { GetItems } from '@/services/item/item'
const ApiEndPoint = {
- login: () => '/login',
+ kakaoLogin: () => '/oauth2/authorize/kakao/login',
+ googleLogin: () => '/oauth2/authorize/google/login',
test: () => '/test',
items: (cursorId: number) => `/items?cursorId=${cursorId}`,
} as const
diff --git a/src/config/environment.ts b/src/config/environment.ts
index 9e21e787..51aef80b 100644
--- a/src/config/environment.ts
+++ b/src/config/environment.ts
@@ -1,5 +1,8 @@
export const Environment = {
- apiAddress: () => process.env.NEXT_PUBLIC_API_ADDRESS,
+ apiAddress: () =>
+ process.env.NEXT_PUBLIC_API_MOCKING === 'enabled'
+ ? process.env.NEXT_PUBLIC_API_MOCKING_ADDRESS
+ : process.env.NEXT_PUBLIC_API_ADDRESS,
apiMocking: () =>
process.env.NEXT_PUBLIC_API_MOCKING === 'enabled' ? 'enabled' : 'disabled',
}
diff --git a/src/lib/msw/mocks/authHandlers.ts b/src/lib/msw/mocks/authHandlers.ts
new file mode 100644
index 00000000..8afc7e18
--- /dev/null
+++ b/src/lib/msw/mocks/authHandlers.ts
@@ -0,0 +1,46 @@
+import { rest } from 'msw'
+import ApiEndPoint from '@/config/apiEndPoint'
+import { Environment } from '@/config/environment'
+
+const baseUrl = Environment.apiAddress()
+
+const authHandlers = [
+ rest.get(`${baseUrl}${ApiEndPoint.kakaoLogin()}`, async (_req, res, ctx) => {
+ return res(
+ ctx.status(200),
+ ctx.json({
+ data: {
+ userInfo: {
+ userId: 1,
+ nickname: '병원에 간 미어캣',
+ imageUrl: 'http://asdf~',
+ },
+ token: {
+ accessToken: 'asdfasdf',
+ refreshToken: 'asdfa',
+ },
+ },
+ }),
+ )
+ }),
+ rest.get(`${baseUrl}${ApiEndPoint.googleLogin()}`, async (_req, res, ctx) => {
+ return res(
+ ctx.status(200),
+ ctx.json({
+ data: {
+ userInfo: {
+ userId: 1,
+ nickname: '병원에 간 미어캣',
+ imageUrl: 'http://asdf~',
+ },
+ token: {
+ accessToken: 'asdfasdf',
+ refreshToken: 'asdfa',
+ },
+ },
+ }),
+ )
+ }),
+]
+
+export default authHandlers
diff --git a/src/lib/msw/mocks/handlers.ts b/src/lib/msw/mocks/handlers.ts
index 4b32ebff..d40939e1 100644
--- a/src/lib/msw/mocks/handlers.ts
+++ b/src/lib/msw/mocks/handlers.ts
@@ -1,4 +1,5 @@
import { itemHandlers } from './itemHandler'
+import authHandlers from './authHandlers'
import { testHandlers } from './testHandler'
-export const handlers = [...testHandlers, ...itemHandlers]
+export const handlers = [...testHandlers, ...authHandlers, itemHandlers]
diff --git a/src/services/auth/auth.ts b/src/services/auth/auth.ts
index 758b38db..201db899 100644
--- a/src/services/auth/auth.ts
+++ b/src/services/auth/auth.ts
@@ -1,15 +1,16 @@
import ApiEndPoint from '@/config/apiEndPoint'
-import { Environment } from '@/config/environment'
-
-const postLogin = async () => {
- const response = await fetch(Environment.apiAddress() + ApiEndPoint.login(), {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
- })
- const data = await response.json()
- return data
+import apiClient from '../apiClient'
+
+const getKakaoLogin = async () => {
+ const response = await apiClient.get(ApiEndPoint.kakaoLogin())
+
+ return response
+}
+
+const getGoogleLogin = async () => {
+ const response = await apiClient.get(ApiEndPoint.googleLogin())
+
+ return response
}
-export { postLogin }
+export { getKakaoLogin, getGoogleLogin }