banner size fixed

This commit is contained in:
2024-05-17 15:32:45 +05:30
parent ed89d6b022
commit 4897b69d97
42 changed files with 1840 additions and 312 deletions

View File

@@ -28,6 +28,7 @@ import {
import { useNavigate } from "react-router-dom";
import Loader01 from "../../Components/Loaders/Loader01";
import Header from "../Header";
import ToastBox from "../ToastBox";
const AddBanner = ({ createApi, navigateLink, title }) => {
const toast = useToast();
@@ -67,18 +68,18 @@ const AddBanner = ({ createApi, navigateLink, title }) => {
if (response?.data?.statusCode === 200) {
setIsLoading(false);
toast({
title: response?.data?.message,
status: "success",
isClosable: true,
render: () => (
<ToastBox status={"success"} message={response?.data?.message} />
),
});
reset();
navigate(navigateLink);
} else if (response?.data?.statusCode === 500) {
setIsLoading(false);
toast({
title: response?.data?.message,
status: "success",
isClosable: true,
render: () => (
<ToastBox status={"success"} message={response?.data?.message} />
),
});
}
})

View File

@@ -0,0 +1,8 @@
const BannerEdit = ({title}) => {
return (
<div>{title}</div>
)
}
export default BannerEdit

View File

@@ -37,11 +37,15 @@ const BannerCommunity = ({
statusUpdateApi,
title,
addLink,
viewLink,
editLink
}) => {
// ====================================================[Hooks]===================================================================
const toast = useToast();
const [deleteAlert, setDeleteAlert] = useState(false);
const [actionId, setActionId] = useState(null);
const [actionStatus, setActionStatus] = useState(null);
const [deleteIsLoading, setDeleteIsLoading] = useState(false);
const [searchTerm, setSearchTerm] = useState("");
const [statusFilter, setStatusFilter] = useState("all");
@@ -56,24 +60,29 @@ const BannerCommunity = ({
// ====================================================[Functions]===================================================================
const handleDelete = async (bannerId) => {
const handleDelete = async (bannerId, status) => {
if (status) {
return toast({
render: () => (
<ToastBox status={"warn"} message="You cant delete active banner" />
),
});
}
try {
// Trigger the mutation
setDeleteIsLoading(true);
await deleteApi(bannerId)
.then((response) => {
// Handle the response here
console.log("Mutation response:", response?.data?.statusCode);
console.log("Mutation response:", response?.data?.message);
if (response?.data?.statusCode === 200) {
setDeleteIsLoading(false);
setDeleteAlert(false);
toast({
title: response?.data?.message,
status: "success",
duration: 1000,
isClosable: true,
render: () => (
<ToastBox status={"success"} message={response?.data?.message} />
),
});
}
})
@@ -95,8 +104,8 @@ const BannerCommunity = ({
<ToastBox status={"warn"} message={"Please toggle another banner."} />
),
});
}
}else{
try {
// Trigger the mutation
await statusUpdateApi({ id })
@@ -114,6 +123,8 @@ const BannerCommunity = ({
// Handle errors
console.error("Error updating community status:", error);
}
}
};
// ====================================================[Table Filter]================================================================
@@ -208,16 +219,17 @@ const BannerCommunity = ({
</MenuButton>
<Portal>
<MenuList minWidth="80px">
<RouterLink to={`/banner/banner-community/edit/${item.id}`}>
<RouterLink to={`${editLink}${item.id}`}>
<MenuItem className="web-text-medium">Edit</MenuItem>
</RouterLink>
<RouterLink to={`/banner/banner-community/view/${item.id}`}>
<RouterLink to={`${viewLink}${item.id}`}>
<MenuItem className="web-text-medium">View</MenuItem>
</RouterLink>
<MenuItem
onClick={() => {
setActionId(item.id);
setDeleteAlert(true);
setActionStatus(item.status)
}}
className="web-text-medium"
>
@@ -339,7 +351,7 @@ const BannerCommunity = ({
<CustomAlertDialog
onClose={() => setDeleteAlert(false)}
isOpen={deleteAlert}
alertHandler={() => handleDelete(actionId)}
alertHandler={() => handleDelete(actionId, actionStatus)}
message={"Are you sure you want to delete member?"}
isLoading={deleteIsLoading}
/>

View File

@@ -0,0 +1,9 @@
const extractFilename = (filePath) => {
console.log(filePath);
// Use the split method to break the path into parts based on '/'
const parts = filePath.split('/');
// Return the last part, which is the filename
return parts[parts.length - 1];
};
export default extractFilename ;

View File

@@ -10,7 +10,7 @@ const FullscreenLoaders = () => {
w={"100%"}
h={"90%"}
>
<Spinner />
<Spinner color='teal.700' />
</Box>
);
};

View File

@@ -0,0 +1,138 @@
import { Box, HStack, Input, Select, Text } from "@chakra-ui/react";
import { OPACITY_ON_LOAD } from "../../Layout/animations";
import { TABLE_PAGINATION } from "../../Constants/Paginations";
import { useGetVideosQuery } from "../../Services/api.service";
import { useState } from "react";
import Header from "../../Components/Header";
import { ChevronLeftIcon, ChevronRightIcon } from "@chakra-ui/icons";
import DataTable from "../../Components/DataTable/DataTable";
const TabularView = ({
apiData,
tableHeadRow,
title,
btnTitle,
link,
extractedArray,
searchTerm,
setSearchTerm,
statusFilter,
setStatusFilter,
currentPage,
setCurrentPage,
pageSize,
setPageSize,
totalPages
}) => {
const [displayRange, setDisplayRange] = useState({
start: TABLE_PAGINATION?.page,
end: pageSize,
});
// ====================================================[Pagination Setup]================================================================
const paginationPrev = () => {
if (currentPage > 1) {
setCurrentPage(currentPage - 1);
updateDisplayRange(currentPage - 1);
}
};
console.log(apiData?.data?.data);
const paginationNext = () => {
const totalPage = Math.ceil(totalPages / pageSize);
if (currentPage < totalPage) {
setCurrentPage(currentPage + 1);
updateDisplayRange(currentPage + 1);
}
};
const updateDisplayRange = (page) => {
const start = (page - 1) * pageSize + 1;
const end = Math.min(start + pageSize - 1, totalPages);
setDisplayRange({ start, end });
};
return (
<Box
overflowY={"scroll"}
paddingBottom={50}
height={"100vh"}
{...OPACITY_ON_LOAD}
>
<Header title={title} btnTitle={btnTitle} link={link} />
<Box bg="white.500">
<HStack
display={"flex"}
justifyContent={"space-between"}
ps={1}
pe={1}
pb={4}
pt={4}
spacing="24px"
>
<Input
type="search"
width={300}
placeholder="Search..."
size="sm"
rounded="sm"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
<HStack>
<Select
className="pointer web-text-small"
width={"90px"}
rounded="sm"
size="sm"
value={statusFilter}
onChange={(e) => setStatusFilter(e.target.value)}
>
<option value="all">All</option>
<option value="active">Active</option>
<option value="inactive">Inactive</option>
</Select>
<Select
className="pointer web-text-small"
width={"90px"}
rounded="sm"
size="sm"
value={pageSize}
onChange={(e) => setPageSize(e.target.value)}
>
<option value={pageSize}>{pageSize}</option>
</Select>
<HStack>
<ChevronLeftIcon
onClick={paginationPrev}
className=" link rounded-3 pointer"
/>
<Text className="web-text-medium" as={"span"}>
{displayRange.start} - {displayRange.end} of{" "}
{totalPages}
</Text>
<ChevronRightIcon
onClick={paginationNext}
className=" link rounded-3 pointer"
/>
</HStack>
</HStack>
</HStack>
</Box>
{/* ====================================================[ Table ]================================================================ */}
<DataTable
emptyMessage={"We don't have any blog for this author"}
tableHeadRow={tableHeadRow}
data={extractedArray}
isLoading={apiData?.isLoading}
/>
</Box>
);
};
export default TabularView;

View File

@@ -4,6 +4,7 @@ import { OPACITY_ON_LOAD } from "../../Layout/animations";
import {
useGetBuildBannerQuery,
useGetCommunityBannerQuery,
useGetHomeBannerQuery,
useGetLearnBannerQuery,
useGetNewsBannerQuery,
} from "../../Services/api.service";
@@ -15,6 +16,7 @@ const Banner = () => {
const learnBanner = useGetLearnBannerQuery();
const buildBanner = useGetBuildBannerQuery();
const newsBanner = useGetNewsBannerQuery();
const homeBanner = useGetHomeBannerQuery();
return (
<Box {...OPACITY_ON_LOAD} overflowY={"scroll"} height={"100vh"}>
@@ -54,8 +56,8 @@ const Banner = () => {
<BannerStack
stackTitle={"Home banner"}
viewAllLink={"/banner/home"}
bannerIsLoading={newsBanner?.isLoading}
bannerArray={newsBanner?.data?.data?.rows?.slice(0, 3)}
bannerIsLoading={homeBanner?.isLoading}
bannerArray={homeBanner?.data?.data?.rows?.slice(0, 3)}
viewBannerLink={"/banner/home/view"}
/>
</Box>

View File

@@ -15,6 +15,8 @@ const BannerBuild = () => {
<BannerTable
addLink={"/banner/build/add-banner"}
title={"Build Banner"}
viewLink={"/banner/build/view/"}
editLink={"/banner/build/edit/"}
deleteApi={deleteBuildBanner}
dataArray={buildBanner}
statusUpdateApi={updateLearnBuildStatus}

View File

@@ -4,7 +4,7 @@ import {
useCreateLearnBannerMutation,
} from "../../../Services/api.service";
const BuildBannerAdd = () => {
const BannerBuildAdd = () => {
const [createBuildBannerData] = useCreateBuildBannerMutation();
return (
<AddBanner
@@ -15,4 +15,4 @@ const BuildBannerAdd = () => {
);
};
export default BuildBannerAdd;
export default BannerBuildAdd;

View File

@@ -0,0 +1,10 @@
import React from 'react'
import BannerEdit from '../../../Components/Banner/BannerEdit'
const BannerBuildEdit = () => {
return (
<BannerEdit title={"Build"}/>
)
}
export default BannerBuildEdit

View File

@@ -11,11 +11,15 @@ const BannerCommunity = () => {
const [deleteCommunityBanner] = useDeleteCommunityBannerMutation();
const [updateCommunityBannerStatus] =
useUpdateCommunityBannerStatusMutation();
return (
<BannerTable
title={'Community banner'}
addLink={"/banner/banner-community/add-banner"}
viewLink={"/banner/banner-community/view/"}
editLink={"/banner/banner-community/edit/"}
deleteApi={deleteCommunityBanner}
dataArray={communityBanner}
statusUpdateApi={updateCommunityBannerStatus}

View File

@@ -15,6 +15,8 @@ const BannerLearn = () => {
<BannerTable
addLink={"/banner/learn/add-banner"}
title={"Learn Banner"}
viewLink={"/banner/learn/view/"}
editLink={"/banner/learn/edit/"}
deleteApi={deleteLearnBanner}
dataArray={learnBanner}
statusUpdateApi={updateLearnBannerStatus}

View File

@@ -1,7 +1,7 @@
import AddBanner from "../../../Components/Banner/AddBanner";
import { useCreateLearnBannerMutation } from "../../../Services/api.service";
const LearnBannerAdd = () => {
const BannerLearnAdd = () => {
const [createLearnBannerData] = useCreateLearnBannerMutation();
return (
<AddBanner
@@ -12,4 +12,4 @@ const LearnBannerAdd = () => {
);
};
export default LearnBannerAdd;
export default BannerLearnAdd;

View File

@@ -0,0 +1,10 @@
import React from 'react'
import BannerEdit from '../../../Components/Banner/BannerEdit'
const BannerLearnEdit = () => {
return (
<BannerEdit title={"Learn"}/>
)
}
export default BannerLearnEdit

View File

@@ -1,9 +1,9 @@
import React from "react";
import { useParams } from "react-router-dom";
import { useGetLearnBannerByIdQuery } from "../../Services/api.service";
import BannerView from "../../Components/Banner/BannerView";
import { useGetLearnBannerByIdQuery } from "../../../Services/api.service";
import BannerView from "../../../Components/Banner/BannerView";
const ViewLearnBanner = () => {
const BannerLearnView = () => {
const { id } = useParams();
console.log(id);
const { data, error, isLoading } = useGetLearnBannerByIdQuery(id);
@@ -12,4 +12,4 @@ const ViewLearnBanner = () => {
return <BannerView editLink={'/banner/learn/edit'} isLoading={isLoading} data={data} />;
};
export default ViewLearnBanner;
export default BannerLearnView;

View File

@@ -22,6 +22,8 @@ const BannerNews = () => {
<BannerTable
addLink={"/banner/news/add-banner"}
title={"News Banner"}
viewLink={"/banner/news/view/"}
editLink={"/banner/news/edit/"}
deleteApi={deleteNewsBanner}
dataArray={newsBanner}
statusUpdateApi={updateNewsBuildStatus}

View File

@@ -1,15 +1,15 @@
import AddBanner from "../../../Components/Banner/AddBanner";
import { useCreateNewsBannerMutation } from "../../../Services/api.service";
import { useCreateLearnBannerMutation, useCreateNewsBannerMutation } from "../../../Services/api.service";
const NewsBannerAdd = () => {
const BannerNewsAdd = () => {
const [createNewsBannerData] = useCreateNewsBannerMutation();
return (
<AddBanner
title={"News banner"}
navigateLink={"/banner/build"}
navigateLink={"/banner/news"}
createApi={createNewsBannerData}
/>
);
};
export default NewsBannerAdd;
export default BannerNewsAdd;

View File

@@ -0,0 +1,10 @@
import React from 'react'
import BannerEdit from '../../../Components/Banner/BannerEdit'
const BannerNewsEdit = () => {
return (
<BannerEdit title={"News"}/>
)
}
export default BannerNewsEdit

View File

@@ -0,0 +1,15 @@
import React from "react";
import { useParams } from "react-router-dom";
import { useGetLearnBannerByIdQuery, useGetNewsBannerByIdQuery } from "../../../Services/api.service";
import BannerView from "../../../Components/Banner/BannerView";
const BannerNewsView = () => {
const { id } = useParams();
console.log(id);
const { data, error, isLoading } = useGetNewsBannerByIdQuery(id);
return <BannerView editLink={'/banner/news/edit'} isLoading={isLoading} data={data} />;
};
export default BannerNewsView;

View File

@@ -1,13 +0,0 @@
import React from 'react'
import { useParams } from 'react-router-dom';
import { useGetNewsBannerByIdQuery } from '../../../Services/api.service';
import BannerView from '../../../Components/Banner/BannerView';
const BannersNews = () => {
const { id } = useParams();
const { data, error, isLoading } = useGetNewsBannerByIdQuery(id);
return <BannerView editLink={'/banner/news/edit'} isLoading={isLoading} data={data} />;
}
export default BannersNews

View File

@@ -0,0 +1,39 @@
import React from "react";
import {
useDeleteBuildBannerMutation,
useDeleteHomeBannerMutation,
useDeleteLearnBannerMutation,
useDeleteNewsBannerMutation,
useGetBuildBannerQuery,
useGetHomeBannerQuery,
useGetLearnBannerQuery,
useGetNewsBannerQuery,
useUpdateBuildBannerStatusMutation,
useUpdateHomeBannerStatusMutation,
useUpdateLearnBannerStatusMutation,
useUpdateNewsBannerStatusMutation,
} from "../../../Services/api.service";
import BannerTable from "../../../Components/Banner/BannerTable";
const HomeBanner = () => {
const homeBanner = useGetHomeBannerQuery();
const [deleteHomeBanner] = useDeleteHomeBannerMutation();
const [updateHomeBuildStatus] = useUpdateHomeBannerStatusMutation();
const { data, error, isLoading } = useUpdateNewsBannerStatusMutation();
return (
<BannerTable
addLink={"/banner/home/add-banner"}
title={"Home Banner"}
viewLink={"/banner/home/view/"}
editLink={"/banner/home/edit/"}
deleteApi={deleteHomeBanner}
dataArray={homeBanner}
statusUpdateApi={updateHomeBuildStatus}
/>
);
};
export default HomeBanner;

View File

@@ -0,0 +1,15 @@
import AddBanner from "../../../Components/Banner/AddBanner";
import { useCreateHomeBannerMutation } from "../../../Services/api.service";
const HomeBannerAdd = () => {
const [createLearnBannerData] = useCreateHomeBannerMutation();
return (
<AddBanner
title={"Home banner"}
navigateLink={"/banner/home"}
createApi={createLearnBannerData}
/>
);
};
export default HomeBannerAdd;

View File

@@ -0,0 +1,10 @@
import React from 'react'
import BannerEdit from '../../../Components/Banner/BannerEdit'
const HomeBannerEdit = () => {
return (
<BannerEdit title={"HOme"}/>
)
}
export default HomeBannerEdit

View File

@@ -0,0 +1,15 @@
import React from "react";
import { useParams } from "react-router-dom";
import { useGetHomeBannerByIdQuery, useGetNewsBannerByIdQuery } from "../../../Services/api.service";
import BannerView from "../../../Components/Banner/BannerView";
const HomeBannerView = () => {
const { id } = useParams();
console.log(id);
const { data, error, isLoading } = useGetHomeBannerByIdQuery(id);
return <BannerView editLink={'/banner/home/edit'} isLoading={isLoading} data={data} />;
};
export default HomeBannerView;

View File

@@ -31,6 +31,7 @@ import ReactQuill from "react-quill";
import "react-quill/dist/quill.snow.css";
import ChipSelector from "../../Components/ChipSelector/ChipSelector";
import Header from "../../Components/Header";
import ToastBox from "../../Components/ToastBox";
const AddBlogsAndArticles = () => {
const toast = useToast();
@@ -94,9 +95,9 @@ const AddBlogsAndArticles = () => {
if (response?.data?.statusCode === 201) {
setIsLoading(false);
toast({
title: response?.data?.message,
status: "success",
isClosable: true,
render: () => (
<ToastBox status={"success"} message={response?.data?.message} />
),
});
reset();
navigate("/blogs-articles");

View File

@@ -51,10 +51,16 @@ import { HiDotsVertical } from "react-icons/hi";
import { formatDate } from "../../Components/Functions/UTCConvertor";
import CustomAlertDialog from "../../Components/CustomAlertDialog";
import Header from "../../Components/Header";
import ToastBox from "../../Components/ToastBox";
import TabularView from "../../Components/TabularView/TabularView";
import { TABLE_PAGINATION } from "../../Constants/Paginations";
const BlogsAndArticles = () => {
// ====================================================[Hooks]===================================================================
const toast = useToast();
const [pageSize, setPageSize] = useState(TABLE_PAGINATION?.size);
const [currentPage, setCurrentPage] = useState(1);
const [deleteAlert, setDeleteAlert] = useState(false);
const [actionId, setActionId] = useState(null);
const [deleteIsLoading, setDeleteIsLoading] = useState(false);
@@ -99,9 +105,12 @@ const BlogsAndArticles = () => {
if (response?.data?.statusCode === 201) {
console.log("toasted");
toast({
title: response?.data?.message,
status: "success",
isClosable: true,
render: () => (
<ToastBox
status={"success"}
message={response?.data?.message}
/>
),
});
}
})
@@ -208,7 +217,7 @@ const BlogsAndArticles = () => {
w={220}
>
{item?.tags?.map(({ id, tag }) => (
<Badge key={id} variant='solid' colorScheme="teal" size={"sm"}>
<Badge key={id} variant="solid" colorScheme="teal" size={"sm"}>
{tag}
</Badge>
))}
@@ -257,79 +266,32 @@ const BlogsAndArticles = () => {
});
return (
<Box
{...OPACITY_ON_LOAD}
overflowY={"scroll"}
paddingBottom={50}
height={"100vh"}
>
{/* ====================================================[ Top bar ]================================================================ */}
{/* <Divider /> */}
<Header
title={"Blog"}
btnTitle={"Create blog"}
link={"/blogs-articles/add-blog"}
/>
<Box pt={4} bg="white.500">
{/* <HStack>
<Text color={"teal.800"} className="web-text-large fw-bold">
Blogs
</Text>
</HStack> */}
<HStack
display={"flex"}
justifyContent={"space-between"}
ps={1}
pe={1}
pb={4}
spacing="24px"
>
<Input
type="search"
width={300}
rounded="sm"
placeholder="Search..."
size="sm"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
<HStack>
<Select
className="pointer"
width={300}
rounded="sm"
size="sm"
value={statusFilter}
onChange={(e) => setStatusFilter(e.target.value)}
>
<option value="all">All</option>
<option value="active">Active</option>
<option value="inactive">Inactive</option>
</Select>
</HStack>
</HStack>
</Box>
{/* ====================================================[ Table ]================================================================ */}
<DataTable
emptyMessage={"We don't have any blog for this author"}
<>
<TabularView
title={"Videos"}
btnTitle={"Create videos"}
link={"/videos/add-videos"}
apiData={blog}
tableHeadRow={tableHeadRow}
data={extractedArray}
isLoading={blog?.isLoading}
extractedArray={extractedArray}
searchTerm={searchTerm}
setSearchTerm={setSearchTerm}
statusFilter={statusFilter}
setStatusFilter={setStatusFilter}
pageSize={pageSize}
setPageSize={setPageSize}
currentPage={currentPage}
setCurrentPage={setCurrentPage}
totalPages={blog?.data?.data?.totalItems}
/>
{/* ====================================================[ Alert ]================================================================ */}
<CustomAlertDialog
onClose={() => setDeleteAlert(false)}
isOpen={deleteAlert}
alertHandler={() => handleDelete(actionId)}
message={"Are you sure you want to delete member?"}
message={"Are you sure you want to delete video?"}
isLoading={deleteIsLoading}
/>
</Box>
</>
);
};

View File

@@ -134,9 +134,9 @@ const EditBlogsAndArticles = () => {
if (response?.data?.statusCode === 201) {
setIsLoading01(false);
toast({
title: response?.data?.message,
status: "success",
isClosable: true,
render: () => (
<ToastBox status={"success"} message={response?.data?.message} />
),
});
reset();
navigate("/blogs-articles");

View File

@@ -30,6 +30,7 @@ import {
import { useNavigate } from "react-router-dom";
import Loader01 from "../../Components/Loaders/Loader01";
import Header from "../../Components/Header";
import { CloseIcon } from "@chakra-ui/icons";
const AddComunity = () => {
const toast = useToast();
@@ -38,6 +39,7 @@ const AddComunity = () => {
const [createCommunityData] = useCreateCommunityMutation(); // Invoke the hook to get the mutation function
const [isLoading, setIsLoading] = useState(false);
const [selectedImage, setSelectedImage] = useState(fallbackImage);
const [imageData, setImageData] = useState(null);
const {
register,
@@ -69,9 +71,9 @@ const AddComunity = () => {
if (response?.data?.statusCode === 200) {
setIsLoading(false);
toast({
title: response?.data?.message,
status: "success",
isClosable: true,
render: () => (
<ToastBox status={"success"} message={response?.data?.message} />
),
});
reset();
navigate("/community");
@@ -91,6 +93,7 @@ const AddComunity = () => {
const handleImageChange = (e) => {
const file = e.target.files[0];
setImageData(file);
if (file) {
const reader = new FileReader();
reader.onloadend = () => {
@@ -129,7 +132,10 @@ const AddComunity = () => {
Below is the profile that will be displayed on the community page.
</span>
<Box boxSize="sm" className="d-flex justify-content-center">
<Box
boxSize="sm"
className="d-flex w-100 justify-content-center flex-column align-items-center gap-3"
>
<Image
shadow={"md"}
rounded={8}
@@ -138,6 +144,20 @@ const AddComunity = () => {
src={selectedImage}
alt="Selected Image"
/>
{selectedImage === fallbackImage || imageData === null ? (
""
) : (
<Box w={"100%"} display={"flex"} justifyContent={'space-between'} >
<Box display={"flex"} flexDirection={"column"}>
<span className="web-text-small">{imageData?.name}</span>
<span className="web-text-small text-secondary fst-italic">
{(imageData?.size / (1024 * 1024)).toFixed(2)} mb
</span>
</Box>
<Box onClick={()=> setSelectedImage(fallbackImage)} className=" web-text-large link rounded-2 pointer p-1" as="span" >
<CloseIcon className="web-text-small" /></Box>
</Box>
)}
</Box>
</Box>

View File

@@ -55,6 +55,7 @@ import CommunityCardDisplay from "./CommunityCardDisplay";
import CommunityBannerCard from "./CommunityBannerCard";
import Header from "../../Components/Header";
import { TABLE_PAGINATION } from "../../Constants/Paginations";
import ToastBox from "../../Components/ToastBox";
const Community = () => {
// ====================================================[Hooks]===================================================================
@@ -71,11 +72,16 @@ const Community = () => {
const [pageSize, setPageSize] = useState(TABLE_PAGINATION?.size);
const [currentPage, setCurrentPage] = useState(1);
const [displayRange, setDisplayRange] = useState({ start: TABLE_PAGINATION?.page, end: pageSize });
const community = useGetCommunityQuery({ page: currentPage, size: pageSize });
const [deleteCommunity] = useDeleteCommunityMutation();
const [updateCommunityStatus] = useUpdateCommunityStatusMutation();
@@ -114,9 +120,9 @@ const Community = () => {
if (response?.data?.statusCode === 201) {
console.log("toasted");
toast({
title: response?.data?.message,
status: "success",
isClosable: true,
render: () => (
<ToastBox status={"success"} message={response?.data?.message} />
),
});
}
})

View File

@@ -10,6 +10,7 @@ import { HiDotsVertical } from 'react-icons/hi';
import { Link as RouterLink } from "react-router-dom";
import { formatDate } from '../../Components/Functions/UTCConvertor';
import CustomAlertDialog from '../../Components/CustomAlertDialog';
import ToastBox from '../../Components/ToastBox';
const Events = () => {
// ====================================================[Hooks]===================================================================
@@ -38,13 +39,15 @@ const Events = () => {
setDeleteIsLoading(true);
await deleteEvents(id)
.then((response) => {
// Handle the response here
console.log("Mutation response:", response?.data?.statusCode);
console.log("Mutation response:", response?.data?.message);
if (response?.data?.statusCode === 201) {
setDeleteIsLoading(false);
setDeleteAlert(false);
toast({
render: () => (
<ToastBox status={"success"} message={response?.data?.message} />
),
});
}
})
.catch((error) => {
@@ -59,8 +62,6 @@ const Events = () => {
};
const handleUpdateStatus = async (id) => {
console.log(id);
try {
// Trigger the mutation
@@ -68,11 +69,10 @@ const Events = () => {
.then((response) => {
console.log(response?.data);
if (response?.data?.statusCode === 201) {
console.log("toasted");
toast({
title: response?.data?.message,
status: "success",
isClosable: true,
render: () => (
<ToastBox status={"success"} message={response?.data?.message} />
),
});
}
})
@@ -103,6 +103,7 @@ const Events = () => {
updateDisplayRange(currentPage + 1);
}
};
const updateDisplayRange = (page) => {
const start = (page - 1) * pageSize + 1;
const end = Math.min(start + pageSize - 1, events?.data?.data?.totalItems);
@@ -192,10 +193,6 @@ const Events = () => {
};
})
return (
<Box
{...OPACITY_ON_LOAD}

View File

@@ -43,6 +43,11 @@ const AddNews = () => {
const [createNews] = useCreateNewsMutation(); // Invoke the hook to get the mutation function
const [isLoading, setIsLoading] = useState(false);
const [selectedImage, setSelectedImage] = useState(fallbackImage);
const [ imageData, setImageData ] = useState(null)
const {
register,
@@ -75,18 +80,18 @@ const AddNews = () => {
if (response?.data?.statusCode === 200) {
setIsLoading(false);
toast({
title: response?.data?.message,
status: "success",
isClosable: true,
render: () => (
<ToastBox status={"success"} message={response?.data?.message} />
),
});
reset();
navigate("/news");
} else if (response?.data?.statusCode === 500) {
setIsLoading(false);
toast({
title: response?.data?.message,
status: "success",
isClosable: true,
render: () => (
<ToastBox status={"success"} message={response?.data?.message} />
),
});
}
})
@@ -105,6 +110,7 @@ const AddNews = () => {
const handleImageChange = (e) => {
const file = e.target.files[0];
setImageData(file);
if (file) {
const reader = new FileReader();
reader.onloadend = () => {
@@ -155,6 +161,16 @@ const AddNews = () => {
src={selectedImage}
alt="Selected Image"
/>
{selectedImage === fallbackImage || imageData === null ? (
""
) : (
<Box display={"flex"} flexDirection={"column"} w={"100%"}>
<span className="web-text-small">{imageData?.name}</span>
<span className="web-text-small text-secondary fst-italic">
{(imageData?.size / (1024 * 1024)).toFixed(2)} mb
</span>
</Box>
)}
<Button
onClick={() => setSelectedImage(fallbackImage)}
backgroundColor="red.400"
@@ -362,6 +378,8 @@ const AddNews = () => {
</Box>
</form>
</Box>
</Box>
);
};

View File

@@ -28,6 +28,8 @@ import { formatDate } from "../../Components/Functions/UTCConvertor";
import CustomAlertDialog from "../../Components/CustomAlertDialog";
import Header from "../../Components/Header";
import { TABLE_PAGINATION } from "../../Constants/Paginations";
import TabularView from "../../Components/TabularView/TabularView";
import ToastBox from "../../Components/ToastBox";
const News = () => {
// ====================================================[Hooks]===================================================================
@@ -40,7 +42,10 @@ const News = () => {
const [statusFilter, setStatusFilter] = useState("all");
const [pageSize, setPageSize] = useState(TABLE_PAGINATION?.size);
const [currentPage, setCurrentPage] = useState(TABLE_PAGINATION?.page);
const [displayRange, setDisplayRange] = useState({ start: TABLE_PAGINATION?.page, end: pageSize });
const [displayRange, setDisplayRange] = useState({
start: TABLE_PAGINATION?.page,
end: pageSize,
});
// ====================================================[RTK Hooks]===================================================================
const news = useGetNewsQuery({ page: currentPage, size: pageSize });
const [deleteNews] = useDeleteNewsMutation();
@@ -72,8 +77,6 @@ const News = () => {
}
};
const handleUpdateStatus = async (id) => {
try {
// Trigger the mutation
@@ -81,11 +84,13 @@ const News = () => {
.then((response) => {
console.log(response?.data);
if (response?.data?.statusCode === 201) {
console.log("toasted");
toast({
title: response?.data?.message,
status: "success",
isClosable: true,
render: () => (
<ToastBox
status={"success"}
message={response?.data?.message}
/>
),
});
}
})
@@ -226,96 +231,32 @@ const News = () => {
};
return (
<Box
{...OPACITY_ON_LOAD}
overflowY={"scroll"}
overflowX={"hidden"}
paddingBottom={50}
height={"100vh"}
>
{/* ====================================================[ Top bar ]================================================================ */}
<Header title={"News"} btnTitle={"Create news"} link={"/news/add-news"} />
<Box pt={4}>
<HStack
display={"flex"}
justifyContent={"space-between"}
ps={1}
pe={1}
pb={4}
spacing="24px"
>
<Input
type="search"
width={300}
rounded="sm"
placeholder="Search..."
size="sm"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
<HStack>
<Select
className="pointer web-text-small"
width={"90px"}
rounded="sm"
size="sm"
value={statusFilter}
onChange={(e) => setStatusFilter(e.target.value)}
>
<option value="all">All</option>
<option value="active">Active</option>
<option value="inactive">Inactive</option>
</Select>
<Select
className="pointer web-text-small"
width={"90px"}
rounded="sm"
size="sm"
value={pageSize}
onChange={(e) => setPageSize(e.target.value)}
>
<option value={pageSize}>{pageSize} rows</option>
{/* <option value={20}>20 rows</option>
<option value={30}>30 rows</option> */}
</Select>
<HStack>
<ChevronLeftIcon
onClick={paginationPrev}
className=" link rounded-3 pointer"
/>
<Text className="web-text-medium" as={"span"}>
{displayRange.start} - {displayRange.end} of{" "}
{news?.data?.data?.totalItems}
</Text>
<ChevronRightIcon
onClick={paginationNext}
className=" link rounded-3 pointer"
/>
</HStack>
</HStack>
</HStack>
</Box>
{/* ====================================================[ Table ]================================================================ */}
<DataTable
emptyMessage={"We don't have any blog for this author"}
<>
<TabularView
title={"Videos"}
btnTitle={"Create videos"}
link={"/news/add-news"}
apiData={news}
tableHeadRow={tableHeadRow}
data={extractedArray}
isLoading={news?.isLoading}
extractedArray={extractedArray}
searchTerm={searchTerm}
setSearchTerm={setSearchTerm}
statusFilter={statusFilter}
setStatusFilter={setStatusFilter}
pageSize={pageSize}
setPageSize={setPageSize}
currentPage={currentPage}
setCurrentPage={setCurrentPage}
totalPages={news?.data?.data?.totalPages}
/>
{/* ====================================================[ Alert ]================================================================ */}
<CustomAlertDialog
onClose={() => setDeleteAlert(false)}
isOpen={deleteAlert}
alertHandler={() => handleDelete(actionId)}
message={"Are you sure you want to delete member?"}
message={"Are you sure you want to delete video?"}
isLoading={deleteIsLoading}
/>
</Box>
</>
);
};

View File

@@ -15,11 +15,9 @@ const ViewNews = () => {
const toast = useToast();
const navigate = useNavigate();
const { data, error, isLoading } = useGetNewsByIdQuery(id);
console.log(isLoading);
// const { data, error, isLoading } = useGetNewsQuery();
const news = data?.data;
console.log(data);
if (isLoading) {
return <FullscreenLoaders />;
}
@@ -69,18 +67,6 @@ const ViewNews = () => {
src={`https://rubix.betadelivery.com/${news?.banner_image}`}
alt="Selected Image"
/>
{/* <Button
onClick={() => setSelectedImage(fallbackImage)}
backgroundColor="red.400"
color={"whitesmoke"}
transition={"0.5s"}
_hover={{
backgroundColor: "red.500",
}}
size="xs"
>
Remove
</Button> */}
</Box>
</Box>

View File

@@ -1,19 +1,263 @@
import { Box } from '@chakra-ui/react'
import { OPACITY_ON_LOAD } from '../Layout/animations'
import {
Box,
HStack,
Image,
Input,
Menu,
MenuButton,
MenuItem,
MenuList,
Portal,
Select,
Switch,
Text,
Tooltip,
useToast,
} from "@chakra-ui/react";
import { TABLE_PAGINATION } from "../Constants/Paginations";
import {
useDeleteVideosMutation,
useGetVideosQuery,
useUpdateVideosStatusMutation,
} from "../Services/api.service";
import { useState } from "react";
import Header from "../Components/Header";
import { ChevronLeftIcon, ChevronRightIcon } from "@chakra-ui/icons";
import DataTable from "../Components/DataTable/DataTable";
import TabularView from "../Components/TabularView/TabularView";
import { HiDotsVertical } from "react-icons/hi";
import { Link } from "react-router-dom";
import { formatDate } from "../Components/Functions/UTCConvertor";
import CustomAlertDialog from "../Components/CustomAlertDialog";
import ToastBox from "../Components/ToastBox";
const Videos = () => {
return (
<Box
display={"flex"}
justifyContent={"center"}
alignItems={"center"}
height={"100vh"}
backgroundColor={"teal"}
color={"whitesmoke"}
{...OPACITY_ON_LOAD}
>Videos</Box>
)
}
const toast = useToast();
const [pageSize, setPageSize] = useState(TABLE_PAGINATION?.size);
const [currentPage, setCurrentPage] = useState(1);
const [searchTerm, setSearchTerm] = useState("");
const [statusFilter, setStatusFilter] = useState("all");
export default Videos
const [deleteAlert, setDeleteAlert] = useState(false);
const [actionId, setActionId] = useState(null);
const [deleteIsLoading, setDeleteIsLoading] = useState(false);
const videos = useGetVideosQuery({ page: currentPage, size: pageSize });
const [deleteVideos] = useDeleteVideosMutation();
const [updateVideoStatus] = useUpdateVideosStatusMutation();
const filteredData = videos?.data?.data?.data?.rows?.filter((item) => {
// Filter by name (case insensitive)
const name = item.title;
const searchLower = searchTerm.toLowerCase();
const nameMatches = name.toLowerCase().includes(searchLower);
// Filter by status
const status = item.status;
const statusMatches =
statusFilter === "all" ||
(statusFilter === "active" && status === true) ||
(statusFilter === "inactive" && status === false);
return nameMatches && statusMatches;
});
// ====================================================[Table Setup]================================================================
const tableHeadRow = [
"Thumbnail",
"Title",
"Discription",
"Duration",
"Active",
"Created At",
];
const extractedArray = filteredData?.map((item, index) => {
return {
Thumbnail: (
<Image
w={150}
h={14}
rounded={4}
objectFit="cover"
src={`https://rubix.betadelivery.com/${item.thumbnail}`}
alt="Dan Abramov"
/>
),
Title: (
<Text as={"span"} isTruncated={true}>
{item?.title}
</Text>
),
Discription: (
<Tooltip
className="rounded-2 web-text-xsmall"
width={"fit-content"}
placement="top"
hasArrow
label={item?.description}
bg="blue.200"
>
<Box display={"flex"} alignItems={"center"} w={180}>
<Text as={"span"} isTruncated={true}>
{item?.description}
</Text>
</Box>
</Tooltip>
),
Duration: (
<Text as={"span"} isTruncated={true}>
{item?.duration} min
</Text>
),
Active: (
<Switch
size={"sm"}
colorScheme="teal"
onChange={() => handleUpdateStatus(item.id, item?.status)}
isChecked={item.status}
// disabled={item.status}
/>
),
"Created At": (
<span className="d-flex justify-content-between align-items-center">
<Text as={"span"} color={"teal.600"} className=" fw-bold">
{formatDate(item?.createdAt)}
</Text>
<Menu>
<MenuButton className="link p-1 rounded-1">
<HiDotsVertical className="rubix-text-dark fs-6" />
</MenuButton>
<Portal>
<MenuList minWidth="80px">
<Link to={`/banner/banner-community/edit/${item.id}`}>
<MenuItem className="web-text-medium">Edit</MenuItem>
</Link>
<Link to={`/banner/banner-community/view/${item.id}`}>
<MenuItem className="web-text-medium">View</MenuItem>
</Link>
<MenuItem
onClick={() => {
setActionId(item.id);
setDeleteAlert(true);
}}
className="web-text-medium"
>
Delete
</MenuItem>
</MenuList>
</Portal>
</Menu>
</span>
),
};
});
// ====================================================[Functions]===================================================================
const handleDelete = async (communityId) => {
try {
// Trigger the mutation
setDeleteIsLoading(true);
await deleteVideos(communityId)
.then((response) => {
// Handle the response here
console.log("Mutation response:", response?.data?.statusCode);
console.log("Mutation response:", response?.data?.message);
if (response?.data?.statusCode === 201) {
setDeleteIsLoading(false);
setDeleteAlert(false);
toast({
render: () => (
<ToastBox
status={"success"}
message={response?.data?.message}
/>
),
});
}
})
.catch((error) => {
console.error("Error creating community:", error);
setDeleteIsLoading(false);
setDeleteAlert(false);
});
} catch (error) {
// Handle errors
console.log("Error deleting community:", error);
}
};
const handleUpdateStatus = async (id) => {
try {
// Trigger the mutation
await updateVideoStatus({ id })
.then((response) => {
if (response?.data?.statusCode === 201) {
toast({
render: () => (
<ToastBox
status={"success"}
message={response?.data?.message}
/>
),
});
}
})
.catch((error) => {
console.log(error);
});
} catch (error) {
// Handle errors
console.error("Error updating community status:", error);
}
};
return (
<>
<TabularView
title={"Videos"}
btnTitle={"Create videos"}
link={"/videos/add-videos"}
apiData={videos}
tableHeadRow={tableHeadRow}
extractedArray={extractedArray}
searchTerm={searchTerm}
setSearchTerm={setSearchTerm}
statusFilter={statusFilter}
setStatusFilter={setStatusFilter}
pageSize={pageSize}
setPageSize={setPageSize}
currentPage={currentPage}
setCurrentPage={setCurrentPage}
totalPages={videos?.data?.data?.data?.totalPages}
/>
<CustomAlertDialog
onClose={() => setDeleteAlert(false)}
isOpen={deleteAlert}
alertHandler={() => handleDelete(actionId)}
message={"Are you sure you want to delete video?"}
isLoading={deleteIsLoading}
/>
</>
);
};
export default Videos;
// Event & Community Pending

View File

@@ -1,18 +0,0 @@
import { Box } from '@chakra-ui/react'
import { OPACITY_ON_LOAD } from '../Layout/animations'
const Whitepapers = () => {
return (
<Box
display={"flex"}
justifyContent={"center"}
alignItems={"center"}
height={"100vh"}
backgroundColor={"teal"}
color={"whitesmoke"}
{...OPACITY_ON_LOAD}
>Whitepapers</Box>
)
}
export default Whitepapers

View File

@@ -0,0 +1,330 @@
import { Box, Button, Divider, FormControl, FormHelperText, FormLabel, Heading, Image, Input, Stack, useToast } from '@chakra-ui/react'
import React, { useState } from 'react'
import { OPACITY_ON_LOAD } from '../../Layout/animations'
import Header from '../../Components/Header'
import { useNavigate } from 'react-router-dom'
import fallbackImage from "../../assets/ultp-fallback-img.webp";
import { addWhitePapers } from '../../Validations/Validations'
import { TiWarning } from 'react-icons/ti'
import { yupResolver } from "@hookform/resolvers/yup";
import { useForm } from "react-hook-form";
import { motion } from 'framer-motion'
import Loader01 from '../../Components/Loaders/Loader01'
import { useCreateWhitepaperMutation } from '../../Services/api.service'
import ToastBox from '../../Components/ToastBox'
const AddWhitepapers = () => {
const toast = useToast();
const navigate = useNavigate();
const [isLoading, setIsLoading] = useState(false);
const [selectedImage, setSelectedImage] = useState(fallbackImage);
const [ imageData, setImageData ] = useState(null)
const [createWhitepaper] = useCreateWhitepaperMutation();
const {
register,
handleSubmit,
reset,
formState: { errors },
} = useForm({
resolver: yupResolver(addWhitePapers),
});
const handleImageChange = (e) => {
const file = e.target.files[0];
setImageData(file);
if (file) {
const reader = new FileReader();
reader.onloadend = () => {
setSelectedImage(reader.result);
};
reader.readAsDataURL(file);
}
};
const onSubmit = async (data) => {
try {
setIsLoading(true);
const formData = new FormData();
formData.append("title", data.title);
if (data.image[0]) {
formData.append("image", data.image[0]);
}
if (data.document[0]) {
formData.append("document", data.document[0]);
}
// Trigger the mutation
createWhitepaper(formData)
.then((response) => {
// Handle the response here
if (response?.data?.statusCode === 201) {
setIsLoading(false);
toast({
render: () => (
<ToastBox status={"success"} message={response?.data?.message} />
),
});
reset();
navigate("/whitepaper");
} else if (response?.data?.statusCode === 500) {
setIsLoading(false);
toast({
render: () => (
<ToastBox status={"success"} message={response?.data?.message} />
),
});
}
})
.catch((error) => {
// Handle errors
console.error("Error creating community:", error);
setIsLoading(false);
// Handle error notification if needed
});
} catch (error) {
// Handle errors
console.error("Error creating community:", error);
setIsLoading(false);
}
};
return (
<Box
{...OPACITY_ON_LOAD}
w={"100%"}
h={"100vh"}
className="overflow-auto "
display={"flex"}
flexDirection={"column"}
>
<Header title={"WhitePaper"} />
<Box className="d-flex">
<Box className="col-5 d-flex flex-column gap-2 pt-4">
<span className="web-text-large fw-bold rubix-text-dark">
Whitepaper Info
</span>
<span className="web-text-medium text-secondary">
Select the platform for which you need to create this campaign.
</span>
<Divider />
<span className="web-text-large fw-bold rubix-text-dark">
Whitepaper banner image
</span>
<span className="web-text-medium text-secondary mb-4">
Below is the whitepaper banner image that will be whitepaper on the community page.
</span>
<Box
boxSize="sm"
className="d-flex w-100 justify-content-center flex-column align-items-center gap-3"
>
<Image
shadow={"md"}
rounded={8}
w={500}
h={240}
src={selectedImage}
alt="Selected Image"
/>
{selectedImage === fallbackImage || imageData === null ? (
""
) : (
<Box display={"flex"} flexDirection={"column"} w={"100%"}>
<span className="web-text-small">{imageData?.name}</span>
<span className="web-text-small text-secondary fst-italic">
{(imageData?.size / (1024 * 1024)).toFixed(2)} mb
</span>
</Box>
)}
<Button
onClick={() => setSelectedImage(fallbackImage)}
backgroundColor="red.400"
color={"whitesmoke"}
transition={"0.5s"}
_hover={{
backgroundColor: "red.500",
}}
size="xs"
>
Remove
</Button>
</Box>
</Box>
<form
onSubmit={handleSubmit(onSubmit)}
className="col-7 pt-4 mb-3 overflow-auto p-4"
>
<FormControl isRequired className="mb-3">
<FormLabel className="web-text-large fw-bold rubix-text-dark">
Title
</FormLabel>
<Input
{...register("title")}
placeholder="Title"
className="web-text-medium"
size="sm"
/>
{errors.title && (
<span className="text-danger web-text-small fw-bold ps-2 d-flex align-items-center gap-1 mt-1">
<TiWarning className="fw-bold fs-5 " /> {errors.title.message}
</span>
)}
</FormControl>
<FormControl isRequired className="mb-3">
<FormLabel className="web-text-large fw-bold rubix-text-dark">
Document
</FormLabel>
<input
type='file'
{...register("document")}
className="web-text-medium form-control rounded-1"
size="sm"
/>
{errors.document && (
<span className="text-danger web-text-small fw-bold ps-2 d-flex align-items-center gap-1 mt-1">
<TiWarning className="fw-bold fs-5 " /> {errors.document.message}
</span>
)}
</FormControl>
<FormControl isRequired className="mb-3">
<FormLabel className="web-text-large fw-bold rubix-text-dark">
Banner image
</FormLabel>
{/* <ImageDropBox /> */}
<Box
borderColor="gray.300"
borderStyle="dashed"
borderWidth="2px"
rounded="md"
shadow="sm"
role="group"
transition="all 150ms ease-in-out"
_hover={{
shadow: "md",
}}
as={motion.div}
initial="rest"
animate="rest"
whileHover="hover"
height={"105px"}
className="pointer"
>
<Box position="relative" height="100%" width="100%">
<Box
position="absolute"
top="0"
left="0"
height="100%"
width="100%"
display="flex"
flexDirection="column"
>
<Stack
height="100%"
width="100%"
display="flex"
alignItems="center"
justify="center"
>
<span
className="d-flex flex-column align-items-center pointer"
spacing="1"
>
<Heading
fontSize="lg"
color="gray.700"
fontWeight="bold"
cursor={"pointer"}
>
Drop images here
</Heading>
<span
fontWeight="light"
className="web-text-large text-secondary text-center pointer"
>
or click to upload
</span>
</span>
</Stack>
</Box>
<Input
{...register("image")}
type="file"
height="100%"
width="100%"
position="absolute"
top="0"
left="0"
opacity="0"
aria-hidden="true"
accept="image/*"
onChange={handleImageChange}
onDrop={handleImageChange}
// onDragEnter={startAnimation}
// onDragLeave={stopAnimation}
/>
</Box>
</Box>
{errors.image && (
<span className="text-danger web-text-small fw-bold ps-2 d-flex align-items-center gap-1 mt-1">
<TiWarning className="fw-bold fs-5 " />{" "}
{errors.image.message}
</span>
)}
<FormHelperText className="web-text-small">
Maximum limit of image is 5mb.
</FormHelperText>
</FormControl>
<Box className=" d-flex justify-content-end mb-5">
<Button
isLoading={isLoading}
spinner={<Loader01 />}
color={"whitesmoke"}
backgroundColor={"purple.700"}
_hover={{
backgroundColor: "purple.800",
}}
type="submit"
rounded={'sm'}
size="sm"
>
Create
</Button>
</Box>
</form>
</Box>
</Box>
)
}
export default AddWhitepapers

View File

@@ -0,0 +1,9 @@
import React from 'react'
const EditWhitepaper = () => {
return (
<div>EditWhitepaper</div>
)
}
export default EditWhitepaper

View File

@@ -0,0 +1,108 @@
import React from "react";
import { OPACITY_ON_LOAD } from "../../Layout/animations";
import { Box, Divider, Image, Tag, Text, useToast } from "@chakra-ui/react";
import { useNavigate, useParams } from "react-router-dom";
import Header from "../../Components/Header";
import { useGetWhitepaperByIdQuery } from "../../Services/api.service";
import { AttachmentIcon } from "@chakra-ui/icons";
import extractFilename from "../../Components/Functions/FileNameAlter";
import FullscreenLoaders from "../../Components/Loaders/FullscreenLoaders";
const ViewWhitePaper = () => {
const { id } = useParams();
const toast = useToast();
const navigate = useNavigate();
const { data, error, isLoading } = useGetWhitepaperByIdQuery(id);
const whitepaper = data?.data?.data;
console.log(whitepaper?.document);
if (isLoading) {
return <FullscreenLoaders />;
}
return (
<Box
{...OPACITY_ON_LOAD}
w={"100%"}
h={"100vh"}
className="overflow-auto "
display={"flex"}
flexDirection={"column"}
>
<Header title={"Whitepaper"} btnTitle={"Edit whitepaper"} link={`/whitepaper/edit/${id}`} />
<Box display={"flex"}>
<Box className="col-5 d-flex flex-column gap-2 pt-4">
<span className="web-text-large fw-bold rubix-text-dark">
Whitepaper Info
</span>
<span className="web-text-medium text-secondary">
Select the platform for which you need to create this campaign.
</span>
<Divider />
<span className="web-text-large fw-bold rubix-text-dark">
Whitepaper banner image
</span>
<span className="web-text-medium text-secondary mb-4">
Below is the profile that will be displayed on the community page.
</span>
<Box
boxSize="sm"
className="d-flex h-auto w-100 justify-content-start flex-column align-items-center gap-3"
>
<Image
shadow={"md"}
rounded={8}
objectFit="cover"
w={500}
h={240}
src={`https://rubix.betadelivery.com/${whitepaper?.bannerImage}`}
alt="Selected Image"
/>
</Box>
</Box>
<Box className="col-7 pt-4 p-4">
<Box>
<Box className="web-text-large fw-bold mb-1 rubix-text-dark">
Status
</Box>
{whitepaper?.status ? (
<Tag size={"sm"} borderRadius="full" colorScheme="teal">
Active
</Tag>
) : (
<Tag size={"sm"} borderRadius="full" colorScheme="red">
Inactive
</Tag>
)}
</Box>
<Box className="mb-3">
<Box className="web-text-large fw-bold rubix-text-dark">Title</Box>
<Box className="web-text-medium text-secondary">{whitepaper?.title}</Box>
</Box>
<Box className="mb-3">
<Box className="web-text-large fw-bold rubix-text-dark">Document</Box>
<Text color="teal" className="web-text-medium d-flex align-items-center gap-2">{extractFilename(whitepaper?.document)}
<Box className="link pointer" as="span" rounded={"md"} p={1}><AttachmentIcon/></Box></Text>
</Box>
<Divider/>
</Box>
</Box>
</Box>
);
};
export default ViewWhitePaper;

View File

@@ -0,0 +1,262 @@
import {
Box,
Image,
Menu,
MenuButton,
MenuItem,
MenuList,
Portal,
Switch,
Text,
Tooltip,
useToast,
} from "@chakra-ui/react";
import { OPACITY_ON_LOAD } from "../../Layout/animations";
import { TABLE_PAGINATION } from "../../Constants/Paginations";
import {
useDeleteWhitepaperMutation,
useGetWhitePaperQuery,
useUpdateWhitepaperStatusMutation,
} from "../../Services/api.service";
import { useState } from "react";
import TabularView from "../../Components/TabularView/TabularView";
import CustomAlertDialog from "../../Components/CustomAlertDialog";
import { HiDotsVertical } from "react-icons/hi";
import { Link } from "react-router-dom";
import { formatDate } from "../../Components/Functions/UTCConvertor";
import ToastBox from "../../Components/ToastBox";
import extractFilename from "../../Components/Functions/FileNameAlter";
const Whitepapers = () => {
const toast = useToast();
const [pageSize, setPageSize] = useState(TABLE_PAGINATION?.size);
const [currentPage, setCurrentPage] = useState(1);
const [searchTerm, setSearchTerm] = useState("");
const [statusFilter, setStatusFilter] = useState("all");
const [deleteAlert, setDeleteAlert] = useState(false);
const [actionId, setActionId] = useState(null);
const [actionStatus, setActionStatus] = useState(null);
const [deleteIsLoading, setDeleteIsLoading] = useState(false);
const whitePaper = useGetWhitePaperQuery({
page: currentPage,
size: pageSize,
});
const [deleteWhitepaper] = useDeleteWhitepaperMutation();
const [updateWhitepaperStatus] = useUpdateWhitepaperStatusMutation();
const filteredData = whitePaper?.data?.data?.data?.rows?.filter((item) => {
// Filter by name (case insensitive)
const name = item.title;
const searchLower = searchTerm.toLowerCase();
const nameMatches = name.toLowerCase().includes(searchLower);
// Filter by status
const status = item.status;
const statusMatches =
statusFilter === "all" ||
(statusFilter === "active" && status === true) ||
(statusFilter === "inactive" && status === false);
return nameMatches && statusMatches;
});
// ====================================================[Table Setup]================================================================
const tableHeadRow = [
"Banner image",
"Title",
"Document",
"Active",
"Created At",
];
const extractedArray = filteredData?.map((item, index) => {
return {
"Banner image": (
<Image
w={150}
h={14}
rounded={4}
objectFit="cover"
src={`https://rubix.betadelivery.com/${item.bannerImage}`}
alt="Dan Abramov"
/>
),
Title: (
<Text as={"span"} isTruncated={true}>
{item?.title}
</Text>
),
Document: (
<Tooltip
className="rounded-2 web-text-xsmall"
width={"fit-content"}
placement="top"
hasArrow
label={item?.document}
bg="blue.200"
>
<Box display={"flex"} alignItems={"center"} w={180}>
<Text as={"span"} isTruncated={true}>
{extractFilename(item?.document)}
</Text>
</Box>
</Tooltip>
),
Active: (
<Switch
size={"sm"}
colorScheme="teal"
onChange={() => handleUpdateStatus(item.id, item?.status)}
isChecked={item.status}
// disabled={item.status}
/>
),
"Created At": (
<span className="d-flex justify-content-between align-items-center">
<Text as={"span"} color={"teal.600"} className=" fw-bold">
{formatDate(item?.createdAt)}
</Text>
<Menu>
<MenuButton className="link p-1 rounded-1">
<HiDotsVertical className="rubix-text-dark fs-6" />
</MenuButton>
<Portal>
<MenuList minWidth="80px">
<Link to={`/whitepaper/edit/${item.id}`}>
<MenuItem className="web-text-medium">Edit</MenuItem>
</Link>
<Link to={`/whitepaper/view/${item.id}`}>
<MenuItem className="web-text-medium">View</MenuItem>
</Link>
<MenuItem
onClick={() => {
setActionId(item.id);
setDeleteAlert(true);
setActionStatus(item.status);
}}
className="web-text-medium"
>
Delete
</MenuItem>
</MenuList>
</Portal>
</Menu>
</span>
),
};
});
// ====================================================[Functions]===================================================================
const handleDelete = async (communityId, status) => {
if (status) {
return toast({
render: () => (
<ToastBox
status={"warn"}
message={"Can't delete whitepaper. Status is true."}
/>
),
});
}
try {
// Trigger the mutation
setDeleteIsLoading(true);
await deleteWhitepaper(communityId)
.then((response) => {
// Handle the response here
console.log("Mutation response:", response?.data?.statusCode);
console.log("Mutation response:", response?.data?.message);
if (response?.data?.statusCode === 201) {
setDeleteIsLoading(false);
setDeleteAlert(false);
toast({
render: () => (
<ToastBox
status={"success"}
message={response?.data?.message}
/>
),
});
}
})
.catch((error) => {
console.error("Error creating community:", error);
setDeleteIsLoading(false);
setDeleteAlert(false);
});
} catch (error) {
// Handle errors
console.log("Error deleting community:", error);
}
};
const handleUpdateStatus = async (id) => {
try {
await updateWhitepaperStatus({ id })
.then((response) => {
console.log(response?.data);
if (response?.data?.statusCode === 201) {
toast({
render: () => (
<ToastBox
status={"success"}
message={"Please toggle another banner."}
/>
),
});
// whitePaper?.refetch()
}
})
.catch((error) => {
console.log(error);
});
} catch (error) {
// Handle errors
console.error("Error updating community status:", error);
}
};
return (
<>
<TabularView
title={"Whitepaper"}
btnTitle={"Create whitepaper"}
link={"/whitepaper/add-whitepaper"}
apiData={whitePaper}
tableHeadRow={tableHeadRow}
extractedArray={extractedArray}
searchTerm={searchTerm}
setSearchTerm={setSearchTerm}
statusFilter={statusFilter}
setStatusFilter={setStatusFilter}
pageSize={pageSize}
setPageSize={setPageSize}
currentPage={currentPage}
setCurrentPage={setCurrentPage}
totalPages={whitePaper?.data?.data?.data?.totalPages}
/>
<CustomAlertDialog
onClose={() => setDeleteAlert(false)}
isOpen={deleteAlert}
alertHandler={() => handleDelete(actionId)}
message={"Are you sure you want to delete video?"}
isLoading={deleteIsLoading}
/>
</>
);
};
export default Whitepapers;

View File

@@ -7,7 +7,7 @@ import ComunityViewPage from "../Pages/Community/ComunityViewPage";
import Events from "../Pages/Events/Events";
import Home from "../Pages/Banners/Banner";
import Videos from "../Pages/Videos";
import Whitepapers from "../Pages/Whitepapers";
import Whitepapers from "../Pages/Whitepapers/Whitepapers";
import BannerCommunity from "../Pages/Banners/BannerCommunity/BannerCommunity";
import BannerComunityEditPage from "../Pages/Banners/BannerCommunity/BannerCommunityEdit";
import BannerComunityViewPage from "../Pages/Banners/BannerCommunity/BannerCommunityView";
@@ -19,24 +19,44 @@ import ViewNews from "../Pages/News/ViewNews";
import ViewBlogsAndArticles from "../Pages/BlogsAndArticles/ViewBlogsAndArticles";
import EditBlogsAndArticles from "../Pages/BlogsAndArticles/EditBlogsAndArticles";
import BannerLearn from "../Pages/Banners/BannerLearn/BannerLearn";
import AddLearnBanner from "../Pages/Banners/BannerLearn/LearnBannerAdd";
import HelpAndSupport from "../Pages/News/HelpAndSupport";
import AddEvents from "../Pages/Events/AddEvents";
import ViewLearnBanner from "../Pages/Events/ViewLearnBanner";
import ViewLearnBanner from "../Pages/Banners/BannerLearn/BannerLearnView";
import BannerBuildView from "../Pages/Banners/BannerBuild/BannerBuildView";
import BannersNews from "../Pages/Banners/BannersNew/BannersNews";
import BannerBuild from "../Pages/Banners/BannerBuild/BannerBuild";
import BannerNews from "../Pages/Banners/BannerNews/BannerNews";
import BannerCommunityAdd from "../Pages/Banners/BannerCommunity/BannerCommunityAdd";
import BuildBannerAdd from "../Pages/Banners/BannerBuild/BuildBannerAdd";
import NewsBannerAdd from "../Pages/Banners/BannersNew/NewsBannerAdd";
import BannerLearnAdd from "../Pages/Banners/BannerLearn/BannerLearnAdd";
import BannerLearnEdit from "../Pages/Banners/BannerLearn/BannerLearnEdit";
import BannerBuildAdd from "../Pages/Banners/BannerBuild/BannerBuildAdd";
import BannerBuildEdit from "../Pages/Banners/BannerBuild/BannerBuildEdit";
import BannerNewsEdit from "../Pages/Banners/BannerNews/BannerNewsEdit";
import BannerNewsView from "../Pages/Banners/BannerNews/BannerNewsView";
import HomeBanner from "../Pages/Banners/HomeBanner/HomeBanner";
import BannerNewsAdd from "../Pages/Banners/BannerNews/BannerNewsAdd";
import BannerHomeAdd from "../Pages/Banners/HomeBanner/HomeBannerAdd";
import HomeBannerView from "../Pages/Banners/HomeBanner/HomeBannerView";
import HomeBannerAdd from "../Pages/Banners/HomeBanner/HomeBannerAdd";
import HomeBannerEdit from "../Pages/Banners/HomeBanner/HomeBannerEdit";
import AddWhitepapers from "../Pages/Whitepapers/AddWhitepapers";
import ViewWhitePaper from "../Pages/Whitepapers/ViewWhitePaper";
import EditWhitepaper from "../Pages/Whitepapers/EditWhitepaper";
export const RouteLink = [
{ path: "/", Component: Home },
{ path: "/videos", Component: Videos },
{ path: "/whitepaper", Component: Whitepapers },
{ path: "/help-and-support", Component: HelpAndSupport },
{ path: "/whitepaper", Component: Whitepapers },
{ path: "whitepaper/add-whitepaper", Component: AddWhitepapers },
{ path: "whitepaper/view/:id", Component: ViewWhitePaper },
{ path: "whitepaper/edit/:id", Component: EditWhitepaper },
{ path: "/community", Component: Community },
{ path: "community/view/:id", Component: ComunityViewPage },
{ path: "community/edit/:id", Component: ComunityEditPage },
@@ -57,29 +77,28 @@ export const RouteLink = [
// =============[ learn banner ]================
{ path: "banner/learn", Component: BannerLearn },
{ path: "banner/learn/add-banner", Component: AddLearnBanner },
{ path: "banner/learn/add-banner", Component: BannerLearnAdd },
{ path: "banner/learn/view/:id", Component: ViewLearnBanner },
{ path: "banner/learn/edit/:id", Component: ViewLearnBanner },
{ path: "banner/learn/edit/:id", Component: BannerLearnEdit },
// =============[ build banner ]================
{ path: "banner/build", Component: BannerBuild },
{ path: "banner/build/add-banner", Component: BuildBannerAdd },
{ path: "banner/build/add-banner", Component: BannerBuildAdd },
{ path: "banner/build/view/:id", Component: BannerBuildView },
{ path: "banner/build/edit/:id", Component: BannerBuildView },
{ path: "banner/build/edit/:id", Component: BannerBuildEdit },
// =============[ news banner ]================
{ path: "banner/news", Component: BannerNews },
{ path: "banner/news/add-banner", Component: NewsBannerAdd },
{ path: "banner/news/view/:id", Component: BannersNews },
{ path: "banner/news/edit/:id", Component: BannersNews },
{ path: "banner/news/add-banner", Component: BannerNewsAdd },
{ path: "banner/news/view/:id", Component: BannerNewsView },
{ path: "banner/news/edit/:id", Component: BannerNewsEdit },
// =============[ home banner ]================
{ path: "banner/home", Component: BannerNews },
{ path: "banner/home/add-banner", Component: NewsBannerAdd },
{ path: "banner/home/view/:id", Component: BannersNews },
{ path: "banner/home/edit/:id", Component: BannersNews },
{ path: "banner/home", Component: HomeBanner },
{ path: "banner/home/add-banner", Component: HomeBannerAdd },
{ path: "banner/home/view/:id", Component: HomeBannerView },
{ path: "banner/home/edit/:id", Component: HomeBannerEdit },
// =============[ blog ]================
{ path: "/blogs-articles", Component: BlogsAndArticles },

View File

@@ -28,6 +28,11 @@ export const rubixApi = createApi({
"getEventsBannerById",
"getEventsBanner",
"getEventsBannerById",
"getVideos",
"getWhitePaper"
],
endpoints: (builder) => ({
// ===============[ Community cards endpoints ]=======================
@@ -327,6 +332,15 @@ export const rubixApi = createApi({
query: () => "/admin/home",
providesTags: ["getHomeBanner"],
}),
createHomeBanner: builder.mutation({
query: (newBanner) => ({
url: "/admin/home",
method: "POST",
body: newBanner,
}),
invalidatesTags: ["getHomeBanner"],
}),
getHomeBannerById: builder.query({
query: (id) => `/admin/home/${id}`,
providesTags: ["getHomeBannerById"],
@@ -345,6 +359,69 @@ export const rubixApi = createApi({
}),
invalidatesTags: ["getHomeBanner"],
}),
// ===============[ Videos endpoints ]=======================
getVideos: builder.query({
query: ({ page, size }) => `/admin/video?page=${page}&size=${size}`,
providesTags: ["getVideos"],
}),
updateVideosStatus: builder.mutation({
query: ({ id }) => ({
url: `/admin/video/change-visibility/${id}`,
method: "POST",
}),
invalidatesTags: ["getVideos"],
}),
deleteVideos: builder.mutation({
query: (id) => ({
url: `/admin/video/${id}`,
method: "DELETE",
}),
invalidatesTags: ["getVideos"],
}),
// ===============[ White paper endpoints ]=======================
getWhitePaper: builder.query({
query: ({ page, size }) => `/admin/whitepaper?page=${page}&size=${size}`,
providesTags: ["getWhitePaper"],
}),
updateWhitepaperStatus: builder.mutation({
query: ({ id }) => ({
url: `/admin/whitepaper/change-visibility/${id}`,
method: "POST",
}),
invalidatesTags: ["getWhitePaper"],
}),
deleteWhitepaper: builder.mutation({
query: (id) => ({
url: `/admin/whitepaper/${id}`,
method: "DELETE",
}),
invalidatesTags: ["getWhitePaper"],
}),
createWhitepaper: builder.mutation({
query: (newBanner) => ({
url: "/admin/whitepaper",
method: "POST",
body: newBanner,
}),
invalidatesTags: ["getWhitePaper"],
}),
getWhitepaperById: builder.query({
query: (id) => `/admin/whitepaper/${id}`,
providesTags: ["getWhitePaper"],
}),
}),
});
@@ -396,8 +473,29 @@ export const {
useGetNewsByIdQuery,
useUpdateNewsMutation,
useGetHomeBannerQuery,
useCreateHomeBannerMutation,
useDeleteHomeBannerMutation,
useUpdateHomeBannerStatusMutation,
useGetHomeBannerByIdQuery,
useGetEventsQuery,
useCreateEventsMutation,
useUpdateEventsStatusMutation,
useDeleteEventsMutation,
useGetVideosQuery,
useDeleteVideosMutation,
useUpdateVideosStatusMutation,
useGetWhitePaperQuery,
useUpdateWhitepaperStatusMutation,
useDeleteWhitepaperMutation,
useCreateWhitepaperMutation,
useGetWhitepaperByIdQuery,
} = rubixApi;

View File

@@ -10,7 +10,28 @@ export const addCommunitySchema = Yup.object().shape({
designation: Yup.string().required("Designation is required"),
description: Yup.string().required("Description is required"),
linkedin: Yup.string().required("Linked In link is required"),
profile_image: Yup.mixed().required("Display picture is required"),
profile_image: Yup.mixed()
.test("required", "You need to provide a file", (files) => {
// return file && file.size <-- u can use this if you don't want to allow empty files to be uploaded;
if (files) return true;
return false;
})
.test(
"fileSize",
" The maximum size of profile picture is 15MB.",
(files) => {
//if u want to allow only certain file sizes
try {
if (files.length !== 0) {
return files[0].size <= 15000000;
}
return true;
} catch (error) {
return false;
}
}
)
.optional(),
});
export const schemaEdit = Yup.object().shape({
@@ -25,7 +46,28 @@ export const addCommunityBannerSchema = Yup.object().shape({
sub_heading: Yup.string().required("Designation is required"),
CTO_button_title: Yup.string().required("Description is required"),
CTO_button_link: Yup.string().required("Linked In link is required"),
banner_image: Yup.mixed().required("Display picture is required"),
banner_image: Yup.mixed()
.test("required", "You need to provide a file", (files) => {
// return file && file.size <-- u can use this if you don't want to allow empty files to be uploaded;
if (files) return true;
return false;
})
.test(
"fileSize",
" The maximum size of profile picture is 15MB.",
(files) => {
//if u want to allow only certain file sizes
try {
if (files.length !== 0) {
return files[0].size <= 15000000;
}
return true;
} catch (error) {
return false;
}
}
)
.optional(),
});
export const editCommunityBannerSchema = Yup.object().shape({
@@ -49,7 +91,48 @@ export const addNews = Yup.object().shape({
release_date: Yup.date().required("Release date is required"),
meta_description: Yup.string().required("Description is required"),
content: Yup.string().required("Content is required"),
banner_image: Yup.mixed().required("Banner image is required"),
banner_image: Yup.mixed()
.test("required", "You need to provide a file", (files) => {
// return file && file.size <-- u can use this if you don't want to allow empty files to be uploaded;
if (files) return true;
return false;
})
.test(
"fileSize",
" The maximum size of profile picture is 15MB.",
(files) => {
//if u want to allow only certain file sizes
try {
if (files.length !== 0) {
return files[0].size <= 15000000;
}
return true;
} catch (error) {
return false;
}
}
)
.test("file_formate", "Image file has unsupported format.", (files) => {
// // console.log(files[0].type)
const SUPPORTED_FORMATS = [
"image/jpeg",
"image/png",
"image/gif",
"image/tiff",
"image/svg+xml",
];
try {
if (files.length !== 0) {
setPreviewImage(URL.createObjectURL(files[0]));
return files && SUPPORTED_FORMATS.includes(files[0].type);
}
return true;
} catch (error) {
return false;
}
})
.optional(),
});
export const editNews = Yup.object().shape({
@@ -57,12 +140,50 @@ export const editNews = Yup.object().shape({
release_date: Yup.date(),
meta_description: Yup.string(),
content: Yup.string(),
banner_image: Yup.mixed().required("Banner image is required"),
banner_image: Yup.mixed()
.test("required", "You need to provide a file", (files) => {
// return file && file.size <-- u can use this if you don't want to allow empty files to be uploaded;
if (files) return true;
return false;
})
.test(
"fileSize",
" The maximum size of profile picture is 15MB.",
(files) => {
//if u want to allow only certain file sizes
try {
if (files.length !== 0) {
return files[0].size <= 15000000;
}
return true;
} catch (error) {
return false;
}
}
)
.test("file_formate", "Image file has unsupported format.", (files) => {
// // console.log(files[0].type)
const SUPPORTED_FORMATS = [
"image/jpeg",
"image/png",
"image/gif",
"image/tiff",
"image/svg+xml",
];
try {
if (files.length !== 0) {
setPreviewImage(URL.createObjectURL(files[0]));
return files && SUPPORTED_FORMATS.includes(files[0].type);
}
return true;
} catch (error) {
return false;
}
})
.optional(),
});
export const addEvents = Yup.object().shape({
title: Yup.string().required("title is required"),
content: Yup.string().required("content is required"),
@@ -71,13 +192,146 @@ export const addEvents = Yup.object().shape({
organizer_mobile_number: Yup.string().required("Org contact is required")
.matches(/^[0-9]{10}$/, "Mobile number must be 10 digits"),
organizer_email: Yup.string().required("Org email is required").email("Please enter valid email"),
banner_image: Yup.mixed().required("Banner image is required"),
banner_image: Yup.mixed()
.test("required", "You need to provide a file", (files) => {
// return file && file.size <-- u can use this if you don't want to allow empty files to be uploaded;
if (files) return true;
return false;
})
.test(
"fileSize",
" The maximum size of profile picture is 15MB.",
(files) => {
//if u want to allow only certain file sizes
try {
if (files.length !== 0) {
return files[0].size <= 15000000;
}
return true;
} catch (error) {
return false;
}
}
)
.test("file_formate", "Image file has unsupported format.", (files) => {
// // console.log(files[0].type)
const SUPPORTED_FORMATS = [
"image/jpeg",
"image/png",
"image/gif",
"image/tiff",
"image/svg+xml",
];
try {
if (files.length !== 0) {
setPreviewImage(URL.createObjectURL(files[0]));
return files && SUPPORTED_FORMATS.includes(files[0].type);
}
return true;
} catch (error) {
return false;
}
})
.optional(),
});
// test("fileSize", "Image must be at least 2MB", (value) => {
export const addWhitePapers = Yup.object().shape({
title: Yup.string().required("title is required"),
image: Yup.mixed()
.test("required", "You need to provide a file", (files) => {
// return file && file.size <-- u can use this if you don't want to allow empty files to be uploaded;
if (files) return true;
return false;
})
.test(
"fileSize",
" The maximum size of profile picture is 15MB.",
(files) => {
//if u want to allow only certain file sizes
try {
if (files.length !== 0) {
return files[0].size <= 15000000;
}
return true;
} catch (error) {
return false;
}
}
)
// .test("file_formate", "Image file has unsupported format.", (files) => {
// // // console.log(files[0].type)
// const SUPPORTED_FORMATS = [
// "image/jpeg",
// "image/jpg",
// "image/png",
// "image/gif",
// "image/tiff",
// "image/svg+xml",
// ];
// try {
// if (files.length !== 0) {
// setPreviewImage(URL.createObjectURL(files[0]));
// return files && SUPPORTED_FORMATS.includes(files[0].type);
// }
// return true;
// } catch (error) {
// return false;
// }
// })
.optional(),
document: Yup.mixed()
.test("required", "You need to provide a file", (files) => {
// return file && file.size <-- u can use this if you don't want to allow empty files to be uploaded;
if (files) return true;
return false;
})
.test(
"fileSize",
" The maximum size of profile picture is 15MB.",
(files) => {
//if u want to allow only certain file sizes
try {
if (files.length !== 0) {
return files[0].size <= 15000000;
}
return true;
} catch (error) {
return false;
}
}
).optional()
// .test("file_formate", "Image file has unsupported format.", (files) => {
// // // console.log(files[0].type)
// const SUPPORTED_FORMATS = [
// "image/jpeg",
// "image/png",
// "image/jpg",
// "image/gif",
// "image/tiff",
// "image/svg+xml",
// ];
// try {
// if (files.length !== 0) {
// setPreviewImage(URL.createObjectURL(files[0]));
// return files && SUPPORTED_FORMATS.includes(files[0].type);
// }
// return true;
// } catch (error) {
// return false;
// }
// })
,
});
// test("fileSize", "Image must be at least 15MB", (value) => {
// if (!value) return true;
// const fileSizeInBytes = value.size;
// const fileSizeInMB = fileSizeInBytes / (1024 * 1024);