377 lines
15 KiB
React
377 lines
15 KiB
React
import {
|
|
validationSchema as VS,
|
|
useDispatch,
|
|
useSelector,
|
|
usersService,
|
|
initialValues as IV,
|
|
initialReqState,
|
|
useState,
|
|
tableReload,
|
|
Formik,
|
|
InputCom,
|
|
Field,
|
|
Form,
|
|
LoadingSpinner,
|
|
} from "./settings";
|
|
|
|
const validationSchema = VS;
|
|
|
|
function AddJob({ popUpHandler, categories }) {
|
|
const ApiCall = new usersService();
|
|
const { walletDetails } = useSelector((state) => state.walletDetails);
|
|
|
|
let dispatch = useDispatch();
|
|
|
|
const [requestStatus, setRequestStatus] = useState(initialReqState); // Holds state when submit button is pressed
|
|
|
|
const handleAddJob = async (values, helpers) => {
|
|
const reqData = {
|
|
country: values?.country,
|
|
price: Number(values.price) * 100,
|
|
title: values?.title,
|
|
description: values?.description,
|
|
job_detail: values?.job_detail,
|
|
timeline_days: values?.timeline_days,
|
|
category: values.category?.join("@"),
|
|
};
|
|
|
|
setRequestStatus({ loading: true, status: false, message: "" });
|
|
|
|
try {
|
|
const res = await ApiCall.jobManagerCreateJob(reqData);
|
|
if (res.data.internal_return < 1) {
|
|
setRequestStatus({
|
|
loading: false,
|
|
status: false,
|
|
message: "Could not complete your request at the moment",
|
|
});
|
|
setTimeout(() => {
|
|
popUpHandler();
|
|
}, 1500);
|
|
} else {
|
|
setRequestStatus({
|
|
loading: false,
|
|
status: true,
|
|
message: "Job Added Successfully",
|
|
});
|
|
setTimeout(() => {
|
|
dispatch(tableReload({ type: "JOBTABLE" }));
|
|
popUpHandler();
|
|
}, 1000);
|
|
}
|
|
} catch (err) {
|
|
setRequestStatus({
|
|
loading: false,
|
|
status: false,
|
|
message: "Oops! Something went wrong. Try Again",
|
|
});
|
|
} finally {
|
|
setTimeout(() => {
|
|
setRequestStatus({ loading: false, status: false, message: "" });
|
|
}, 5000);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="add-job p-5 w-full bg-white dark:bg-dark-white dark:text-white rounded-md flex flex-col justify-between">
|
|
<Formik
|
|
initialValues={IV}
|
|
validationSchema={validationSchema}
|
|
onSubmit={handleAddJob}
|
|
>
|
|
{(props) => {
|
|
return (
|
|
<Form>
|
|
<div className="flex flex-col-reverse sm:flex-row">
|
|
<div className="fields w-full">
|
|
{/* inputs starts here */}
|
|
<div className="xl:flex xl:space-x-7 mb-[5px]">
|
|
<div className="field w-full mb-6 xl:mb-0">
|
|
<label
|
|
htmlFor="country"
|
|
className="input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold flex item-center gap-1"
|
|
>
|
|
Currency
|
|
{props.errors.country && props.touched.country && (
|
|
<span className="text-[12px] text-red-500">
|
|
{props.errors.country}
|
|
</span>
|
|
)}
|
|
</label>
|
|
<select
|
|
id="country"
|
|
name="country"
|
|
value={props.values.country}
|
|
className={`input-field p-2 mt-3 rounded-md placeholder:text-base text-dark-gray dark:text-white w-full h-10 bg-slate-100 dark:bg-[#11131F] focus:ring-0 focus:outline-none border`}
|
|
onChange={props.handleChange}
|
|
onBlur={props.handleBlur}
|
|
>
|
|
{walletDetails?.loading ? (
|
|
<option className="text-slate-500 text-lg" value="">
|
|
Loading...
|
|
</option>
|
|
) : walletDetails.data.length ? (
|
|
<>
|
|
<option className="text-slate-500 text-lg" value="">
|
|
Select a currency
|
|
</option>
|
|
{walletDetails.data?.map((item, index) => (
|
|
<option
|
|
key={index}
|
|
className="text-slate-500 text-lg"
|
|
value={item?.country}
|
|
>
|
|
{item?.description}
|
|
</option>
|
|
))}
|
|
</>
|
|
) : (
|
|
<option className="text-slate-500 text-lg" value="">
|
|
No Options Found! Try Again
|
|
</option>
|
|
)}
|
|
</select>
|
|
</div>
|
|
|
|
{/* Price */}
|
|
<div className="field w-full">
|
|
<InputCom
|
|
fieldClass="px-6 text-right"
|
|
label="Price"
|
|
labelClass="tracking-wide"
|
|
type="number"
|
|
name="price"
|
|
placeholder="0"
|
|
value={props.values.price}
|
|
inputHandler={props.handleChange}
|
|
blurHandler={props.handleBlur}
|
|
error={
|
|
props.errors.price &&
|
|
props.touched.price &&
|
|
props.errors.price
|
|
}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Title */}
|
|
<div className="field w-full mb-[5px]">
|
|
<InputCom
|
|
fieldClass="px-6"
|
|
label="Title"
|
|
labelClass="tracking-wide"
|
|
type="text"
|
|
name="title"
|
|
value={props.values.title}
|
|
inputHandler={props.handleChange}
|
|
blurHandler={props.handleBlur}
|
|
error={
|
|
props.errors.title &&
|
|
props.touched.title &&
|
|
props.errors.title
|
|
}
|
|
/>
|
|
</div>
|
|
|
|
{/* Description */}
|
|
<div className="field w-full mb-[5px]">
|
|
<InputCom
|
|
fieldClass="px-6"
|
|
label="Description"
|
|
labelClass="tracking-wide"
|
|
type="text"
|
|
name="description"
|
|
value={props.values.description}
|
|
inputHandler={props.handleChange}
|
|
blurHandler={props.handleBlur}
|
|
error={
|
|
props.errors.description &&
|
|
props.touched.description &&
|
|
props.errors.description
|
|
}
|
|
/>
|
|
</div>
|
|
|
|
{/* Details */}
|
|
<div className="field flex flex-col sm:flex-row w-full mb-[5px] gap-2">
|
|
<div className="sm:w-[60%] w-full">
|
|
<label
|
|
htmlFor="Job Delivery Details"
|
|
className="input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold flex items-center gap-1"
|
|
>
|
|
Job Delivery Details
|
|
{props.errors.job_detail &&
|
|
props.touched.job_detail && (
|
|
<span className="text-[12px] text-red-500">
|
|
{props.errors.job_detail}
|
|
</span>
|
|
)}
|
|
</label>
|
|
<textarea
|
|
id="Job Delivery Details"
|
|
rows="5"
|
|
className={`input-field px-3 py-2 placeholder:text-base text-dark-gray dark:text-white w-full h-[100px] bg-slate-100 dark:bg-[#11131F] focus:ring-0 focus:outline-[#dce4e9] rounded-[10px] border`}
|
|
style={{ resize: "none" }}
|
|
name="job_detail"
|
|
value={props.values.job_detail}
|
|
onChange={props.handleChange}
|
|
onBlur={props.handleBlur}
|
|
/>
|
|
</div>
|
|
|
|
<div className="sm:w-[35%] w-full">
|
|
<div
|
|
htmlFor="Job Categories"
|
|
className='className="input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold block"'
|
|
id="checked-group"
|
|
>
|
|
Categories
|
|
</div>
|
|
<div
|
|
className="sm:flex-col flex flex-wrap px-3 mt-3"
|
|
role="group"
|
|
aria-labelledby="checked-group"
|
|
>
|
|
{categories ? (
|
|
<>
|
|
{Object?.entries(categories).map(([key, value]) => (
|
|
<label
|
|
key={key}
|
|
className="flex gap-1 w-full items-center"
|
|
>
|
|
<Field
|
|
type="checkbox"
|
|
name="category"
|
|
value={key}
|
|
/>
|
|
<span className="text-[13.975px]">{value}</span>
|
|
</label>
|
|
))}
|
|
</>
|
|
) : (
|
|
<label className="flex gap-1 w-full items-center">
|
|
<Field type="checkbox" name="category" />
|
|
<span className="text-[13.975px]">null</span>
|
|
</label>
|
|
)}
|
|
<span className="h-5 text-sm italic text-[#cf3917]">
|
|
{props.errors.category &&
|
|
props.touched.category &&
|
|
"please select a category"}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="field w-full mb-[5px]">
|
|
<div className={`flex items-center justify-between mb-2.5`}>
|
|
<label
|
|
className="input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold block"
|
|
htmlFor="timeline_days"
|
|
>
|
|
Timeline
|
|
<span className="text-green-700 text-sm tracking-wide">
|
|
- Expected duration of this task
|
|
</span>
|
|
</label>
|
|
</div>
|
|
|
|
<Field
|
|
component="select"
|
|
name="timeline_days"
|
|
className={`input-field p-2 mt-3 rounded-md placeholder:text-base text-dark-gray dark:text-white w-full h-10 bg-slate-100 dark:bg-[#11131F] focus:ring-0 focus:outline-none border ${
|
|
props.errors.timeline_days &&
|
|
props.touched.timeline_days
|
|
? "border-[#ff0a0a63] shadow-red-500 border-[0.5px] animate-shake"
|
|
: "border border-[#f5f8fa] dark:border-[#5e6278]"
|
|
}`}
|
|
value={props.values.timeline_days}
|
|
>
|
|
<option value="">Select Duration</option>
|
|
{publicArray.map(({ name, duration }, idx) => (
|
|
<option
|
|
key={idx}
|
|
className="text-slate-500 text-lg"
|
|
value={duration}
|
|
>
|
|
{name}
|
|
</option>
|
|
))}
|
|
</Field>
|
|
</div>
|
|
{/* inputs ends here */}
|
|
</div>
|
|
</div>
|
|
|
|
{/* ERROR DISPLAY AND SUBMIT BUTTON */}
|
|
<div className="content-footer w-full">
|
|
{/* error or success display */}
|
|
{requestStatus.message != "" &&
|
|
(!requestStatus.status ? (
|
|
<div
|
|
className={`relative p-4 my-4 text-[#912741] bg-[#fcd9e2] border-[#fbc6d3] mb-4 rounded-[0.475rem] text-md font-light leading-[19.5px] text-[13px]`}
|
|
>
|
|
{requestStatus.message}
|
|
</div>
|
|
) : (
|
|
requestStatus.status && (
|
|
<div
|
|
className={`relative p-4 my-4 text-green-700 bg-slate-200 border-slate-800 mb-4 rounded-[0.475rem] text-md font-light leading-[19.5px] text-[13px]`}
|
|
>
|
|
{requestStatus.message}
|
|
</div>
|
|
)
|
|
))}
|
|
{/* End of error or success display */}
|
|
|
|
<div className="w-full h-[70px] border-t border-light-purple dark:border-[#5356fb29] flex justify-end items-center">
|
|
<div className="flex items-center space-x-4 mr-9">
|
|
<button
|
|
type="button"
|
|
className="text-18 text-light-red tracking-wide "
|
|
>
|
|
<span
|
|
className="border-b dark:border-[#5356fb29] border-light-red"
|
|
onClick={popUpHandler}
|
|
>
|
|
{" "}
|
|
Cancel
|
|
</span>
|
|
</button>
|
|
|
|
{requestStatus?.loading ? (
|
|
<LoadingSpinner size="8" color="sky-blue" />
|
|
) : (
|
|
<button
|
|
type="submit"
|
|
className="w-[152px] h-[46px] flex justify-center items-center btn-gradient text-base rounded-full text-white"
|
|
>
|
|
Add Job
|
|
</button>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Form>
|
|
);
|
|
}}
|
|
</Formik>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default AddJob;
|
|
|
|
const publicArray = [
|
|
{ duration: 1, name: "1 day" },
|
|
{ duration: 2, name: "2 days" },
|
|
{ duration: 3, name: "3 days" },
|
|
{ duration: 4, name: "4 days" },
|
|
{ duration: 5, name: "5 days" },
|
|
{ duration: 6, name: "6 days" },
|
|
{ duration: 7, name: "1 week" },
|
|
{ duration: 14, name: "2 weeks" },
|
|
{ duration: 21, name: "3 weeks" },
|
|
{ duration: 28, name: "4 weeks" },
|
|
];
|