-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Labels
enhancementNew feature or requestNew feature or request
Description
Un petit template sympa qui peut être mis à dispo pour remplacer l'exemple Advanced Sliders sur formedible.dev

RatingComponent.tsx :
"use client";
import React from 'react';
import { cn } from '@/lib/utils';
export type ColorScheme = 'dpe' | 'ges';
interface EnergyRatingComponentProps {
displayValue: string | number;
isActive: boolean;
colorScheme?: ColorScheme; // Nouveau prop pour choisir le schéma de couleurs
}
export const EnergyRatingComponent: React.FC<EnergyRatingComponentProps> = ({
displayValue,
isActive,
colorScheme = 'dpe', // Valeur par défaut
}) => {
// Color mapping for each DPE rating
const getColorClassesDpe = (rating: string | number) => {
const ratingStr = rating.toString().toUpperCase();
switch (ratingStr) {
case 'A':
return {
bg: 'bg-green-500',
text: 'text-white',
border: 'border-green-600',
};
case 'B':
return {
bg: 'bg-lime-500',
text: 'text-white',
border: 'border-lime-600',
};
case 'C':
return {
bg: 'bg-yellow-500',
text: 'text-white',
border: 'border-yellow-600',
};
case 'D':
return {
bg: 'bg-orange-500',
text: 'text-white',
border: 'border-orange-600',
};
case 'E':
return {
bg: 'bg-red-500',
text: 'text-white',
border: 'border-red-600',
};
case 'F':
return {
bg: 'bg-red-700',
text: 'text-white',
border: 'border-red-800',
};
case 'G':
return {
bg: 'bg-red-900',
text: 'text-white',
border: 'border-red-1000',
};
default:
return {
bg: 'bg-gray-500',
text: 'text-white',
border: 'border-gray-600',
};
}
};
// Color mapping for each GES rating
const getColorClassesGes = (rating: string | number) => {
const ratingStr = rating.toString().toUpperCase();
switch (ratingStr) {
case 'A':
return {
bg: 'bg-purple-200',
text: 'text-black',
border: 'border-purple-200',
};
case 'B':
return {
bg: 'bg-purple-300',
text: 'text-black',
border: 'border-purple-300',
};
case 'C':
return {
bg: 'bg-purple-400',
text: 'text-black',
border: 'border-purple-400',
};
case 'D':
return {
bg: 'bg-purple-500',
text: 'text-black',
border: 'border-purple-500',
};
case 'E':
return {
bg: 'bg-purple-600',
text: 'text-black',
border: 'border-purple-600',
};
case 'F':
return {
bg: 'bg-purple-700',
text: 'text-black',
border: 'border-purple-700',
};
case 'G':
return {
bg: 'bg-purple-900',
text: 'text-black',
border: 'border-purple-900',
};
default:
return {
bg: 'bg-gray-500',
text: 'text-black',
border: 'border-gray-600',
};
}
};
// Sélection du schéma de couleurs basé sur le prop
const colors = colorScheme === 'ges'
? getColorClassesGes(displayValue)
: getColorClassesDpe(displayValue);
const rating = displayValue.toString().toUpperCase();
// Get energy efficiency description
const getDescription = (rating: string) => {
switch (rating) {
case 'A':
return 'Excellent';
case 'B':
return 'Très bien';
case 'C':
return 'Bien';
case 'D':
return 'Moyen';
case 'E':
return 'Médiocre';
case 'F':
return 'Mauvais';
case 'G':
return 'Très mauvais';
default:
return '';
}
};
// Get energy consumption range (approximate kWh/m²/an for DPE or kg CO2/m²/an for GES)
const getEnergyRange = (rating: string) => {
if (colorScheme === 'ges') {
// GES ranges in kg CO2/m²/an
switch (rating) {
case 'A':
return '≤ 5';
case 'B':
return '6-10';
case 'C':
return '11-20';
case 'D':
return '21-35';
case 'E':
return '36-55';
case 'F':
return '56-80';
case 'G':
return '> 80';
default:
return '';
}
} else {
// DPE ranges in kWh/m²/an
switch (rating) {
case 'A':
return '≤ 50';
case 'B':
return '51-90';
case 'C':
return '91-150';
case 'D':
return '151-230';
case 'E':
return '231-330';
case 'F':
return '331-420';
case 'G':
return '> 420';
default:
return '';
}
}
};
// Get the unit based on color scheme
const getUnit = () => {
return colorScheme === 'ges' ? 'KGeqCO2/m²/an' : 'kWh/m²/an';
};
return (
<div className="flex flex-col items-center space-y-2 transition-all duration-300">
{/* Energy rating badge */}
<div
className={cn(
'relative flex items-center justify-center',
'w-12 h-12 rounded-lg border-2 font-bold text-lg',
'transition-all duration-300 transform',
colors.bg,
colors.text,
colors.border,
isActive ? [
'scale-125',
'ring-2 ring-white ring-opacity-60',
'z-10'
] : [
'scale-100 hover:scale-110',
]
)}
>
{/* Animated background pulse when active */}
{isActive && (
<div
className={cn(
'absolute inset-0 rounded-lg animate-pulse',
colors.bg,
'opacity-20'
)}
/>
)}
{/* Energy icon */}
<div className="absolute -top-1 -right-1">
{rating === 'A' ? (
// first place
<div
className={cn(
'w-5 h-5',
)}>🤩</div>
) : rating === 'B' ? (
// second place
<div
className={cn(
'w-5 h-5',
)}>😁</div>
) : rating === 'C' ? (
// third place
<div
className={cn(
'w-5 h-5',
)}>😅</div>
) : rating === 'F' ? (
// Warning icon for poor ratings
<div
className={cn(
'w-5 h-5',
)}>😨</div>
) : rating === 'G' ? (
// Warning icon for poor ratings
<div
className={cn(
'w-5 h-5',
)}>😰</div>
) : null}
</div>
{rating}
</div>
{/* Description and energy range when active */}
<div
className={cn(
'text-center transition-all duration-300',
isActive ? 'opacity-100 transform translate-y-0' : 'opacity-60 transform translate-y-1'
)}
>
<div className={cn(
'text-xs font-medium',
isActive ? 'text-foreground' : 'text-muted-foreground'
)}>
{getDescription(rating)}
</div>
{isActive && (
<div className="text-xs text-muted-foreground mt-1">
{getEnergyRange(rating)} {getUnit()}
</div>
)}
</div>
{/* Connection line to slider */}
<div
className={cn(
'w-0.5 h-4 transition-all duration-300',
isActive ? colors.bg : 'bg-border'
)}
/>
</div>
);
};
Page.tsx :
"use client"
import { useFormedible } from "@/hooks/use-formedible";
import React from 'react';
import { z } from 'zod';
import { Card, CardContent } from "@/components/ui/card";
import { EnergyRatingComponent, type ColorScheme } from '@/components/formedible/custom/RatingComponent';
const MySchema = z.object({
dpe: z.number().min(1).max(7),
ges: z.number().min(1).max(7),
});
type MyFormValues = z.infer<typeof MySchema>;
export default function MyForm() {
const { Form } = useFormedible<MyFormValues>({
schema: MySchema,
fields: [
// DPE (Diagnostic de Performance Énergétique)
{
section: { title: "🚥 Performance énergétique" },
name: "dpe",
type: "slider",
label: "DPE (Diagnostic de Performance Énergétique) *",
description: "Classe énergétique du logement",
sliderConfig: {
min: 1,
max: 7,
step: 1,
valueMapping: [
{ sliderValue: 1, displayValue: "A" },
{ sliderValue: 2, displayValue: "B" },
{ sliderValue: 3, displayValue: "C" },
{ sliderValue: 4, displayValue: "D" },
{ sliderValue: 5, displayValue: "E" },
{ sliderValue: 6, displayValue: "F" },
{ sliderValue: 7, displayValue: "G" },
],
visualizationComponent: (props) => (
<EnergyRatingComponent {...props} colorScheme="dpe" />
),
showValue: true,
showTooltip: false,
showTicks: false,
},
validation: z.number().min(1).max(7),
},
// GES (Gaz à Effet de Serre)
{
section: { title: "🌍 Émissions de GES" },
name: "ges",
type: "slider",
label: "GES (Émissions de Gaz à Effet de Serre) *",
description: "Classe d'émissions de CO2 du logement",
sliderConfig: {
min: 1,
max: 7,
step: 1,
valueMapping: [
{ sliderValue: 1, displayValue: "A" },
{ sliderValue: 2, displayValue: "B" },
{ sliderValue: 3, displayValue: "C" },
{ sliderValue: 4, displayValue: "D" },
{ sliderValue: 5, displayValue: "E" },
{ sliderValue: 6, displayValue: "F" },
{ sliderValue: 7, displayValue: "G" },
],
visualizationComponent: (props) => (
<EnergyRatingComponent {...props} colorScheme="ges" />
),
showValue: true,
showTooltip: false,
showTicks: false,
},
validation: z.number().min(1).max(7),
},
],
formOptions: {
defaultValues: {
dpe: 3,
ges: 4,
},
onSubmit: async ({ value }) => {
console.log("Données du formulaire soumises:", value);
try {
// Simulate API call
await new Promise(resolve => setTimeout(resolve, 1000));
// Success notification
alert("Formulaire soumis avec succès ! Vos informations ont été enregistrées.");
// Clear stored form data on success
localStorage.removeItem("real-estate-form-draft");
} catch (error) {
console.error("Erreur lors de la soumission:", error);
alert("Une erreur s'est produite. Veuillez réessayer.");
}
}
},
});
return (
<div className="min-h-screen bg-background p-6">
<div className="max-w-6xl mx-auto">
<h1 className="text-3xl font-bold text-center mb-8">Formulaire</h1>
<Card
className="bg-gradient-to-br from-chart-2 to-chart-3 border-0 shadow-2xl overflow-hidden hover:shadow-3xl transition-all duration-500 p-4"
>
<CardContent className="">
<Form className="max-w-6xl mx-auto" />
</CardContent>
</Card>
</div>
</div>
);
}
Enjoy :)
PS : Désolé je ne peux pas attacher directement mes fichiers à l'issue, il ne veut pas des .tsx !
DimitriGilbert
Metadata
Metadata
Assignees
Labels
enhancementNew feature or requestNew feature or request