Files
hushroom/src/features/boarding/ui/BoardingMissionForm.tsx

87 lines
2.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client';
import { FormEvent, useState } from 'react';
import { useI18n } from '@/features/i18n/model/useI18n';
const OPTIONAL_PREFIX_PATTERN = /^(?:선택|optional|任意|facultatif)\s*[:]\s*/i;
const EXAMPLE_PREFIX_PATTERN =
/^(?:예|例|e\.?\s?g\.?|eg\.?|example|exemple|beispiel|p\.?\s?ex\.?|z\.?\s?b\.?)\s*[:)\.]\s*/i;
const buildMissionPlaceholder = (raw: string, optionalLabel: string) => {
const sanitized = raw
.trim()
.replace(OPTIONAL_PREFIX_PATTERN, '')
.replace(EXAMPLE_PREFIX_PATTERN, '')
.trim();
if (!sanitized) return '';
const normalizedOptionalLabel = optionalLabel.trim();
if (!normalizedOptionalLabel) return sanitized;
return `${sanitized} (${normalizedOptionalLabel})`;
};
export function BoardingMissionForm({
onDock,
onCancel,
autoFocus = false,
compact = false,
}: {
onDock: (mission: string) => void;
onCancel?: () => void;
autoFocus?: boolean;
compact?: boolean;
}) {
const { t } = useI18n();
const [mission, setMission] = useState('');
const trimmedMission = mission.trim();
const missionPlaceholder = buildMissionPlaceholder(
t('boarding.missionPlaceholder'),
t('boarding.optionalLabel'),
);
const handleSubmit = (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();
onDock(trimmedMission);
};
return (
<form
onSubmit={handleSubmit}
className={`flex flex-col ${compact ? 'gap-6' : 'space-y-8 flex-1'}`}
>
<div className="space-y-3">
<label className="block text-sm font-medium text-slate-300">
{t('boarding.missionLabel')}
</label>
<input
type="text"
value={mission}
onChange={(event) => setMission(event.target.value)}
placeholder={missionPlaceholder}
className="w-full border-b-2 border-slate-700 bg-slate-900/50 px-0 py-3 text-lg outline-none transition-colors placeholder:text-slate-600 focus:border-indigo-500"
autoFocus={autoFocus}
/>
</div>
<div className={`flex ${compact ? 'justify-end gap-3' : 'mt-8 flex-col gap-3'} w-full`}>
{onCancel && (
<button
type="button"
onClick={onCancel}
className="rounded-xl border border-slate-700 bg-transparent px-4 py-2 font-semibold text-slate-300 transition-colors hover:bg-slate-900/60 hover:text-white"
>
{t('boarding.cancel')}
</button>
)}
<button
type="submit"
className={`rounded-xl bg-indigo-600 font-bold text-white transition-all shadow-lg shadow-indigo-900/30 hover:bg-indigo-500 ${compact ? 'px-6 py-2' : 'w-full py-4 text-lg'}`}
>
{t('boarding.submit')}
</button>
</div>
</form>
);
}