Compare commits
57 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5f81c0b847 | |||
| 99eb1591a2 | |||
| 85b9aab229 | |||
| 67a0a34288 | |||
| 814e4c9693 | |||
| e74eb38caf | |||
| 67db1a72bf | |||
| 41e46d8030 | |||
| 8707411dda | |||
| 327a4a42ae | |||
| 455f4001f7 | |||
| 775bcd5005 | |||
| 492bda021f | |||
| eacfae19f0 | |||
| 376cf44a9c | |||
| 1aab0c2910 | |||
| 1f5fb8c7c3 | |||
| a303b24b53 | |||
| 322927045c | |||
| 3cf1dc7166 | |||
| 8ed331e909 | |||
| 2428923f73 | |||
| 139f87c919 | |||
| c24fbedf2c | |||
| 1a817e723e | |||
| c023911cd4 | |||
| 907dc298ab | |||
| 8095006386 | |||
| d9d28791da | |||
| a98d967ba4 | |||
| 59a5e84ee2 | |||
| 35ed1d48a3 | |||
| f9d385dfec | |||
| 033af03221 | |||
| b3afb94030 | |||
| 0b1aa4e7d9 | |||
| 18c4f31322 | |||
| 97e3344953 | |||
| 9565ca0d35 | |||
| 51cc4edc1d | |||
| d12a1fd579 | |||
| 21f1173e66 | |||
| cf5ae81918 | |||
| 235bb7d667 | |||
| 18a319a437 | |||
| d3e2cc6744 | |||
| a08d8feb7d | |||
| 7cb5cc558b | |||
| 36025ade56 | |||
| b80c21358a | |||
| f5ad68f7bb | |||
| 27cba1ac68 | |||
| dbb21d8a08 | |||
| a4597599b7 | |||
| 894f986574 | |||
| e42a358da6 | |||
| 23c2e840c2 |
@@ -50,6 +50,7 @@ import FamilyMarketPage from "./views/FamilyMarketPage";
|
||||
import FacebookRedirect from "./views/FacebookRedirect";
|
||||
import AppleRedirectPage from "./views/AppleRedirectPage";
|
||||
import LndPage from "./views/LndPage";
|
||||
import FamilySettingsPage from "./views/FamilySettingsPage";
|
||||
|
||||
export default function Routers() {
|
||||
return (
|
||||
@@ -98,6 +99,7 @@ export default function Routers() {
|
||||
<Route exact path="/market-place" element={<MarketPlacePage />} />
|
||||
<Route exact path="/market" element={<MarketPlacePage />} />
|
||||
<Route exact path="/familymarket" element={<FamilyMarketPage />} />
|
||||
<Route exact path="/familysettings" element={<FamilySettingsPage />} />
|
||||
<Route exact path="/notification" element={<Notification />} />
|
||||
<Route exact path="/mytask" element={<MyTaskPage />} />
|
||||
<Route exact path="/myjobs" element={<MyJobsPage />} />
|
||||
|
||||
@@ -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 |
@@ -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>
|
||||
|
||||
@@ -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
|
||||
};
|
||||
@@ -5,6 +5,8 @@ import { PriceFormatter } from "../../Helpers/PriceFormatter";
|
||||
import LoadingSpinner from "../../Spinners/LoadingSpinner";
|
||||
import Detail from "../../jobPopout/popoutcomponent/Detail";
|
||||
import { NewTasks } from "./forms";
|
||||
import { tableReload } from "../../../store/TableReloads";
|
||||
import { useDispatch } from "react-redux";
|
||||
|
||||
const AssignTaskPopout = React.memo(
|
||||
({
|
||||
@@ -19,6 +21,8 @@ const AssignTaskPopout = React.memo(
|
||||
}) => {
|
||||
const apiCall = new usersService();
|
||||
|
||||
const dispatch = useDispatch()
|
||||
|
||||
let [requestStatus, setRequestStatus] = useState({
|
||||
loading: false,
|
||||
status: false,
|
||||
@@ -90,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,
|
||||
};
|
||||
|
||||
@@ -104,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: "" });
|
||||
@@ -145,6 +149,7 @@ const AssignTaskPopout = React.memo(
|
||||
message: "action successful",
|
||||
});
|
||||
setUpdatePage(prev => !prev) // Updates family task page by calling the useeffect hook
|
||||
dispatch(tableReload({ type: "WALLETTABLE" })); // RELOADS USER WALLET
|
||||
setTimeout(() => {
|
||||
setRequestStatus({ loading: false, status: false, message: "" });
|
||||
action(); // FUNCTION THAT CLOSES THE MODAL BOX
|
||||
|
||||
@@ -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}
|
||||
@@ -0,0 +1,103 @@
|
||||
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">
|
||||
<div className="notification-wrapper w-full">
|
||||
{/* heading */}
|
||||
<div className="sm:flex justify-between items-center mb-6">
|
||||
<div className="mb-5 sm:mb-0">
|
||||
<h1 className="text-26 font-bold inline-flex gap-3 text-dark-gray dark:text-white items-center">
|
||||
<span className={``}>Family Settings</span>
|
||||
</h1>
|
||||
</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>
|
||||
);
|
||||
};
|
||||
|
||||
export default FamilySettings;
|
||||
@@ -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]"
|
||||
|
||||
@@ -5,6 +5,7 @@ import React, {
|
||||
useMemo,
|
||||
useState,
|
||||
} from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import usersService from "../../services/UsersService";
|
||||
import InputCom from "../Helpers/Inputs/InputCom";
|
||||
import ModalCom from "../Helpers/ModalCom";
|
||||
@@ -13,7 +14,6 @@ import LoadingSpinner from "../Spinners/LoadingSpinner";
|
||||
import FamilyTable from "./FamilyTable";
|
||||
|
||||
export default function FamilyAcc() {
|
||||
const [selectTab, setValue] = useState("today");
|
||||
// State to store the selected year and month
|
||||
const [selectedYear, setSelectedYear] = useState("");
|
||||
const [selectedMonth, setSelectedMonth] = useState("");
|
||||
@@ -33,10 +33,6 @@ export default function FamilyAcc() {
|
||||
setPopUp((prev) => !prev);
|
||||
};
|
||||
|
||||
const filterHandler = (value) => {
|
||||
setValue(value);
|
||||
};
|
||||
|
||||
// Handle year selection
|
||||
const handleYearChange = (e) => {
|
||||
setSelectedYear(e.target.value);
|
||||
@@ -116,7 +112,7 @@ export default function FamilyAcc() {
|
||||
const { data } = res;
|
||||
if (data?.internal_return >= 0 && data?.status === "OK") {
|
||||
const { result_list, session_image_server } = data;
|
||||
setFamilyList({result_list, session_image_server});
|
||||
setFamilyList({ result_list, session_image_server });
|
||||
setLoader(false);
|
||||
} else {
|
||||
return;
|
||||
@@ -146,12 +142,9 @@ export default function FamilyAcc() {
|
||||
<div className="sm:flex justify-between items-center mb-6">
|
||||
<div className="mb-5 sm:mb-0">
|
||||
<h1 className="text-26 font-bold inline-flex gap-3 text-dark-gray dark:text-white items-center">
|
||||
<span
|
||||
className={`${selectTab === "today" ? "block" : "hidden"}`}
|
||||
>
|
||||
Family Accounts
|
||||
</span>
|
||||
{familyList?.result_list?.length < process.env.REACT_APP_MAX_FAMILY_MEMBERS &&
|
||||
<span className={``}>Family Accounts</span>
|
||||
{familyList?.result_list?.length <
|
||||
process.env.REACT_APP_MAX_FAMILY_MEMBERS &&
|
||||
!loader && (
|
||||
<button
|
||||
onClick={popUpHandler}
|
||||
@@ -163,12 +156,31 @@ export default function FamilyAcc() {
|
||||
)}
|
||||
</h1>
|
||||
</div>
|
||||
<div className="slider-btns flex space-x-4">
|
||||
<div
|
||||
onClick={() => filterHandler("today")}
|
||||
className="relative"
|
||||
></div>
|
||||
</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
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth={1.5}
|
||||
stroke="currentColor"
|
||||
className="w-6 h-6 dark:stroke-white"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.324.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 011.37.49l1.296 2.247a1.125 1.125 0 01-.26 1.431l-1.003.827c-.293.24-.438.613-.431.992a6.759 6.759 0 010 .255c-.007.378.138.75.43.99l1.005.828c.424.35.534.954.26 1.43l-1.298 2.247a1.125 1.125 0 01-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.57 6.57 0 01-.22.128c-.331.183-.581.495-.644.869l-.213 1.28c-.09.543-.56.941-1.11.941h-2.594c-.55 0-1.02-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 01-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 01-1.369-.49l-1.297-2.247a1.125 1.125 0 01.26-1.431l1.004-.827c.292-.24.437-.613.43-.992a6.932 6.932 0 010-.255c.007-.378-.138-.75-.43-.99l-1.004-.828a1.125 1.125 0 01-.26-1.43l1.297-2.247a1.125 1.125 0 011.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.087.22-.128.332-.183.582-.495.644-.869l.214-1.281z"
|
||||
/>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
|
||||
/>
|
||||
</svg>
|
||||
</Link>
|
||||
</div>
|
||||
<Suspense fallback={<LoadingSpinner color="sky-blue" size="16" />}>
|
||||
<FamilyTable
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
import React, {useEffect, useState} from 'react'
|
||||
import Image from '../../assets/images/taskbanners/default.jpg'
|
||||
|
||||
import usersService from '../../services/UsersService';
|
||||
import { handlePagingFunc } from '../../components/Pagination/HandlePagination';
|
||||
import PaginatedList from '../../components/Pagination/PaginatedList';
|
||||
|
||||
import LoadingSpinner from '../Spinners/LoadingSpinner';
|
||||
|
||||
import { AmountTo2DP } from '../Helpers/PriceFormatter';
|
||||
|
||||
function JobsCompleted() {
|
||||
|
||||
const apiCall = new usersService()
|
||||
|
||||
let [familyRewardHistory, setFamilyRewardHistory] = useState({ // FOR PURCHASE HISTORY
|
||||
loading: true,
|
||||
data: [],
|
||||
error: false
|
||||
})
|
||||
|
||||
const [currentPage, setCurrentPage] = useState(0);
|
||||
const indexOfFirstItem = Number(currentPage);
|
||||
const indexOfLastItem = Number(indexOfFirstItem)+Number(process.env.REACT_APP_ITEM_PER_PAGE);
|
||||
const currentReward = familyRewardHistory?.data?.slice(indexOfFirstItem, indexOfLastItem);
|
||||
|
||||
const handlePagination = (e) => {
|
||||
handlePagingFunc(e,setCurrentPage)
|
||||
}
|
||||
|
||||
|
||||
//FUNCTION TO GET FAMILY REWARD HISTORY
|
||||
const getJobCompletedHistory = ()=>{
|
||||
// apiCall.getFamilyRewardHx().then((res)=>{
|
||||
// if(res.data.internal_return < 0){ // success but no data
|
||||
// setFamilyRewardHistory(prev => ({...prev, loading: false}))
|
||||
// return
|
||||
// }
|
||||
// setFamilyRewardHistory(prev => ({...prev, loading: false, data: res.data.result_list}))
|
||||
// }).catch((error)=>{
|
||||
// setFamilyRewardHistory(prev => ({...prev, loading: false, error: true}))
|
||||
// })
|
||||
setTimeout(()=>{
|
||||
setFamilyRewardHistory(prev => ({...prev, loading: false, error:true}))
|
||||
},3000)
|
||||
}
|
||||
|
||||
useEffect(()=>{
|
||||
getJobCompletedHistory()
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className='flex flex-col justify-between min-h-[500px]'>
|
||||
{familyRewardHistory.loading ?
|
||||
<LoadingSpinner size='16' color='sky-blue' height='h-[500px]' />
|
||||
: familyRewardHistory.data.length ?
|
||||
<table className="wallet-activity w-full table-auto border-collapse text-left">
|
||||
<thead className='border-b-2'>
|
||||
<tr className='text-slate-600'>
|
||||
<th className="p-2"></th>
|
||||
<th className="p-2">Amount</th>
|
||||
<th className="p-2">Date</th>
|
||||
<th className="p-2">Confirmation</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{currentReward.map((item, index) => {
|
||||
let date = new Date(item.added).toLocaleDateString()
|
||||
return (
|
||||
<tr key={index} className='text-slate-500'>
|
||||
<td className="p-2">
|
||||
<div className='flex items-center gap-2'>
|
||||
<img src={item.icon} className='min-w-[60px] max-w-[60px] min-h-[60px] max-h-[60px] rounded-full bg-slate-500' alt='Reward Logo' />
|
||||
<div className='flex flex-col'>
|
||||
<h1 className='text-lg font-bold'>Reward to {item.rec_firstname} {item.rec_lastname}</h1>
|
||||
<p className='text-sm'>{item.description}</p>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="p-2">{AmountTo2DP(item.amount*0.01)} {item.currency}</td>
|
||||
<td className="p-2">{date}</td>
|
||||
<td className="p-2">{item.confirmation}</td>
|
||||
</tr>
|
||||
)
|
||||
}
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
:familyRewardHistory.error ?
|
||||
<div className="p-2 text-slate-500 flex flex-col grow justify-center items-center">
|
||||
<span>Opps! an error occurred. Please try again!</span>
|
||||
</div>
|
||||
:
|
||||
<div className="p-2 text-slate-500 flex flex-col grow justify-center items-center">
|
||||
<span>No Completed Job History Found!</span>
|
||||
</div>
|
||||
}
|
||||
|
||||
{/* PAGINATION BUTTON */}
|
||||
<PaginatedList onClick={handlePagination} prev={currentPage == 0 ? true : false} next={currentPage+Number(process.env.REACT_APP_ITEM_PER_PAGE) >= familyRewardHistory?.data?.length ? true : false} data={familyRewardHistory?.data} start={indexOfFirstItem} stop={indexOfLastItem} />
|
||||
{/* END OF PAGINATION BUTTON */}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default JobsCompleted
|
||||
@@ -11,6 +11,7 @@ import PurchasesTable from "../MyWallet/WalletComponent/PurchasesTable";
|
||||
import RecentActivityTable from "../MyWallet/WalletComponent/RecentActivityTable";
|
||||
import LoadingSpinner from "../Spinners/LoadingSpinner";
|
||||
import RewardsTable from "./RewardsTable";
|
||||
import JobsCompleted from "./JobsCompleted";
|
||||
|
||||
export default function History() {
|
||||
|
||||
@@ -249,6 +250,15 @@ export default function History() {
|
||||
>
|
||||
Rewards
|
||||
</button>
|
||||
<button
|
||||
name="jobs_completed"
|
||||
onClick={(e) => setTab(e.target.name)}
|
||||
className={`px-4 py-1 rounded-t-2xl ${
|
||||
tab == "jobs_completed" ? "bg-[#4687ba] border-[2px] border-[#4687ba] text-white" : "bg-white text-[#000] border-t-[2px]"
|
||||
}`}
|
||||
>
|
||||
Jobs Completed
|
||||
</button>
|
||||
</div>
|
||||
{/* END OF switch button */}
|
||||
<div className="history-tables w-full">
|
||||
@@ -286,6 +296,14 @@ export default function History() {
|
||||
</div>
|
||||
}
|
||||
{/* END OF REWARD SECTION */}
|
||||
|
||||
{/* JOBS COMPLETED SECTION */}
|
||||
{tab == 'jobs_completed' &&
|
||||
<div className="wallet w-full border-t">
|
||||
<JobsCompleted />
|
||||
</div>
|
||||
}
|
||||
{/* END OF JOBS COMPLETED SECTION */}
|
||||
</div>
|
||||
</div>
|
||||
{/*<HistoryTable />*/}
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
:
|
||||
|
||||
@@ -3,9 +3,12 @@ import ModalCom from '../../Helpers/ModalCom'
|
||||
import LoadingSpinner from '../../Spinners/LoadingSpinner'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import usersService from '../../../services/UsersService'
|
||||
import { useDispatch } from 'react-redux'
|
||||
import { tableReload } from '../../../store/TableReloads'
|
||||
|
||||
function ReviewJobAction({jobDetails}) {
|
||||
|
||||
const dispatch = useDispatch()
|
||||
const apiCall = new usersService()
|
||||
const navigate = useNavigate()
|
||||
|
||||
@@ -48,6 +51,7 @@ function ReviewJobAction({jobDetails}) {
|
||||
return
|
||||
}
|
||||
setReqStatus({loading:false, status: true, message: 'job completion accepted successfully'})
|
||||
dispatch(tableReload({ type: "WALLETTABLE" }));
|
||||
setTimeout(()=>{ // Sets popout to false and navigates user to /my-review-jobs after 3 seconds
|
||||
popUpHandler()
|
||||
navigate('/my-review-jobs', {replace: true})
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -50,7 +50,7 @@ export default function WalletItemCardFamily({ walletItem, payment, countries })
|
||||
background: `url(${background}) 0% 0% / cover no-repeat`,
|
||||
}}
|
||||
>
|
||||
<div className="wallet w-full flex justify-between items-start gap-3">
|
||||
<div className="wallet w-full flex justify-between items-center gap-3">
|
||||
<div className="min-w-[100px] min-h-[100px] max-w-min md:max-w-[150px] max-h-min md:max-h-[150px] rounded-full bg-[#e3e3e3] flex justify-center items-center">
|
||||
<img
|
||||
src={localImgLoad(`images/currency/${image}`)}
|
||||
@@ -75,18 +75,6 @@ export default function WalletItemCardFamily({ walletItem, payment, countries })
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p className="text-lg text-white tracking-wide flex justify-center items-center gap-8">
|
||||
HOLDINGS :{" "}
|
||||
<span className="xxs:scale-100 lg:scale-100 xl:scale-125">
|
||||
{PriceFormatter(
|
||||
walletItem.escrow * 0.01,
|
||||
walletItem.code,
|
||||
undefined,
|
||||
"text-[2rem]"
|
||||
)}
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<div className="my-2 w-full h-[1px] bg-white"></div>
|
||||
|
||||
{/* <WalletAction
|
||||
|
||||
@@ -6,8 +6,11 @@ import CommonHead from "../UserHeader/CommonHead";
|
||||
import usersService from "../../services/UsersService";
|
||||
import LoadingSpinner from "../Spinners/LoadingSpinner";
|
||||
import OthersInterestedTable from "./OthersInterestedTable";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { tableReload } from "../../store/TableReloads";
|
||||
|
||||
export default function ManageInterestOffer(props) {
|
||||
const dispatch = useDispatch()
|
||||
const navigate = useNavigate()
|
||||
const apiCall = new usersService()
|
||||
|
||||
@@ -89,6 +92,7 @@ export default function ManageInterestOffer(props) {
|
||||
setRedirectTime(prev => prev - 1)
|
||||
}, 1000);
|
||||
setRequestStatus({loading: false, status: true, message: `Offer ${name}ed`, processType: ''})
|
||||
dispatch(tableReload({ type: "WALLETTABLE" }));
|
||||
setTimeout(()=>{
|
||||
navigate('/offer-interest', {replace: true})
|
||||
clearInterval(intervalTime)
|
||||
|
||||
@@ -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"
|
||||
/>
|
||||
|
||||
@@ -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`}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 dark:text-white"
|
||||
>
|
||||
<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>
|
||||
|
||||
@@ -6,4 +6,4 @@ export default function FamilyManagePage() {
|
||||
<FamilyManage />
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import FamilySettings from "../components/FamilyAcc/FamilySettings";
|
||||
|
||||
export default function FamilySettingsPage() {
|
||||
return (
|
||||
<>
|
||||
<FamilySettings />
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -39,6 +39,7 @@ function ManageActiveJobs() {
|
||||
loading: false,
|
||||
error: false,
|
||||
data: res.data.result_list,
|
||||
image: res.data.session_image_server
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
|
||||
Reference in New Issue
Block a user