-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
π μν μ λ°λ₯Έ url μ²λ¦¬ μ§ν #77
Conversation
μν¬μ€λ£¨μ΄ ν 리νμ€νΈλ κ΄λ¦¬μ κ³μ μμ κΈ°λ₯μ μΆκ°νκ³ λ―Έλ€μ¨μ΄μ κ²½λ‘ μ ν λ‘μ§μ κ°μ ν©λλ€. μλ‘μ΄ API μλν¬μΈνΈμ νλ‘ νΈμλ μ»΄ν¬λνΈλ₯Ό ν΅ν΄ κ΄λ¦¬μκ° μμ μ κ³μ μ μμ ν μ μκ² λμμΌλ©°, λ―Έλ€μ¨μ΄λ μ¬μ©μ μν κ³Ό κ²½λ‘ μ κ·Όμ λν λ μΈλ°ν μ μ΄λ₯Ό μ 곡ν©λλ€. λ³κ²½ μ¬ν
κ°λ₯ν κ΄λ ¨ PR
μ μλ λ μ΄λΈ
μ μλ 리뷰μ΄
μ(θ©©)
Finishing Touches
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? πͺ§ TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
π§Ή Nitpick comments (8)
src/middleware.ts (3)
44-46
: λ―ΈμΈμ¦ μ¬μ©μμ λν 리λλ μ λ‘μ§ κ²νλ―ΈμΈμ¦ μ¬μ©μκ°
USER_RESTRICTED_PATHS
μ ν΄λΉνλ κ²½λ‘μ μ κ·Όν λ 루νΈλ‘ 리λλ μ νκ³ μμ΅λλ€. κ·Έλ¬λ μ¬μ©μ κ²½νμ ν₯μμν€κΈ° μν΄ λ‘κ·ΈμΈ νμ΄μ§λ‘ 리λλ μ νλ κ²μ΄ λ μ μ ν μ μμ΅λλ€.λ€μκ³Ό κ°μ΄ μμ νμ¬ λ‘κ·ΈμΈ νμ΄μ§λ‘ 리λλ μ ν κ²μ μ μν©λλ€:
if (!accessToken && isPathMatch(pathname, USER_RESTRICTED_PATHS)) { - return NextResponse.redirect(new URL('/', request.url)); + return NextResponse.redirect(new URL('/signIn', request.url)); }
48-50
: μΈμ¦λ μ¬μ©μμ λν μ κ·Ό μ ν λ‘μ§ κ²νμ΄λ―Έ μΈμ¦λ μ¬μ©μκ°
MANAGE_RESTRICTED_PATHS
μ ν΄λΉνλ κ²½λ‘μ μ κ·Όν λ 루νΈλ‘ 리λλ μ νκ³ μμ΅λλ€. κ·Έλ¬λ μ΄ κ²½μ°μλ μ¬μ©μ κ²½νμ κ³ λ €νμ¬ νΉμ νμ΄μ§λ‘ 리λλ μ νκ±°λ μ κ·Όμ νμ©νλ κ²μ΄ μ’μ μ μμ΅λλ€.μΈμ¦λ μ¬μ©μκ° νμκ°μ μ΄λ λ‘κ·ΈμΈ νμ΄μ§μ μ κ·Όν νμκ° μλ€λ©΄, ν΄λΉ κ²½λ‘μ μ κ·Όν κ²½μ° λμ보λλ νλ‘ν νμ΄μ§λ‘ 리λλ μ νλ κ²μ κ³ λ €ν΄λ³΄μΈμ.
if (accessToken && isPathMatch(pathname, MANAGE_RESTRICTED_PATHS)) { - return NextResponse.redirect(new URL('/', request.url)); + return NextResponse.redirect(new URL('/dashboard', request.url)); }
56-70
:matcher
μ€μ μ μ±λ₯ λ° μ μ§λ³΄μμ± κ°μνμ¬
matcher
λ°°μ΄μ λ§μ κ²½λ‘κ° νλμ½λ©λμ΄ μμ΅λλ€. μ΄λ μ μ§λ³΄μμ μ΄λ €μμ μ€ μ μμΌλ©°, λλ½λ κ²½λ‘λ μ€νλ‘ μΈν λ²κ·Έκ° λ°μν μ μμ΅λλ€.λ€μκ³Ό κ°μ΄ μ κ·μμ΄λ ν¨ν΄μ νμ©νμ¬
matcher
λ₯Ό κ°κ²°νκ² ννν κ²μ μ μν©λλ€:export const config = { matcher: [ - '/api/role', - '/signIn', - '/signUp', - '/admin', - '/create-exhibition', - '/expo-manage/:path*', - '/name-tag/:path*', - '/sms/:path*/STANDARD', - '/sms/:path*/TRAINEE', - '/program/:path*', - '/program/detail/:path*', - '/application/:path*/STANDARD', - '/application/:path*/TRAINEE', + '/((api/role)|(signIn)|(signUp)|(admin)|(create-exhibition)|(expo-manage.*)|(name-tag.*)|(sms.*)|(program.*)|(application.*))', ], };src/entities/admin/model/useDeleteUserAccount.ts (2)
10-10
: λΆνμν νμ΄ν ν¨μ κ°μν
mutationFn
μμ λ¨μν λ€λ₯Έ ν¨μλ₯Ό νΈμΆνκ³ μμΌλ―λ‘, νμ΄ν ν¨μλ₯Ό μ¬μ©νμ§ μκ³ λ°λ‘ ν¨μλͺ μ μ λ¬ν μ μμ΅λλ€.λ€μκ³Ό κ°μ΄ μ½λλ₯Ό κ°μνν μ μμ΅λλ€:
return useMutation({ - mutationFn: () => deleteUserAccount(), + mutationFn: deleteUserAccount,
16-17
: μλ¬ λ©μμ§ κ°μμλ¬ λ°μ μ μ¬μ©μμκ² μ 곡λλ λ©μμ§λ₯Ό ꡬ체μ μΌλ‘ μμ±νμ¬ μ¬μ©μ κ²½νμ ν₯μμν¬ μ μμ΅λλ€. μλ¬ μμΈμ΄λ μΆκ° μ‘°μΉμ λν μλ΄λ₯Ό ν¬ν¨νλ©΄ μ’μ΅λλ€.
μλ₯Ό λ€μ΄:
onError: () => { - toast.error('μ μ νν΄λ₯Ό μ€ν¨νμ΅λλ€.'); + toast.error('νν΄ κ³Όμ μμ λ¬Έμ κ° λ°μνμ΅λλ€. μ μ ν λ€μ μλν΄μ£ΌμΈμ.'); },src/app/api/admin/route.ts (2)
39-49
: 보μ κ°νλ₯Ό μν μ μμ¬νμ΄ μμ΅λλ€.
- refreshTokenμ μ ν¨μ±λ κ²μ¦νλ κ²μ΄ μ’μ΅λλ€.
- λ―Όκ°ν μμ μ΄λ―λ‘ λ‘κ·Έλ₯Ό μΆκ°νλ κ²μ΄ μ’μ΅λλ€.
- μ±κ³΅ μλ΅ μ λ μμΈν λ©μμ§λ₯Ό ν¬ν¨νλ κ²μ΄ μ’μ΅λλ€.
λ€μκ³Ό κ°μ΄ μμ νλ κ²μ μ μν©λλ€:
try { + const refreshToken = cookieStore.get('refreshToken')?.value; + if (!refreshToken) { + return NextResponse.json( + { error: 'μΈμ¦μ΄ νμν©λλ€' }, + { status: 401 } + ); + } + console.log('κ΄λ¦¬μ κ³μ μμ μλ:', new Date().toISOString()); await apiClient.delete('/admin', { headers: { Authorization: `Bearer ${accessToken}`, }, }); + console.log('κ΄λ¦¬μ κ³μ μμ μ±κ³΅'); const response = NextResponse.json({ - success: true + success: true, + message: 'κ΄λ¦¬μ κ³μ μ΄ μ±κ³΅μ μΌλ‘ μμ λμμ΅λλ€' });
32-37
: μλ¬ λ©μμ§λ₯Ό νκΈλ‘ λ³κ²½νλ κ²μ΄ μ’μ΅λλ€.νμ¬ μλ¬ λ©μμ§κ° μμ΄λ‘ λμ΄ μμ΅λλ€. μΌκ΄μ±μ μν΄ νκΈλ‘ λ³κ²½νλ κ²μ΄ μ’μ΅λλ€.
if (!accessToken) { return NextResponse.json( - { error: 'Access token not found' }, + { error: 'μ‘μΈμ€ ν ν°μ μ°Ύμ μ μμ΅λλ€' }, { status: 401 }, ); }src/entities/admin/ui/AdminProfile/index.tsx (1)
15-20
: μν κ΄λ¦¬ λ‘μ§μ λΆλ¦¬νλ κ²μ΄ μ’μ΅λλ€.ν κΈ μν κ΄λ¦¬ λ‘μ§μ λ³λμ 컀μ€ν ν μΌλ‘ λΆλ¦¬νλ©΄ μ¬μ¬μ©μ±κ³Ό ν μ€νΈ μ©μ΄μ±μ΄ ν₯μλ©λλ€.
+ const useToggle = (initialState = false) => { + const [state, setState] = useState(initialState); + const toggle = useCallback(() => setState(prev => !prev), []); + return [state, toggle] as const; + }; const AdminProfile = () => { const { mutate: logout } = useLogout(); const { mutate: deleteAccount } = useDeleteUserAccount(); - const [isToggleLogout, setIsToggleLogout] = useState(false); + const [isToggleLogout, toggleLogout] = useToggle(false); - const handleLogoutClick = () => { - setIsToggleLogout((prev) => !prev); - };
π Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
π Files selected for processing (5)
src/app/api/admin/route.ts
(1 hunks)src/entities/admin/api/deleteUserAccount.ts
(1 hunks)src/entities/admin/model/useDeleteUserAccount.ts
(1 hunks)src/entities/admin/ui/AdminProfile/index.tsx
(2 hunks)src/middleware.ts
(2 hunks)
π Additional comments (2)
src/middleware.ts (2)
10-17
: μ κ·μ ν¨ν΄μ μ νμ± νμΈ νμ
USER_RESTRICTED_PATHS
λ°°μ΄μ μ μλ μ κ·μ ν¨ν΄λ€μ΄ μλν URLλ€μ μ νν 맀μΉνλμ§ νμΈν΄μΌ ν©λλ€. νΉν/program
κ΄λ ¨ κ²½λ‘λ€μ ν¨ν΄μ΄ λͺ¨λ κ²½μ°λ₯Ό ν¬κ΄νλμ§ κ²ν κ° νμν©λλ€.λ€μ μ€ν¬λ¦½νΈλ₯Ό μ€ννμ¬ ν¨ν΄ 맀μΉμ κ²μ¦νμΈμ:
β Verification successful
μ κ·μ ν¨ν΄μ΄ μ νν ꡬνλμ΄ μμμ νμΈνμ΅λλ€
μ½λλ² μ΄μ€ λΆμ κ²°κ³Ό,
USER_RESTRICTED_PATHS
μ λͺ¨λ μ κ·μ ν¨ν΄μ΄ μ€μ μ ν리μΌμ΄μ μμ μ¬μ©λλ λΌμ°νΈμ μ νν μΌμΉνλ©°, κ° ν¨ν΄μ΄ μλν URL ꡬ쑰λ₯Ό μ¬λ°λ₯΄κ² 맀μΉνκ³ μμ΅λλ€. νΉν/program
κ΄λ ¨ ν¨ν΄λ λͺ¨λ νμ κ²½λ‘λ₯Ό μ ννκ² ν¬ν¨νλλ‘ κ΅¬νλμ΄ μμ΅λλ€.π Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # μ€λͺ : USER_RESTRICTED_PATHSμ μ κ·μ ν¨ν΄μ΄ μλν κ²½λ‘μ 맀μΉλλμ§ νμΈν©λλ€. # ν μ€νΈ: κ° ν¨ν΄μ λν΄ λ§€μΉλλ κ²½λ‘λ₯Ό μΆλ ₯ν©λλ€. for pattern in '^/admin$' '^/create-exhibition$' '^/expo-manage/.+$' '^/name-tag/.+$' '^/sms/.+/(STANDARD|TRAINEE)$' '^/program(/.*)?$'; do echo "ν¨ν΄: $pattern" rg --files | grep -E "$pattern" doneLength of output: 1406
Script:
#!/bin/bash # Find where USER_RESTRICTED_PATHS is used echo "=== USER_RESTRICTED_PATHS Usage ===" rg "USER_RESTRICTED_PATHS" -B 2 -A 2 # Look for route definitions and tests echo -e "\n=== Route Definitions and Tests ===" rg "(router\.|app\.|routes?\.|test)" "src/" -g "*.{ts,tsx,js,jsx}" -A 2 # Look for test files that might contain these paths echo -e "\n=== Path Tests ===" rg "(admin|create-exhibition|expo-manage|name-tag|sms|program)" "src/" -g "*test*" -A 2Length of output: 5541
4-8
: μ κ·μ ν¨ν΄μ μ νμ± νμΈ νμ
MANAGE_RESTRICTED_PATHS
λ°°μ΄μ μ μλ μ κ·μ ν¨ν΄λ€μ΄ μλν URLλ€μ μ νν 맀μΉνλμ§ νμΈν΄μΌ ν©λλ€. νΉν/application/...
κ²½λ‘μ ν¨ν΄μ΄ μ¬λ°λ₯΄κ² μμ±λμλμ§ κ²ν κ° νμν©λλ€.λ€μ μ€ν¬λ¦½νΈλ₯Ό μ€ννμ¬ ν¨ν΄ 맀μΉμ κ²μ¦νμΈμ:
β Verification successful
μ κ·μ ν¨ν΄μ΄ μ¬λ°λ₯΄κ² ꡬνλμ΄ μμμ νμΈνμ΅λλ€
middleware.tsμ μ κ·μ ν¨ν΄λ€μ΄ λ€μκ³Ό κ°μ΄ μ ννκ² κ΅¬νλμ΄ μμ΅λλ€:
/signIn
,/signUp
κ²½λ‘μ λν μ νν 맀μΉ/application/[...]/STANDARD
λλ/application/[...]/TRAINEE
νμμ λμ κ²½λ‘ λ§€μΉμ΄ ν¨ν΄λ€μ λ―Έλ€μ¨μ΄μμ μ μ νκ² μ¬μ©λμ΄ μΈμ¦λ μ¬μ©μμ μ κ·Όμ μ μ΄νκ³ μμ΅λλ€.
π Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # μ€λͺ : MANAGE_RESTRICTED_PATHSμ μ κ·μ ν¨ν΄μ΄ μλν κ²½λ‘μ 맀μΉλλμ§ νμΈν©λλ€. # ν μ€νΈ: κ° ν¨ν΄μ λν΄ λ§€μΉλλ κ²½λ‘λ₯Ό μΆλ ₯ν©λλ€. for pattern in '^/signIn$' '^/signUp$' '^/application/.+/(STANDARD|TRAINEE)$'; do echo "ν¨ν΄: $pattern" rg --files | grep -E "$pattern" doneLength of output: 536
Script:
#!/bin/bash # Find usages of MANAGE_RESTRICTED_PATHS and router definitions echo "=== MANAGE_RESTRICTED_PATHS μ¬μ©μ² κ²μ ===" rg "MANAGE_RESTRICTED_PATHS" -B 2 -A 2 echo -e "\n=== λΌμ°ν° μ μ κ²μ ===" rg "router\.(get|post|put|delete)" -B 1 -A 1 echo -e "\n=== URL ν¨ν΄μ΄ ν¬ν¨λ ν μ€νΈ νμΌ κ²μ ===" rg "signIn|signUp|STANDARD|TRAINEE" --type=testLength of output: 816
Script:
#!/bin/bash # isPathMatch ν¨μ ꡬν κ²μ echo "=== isPathMatch ν¨μ ꡬν κ²μ ===" ast-grep --pattern 'function isPathMatch' -A 10 echo -e "\n=== κ΄λ ¨ νμ΄μ§ νμΌ κ²μ ===" fd -e tsx -e ts "signIn|signUp|application" app pages src echo -e "\n=== application κ²½λ‘ κ΄λ ¨ νμΌ κ²μ ===" fd "application" -t fLength of output: 548
Script:
#!/bin/bash # isPathMatch ν¨μ ꡬν λ€μ κ²μ echo "=== isPathMatch ν¨μ κ²μ (μμ λ ν¨ν΄) ===" rg "isPathMatch" -B 3 -A 10 echo -e "\n=== λΌμ°νΈ ꡬ쑰 κ²μ ===" fd -t d "^(app|src)$" . fd -t f . src -e tsx -e ts --max-depth 2 echo -e "\n=== application μ»΄ν¬λνΈ/νμ΄μ§ κ²μ ===" rg -l "application.*/(STANDARD|TRAINEE)" --type ts --type tsxLength of output: 1770
} | ||
function handleApiRole(request: NextRequest): NextResponse { | ||
const requestHeaders = new Headers(request.headers); | ||
const role = request.cookies.get('accessToken') ? 'manage' : 'user'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
κΆν μ€μ λ‘μ§μ 보μ κ°ν νμ
νμ¬ accessToken
μ μ‘΄μ¬ μ¬λΆλ‘λ§ role
μ manage
λλ user
λ‘ μ€μ νκ³ μμ΅λλ€. ν ν°μ μ ν¨μ±κ³Ό μ€μ μ¬μ©μμ μν (μ: κ΄λ¦¬μ, μΌλ° μ¬μ©μ)μ κ²μ¦νλ μΆκ°μ μΈ λ‘μ§μ΄ νμν©λλ€. μ΄λ 보μ κ°νλ₯Ό μν΄ μ€μν©λλ€.
accessToken
μ κ²μ¦νκ³ μ¬μ©μ μν μ μ ννκ² νλ¨νλ λ‘μ§μ μΆκ°νμΈμ. μλ₯Ό λ€μ΄, ν ν°μ ν΄μνμ¬ μ¬μ©μ μ 보λ₯Ό μΆμΆνκ³ , ν΄λΉ μ¬μ©μμ κΆνμ λ°λΌ μν μ λΆμ¬νλ λ°©μμ κ³ λ €ν μ μμ΅λλ€.
import axios from 'axios'; | ||
|
||
export const deleteUserAccount = async () => { | ||
const response = await axios.delete('/api/admin'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π οΈ Refactor suggestion
μλ¬ μ²λ¦¬ λ‘μ§ μΆκ° νμ
νμ¬ deleteUserAccount
ν¨μλ μμ² μ€ν¨ μμ μ²λ¦¬ λ‘μ§μ΄ μμ΅λλ€. μλ²λ‘λΆν° μλ¬ μλ΅μ λ°λ κ²½μ°λ₯Ό λλΉνμ¬ μμΈ μ²λ¦¬λ₯Ό μΆκ°νλ κ²μ΄ μ’μ΅λλ€.
λ€μκ³Ό κ°μ΄ try-catch
λΈλ‘μ μ¬μ©νμ¬ μλ¬λ₯Ό μ²λ¦¬νλλ‘ μμ νμΈμ:
export const deleteUserAccount = async () => {
- const response = await axios.delete('/api/admin');
- return response;
+ try {
+ const response = await axios.delete('/api/admin');
+ return response;
+ } catch (error) {
+ // μλ¬ μ²λ¦¬ λ‘μ§ μΆκ°
+ throw error;
+ }
};
π Committable suggestion
βΌοΈ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const response = await axios.delete('/api/admin'); | |
export const deleteUserAccount = async () => { | |
try { | |
const response = await axios.delete('/api/admin'); | |
return response; | |
} catch (error) { | |
// μλ¬ μ²λ¦¬ λ‘μ§ μΆκ° | |
throw error; | |
} | |
}; |
export async function DELETE() { | ||
const cookieStore = cookies(); | ||
const accessToken = cookieStore.get('accessToken')?.value; | ||
|
||
if (!accessToken) { | ||
return NextResponse.json( | ||
{ error: 'Access token not found' }, | ||
{ status: 401 }, | ||
); | ||
} | ||
|
||
try { | ||
await apiClient.delete('/admin', { | ||
headers: { | ||
Authorization: `Bearer ${accessToken}`, | ||
}, | ||
}); | ||
|
||
const response = NextResponse.json({ success: true }); | ||
response.cookies.set('accessToken', '', { maxAge: 0 }); | ||
response.cookies.set('refreshToken', '', { maxAge: 0 }); | ||
return response; | ||
} catch (error) { | ||
if (error instanceof AxiosError) { | ||
const status = error.response?.status || 500; | ||
const message = | ||
error.response?.data?.message || 'delete user account failed'; | ||
return NextResponse.json({ error: message }, { status }); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
catch λΈλ‘μμ κΈ°λ³Έ μλ΅μ΄ λλ½λμμ΅λλ€.
errorκ° AxiosError μΈμ€ν΄μ€κ° μλ κ²½μ°μ λν μλ΅μ΄ λλ½λμ΄ μμ΅λλ€. μ΄λ μκΈ°μΉ μμ μ€λ₯κ° λ°μν μ μμ΅λλ€.
λ€μκ³Ό κ°μ΄ μμ νλ κ²μ μ μν©λλ€:
} catch (error) {
if (error instanceof AxiosError) {
const status = error.response?.status || 500;
const message =
error.response?.data?.message || 'delete user account failed';
return NextResponse.json({ error: message }, { status });
}
+ return NextResponse.json(
+ { error: 'Internal server error' },
+ { status: 500 }
+ );
}
π Committable suggestion
βΌοΈ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
export async function DELETE() { | |
const cookieStore = cookies(); | |
const accessToken = cookieStore.get('accessToken')?.value; | |
if (!accessToken) { | |
return NextResponse.json( | |
{ error: 'Access token not found' }, | |
{ status: 401 }, | |
); | |
} | |
try { | |
await apiClient.delete('/admin', { | |
headers: { | |
Authorization: `Bearer ${accessToken}`, | |
}, | |
}); | |
const response = NextResponse.json({ success: true }); | |
response.cookies.set('accessToken', '', { maxAge: 0 }); | |
response.cookies.set('refreshToken', '', { maxAge: 0 }); | |
return response; | |
} catch (error) { | |
if (error instanceof AxiosError) { | |
const status = error.response?.status || 500; | |
const message = | |
error.response?.data?.message || 'delete user account failed'; | |
return NextResponse.json({ error: message }, { status }); | |
} | |
} | |
} | |
export async function DELETE() { | |
const cookieStore = cookies(); | |
const accessToken = cookieStore.get('accessToken')?.value; | |
if (!accessToken) { | |
return NextResponse.json( | |
{ error: 'Access token not found' }, | |
{ status: 401 }, | |
); | |
} | |
try { | |
await apiClient.delete('/admin', { | |
headers: { | |
Authorization: `Bearer ${accessToken}`, | |
}, | |
}); | |
const response = NextResponse.json({ success: true }); | |
response.cookies.set('accessToken', '', { maxAge: 0 }); | |
response.cookies.set('refreshToken', '', { maxAge: 0 }); | |
return response; | |
} catch (error) { | |
if (error instanceof AxiosError) { | |
const status = error.response?.status || 500; | |
const message = | |
error.response?.data?.message || 'delete user account failed'; | |
return NextResponse.json({ error: message }, { status }); | |
} | |
return NextResponse.json( | |
{ error: 'Internal server error' }, | |
{ status: 500 } | |
); | |
} | |
} |
<div className="relative flex w-full justify-between"> | ||
<div className="flex items-center gap-[124px] mobile:flex-col mobile:gap-[30px]"> | ||
<div className="space-y-[32px]"> | ||
<ProfileInfo label="μ΄λ¦" value="κΉμ§μ" /> | ||
<ProfileInfo label="μμ΄λ" value="jin1234" /> | ||
<ProfileInfo label="μ΄λ©μΌ" value="[email protected]" /> | ||
</div> | ||
</div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π οΈ Refactor suggestion
νλμ½λ©λ μ¬μ©μ μ 보λ₯Ό propsλ μνλ‘ κ΄λ¦¬νλ κ²μ΄ μ’μ΅λλ€.
νμ¬ μ¬μ©μ μ λ³΄κ° νλμ½λ©λμ΄ μμ΅λλ€. μ΄λ μ μ§λ³΄μμ±μ μ νμν¬ μ μμ΅λλ€.
λ€μκ³Ό κ°μ΄ μμ νλ κ²μ μ μν©λλ€:
+ interface AdminProfileProps {
+ name: string;
+ username: string;
+ email: string;
+ }
- const AdminProfile = () => {
+ const AdminProfile = ({ name, username, email }: AdminProfileProps) => {
return (
<div className="relative flex w-full justify-between">
<div className="flex items-center gap-[124px] mobile:flex-col mobile:gap-[30px]">
<div className="space-y-[32px]">
- <ProfileInfo label="μ΄λ¦" value="κΉμ§μ" />
- <ProfileInfo label="μμ΄λ" value="jin1234" />
- <ProfileInfo label="μ΄λ©μΌ" value="[email protected]" />
+ <ProfileInfo label="μ΄λ¦" value={name} />
+ <ProfileInfo label="μμ΄λ" value={username} />
+ <ProfileInfo label="μ΄λ©μΌ" value={email} />
</div>
</div>
π Committable suggestion
βΌοΈ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
<div className="relative flex w-full justify-between"> | |
<div className="flex items-center gap-[124px] mobile:flex-col mobile:gap-[30px]"> | |
<div className="space-y-[32px]"> | |
<ProfileInfo label="μ΄λ¦" value="κΉμ§μ" /> | |
<ProfileInfo label="μμ΄λ" value="jin1234" /> | |
<ProfileInfo label="μ΄λ©μΌ" value="[email protected]" /> | |
</div> | |
</div> | |
interface AdminProfileProps { | |
name: string; | |
username: string; | |
email: string; | |
} | |
const AdminProfile = ({ name, username, email }: AdminProfileProps) => { | |
<div className="relative flex w-full justify-between"> | |
<div className="flex items-center gap-[124px] mobile:flex-col mobile:gap-[30px]"> | |
<div className="space-y-[32px]"> | |
<ProfileInfo label="μ΄λ¦" value={name} /> | |
<ProfileInfo label="μμ΄λ" value={username} /> | |
<ProfileInfo label="μ΄λ©μΌ" value={email} /> | |
</div> | |
</div> |
<div> | ||
<button onClick={handleLogoutClick}> | ||
<Logout /> | ||
</button> | ||
{isToggleLogout && ( | ||
<div className="absolute right-0 top-[30px] flex h-fit flex-col gap-2 rounded-[6px] border border-gray-200 bg-white p-2 shadow-[0px_4px_4px_0px_rgba(0,_0,_0,_0.25)]"> | ||
<button | ||
onClick={() => logout()} | ||
className="w-full rounded-[6px] px-5 py-2 text-body2 text-gray-500 hover:bg-error hover:text-white" | ||
> | ||
λ‘κ·Έμμ | ||
</button> | ||
<button | ||
onClick={() => deleteAccount()} | ||
className="w-full rounded-[6px] px-5 py-2 text-body2 text-gray-500 hover:bg-error hover:text-white" | ||
> | ||
νμνν΄ | ||
</button> | ||
</div> | ||
)} | ||
</div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π οΈ Refactor suggestion
μ κ·Όμ± λ° μ¬μ©μ κ²½ν κ°μ μ΄ νμν©λλ€.
- λ²νΌμ aria-labelμ΄ μμ΅λλ€.
- νμνν΄ μ νμΈ λνμμκ° μμ΅λλ€.
- λλ‘λ€μ΄μ΄ μ΄λ €μμ λ μΈλΆ ν΄λ¦μΌλ‘ λ«νμ§ μμ΅λλ€.
λ€μκ³Ό κ°μ΄ μμ νλ κ²μ μ μν©λλ€:
<div>
<button
+ aria-label="λ‘κ·Έμμ λ©λ΄"
+ aria-expanded={isToggleLogout}
onClick={handleLogoutClick}>
<Logout />
</button>
{isToggleLogout && (
<div className="absolute right-0 top-[30px] flex h-fit flex-col gap-2 rounded-[6px] border border-gray-200 bg-white p-2 shadow-[0px_4px_4px_0px_rgba(0,_0,_0,_0.25)]">
<button
onClick={() => logout()}
+ aria-label="λ‘κ·Έμμ μ€ν"
className="w-full rounded-[6px] px-5 py-2 text-body2 text-gray-500 hover:bg-error hover:text-white"
>
λ‘κ·Έμμ
</button>
<button
- onClick={() => deleteAccount()}
+ onClick={() => {
+ if (window.confirm('μ λ§λ‘ νμνν΄λ₯Ό μ§ννμκ² μ΅λκΉ?')) {
+ deleteAccount();
+ }
+ }}
+ aria-label="νμνν΄ μ€ν"
className="w-full rounded-[6px] px-5 py-2 text-body2 text-gray-500 hover:bg-error hover:text-white"
>
νμνν΄
</button>
</div>
)}
</div>
π Committable suggestion
βΌοΈ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
<div> | |
<button onClick={handleLogoutClick}> | |
<Logout /> | |
</button> | |
{isToggleLogout && ( | |
<div className="absolute right-0 top-[30px] flex h-fit flex-col gap-2 rounded-[6px] border border-gray-200 bg-white p-2 shadow-[0px_4px_4px_0px_rgba(0,_0,_0,_0.25)]"> | |
<button | |
onClick={() => logout()} | |
className="w-full rounded-[6px] px-5 py-2 text-body2 text-gray-500 hover:bg-error hover:text-white" | |
> | |
λ‘κ·Έμμ | |
</button> | |
<button | |
onClick={() => deleteAccount()} | |
className="w-full rounded-[6px] px-5 py-2 text-body2 text-gray-500 hover:bg-error hover:text-white" | |
> | |
νμνν΄ | |
</button> | |
</div> | |
)} | |
</div> | |
<div> | |
<button | |
aria-label="λ‘κ·Έμμ λ©λ΄" | |
aria-expanded={isToggleLogout} | |
onClick={handleLogoutClick}> | |
<Logout /> | |
</button> | |
{isToggleLogout && ( | |
<div className="absolute right-0 top-[30px] flex h-fit flex-col gap-2 rounded-[6px] border border-gray-200 bg-white p-2 shadow-[0px_4px_4px_0px_rgba(0,_0,_0,_0.25)]"> | |
<button | |
onClick={() => logout()} | |
aria-label="λ‘κ·Έμμ μ€ν" | |
className="w-full rounded-[6px] px-5 py-2 text-body2 text-gray-500 hover:bg-error hover:text-white" | |
> | |
λ‘κ·Έμμ | |
</button> | |
<button | |
onClick={() => { | |
if (window.confirm('μ λ§λ‘ νμνν΄λ₯Ό μ§ννμκ² μ΅λκΉ?')) { | |
deleteAccount(); | |
} | |
}} | |
aria-label="νμνν΄ μ€ν" | |
className="w-full rounded-[6px] px-5 py-2 text-body2 text-gray-500 hover:bg-error hover:text-white" | |
> | |
νμνν΄ | |
</button> | |
</div> | |
)} | |
</div> |
π‘ λ°°κ²½ λ° κ°μ
μν μ λ°λ₯Έ url μ²λ¦¬ μ§ν
π μμ λ΄μ©
μν μ λ°λΌ νΉμ νμ΄μ§λ‘ μ μμ΄ λμ§ μλλ‘ μ μ©νλ€.
πΈ κΈ°ν
MANAGE_RESTRICTED_PATHSμ USER_RESTRICTED_PATHS 2κ°λ‘ λλμ΄ μ κ·μμ μ μ©νμλ€.
μ΄λ‘μΈν΄ ν΄λΉ μ κ·μμ΄ μ³μμ§ μΆ©λΆν ν μ€νΈκ° νμν΄λ³΄μΈλ€.
Summary by CodeRabbit
μλ‘μ΄ κΈ°λ₯
λ²κ·Έ μμ
보μ κ°μ