fix: smart next-free room number suggestion
- Placeholder shows next free after global max (e.g. 204 if 203 is max) - Error message suggests next free starting from typed+1: type 101 (taken) → suggests 102 type 201 (taken) → suggests 202 type 1011 (taken) → suggests 1012 - Suggestion is a clickable link that auto-fills the field Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -127,21 +127,31 @@ export function RoomModal({ open, room, existingNumbers = [], categories = [], o
|
|||||||
setPhotoIdx(p => Math.max(0, p - 1))
|
setPhotoIdx(p => Math.max(0, p - 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find next available room number (skips existing ones)
|
const numberTaken = !isEdit && !!form.number && existingNumbers.includes(form.number)
|
||||||
const nextFreeNumber = (() => {
|
|
||||||
if (isEdit) return null
|
// Find next available room number starting from a given base
|
||||||
|
const findNextFree = (base: number): string => {
|
||||||
const taken = new Set(existingNumbers)
|
const taken = new Set(existingNumbers)
|
||||||
// Try incrementing from the highest existing number
|
let candidate = base
|
||||||
const nums = existingNumbers
|
|
||||||
.map(n => parseInt(n))
|
|
||||||
.filter(n => !isNaN(n))
|
|
||||||
.sort((a, b) => a - b)
|
|
||||||
let candidate = (nums[nums.length - 1] ?? 100) + 1
|
|
||||||
while (taken.has(String(candidate))) candidate++
|
while (taken.has(String(candidate))) candidate++
|
||||||
return String(candidate)
|
return String(candidate)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Placeholder for empty field: next free after current max
|
||||||
|
const placeholderNumber = (() => {
|
||||||
|
if (isEdit) return null
|
||||||
|
const nums = existingNumbers.map(n => parseInt(n)).filter(n => !isNaN(n))
|
||||||
|
const max = nums.length > 0 ? Math.max(...nums) : 100
|
||||||
|
return findNextFree(max + 1)
|
||||||
})()
|
})()
|
||||||
|
|
||||||
const numberTaken = !isEdit && !!form.number && existingNumbers.includes(form.number)
|
// Suggestion when typed number is taken: increment from typed+1
|
||||||
|
const nextFreeNumber = (() => {
|
||||||
|
if (!numberTaken) return null
|
||||||
|
const typedNum = parseInt(form.number)
|
||||||
|
if (isNaN(typedNum)) return null
|
||||||
|
return findNextFree(typedNum + 1)
|
||||||
|
})()
|
||||||
|
|
||||||
const handleSave = () => {
|
const handleSave = () => {
|
||||||
if (!form.number || numberTaken) return
|
if (!form.number || numberTaken) return
|
||||||
@@ -233,12 +243,15 @@ export function RoomModal({ open, room, existingNumbers = [], categories = [], o
|
|||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
className={cn('input', numberTaken && 'border-red-400 focus:ring-red-400')}
|
className={cn('input', numberTaken && 'border-red-400 focus:ring-red-400')}
|
||||||
placeholder={nextFreeNumber ?? '101'}
|
placeholder={placeholderNumber ?? '101'}
|
||||||
value={form.number}
|
value={form.number}
|
||||||
onChange={e => set('number', e.target.value)}
|
onChange={e => set('number', e.target.value)}
|
||||||
/>
|
/>
|
||||||
{numberTaken && (
|
{numberTaken && (
|
||||||
<p className="text-xs text-red-500 mt-1">Номер {form.number} уже существует{nextFreeNumber ? `. Следующий свободный: ${nextFreeNumber}` : ''}</p>
|
<p className="text-xs text-red-500 mt-1">
|
||||||
|
Номер {form.number} уже занят
|
||||||
|
{nextFreeNumber ? <> — следующий свободный: <button type="button" className="underline font-medium" onClick={() => set('number', nextFreeNumber)}>{nextFreeNumber}</button></> : ''}
|
||||||
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
Reference in New Issue
Block a user