Skip to content

Commit 97bd664

Browse files
committed
Cant flex to 4, and forcing user to choose flex number of current key when flexing null keys
1 parent 5829be8 commit 97bd664

File tree

1 file changed

+141
-48
lines changed

1 file changed

+141
-48
lines changed

apps/keys-portal/src/components/loan/dialogs/FlexMenu.tsx

Lines changed: 141 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@ import {
88
DialogHeader,
99
DialogTitle,
1010
} from '@/components/ui/dialog'
11+
import {
12+
Select,
13+
SelectContent,
14+
SelectItem,
15+
SelectTrigger,
16+
SelectValue,
17+
} from '@/components/ui/select'
1118
import { Plus, Minus } from 'lucide-react'
1219
import { Spinner } from '@/components/ui/spinner'
1320
import type { Key, KeyType } from '@/services/types'
@@ -23,6 +30,8 @@ type KeyGroup = {
2330
sampleKey: Key
2431
currentFlexNumber: number
2532
hasFlexConflict: boolean
33+
hasNullFlex: boolean
34+
isAtMaxFlex: boolean
2635
}
2736

2837
type Props = {
@@ -46,6 +55,11 @@ export function FlexMenu({
4655
// Group keys by name and type, with a default count of 3
4756
const [keyGroups, setKeyGroups] = useState<Map<string, KeyGroup>>(new Map())
4857

58+
// Track user-specified flex for groups with null flex
59+
const [flexOverrides, setFlexOverrides] = useState<Map<string, number>>(
60+
new Map()
61+
)
62+
4963
// Initialize key groups when selectedKeys changes
5064
useMemo(() => {
5165
const groups = new Map<string, KeyGroup>()
@@ -66,22 +80,27 @@ export function FlexMenu({
6680

6781
const uniqueFlexNumbers = new Set(flexNumbers)
6882
const hasFlexConflict = uniqueFlexNumbers.size > 1
83+
const hasNullFlex = flexNumbers.length === 0
6984

7085
// Use the first flex number found, or 0 if none
7186
const currentFlexNumber = flexNumbers.length > 0 ? flexNumbers[0] : 0
87+
const isAtMaxFlex = currentFlexNumber === 3
7288

7389
groups.set(groupKey, {
7490
keyName: key.keyName,
7591
keyType: key.keyType,
76-
count: 3,
92+
count: isAtMaxFlex ? 0 : 3,
7793
sampleKey: key,
7894
currentFlexNumber,
7995
hasFlexConflict,
96+
hasNullFlex,
97+
isAtMaxFlex,
8098
})
8199
}
82100
})
83101

84102
setKeyGroups(groups)
103+
setFlexOverrides(new Map())
85104
}, [selectedKeys])
86105

87106
const incrementCount = (groupKey: string) => {
@@ -106,29 +125,42 @@ export function FlexMenu({
106125
})
107126
}
108127

128+
const handleFlexOverride = (groupKey: string, value: string) => {
129+
const flexNumber = parseInt(value, 10)
130+
setFlexOverrides((prev) => {
131+
const newOverrides = new Map(prev)
132+
newOverrides.set(groupKey, flexNumber)
133+
return newOverrides
134+
})
135+
}
136+
137+
const getEffectiveFlexNumber = (group: KeyGroup, groupKey: string) => {
138+
if (group.hasNullFlex) {
139+
return flexOverrides.get(groupKey) ?? null
140+
}
141+
return group.currentFlexNumber
142+
}
143+
109144
const handleCreate = async () => {
110145
setIsCreating(true)
111146
try {
112147
const createdKeys: Key[] = []
113148

114-
// Calculate total keys to create across all groups
115-
let totalKeysToCreate = 0
116-
for (const group of keyGroups.values()) {
117-
totalKeysToCreate += group.count
118-
}
149+
// Create keys for each group (skip max-flex groups)
150+
for (const [groupKey, group] of keyGroups.entries()) {
151+
if (group.isAtMaxFlex || group.count === 0) continue
152+
153+
const effectiveFlex = getEffectiveFlexNumber(group, groupKey)
154+
if (effectiveFlex === null) continue
119155

120-
// Create keys for each group
121-
for (const group of keyGroups.values()) {
122-
// Calculate the new flex number (current + 1)
123-
const currentFlexNumber = group.currentFlexNumber ?? 0
124-
const newFlexNumber = currentFlexNumber + 1
156+
const newFlexNumber = effectiveFlex + 1
125157

126158
// Create 'count' number of keys with sequence numbers 1, 2, 3, etc.
127159
for (let i = 1; i <= group.count; i++) {
128160
const newKey = await keyService.createKey({
129161
keyName: group.keyName,
130162
keyType: group.keyType,
131-
keySequenceNumber: i, // Sequence number: 1, 2, 3, etc.
163+
keySequenceNumber: i,
132164
flexNumber: newFlexNumber,
133165
rentalObjectCode: group.sampleKey.rentalObjectCode,
134166
keySystemId: group.sampleKey.keySystemId,
@@ -165,11 +197,18 @@ export function FlexMenu({
165197
}
166198
}
167199

168-
const totalKeysToCreate = Array.from(keyGroups.values()).reduce(
169-
(sum, group) => sum + group.count,
200+
// Only count groups that can actually create keys
201+
const totalKeysToCreate = Array.from(keyGroups.entries()).reduce(
202+
(sum, [, group]) => (group.isAtMaxFlex ? sum : sum + group.count),
170203
0
171204
)
172205

206+
// Check if any null-flex group is missing a user override
207+
const hasUnresolvedNullFlex = Array.from(keyGroups.entries()).some(
208+
([groupKey, group]) =>
209+
group.hasNullFlex && !group.isAtMaxFlex && !flexOverrides.has(groupKey)
210+
)
211+
173212
return (
174213
<Dialog open={open} onOpenChange={onOpenChange}>
175214
<DialogContent className="max-w-4xl max-h-[80vh] overflow-y-auto">
@@ -195,8 +234,9 @@ export function FlexMenu({
195234
<div className="font-medium">{key.keyName}</div>
196235
<div className="text-muted-foreground">
197236
{KeyTypeLabels[key.keyType]}
198-
{key.flexNumber !== undefined &&
199-
` • Flex ${key.flexNumber}`}
237+
{key.flexNumber != null
238+
? ` • Flex ${key.flexNumber}`
239+
: ' • Flex saknas'}
200240
{key.keySequenceNumber !== undefined &&
201241
` • Löpnr: ${key.keySequenceNumber}`}
202242
</div>
@@ -212,7 +252,10 @@ export function FlexMenu({
212252
</h3>
213253
<div className="space-y-3 max-h-[400px] overflow-y-auto">
214254
{Array.from(keyGroups.entries()).map(([groupKey, group]) => {
215-
const newFlexNumber = group.currentFlexNumber + 1
255+
const effectiveFlex = getEffectiveFlexNumber(group, groupKey)
256+
const newFlexNumber =
257+
effectiveFlex !== null ? effectiveFlex + 1 : null
258+
216259
return (
217260
<div
218261
key={groupKey}
@@ -225,41 +268,89 @@ export function FlexMenu({
225268
</div>
226269
{group.hasFlexConflict && (
227270
<div className="text-xs text-destructive mt-1">
228-
⚠️ Varning: Valda nycklar har olika flex-nummer
271+
Varning: Valda nycklar har olika flex-nummer
229272
</div>
230273
)}
231274
</div>
232275

233-
<div className="flex items-center justify-between">
234-
<span className="text-xs text-muted-foreground">
235-
Flex {newFlexNumber} • Löpnr 1-{group.count}
236-
</span>
237-
<div className="flex items-center gap-2">
238-
<Button
239-
type="button"
240-
size="icon"
241-
variant="outline"
242-
className="h-7 w-7"
243-
onClick={() => decrementCount(groupKey)}
244-
disabled={group.count === 0 || isCreating}
245-
>
246-
<Minus className="h-3 w-3" />
247-
</Button>
248-
<span className="w-8 text-center font-medium">
249-
{group.count}
250-
</span>
251-
<Button
252-
type="button"
253-
size="icon"
254-
variant="outline"
255-
className="h-7 w-7"
256-
onClick={() => incrementCount(groupKey)}
257-
disabled={isCreating}
258-
>
259-
<Plus className="h-3 w-3" />
260-
</Button>
276+
{/* Max flex warning */}
277+
{group.isAtMaxFlex && (
278+
<div className="text-xs text-destructive">
279+
Kan inte flexa – redan på flex 3
261280
</div>
262-
</div>
281+
)}
282+
283+
{/* Null flex - require user to set flex */}
284+
{group.hasNullFlex && !group.isAtMaxFlex && (
285+
<div className="space-y-2">
286+
<div className="text-xs text-destructive">
287+
Flex saknas – ange nuvarande flex innan du flexar
288+
</div>
289+
<div className="flex items-center gap-2">
290+
<span className="text-xs text-muted-foreground">
291+
Nuvarande flex:
292+
</span>
293+
<Select
294+
value={
295+
flexOverrides.has(groupKey)
296+
? String(flexOverrides.get(groupKey))
297+
: undefined
298+
}
299+
onValueChange={(v) =>
300+
handleFlexOverride(groupKey, v)
301+
}
302+
>
303+
<SelectTrigger className="w-20 h-7 text-xs">
304+
<SelectValue placeholder="–" />
305+
</SelectTrigger>
306+
<SelectContent>
307+
<SelectItem value="1">1</SelectItem>
308+
<SelectItem value="2">2</SelectItem>
309+
</SelectContent>
310+
</Select>
311+
{newFlexNumber !== null && (
312+
<span className="text-xs text-muted-foreground">
313+
→ Ny flex: {newFlexNumber}
314+
</span>
315+
)}
316+
</div>
317+
</div>
318+
)}
319+
320+
{/* Normal group or null-flex with override set - show quantity controls */}
321+
{!group.isAtMaxFlex &&
322+
(!group.hasNullFlex || flexOverrides.has(groupKey)) && (
323+
<div className="flex items-center justify-between">
324+
<span className="text-xs text-muted-foreground">
325+
Flex {newFlexNumber} • Löpnr 1-{group.count}
326+
</span>
327+
<div className="flex items-center gap-2">
328+
<Button
329+
type="button"
330+
size="icon"
331+
variant="outline"
332+
className="h-7 w-7"
333+
onClick={() => decrementCount(groupKey)}
334+
disabled={group.count === 0 || isCreating}
335+
>
336+
<Minus className="h-3 w-3" />
337+
</Button>
338+
<span className="w-8 text-center font-medium">
339+
{group.count}
340+
</span>
341+
<Button
342+
type="button"
343+
size="icon"
344+
variant="outline"
345+
className="h-7 w-7"
346+
onClick={() => incrementCount(groupKey)}
347+
disabled={isCreating}
348+
>
349+
<Plus className="h-3 w-3" />
350+
</Button>
351+
</div>
352+
</div>
353+
)}
263354
</div>
264355
)
265356
})}
@@ -277,7 +368,9 @@ export function FlexMenu({
277368
</Button>
278369
<Button
279370
onClick={handleCreate}
280-
disabled={isCreating || totalKeysToCreate === 0}
371+
disabled={
372+
isCreating || totalKeysToCreate === 0 || hasUnresolvedNullFlex
373+
}
281374
>
282375
{isCreating ? (
283376
<>

0 commit comments

Comments
 (0)