o2o-infinith-frontend/src/features/clinics/components/tabs/SettingsTab.tsx

151 lines
5.7 KiB
TypeScript

/**
* SettingsTab — 워크스페이스 설정 탭.
* ReportBody 의 SectionWrapper 스타일을 그대로 따름.
* 분석 대상 URL/소셜 핸들 편집 + 병원 기본 정보 확인.
*/
import { useState } from 'react';
import { Save, AlertCircle, Info } from 'lucide-react';
import { Input } from '@/shared/ui/input';
import { Button } from '@/shared/ui/button';
import { SectionWrapper } from '@/features/report/components/ui/SectionWrapper';
import { PLATFORM_META } from '../PlatformChips';
import type { PlatformKey, WorkspaceClinicProfile } from '../../types/workspace';
const EDITABLE_PLATFORMS: PlatformKey[] = [
'website',
'youtube',
'instagram',
'facebook',
'naverPlace',
'naverBlog',
'gangnamUnni',
'tiktok',
];
const PLATFORM_PLACEHOLDER: Record<PlatformKey, string> = {
website: 'your-clinic.co.kr',
instagram: 'instagram.com/your_clinic',
youtube: 'youtube.com/@your_channel',
facebook: 'facebook.com/your.page',
tiktok: '@your_clinic',
gangnamUnni: 'gangnamunni.com/hospitals/000',
naverPlace: 'place.naver.com/hospital/0000000',
naverBlog: 'blog.naver.com/your_blog',
};
interface SettingsTabProps {
clinic: WorkspaceClinicProfile;
}
export function SettingsTab({ clinic }: SettingsTabProps) {
const [values, setValues] = useState<Record<PlatformKey, string>>(() => {
const initial: Record<PlatformKey, string> = {
website: '',
instagram: '',
youtube: '',
facebook: '',
tiktok: '',
};
clinic.defaultTargets.forEach((t) => {
initial[t.platform] = t.handle;
});
return initial;
});
const [saved, setSaved] = useState(false);
const handleChange = (platform: PlatformKey, value: string) => {
setValues((prev) => ({ ...prev, [platform]: value }));
setSaved(false);
};
const handleSave = () => {
// TODO: API 연동 — PATCH /api/clinics/:id
setSaved(true);
};
return (
<SectionWrapper
id="settings"
title="분석 대상 설정"
subtitle="이 병원의 채널 정보를 등록해두면 새 분석 실행 시 자동으로 불러옵니다."
>
<div className="space-y-6">
{/* Platform handles */}
<div className="rounded-2xl border border-slate-100 bg-white p-6 shadow-[3px_4px_12px_rgba(0,0,0,0.06)]">
<div className="mb-5">
<h3 className="font-serif text-lg font-bold text-primary-900"> URL · </h3>
<p className="text-xs text-slate-400 mt-1">
. .
</p>
</div>
<div className="space-y-3">
{EDITABLE_PLATFORMS.map((platform) => {
const meta = PLATFORM_META[platform];
const Icon = meta.Icon;
return (
<div key={platform}>
<div className="flex items-center gap-3">
<label
htmlFor={`platform-${platform}`}
className="flex items-center gap-2 w-32 flex-shrink-0"
>
<span
className="flex items-center justify-center rounded-full w-7 h-7"
style={{ backgroundColor: `${meta.color}14` }}
>
<Icon size={14} style={{ color: meta.color }} />
</span>
<span className="text-xs font-medium text-primary-900">{meta.label}</span>
</label>
<Input
id={`platform-${platform}`}
value={values[platform]}
onChange={(e) => handleChange(platform, e.target.value)}
placeholder={PLATFORM_PLACEHOLDER[platform]}
className="flex-1 h-10 text-sm bg-slate-50 border border-slate-200 rounded-xl focus:bg-white focus:border-[#9B8AD4] focus:ring-2 focus:ring-[#9B8AD4]/20"
/>
</div>
{platform === 'website' && (
<p className="ml-[140px] mt-1.5 flex items-start gap-1.5 text-[11px] text-slate-500 leading-relaxed">
<Info size={11} className="mt-0.5 shrink-0 text-brand-purple-vivid" />
(··· ) .
</p>
)}
</div>
);
})}
</div>
<div className="mt-6 flex items-center justify-between border-t border-slate-100 pt-4">
<p
className={`inline-flex items-center gap-1.5 text-xs ${
saved ? 'text-emerald-600' : 'text-slate-400'
}`}
>
{saved ? (
<>
<span className="w-1.5 h-1.5 rounded-full bg-emerald-500" aria-hidden />
(API )
</>
) : (
<>
<AlertCircle size={12} className="text-slate-300" />
.
</>
)}
</p>
<Button
type="button"
onClick={handleSave}
className="inline-flex items-center gap-1.5 px-5 py-2.5 rounded-full text-xs font-semibold text-white bg-gradient-to-r from-[#4F1DA1] to-[#021341] shadow-sm hover:opacity-90 transition-all"
>
<Save size={13} />
</Button>
</div>
</div>
</div>
</SectionWrapper>
);
}