Files
Rasadyar_Inspection_System/src/components/Button/Button.tsx
2026-01-26 10:14:10 +03:30

233 lines
6.3 KiB
TypeScript

import React, { ReactNode, ReactElement, ButtonHTMLAttributes } from "react";
import clsx from "clsx";
import {
ChartBarIcon,
DocumentChartBarIcon,
EyeIcon,
FolderPlusIcon,
PencilIcon,
PencilSquareIcon,
TrashIcon,
ViewfinderCircleIcon,
} from "@heroicons/react/24/outline";
import {
bgPrimaryColor,
mobileBorders,
textColorOnPrimary,
} from "../../data/getColorBasedOnMode";
import { checkIsMobile } from "../../utils/checkIsMobile";
import { inputWidths } from "../../data/getItemsWidth";
import { PlusIcon } from "@heroicons/react/24/solid";
import { useUserProfileStore } from "../../context/zustand-store/userStore";
import excel from "../../assets/images/svg/excel.svg?react";
import SVGImage from "../SvgImage/SvgImage";
import api from "../../utils/axios";
import { useBackdropStore } from "../../context/zustand-store/appStore";
import { useToast } from "../../hooks/useToast";
type ExcelProps = {
link: string;
title: string;
};
type ButtonProps = {
children?: ReactNode | string;
icon?: ReactElement;
direction?: "row" | "row-reverse" | "col" | "col-reverse";
iconColor?: string;
iconBgColor?: string;
iconSize?: number | string;
className?: string;
variant?:
| "submit"
| "secondary-submit"
| "edit"
| "secondary-edit"
| "detail"
| "delete"
| "view"
| "info"
| "chart";
access?: string;
height?: string | number;
fullWidth?: boolean;
excelInfo?: ExcelProps;
rounded?: boolean;
size?: "small" | "medium" | "large";
} & ButtonHTMLAttributes<HTMLButtonElement>;
const Button: React.FC<ButtonProps> = ({
children,
icon,
direction = "row",
iconSize,
className = "",
variant = "",
access = "",
height,
fullWidth = false,
excelInfo,
rounded = false,
size = "medium",
...props
}) => {
const directionClass = {
row: "flex-row",
"row-reverse": "flex-row-reverse",
col: "flex-col",
"col-reverse": "flex-col-reverse",
}[direction];
const sizeStyles = {
small: {
padding: "h-[32px] px-2",
text: "text-xs",
icon: iconSize ?? 14,
},
medium: {
padding: "h-[40px] px-2",
text: "text-sm",
icon: iconSize ?? 18,
},
large: {
padding: "h-[48px] px-2",
text: "text-base",
icon: iconSize ?? 20,
},
}[size] ?? {
padding: "px-4 py-2",
text: "text-sm",
icon: iconSize ?? 18,
};
const getVariantIcon = () => {
switch (variant) {
case "submit":
return (
<PlusIcon
className={`w-5 h-5 ${
children ? "text-white" : "text-purple-400 dark:text-white"
}`}
/>
);
case "secondary-submit":
return (
<FolderPlusIcon
className={`w-5 h-5 ${
children ? "text-white" : "text-purple-400 dark:text-white"
}`}
/>
);
case "edit":
return (
<PencilIcon className="w-5 h-5 text-purple-400 dark:text-purple-100" />
);
case "secondary-edit":
return (
<PencilSquareIcon className="w-5 h-5 text-purple-400 dark:text-purple-100" />
);
case "detail":
return (
<EyeIcon className="w-5 h-5 text-purple-400 dark:text-purple-100" />
);
case "view":
return (
<ViewfinderCircleIcon className="w-5 h-5 text-purple-400 dark:text-purple-100" />
);
case "delete":
return <TrashIcon className="w-5 h-5 text-red-500" />;
case "info":
return (
<DocumentChartBarIcon className="w-5 h-5 text-purple-400 dark:text-purple-100" />
);
case "chart":
return (
<ChartBarIcon className="w-5 h-5 text-purple-400 dark:text-purple-100" />
);
default:
return null;
}
};
const { profile } = useUserProfileStore();
const { openBackdrop, closeBackdrop } = useBackdropStore();
const showToast = useToast();
const ableToSeeButton = () => {
if (!access) {
return true;
} else {
const permissions = profile?.permissions || [];
// Check if access exists in the permissions array (simple array of strings)
return permissions.includes(access);
}
};
return (
<button
{...props}
className={clsx(
`${
ableToSeeButton() ? "flex" : "hidden"
} flex items-center justify-center gap-1 backdrop-blur-md transition-all duration-200 focus:outline-none cursor-pointer`,
fullWidth ? "w-full" : inputWidths,
!className.includes("bg-") ? children && bgPrimaryColor : "hover-",
directionClass,
!className.includes("text-") && textColorOnPrimary,
rounded ? "rounded-2xl" : "rounded-[8px]",
sizeStyles.padding,
sizeStyles.text,
className,
checkIsMobile() && !icon && !variant && children && mobileBorders
)}
style={{ height }}
>
<div className="w-full flex justify-center items-center">
{variant && !icon && <>{getVariantIcon()}</>}
<span className="whitespace-nowrap">{children}</span>
{icon && <div>{icon}</div>}
{excelInfo && (
<a
onClick={() => {
openBackdrop();
api
.get(excelInfo?.link || "", {
responseType: "blob",
})
.then((response) => {
closeBackdrop();
const url = window.URL.createObjectURL(
new Blob([response.data])
);
const link = document.createElement("a");
link.href = url;
link.setAttribute("download", `${excelInfo?.title}.xlsx`);
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
window.URL.revokeObjectURL(url);
})
.catch((error) => {
console.error("Error downloading file:", error);
closeBackdrop();
showToast("خطا در دانلود فایل", "error");
});
}}
>
<SVGImage
src={excel}
className={` text-primary-600 dark:text-primary-100 w-5 h-5`}
/>
</a>
)}
</div>
</button>
);
};
export default Button;