Compare commits

...

19 Commits

Author SHA1 Message Date
victorAnumudu bd59f26146 added past due task page 2024-03-06 00:00:27 +01:00
ameye 3a397aad86 Merge branch 'family-home-active-task' of WrenchBoard/Users-Wrench into master 2024-03-05 14:51:16 +00:00
victorAnumudu 0f548e216d removed active task display from family home page 2024-03-05 15:49:04 +01:00
ameye 50fd9711e0 Merge branch 'breadcrumb-addition' of WrenchBoard/Users-Wrench into master 2024-03-04 17:46:41 +00:00
victorAnumudu f4d9eb65c6 added breadcrumb component to other family account pages 2024-03-04 18:12:02 +01:00
ameye 774224ba6d Merge branch 'home-banners-dashboard' of WrenchBoard/Users-Wrench into master 2024-03-04 16:46:09 +00:00
Ebube 9eae733755 changed to square brackets and reduced font 2024-03-04 17:34:11 +01:00
ameye 0aee3b9d6f Merge branch 'home-banners-dashboard' of WrenchBoard/Users-Wrench into master 2024-03-04 15:29:11 +00:00
Ebube b676a2a4f3 username replacement and Active task window feedback 2024-03-04 15:16:41 +01:00
ameye 0baacb3057 Merge branch 'family-blog-population' of WrenchBoard/Users-Wrench into master 2024-03-04 14:14:58 +00:00
victorAnumudu 9737c02d45 added family blog api resources 2024-03-04 15:05:31 +01:00
ameye 1048e51ddf Merge branch 'family-commonheader' of WrenchBoard/Users-Wrench into master 2024-03-04 10:52:33 +00:00
victorAnumudu 6545c32326 removed common header in family single blog post page 2024-03-04 01:29:22 +01:00
ameye 6ea9078848 Merge branch 'family-file-resource' of WrenchBoard/Users-Wrench into master 2024-03-01 20:55:47 +00:00
victorAnumudu 735cc0b296 corrected text error 2024-03-01 21:36:28 +01:00
ameye 29e058828b Merge branch 'family-resource-pages' of WrenchBoard/Users-Wrench into master 2024-03-01 20:13:32 +00:00
victorAnumudu 5d5542c221 merged master to branch 2024-03-01 21:05:03 +01:00
ameye b59f92c89f Merge branch 'bug-fixing' of WrenchBoard/Users-Wrench into master 2024-03-01 19:58:07 +00:00
victorAnumudu e01bfa369b created pages for family resources 2024-03-01 18:49:23 +01:00
31 changed files with 963 additions and 133 deletions
+11 -2
View File
@@ -59,7 +59,11 @@ import VerifyYouPagesTwo from "./views/VerifyYouPagesTwo";
import YourPages from "./views/YourPage_";
import ParentWaitingPage from "./views/ParentWaitingPage";
import FamilyPendingOfferPage from "./views/FamilyPendingOfferPage";
import FamilyPastDuePage from "./views/FamilyPastDuePage";
import FamBlogPage from "./views/FamBlogPage"
import FamAIQuestionPage from "./views/FamAIQuestionPage"
import FamMyFilesPage from "./views/FamMyFilesPage"
import FamWorkInProgressPage from "./views/FamWorkInProgressPage";
import MyPastDueTasksPage from "./views/MyPastDueTasksPage";
export default function Routers() {
return (
@@ -133,13 +137,18 @@ export default function Routers() {
<Route exact path="/market" element={<MarketPlacePage />} />
<Route exact path="/familymarket" element={<FamilyMarketPage />} />
<Route exact path="/suggested" element={<ParentWaitingPage />} />
<Route exact path="/pastdue" element={<FamilyPastDuePage />} />
<Route exact path="/pending" element={<FamilyPendingOfferPage />} />
<Route exact path="/fam-blog" element={<FamBlogPage />} />
<Route exact path="/ai-question" element={<FamAIQuestionPage />} />
<Route exact path="/myfiles" element={<FamMyFilesPage />} />
<Route exact path="/ai-lab" element={<FamAIQuestionPage />} />
<Route exact path="/work-in-progress" element={<FamWorkInProgressPage />} />
<Route
exact
path="/familysettings"
element={<FamilySettingsPage />}
/>
<Route exact path="/pastdue" element={<MyPastDueTasksPage />} />
<Route exact path="/notification" element={<Notification />} />
<Route exact path="/mytask" element={<MyTaskPage />} />
<Route exact path="/myjobs" element={<MyJobsPage />} />
+32 -11
View File
@@ -4,9 +4,15 @@ import usersService from "../../services/UsersService";
import Layout from "../Partials/Layout";
import LoadingSpinner from "../Spinners/LoadingSpinner";
import CommonHead from "../UserHeader/CommonHead";
import { useSelector } from "react-redux";
import CustomBreadcrumb from "../Breadcrumb/CustomBreadcrumb";
export default function BlogItem(props) {
const {
userDetails: { account_type },
} = useSelector((state) => state?.userDetails); // CHECKS IF USER Details account type
const apiCall = new usersService()
const navigate = useNavigate()
@@ -33,11 +39,26 @@ export default function BlogItem(props) {
},[blog_id])
return (
<Layout>
<CommonHead
commonHeadData={props.commonHeadData}
/>
{account_type == 'FULL' &&
<CommonHead
commonHeadData={props.commonHeadData}
/>
}
{ account_type == 'FAMILY' &&
<div className="mb-5">
<CustomBreadcrumb
title = {blogdata?.data?.blogdata?.length > 0 ? blogdata?.data?.blogdata[0]?.post_title : 'Blog'}
breadcrumb={
[
{ link: "/", title: "Home" },
{ link: "/fam-blog", title: "Blogs", active: true},
]
}
/>
</div>
}
<div className="notification-page w-full mb-10">
<div className="mb-5">
{/* <div className="mb-5">
<h1 className="text-26 font-bold text-dark-gray dark:text-white">
<span
className={`${selectTab === "today" ? "block" : "hidden"}`}
@@ -45,7 +66,7 @@ export default function BlogItem(props) {
{blogdata.data?.blogdata?.[0]?.post_title}
</span>
</h1>
</div>
</div> */}
<div className="notification-wrapper w-full bg-white p-8 rounded-2xl">
{blogdata?.loading ?
<LoadingSpinner size='8' color='sky-blue' height='h-[100px]' />
@@ -53,8 +74,8 @@ export default function BlogItem(props) {
blogdata?.data?.blogdata && blogdata.data?.blogdata.length ?
<div className="w-full">
{/* heading */}
<div className="sm:flex justify-between items-center mb-6">
{/* <div className="mb-5">
{/* <div className="sm:flex justify-between items-center mb-6">
<div className="mb-5">
<h1 className="text-26 font-bold text-dark-gray dark:text-white">
<span
className={`${selectTab === "today" ? "block" : "hidden"}`}
@@ -62,10 +83,10 @@ export default function BlogItem(props) {
{blogdata.data?.blogdata?.[0]?.post_title}
</span>
</h1>
</div> */}
{/* <div className="slider-btns flex space-x-4">
</div> */}
</div>
</div>
<div className="slider-btns flex space-x-4">
</div>
</div> */}
<div dangerouslySetInnerHTML={{__html: blogdata.data?.blogdata?.[0]?.post_content}}>
</div>
</div>
+13 -1
View File
@@ -4,6 +4,7 @@ import SearchCom from "../Helpers/SearchCom";
import FamilyMarketCard from "../Cards/FamilyMarketCard";
import usersService from "../../services/UsersService";
import SuggestTask from "../FamilyPopup/SuggestTask";
import CustomBreadcrumb from "../Breadcrumb/CustomBreadcrumb";
export default function FamilyMarket() {
const [popUp, setPopUp] = useState(false);
@@ -53,12 +54,23 @@ export default function FamilyMarket() {
<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="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>Suggest Task to the Parents</span>
</h1>
</div>
</div> */}
<div className="mb-5">
<CustomBreadcrumb
title = {'Suggest Task to the Parents'}
breadcrumb={
[
{ link: "/", title: "Home" },
{ link: "/familymarket", title: "Family Market", active: true},
]
}
/>
</div>
{/* Body */}
<div className="filter-section w-full items-center sm:flex justify-between mb-6">
@@ -3,6 +3,7 @@ import Layout from '../Partials/Layout'
import MyOffersFamilyTable from '../MyTasks/MyOffersFamilyTable'
import LoadingSpinner from '../Spinners/LoadingSpinner';
import usersService from '../../services/UsersService';
import CustomBreadcrumb from '../Breadcrumb/CustomBreadcrumb';
export default function FamilyPendingOffer() {
const userApi = new usersService();
@@ -25,8 +26,21 @@ export default function FamilyPendingOffer() {
},[])
return (
<Layout>
<div className="mb-5">
<CustomBreadcrumb
title = {'Ready to Start'}
breadcrumb={
[
{ link: "/", title: "Home" },
{ link: "/pending", title: "Pending", active: true},
]
}
/>
</div>
{myOffersList.loading ?
<div className='w-full flex justify-center items-center rounded-2xl bg-white'>
<LoadingSpinner size='10' color='sky-blue' height='h-[20rem]' />
</div>
:
myOffersList?.data?.result_list && myOffersList?.data?.result_list.length > 0 ?
<MyOffersFamilyTable
+25 -9
View File
@@ -19,7 +19,7 @@ export default function FamilyTable({
familyList,
loader,
popUpHandler,
imageServer
imageServer,
}) {
const navigate = useNavigate();
const [currentPage, setCurrentPage] = useState(0);
@@ -55,14 +55,19 @@ export default function FamilyTable({
banner,
enable_traking,
profile_picture,
imageServer
imageServer,
username,
}) => {
// Check for valid dates
const addedDate = added ? added.split(" ")[0] : "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 image = localStorage.getItem("session_token")
? `${imageServer}${localStorage.getItem(
"session_token"
)}/family/${family_uid}`
: "";
const trackingStatus =
enable_traking === "0"
? "Stopped"
@@ -80,14 +85,19 @@ export default function FamilyTable({
<div className="w-[60px] h-[60px] rounded-full overflow-hidden flex justify-center items-center">
<img
// src={profile_picture}
src={image || profile_picture || localImgLoad(`images/icons/${banner}`)}
src={
image ||
profile_picture ||
localImgLoad(`images/icons/${banner}`)
}
alt={`Avatar of ${firstname} ${lastname}`}
className="w-full h-full"
/>
</div>
<div className="flex flex-col flex-[0.9]">
<h1 className="font-bold text-xl text-dark-gray dark:text-white whitespace-nowrap">
{`${firstname} ${lastname} (${age < 10 ? `0${age}` : age})`}
<h1 className="font-bold text-lg text-dark-gray dark:text-white whitespace-nowrap">
{`${firstname} ${lastname}`}{" "}
<span className="ml-1 text-sm">{`[${username}]`}</span>
</h1>
<span className="text-sm text-thin-light-gray">
Added: <span className="text-purple ml-1">{addedDate}</span>
@@ -136,7 +146,7 @@ export default function FamilyTable({
task_count,
family_uid,
banner,
image
image,
})
}
type="button"
@@ -186,7 +196,13 @@ export default function FamilyTable({
</thead>
<tbody className="h-full">
{currentFamilyList?.map((familyMember, index) => {
return <FamilyRow key={index} {...familyMember} imageServer={imageServer} />;
return (
<FamilyRow
key={index}
{...familyMember}
imageServer={imageServer}
/>
);
})}
</tbody>
</table>
+8 -48
View File
@@ -7,14 +7,14 @@ import { useDispatch, useSelector } from "react-redux";
import { tableReload } from "../../store/TableReloads";
import LoadingSpinner from "../Spinners/LoadingSpinner";
export default function FamilyDash({ MyActiveJobList, serverImg }) {
export default function FamilyDash({ MyActiveJobList=[], serverImg }) {
// console.log("PROPS IN FAMILY DASH->", familyOffers?.result_list);
const dispatch = useDispatch();
const userApi = new usersService();
const trending = MyActiveJobList;
// const trending = MyActiveJobList;
const { familyBannersList } = useSelector((state) => state.familyBannersList);
@@ -24,25 +24,6 @@ export default function FamilyDash({ MyActiveJobList, serverImg }) {
let [reloadBanner, setReloadBanner] = useState(0)
// DO NOT UNCOMMENT THE CODE BELOW
// let [familyBannersList, setFamilyBannersList] = useState({loading:false, result:{}})
// const getFamilyBanners = async () => { // FUNCTION TO GET FAMILY BANNERS
// setFamilyBannersList({loading:true, result:[]});
// try {
// const res = await userApi.getFamilyBannersList();
// setFamilyBannersList({loading:false, result:res.data});
// console.log('TEST RESPONSE', res.data)
// } catch (error) {
// setFamilyBannersList({loading:false, result:[]});
// console.log("Error getting tasks");
// }
// };
// useEffect(()=>{
// getFamilyBanners()
// },[])
useEffect(()=>{
if(reloadBanner >= 2){
dispatch(tableReload({ type: "FAMILYBANNERSLIST" })); // RELOAD FAMILY BANNERS LIST EVERY 10 MINS
@@ -60,8 +41,6 @@ export default function FamilyDash({ MyActiveJobList, serverImg }) {
return (
<div>
<div className="home-page-wrapper">
{/* <CommonHead commonHeadData={props.commonHeadData} /> */}
{/* Header */}
<div className="text-white mb-4 p-2 w-full rounded-xl bg-sky-blue place-content-center">
<div className="w-full flex flex-wrap gap-x-4">
@@ -112,29 +91,10 @@ export default function FamilyDash({ MyActiveJobList, serverImg }) {
<h1 className="my-4 text-26 font-bold text-dark-gray dark:text-white tracking-wide">Resources</h1>
<div className="w-full grid grid-cols-2 md:grid-cols-4 gap-2 md:gap-4">
{tab_categories.data.map((item) => {
// onClick={()=>navigate('/resources', {state:{tab:'created'}})}
let resourceState = ''
switch(item?.action){
case 'fam-blog':
resourceState = 'blog'
break
case 'ai-question':
resourceState = 'onsale'
break
case 'myfiles':
resourceState = 'created'
break
case 'ai-lab':
resourceState = 'onsale'
break
default:
resourceState = 'blog'
break
}
// console.log('EX', item.enabled, item?.action, resourceState)
if(item.enabled){
// if(item.enabled){
// }
return (
<Link key={item.uid} to={'/resources'} state={{tab:resourceState}} className={`group rounded-xl bg-white dark:bg-dark-white shadow-md flex justify-center items-center transition-all duration-300 hover:shadow-sm`}>
<Link key={item.uid} to={`/${item?.action}`} className={`group rounded-xl bg-white dark:bg-dark-white shadow-md flex justify-center items-center transition-all duration-300 hover:shadow-sm`}>
<div className="h-full w-full">
<div className="w-full h-[8rem] rounded-t-xl overflow-hidden">
<img className="w-full h-full group-hover:scale-110 object-cover transition-all duration-300" src={item?.banner} alt='banner image' />
@@ -151,7 +111,7 @@ export default function FamilyDash({ MyActiveJobList, serverImg }) {
</div>
</div>
</Link>
)}
)
})}
</div>
</div>
@@ -167,13 +127,13 @@ export default function FamilyDash({ MyActiveJobList, serverImg }) {
/>
)} */}
{trending && trending.length > 0 && (
{/* {trending && trending.length > 0 && (
<FamilyActiveLSlde
trending={trending}
className="mb-10"
image_server={serverImg}
/>
)}
)} */}
</div>
</div>
);
+2 -24
View File
@@ -58,17 +58,13 @@ export default function Home(props) {
useEffect(() => {
const fetchData = async () => {
await Promise.all([getHomeDate(), getMyOffersList()]);
await Promise.all([getHomeDate(), getMyOffersList(), getMyActiveJobList()]);
};
if(userDetails?.account_type == 'FULL'){
fetchData();
}
}, []);
useEffect(() => {
getMyActiveJobList();
}, []);
return (
<Layout>
<div className="home-page-wrapper">
@@ -78,7 +74,7 @@ export default function Home(props) {
commonHeadData={props.bannerList}
// familyOffers={MyOffersList?.data}
serverImg = {userDetails?.session_image_server}
MyActiveJobList={MyActiveJobList?.data}
// MyActiveJobList={MyActiveJobList?.data}
/>
) : userDetails && userDetails?.account_type == "FULL" ? (
<FullAccountDash
@@ -97,21 +93,3 @@ export default function Home(props) {
</Layout>
);
}
// /*
// <Layout>
// <div className="home-page-wrapper">
// <Hero className="mb-10" data={userDetails} />
// {/* <CreateNft />
// <TrendingSection trending={trending} className="mb-10" />*/}
// <HomeTaskDisplay
// jobData={jobData}
// className="mb-10"
// bannerList={props.bannerList}
// />
{
/* <SellHistoryMarketVisitorAnalytic className="mb-10"/>
<TopSellerTopBuyerSliderSection className="mb-10" />
<UpdateTable className="mb-10"/>*/
}
// </div>
// </Layout>
+4 -4
View File
@@ -286,7 +286,7 @@ function ActiveJobs(props) {
<path d="M19 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H19v-2z" />
</svg>
</button>
<h1 className="text-xl lg:text-2xl font-bold text-dark-gray dark:text-white tracking-wide">
<h1 className="text-[22px] font-bold text-dark-gray dark:text-white tracking-wide">
{props.details?.title && props.details.title}
</h1>
</div>
@@ -412,7 +412,7 @@ function ActiveJobs(props) {
</div>
{tab == "message" ? (
<textarea
className="p-4 w-full h-[300px] text-base text-slate-600 dark:text-white bg-white dark:bg-black border border-slate-300 outline-none"
className="p-4 w-full h-[200px] text-base text-slate-600 dark:text-white bg-white dark:bg-black border border-slate-300 outline-none"
// rows="10"
style={{ resize: "none" }}
name="message"
@@ -538,13 +538,13 @@ function ActiveJobs(props) {
<p className="text-lg font-bold text-dark-gray dark:text-white tracking-wide">
Message
</p>
<button
{/* <button
type="button"
onClick={popUpHandler}
className="btn-gradient text-base tracking-wide px-4 py-2 rounded-full text-white cursor-pointer flex justify-center items-center"
>
View all
</button>
</button> */}
</div>
{props.activeJobMesList.loading ? (
<LoadingSpinner size="16" color="sky-blue" />
@@ -112,7 +112,7 @@ function ReviewJobAction({jobDetails}) {
<tr>
<td>
<div className="flex justify-center items-center">
<button type="button" onClick={popUpHandler} className="w-[150px] h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white">
<button type="button" onClick={popUpHandler} className="w-[130px] h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white">
Reject or Accept
</button>
</div>
@@ -0,0 +1,153 @@
import React, { useState } from "react";
import { useLocation, useNavigate } from "react-router-dom";
import { PriceFormatter } from "../Helpers/PriceFormatter";
import { handlePagingFunc } from "../Pagination/HandlePagination";
import PaginatedList from "../Pagination/PaginatedList";
export default function MyPastDueTaskTable({ MyJobList, className }) {
const navigate = useNavigate();
let { pathname } = useLocation();
const [currentPage, setCurrentPage] = useState(0);
const indexOfFirstItem = Number(currentPage);
const indexOfLastItem =
Number(indexOfFirstItem) + Number(process.env.REACT_APP_ITEM_PER_PAGE);
const currentActiveJobList = MyJobList?.result_list?.slice(
indexOfFirstItem,
indexOfLastItem
);
const handlePagination = (e) => {
handlePagingFunc(e, setCurrentPage);
};
return (
<div
className={`update-table w-full p-3 sm:p-8 bg-white dark:bg-dark-white overflow-hidden rounded-2xl section-shadow min-h-[520px] ${
className || ""
}`}
>
{MyJobList && MyJobList?.result_list && (
<div className="relative w-full overflow-x-auto sm:rounded-lg flex flex-col justify-between h-full">
<table className="w-full text-sm text-left text-gray-500 dark:text-gray-400">
<tbody>
{
<>
{MyJobList &&
MyJobList?.result_list &&
MyJobList.result_list.length > 0 ? (
currentActiveJobList.map((value, index) => {
let deliveryDate = value?.delivery_date?.split(" ")[0];
let thePrice = PriceFormatter(
value?.price * 0.01,
value?.currency_code,
value?.currency
);
let image = `${
MyJobList.session_image_server
}${localStorage.getItem("session_token")}/job/${
value.job_uid
}`;
return (
<tr
key={index}
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">
<div className="max-w-[60px] max-h-[60px] min-w-[60px] min-h-[60px] p-2 bg-alice-blue rounded-full overflow-hidden flex justify-center items-center">
<img
src={image}
alt="data"
className="w-full h-full rounded-full"
/>
</div>
<div className="flex flex-col flex-[0.9]">
<h1 className="font-bold text-xl text-dark-gray dark:text-white">
{value.title}
</h1>
<div>{value.description}</div>
<span className="text-sm text-thin-light-gray flex flext-start gap-1">
Price:{" "}
<span className="text-purple">
{thePrice}
</span>
</span>
<div className="flex flex-col sm:flex-row items-start gap-1 md:gap-4 md:items-center">
<span className="text-sm text-thin-light-gray">
Duration:{" "}
<span className="text-purple">
{" "}
{value.timeline_days} day(s)
</span>
</span>
<span className="text-sm text-thin-light-gray">
Due:{" "}
<span className="text-purple">
{" "}
{deliveryDate}
</span>
</span>
<span className="text-sm text-thin-light-gray">
Sent to:{" "}
<span className="text-purple">
{" "}
{value.job_to === null
? "public"
: value.job_to}
</span>
</span>
</div>
</div>
</div>
</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="px-4 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white"
>
{value.owner_status == "OWNER"
? "Review"
: "Send Updates"}
</button>
</div>
</td>
</tr>
);
})
) : (
<tr className="font-bold text-xl text-dark-gray dark:text-white whitespace-nowrap">
<td className="p-2">No Past Due Task!</td>
</tr>
)}
</>
}
</tbody>
</table>
{/* PAGINATION BUTTON */}
<PaginatedList
onClick={handlePagination}
prev={currentPage == 0 ? true : false}
next={
currentPage + Number(process.env.REACT_APP_ITEM_PER_PAGE) >=
MyJobList?.result_list.length
? true
: false
}
data={MyJobList?.result_list}
start={indexOfFirstItem}
stop={indexOfLastItem}
/>
{/* END OF PAGINATION BUTTON */}
</div>
)}
</div>
);
}
@@ -0,0 +1,57 @@
import React, { useState } from "react";
import { Link } from "react-router-dom";
import Layout from "../Partials/Layout";
import CommonHead from "../UserHeader/CommonHead";
import MyPastDueTaskTable from "./MyPastDueTaskTable";
import CustomBreadcrumb from "../Breadcrumb/CustomBreadcrumb";
import LoadingSpinner from "../Spinners/LoadingSpinner";
import { useSelector } from "react-redux";
export default function MyPastDueTasks(props) {
const { userDetails: { account_type } } = useSelector((state) => state?.userDetails); // Gets user details
return (
<Layout>
{account_type == 'FULL' &&
<CommonHead commonHeadData={props.commonHeadData} />
}
<div className="notification-page w-full mb-10">
<div className="notification-wrapper w-full">
{/* heading */}
{account_type == 'FULL' ?
<div className="sm:flex justify-between items-center mb-6">
<div className="mb-5 sm:mb-0">
<h1 className="text-26 font-bold text-dark-gray dark:text-white">
<span
>
Past Due Task(s)
</span>
</h1>
</div>
</div>
:
<div className="mb-5">
<CustomBreadcrumb
title = {'Past Due Task(s)'}
breadcrumb={
[
{ link: "/", title: "Home" },
{ link: "/pastdue", title: "Past Due", active: true},
]
}
/>
</div>
}
{props.loading ?
<div className="w-full flex justify-center items-center bg-white rounded-2xl">
<LoadingSpinner size='10' color='sky-blue' height='h-[20rem]' />
</div>
:
<MyPastDueTaskTable MyJobList={props.MyJobList} />
}
</div>
</div>
</Layout>
);
}
+14 -2
View File
@@ -3,6 +3,7 @@ import { Link } from "react-router-dom";
import { toast } from "react-toastify";
import activeAidsBanner from "../../assets/images/kids-waiting.jpg";
import ParentWaitingTable from "./ParentWaitingTable";
import CustomBreadcrumb from "../Breadcrumb/CustomBreadcrumb";
export default function ParentWaiting({ className }) {
const [addFavorite, setValue] = useState(false);
@@ -19,9 +20,20 @@ export default function ParentWaiting({ className }) {
<>
<div className={`overview-section w-full ${className || ""}`}>
<div className="w-full mb-3 flex justify-between items-center gap-1">
<h1 className="text-26 font-bold text-dark-gray dark:text-white">
{/* <h1 className="text-26 font-bold text-dark-gray dark:text-white">
Waiting for Parent to Get Started...
</h1>
</h1> */}
<CustomBreadcrumb
title = {'Waiting for Parent to Get Started...'}
breadcrumb={
[
{ link: "/", title: "Home" },
{ link: "/suggested", title: "Suggested", active: true},
]
}
/>
<Link
to='/familymarket'
className="px-4 h-10 flex justify-center items-center btn-gradient text-base rounded-full text-white"
@@ -0,0 +1,137 @@
import React, { useEffect, useState } from 'react'
import Layout from '../Partials/Layout'
import usersService from '../../services/UsersService'
import SearchCom from '../Helpers/SearchCom'
import LoadingSpinner from '../Spinners/LoadingSpinner'
import { useLocation } from 'react-router-dom'
import CustomBreadcrumb from '../Breadcrumb/CustomBreadcrumb'
import { localImgLoad } from '../../lib'
export default function FamAIQuestion() {
const apiCall = new usersService()
const {pathname} = useLocation()
const [requestStatus, setRequestStatus] = useState({loading: false, status: false, message: ''})
const [error, setError] = useState({question: '', searchPhrase: ''})
const [questions, setQuestions] = useState({loading: true, data: []})
const [askQuestion, setAskQuestion] = useState({question: '', searchPhrase: ''})
const changeAskQuestion = ({target: {name, value}}) => {
setAskQuestion(prev => ({...prev, [name]: value}))
setRequestStatus({loading: false, status: false, message: ''})
}
const onSearch = () => {
setError({question: '', searchPhrase: ''}) // sets error to false
if(!askQuestion.question){
return setError(prev => ({...prev, question: 'Select a question'}))
}
if(!askQuestion.searchPhrase){
return setError(prev => ({...prev, searchPhrase: 'Enter search parameter'}))
}
if(askQuestion.searchPhrase.length > 60){
return setError(prev => ({...prev, searchPhrase: 'Max of 60 characters'}))
}
setRequestStatus({loading: true, status: false, message: ''})
let reqData = {
question_key: '',
question: ''
}
apiCall.askResourcesResult().then(res => {
console.log(res.data.choices[0].text)
if(!res.data || res.data?.choices?.length < 1){
setRequestStatus({loading: false, status: false, message: 'No result found!'})
}
setRequestStatus({loading: false, status: false, message: res.data?.choices[0].text})
}).catch(error => {
setRequestStatus({loading: false, status: false, message: 'No result found!'})
})
}
useEffect(()=>{
apiCall.getResourceList().then(res => {
setQuestions({loading: false, data: res.data?.ask_categories?.data})
}).catch(error => {
setQuestions({loading: false, data: []})
console.log('ERROR', error)
})
}, [])
return (
<Layout>
<>
<div className='mb-4'>
<CustomBreadcrumb
title={pathname == '/ai-question' ? 'Questions' : 'AI Lab'}
breadcrumb = {
[
{ link: "/", title: "Home" },
{ link: pathname == '/ai-question' ? '/ai-question' : '/ai-lab', title: pathname == '/ai-question' ? 'Questions' : 'AI Lab', active: true},
]
}
/>
</div>
<div className={`w-full`}>
<div className="main-container w-full">
<div className="filter-section w-fullmb-6">
{/* <h1 className="text-xl lg:text-2xl font-bold text-dark-gray dark:text-white tracking-wide">Ask our A.I</h1> */}
<div className="mt-2 lg:grid grid-cols-2 gap-2 h-full lg:h-[500px]">
<div className="h-full mb-5 lg:mb-0">
<img className="w-full h-full rounded-2xl" src={localImgLoad(`images/resources-ask.jpg`)} alt='AI' />
</div>
<div className="p-8 bg-white rounded-2xl h-full">
<div className="input-wrapper border border-[#f5f8fa] dark:border-[#5e6278] w-full rounded-full h-[42px] overflow-hidden relative font-medium leading-6 bg-clip-padding text-[#5e6278] dark:text-gray-100 bg-[#f5f8fa] dark:bg-[#5e6278] text-base">
<select value={askQuestion.question} name='question' onChange={changeAskQuestion} className="input-field px-2 placeholder:text-base text-dark-gray w-full h-full tracking-wide dark:bg-[#11131F] bg-[#fafafa] focus:ring-0 focus:outline-none">
{questions.loading ?
<option value='' className="">Loading...</option>
:
<>
<option value='' className="">Find answer on:</option>
{questions.data.length > 0 && questions.data.map((item, index)=>(
<option key={index} value={item.question_key} className="">{item.name}</option>
))}
</>
}
</select>
</div>
{error.question && <p className="text-red-500 text-[12px]">{error.question}</p>}
{/* filter-search */}
<div className="w-full my-5 border-2 rounded-full">
<SearchCom
name={'searchPhrase'}
value={askQuestion.searchPhrase}
handleSearch={changeAskQuestion}
/>
</div>
{error.searchPhrase && <p className="text-red-500 text-[12px]">{error.searchPhrase}</p>}
<div className="w-full flex justify-end items-center border-b-2 pb-4">
<button
onClick={onSearch}
disabled={requestStatus.loading}
className="btn-gradient text-base tracking-wide px-4 py-2 rounded-full text-white cursor-pointer"
>
Search
</button>
</div>
<div className="search_result my-2 max-h-[400px] overflow-auto">
{requestStatus.loading ?
<LoadingSpinner size='8' color='sky-blue' height='h-[100px]' />
:
<p className="py-2 text-sm font-bold text-dark-gray dark:text-white tracking-wide">{requestStatus.message}</p>
}
</div>
</div>
</div>
</div>
</div>
</div>
</>
</Layout>
)
}
+108
View File
@@ -0,0 +1,108 @@
import React, { useEffect, useState } from 'react'
import Layout from '../Partials/Layout'
import SearchCom from '../Helpers/SearchCom'
import DataIteration from '../Helpers/DataIteration'
import FamBlogItem from './FamBlogItem'
import CustomBreadcrumb from '../Breadcrumb/CustomBreadcrumb'
import usersService from '../../services/UsersService'
import LoadingSpinner from '../Spinners/LoadingSpinner'
export default function FamBlog() {
const [blogData, setBlogData] = useState({loading: true, data: []});
const [filteredBlog, setFilteredBlog] = useState({value: '', data:[]}) // State to hold filter blog
const handleFilterBlog = ({target}) => {
let filterWord = target.value
let filteredData = []
if(!filterWord){
filteredData = blogData?.data?.blogdata
}else{
filteredData = blogData?.data?.blogdata?.filter(item => item.post_title.toLowerCase().startsWith(filterWord.toLowerCase()))
}
setFilteredBlog({value:target.value, data: filteredData})
}
const api = new usersService();
const getFamilyBlog = async () => {
setBlogData({loading: true, data: []})
try {
const res = await api.getFamilyBlogData();
setBlogData({loading: false, data:res.data});
setFilteredBlog(prev => ({...prev, data:res.data?.blogdata}))
} catch (error) {
setBlogData({loading: false, data: []})
throw new Error("Error getting mode");
}
};
useEffect(() => {
getFamilyBlog();
}, []);
return (
<Layout>
<>
<div className='mb-4'>
<CustomBreadcrumb
title='Blog'
breadcrumb = {
[
{ link: "/", title: "Home" },
{ link: "/fam-blog", title: "Blogs", active: true},
]
}
/>
</div>
<div className={`w-full`}>
<div className="main-container w-full">
<div className="filter-section w-full items-center sm:flex justify-between mb-6">
{/* filter-search */}
{blogData?.data?.blogdata?.length > 0 &&
<div className="sm:w-1/2 w-full sm:pr-20 pr-0 mb-5 sm:mb-0">
<SearchCom
placeholder='Search Blog Items...'
value={filteredBlog.value}
handleSearch={handleFilterBlog}
/>
</div>
}
</div>
<div className="content-section w-full-width">
{blogData.loading ?
<div className='flex justify-center items-center bg-white rounded-2xl'>
<LoadingSpinner size='10' color='sky-blue' height='h-[20rem]' />
</div>
: blogData?.data?.blogdata?.length > 0 && filteredBlog?.data?.length > 0?
<div className="grid lg:grid-cols-3 sm:grid-cols-2 grid-cols-1 gap-[30px]">
<DataIteration
datas={filteredBlog?.data}
startLength={process.env.REACT_APP_ZERO_STATE}
endLength={filteredBlog?.data?.length}
>
{({ datas }) => (
<div key={Math.random()}>
<FamBlogItem
datas={datas}
bg={blogData?.data?.image_url && blogData?.data?.image_url}
className=''
hidden={false}
/>
</div>
)}
</DataIteration>
</div>
:
<div className='h-[30rem] flex justify-center items-center bg-white rounded-2xl'>
<p>No Blog Found</p>
</div>
}
</div>
</div>
</div>
</>
</Layout>
)
}
@@ -0,0 +1,54 @@
import React from 'react'
import { Link } from 'react-router-dom';
export default function FamBlogItem({datas, className, bg, hidden=false}) {
return (
<div
className={`card-style-two w-full h-[336px] p-[20px] bg-white dark:bg-dark-white rounded-2xl section-shadow ${
className || ""
}`}
>
<div className="flex flex-col justify-between w-full h-full">
<div className="thumbnail-area w-full">
<div
className="w-full h-[236px] p-6 rounded-xl overflow-hidden bg-sky-200"
style={{
background: `url(${`${bg}${datas.meta_value}`}) 0% 0% / cover no-repeat`,
}}
>
<div className="product-two-options flex justify-between mb-5 relative">
<div className="status">
{datas?.isActive && (
<span className="text-xs px-3 py-1.5 tracking-wide rounded-full bg-gold text-white">
Active
</span>
)}
</div>
</div>
{hidden && <div className="flex justify-center"></div>}
</div>
</div>
<div className="details-area">
{/* title */}
<Link to={`/blog-page?blog_id=${datas?.ID ? datas.ID : '1'}`} className="mb-2.5" rel="noreferrer">
<h1 className="font-bold text-xl tracking-wide line-clamp-1 text-dark-gray dark:text-white capitalize">
{datas?.post_title ? datas?.post_title : "dummy title..."}
</h1>
</Link>
<div className="flex justify-between">
<div className="flex items-center space-x-2"></div>
<div className="my-1">
<Link
to={`/blog-page?blog_id=${datas?.ID ? datas.ID : '1'}`}
className="px-4 py-2.5 text-white text-sm bg-pink rounded-full tracking-wide"
rel="noreferrer"
>
View
</Link>
</div>
</div>
</div>
</div>
</div>
);
}
@@ -1,10 +1,10 @@
import React from 'react'
import Layout from '../Partials/Layout'
export default function FamilyPastDue() {
export default function FamGames() {
return (
<Layout>
<div>Family PastDue Page Here</div>
<div>Family Games Page</div>
</Layout>
)
}
@@ -0,0 +1,10 @@
import React from 'react'
import Layout from '../Partials/Layout'
export default function FamInterest() {
return (
<Layout>
<div>Fam Interesting Dummy Page</div>
</Layout>
)
}
@@ -0,0 +1,180 @@
import React, { useState } from "react";
import { Link } from "react-router-dom";
import defaultImg from "../../assets/images/myfiles/default.svg";
import localImgLoad from "../../lib/localImgLoad";
import { PaginatedList, handlePagingFunc } from "../../components/Pagination";
import Layout from "../Partials/Layout";
import CustomBreadcrumb from "../Breadcrumb/CustomBreadcrumb";
export default function FamMyFiles() {
let uploadedFiles = [] // To be updated Later from replaced with real data from API CALL
const [currentPage, setCurrentPage] = useState(0);
const indexOfFirstItem = Number(currentPage);
const indexOfLastItem =
Number(indexOfFirstItem) + Number(process.env.REACT_APP_ITEM_PER_PAGE);
const currentFiles = uploadedFiles?.data?.slice(
indexOfFirstItem,
indexOfLastItem
);
const handlePagination = (e) => {
handlePagingFunc(e, setCurrentPage);
};
return (
<Layout>
<>
<div className=''>
<CustomBreadcrumb
title='My Files'
breadcrumb = {
[
{ link: "/", title: "Home" },
{ link: "/myfiles", title: "My Files", active: true},
]
}
/>
</div>
<div className="mb-4 w-full flex justify-end item-center">
<Link
to="/my-uploads"
className="btn-gradient lg:flex hidden w-[153px] h-[46px] rounded-full text-white justify-center items-center"
>
Add My Item
</Link>
</div>
<div
className={`update-table w-full p-8 bg-white dark:bg-dark-white overflow-hidden rounded-2xl section-shadow relative min-h-[520px]`}
>
<div className="header w-full sm:flex justify-between items-center mb-5">
<div className="flex space-x-2 items-center mb-2 sm:mb-0">
<h1 className="text-xl font-bold text-dark-gray dark:text-white tracking-wide">
My Uploads
</h1>
</div>
</div>
<div className="relative w-full overflow-x-auto sm:rounded-lg">
<table className="w-full text-sm text-left text-gray-500 dark:text-gray-400">
<tbody>
<>
{uploadedFiles?.data && uploadedFiles?.data.length ? (
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"
>
<td className=" py-4">
<div className="flex space-x-2 items-center w-full">
<div className="w-[60px] h-[60px] p-2 bg-alice-blue rounded-full overflow-hidden flex justify-center items-center">
<img
src={
localImgLoad(
`images/myfiles/${value.banner}`
) || defaultImg
}
alt="data"
className="w-full h-full rounded-full"
/>
</div>
<div className="flex flex-col flex-[0.9]">
<h1 className="font-bold text-xl text-dark-gray dark:text-white">
{value.title || "Dummy Text"}
</h1>
<div>
{value.description || "Dummy Description"}
</div>
<span className="text-sm text-thin-light-gray flex flext-start gap-1">
Added:{" "}
<span className="text-purple">{addedDate}</span>
</span>
<div className="flex gap-4 items-center">
<span className="text-sm text-thin-light-gray">
File Name:{" "}
<span className="text-purple">
{" "}
{value.file_name}
</span>
</span>
<span className="text-sm text-thin-light-gray">
File Size:{" "}
<span className="text-purple">
{" "}
{formattedSize}
</span>
</span>
<span className="text-sm text-thin-light-gray">
File Type:{" "}
<span className="text-purple">
{" "}
{value?.file_type}
</span>
</span>
</div>
</div>
</div>
</td>
<td className="text-right py-4 px-2">
<div className="flex justify-center items-center">
<a
href={imageLink}
title="download"
// className="w-20 h-11 flex justify-center items-center btn-gradient text-base rounded-full text-white"
>
<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>
);
})
) : (
<tr className="font-bold text-xl text-dark-gray dark:text-white whitespace-nowrap">
<td className="p-2" colSpan={3}>
No Files Currently!
</td>
</tr>
)}
</>
</tbody>
</table>
{/* PAGINATION BUTTON */}
<PaginatedList
onClick={handlePagination}
prev={currentPage == 0 ? true : false}
next={
currentPage + Number(process.env.REACT_APP_ITEM_PER_PAGE) >=
uploadedFiles?.data?.length
? true
: false
}
data={uploadedFiles?.data}
start={indexOfFirstItem}
stop={indexOfLastItem}
/>
{/* END OF PAGINATION BUTTON */}
</div>
</div>
</>
</Layout>
);
}
const formatFileSize = (sizeInBytes) => {
if (sizeInBytes < 1024) {
return `${sizeInBytes} bytes`;
} else if (sizeInBytes < 1024 * 1024) {
const sizeInKB = (sizeInBytes / 1024).toFixed(2);
return `${sizeInKB} KB`;
} else {
const sizeInMB = (sizeInBytes / (1024 * 1024)).toFixed(2);
return `${sizeInMB} MB`;
}
};
@@ -0,0 +1,24 @@
import React from 'react'
import Layout from '../Partials/Layout'
import CustomBreadcrumb from '../Breadcrumb/CustomBreadcrumb'
export default function FamWorkInProgress() {
return (
<Layout>
<>
<div className='mb-4'>
<CustomBreadcrumb
title='Games and Interest'
breadcrumb = {
[
{ link: "/", title: "Home" },
{ link: "/work-in-progress", title: "Games and Interest", active: true},
]
}
/>
</div>
<div className='h-[20rem] w-full bg-white shadow-lg flex justify-center items-center rounded-2xl'>Work in Progress Coming Soon</div>
</>
</Layout>
)
}
+2 -15
View File
@@ -288,23 +288,10 @@ const AuthRoute = ({ redirectPath = "/login", children }) => {
}
};
getFamilyResourcesList()
}, [isLogin.status, familyBannersListTable]);
}, [isLogin.status]);
// useEffect(() => {
// apiCall
// .getHeroJBanners()
// .then((res) => {
// if (res.data.internal_return < 0) {
// return;
// }
// dispatch(commonHeadBanner(res.data));
// })
// .catch((error) => {
// console.log("ERROR ", error);
// });
// }, []);
//
// RENDER PAGE
return isLogin.loading && !loggedIn ? (
<LoadingSpinner size="32" color="sky-blue" height="h-screen" />
) : !isLogin.status && !loggedIn ? (
+14
View File
@@ -1279,6 +1279,20 @@ class usersService {
};
return this.postAuxEnd("/familyresources", postData);
}
// API FUNCTION TO GET FAMILY BLOG DATA
getFamilyBlogData() {
var postData = {
uuid: localStorage.getItem("uid"),
member_id: localStorage.getItem("member_id"),
sessionid: localStorage.getItem("session_token"),
page: 0,
offset: 0,
limit: 100,
};
return this.postAuxEnd("/blogdata", postData);
}
/*
- 20:27:30.118 FLOG_MAX [757411]: REQ_STRING(username)
- 20:27:30.118 FLOG_MAX [757411]: REQ_STRING(password)
+10
View File
@@ -0,0 +1,10 @@
import React from 'react'
import FamAIQuestion from '../components/familyResources/FamAIQuestion'
export default function FamAIQuestionPage() {
return (
<>
<FamAIQuestion />
</>
)
}
+10
View File
@@ -0,0 +1,10 @@
import React from 'react'
import FamBlog from '../components/familyResources/FamBlog'
export default function FamBlogPage() {
return (
<>
<FamBlog />
</>
)
}
+9
View File
@@ -0,0 +1,9 @@
import React from 'react'
import FamGames from '../components/familyResources/FamGames'
export default function FamGamesPage() {
return (
<>
<FamGames />
</>
)
}
+10
View File
@@ -0,0 +1,10 @@
import React from 'react'
import FamInterest from '../components/familyResources/FamInterest'
export default function FamInterestPage() {
return (
<>
<FamInterest />
</>
)
}
+10
View File
@@ -0,0 +1,10 @@
import React from 'react'
import FamMyFiles from '../components/familyResources/FamMyFiles'
export default function FamMyFilesPage() {
return (
<>
<FamMyFiles />
</>
)
}
+10
View File
@@ -0,0 +1,10 @@
import React from 'react'
import FamWorkInProgress from '../components/familyResources/FamWorkInProgress'
export default function FamWorkInProgressPage() {
return (
<>
<FamWorkInProgress />
</>
)
}
-10
View File
@@ -1,10 +0,0 @@
import React from 'react'
import FamilyPastDue from '../components/FamilyAcc/FamilyPastDue'
export default function FamilyPastDuePage() {
return (
<>
<FamilyPastDue />
</>
)
}
+1 -1
View File
@@ -39,7 +39,7 @@ function ManageActiveJobs() {
loading: false,
error: false,
data: res.data.result_list,
image: res.data.session_image_server
image: res.data.session_image_server,
});
})
.catch((error) => {
+2 -3
View File
@@ -1,7 +1,6 @@
import React, { useContext,useState, useEffect } from "react";
import usersService from "../services/UsersService";
//import MyJobs from "../components/MyJobs";
//import MyActiveJobs from "../components/MyActiveJobs";
import MyPastDueJobs from "../components/MyActiveJobs/MyPastDueJobs";
import { useSelector } from "react-redux";
@@ -9,7 +8,7 @@ export default function MyPastDueJobsPage() {
let {commonHeadBanner} = useSelector(state => state.commonHeadBanner)
const [MyJobList, setMyJobList] = useState([]);
const api = new usersService();
//TARGET ENDPOINT[POST]http://10.204.5.100:9083/en/wrench/api/v1/jobmanageractive
const getMyJobList = async () => {
try {
const res = await api.getMyPastDueJobList();
+36
View File
@@ -0,0 +1,36 @@
import React, { useContext,useState, useEffect } from "react";
import usersService from "../services/UsersService";
import MyPastDueTasks from "../components/MyActiveJobs/MyPastDueTasks";
import { useSelector } from "react-redux";
export default function MyPastDueTasksPage() {
let {commonHeadBanner} = useSelector(state => state.commonHeadBanner)
const [MyJobList, setMyJobList] = useState({loading:true, data:[]});
const api = new usersService();
const getMyJobList = async () => {
try {
const res = await api.getMyPastDueJobList();
console.log("DATA", res.data);
setMyJobList({loading:false, data:res.data})
} catch (error) {
setMyJobList({loading:false, data:[]})
console.log("Error getting mode");
}
};
useEffect(() => {
getMyJobList();
}, []);
// debugger;
return (
<>
<MyPastDueTasks
MyJobList={MyJobList?.data}
loading={MyJobList?.loading}
commonHeadData={commonHeadBanner?.result_list}
/>
</>
);
}