Update Tasks
This commit is contained in:
@@ -0,0 +1,232 @@
|
||||
import React, { useEffect } 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 {
|
||||
GlobalContext,
|
||||
RequestItems,
|
||||
createRequest,
|
||||
customRequest,
|
||||
deleteRequest,
|
||||
updateRequest,
|
||||
} from "Context/Global";
|
||||
import { AuthContext } from "Context/Auth";
|
||||
import { MkdInput } from "Components/MkdInput";
|
||||
import { InteractiveButton } from "Components/InteractiveButton";
|
||||
import { AddButton } from "Components/AddButton";
|
||||
|
||||
export const ActionConfirmation = ({
|
||||
data = { id: null },
|
||||
options = { endpoint: null, method: "GET" },
|
||||
onSuccess,
|
||||
onClose,
|
||||
multiple = false,
|
||||
action = "",
|
||||
mode = "create",
|
||||
table = "",
|
||||
inputConfirmation = true,
|
||||
}) => {
|
||||
let sdk = new MkdSDK();
|
||||
|
||||
const schema = yup
|
||||
.object({
|
||||
confirm: yup
|
||||
.string()
|
||||
.required()
|
||||
.oneOf([action], `Confirmation must be "${action}"`),
|
||||
})
|
||||
.required();
|
||||
|
||||
const {
|
||||
state: { createModel, updateModel, deleteModel },
|
||||
dispatch: globalDispatch,
|
||||
} = React.useContext(GlobalContext);
|
||||
const { state: authState, dispatch } = React.useContext(AuthContext);
|
||||
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
setValue,
|
||||
formState: { errors },
|
||||
} = useForm({
|
||||
resolver: yupResolver(schema),
|
||||
});
|
||||
|
||||
const onSubmit = async () => {
|
||||
if (!multiple) {
|
||||
switch (mode) {
|
||||
case "create":
|
||||
return createData(data);
|
||||
case "update":
|
||||
return editData(data);
|
||||
case "delete":
|
||||
return deleteData(data);
|
||||
case "custom":
|
||||
return customData(data);
|
||||
case "manual":
|
||||
return manualData(data);
|
||||
}
|
||||
} else {
|
||||
makeRequests();
|
||||
}
|
||||
};
|
||||
|
||||
const makeRequests = async () => {
|
||||
const result = await createRequest(globalDispatch, dispatch, table, data);
|
||||
if (!result.error && onSuccess) {
|
||||
onSuccess();
|
||||
}
|
||||
};
|
||||
|
||||
const editData = async (data) => {
|
||||
console.log("data >>", data);
|
||||
const result = await updateRequest(
|
||||
globalDispatch,
|
||||
dispatch,
|
||||
table,
|
||||
data?.id,
|
||||
data
|
||||
);
|
||||
|
||||
if (!result?.error && onSuccess) {
|
||||
onSuccess();
|
||||
}
|
||||
};
|
||||
|
||||
const createData = async (data) => {
|
||||
if (action === "move") return moveRequest(data);
|
||||
const result = await createRequest(globalDispatch, dispatch, table, data);
|
||||
|
||||
if (!result?.error && onSuccess) {
|
||||
onSuccess();
|
||||
}
|
||||
};
|
||||
|
||||
const deleteData = async (data) => {
|
||||
const result = await deleteRequest(
|
||||
globalDispatch,
|
||||
dispatch,
|
||||
table,
|
||||
data.id
|
||||
);
|
||||
|
||||
if (!result?.error && onSuccess) {
|
||||
onSuccess();
|
||||
}
|
||||
};
|
||||
|
||||
const customData = async (data) => {
|
||||
const result = await customRequest(
|
||||
globalDispatch,
|
||||
dispatch,
|
||||
{
|
||||
endpoint: options?.endpoint,
|
||||
method: options?.method,
|
||||
payload: data,
|
||||
},
|
||||
RequestItems.createModel
|
||||
);
|
||||
|
||||
if (
|
||||
result &&
|
||||
result?.hasOwnProperty("error") &&
|
||||
!result?.error &&
|
||||
onSuccess
|
||||
) {
|
||||
onSuccess(result);
|
||||
}
|
||||
};
|
||||
const manualData = (data) => {
|
||||
if (onSuccess) {
|
||||
onSuccess(data);
|
||||
}
|
||||
};
|
||||
const moveRequest = async (data) => {
|
||||
const result = await customRequest(
|
||||
globalDispatch,
|
||||
dispatch,
|
||||
{
|
||||
endpoint: "/v3/api/custom/qualitysign/inventory/move",
|
||||
method: "POST",
|
||||
payload: data,
|
||||
},
|
||||
RequestItems.createModel
|
||||
);
|
||||
|
||||
if (!result?.error && onSuccess) {
|
||||
onSuccess(result);
|
||||
}
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!inputConfirmation) {
|
||||
setValue("confirm", action);
|
||||
}
|
||||
}, [inputConfirmation]);
|
||||
|
||||
return (
|
||||
// <div className={`px-5 ${multiple ? "flex justify-center" : ""}`}>
|
||||
<div className="mx-auto flex h-fit flex-col items-center justify-start rounded !font-inter leading-snug tracking-wide">
|
||||
<form
|
||||
className={`flex h-fit w-full flex-col text-start`}
|
||||
onSubmit={handleSubmit(onSubmit)}
|
||||
>
|
||||
<div className="space-y-5">
|
||||
<div className="my-2">
|
||||
<div>
|
||||
Are you sure you want to {action}{" "}
|
||||
{data?.id && data?.id?.length && data?.id?.length > 1
|
||||
? "these"
|
||||
: "this"}{" "}
|
||||
{table}?
|
||||
</div>
|
||||
</div>
|
||||
<div className={`!mb-10 ${inputConfirmation ? "" : "hidden"}`}>
|
||||
<MkdInput
|
||||
type={"text"}
|
||||
page={"items"}
|
||||
name={`confirm`}
|
||||
errors={errors}
|
||||
register={register}
|
||||
label={
|
||||
<div className="font-bold text-black">
|
||||
Type '{action}' below
|
||||
</div>
|
||||
}
|
||||
className={"grow"}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mt-5 flex w-full grow gap-5">
|
||||
<AddButton
|
||||
type="button"
|
||||
onClick={() => onClose()}
|
||||
className="grow self-end !border-soft-200 !bg-transparent font-bold !text-[#4F46E5]"
|
||||
>
|
||||
Cancel
|
||||
</AddButton>
|
||||
<InteractiveButton
|
||||
type="submit"
|
||||
loading={
|
||||
createModel?.loading ||
|
||||
updateModel?.loading ||
|
||||
deleteModel?.loading
|
||||
}
|
||||
disabled={
|
||||
createModel?.loading ||
|
||||
updateModel?.loading ||
|
||||
deleteModel?.loading
|
||||
}
|
||||
className="focus:shadow-outline bg-primaryBlue !w-1/2 self-end rounded px-4 py-2 font-bold capitalize text-white focus:outline-none"
|
||||
>
|
||||
{action}
|
||||
</InteractiveButton>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ActionConfirmation;
|
||||
@@ -0,0 +1 @@
|
||||
export { default as ActionConfirmation } from "./ActionConfirmation";
|
||||
@@ -0,0 +1,48 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { Modal } from "Components/Modal";
|
||||
import { ActionConfirmation } from "Components/ActionConfirmation";
|
||||
|
||||
export const ActionConfirmationModal = ({
|
||||
data = { id: null },
|
||||
options = { endpoint: null, method: "GET" },
|
||||
onSuccess,
|
||||
onClose,
|
||||
multiple = false,
|
||||
action = "",
|
||||
mode = "create",
|
||||
table = "",
|
||||
title = "",
|
||||
isOpen = false,
|
||||
inputConfirmation = true,
|
||||
modalClasses = {
|
||||
modalDialog:
|
||||
"max-h-[90%] min-h-[12rem] overflow-y-auto !w-full md:!w-[29.0625rem]",
|
||||
modal: "h-full",
|
||||
},
|
||||
}) => {
|
||||
return (
|
||||
<Modal
|
||||
isOpen={isOpen}
|
||||
modalCloseClick={onClose}
|
||||
title={title}
|
||||
modalHeader
|
||||
classes={modalClasses}
|
||||
>
|
||||
{isOpen && (
|
||||
<ActionConfirmation
|
||||
data={data}
|
||||
mode={mode}
|
||||
table={table}
|
||||
action={action}
|
||||
onClose={onClose}
|
||||
options={options}
|
||||
multiple={multiple}
|
||||
onSuccess={onSuccess}
|
||||
inputConfirmation={inputConfirmation}
|
||||
/>
|
||||
)}
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default ActionConfirmationModal;
|
||||
@@ -0,0 +1 @@
|
||||
export { default as ActionConfirmationModal } from "./ActionConfirmationModal";
|
||||
@@ -37,7 +37,7 @@ const AddButton = ({
|
||||
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}`}
|
||||
} relative flex h-[3rem] cursor-pointer items-center justify-center gap-2 overflow-hidden rounded-[.625rem] border border-[#4F46E5] bg-[#4F46E5] px-[.625rem] py-2 font-inter text-sm font-medium leading-loose tracking-wide text-white ${className}`}
|
||||
>
|
||||
<>
|
||||
<MoonLoader
|
||||
|
||||
@@ -8,11 +8,11 @@
|
||||
text-decoration: none;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
/* background-color: #7B1113; */
|
||||
/* background-color:#4F46E5; */
|
||||
}
|
||||
.button:after {
|
||||
content: "";
|
||||
background-color: #7b1113;
|
||||
background-color: #4f46e5;
|
||||
/* background: #4f46e5; */
|
||||
display: block;
|
||||
position: absolute;
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import React, { memo, useId } from "react";
|
||||
import MoonLoader from "react-spinners/MoonLoader";
|
||||
import classes from "./InteractiveButton.module.css";
|
||||
|
||||
const InteractiveButton = ({
|
||||
loading = false,
|
||||
disabled,
|
||||
children,
|
||||
type = "button",
|
||||
className,
|
||||
loaderclasses,
|
||||
onClick,
|
||||
color = "#ffffff",
|
||||
}) => {
|
||||
const override = {
|
||||
borderColor: "#ffffff",
|
||||
};
|
||||
const id = useId();
|
||||
return (
|
||||
<button
|
||||
type={type}
|
||||
disabled={disabled}
|
||||
className={`${classes.button} relative flex h-[3rem] cursor-pointer items-center justify-center gap-5 overflow-hidden rounded-[.625rem] border border-[#4F46E5] bg-[#4F46E5] px-[.625rem] py-[.5625rem] text-sm font-medium leading-none text-white ${className}`}
|
||||
onClick={onClick}
|
||||
>
|
||||
<>
|
||||
<MoonLoader
|
||||
color={color}
|
||||
loading={loading}
|
||||
cssOverride={override}
|
||||
size={14}
|
||||
className={loaderclasses}
|
||||
// aria-label="Loading Spinner"
|
||||
data-testid={id}
|
||||
/>
|
||||
|
||||
{children ? <span>{children}</span> : null}
|
||||
</>
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(InteractiveButton);
|
||||
@@ -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: #4F46E5; */
|
||||
}
|
||||
.button:after {
|
||||
content: "";
|
||||
background-color: #4f46e5;
|
||||
/* 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 InteractiveButton } from "./InteractiveButton";
|
||||
@@ -36,7 +36,7 @@ const MkdListTableRowDropdown = ({
|
||||
actions[key]?.action([row[actionId]]);
|
||||
}
|
||||
}}
|
||||
className={`!h-[2rem] !w-[2.0713rem] !border-soft-200 !bg-white`}
|
||||
className={`!h-[2rem] !w-[2.0713rem] !border-gray-200 !bg-white`}
|
||||
>
|
||||
{actions[key]?.icon
|
||||
? actions[key]?.icon
|
||||
@@ -63,7 +63,7 @@ const MkdListTableRowDropdown = ({
|
||||
// actions[key]?.action([row[actionId]]);
|
||||
// }
|
||||
}}
|
||||
className={`!h-[2rem] !w-[2.0713rem] !border-soft-200 !bg-white`}
|
||||
className={`!h-[2rem] !w-[2.0713rem] !border-gray-200 !bg-white`}
|
||||
>
|
||||
{actions[key]?.icon
|
||||
? actions[key]?.icon
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
import React, { memo, useEffect, useRef } from "react";
|
||||
import { MdClose } from "react-icons/md";
|
||||
|
||||
const Modal = ({
|
||||
children,
|
||||
title,
|
||||
modalCloseClick,
|
||||
modalHeader,
|
||||
classes = { modal: "h-full", modalDialog: "h-[90%]", modalContent: "" },
|
||||
page = "",
|
||||
isOpen,
|
||||
}) => {
|
||||
const modalRef = useRef(null);
|
||||
|
||||
// useEffect(() => {
|
||||
// if (isOpen) {
|
||||
// document.body.style.overflow = "hidden";
|
||||
// } else {
|
||||
// document.body.style.overflow = "auto";
|
||||
// }
|
||||
// }, [isOpen]);
|
||||
|
||||
useEffect(() => {
|
||||
const scrollableElements = document.querySelectorAll(
|
||||
"body, .scrollable-container" // Add other selectors if needed
|
||||
);
|
||||
|
||||
if (isOpen) {
|
||||
scrollableElements.forEach((element) => {
|
||||
element.style.overflow = "hidden";
|
||||
});
|
||||
} else {
|
||||
scrollableElements.forEach((element) => {
|
||||
element.style.overflow = "auto";
|
||||
});
|
||||
}
|
||||
|
||||
return () => {
|
||||
scrollableElements.forEach((element) => {
|
||||
element.style.overflow = "auto";
|
||||
});
|
||||
};
|
||||
}, [isOpen]);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={modalRef}
|
||||
style={{
|
||||
zIndex: 999999999999,
|
||||
backgroundColor: "rgba(0, 0, 0, 0.5)",
|
||||
}}
|
||||
className={`fixed bottom-0 left-0 right-0 top-0 flex w-full scale-0 items-center justify-center bg-[#00000099] p-5 backdrop-blur-sm transition-all ${
|
||||
isOpen ? "scale-100" : "scale-0"
|
||||
} ${classes?.modal}`}
|
||||
>
|
||||
<div
|
||||
className={`${
|
||||
page === "ManagePermissionAddRole" ? "w-fit" : "w-[80%]"
|
||||
} relative overflow-auto rounded-lg bg-white pb-5 shadow ${
|
||||
classes?.modalDialog
|
||||
}`}
|
||||
>
|
||||
{modalHeader && (
|
||||
<div
|
||||
className={`sticky inset-x-0 top-0 !z-50 m-auto flex w-full justify-between border-b bg-white px-5 py-4`}
|
||||
>
|
||||
<div className="text-center font-inter text-[1.125rem] font-bold capitalize leading-[1.5rem] tracking-[-1.5%]">
|
||||
{title}
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
className="modal-close cursor-pointer"
|
||||
onClick={modalCloseClick}
|
||||
>
|
||||
<MdClose className="text-xl" />
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className={`-z-10 mt-4 px-5 ${classes?.modalContent}`}>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const ModalMemo = memo(Modal);
|
||||
export { ModalMemo as Modal };
|
||||
@@ -0,0 +1,56 @@
|
||||
|
||||
// import { Close, danger, warning } from 'Assets/svgs'
|
||||
import React from 'react'
|
||||
|
||||
|
||||
const ModalAlert = ( { closeModalFunction, message, title, messageClasses, titleClasses, buttonText = "OK" } ) => {
|
||||
return (
|
||||
<aside
|
||||
className='fixed top-0 right-0 bottom-0 left-0 flex justify-center items-center '
|
||||
style={ {
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
||||
zIndex: '1000',
|
||||
} }
|
||||
>
|
||||
<section className='bg-white min-w-[25rem] w-[25rem] rounded-[.5rem] py-6 px-6 flex flex-col gap-6'>
|
||||
<div className='flex justify-between '>
|
||||
<div>
|
||||
{/* <img src={danger} width={30} height={30} alt='danger' /> */ }
|
||||
</div>
|
||||
<button onClick={ closeModalFunction }>
|
||||
{/* <img src={Close} width={30} height={30} alt='close' /> */ }
|
||||
</button>
|
||||
</div>
|
||||
{
|
||||
title ?
|
||||
<div className={ ` ${ titleClasses }` }>
|
||||
{ title }
|
||||
{/* <div className='py-3 text-[1rem] leading-[1.75rem] text-[#333333] '>{message}</div> */ }
|
||||
</div> : null
|
||||
}
|
||||
{
|
||||
message ?
|
||||
<div className={ `text-[1.5rem] leading-[1.5rem] text-[#667085] font-normal ${ messageClasses }` }>
|
||||
{ message }
|
||||
{/* <div className='py-3 text-[1rem] leading-[1.75rem] text-[#333333] '>{message}</div> */ }
|
||||
</div> : null
|
||||
}
|
||||
|
||||
<div className='w-full flex justify-center items-center font-medium text-[base] leading-[1.5rem]'>
|
||||
<button
|
||||
className='border border-[#DC5A5D] bg-[#DC5A5D] rounded-[.5rem] w-[10.375rem] h-[2.75rem] flex items-center justify-center text-white'
|
||||
style={ {
|
||||
width: '10.375rem',
|
||||
height: '2.75rem',
|
||||
} }
|
||||
onClick={ closeModalFunction }
|
||||
>
|
||||
{ buttonText }
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
</aside>
|
||||
)
|
||||
}
|
||||
|
||||
export default ModalAlert
|
||||
@@ -0,0 +1,98 @@
|
||||
import React from "react";
|
||||
import { CloseIcon, DangerIcon } from "Assets/svgs";
|
||||
import { InteractiveButton } from "Components/InteractiveButton";
|
||||
import { MdClose } from "react-icons/md";
|
||||
|
||||
// type Props = {
|
||||
// closeModalFunction: () => void
|
||||
// actionHandler: any
|
||||
// message?: string
|
||||
// title?: string
|
||||
// rejectText?: string
|
||||
// acceptText?: string
|
||||
// titleClasses?: string
|
||||
// messageClasses?: string
|
||||
// }
|
||||
|
||||
const ModalPrompt = ({
|
||||
open,
|
||||
closeModalFunction,
|
||||
actionHandler,
|
||||
message,
|
||||
title,
|
||||
messageClasses,
|
||||
titleClasses,
|
||||
acceptText = "",
|
||||
rejectText = "Cancel",
|
||||
loading = false,
|
||||
allowAccept = true,
|
||||
}) => {
|
||||
return (
|
||||
<aside
|
||||
className={`fixed inset-0 m-auto flex items-center justify-center backdrop-blur-sm transition-all ${
|
||||
open ? "scale-100" : "scale-0"
|
||||
}`}
|
||||
style={{
|
||||
backgroundColor: "rgba(0, 0, 0, 0.5)",
|
||||
zIndex: "91000",
|
||||
}}
|
||||
>
|
||||
<section className="flex w-[25rem] min-w-[25rem] flex-col gap-6 rounded-md bg-white px-6 py-6">
|
||||
<div className="flex justify-between ">
|
||||
<div>
|
||||
{title ? (
|
||||
<div className={` ${titleClasses}`}>
|
||||
{title}
|
||||
{/* <div className='py-3 text-[1rem] leading-[1.75rem] text-[#333333] '>{message}</div> */}
|
||||
</div>
|
||||
) : null}
|
||||
{/* <DangerIcon className={`h-5 w-5`} /> */}
|
||||
{/* <img src={danger} width={30} height={30} alt='danger' /> */}
|
||||
</div>
|
||||
<button disabled={loading} onClick={closeModalFunction}>
|
||||
<MdClose className="text-xl" />
|
||||
{/* <img src={Close} width={30} height={30} alt='close' /> */}
|
||||
</button>
|
||||
</div>
|
||||
{/* {title ? (
|
||||
<div className={` ${titleClasses}`}>
|
||||
{title}
|
||||
</div>
|
||||
) : null} */}
|
||||
{/* <div className='py-3 text-[1rem] leading-[1.75rem] text-[#333333] '>{message}</div> */}
|
||||
{message ? (
|
||||
<div className={`text-[#667085] ${messageClasses}`}>
|
||||
{message}
|
||||
{/* <div className='py-3 text-[1rem] leading-[1.75rem] text-[#333333] '>{message}</div> */}
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
<div className="flex w-full justify-between gap-2 font-medium uppercase leading-[1.5rem] text-[base]">
|
||||
<InteractiveButton
|
||||
disabled={loading}
|
||||
loading={loading}
|
||||
className={`${
|
||||
allowAccept ? "flex !w-1/2" : "hidden w-0"
|
||||
} h-[2.75rem] !rounded-[.625rem] bg-primary uppercase !text-white`}
|
||||
onClick={actionHandler}
|
||||
>
|
||||
{acceptText && acceptText.toLowerCase() !== "yes"
|
||||
? `Yes ${acceptText}`
|
||||
: "Yes"}
|
||||
</InteractiveButton>
|
||||
<button
|
||||
disabled={loading}
|
||||
className={`flex h-[2.75rem] items-center justify-center rounded-[.625rem] border border-[#d8dae5] text-[#667085] ${
|
||||
allowAccept ? " w-1/2" : "grow"
|
||||
}`}
|
||||
onClick={closeModalFunction}
|
||||
>
|
||||
{rejectText}
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
</aside>
|
||||
);
|
||||
};
|
||||
|
||||
export default ModalPrompt;
|
||||
@@ -0,0 +1,3 @@
|
||||
export { Modal } from "./Modal";
|
||||
export { default as ModalPrompt } from "./ModalPrompt";
|
||||
export { default as ModalAlert } from "./ModalAlert";
|
||||
Reference in New Issue
Block a user