diff --git a/AppUi/src/components/common/Buttons/ButtonComponent.jsx b/AppUi/src/components/common/Buttons/ButtonComponent.jsx
index 9dc326e..5cd931e 100644
--- a/AppUi/src/components/common/Buttons/ButtonComponent.jsx
+++ b/AppUi/src/components/common/Buttons/ButtonComponent.jsx
@@ -1,115 +1,125 @@
-import * as React from "react"
-import { Slot } from "@radix-ui/react-slot"
-import { cva } from "class-variance-authority"
-import { Loader2 } from "lucide-react"
-import PropTypes from "prop-types"
+import * as React from "react";
+import { Slot } from "@radix-ui/react-slot";
+import { cva } from "class-variance-authority";
+import { Loader2 } from "lucide-react";
+import PropTypes from "prop-types";
-import { cn } from "../../../utils/utils"
+import { cn } from "../../../utils/utils";
const buttonVariants = cva(
- "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-lg text-sm font-bold tracking-wide uppercase ring-offset-background transition-all duration-300 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 relative overflow-hidden",
- {
- variants: {
- variant: {
- primary:
- "bg-gradient-primary text-primary-foreground hover:shadow-glow-primary hover:scale-105 active:scale-95 border border-primary/20",
- secondary:
- "bg-gradient-secondary text-secondary-foreground hover:shadow-glow-secondary hover:scale-105 active:scale-95 border border-secondary/20",
- danger:
- "bg-gradient-danger text-destructive-foreground hover:shadow-glow-danger hover:scale-105 active:scale-95 border border-destructive/20",
- success:
- "bg-gradient-success text-primary-foreground hover:shadow-[0_0_20px_hsl(var(--game-success)/0.5)] hover:scale-105 active:scale-95 border border-game-success/20",
- outline:
- "border-2 border-primary bg-transparent text-primary hover:bg-primary hover:text-primary-foreground hover:shadow-glow-primary hover:scale-105 active:scale-95",
- ghost:
- "hover:bg-accent hover:text-accent-foreground hover:scale-105 active:scale-95",
- disabled:
- "bg-game-disabled text-muted-foreground cursor-not-allowed opacity-60",
- link:
- "text-primary underline-offset-4 hover:underline hover:text-primary/80",
- },
- size: {
- default: "h-12 px-6 py-3 text-sm",
- sm: "h-9 rounded-md px-4 text-xs",
- lg: "h-14 rounded-xl px-8 text-base",
- icon: "h-12 w-12",
- },
- },
- defaultVariants: {
- variant: "primary",
- size: "default",
- },
- }
-)
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-lg text-sm font-bold tracking-wide uppercase ring-offset-background transition-all duration-300 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 relative overflow-hidden",
+ {
+ variants: {
+ variant: {
+ primary:
+ "bg-gradient-primary text-primary-foreground hover:shadow-glow-primary hover:scale-105 active:scale-95 border border-primary/20",
+ secondary:
+ "bg-gradient-secondary text-secondary-foreground hover:shadow-glow-secondary hover:scale-105 active:scale-95 border border-secondary/20",
+ danger: "bg-gradient-danger text-destructive-foreground hover:shadow-glow-danger hover:scale-105 active:scale-95 border border-destructive/20",
+ success:
+ "bg-gradient-success text-primary-foreground hover:shadow-[0_0_20px_hsl(var(--game-success)/0.5)] hover:scale-105 active:scale-95 border border-game-success/20",
+ outline:
+ "border-2 border-primary bg-transparent text-primary hover:bg-primary hover:text-primary-foreground hover:shadow-glow-primary hover:scale-105 active:scale-95",
+ ghost: "hover:bg-accent hover:text-accent-foreground hover:scale-105 active:scale-95",
+ disabled:
+ "bg-game-disabled text-muted-foreground cursor-not-allowed opacity-60",
+ link: "text-primary underline-offset-4 hover:underline hover:text-primary/80",
+ },
+ size: {
+ default: "h-12 px-6 py-3 text-sm",
+ sm: "h-9 rounded-md px-4 text-xs",
+ lg: "h-14 rounded-xl px-8 text-base",
+ icon: "h-12 w-12",
+ },
+ },
+ defaultVariants: {
+ variant: "primary",
+ size: "default",
+ },
+ }
+);
const Button = React.forwardRef(
- ({ className, variant, size, asChild = false, isLoading = false, disabled, children, ...props }, ref) => {
- const Comp = asChild ? Slot : "button"
- const isDisabled = disabled || isLoading || variant === "disabled"
-
- // Only pass disabled prop to button elements, not to other elements when using asChild
- const componentProps = {
- className: cn(
- buttonVariants({
- variant: isDisabled ? "disabled" : variant,
- size,
- className
- }),
- isLoading && "animate-pulse-glow"
- ),
- ref,
- ...props
- }
-
- // Only add disabled prop for button elements
- if (!asChild) {
- componentProps.disabled = isDisabled
- }
-
- if (asChild) {
- // For asChild, we need to clone the child and merge props
- return (
-
- {React.cloneElement(children, {
- className: cn(children.props.className, componentProps.className)
- })}
-
- )
+ (
+ {
+ className,
+ variant,
+ size,
+ asChild = false,
+ isLoading = false,
+ disabled,
+ children,
+ ...props
+ },
+ ref
+ ) => {
+ const Comp = asChild ? Slot : "button";
+ const isDisabled = disabled || isLoading || variant === "disabled";
+
+ // Only pass disabled prop to button elements, not to other elements when using asChild
+ const componentProps = {
+ className: cn(
+ buttonVariants({
+ variant: isDisabled ? "disabled" : variant,
+ size,
+ className,
+ }),
+ isLoading && "animate-pulse-glow"
+ ),
+ ref,
+ ...props,
+ };
+
+ // Only add disabled prop for button elements
+ if (!asChild) {
+ componentProps.disabled = isDisabled;
+ }
+
+ if (asChild) {
+ // For asChild, we need to clone the child and merge props
+ return (
+
+ {React.cloneElement(children, {
+ className: cn(
+ children.props.className,
+ componentProps.className
+ ),
+ })}
+
+ );
+ }
+
+ return (
+
+ {isLoading && }
+ {children}
+ {/* Gaming button shine effect */}
+
+
+ );
}
-
- return (
-
- {isLoading && (
-
- )}
- {children}
- {/* Gaming button shine effect */}
-
-
- )
- }
-)
+);
-Button.displayName = "Button"
+Button.displayName = "Button";
// PropTypes for runtime type checking
Button.propTypes = {
- className: PropTypes.string,
- variant: PropTypes.oneOf([
- "primary",
- "secondary",
- "danger",
- "success",
- "outline",
- "ghost",
- "disabled",
- "link"
- ]),
- size: PropTypes.oneOf(["default", "sm", "lg", "icon"]),
- asChild: PropTypes.bool,
- isLoading: PropTypes.bool,
- disabled: PropTypes.bool,
- children: PropTypes.node,
-}
+ className: PropTypes.string,
+ variant: PropTypes.oneOf([
+ "primary",
+ "secondary",
+ "danger",
+ "success",
+ "outline",
+ "ghost",
+ "disabled",
+ "link",
+ ]),
+ size: PropTypes.oneOf(["default", "sm", "lg", "icon"]),
+ asChild: PropTypes.bool,
+ isLoading: PropTypes.bool,
+ disabled: PropTypes.bool,
+ children: PropTypes.node,
+};
-export default Button
+export default Button;
diff --git a/AppUi/src/components/common/Form/FormComponents.jsx b/AppUi/src/components/common/Form/FormComponents.jsx
index d08ae37..8f1b7d4 100644
--- a/AppUi/src/components/common/Form/FormComponents.jsx
+++ b/AppUi/src/components/common/Form/FormComponents.jsx
@@ -1,302 +1,599 @@
// FormComponents.jsx
-import React, { useState, useRef, useEffect } from 'react';
-import { ChevronDown, Calendar, Upload, X, Check, Search, Eye, EyeOff, Loader2 } from 'lucide-react';
+import React, { useState, useRef, useEffect } from "react";
+import {
+ ChevronDown,
+ Calendar,
+ Upload,
+ X,
+ Check,
+ Search,
+ Eye,
+ EyeOff,
+ Loader2,
+} from "lucide-react";
import { cva } from "class-variance-authority";
import { cn } from "../../../utils/utils";
-
const inputBaseStyles =
- "light-glass-input w-full rounded-lg text-slate-800 " +
- "placeholder:text-slate-500 focus:outline-none focus:ring-2 focus:ring-orange-500 focus:border-orange-500 transition-all duration-300";
+ "light-glass-input w-full rounded-lg text-slate-800 " +
+ "placeholder:text-slate-500 focus:outline-none focus:ring-2 focus:ring-orange-500 focus:border-orange-500 transition-all duration-300";
-const labelBaseStyles = "block text-sm font-semibold text-slate-800 mb-2 text-left";
+const labelBaseStyles =
+ "block text-sm font-semibold text-slate-800 mb-2 text-left";
const requiredIndicatorStyles = "text-orange-600 ml-1";
const errorTextStyles = "text-red-600 text-xs mt-1 text-left font-semibold";
const inputVariants = cva(inputBaseStyles, {
- variants: {
- variant: {
- default: "",
- error: "border-red-500/80 text-red-900 focus:ring-red-500",
+ variants: {
+ variant: {
+ default: "",
+ error: "border-red-500/80 text-red-900 focus:ring-red-500",
+ },
+ size: {
+ default: "h-11 px-4 text-sm",
+ sm: "h-9 px-3 text-xs",
+ lg: "h-14 px-5 text-base",
+ },
},
- size: {
- default: "h-11 px-4 text-sm",
- sm: "h-9 px-3 text-xs",
- lg: "h-14 px-5 text-base",
+ defaultVariants: {
+ variant: "default",
+ size: "default",
},
- },
- defaultVariants: {
- variant: "default",
- size: "default",
- },
});
-
const Input = React.forwardRef(
- ({ label, id, name, type = 'text', value, onChange, error, required, size, placeholder, ...props }, ref) => {
- const [showPassword, setShowPassword] = useState(false);
- const inputType = type === 'password' && showPassword ? 'text' : type;
+ (
+ {
+ label,
+ id,
+ name,
+ type = "text",
+ value,
+ onChange,
+ error,
+ required,
+ size,
+ placeholder,
+ ...props
+ },
+ ref
+ ) => {
+ const [showPassword, setShowPassword] = useState(false);
+ const inputType = type === "password" && showPassword ? "text" : type;
- return (
-
- {label && (
-
- )}
-
-
- {type === 'password' && (
-
- )}
-
- {error &&
{error}
}
-
- );
- }
+ return (
+
+ {label && (
+
+ )}
+
+
+ {type === "password" && (
+
+ )}
+
+ {error &&
{error}
}
+
+ );
+ }
);
Input.displayName = "Input";
-
const SingleSelectDropdown = React.forwardRef(
- ({ label, id, name, value, onChange, options, error, required, size, placeholder = "Select an option" }, ref) => {
- const [isOpen, setIsOpen] = useState(false);
- const wrapperRef = useRef(null);
-
- const selectedOption = options.find(opt => opt.value === value);
+ (
+ {
+ label,
+ id,
+ name,
+ value,
+ onChange,
+ options,
+ error,
+ required,
+ size,
+ placeholder = "Select an option",
+ },
+ ref
+ ) => {
+ const [isOpen, setIsOpen] = useState(false);
+ const wrapperRef = useRef(null);
- useEffect(() => {
- const handleClickOutside = (event) => {
- if (wrapperRef.current && !wrapperRef.current.contains(event.target)) {
- setIsOpen(false);
- }
- };
- document.addEventListener("mousedown", handleClickOutside);
- return () => document.removeEventListener("mousedown", handleClickOutside);
- }, [wrapperRef]);
-
- const handleSelectOption = (optionValue) => {
- onChange({ target: { name, value: optionValue } });
- setIsOpen(false);
- };
+ const selectedOption = options.find((opt) => opt.value === value);
- return (
-
- {label &&
}
-
- {/* This button looks like an input and triggers the dropdown */}
-
+ useEffect(() => {
+ const handleClickOutside = (event) => {
+ if (
+ wrapperRef.current &&
+ !wrapperRef.current.contains(event.target)
+ ) {
+ setIsOpen(false);
+ }
+ };
+ document.addEventListener("mousedown", handleClickOutside);
+ return () =>
+ document.removeEventListener("mousedown", handleClickOutside);
+ }, [wrapperRef]);
- {isOpen && (
-
-
- {options.map(option => (
- - handleSelectOption(option.value)}
- className={cn("flex items-center justify-between p-2 text-sm rounded-md cursor-pointer hover:bg-muted", option.value === value && "font-semibold")}
- >
- {option.label}
- {option.value === value && }
-
- ))}
-
+ const handleSelectOption = (optionValue) => {
+ onChange({ target: { name, value: optionValue } });
+ setIsOpen(false);
+ };
+
+ return (
+
+ {label && (
+
+ )}
+
+ {/* This button looks like an input and triggers the dropdown */}
+
+
+ {isOpen && (
+
+
+ {options.map((option) => (
+ -
+ handleSelectOption(option.value)
+ }
+ className={cn(
+ "flex items-center justify-between p-2 text-sm rounded-md cursor-pointer hover:bg-muted",
+ option.value === value &&
+ "font-semibold"
+ )}
+ >
+ {option.label}
+ {option.value === value && (
+
+ )}
+
+ ))}
+
+
+ )}
+
+ {error &&
{error}
}
- )}
-
- {error &&
{error}
}
-
- );
- }
+ );
+ }
);
SingleSelectDropdown.displayName = "SingleSelectDropdown";
-
const MultiSelectDropdown = React.forwardRef(
- ({ label, id, name, selectedValues = [], onChange, options, error, required, placeholder = "Select options...", ...props }, ref) => {
- const [isOpen, setIsOpen] = useState(false);
- const wrapperRef = useRef(null);
+ (
+ {
+ label,
+ id,
+ name,
+ selectedValues = [],
+ onChange,
+ options,
+ error,
+ required,
+ placeholder = "Select options...",
+ ...props
+ },
+ ref
+ ) => {
+ const [isOpen, setIsOpen] = useState(false);
+ const wrapperRef = useRef(null);
+
+ useEffect(() => {
+ function handleClickOutside(event) {
+ if (
+ wrapperRef.current &&
+ !wrapperRef.current.contains(event.target)
+ ) {
+ setIsOpen(false);
+ }
+ }
+ document.addEventListener("mousedown", handleClickOutside);
+ return () =>
+ document.removeEventListener("mousedown", handleClickOutside);
+ }, [wrapperRef]);
+
+ const handleSelectOption = (value) => {
+ const newSelectedValues = selectedValues.includes(value)
+ ? selectedValues.filter((v) => v !== value)
+ : [...selectedValues, value];
+ onChange({ target: { name, value: newSelectedValues } });
+ };
- useEffect(() => {
- function handleClickOutside(event) {
- if (wrapperRef.current && !wrapperRef.current.contains(event.target)) {
- setIsOpen(false);
- }
- }
- document.addEventListener("mousedown", handleClickOutside);
- return () => document.removeEventListener("mousedown", handleClickOutside);
- }, [wrapperRef]);
-
- const handleSelectOption = (value) => {
- const newSelectedValues = selectedValues.includes(value)
- ? selectedValues.filter((v) => v !== value)
- : [...selectedValues, value];
- onChange({ target: { name, value: newSelectedValues } });
- };
+ const handleRemoveTag = (valueToRemove, e) => {
+ e.stopPropagation();
+ const newSelectedValues = selectedValues.filter(
+ (v) => v !== valueToRemove
+ );
+ onChange({ target: { name, value: newSelectedValues } });
+ };
- const handleRemoveTag = (valueToRemove, e) => {
- e.stopPropagation();
- const newSelectedValues = selectedValues.filter((v) => v !== valueToRemove);
- onChange({ target: { name, value: newSelectedValues } });
- };
-
- const selectedOptionsMap = options.reduce((acc, opt) => {
- if (selectedValues.includes(opt.value)) {
- acc[opt.value] = opt.label;
- }
- return acc;
- }, {});
+ const selectedOptionsMap = options.reduce((acc, opt) => {
+ if (selectedValues.includes(opt.value)) {
+ acc[opt.value] = opt.label;
+ }
+ return acc;
+ }, {});
- return (
-
- {label && (
-
- )}
-
-
setIsOpen(true)}
- >
- {selectedValues.map(value => (
-
- {selectedOptionsMap[value]}
-
-
- ))}
-
-
- {isOpen && (
-
-
- {options.map(option => (
- - handleSelectOption(option.value)}>
-
- {selectedValues.includes(option.value) &&
}
+ return (
+
+ {label && (
+
+ )}
+
+
setIsOpen(true)}
+ >
+ {selectedValues.map((value) => (
+
+ {selectedOptionsMap[value]}
+
+
+ ))}
+
-
{option.label}
-
- ))}
-
+ {isOpen && (
+
+ )}
+
+ {error &&
{error}
}
- )}
-
- {error && {error}
}
-
- );
- }
+ );
+ }
);
MultiSelectDropdown.displayName = "MultiSelectDropdown";
-
const DatePicker = React.forwardRef(
- ({ label, id, name, value, onChange, error, required, size, ...props }, ref) => (
-
- {label &&
}
-
- {error &&
{error}
}
-
- )
+ (
+ { label, id, name, value, onChange, error, required, size, ...props },
+ ref
+ ) => (
+
+ {label && (
+
+ )}
+
+ {error &&
{error}
}
+
+ )
);
DatePicker.displayName = "DatePicker";
-
const FileUpload = React.forwardRef(
- ({ label, id, name, onChange, error, required, isLoading = false, ...props }, ref) => {
- const [fileName, setFileName] = useState('');
- const handleFileChange = (e) => {
- if (e.target.files?.length) setFileName(Array.from(e.target.files).map(file => file.name).join(', '));
- else setFileName('');
- if (onChange) onChange(e);
- };
- return (
-
- {label &&
}
-
- {error &&
{error}
}
-
- );
- }
+ (
+ {
+ label,
+ id,
+ name,
+ onChange,
+ error,
+ required,
+ isLoading = false,
+ ...props
+ },
+ ref
+ ) => {
+ const [fileName, setFileName] = useState("");
+ const handleFileChange = (e) => {
+ if (e.target.files?.length)
+ setFileName(
+ Array.from(e.target.files)
+ .map((file) => file.name)
+ .join(", ")
+ );
+ else setFileName("");
+ if (onChange) onChange(e);
+ };
+ return (
+
+ {label && (
+
+ )}
+
+ {error &&
{error}
}
+
+ );
+ }
);
FileUpload.displayName = "FileUpload";
-
const RadioGroup = React.forwardRef(
- ({ label, idPrefix, name, selectedValue, onChange, options, error, required, ...props }, ref) => (
-
- )
+ (
+ {
+ label,
+ idPrefix,
+ name,
+ selectedValue,
+ onChange,
+ options,
+ error,
+ required,
+ ...props
+ },
+ ref
+ ) => (
+
+ )
);
RadioGroup.displayName = "RadioGroup";
-
const Checkbox = React.forwardRef(
- ({ label, id, name, checked, onChange, error, required, ...props }, ref) => (
-
-