Update Tasks

This commit is contained in:
Possible
2024-06-26 15:42:26 +01:00
parent 3ce5e57376
commit 7adba815e2
16 changed files with 712 additions and 8 deletions
@@ -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";
+1 -1
View File
@@ -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
+89
View File
@@ -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 };
+56
View File
@@ -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
+98
View File
@@ -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;
+3
View File
@@ -0,0 +1,3 @@
export { Modal } from "./Modal";
export { default as ModalPrompt } from "./ModalPrompt";
export { default as ModalAlert } from "./ModalAlert";