136 lines
6.6 KiB
TypeScript
136 lines
6.6 KiB
TypeScript
|
|
import React from 'react';
|
|
import type { InputData } from '../types';
|
|
import { LANGUAGE_OPTIONS, CHANNEL_OPTIONS, translations } from '../constants';
|
|
import { LoadingSpinner, SparklesIcon } from './Icons';
|
|
|
|
interface InputFormProps {
|
|
inputData: InputData;
|
|
setInputData: React.Dispatch<React.SetStateAction<InputData>>;
|
|
onGenerate: () => void;
|
|
isLoading: boolean;
|
|
t: typeof translations.de;
|
|
}
|
|
|
|
export const InputForm: React.FC<InputFormProps> = ({ inputData, setInputData, onGenerate, isLoading, t }) => {
|
|
|
|
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>) => {
|
|
const { name, value } = e.target;
|
|
setInputData(prev => ({ ...prev, [name]: value }));
|
|
};
|
|
|
|
const handleChannelChange = (channel: string) => {
|
|
setInputData(prev => {
|
|
const newChannels = prev.channels.includes(channel)
|
|
? prev.channels.filter(c => c !== channel)
|
|
: [...prev.channels, channel];
|
|
return { ...prev, channels: newChannels };
|
|
});
|
|
};
|
|
|
|
return (
|
|
<form onSubmit={(e) => { e.preventDefault(); onGenerate(); }} className="space-y-6">
|
|
<div>
|
|
<label htmlFor="companyUrl" className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">
|
|
{t.companyUrlLabel}
|
|
</label>
|
|
<input
|
|
type="url"
|
|
name="companyUrl"
|
|
id="companyUrl"
|
|
value={inputData.companyUrl}
|
|
onChange={handleInputChange}
|
|
className="block w-full px-4 py-2 bg-white dark:bg-slate-900 border border-slate-300 dark:border-slate-600 rounded-md shadow-sm placeholder-slate-400 focus:outline-none focus:ring-2 focus:ring-sky-500 focus:border-sky-500"
|
|
placeholder={t.companyUrlPlaceholder}
|
|
required
|
|
/>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<div>
|
|
<label htmlFor="language" className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">
|
|
{t.targetLanguageLabel}
|
|
</label>
|
|
<select
|
|
id="language"
|
|
name="language"
|
|
value={inputData.language}
|
|
onChange={handleInputChange}
|
|
className="block w-full pl-3 pr-10 py-2 bg-white dark:bg-slate-900 border border-slate-300 dark:border-slate-600 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-sky-500 focus:border-sky-500"
|
|
>
|
|
{LANGUAGE_OPTIONS.map(option => (
|
|
<option key={option.value} value={option.value}>{option.label}</option>
|
|
))}
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label htmlFor="focus" className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">
|
|
{t.productFocusLabel} <span className="text-slate-400">{t.productFocusOptional}</span>
|
|
</label>
|
|
<input
|
|
type="text"
|
|
name="focus"
|
|
id="focus"
|
|
value={inputData.focus}
|
|
onChange={handleInputChange}
|
|
className="block w-full px-4 py-2 bg-white dark:bg-slate-900 border border-slate-300 dark:border-slate-600 rounded-md shadow-sm placeholder-slate-400 focus:outline-none focus:ring-2 focus:ring-sky-500 focus:border-sky-500"
|
|
placeholder={t.productFocusPlaceholder}
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<label htmlFor="regions" className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-1">
|
|
{t.regionsLabel} <span className="text-slate-400">{t.regionsOptional}</span>
|
|
</label>
|
|
<input
|
|
type="text"
|
|
name="regions"
|
|
id="regions"
|
|
value={inputData.regions}
|
|
onChange={handleInputChange}
|
|
className="block w-full px-4 py-2 bg-white dark:bg-slate-900 border border-slate-300 dark:border-slate-600 rounded-md shadow-sm placeholder-slate-400 focus:outline-none focus:ring-2 focus:ring-sky-500 focus:border-sky-500"
|
|
placeholder={t.regionsPlaceholder}
|
|
/>
|
|
</div>
|
|
<div>
|
|
<label className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">
|
|
{t.channelsLabel} <span className="text-slate-400">{t.channelsOptional}</span>
|
|
</label>
|
|
<div className="flex flex-wrap gap-4">
|
|
{CHANNEL_OPTIONS.map(channel => (
|
|
<label key={channel} className="flex items-center space-x-2 cursor-pointer">
|
|
<input
|
|
type="checkbox"
|
|
checked={inputData.channels.includes(channel)}
|
|
onChange={() => handleChannelChange(channel)}
|
|
className="h-4 w-4 rounded border-slate-300 dark:border-slate-600 text-sky-600 focus:ring-sky-500 bg-slate-100 dark:bg-slate-700"
|
|
/>
|
|
<span className="text-sm text-slate-600 dark:text-slate-300">{channel}</span>
|
|
</label>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
<div className="pt-2">
|
|
<button
|
|
type="submit"
|
|
disabled={isLoading}
|
|
className="w-full flex items-center justify-center px-6 py-3 border border-transparent text-base font-medium rounded-md shadow-sm text-white bg-sky-600 hover:bg-sky-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-sky-500 disabled:bg-slate-400 dark:disabled:bg-slate-600 disabled:cursor-not-allowed transition-colors duration-200"
|
|
>
|
|
{isLoading ? (
|
|
<>
|
|
<LoadingSpinner className="mr-3" />
|
|
{t.analyzingButton}
|
|
</>
|
|
) : (
|
|
<>
|
|
<SparklesIcon className="mr-2 h-5 w-5" />
|
|
{t.generateButton}
|
|
</>
|
|
)}
|
|
</button>
|
|
</div>
|
|
</form>
|
|
);
|
|
};
|