améliore la création de campagnes (proposition de paliers harmonieux automatiques)
This commit is contained in:
@@ -239,9 +239,9 @@ function AdminPageContent() {
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="grid gap-6">
|
<div className="grid gap-6 group/campaigns">
|
||||||
{campaigns.map((campaign) => (
|
{campaigns.map((campaign) => (
|
||||||
<Card key={campaign.id} className="group hover:shadow-xl hover:shadow-slate-100 dark:hover:shadow-slate-900/20 transition-all duration-300 border-slate-200 dark:border-slate-700 overflow-hidden">
|
<Card key={campaign.id} className="group hover:shadow-xl hover:shadow-slate-100 dark:hover:shadow-slate-900/20 transition-all duration-300 border-slate-200 dark:border-slate-700 overflow-hidden group-hover/campaigns:opacity-50 hover:!opacity-100">
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
|
|
||||||
<CardHeader className="pb-4">
|
<CardHeader className="pb-4">
|
||||||
|
|||||||
@@ -47,13 +47,79 @@ export default function CreateCampaignModal({ isOpen, onClose, onSuccess }: Crea
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const generateOptimalTiers = (budget: number): string => {
|
||||||
|
if (budget <= 0) return "0";
|
||||||
|
|
||||||
|
// Cas spéciaux pour des budgets courants
|
||||||
|
if (budget === 10000) {
|
||||||
|
return "0, 500, 1000, 2000, 3000, 5000, 7500, 10000";
|
||||||
|
}
|
||||||
|
if (budget === 8000) {
|
||||||
|
return "0, 500, 1000, 2000, 3000, 4000, 6000, 8000";
|
||||||
|
}
|
||||||
|
|
||||||
|
const tiers = [0];
|
||||||
|
|
||||||
|
// Déterminer les paliers "ronds" selon la taille du budget
|
||||||
|
let roundValues: number[] = [];
|
||||||
|
|
||||||
|
if (budget <= 100) {
|
||||||
|
// Petits budgets : multiples de 5, 10, 25
|
||||||
|
roundValues = [5, 10, 25, 50, 75, 100];
|
||||||
|
} else if (budget <= 500) {
|
||||||
|
// Budgets moyens : multiples de 25, 50, 100
|
||||||
|
roundValues = [25, 50, 75, 100, 150, 200, 250, 300, 400, 500];
|
||||||
|
} else if (budget <= 2000) {
|
||||||
|
// Budgets moyens-grands : multiples de 100, 250, 500
|
||||||
|
roundValues = [100, 250, 500, 750, 1000, 1250, 1500, 1750, 2000];
|
||||||
|
} else if (budget <= 10000) {
|
||||||
|
// Gros budgets : multiples de 500, 1000, 2000
|
||||||
|
roundValues = [500, 1000, 1500, 2000, 2500, 3000, 4000, 5000, 6000, 7500, 10000];
|
||||||
|
} else {
|
||||||
|
// Très gros budgets : multiples de 1000, 2000, 5000
|
||||||
|
roundValues = [1000, 2000, 3000, 5000, 7500, 10000, 15000, 20000, 25000, 50000];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sélectionner les paliers qui sont inférieurs ou égaux au budget
|
||||||
|
const validTiers = roundValues.filter(tier => tier <= budget);
|
||||||
|
|
||||||
|
// Prendre 6-8 paliers intermédiaires + 0 et le budget final
|
||||||
|
const targetCount = Math.min(8, Math.max(6, validTiers.length));
|
||||||
|
const step = Math.max(1, Math.floor(validTiers.length / targetCount));
|
||||||
|
|
||||||
|
for (let i = 0; i < validTiers.length && tiers.length < targetCount + 1; i += step) {
|
||||||
|
if (!tiers.includes(validTiers[i])) {
|
||||||
|
tiers.push(validTiers[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ajouter le budget final s'il n'est pas déjà présent
|
||||||
|
if (!tiers.includes(budget)) {
|
||||||
|
tiers.push(budget);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trier et retourner
|
||||||
|
return tiers.sort((a, b) => a - b).join(', ');
|
||||||
|
};
|
||||||
|
|
||||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
||||||
|
const { name, value } = e.target;
|
||||||
setFormData(prev => ({
|
setFormData(prev => ({
|
||||||
...prev,
|
...prev,
|
||||||
[e.target.name]: e.target.value
|
[name]: value
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleBudgetBlur = (e: React.FocusEvent<HTMLInputElement>) => {
|
||||||
|
const budget = parseInt(e.target.value);
|
||||||
|
if (!isNaN(budget) && budget > 0 && !formData.spending_tiers) {
|
||||||
|
setFormData(prev => ({
|
||||||
|
...prev,
|
||||||
|
spending_tiers: generateOptimalTiers(budget)
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
setFormData({
|
setFormData({
|
||||||
title: '',
|
title: '',
|
||||||
@@ -108,13 +174,14 @@ export default function CreateCampaignModal({ isOpen, onClose, onSuccess }: Crea
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label htmlFor="budget_per_user">Budget par utilisateur (€) *</Label>
|
<Label htmlFor="budget_per_user">Budget (€) *</Label>
|
||||||
<Input
|
<Input
|
||||||
id="budget_per_user"
|
id="budget_per_user"
|
||||||
name="budget_per_user"
|
name="budget_per_user"
|
||||||
type="number"
|
type="number"
|
||||||
value={formData.budget_per_user}
|
value={formData.budget_per_user}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
|
onBlur={handleBudgetBlur}
|
||||||
placeholder="100"
|
placeholder="100"
|
||||||
min="1"
|
min="1"
|
||||||
required
|
required
|
||||||
@@ -133,6 +200,11 @@ export default function CreateCampaignModal({ isOpen, onClose, onSuccess }: Crea
|
|||||||
/>
|
/>
|
||||||
<p className="text-xs text-slate-500 dark:text-slate-400">
|
<p className="text-xs text-slate-500 dark:text-slate-400">
|
||||||
Séparez les montants par des virgules (ex: 0, 10, 25, 50, 100)
|
Séparez les montants par des virgules (ex: 0, 10, 25, 50, 100)
|
||||||
|
{formData.budget_per_user && !formData.spending_tiers && (
|
||||||
|
<span className="block mt-1 text-blue-600 dark:text-blue-400">
|
||||||
|
💡 Les paliers seront générés automatiquement après avoir saisi le budget
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ export default function EditCampaignModal({ isOpen, onClose, onSuccess, campaign
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label htmlFor="budget_per_user">Budget par utilisateur (€) *</Label>
|
<Label htmlFor="budget_per_user">Budget (€) *</Label>
|
||||||
<Input
|
<Input
|
||||||
id="budget_per_user"
|
id="budget_per_user"
|
||||||
name="budget_per_user"
|
name="budget_per_user"
|
||||||
|
|||||||
Reference in New Issue
Block a user