o2o-castad-frontend/src/components/BusinessNameInputModal.tsx

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;