Skip to content

Commit 1a09bc4

Browse files
kimnamheeeec0912jy
andauthored
중간 배포 (#74)
* 🧹 chore: add tanstack router plugins * ✨ feat(routes): integrate tanstack router * ✨ feat(routes): add basic routes profile, explore, login * 🧹 chore(eslint): add ignore for shared/ui * ✨ feat(components): add sidebar component * 🧹 chore(asset): add instagram logo * 💎 style(index): initialize style * ✨ feat(route): add /me to route * ✨ feat(provider): add sidebar provider * ✨ feat(route): configure provider * ✨ feat(components): add sidebar navigation item component * ✨ feat(component): add sidebar component * ✨ feat(routes): separate homepage component * ✨ feat(components): add drawer component * ✨ feat(components): add dialog component * ✨ feat(components): add action, type to navItems * ✨ feat(components): add app level modal, drawer * ✨ feat(components): open drawer on search click, open modal on create click * 로그인 페이지 UI 구현 * 비밀번호 찾기 화면 구현 * 계정 생성 UI 및 비밀번호 생성 로직 구현 * 로그인 메인화면 가입하기 버튼 버그 수정 * ✨ feat(components): add create post modal component * package-lock.json 삭제 * ✨ feat(components): add sonner * ✨ feat(provider): integrate toaster * ✨ feat(components): add dropzone component * ✨ feat(components): integrate drag and drop to createmodal * ♻️ refactor(components): separate logic using custom hook * ♻️ refactor(components): separate ui components * ✨ feat(components): add post details pane * ✨ feat(components): add double modal on exit * 🧹 chore: add testing library * 🧪 test(createmodal): add create post modal related tests * ✨ feat(components): add profile header * ✨ feat(api): initialize ky instance * ✨ feat(components): add tabs * ✨ feat(routes): separate app route layer * ✨ feat(routes): update route tree * ✨ feat(components): add fallback image * ✨ feat(profile-posts): add grid ui * ✨ feat(profilepage): add posts grid ui * 🧹 chore(homepage): remove duplicate navigation shell * ♻️ refactor(profilepage): add common style container component * ✨ feat(profile): add profile page component * ✨ feat(navigation): add useNavController hook * 🧹 chore: rerun yarn install * ✨ feat(msw): msw 기본 설정 * ✨ feat(components): add carousel * ♻️ refactor(sidebar): collapse sidebar below xl * ✨ feat(components): add stories field * ✨ feat(stories): add link to story route * ✨ feat: msw 구조 수정 * ✨ feat: msw post db 업데이트 및 기본 레이아웃 구현 * ✨ feat: 사진 기본 ui 구현 * ✨ feat: 하트 색깔 및 불투명도 수정 * ✨ feat: 하트 올라가는 애니메이션 구현 * ✨ feat: 하트 애니메이션 구체화 및 버그 수정 * ✨ feat(msw): add common response type * 🐛 fix(msw): fix common response type field name * ✨ feat(msw): add mock users * ✨ feat(msw): add follow handlers * 💎 style(sidebar): add padding * ✨ feat(components): add follow list modal component needs to be fixed based on real api * ✨ feat(components): add mock data / match data type * 💎 style(search): adjust search drawer style * ✨ feat: ... (설정) 화면 모달 구현 * ✨ feat(search): apply debounce to input value * ✨ feat: msw 구현 (comment) * 🧹 chore: remove duplicate key * ✨ feat: 댓글 ui * ✨ feat: 댓글 설정창(...) ui 구현 * ✨ feat: ... 모달 로직 수정 * ✨ feat: 글 본문 및 프로필 ui 수정 (여백 정리) * ✨ feat(msw): warn unhandled requests for debugging * ✨ feat(gitignore): add env * ✨ feat(providers): add query client provider * ✨ feat(api): add test (health check) handler * ✨ feat(route): add test route for api connection test * ✨ feat: 액션 바 (상호작용) ui 구현 * ✨ feat: env 삭제 * 💎 style(sidebar): update layout stability * ✨ feat(sidebar): updage search drawer toggle logic * ✨ feat(sidebar): remain page width when opening search drawer * ✨ feat(components): add pagination * ✨ feat(components): add shared components lazyimage / card * ✨ feat(msw): add post mock data * ✨ feat(api): add feed schema / types * ✨ feat(api): add handler / api function * ✨ feat(home): add feed ui * ✨ feat(actions): add env variable on cd workflow * 💎 style(sidebar): collapse sidebar on search drawer toggle * 🐛 fix(route): update route from profile_id to post_id * ✨ feat(feed): link to post detail on click * ✨ feat(components): add dropdown * ✨ feat(msw): add album handler * ✨ feat(api): add album api call functions * ✨ feat(api): add album api call function * 🐛 fix(msw): adjust handler order * 💎 style(dropdown): remove circle icon * ✨ feat(album): add album dropdown * 🧪 test(album): add album dropdown tests * 🐛 fix(actions): apply secrets * 🧹 chore: update test:ci command option * ✨ feat(msw): add bookmarks handler * ✨ feat(bookmarks): add bookmarked posts ui * ✨ feat(postdetail): return to previous page when closing page * ✨ feat(postdetail): validate search params with zod * ✨ feat: 하단 푸터 - 위치 화면 구현 * ✨ feat: 하단 푸터 수정 (Instagram Lite 추가) * ✨ feat: 푸터 완성 * ✨ feat: 푸터 ui, 기능, 경로 설정 완성 * ✨ feat: 로그인 msw 설정 * ✨ feat: 로그인 검사 로직 추가 및 카카오톡 로그인 ui 구현 --------- Co-authored-by: c0912jy <c0912jy@gmail.com>
1 parent d9c9f53 commit 1a09bc4

File tree

7 files changed

+136
-18
lines changed

7 files changed

+136
-18
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
"framer-motion": "^12.26.2",
4242
"immer": "^11.1.3",
4343
"ky": "^1.14.2",
44-
"lucide-react": "^0.562.0",
44+
"lucide-react": "^0.563.0",
4545
"next-themes": "^0.4.6",
4646
"react": "^19.2.0",
4747
"react-dom": "^19.2.0",

src/components/auth/LoginCard.tsx

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { useState } from 'react'
22
import { useNavigate } from '@tanstack/react-router'
33
import instagramLogo from '../../assets/instagram-logo.svg'
4+
import { instance } from '../../shared/api/ky'
5+
import { MessageCircle } from 'lucide-react'
46

57
interface FloatingInputProps {
68
label: string
@@ -11,6 +13,14 @@ interface FloatingInputProps {
1113
setShowPw?: (show: boolean) => void
1214
}
1315

16+
interface LoginResponse {
17+
success: boolean
18+
data?: {
19+
accessToken: string
20+
refreshToken: string
21+
}
22+
}
23+
1424
const FloatingInput = ({
1525
label,
1626
value,
@@ -61,10 +71,32 @@ const LoginCard = () => {
6171
const [id, setId] = useState('')
6272
const [pw, setPw] = useState('')
6373
const [showPw, setShowPw] = useState(false)
74+
const [errorMsg, setErrorMsg] = useState('')
6475
const navigate = useNavigate()
6576

6677
const isValid = id.length > 0 && pw.length >= 6
6778

79+
const handleLogin = async (e: React.FormEvent) => {
80+
e.preventDefault()
81+
setErrorMsg('')
82+
83+
try {
84+
const res = await instance
85+
.post('*/api/v1/auth/login', {
86+
json: { loginId: id, password: pw },
87+
})
88+
.json<LoginResponse>()
89+
90+
if (res.success && res.data) {
91+
localStorage.setItem('accessToken', res.data.accessToken)
92+
localStorage.setItem('refreshToken', res.data.refreshToken)
93+
navigate({ to: '/' })
94+
}
95+
} catch {
96+
setErrorMsg('잘못된 이메일 또는 비밀번호입니다. 다시 입력해주세요.')
97+
}
98+
}
99+
68100
return (
69101
<div className="flex w-full flex-col items-center bg-white p-10">
70102
<img
@@ -73,13 +105,7 @@ const LoginCard = () => {
73105
className="mt-2 mb-8 w-[175px]"
74106
/>
75107

76-
<form
77-
className="flex w-full flex-col"
78-
onSubmit={(e) => {
79-
e.preventDefault()
80-
navigate({ to: '/' })
81-
}}
82-
>
108+
<form className="flex w-full flex-col" onSubmit={handleLogin}>
83109
<FloatingInput
84110
label="전화번호, 사용자 이름 또는 이메일"
85111
value={id}
@@ -94,9 +120,16 @@ const LoginCard = () => {
94120
setShowPw={setShowPw}
95121
/>
96122

123+
{errorMsg && (
124+
<p className="mb-2 px-1 text-left text-[11px] leading-tight text-[#ed4956]">
125+
{errorMsg}
126+
</p>
127+
)}
128+
97129
<button
130+
type="submit"
98131
disabled={!isValid}
99-
className={`mt-3 rounded py-1.5 text-sm font-semibold text-white transition-colors ${
132+
className={`mt-1.5 rounded py-1.5 text-sm font-semibold text-white transition-colors ${
100133
isValid ? 'bg-[#0095f6]' : 'bg-[#b2dffc]'
101134
}`}
102135
>
@@ -112,9 +145,17 @@ const LoginCard = () => {
112145
<div className="h-px flex-1 bg-gray-300"></div>
113146
</div>
114147

148+
<button
149+
type="button"
150+
className="flex w-full items-center justify-center gap-2 rounded bg-[#FEE500] py-2 text-[14px] font-semibold text-[#191919] transition-opacity hover:opacity-90"
151+
>
152+
<MessageCircle className="h-4 w-4 fill-[#191919] stroke-none" />
153+
카카오톡으로 로그인
154+
</button>
155+
115156
<button
116157
onClick={() => navigate({ to: '/password/reset' })}
117-
className="mt-2 cursor-pointer text-xs text-[#00376b] hover:underline"
158+
className="mt-6 cursor-pointer text-xs text-[#00376b] hover:underline"
118159
>
119160
비밀번호를 잊으셨나요?
120161
</button>

src/components/post/PostDetail.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ export default function PostDetail() {
131131
}}
132132
transition={{
133133
duration: 0.7,
134-
times: [0, 0.57, 1], // 0.4s 지점까지 기울기 유지, 이후 0.3s 동안 회전 완료
134+
times: [0, 0.57, 1],
135135
ease: 'easeInOut',
136136
}}
137137
onAnimationComplete={() => setIsAnimating(false)}

src/mocks/db/auth.db.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
export interface MockAuth {
2+
loginId: string
3+
password: string
4+
userId: number
5+
}
6+
7+
export const authUsers: MockAuth[] = [
8+
{
9+
loginId: 'admin123@gmail.com',
10+
password: 'admin123',
11+
userId: 1,
12+
},
13+
{
14+
loginId: 'user2@gmail.com',
15+
password: 'password123',
16+
userId: 2,
17+
},
18+
{
19+
loginId: 'user3@gmail.com',
20+
password: 'password123',
21+
userId: 3,
22+
},
23+
{
24+
loginId: 'user4@gmail.com',
25+
password: 'password123',
26+
userId: 4,
27+
},
28+
{
29+
loginId: 'user5@gmail.com',
30+
password: 'password123',
31+
userId: 5,
32+
},
33+
]

src/mocks/handlers.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ import { albumHandlers } from './handlers/album'
44
import { feedHandlers } from './handlers/feed'
55
import { followHandlers } from './handlers/follow'
66
import { testHandlers } from './handlers/test'
7+
import { authHandlers } from './handlers/auth'
78

89
export const handlers = [
10+
...authHandlers,
911
...postHandlers,
1012
...commentHandlers,
1113
...albumHandlers,

src/mocks/handlers/auth.ts

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,48 @@
1-
// 해당 엔티티에 필요한 데이터를 나중에 여기서 가져옴
2-
// import { mockData } from '../db/entity.db';
1+
import { http, HttpResponse } from 'msw'
2+
import { authUsers } from '../db/auth.db'
33

44
export const authHandlers = [
5-
// 여기에 http.get, http.post 등을 추가
5+
http.post('*/api/v1/auth/login', async ({ request }) => {
6+
const body = (await request.json()) as Record<string, string>
7+
const { loginId, password } = body
8+
9+
const authInfo = authUsers.find((u) => u.loginId === loginId)
10+
11+
if (!authInfo) {
12+
return HttpResponse.json(
13+
{
14+
code: 'USER404',
15+
message: '사용자를 찾을 수 없습니다.',
16+
data: null,
17+
success: false,
18+
},
19+
{ status: 404 }
20+
)
21+
}
22+
23+
if (authInfo.password !== password) {
24+
return HttpResponse.json(
25+
{
26+
code: 'AUTH401',
27+
message: '비밀번호가 일치하지 않습니다.',
28+
data: null,
29+
success: false,
30+
},
31+
{ status: 401 }
32+
)
33+
}
34+
35+
return HttpResponse.json(
36+
{
37+
code: 'COMMON200',
38+
message: '성공입니다.',
39+
data: {
40+
accessToken: `mock-access-token-${authInfo.userId}`,
41+
refreshToken: 'mock-refresh-token',
42+
},
43+
success: true,
44+
},
45+
{ status: 200 }
46+
)
47+
}),
648
]

yarn.lock

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3281,10 +3281,10 @@ lru-cache@^5.1.1:
32813281
dependencies:
32823282
yallist "^3.0.2"
32833283

3284-
lucide-react@^0.562.0:
3285-
version "0.562.0"
3286-
resolved "https://registry.yarnpkg.com/lucide-react/-/lucide-react-0.562.0.tgz#217796c2f57624f012b484ea7f08505067c90d51"
3287-
integrity sha512-82hOAu7y0dbVuFfmO4bYF1XEwYk/mEbM5E+b1jgci/udUBEE/R7LF5Ip0CCEmXe8AybRM8L+04eP+LGZeDvkiw==
3284+
lucide-react@^0.563.0:
3285+
version "0.563.0"
3286+
resolved "https://registry.yarnpkg.com/lucide-react/-/lucide-react-0.563.0.tgz#9a660d6f009942914a0df42391cf7d7d4dbcc713"
3287+
integrity sha512-8dXPB2GI4dI8jV4MgUDGBeLdGk8ekfqVZ0BdLcrRzocGgG75ltNEmWS+gE7uokKF/0oSUuczNDT+g9hFJ23FkA==
32883288

32893289
lz-string@^1.5.0:
32903290
version "1.5.0"

0 commit comments

Comments
 (0)