wass-rct-ui
Version:
A lightweight and customizable WASS Rct UI component library for modern web applications.
849 lines (817 loc) • 129 kB
JavaScript
'use strict';
var jsxRuntime = require('react/jsx-runtime');
var React = require('react');
var dayjs = require('dayjs');
var isBetween = require('dayjs/plugin/isBetween');
var timezone = require('dayjs/plugin/timezone');
var utc = require('dayjs/plugin/utc');
var reactRouterDom = require('react-router-dom');
function _interopNamespaceDefault(e) {
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n.default = e;
return Object.freeze(n);
}
var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
const Block = React__namespace.memo(({ className = "", bgColor, children }) => {
const dynamicClasses = [className, bgColor].filter(Boolean).join(" ");
return jsxRuntime.jsx("div", { className: `block ${dynamicClasses}`.trim(), children: children });
});
const Buttons = React__namespace.memo(({ children, className }) => {
const classNames = React.useMemo(() => {
const baseClasses = ["buttons"];
if (className)
baseClasses.push(className);
return baseClasses.join(" ");
}, [className]);
return jsxRuntime.jsx("div", { className: classNames, children: children });
});
const spriteUrl = "/svg/icons.svg";
const getIconStyle = (style, color) => ({
...style,
fill: color,
cursor: "pointer",
userSelect: "none",
});
const Icon = React__namespace.memo(({ name, width = 20, height = 20, style = {}, color = "white", onClick }) => {
const computedStyle = React.useMemo(() => getIconStyle(style, color), [style, color]);
return (jsxRuntime.jsx("svg", { width: width, height: height, style: computedStyle, role: onClick ? "button" : "presentation", "aria-hidden": !onClick, onClick: onClick, children: jsxRuntime.jsx("use", { xlinkHref: `${spriteUrl}#${name}` }) }));
});
const Button = React__namespace.memo(({ keyId, label, iconAlignment = "right", iconName, iconSize = 20, iconColor = "white", colorVariant, sizeVariant, fullWidth, outlined, inverted, rounded, hovered, focused, isStatic, active, loading, disabled, dark, light, skeleton, responsive, onClick, type = "button", as: Component = "button", href, className = "", }) => {
const classNames = [
"button",
colorVariant,
sizeVariant,
fullWidth && "fullwidth",
outlined && "outlined",
inverted && "inverted",
rounded && "rounded",
hovered && "hovered",
focused && "focused",
active && "active",
loading && "loading",
disabled && "disabled",
isStatic && "static",
dark && "dark",
light && "light",
responsive && "responsive",
skeleton && "skeleton",
className,
]
.filter(Boolean)
.join(" ");
const handleClick = (event) => {
if (disabled || loading || skeleton) {
event.preventDefault();
return;
}
onClick?.(event);
};
const content = (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [iconAlignment === "right" && label, iconName && (jsxRuntime.jsx("span", { className: `icon ${sizeVariant}`, children: jsxRuntime.jsx(Icon, { name: iconName, width: iconSize, height: iconSize, color: skeleton ? "transparent" : iconColor }) })), iconAlignment === "left" && label] }));
if (Component === "a" && href) {
return (jsxRuntime.jsx("a", { className: classNames, href: href, onClick: handleClick, "aria-disabled": disabled, role: "button", children: content }, keyId));
}
if (Component === "input") {
return (jsxRuntime.jsx("input", { className: classNames, type: type, value: label, onClick: handleClick, disabled: disabled }, keyId));
}
return (jsxRuntime.jsx("button", { className: classNames, type: type, onClick: handleClick, disabled: disabled, role: "button", children: content }, keyId));
});
const Field = ({ label, sideLabel = false, rightIcon = false, leftIcon = false, isExpanded = false, isGrouped = false, isLoading = false, isAddon = false, rightButton, buttonDisabled = false, leftButton, groupAlignment = "", labelSizeVariant = "normal", iconSizeVariant = "normal", leftIconSize = 16, leftIconColor = "grey", leftIconName = "default-icon", rightIconSize = 16, rightIconColor = "grey", rightIconName = "default-icon", rightButtonColor = "link", leftButtonColor = "link", className = "", children, onLeftIconClick, onRightIconClick, }) => {
const classNames = ["field", className];
if (sideLabel)
classNames.push("horizontal");
if (isGrouped)
classNames.push("grouped");
if (isAddon)
classNames.push("addons");
if (groupAlignment)
classNames.push(groupAlignment);
const controlClassNames = ["control"];
if (!rightButton && rightIcon)
controlClassNames.push("icons-right");
if (!leftButton && leftIcon)
controlClassNames.push("icons-left");
if (isLoading)
controlClassNames.push("loading");
if (isExpanded)
controlClassNames.push("expanded");
const labelClassNames = ["label", labelSizeVariant, isAddon ? "pr-3" : ""];
return (jsxRuntime.jsxs("div", { className: classNames.join(" "), children: [sideLabel ? (jsxRuntime.jsx("div", { className: "field-label", children: jsxRuntime.jsx("label", { className: labelClassNames.join(" "), children: label }) })) : (jsxRuntime.jsx("label", { className: labelClassNames.join(" "), children: label })), jsxRuntime.jsx("div", { className: sideLabel ? "field-body" : "field-width", children: jsxRuntime.jsxs("div", { className: `field ${leftButton || rightButton ? "addons" : ""}`, children: [leftButton && (jsxRuntime.jsx("div", { className: controlClassNames.join(" "), children: jsxRuntime.jsx(Button, { colorVariant: leftButtonColor, iconName: leftIconName, disabled: buttonDisabled, iconColor: leftIconColor, iconSize: leftIconSize, onClick: onLeftIconClick }) })), jsxRuntime.jsxs("div", { className: controlClassNames.join(" "), children: [leftIcon && !leftButton && (jsxRuntime.jsx("span", { className: `icon ${iconSizeVariant} left`, children: jsxRuntime.jsx(Icon, { name: leftIconName, color: leftIconColor, height: leftIconSize, width: leftIconSize, onClick: onLeftIconClick }) })), children, rightIcon && !rightButton && (jsxRuntime.jsx("span", { className: `icon ${iconSizeVariant} right`, onClick: onRightIconClick, children: jsxRuntime.jsx(Icon, { name: rightIconName, color: rightIconColor, height: rightIconSize, width: rightIconSize, onClick: onRightIconClick }) }))] }), rightButton && (jsxRuntime.jsx("div", { className: controlClassNames.join(" "), children: jsxRuntime.jsx(Button, { colorVariant: rightButtonColor, iconName: rightIconName, disabled: buttonDisabled, iconColor: rightIconColor, iconSize: rightIconSize, onClick: onRightIconClick }) }))] }) })] }));
};
const InputFactory = React.memo((props) => {
const { colorVariant, sizeVariant, isReadonly, fixedSize, rows, disabled, id, type, name, placeholder, value, defaultValue, options = [], checked, required, minLength, maxLength, pattern, accept, multiple, step, readOnly, onChange, onBlur, onKeyDown, onKeyUp, onFocus, onClick, } = props;
let className = "";
if (type === "text" ||
type === "color" ||
type === "password" ||
type === "number" ||
type === "tel")
className = "input";
if (type === "textarea")
className = "textarea";
const classNames = [
className,
colorVariant,
sizeVariant,
isReadonly,
fixedSize,
]
.filter(Boolean)
.join(" ");
const commonProps = {
className: classNames,
rows,
disabled,
id,
name,
placeholder,
value,
defaultValue,
required,
readOnly,
minLength,
maxLength,
pattern,
accept,
multiple,
step,
onChange,
onBlur,
onKeyDown,
onKeyUp,
onFocus,
onClick,
};
switch (type) {
case "text":
case "password":
case "color":
case "number":
case "tel":
return jsxRuntime.jsx("input", { type: type, ...commonProps });
case "textarea":
return jsxRuntime.jsx("textarea", { ...commonProps });
case "select":
return (jsxRuntime.jsx("div", { className: "select", children: jsxRuntime.jsx("select", { ...commonProps, children: options.map((option) => (jsxRuntime.jsx("option", { value: option.value, children: option.label }, option.value))) }) }));
case "checkbox":
return (jsxRuntime.jsxs("label", { className: "checkbox", children: [jsxRuntime.jsx("input", { type: "checkbox", checked: checked, ...commonProps }), props.label] }));
case "radio":
return (jsxRuntime.jsx("div", { children: options.map((option) => (jsxRuntime.jsxs("label", { className: "radio", children: [jsxRuntime.jsx("input", { type: "radio", checked: value === option.value, ...commonProps }), option.label] }, option.value))) }));
default:
return null;
}
});
const FormInput = React.memo((props) => {
const { fieldProps = {}, validationMessage } = props;
return (jsxRuntime.jsxs(Field, { ...fieldProps, children: [jsxRuntime.jsx(InputFactory, { ...props }), validationMessage && (jsxRuntime.jsx("p", { className: "help text-danger", children: validationMessage }))] }));
});
const GridBox = React.memo(({ minCol = 4, gap = 0, columnGap = 0, rowGap = 0, mobileCols, tabletCols, desktopCols, widescreenCols, fullhdCols, allDeviceCols, autoCount = false, fixedGrid = false, className, children, }) => {
const gridClasses = React.useMemo(() => {
const classes = ["grid"];
classes.push(`col-min-${Math.min(Math.max(minCol, 1), 32)}`);
if (gap > 0)
classes.push(`gap-${Math.min(Math.max(gap, 0), 8)}`);
if (columnGap > 0)
classes.push(`column-gap-${Math.min(Math.max(columnGap, 0), 8)}`);
if (rowGap > 0)
classes.push(`row-gap-${Math.min(Math.max(rowGap, 0), 8)}`);
if (className)
classes.push(className);
return classes.join(" ");
}, [minCol, gap, columnGap, rowGap, className]);
const fixedGridClasses = React.useMemo(() => {
const classes = ["fixed-grid"];
if (mobileCols)
classes.push(`cols-${mobileCols}-mobile`);
if (tabletCols)
classes.push(`cols-${tabletCols}-tablet`);
if (desktopCols)
classes.push(`cols-${desktopCols}-desktop`);
if (widescreenCols)
classes.push(`cols-${widescreenCols}-widescreen`);
if (fullhdCols)
classes.push(`cols-${fullhdCols}-fullhd`);
if (allDeviceCols)
classes.push(`cols-${allDeviceCols}`);
if (autoCount)
classes.push("auto-count");
if (className)
classes.push(className);
return classes.join(" ");
}, [
mobileCols,
tabletCols,
desktopCols,
widescreenCols,
fullhdCols,
allDeviceCols,
autoCount,
className,
]);
return fixedGrid ? (jsxRuntime.jsx("div", { className: fixedGridClasses, children: jsxRuntime.jsx("div", { className: gridClasses, children: children }) })) : (jsxRuntime.jsx("div", { className: gridClasses, children: children }));
});
const GridBoxCell = React.memo(({ className, children, colStart, colFromEnd, colSpan, rowStart, rowFromEnd, rowSpan, }) => {
const gridCellClasses = React.useMemo(() => {
const classes = ["cell"];
if (colStart)
classes.push(`col-start-${colStart}`);
if (colFromEnd)
classes.push(`col-from-end-${colFromEnd}`);
if (colSpan)
classes.push(`col-span-${colSpan}`);
if (rowStart)
classes.push(`row-start-${rowStart}`);
if (rowFromEnd)
classes.push(`row-from-end-${rowFromEnd}`);
if (rowSpan)
classes.push(`row-span-${rowSpan}`);
if (className)
classes.push(className);
return classes.join(" ");
}, [
colStart,
colFromEnd,
colSpan,
rowStart,
rowFromEnd,
rowSpan,
className,
]);
return jsxRuntime.jsx("div", { className: gridCellClasses, children: children });
});
const SubTitle = React.memo(({ sizeLevel, skeleton = false, colorVariant = "text-black", children, className }) => {
const Tag = `h${sizeLevel}`;
const classNames = [
`subtitle s-${sizeLevel}`,
skeleton && "skeleton",
colorVariant,
className
]
.filter(Boolean)
.join(" ");
return jsxRuntime.jsx(Tag, { className: classNames, children: children });
});
const getPositionStyles = (position) => {
const positions = {
"bottom-right": { bottom: "20px", right: "20px" },
"bottom-left": { bottom: "20px", left: "20px" },
"top-right": { top: "20px", right: "20px" },
"top-left": { top: "20px", left: "20px" },
"top-center": { top: "20px", left: "50%", transform: "translateX(-50%)" },
"middle-left": { top: "50%", left: "20px", transform: "translateY(-50%)" },
"middle-right": {
top: "50%",
right: "20px",
transform: "translateY(-50%)",
},
"bottom-center": {
bottom: "20px",
left: "50%",
transform: "translateX(-50%)",
},
};
return positions[position] || positions["bottom-right"];
};
const getChatBoxPosition = (position) => {
const positions = {
"bottom-right": { bottom: "60px", right: "20px" },
"bottom-left": { bottom: "60px", left: "20px" },
"top-right": { top: "60px", right: "20px" },
"top-left": { top: "60px", left: "20px" },
"top-center": { top: "60px", left: "50%", transform: "translateX(-50%)" },
"middle-left": { top: "50%", left: "20px", transform: "translateY(-50%)" },
"middle-right": {
top: "50%",
right: "20px",
transform: "translateY(-50%)",
},
"bottom-center": {
bottom: "60px",
left: "50%",
transform: "translateX(-50%)",
},
};
return positions[position] || positions["bottom-right"];
};
const ChatBot = React.forwardRef(({ position = "bottom-right", iconName = "solid-message-rounded", iconColor = "white", iconSize = 30, buttonColor = "link", chatTheme = "background-link", defaultMessages = [], chatBotTitle = "Chat Assistant", welcomeMessage = "👋 Hi! I'm your chat assistant. How can I help you today?", botResponses = {}, placeholderText = "Type a message...", quickReplies = [], onAskQuestion, }, ref) => {
const [isOpen, setIsOpen] = React.useState(false);
const [messages, setMessages] = React.useState(defaultMessages);
const [inputValue, setInputValue] = React.useState("");
const [showTypingIndicator, setShowTypingIndicator] = React.useState(false);
const messagesContainerRef = React.useRef(null);
React.useEffect(() => {
if (isOpen && messages.length === 0) {
setTimeout(() => {
addMessage(welcomeMessage, "bot");
}, 1000);
}
}, [isOpen]);
const addMessage = (text, sender) => {
setMessages((prevMessages) => [...prevMessages, { text, sender }]);
scrollToBottom();
};
const getBotResponse = (message) => {
return botResponses[message];
};
const handleSendMessage = () => {
if (!inputValue.trim())
return;
onAskQuestion?.(inputValue);
addMessage(inputValue, "user");
setInputValue("");
setShowTypingIndicator(true);
setTimeout(() => {
setShowTypingIndicator(false);
addMessage(getBotResponse(inputValue), "bot");
}, 1500);
};
const handleQuickReply = (text) => {
addMessage(text, "user");
setShowTypingIndicator(true);
setTimeout(() => {
setShowTypingIndicator(false);
const botReply = getBotResponse(text);
addMessage(botReply, "bot");
}, 1500);
};
const scrollToBottom = () => {
if (messagesContainerRef.current) {
setTimeout(() => {
messagesContainerRef.current.scrollTop =
messagesContainerRef.current.scrollHeight - 20;
}, 100);
}
};
React.useImperativeHandle(ref, () => ({
addNewMessage: (message, sender = "bot") => {
addMessage(message, sender);
},
}));
return (jsxRuntime.jsxs("div", { className: "chat-widget", style: getPositionStyles(position), children: [jsxRuntime.jsxs("div", { className: `chat-toggle ${chatTheme}`, onClick: () => setIsOpen(!isOpen), children: [jsxRuntime.jsx("span", { className: "notification-badge", children: "1" }), jsxRuntime.jsx(Icon, { name: iconName, height: iconSize, width: iconSize, color: iconColor })] }), jsxRuntime.jsxs("div", { className: `chat-box ${isOpen ? "active" : ""}`, style: getChatBoxPosition(position), children: [jsxRuntime.jsxs(GridBox, { fixedGrid: true, minCol: 2, className: `p-1 mb-0 ${chatTheme}`, children: [jsxRuntime.jsx(GridBoxCell, { colSpan: 1, children: jsxRuntime.jsx(SubTitle, { sizeLevel: 6, colorVariant: "text-white", children: chatBotTitle }) }), jsxRuntime.jsx(GridBoxCell, { colSpan: 1, className: "icons-controll", children: jsxRuntime.jsxs(Buttons, { children: [jsxRuntime.jsx(Button, { colorVariant: "black", iconName: "minus", sizeVariant: "small", iconColor: "white", iconSize: 16, onClick: () => setIsOpen(false) }), jsxRuntime.jsx(Button, { colorVariant: "black", iconName: "x", sizeVariant: "small", iconColor: "white", iconSize: 16, onClick: () => setIsOpen(false) })] }) })] }), jsxRuntime.jsxs("div", { className: "chat-messages", ref: messagesContainerRef, children: [messages.map((message, index) => (jsxRuntime.jsxs("div", { className: `message ${message.sender}-message`, children: [message.text, jsxRuntime.jsx("span", { className: "message-time", children: new Date().toLocaleTimeString() }), message.sender === "user" && (jsxRuntime.jsx("div", { className: "message-status", children: "\u2713\u2713" }))] }, index))), showTypingIndicator && (jsxRuntime.jsxs("div", { className: "typing-indicator background-link", children: [jsxRuntime.jsx("span", {}), jsxRuntime.jsx("span", {}), jsxRuntime.jsx("span", {})] }))] }), jsxRuntime.jsx(Buttons, { className: "mb-0 p-2", children: quickReplies.map((reply, index) => (jsxRuntime.jsx(Button, { rounded: true, sizeVariant: "small", label: reply, onClick: () => handleQuickReply(reply) }, index))) }), jsxRuntime.jsxs(GridBox, { fixedGrid: true, allDeviceCols: 4, className: "p-1 mb-0", children: [jsxRuntime.jsx(GridBoxCell, { colSpan: 3, children: jsxRuntime.jsx(FormInput, { type: "text", name: "chat-input", id: "chat-input", value: inputValue, placeholder: placeholderText, onChange: (e) => setInputValue(e.target.value) }) }), jsxRuntime.jsx(GridBoxCell, { colSpan: 1, className: "pt-2", children: jsxRuntime.jsx(Buttons, { children: jsxRuntime.jsx(Button, { colorVariant: buttonColor, label: "Send", onClick: handleSendMessage }) }) })] })] })] }));
});
const Collapsible = ({ title, children, isOpen, onToggle, bodyBGColor = "background-danger", headerBGColor = "background-success", titleColor = "text-black", iconColor = "#000", iconSize = 16, padding = 2, }) => {
return (jsxRuntime.jsxs("div", { className: "card mb-3", children: [jsxRuntime.jsxs("header", { className: `card-header ${headerBGColor}`, onClick: onToggle, children: [jsxRuntime.jsx("p", { className: `card-header-title ${titleColor} p-${padding}`, children: title }), jsxRuntime.jsx("button", { className: "card-header-icon", "aria-label": "more options", children: jsxRuntime.jsx("span", { className: "icon", children: jsxRuntime.jsx(Icon, { name: isOpen ? "solid-up-arrow" : "solid-down-arrow", color: iconColor, width: iconSize, height: iconSize }) }) })] }), isOpen && (jsxRuntime.jsx("div", { className: `card-footer p-${padding} ${bodyBGColor}`, children: children }))] }));
};
const CollapsibleGroup = ({ iconColor = "#000", iconSize = 16, padding = 2, className = "", items, }) => {
const [openIndex, setOpenIndex] = React.useState(null);
const handleToggle = React.useCallback((index) => {
setOpenIndex((prevIndex) => (prevIndex === index ? null : index));
}, []);
const collapsibles = React.useMemo(() => items.map((item, index) => (jsxRuntime.jsx(Collapsible, { title: item.title, isOpen: openIndex === index, onToggle: () => handleToggle(index), iconColor: iconColor, padding: padding, iconSize: iconSize, bodyBGColor: item.bodyBGColor, headerBGColor: item.headerBGColor, titleColor: item.titleColor, children: item.content }, index))), [items, openIndex, iconColor, padding, iconSize, handleToggle]);
const classNames = [];
if (className)
classNames.push(className);
return jsxRuntime.jsx("div", { className: classNames.join(" "), children: collapsibles });
};
const Column = React.memo(({ size, offset, isNarrow, isNarrowMobile, isNarrowTablet, isNarrowTouch, isNarrowDesktop, isNarrowWidescreen, isNarrowFullhd, children, clasName, }) => {
const columnClassNames = [
"column",
size ? size : "",
offset ? offset : "",
isNarrow ? "narrow" : "",
isNarrowMobile ? "narrow-mobile" : "",
isNarrowTablet ? "narrow-tablet" : "",
isNarrowTouch ? "narrow-touch" : "",
isNarrowDesktop ? "narrow-desktop" : "",
isNarrowWidescreen ? "narrow-widescreen" : "",
isNarrowFullhd ? "narrow-fullhd" : "",
clasName,
]
.filter(Boolean)
.join(" ");
return jsxRuntime.jsx("div", { className: columnClassNames, children: children });
});
const Columns = React.memo(({ isMobile, isTablet, isTouch, isDesktop, isWidescreen, isFullhd, isGapLess, isMultiLine, isCentered, isVCentered, children, className, }) => {
const columnsClassNames = [
"columns",
isCentered ? "centered" : "",
isVCentered ? "vcentered" : "",
isGapLess ? "gapless" : "",
isMultiLine ? "multiline" : "",
isMobile ? "mobile" : "",
isTablet ? "tablet" : "",
isTouch ? "touch" : "",
isDesktop ? "desktop" : "",
isWidescreen ? "widescreen" : "",
isFullhd ? "fullhd" : "",
className || "",
]
.filter(Boolean)
.join(" ");
return jsxRuntime.jsx("div", { className: columnsClassNames, children: children });
});
const Container = React.memo(({ containerVariant, className = "", children }) => {
const classNames = ["container"];
if (containerVariant)
classNames.push(containerVariant);
if (className)
classNames.push(className);
return jsxRuntime.jsx("section", { className: classNames.join(" "), children: children });
});
const Content = React.memo(({ sizeVariant, className = "", children }) => {
const classNames = ["content"];
if (sizeVariant)
classNames.push(sizeVariant);
if (className)
classNames.push(className);
return jsxRuntime.jsx("section", { className: classNames.join(" "), children: children });
});
// Extend dayjs with plugins
dayjs.extend(utc);
dayjs.extend(timezone);
dayjs.extend(isBetween);
const DatePicker = React.memo(({ value = "", onChange = () => { }, timeZone = "Asia/Kolkata", pickerType = "date", placeholder = "Pick Date", minDate, maxDate, dateRange = false, colorVariant = "link", }) => {
const now = dayjs().tz(timeZone);
const datePickerRef = React.useRef(null);
const [selectedDate, setSelectedDate] = React.useState(value || "");
const [showCalendar, setShowCalendar] = React.useState(false);
const [showMonthPicker, setShowMonthPicker] = React.useState(false);
const [showYearPicker, setShowYearPicker] = React.useState(false);
const [currentMonth, setCurrentMonth] = React.useState(now.month());
const [currentYear, setCurrentYear] = React.useState(now.year());
const [startYear, setStartYear] = React.useState(Math.floor(now.year() / 12) * 12);
const [rangeStart, setRangeStart] = React.useState(null);
const [rangeEnd, setRangeEnd] = React.useState(null);
const prevYearRange = () => setStartYear(startYear - 12);
const nextYearRange = () => setStartYear(startYear + 12);
const firstDayOfMonth = (month, year) => dayjs(new Date(year, month)).startOf("month").day();
const parseDateString = (dateString) => {
const [day, month, year] = dateString.split("/").map(Number);
return dayjs(new Date(year, month - 1, day)).tz(timeZone);
};
const [validMinDate, setValidMinDate] = React.useState(minDate ? parseDateString(minDate) : null);
const [validMaxDate, setValidMaxDate] = React.useState(maxDate ? parseDateString(maxDate) : null);
React.useEffect(() => {
if (value) {
if (dateRange && value.includes(" - ")) {
const [startDateStr, endDateStr] = value.split(" - ");
const startDate = parseDateString(startDateStr);
const endDate = parseDateString(endDateStr);
setRangeStart(startDate);
setRangeEnd(endDate);
setSelectedDate(`${startDate.format("DD/MM/YYYY")} - ${endDate.format("DD/MM/YYYY")}`);
}
else {
const date = parseDateString(value);
setSelectedDate(date.format("DD/MM/YYYY"));
if (dateRange) {
setRangeStart(date);
setRangeEnd(null);
}
}
}
else {
setSelectedDate("");
setRangeStart(null);
setRangeEnd(null);
}
}, [value, dateRange]);
React.useEffect(() => {
if (minDate) {
const minDateObj = parseDateString(minDate);
setValidMinDate(minDateObj);
}
else {
setValidMinDate(null);
}
if (maxDate) {
const maxDateObj = parseDateString(maxDate);
setValidMaxDate(maxDateObj);
}
else {
setValidMaxDate(null);
}
}, [minDate, maxDate]);
const handleDateClick = (day) => {
const date = dayjs(new Date(currentYear, currentMonth, day)).tz(timeZone);
if (dateRange) {
if (!rangeStart || (rangeStart && rangeEnd)) {
setRangeStart(date);
setRangeEnd(null);
}
else if (rangeStart && !rangeEnd) {
if (date.isBefore(rangeStart)) {
setRangeStart(date);
setRangeEnd(rangeStart);
}
else {
setRangeEnd(date);
}
const fromDate = rangeStart.format("DD/MM/YYYY");
const toDate = date.format("DD/MM/YYYY");
setSelectedDate(`${fromDate} - ${toDate}`);
onChange([fromDate, toDate]);
setShowCalendar(false);
setRangeStart(null);
setRangeEnd(null);
}
}
else {
const selectedDate = date.format("DD/MM/YYYY");
setSelectedDate(selectedDate);
onChange(selectedDate);
setShowCalendar(false);
}
};
const toggleCalendar = (type) => {
if (type === "date")
setShowCalendar(true);
if (type === "month")
setShowMonthPicker(true);
if (type === "year")
setShowYearPicker(true);
};
const handleMonthClick = (month) => {
setCurrentMonth(month);
setShowMonthPicker(false);
setShowCalendar(true);
if (pickerType === "month") {
const formattedMonth = dayjs(new Date(currentYear, month)).format("MM/YYYY");
setSelectedDate(formattedMonth);
onChange(formattedMonth);
}
};
const handleYearClick = (year) => {
setCurrentYear(year);
setShowYearPicker(false);
setShowMonthPicker(true);
if (pickerType === "year") {
const formattedYear = dayjs(new Date(year, currentMonth)).format("YYYY");
setSelectedDate(formattedYear);
onChange(formattedYear);
}
};
const prevMonth = () => {
const newDate = dayjs(new Date(currentYear, currentMonth)).subtract(1, "month");
setCurrentMonth(newDate.month());
setCurrentYear(newDate.year());
};
const nextMonth = () => {
const newDate = dayjs(new Date(currentYear, currentMonth)).add(1, "month");
setCurrentMonth(newDate.month());
setCurrentYear(newDate.year());
};
React.useEffect(() => {
const handleClickOutside = (event) => {
if (datePickerRef.current &&
!datePickerRef.current.contains(event.target)) {
setShowCalendar(false);
setShowMonthPicker(false);
setShowYearPicker(false);
}
};
if (showCalendar || showMonthPicker || showYearPicker) {
document.addEventListener("mousedown", handleClickOutside);
}
return () => {
document.removeEventListener("mousedown", handleClickOutside);
};
}, [showCalendar, showMonthPicker, showYearPicker]);
const isDateDisabled = (day) => {
const date = dayjs(new Date(currentYear, currentMonth, day)).tz(timeZone);
if (validMinDate && date.isBefore(validMinDate)) {
return true;
}
if (validMaxDate && date.isAfter(validMaxDate)) {
return true;
}
if (rangeStart && date.isBefore(rangeStart)) {
return true;
}
return false;
};
const isDateInRange = (day) => {
const date = dayjs(new Date(currentYear, currentMonth, day)).tz(timeZone);
if (rangeStart && rangeEnd) {
return date.isBetween(rangeStart, rangeEnd, null, "[]");
}
return false;
};
const renderDatePicker = () => {
const daysInMonth = dayjs(new Date(currentYear, currentMonth)).daysInMonth();
const firstDayOfWeek = firstDayOfMonth(currentMonth, currentYear);
const lastDayOfPrevMonth = dayjs(new Date(currentYear, currentMonth - 1)).daysInMonth();
const daysFromPrevMonth = firstDayOfWeek;
const daysFromNextMonth = 6 * 7 - (daysInMonth + daysFromPrevMonth);
return (jsxRuntime.jsx("div", { className: "fixed-grid cols-7 date-picker-calendar animate-fade-in", children: jsxRuntime.jsxs("div", { className: "grid column-gap-1 row-gap-1", children: [jsxRuntime.jsx("div", { className: "cell", children: jsxRuntime.jsx(Button, { iconName: "solid-left-arrow", iconSize: 14, iconColor: "black", sizeVariant: "small", onClick: prevMonth }, "month-next") }), jsxRuntime.jsx("div", { className: "cell col-span-5", children: jsxRuntime.jsx("span", { className: "month-year", onClick: () => setShowMonthPicker(true), children: dayjs(new Date(currentYear, currentMonth)).format("MMMM YYYY") }) }), jsxRuntime.jsx("div", { className: "cell", children: jsxRuntime.jsx(Button, { iconName: "solid-right-arrow", iconSize: 14, iconColor: "black", sizeVariant: "small", onClick: nextMonth }, "month-next") }), ["S", "M", "T", "W", "T", "F", "S"].map((d, index) => (jsxRuntime.jsx("div", { className: "cell", children: jsxRuntime.jsx("b", { children: d }) }, index))), [...Array(daysFromPrevMonth)].map((_, i) => (jsxRuntime.jsx(Button, { label: lastDayOfPrevMonth - daysFromPrevMonth + i + 1, sizeVariant: "small", disabled: true }, `prev-month-day-${i}`))), [...Array(daysInMonth)].map((_, i) => (jsxRuntime.jsx(Button, { label: i + 1, sizeVariant: "small", colorVariant: colorVariant, className: `${isDateDisabled(i + 1) ? "disabled" : ""} ${isDateInRange(i + 1) ||
(rangeStart &&
rangeStart.format("DD/MM/YYYY") ===
dayjs(new Date(currentYear, currentMonth, i + 1)).format("DD/MM/YYYY"))
? "in-range"
: ""}`, onClick: () => handleDateClick(i + 1), disabled: isDateDisabled(i + 1) }, `day-${i + 1}`))), [...Array(daysFromNextMonth)].map((_, i) => (jsxRuntime.jsx(Button, { label: i + 1, sizeVariant: "small", disabled: true }, `next-month-day-${i}`)))] }) }));
};
const renderMonthPicker = () => (jsxRuntime.jsx("div", { className: "fixed-grid cols-3 month-picker animate-fade-in", children: jsxRuntime.jsxs("div", { className: "grid column-gap-1 row-gap-1", children: [jsxRuntime.jsx("div", { className: "cell", children: "\u00A0" }), jsxRuntime.jsx("div", { className: "cell", children: jsxRuntime.jsx(Button, { label: currentYear, sizeVariant: "small", onClick: () => {
setShowMonthPicker(false);
setShowYearPicker(true);
} }, "year") }), jsxRuntime.jsx("div", { className: "cell", children: "\u00A0" }), [...Array(12)].map((_, i) => (jsxRuntime.jsx(Button, { label: dayjs(new Date(currentYear, i)).format("MMM"), sizeVariant: "small", colorVariant: colorVariant, onClick: () => handleMonthClick(i) }, `month-${i}`)))] }) }));
const renderYearPicker = () => (jsxRuntime.jsx("div", { className: "fixed-grid cols-4 year-picker animate-fade-in", children: jsxRuntime.jsxs("div", { className: "grid column-gap-1 row-gap-1", children: [jsxRuntime.jsx("div", { className: "cell", children: jsxRuntime.jsx(Button, { iconName: "solid-left-arrow", iconSize: 14, iconColor: "black", sizeVariant: "small", onClick: prevYearRange }, "year-prev") }), jsxRuntime.jsxs("div", { className: "cell col-span-2", children: [startYear, " - ", startYear + 11] }), jsxRuntime.jsx("div", { className: "cell", children: jsxRuntime.jsx(Button, { iconName: "solid-right-arrow", iconSize: 14, iconColor: "black", sizeVariant: "small", onClick: nextYearRange }, "year-next") }), [...Array(12)].map((_, i) => (jsxRuntime.jsx(Button, { label: startYear + i, sizeVariant: "small", colorVariant: colorVariant, onClick: () => handleYearClick(startYear + i) }, startYear + i)))] }) }));
return (jsxRuntime.jsxs("div", { className: "date-picker", ref: datePickerRef, children: [jsxRuntime.jsx(FormInput, { type: "text", name: "date-picker", placeholder: placeholder, readOnly: true, value: selectedDate, onClick: () => toggleCalendar(pickerType), fieldProps: {
leftIcon: true,
leftIconColor: "grey",
leftIconName: "calendar",
leftIconSize: 20,
rightIcon: true,
rightIconColor: "grey",
rightIconName: "refresh",
rightIconSize: 20,
onRightIconClick() {
setSelectedDate("");
},
} }, Date.now().toString()), pickerType === "date" &&
showCalendar &&
!showMonthPicker &&
!showYearPicker &&
renderDatePicker(), (pickerType === "date" || pickerType === "month") &&
showMonthPicker &&
renderMonthPicker(), (pickerType === "year" ||
pickerType === "month" ||
pickerType === "date") &&
showYearPicker &&
renderYearPicker()] }));
});
const Figure = React__namespace.memo(({ width = 1, height = 1, className = "", children, caption }) => {
const classNames = React.useMemo(() => {
const baseClasses = ["image", `s-${width}by${height}`];
if (className)
baseClasses.push(className);
return baseClasses.join(" ");
}, [width, height, className]);
return (jsxRuntime.jsxs("figure", { className: classNames, children: [children, caption && jsxRuntime.jsx("figcaption", { children: caption })] }));
});
const FlexContainer = ({ direction, wrap, justify, alignContent, alignItems, alignSelf, flexGrow, flexShrink, className = "", children, }) => {
const flexClasses = React.useMemo(() => [
"flex",
direction && `flex-direction-${direction}`,
wrap && `flex-wrap-${wrap}`,
justify && `justify-content-${justify}`,
alignContent && `align-content-${alignContent}`,
alignItems && `align-items-${alignItems}`,
alignSelf && `align-self-${alignSelf}`,
flexGrow !== undefined && `flex-grow-${flexGrow}`,
flexShrink !== undefined && `flex-shrink-${flexShrink}`,
className,
]
.filter(Boolean)
.join(" "), [
direction,
wrap,
justify,
alignContent,
alignItems,
alignSelf,
flexGrow,
flexShrink,
className,
]);
return jsxRuntime.jsx("div", { className: flexClasses, children: children });
};
const FlexBox = React__namespace.memo(FlexContainer);
const Footer = React.memo(({ className = "", children }) => {
return jsxRuntime.jsx("footer", { className: `footer ${className}`.trim(), children: children });
});
const Form = React.forwardRef(({ className = "", children, onSubmit, ...props }, ref) => {
return (jsxRuntime.jsx("form", { ref: ref, className: `form ${className}`.trim(), onSubmit: (event) => {
event.preventDefault();
onSubmit?.(event);
}, ...props, children: children }));
});
Form.displayName = "Form";
const MemoizedForm = React__namespace.memo(Form);
const getClassNames = ({ className, colorVariant, sizeVariant, }) => {
return ["hero", colorVariant, sizeVariant, className]
.filter(Boolean)
.join(" ");
};
const Hero = React__namespace.memo(({ className = "", colorVariant, sizeVariant, children }) => {
const classNames = React.useMemo(() => getClassNames({ className, colorVariant, sizeVariant }), [className, colorVariant, sizeVariant]);
return (jsxRuntime.jsx("section", { className: classNames, children: jsxRuntime.jsx("div", { className: "hero-body", children: children }) }));
});
const ImageViewer = ({ isOpen, onClose, imageUrl, altText, }) => {
if (!isOpen)
return null;
return (jsxRuntime.jsxs("div", { className: "modal active", children: [jsxRuntime.jsx("div", { className: "modal-background", onClick: onClose }), jsxRuntime.jsx("div", { className: "modal-content", children: jsxRuntime.jsx("p", { className: "image", children: jsxRuntime.jsx("img", { src: imageUrl ||
"https://bulma.io/assets/images/placeholders/1280x960.png", alt: altText || "Placeholder" }) }) }), jsxRuntime.jsx("button", { className: "modal-close large", "aria-label": "close", onClick: onClose })] }));
};
const Media = React.memo(({ className = "", mediaLeft, mediaRight, mediaContent }) => {
const mediaClass = `media ${className}`.trim();
return (jsxRuntime.jsxs("section", { className: mediaClass, children: [mediaLeft && jsxRuntime.jsx("div", { className: "media-left", children: mediaLeft }), jsxRuntime.jsx("div", { className: "media-content", children: mediaContent }), mediaRight && jsxRuntime.jsx("div", { className: "media-right", children: mediaRight })] }));
});
const Navbar = ({ logo, leftLinks, rightLinks, logoWidth = 120, logoHeight = 40, navColor, isSideBarEnabled, sideBarIcon = "menu-alt-left", sideBarIconColor = "white", sideBarIconSize = 32, toggleSidebar, className, }) => {
const [isActive, setIsActive] = React.useState(false);
const [activeDropdown, setActiveDropdown] = React.useState(null);
const [isTouchDevice, setIsTouchDevice] = React.useState(false);
const [isScreenLarge, setIsScreenLarge] = React.useState(window.innerWidth > 1028);
React.useEffect(() => {
const handleResize = () => {
setIsScreenLarge(window.innerWidth > 1028);
};
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);
React.useEffect(() => {
setIsTouchDevice("ontouchstart" in window || navigator.maxTouchPoints > 0);
}, []);
const toggleMenu = () => setIsActive((prev) => !prev);
const handleDropdownClick = (index) => setActiveDropdown((prev) => (prev === index ? null : index));
const closeDropdown = () => {
setActiveDropdown(null);
setIsActive(false);
};
return (jsxRuntime.jsxs("nav", { className: `navbar ${className} ${navColor || ""}`.trim(), children: [jsxRuntime.jsxs("div", { className: "navbar-brand", children: [isSideBarEnabled && !isScreenLarge && (jsxRuntime.jsx(Icon, { style: { paddingLeft: "0.5em" }, name: sideBarIcon, color: sideBarIconColor, height: sideBarIconSize, width: sideBarIconSize, onClick: () => toggleSidebar(!isSideBarEnabled) })), logo && (jsxRuntime.jsx(reactRouterDom.Link, { className: "navbar-item", to: "/", children: jsxRuntime.jsx("img", { src: logo, alt: "Logo", width: logoWidth, height: logoHeight }) })), jsxRuntime.jsxs("button", { className: `navbar-burger ${isActive ? "active" : ""}`, onClick: toggleMenu, children: [jsxRuntime.jsx("span", {}), jsxRuntime.jsx("span", {}), jsxRuntime.jsx("span", {}), jsxRuntime.jsx("span", {})] })] }), jsxRuntime.jsxs("div", { className: `navbar-menu ${isActive ? "active" : ""}`, children: [jsxRuntime.jsx("div", { className: "navbar-start", children: leftLinks.map((link, index) => link.type === "dropdown" && link.dropdownList ? (jsxRuntime.jsxs("div", { className: `navbar-item dropdown ${activeDropdown === index ? "active" : ""}`, onClick: () => handleDropdownClick(index), onMouseEnter: () => !isTouchDevice && setActiveDropdown(index), onMouseLeave: () => !isTouchDevice && setActiveDropdown(null), children: [jsxRuntime.jsx("span", { className: "navbar-link", children: link.label }), jsxRuntime.jsx("div", { className: `navbar-dropdown radius-sm ${link.dropdownRight ? "right" : ""}`, children: link.dropdownList &&
link.dropdownList.map((subLink, subIndex) => (jsxRuntime.jsx(reactRouterDom.Link, { className: "navbar-item", to: subLink.link, onClick: closeDropdown, children: subLink.label }, subIndex))) })] }, index)) : (jsxRuntime.jsx(reactRouterDom.Link, { className: `navbar-item ${link.className}`, to: link.link, onClick: closeDropdown, children: link.label }, index))) }), rightLinks && (jsxRuntime.jsx("div", { className: "navbar-end", children: jsxRuntime.jsx("div", { className: "navbar-item", children: jsxRuntime.jsx("div", { className: "buttons", children: rightLinks.map((link, index) => link.type === "dropdown" && link.dropdownList ? (jsxRuntime.jsxs("div", { className: `navbar-item dropdown ${activeDropdown === index ? "active" : ""}`, onClick: () => handleDropdownClick(index), onMouseEnter: () => !isTouchDevice && setActiveDropdown(index), onMouseLeave: () => !isTouchDevice && setActiveDropdown(null), children: [jsxRuntime.jsx("span", { className: "navbar-link", children: link.label }), jsxRuntime.jsx("div", { className: `navbar-dropdown radius-sm ${link.dropdownRight ? "right" : ""}`, children: link.dropdownList.map((subLink, subIndex) => (jsxRuntime.jsx(reactRouterDom.Link, { className: "navbar-item", to: subLink.link, onClick: closeDropdown, children: subLink.label }, subIndex))) })] }, index)) : link.type === "icon-button" ? (jsxRuntime.jsx(reactRouterDom.Link, { className: `button ${link.className} ${link.colorVariant}`, to: link.link, onClick: closeDropdown, children: link.iconName && (jsxRuntime.jsx(Icon, { name: link.iconName, color: link.iconColor, height: link.iconSize, width: link.iconSize })) }, index)) : link.type === "icon" ? (jsxRuntime.jsx(reactRouterDom.Link, { to: link.link, children: link.iconName && (jsxRuntime.jsx(Icon, { name: link.iconName, color: link.iconColor, height: link.iconSize, width: link.iconSize })) }, index)) : link.type === "button" ? (jsxRuntime.jsx(reactRouterDom.Link, { className: `button ${link.className} ${link.colorVariant}`, to: link.link, onClick: closeDropdown, children: jsxRuntime.jsx("strong", { children: link.label }) }, index)) : (jsxRuntime.jsx(reactRouterDom.Link, { className: `navbar-item ${link.className}`, to: link.link, onClick: closeDropdown, children: link.label }, index))) }) }) }))] })] }));
};
const Card = React.memo(({ header, children, footer, className = "", skeleton = false, bgColorVariant = "background-white", }) => {
const classNames = React.useMemo(() => {
const baseClasses = ["card", "rounded-sm", "overflow-hidden"];
if (skeleton)
baseClasses.push("skeleton");
if (!skeleton && bgColorVariant)
baseClasses.push(bgColorVariant);
if (className)
baseClasses.push(className);
return baseClasses.join(" ");
}, [bgColorVariant, className, skeleton]);
return (jsxRuntime.jsxs("section", { className: classNames, role: "region", "aria-label": "Card", children: [header && (jsxRuntime.jsx("header", { className: "card-header p-4", role: "heading", children: header })), jsxRuntime.jsx("main", { className: "card-content p-4", role: "main", children: jsxRuntime.jsx("div", { className: "content", children: children }) }), footer && (jsxRuntime.jsx("footer", { className: "card-footer p-4", role: "contentinfo", children: footer }))] }));
});
const NoData = React.memo(({ className = "", title = "No Data", paddingLevel = 4 }) => {
const classNames = ["no-data", "text-centered", className]
.filter(Boolean)
.join(" ");
return (jsxRuntime.jsx("section", { className: classNames, role: "alert", "aria-live": "polite", children: jsxRuntime.jsx(Card, { children: jsxRuntime.jsx(SubTitle, { sizeLevel: 6, children: jsxRuntime.jsx("p", { className: `p-${paddingLevel}`, children: title }) }) }) }));
});
const areEqual = (prevProps, nextProps) => {
return (prevProps.rows === nextProps.rows &&
prevProps.viewMode === nextProps.viewMode &&
prevProps.min === nextProps.min &&
prevProps.max === nextProps.max &&
prevProps.onCellClick === nextProps.onCellClick);
};
const OddsTableTable = React.memo(({ rows: initialRows, onCellClick, viewMode = "standard", tableHeader = "Odds", headerBGColor = "background-warning", headerTextColor = "text-black", min, max, }) => {
const [rows, setRows] = React.useState(initialRows);
const [changedCells, setChangedCells] = React.useState({});
const prevRows = React.useRef(initialRows);
const handleCellClick = React.useCallback((rowId, cellType, teamId, odds, size) => {
if (onCellClick) {
onCellClick(rowId, cellType, teamId, odds, size);
}
}, [onCellClick]);
const renderMinMaxLabel = React.useCallback(() => {
if (min !== undefined && max !== undefined) {
return `Min / Max: ${min} / ${max}`;
}
return null;
}, [min, max]);
React.useEffect(() => {
const newChangedCells = {};
initialRows.forEach((row, rowIndex) => {
const prevRow = prevRows.current[rowIndex];
if (!prevRow)
return;
if (row.suspended)
return;
row.backOdds.forEach((oddItem, oddIndex) => {
const prevOddItem = prevRow.backOdds[oddIndex];
if (!prevOddItem)
return;
if (oddItem.odd !== prevOddItem.odd ||
oddItem.size !== prevOddItem.size) {
const cellId = viewMode === "fancy"
? `${row.id}-back1`
: `${row.id}-back${oddIndex + 1}`;
newChangedCells[cellId] = true;
}
});
row.layOdds.forEach((oddItem, oddIndex) => {
const prevOddItem = prevRow.layOdds[oddIndex];
if (!prevOddItem)
return;
if (oddItem.odd !== prevOddItem.odd ||
oddItem.size !== prevOddItem.size) {
const cellId = viewMode === "fancy"
? `${row.id}-lay1`
: `${row.id}-lay${oddIndex + 1}`;
newChangedCells[cellId] = true;
}
});
});
setChangedCells(newChangedCells);
prevRows.current = initialRows;
setRows(initialRows);
const timeout = setTimeout(() => {
setChangedCells({});
}, 1200);
return () => clearTimeout(timeout);
}, [initialRows, viewMode]);
const renderStandardRow = React.useCallback((row) => (jsxRuntime.jsxs("tr", { className: row.suspended ? "suspended" : "", "data-suspended-message": row.suspendedMessage || "SUSPENDED", children: [jsxRuntime.jsxs("td", { className: "text-weight-bold team-name", children: [jsxRuntime.jsx("span", { className: "team-name-text", children: row.teamName }), row.profitLoss !== null && (jsxRuntime.jsx("span", { className: `text-weight-bold profit-loss ${row.profitLoss >= 0 ? "profit" : "loss"}`, children: row.profitLoss >= 0 ? `+${row.profitLoss}` : row.profitLoss }))] }), row.backOdds.map((oddsItem, index) => {
const cellId = `${row.id}-back${index + 1}`;
return (jsxRuntime.jsx("td", { className: `text-centered back back-${index + 1} ${changedCells[cellId] ? "changed" : ""} ${row.suspended ? "suspended-cell" : ""}`, id: cellId, onClick: !row.suspended && onCellClick