fix: standardize admin form inputs, validation, and sync with backend constraints

- Unified all inputs to use .input CSS class, consistent label styles, and btn-primary/btn-secondary buttons
- Fixed number inputs to use number | '' pattern allowing field clearing without default replacement
- Added field-level validation with inline error borders and messages
- Synced frontend constraints with backend Pydantic schemas (maxLength, min/max values)
- Fixed toggle switch dimensions across all admin forms
This commit is contained in:
c0mrade
2026-02-06 19:37:07 +03:00
parent 88d9377adb
commit 6e7eb36f76
13 changed files with 364 additions and 227 deletions

View File

@@ -230,7 +230,10 @@ export default function AdminCampaignEdit() {
updateMutation.mutate(data);
};
const isValid = name.trim() && startParameter.trim() && /^[a-zA-Z0-9_-]+$/.test(startParameter);
const isNameValid = name.trim().length > 0;
const isStartParamValid =
startParameter.trim().length > 0 && /^[a-zA-Z0-9_-]+$/.test(startParameter);
const isValid = isNameValid && isStartParamValid;
if (isLoading) {
return (
@@ -286,27 +289,36 @@ export default function AdminCampaignEdit() {
<div>
<label className="mb-2 block text-sm font-medium text-dark-300">
{t('admin.campaigns.form.name')}
<span className="text-error-400">*</span>
</label>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
className="input"
className={`input ${name.length > 0 && !isNameValid ? 'border-error-500/50' : ''}`}
placeholder={t('admin.campaigns.form.namePlaceholder')}
maxLength={255}
/>
{name.length > 0 && !isNameValid && (
<p className="mt-1 text-xs text-error-400">
{t('admin.campaigns.validation.nameRequired')}
</p>
)}
</div>
{/* Start Parameter */}
<div>
<label className="mb-2 block text-sm font-medium text-dark-300">
{t('admin.campaigns.form.startParameter')}
<span className="text-error-400">*</span>
</label>
<input
type="text"
value={startParameter}
onChange={(e) => setStartParameter(e.target.value.replace(/[^a-zA-Z0-9_-]/g, ''))}
className="input font-mono"
className={`input font-mono ${startParameter.length > 0 && !isStartParamValid ? 'border-error-500/50' : ''}`}
placeholder="instagram_jan2024"
maxLength={100}
/>
<p className="mt-1 text-xs text-dark-500">
{t('admin.campaigns.form.startParameterHint')}
@@ -390,7 +402,7 @@ export default function AdminCampaignEdit() {
<div className="grid grid-cols-3 gap-4">
<div>
<label className="mb-2 block text-sm text-dark-400">
<label className="mb-2 block text-sm font-medium text-dark-300">
{t('admin.campaigns.form.days')}
</label>
<input
@@ -402,7 +414,7 @@ export default function AdminCampaignEdit() {
/>
</div>
<div>
<label className="mb-2 block text-sm text-dark-400">
<label className="mb-2 block text-sm font-medium text-dark-300">
{t('admin.campaigns.form.trafficGb')}
</label>
<input
@@ -414,7 +426,7 @@ export default function AdminCampaignEdit() {
/>
</div>
<div>
<label className="mb-2 block text-sm text-dark-400">
<label className="mb-2 block text-sm font-medium text-dark-300">
{t('admin.campaigns.form.devices')}
</label>
<input