Skip to content

Commit

Permalink
🎉 프로필 이미지 변경 로직 작성
Browse files Browse the repository at this point in the history
  • Loading branch information
oaoong committed Nov 8, 2023
1 parent 9f01553 commit e8fef2e
Show file tree
Hide file tree
Showing 9 changed files with 153 additions and 11 deletions.
31 changes: 31 additions & 0 deletions src/app/(root)/(routes)/mypage/error.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
'use client'

// Error components must be Client Components
import { useEffect } from 'react'

export default function Error({
error,
reset,
}: {
error: Error & { digest?: string }
reset: () => void
}) {
useEffect(() => {
// Log the error to an error reporting service
console.error(error)
}, [error])

return (
<div>
<h2>Something went wrong!</h2>
<button
onClick={
// Attempt to recover by trying to re-render the segment
() => reset()
}
>
Try again
</button>
</div>
)
}
18 changes: 18 additions & 0 deletions src/app/(root)/(routes)/mypage/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from 'react'
import UserInfo from './section/UserInfo'

const MyPage = () => {
return (
<main className="flex flex-col items-center gap-5 mt-5">
<header>
<h1>마이페이지</h1>
</header>
<section>
<UserInfo />
</section>
<section>{/* TODO: 각 내용에 대한 라우팅 추가 */}</section>
</main>
)
}

export default MyPage
32 changes: 32 additions & 0 deletions src/app/(root)/(routes)/mypage/section/UserInfo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
'use client'

import React, { useState } from 'react'
import AvatarEditable from '@/components/domain/AvatarEditable'
import { putUserProfile } from '@/services/user/user'

const UserInfo = () => {
const [isProfileChanged, setIsProfileChanged] = useState(true)
const [isNicknameChanged, setIsNicknameChanged] = useState(true)

const fileChangeHandler = async (file: File) => {
setIsProfileChanged(true)
try {
const _data = await putUserProfile({ file: file })
} catch (error) {
setIsProfileChanged(false)
console.log(error)
// TODO: toast error message 추가
}
}

return (
<div>
<AvatarEditable
fileChangeHandler={fileChangeHandler}
changedSuccessfully={isProfileChanged}
/>
</div>
)
}

export default UserInfo
11 changes: 6 additions & 5 deletions src/components/domain/AvatarEditable/AvatarEditable.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ export default meta
type Story = StoryObj<typeof meta>

export const Normal: Story = {
args: {},
}

export const Disabled: Story = {
args: {},
args: {
fileChangeHandler: (file) => {
alert(file.name)
},
changedSuccessfully: true,
},
}
19 changes: 13 additions & 6 deletions src/components/domain/AvatarEditable/AvatarEditable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,30 @@ interface EditButtonProps extends React.HTMLAttributes<HTMLInputElement> {
onChangeHandler: (_event: ChangeEvent<HTMLInputElement>) => void
}

const AvatarEditable = () => {
type AvatarEditablePropsType = {
fileChangeHandler: (_file: File) => void
changedSuccessfully: boolean
}

const AvatarEditable = ({
fileChangeHandler,
changedSuccessfully,
}: AvatarEditablePropsType) => {
const [profileImage, setProfileImage] = useState<string | null>(null)
const [file, setFile] = useState<File | null>(null)

useEffect(() => {
if (file) {
console.log(file)
if (!changedSuccessfully) {
setProfileImage(() => null)
}
}, [file])
}, [changedSuccessfully])

const onClickEdit = (event: ChangeEvent<HTMLInputElement>) => {
event.preventDefault()

if (event.target.files) {
const file = event.target.files[0]
const reader = new FileReader()
setFile(() => file)
fileChangeHandler(file)
reader.onloadend = () => {
setProfileImage(() => reader.result as string)
}
Expand Down
1 change: 1 addition & 0 deletions src/config/apiEndPoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const ApiEndPoint = {
items: (cursorId: number) => `/items?cursorId=${cursorId}`,
dibs: (itemId: number) => `/dib/${itemId}`,
suggestions: (itemId: string) => `/${itemId}/available-cards`,
putUserProfile: () => '/users/profile-image',
} as const

export default ApiEndPoint
2 changes: 2 additions & 0 deletions src/lib/msw/mocks/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import { dibsHandlers } from './dibsHandlers'
import { itemHandlers } from './itemHandlers'
import { suggestHandlers } from './suggestHandlers'
import { testHandlers } from './testHandler'
import { userHandlers } from './userHandlers'

export const handlers = [
...testHandlers,
...authHandlers,
...itemHandlers,
...dibsHandlers,
...suggestHandlers,
...userHandlers,
]
27 changes: 27 additions & 0 deletions src/lib/msw/mocks/userHandlers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { rest } from 'msw'
import ApiEndPoint from '@/config/apiEndPoint'
import { Environment } from '@/config/environment'

const baseUrl = Environment.apiAddress()

const userHandlers = [
rest.put(
`${baseUrl}${ApiEndPoint.putUserProfile()}`,
async (_req, res, ctx) => {
return res(
ctx.status(200),
ctx.json({
data: {
userInfo: {
userId: 1,
nickname: '귀염둥이파김치',
profileUrl: 'xxx',
},
},
}),
)
},
),
]

export { userHandlers }
23 changes: 23 additions & 0 deletions src/services/user/user.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import ApiEndPoint from '@/config/apiEndPoint'
import apiClient from '../apiClient'

type putUserProfileReq = {
file: File
}

const putUserProfile = async ({ file }: putUserProfileReq) => {
const formData = new FormData()
formData.append('profile', file)
const response = await apiClient.put(
ApiEndPoint.putUserProfile(),
formData,
{},
{
'Content-Type': 'multipart/form-data',
},
)
console.log(response)
return response
}

export { putUserProfile }

0 comments on commit e8fef2e

Please sign in to comment.