improved UI
This commit is contained in:
parent
67ea288de6
commit
0917124bd3
|
|
@ -15,72 +15,60 @@ export function DeviceGrid({
|
||||||
totalSeats?: number;
|
totalSeats?: number;
|
||||||
}) {
|
}) {
|
||||||
const getMachineNumber = useMachineNumber();
|
const getMachineNumber = useMachineNumber();
|
||||||
const deviceMap = new Map<number, any>();
|
const parsedDevices = devices
|
||||||
|
.map((device, index) => ({
|
||||||
|
device,
|
||||||
|
index,
|
||||||
|
number: getMachineNumber(device.id || ""),
|
||||||
|
}))
|
||||||
|
.sort((a, b) => {
|
||||||
|
const aNumber = a.number > 0 ? a.number : Number.MAX_SAFE_INTEGER;
|
||||||
|
const bNumber = b.number > 0 ? b.number : Number.MAX_SAFE_INTEGER;
|
||||||
|
|
||||||
let maxMachineNumber = 0;
|
if (aNumber !== bNumber) {
|
||||||
devices.forEach((device) => {
|
return aNumber - bNumber;
|
||||||
const number = getMachineNumber(device.id || "");
|
}
|
||||||
if (number > maxMachineNumber) maxMachineNumber = number;
|
|
||||||
|
return a.index - b.index;
|
||||||
});
|
});
|
||||||
|
|
||||||
const seatCount =
|
const seatCount =
|
||||||
typeof totalSeats === "number" && totalSeats > 0 ? totalSeats : maxMachineNumber;
|
typeof totalSeats === "number" && totalSeats > 0 ? totalSeats : parsedDevices.length;
|
||||||
|
const rightCapacity = Math.ceil(seatCount / 2);
|
||||||
|
const inRangeCount = parsedDevices.filter(
|
||||||
|
(item) => item.number > 0 && item.number <= seatCount
|
||||||
|
).length;
|
||||||
|
const useThresholdSplit =
|
||||||
|
seatCount > 0 && inRangeCount >= Math.ceil(parsedDevices.length * 0.6);
|
||||||
|
|
||||||
devices.forEach((device) => {
|
let rightDevices = parsedDevices;
|
||||||
const number = getMachineNumber(device.id || "");
|
let leftDevices: typeof parsedDevices = [];
|
||||||
if (number > 0 && number <= seatCount) deviceMap.set(number, device);
|
|
||||||
});
|
|
||||||
|
|
||||||
const columnsPerSide = 4;
|
if (useThresholdSplit) {
|
||||||
const rightCount = Math.ceil(seatCount / 2);
|
rightDevices = parsedDevices.filter(
|
||||||
const leftCount = seatCount - rightCount;
|
(item) => item.number > 0 && item.number <= rightCapacity
|
||||||
const totalRows = Math.max(
|
|
||||||
Math.ceil(rightCount / columnsPerSide),
|
|
||||||
Math.ceil(leftCount / columnsPerSide)
|
|
||||||
);
|
);
|
||||||
|
leftDevices = parsedDevices.filter((item) => item.number > rightCapacity);
|
||||||
|
|
||||||
const buildRowPositions = (side: "left" | "right", rowIndexFromBottom: number) => {
|
const unassigned = parsedDevices.filter(
|
||||||
const start =
|
(item) => item.number <= 0 || item.number > seatCount
|
||||||
side === "right"
|
);
|
||||||
? rowIndexFromBottom * columnsPerSide + 1
|
leftDevices = [...leftDevices, ...unassigned];
|
||||||
: rightCount + 1 + rowIndexFromBottom * columnsPerSide;
|
} else {
|
||||||
const end =
|
const splitIndex = Math.ceil(parsedDevices.length / 2);
|
||||||
side === "right"
|
rightDevices = parsedDevices.slice(0, splitIndex);
|
||||||
? Math.min(start + columnsPerSide - 1, rightCount)
|
leftDevices = parsedDevices.slice(splitIndex);
|
||||||
: Math.min(start + columnsPerSide - 1, seatCount);
|
|
||||||
|
|
||||||
const count = Math.max(0, end - start + 1);
|
|
||||||
const positions = Array<number | null>(columnsPerSide).fill(null);
|
|
||||||
|
|
||||||
if (count === 0) {
|
|
||||||
return positions;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const numbers: number[] = [];
|
const renderDevice = (item: (typeof parsedDevices)[number]) => {
|
||||||
for (let n = end; n >= start; n -= 1) {
|
const device = item.device;
|
||||||
numbers.push(n);
|
const position = item.number > 0 ? item.number : item.index + 1;
|
||||||
}
|
|
||||||
|
|
||||||
const offset = side === "right" ? 0 : columnsPerSide - count;
|
|
||||||
numbers.forEach((n, index) => {
|
|
||||||
positions[offset + index] = n;
|
|
||||||
});
|
|
||||||
|
|
||||||
return positions;
|
|
||||||
};
|
|
||||||
|
|
||||||
const renderSeat = (position: number | null, key: string) => {
|
|
||||||
if (!position) {
|
|
||||||
return <div key={key} className="w-24 h-24 shrink-0" />;
|
|
||||||
}
|
|
||||||
|
|
||||||
const device = deviceMap.get(position);
|
|
||||||
const macAddress = device?.networkInfos?.[0]?.macAddress || device?.id;
|
const macAddress = device?.networkInfos?.[0]?.macAddress || device?.id;
|
||||||
const folderStatus = folderStatuses?.get(macAddress);
|
const folderStatus = folderStatuses?.get(macAddress);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ComputerCard
|
<ComputerCard
|
||||||
key={key}
|
key={device?.id || `device-${item.index}`}
|
||||||
device={device}
|
device={device}
|
||||||
position={position}
|
position={position}
|
||||||
folderStatus={folderStatus}
|
folderStatus={folderStatus}
|
||||||
|
|
@ -89,33 +77,28 @@ export function DeviceGrid({
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderRow = (rowIndex: number) => {
|
const gridTemplateColumns = "repeat(auto-fit, minmax(6rem, 6rem))";
|
||||||
const rowIndexFromBottom = totalRows - 1 - rowIndex;
|
|
||||||
const leftPositions = buildRowPositions("left", rowIndexFromBottom);
|
|
||||||
const rightPositions = buildRowPositions("right", rowIndexFromBottom);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div key={rowIndex} className="flex items-center justify-center gap-3">
|
|
||||||
{leftPositions.map((position, i) =>
|
|
||||||
renderSeat(position, `left-${rowIndex}-${i}`)
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Đường chia giữa */}
|
|
||||||
<div className="w-32 flex items-center justify-center">
|
|
||||||
<div className="h-px w-full bg-border border-t-2 border-dashed" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{rightPositions.map((position, i) =>
|
|
||||||
renderSeat(position, `right-${rowIndex}-${i}`)
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="px-0.5 py-8 space-y-6">
|
<div className="px-0.5 py-8 space-y-6">
|
||||||
<div className="space-y-4">
|
<div className="flex items-start justify-center gap-6">
|
||||||
{Array.from({ length: totalRows }).map((_, i) => renderRow(i))}
|
<div
|
||||||
|
className="grid flex-1 gap-3"
|
||||||
|
style={{ gridTemplateColumns, justifyContent: "end" }}
|
||||||
|
>
|
||||||
|
{leftDevices.map(renderDevice)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex items-stretch justify-center w-6">
|
||||||
|
<div className="w-px bg-border border-l-2 border-dashed" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
className="grid flex-1 gap-3"
|
||||||
|
style={{ gridTemplateColumns, justifyContent: "start" }}
|
||||||
|
>
|
||||||
|
{rightDevices.map(renderDevice)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center justify-between px-4 pb-6 border-b-2 border-dashed">
|
<div className="flex items-center justify-between px-4 pb-6 border-b-2 border-dashed">
|
||||||
<div className="flex items-center gap-3 px-6 py-4 bg-muted rounded-lg border-2 border-border">
|
<div className="flex items-center gap-3 px-6 py-4 bg-muted rounded-lg border-2 border-border">
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user