Compare commits

..

46 Commits

Author SHA1 Message Date
ebube 0756747143 updated payload 2023-12-11 20:30:44 -08:00
ameye 99eb1591a2 Merge branch 'Server-path-added' of WrenchBoard/Users-Wrench into master 2023-12-11 19:46:01 +00:00
ameye 85b9aab229 Merge branch 'upload_filename' of WrenchBoard/Users-Wrench into master 2023-12-11 19:45:55 +00:00
ebube 67a0a34288 Fixed a typo 2023-12-10 10:19:56 -08:00
ebube 814e4c9693 Fixed the amount in naira add credit payload to flutterwave 2023-12-03 23:55:43 -08:00
victorAnumudu e74eb38caf defaulted filename to myfile 2023-11-29 19:56:28 +01:00
ameye 67db1a72bf Merge branch 'Server-path-added' of WrenchBoard/Users-Wrench into master 2023-11-29 14:32:03 +00:00
ebube 41e46d8030 Reverted updates 2023-11-29 06:30:36 -08:00
ebube 8707411dda added a linux checker 2023-11-28 21:02:17 -08:00
ameye 327a4a42ae Merge branch 'Server-path-added' of WrenchBoard/Users-Wrench into master 2023-11-29 01:33:58 +00:00
ebube 455f4001f7 Final Check 2023-11-28 09:18:54 -08:00
ebube 775bcd5005 Clean up...added feature to edit popup 2023-11-28 09:11:52 -08:00
ebube 492bda021f Select Option Bug Fixed 2023-11-28 07:41:31 -08:00
ebube eacfae19f0 Currency Bug Fix 2023-11-28 07:26:34 -08:00
ebube 376cf44a9c Currency option set to fixed and category option set 2023-11-28 06:41:32 -08:00
ameye 1aab0c2910 Merge branch 'upload_download_link' of WrenchBoard/Users-Wrench into master 2023-11-28 11:56:05 +00:00
victorAnumudu 1f5fb8c7c3 upload file bug fixed 2023-11-28 11:50:16 +01:00
victorAnumudu a303b24b53 upload file bug fixed 2023-11-28 11:33:59 +01:00
victorAnumudu 322927045c Merge master into upload_download_link 2023-11-28 03:18:45 +01:00
victorAnumudu 3cf1dc7166 added download link# 2023-11-28 03:17:23 +01:00
ameye 8ed331e909 Merge branch 'wrong-upload-placeholder' of WrenchBoard/Users-Wrench into master 2023-11-28 01:42:14 +00:00
ameye 2428923f73 Merge branch 'file_link_bug' of WrenchBoard/Users-Wrench into master 2023-11-28 01:41:53 +00:00
victorAnumudu 139f87c919 corrected wrong placeholders 2023-11-28 02:16:49 +01:00
victorAnumudu c24fbedf2c file link updated 2023-11-27 12:49:18 +01:00
ameye 1a817e723e Merge branch 'Server-path-added' of WrenchBoard/Users-Wrench into master 2023-11-27 11:31:03 +00:00
ebube c023911cd4 Fixed prev card issue 2023-11-27 03:19:39 -08:00
ameye 907dc298ab Merge branch 'file_link_update' of WrenchBoard/Users-Wrench into master 2023-11-27 10:32:02 +00:00
ameye 8095006386 Merge branch 'Server-path-added' of WrenchBoard/Users-Wrench into master 2023-11-27 10:31:57 +00:00
ebube d9d28791da Added and specified card_uid for prev and new card 2023-11-27 01:49:09 -08:00
ebube a98d967ba4 Fixed the credit issues 2023-11-27 01:12:24 -08:00
victorAnumudu 59a5e84ee2 uploaded link for file added 2023-11-27 07:00:58 +01:00
ameye 35ed1d48a3 Merge branch 'zero-bal-job-add' of WrenchBoard/Users-Wrench into master 2023-11-23 11:12:47 +00:00
victorAnumudu f9d385dfec made user to be able to add job even with zero wallet bal 2023-11-23 12:04:29 +01:00
ameye 033af03221 Merge branch 'Server-path-added' of WrenchBoard/Users-Wrench into master 2023-11-22 03:26:54 +00:00
ebube b3afb94030 Added family banner 2023-11-21 15:47:02 -08:00
ameye 0b1aa4e7d9 Merge branch 'Server-path-added' of WrenchBoard/Users-Wrench into master 2023-11-21 16:18:24 +00:00
ebube 18c4f31322 seen the issue 2023-11-21 08:02:11 -08:00
ebube 97e3344953 Added tabs as individual components 2023-11-21 07:32:36 -08:00
ebube 9565ca0d35 Fixed typo causing error displays in the console.log 2023-11-21 07:22:33 -08:00
ameye 51cc4edc1d Merge branch 'assign-task-message-bug' of WrenchBoard/Users-Wrench into master 2023-11-21 14:15:49 +00:00
victorAnumudu d12a1fd579 fixed error message display 2023-11-21 15:04:22 +01:00
ameye 21f1173e66 Merge branch 'Server-path-added' of WrenchBoard/Users-Wrench into master 2023-11-21 14:03:58 +00:00
ebube cf5ae81918 Added tabs for family settings 2023-11-21 05:58:57 -08:00
ameye 235bb7d667 Merge branch 'wallet-reload' of WrenchBoard/Users-Wrench into master 2023-11-21 11:25:59 +00:00
ameye 18a319a437 Merge branch 'Server-path-added' of WrenchBoard/Users-Wrench into master 2023-11-21 11:25:54 +00:00
Chief Bube 7cb5cc558b added box 2023-11-12 12:55:13 -08:00
24 changed files with 655 additions and 246 deletions
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" id="DownloadArrow"><g fill="#4687ba" class="color9a7baa svgShape"><path d="M30.179 3.525V1.857c0-1.551-1.784-2.415-3.011-1.449L24 2.907 20.824.402c-1.216-.959-3.002-.093-3.002 1.456v1.668a1 1 0 0 0 1 1h10.357c.552-.001 1-.449 1-1.001zM30.179 25.172v-2.524a1 1 0 0 0-1-1H18.822a1 1 0 0 0-1 1v2.524a1 1 0 0 0 1 1h10.357a1 1 0 0 0 1-1zM30.179 10.74V8.217a1 1 0 0 0-1-1H18.822a1 1 0 0 0-1 1v2.524a1 1 0 0 0 1 1h10.357c.552-.001 1-.448 1-1.001zM30.179 17.956v-2.524a1 1 0 0 0-1-1H18.822a1 1 0 0 0-1 1v2.524a1 1 0 0 0 1 1h10.357a1 1 0 0 0 1-1zM25.748 47.029l9.336-15.018c.852-1.371-.133-3.145-1.748-3.145H14.664c-1.614 0-2.6 1.774-1.748 3.145l9.336 15.018a2.058 2.058 0 0 0 3.496 0z" fill="#000000" class="color000000 svgShape"></path></g></svg>

After

Width:  |  Height:  |  Size: 799 B

+20 -82
View File
@@ -1,74 +1,28 @@
import { Field, Form, Formik } from "formik";
import React, { useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import * as Yup from "yup";
import usersService from "../../services/UsersService";
import { tableReload } from "../../store/TableReloads";
import InputCom from "../Helpers/Inputs/InputCom";
import LoadingSpinner from "../Spinners/LoadingSpinner";
import {
validationSchema as VS,
useDispatch,
useSelector,
usersService,
initialValues as IV,
initialReqState,
useState,
tableReload,
Formik,
InputCom,
Field,
Form,
LoadingSpinner,
} from "./settings";
const validationSchema = Yup.object().shape({
country: Yup.string()
.min(1, "Minimum 3 characters")
.max(25, "Maximum 25 characters")
.required("Currency is required"),
price: Yup.string()
.typeError("Invalid number")
.min(1, "Price must be greater than 0")
.test("no-e", "Invalid number", (value) => {
if (value && /\d+e/.test(value)) {
return false;
}
return true;
})
.required("Price is required"),
title: Yup.string()
.min(5, "Minimum 5 characters")
.max(149, "Maximum 149 characters")
.required("Title is required"),
description: Yup.string()
.min(5, "Minimum 5 characters")
.max(299, "Maximum 299 characters")
.required("Description is required"),
job_detail: Yup.string()
.min(3, "Minimum 3 characters")
.max(499, "Maximum 499 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"),
category: Yup.array().min(1, "Select at least one checkbox"),
});
const validationSchema = VS;
function AddJob({ popUpHandler, categories }) {
const ApiCall = new usersService();
const { walletDetails } = useSelector((state) => state.walletDetails);
let dispatch = useDispatch();
let initialValues = {
// initial values for formik
country: "",
price: "",
title: "",
description: "",
job_detail: "",
timeline_days: "",
category: [],
};
let [requestStatus, setRequestStatus] = useState({
loading: false,
status: false,
message: "",
}); // Holds state when submit button is pressed
const getWalletDetail = (country) => { // A FUNCTION TO GET USER BALANCE BASED ON COUNTRY SELECTED
const walletChecker = walletDetails?.data.find(
(item) => item.country === country
);
return walletChecker ? walletChecker.amount : 0;
};
const [requestStatus, setRequestStatus] = useState(initialReqState); // Holds state when submit button is pressed
const handleAddJob = async (values, helpers) => {
const reqData = {
@@ -81,21 +35,6 @@ function AddJob({ popUpHandler, categories }) {
category: values.category?.join("@"),
};
const walletAmount = getWalletDetail(reqData.country); // GETTING USER BALANCE BASED ON COUNTRY SELECTED
if (reqData.price > walletAmount) {
setRequestStatus({
loading: false,
status: false,
message: "Insufficient Balance",
});
setTimeout(() => {
setRequestStatus({ loading: false, status: false, message: "" });
}, 1500);
return;
}
setRequestStatus({ loading: true, status: false, message: "" });
try {
@@ -136,7 +75,7 @@ function AddJob({ popUpHandler, categories }) {
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={initialValues}
initialValues={IV}
validationSchema={validationSchema}
onSubmit={handleAddJob}
>
@@ -258,7 +197,7 @@ function AddJob({ popUpHandler, categories }) {
<div className="sm:w-[60%] w-full">
<label
htmlFor="Job Delivery Details"
className='className="input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold flex items-center gap-1'
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 &&
@@ -406,7 +345,6 @@ function AddJob({ popUpHandler, categories }) {
<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>
+100
View File
@@ -0,0 +1,100 @@
import { Field, Form, Formik } from "formik";
import { useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import * as Yup from "yup";
import usersService from "../../services/UsersService";
import { tableReload } from "../../store/TableReloads";
import InputCom from "../Helpers/Inputs/InputCom";
import LoadingSpinner from "../Spinners/LoadingSpinner";
// Initialize state for request values
const initialReqState = {
loading: false,
status: false,
message: "",
};
// For form initial values
const initialValues = {
// initial values for formik
country: "",
price: "",
title: "",
description: "",
job_detail: "",
timeline_days: "",
category: [],
};
// const getWalletDetail = (country) => { // A FUNCTION TO GET USER BALANCE BASED ON COUNTRY SELECTED
// const walletChecker = walletDetails?.data.find(
// (item) => item.country === country
// );
// return walletChecker ? walletChecker.amount : 0;
// };
// To get the validation schema
const validationSchema = Yup.object().shape({
country: Yup.string()
.min(1, "Minimum 3 characters")
.max(25, "Maximum 25 characters")
.required("Currency is required"),
price: Yup.string()
.typeError("Invalid number")
.min(1, "Price must be greater than 0")
.test("no-e", "Invalid number", (value) => {
if (value && /\d+e/.test(value)) {
return false;
}
return true;
})
.required("Price is required"),
title: Yup.string()
.min(5, "Minimum 5 characters")
.max(149, "Maximum 149 characters")
.required("Title is required"),
description: Yup.string()
.min(5, "Minimum 5 characters")
.max(299, "Maximum 299 characters")
.required("Description is required"),
job_detail: Yup.string()
.min(3, "Minimum 3 characters")
.max(499, "Maximum 499 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"),
category: Yup.array().min(1, "Select category"),
});
const getWalletDetail = (countryParams, walletDetails) => {
// A FUNCTION TO GET USER BALANCE BASED ON COUNTRY SELECTED
const walletChecker = walletDetails?.data.find(
(item) => item.country === countryParams
);
return walletChecker
? {
description: walletChecker.description,
country: walletChecker.country,
}
: "";
};
export {
Field,
Form,
Formik,
useState,
useEffect,
useDispatch,
useSelector,
usersService,
InputCom,
LoadingSpinner,
initialReqState,
initialValues,
validationSchema,
getWalletDetail,
tableReload
};
@@ -94,11 +94,11 @@ const AssignTaskPopout = React.memo(
const requiredFields = {
banner,
// category,
country,
currency:country,
description,
job_detail,
'job detail':job_detail,
price,
timeline_days,
timeline:timeline_days,
title,
};
@@ -108,7 +108,7 @@ const AssignTaskPopout = React.memo(
setRequestStatus({
loading: false,
status: false,
message: `${field} is empty`,
message: `${field[0].toUpperCase()+field.slice(1).toLowerCase()} is empty`,
});
return setTimeout(() => {
setRequestStatus({ loading: false, status: false, message: "" });
@@ -0,0 +1,9 @@
import React from 'react'
const AddFamily = () => {
return (
<div>Add Family</div>
)
}
export default AddFamily
@@ -0,0 +1,153 @@
import React, { useMemo, useRef, useState } from "react";
import usersService from "../../../../services/UsersService";
const FamilyBanner = ({ imageServer }) => {
const uploadedImage = `${imageServer}${localStorage.getItem(
"session_token"
)}/familybanner/${localStorage.getItem("uid")}`;
const familyBannerRef = useRef(null);
const jobApi = useMemo(() => new usersService(), []);
const [familyBannerImage, setFamilyBannerImage] = useState(uploadedImage);
const [uploadStatus, setUploadStatus] = useState({
loading: false,
status: false,
message: "",
});
/**
* Handles the change event of the family image input field.
* Checks if the selected file exceeds the maximum file size limit and displays an alert if it does.
* If the file is within the size limit, it reads the file using the FileReader API and sets the profile image state with the result.
*/
const familyBannerHandler = (e) => {
setUploadStatus({ loading: false, status: false, message: "" });
let acceptedFormat = ["jpeg", "jpg", "png", "bmp"]; // ARRAY OF SUPPORTED FORMATS
let uploadedFile = e.target.files[0]; //UPLOADED FILE
const fileFormat = uploadedFile?.type?.split("/")[1]?.toLowerCase();
if (!acceptedFormat.includes(fileFormat)) {
//CHECKING FOR CORRECT UPLOAD FORMAT
const msg = `Please select ${acceptedFormat
.slice(0, -1)
.join(", ")} or ${acceptedFormat.slice(-1)}`;
setUploadStatus({ loading: false, status: false, message: msg });
return setTimeout(() => {
// profileImgInput.current.value = '' // clear the input
setUploadStatus({ loading: false, status: false, message: "" });
}, 5000);
}
if (uploadedFile.size > 5 * 1048576) {
// CHECKING FOR CORRECT FILE SIZE
setUploadStatus({
loading: false,
status: false,
message: "File must not exceed 5MB",
});
return setTimeout(() => {
// profileImgInput.current.value = '' // clear the input
setUploadStatus({ loading: false, status: false, message: "" });
}, 5000);
}
if (e.target.value !== "") {
const imgReader = new FileReader();
imgReader.onload = (event) => {
let base64Img = imgReader.result.split(",")[1];
let reqData = {
// PAYLOAD FOR API CALL
job_uid: localStorage.getItem("uid"),
file_name: uploadedFile?.name.slice(0, 19),
file_size: uploadedFile?.size,
file_type: uploadedFile?.type?.split("/")[0]?.toLowerCase(),
file_data: base64Img,
msg_type: "FILE",
action: 11303,
};
setUploadStatus({
loading: true,
status: false,
message: "Loading...",
});
jobApi
.sendFiles(reqData)
.then((res) => {
if (res.status != 200 || res.data.internal_return < 0) {
return setUploadStatus({
loading: false,
status: false,
message: "Something went wrong, try again",
});
}
setUploadStatus({
loading: false,
status: true,
message: "Uploaded successfully",
});
setFamilyBannerImage(event.target.result);
})
.catch((error) => {
setUploadStatus({
loading: false,
status: false,
message: "Network error, try again",
});
})
.finally(() => {
setTimeout(() => {
setUploadStatus({ loading: false, status: false, message: "" });
}, 5000);
});
};
imgReader.readAsDataURL(e.target.files[0]);
}
};
return (
<div className="flex flex-col gap-4">
<div className="w-full lg:h-[400px] rounded-2xl">
<img
src={familyBannerImage}
alt="familyBanner"
className="w-full h-full object-cover rounded-2xl"
/>
</div>
<div className="flex justify-between w-full">
<div>
{uploadStatus.message && !uploadStatus.loading && (
<p
className={`text-center ${
uploadStatus.status ? "text-green-500" : "text-red-500"
}`}
>
{uploadStatus.message}
</p>
)}
{uploadStatus.loading && (
<p className="text-center">{uploadStatus.message}</p>
)}
</div>
<div>
<input
ref={familyBannerRef}
className="hidden"
type="file"
accept="image/*"
onChange={familyBannerHandler}
/>
<button
className="btn-gradient w-[153px] h-[46px] rounded-full text-white lg:flex hidden justify-center items-center"
onClick={() => familyBannerRef.current.click()}
>
Change Banner
</button>
</div>
</div>
</div>
);
};
export default FamilyBanner;
@@ -0,0 +1,9 @@
import React from 'react'
const Relatives = () => {
return (
<div>Relatives</div>
)
}
export default Relatives
@@ -0,0 +1,5 @@
import AddFamily from "./AddFamily";
import FamilyBanner from "./FamilyBanner";
import Relatives from "./Relatives";
export {AddFamily, FamilyBanner, Relatives}
@@ -1,7 +1,56 @@
import React from "react";
import React, { useEffect, useState } from "react";
import { Link, useLocation } from "react-router-dom";
import Icons from "../../Helpers/Icons";
import Layout from "../../Partials/Layout";
import { AddFamily, FamilyBanner, Relatives } from "./Tabs";
const FamilySettings = () => {
let {state} = useLocation()
const tabs = [
{
id: 1,
name: "add_family",
title: "Add Family",
iconName: "new-family",
},
{
id: 2,
name: "relatives",
title: "Relatives",
iconName: "people-hover",
},
{
id: 3,
name: "family_banner",
title: "Family Banner",
iconName: "people-hover",
},
];
const [tab, setTab] = useState(() => {
// Retrieve the active tab from local storage or use the default tab
return localStorage.getItem("activeTab") || tabs[0].name;
});
const tabHandler = (value) => {
setTab(value);
};
// Update local storage when the tab changes
useEffect(() => {
localStorage.setItem("activeTab", tab);
}, [tab]);
const tabComponents = {
add_family: <AddFamily />,
relatives: <Relatives />,
family_banner: <FamilyBanner imageServer={state.imageServer} />,
};
const defaultTabComponent = Array(tabComponents)[0].add_family;
const selectedComponent = tabComponents[tab] || defaultTabComponent;
return (
<Layout>
<div className="notification-page w-full mb-10">
@@ -13,9 +62,38 @@ const FamilySettings = () => {
<span className={``}>Family Settings</span>
</h1>
</div>
<div></div>
<Link to="/acc-family">Go Back</Link>
</div>
{/* Something Here */}
{/* <form className="logout-modal-body w-full flex flex-col items-center px-10 py-8 gap-4"></form> */}
<div className="w-full bg-white dark:bg-dark-white overflow-y-auto rounded-2xl section-shadow h-full ">
<div className="update-table w-full h-full p-4 bg-white dark:bg-dark-white overflow-y-auto rounded-2xl section-shadow min-h-[520px] lg:flex lg:px-10 px-4 justify-between">
<div className="content-tab-items lg:w-[230px] w-full mr-2">
<ul className="overflow-hidden mb-10 lg:mb-0 py-8">
{tabs.map(({ name, id, title, iconName }) => (
<li
onClick={() => tabHandler(name)}
key={id}
className={`flex lg:space-x-4 space-x-2 hover:text-purple transition-all duration-300 ease-in-out items-center cursor-pointer lg:mb-11 mb-2 mr-6 lg:mr-0 float-left lg:float-none overflow-hidden ${
tab === name ? "text-purple" : " text-thin-light-gray"
}`}
>
<div>
<Icons name={iconName} />
</div>
<div>
<p className="text-18 tracking-wide">{title}</p>
</div>
</li>
))}
</ul>
</div>
<div className="w-[1px] bg-[#E3E4FE] dark:bg-[#a7a9b533] mr-10"></div>
<div className="flex-1">
<div className="tab-item">{selectedComponent}</div>
</div>
</div>
</div>
</div>
</div>
</Layout>
+1 -1
View File
@@ -149,7 +149,7 @@ export default function FamilyTable({
className="w-[0.7rem]"
>
<path
fill-rule="evenodd"
fillRule="evenodd"
d="M.366 19.708c.405.39 1.06.39 1.464 0l8.563-8.264a1.95 1.95 0 0 0 0-2.827L1.768.292A1.063 1.063 0 0 0 .314.282a.976.976 0 0 0-.011 1.425l7.894 7.617a.975.975 0 0 1 0 1.414L.366 18.295a.974.974 0 0 0 0 1.413"
// fill=""
className="color000000 svgShape fill-[#fff]"
+1
View File
@@ -158,6 +158,7 @@ export default function FamilyAcc() {
</div>
<Link
to={`/familysettings`}
state={{ imageServer: familyList?.session_image_server }}
className="slider-btns flex space-x-4 w-12 h-12 rounded-md shadow-sm justify-center items-center cursor-pointer dark:bg-[linear-gradient(134.38deg,#f539f8_0%,#c342f9_43.55%,#5356fb_104.51%)]"
>
<svg
@@ -30,21 +30,26 @@ export default function ActiveJobMessage({ activeJobMesList }) {
{activeJobMesList?.data?.length ?
(
<tbody>
{activeJobMesList.data.map((item, index) => (
<tr key={index} className='text-slate-500'>
<td>
<div className={`msg_box ${item.who}`}>
<div className="msg_header">{item.msg_date} {item.msg_firstname}</div>
{item.msg_type == 'FILE' ?
<a href='' className="p-2" dangerouslySetInnerHTML={{__html: item.message}}></a>
:
<span className="p-2" dangerouslySetInnerHTML={{__html: item.message}}></span>
}
</div>
</td>
</tr>
))}
{activeJobMesList.data.map((item, index) =>
{
let imageLink = `${activeJobMesList?.image}${localStorage.getItem('session_token')}/contracts/${item.msg_uid}`
return (
<tr key={index} className='text-slate-500'>
<td>
<div className={`msg_box ${item.who}`}>
<div className="msg_header">{item.msg_date} {item.msg_firstname}</div>
{item.msg_type == 'FILE' ?
<a href={imageLink} target="_blank" className="p-2" dangerouslySetInnerHTML={{__html: item.message}}></a>
:
<span className="p-2" dangerouslySetInnerHTML={{__html: item.message}}></span>
}
</div>
</td>
</tr>
)
}
)}
</tbody>
)
:
@@ -34,7 +34,7 @@ function PastDueJobAction({jobDetails}) {
let reqData = { // API PAYLOADS
contract: jobDetails.contract,
contract_uid: jobDetails.contract_uid,
job_action: 'REQUEST_CANCEL',
job_action: 'CANCEL_CONTRACT',
}
if(!checked){ // CHECKS IF CHECKBOX IS SELECTED
@@ -21,7 +21,7 @@ export default function MyPastDueJobs(props) {
<span
className={`${selectTab === "today" ? "block" : "hidden"}`}
>
Pass Due Job(s)
Past Due Job(s)
</span>
</h1>
</div>
@@ -64,17 +64,21 @@ const initialValues = {
};
function AddFundDollars(props) {
let MaxNoOfCards = process.env.REACT_APP_MAX_CREDIT_CARDS // HOLDS THE VALUE OF THE MAX NUMBER OF CARDS USER CAN ADD
let MaxNoOfCards = process.env.REACT_APP_MAX_CREDIT_CARDS; // HOLDS THE VALUE OF THE MAX NUMBER OF CARDS USER CAN ADD
const apiCall = new usersService();
let countryWallet = props.walletItem.country;
const [tab, setTab] = useState("previous");
const [selectedOption, setSelectedOption] = useState("previous");
const { userDetails } = useSelector((state) => state?.userDetails);
const [prevCardDetails, setPrevCardDetails] = useState({});
const [payListCards, setPayListCards] = useState({ loading: true, data: [] });
const [cardIcons, setCardIcons] = useState("atm-card");
const [prevCardError, setPrevCardError] = useState("");
const handleOptionChange = (event) => {
setSelectedOption(event.target.value);
};
const { firstname, lastname } = userDetails;
// Handling Card Icons
@@ -144,7 +148,12 @@ function AddFundDollars(props) {
return;
}
if (tab === "previous") {
let stateData = {
amount: Number(props.input) * 100,
currency: props.walletItem?.code,
};
if (selectedOption === "previous") {
// To check if card is empty
if (Object.keys(prevCardDetails).length === 0) {
setPrevCardError("No card selected!");
@@ -158,10 +167,26 @@ function AddFundDollars(props) {
show: { awaitConfirm: { loader: true } },
}));
let stateData = {
amount: Number(props.input) * 100,
currency: props.walletItem?.code,
};
// Extracting card_uid from the previous card details
const paymentCardValue = prevCardDetails["payment-card"];
if (paymentCardValue) {
try {
const paymentCardObject = JSON.parse(paymentCardValue);
stateData = {
...stateData,
card_uid: paymentCardObject.card_uid,
};
} catch (error) {
console.error("Error parsing JSON:", error);
}
} else {
// For the new card details
stateData = {
...stateData,
card_uid: "",
};
}
try {
const res = await apiCall.getStartCredit(stateData);
@@ -171,12 +196,11 @@ function AddFundDollars(props) {
}
const _response = res.data;
stateData.amount = Number(props.input);
stateData.card =
tab === "previous"
selectedOption === "previous"
? prevCardDetails["payment-card"]
: { ...values, cvv: values.cvv };
stateData.cardType = tab === "previous" ? "prev" : "new";
stateData.cardType = selectedOption === "previous" ? "prev" : "new";
stateData = { ...stateData, ..._response };
setTimeout(() => {
@@ -224,36 +248,45 @@ function AddFundDollars(props) {
</h1>
<div className="my-1 flex items-center gap-2">
<label
onClick={() => setTab("previous")}
htmlFor="previous"
className="cursor-pointer flex items-center gap-1"
>
<input
type="radio"
id="previous"
value="previous"
name="card-option"
checked={tab === "previous"}
onChange={handleOptionChange}
checked={selectedOption === "previous"}
className={`p-2 text-lg font-bold text-slate-600 dark:text-white border pointer-events-none w-7 h-7 ${
tab == "previous" ? "" : ""
selectedOption == "previous" ? "" : ""
} tracking-wide transition duration-200`}
/>
Previous Cards
</label>
<label
onClick={() => setTab("new")}
htmlFor="new"
className={`cursor-pointer flex items-center gap-1 ${payListCards.data.length >= MaxNoOfCards ? 'pointer-events-none':''}`}
className={`cursor-pointer flex items-center gap-1 ${
payListCards.data.length >= MaxNoOfCards
? "pointer-events-none"
: ""
}`}
>
<input
id="new"
type="radio"
name="card-option"
checked={tab === "new"}
value="new"
onChange={handleOptionChange}
checked={selectedOption === "new"}
className={`p-2 text-lg font-bold text-slate-600 dark:text-white border pointer-events-none w-7 h-7 ${
tab == "new" ? "" : ""
selectedOption == "new" ? "" : ""
} tracking-wide transition duration-200`}
/>
Add New Card {payListCards.data.length >= MaxNoOfCards && <span className="text-[14px] text-red-500">Max Reached</span>}
Add New Card{" "}
{payListCards.data.length >= MaxNoOfCards && (
<span className="text-[14px] text-red-500">Max Reached</span>
)}
</label>
</div>
</form>
@@ -261,8 +294,8 @@ function AddFundDollars(props) {
<hr />
{/* END OF switch button */}
{/* previous tab */}
{tab === "previous" && (
{/* previous selectedOption */}
{selectedOption === "previous" && (
<div className="p-4 previous-details w-full min-h-[16.5rem] flex flex-col">
{payListCards.loading ? (
<LoadingSpinner size="10" color="sky-blue" />
@@ -278,10 +311,11 @@ function AddFundDollars(props) {
{currentPreviousCards.map((item, index) => (
<option
key={index}
className={index !== 0 && "border-t-2"}
className={index !== 0 ? "border-t-2" : undefined}
value={JSON.stringify(item)}
title={`${item.description} Card\nBank **************${item.digits}`}
>
<div className="my-2 flex items-center gap-5">
{/* <div className="my-2 flex items-center gap-5">
<div className="card-details">
<h1 className="text-lg font-bold text-dark-gray dark:text-white tracking-wide">
{item.description} Card
@@ -290,7 +324,8 @@ function AddFundDollars(props) {
Bank **************{item.digits}
</p>
</div>
</div>
</div> */}
{item.description} Card - Bank **************{item.digits}
</option>
))}
</select>
@@ -300,7 +335,7 @@ function AddFundDollars(props) {
No Previous Card Found!
</p>
<button
onClick={() => setTab("new")}
onClick={() => setSelectedOption("new")}
type="button"
className="my-5 px-2 py-1 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white"
>
@@ -314,13 +349,13 @@ function AddFundDollars(props) {
</div>
)}
{tab === "new" && (
{selectedOption === "new" && (
<div className="new-details w-full max-h-[22rem]">
{payListCards.loading ?
{payListCards.loading ? (
<div className="pt-10 flex w-full h-full justify-center items-center">
<LoadingSpinner size='10' color='sky-blue' />
<LoadingSpinner size="10" color="sky-blue" />
</div>
:payListCards.data.length < MaxNoOfCards ?
) : payListCards.data.length < MaxNoOfCards ? (
<div className="w-full flex flex-col justify-between">
<Formik
initialValues={initialValues}
@@ -379,7 +414,8 @@ function AddFundDollars(props) {
*
</span>
<span className="text-[12px] text-red-500 ml-1">
{props.errors.expirationMonth && "**"}
{props.errors.expirationMonth &&
"**"}
</span>
</label>
</div>
@@ -431,7 +467,8 @@ function AddFundDollars(props) {
*
</span>
<span className="text-[12px] text-red-500 italic">
{props.errors.expirationYear && "**"}
{props.errors.expirationYear &&
"**"}
</span>
</label>
</div>
@@ -560,14 +597,12 @@ function AddFundDollars(props) {
}}
</Formik>
</div>
:
null
}
) : null}
</div>
)}
</div>
{tab == "previous" && (
{selectedOption == "previous" && (
<div className="md:py-8 add-fund-btn flex justify-end items-center gap-2 py-4">
<button
className="px-4 py-1 h-11 max-w-[100px] w-full flex justify-center bg-[#f5a430] text-black items-center text-base rounded-full"
@@ -71,6 +71,7 @@ function AddFundPop({
// Prepare state data for API call
let stateData = {
amount: Number(input) * 100,
card_uid: "", //added card_uid as empty string
currency: walletItem?.code,
};
@@ -45,7 +45,7 @@ function ThePaymentText({ value, type }) {
* @returns {JSX.Element} - The rendered component.
*/
function AmountSection({ currency, amount, country }) {
const formattedAmount = amount?.toFixed(2);
const formattedAmount = (+amount * 0.01)?.toFixed(2);
const gapClassName = country === "US" ? "gap-14" : "gap-4";
return (
@@ -87,7 +87,7 @@ function TransactionFeeSection({ currency, fee, country }) {
*/
function TotalSection({ currency, amount, fee, country }) {
const total = Number(amount) + Number(fee);
const formattedTotal = total?.toFixed(2);
const formattedTotal = (total * 0.01)?.toFixed(2);
const gap = country === "US" ? "gap-[8rem]" : "gap-[6.3rem]";
@@ -130,7 +130,7 @@ function ConfirmAddFund({
public_key: __confirmData?.flutterwave_key,
tx_ref: __confirmData?.credit_reference,
currency: "NGN",
amount: Number(__confirmData.amount),
amount: Number(__confirmData.amount) * 0.01,
payment_options: "card,mobilemoney,ussd",
customer: {
email: userDetails.email,
@@ -224,7 +224,7 @@ function ConfirmAddFund({
// Create request data object with required parameters for making the payment
const reqData = {
amount: amount * 100,
amount: amount,
card_uid,
credit_reference,
currency,
@@ -289,7 +289,7 @@ function ConfirmAddFund({
// Prepare request data
const reqData = {
amount: amount * 100,
amount: amount,
cardnumber: cardNum.replace(/\s/g, ""),
credit_reference,
cvc: cvv,
+1
View File
@@ -63,6 +63,7 @@ export default function Resources(props) {
loading: false,
msg: "success",
data: res?.result_list,
image:res?.session_image_server
}));
} catch (error) {
setUploadedFiles((prev) => ({
@@ -13,7 +13,6 @@ export default function MyUploadedFiles({ uploadedFiles }) {
indexOfFirstItem,
indexOfLastItem
);
const handlePagination = (e) => {
handlePagingFunc(e, setCurrentPage);
};
@@ -45,10 +44,11 @@ export default function MyUploadedFiles({ uploadedFiles }) {
currentFiles.map((value, idx) => {
let addedDate = value?.added?.split(" ")[0];
let formattedSize = formatFileSize(value?.file_size);
let imageLink = `${uploadedFiles?.image}${localStorage.getItem('session_token')}/myfile/${value.file_uid}`
return (
<tr
key={value?.file_uid}
className="bg-white dark:bg-dark-white border-b dark:border-[#5356fb29] hover:bg-gray-50"
className="bg-white dark:bg-dark-white border-b dark:border-[#5356fb29] hover:bg-gray-50"
>
<td className=" py-4">
<div className="flex space-x-2 items-center w-full">
@@ -102,17 +102,17 @@ export default function MyUploadedFiles({ uploadedFiles }) {
</td>
<td className="text-right py-4 px-2">
<div className="flex justify-center items-center">
<button
type="button"
// onClick={() => {
// navigate("/manage-active-job", {
// state: { ...value, pathname },
// });
// }}
className="w-20 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white"
<a
href={imageLink}
title="download"
// className="w-20 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white"
>
View
</button>
<img
src={localImgLoad('images/icons/download-arrow.svg')}
alt='download-link'
className="w-auto h-6 flex justify-center items-center"
/>
</a>
</div>
</td>
</tr>
@@ -157,7 +157,7 @@ export default function ProductUploadField({
fieldClass="px-6"
type="text"
name="name"
placeholder="RaidParty Fighters"
placeholder="Item Name"
inputHandler={inh}
value={datas.itemName}
/>
@@ -186,7 +186,7 @@ export default function ProductUploadField({
<textarea
value={datas.description}
onChange={(e) => dscrphn(e)}
placeholder="provide a detailed description of your item."
placeholder="Enter detail description"
rows="7"
className="w-full h-full px-7 py-4 border border-light-purple dark:border-[#5356fb29] rounded-[20px] text-dark-gray dark:text-white bg-[#FAFAFA] dark:bg-[#11131F] focus:ring-0 focus:outline-none"
/>
+12 -6
View File
@@ -144,14 +144,14 @@ export default function UploadProduct({uploadTypes}) {
}
let reqData = { // PAYLOAD FOR API CALL
file_name: selectedFile.substring(0,21).replace(/ /gi, ""),//selectedFile.replace(/[ -]/gi, ""),
// file_name: selectedFile.substring(0,21).replace(/ /gi, ""),
file_name: `myfile.${imgDetails?.type?.split('/')[1]}`,
file_size: imgDetails.size,
file_type: imgDetails.type,
file_data: img.file,
file_data: img.file?.split(",")[1],
title: itemName,
description: description,
msg_type: 'FILE',
// action: 'WRENCHBOARD_RESOURCE_MYFILES',
action: 11307
}
@@ -602,7 +602,10 @@ export default function UploadProduct({uploadTypes}) {
//FUNCTIONS to check if file upload type is valid
const isValidFile = (file, supportedFile=[]) => {
let fileType = file.type.split("/")[1];
let fileType = file.type.split("/")[1].toLowerCase();
if(fileType=='jpg' || fileType=='jpeg'){ //forcing both JPG and JPEG TO RETURN JPG AS FILE TYPE
fileType = 'jpg'
}
let valid = supportedFile.filter(item => (
item.name.toLowerCase() == fileType.toLowerCase()
))
@@ -615,7 +618,10 @@ const isValidFile = (file, supportedFile=[]) => {
//FUNCTIONS TO CHECK IF FILE SIZE IS VALID
const isValidFileSize = (file, supportedFile=[]) => {
let fileType = file.type.split("/")[1];
let fileType = file.type.split("/")[1].toLowerCase();
if(fileType=='jpg' || fileType=='jpeg'){ //forcing both JPG and JPEG TO RETURN JPG AS FILE TYPE
fileType = 'jpg'
}
let fileSize = file.size;
let valid = supportedFile.filter(item => (
item.name.toLowerCase() == fileType.toLowerCase()
@@ -627,6 +633,6 @@ const isValidFileSize = (file, supportedFile=[]) => {
return {status: false, message: `File must not exceed ${valid[0].max_size_mb}MB`}
}
}else{
return false
return {status: false, message: `Cannot read file size, try again`}
}
}
+144 -78
View File
@@ -52,12 +52,19 @@ const EditJobPopOut = ({
}) => {
const dispatch = useDispatch();
const { userDetails } = useSelector((state) => state.userDetails);
const uploadedImage = `${userDetails.session_image_server}${localStorage.getItem('session_token')}/job/${details?.job_uid}`
const { walletDetails } = useSelector((state) => state.walletDetails);
const [taskImage, setTaskImage] = useState(uploadedImage)
const uploadedImage = `${
userDetails.session_image_server
}${localStorage.getItem("session_token")}/job/${details?.job_uid}`;
let [uploadStatus, setUploadStatus] = useState({loading: false, status: false, message:''}) // HOLDS STATE FOR UPLOAD PROFILE PICTURE STATUS
const [taskImage, setTaskImage] = useState(uploadedImage);
let [uploadStatus, setUploadStatus] = useState({
loading: false,
status: false,
message: "",
}); // HOLDS STATE FOR UPLOAD PROFILE PICTURE STATUS
let [requestStatus, setRequestStatus] = useState({
loading: false,
@@ -113,65 +120,100 @@ const EditJobPopOut = ({
);
const taskImgChangeHandler = (e) => {
setUploadStatus({loading: false, status: false, message:''})
let acceptedFormat = ["jpeg", "jpg", "png", "bmp", "gif"] // ARRAY OF SUPPORTED FORMATS
let uploadedFile = e.target.files[0] //UPLOADED FILE
setUploadStatus({ loading: false, status: false, message: "" });
let acceptedFormat = ["jpeg", "jpg", "png", "bmp", "gif"]; // ARRAY OF SUPPORTED FORMATS
let uploadedFile = e.target.files[0]; //UPLOADED FILE
const fileFormat = uploadedFile?.type?.split("/")[1]?.toLowerCase();
if(!acceptedFormat.includes(fileFormat)){ //CHECKING FOR CORRECT UPLOAD FORMAT
const msg = `Please select ${acceptedFormat.slice(0, -1).join(', ')} or ${acceptedFormat.slice(-1)}`;
setUploadStatus({loading: false, status: false, message:msg})
return setTimeout(()=>{
if (!acceptedFormat.includes(fileFormat)) {
//CHECKING FOR CORRECT UPLOAD FORMAT
const msg = `Please select ${acceptedFormat
.slice(0, -1)
.join(", ")} or ${acceptedFormat.slice(-1)}`;
setUploadStatus({ loading: false, status: false, message: msg });
return setTimeout(() => {
// profileImgInput.current.value = '' // clear the input
setUploadStatus({loading: false, status: false, message:''})
},5000)
setUploadStatus({ loading: false, status: false, message: "" });
}, 5000);
}
if(uploadedFile.size > 5*1048576){ // CHECKING FOR CORRECT FILE SIZE
setUploadStatus({loading: false, status: false, message:'File must not exceed 5MB'})
return setTimeout(()=>{
if (uploadedFile.size > 5 * 1048576) {
// CHECKING FOR CORRECT FILE SIZE
setUploadStatus({
loading: false,
status: false,
message: "File must not exceed 5MB",
});
return setTimeout(() => {
// profileImgInput.current.value = '' // clear the input
setUploadStatus({loading: false, status: false, message:''})
},5000)
setUploadStatus({ loading: false, status: false, message: "" });
}, 5000);
}
if (e.target.value !== "") {
const imgReader = new FileReader();
imgReader.onload = (event) => {
let base64Img = imgReader.result.split(",")[1];
let reqData = { // PAYLOAD FOR API CALL
let reqData = {
// PAYLOAD FOR API CALL
job_uid: details?.job_uid,
file_name: uploadedFile?.name.slice(0,19),
file_name: uploadedFile?.name.slice(0, 19),
file_size: uploadedFile?.size,
file_type: uploadedFile?.type?.split("/")[0]?.toLowerCase(),
file_data: base64Img,
msg_type: 'FILE',
action: 11303
}
setUploadStatus({loading: true, status: false, message:'Loading...'})
jobApi.sendFiles(reqData).then(res=>{
if(res.status != 200 || res.data.internal_return < 0){
return setUploadStatus({loading: false, status: false, message: 'Something went wrong, try again'})
}
setUploadStatus({loading: false, status: true, message: 'Uploaded successfully'})
setTaskImage(event.target.result);
setTimeout(() => {
dispatch(tableReload({ type: "JOBTABLE" }));
navigate("/myjobs", { replace: true });
onClose();
}, 1000);
}).catch(error=>{
setUploadStatus({loading: false, status: false, message: 'Network error, try again'})
}).finally(()=>{
setTimeout(()=>{
setUploadStatus({loading: false, status: false, message: ''})
},5000)
})
msg_type: "FILE",
action: 11303,
};
setUploadStatus({
loading: true,
status: false,
message: "Loading...",
});
jobApi
.sendFiles(reqData)
.then((res) => {
if (res.status != 200 || res.data.internal_return < 0) {
return setUploadStatus({
loading: false,
status: false,
message: "Something went wrong, try again",
});
}
setUploadStatus({
loading: false,
status: true,
message: "Uploaded successfully",
});
setTaskImage(event.target.result);
setTimeout(() => {
dispatch(tableReload({ type: "JOBTABLE" }));
navigate("/myjobs", { replace: true });
onClose();
}, 1000);
})
.catch((error) => {
setUploadStatus({
loading: false,
status: false,
message: "Network error, try again",
});
})
.finally(() => {
setTimeout(() => {
setUploadStatus({ loading: false, status: false, message: "" });
}, 5000);
});
};
imgReader.readAsDataURL(e.target.files[0]);
}
};
// Check if the user is using iOS
const isIOS = /MacIntel|MacPPC/.test(navigator.platform) && !window.MSStream;
// Check if the user is using Windows
const isWindows = /Windows/.test(navigator.userAgent);
return (
<ModalCom action={onClose} situation={situation} className="edit-popup">
<div className="logout-modal-wrapper lg:w-[600px] h-full lg:h-auto bg-white dark:bg-dark-white lg:rounded-2xl">
@@ -325,19 +367,20 @@ const EditJobPopOut = ({
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>
))}
{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>
))}
<span className="h-5 text-sm italic text-[#cf3917]">
{props.errors.category &&
props.touched.category &&
@@ -349,31 +392,40 @@ const EditJobPopOut = ({
<div className="w-full flex items-center gap-2 mb-2">
{/* FOR TASK IMAGE */}
<div className="w-1/2 relative max-h-[130px] min-h-[130px]">
<input
<input
id="task_image"
className="hidden"
type="file"
accept="image/*"
className="hidden"
type="file"
accept="image/*"
onChange={taskImgChangeHandler}
/>
{taskImage ?
<div className="w-full absolute -top-5">
<img src={taskImage} className="max-h-[150px] min-h-[150px] w-full object-cover" alt="uplaoded task image" />
<span onClick={()=>setTaskImage('')} className="p-2 absolute text-sm top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 bg-white/80 hover:bg-white hover:shadow-md transition-all duration-500 cursor-pointer text-slate-800">Remove Image</span>
</div>
:
<label
className="absolute -top-5 h-[150px] w-full flex flex-col justify-center items-center bg-slate-100 dark:bg-[#11131F] cursor-pointer input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold" htmlFor='task_image'>
{taskImage ? (
<div className="w-full absolute -top-5">
<img
src={taskImage}
className="max-h-[150px] min-h-[150px] w-full object-cover"
alt="uploaded task"
/>
<span
onClick={() => setTaskImage("")}
className="p-2 absolute text-sm top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 bg-white/80 hover:bg-white hover:shadow-md transition-all duration-500 cursor-pointer text-slate-800"
>
Remove Image
</span>
</div>
) : (
<label
className="absolute -top-5 h-[150px] w-full flex flex-col justify-center items-center bg-slate-100 dark:bg-[#11131F] cursor-pointer input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold"
htmlFor="task_image"
>
Select Task Image
</label>
}
</label>
)}
</div>
{/* END OF TASK IMAGE */}
<div className="field w-1/2">
<div
className={`flex items-center justify-between`}
>
<div className={`flex items-center justify-between`}>
<label
className="w-full input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold flex flex-col"
htmlFor="timeline_days"
@@ -433,11 +485,23 @@ const EditJobPopOut = ({
))}
{/* End of error or success display */}
{/* DISPLAYS TASK IMAGE UPLOADING STATUS */}
<div className="w-full">
{uploadStatus.message && !uploadStatus.loading && <p className={`text-center ${uploadStatus.status ? 'text-green-500':'text-red-500'}`}>{uploadStatus.message}</p>}
{uploadStatus.loading && <p className="text-center">{uploadStatus.message}</p>}
</div>
{/* DISPLAYS TASK IMAGE UPLOADING STATUS */}
<div className="w-full">
{uploadStatus.message && !uploadStatus.loading && (
<p
className={`text-center ${
uploadStatus.status
? "text-green-500"
: "text-red-500"
}`}
>
{uploadStatus.message}
</p>
)}
{uploadStatus.loading && (
<p className="text-center">{uploadStatus.message}</p>
)}
</div>
<div className="w-full border-t border-light-purple dark:border-[#5356fb29] flex justify-end items-center">
<div className="flex items-center space-x-4 mr-2 mt-2">
@@ -448,7 +512,9 @@ const EditJobPopOut = ({
type="submit"
className="w-[120px] h-[40px] 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'
disabled={requestStatus.loading || uploadStatus.loading}
disabled={
requestStatus.loading || uploadStatus.loading
}
>
Save
</button>
+2 -2
View File
@@ -133,9 +133,9 @@ function OfferJobPopout({ details, onClose, situation }) {
</svg>
</button>
</div>
<div className="md:flex bg-white rounded-lg shadow-lg">
<div className="md:flex bg-white dark:bg-dark-white rounded-lg shadow-lg">
<div className="p-4 w-full md:w-3/4 md:border-r-2">
<p className="text-lg my-5 font-semibold text-slate-900 tracking-wide">
<p className="text-lg my-5 font-semibold text-slate-900 dark:text-white tracking-wide">
{details.title}
</p>
+1
View File
@@ -39,6 +39,7 @@ function ManageActiveJobs() {
loading: false,
error: false,
data: res.data.result_list,
image: res.data.session_image_server
});
})
.catch((error) => {