New Tasks
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
import React, { useId, useState } from "react";
|
||||
import classes from "./AddButton.module.css";
|
||||
import MoonLoader from "react-spinners/MoonLoader";
|
||||
|
||||
const AddButton = ({
|
||||
onClick,
|
||||
children = "Add New",
|
||||
showPlus = true,
|
||||
className,
|
||||
showChildren = true,
|
||||
loaderclasses,
|
||||
color = "#ffffff",
|
||||
loading = false,
|
||||
disabled = false,
|
||||
icon = null,
|
||||
title,
|
||||
}) => {
|
||||
const override = {
|
||||
borderColor: "#ffffff",
|
||||
};
|
||||
const id = useId();
|
||||
const [animate, setAnimate] = useState(false);
|
||||
|
||||
const onClickHandle = () => {
|
||||
if (onClick) {
|
||||
onClick();
|
||||
}
|
||||
setAnimate(true);
|
||||
};
|
||||
// const classes = ` after:bg-[#90EE90] after:block after:absolute after:pt-[300%] after:pl-[350%] after:!ml-[-1.25rem] after:mt-[-120%] after:opacity-0 after:transition-all active:after:p-0 active:after:m-0 active:after:opacity-100 `;
|
||||
return (
|
||||
<button
|
||||
title={title}
|
||||
disabled={disabled}
|
||||
type="button"
|
||||
onAnimationEnd={() => setAnimate(false)}
|
||||
onClick={onClickHandle}
|
||||
className={`${animate && "animate-wiggle"} ${
|
||||
classes.button
|
||||
} relative flex h-[3rem] cursor-pointer items-center justify-center gap-2 overflow-hidden rounded-[.625rem] border border-primary bg-primary px-[.625rem] py-2 font-inter text-sm font-medium leading-loose tracking-wide text-white ${className}`}
|
||||
>
|
||||
<>
|
||||
<MoonLoader
|
||||
color={color}
|
||||
loading={loading}
|
||||
cssOverride={override}
|
||||
size={14}
|
||||
className={loaderclasses}
|
||||
// aria-label="Loading Spinner"
|
||||
data-testid={id}
|
||||
/>
|
||||
{!loading && icon ? icon : null}
|
||||
{/* {showPlus ? "+" : null} */}
|
||||
{showChildren ? children : null}
|
||||
</>
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddButton;
|
||||
@@ -0,0 +1,32 @@
|
||||
.button {
|
||||
position: relative;
|
||||
/* border: none; */
|
||||
color: #ffffff;
|
||||
text-align: center;
|
||||
-webkit-transition-duration: 0.4s; /* Safari */
|
||||
transition-duration: 0.4s;
|
||||
text-decoration: none;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
/* background-color: #7B1113; */
|
||||
}
|
||||
.button:after {
|
||||
content: "";
|
||||
background-color: #7b1113;
|
||||
/* background: #4f46e5; */
|
||||
display: block;
|
||||
position: absolute;
|
||||
padding-top: 300%;
|
||||
padding-left: 350%;
|
||||
margin-left: -20px !important;
|
||||
margin-top: -120%;
|
||||
opacity: 0;
|
||||
transition: all 0.8s;
|
||||
}
|
||||
|
||||
.button:active:after {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
opacity: 1;
|
||||
transition: 0s;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export { default as AddButton } from "./AddButton";
|
||||
@@ -0,0 +1,24 @@
|
||||
import React from "react";
|
||||
|
||||
const DropdownOption = ({
|
||||
icon,
|
||||
onClick = () => {},
|
||||
name,
|
||||
style = {},
|
||||
className = "",
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
style={{ ...style }}
|
||||
className={`flex h-[2.25rem] max-h-[2.25rem] min-h-[2.25rem] w-full cursor-pointer items-center gap-3 px-2 capitalize text-[#262626] hover:bg-[#F4F4F4] hover:text-[#262626] ${className}`}
|
||||
onClick={(e) => {
|
||||
onClick(e);
|
||||
}}
|
||||
>
|
||||
{icon && <span className=""> {icon}</span>}
|
||||
{name && <span className="grow"> {name}</span>}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DropdownOption;
|
||||
@@ -0,0 +1,3 @@
|
||||
import { lazy } from "react";
|
||||
|
||||
export const DropdownOption = lazy(() => import("./DropdownOption"));
|
||||
@@ -0,0 +1,29 @@
|
||||
import React from "react";
|
||||
import { KebabIcon } from "Assets/svgs";
|
||||
|
||||
const DropdownOptions = ({
|
||||
icon,
|
||||
children,
|
||||
childrenWrapperClass = "",
|
||||
iconWrapperClass = "",
|
||||
className = "",
|
||||
style = {},
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
style={{ ...style }}
|
||||
className={`relative flex items-center justify-center ${className}`}
|
||||
>
|
||||
<button className={`peer relative ${iconWrapperClass}`}>
|
||||
{icon ? icon : <KebabIcon />}
|
||||
</button>
|
||||
<div
|
||||
className={`absolute right-0 top-[85%] z-[9999999999] m-auto hidden whitespace-nowrap rounded-lg border border-[#a8a8a8] bg-white text-sm text-[#525252] shadow-md hover:block focus:block peer-focus:block peer-focus-visible:block ${childrenWrapperClass} `}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DropdownOptions;
|
||||
@@ -0,0 +1,4 @@
|
||||
import { lazy } from "react";
|
||||
|
||||
export const DropdownOptions = lazy(() => import("./DropdownOptions"));
|
||||
export { DropdownOption } from "./DropdownOption";
|
||||
@@ -0,0 +1,145 @@
|
||||
.toggleClass.react-toggle--checked .react-toggle-track {
|
||||
background-color: #7b1113;
|
||||
}
|
||||
|
||||
.react-toggle {
|
||||
touch-action: pan-x;
|
||||
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
|
||||
-webkit-tap-highlight-color: #ffffff;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
|
||||
.react-toggle-screenreader-only {
|
||||
border: 0;
|
||||
clip: rect(0 0 0 0);
|
||||
height: 1px;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
}
|
||||
|
||||
.react-toggle--disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.5;
|
||||
-webkit-transition: opacity 0.25s;
|
||||
transition: opacity 0.25s;
|
||||
}
|
||||
|
||||
.react-toggle-track {
|
||||
width: 50px;
|
||||
height: 24px;
|
||||
padding: 0;
|
||||
border-radius: 30px;
|
||||
background-color: #d4d4d8;
|
||||
-webkit-transition: all 0.2s ease;
|
||||
-moz-transition: all 0.2s ease;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.react-toggle:hover:not(.react-toggle--disabled) .react-toggle-track {
|
||||
/* background-color: #000000; */
|
||||
}
|
||||
|
||||
.react-toggle--checked .react-toggle-track {
|
||||
background-color: #7b1113;
|
||||
}
|
||||
|
||||
.react-toggle--checked:hover:not(.react-toggle--disabled) .react-toggle-track {
|
||||
background-color: #7b1113;
|
||||
}
|
||||
|
||||
.react-toggle-track-check {
|
||||
position: absolute;
|
||||
width: 14px;
|
||||
height: 10px;
|
||||
top: 0px;
|
||||
bottom: 0px;
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
line-height: 0;
|
||||
left: 8px;
|
||||
opacity: 0;
|
||||
-webkit-transition: opacity 0.25s ease;
|
||||
-moz-transition: opacity 0.25s ease;
|
||||
transition: opacity 0.25s ease;
|
||||
}
|
||||
|
||||
.react-toggle--checked .react-toggle-track-check {
|
||||
opacity: 1;
|
||||
-webkit-transition: opacity 0.25s ease;
|
||||
-moz-transition: opacity 0.25s ease;
|
||||
transition: opacity 0.25s ease;
|
||||
}
|
||||
|
||||
.react-toggle-track-x {
|
||||
position: absolute;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
top: 0px;
|
||||
bottom: 0px;
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
line-height: 0;
|
||||
right: 10px;
|
||||
opacity: 1;
|
||||
-webkit-transition: opacity 0.25s ease;
|
||||
-moz-transition: opacity 0.25s ease;
|
||||
transition: opacity 0.25s ease;
|
||||
}
|
||||
|
||||
.react-toggle--checked .react-toggle-track-x {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.react-toggle-thumb {
|
||||
transition: all 0.5s cubic-bezier(0.23, 1, 0.32, 1) 0ms;
|
||||
position: absolute;
|
||||
top: 1px;
|
||||
left: 1px;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
border: 1px solid #4d4d4d;
|
||||
border-radius: 50%;
|
||||
background-color: #fafafa;
|
||||
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
|
||||
-webkit-transition: all 0.25s ease;
|
||||
-moz-transition: all 0.25s ease;
|
||||
transition: all 0.25s ease;
|
||||
}
|
||||
|
||||
.react-toggle--checked .react-toggle-thumb {
|
||||
left: 27px;
|
||||
border-color: #7b1113;
|
||||
}
|
||||
|
||||
.react-toggle--focus .react-toggle-thumb {
|
||||
-webkit-box-shadow: 0px 0px 3px 2px #7b1113;
|
||||
-moz-box-shadow: 0px 0px 3px 2px #7b1113;
|
||||
box-shadow: 0px 0px 2px 3px #7b1113;
|
||||
}
|
||||
|
||||
.react-toggle:active:not(.react-toggle--disabled) .react-toggle-thumb {
|
||||
-webkit-box-shadow: 0px 0px 5px 5px #7b1113;
|
||||
-moz-box-shadow: 0px 0px 5px 5px #7b1113;
|
||||
box-shadow: 0px 0px 5px 5px #7b1113;
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
import React, { useId } from "react";
|
||||
import { StringCaser } from "Utils/utils";
|
||||
import Toggle from "react-toggle";
|
||||
import "./MkdInput.css";
|
||||
import { SkeletonLoader } from "Components/Skeleton";
|
||||
|
||||
const MkdInput = ({
|
||||
type = "text",
|
||||
page,
|
||||
cols = "30",
|
||||
rows = "50",
|
||||
name,
|
||||
label,
|
||||
errors = null,
|
||||
register = () => ({}),
|
||||
className,
|
||||
placeholder,
|
||||
options = [],
|
||||
mapping = null,
|
||||
disabled = false,
|
||||
value = null,
|
||||
onChange,
|
||||
loading = false,
|
||||
required = false,
|
||||
}) => {
|
||||
const uniqueId = useId();
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className={`relative grow ${
|
||||
page === "list" ? "w-full pl-2 pr-2 md:w-1/2" : ""
|
||||
}`}
|
||||
>
|
||||
{["radio", "checkbox", "color", "toggle"].includes(type) ? null : (
|
||||
<>
|
||||
{label && (
|
||||
<label
|
||||
className="mb-2 block cursor-pointer text-sm "
|
||||
htmlFor={uniqueId}
|
||||
>
|
||||
{label}
|
||||
{required && (
|
||||
<sup className="text-[.825rem] text-red-600">*</sup>
|
||||
)}
|
||||
{/* {StringCaser(label, { casetype: "capitalize", separator: "space" })} */}
|
||||
</label>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{loading ? (
|
||||
<SkeletonLoader
|
||||
count={1}
|
||||
counts={[2]}
|
||||
className={`!h-[3rem] !gap-0 rounded-[.625rem] !bg-[#ebebeb] !p-0 `}
|
||||
/>
|
||||
) : type === "textarea" ? (
|
||||
<>
|
||||
<textarea
|
||||
className={`focus:shadow-outline w-full appearance-none rounded border border-soft-200 px-3 py-2 font-inter leading-tight text-black shadow focus:outline-none ${className} ${
|
||||
errors && errors[name] && errors[name]?.message
|
||||
? "border-red-500"
|
||||
: ""
|
||||
}`}
|
||||
disabled={disabled}
|
||||
id={uniqueId}
|
||||
cols={cols}
|
||||
name={name}
|
||||
placeholder={placeholder}
|
||||
rows={rows}
|
||||
{...register(name)}
|
||||
></textarea>
|
||||
</>
|
||||
) : ["radio", "checkbox", "color", "toggle"].includes(type) ? (
|
||||
<div className="flex h-[1.875rem] items-center gap-2 pb-1 pt-3">
|
||||
{["toggle"].includes(type) ? (
|
||||
<Toggle
|
||||
className={`toggle_class ${className}`}
|
||||
// defaultChecked={}
|
||||
// checked={selectRoles}
|
||||
icons={false}
|
||||
{...(onChange ? { onChange: onChange } : null)}
|
||||
{...(value ? { checked: value } : null)}
|
||||
// placeholder={placeholder}
|
||||
// {...register(name)}
|
||||
/>
|
||||
) : (
|
||||
// <input
|
||||
// disabled={disabled}
|
||||
// type={type}
|
||||
// id={name}
|
||||
// name={name}
|
||||
// {...(value ? { value: value } : null)}
|
||||
// placeholder={placeholder}
|
||||
// {...register(name)}
|
||||
// className={`focus:shadow-outline !h-4 !w-4 cursor-pointer appearance-none rounded border border-soft-200 font-inter leading-tight text-primary shadow focus:outline-none focus:ring-0 ${className} ${
|
||||
// errors && errors[name] && errors[name]?.message
|
||||
// ? "border-red-500"
|
||||
// : ""
|
||||
// } ${
|
||||
// type === "color" ? "min-h-[3.125rem] min-w-[6.25rem]" : ""
|
||||
// }`}
|
||||
// />
|
||||
<input
|
||||
disabled={disabled}
|
||||
type={type}
|
||||
id={uniqueId}
|
||||
name={name}
|
||||
{...(value ? { value: value } : null)}
|
||||
// {...(value ? { checked: value } : null)}
|
||||
placeholder={placeholder}
|
||||
{...register(name)}
|
||||
className={`focus:shadow-outline !h-4 !w-4 cursor-pointer appearance-none rounded border border-soft-200 font-inter leading-tight text-primary shadow focus:outline-none focus:ring-0 ${className} ${
|
||||
errors && errors[name] && errors[name]?.message
|
||||
? "border-red-500"
|
||||
: ""
|
||||
} ${
|
||||
type === "color" ? "min-h-[3.125rem] min-w-[6.25rem]" : ""
|
||||
}`}
|
||||
/>
|
||||
)}
|
||||
<label
|
||||
className="mb-2 block h-full cursor-pointer font-inter text-sm font-[500] capitalize text-black"
|
||||
htmlFor={uniqueId}
|
||||
>
|
||||
{label}
|
||||
{/* {StringCaser(label, {
|
||||
casetype: "capitalize",
|
||||
separator: "space",
|
||||
})} */}
|
||||
</label>
|
||||
</div>
|
||||
) : type === "dropdown" || type === "select" ? (
|
||||
<select
|
||||
type={type}
|
||||
id={uniqueId}
|
||||
disabled={disabled}
|
||||
placeholder={placeholder}
|
||||
{...register(name)}
|
||||
className={`focus:shadow-outline h-[3rem] w-full appearance-none rounded-[.625rem] border border-soft-200 p-[.625rem] px-3 py-2 font-inter leading-tight text-black shadow focus:outline-none focus:ring-0 ${className} ${
|
||||
errors && errors[name] && errors[name]?.message
|
||||
? "border-red-500"
|
||||
: ""
|
||||
}`}
|
||||
>
|
||||
<option></option>
|
||||
{options.map((option, key) => (
|
||||
<option value={option} key={key + 1}>
|
||||
{option}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
) : type === "mapping" ? (
|
||||
<>
|
||||
{mapping ? (
|
||||
<select
|
||||
type={"number"}
|
||||
id={uniqueId}
|
||||
disabled={disabled}
|
||||
{...(value ? { value: value } : null)}
|
||||
placeholder={placeholder}
|
||||
{...register(name)}
|
||||
className={`focus:shadow-outline h-[3rem] w-full appearance-none rounded-[.625rem] border border-soft-200 p-[.625rem] px-3 py-2 font-inter leading-tight text-black shadow focus:outline-none focus:ring-0 ${className} ${
|
||||
errors && errors[name] && errors[name]?.message
|
||||
? "border-red-500"
|
||||
: ""
|
||||
}`}
|
||||
>
|
||||
<option></option>
|
||||
{options.map((option, key) => (
|
||||
<option value={option} key={key + 1}>
|
||||
{mapping[option]}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
) : (
|
||||
`Please Pass the mapping e.g {key:value}`
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<input
|
||||
type={type}
|
||||
id={uniqueId}
|
||||
disabled={disabled}
|
||||
placeholder={placeholder}
|
||||
{...register(name)}
|
||||
{...(type === "number" ? { step: "0.01" } : null)}
|
||||
min={type === "number" ? "0.00" : undefined} //
|
||||
className={`focus:shadow-outline h-[3rem] w-full appearance-none rounded-[.625rem] border border-soft-200 p-[.625rem] px-3 py-2 font-inter leading-tight text-black shadow focus:outline-none focus:ring-0 ${className} ${
|
||||
errors && errors[name] && errors[name]?.message
|
||||
? "border-red-500"
|
||||
: ""
|
||||
}`}
|
||||
/>
|
||||
)}
|
||||
|
||||
{errors && errors[name] && (
|
||||
<p className="text-field-error absolute inset-x-0 top-full m-auto mt-2 text-[.8rem] italic text-red-500">
|
||||
{StringCaser(errors[name]?.message, {
|
||||
casetype: "capitalize",
|
||||
separator: " ",
|
||||
})}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default MkdInput;
|
||||
@@ -0,0 +1,145 @@
|
||||
.toggleClass.react-toggle--checked .react-toggle-track {
|
||||
background-color: #7b1113;
|
||||
}
|
||||
|
||||
.react-toggle {
|
||||
touch-action: pan-x;
|
||||
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
|
||||
.react-toggle-screenreader-only {
|
||||
border: 0;
|
||||
clip: rect(0 0 0 0);
|
||||
height: 1px;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
}
|
||||
|
||||
.react-toggle--disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.5;
|
||||
-webkit-transition: opacity 0.25s;
|
||||
transition: opacity 0.25s;
|
||||
}
|
||||
|
||||
.react-toggle-track {
|
||||
width: 50px;
|
||||
height: 24px;
|
||||
padding: 0;
|
||||
border-radius: 30px;
|
||||
background-color: #4d4d4d;
|
||||
-webkit-transition: all 0.2s ease;
|
||||
-moz-transition: all 0.2s ease;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.react-toggle:hover:not(.react-toggle--disabled) .react-toggle-track {
|
||||
background-color: #000000;
|
||||
}
|
||||
|
||||
.react-toggle--checked .react-toggle-track {
|
||||
background-color: #19ab27;
|
||||
}
|
||||
|
||||
.react-toggle--checked:hover:not(.react-toggle--disabled) .react-toggle-track {
|
||||
background-color: #128d15;
|
||||
}
|
||||
|
||||
.react-toggle-track-check {
|
||||
position: absolute;
|
||||
width: 14px;
|
||||
height: 10px;
|
||||
top: 0px;
|
||||
bottom: 0px;
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
line-height: 0;
|
||||
left: 8px;
|
||||
opacity: 0;
|
||||
-webkit-transition: opacity 0.25s ease;
|
||||
-moz-transition: opacity 0.25s ease;
|
||||
transition: opacity 0.25s ease;
|
||||
}
|
||||
|
||||
.react-toggle--checked .react-toggle-track-check {
|
||||
opacity: 1;
|
||||
-webkit-transition: opacity 0.25s ease;
|
||||
-moz-transition: opacity 0.25s ease;
|
||||
transition: opacity 0.25s ease;
|
||||
}
|
||||
|
||||
.react-toggle-track-x {
|
||||
position: absolute;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
top: 0px;
|
||||
bottom: 0px;
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
line-height: 0;
|
||||
right: 10px;
|
||||
opacity: 1;
|
||||
-webkit-transition: opacity 0.25s ease;
|
||||
-moz-transition: opacity 0.25s ease;
|
||||
transition: opacity 0.25s ease;
|
||||
}
|
||||
|
||||
.react-toggle--checked .react-toggle-track-x {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.react-toggle-thumb {
|
||||
transition: all 0.5s cubic-bezier(0.23, 1, 0.32, 1) 0ms;
|
||||
position: absolute;
|
||||
top: 1px;
|
||||
left: 1px;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
border: 1px solid #4d4d4d;
|
||||
border-radius: 50%;
|
||||
background-color: #fafafa;
|
||||
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
|
||||
-webkit-transition: all 0.25s ease;
|
||||
-moz-transition: all 0.25s ease;
|
||||
transition: all 0.25s ease;
|
||||
}
|
||||
|
||||
.react-toggle--checked .react-toggle-thumb {
|
||||
left: 27px;
|
||||
border-color: #19ab27;
|
||||
}
|
||||
|
||||
.react-toggle--focus .react-toggle-thumb {
|
||||
-webkit-box-shadow: 0px 0px 3px 2px #0099e0;
|
||||
-moz-box-shadow: 0px 0px 3px 2px #0099e0;
|
||||
box-shadow: 0px 0px 2px 3px #0099e0;
|
||||
}
|
||||
|
||||
.react-toggle:active:not(.react-toggle--disabled) .react-toggle-thumb {
|
||||
-webkit-box-shadow: 0px 0px 5px 5px #0099e0;
|
||||
-moz-box-shadow: 0px 0px 5px 5px #0099e0;
|
||||
box-shadow: 0px 0px 5px 5px #0099e0;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
export { default as MkdInput } from "./MkdInput";
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
table thead {
|
||||
border-top-left-radius: 0.625rem !important;
|
||||
border-top-right-radius: 0.625rem !important;
|
||||
}
|
||||
table thead tr {
|
||||
border-top-left-radius: 0.625rem !important;
|
||||
border-top-right-radius: 0.625rem !important;
|
||||
background-color: #f4f4f5;
|
||||
}
|
||||
tbody tr:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
table thead tr:first-child th:first-child {
|
||||
border-left: 0.0313rem solid #e5e7eb;
|
||||
border-top: 0.0313rem solid #e5e7eb;
|
||||
border-top-left-radius: 0.625rem !important;
|
||||
}
|
||||
table thead tr:first-child th:last-child {
|
||||
border-right: 0.0313rem solid #e5e7eb;
|
||||
border-top: 0.0313rem solid #e5e7eb;
|
||||
border-top-right-radius: 0.625rem !important;
|
||||
}
|
||||
table thead tr:first-child th {
|
||||
border-top: 0.0313rem solid #e5e7eb;
|
||||
}
|
||||
table tbody tr:last-child td:first-child {
|
||||
border-bottom-left-radius: 0.625rem !important;
|
||||
}
|
||||
table tbody tr:last-child td:last-child {
|
||||
border-bottom-right-radius: 0.625rem !important;
|
||||
}
|
||||
|
||||
table tbody tr td:first-child {
|
||||
border-left: 0.0313rem solid #e5e7eb;
|
||||
}
|
||||
table tbody tr td {
|
||||
border-right: 0.0313rem solid #e5e7eb;
|
||||
}
|
||||
|
||||
.no-data-found {
|
||||
filter: grayscale(10);
|
||||
}
|
||||
@@ -0,0 +1,339 @@
|
||||
import React, { Fragment } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { DotIcon, KebabIcon, NarrowUpArrowIcon, Spinner } from "Assets/svgs";
|
||||
import { SkeletonLoader } from "Components/Skeleton";
|
||||
import { NoDataFoundImg } from "Assets/images";
|
||||
import MkdListTableSelectRow from "./MkdListTableSelectRow";
|
||||
import MkdListTableRightActionPanel from "./MkdListTableRightActionPanel";
|
||||
import MkdListTableRow from "./MkdListTableRow";
|
||||
|
||||
const MkdListTable = ({
|
||||
table,
|
||||
tableTitle,
|
||||
onSort,
|
||||
loading,
|
||||
columns = [],
|
||||
actions,
|
||||
actionPostion = [],
|
||||
tableRole,
|
||||
deleteItem,
|
||||
deleteLoading,
|
||||
actionId = "id",
|
||||
showDeleteModal,
|
||||
currentTableData = [],
|
||||
setShowDeleteModal,
|
||||
handleTableCellChange,
|
||||
setSelectedItems,
|
||||
allowEditing,
|
||||
useImage = true,
|
||||
columnData = null,
|
||||
setColumns = null,
|
||||
setColumnData = null,
|
||||
allowSortColumns = true,
|
||||
onPopoverStateChange = null,
|
||||
popoverShown = false,
|
||||
}) => {
|
||||
const [deleteId, setIdToDelete] = React.useState(null);
|
||||
const [isOneOrMoreRowSelected, setIsOneOrMoreRowSelected] =
|
||||
React.useState(false);
|
||||
const [areAllRowsSelected, setAreAllRowsSelected] = React.useState(false);
|
||||
const [selectedIds, setSelectedIds] = React.useState([]);
|
||||
const [dragging, setDragging] = React.useState(false);
|
||||
const [fromKey, setFromKey] = React.useState(null);
|
||||
const [toKey, setToKey] = React.useState(null);
|
||||
|
||||
function handleSelectRow(id) {
|
||||
setIsOneOrMoreRowSelected(true);
|
||||
const tempIds = selectedIds;
|
||||
|
||||
if (actions?.select?.multiple) {
|
||||
if (tempIds.includes(id)) {
|
||||
const newIds = tempIds.filter((selectedId) => selectedId !== id);
|
||||
setSelectedIds(() => [...newIds]);
|
||||
setSelectedItems(newIds);
|
||||
} else {
|
||||
const newIds = [...tempIds, id];
|
||||
setSelectedIds(() => [...newIds]);
|
||||
setSelectedItems(newIds);
|
||||
}
|
||||
} else {
|
||||
if (tempIds.includes(id)) {
|
||||
const newIds = tempIds.filter((selectedId) => selectedId !== id);
|
||||
setSelectedIds(() => [...newIds]);
|
||||
setSelectedItems(newIds);
|
||||
} else {
|
||||
const newIds = [id];
|
||||
setSelectedIds(() => [...newIds]);
|
||||
setSelectedItems(newIds);
|
||||
}
|
||||
}
|
||||
console.log(id);
|
||||
}
|
||||
|
||||
const handleSelectAll = () => {
|
||||
setAreAllRowsSelected((prevSelectAll) => !prevSelectAll);
|
||||
if (!areAllRowsSelected) {
|
||||
const allIds = currentTableData.map((item) => item[actionId]);
|
||||
setSelectedIds(allIds);
|
||||
setSelectedItems(allIds);
|
||||
} else {
|
||||
setSelectedIds([]);
|
||||
setSelectedItems([]);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDeleteAll = async (id) => {
|
||||
setShowDeleteModal(true);
|
||||
setIdToDelete(id);
|
||||
};
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
const setDeleteId = async (id) => {
|
||||
console.log("id >>", id);
|
||||
setShowDeleteModal(true);
|
||||
setIdToDelete(id);
|
||||
};
|
||||
|
||||
const onDragStart = (e, key) => {
|
||||
if (!allowSortColumns) return;
|
||||
// e.preventDefault();
|
||||
// console.log("onDragStart");
|
||||
setFromKey(key);
|
||||
setDragging(true);
|
||||
};
|
||||
const onDrop = (e) => {
|
||||
if (!allowSortColumns) return;
|
||||
e.preventDefault();
|
||||
if (fromKey && toKey && fromKey != toKey) {
|
||||
const tempColumns = [...columns];
|
||||
const fromColumn = tempColumns[fromKey];
|
||||
const toColumn = tempColumns[toKey];
|
||||
|
||||
tempColumns.splice(fromKey, 1);
|
||||
tempColumns.splice(toKey, 0, fromColumn);
|
||||
if (setColumns) {
|
||||
setColumns(() => tempColumns);
|
||||
}
|
||||
}
|
||||
setToKey(null);
|
||||
setFromKey(null);
|
||||
setDragging(false);
|
||||
};
|
||||
const onDragOver = (e, key) => {
|
||||
if (!allowSortColumns) return;
|
||||
e.preventDefault();
|
||||
|
||||
setToKey(key);
|
||||
// if (fromKey != key) {
|
||||
// }
|
||||
};
|
||||
const onDragEnter = (e) => {
|
||||
if (!allowSortColumns) return;
|
||||
e.preventDefault();
|
||||
};
|
||||
const onDragEnd = (e) => {
|
||||
if (!allowSortColumns) return;
|
||||
e.preventDefault();
|
||||
setToKey(null);
|
||||
setFromKey(null);
|
||||
// console.log("onDragEnd");
|
||||
|
||||
setDragging(false);
|
||||
};
|
||||
const onDragLeave = (e) => {
|
||||
if (!allowSortColumns) return;
|
||||
e.preventDefault();
|
||||
setToKey(null);
|
||||
// setFromKey(null);
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
if (selectedIds.length <= 0) {
|
||||
setIsOneOrMoreRowSelected(false);
|
||||
setAreAllRowsSelected(false);
|
||||
}
|
||||
if (selectedIds.length === currentTableData?.length) {
|
||||
setAreAllRowsSelected(true);
|
||||
setIsOneOrMoreRowSelected(true);
|
||||
}
|
||||
if (
|
||||
selectedIds.length < currentTableData?.length &&
|
||||
selectedIds.length > 0
|
||||
) {
|
||||
setAreAllRowsSelected(false);
|
||||
}
|
||||
}, [selectedIds, currentTableData]);
|
||||
// console.log("currentTableData");
|
||||
// console.log(currentTableData);
|
||||
// console.log(columns)
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className={`${
|
||||
loading || !currentTableData?.length
|
||||
? "grid-cols-1"
|
||||
: "grid-cols-[auto_1fr_auto]"
|
||||
} relative grid !max-h-fit !min-h-fit !w-full justify-center !rounded-[.625rem] border border-soft-200 bg-white`}
|
||||
>
|
||||
<MkdListTableSelectRow
|
||||
actions={actions}
|
||||
loading={loading}
|
||||
columns={columns}
|
||||
currentTableData={currentTableData}
|
||||
handleSelectAll={handleSelectAll}
|
||||
areAllRowsSelected={areAllRowsSelected}
|
||||
handleSelectRow={handleSelectRow}
|
||||
selectedIds={selectedIds}
|
||||
actionId={actionId}
|
||||
/>
|
||||
|
||||
{/* BR */}
|
||||
<div
|
||||
className={`${
|
||||
loading ? "" : ""
|
||||
} relative flex max-h-fit !min-h-fit w-full justify-start overflow-y-clip bg-white ${
|
||||
!popoverShown ? "overflow-x-auto" : ""
|
||||
} `}
|
||||
>
|
||||
{(loading && useImage) ||
|
||||
(loading && !columns?.length) ||
|
||||
(loading && !currentTableData?.length) ? (
|
||||
<div
|
||||
className={`max-h-fit min-h-fit w-full min-w-full max-w-full items-center justify-center`}
|
||||
>
|
||||
<SkeletonLoader />
|
||||
</div>
|
||||
) : columns?.length && currentTableData?.length ? (
|
||||
<>
|
||||
{columns?.map((cell, cellIndex) => {
|
||||
if (
|
||||
!["row", ""].includes(cell?.accessor) &&
|
||||
cell?.selected_column
|
||||
) {
|
||||
return (
|
||||
<div key={cellIndex} className="h-full grow">
|
||||
<div
|
||||
draggable={allowSortColumns}
|
||||
onDragStart={(e) => onDragStart(e, cellIndex)}
|
||||
onDragEnd={onDragEnd}
|
||||
onDragOver={(e) => onDragOver(e, cellIndex)}
|
||||
onDragLeave={(e) => onDragLeave(e)}
|
||||
onDrop={(e) => onDrop(e)}
|
||||
className={`flex !h-[2.65rem] !max-h-[2.65rem] !min-h-[2.65rem] w-full !min-w-full max-w-fit items-center justify-start gap-2 px-[.75rem] py-[.5rem] ${
|
||||
allowSortColumns && dragging
|
||||
? "cursor-grabbing"
|
||||
: cell?.isSorted
|
||||
? "cursor-pointer"
|
||||
: ""
|
||||
} ${
|
||||
toKey == cellIndex
|
||||
? "bg-primary-light"
|
||||
: "bg-weak-100"
|
||||
} `}
|
||||
>
|
||||
<div
|
||||
className="flex grow items-center justify-between gap-5"
|
||||
onClick={
|
||||
cell?.isSorted ? () => onSort(cellIndex) : undefined
|
||||
}
|
||||
>
|
||||
<div className="w-auto grow whitespace-nowrap capitalize">
|
||||
{cell.header}
|
||||
</div>
|
||||
<span className="w-fit">
|
||||
{cell.isSorted ? (
|
||||
<NarrowUpArrowIcon
|
||||
className={`h-2 w-2 ${
|
||||
cell.isSortedDesc ? "rotate-180" : ""
|
||||
}`}
|
||||
/>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
{allowSortColumns ? (
|
||||
<DotIcon className="h-2 w-2 cursor-grab" />
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
{currentTableData?.map((row, rowIndex) => {
|
||||
return (
|
||||
<MkdListTableRow
|
||||
key={rowIndex}
|
||||
columnIndex={cellIndex}
|
||||
row={row}
|
||||
columns={columns}
|
||||
column={cell}
|
||||
currentTableData={currentTableData}
|
||||
actions={actions}
|
||||
allowEditing={allowEditing}
|
||||
handleSelectRow={handleSelectRow}
|
||||
handleTableCellChange={handleTableCellChange}
|
||||
actionPostion={actionPostion}
|
||||
onPopoverStateChange={onPopoverStateChange}
|
||||
selectedIds={selectedIds}
|
||||
actionId={actionId}
|
||||
tableRole={tableRole}
|
||||
className={`!h-[3rem] !max-h-[3rem] !min-h-[3rem] w-full min-w-full max-w-fit whitespace-nowrap !border-b border-soft-200 bg-white px-[.75rem] py-[.5rem] ${
|
||||
cellIndex === 0 ? "border-l border-r" : "border-r"
|
||||
}`}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
})}
|
||||
</>
|
||||
) : !loading && !currentTableData?.length ? (
|
||||
<div className="relative w-full">
|
||||
<div
|
||||
className={`relative max-h-fit min-h-fit w-full min-w-fit max-w-full items-center justify-center `}
|
||||
>
|
||||
<div
|
||||
className={`relative ${
|
||||
useImage
|
||||
? "h-[31.25rem]"
|
||||
: "flex h-[6.25rem] items-center justify-center"
|
||||
} w-full`}
|
||||
>
|
||||
{useImage ? (
|
||||
<img
|
||||
src={NoDataFoundImg}
|
||||
className={`no-data-found absolute inset-x-0 m-auto h-full w-[50%] grayscale-[10%]`}
|
||||
/>
|
||||
) : (
|
||||
<>No Data</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
<MkdListTableRightActionPanel
|
||||
table={table}
|
||||
tableTitle={tableTitle}
|
||||
onSort={onSort}
|
||||
loading={loading}
|
||||
columns={columns}
|
||||
actions={actions}
|
||||
actionPostion={actionPostion}
|
||||
tableRole={tableRole}
|
||||
deleteItem={deleteItem}
|
||||
deleteLoading={deleteLoading}
|
||||
actionId={actionId}
|
||||
showDeleteModal={showDeleteModal}
|
||||
currentTableData={currentTableData}
|
||||
setShowDeleteModal={setShowDeleteModal}
|
||||
handleTableCellChange={handleTableCellChange}
|
||||
setSelectedItems={setSelectedItems}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default MkdListTable;
|
||||
@@ -0,0 +1,104 @@
|
||||
export const operations = {
|
||||
EQUAL: "eq",
|
||||
NOT_EQUAL: "neq",
|
||||
IS_NULL: "isn",
|
||||
IS_NOT_NULL: "isnn",
|
||||
CONTAINS: "cs",
|
||||
START_WITH: "sw",
|
||||
END_WITH: "ew",
|
||||
LESS_THAN: "lt",
|
||||
GREATER_THAN: "gt",
|
||||
};
|
||||
|
||||
export const runOperation = (row, column, operator, value) => {
|
||||
switch (operator) {
|
||||
case operations.EQUAL:
|
||||
// TO DO
|
||||
// return runEqualOperation(row, column, value);
|
||||
case operations.NOT_EQUAL:
|
||||
// TO DO
|
||||
// return runNotEqualOperation(row, column, value);
|
||||
case operations.IS_NULL:
|
||||
// TO DO
|
||||
// return runIsNullOperation(row, column, value);
|
||||
case operations.IS_NOT_NULL:
|
||||
// TO DO
|
||||
// return runIsNotNullOperation(row, column, value);
|
||||
case operations.CONTAINS:
|
||||
// TO DO
|
||||
// return runContainsOperation(row, column, value);
|
||||
case operations.START_WITH:
|
||||
// TO DO
|
||||
// return runStartWithOperation(row, column, value);
|
||||
case operations.END_WITH:
|
||||
// TO DO
|
||||
// return runEndWithOperation(row, column, value);
|
||||
case operations.GREATER_THAN:
|
||||
// TO DO
|
||||
// return runGreaterThanOperation(row, column, value);
|
||||
case operations.LESS_THAN:
|
||||
// TO DO
|
||||
// return runLessThanOperation(row, column, value);
|
||||
}
|
||||
};
|
||||
export const logicalOR = (action, row) => {
|
||||
if (
|
||||
!Array.isArray(action?.bind?.column) ||
|
||||
!Array.isArray(action?.bind?.ifValue)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
if (action?.bind?.column?.length !== action?.bind?.ifValue?.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const result = action?.bind?.ifValue.map((value, index) =>
|
||||
runOperation(
|
||||
row,
|
||||
action?.bind?.column[index],
|
||||
action?.bind?.operator,
|
||||
value
|
||||
)
|
||||
);
|
||||
return result.some((res) => res === true);
|
||||
};
|
||||
|
||||
export const logicalAND = (action, row) => {
|
||||
if (
|
||||
!Array.isArray(action?.bind?.column) ||
|
||||
!Array.isArray(action?.bind?.ifValue)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
if (action?.bind?.column?.length !== action?.bind?.ifValue?.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const result = action?.bind?.ifValue.map((value, index) =>
|
||||
runOperation(
|
||||
row,
|
||||
action?.bind?.column[index],
|
||||
action?.bind?.operator,
|
||||
value
|
||||
)
|
||||
);
|
||||
return result.every((res) => res === true);
|
||||
};
|
||||
|
||||
export const processBind = (action, row) => {
|
||||
if (action?.bind?.logic) {
|
||||
switch (action?.bind?.logic) {
|
||||
case "or":
|
||||
return logicalOR(action, row);
|
||||
case "and":
|
||||
return logicalAND(action, row);
|
||||
}
|
||||
} else {
|
||||
return runOperation(
|
||||
row,
|
||||
action?.bind?.column,
|
||||
action?.bind?.operator,
|
||||
action?.bind?.ifValue
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,52 @@
|
||||
import React from "react";
|
||||
import { NarrowUpArrowIcon } from "Assets/svgs";
|
||||
import { SkeletonLoader } from "Components/Skeleton";
|
||||
|
||||
const MkdListTableHead = ({ onSort, columns }) => {
|
||||
return (
|
||||
<>
|
||||
<tr className="flex !h-[2.25rem] !max-h-[2.25rem] !min-h-[2.25rem] overflow-hidden">
|
||||
{!columns?.length ? (
|
||||
<th scope="col" className={`!w-full !min-w-full !max-w-full `}>
|
||||
<SkeletonLoader
|
||||
count={1}
|
||||
counts={[1]}
|
||||
className="!m-0 !h-full !p-0"
|
||||
/>
|
||||
</th>
|
||||
) : null}
|
||||
{columns.map((column, i) => {
|
||||
if (column?.accessor !== "" && column?.selected_column) {
|
||||
return (
|
||||
<th
|
||||
key={i}
|
||||
scope="col"
|
||||
className={`flex !w-[6.25rem] !min-w-[6.25rem] max-w-[auto] shrink-0 grow cursor-pointer justify-start px-[.75rem] py-[.5rem] text-left text-sm font-[400] capitalize leading-[1.5rem] tracking-wider text-sub-500 ${
|
||||
column.isSorted ? "cursor-pointer" : ""
|
||||
} `}
|
||||
onClick={column.isSorted ? () => onSort(i) : undefined}
|
||||
>
|
||||
<div className="flex !w-auto !min-w-fit max-w-[auto] shrink-0 items-center justify-start gap-2">
|
||||
{column.header}
|
||||
<span className="shrink-0">
|
||||
{column.isSorted ? (
|
||||
<NarrowUpArrowIcon
|
||||
className={`h-2 w-2 ${
|
||||
column.isSortedDesc ? "rotate-180" : ""
|
||||
}`}
|
||||
/>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
</th>
|
||||
);
|
||||
}
|
||||
})}
|
||||
</tr>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default MkdListTableHead;
|
||||
@@ -0,0 +1,96 @@
|
||||
import React, { Fragment } from "react";
|
||||
import MkdListTableRowDropdown from "./MkdListTableRowDropdown";
|
||||
import MkdListTableRowButtons from "./MkdListTableRowButtons";
|
||||
|
||||
const MkdListTableRightActionPanel = ({
|
||||
table,
|
||||
loading,
|
||||
columns = [],
|
||||
actions,
|
||||
actionPostion = [],
|
||||
tableRole,
|
||||
deleteItem,
|
||||
deleteLoading,
|
||||
actionId = "id",
|
||||
showDeleteModal,
|
||||
currentTableData = [],
|
||||
setShowDeleteModal,
|
||||
}) => {
|
||||
const [deleteId, setIdToDelete] = React.useState(null);
|
||||
|
||||
const setDeleteId = async (id) => {
|
||||
console.log("id >>", id);
|
||||
setShowDeleteModal(true);
|
||||
setIdToDelete(id);
|
||||
};
|
||||
return (
|
||||
<Fragment>
|
||||
{!loading && currentTableData.length && columns.length ? (
|
||||
<>
|
||||
{(columns.find((item) => item.accessor === "") &&
|
||||
actions?.delete?.show) ||
|
||||
Object.keys(actions).filter(
|
||||
(key) =>
|
||||
actions[key]?.show &&
|
||||
actions[key]?.locations &&
|
||||
actions[key]?.locations?.length &&
|
||||
(actions[key]?.locations?.includes("dropdown") ||
|
||||
actions[key]?.locations?.includes("buttons"))
|
||||
)?.length ? (
|
||||
<div className="h-full ">
|
||||
<div className="grid grid-rows-[auto_1fr]">
|
||||
<div className="flex !h-[2.65rem] !max-h-[2.65rem] !min-h-[2.65rem] border-b !bg-weak-100 "></div>
|
||||
|
||||
<div className="flex flex-col px-1">
|
||||
{currentTableData?.map((rowData, rowDataIndex) => {
|
||||
return (
|
||||
<div
|
||||
className="flex !h-[3rem] !max-h-[3rem] !min-h-[3rem] w-full items-center border-b"
|
||||
key={rowDataIndex}
|
||||
>
|
||||
{/* // key={rowDataIndex}
|
||||
// className="!h-[3rem] !max-h-[3rem] !min-h-[3rem] w-fit border-b" */}
|
||||
{actionPostion?.includes("dropdown") ? (
|
||||
<>
|
||||
{/* <KebabIcon className="rotate-90" /> */}
|
||||
<MkdListTableRowDropdown
|
||||
actions={actions}
|
||||
columns={columns}
|
||||
row={rowData}
|
||||
setDeleteId={setDeleteId}
|
||||
// onPopoverStateChange={onPopoverStateChange}
|
||||
actionId={actionId}
|
||||
/>
|
||||
</>
|
||||
) : null}
|
||||
{actionPostion?.includes("buttons") ? (
|
||||
<>
|
||||
<MkdListTableRowButtons
|
||||
row={rowData}
|
||||
actions={actions}
|
||||
columns={columns}
|
||||
actionId={actionId}
|
||||
setDeleteId={setDeleteId}
|
||||
/>
|
||||
</>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
</>
|
||||
) : null}
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export default MkdListTableRightActionPanel;
|
||||
// [
|
||||
// actions?.view?.show,
|
||||
// actions?.edit?.show,
|
||||
// actions?.delete?.show,
|
||||
// actions?.status?.show,
|
||||
// ].includes(true) ||
|
||||
@@ -0,0 +1,296 @@
|
||||
import React from "react";
|
||||
import { MdPhoto } from "react-icons/md";
|
||||
import { MkdPopover } from "Components/MkdPopover";
|
||||
import { NotesIcon } from "Assets/svgs";
|
||||
|
||||
import { truncate, processList, mappingValues } from "Utils/utils";
|
||||
import { GlobalContext } from "Context/Global";
|
||||
import { AuthContext } from "Context/Auth";
|
||||
import { SkeletonLoader } from "Components/Skeleton";
|
||||
|
||||
const statusNames = {
|
||||
status: "status",
|
||||
verify: "verify",
|
||||
receipt_status: "receipt_status",
|
||||
};
|
||||
|
||||
const MkdListTableRow = ({
|
||||
column = null,
|
||||
actions,
|
||||
tableRole = "",
|
||||
actionPostion = [],
|
||||
actionId = "id",
|
||||
handleTableCellChange,
|
||||
selectedIds = [],
|
||||
handleSelectRow,
|
||||
columnIndex,
|
||||
allowEditing,
|
||||
onPopoverStateChange = null,
|
||||
columns = [],
|
||||
row,
|
||||
currentTableData = [],
|
||||
expandRow = false,
|
||||
}) => {
|
||||
const { dispatch } = React.useContext(AuthContext);
|
||||
const {
|
||||
dispatch: globalDispatch,
|
||||
state: {},
|
||||
} = React.useContext(GlobalContext);
|
||||
|
||||
const [listResult, setResult] = React.useState(null);
|
||||
|
||||
const showWithLimit = (column) => {
|
||||
if (expandRow) {
|
||||
if (["string", "number"].includes(typeof listResult)) {
|
||||
return (
|
||||
<span
|
||||
className={`flex w-fit items-center justify-normal gap-[.25rem] rounded-[.375rem] border border-soft-200 p-[.25rem_.5rem_.25rem_.25rem] capitalize`}
|
||||
>
|
||||
{listResult}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
if (typeof listResult === "object" && Array.isArray(listResult)) {
|
||||
return (
|
||||
<>
|
||||
{listResult.map((item, itemKey) => {
|
||||
return (
|
||||
<span
|
||||
className={`flex w-fit items-center justify-normal gap-[.25rem] rounded-[.375rem] border border-soft-200 p-[.25rem_.5rem_.25rem_.25rem] capitalize`}
|
||||
key={itemKey}
|
||||
>
|
||||
{item}
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (["string", "number"].includes(typeof listResult)) {
|
||||
return (
|
||||
<span
|
||||
className={`flex w-fit items-center justify-normal gap-[.25rem] rounded-[.375rem] border border-soft-200 p-[.25rem_.5rem_.25rem_.25rem] capitalize`}
|
||||
>
|
||||
{listResult}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
if (typeof listResult === "object" && Array.isArray(listResult)) {
|
||||
const lengthToHide =
|
||||
listResult.length > column.limit
|
||||
? `+${listResult.length - column?.limit}`
|
||||
: null;
|
||||
const itemsToShow = listResult
|
||||
.map((item, index) => {
|
||||
if (index + 1 <= column.limit) {
|
||||
return item;
|
||||
}
|
||||
})
|
||||
.filter(Boolean);
|
||||
|
||||
if (lengthToHide) itemsToShow.push(lengthToHide);
|
||||
|
||||
return (
|
||||
<>
|
||||
{itemsToShow.map((item, itemKey) => {
|
||||
return (
|
||||
<span
|
||||
className={`flex w-fit items-center justify-normal gap-[.25rem] rounded-[.375rem] border border-soft-200 p-[.25rem_.5rem_.25rem_.25rem] capitalize`}
|
||||
key={itemKey}
|
||||
>
|
||||
{item}
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const getColumnListData = async (value, column) => {
|
||||
// TO DO the processList function
|
||||
const result = await processList(value, column, globalDispatch, dispatch);
|
||||
if (["string", "number"].includes(typeof result)) {
|
||||
setResult(result);
|
||||
}
|
||||
|
||||
if (typeof result === "object" && Array.isArray(result)) {
|
||||
setResult(() => [...result]);
|
||||
}
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
if (column?.list && !listResult) {
|
||||
getColumnListData(row[column?.accessor], column);
|
||||
}
|
||||
}, [column?.accessor]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`!h-[3rem] !max-h-[3rem] !min-h-[3rem] w-full min-w-full max-w-fit whitespace-nowrap !border-b border-soft-200 bg-white px-[.75rem] py-[.5rem] ${
|
||||
columnIndex === 0 ? "border-l border-r" : "border-r"
|
||||
}`}
|
||||
>
|
||||
{column?.accessor?.indexOf("image") > -1 ||
|
||||
(column?.accessor?.indexOf("photo") > -1 && column?.selected_column) ? (
|
||||
<LazyLoad>
|
||||
<MkdPopover
|
||||
display={<MdPhoto className="peer " />}
|
||||
openOnClick={false}
|
||||
zIndex={999999999999999}
|
||||
onPopoverStateChange={onPopoverStateChange}
|
||||
place="left-end"
|
||||
tooltipClasses={`whitespace-nowrap h-fit min-h-[1rem] max-h-fit w-[18.75rem] !rounded-lg border border-[#a8a8a8] !bg-white p-2 text-sm text-[#525252] shadow-md`}
|
||||
>
|
||||
<LazyLoad
|
||||
className={`h-[18.75rem] w-[18.75rem] whitespace-nowrap !rounded-lg border border-[#a8a8a8] !bg-white p-2 text-sm text-[#525252] shadow-md`}
|
||||
>
|
||||
<img
|
||||
src={row[column?.accessor]}
|
||||
className="w-[18.75rem]"
|
||||
alt=""
|
||||
/>
|
||||
</LazyLoad>
|
||||
</MkdPopover>
|
||||
</LazyLoad>
|
||||
) : (column?.accessor?.indexOf("pdf") > -1 ||
|
||||
column?.accessor?.indexOf("doc") > -1 ||
|
||||
column?.accessor?.indexOf("file") > -1 ||
|
||||
column?.accessor?.indexOf("video") > -1) &&
|
||||
column?.selected_column ? (
|
||||
<a
|
||||
className="text-blue-500"
|
||||
target="_blank"
|
||||
href={row[column?.accessor]}
|
||||
rel="noreferrer"
|
||||
>
|
||||
{" "}
|
||||
View
|
||||
</a>
|
||||
) : column?.join && column?.selected_column ? (
|
||||
<>
|
||||
{row[column?.join] && row[column?.join][column?.accessor]
|
||||
? row[column?.join][column?.accessor]
|
||||
: null}
|
||||
</>
|
||||
) : column?.mappingExist &&
|
||||
["status", "role", "verify", "receipt_status"].includes(
|
||||
column?.accessor
|
||||
) &&
|
||||
!["admin"].includes(tableRole) &&
|
||||
column?.selected_column ? (
|
||||
<span
|
||||
style={{
|
||||
backgroudColor: column?.mappings[row[column?.accessor]]?.bg,
|
||||
color: column?.mappings[row[column?.accessor]]?.color,
|
||||
}}
|
||||
className={`flex w-fit items-center justify-normal gap-[.25rem] rounded-[.375rem] border border-soft-200 p-[.25rem_.5rem_.25rem_.25rem] capitalize`}
|
||||
>
|
||||
{mappingValues[
|
||||
column?.mappings[row[column?.accessor]]?.toLowerCase()
|
||||
] ?? column?.mappings[row[column?.accessor]]}
|
||||
</span>
|
||||
) : column?.mappingExist &&
|
||||
allowEditing &&
|
||||
["admin"].includes(tableRole) &&
|
||||
column?.selected_column ? (
|
||||
<select
|
||||
// onChange={(e) =>
|
||||
// handleTableCellChange(
|
||||
// row[actionId],
|
||||
// e.target.value,
|
||||
// i,
|
||||
// column?.accessor
|
||||
// )
|
||||
// }
|
||||
value={row[column?.accessor]}
|
||||
>
|
||||
{Object.keys(column?.mappings).map((columnDataKey, index) => (
|
||||
<option
|
||||
key={index}
|
||||
value={columnDataKey}
|
||||
selected={columnDataKey === row[column?.accessor]}
|
||||
>
|
||||
{column?.mappings[columnDataKey]}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
) : column?.mappingExist &&
|
||||
!allowEditing &&
|
||||
["admin"].includes(tableRole) &&
|
||||
column?.selected_column ? (
|
||||
<span
|
||||
style={{
|
||||
backgroundColor: column?.mappings[row[column?.accessor]]?.bg,
|
||||
color: column?.mappings[row[column?.accessor]]?.color,
|
||||
}}
|
||||
className={`flex w-fit items-center justify-normal gap-[.25rem] rounded-[.375rem] border border-soft-200 p-[.25rem_.5rem_.25rem_.25rem] capitalize`}
|
||||
>
|
||||
{mappingValues[
|
||||
column?.mappings[row[column?.accessor]]?.toLowerCase()
|
||||
] ?? column?.mappings[row[column?.accessor]]}
|
||||
</span>
|
||||
) : !column?.mappingExist &&
|
||||
column?.accessor !== "id" &&
|
||||
column?.accessor !== "create_at" &&
|
||||
column?.accessor !== "update_at" &&
|
||||
column?.accessor !== "user_id" &&
|
||||
column?.accessor !== "" &&
|
||||
allowEditing &&
|
||||
column?.selected_column ? (
|
||||
<input
|
||||
className="text-ellipsis border-0"
|
||||
type="text"
|
||||
value={row[column?.accessor]}
|
||||
// onChange={(e) =>
|
||||
// handleTableCellChange(
|
||||
// row[actionId],
|
||||
// e.target.value,
|
||||
// i,
|
||||
// column?.accessor
|
||||
// )
|
||||
// }
|
||||
/>
|
||||
) : column?.truncate && column?.selected_column ? (
|
||||
<>{truncate(row[column?.accessor], 50)}</>
|
||||
) : column?.replace && column?.selected_column ? (
|
||||
<>{truncate(row[column?.accessor], 30)}</>
|
||||
) : column?.list && column?.selected_column ? (
|
||||
<>
|
||||
{listResult ? (
|
||||
<div className="flex items-center gap-2">
|
||||
{showWithLimit(column)}
|
||||
</div>
|
||||
) : (
|
||||
<SkeletonLoader
|
||||
count={1}
|
||||
counts={[2]}
|
||||
className={`!h-[2rem] !gap-0 rounded-[.625rem] !bg-[#ebebeb] !p-0`}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
) : column?.isCurrency && column?.selected_column ? (
|
||||
<>
|
||||
{column?.currency}
|
||||
{row[column?.accessor]}
|
||||
</>
|
||||
) : ["notes"].includes(column?.accessor) && column?.selected_column ? (
|
||||
<button type="button" className="flex items-center gap-2 ">
|
||||
<NotesIcon className="h-[1.0313rem] w-[1.0313rem]" />
|
||||
View
|
||||
</button>
|
||||
) : column?.accessor !== "" && column?.selected_column ? (
|
||||
<>
|
||||
{typeof row[column?.accessor] === "object"
|
||||
? null
|
||||
: row[column?.accessor]}
|
||||
</>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default MkdListTableRow;
|
||||
@@ -0,0 +1,80 @@
|
||||
import React from "react";
|
||||
import { AddButton } from "Components/AddButton";
|
||||
import { processBind } from "./MkdListTableBindOperations";
|
||||
|
||||
const MkdListTableRowDropdown = ({
|
||||
row,
|
||||
columns,
|
||||
actions,
|
||||
actionId = "id",
|
||||
setDeleteId = null,
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<div className="z-3 relative flex h-fit w-fit items-center gap-2">
|
||||
{Object.keys(actions)
|
||||
.filter(
|
||||
(key) =>
|
||||
actions[key]?.locations &&
|
||||
actions[key]?.locations?.includes("buttons")
|
||||
)
|
||||
.map((key, keyIndex) => {
|
||||
if (actions[key]?.bind) {
|
||||
switch (actions[key]?.bind?.action) {
|
||||
case "hide":
|
||||
if (!processBind(actions[key], row)) {
|
||||
return (
|
||||
<AddButton
|
||||
key={keyIndex}
|
||||
title={actions[key]?.children ?? key}
|
||||
onClick={() => {
|
||||
if (["delete"].includes(key)) {
|
||||
if (setDeleteId) {
|
||||
setDeleteId(row[actionId]);
|
||||
}
|
||||
} else if (actions[key]?.action) {
|
||||
actions[key]?.action([row[actionId]]);
|
||||
}
|
||||
}}
|
||||
className={`!h-[2rem] !w-[2.0713rem] !border-soft-200 !bg-white`}
|
||||
>
|
||||
{actions[key]?.icon
|
||||
? actions[key]?.icon
|
||||
: actions[key]?.children ?? key}
|
||||
</AddButton>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!actions[key]?.bind) {
|
||||
return (
|
||||
<AddButton
|
||||
key={keyIndex}
|
||||
title={actions[key]?.children ?? key}
|
||||
onClick={() => {
|
||||
if (["delete"].includes(key) && !actions[key]?.action) {
|
||||
if (setDeleteId) {
|
||||
setDeleteId(row[actionId]);
|
||||
}
|
||||
} else if (actions[key]?.action) {
|
||||
actions[key]?.action([row[actionId]]);
|
||||
}
|
||||
// if (actions[key]?.action) {
|
||||
// actions[key]?.action([row[actionId]]);
|
||||
// }
|
||||
}}
|
||||
className={`!h-[2rem] !w-[2.0713rem] !border-soft-200 !bg-white`}
|
||||
>
|
||||
{actions[key]?.icon
|
||||
? actions[key]?.icon
|
||||
: actions[key]?.children ?? key}
|
||||
</AddButton>
|
||||
);
|
||||
}
|
||||
})}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default MkdListTableRowDropdown;
|
||||
@@ -0,0 +1,119 @@
|
||||
import React from "react";
|
||||
import { AiFillEye } from "react-icons/ai";
|
||||
import { MkdPopover } from "Components/MkdPopover";
|
||||
import { DropdownOption } from "Components/DropdownOptions";
|
||||
import { KebabIcon, TrashIcon, EditIcon2, UpdateIcon } from "Assets/svgs";
|
||||
import { optionTypes } from "Utils/utils";
|
||||
import RenderDropdownActions from "./RenderDropdownActions";
|
||||
import RenderActions from "./RenderActions";
|
||||
|
||||
const MkdListTableRowDropdown = ({
|
||||
row,
|
||||
columns,
|
||||
actions,
|
||||
actionId = "id",
|
||||
setDeleteId,
|
||||
onPopoverStateChange = null,
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<div className="items center z-3 relative flex h-fit w-fit">
|
||||
<MkdPopover
|
||||
display={<KebabIcon className="rotate-90" />}
|
||||
tooltipClasses="!rounded-[.5rem] !min-w-[11rem] !px-0 !right-[3.25rem] !border bg-white"
|
||||
place={"left-end"}
|
||||
onPopoverStateChange={onPopoverStateChange}
|
||||
>
|
||||
{actions?.edit?.show && (
|
||||
<DropdownOption
|
||||
className="bg-white"
|
||||
icon={<EditIcon2 />}
|
||||
name={"Edit"}
|
||||
onClick={() => {
|
||||
if (actions?.edit?.action) {
|
||||
actions?.edit?.action([row[actionId]]);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{actions?.view?.show && (
|
||||
<DropdownOption
|
||||
icon={<AiFillEye className="text-gray-400" />}
|
||||
name={"View"}
|
||||
onClick={() => {
|
||||
if (actions?.view?.action) {
|
||||
actions?.view?.action([row[actionId]]);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{actions?.status?.show && (
|
||||
<DropdownOption
|
||||
icon={<UpdateIcon />}
|
||||
name={getStatusMap(statusRow, statusCol, row)}
|
||||
onClick={() => {
|
||||
if (actions?.status?.action) {
|
||||
actions?.status?.action([row[actionId]]);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{actions?.delete?.show && (
|
||||
<DropdownOption
|
||||
icon={<TrashIcon />}
|
||||
name={"Delete"}
|
||||
onClick={() => {
|
||||
if (!actions[key]?.action) {
|
||||
if (setDeleteId) {
|
||||
setDeleteId(row[actionId]);
|
||||
}
|
||||
} else if (actions[key]?.action) {
|
||||
actions[key]?.action([row[actionId]]);
|
||||
}
|
||||
// setDeleteId(row[actionId]);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{Object.keys(actions)
|
||||
.filter(
|
||||
(key) =>
|
||||
actions[key]?.show &&
|
||||
actions[key]?.locations &&
|
||||
actions[key]?.locations?.includes("dropdown")
|
||||
)
|
||||
.map((key, keyIndex) => {
|
||||
if (
|
||||
actions[key]?.type &&
|
||||
[optionTypes.DROPDOWN].includes(actions[key]?.type)
|
||||
) {
|
||||
return (
|
||||
<RenderDropdownActions
|
||||
row={row}
|
||||
key={keyIndex}
|
||||
actionKey={key}
|
||||
actionId={actionId}
|
||||
action={actions[key]}
|
||||
/>
|
||||
);
|
||||
} else if (!actions[key]?.type) {
|
||||
return (
|
||||
<RenderActions
|
||||
row={row}
|
||||
key={keyIndex}
|
||||
actionId={actionId}
|
||||
action={actions[key]}
|
||||
/>
|
||||
);
|
||||
}
|
||||
})}
|
||||
</MkdPopover>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default MkdListTableRowDropdown;
|
||||
@@ -0,0 +1,85 @@
|
||||
import React, { Fragment } from "react";
|
||||
|
||||
const MkdListTableSelectRow = ({
|
||||
loading,
|
||||
columns = [],
|
||||
actions,
|
||||
currentTableData = [],
|
||||
areAllRowsSelected,
|
||||
handleSelectAll,
|
||||
handleSelectRow,
|
||||
actionId = "id",
|
||||
selectedIds,
|
||||
}) => {
|
||||
return (
|
||||
<Fragment>
|
||||
{!loading && currentTableData?.length && columns.length ? (
|
||||
<>
|
||||
{[actions?.select?.show].includes(true) ||
|
||||
columns.find((item) => item?.accessor === "row") ? (
|
||||
<div className="">
|
||||
<div className="flex !h-[2.65rem] !max-h-[2.65rem] !min-h-[2.65rem] w-fit !bg-weak-100 ">
|
||||
{[actions?.select?.show].includes(true) ? (
|
||||
<div
|
||||
className={`!w-[2.65rem] !min-w-[2.65rem] !max-w-[2.65rem] cursor-pointer !bg-weak-100 px-[.75rem] py-[.5rem] text-sm font-[400] capitalize leading-[1.5rem] tracking-wider text-sub-500`}
|
||||
>
|
||||
{actions?.select?.multiple ? (
|
||||
<input
|
||||
type="checkbox"
|
||||
disabled={!actions?.select?.multiple}
|
||||
id="select_all_rows"
|
||||
className={`focus:shadow-outline mr-1 !h-4 !w-4 cursor-pointer appearance-none rounded border leading-tight text-primary shadow focus:outline-none focus:ring-0`}
|
||||
checked={areAllRowsSelected}
|
||||
onChange={handleSelectAll}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
) : null}
|
||||
{columns.find((item) => item.accessor === "row") ? (
|
||||
<div
|
||||
className={`flex !w-[2.65rem] !min-w-[2.65rem] !max-w-[2.65rem] cursor-pointer justify-center !bg-weak-100 py-[.5rem] text-sm font-[400] capitalize leading-[1.5rem] tracking-wider text-sub-500 `}
|
||||
>
|
||||
Row
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
{currentTableData?.map((rowData, rowDataIndex) => {
|
||||
return (
|
||||
<div
|
||||
className=" flex !h-[3rem] !max-h-[3rem] !min-h-[3rem] border-b"
|
||||
key={rowDataIndex}
|
||||
>
|
||||
{[actions?.select?.show].includes(true) && (
|
||||
<div
|
||||
className={` !h-full !max-h-full !min-h-full !w-[2.65rem] !min-w-[2.65rem] !max-w-[2.65rem] cursor-pointer px-[.75rem] py-[.5rem] text-sm font-[400] capitalize leading-[1.5rem] tracking-wider text-sub-500`}
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
// disabled={!actions?.select?.multiple}
|
||||
className={`focus:shadow-outline mr-1 !h-4 !w-4 cursor-pointer appearance-none rounded border leading-tight text-primary shadow focus:outline-none focus:ring-0`}
|
||||
name="select_item"
|
||||
checked={selectedIds.includes(rowData[actionId])}
|
||||
onChange={() => handleSelectRow(rowData[actionId])}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{columns.find((item) => item.accessor === "row") ? (
|
||||
<div
|
||||
className={`flex h-full !w-[2.65rem] !min-w-[2.65rem] !max-w-[2.65rem] items-center whitespace-nowrap px-[.75rem] py-[.5rem] text-sm`}
|
||||
>
|
||||
{rowDataIndex + 1}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
) : null}
|
||||
</>
|
||||
) : null}
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export default MkdListTableSelectRow;
|
||||
@@ -0,0 +1,809 @@
|
||||
import React, { memo, useMemo } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { yupResolver } from "@hookform/resolvers/yup";
|
||||
import * as yup from "yup";
|
||||
import MkdSDK from "Utils/MkdSDK";
|
||||
import { StringCaser } from "Utils/utils";
|
||||
import { AuthContext, tokenExpireError } from "Context/Auth";
|
||||
import {
|
||||
GlobalContext,
|
||||
customRequest,
|
||||
getMany,
|
||||
setLoading as setGlobalLoading,
|
||||
} from "Context/Global";
|
||||
import {
|
||||
MkdListTable,
|
||||
OverlayTableActions,
|
||||
TableActions,
|
||||
} from "Components/MkdListTable";
|
||||
import { AddButton } from "Components/AddButton";
|
||||
import TreeSDK from "Utils/TreeSDK";
|
||||
import "./MkdListTable.css";
|
||||
import { ExCircleIcon } from "Assets/svgs";
|
||||
|
||||
import { MkdInput } from "Components/MkdInput";
|
||||
|
||||
let sdk = new MkdSDK();
|
||||
// const getSchemaStructure = (schema) => {
|
||||
// return;
|
||||
// };
|
||||
const getType = (type) => {
|
||||
switch (type) {
|
||||
case "varchar":
|
||||
return "text";
|
||||
case "text":
|
||||
return "textarea";
|
||||
case "mediumtext":
|
||||
return "textarea";
|
||||
case "longtext":
|
||||
return "textarea";
|
||||
case "tinyint":
|
||||
return "number";
|
||||
case "int":
|
||||
return "number";
|
||||
case "bigint":
|
||||
return "number";
|
||||
case "float":
|
||||
return "number";
|
||||
case "double":
|
||||
return "number";
|
||||
case "image":
|
||||
return "image";
|
||||
case "file":
|
||||
return "file";
|
||||
case "date":
|
||||
return "date";
|
||||
case "datetime":
|
||||
return "datetime";
|
||||
default:
|
||||
return "text";
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @params {"dropwdown" | "ontop" | "overlay"} actionPostion
|
||||
*
|
||||
*/
|
||||
const MkdListTableV2 = ({
|
||||
externalData = [],
|
||||
useExternalData = false,
|
||||
defaultColumns = [],
|
||||
columnModel = null,
|
||||
// setColumns,
|
||||
actions = {
|
||||
view: { show: true, multiple: true, action: null },
|
||||
edit: { show: true, multiple: true, action: null },
|
||||
delete: { show: true, multiple: true, action: null },
|
||||
select: { show: true, multiple: true, action: null },
|
||||
action: {
|
||||
show: false,
|
||||
multiple: false,
|
||||
action: null,
|
||||
showChildren: true,
|
||||
children: "+",
|
||||
type: "",
|
||||
className: "",
|
||||
locations: [],
|
||||
icon: null,
|
||||
},
|
||||
add: {
|
||||
show: true,
|
||||
multiple: true,
|
||||
action: null,
|
||||
showChildren: true,
|
||||
children: "+",
|
||||
type: "",
|
||||
className: "",
|
||||
},
|
||||
export: {
|
||||
show: true,
|
||||
multiple: true,
|
||||
action: null,
|
||||
showText: false,
|
||||
className: "",
|
||||
},
|
||||
},
|
||||
actionPostion = ["dropdown"], // "dropwdown" | "ontop" | "overlay" | "button"
|
||||
actionId = "id",
|
||||
tableRole = "admin",
|
||||
table = "user",
|
||||
tableTitle = "",
|
||||
tableSchema = [],
|
||||
hasFilter = true,
|
||||
schemaFields = [],
|
||||
showPagination = true,
|
||||
defaultFilter = [],
|
||||
refreshRef = null,
|
||||
allowEditing = false,
|
||||
allowSortColumns = true,
|
||||
topClasses = "",
|
||||
join = [],
|
||||
filterDisplays = [],
|
||||
}) => {
|
||||
const tdk = new TreeSDK();
|
||||
|
||||
const { dispatch } = React.useContext(AuthContext);
|
||||
const {
|
||||
dispatch: globalDispatch,
|
||||
state: { columModel },
|
||||
} = React.useContext(GlobalContext);
|
||||
|
||||
const [query, setQuery] = React.useState("");
|
||||
const [currentTableData, setCurrentTableData] = React.useState([]);
|
||||
const [pageSize, setPageSize] = React.useState(1000);
|
||||
const [pageCount, setPageCount] = React.useState(0);
|
||||
const [dataTotal, setDataTotal] = React.useState(0);
|
||||
const [currentPage, setPage] = React.useState(1);
|
||||
const [canPreviousPage, setCanPreviousPage] = React.useState(false);
|
||||
const [canNextPage, setCanNextPage] = React.useState(false);
|
||||
const [showDeleteModal, setShowDeleteModal] = React.useState(false);
|
||||
const [deleteLoading, setDeleteLoading] = React.useState(false);
|
||||
const [selectedOptions, setSelectedOptions] = React.useState([]);
|
||||
const [filterConditions, setFilterConditions] = React.useState([]);
|
||||
const [selectedItems, setSelectedItems] = React.useState([]);
|
||||
const [searchValue, setSearchValue] = React.useState("");
|
||||
const [isSearchDirty, setIsSearchDirty] = React.useState(false);
|
||||
// const [optionValue, setOptionValue] = React.useState("eq");
|
||||
const [isLoading, setIsLoading] = React.useState(false);
|
||||
const [loading, setLoading] = React.useState(false);
|
||||
const [runFilter, setRunFilter] = React.useState(false);
|
||||
const [searchField, setSearchField] = React.useState("name");
|
||||
|
||||
const [columnData, setColumnData] = React.useState(null);
|
||||
const [columns, setColumns] = React.useState([]);
|
||||
const [columnId, setColumnId] = React.useState(0);
|
||||
const [popoverShown, setPopoverShow] = React.useState(false);
|
||||
|
||||
const selectedOptionsMemo = useMemo(() => selectedOptions, [selectedOptions]);
|
||||
|
||||
const schema = yup.object({});
|
||||
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
setError,
|
||||
reset,
|
||||
formState: { errors },
|
||||
} = useForm({
|
||||
resolver: yupResolver(schema),
|
||||
});
|
||||
|
||||
function onSort(columnIndex) {
|
||||
console.log(columns[columnIndex]);
|
||||
if (columns[columnIndex].isSorted) {
|
||||
columns[columnIndex].isSortedDesc = !columns[columnIndex].isSortedDesc;
|
||||
} else {
|
||||
columns.map((i) => (i.isSorted = false));
|
||||
columns.map((i) => (i.isSortedDesc = false));
|
||||
columns[columnIndex].isSorted = true;
|
||||
}
|
||||
|
||||
(async function () {
|
||||
await getData(currentPage, pageSize, {
|
||||
filterConditions,
|
||||
order: columns[columnIndex].accessor,
|
||||
direction: columns[columnIndex].isSortedDesc ? "desc" : "asc",
|
||||
});
|
||||
})();
|
||||
}
|
||||
|
||||
function updatePageSize(limit) {
|
||||
(async function () {
|
||||
setPageSize(limit);
|
||||
|
||||
if (isSearchDirty && !searchValue) {
|
||||
await getData(currentPage, limit);
|
||||
setIsSearchDirty(false);
|
||||
} else if (isSearchDirty && searchValue) {
|
||||
getSearchData({ limit, page: currentPage });
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
||||
function setOptionValue(field, value, uid) {
|
||||
const tempSelectedOptions = [...selectedOptions];
|
||||
const data = tempSelectedOptions.map((item) => {
|
||||
if (item?.uid === uid) {
|
||||
return {
|
||||
...item,
|
||||
[field]: value,
|
||||
};
|
||||
}
|
||||
return item;
|
||||
});
|
||||
setSelectedOptions((prev) => [...data]);
|
||||
// console.log("field", field);
|
||||
if (field === "value") {
|
||||
// console.log("field", field);
|
||||
setRunFilter(true);
|
||||
}
|
||||
}
|
||||
|
||||
function previousPage() {
|
||||
(async function () {
|
||||
if (isSearchDirty && !searchValue) {
|
||||
// await getData(currentPage, pageSize, { filterConditions: [] });
|
||||
await getData(
|
||||
currentPage - 1 > 0 ? currentPage - 1 : currentPage,
|
||||
pageSize
|
||||
);
|
||||
setIsSearchDirty(false);
|
||||
} else if (isSearchDirty && searchValue) {
|
||||
getSearchData({
|
||||
limit: pageSize,
|
||||
page: currentPage - 1 > 0 ? currentPage - 1 : currentPage,
|
||||
});
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
||||
function updateCurrentPage(page) {
|
||||
(async function () {
|
||||
setPage(page);
|
||||
if (isSearchDirty && !searchValue) {
|
||||
await getData(page, pageSize);
|
||||
setIsSearchDirty(false);
|
||||
} else if (isSearchDirty && searchValue) {
|
||||
getSearchData({ limit: pageSize, page });
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
||||
function nextPage() {
|
||||
(async function () {
|
||||
if (isSearchDirty && !searchValue) {
|
||||
await getData(
|
||||
currentPage + 1 <= pageCount ? currentPage + 1 : currentPage,
|
||||
pageSize
|
||||
);
|
||||
setIsSearchDirty(false);
|
||||
} else if (isSearchDirty && searchValue) {
|
||||
getSearchData({
|
||||
limit: pageSize,
|
||||
page: currentPage + 1 <= pageCount ? currentPage + 1 : currentPage,
|
||||
});
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
||||
const addFilterCondition = (option, selectedValue, inputValue) => {
|
||||
const input =
|
||||
selectedValue === "eq" && isNaN(inputValue)
|
||||
? `${inputValue}`
|
||||
: inputValue;
|
||||
const condition = `${option},${selectedValue},${input}`.toLowerCase();
|
||||
setFilterConditions((prevConditions) => {
|
||||
const newConditions = prevConditions.filter(
|
||||
(condition) => !condition.includes(option)
|
||||
);
|
||||
return [...newConditions, condition];
|
||||
});
|
||||
setSearchValue(inputValue);
|
||||
};
|
||||
// options.size = payload.limit;
|
||||
// options.order = payload.sortId;
|
||||
// options.direction = payload.direction;
|
||||
// options.page = payload.page;
|
||||
// options.join = payload.join;
|
||||
async function getData(pageNum, limitNum, currentTableData) {
|
||||
// console.log("currentTableData >>", currentTableData);
|
||||
try {
|
||||
setLoading(true);
|
||||
const result = await tdk.getPaginate(table, {
|
||||
size: limitNum,
|
||||
page: pageNum,
|
||||
...{
|
||||
...(join && join.length
|
||||
? {
|
||||
join,
|
||||
}
|
||||
: null),
|
||||
},
|
||||
...{
|
||||
...(currentTableData?.order
|
||||
? {
|
||||
order: currentTableData?.order,
|
||||
direction: currentTableData?.direction,
|
||||
}
|
||||
: null),
|
||||
},
|
||||
...{
|
||||
...(currentTableData?.filterConditions &&
|
||||
currentTableData?.filterConditions.length
|
||||
? {
|
||||
filter: [
|
||||
...currentTableData?.filterConditions,
|
||||
...(defaultFilter.length ? defaultFilter : []),
|
||||
],
|
||||
}
|
||||
: defaultFilter.length
|
||||
? { filter: [...defaultFilter] }
|
||||
: null),
|
||||
},
|
||||
});
|
||||
// sdk.setTable(table);
|
||||
// const result = await sdk.callRestAPI(
|
||||
// {
|
||||
// payload: {
|
||||
// ...currentTableData,
|
||||
// ...{
|
||||
// ...(filterConditions.length
|
||||
// ? {
|
||||
// filter: [
|
||||
// ...(defaultFilter.length && defaultFilter),
|
||||
// ...filterConditions,
|
||||
// ],
|
||||
// }
|
||||
// : defaultFilter.length
|
||||
// ? { filter: [...defaultFilter] }
|
||||
// : null),
|
||||
// },
|
||||
// },
|
||||
// page: pageNum,
|
||||
// limit: limitNum,
|
||||
// },
|
||||
// "PAGINATE"
|
||||
// );
|
||||
// if (!result) {
|
||||
// setLoading(false);
|
||||
// }
|
||||
setSelectedItems(() => []);
|
||||
const { list, total, limit, num_pages, page } = result;
|
||||
|
||||
setCurrentTableData(list);
|
||||
console.log("v2 component fetch result");
|
||||
console.log(result);
|
||||
console.log("list");
|
||||
console.log(list);
|
||||
setPageSize(limit);
|
||||
setPageCount(num_pages);
|
||||
setPage(page);
|
||||
setDataTotal(total);
|
||||
setCanPreviousPage(page > 1);
|
||||
setCanNextPage(page + 1 <= num_pages);
|
||||
setLoading(false);
|
||||
if (selectedItems?.length) {
|
||||
setSelectedItems(() => []);
|
||||
}
|
||||
} catch (error) {
|
||||
setLoading(false);
|
||||
console.log("ERROR", error);
|
||||
tokenExpireError(dispatch, error.message);
|
||||
}
|
||||
}
|
||||
|
||||
const deleteItem = async (id) => {
|
||||
async function deleteId(id) {
|
||||
try {
|
||||
setDeleteLoading(true);
|
||||
sdk.setTable(table);
|
||||
const result = await sdk.callRestAPI({ id }, "DELETE");
|
||||
if (!result?.error) {
|
||||
setCurrentTableData((list) =>
|
||||
list.filter((x) => Number(x.id) !== Number(id))
|
||||
);
|
||||
setDeleteLoading(false);
|
||||
setShowDeleteModal(false);
|
||||
}
|
||||
} catch (err) {
|
||||
setDeleteLoading(false);
|
||||
setShowDeleteModal(false);
|
||||
tokenExpireError(dispatch, err?.message);
|
||||
throw new Error(err);
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof id === "object") {
|
||||
id.forEach(async (idToDelete) => {
|
||||
await deleteId(idToDelete);
|
||||
});
|
||||
} else if (typeof id === "number") {
|
||||
await deleteId(id);
|
||||
}
|
||||
};
|
||||
|
||||
const exportTable = async (id) => {
|
||||
try {
|
||||
sdk.setTable(table);
|
||||
const result = await sdk.exportCSV();
|
||||
} catch (err) {
|
||||
throw new Error(err);
|
||||
}
|
||||
};
|
||||
|
||||
const handleAlphaSearchInput = async (e) => {
|
||||
if ([e?.code?.toLowerCase(), e?.key?.toLowerCase()].includes("enter")) {
|
||||
console.log("searchValue >>", searchValue);
|
||||
if (isSearchDirty && !searchValue) {
|
||||
await getData(currentPage, pageSize, { filterConditions: [] });
|
||||
setIsSearchDirty(false);
|
||||
} else if (isSearchDirty && searchValue) {
|
||||
getSearchData();
|
||||
}
|
||||
} else {
|
||||
setSearchValue(e?.target?.value);
|
||||
if (!isSearchDirty) {
|
||||
setIsSearchDirty(true);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const getSearchData = async (query = { limit: pageSize, page: 1 }) => {
|
||||
try {
|
||||
const apiEndpoint = `/v3/api/custom/qualitysign/generic/search/${table}?limit=${query?.limit}&page=${query?.page}`;
|
||||
setLoading(true);
|
||||
const result = await customRequest(globalDispatch, dispatch, {
|
||||
endpoint: apiEndpoint,
|
||||
method: "POST",
|
||||
payload: {
|
||||
search: searchValue,
|
||||
columns: columns,
|
||||
},
|
||||
});
|
||||
if (!result?.error) {
|
||||
setSelectedItems(() => []);
|
||||
const { data, total, limit, num_pages, page } = result;
|
||||
|
||||
setCurrentTableData(() => data);
|
||||
console.log("v2 component fetch search result");
|
||||
console.log(result);
|
||||
console.log("list");
|
||||
console.log(data);
|
||||
setPageSize(Number(limit));
|
||||
setPageCount(num_pages ?? pageCount);
|
||||
setPage(Number(page));
|
||||
setDataTotal(Number(total));
|
||||
setCanPreviousPage(Number(page) > 1);
|
||||
setCanNextPage(
|
||||
Number(page) + 1 <= num_pages ? Number(num_pages) : pageCount
|
||||
);
|
||||
setLoading(false);
|
||||
if (selectedItems?.length) {
|
||||
setSelectedItems(() => []);
|
||||
}
|
||||
}
|
||||
setLoading(false);
|
||||
} catch (error) {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const resetForm = async () => {
|
||||
reset();
|
||||
await getData(currentPage, pageSize);
|
||||
};
|
||||
|
||||
const onSubmit = (e) => {
|
||||
let filters = [];
|
||||
// find duplicate fields
|
||||
const uniqueSet = new Set(
|
||||
selectedOptionsMemo.map((item) => item?.accessor)
|
||||
);
|
||||
if (uniqueSet?.size) {
|
||||
uniqueSet.forEach((uniqueSetItem) => {
|
||||
const filterSet = selectedOptionsMemo.filter(
|
||||
(item) => item.accessor === uniqueSetItem
|
||||
);
|
||||
console.log("filterSet >>", filterSet);
|
||||
if (filterSet?.length > 0 && filterSet?.length > 1) {
|
||||
const valueSet = filterSet
|
||||
.map((item) => {
|
||||
if (item?.value) {
|
||||
return item;
|
||||
}
|
||||
})
|
||||
.filter(Boolean);
|
||||
|
||||
if (valueSet.length > 1) {
|
||||
// const value = `${uniqueSetItem},in,${valueSet
|
||||
// .map((item) => item.value)
|
||||
// .join(",")}`;
|
||||
// filters.push(value);
|
||||
valueSet.forEach((valueSetItem) => {
|
||||
switch (valueSetItem?.operator) {
|
||||
case "cs":
|
||||
case "eq":
|
||||
filters.push(
|
||||
`qualitysign_${table}.${valueSetItem?.accessor},o${valueSetItem?.operator},${valueSetItem?.value}`
|
||||
);
|
||||
break;
|
||||
default:
|
||||
filters.push(
|
||||
`qualitysign_${table}.${valueSetItem?.accessor},${valueSetItem?.operator},${valueSetItem?.value}`
|
||||
);
|
||||
}
|
||||
});
|
||||
} else if (valueSet.length === 1) {
|
||||
filters.push(
|
||||
`qualitysign_${table}.${valueSet[0]?.accessor},${valueSet[0]?.operator},${valueSet[0]?.value}`
|
||||
);
|
||||
}
|
||||
} else if (filterSet?.length === 1) {
|
||||
if (filterSet[0]?.value) {
|
||||
filters.push(
|
||||
`qualitysign_${table}.${filterSet[0]?.accessor},${filterSet[0]?.operator},${filterSet[0]?.value}`
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
// return console.log("filters >>", filters);
|
||||
if (filters?.length) {
|
||||
getData(currentPage, pageSize, { filterConditions: filters });
|
||||
} else {
|
||||
getData(currentPage, pageSize, { filterConditions: [] });
|
||||
}
|
||||
|
||||
// getData(currentPage, pageSize, filter);
|
||||
};
|
||||
|
||||
async function updateTableData(id, key, updatedData) {
|
||||
try {
|
||||
// setLoading(true);
|
||||
sdk.setTable(table);
|
||||
const result = await sdk.callRestAPI(
|
||||
{
|
||||
id,
|
||||
[key]: updatedData,
|
||||
},
|
||||
"PUT"
|
||||
);
|
||||
// if (result) {
|
||||
// setLoading(false);
|
||||
// }
|
||||
|
||||
console.log("update user data");
|
||||
console.log(result);
|
||||
} catch (error) {
|
||||
// setLoading(false);
|
||||
console.log("ERROR", error);
|
||||
tokenExpireError(dispatch, error.message);
|
||||
}
|
||||
}
|
||||
|
||||
async function handleTableCellChange(id, newValue, index, newValueKey) {
|
||||
console.log(newValue);
|
||||
console.log(index);
|
||||
console.log(newValueKey);
|
||||
let runApiCall;
|
||||
newValue = isNaN(Number.parseInt(newValue))
|
||||
? newValue
|
||||
: Number.parseInt(newValue);
|
||||
try {
|
||||
clearTimeout(runApiCall);
|
||||
runApiCall = setTimeout(async () => {
|
||||
await updateTableData(id, newValueKey, newValue);
|
||||
}, 200);
|
||||
setCurrentTableData((prevData) => {
|
||||
const updatedData = prevData.map((item, i) => {
|
||||
if (i === index) {
|
||||
return {
|
||||
...item,
|
||||
[newValueKey]: newValue,
|
||||
};
|
||||
}
|
||||
return item;
|
||||
});
|
||||
return updatedData;
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
const populateColums = (result) => {
|
||||
setColumnId(result?.data[0]?.id);
|
||||
setColumnData(result?.data[0]);
|
||||
const data =
|
||||
result?.data[0].columns && JSON.parse(result?.data[0].columns)
|
||||
? JSON.parse(result?.data[0].columns)
|
||||
: [];
|
||||
|
||||
console.log("data >>", data);
|
||||
|
||||
if (data.length) {
|
||||
setColumns(() => [...data]);
|
||||
} else {
|
||||
setColumns(() => [...defaultColumns]);
|
||||
}
|
||||
};
|
||||
|
||||
const getColumns = async () => {
|
||||
setGlobalLoading(globalDispatch, true, "columModel");
|
||||
const result = await getMany(globalDispatch, dispatch, "column", [
|
||||
...(columnModel
|
||||
? [`model,eq,'${columnModel}'`]
|
||||
: [`model,eq,'${table}'`]),
|
||||
`user_id,eq,0`,
|
||||
]);
|
||||
|
||||
// console.log("result >>", result);
|
||||
if (!result?.error && result?.data?.length) {
|
||||
populateColums(result);
|
||||
} else {
|
||||
const result = await getMany(globalDispatch, dispatch, "column", [
|
||||
...(columnModel
|
||||
? [`model,eq,'${columnModel}'`]
|
||||
: [`model,eq,'${table}'`]),
|
||||
`user_id,eq,0`,
|
||||
]);
|
||||
if (!result?.error && result?.data?.length) {
|
||||
populateColums(result);
|
||||
}
|
||||
}
|
||||
setGlobalLoading(globalDispatch, false, "columModel");
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
if (useExternalData) {
|
||||
setColumns(() => defaultColumns);
|
||||
} else {
|
||||
getColumns();
|
||||
}
|
||||
}, [useExternalData]);
|
||||
|
||||
// Update External Selected Items
|
||||
React.useEffect(() => {
|
||||
if (actions?.select?.action) {
|
||||
actions.select.action(selectedItems);
|
||||
}
|
||||
}, [selectedItems?.length]);
|
||||
|
||||
React.useEffect(() => {
|
||||
const searchableCol = columns.find((col) => col?.searchable);
|
||||
if (searchableCol) {
|
||||
setSearchField(searchableCol?.accessor);
|
||||
}
|
||||
}, []);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (useExternalData) {
|
||||
setCurrentTableData(() => externalData);
|
||||
} else {
|
||||
getData(currentPage, pageSize, { filterConditions: [] });
|
||||
}
|
||||
}, [useExternalData]);
|
||||
|
||||
return (
|
||||
<div className="!h-fit">
|
||||
{refreshRef && (
|
||||
<button
|
||||
type="button"
|
||||
ref={refreshRef}
|
||||
onClick={() => getData(1, pageSize)}
|
||||
className="hidden"
|
||||
></button>
|
||||
)}
|
||||
<div
|
||||
className={`flex w-full justify-between ${
|
||||
tableTitle && hasFilter ? "flex-col gap-3" : "h-fit items-center"
|
||||
} ${topClasses}`}
|
||||
>
|
||||
<h4 className="flex items-center font-inter text-[1rem] font-medium capitalize leading-[1.5rem] tracking-[-0.011em]">
|
||||
{tableTitle ? tableTitle : ""}
|
||||
</h4>
|
||||
|
||||
<div
|
||||
className={`flex h-fit ${
|
||||
hasFilter ? "w-full" : "w-fit"
|
||||
} items-center justify-between gap-2 text-center`}
|
||||
>
|
||||
<div
|
||||
className={`flex h-full w-fit justify-end gap-2 self-end ${
|
||||
!tableTitle && !hasFilter ? "w-full" : ""
|
||||
}`}
|
||||
>
|
||||
{Object.keys(actions).map((key, keyIndex) => {
|
||||
if (
|
||||
actions[key].show &&
|
||||
actions[key].hasOwnProperty("type") &&
|
||||
["toggle"].includes(actions[key].type)
|
||||
) {
|
||||
return (
|
||||
<MkdInput
|
||||
key={keyIndex}
|
||||
type="toggle"
|
||||
onChange={(e) => {
|
||||
if (actions[key]?.action) {
|
||||
actions[key]?.action(e?.target?.checked);
|
||||
}
|
||||
}}
|
||||
label={actions[key]?.children ?? key}
|
||||
value={actions[key]?.value}
|
||||
/>
|
||||
);
|
||||
}
|
||||
})}
|
||||
|
||||
{selectedItems?.length && actionPostion.includes("ontop") ? (
|
||||
<TableActions actions={actions} selectedItems={selectedItems} />
|
||||
) : null}
|
||||
|
||||
{Object.keys(actions).map((key, keyIndex) => {
|
||||
if (
|
||||
actions[key].show &&
|
||||
actions[key].hasOwnProperty("type") &&
|
||||
["static"].includes(actions[key].type)
|
||||
) {
|
||||
return (
|
||||
<AddButton
|
||||
key={keyIndex}
|
||||
onClick={() => {
|
||||
if (actions[key]?.action) {
|
||||
actions[key]?.action();
|
||||
}
|
||||
}}
|
||||
title={actions[key]?.title ?? key}
|
||||
// showChildren={actions?.add?.showChildren}
|
||||
showPlus={false}
|
||||
className={`!h-[2.5rem] ${actions[key]?.className}`}
|
||||
loading={actions[key]?.loading ?? false}
|
||||
disabled={actions[key]?.disabled ?? false}
|
||||
icon={actions[key]?.icon ?? null}
|
||||
>
|
||||
{key === "delete" ? <ExCircleIcon /> : null}
|
||||
{actions[key].children ? (
|
||||
actions[key].children
|
||||
) : (
|
||||
<>
|
||||
{StringCaser(key === "delete" ? "Remove" : key, {
|
||||
casetype: "capitalize",
|
||||
separator: " ",
|
||||
})}
|
||||
</>
|
||||
)}
|
||||
</AddButton>
|
||||
);
|
||||
}
|
||||
})}
|
||||
|
||||
{actions?.add?.show && (
|
||||
<AddButton
|
||||
onClick={() => {
|
||||
if (actions?.add?.action) {
|
||||
actions?.add?.action();
|
||||
}
|
||||
}}
|
||||
showChildren={actions?.add?.showChildren}
|
||||
className={`!h-[2.5rem] ${actions?.add?.className}`}
|
||||
>
|
||||
{actions?.add?.children}
|
||||
</AddButton>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="my-2">
|
||||
<MkdListTable
|
||||
table={table}
|
||||
onSort={onSort}
|
||||
columns={columns}
|
||||
actions={actions}
|
||||
actionId={actionId}
|
||||
tableRole={tableRole}
|
||||
tableTitle={tableTitle}
|
||||
columnData={columnData}
|
||||
deleteItem={deleteItem}
|
||||
setColumns={setColumns}
|
||||
allowEditing={allowEditing}
|
||||
setColumnData={setColumnData}
|
||||
actionPostion={actionPostion}
|
||||
deleteLoading={deleteLoading}
|
||||
showDeleteModal={showDeleteModal}
|
||||
allowSortColumns={allowSortColumns}
|
||||
currentTableData={currentTableData}
|
||||
setSelectedItems={setSelectedItems}
|
||||
setShowDeleteModal={setShowDeleteModal}
|
||||
loading={loading || columModel?.loading}
|
||||
handleTableCellChange={handleTableCellChange}
|
||||
// onPopoverStateChange={setPopoverShow}
|
||||
popoverShown={popoverShown}
|
||||
/>
|
||||
</div>
|
||||
{selectedItems?.length && actionPostion.includes("overlay") ? (
|
||||
<OverlayTableActions actions={actions} selectedItems={selectedItems} />
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(MkdListTableV2);
|
||||
@@ -0,0 +1,184 @@
|
||||
import React from "react";
|
||||
import { StringCaser, optionTypes } from "Utils/utils";
|
||||
import { AddButton } from "Components/AddButton";
|
||||
import { ChevronRightIcon, ExCircleIcon } from "Assets/svgs";
|
||||
import { MkdPopover } from "Components/MkdPopover";
|
||||
import { DropdownOption } from "Components/DropdownOptions";
|
||||
|
||||
const OverlayTableActions = ({ actions, selectedItems }) => {
|
||||
return (
|
||||
<div className="fixed inset-x-0 bottom-5 m-auto flex !h-[3.25rem] !max-h-[3.25rem] w-fit items-center justify-start gap-2 rounded-[.875rem] bg-black px-[.75rem] pb-[.5rem] pt-[.5rem]">
|
||||
<div className="font-inter text-white">
|
||||
Selected: {selectedItems.length}
|
||||
</div>
|
||||
{Object.keys(actions).filter(
|
||||
(key) =>
|
||||
actions[key]?.show &&
|
||||
actions[key]?.locations &&
|
||||
actions[key]?.locations?.includes("overlay")
|
||||
)?.length ? (
|
||||
<>
|
||||
{Object.keys(actions)
|
||||
.filter(
|
||||
(key) =>
|
||||
actions[key]?.show &&
|
||||
actions[key]?.locations &&
|
||||
actions[key]?.locations?.includes("overlay")
|
||||
)
|
||||
.map((key, keyIndex) => {
|
||||
if (
|
||||
actions[key]?.type &&
|
||||
[optionTypes.DROPDOWN].includes(actions[key]?.type)
|
||||
) {
|
||||
return (
|
||||
<RenderButtonDropdownActions
|
||||
action={actions[key]}
|
||||
actionKey={key}
|
||||
selectedItems={selectedItems}
|
||||
key={keyIndex}
|
||||
/>
|
||||
);
|
||||
} else if (!actions[key]?.type) {
|
||||
return (
|
||||
<RenderButtons
|
||||
action={actions[key]}
|
||||
actionKey={key}
|
||||
selectedItems={selectedItems}
|
||||
key={keyIndex}
|
||||
/>
|
||||
);
|
||||
}
|
||||
})
|
||||
.filter(Boolean)}
|
||||
</>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default OverlayTableActions;
|
||||
|
||||
const RenderButtonDropdownActions = ({ action, actionKey, selectedItems }) => {
|
||||
return (
|
||||
<MkdPopover
|
||||
display={
|
||||
<span
|
||||
className={`hover:text[#262626] relative flex h-[3rem] w-full cursor-pointer items-center justify-between gap-2 overflow-hidden rounded-[.625rem] border !border-white-200 border-primary !bg-white-100 bg-primary px-2 py-2 font-inter text-sm font-medium capitalize leading-loose tracking-wide text-white hover:bg-[#F4F4F4]`}
|
||||
>
|
||||
<span className="flex grow items-center justify-start gap-3 text-white">
|
||||
{action?.icon}
|
||||
{action?.children ?? actionKey}
|
||||
</span>
|
||||
<ChevronRightIcon className="-rotate-90" />
|
||||
</span>
|
||||
}
|
||||
zIndex={999}
|
||||
className={`w-full`}
|
||||
tooltipClasses="!rounded-[.5rem] !text-white w-full !min-w-[11rem] !px-0 !right-[3.25rem] !border"
|
||||
place={"top-start"}
|
||||
backgroundColor="#18181B"
|
||||
>
|
||||
{action?.options && Object.keys(action?.options).length
|
||||
? Object.keys(action?.options).map((key, keyIndex) => {
|
||||
return (
|
||||
<RenderButtonActions
|
||||
key={keyIndex}
|
||||
action={action?.options[key]}
|
||||
selectedItems={selectedItems}
|
||||
/>
|
||||
);
|
||||
})
|
||||
: null}
|
||||
</MkdPopover>
|
||||
);
|
||||
};
|
||||
|
||||
const RenderButtonActions = ({ action, selectedItems }) => {
|
||||
return (
|
||||
<DropdownOption
|
||||
name={action?.children ?? key}
|
||||
// key={keyIndex}
|
||||
className="!text-white hover:!bg-white-100 "
|
||||
icon={action?.icon}
|
||||
onClick={() => {
|
||||
if (action?.action) {
|
||||
action?.action(selectedItems);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const RenderButtons = ({ selectedItems, action, actionKey }) => {
|
||||
if (selectedItems && selectedItems?.length === 1 && !action?.multiple) {
|
||||
return (
|
||||
<AddButton
|
||||
showPlus={false}
|
||||
loading={action?.loading ?? false}
|
||||
disabled={action?.disabled ?? false}
|
||||
icon={action?.icon ?? null}
|
||||
className={`flex cursor-pointer gap-2 !border-white-200 !bg-white-100 px-2 py-2 text-lg font-medium leading-loose tracking-wide ${
|
||||
actionKey === "view"
|
||||
? "text-blue-500"
|
||||
: actionKey === "delete"
|
||||
? "!text-red-500"
|
||||
: "text-[#292829fd]"
|
||||
} hover:underline`}
|
||||
onClick={() => {
|
||||
if (action?.action) {
|
||||
console.log("actionKey >>", actionKey);
|
||||
action.action(selectedItems);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{actionKey === "delete" ? <ExCircleIcon /> : null}
|
||||
{action.children ? (
|
||||
action.children
|
||||
) : (
|
||||
<>
|
||||
{StringCaser(actionKey === "delete" ? "Remove" : actionKey, {
|
||||
casetype: "capitalize",
|
||||
separator: " ",
|
||||
})}
|
||||
</>
|
||||
)}
|
||||
</AddButton>
|
||||
);
|
||||
}
|
||||
if (selectedItems && selectedItems?.length >= 1 && action?.multiple) {
|
||||
return (
|
||||
<AddButton
|
||||
actionKey={actionKey}
|
||||
showPlus={false}
|
||||
loading={action?.loading ?? false}
|
||||
disabled={action?.disabled ?? false}
|
||||
icon={action?.icon ?? null}
|
||||
className={`cursor-pointer gap-2 !border-white-200 !bg-white-100 px-2 py-2 text-lg font-medium leading-loose tracking-wide ${
|
||||
actionKey === "view"
|
||||
? "text-blue-500"
|
||||
: actionKey === "delete"
|
||||
? "!text-red-500"
|
||||
: "text-[#292829fd]"
|
||||
} hover:underline`}
|
||||
onClick={() => {
|
||||
if (action?.action) {
|
||||
console.log("actionKey >>", actionKey);
|
||||
action.action(selectedItems);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{actionKey === "delete" ? <ExCircleIcon /> : null}
|
||||
{action.children ? (
|
||||
action.children
|
||||
) : (
|
||||
<>
|
||||
{StringCaser(actionKey === "delete" ? "Remove" : actionKey, {
|
||||
casetype: "capitalize",
|
||||
separator: " ",
|
||||
})}
|
||||
</>
|
||||
)}
|
||||
</AddButton>
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,43 @@
|
||||
import React from "react";
|
||||
import { DropdownOption } from "Components/DropdownOptions";
|
||||
import { processBind } from "./MkdListTableBindOperations";
|
||||
|
||||
const RenderActions = ({ action, row, actionId, key }) => {
|
||||
if (action?.bind) {
|
||||
switch (action?.bind?.action) {
|
||||
case "hide":
|
||||
if (!processBind(action, row)) {
|
||||
return (
|
||||
<DropdownOption
|
||||
name={action?.children ?? key}
|
||||
// key={keyIndex}
|
||||
className="hover:!bg-white-100 "
|
||||
icon={action?.icon}
|
||||
onClick={() => {
|
||||
if (action?.action) {
|
||||
action?.action([row[actionId]]);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!action?.bind) {
|
||||
return (
|
||||
<DropdownOption
|
||||
name={action?.children ?? key}
|
||||
// key={keyIndex}
|
||||
className="hover:!bg-white-100 "
|
||||
icon={action?.icon}
|
||||
onClick={() => {
|
||||
if (action?.action) {
|
||||
action?.action([row[actionId]]);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default RenderActions;
|
||||
@@ -0,0 +1,41 @@
|
||||
import React from "react";
|
||||
import { MkdPopover } from "Components/MkdPopover";
|
||||
import { ChevronRightIcon } from "Assets/svgs";
|
||||
import RenderActions from "./RenderActions";
|
||||
|
||||
const RenderDropdownActions = ({ action, actionKey, row, actionId }) => {
|
||||
return (
|
||||
<MkdPopover
|
||||
display={
|
||||
<span
|
||||
className={`flex w-full cursor-pointer items-center justify-between gap-3 px-2 capitalize text-[#262626] hover:bg-[#F4F4F4]`}
|
||||
>
|
||||
<span className="flex grow gap-3">
|
||||
{action?.icon}
|
||||
{action?.children ?? actionKey}
|
||||
</span>
|
||||
<ChevronRightIcon />
|
||||
</span>
|
||||
}
|
||||
className={`w-full`}
|
||||
tooltipClasses="!rounded-[.5rem] w-full !min-w-[11rem] !px-0 !right-[3.25rem] !border bg-white"
|
||||
place={"left-start"}
|
||||
backgroundColor="#fff"
|
||||
>
|
||||
{action?.options && Object.keys(action?.options).length
|
||||
? Object.keys(action?.options).map((key, keyIndex) => {
|
||||
return (
|
||||
<RenderActions
|
||||
key={keyIndex}
|
||||
action={action?.options[key]}
|
||||
actionId={actionId}
|
||||
row={row}
|
||||
/>
|
||||
);
|
||||
})
|
||||
: null}
|
||||
</MkdPopover>
|
||||
);
|
||||
};
|
||||
|
||||
export default RenderDropdownActions;
|
||||
@@ -0,0 +1,92 @@
|
||||
import React from "react";
|
||||
import { StringCaser } from "Utils/utils";
|
||||
import { AddButton } from "Components/AddButton";
|
||||
|
||||
const TableActions = ({ actions, selectedItems }) => {
|
||||
return (
|
||||
<div className="flex gap-2">
|
||||
{Object.keys(actions)
|
||||
.map((key) => actions[key].show)
|
||||
.includes(true) ? (
|
||||
<>
|
||||
{Object.keys(actions)
|
||||
.map((key) => {
|
||||
if (
|
||||
actions[key].show &&
|
||||
!["static"].includes(actions[key].type) &&
|
||||
!["select", "add", "export"].includes(key)
|
||||
) {
|
||||
if (
|
||||
selectedItems &&
|
||||
selectedItems?.length === 1 &&
|
||||
!actions[key]?.multiple
|
||||
) {
|
||||
return (
|
||||
<AddButton
|
||||
key={key}
|
||||
showPlus={false}
|
||||
loading={actions[key]?.loading ?? false}
|
||||
disabled={actions[key]?.disabled ?? false}
|
||||
icon={actions[key]?.icon ?? null}
|
||||
className={`!h-[2.5rem] cursor-pointer px-2 py-2 text-lg font-medium leading-loose tracking-wide ${
|
||||
key === "view"
|
||||
? "text-blue-500"
|
||||
: key === "delete"
|
||||
? "text-red-500"
|
||||
: "text-[#292829fd]"
|
||||
} hover:underline`}
|
||||
onClick={() => {
|
||||
if (actions[key]?.action) {
|
||||
actions[key].action(selectedItems);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{StringCaser(key, {
|
||||
casetype: "capitalize",
|
||||
separator: " ",
|
||||
})}
|
||||
</AddButton>
|
||||
);
|
||||
}
|
||||
if (
|
||||
selectedItems &&
|
||||
selectedItems?.length >= 1 &&
|
||||
actions[key]?.multiple
|
||||
) {
|
||||
return (
|
||||
<AddButton
|
||||
key={key}
|
||||
showPlus={false}
|
||||
loading={actions[key]?.loading ?? false}
|
||||
disabled={actions[key]?.disabled ?? false}
|
||||
icon={actions[key]?.icon ?? null}
|
||||
className={`!h-[2.5rem] cursor-pointer px-2 py-2 text-lg font-medium leading-loose tracking-wide ${
|
||||
key === "view"
|
||||
? "text-blue-500"
|
||||
: key === "delete"
|
||||
? "text-red-500"
|
||||
: "text-[#292829fd]"
|
||||
} hover:underline`}
|
||||
onClick={() => {
|
||||
if (actions[key]?.action) {
|
||||
actions[key].action(selectedItems);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{StringCaser(key, {
|
||||
casetype: "capitalize",
|
||||
separator: " ",
|
||||
})}
|
||||
</AddButton>
|
||||
);
|
||||
}
|
||||
}
|
||||
})
|
||||
.filter(Boolean)}
|
||||
</>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TableActions;
|
||||
@@ -0,0 +1,8 @@
|
||||
export { default as MkdListTable } from "./MkdListTable";
|
||||
export { default as MkdListTableV2 } from "./MkdListTableV2";
|
||||
export { default as TableActions } from "./TableActions";
|
||||
export { default as OverlayTableActions } from "./OverlayTableActions";
|
||||
export { default as MkdListTableRow } from "./MkdListTableRow";
|
||||
export { default as MkdListTableHead } from "./MkdListTableHead";
|
||||
export { default as MkdListTableRowButtons } from "./MkdListTableRowButtons";
|
||||
export { default as MkdListTableRowDropdown } from "./MkdListTableRowDropdown";
|
||||
@@ -0,0 +1,10 @@
|
||||
/* PopoverOnClick.css */
|
||||
|
||||
/* Customize the appearance of the tooltip */
|
||||
/* .tooltip {
|
||||
background-color: white !important;
|
||||
color: #fff;
|
||||
padding: 0.5rem;
|
||||
border-radius: 0.25rem;
|
||||
font-size: 0.875rem;
|
||||
} */
|
||||
@@ -0,0 +1,61 @@
|
||||
import React, { useId } from "react";
|
||||
import { Tooltip as ReactTooltip } from "react-tooltip";
|
||||
import "./MkdPopover.css";
|
||||
|
||||
const MkdPopover = ({
|
||||
display,
|
||||
className,
|
||||
children,
|
||||
tooltipClasses,
|
||||
place = "bottom",
|
||||
openOnClick = true,
|
||||
zIndex = 99999,
|
||||
onPopoverStateChange,
|
||||
backgroundColor = "#fff",
|
||||
textColor = "#000",
|
||||
}) => {
|
||||
const tooltipId = useId();
|
||||
const handleTooltipShow = () => {
|
||||
if (onPopoverStateChange) {
|
||||
onPopoverStateChange(true);
|
||||
}
|
||||
};
|
||||
|
||||
const handleTooltipHide = () => {
|
||||
if (onPopoverStateChange) {
|
||||
onPopoverStateChange(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="App">
|
||||
<button
|
||||
type="button"
|
||||
data-tooltip-id={tooltipId}
|
||||
className={`${className}`}
|
||||
>
|
||||
{display ? display : null}
|
||||
{/* <AlertCircle className="rotate-180" /> */}
|
||||
</button>
|
||||
</div>
|
||||
<ReactTooltip
|
||||
// globalCloseEvents={{ scroll: true }}
|
||||
id={tooltipId}
|
||||
openOnClick={openOnClick}
|
||||
style={{ backgroundColor, color: textColor, zIndex: zIndex }}
|
||||
className={`z-[${zIndex}] ${tooltipClasses} !shadow-md`}
|
||||
clickable
|
||||
place={place}
|
||||
effect="solid"
|
||||
afterShow={handleTooltipShow}
|
||||
afterHide={handleTooltipHide}
|
||||
// getTextColor={() => textColor}
|
||||
>
|
||||
{children}
|
||||
</ReactTooltip>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default MkdPopover;
|
||||
@@ -0,0 +1,47 @@
|
||||
.button {
|
||||
position: relative;
|
||||
border: none;
|
||||
color: #ffffff;
|
||||
text-align: center;
|
||||
-webkit-transition-duration: 0.4s; /* Safari */
|
||||
transition-duration: 0.4s;
|
||||
text-decoration: none;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
}
|
||||
.button:after {
|
||||
content: "";
|
||||
background: #4f46e5;
|
||||
display: block;
|
||||
position: absolute;
|
||||
padding-top: 300%;
|
||||
padding-left: 350%;
|
||||
margin-left: -20px !important;
|
||||
margin-top: -120%;
|
||||
opacity: 0;
|
||||
transition: all 0.8s;
|
||||
}
|
||||
|
||||
.button:active:after {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
opacity: 1;
|
||||
transition: 0s;
|
||||
}
|
||||
.tip {
|
||||
position: absolute;
|
||||
top: anchor(bottom);
|
||||
left: anchor(50%);
|
||||
}
|
||||
|
||||
/* PopoverOnClick.css */
|
||||
|
||||
/* Customize the appearance of the tooltip */
|
||||
.tooltip {
|
||||
background-color: #333;
|
||||
color: #fff;
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
/* Add any other styles you need */
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
import { lazy } from "react";
|
||||
|
||||
export const MkdPopover = lazy(() => import("./MkdPopover"));
|
||||
@@ -0,0 +1,41 @@
|
||||
import React from "react";
|
||||
import Skeleton from "react-loading-skeleton";
|
||||
|
||||
const SkeletonLoader = ({
|
||||
className = "",
|
||||
count = 5,
|
||||
counts = [2, 1, 3, 1, 1],
|
||||
circle = false,
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
className={`flex h-fit max-h-screen min-h-fit w-full flex-col gap-5 overflow-hidden p-4 ${className} `}
|
||||
>
|
||||
{/* <Skeleton circle width={60} height={60} /> */}
|
||||
{Array.from({ length: count }).map((_, index) => (
|
||||
<Skeleton
|
||||
key={`${_}${index}`}
|
||||
count={counts[index] ?? 1}
|
||||
height={
|
||||
counts[index] && counts[index] > 1
|
||||
? 25
|
||||
: index + 1 === count
|
||||
? 25
|
||||
: 80
|
||||
}
|
||||
circle={circle}
|
||||
// style={{ marginBottom: "0.6rem" }}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SkeletonLoader;
|
||||
|
||||
{
|
||||
/* <Skeleton count={1} height={60} style={{ marginBottom: "0.6rem" }} />
|
||||
<Skeleton count={3} height={25} style={{ marginBottom: "0.6rem" }} />
|
||||
<Skeleton count={1} height={80} style={{ marginBottom: "0.6rem" }} />
|
||||
<Skeleton count={1} height={25} style={{ marginBottom: "0.6rem" }} /> */
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
|
||||
import { lazy } from "react";
|
||||
|
||||
export const SkeletonLoader = lazy(()=> import("./Skeleton"))
|
||||
|
||||
|
||||
+117
-28
@@ -1,39 +1,128 @@
|
||||
import React from "react";
|
||||
import { GlobalContext } from "../globalContext";
|
||||
import { GlobalContext } from "Context/Global";
|
||||
const SnackBar = () => {
|
||||
const { state, dispatch } = React.useContext(GlobalContext);
|
||||
const show = state.globalMessage.length > 0;
|
||||
const {
|
||||
state: { globalMessage, toastStatus },
|
||||
dispatch,
|
||||
} = React.useContext(GlobalContext);
|
||||
const show = globalMessage.length > 0;
|
||||
return show ? (
|
||||
<div
|
||||
id="mkd-toast"
|
||||
className="absolute top-5 right-5 flex items-center w-full max-w-xs p-4 text-gray-500 bg-white rounded-lg shadow dark:text-gray-400"
|
||||
className={`fixed right-5 top-10 z-[100000000001] flex max-h-[5.625rem] min-h-[4.375rem] w-fit max-w-[50%] items-center justify-between rounded-lg border-2 bg-white px-4 py-2 text-sm shadow-2xl dark:text-gray-400`}
|
||||
role="alert"
|
||||
>
|
||||
<div className="text-sm font-normal">{state.globalMessage}</div>
|
||||
<div className="flex items-center ml-auto space-x-2">
|
||||
<button
|
||||
type="button"
|
||||
className="bg-white text-gray-400 hover:text-gray-900 rounded-lg focus:ring-2 focus:ring-gray-300 p-1.5 hover:bg-gray-100 inline-flex h-8 w-8 dark:text-gray-500 dark:hover:text-white dark:hover:bg-gray-700"
|
||||
aria-label="Close"
|
||||
onClick={() => {
|
||||
dispatch({ type: "SNACKBAR", payload: { message: "" } });
|
||||
}}
|
||||
>
|
||||
<span className="sr-only">Close</span>
|
||||
<svg
|
||||
className="w-5 h-5"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
|
||||
clipRule="evenodd"
|
||||
></path>
|
||||
</svg>
|
||||
</button>
|
||||
<div className="mr-8 flex w-fit items-center gap-4">
|
||||
<span>
|
||||
{toastStatus === "success" ? (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2ZM15.5805 9.97493C15.8428 9.65434 15.7955 9.18183 15.4749 8.91953C15.1543 8.65724 14.6818 8.70449 14.4195 9.02507L10.4443 13.8837L9.03033 12.4697C8.73744 12.1768 8.26256 12.1768 7.96967 12.4697C7.67678 12.7626 7.67678 13.2374 7.96967 13.5303L9.96967 15.5303C10.1195 15.6802 10.3257 15.7596 10.5374 15.7491C10.749 15.7385 10.9463 15.6389 11.0805 15.4749L15.5805 9.97493Z"
|
||||
fill="#16A34A"
|
||||
/>
|
||||
</svg>
|
||||
) : toastStatus === "error" ? (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M10.4902 2.84406C11.1661 1.69 12.8343 1.69 13.5103 2.84406L22.0156 17.3654C22.699 18.5321 21.8576 19.9999 20.5056 19.9999H3.49483C2.14281 19.9999 1.30147 18.5321 1.98479 17.3654L10.4902 2.84406ZM12 9C12.4142 9 12.75 9.33579 12.75 9.75V13.25C12.75 13.6642 12.4142 14 12 14C11.5858 14 11.25 13.6642 11.25 13.25V9.75C11.25 9.33579 11.5858 9 12 9ZM13 15.75C13 16.3023 12.5523 16.75 12 16.75C11.4477 16.75 11 16.3023 11 15.75C11 15.1977 11.4477 14.75 12 14.75C12.5523 14.75 13 15.1977 13 15.75Z"
|
||||
fill="#DC2626"
|
||||
/>
|
||||
</svg>
|
||||
) : toastStatus === "info" ? (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2ZM10 11C10 10.5858 10.3358 10.25 10.75 10.25H12C12.4142 10.25 12.75 10.5858 12.75 11L12.75 16.25C12.75 16.6642 12.4142 17 12 17C11.5858 17 11.25 16.6642 11.25 16.25L11.25 11.75H10.75C10.3358 11.75 10 11.4142 10 11ZM12 7.25C11.5858 7.25 11.25 7.58579 11.25 8C11.25 8.41421 11.5858 8.75 12 8.75C12.4142 8.75 12.75 8.41421 12.75 8C12.75 7.58579 12.4142 7.25 12 7.25Z"
|
||||
fill="#4F46E5"
|
||||
/>
|
||||
</svg>
|
||||
) : toastStatus === "warning" ? (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
>
|
||||
<path
|
||||
d="M12 2C6.48 2 2 6.48 2 12C2 17.52 6.48 22 12 22C17.52 22 22 17.52 22 12C22 6.48 17.52 2 12 2ZM12 13C11.45 13 11 12.55 11 12V8C11 7.45 11.45 7 12 7C12.55 7 13 7.45 13 8V12C13 12.55 12.55 13 12 13ZM13 17H11V15H13V17Z"
|
||||
fill="#F59E0B"
|
||||
/>
|
||||
</svg>
|
||||
) : (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2ZM10 11C10 10.5858 10.3358 10.25 10.75 10.25H12C12.4142 10.25 12.75 10.5858 12.75 11L12.75 16.25C12.75 16.6642 12.4142 17 12 17C11.5858 17 11.25 16.6642 11.25 16.25L11.25 11.75H10.75C10.3358 11.75 10 11.4142 10 11ZM12 7.25C11.5858 7.25 11.25 7.58579 11.25 8C11.25 8.41421 11.5858 8.75 12 8.75C12.4142 8.75 12.75 8.41421 12.75 8C12.75 7.58579 12.4142 7.25 12 7.25Z"
|
||||
fill="#4F46E5"
|
||||
/>
|
||||
</svg>
|
||||
)}
|
||||
</span>
|
||||
<span className="max-h-[3.75rem] w-fit max-w-fit grow truncate whitespace-pre-wrap font-medium text-[#525252]">
|
||||
{globalMessage}
|
||||
{/* M12 2C6.48 2 2 6.48 2 12C2 17.52 6.48 22 12 22C17.52 22 22 17.52 22
|
||||
12C22 6.48 17.52 2 12 2ZM12 13C11.45 13 11 12.55 11 12V8C11 7.45 11.45
|
||||
7 12 7C12.55 7 13 7.45 13 8V12C13 12.55 12.55 13 12 13ZM13
|
||||
17H11V15H13V17Z"M12 2C6.48 2 2 6.48 2 12C2 17.52 6.48 22 12 22C17.52
|
||||
22 22 17.52 22 12C22 6.48 17.52 2 12 2ZM12 13C11.45 13 11 12.55 11
|
||||
12V8C11 7.45 11.45 7 12 7C12.55 7 13 7.45 13 8V12C13 12.55 12.55 13 12
|
||||
13ZM13 17H11V15H13V17Z" */}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<button
|
||||
aria-label="Close"
|
||||
onClick={() => {
|
||||
dispatch({ type: "SNACKBAR", payload: { message: "" } });
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
fill="none"
|
||||
>
|
||||
<path
|
||||
d="M15 5L5 15M5 5L15 15"
|
||||
stroke="#A8A8A8"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
) : null;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user