chore: update
ci-api / test (push) Successful in 22m1s
ci-web / test (push) Successful in 13m23s

This commit is contained in:
Nuxgrid
2026-08-02 13:48:21 +02:00
parent eeec8e239b
commit d4009d329c
10 changed files with 343 additions and 604 deletions
+134 -3
View File
@@ -1,6 +1,5 @@
import { useState } from 'react'
import {
Box,
Button,
FormControl,
FormLabel,
@@ -36,13 +35,23 @@ export function CreateDemoModal({ isOpen, onClose, onCreated, leadId, lockedUser
const toast = useToast()
const [username, setUsername] = useState(lockedUsername ?? '')
const [adminUsername, setAdminUsername] = useState('admin')
const [adminPassword, setAdminPassword] = useState('')
const [enableTelegram, setEnableTelegram] = useState(false)
const [telegramBotUsername, setTelegramBotUsername] = useState('')
const [telegramBotToken, setTelegramBotToken] = useState('')
const [enableNowPayments, setEnableNowPayments] = useState(false)
const [nowPaymentsApiKey, setNowPaymentsApiKey] = useState('')
const [nowPaymentsIpnSecret, setNowPaymentsIpnSecret] = useState('')
const [enableLBTelegram, setEnableLBTelegram] = useState(false)
const [lbBot1Username, setLbBot1Username] = useState('')
const [lbBot1Token, setLbBot1Token] = useState('')
const [lbBot2Username, setLbBot2Username] = useState('')
const [lbBot2Token, setLbBot2Token] = useState('')
const [storageDriver, setStorageDriver] = useState<StorageDriver>('local')
const [s3Bucket, setS3Bucket] = useState('')
const [s3Endpoint, setS3Endpoint] = useState('')
@@ -50,11 +59,19 @@ export function CreateDemoModal({ isOpen, onClose, onCreated, leadId, lockedUser
const reset = () => {
setUsername(lockedUsername ?? '')
setAdminUsername('admin')
setAdminPassword('')
setEnableTelegram(false)
setTelegramBotUsername('')
setTelegramBotToken('')
setEnableNowPayments(false)
setNowPaymentsApiKey('')
setNowPaymentsIpnSecret('')
setEnableLBTelegram(false)
setLbBot1Username('')
setLbBot1Token('')
setLbBot2Username('')
setLbBot2Token('')
setStorageDriver('local')
setS3Bucket('')
setS3Endpoint('')
@@ -71,14 +88,25 @@ export function CreateDemoModal({ isOpen, onClose, onCreated, leadId, lockedUser
toast({ status: 'warning', title: 'Username requis' })
return
}
if (!adminUsername.trim() || adminPassword.trim().length < 8) {
toast({ status: 'warning', title: 'Identifiants admin requis (mot de passe : 8 caractères min.)' })
return
}
if (storageDriver === 's3' && (!s3Bucket.trim() || !s3Endpoint.trim())) {
toast({ status: 'warning', title: 'Bucket et endpoint S3 requis' })
return
}
if (enableLBTelegram && !lbBot1Username.trim() && !lbBot2Username.trim()) {
toast({ status: 'warning', title: 'Au moins un bot (username) requis pour le load-balancer' })
return
}
const params: CreateDemoParams = {
username: username.trim(),
leadId,
adminUsername: adminUsername.trim(),
adminPassword: adminPassword.trim(),
telegramBotUsername: enableTelegram ? telegramBotUsername.trim() || undefined : undefined,
telegramBotToken: enableTelegram ? telegramBotToken.trim() || undefined : undefined,
nowPaymentsApiKey: enableNowPayments ? nowPaymentsApiKey.trim() || undefined : undefined,
nowPaymentsIpnSecret: enableNowPayments ? nowPaymentsIpnSecret.trim() || undefined : undefined,
@@ -86,6 +114,14 @@ export function CreateDemoModal({ isOpen, onClose, onCreated, leadId, lockedUser
...(storageDriver === 's3'
? { s3Bucket: s3Bucket.trim(), s3Endpoint: s3Endpoint.trim() }
: {}),
...(enableLBTelegram
? {
lbBot1Username: lbBot1Username.trim() || undefined,
lbBot1Token: lbBot1Token.trim() || undefined,
lbBot2Username: lbBot2Username.trim() || undefined,
lbBot2Token: lbBot2Token.trim() || undefined,
}
: {}),
}
setSubmitting(true)
@@ -120,6 +156,35 @@ export function CreateDemoModal({ isOpen, onClose, onCreated, leadId, lockedUser
/>
</FormControl>
{/* --- Compte admin de la démo --- */}
<Stack spacing={3} p={3} borderWidth="1px" borderRadius="md">
<Text fontSize="sm" fontWeight="semibold">
Compte admin de la démo
</Text>
<Text fontSize="xs" color="gray.500">
Créé une fois postgres/redis/backend/frontend démarrés c'est ce que le client utilisera pour se connecter au backoffice de sa démo.
</Text>
<HStack spacing={3} align="start">
<FormControl isRequired isDisabled={submitting}>
<FormLabel fontSize="sm">Username</FormLabel>
<Input
value={adminUsername}
onChange={(e) => setAdminUsername(e.target.value)}
/>
</FormControl>
<FormControl isRequired isDisabled={submitting}>
<FormLabel fontSize="sm">Mot de passe</FormLabel>
<Input
placeholder="8 caractères min."
value={adminPassword}
onChange={(e) => setAdminPassword(e.target.value)}
type="password"
autoComplete="off"
/>
</FormControl>
</HStack>
</Stack>
{/* --- Telegram --- */}
<FormControl isDisabled={submitting}>
<HStack justify="space-between">
@@ -131,7 +196,15 @@ export function CreateDemoModal({ isOpen, onClose, onCreated, leadId, lockedUser
</HStack>
</FormControl>
{enableTelegram && (
<Box pl={3} borderLeftWidth="2px" borderColor="primary.500">
<Stack spacing={3} pl={3} borderLeftWidth="2px" borderColor="primary.500">
<FormControl isDisabled={submitting}>
<FormLabel fontSize="sm">Nom du bot (username)</FormLabel>
<Input
placeholder="mon_bot"
value={telegramBotUsername}
onChange={(e) => setTelegramBotUsername(e.target.value)}
/>
</FormControl>
<FormControl isDisabled={submitting}>
<FormLabel fontSize="sm">Token bot Telegram</FormLabel>
<Input
@@ -142,7 +215,7 @@ export function CreateDemoModal({ isOpen, onClose, onCreated, leadId, lockedUser
autoComplete="off"
/>
</FormControl>
</Box>
</Stack>
)}
{/* --- NowPayments --- */}
@@ -183,6 +256,64 @@ export function CreateDemoModal({ isOpen, onClose, onCreated, leadId, lockedUser
</Stack>
)}
{/* --- Load-balancer Telegram (multi-bots) --- */}
<FormControl isDisabled={submitting}>
<HStack justify="space-between">
<FormLabel mb={0}>Load-balancer Telegram</FormLabel>
<Switch
isChecked={enableLBTelegram}
onChange={(e) => setEnableLBTelegram(e.target.checked)}
/>
</HStack>
</FormControl>
{enableLBTelegram && (
<Stack spacing={4} pl={3} borderLeftWidth="2px" borderColor="primary.500">
<Text fontSize="xs" color="gray.500">
Répartit le trafic entre plusieurs bots. Renseignez au moins le bot 1 ; le bot 2 est optionnel.
</Text>
<HStack spacing={3} align="start">
<FormControl isDisabled={submitting}>
<FormLabel fontSize="sm">Bot 1 — username</FormLabel>
<Input
placeholder="mon_bot_1"
value={lbBot1Username}
onChange={(e) => setLbBot1Username(e.target.value)}
/>
</FormControl>
<FormControl isDisabled={submitting}>
<FormLabel fontSize="sm">Bot 1 — token</FormLabel>
<Input
placeholder="123456:ABC-DEF..."
value={lbBot1Token}
onChange={(e) => setLbBot1Token(e.target.value)}
type="password"
autoComplete="off"
/>
</FormControl>
</HStack>
<HStack spacing={3} align="start">
<FormControl isDisabled={submitting}>
<FormLabel fontSize="sm">Bot 2 — username (optionnel)</FormLabel>
<Input
placeholder="mon_bot_2"
value={lbBot2Username}
onChange={(e) => setLbBot2Username(e.target.value)}
/>
</FormControl>
<FormControl isDisabled={submitting}>
<FormLabel fontSize="sm">Bot 2 — token</FormLabel>
<Input
placeholder="123456:ABC-DEF..."
value={lbBot2Token}
onChange={(e) => setLbBot2Token(e.target.value)}
type="password"
autoComplete="off"
/>
</FormControl>
</HStack>
</Stack>
)}
{/* --- Stockage --- */}
<FormControl isDisabled={submitting}>
<FormLabel>Stockage des fichiers</FormLabel>
+12
View File
@@ -77,12 +77,19 @@ export type StorageDriver = 'local' | 's3'
export interface CreateDemoParams {
username: string
leadId?: string
telegramBotUsername?: string
telegramBotToken?: string
nowPaymentsApiKey?: string
nowPaymentsIpnSecret?: string
storageDriver: StorageDriver
s3Bucket?: string
s3Endpoint?: string
lbBot1Username?: string
lbBot1Token?: string
lbBot2Username?: string
lbBot2Token?: string
adminUsername: string
adminPassword: string
}
export interface CodeBuySub {
@@ -168,6 +175,7 @@ export const api = {
request<Demo>('POST', '/demos', {
username: params.username,
...(params.leadId ? { lead_id: params.leadId } : {}),
...(params.telegramBotUsername ? { telegram_bot_username: params.telegramBotUsername } : {}),
...(params.telegramBotToken ? { telegram_bot_token: params.telegramBotToken } : {}),
...(params.nowPaymentsApiKey ? { nowpayments_api_key: params.nowPaymentsApiKey } : {}),
...(params.nowPaymentsIpnSecret ? { nowpayments_ipn_secret: params.nowPaymentsIpnSecret } : {}),
@@ -175,6 +183,10 @@ export const api = {
...(params.storageDriver === 's3'
? { s3_bucket: params.s3Bucket, s3_endpoint: params.s3Endpoint }
: {}),
...(params.lbBot1Username ? { lb_bot1_username: params.lbBot1Username, lb_bot1_token: params.lbBot1Token } : {}),
...(params.lbBot2Username ? { lb_bot2_username: params.lbBot2Username, lb_bot2_token: params.lbBot2Token } : {}),
admin_username: params.adminUsername,
admin_password: params.adminPassword,
}),
extendDemo: (id: string) => request<Demo>('POST', `/demos/${id}/extend`),
deleteDemo: (id: string) => request<Demo>('DELETE', `/demos/${id}`),