Compare commits

..

48 Commits

Author SHA1 Message Date
Chief Bube 53db8df5c7 Added Picture path 2023-11-06 05:07:45 -08:00
ameye dd3f9d99f3 Merge branch 'Family-Acc-layout-update' of WrenchBoard/Users-Wrench into master 2023-11-06 09:33:43 +00:00
Chief Bube 8807b671ad update market data 2023-11-06 01:25:44 -08:00
ameye d66093a2ad Merge branch 'edit-job-add-image' of WrenchBoard/Users-Wrench into master 2023-11-05 10:53:44 +00:00
victorAnumudu b79eb6b158 Merge master into edit-job-add-image 2023-11-04 17:37:19 +01:00
victorAnumudu a759daaf90 edit job upload image added 2023-11-04 17:35:18 +01:00
ameye 600aec62cf Merge branch 'Family-Acc-layout-update' of WrenchBoard/Users-Wrench into master 2023-11-04 15:54:50 +00:00
Chief Bube 1612bf11ce Added JobOfferCancel 2023-11-04 08:47:42 -07:00
ameye f4e261eb6c Merge branch 'Family-Acc-layout-update' of WrenchBoard/Users-Wrench into master 2023-11-04 08:13:03 +00:00
Chief Bube b622398b6a added assignJobTask function to userServices 2023-11-03 18:47:14 -07:00
ameye e60957e6be Merge branch 'dummy-lnd-page' of WrenchBoard/Users-Wrench into master 2023-11-02 21:35:01 +00:00
victorAnumudu 6a2082d732 added lnd page 2023-11-02 19:01:48 +01:00
ameye 452c6bf8a1 Merge branch 'session-bug' of WrenchBoard/Users-Wrench into master 2023-11-02 01:54:41 +00:00
victorAnumudu 9f89376aa9 Hid text when session expires 2023-11-01 22:11:34 +01:00
ameye 4e91e47978 Merge branch 'session-implement' of WrenchBoard/Users-Wrench into master 2023-11-01 20:09:08 +00:00
ameye fcaa485b17 Merge branch 'history-header-removal' of WrenchBoard/Users-Wrench into master 2023-11-01 20:08:55 +00:00
victorAnumudu e4526652d3 Merge master into session-implement 2023-11-01 20:27:35 +01:00
victorAnumudu 64056bb2a4 changed payment to purchase 2023-11-01 18:45:25 +01:00
victorAnumudu e49c4d66f8 removed table headers if no record is found 2023-11-01 18:39:24 +01:00
ameye 8fdb939b72 Merge branch 'Family-Acc-layout-update' of WrenchBoard/Users-Wrench into master 2023-11-01 17:06:51 +00:00
victorAnumudu 79325450f3 session logout implemented 2023-11-01 18:04:47 +01:00
Chief Bube 7849a027b4 changed fill 2023-11-01 10:04:00 -07:00
ameye 38432a6d50 Merge branch 'Family-Acc-layout-update' of WrenchBoard/Users-Wrench into master 2023-11-01 16:08:13 +00:00
Chief Bube 83a54ff3ef . 2023-11-01 07:37:00 -07:00
Chief Bube 5e0fdffa1e done 2023-11-01 07:34:23 -07:00
ameye 11d2cb3e3a Merge branch 'Added-uid-to-completesignup' of WrenchBoard/Users-Wrench into master 2023-11-01 14:00:31 +00:00
ameye 93ac55b44b Merge branch 'error-page-style' of WrenchBoard/Users-Wrench into master 2023-11-01 14:00:23 +00:00
Chief Bube 237ce13a6c . 2023-11-01 06:40:13 -07:00
Chief Bube 4253174494 . 2023-11-01 06:31:05 -07:00
victorAnumudu da0ed0364b changed the height of the page 2023-11-01 13:43:51 +01:00
ameye 466175c49d Merge branch 'fixing-height-in-intrest-popup' of WrenchBoard/Users-Wrench into master 2023-11-01 10:39:10 +00:00
Chief Bube ed148ce267 Fixed Family Profile Break 2023-10-31 21:42:15 -07:00
ameye 6de795c07b Merge branch 'error-page' of WrenchBoard/Users-Wrench into master 2023-10-31 21:29:49 +00:00
victorAnumudu 436498bef9 added background image to error page 2023-10-31 19:51:36 +01:00
victorAnumudu 086b1202a4 error 404 page adjusted 2023-10-31 16:59:02 +01:00
ameye a81ccdc4d7 Merge branch 'reward-tab-cleanup' of WrenchBoard/Users-Wrench into master 2023-10-31 12:57:55 +00:00
victorAnumudu 33abbbcd2b adjusted reward component contents 2023-10-31 13:53:02 +01:00
ameye 04844af733 Merge branch 'lastname-bug-fix' of WrenchBoard/Users-Wrench into master 2023-10-31 12:42:42 +00:00
victorAnumudu 46d919090d lastname bug fixed 2023-10-31 13:36:53 +01:00
ameye 8e67892f16 Merge branch 'rewards-tab' of WrenchBoard/Users-Wrench into master 2023-10-31 12:21:17 +00:00
victorAnumudu a67d2b7bb4 reward tab clean up 2023-10-31 13:16:33 +01:00
victorAnumudu 99c0c24489 Merge master into rewards-tab 2023-10-31 13:15:22 +01:00
victorAnumudu 1a1d59a8c7 rewards API implemented 2023-10-31 13:13:58 +01:00
ameye 31dcfcfd0b Merge branch 'fixing-height-in-intrest-popup' of WrenchBoard/Users-Wrench into master 2023-10-31 11:45:48 +00:00
Chief Bube e9aa58f2f5 Added tracking text color 2023-10-31 04:42:50 -07:00
victorAnumudu 55fe2bf6d2 Merge master into rewards-tab 2023-10-31 04:23:42 +01:00
victorAnumudu 738eb1589e rewards tab added 2023-10-31 04:22:50 +01:00
ameye 139e0c2827 Merge branch 'send-btn-disable' of WrenchBoard/Users-Wrench into master 2023-10-30 17:43:22 +00:00
27 changed files with 817 additions and 402 deletions
+2
View File
@@ -49,6 +49,7 @@ import MyWaitingJobsPage from "./views/MyWaitingJobsPage";
import FamilyMarketPage from "./views/FamilyMarketPage"; import FamilyMarketPage from "./views/FamilyMarketPage";
import FacebookRedirect from "./views/FacebookRedirect"; import FacebookRedirect from "./views/FacebookRedirect";
import AppleRedirectPage from "./views/AppleRedirectPage"; import AppleRedirectPage from "./views/AppleRedirectPage";
import LndPage from "./views/LndPage";
export default function Routers() { export default function Routers() {
return ( return (
@@ -76,6 +77,7 @@ export default function Routers() {
<Route path="/vemail" element={<VerifyLinkPages />} /> <Route path="/vemail" element={<VerifyLinkPages />} />
<Route path="/complereset" element={<VerifyPasswordPages />} /> <Route path="/complereset" element={<VerifyPasswordPages />} />
<Route exact path="/outmessage" element={<VerifyYouPages />} /> <Route exact path="/outmessage" element={<VerifyYouPages />} />
<Route exact path="/lnd/*" element={<LndPage />} />
{/* private route */} {/* private route */}
<Route element={<AuthRoute />}> <Route element={<AuthRoute />}>
Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

+15
View File
@@ -17,6 +17,10 @@ import { updateUserDetails } from "../../../store/UserDetails";
import ReCAPTCHA from "react-google-recaptcha"; import ReCAPTCHA from "react-google-recaptcha";
export default function Login() { export default function Login() {
const queryParams = new URLSearchParams(location?.search);
const sessionExpired = queryParams.get("sessionExpired")
const dispatch = useDispatch(); const dispatch = useDispatch();
const { state } = useLocation(); const { state } = useLocation();
@@ -241,6 +245,9 @@ export default function Login() {
</div> </div>
<div className="content-wrapper login shadow-md w-full lg:max-w-[530px] mx-auto flex justify-center items-center xl:bg-white dark:bg-dark-white 2xl:w-[828px] rounded-[0.475rem] sm:p-7 p-5"> <div className="content-wrapper login shadow-md w-full lg:max-w-[530px] mx-auto flex justify-center items-center xl:bg-white dark:bg-dark-white 2xl:w-[828px] rounded-[0.475rem] sm:p-7 p-5">
<div className="w-full"> <div className="w-full">
{/* HIDES THIS IF USER SESSION HAS EXPIRED */}
{sessionExpired != 'true' &&
<div className="title-area flex flex-col justify-center items-center relative text-center mb-7"> <div className="title-area flex flex-col justify-center items-center relative text-center mb-7">
{/* <h1 className="text-[#181c32] font-semibold dark:text-white mb-3 leading-[27.3px] text-[22.75px]"> {/* <h1 className="text-[#181c32] font-semibold dark:text-white mb-3 leading-[27.3px] text-[22.75px]">
Sign In to WrenchBoard Sign In to WrenchBoard
@@ -255,6 +262,14 @@ export default function Login() {
</Link> </Link>
</span> </span>
</div> </div>
}
{/* SHOWS THIS IF USER SESSION HAS EXPIRED */}
{sessionExpired == 'true' &&
<div className="w-full p-1 mb-7">
<p className="text-red-500 text-base text-center">Your session expired and will need to login again</p>
</div>
}
{/* switch login component */} {/* switch login component */}
<div className="ml-7 flex justify-start items-center gap-3"> <div className="ml-7 flex justify-start items-center gap-3">
@@ -6,6 +6,7 @@ import InputCom from "../../Helpers/Inputs/InputCom";
import AuthLayout from "../AuthLayout"; import AuthLayout from "../AuthLayout";
export default function SignUp() { export default function SignUp() {
// eslint-disable-next-line no-restricted-globals
const queryParams = new URLSearchParams(location?.search); const queryParams = new URLSearchParams(location?.search);
const country = queryParams.get("cnt")?.toUpperCase(); const country = queryParams.get("cnt")?.toUpperCase();
@@ -54,6 +54,8 @@ export default function VerifyLink() {
localStorage.setItem("member_id", `${data?.member_id}`); localStorage.setItem("member_id", `${data?.member_id}`);
localStorage.setItem("session_token", `${data?.session}`); localStorage.setItem("session_token", `${data?.session}`);
localStorage.setItem("session", `${data?.session}`); localStorage.setItem("session", `${data?.session}`);
localStorage.setItem("uid", data?.uid)
navigate("/", { replace: true }); navigate("/", { replace: true });
setLinkLoader(false); setLinkLoader(false);
+72 -15
View File
@@ -33,7 +33,7 @@ export default function FamilyManageTabs({
loading: false, loading: false,
data: null, data: null,
}; };
console.log('accountDetails',accountDetails)
// State for family details, tasks, waitlist, and pending // State for family details, tasks, waitlist, and pending
const [details, setDetails] = useState({ const [details, setDetails] = useState({
familyDetails: { ...initialDetailState }, familyDetails: { ...initialDetailState },
@@ -66,8 +66,10 @@ export default function FamilyManageTabs({
// State for family task popout // State for family task popout
const [familyTaskPopout, setFamilyTaskPopout] = useState(false); const [familyTaskPopout, setFamilyTaskPopout] = useState(false);
let [uploadStatus, setUploadStatus] = useState({loading: false, status: false, message:''}) // HOLDS STATE FOR UPLOAD PROFILE PICTURE STATUS
// State for profile image // State for profile image
const [profileImg, setProfileImg] = useState(profile); const [profileImg, setProfileImg] = useState(accountDetails.image ? accountDetails.image : profile);
// Ref for profile image input // Ref for profile image input
const profileImgInput = useRef(null); const profileImgInput = useRef(null);
@@ -90,24 +92,78 @@ export default function FamilyManageTabs({
* Checks if the selected file exceeds the maximum file size limit and displays an alert if it does. * 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. * 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 profileImgChangeHandler = (e) => { // const profileImgChangeHandler = (e) => {
const MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB // const MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB
const file = e.target.files[0]; // const file = e.target.files[0];
if (file && file.size > MAX_FILE_SIZE) { // if (file && file.size > MAX_FILE_SIZE) {
alert("File size exceeds the limit."); // alert("File size exceeds the limit.");
return; // return;
// }
// if (file) {
// const imgReader = new FileReader();
// imgReader.onload = () => {
// const imageDataUrl = imgReader.result;
// // Set the profile image
// setProfileImg(imageDataUrl);
// };
// imgReader.readAsDataURL(file);
// }
// };
const profileImgChangeHandler = (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
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 (file) { if(uploadedFile.size > 5*1048576){ // CHECKING FOR CORRECT FILE SIZE
const imgReader = new FileReader(); setUploadStatus({loading: false, status: false, message:'File must not exceed 5MB'})
imgReader.onload = () => { return setTimeout(()=>{
const imageDataUrl = imgReader.result; profileImgInput.current.value = '' // clear the input
setUploadStatus({loading: false, status: false, message:''})
},5000)
}
// Set the profile image if (e.target.value !== "") {
setProfileImg(imageDataUrl); const imgReader = new FileReader();
imgReader.onload = (event) => {
let reqData = { // PAYLOAD FOR API CALL
family_uid: accountDetails?.family_uid,
file_name: uploadedFile?.name,
file_size: uploadedFile?.size,
file_type: uploadedFile?.type?.split("/")[0]?.toLowerCase(),
file_data: event?.target?.result,
msg_type: 'FILE',
action: 111305
}
setUploadStatus({loading: true, status: false, message:'Loading...'})
apiCall.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'})
setProfileImg(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(file); imgReader.readAsDataURL(e.target.files[0]);
} }
}; };
@@ -298,6 +354,7 @@ export default function FamilyManageTabs({
profileImgChangeHandler={profileImgChangeHandler} profileImgChangeHandler={profileImgChangeHandler}
browseProfileImg={browseProfileImg} browseProfileImg={browseProfileImg}
accountDetails={accountDetails} accountDetails={accountDetails}
uploadStatus={uploadStatus}
/> />
<div className="mt-4 flex flex-col justify-center items-center gap-2 lg:flex-row lg:justify-center lg:items-center xl:flex-col xl:justify-center xl:items-center 2xl:flex-row 2xl:justify-center 2xl:items-center 2xl:gap-[2px]"> <div className="mt-4 flex flex-col justify-center items-center gap-2 lg:flex-row lg:justify-center lg:items-center xl:flex-col xl:justify-center xl:items-center 2xl:flex-row 2xl:justify-center 2xl:items-center 2xl:gap-[2px]">
<button <button
+52 -6
View File
@@ -19,6 +19,7 @@ export default function FamilyTable({
familyList, familyList,
loader, loader,
popUpHandler, popUpHandler,
imageServer
}) { }) {
const navigate = useNavigate(); const navigate = useNavigate();
const [currentPage, setCurrentPage] = useState(0); const [currentPage, setCurrentPage] = useState(0);
@@ -52,21 +53,34 @@ export default function FamilyTable({
task_count, task_count,
family_uid, family_uid,
banner, banner,
enable_traking,
profile_picture,
imageServer
}) => { }) => {
// Check for valid dates // Check for valid dates
const addedDate = added ? added.split(" ")[0] : "N/A"; const addedDate = added ? added.split(" ")[0] : "N/A";
const loginDate = last_login ? formatDateString(last_login) : "N/A"; const loginDate = last_login ? formatDateString(last_login) : "N/A";
const key = `family-${family_uid}`; // Assign a unique key
const image = localStorage.getItem('session_token') ? `${imageServer}${localStorage.getItem('session_token')}/family/${family_uid}` : ''
const trackingStatus =
enable_traking === "0"
? "Stopped"
: enable_traking === "100"
? "Active"
: "";
return ( return (
<tr <tr
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"
key={family_uid} key={key}
> >
<td className="py-4"> <td className="py-4">
<div className="flex space-x-2 items-center w-full"> <div className="flex space-x-2 items-center w-full">
<div className="w-[60px] h-[60px] rounded-full overflow-hidden flex justify-center items-center flex-[0.1]"> <div className="w-[60px] h-[60px] rounded-full overflow-hidden flex justify-center items-center flex-[0.1]">
<img <img
src={localImgLoad(`images/icons/${banner}`)} // src={profile_picture}
src={image || profile_picture || localImgLoad(`images/icons/${banner}`)}
alt={`Avatar of ${firstname} ${lastname}`} alt={`Avatar of ${firstname} ${lastname}`}
className="w-full h-full" className="w-full h-full"
/> />
@@ -85,6 +99,23 @@ export default function FamilyTable({
</div> </div>
</div> </div>
</td> </td>
<td className="text-center py-4 px-2">
<div className="flex space-x-1 items-center justify-center">
<span
className={`text-base font-medium whitespace-nowrap ${
enable_traking === "0"
? "text-[#FF0000] dark:text-[#FF6666]"
: enable_traking === "100"
? "text-[#00A000] dark:text-[#00FF00]"
: "text-dark-gray dark:text-white"
}`}
>
{trackingStatus}
</span>
</div>
</td>
<td className="text-center py-4 px-2"> <td className="text-center py-4 px-2">
<div className="flex space-x-1 items-center justify-center"> <div className="flex space-x-1 items-center justify-center">
<span className="text-base text-dark-gray dark:text-white font-medium whitespace-nowrap"> <span className="text-base text-dark-gray dark:text-white font-medium whitespace-nowrap">
@@ -92,6 +123,7 @@ export default function FamilyTable({
</span> </span>
</div> </div>
</td> </td>
<td className="text-right py-4 px-2 flex items-center justify-center"> <td className="text-right py-4 px-2 flex items-center justify-center">
<button <button
onClick={() => onClick={() =>
@@ -104,12 +136,25 @@ export default function FamilyTable({
task_count, task_count,
family_uid, family_uid,
banner, banner,
image
}) })
} }
type="button" type="button"
className="w-20 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white" className="w-12 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white"
> >
Manage <svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 11 20"
id="Arrow"
className="w-[0.7rem]"
>
<path
fill-rule="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]"
></path>
</svg>
</button> </button>
</td> </td>
</tr> </tr>
@@ -134,13 +179,14 @@ export default function FamilyTable({
<thead className="sticky top-0"> <thead className="sticky top-0">
<tr className="text-base text-thin-light-gray whitespace-nowrap border-b dark:border-[#5356fb29] default-border-bottom "> <tr className="text-base text-thin-light-gray whitespace-nowrap border-b dark:border-[#5356fb29] default-border-bottom ">
<th className="py-4">Name</th> <th className="py-4">Name</th>
<th className="py-4 text-center">Tracking</th>
<th className="py-4 text-center">No of Tasks</th> <th className="py-4 text-center">No of Tasks</th>
<th className="py-4 text-right"></th> <th className="py-4 text-right"></th>
</tr> </tr>
</thead> </thead>
<tbody className="h-full"> <tbody className="h-full">
{currentFamilyList?.map((familyMember, index) => { {currentFamilyList?.map((familyMember, index) => {
return <FamilyRow key={index} {...familyMember} />; return <FamilyRow key={index} {...familyMember} imageServer={imageServer} />;
})} })}
</tbody> </tbody>
</table> </table>
@@ -171,7 +217,7 @@ export default function FamilyTable({
<PaginatedList <PaginatedList
onClick={handlePagination} onClick={handlePagination}
prev={currentPage == 0} prev={currentPage == 0}
next={currentPage + itemsPerPage >= familyList.length} next={currentPage + itemsPerPage >= familyList?.length}
data={familyList} data={familyList}
start={indexOfFirstItem} start={indexOfFirstItem}
stop={indexOfLastItem} stop={indexOfLastItem}
@@ -49,12 +49,12 @@ export default function FamilyProfile({ familyData, className }) {
// initial values for formik // initial values for formik
let initialValues = { let initialValues = {
family_uid: familyData.uid, family_uid: familyData?.uid,
firstname: familyData.firstname, firstname: familyData?.firstname,
lastname: familyData.lastname, lastname: familyData?.lastname,
year: familyData.year, year: familyData?.year,
month: familyData.month, month: familyData?.month,
enable_traking: familyData.enable_traking, enable_traking: familyData?.enable_traking,
action: 22020, action: 22020,
}; };
+2 -2
View File
@@ -5,7 +5,7 @@ import React, {
useMemo, useMemo,
useState, useState,
} from "react"; } from "react";
import SiteService from "../../services/SiteService"; import usersService from "../../services/UsersService";
import InputCom from "../Helpers/Inputs/InputCom"; import InputCom from "../Helpers/Inputs/InputCom";
import ModalCom from "../Helpers/ModalCom"; import ModalCom from "../Helpers/ModalCom";
import Layout from "../Partials/Layout"; import Layout from "../Partials/Layout";
@@ -27,7 +27,7 @@ export default function FamilyAcc() {
last_name: "", last_name: "",
}); });
const apiCall = useMemo(() => new SiteService(), []); const apiCall = useMemo(() => new usersService(), []);
const popUpHandler = () => { const popUpHandler = () => {
setPopUp((prev) => !prev); setPopUp((prev) => !prev);
+12 -5
View File
@@ -2,6 +2,8 @@ import React from "react";
// import Lottie from "react-lottie"; // import Lottie from "react-lottie";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import * as animationData from "../../assets/images/Lotties/77618-website-404-error-animation.json"; import * as animationData from "../../assets/images/Lotties/77618-website-404-error-animation.json";
import { localImgLoad } from "../../lib";
// import BgError from '../../assets/images/wrench-page-notfound.jpg'
export default function FourZeroFour() { export default function FourZeroFour() {
const navigate = useNavigate(); const navigate = useNavigate();
@@ -14,16 +16,21 @@ export default function FourZeroFour() {
}, },
}; };
return ( return (
<div className="flex justify-center items-center w-full h-screen bg-[#232247]"> <div className={`my-custom-bg-class flex justify-center items-center w-full min-h-screen before:content-[''] before:absolute before:inset-0 before:bg-[#cdcdcd]/[.8]`}>
<div> <div className="relative pt-32 max-w-3xl">
{/* <Lottie options={defaultOptions} width={600} height={600} /> */} {/* <Lottie options={defaultOptions} width={600} height={600} /> */}
<div className="flex justify-center"> <div className="px-16 md:px-24 flex flex-col items-center justify-center gap-4">
<img src={localImgLoad('images/404.png')} className="w-72" alt='404Image' />
<p className="mt-8 text-red-600 font-black text-4xl md:text-5xl tracking-wider text-center">Sorry!</p>
<h1 className="text-black text-4xl md:text-5xl font-black tracking-wide text-center leading-tight">The page cant be found.</h1>
<p className="px-2 md:px-8 text-slate-700 text-base md:text-lg text-center">The page you're looking for isn't available. Use the go back button below</p>
<button <button
onClick={() => navigate(-1)} onClick={() => navigate(-1)}
type="button" type="button"
className="btn-gradient text-white text-lg w-[150px] h-[50px] rounded-full" className="px-4 md:px-8 border-2 border-[#2b70fa] rounded-lg text-[#007bff] text-base md:text-lg h-[48px] flex justify-center items-center gap-1"
> >
Go Back <span>Go Back</span>
<span className="pb-1">&rarr;</span>
</button> </button>
</div> </div>
</div> </div>
+103
View File
@@ -0,0 +1,103 @@
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 RewardsTable() {
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 getFamilyRewardHistory = ()=>{
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}))
})
}
useEffect(()=>{
getFamilyRewardHistory()
}, [])
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 Rewards 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 RewardsTable
+25 -4
View File
@@ -10,6 +10,7 @@ import usersService from "../../services/UsersService";
import PurchasesTable from "../MyWallet/WalletComponent/PurchasesTable"; import PurchasesTable from "../MyWallet/WalletComponent/PurchasesTable";
import RecentActivityTable from "../MyWallet/WalletComponent/RecentActivityTable"; import RecentActivityTable from "../MyWallet/WalletComponent/RecentActivityTable";
import LoadingSpinner from "../Spinners/LoadingSpinner"; import LoadingSpinner from "../Spinners/LoadingSpinner";
import RewardsTable from "./RewardsTable";
export default function History() { export default function History() {
@@ -58,6 +59,9 @@ export default function History() {
useEffect(()=>{ useEffect(()=>{
getPaymentHistory() getPaymentHistory()
}, [])
useEffect(()=>{
getPurchaseHistory() getPurchaseHistory()
}, []) }, [])
@@ -236,15 +240,24 @@ export default function History() {
> >
Recent Activity Recent Activity
</button> </button>
<button
name="reward"
onClick={(e) => setTab(e.target.name)}
className={`px-4 py-1 rounded-t-2xl ${
tab == "reward" ? "bg-[#4687ba] border-[2px] border-[#4687ba] text-white" : "bg-white text-[#000] border-t-[2px]"
}`}
>
Rewards
</button>
</div> </div>
{/* END OF switch button */} {/* END OF switch button */}
<div className="history-tables w-full"> <div className="history-tables w-full">
{/* PURCHASE SECTION */} {/* PURCHASE SECTION */}
{tab == 'purchases' && {tab == 'purchases' &&
<div className="wallet w-full border-t"> <div className="wallet w-full border-t">
<h1 className="p-2 text-xl font-bold text-dark-gray dark:text-white tracking-wide">Purchases</h1> {/* <h1 className="p-2 text-xl font-bold text-dark-gray dark:text-white tracking-wide">Purchases</h1> */}
{purchaseHistory.loading ? {purchaseHistory.loading ?
<LoadingSpinner size='16' color='sky-blue' /> <LoadingSpinner size='16' color='sky-blue' height='h-[500px]' />
: :
<PurchasesTable purchase={purchaseHistory} /> <PurchasesTable purchase={purchaseHistory} />
} }
@@ -255,16 +268,24 @@ export default function History() {
{/* RECENT ACTIVITY SECTION */} {/* RECENT ACTIVITY SECTION */}
{tab == 'recent' && {tab == 'recent' &&
<div className="wallet w-full border-t"> <div className="wallet w-full border-t">
<h1 className="p-2 text-xl font-bold text-dark-gray dark:text-white tracking-wide">Recent Activity</h1> {/* <h1 className="p-2 text-xl font-bold text-dark-gray dark:text-white tracking-wide">Recent Activity</h1> */}
{/* <p className='text-base text-slate-500 dark:text-white'>Activity Report</p> */} {/* <p className='text-base text-slate-500 dark:text-white'>Activity Report</p> */}
{paymentHistory.loading ? {paymentHistory.loading ?
<LoadingSpinner size='16' color='sky-blue' /> <LoadingSpinner size='16' color='sky-blue' height='h-[500px]' />
: :
<RecentActivityTable payment={paymentHistory} /> <RecentActivityTable payment={paymentHistory} />
} }
</div> </div>
} }
{/* END OF RECENT ACTIVITY SECTION */} {/* END OF RECENT ACTIVITY SECTION */}
{/* REWARD SECTION */}
{tab == 'reward' &&
<div className="wallet w-full border-t">
<RewardsTable />
</div>
}
{/* END OF REWARD SECTION */}
</div> </div>
</div> </div>
{/*<HistoryTable />*/} {/*<HistoryTable />*/}
+27
View File
@@ -0,0 +1,27 @@
import React, { useEffect, useState } from 'react'
import Layout from '../Partials/Layout'
import LoadingSpinner from '../Spinners/LoadingSpinner'
function Lnd() {
const [reqStatus, setReqStatus] = useState({loading:true, data: []})
useEffect(()=>{
const timer = setTimeout(()=>{
setReqStatus({loading:false, data: []})
},2000)
return () => clearTimeout(timer)
}, [])
return (
<>
{reqStatus.loading ?
<LoadingSpinner color='sky-blue' size='32' height='min-h-screen' />
:
<div className='min-h-screen flex flex-col justify-center items-center'>Empty Dummy Page</div>
}
</>
)
}
export default Lnd
@@ -16,6 +16,7 @@ function PurchasesTable({purchase}) {
return ( return (
<div className='flex flex-col justify-between min-h-[500px]'> <div className='flex flex-col justify-between min-h-[500px]'>
{purchase.data.length ?
<table className="wallet-activity w-full table-auto border-collapse text-left"> <table className="wallet-activity w-full table-auto border-collapse text-left">
<thead className='border-b-2'> <thead className='border-b-2'>
<tr className='text-slate-600'> <tr className='text-slate-600'>
@@ -24,8 +25,6 @@ function PurchasesTable({purchase}) {
<th className="p-2">Fee</th> <th className="p-2">Fee</th>
</tr> </tr>
</thead> </thead>
{purchase.data.length ?
(
<tbody> <tbody>
{currentPurchase.map((item, index) => ( {currentPurchase.map((item, index) => (
<tr key={index} className='text-slate-500'> <tr key={index} className='text-slate-500'>
@@ -37,24 +36,16 @@ function PurchasesTable({purchase}) {
</tr> </tr>
))} ))}
</tbody> </tbody>
)
:
purchase.error ?
(
<tbody>
<tr className='text-slate-500'>
<td className="p-2" colSpan={4}>Opps! an error occurred. Please try again!</td>
</tr>
</tbody>
)
:
<tbody>
<tr className='text-slate-500'>
<td className="p-2" colSpan={4}>No Purchase History Found!</td>
</tr>
</tbody>
}
</table> </table>
:purchase.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 Purchase History Found!</span>
</div>
}
{/* PAGINATION BUTTON */} {/* PAGINATION BUTTON */}
<PaginatedList onClick={handlePagination} prev={currentPage == 0 ? true : false} next={currentPage+Number(process.env.REACT_APP_ITEM_PER_PAGE) >= purchase?.data?.length ? true : false} data={purchase?.data} start={indexOfFirstItem} stop={indexOfLastItem} /> <PaginatedList onClick={handlePagination} prev={currentPage == 0 ? true : false} next={currentPage+Number(process.env.REACT_APP_ITEM_PER_PAGE) >= purchase?.data?.length ? true : false} data={purchase?.data} start={indexOfFirstItem} stop={indexOfLastItem} />
@@ -19,6 +19,7 @@ function RecentActivityTable({ payment }) {
return ( return (
<div className="flex flex-col justify-between min-h-[500px]"> <div className="flex flex-col justify-between min-h-[500px]">
{payment?.data?.length > 0 ?
<table className="wallet-activity w-full table-auto border-collapse text-left"> <table className="wallet-activity w-full table-auto border-collapse text-left">
<thead className="border-b-2"> <thead className="border-b-2">
<tr className="text-slate-600"> <tr className="text-slate-600">
@@ -28,7 +29,6 @@ function RecentActivityTable({ payment }) {
<th className="p-2">Status</th> <th className="p-2">Status</th>
</tr> </tr>
</thead> </thead>
{payment?.data?.length > 0 ? (
<tbody> <tbody>
{currentActivity.map((item, index) => ( {currentActivity.map((item, index) => (
<tr key={index} className="text-slate-500"> <tr key={index} className="text-slate-500">
@@ -46,24 +46,16 @@ function RecentActivityTable({ payment }) {
</tr> </tr>
))} ))}
</tbody> </tbody>
) : payment?.error ? (
<tbody>
<tr className="text-slate-500">
<td className="p-2" colSpan={4}>
Opps! an error occurred. Please try again!
</td>
</tr>
</tbody>
) : (
<tbody>
<tr className="text-slate-500">
<td className="p-2" colSpan={4}>
No Payment History Found!
</td>
</tr>
</tbody>
)}
</table> </table>
:payment.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 Payment History Found!</span>
</div>
}
{/* PAGINATION BUTTON */} {/* PAGINATION BUTTON */}
<PaginatedList <PaginatedList
+5 -1
View File
@@ -36,6 +36,10 @@ export default function Header({ logoutModalHandler, sidebarHandler }) {
const { notifications } = useSelector((state) => state?.notifications); // NOTIFICATION STORE const { notifications } = useSelector((state) => state?.notifications); // NOTIFICATION STORE
const { walletDetails } = useSelector((state) => state?.walletDetails); // WALLET STORE const { walletDetails } = useSelector((state) => state?.walletDetails); // WALLET STORE
const image = `${userDetails.session_image_server}${localStorage.getItem(
"session_token"
)}/profile/${userDetails.uid}`;
const handlerBalance = () => { const handlerBalance = () => {
setbalanceValue.toggle(); setbalanceValue.toggle();
if (notificationDropdown) { if (notificationDropdown) {
@@ -91,7 +95,7 @@ export default function Header({ logoutModalHandler, sidebarHandler }) {
// User Profile // User Profile
let { firstname, lastname, email, profile_pic_url } = userDetails; let { firstname, lastname, email, profile_pic_url } = userDetails;
let userEmail = email?.split("@")[0]; let userEmail = email?.split("@")[0];
const userProfileImage = profile_pic_url || DEFAULT_PROFILE_IMAGE; const userProfileImage = image || DEFAULT_PROFILE_IMAGE;
return ( return (
<> <>
+143 -16
View File
@@ -1,4 +1,4 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useRef, useState } from "react";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import usersService from "../../../services/UsersService"; import usersService from "../../../services/UsersService";
@@ -6,6 +6,9 @@ import Icons from "../../Helpers/Icons";
import InputCom from "../../Helpers/Inputs/InputCom"; import InputCom from "../../Helpers/Inputs/InputCom";
import LoadingSpinner from "../../Spinners/LoadingSpinner"; import LoadingSpinner from "../../Spinners/LoadingSpinner";
import cover from "../../../assets/images/profile-info-cover.png";
import profileImage from "../../../assets/images/profile.jpg";
import { Form, Formik } from "formik"; import { Form, Formik } from "formik";
import * as Yup from "yup"; import * as Yup from "yup";
@@ -43,18 +46,13 @@ export default function PersonalInfoTab({
frstNmeHndlr, frstNmeHndlr,
lstNmeHndlr, lstNmeHndlr,
dscrphn, dscrphn,
profileImg,
coverImg,
profileImgInput,
browseProfileImg,
profileImgChangHandler,
coverImgInput,
browseCoverImg,
coverImgChangHandler,
uploadStatus
}) { }) {
let { userDetails } = useSelector((state) => state.userDetails); let { userDetails } = useSelector((state) => state.userDetails);
const image = `${userDetails.session_image_server}${localStorage.getItem(
"session_token"
)}/profile/${userDetails.uid}`;
const apiCall = new usersService(); const apiCall = new usersService();
let navigate = useNavigate(); let navigate = useNavigate();
@@ -85,6 +83,123 @@ export default function PersonalInfoTab({
status: false, status: false,
}); });
const [profileImg, setProfileImg] = useState(
userDetails?.session_image_server ? image : profileImage
);
let [uploadStatus, setUploadStatus] = useState({
loading: false,
status: false,
message: "",
}); // HOLDS STATE FOR UPLOAD PROFILE PICTURE STATUS
const [coverImg, setCoverImg] = useState(cover);
// profile img
const profileImgInput = useRef(null);
const browseProfileImg = () => {
profileImgInput.current.click();
};
const profileImgChangHandler = (e) => {
setUploadStatus({ loading: false, status: false, message: "" });
const acceptedFormat = ["jpeg", "jpg", "png", "bmp", "gif"]; // ARRAY OF SUPPORTED FORMATS
const uploadedFile = e.target.files[0]; //UPLOADED FILE
const fileFormat = uploadedFile?.type?.split("/")[1]?.toLowerCase();
const MAX_FILE_SIZE = 5 * 1048576; // 5MB
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 > MAX_FILE_SIZE) {
// 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 reqData = {
// PAYLOAD FOR API CALL
file_name: uploadedFile?.name,
file_size: uploadedFile?.size,
file_type: uploadedFile?.type?.split("/")[0]?.toLowerCase(),
file_data: event?.target?.result,
msg_type: "FILE",
action: 11300,
};
setUploadStatus({
loading: true,
status: false,
message: "Loading...",
});
apiCall
.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",
});
setProfileImg(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(uploadedFile);
}
};
// cover img
const coverImgInput = useRef(null);
const browseCoverImg = () => {
coverImgInput.current.click();
};
const coverImgChangHandler = (e) => {
if (e.target.value !== "") {
const imgReader = new FileReader();
imgReader.onload = (event) => {
setCoverImg(event.target.result);
};
imgReader.readAsDataURL(e.target.files[0]);
}
};
const handleUpdateUser = (values, helpers) => { const handleUpdateUser = (values, helpers) => {
setRequestState({ message: "", loading: true, status: false }); setRequestState({ message: "", loading: true, status: false });
@@ -374,7 +489,7 @@ export default function PersonalInfoTab({
<p className="text-base text-thin-light-gray mb-5"> <p className="text-base text-thin-light-gray mb-5">
Profile of at least Size Profile of at least Size
<span className="ml-1 text-dark-gray dark:text-white"> <span className="ml-1 text-dark-gray dark:text-white">
300x300 200x200
</span> </span>
. Gifs work too. . Gifs work too.
<span className="ml-1 text-dark-gray dark:text-white"> <span className="ml-1 text-dark-gray dark:text-white">
@@ -383,11 +498,11 @@ export default function PersonalInfoTab({
. .
</p> </p>
<div className="flex justify-center"> <div className="flex justify-center">
<div className="w-full relative"> <div className="w-[200px] h-[200px] relative">
<img <img
src={profileImg} src={profileImg}
alt="profile" alt="profile"
className="sm:w-[198px] sm:h-[198px] w-[120px] h-[120px] rounded-full overflow-hidden object-contain object-center" className="sm:w-[198px] sm:h-[198px] w-full h-full rounded-full overflow-hidden object-cover object-center"
/> />
<input <input
ref={profileImgInput} ref={profileImgInput}
@@ -397,7 +512,7 @@ export default function PersonalInfoTab({
/> />
<div <div
onClick={browseProfileImg} onClick={browseProfileImg}
className="w-[32px] h-[32px] absolute bottom-7 sm:right-10 right-[105px] hover:bg-pink bg-dark-gray rounded-full cursor-pointer" className="w-[32px] h-[32px] absolute bottom-4 right-4 hover:bg-pink bg-dark-gray rounded-full cursor-pointer"
> >
<svg <svg
width="32" width="32"
@@ -418,8 +533,20 @@ export default function PersonalInfoTab({
</div> </div>
</div> </div>
</div> </div>
{uploadStatus.message && !uploadStatus.loading && <p className={`text-center ${uploadStatus.status ? 'text-green-500':'text-red-500'}`}>{uploadStatus.message}</p>} {uploadStatus.message && !uploadStatus.loading && (
{uploadStatus.loading && <p className="text-center">{uploadStatus.message}</p>} <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>
</div> </div>
{/* } */} {/* } */}
+115 -194
View File
@@ -6,8 +6,6 @@ import React, {
useState, useState,
} from "react"; } from "react";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
import cover from "../../assets/images/profile-info-cover.png";
import profile from "../../assets/images/profile.jpg";
import usersService from "../../services/UsersService"; import usersService from "../../services/UsersService";
import Icons from "../Helpers/Icons"; import Icons from "../Helpers/Icons";
import Layout from "../Partials/Layout"; import Layout from "../Partials/Layout";
@@ -26,161 +24,8 @@ import RecipientAccountTab from "./Tabs/RecipientAccountTab";
export default function Settings({ faq }) { export default function Settings({ faq }) {
const apiCall = new usersService(); const apiCall = new usersService();
const { userDetails } = useSelector((state) => state?.userDetails); const { userDetails } = useSelector((state) => state?.userDetails);
const [profileImg, setProfileImg] = useState(
userDetails?.profile_pic_url ? userDetails.profile_pic_url : profile
);
let [uploadStatus, setUploadStatus] = useState({loading: false, status: false, message:''}) // HOLDS STATE FOR UPLOAD PROFILE PICTURE STATUS
const [coverImg, setCoverImg] = useState(cover);
const [reloadCardList, setReloadCardList] = useState(false); // STATE TO DETERMINE WHEN CARD LIST RELOADS. EG: WHEN USER DELETES A CARD const [reloadCardList, setReloadCardList] = useState(false); // STATE TO DETERMINE WHEN CARD LIST RELOADS. EG: WHEN USER DELETES A CARD
// profile img
const profileImgInput = useRef(null);
const browseProfileImg = () => {
profileImgInput.current.click();
};
const profileImgChangHandler = (e) => {
// if (e.target.value !== "") {
// const imgReader = new FileReader();
// imgReader.onload = (event) => {
// setProfileImg(event.target.result);
// };
// imgReader.readAsDataURL(e.target.files[0]);
// }
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
if(!acceptedFormat.includes(uploadedFile?.type?.split("/")[1]?.toLowerCase())){ //CHECKING FOR CORRECT UPLOAD FORMAT
let msg = 'Please select '
for(let i=0; i<=acceptedFormat.length-1; i++){
if(i == acceptedFormat.length-1){
msg+=`or ${acceptedFormat[i]}`
}else{
msg+=`${acceptedFormat[i]}, `
}
}
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 reqData = { // PAYLOAD FOR API CALL
file_name: uploadedFile?.name,
file_size: uploadedFile?.size,
file_type: uploadedFile?.type?.split("/")[0]?.toLowerCase(),
file_data: event?.target?.result,
msg_type: 'FILE',
action: 'WRENCHBOARD_PICTURE_PROFILE',
// action: 11307
}
setUploadStatus({loading: true, status: false, message:'Loading...'})
apiCall.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'})
setProfileImg(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]);
}
};
// cover img
const coverImgInput = useRef(null);
const browseCoverImg = () => {
coverImgInput.current.click();
};
const coverImgChangHandler = (e) => {
if (e.target.value !== "") {
const imgReader = new FileReader();
imgReader.onload = (event) => {
setCoverImg(event.target.result);
};
imgReader.readAsDataURL(e.target.files[0]);
}
};
// Tabs Handling
const tabs = [
{
id: 1,
name: "personal",
title: "Edit Profile",
iconName: "people-hover",
},
{
id: 2,
name: "payment",
title: "Payment Cards",
iconName: "bank-card",
},
{
id: 3,
name: "recipients-account",
title: "Recipients Account",
iconName: "bank-card",
},
{
id: 4,
name: "notification",
title: "Notification Setting",
iconName: "notification-setting",
},
{
id: 5,
name: "login_activity",
title: "Login Activity",
iconName: "login-activity",
},
{
id: 6,
name: "password",
title: "Change Password",
iconName: "password-hover",
},
{
id: 7,
name: "faq",
title: "FAQ",
iconName: "block-question",
},
{
id: 8,
name: "privacy",
title: "Privacy Policy",
iconName: "page-right",
},
{
id: 9,
name: "terms",
title: "Terms and Conditions",
iconName: "page-right",
},
];
const [tab, setTab] = useState(tabs[0].name);
const tabHandler = (value) => {
setTab(value);
};
// Recipient Account // Recipient Account
const [recipientAccount, setRecipientAccount] = useState({ const [recipientAccount, setRecipientAccount] = useState({
state: false, state: false,
@@ -223,6 +68,120 @@ export default function Settings({ faq }) {
getRecipientAccount(); getRecipientAccount();
}, [reloadCardList]); }, [reloadCardList]);
// Tabs Handling
const tabs = [
{
id: 1,
name: "personal",
title: "Edit Profile",
iconName: "people-hover",
},
{
id: 2,
name: "payment",
title: "Payment Cards",
iconName: "bank-card",
},
{
id: 3,
name: "recipients_account",
title: "Recipients Account",
iconName: "bank-card",
},
{
id: 4,
name: "notification",
title: "Notification Setting",
iconName: "notification-setting",
},
{
id: 5,
name: "login_activity",
title: "Login Activity",
iconName: "login-activity",
},
{
id: 6,
name: "password",
title: "Change Password",
iconName: "password-hover",
},
{
id: 7,
name: "faq",
title: "FAQ",
iconName: "block-question",
},
{
id: 8,
name: "privacy",
title: "Privacy Policy",
iconName: "page-right",
},
{
id: 9,
name: "terms",
title: "Terms and Conditions",
iconName: "page-right",
},
];
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 = {
personal: (
<div className="tab-item">
<PersonalInfoTab />
</div>
),
payment: (
<div className="tab-item">
<PaymentMathodsTab />
</div>
),
recipients_account: (
<div className="tab-item">
<RecipientAccountTab
recipientAccount={recipientAccount}
setRecipientAccount={setRecipientAccount}
setReloadCardList={setReloadCardList}
/>
</div>
),
notification: (
<div className="tab-item">
<NotificationSettingTab />
</div>
),
login_activity: <LoginActivityTab />,
password: <ChangePasswordTab />,
faq: <FaqTab datas={faq} />,
privacy: <PrivacyPolicyTab />,
terms: <TermsConditionTab />,
};
// Default tab component
const defaultTabComponent = (
<div className="tab-item">
<PersonalInfoTab />
</div>
);
// Selected tab component based on the current 'tab'
const selectedTabComponent = tabComponents[tab] || defaultTabComponent;
return ( return (
<> <>
<Layout> <Layout>
@@ -263,45 +222,7 @@ export default function Settings({ faq }) {
</div> </div>
<div className="w-[1px] bg-[#E3E4FE] dark:bg-[#a7a9b533] mr-10"></div> <div className="w-[1px] bg-[#E3E4FE] dark:bg-[#a7a9b533] mr-10"></div>
<div className="content-body-items flex-1"> <div className="content-body-items flex-1">
{tab === "personal" && ( {selectedTabComponent}
<div className="tab-item">
<PersonalInfoTab
profileImg={profileImg}
coverImg={coverImg}
browseProfileImg={browseProfileImg}
profileImgInput={profileImgInput}
profileImgChangHandler={profileImgChangHandler}
coverImgChangHandler={coverImgChangHandler}
browseCoverImg={browseCoverImg}
coverImgInput={coverImgInput}
uploadStatus={uploadStatus}
/>
</div>
)}
{tab === "payment" && (
<div className="tab-item">
<PaymentMathodsTab />
</div>
)}
{tab === "recipients-account" && (
<div className="tab-item">
<RecipientAccountTab
recipientAccount={recipientAccount}
setRecipientAccount={setRecipientAccount}
setReloadCardList={setReloadCardList}
/>
</div>
)}
{tab === "notification" && (
<div className="tab-item">
<NotificationSettingTab />
</div>
)}
{tab === "login_activity" && <LoginActivityTab />}
{tab === "password" && <ChangePasswordTab />}
{tab === "faq" && <FaqTab datas={faq} />}
{tab === "privacy" && <PrivacyPolicyTab />}
{tab === "terms" && <TermsConditionTab />}
</div> </div>
</div> </div>
</div> </div>
+43 -7
View File
@@ -52,6 +52,18 @@ const EditJobPopOut = ({
}) => { }) => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const [taskImage, setTaskImage] = useState('')
const changeTaskImage = (e) => {
if (e.target.value !== "") {
const imgReader = new FileReader();
imgReader.onload = (event) => {
setTaskImage(event.target.result);
};
imgReader.readAsDataURL(e.target.files[0]);
}
}
let [requestStatus, setRequestStatus] = useState({ let [requestStatus, setRequestStatus] = useState({
loading: false, loading: false,
status: false, status: false,
@@ -138,7 +150,7 @@ const EditJobPopOut = ({
</svg> </svg>
</button> </button>
</div> </div>
<div className="logout-modal-body w-full flex flex-col items-center px-10 py-8"> <div className="logout-modal-body w-full flex flex-col items-center px-10 pb-8 pt-2">
<Formik <Formik
initialValues={initialValues} initialValues={initialValues}
validationSchema={validationSchema} validationSchema={validationSchema}
@@ -279,18 +291,41 @@ const EditJobPopOut = ({
</div> </div>
</div> </div>
</div> </div>
<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
id="task_image"
className="hidden"
type="file"
accept="image/*"
onChange={changeTaskImage}
/>
{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/20 hover:bg-white/70 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>
}
</div>
{/* END OF TASK IMAGE */}
<div className="field w-full mb-6"> <div className="field w-1/2">
<div <div
className={`flex items-center justify-between mb-2.5`} className={`flex items-center justify-between`}
> >
<label <label
className="input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold block" className="w-full input-label text-[#181c32] dark:text-white text-[13.975px] leading-[20.9625px] font-semibold flex flex-col"
htmlFor="timeline_days" htmlFor="timeline_days"
> >
Timeline Timeline -
<span className="text-green-700 text-sm tracking-wide"> <span className="w-full text-center text-green-700 text-sm tracking-wide">
- Expected duration of this task Expected duration of this task
</span> </span>
</label> </label>
</div> </div>
@@ -317,6 +352,7 @@ const EditJobPopOut = ({
))} ))}
</Field> </Field>
</div> </div>
</div>
{/* inputs ends here */} {/* inputs ends here */}
</div> </div>
</div> </div>
+2 -2
View File
@@ -1,7 +1,7 @@
import { Field, Form, Formik } from "formik"; import { Field, Form, Formik } from "formik";
import React, { useCallback, useEffect, useMemo, useState } from "react"; import React, { useCallback, useEffect, useMemo, useState } from "react";
import * as Yup from "yup"; import * as Yup from "yup";
import SiteService from "../../services/SiteService"; import usersService from "../../services/UsersService";
import InputCom from "../Helpers/Inputs/InputCom/index"; import InputCom from "../Helpers/Inputs/InputCom/index";
import ModalCom from "../Helpers/ModalCom"; import ModalCom from "../Helpers/ModalCom";
import LoadingSpinner from "../Spinners/LoadingSpinner"; import LoadingSpinner from "../Spinners/LoadingSpinner";
@@ -36,7 +36,7 @@ const dispatch = useDispatch()
}, },
}); });
const apiCall = useMemo(() => new SiteService(), []); const apiCall = useMemo(() => new usersService(), []);
// member listing // member listing
const memberList = useCallback(async () => { const memberList = useCallback(async () => {
+33 -2
View File
@@ -24,6 +24,7 @@ function PendingJobsPopout({ details, onClose, situation }) {
const [pendingJobLoader, setPendingJobLoader] = useState({ const [pendingJobLoader, setPendingJobLoader] = useState({
extend: false, extend: false,
offer: false, offer: false,
cancel: false,
}); });
let [requestMessage, setRequestMessage] = useState({ let [requestMessage, setRequestMessage] = useState({
@@ -81,6 +82,29 @@ function PendingJobsPopout({ details, onClose, situation }) {
setRequestMessage({ status: false, message: "" }); setRequestMessage({ status: false, message: "" });
}, 3000); }, 3000);
}); });
} else if (name == "cancel") {
// RUNS THIS IF JOB OFFER IS CANCELLED
reqData = { ...pendingData, reason: "cancel", offer_result: 3333 };
setPendingJobLoader({ cancel: true });
apiCall
.pendingCancelOffer(reqData)
.then((res) => {
setRequestMessage({ status: true, message: res.data.status });
setTimeout(() => {
setPendingJobLoader({ cancel: false });
setRequestMessage({ status: false, message: "" });
onClose();
dispatch(tableReload({ type: "PENDINGTABLE" }));
dispatch(tableReload({ type: "JOBTABLE" }));
}, 4000);
})
.catch((error) => {
setRequestMessage("Try Again");
setTimeout(() => {
setPendingJobLoader({ cancel: false });
setRequestMessage({ status: false, message: "" });
}, 3000);
});
} else return; } else return;
// try { // try {
// if (name === "extend") { // if (name === "extend") {
@@ -274,9 +298,16 @@ function PendingJobsPopout({ details, onClose, situation }) {
<div className="mt-10 md:mt-32 md:flex md:justify-center"> <div className="mt-10 md:mt-32 md:flex md:justify-center">
<button <button
className="px-2 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white" className="px-2 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white"
onClick={onClose} onClick={handlePendingJobsBtn}
name="cancel"
> >
Cancel Offer {pendingJobLoader.cancel ? (
<div className="w-[96px] flex justify-center items-center h-full">
<LoadingSpinner size={5} color="sky-blue" />
</div>
) : (
"Cancel Offer"
)}
</button> </button>
</div> </div>
</div> </div>
+6
View File
@@ -304,6 +304,12 @@ input[type="text"][dir="rtl"] {
transform: rotate(360deg); transform: rotate(360deg);
} }
} }
.my-custom-bg-class{
background: url("./assets/images/wrench-page-notfound.jpg") center/cover;
position: relative;
}
/* TODO: =================================default end================================ */ /* TODO: =================================default end================================ */
/* TODO: =================================update password================================ */ /* TODO: =================================update password================================ */
.content-wrapper.thankyou-section { .content-wrapper.thankyou-section {
+13
View File
@@ -496,6 +496,19 @@ class usersService {
return this.postAuxEnd("/purchasehx", postData); return this.postAuxEnd("/purchasehx", postData);
} }
// API FUNCTION TO GET FAMILY REWARD HISTORY
getFamilyRewardHx() {
var postData = {
uid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
offset: 1,
limit: 20,
action: 22011,
};
return this.postAuxEnd("/familyrewardhx", postData);
}
// API FUNCTION TO GET PAYMENT HISTORY // API FUNCTION TO GET PAYMENT HISTORY
getPaymentHx() { getPaymentHx() {
var postData = { var postData = {
+13
View File
@@ -0,0 +1,13 @@
import React from 'react'
import Lnd from '../components/Lnd/Lnd'
function LndPage() {
return (
<>
<Lnd />
</>
)
}
export default LndPage