399 lines
15 KiB
React
399 lines
15 KiB
React
import React, { useState, useEffect } from "react";
|
|
import { Link, useNavigate } from "react-router-dom";
|
|
import InputCom from "../Helpers/Inputs/InputCom";
|
|
import LoadingSpinner from "../Spinners/LoadingSpinner";
|
|
import usersService from "../../services/UsersService";
|
|
|
|
import { useSelector } from "react-redux";
|
|
|
|
import { Form, Formik } from "formik";
|
|
import * as Yup from "yup";
|
|
|
|
const validationSchema = Yup.object().shape({
|
|
country: Yup.string()
|
|
.min(1, "Minimum 3 characters")
|
|
.max(25, "Maximum 25 characters")
|
|
.required("Country is required"),
|
|
price: Yup.number()
|
|
.typeError("you must specify a number")
|
|
.min(1, "Price must be greater than 0")
|
|
.required("Price is required"),
|
|
title: Yup.string()
|
|
.min(3, "Minimum 3 characters")
|
|
.max(100, "Maximum 25 characters")
|
|
.required("Title is required"),
|
|
description: Yup.string()
|
|
.min(3, "Minimum 3 characters")
|
|
.max(250, "Maximum 250 characters")
|
|
.required("Description is required"),
|
|
job_detail: Yup.string()
|
|
.min(3, "Minimum 3 characters")
|
|
.max(250, "Maximum 250 characters")
|
|
.required("Details is required"),
|
|
timeline_days: Yup.number()
|
|
.typeError("you must specify a number")
|
|
.min(1, "Price must be greater than 0")
|
|
.required("Timeline is required"),
|
|
});
|
|
|
|
// let initialValues = {
|
|
// // initial values for formik
|
|
// country: "NG",
|
|
// price: 0,
|
|
// title: "",
|
|
// description: "",
|
|
// job_detail: "",
|
|
// timeline_days: "",
|
|
// };
|
|
|
|
function AddJob() {
|
|
const ApiCall = new usersService();
|
|
const navigate = useNavigate();
|
|
|
|
let {userDetails} = useSelector((state)=> state.userDetails)
|
|
|
|
let [pageLoading, setPageLoading] = useState(true); // State used for knowing when the page is mounting
|
|
|
|
let [country, setCountry] = useState({
|
|
loading: true,
|
|
status: false,
|
|
data: [],
|
|
}); // To Hold the array of country getUserCountry returns
|
|
|
|
let initialValues = {
|
|
// initial values for formik
|
|
country: userDetails.country,
|
|
price: "",
|
|
title: "",
|
|
description: "",
|
|
job_detail: "",
|
|
timeline_days: "",
|
|
};
|
|
|
|
let [requestStatus, setRequestStatus] = useState({
|
|
loading: false,
|
|
status: false,
|
|
message: "",
|
|
}); // Holds state when submit button is pressed
|
|
|
|
// FUNCTION TO GET COUNTRY
|
|
const getUserCountry = () => {
|
|
setCountry((prev) => ({ ...prev, loading: true }));
|
|
ApiCall.getSignupCountryData()
|
|
.then((res) => {
|
|
if (res.data.internal_return < 1) {
|
|
setCountry({ loading: false, status: true, data: [] });
|
|
return;
|
|
}
|
|
setCountry({
|
|
loading: false,
|
|
status: true,
|
|
data: res.data.signup_country,
|
|
});
|
|
})
|
|
.catch((err) => {
|
|
setCountry({ loading: false, status: false, data: [] });
|
|
});
|
|
};
|
|
|
|
// FUNCTION TO HANDLE ADD JOB FORM
|
|
const handleAddJob = (values, helpers) => {
|
|
setRequestStatus({ loading: true, status: false, message: "" });
|
|
ApiCall.jobManagerCreateJob(values)
|
|
.then((res) => {
|
|
if (res.data.internal_return < 1) {
|
|
setRequestStatus({
|
|
loading: false,
|
|
status: false,
|
|
message: "Could not complete your request at the moment",
|
|
});
|
|
return;
|
|
}
|
|
setRequestStatus({
|
|
loading: false,
|
|
status: true,
|
|
message: "Job Added Successfully",
|
|
});
|
|
setTimeout(() => {
|
|
navigate("/myjobs", { replace: true });
|
|
}, 1000);
|
|
})
|
|
.catch((err) => {
|
|
setRequestStatus({
|
|
loading: false,
|
|
status: false,
|
|
message: "Opps! soemthing went wrong. Try Again",
|
|
});
|
|
})
|
|
.finally(() => {
|
|
setTimeout(() => {
|
|
setRequestStatus({ loading: false, status: false, message: "" });
|
|
}, 5000);
|
|
});
|
|
};
|
|
|
|
useEffect(() => {
|
|
getUserCountry();
|
|
setPageLoading(false);
|
|
}, []);
|
|
|
|
return pageLoading.loading ? (
|
|
<div className="personal-info-tab w-full flex flex-col justify-between">
|
|
<div className="p-3">
|
|
<LoadingSpinner size="32" color="sky-blue" />
|
|
</div>
|
|
</div>
|
|
) : (
|
|
<div className="add-job p-5 w-full bg-white rounded-md flex flex-col justify-between">
|
|
<Formik
|
|
initialValues={initialValues}
|
|
validationSchema={validationSchema}
|
|
onSubmit={handleAddJob}
|
|
>
|
|
{(props) => {
|
|
return (
|
|
<Form>
|
|
<h1 className="py-2 my-4 text-lg md:text-xl font-bold tracking-wide">
|
|
Create New Job
|
|
</h1>
|
|
<div className="flex flex-col-reverse sm:flex-row">
|
|
<div className="fields w-full">
|
|
{/* inputs starts here */}
|
|
{/* country */}
|
|
<div className="xl:flex xl:space-x-7 mb-6">
|
|
<div className="field w-full mb-6 xl:mb-0">
|
|
{/* <InputCom
|
|
fieldClass="px-6 cursor-not-allowed"
|
|
label="Country"
|
|
labelClass='tracking-wide'
|
|
inputBg = 'bg-slate-100'
|
|
type="text"
|
|
name="country"
|
|
disable={true}
|
|
value={country.loading ? 'loading' : country.data ? country.data : 'no country found!'}
|
|
inputHandler={(e)=> setCountry((prev) => ({...prev, data:e.target.value}))}
|
|
|
|
/> */}
|
|
<label
|
|
htmlFor="country"
|
|
className="input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold block"
|
|
>
|
|
Country
|
|
</label>
|
|
<select
|
|
id="country"
|
|
name="country"
|
|
disabled
|
|
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`}
|
|
onChange={props.handleChange}
|
|
onBlur={props.handleBlur}
|
|
>
|
|
{country.loading ? (
|
|
<option className="text-slate-500 text-lg" value="">
|
|
Loading...
|
|
</option>
|
|
) : country.data.length ? (
|
|
<>
|
|
<option className="text-slate-500 text-lg" value="">
|
|
Select...
|
|
</option>
|
|
{country.data.map((item, index) => {
|
|
if(item[0] == userDetails.country){
|
|
return (
|
|
<option
|
|
key={index}
|
|
className="text-slate-500 text-lg"
|
|
value={item[0]}
|
|
>
|
|
{item[1]}
|
|
</option>
|
|
)
|
|
}
|
|
})}
|
|
</>
|
|
) : (
|
|
<option className="text-slate-500 text-lg" value="">
|
|
No Options Found! Try Again
|
|
</option>
|
|
)}
|
|
</select>
|
|
{props.errors.country && props.touched.country && (
|
|
<p className="text-sm text-red-500">
|
|
{props.errors.country}
|
|
</p>
|
|
)}
|
|
</div>
|
|
|
|
{/* Price */}
|
|
<div className="field w-full">
|
|
<InputCom
|
|
fieldClass="px-6 text-right"
|
|
label="Price"
|
|
labelClass="tracking-wide"
|
|
inputBg="bg-slate-100"
|
|
type="number"
|
|
name="price"
|
|
placeholder="0"
|
|
value={props.values.price}
|
|
inputHandler={props.handleChange}
|
|
blurHandler={props.handleBlur}
|
|
/>
|
|
{props.errors.price && props.touched.price && (
|
|
<p className="text-sm text-red-500">
|
|
{props.errors.price}
|
|
</p>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Title */}
|
|
|
|
<div className="field w-full mb-6">
|
|
<InputCom
|
|
fieldClass="px-6"
|
|
label="Title"
|
|
labelClass="tracking-wide"
|
|
inputBg="bg-slate-100"
|
|
type="text"
|
|
name="title"
|
|
// placeholder="Enter Job Title"
|
|
value={props.values.title}
|
|
inputHandler={props.handleChange}
|
|
blurHandler={props.handleBlur}
|
|
/>
|
|
{props.errors.title && props.touched.title && (
|
|
<p className="text-sm text-red-500">
|
|
{props.errors.title}
|
|
</p>
|
|
)}
|
|
</div>
|
|
|
|
{/* Description */}
|
|
<div className="field w-full mb-6">
|
|
<InputCom
|
|
fieldClass="px-6"
|
|
label="Description"
|
|
labelClass="tracking-wide"
|
|
inputBg="bg-slate-100"
|
|
type="text"
|
|
name="description"
|
|
// placeholder="Enter a description"
|
|
value={props.values.description}
|
|
inputHandler={props.handleChange}
|
|
blurHandler={props.handleBlur}
|
|
/>
|
|
{props.errors.description && props.touched.description && (
|
|
<p className="text-sm text-red-500">
|
|
{props.errors.description}
|
|
</p>
|
|
)}
|
|
</div>
|
|
|
|
{/* Details */}
|
|
<div className="field w-full mb-6">
|
|
<label
|
|
htmlFor="Job Delivery Details"
|
|
className='className="input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold block"'
|
|
>
|
|
Job Delivery Details
|
|
</label>
|
|
<textarea
|
|
id="Job Delivery Details"
|
|
rows="7"
|
|
className={`input-field p-6 mt-3 rounded-md placeholder:text-base text-dark-gray dark:text-white w-full h-full bg-slate-100 dark:bg-[#11131F] focus:ring-0 focus:outline-none`}
|
|
style={{ resize: "none" }}
|
|
name="job_detail"
|
|
value={props.values.job_detail}
|
|
onChange={props.handleChange}
|
|
onBlur={props.handleBlur}
|
|
/>
|
|
{props.errors.job_detail && props.touched.job_detail && (
|
|
<p className="text-sm text-red-500">
|
|
{props.errors.job_detail}
|
|
</p>
|
|
)}
|
|
</div>
|
|
|
|
<div className="field w-full mb-6">
|
|
<InputCom
|
|
fieldClass="px-6"
|
|
label="Timeline"
|
|
labelClass="tracking-wide"
|
|
inputBg="bg-slate-100"
|
|
type="text"
|
|
name="timeline_days"
|
|
spanTag=" - Expected duration of this task"
|
|
// placeholder="Please Enter Detail Description of Job"
|
|
value={props.values.timeline_days}
|
|
inputHandler={props.handleChange}
|
|
blurHandler={props.handleBlur}
|
|
/>
|
|
{props.errors.timeline_days &&
|
|
props.touched.timeline_days && (
|
|
<p className="text-sm text-red-500">
|
|
{props.errors.timeline_days}
|
|
</p>
|
|
)}
|
|
</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-[120px] border-t border-light-purple dark:border-[#5356fb29] flex justify-end items-center">
|
|
<div className="flex items-center space-x-4 mr-9">
|
|
<Link
|
|
to="/myjobs"
|
|
className="text-18 text-light-red tracking-wide "
|
|
>
|
|
<span className="border-b dark:border-[#5356fb29] border-light-red">
|
|
{" "}
|
|
Cancel
|
|
</span>
|
|
</Link>
|
|
|
|
{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"
|
|
// className='w-20 h-11 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;
|