2026-01-08 23:53:05 +01:00

133 lines
4.3 KiB
TypeScript

import React from 'react'
import { t } from '@/lib/i18n'
import type { ReviewFormController } from './useReviewFormController'
export function ReviewFormView(params: { ctrl: ReviewFormController; onCancel?: () => void }): React.ReactElement {
return (
<form
onSubmit={(e) => void params.ctrl.handleSubmit(e)}
className="border border-neon-cyan/30 rounded-lg p-4 bg-cyber-dark space-y-4"
>
<h3 className="text-lg font-semibold text-neon-cyan">{t('review.form.title')}</h3>
<TextInput
id="review-title"
label={t('review.form.title.label')}
value={params.ctrl.title}
onChange={params.ctrl.setTitle}
placeholder={t('review.form.title.placeholder')}
optionalLabel={`(${t('common.optional')})`}
/>
<TextAreaInput
id="review-content"
label={t('review.form.content.label')}
value={params.ctrl.content}
onChange={params.ctrl.setContent}
placeholder={t('review.form.content.placeholder')}
rows={6}
required
requiredMark
/>
<TextAreaInput
id="review-text"
label={t('review.form.text.label')}
value={params.ctrl.text}
onChange={params.ctrl.setText}
placeholder={t('review.form.text.placeholder')}
rows={3}
helpText={t('review.form.text.help')}
optionalLabel={`(${t('common.optional')})`}
/>
{params.ctrl.error ? <ErrorBox message={params.ctrl.error} /> : null}
<div className="flex gap-2">
<button
type="submit"
disabled={params.ctrl.loading}
className="px-4 py-2 bg-neon-green/20 hover:bg-neon-green/30 text-neon-green rounded-lg font-medium transition-all border border-neon-green/50 hover:shadow-glow-green disabled:opacity-50"
>
{params.ctrl.loading ? t('common.loading') : t('review.form.submit')}
</button>
{params.onCancel ? (
<button
type="button"
onClick={params.onCancel}
className="px-4 py-2 bg-cyber-darker hover:bg-cyber-dark text-cyber-accent rounded-lg font-medium transition-all border border-neon-cyan/30"
>
{t('common.cancel')}
</button>
) : null}
</div>
</form>
)
}
function ErrorBox({ message }: { message: string }): React.ReactElement {
return (
<div className="p-3 bg-red-900/20 border border-red-500/50 rounded text-red-400 text-sm">
{message}
</div>
)
}
function TextInput(params: {
id: string
label: string
value: string
onChange: (value: string) => void
placeholder: string
optionalLabel?: string
}): React.ReactElement {
return (
<div>
<label htmlFor={params.id} className="block text-sm font-medium text-cyber-accent mb-1">
{params.label} {params.optionalLabel ? <span className="text-cyber-accent/50">{params.optionalLabel}</span> : null}
</label>
<input
id={params.id}
type="text"
value={params.value}
onChange={(e) => params.onChange(e.target.value)}
placeholder={params.placeholder}
className="w-full px-3 py-2 bg-cyber-darker border border-neon-cyan/30 rounded text-cyber-accent focus:border-neon-cyan focus:outline-none"
/>
</div>
)
}
function TextAreaInput(params: {
id: string
label: string
value: string
onChange: (value: string) => void
placeholder: string
rows: number
required?: boolean
requiredMark?: boolean
optionalLabel?: string
helpText?: string
}): React.ReactElement {
return (
<div>
<label htmlFor={params.id} className="block text-sm font-medium text-cyber-accent mb-1">
{params.label}{' '}
{params.requiredMark ? <span className="text-red-400">*</span> : null}{' '}
{params.optionalLabel ? <span className="text-cyber-accent/50">{params.optionalLabel}</span> : null}
</label>
<textarea
id={params.id}
value={params.value}
onChange={(e) => params.onChange(e.target.value)}
placeholder={params.placeholder}
rows={params.rows}
required={params.required}
className="w-full px-3 py-2 bg-cyber-darker border border-neon-cyan/30 rounded text-cyber-accent focus:border-neon-cyan focus:outline-none"
/>
{params.helpText ? <p className="text-xs text-cyber-accent/70 mt-1">{params.helpText}</p> : null}
</div>
)
}