199 lines
6.2 KiB
TypeScript
199 lines
6.2 KiB
TypeScript
import { useState } from 'react'
|
|
import api from '../lib/api'
|
|
|
|
interface Props {
|
|
onClose: () => void
|
|
}
|
|
|
|
export default function FriendSearchDialog({ onClose }: Props) {
|
|
const [mode, setMode] = useState<'email' | 'character'>('email')
|
|
const [input, setInput] = useState({ email: '', name: '', server: '' })
|
|
const [result, setResult] = useState<any | null>(null)
|
|
const [error, setError] = useState<string | null>(null)
|
|
const [loading, setLoading] = useState(false)
|
|
|
|
const handleSearch = async () => {
|
|
setLoading(true)
|
|
setError(null)
|
|
setResult(null)
|
|
|
|
try {
|
|
const res = mode === 'email'
|
|
? await api.get('/users/public-info', { params: { email: input.email } })
|
|
: await api.get('/users/by-character', {
|
|
params: { server: input.server, name: input.name }
|
|
})
|
|
setResult(res.data)
|
|
} catch (e: any) {
|
|
setError(e.response?.data?.detail || '검색에 실패했습니다.')
|
|
} finally {
|
|
setLoading(false)
|
|
}
|
|
}
|
|
|
|
const handleRequest = async () => {
|
|
try {
|
|
await api.post('/friends/request', { to_user_email: result.email })
|
|
alert('친구 요청을 보냈습니다.')
|
|
onClose()
|
|
} catch {
|
|
alert('요청 실패')
|
|
}
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<div className="popup-backdrop" onClick={onClose} />
|
|
<div className="popup">
|
|
<h3>친구 추가</h3>
|
|
|
|
<div className="radio-group">
|
|
<label className="radio-option">
|
|
<input
|
|
type="radio"
|
|
name="search-mode"
|
|
checked={mode === 'email'}
|
|
onChange={() => setMode('email')}
|
|
/>
|
|
이메일로 검색
|
|
</label>
|
|
<label className="radio-option">
|
|
<input
|
|
type="radio"
|
|
name="search-mode"
|
|
checked={mode === 'character'}
|
|
onChange={() => setMode('character')}
|
|
/>
|
|
캐릭터로 검색
|
|
</label>
|
|
</div>
|
|
|
|
|
|
{mode === 'email' ? (
|
|
<input
|
|
type="text"
|
|
placeholder="example@naver.com"
|
|
value={input.email}
|
|
onChange={e => setInput({ ...input, email: e.target.value })}
|
|
/>
|
|
) : (
|
|
<>
|
|
<input
|
|
type="text"
|
|
placeholder="서버명"
|
|
value={input.server}
|
|
onChange={e => setInput({ ...input, server: e.target.value })}
|
|
/>
|
|
<input
|
|
type="text"
|
|
placeholder="캐릭터명"
|
|
value={input.name}
|
|
onChange={e => setInput({ ...input, name: e.target.value })}
|
|
/>
|
|
</>
|
|
)}
|
|
|
|
<div style={{ marginTop: '8px' }}>
|
|
<button onClick={handleSearch} disabled={loading}>
|
|
{loading ? '검색 중...' : '검색'}
|
|
</button>
|
|
<button onClick={onClose}>닫기</button>
|
|
</div>
|
|
|
|
{error && <p style={{ color: 'red' }}>{error}</p>}
|
|
|
|
{result && (
|
|
<div style={{ marginTop: '10px' }}>
|
|
<p>이메일: {result.email}</p>
|
|
<p>공개 여부: {result.is_public ? '공개' : '비공개'}</p>
|
|
|
|
{result.is_friend ? (
|
|
<p>✅ 이미 친구입니다</p>
|
|
) : result.request_sent ? (
|
|
<p>⏳ 이미 요청 보낸 상태입니다</p>
|
|
) : result.request_received ? (
|
|
<p>📩 상대가 요청을 보냈습니다 (요청 수락 화면에서 처리)</p>
|
|
) : (
|
|
<button onClick={handleRequest}>친구 요청 보내기</button>
|
|
)}
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
<style>{`
|
|
.popup-backdrop {
|
|
position: fixed;
|
|
top: 0; left: 0;
|
|
width: 100vw;
|
|
height: 100vh;
|
|
background: rgba(0, 0, 0, 0.7);
|
|
z-index: 1000;
|
|
}
|
|
.popup {
|
|
position: fixed;
|
|
top: 50%; left: 50%;
|
|
transform: translate(-50%, -50%);
|
|
background: #222;
|
|
color: white;
|
|
padding: 20px;
|
|
border-radius: 8px;
|
|
box-shadow: 0 0 10px #000;
|
|
z-index: 1001;
|
|
min-width: 280px;
|
|
}
|
|
.popup input {
|
|
display: block;
|
|
margin-top: 8px;
|
|
width: 100%;
|
|
padding: 5px;
|
|
}
|
|
.popup button {
|
|
margin-right: 8px;
|
|
margin-top: 10px;
|
|
}
|
|
|
|
.radio-group {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 6px;
|
|
margin: 10px 0;
|
|
}
|
|
|
|
.radio-option {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
font-size: 14px;
|
|
color: white;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.radio-option input[type="radio"] {
|
|
margin-right: 6px;
|
|
appearance: none;
|
|
width: 16px;
|
|
height: 16px;
|
|
border: 2px solid #aaa;
|
|
border-radius: 50%;
|
|
display: inline-block;
|
|
position: relative;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.radio-option input[type="radio"]:checked::before {
|
|
content: "";
|
|
display: block;
|
|
width: 8px;
|
|
height: 8px;
|
|
background-color: #00aaff;
|
|
border-radius: 50%;
|
|
position: absolute;
|
|
top: 3px;
|
|
left: 3px;
|
|
}
|
|
|
|
|
|
`}</style>
|
|
</>
|
|
)
|
|
}
|