/*
* Copyright (C) 2026 Fluxer Contributors
*
* This file is part of Fluxer.
*
* Fluxer is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Fluxer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Fluxer. If not, see .
*/
/** @jsxRuntime automatic */
/** @jsxImportSource hono/jsx */
import {hasPermission} from '@fluxer/admin/src/AccessControlList';
import {Layout} from '@fluxer/admin/src/components/Layout';
import {FormFieldGroup} from '@fluxer/admin/src/components/ui/Form/FormFieldGroup';
import {Input} from '@fluxer/admin/src/components/ui/Input';
import {PageLayout} from '@fluxer/admin/src/components/ui/Layout/PageLayout';
import {VStack} from '@fluxer/admin/src/components/ui/Layout/VStack';
import {Table} from '@fluxer/admin/src/components/ui/Table';
import {TableBody} from '@fluxer/admin/src/components/ui/TableBody';
import {TableCell} from '@fluxer/admin/src/components/ui/TableCell';
import {TableContainer} from '@fluxer/admin/src/components/ui/TableContainer';
import {TableHeader} from '@fluxer/admin/src/components/ui/TableHeader';
import {TableHeaderCell} from '@fluxer/admin/src/components/ui/TableHeaderCell';
import {TableRow} from '@fluxer/admin/src/components/ui/TableRow';
import {Heading, Text} from '@fluxer/admin/src/components/ui/Typography';
import type {Session} from '@fluxer/admin/src/types/App';
import type {AdminConfig as Config} from '@fluxer/admin/src/types/Config';
import {AdminACLs} from '@fluxer/constants/src/AdminACLs';
import type {Flash} from '@fluxer/hono/src/Flash';
import type {UserAdminResponse} from '@fluxer/schema/src/domains/admin/AdminUserSchemas';
import {Button} from '@fluxer/ui/src/components/Button';
import {Card} from '@fluxer/ui/src/components/Card';
import {CsrfInput} from '@fluxer/ui/src/components/CsrfInput';
import {SliderInput} from '@fluxer/ui/src/components/SliderInput';
import type {FC} from 'hono/jsx';
const MAX_EXPAND_COUNT = 1000;
const DEFAULT_EXPAND_COUNT = 10;
export interface VisionarySlot {
slot_index: number;
user_id: string | null;
}
export interface VisionarySlotsPageProps {
config: Config;
session: Session;
currentAdmin: UserAdminResponse | undefined;
flash: Flash | undefined;
adminAcls: Array;
assetVersion: string;
csrfToken: string;
slots: Array;
totalCount: number;
reservedCount: number;
}
export const VisionarySlotsPage: FC = ({
config,
session,
currentAdmin,
flash,
adminAcls,
assetVersion,
csrfToken,
slots,
totalCount,
reservedCount,
}) => {
const hasViewPermission = hasPermission(adminAcls, AdminACLs.VISIONARY_SLOT_VIEW);
const hasExpandPermission = hasPermission(adminAcls, AdminACLs.VISIONARY_SLOT_EXPAND);
const hasShrinkPermission = hasPermission(adminAcls, AdminACLs.VISIONARY_SLOT_SHRINK);
const hasReservePermission = hasPermission(adminAcls, AdminACLs.VISIONARY_SLOT_RESERVE);
const hasSwapPermission = hasPermission(adminAcls, AdminACLs.VISIONARY_SLOT_SWAP);
const reservedSlots = slots.filter((s) => s.user_id !== null);
const minAllowedTotalCount = reservedSlots.length > 0 ? Math.max(...reservedSlots.map((s) => s.slot_index)) : 0;
return (
{hasViewPermission ? (
Visionary Slots Management
Total slots: {totalCount} | Reserved: {reservedCount} | Available:{' '}
{totalCount - reservedCount}
{hasExpandPermission && (
Expand Slots
)}
{hasShrinkPermission && (
Shrink Slots
{totalCount === 0 ? (
No slots to shrink.
) : minAllowedTotalCount >= totalCount ? (
Cannot shrink further. The highest reserved slot is index {minAllowedTotalCount}.
) : (
)}
)}
{hasReservePermission && (
Reserve Slot
{totalCount === 0 ? (
No slots exist yet. Expand slots first before reserving.
) : (
)}
)}
{hasSwapPermission && (
Swap Slots
{totalCount < 2 ? (
Need at least two slots to swap.
) : (
)}
)}
All Slots
{slots.length === 0 ? (
No slots exist yet.
) : (
Slot Index
User ID
Status
{slots.map((slot) => (
{slot.slot_index}
{slot.user_id ?? null}
{slot.user_id ? 'Reserved' : 'Available'}
))}
)}
) : (
Visionary Slots
You do not have permission to view visionary slots.
)}
);
};