Skip to content

Commit e328d2d

Browse files
Merge branch 'develop' into FE-209
2 parents 22bc743 + 48f11a1 commit e328d2d

7 files changed

Lines changed: 164 additions & 45 deletions

File tree

β€Žsrc/apis/user.tsβ€Ž

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,7 @@ import { baseInstance } from './instance'
33
export const getUserInfo = () => {
44
return baseInstance.get(`/member/auth`)
55
}
6+
7+
export const updateUserInfo = (nickname: string) => {
8+
return baseInstance.put(`/member`, { nickName: nickname })
9+
}

β€Žsrc/assets/constant/constant.tsβ€Ž

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,6 @@ export const INPUT_MODE = Object.freeze({
3838
REPLY: 'reply',
3939
NESTEDREPLY: 'nestedReply',
4040
})
41+
42+
export const NICKNAME_MIN_LENGTH = 2
43+
export const NICKNAME_MAX_LENGTH = 8
Lines changed: 98 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,103 @@
1-
import React from 'react'
1+
import React, { useRef, useState } from 'react'
2+
import { ReactComponent as CloseIcon } from '@assets/icon_closed.svg'
3+
import { updateUserInfo } from '@apis/user'
4+
import useDebounce from '@hooks/useDebounce'
5+
import BackButton from '@components/BackButton'
6+
import { getIsValidateNickname } from '@utils/getIsValidateNickname'
7+
import { NICKNAME_MAX_LENGTH } from '@assets/constant/constant'
8+
import Button from '@components/Button'
9+
import { useLocation, useNavigate } from 'react-router-dom'
210

311
function ModifyInfo() {
4-
return <div>λ‚΄μ •λ³΄μˆ˜μ •μΈλ°μš©</div>
12+
const navigate = useNavigate()
13+
const { state } = useLocation()
14+
const inputRef = useRef<HTMLInputElement>(null)
15+
const [isCheckedNickname, setIsCheckedNickname] = useState(false)
16+
const [nickname, setNickname] = useState(state.nickname || '')
17+
const [errorMessage, setErrorMessage] = useState('')
18+
const [inputBorderStyle, setInputBorderStyle] = useState('')
19+
20+
useDebounce(
21+
async () => {
22+
setErrorMessage('')
23+
setInputBorderStyle('')
24+
setIsCheckedNickname(false)
25+
if (getIsValidateNickname(nickname, setErrorMessage)) {
26+
if (nickname.length > 0) {
27+
try {
28+
setIsCheckedNickname(true)
29+
setInputBorderStyle('border border-solid border-primary-2')
30+
} catch (e) {
31+
setErrorMessage('이미 μ‚¬μš©μ€‘μΈ λ‹‰λ„€μž„μ΄μ—μš”.')
32+
setIsCheckedNickname(false)
33+
setInputBorderStyle('border border-solid border-sub-1')
34+
}
35+
}
36+
} else {
37+
setInputBorderStyle('border border-solid border-sub-1')
38+
}
39+
},
40+
300,
41+
[nickname]
42+
)
43+
44+
const handleClickUpdateButton = async () => {
45+
try {
46+
await updateUserInfo(nickname)
47+
navigate('/setting')
48+
} catch (e) {
49+
setIsCheckedNickname(false)
50+
}
51+
}
52+
53+
return (
54+
<div className="relative h-screen w-full">
55+
<section id="route-backIcon-button" className="ml-[18px] mt-4">
56+
<BackButton />
57+
</section>
58+
<section id="modify-info-nickname" className="relative mt-11 px-6">
59+
<p className="font-medium">λ‹‰λ„€μž„</p>
60+
<div className="relative mt-[9px] flex w-full items-center">
61+
<input
62+
ref={inputRef}
63+
id="modify-nickname-input"
64+
value={nickname}
65+
className={`w-full rounded-[8px] bg-grey-2 py-[17px] pl-[12px] text-[14px] font-medium placeholder:text-grey-5 focus:outline-none
66+
${inputBorderStyle}`}
67+
autoComplete="off"
68+
onChange={(e) => setNickname(e.target.value)}
69+
maxLength={NICKNAME_MAX_LENGTH}
70+
autoFocus
71+
/>
72+
<CloseIcon
73+
className="absolute right-[10px] cursor-pointer"
74+
onClick={() => {
75+
setNickname('')
76+
inputRef.current?.focus()
77+
}}
78+
/>
79+
</div>
80+
<p
81+
className={`pt-3 text-sm ${
82+
isCheckedNickname ? 'text-primary-2' : 'text-sub-1'
83+
}`}
84+
>
85+
{isCheckedNickname ? 'μ‚¬μš© κ°€λŠ₯ν•œ λ‹‰λ„€μž„μ΄μ—μš”.' : errorMessage}
86+
</p>
87+
</section>
88+
<div className="relative mt-[104px] px-6">
89+
<Button
90+
type="submit"
91+
property="solid"
92+
active={isCheckedNickname}
93+
onClick={handleClickUpdateButton}
94+
disabled={!isCheckedNickname}
95+
>
96+
μˆ˜μ • μ™„λ£Œ
97+
</Button>
98+
</div>
99+
</div>
100+
)
5101
}
6102

7103
export default ModifyInfo

β€Žsrc/pages/Setting/Setting.tsxβ€Ž

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ import SettingSection from './SettingSection'
44
import { ReactComponent as Front } from '@assets/front_white.svg'
55
import { useNavigate } from 'react-router-dom'
66
import Alert from '@components/Alert'
7+
import Loading from '@components/Loading'
78

89
export default function Setting() {
9-
const { user, logoutUser } = useUser()
10+
const { user, isLoading, logoutUser } = useUser()
1011
const [isClickedLogout, setIsClickedLogout] = useState(false)
12+
1113
const PADDING_VALUE = 24
1214

1315
const navigate = useNavigate()
@@ -24,6 +26,11 @@ export default function Setting() {
2426
const getPaddingIgnoreWidth = () => {
2527
return `ml-[-${PADDING_VALUE}px] w-[calc(100%+${PADDING_VALUE * 2}px)]`
2628
}
29+
30+
if (isLoading) {
31+
return <Loading />
32+
}
33+
2734
return (
2835
<div className="flex h-full flex-col px-6 pt-10">
2936
{user !== null ? (
@@ -39,6 +46,7 @@ export default function Setting() {
3946
<SettingSection
4047
routeText="λ‚΄ 정보 μˆ˜μ •"
4148
routeUrl="/setting/modifyinfo"
49+
state={{ nickname: user.data }}
4250
/>
4351
<SettingSection
4452
routeText="λ‚΄ λŒ“κΈ€ 관리"

β€Žsrc/pages/Setting/SettingSection.tsxβ€Ž

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
import React from 'react'
22
import { ReactComponent as Front } from '@assets/front.svg'
33
import { useNavigate } from 'react-router-dom'
4-
54
interface SettingSectionProps {
65
routeUrl?: string
76
routeText: string
7+
state?: Record<string, string>
88
}
99

10-
function SettingSection({ routeUrl, routeText }: SettingSectionProps) {
10+
function SettingSection({ routeUrl, routeText, state }: SettingSectionProps) {
1111
const navigate = useNavigate()
1212

1313
const handleClickSection = () => {
1414
if (routeUrl) {
15-
navigate(routeUrl)
15+
navigate(routeUrl, { state })
1616
}
1717
}
1818

β€Žsrc/pages/SignUp/SignUp.tsxβ€Ž

Lines changed: 7 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import Input from '@components/Input'
66
import { useAuth } from '@react-query/hooks/useAuth'
77
import { getIsDuplicatedNickname } from '@apis/auth'
88
import useDebounce from '@hooks/useDebounce'
9-
10-
const NICKNAME_MIN_LENGTH = 2
9+
import { NICKNAME_MAX_LENGTH } from '@assets/constant/constant'
10+
import { getIsValidateNickname } from '@utils/getIsValidateNickname'
1111

1212
export default function SignUp() {
1313
const location = useLocation()
@@ -28,7 +28,10 @@ export default function SignUp() {
2828
async () => {
2929
setErrorMessage('')
3030
setIsCheckedNickname(false)
31-
if (nickname.length > 0 && validateNickname(nickname)) {
31+
if (
32+
nickname.length > 0 &&
33+
getIsValidateNickname(nickname, setErrorMessage)
34+
) {
3235
try {
3336
await getIsDuplicatedNickname(nickname)
3437
setIsCheckedNickname(true)
@@ -42,41 +45,6 @@ export default function SignUp() {
4245
[nickname]
4346
)
4447

45-
const validateNickname = (nickname: string) => {
46-
const spacePattern = /\s/g
47-
const consonantAndVowelPattern = /[γ„±-γ…Žγ…-γ…£]/
48-
const specialPattern = /[`~!@#$%^&*()_|+\-=?;:'",.<>\\{}[\]\\/β‚©]/gim
49-
const emojiPattern =
50-
/([\u2700-\u27BF]|[\uE000-\uF8FF]|\uD83C[\uDC00-\uDFFF]|\uD83D[\uDC00-\uDFFF]|[\u2011-\u26FF]|\uD83E[\uDD10-\uDDFF])/g
51-
52-
if (nickname.length < NICKNAME_MIN_LENGTH) {
53-
setErrorMessage(`${NICKNAME_MIN_LENGTH}κΈ€μž 이상 μž…λ ₯ν•΄μ£Όμ„Έμš”.`)
54-
return false
55-
}
56-
57-
if (nickname.match(spacePattern)) {
58-
setErrorMessage('곡백은 μ‚¬μš©ν•  수 μ—†μ–΄μš”.')
59-
return false
60-
}
61-
62-
if (nickname.match(specialPattern)) {
63-
setErrorMessage('νŠΉμˆ˜λ¬ΈμžλŠ” μ‚¬μš©ν•  수 μ—†μ–΄μš”.')
64-
return false
65-
}
66-
67-
if (nickname.match(consonantAndVowelPattern)) {
68-
setErrorMessage('μžμŒμ΄λ‚˜ λͺ¨μŒλ§Œμ€ μ‚¬μš©ν•  수 μ—†μ–΄μš”.')
69-
return false
70-
}
71-
72-
if (nickname.match(emojiPattern)) {
73-
setErrorMessage('이λͺ¨μ§€λŠ” μ‚¬μš©ν•  수 μ—†μ–΄μš”.')
74-
return false
75-
}
76-
77-
return true
78-
}
79-
8048
const setPropertyWithIsCheckedNickname = () => {
8149
if (nickname.length < 1 && !isInputClicked) return 'default'
8250
if (errorMessage.length > 0 && !isCheckedNickname) return 'error'
@@ -107,7 +75,7 @@ export default function SignUp() {
10775
name="nickname"
10876
label="λ‹‰λ„€μž„"
10977
value={nickname}
110-
maxLength={8}
78+
maxLength={NICKNAME_MAX_LENGTH}
11179
placeholder={isInputClicked ? '' : `κ΅­λ¬Έ, 영문, 숫자 포함 2~8자`}
11280
message={
11381
isCheckedNickname ? 'μ‚¬μš© κ°€λŠ₯ν•œ λ‹‰λ„€μž„μž…λ‹ˆλ‹€.' : errorMessage
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { NICKNAME_MIN_LENGTH } from '@assets/constant/constant'
2+
import { Dispatch, SetStateAction } from 'react'
3+
4+
export const getIsValidateNickname = (
5+
nickname: string,
6+
setErrorMessage: Dispatch<SetStateAction<string>>
7+
) => {
8+
const spacePattern = /\s/g
9+
const consonantAndVowelPattern = /[γ„±-γ…Žγ…-γ…£]/
10+
const specialPattern = /[`~!@#$%^&*()_|+\-=?;:'",.<>\\{}[\]\\/β‚©]/gim
11+
const emojiPattern =
12+
/([\u2700-\u27BF]|[\uE000-\uF8FF]|\uD83C[\uDC00-\uDFFF]|\uD83D[\uDC00-\uDFFF]|[\u2011-\u26FF]|\uD83E[\uDD10-\uDDFF])/g
13+
14+
if (nickname.length < NICKNAME_MIN_LENGTH) {
15+
setErrorMessage(`${NICKNAME_MIN_LENGTH}κΈ€μž 이상 μž…λ ₯ν•΄μ£Όμ„Έμš”.`)
16+
return false
17+
}
18+
19+
if (nickname.match(spacePattern)) {
20+
setErrorMessage('곡백은 μ‚¬μš©ν•  수 μ—†μ–΄μš”.')
21+
return false
22+
}
23+
24+
if (nickname.match(specialPattern)) {
25+
setErrorMessage('νŠΉμˆ˜λ¬ΈμžλŠ” μ‚¬μš©ν•  수 μ—†μ–΄μš”.')
26+
return false
27+
}
28+
29+
if (nickname.match(consonantAndVowelPattern)) {
30+
setErrorMessage('μžμŒμ΄λ‚˜ λͺ¨μŒλ§Œμ€ μ‚¬μš©ν•  수 μ—†μ–΄μš”.')
31+
return false
32+
}
33+
34+
if (nickname.match(emojiPattern)) {
35+
setErrorMessage('이λͺ¨μ§€λŠ” μ‚¬μš©ν•  수 μ—†μ–΄μš”.')
36+
return false
37+
}
38+
39+
return true
40+
}

0 commit comments

Comments
Β (0)