172 lines
6.5 KiB
TypeScript
172 lines
6.5 KiB
TypeScript
import React, { useState, useEffect } from 'react';
|
|
import { createPortal } from 'react-dom';
|
|
import { useTranslation } from 'react-i18next';
|
|
import CitySelectModal, { REGIONS } from './CitySelectModal';
|
|
import { useOverlayClose } from '../hooks/useOverlayClose';
|
|
|
|
interface BusinessNameInputModalProps {
|
|
onClose: () => void;
|
|
onSubmit: (businessName: string, address: string, category: string, officialSiteUrl: string) => void;
|
|
}
|
|
|
|
const BusinessNameInputModal: React.FC<BusinessNameInputModalProps> = ({ onClose, onSubmit }) => {
|
|
const { t } = useTranslation();
|
|
const [businessName, setBusinessName] = useState('');
|
|
const [selectedCity, setSelectedCity] = useState('');
|
|
const [detailAddress, setDetailAddress] = useState('');
|
|
const [category, setCategory] = useState('');
|
|
const [officialSiteUrl, setOfficialSiteUrl] = useState('');
|
|
const [isCityModalOpen, setIsCityModalOpen] = useState(false);
|
|
const overlayCloseHandlers = useOverlayClose(onClose);
|
|
|
|
useEffect(() => {
|
|
document.body.style.overflow = 'hidden';
|
|
|
|
const handleKeyDown = (e: KeyboardEvent) => {
|
|
if (e.key === 'Escape') onClose();
|
|
};
|
|
document.addEventListener('keydown', handleKeyDown);
|
|
|
|
return () => {
|
|
document.body.style.overflow = '';
|
|
document.removeEventListener('keydown', handleKeyDown);
|
|
};
|
|
}, [onClose]);
|
|
|
|
const handleCitySelect = (city: string) => {
|
|
const region = REGIONS.find(r => r.cities.includes(city));
|
|
// 특별시/광역시는 도 이름 없이 도시명만 사용
|
|
const prefix = region && region.label !== '특별시 / 광역시' ? `${region.label} ` : '';
|
|
setSelectedCity(`${prefix}${city}`);
|
|
};
|
|
|
|
const isValid = businessName.trim().length > 0 && selectedCity.length > 0 && detailAddress.trim().length > 0;
|
|
|
|
const handleSubmit = () => {
|
|
if (!isValid) return;
|
|
const fullAddress = `${selectedCity} ${detailAddress.trim()}`;
|
|
// 프로토콜 없이 입력하면 https:// 를 붙여서 전달
|
|
const trimmedUrl = officialSiteUrl.trim();
|
|
const normalizedUrl = trimmedUrl && !/^https?:\/\//i.test(trimmedUrl)
|
|
? `https://${trimmedUrl}`
|
|
: trimmedUrl;
|
|
onSubmit(businessName.trim(), fullAddress, category.trim(), normalizedUrl);
|
|
onClose();
|
|
};
|
|
|
|
const handleKeyDown = (e: React.KeyboardEvent) => {
|
|
if (e.key === 'Enter' && isValid) handleSubmit();
|
|
};
|
|
|
|
// CitySelectModal의 selected prop용 — 도시명만 추출
|
|
const cityOnly = selectedCity.split(' ').pop() ?? '';
|
|
|
|
return createPortal(
|
|
<>
|
|
<div className="manual-modal-backdrop" {...overlayCloseHandlers}>
|
|
<div className="manual-modal" onClick={e => e.stopPropagation()}>
|
|
<div className="manual-modal-header">
|
|
<span className="manual-modal-title">{t('landing.hero.manualModalTitle')}</span>
|
|
<button className="manual-modal-close" onClick={onClose}>✕</button>
|
|
</div>
|
|
<p className="manual-modal-subtitle">{t('landing.hero.manualModalSubtitle')}</p>
|
|
|
|
<div className="manual-modal-body">
|
|
<div className="manual-modal-field">
|
|
<label className="manual-modal-label">{t('landing.hero.manualLabelName')}</label>
|
|
<input
|
|
type="text"
|
|
className="manual-modal-input"
|
|
placeholder={t('landing.hero.manualPlaceholderName')}
|
|
value={businessName}
|
|
onChange={e => setBusinessName(e.target.value)}
|
|
onKeyDown={handleKeyDown}
|
|
maxLength={50}
|
|
autoFocus
|
|
/>
|
|
</div>
|
|
|
|
<div className="manual-modal-field">
|
|
<label className="manual-modal-label">{t('landing.hero.manualLabelRegion')}</label>
|
|
<button
|
|
type="button"
|
|
className={`manual-modal-city-btn ${selectedCity ? 'selected' : ''}`}
|
|
onClick={() => setIsCityModalOpen(true)}
|
|
>
|
|
<span>{selectedCity || t('landing.hero.manualPlaceholderRegion')}</span>
|
|
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
|
<path d="M6 9l6 6 6-6" />
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
|
|
<div className="manual-modal-field">
|
|
<label className="manual-modal-label">{t('landing.hero.manualLabelDetail')}</label>
|
|
<input
|
|
type="text"
|
|
className="manual-modal-input"
|
|
placeholder={t('landing.hero.manualPlaceholderDetail')}
|
|
value={detailAddress}
|
|
onChange={e => setDetailAddress(e.target.value)}
|
|
onKeyDown={handleKeyDown}
|
|
maxLength={100}
|
|
/>
|
|
</div>
|
|
|
|
<div className="manual-modal-field">
|
|
<label className="manual-modal-label">{t('landing.hero.manualLabelCategory')}</label>
|
|
<input
|
|
type="text"
|
|
className="manual-modal-input"
|
|
placeholder={t('landing.hero.manualPlaceholderCategory')}
|
|
value={category}
|
|
onChange={e => setCategory(e.target.value)}
|
|
onKeyDown={handleKeyDown}
|
|
maxLength={30}
|
|
/>
|
|
</div>
|
|
|
|
<div className="manual-modal-field">
|
|
<label className="manual-modal-label">{t('landing.hero.manualLabelSiteUrl')}</label>
|
|
<input
|
|
type="url"
|
|
className="manual-modal-input"
|
|
placeholder={t('landing.hero.manualPlaceholderSiteUrl')}
|
|
value={officialSiteUrl}
|
|
onChange={e => setOfficialSiteUrl(e.target.value)}
|
|
onKeyDown={handleKeyDown}
|
|
maxLength={2048}
|
|
/>
|
|
</div>
|
|
|
|
<div className="manual-modal-actions">
|
|
<button type="button" className="manual-modal-cancel" onClick={onClose}>
|
|
{t('common.cancel')}
|
|
</button>
|
|
<button
|
|
type="button"
|
|
className="manual-modal-submit"
|
|
onClick={handleSubmit}
|
|
disabled={!isValid}
|
|
>
|
|
{t('landing.hero.manualAnalyzeButton')}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{isCityModalOpen && (
|
|
<CitySelectModal
|
|
selected={cityOnly}
|
|
onSelect={(city) => { handleCitySelect(city); setIsCityModalOpen(false); }}
|
|
onClose={() => setIsCityModalOpen(false)}
|
|
/>
|
|
)}
|
|
</>,
|
|
document.body
|
|
);
|
|
};
|
|
|
|
export default BusinessNameInputModal;
|