feat: add server selection for test_access promo offer templates

AdminPromoOfferTemplateEdit now shows checkboxes to select test
squad servers when editing a test_access template.
This commit is contained in:
c0mrade
2026-03-27 12:31:46 +03:00
parent c697ddb224
commit 5246ad2a09

View File

@@ -8,6 +8,7 @@ import {
OFFER_TYPE_CONFIG, OFFER_TYPE_CONFIG,
OfferType, OfferType,
} from '../api/promoOffers'; } from '../api/promoOffers';
import { serversApi } from '../api/servers';
import { AdminBackButton } from '../components/admin'; import { AdminBackButton } from '../components/admin';
import { createNumberInputHandler, toNumber } from '../utils/inputHelpers'; import { createNumberInputHandler, toNumber } from '../utils/inputHelpers';
@@ -31,6 +32,14 @@ export default function AdminPromoOfferTemplateEdit() {
const [testDurationHours, setTestDurationHours] = useState<number | ''>(0); const [testDurationHours, setTestDurationHours] = useState<number | ''>(0);
const [isActive, setIsActive] = useState(true); const [isActive, setIsActive] = useState(true);
const [isTestAccess, setIsTestAccess] = useState(false); const [isTestAccess, setIsTestAccess] = useState(false);
const [selectedSquadUuids, setSelectedSquadUuids] = useState<string[]>([]);
// Fetch available servers for test_access squad selection
const { data: serversData } = useQuery({
queryKey: ['admin-servers-for-promo'],
queryFn: () => serversApi.getServers(true),
enabled: isTestAccess,
});
// Query template // Query template
const { data: templatesData, isLoading } = useQuery({ const { data: templatesData, isLoading } = useQuery({
@@ -52,6 +61,7 @@ export default function AdminPromoOfferTemplateEdit() {
setTestDurationHours(template.test_duration_hours || 0); setTestDurationHours(template.test_duration_hours || 0);
setIsActive(template.is_active); setIsActive(template.is_active);
setIsTestAccess(template.offer_type === 'test_access'); setIsTestAccess(template.offer_type === 'test_access');
setSelectedSquadUuids(template.test_squad_uuids || []);
} }
}, [template]); }, [template]);
@@ -78,6 +88,7 @@ export default function AdminPromoOfferTemplateEdit() {
const discountHours = toNumber(activeDiscountHours); const discountHours = toNumber(activeDiscountHours);
if (isTestAccess) { if (isTestAccess) {
data.test_duration_hours = testHours > 0 ? testHours : undefined; data.test_duration_hours = testHours > 0 ? testHours : undefined;
data.test_squad_uuids = selectedSquadUuids;
} else { } else {
data.active_discount_hours = discountHours > 0 ? discountHours : undefined; data.active_discount_hours = discountHours > 0 ? discountHours : undefined;
} }
@@ -201,22 +212,70 @@ export default function AdminPromoOfferTemplateEdit() {
</div> </div>
{isTestAccess ? ( {isTestAccess ? (
<div> <>
<label className="mb-2 block text-sm font-medium text-dark-300"> <div>
{t('admin.promoOffers.form.testDurationHours')} <label className="mb-2 block text-sm font-medium text-dark-300">
</label> {t('admin.promoOffers.form.testDurationHours')}
<input </label>
type="number" <input
value={testDurationHours} type="number"
onChange={createNumberInputHandler(setTestDurationHours, 0)} value={testDurationHours}
className="input" onChange={createNumberInputHandler(setTestDurationHours, 0)}
min={0} className="input"
placeholder="0" min={0}
/> placeholder="0"
<p className="mt-1 text-xs text-dark-500"> />
{t('admin.promoOffers.form.defaultZero')} <p className="mt-1 text-xs text-dark-500">
</p> {t('admin.promoOffers.form.defaultZero')}
</div> </p>
</div>
<div>
<label className="mb-2 block text-sm font-medium text-dark-300">
{t('admin.promoOffers.form.testSquads', 'Тестовые серверы')}
</label>
{serversData?.servers && serversData.servers.length > 0 ? (
<div className="space-y-1.5">
{serversData.servers.map((server) => (
<label
key={server.squad_uuid || server.id}
className="flex cursor-pointer items-center gap-2.5 rounded-lg border border-dark-600 bg-dark-700/50 px-3 py-2 text-sm transition-colors hover:border-accent-500/50"
>
<input
type="checkbox"
checked={selectedSquadUuids.includes(server.squad_uuid)}
onChange={(e) => {
if (e.target.checked) {
setSelectedSquadUuids([...selectedSquadUuids, server.squad_uuid]);
} else {
setSelectedSquadUuids(
selectedSquadUuids.filter((u) => u !== server.squad_uuid),
);
}
}}
className="accent-accent-500"
/>
<span className="text-dark-200">{server.display_name}</span>
{server.country_code && (
<span className="text-dark-500">{server.country_code}</span>
)}
</label>
))}
</div>
) : (
<p className="text-sm text-dark-500">
{t('admin.promoOffers.form.noServers', 'Нет доступных серверов')}
</p>
)}
{selectedSquadUuids.length === 0 && (
<p className="mt-1 text-xs text-warning-400">
{t(
'admin.promoOffers.form.selectSquadHint',
'Выберите хотя бы один сервер для тестового доступа',
)}
</p>
)}
</div>
</>
) : ( ) : (
<div> <div>
<label className="mb-2 block text-sm font-medium text-dark-300"> <label className="mb-2 block text-sm font-medium text-dark-300">