Search
@@ -224,7 +224,10 @@ function EventsTable() {
: "hover:bg-[#F7F7F7] text-[#656767] text-sm"
}
>
-
+
{
+ const amount = parseFloat(row.getValue("cost"));
+
+ return (
+
+ {new Intl.NumberFormat("sw-KE", {
+ style: "currency",
+ currency: "KES",
+ }).format(amount)}
+
+ );
+ },
+ },
+ {
+ accessorKey: "status",
+ header: "Status",
+ cell: ({ row }) => (
+
+
+ {row.original.status}
+
+
+ ),
+ },
+ {
+ id: "actions",
+ enableHiding: false,
+ cell: () => (
+
+
+ View
+
+
+ ),
+ },
+];
+
+export default columns;
diff --git a/src/components/admin/shop/dashboard/OrdersPreviewTable.jsx b/src/components/admin/shop/dashboard/OrdersPreviewTable.jsx
new file mode 100644
index 00000000..e07c27f6
--- /dev/null
+++ b/src/components/admin/shop/dashboard/OrdersPreviewTable.jsx
@@ -0,0 +1,81 @@
+import {
+ flexRender,
+ getCoreRowModel,
+ useReactTable,
+} from "@tanstack/react-table";
+
+import PropTypes from "prop-types";
+import {
+ Table,
+ TableBody,
+ TableCell,
+ TableHead,
+ TableHeader,
+ TableRow,
+} from "../../../ui/table";
+
+function OrdersPreviewTable({ columns, data }) {
+ const table = useReactTable({
+ data,
+ columns,
+ getCoreRowModel: getCoreRowModel(),
+ });
+
+ return (
+
+
+ {table.getHeaderGroups().map((headerGroup) => (
+
+ {headerGroup.headers.map((header) => (
+
+ {header.isPlaceholder
+ ? null
+ : flexRender(
+ header.column.columnDef.header,
+ header.getContext()
+ )}
+
+ ))}
+
+ ))}
+
+
+ {table.getRowModel().rows?.length ? (
+ table.getRowModel().rows.map((row) => (
+
+ {row.getVisibleCells().map((cell) => (
+
+ {flexRender(cell.column.columnDef.cell, cell.getContext())}
+
+ ))}
+
+ ))
+ ) : (
+
+
+ No results.
+
+
+ )}
+
+
+ );
+}
+
+export default OrdersPreviewTable;
+
+OrdersPreviewTable.propTypes = {
+ columns: PropTypes.arrayOf(
+ PropTypes.shape({
+ accessorKey: PropTypes.string,
+ cell: PropTypes.func,
+ header: PropTypes.func,
+ id: PropTypes.string,
+ })
+ ).isRequired,
+ // eslint-disable-next-line react/forbid-prop-types
+ data: PropTypes.arrayOf(PropTypes.object).isRequired,
+};
diff --git a/src/components/admin/shop/inventory/InventoryCardComponent.jsx b/src/components/admin/shop/inventory/InventoryCardComponent.jsx
new file mode 100644
index 00000000..d01e1a99
--- /dev/null
+++ b/src/components/admin/shop/inventory/InventoryCardComponent.jsx
@@ -0,0 +1,34 @@
+/* eslint-disable react/require-default-props */
+import PropTypes from "prop-types";
+
+function InventoryCardComponent({
+ title = "All Orders",
+ number = 500,
+ categories,
+}) {
+ return (
+
+
+
+
+
{title}
+
{number}
+ {categories && (
+
+
{categories} Categories
+
+ )}
+
+
+
+
+ );
+}
+
+export default InventoryCardComponent;
+
+InventoryCardComponent.propTypes = {
+ categories: PropTypes.number,
+ number: PropTypes.number,
+ title: PropTypes.string,
+};
diff --git a/src/components/admin/shop/inventory/InventoryPreviewColumn.jsx b/src/components/admin/shop/inventory/InventoryPreviewColumn.jsx
new file mode 100644
index 00000000..652d50e3
--- /dev/null
+++ b/src/components/admin/shop/inventory/InventoryPreviewColumn.jsx
@@ -0,0 +1,32 @@
+const columns = [
+ {
+ accessorKey: "id",
+ header: "Item ID",
+ },
+ {
+ accessorKey: "name",
+ header: "Name",
+ },
+ {
+ accessorKey: "items-sold",
+ header: "Items Sold",
+ },
+ {
+ accessorKey: "items-remaining",
+ header: "Items Remaining",
+ },
+
+ {
+ id: "actions",
+ enableHiding: false,
+ cell: () => (
+
+
+ View
+
+
+ ),
+ },
+];
+
+export default columns;
diff --git a/src/components/admin/shop/inventory/InventoryPreviewTable.jsx b/src/components/admin/shop/inventory/InventoryPreviewTable.jsx
new file mode 100644
index 00000000..ec406f90
--- /dev/null
+++ b/src/components/admin/shop/inventory/InventoryPreviewTable.jsx
@@ -0,0 +1,81 @@
+import {
+ flexRender,
+ getCoreRowModel,
+ useReactTable,
+} from "@tanstack/react-table";
+
+import PropTypes from "prop-types";
+import {
+ Table,
+ TableBody,
+ TableCell,
+ TableHead,
+ TableHeader,
+ TableRow,
+} from "../../../ui/table";
+
+function InventoryPreviewTable({ columns, data }) {
+ const table = useReactTable({
+ data,
+ columns,
+ getCoreRowModel: getCoreRowModel(),
+ });
+
+ return (
+
+
+ {table.getHeaderGroups().map((headerGroup) => (
+
+ {headerGroup.headers.map((header) => (
+
+ {header.isPlaceholder
+ ? null
+ : flexRender(
+ header.column.columnDef.header,
+ header.getContext()
+ )}
+
+ ))}
+
+ ))}
+
+
+ {table.getRowModel().rows?.length ? (
+ table.getRowModel().rows.map((row) => (
+
+ {row.getVisibleCells().map((cell) => (
+
+ {flexRender(cell.column.columnDef.cell, cell.getContext())}
+
+ ))}
+
+ ))
+ ) : (
+
+
+ No results.
+
+
+ )}
+
+
+ );
+}
+
+export default InventoryPreviewTable;
+
+InventoryPreviewTable.propTypes = {
+ columns: PropTypes.arrayOf(
+ PropTypes.shape({
+ accessorKey: PropTypes.string,
+ cell: PropTypes.func,
+ header: PropTypes.func,
+ id: PropTypes.string,
+ })
+ ).isRequired,
+ // eslint-disable-next-line react/forbid-prop-types
+ data: PropTypes.arrayOf(PropTypes.object).isRequired,
+};
diff --git a/src/components/admin/shop/inventory/Modal.jsx b/src/components/admin/shop/inventory/Modal.jsx
new file mode 100644
index 00000000..7b08e1c6
--- /dev/null
+++ b/src/components/admin/shop/inventory/Modal.jsx
@@ -0,0 +1,280 @@
+/* eslint-disable react/jsx-props-no-spreading */
+/* eslint-disable jsx-a11y/label-has-associated-control */
+import { yupResolver } from "@hookform/resolvers/yup";
+import PropTypes from "prop-types";
+import { useForm } from "react-hook-form";
+import { IoMdClose } from "react-icons/io";
+import * as yup from "yup";
+
+const validFileExtensions = {
+ image: ["jpg", "gif", "png", "jpeg", "svg", "webp"],
+};
+
+const MAX_FILE_SIZE = 10485760;
+
+// get allowed file extensions
+function getAllowedExt(type) {
+ return validFileExtensions[type].map((e) => `.${e}`).toString();
+}
+
+// validate file type and extension
+function isValidFileType(fileName, fileType) {
+ if (!fileName) return false;
+ const extension = fileName.split(".").pop().toLowerCase();
+ return validFileExtensions[fileType].includes(extension);
+}
+
+// form validation schema in yup
+const schema = yup.object().shape({
+ price: yup.number().required("Price is required"),
+ size: yup.string().required("Size is required"),
+ category: yup.string().required("Category is required"),
+ color: yup.string().required("Color is required"),
+ description: yup.string().required("Description is required"),
+ image: yup
+ .mixed()
+ .required("Image is required")
+ .test("is-valid-type", "Not a valid image type", (value) =>
+ isValidFileType(value && value[0]?.name, "image")
+ )
+ .test(
+ "is-valid-size",
+ "Max allowed size is 10MB",
+ (value) => value && value[0]?.size <= MAX_FILE_SIZE
+ ),
+});
+
+export default function Modal({ showModal, onClose }) {
+ const {
+ register,
+ handleSubmit,
+ formState: { errors },
+ } = useForm({
+ resolver: yupResolver(schema),
+ });
+ const onSubmit = () => {
+ // console.log(data);
+ };
+
+ const allowedExts = getAllowedExt("image");
+
+ return (
+ <>
+
+ {showModal ? (
+ <>
+
+
+ >
+ ) : null}
+ >
+ );
+}
+
+Modal.propTypes = {
+ showModal: PropTypes.bool.isRequired,
+ onClose: PropTypes.func.isRequired,
+};
diff --git a/src/components/admin/shop/orders/Columns.jsx b/src/components/admin/shop/orders/Columns.jsx
new file mode 100644
index 00000000..09e60afe
--- /dev/null
+++ b/src/components/admin/shop/orders/Columns.jsx
@@ -0,0 +1,63 @@
+/* eslint-disable no-nested-ternary */
+const Columns = (handleViewClick) => [
+ {
+ accessorKey: "id",
+ header: "Order ID",
+ },
+ {
+ accessorKey: "email",
+ header: "Customer Email",
+ },
+ {
+ accessorKey: "date",
+ header: "Date Ordered",
+ },
+ {
+ accessorKey: "items",
+ header: "Items",
+ cell: ({ row }) => (
+
+ {`No. of items: ${row.original.number} | `}
+
+ {` Total Cost: KES ${row.original.cost}`}
+
+
+ ),
+ },
+ {
+ accessorKey: "status",
+ header: "Status",
+ cell: ({ row }) => (
+
+
+ {row.original.status}
+
+
+ ),
+ },
+ {
+ id: "actions",
+ enableHiding: false,
+ cell: ({ row }) => (
+
+ handleViewClick(row.original.id)}
+ >
+ View
+
+
+ ),
+ },
+];
+
+export default Columns;
diff --git a/src/components/admin/shop/orders/Orders.jsx b/src/components/admin/shop/orders/Orders.jsx
new file mode 100644
index 00000000..5a9082b1
--- /dev/null
+++ b/src/components/admin/shop/orders/Orders.jsx
@@ -0,0 +1,106 @@
+import {
+ flexRender,
+ getCoreRowModel,
+ useReactTable,
+} from "@tanstack/react-table";
+import PropTypes from "prop-types";
+import { useState } from "react";
+import {
+ Table,
+ TableBody,
+ TableCell,
+ TableHead,
+ TableHeader,
+ TableRow,
+} from "../../../ui/table";
+import Columns from "./Columns";
+import OrdersInvoiceModal from "./OrdersInvoiceModal";
+
+function Orders({ data }) {
+ const [isModalOpen, setIsModalOpen] = useState(false);
+ const [selectedOrderId, setSelectedOrderId] = useState(null);
+
+ const handleViewClick = (orderId) => {
+ setSelectedOrderId(orderId);
+ setIsModalOpen(true);
+ };
+
+ const handleCloseModal = () => {
+ setIsModalOpen(false);
+ setSelectedOrderId(null);
+ };
+
+ const columns = Columns(handleViewClick);
+ const table = useReactTable({
+ data,
+ columns,
+ getCoreRowModel: getCoreRowModel(),
+ });
+
+ return (
+
+
+
+ {table.getHeaderGroups().map((headerGroup) => (
+
+ {headerGroup.headers.map((header) => (
+
+ {header.isPlaceholder
+ ? null
+ : flexRender(
+ header.column.columnDef.header,
+ header.getContext()
+ )}
+
+ ))}
+
+ ))}
+
+
+ {table.getRowModel().rows?.length ? (
+ table.getRowModel().rows.map((row) => (
+
+ {row.getVisibleCells().map((cell) => (
+
+ {flexRender(cell.column.columnDef.cell, cell.getContext())}
+
+ ))}
+
+ ))
+ ) : (
+
+
+ No results.
+
+
+ )}
+
+
+
+ {isModalOpen && (
+
+ )}
+
+ );
+}
+
+export default Orders;
+
+Orders.propTypes = {
+ data: PropTypes.arrayOf(
+ PropTypes.shape({
+ id: PropTypes.string.isRequired,
+ email: PropTypes.string.isRequired,
+ date: PropTypes.string.isRequired,
+ number: PropTypes.number.isRequired,
+ cost: PropTypes.number.isRequired,
+ status: PropTypes.string.isRequired,
+ })
+ ).isRequired,
+};
diff --git a/src/components/admin/shop/orders/OrdersChart.jsx b/src/components/admin/shop/orders/OrdersChart.jsx
new file mode 100644
index 00000000..62814c55
--- /dev/null
+++ b/src/components/admin/shop/orders/OrdersChart.jsx
@@ -0,0 +1,89 @@
+import { Area, AreaChart, CartesianGrid, Tooltip, XAxis } from "recharts";
+
+const data = [
+ {
+ name: "",
+ orders: 440,
+ },
+ {
+ name: "Jan",
+ orders: 640,
+ },
+ {
+ name: "Feb",
+ orders: 710,
+ },
+ {
+ name: "Mar",
+ orders: 890,
+ },
+ {
+ name: "Apr",
+ orders: 1500,
+ },
+ {
+ name: "May",
+ orders: 1001,
+ },
+ {
+ name: "Jun",
+ orders: 1300,
+ },
+ {
+ name: "Jul",
+ orders: 2210,
+ },
+ {
+ name: "Aug",
+ orders: 1900,
+ },
+ {
+ name: "Sep",
+ orders: 1700,
+ },
+ {
+ name: "Oct",
+ orders: 2390,
+ },
+ {
+ name: "Nov",
+ orders: 2781,
+ },
+ {
+ name: "Dec",
+ orders: 2501,
+ },
+ {
+ name: "",
+ orders: 2401,
+ },
+];
+
+export default function OrdersChart() {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/components/admin/shop/orders/OrdersInvoiceModal.jsx b/src/components/admin/shop/orders/OrdersInvoiceModal.jsx
new file mode 100644
index 00000000..34405e3b
--- /dev/null
+++ b/src/components/admin/shop/orders/OrdersInvoiceModal.jsx
@@ -0,0 +1,132 @@
+import axios from "axios";
+import PropTypes from "prop-types";
+import { useEffect, useState } from "react";
+import { IoCloseOutline } from "react-icons/io5";
+// import html2canvas from "html2canvas";
+// import jsPDF from "jspdf";
+
+export default function OrdersInvoiceModal({ orderId, onClose }) {
+ const [orderDetails, setOrderDetails] = useState(null);
+
+ useEffect(() => {
+ axios
+ .get(`/api/orders/${orderId}`)
+ .then((response) => {
+ setOrderDetails(response.data);
+ })
+ .catch((error) => {
+ // eslint-disable-next-line no-console
+ console.error("Error fetching order details", error);
+ });
+ }, [orderId]);
+
+ // const downloadInvoice = () => {
+ // const input = document.getElementById("invoice");
+
+ // html2canvas(input).then((canvas) => {
+ // const imgData = canvas.toDataURL("image/png");
+ // const pdf = new jsPDF();
+ // pdf.addImage(imgData, "PNG", 0, 0);
+ // pdf.save(`invoice-${orderId}.pdf`);
+ // });
+ // };
+
+ if (!orderDetails) {
+ return Loading...
;
+ }
+
+ return (
+
+
+
+
+
{orderDetails.status}
+
+
+
+
+
{orderId}
+
+
Item Information
+
+
+
Name
+ {/* {orderDetails.items.map((item) => (
+
+ {item.product.name}
+
+ ))} */}
+
+
+
Quantity
+ {/* {orderDetails.items.map((item) => (
+
{item.quantity}
+ ))} */}
+
+
+
Unit Cost
+ {/* {orderDetails.items.map((item) => (
+
${item.product.price}
+ ))} */}
+
+
+
+
Subtotal
+ {/* {orderDetails.items.map((item) => (
+
${item.total_price}
+ ))} */}
+
+
+
+
+
Offer
+
KES {orderDetails.offer || 0}
+
+
+
Discount
+
+ KES {orderDetails.discount || 0}
+
+
+
+
V.A.T
+
KES {orderDetails.vat || 0}
+
+
+
+
TOTAL
+
+ KES {orderDetails.total_price_of_orders || 0}
+
+
+
+
+
Customer Information
+ {/*
Name: {orderDetails.user.name}
+
Email: {orderDetails.user.email}
+
Phone: {orderDetails.user.phone}
+
Payment Mode: {orderDetails.user.payment_mode}
+
Order Date: {new Date(orderDetails.created_at).toLocaleDateString()}
*/}
+
+
+ DOWNLOAD INVOICE
+
+
+
+
+ );
+}
+
+OrdersInvoiceModal.propTypes = {
+ orderId: PropTypes.string.isRequired,
+ onClose: PropTypes.func.isRequired,
+};
diff --git a/src/components/admin/shop/orders/OrdersTrends.jsx b/src/components/admin/shop/orders/OrdersTrends.jsx
new file mode 100644
index 00000000..06ae2a24
--- /dev/null
+++ b/src/components/admin/shop/orders/OrdersTrends.jsx
@@ -0,0 +1,82 @@
+import { FaArrowUp } from "react-icons/fa";
+import { Area, AreaChart, CartesianGrid, Tooltip } from "recharts";
+
+function OrdersTrends() {
+ const trends = [
+ {
+ metric: "All Orders",
+ value: "4000",
+ },
+ {
+ metric: "Orders This Week",
+ value: "500",
+ },
+ {
+ metric: "Orders This Month",
+ value: "750",
+ },
+ {
+ metric: "Orders This Year",
+ value: "1000",
+ },
+ ];
+
+ const data = [
+ {
+ name: "",
+ orders: 0,
+ },
+ {
+ name: "",
+ orders: 450,
+ },
+ {
+ name: "",
+ orders: 200,
+ },
+ {
+ name: "",
+ orders: 750,
+ },
+ ];
+
+ return (
+
+
+ {trends.map((trend, index) => (
+
+
+
{trend.metric}
+
{trend.value}
+
+
+
10%
+
vs last quarter
+
+
+
+
+ ))}
+
+
+ );
+}
+
+export default OrdersTrends;
diff --git a/src/components/admin/shop/sales/SalesGraph.jsx b/src/components/admin/shop/sales/SalesGraph.jsx
new file mode 100644
index 00000000..10d01036
--- /dev/null
+++ b/src/components/admin/shop/sales/SalesGraph.jsx
@@ -0,0 +1,47 @@
+// import React, { PureComponent } from 'react';
+import {
+ AreaChart,
+ Area,
+ XAxis,
+ YAxis,
+ CartesianGrid,
+ Tooltip,
+ ResponsiveContainer,
+} from "recharts";
+import data from "./data";
+
+export default function SalesGraph() {
+ return (
+
+ {/* */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/components/admin/shop/sales/SalesPreviewColumn.jsx b/src/components/admin/shop/sales/SalesPreviewColumn.jsx
new file mode 100644
index 00000000..652d50e3
--- /dev/null
+++ b/src/components/admin/shop/sales/SalesPreviewColumn.jsx
@@ -0,0 +1,32 @@
+const columns = [
+ {
+ accessorKey: "id",
+ header: "Item ID",
+ },
+ {
+ accessorKey: "name",
+ header: "Name",
+ },
+ {
+ accessorKey: "items-sold",
+ header: "Items Sold",
+ },
+ {
+ accessorKey: "items-remaining",
+ header: "Items Remaining",
+ },
+
+ {
+ id: "actions",
+ enableHiding: false,
+ cell: () => (
+
+
+ View
+
+
+ ),
+ },
+];
+
+export default columns;
diff --git a/src/components/admin/shop/sales/SalesPreviewTable.jsx b/src/components/admin/shop/sales/SalesPreviewTable.jsx
new file mode 100644
index 00000000..025a1f5a
--- /dev/null
+++ b/src/components/admin/shop/sales/SalesPreviewTable.jsx
@@ -0,0 +1,81 @@
+import {
+ flexRender,
+ getCoreRowModel,
+ useReactTable,
+} from "@tanstack/react-table";
+
+import PropTypes from "prop-types";
+import {
+ Table,
+ TableBody,
+ TableCell,
+ TableHead,
+ TableHeader,
+ TableRow,
+} from "../../../ui/table";
+
+function SalesPreviewTable({ columns, data }) {
+ const table = useReactTable({
+ data,
+ columns,
+ getCoreRowModel: getCoreRowModel(),
+ });
+
+ return (
+
+
+ {table.getHeaderGroups().map((headerGroup) => (
+
+ {headerGroup.headers.map((header) => (
+
+ {header.isPlaceholder
+ ? null
+ : flexRender(
+ header.column.columnDef.header,
+ header.getContext()
+ )}
+
+ ))}
+
+ ))}
+
+
+ {table.getRowModel().rows?.length ? (
+ table.getRowModel().rows.map((row) => (
+
+ {row.getVisibleCells().map((cell) => (
+
+ {flexRender(cell.column.columnDef.cell, cell.getContext())}
+
+ ))}
+
+ ))
+ ) : (
+
+
+ No results.
+
+
+ )}
+
+
+ );
+}
+
+export default SalesPreviewTable;
+
+SalesPreviewTable.propTypes = {
+ columns: PropTypes.arrayOf(
+ PropTypes.shape({
+ accessorKey: PropTypes.string,
+ cell: PropTypes.func,
+ header: PropTypes.func,
+ id: PropTypes.string,
+ })
+ ).isRequired,
+ // eslint-disable-next-line react/forbid-prop-types
+ data: PropTypes.arrayOf(PropTypes.object).isRequired,
+};
diff --git a/src/components/admin/shop/sales/data.js b/src/components/admin/shop/sales/data.js
new file mode 100644
index 00000000..5d3ab229
--- /dev/null
+++ b/src/components/admin/shop/sales/data.js
@@ -0,0 +1,59 @@
+const data = [
+ {
+ name: "Jan",
+ uv: 4300,
+ amt: 2400,
+ },
+ {
+ name: "Feb",
+ uv: 5600,
+ amt: 2210,
+ },
+ {
+ name: "Apr",
+ uv: 5408,
+ amt: 2290,
+ },
+ {
+ name: "May",
+ uv: 6420,
+ amt: 2000,
+ },
+ {
+ name: "Jun",
+ uv: 7500,
+ amt: 2181,
+ },
+ {
+ name: "Jul",
+ uv: 6300,
+ amt: 2500,
+ },
+ {
+ name: "Aug",
+ uv: 8600,
+ amt: 2100,
+ },
+ {
+ name: "Sep",
+ uv: 8300,
+ amt: 2100,
+ },
+ {
+ name: "Oct",
+ uv: 10200,
+ amt: 2100,
+ },
+ {
+ name: "Nov",
+ uv: 9500,
+ amt: 2100,
+ },
+ {
+ name: "Dev",
+ uv: 12200,
+ amt: 2100,
+ },
+];
+
+export default data;
diff --git a/src/APP/components/auth/NotificationModal.jsx b/src/components/auth/NotificationModal.jsx
similarity index 100%
rename from src/APP/components/auth/NotificationModal.jsx
rename to src/components/auth/NotificationModal.jsx
diff --git a/src/APP/components/index.js b/src/components/index.js
similarity index 69%
rename from src/APP/components/index.js
rename to src/components/index.js
index 86643407..729a89cf 100644
--- a/src/APP/components/index.js
+++ b/src/components/index.js
@@ -2,6 +2,8 @@ export { default as Button } from "./Button";
export { default as Caroussel } from "./Caroussel";
export { default as CartDrawer } from "./shop/CartDrawer";
export { default as Counter } from "./shop/Counter";
+export { default as CurriculumAccordion } from "../pages/mastercraft/sections/CurriculumAccordion";
+export { default as MastercraftFAQAccordion } from "../pages/mastercraft-home/sections/MastercraftFAQAccordion";
export { default as FAQ } from "./FAQ";
export { default as Footer } from "./Footer";
export { default as GoBackBtn } from "./GoBackBtn";
@@ -9,4 +11,5 @@ export { default as Header } from "./Header";
export { default as FallbackLoader } from "./FallbackLoader";
export { default as Loader } from "./Loader";
export { default as PodcastCard } from "./PodcastCard";
+export { default as ResourcesFooter } from "./ResourcesFooter";
export { default as LandingWrapper } from "./LandingWrapper";
diff --git a/src/components/shop/CartDrawer.jsx b/src/components/shop/CartDrawer.jsx
new file mode 100644
index 00000000..f4444008
--- /dev/null
+++ b/src/components/shop/CartDrawer.jsx
@@ -0,0 +1,245 @@
+import { Dialog, Transition } from "@headlessui/react";
+import PropTypes from "prop-types";
+import { Fragment, useEffect, useState } from "react";
+import { CiShoppingTag } from "react-icons/ci";
+import { IoIosCloseCircleOutline } from "react-icons/io";
+import { RiDeleteBin6Line } from "react-icons/ri";
+import { LazyLoadImage } from "react-lazy-load-image-component";
+import { Link, useNavigate } from "react-router-dom";
+import { useDeleteSwag } from "../../hooks/Mutations/shop/useCartSwagg";
+import formatPrice from "../../utilities/formatPrice";
+import { categoryColors } from "../../utilities/utils";
+
+function CartDrawer({ open, setOpen }) {
+ const navigate = useNavigate();
+
+ // Get the JSON string from localStorage
+ const [cartProducts, setCartProducts] = useState(() => {
+ // Initialize state with the value from localStorage if it exists
+ const storedProducts = localStorage.getItem("swagList");
+ return storedProducts ? JSON.parse(storedProducts) : [];
+ });
+
+ useEffect(() => {
+ if (open) {
+ const storedProducts = localStorage.getItem("swagList");
+ if (storedProducts) {
+ setCartProducts(JSON.parse(storedProducts));
+ }
+ }
+ }, [open]);
+
+ // const { data: cartProducts, isSuccess } = useProductsInCart();
+ useEffect(() => {
+ // Function to handle storage changes
+ const handleStorageChange = (e) => {
+ if (e.key === "swagList") {
+ setCartProducts(JSON.parse(e.newValue));
+ }
+ };
+
+ // Add event listener
+ window.addEventListener("storage", handleStorageChange);
+
+ // Remove event listener on cleanup
+ return () => {
+ window.removeEventListener("storage", handleStorageChange);
+ };
+ }, []);
+
+ const { mutate: removeSwagFromCart } = useDeleteSwag();
+
+ const deleteFromLocalStorage = (cartItemId) => {
+ // Create a new array by filtering out the item to delete
+ const updatedSwagList = cartProducts.filter(
+ (swag) => swag.id !== cartItemId
+ );
+
+ // Update the state with the new array
+ setCartProducts(updatedSwagList);
+
+ // Convert the updated list to a JSON string and store it in localStorage
+ localStorage.setItem("swagList", JSON.stringify(updatedSwagList));
+ };
+
+ const handleDeleteSwag = (cartItemId) => {
+ removeSwagFromCart(cartItemId);
+ deleteFromLocalStorage(cartItemId);
+ // dispatch custom event to notify cart change
+ window.dispatchEvent(new Event("swagListUpdated"));
+ };
+
+ const handleCheckout = () => {
+ // if (auth?.access) {
+ navigate("/shop/checkout");
+ // }
+ };
+
+ // query cart products
+ // console.log("cartProducts: ", cartProducts);
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Your cart
+
+
+ setOpen(false)}
+ >
+ Close panel
+
+ {/* Close Icon */}
+
+
+
+
+
+ {/* Items in Cart */}
+
+
+
+ {/* {isSuccess && */}
+ {cartProducts?.length > 0 &&
+ cartProducts?.map((cartProduct) => (
+
+
+
+
+
+
+
+
+
+
+
+
+ {cartProduct.category}
+
+
+
+
+ {" "}
+
+ {cartProduct.name}
+
+
+
+
+
{
+ handleDeleteSwag(cartProduct.id);
+ }}
+ >
+ {/* Delete icon */}
+
+
+
+
+
Qty: {cartProduct.orderUnits}
+
+ KES {formatPrice(cartProduct.price)}
+
+
+
+
+
+ ))}
+
+
+
+
+
+ {/* Sub Total */}
+
+
+ {/*
Sub Total
+
+ Ksh
+ {cartProducts?.total_price || "00"}
+ */}
+
+
+
+ Proceed to Checkout
+
+ setOpen(false)}
+ >
+ Continue Shopping
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default CartDrawer;
+
+CartDrawer.propTypes = {
+ open: PropTypes.bool.isRequired,
+ setOpen: PropTypes.func.isRequired,
+};
diff --git a/src/components/shop/CartIcon.jsx b/src/components/shop/CartIcon.jsx
new file mode 100644
index 00000000..9a43d31d
--- /dev/null
+++ b/src/components/shop/CartIcon.jsx
@@ -0,0 +1,48 @@
+import { useEffect, useState } from "react";
+import { MdAddShoppingCart } from "react-icons/md";
+import SectionWrapper from "./SectionWrapper";
+
+function CartIcon() {
+ const [cartProducts, setCartProducts] = useState(() => {
+ // Initialize state with the value from localStorage if it exists
+ const storedProducts = localStorage.getItem("swagList");
+ return storedProducts ? JSON.parse(storedProducts) : [];
+ });
+
+ useEffect(() => {
+ // Event listener for storage changes in other tabs/windows
+ const handleStorageChange = () => {
+ const storedProducts = localStorage.getItem("swagList");
+ setCartProducts(storedProducts ? JSON.parse(storedProducts) : []);
+ };
+
+ // Listen for "storage" events, whenever swagList is updated from another tab
+ window.addEventListener("storage", handleStorageChange);
+ // Listen for custom swagListUpdated events, fired whenever swagList is updated
+ window.addEventListener("swagListUpdated", handleStorageChange);
+
+ // Cleanup event listeners on unmount
+ return () => {
+ window.removeEventListener("storage", handleStorageChange);
+ window.removeEventListener("swagListUpdated", handleStorageChange);
+ };
+ }, []);
+
+ return (
+
+
+
+
+
+
+ {cartProducts.length > 0 && (
+
+
{cartProducts?.length}
+
+ )}
+
+
+
+ );
+}
+export default CartIcon;
diff --git a/src/APP/components/shop/Counter.jsx b/src/components/shop/Counter.jsx
similarity index 57%
rename from src/APP/components/shop/Counter.jsx
rename to src/components/shop/Counter.jsx
index e4252a23..63045311 100644
--- a/src/APP/components/shop/Counter.jsx
+++ b/src/components/shop/Counter.jsx
@@ -1,27 +1,32 @@
import PropTypes from "prop-types";
-function Counter({ className, setCount, count }) {
+function Counter({ className, setCount, count, maxStock }) {
+ const increment = () => setCount((prevCount) => prevCount + 1);
+ const decrement = () =>
+ setCount((prevCount) => (prevCount > 1 ? prevCount - 1 : prevCount));
+ // console.log(count)
return (
setCount(count > 1 ? count - 1 : 1)}
+ className="cursor-pointer outline-none w-20 border-y border-l border-l-[#EAECF0] border-y-[#EAECF0] rounded-l-md border-r"
+ onClick={decrement}
>
−
{count}
maxStock}
type="button"
data-action="increment"
- className="cursor-pointer outline-none w-20 border-y border-r border-r-[#323433] border-y-[#323433] rounded-r-full"
- onClick={() => setCount(count + 1)}
+ className="cursor-pointer outline-none w-20 border-y border-r border-r-[#EAECF0] border-y-[#EAECF0] rounded-r-md border-l"
+ onClick={increment}
>
+
@@ -39,4 +44,5 @@ Counter.propTypes = {
className: PropTypes.string,
setCount: PropTypes.func.isRequired,
count: PropTypes.number.isRequired,
+ maxStock: PropTypes.number.isRequired,
};
diff --git a/src/components/shop/ProductCard.jsx b/src/components/shop/ProductCard.jsx
new file mode 100644
index 00000000..cbd9ac00
--- /dev/null
+++ b/src/components/shop/ProductCard.jsx
@@ -0,0 +1,113 @@
+import PropTypes from "prop-types";
+import { CiShoppingTag } from "react-icons/ci";
+import { MdAddShoppingCart } from "react-icons/md";
+import { LazyLoadImage } from "react-lazy-load-image-component";
+import { Link } from "react-router-dom";
+import { addCommaSeparator, categoryColors } from "../../utilities/utils";
+
+function ProductCard({ product }) {
+ const { backgroundColor, color } = categoryColors(product.category);
+
+ const attributeWithImages = product.attributes.find(
+ (attribute) => attribute.images.length > 0
+ );
+ const image = attributeWithImages
+ ? attributeWithImages.images.map((img) => img.image)[0]
+ : "";
+ const totalStock = product.attributes.reduce(
+ (acc, attribute) => acc + attribute.stock,
+ 0
+ );
+ return (
+
+
+
+
+
+
+ {product.name.length > 15
+ ? `${product.name.slice(0, 18)}...`
+ : product.name}
+
+
+ {totalStock > 0 ? (
+
+ {totalStock}
+
+ {totalStock === 1 ? "item" : "items"} left
+
+
+ ) : (
+
+ )}
+
+
+
+
+
+ KES {addCommaSeparator(Number(product.price))}
+
+
+
+
+ );
+}
+export default ProductCard;
+
+const imagePropTypes = PropTypes.shape({
+ id: PropTypes.number.isRequired,
+ product_attribute: PropTypes.number.isRequired,
+ image: PropTypes.string.isRequired,
+ is_primary: PropTypes.bool.isRequired,
+ angle: PropTypes.string.isRequired,
+});
+
+const sizePropTypes = PropTypes.shape({
+ id: PropTypes.number.isRequired,
+ name: PropTypes.string.isRequired,
+});
+
+const attributePropTypes = PropTypes.shape({
+ id: PropTypes.number.isRequired,
+ size: PropTypes.arrayOf(sizePropTypes).isRequired,
+ color: PropTypes.string.isRequired,
+ stock: PropTypes.number.isRequired,
+ images: PropTypes.arrayOf(imagePropTypes).isRequired,
+});
+
+const ProductCardPropTypes = {
+ id: PropTypes.number.isRequired,
+ name: PropTypes.string.isRequired,
+ slug: PropTypes.string.isRequired,
+ description: PropTypes.string.isRequired,
+ price: PropTypes.string.isRequired,
+ category: PropTypes.string.isRequired,
+ is_featured: PropTypes.bool.isRequired,
+ attributes: PropTypes.arrayOf(attributePropTypes).isRequired,
+};
+ProductCard.propTypes = {
+ product: PropTypes.shape(ProductCardPropTypes).isRequired,
+};
diff --git a/src/components/shop/SearchInput.jsx b/src/components/shop/SearchInput.jsx
new file mode 100644
index 00000000..e508c5c7
--- /dev/null
+++ b/src/components/shop/SearchInput.jsx
@@ -0,0 +1,36 @@
+import { useState } from "react";
+import { IoMdSearch } from "react-icons/io";
+import { useNavigate } from "react-router-dom";
+
+function SearchInput() {
+ const [searchText, setSearchText] = useState("");
+ const navigate = useNavigate();
+
+ function handleSubmit(e) {
+ e.preventDefault();
+ navigate(`/shop/items?search=${searchText}`);
+ }
+
+ return (
+
+ setSearchText(e.target.value)}
+ />
+
+
+ Search
+
+
+ );
+}
+export default SearchInput;
diff --git a/src/components/shop/SectionWrapper.jsx b/src/components/shop/SectionWrapper.jsx
new file mode 100644
index 00000000..36cfb474
--- /dev/null
+++ b/src/components/shop/SectionWrapper.jsx
@@ -0,0 +1,10 @@
+import PropTypes from "prop-types";
+
+function SectionWrapper({ children }) {
+ return
{children}
;
+}
+export default SectionWrapper;
+
+SectionWrapper.propTypes = {
+ children: PropTypes.node.isRequired,
+};
diff --git a/src/components/shop/SortItems.jsx b/src/components/shop/SortItems.jsx
new file mode 100644
index 00000000..2a147780
--- /dev/null
+++ b/src/components/shop/SortItems.jsx
@@ -0,0 +1,41 @@
+import { Menu } from "@headlessui/react";
+import { IoFilter } from "react-icons/io5";
+import { Link, useLocation } from "react-router-dom";
+
+function SortItems() {
+ const { pathname } = useLocation();
+ const path = pathname.includes("category") ? pathname : "/shop/items";
+
+ return (
+
+
+
+
+ Sort
+
+
+
+
+ Lowest price first
+
+
+
+
+ Highest price first
+
+
+
+
+
+ );
+}
+export default SortItems;
diff --git a/src/components/ui/table.jsx b/src/components/ui/table.jsx
new file mode 100644
index 00000000..f2cb75db
--- /dev/null
+++ b/src/components/ui/table.jsx
@@ -0,0 +1,95 @@
+/* eslint-disable react/jsx-props-no-spreading */
+/* eslint-disable react/prop-types */
+import * as React from "react";
+
+import { cn } from "../../utilities/utils";
+
+const Table = React.forwardRef(({ className, ...props }, ref) => (
+
+));
+Table.displayName = "Table";
+
+const TableHeader = React.forwardRef(({ className, ...props }, ref) => (
+
+));
+TableHeader.displayName = "TableHeader";
+
+const TableBody = React.forwardRef(({ className, ...props }, ref) => (
+
+));
+TableBody.displayName = "TableBody";
+
+const TableFooter = React.forwardRef(({ className, ...props }, ref) => (
+
tr]:last:border-b-0 dark:bg-gray-800/50",
+ className
+ )}
+ {...props}
+ />
+));
+TableFooter.displayName = "TableFooter";
+
+const TableRow = React.forwardRef(({ className, ...props }, ref) => (
+
+));
+TableRow.displayName = "TableRow";
+
+const TableHead = React.forwardRef(({ className, ...props }, ref) => (
+
+));
+TableHead.displayName = "TableHead";
+
+const TableCell = React.forwardRef(({ className, ...props }, ref) => (
+
+));
+TableCell.displayName = "TableCell";
+
+const TableCaption = React.forwardRef(({ className, ...props }, ref) => (
+
+));
+TableCaption.displayName = "TableCaption";
+
+export {
+ Table,
+ TableBody,
+ TableCaption,
+ TableCell,
+ TableFooter,
+ TableHead,
+ TableHeader,
+ TableRow,
+};
diff --git a/src/context/AuthContext.jsx b/src/context/AuthContext.jsx
index 8d19c693..da0dbdcb 100644
--- a/src/context/AuthContext.jsx
+++ b/src/context/AuthContext.jsx
@@ -1,4 +1,11 @@
-import { useState, useEffect, createContext } from "react";
+import PropTypes from "prop-types";
+import {
+ createContext,
+ useCallback,
+ useEffect,
+ useMemo,
+ useState,
+} from "react";
export const AuthContext = createContext({
auth: {
@@ -22,14 +29,19 @@ export function AuthContextProvider({ children }) {
localStorage.setItem("auth", JSON.stringify(auth));
}, [auth]);
- const logout = () => {
+ const logout = useCallback(() => {
localStorage.removeItem("auth");
setAuth(null);
- };
+ }, [setAuth]);
- return (
-
- {children}
-
+ const value = useMemo(
+ () => ({ auth, setAuth, logout }),
+ [auth, setAuth, logout]
);
+
+ return {children} ;
}
+
+AuthContextProvider.propTypes = {
+ children: PropTypes.node.isRequired,
+};
diff --git a/src/context/searchBlog.jsx b/src/context/searchBlog.jsx
index bc1183c6..02bf6ec0 100644
--- a/src/context/searchBlog.jsx
+++ b/src/context/searchBlog.jsx
@@ -1,4 +1,11 @@
-import React, { createContext, useEffect, useMemo, useState } from "react";
+import PropTypes from "prop-types";
+import {
+ createContext,
+ useEffect,
+ useMemo,
+ useState,
+ startTransition,
+} from "react";
import { useSearchBlog } from "../hooks/Queries/blogs/useAllBlogsData";
export const SearchBlogContext = createContext();
@@ -11,10 +18,13 @@ export function SearchBlogProvider({ children }) {
useEffect(() => {
const dalayDebounceFn = setTimeout(() => {
- refetchSearchBlog();
+ startTransition(() => {
+ refetchSearchBlog();
+ });
}, 500);
return () => clearTimeout(dalayDebounceFn);
+ // eslint-disable-next-line react-hooks/exhaustive-deps
}, [searchText]);
const value = useMemo(
@@ -28,3 +38,7 @@ export function SearchBlogProvider({ children }) {
);
}
+
+SearchBlogProvider.propTypes = {
+ children: PropTypes.node.isRequired,
+};
diff --git a/src/hooks/Mutations/mastercraft/useCheckPaymentStatus.jsx b/src/hooks/Mutations/mastercraft/useCheckPaymentStatus.jsx
new file mode 100644
index 00000000..fc330f56
--- /dev/null
+++ b/src/hooks/Mutations/mastercraft/useCheckPaymentStatus.jsx
@@ -0,0 +1,131 @@
+import { useQuery } from "@tanstack/react-query";
+import { useCallback, useEffect, useRef, useState } from "react";
+import privateAxios from "../../../api/privateAxios";
+
+const useCheckPaymentStatus = (enrollmentId, options = {}) => {
+ const {
+ enabled = false,
+ pollingInterval = 5000,
+ maxAttempts = 3,
+ isOpen = true,
+ } = options;
+
+ const [status, setStatus] = useState({
+ isSuccess: false,
+ isError: false,
+ isPending: true,
+ message: "",
+ errorCode: null,
+ });
+
+ const attemptsRef = useRef(0);
+
+ const { data, isError, isSuccess, refetch, isLoading } = useQuery({
+ queryKey: ["paymentStatus", enrollmentId],
+ queryFn: async () => {
+ if (!enrollmentId) return null;
+ try {
+ const response = await privateAxios.get(`/callback/${enrollmentId}/`);
+ return response.data;
+ } catch (error) {
+ if (error.response?.status === 400) {
+ setStatus({
+ isSuccess: false,
+ isError: true,
+ isPending: false,
+ message: error.response.data?.message || "Payment failed",
+ errorCode: error.response.status,
+ });
+
+ return {
+ error: true,
+ message: error.response.data?.message || "Payment failed",
+ errorCode: error.response.status,
+ };
+ }
+ throw error;
+ }
+ },
+ enabled:
+ Boolean(enrollmentId) &&
+ enabled &&
+ attemptsRef.current < maxAttempts &&
+ isOpen,
+ refetchInterval: status.isPending ? pollingInterval : false,
+ refetchOnWindowFocus: false,
+ retry: (failureCount, error) => {
+ if (error.response?.status === 400) {
+ return false;
+ }
+ if (attemptsRef.current >= maxAttempts) {
+ return false;
+ }
+ return failureCount < maxAttempts;
+ },
+ });
+
+ useEffect(() => {
+ if ((isSuccess || isError) && !isLoading && status.isPending) {
+ attemptsRef.current += 1;
+ }
+
+ if (attemptsRef.current >= maxAttempts && status.isPending) {
+ setStatus({
+ isSuccess: false,
+ isError: true,
+ isPending: false,
+ message: "Payment verification timed out. Please contact support.",
+ errorCode: "TIMEOUT",
+ });
+ return;
+ }
+
+ if (isSuccess && data) {
+ if (data.error) {
+ setStatus({
+ isSuccess: false,
+ isError: true,
+ isPending: false,
+ message: data.message || "Payment failed",
+ errorCode: data.errorCode || "PAYMENT_FAILED",
+ });
+ } else {
+ setStatus({
+ isSuccess: true,
+ isError: false,
+ isPending: false,
+ message: data.message || "Payment successful",
+ errorCode: null,
+ });
+ }
+ }
+ }, [data, isSuccess, isError, isLoading, status.isPending, maxAttempts]);
+
+ const checkStatus = useCallback(() => {
+ if (!enrollmentId) return null;
+ attemptsRef.current = 0;
+ setStatus({
+ isSuccess: false,
+ isError: false,
+ isPending: true,
+ message: "",
+ errorCode: null,
+ });
+ return refetch();
+ }, [enrollmentId, refetch]);
+
+ useEffect(() => {
+ if (enrollmentId && enabled && isOpen) {
+ checkStatus();
+ }
+ }, [checkStatus, enabled, enrollmentId, isOpen]);
+
+ return {
+ ...status,
+ data,
+ checkStatus,
+ attemptsCount: attemptsRef.current,
+ };
+};
+
+export default useCheckPaymentStatus;
diff --git a/src/hooks/Mutations/mastercraft/useEnroll.jsx b/src/hooks/Mutations/mastercraft/useEnroll.jsx
new file mode 100644
index 00000000..a359375a
--- /dev/null
+++ b/src/hooks/Mutations/mastercraft/useEnroll.jsx
@@ -0,0 +1,49 @@
+/* eslint-disable no-alert */
+/* eslint-disable no-console */
+import { useMutation, useQueryClient } from "@tanstack/react-query";
+import privateAxios from "../../../api/privateAxios";
+
+const useEnroll = () => {
+ const queryClient = useQueryClient();
+
+ return useMutation({
+ mutationFn: async (formData) => {
+ const response = await privateAxios.post(
+ "/mastercraft-enrollment/",
+ formData,
+ {
+ headers: {
+ "Content-Type": "application/json",
+ },
+ }
+ );
+ return response.data;
+ },
+ mutationKey: ["enrollment"],
+ onSuccess: (data) => {
+ queryClient.invalidateQueries({ queryKey: ["enrollment"] });
+
+ return data;
+ },
+ onError: (error) => {
+ const profileErrors = error?.response?.data?.profile;
+
+ if (profileErrors && typeof profileErrors === "object") {
+ Object.entries(profileErrors).forEach(([field, messages]) => {
+ if (Array.isArray(messages)) {
+ messages.forEach((message) => {
+ console.error(`${field}: ${message}`);
+ alert(`${field}: ${message}`);
+ });
+ }
+ });
+ } else if (error?.response?.data?.program_name) {
+ console.error("Program name error:", error.response.data.program_name);
+ } else {
+ console.error("Enrollment failed with an unknown error", error);
+ }
+ },
+ });
+};
+
+export default useEnroll;
diff --git a/src/hooks/Mutations/shop/useCartSwagg.jsx b/src/hooks/Mutations/shop/useCartSwagg.jsx
index 3ae6fbda..90be5009 100644
--- a/src/hooks/Mutations/shop/useCartSwagg.jsx
+++ b/src/hooks/Mutations/shop/useCartSwagg.jsx
@@ -4,12 +4,12 @@ import useAuth from "../../useAuth";
// !!! choose colorSwagg
const useAddSwagToCart = () => {
- const { auth, logout } = useAuth();
+ const { logout } = useAuth();
const queryClient = useQueryClient();
- return useMutation(
- async (cartItems) => {
- const response = await publicAxios.post("/cart/swaggs/", cartItems, {
+ return useMutation({
+ mutationFn: async (cartItems) => {
+ const response = await publicAxios.post("/cart-items/", cartItems, {
headers: {
"Content-Type": "application/json",
// Authorization: `Bearer ${auth?.access}`,
@@ -17,51 +17,73 @@ const useAddSwagToCart = () => {
});
return response.data;
},
- {
- onSuccess: (data) => {
- console.log("Added to cart: ", data);
- queryClient.invalidateQueries(["productsInCart"]);
- },
- onError: (error) => {
- // eslint-disable-next-line no-console
- console.error("Unable to add availability");
- if (error.response.status === 401) {
- logout();
- }
- },
- }
- );
+ onSuccess: () => {
+ queryClient.invalidateQueries({ queryKey: ["productsInCart"] });
+ },
+ onError: (error) => {
+ // eslint-disable-next-line no-console
+ console.error("Unable to add availability");
+ if (error.response.status === 401) {
+ logout();
+ }
+ },
+ });
};
const useDeleteSwag = () => {
- const { auth, logout } = useAuth();
+ const { logout } = useAuth();
const queryClient = useQueryClient();
- return useMutation(
- async (id) => {
- const response = await publicAxios.delete(`/cart/swaggs/${id}/`, {
+ return useMutation({
+ mutationFn: async (id) => {
+ const response = await publicAxios.delete(`/cart-items/${id}/`, {
headers: {
"Content-Type": "application/json",
// Authorization: `Bearer ${auth?.access}`,
},
});
- console.log("response ", response.data);
+
return response.data;
},
- {
- onSuccess: (data) => {
- console.log("Successfully deleted ", data);
- queryClient.invalidateQueries(["productsInCart"]);
- },
- onError: (error) => {
- // eslint-disable-next-line no-console
- console.error("Unable to delete swag");
- if (error.response.status === 401) {
- logout();
- }
- },
- }
- );
+ onSuccess: () => {
+ queryClient.invalidateQueries({ queryKey: ["productsInCart"] });
+ },
+ onError: (error) => {
+ // eslint-disable-next-line no-console
+ console.error("Unable to delete swag");
+ if (error.response.status === 401) {
+ logout();
+ }
+ },
+ });
+};
+
+const useDeleteAllSwag = () => {
+ const { logout } = useAuth();
+ const queryClient = useQueryClient();
+
+ return useMutation({
+ mutationFn: async () => {
+ const response = await publicAxios.delete("/cart-items/clear_cart/", {
+ headers: {
+ "Content-Type": "application/json",
+ // Authorization: `Bearer ${auth?.access}`,
+ },
+ });
+
+ return response.data;
+ },
+ onSuccess: () => {
+ queryClient.invalidateQueries({ queryKey: ["productsInCart"] });
+ },
+ onError: (error) => {
+ // eslint-disable-next-line no-console
+ console.error("Unable to delete all cart items");
+ if (error.response.status === 401) {
+ logout();
+ }
+ },
+ });
};
-export { useAddSwagToCart, useDeleteSwag };
+export { useAddSwagToCart, useDeleteSwag, useDeleteAllSwag };
diff --git a/src/hooks/Mutations/shop/useMakeOrder.jsx b/src/hooks/Mutations/shop/useMakeOrder.jsx
index c3ecf2ea..df6b2e68 100644
--- a/src/hooks/Mutations/shop/useMakeOrder.jsx
+++ b/src/hooks/Mutations/shop/useMakeOrder.jsx
@@ -1,36 +1,34 @@
import { useMutation, useQueryClient } from "@tanstack/react-query";
import privateAxios from "../../../api/privateAxios";
-import useAuth from "../../useAuth";
+// import useAuth from "../../useAuth";
-// POST: https://apis.spaceyatech.com/api/orders/
+// POST: https://apis.spaceyatech.com/api/checkout/
const useMakeOrder = () => {
- const { auth, logout } = useAuth();
+ // const { auth, logout } = useAuth();
const queryClient = useQueryClient();
- return useMutation(
- async (customerInfo) => {
- const response = await privateAxios.post("/orders/", customerInfo, {
+ return useMutation({
+ mutationFn: async (customerInfo) => {
+ const response = await privateAxios.post("/checkout/", customerInfo, {
headers: {
"Content-Type": "application/json",
- Authorization: `Bearer ${auth?.access}`,
+ // Authorization: `Bearer ${auth?.access}`,
},
});
return response.data;
},
- {
- onSuccess: (data) => {
- console.log("Added to cart: ", data);
- queryClient.invalidateQueries(["productsInCart"]);
- },
- onError: (error) => {
- // eslint-disable-next-line no-console
- console.error("Unable to add availability");
- if (error.response.status === 401) {
- logout();
- }
- },
- }
- );
+
+ onSuccess: () => {
+ queryClient.invalidateQueries({ queryKey: ["productsInCart"] });
+ },
+ onError: (error) => {
+ // eslint-disable-next-line no-console
+ console.error("Unable to add availability");
+ if (error.response.status === 401) {
+ // logout();
+ }
+ },
+ });
};
export default useMakeOrder;
diff --git a/src/hooks/Queries/blog/useBlogData.jsx b/src/hooks/Queries/blog/useBlogData.jsx
index c4c47ef0..ec8f9d02 100644
--- a/src/hooks/Queries/blog/useBlogData.jsx
+++ b/src/hooks/Queries/blog/useBlogData.jsx
@@ -1,45 +1,47 @@
-import { useQuery } from "@tanstack/react-query";
-import axios from "axios";
-
-const fetchBlogData = async (title_slug) => {
- try {
- const response = await axios.get(
- `${process.env.REACT_APP_API_BASE_URL}/blog/${title_slug}`
- );
- return response.data;
- } catch (error) {
- console.error("Error fetching blog:", error);
- throw error;
- }
-};
-
-const useBlogData = (title_slug) =>
- useQuery({
- queryKey: ["blogdata"],
- queryFn: () => fetchBlogData(title_slug),
- refetchOnWindowFocus: false,
- staleTime: 5 * 60 * 60, // A recall will be made after 30 seconds
- });
-
-// fetch related blogs
-const fetchRelatedBlogs = async (categoryId) => {
- try {
- const url = `${process.env.REACT_APP_API_BASE_URL}/blog/category/${categoryId}`;
-
- const response = await axios.get(url);
-
- return response.data;
- } catch (error) {
- throw new Error(error);
- }
-};
-
-export const useRelatedBlogsData = (categoryId) =>
- useQuery({
- queryKey: ["relatedBlogsData"],
- queryFn: () => fetchRelatedBlogs(categoryId),
- refetchOnWindowFocus: false,
- staleTime: 5 * 60 * 60, // A recall will be made after 30 seconds
- });
-
-export default useBlogData;
+/* eslint-disable camelcase */
+import { useQuery } from "@tanstack/react-query";
+import axios from "axios";
+import toast from "react-hot-toast";
+
+const fetchBlogData = async (title_slug) => {
+ try {
+ const response = await axios.get(
+ `${process.env.REACT_APP_API_BASE_URL}/blog/${title_slug}`
+ );
+ return response.data;
+ } catch (error) {
+ toast.error("Error fetching blog:", error);
+ throw error;
+ }
+};
+
+const useBlogData = (title_slug) =>
+ useQuery({
+ queryKey: ["blogdata"],
+ queryFn: () => fetchBlogData(title_slug),
+ refetchOnWindowFocus: false,
+ staleTime: 5 * 60 * 60, // A recall will be made after 30 seconds
+ });
+
+// fetch related blogs
+const fetchRelatedBlogs = async (categoryId) => {
+ try {
+ const url = `${process.env.REACT_APP_API_BASE_URL}/blog/category/${categoryId}`;
+
+ const response = await axios.get(url);
+
+ return response.data;
+ } catch (error) {
+ throw new Error(error);
+ }
+};
+
+export const useRelatedBlogsData = (categoryId) =>
+ useQuery({
+ queryKey: ["relatedBlogsData"],
+ queryFn: () => fetchRelatedBlogs(categoryId),
+ refetchOnWindowFocus: false,
+ staleTime: 5 * 60 * 60, // A recall will be made after 30 seconds
+ });
+
+export default useBlogData;
diff --git a/src/hooks/Queries/blog/usePostLikeBlog.jsx b/src/hooks/Queries/blog/usePostLikeBlog.jsx
index c59ffd6e..545bc0fb 100644
--- a/src/hooks/Queries/blog/usePostLikeBlog.jsx
+++ b/src/hooks/Queries/blog/usePostLikeBlog.jsx
@@ -1,58 +1,60 @@
-import axios from 'axios';
-import React, { useEffect, useState } from 'react'
+/* eslint-disable no-unused-expressions */
+import axios from "axios";
+import { useEffect, useState } from "react";
const usePostLikeBlog = () => {
- const [ blogIDLikes, setBlogIDLikes ] = useState(null);
- const [ error, setError ] = useState(null);
- const [ status, setStatus ] = useState(null);
+ const [blogIDLikes, setBlogIDLikes] = useState(null);
+ const [error, setError] = useState(null);
+ const [status, setStatus] = useState(null);
- const clearError = (error = 'all') => {
- error === 'all' && setError(null);
- }
+ const clearError = (errorArg = "all") => {
+ errorArg === "all" && setError(null);
+ };
- const clearStatus = (status = 'all') => {
- status === 'all' && setStatus(null);
- }
+ const clearStatus = (statusArg = "all") => {
+ statusArg === "all" && setStatus(null);
+ };
useEffect(() => {
if (blogIDLikes) {
- axios.post(
- `${process.env.REACT_APP_API_BASE_URL}/blog/${blogIDLikes.id}/like/`
- ).then(response => {
- if (response.status === 200 || response.status === 201) {
- setStatus("success");
- // setChapterData(null);
- setError(null);
- } else {
- setStatus("error");
- setError(response.data);
- }
- }).catch((error) => {
- switch (error.code) {
- case 'ERR_NETWORK':
- setError({ axios: error.message });
+ axios
+ .post(
+ `${process.env.REACT_APP_API_BASE_URL}/blog/${blogIDLikes.id}/like/`
+ )
+ .then((response) => {
+ if (response.status === 200 || response.status === 201) {
+ setStatus("success");
+ // setChapterData(null);
+ setError(null);
+ } else {
setStatus("error");
- break;
- case 'ERR_BAD_REQUEST':
- error.response ? (
- setError({
- blog: error.response.data
- })
- ) : (
- setError({ server: "Problem contacting the server!" })
- );
- setStatus("error");
- break;
- default:
- setStatus("error");
- setError({ axios: "Please try again later."})
- break;
- }
- })
+ setError(response.data);
+ }
+ })
+ .catch((err) => {
+ switch (err.code) {
+ case "ERR_NETWORK":
+ setError({ axios: err.message });
+ setStatus("error");
+ break;
+ case "ERR_BAD_REQUEST":
+ err.response
+ ? setError({
+ blog: err.response.data,
+ })
+ : setError({ server: "Problem contacting the server!" });
+ setStatus("error");
+ break;
+ default:
+ setStatus("error");
+ setError({ axios: "Please try again later." });
+ break;
+ }
+ });
}
}, [blogIDLikes]);
return { setBlogIDLikes, error, clearError, status, clearStatus };
-}
+};
-export default usePostLikeBlog
\ No newline at end of file
+export default usePostLikeBlog;
diff --git a/src/hooks/Queries/blogs/useAllBlogsData.jsx b/src/hooks/Queries/blogs/useAllBlogsData.jsx
index d119d919..af30a89b 100644
--- a/src/hooks/Queries/blogs/useAllBlogsData.jsx
+++ b/src/hooks/Queries/blogs/useAllBlogsData.jsx
@@ -1,73 +1,71 @@
-import { useQuery } from "@tanstack/react-query";
-import axios from "axios";
-
-const fetchBlogCategories = async () => {
- try {
- const response = await axios.get(
- `${process.env.REACT_APP_API_BASE_URL}/blog/category/`
- );
- return response.data;
- } catch (error) {
- console.error("Error fetching blog categories: ", error);
- throw error;
- }
-};
-
-const useBlogCategories = () => {
- return useQuery({
- queryKey: ["blogcategories"],
- queryFn: () => fetchBlogCategories(),
- refetchOnWindowFocus: false,
- staleTime: 5 * 60 * 60, // A recall will be made after 30 seconds
- });
-};
-
-const fetchBlogsData = async (page) => {
- let url = `${process.env.REACT_APP_API_BASE_URL}/blog/`;
-
- if (page) {
- url += `?page=${page}`;
- }
-
- try {
- const response = await axios.get(url);
- return response.data;
- } catch (error) {
- console.error("Error fetching blogs:", error);
- throw error;
- }
-};
-
-const useBlogsData = (page) => {
- return useQuery({
- queryKey: ["blogsdata"],
- queryFn: () => fetchBlogsData(page),
- refetchOnWindowFocus: false,
- staleTime: 5 * 60 * 60, // A recall will be made after 30 seconds
- });
-};
-
-// Search blog
-const fetchSearchBlog = async (keyword) => {
- // if (keyword === "") return;
-
- const url = `${process.env.REACT_APP_API_BASE_URL}/blog/?keyword=${keyword}`;
-
- try {
- const response = await axios.get(url);
- return response.data;
- } catch (error) {
- throw new Error(error);
- }
-};
-
-const useSearchBlog = (keyword) => {
- return useQuery({
- queryKey: ["searchBlog"],
- queryFn: () => fetchSearchBlog(keyword),
- refetchOnWindowFocus: false,
- staleTime: 5 * 60 * 60,
- });
-};
-
-export { useBlogsData, useBlogCategories, useSearchBlog };
+import { useQuery } from "@tanstack/react-query";
+import axios from "axios";
+import toast from "react-hot-toast";
+
+const fetchBlogCategories = async () => {
+ try {
+ const response = await axios.get(
+ `${process.env.REACT_APP_API_BASE_URL}/blog/category/`
+ );
+ return response.data;
+ } catch (error) {
+ toast.error("Error fetching blog categories: ", error);
+ throw error;
+ }
+};
+
+const useBlogCategories = () =>
+ useQuery({
+ queryKey: ["blogcategories"],
+ queryFn: () => fetchBlogCategories(),
+ refetchOnWindowFocus: false,
+ staleTime: 5 * 60 * 60, // A recall will be made after 30 seconds
+ });
+
+const fetchBlogsData = async (page) => {
+ let url = `${process.env.REACT_APP_API_BASE_URL}/blog/`;
+
+ if (page) {
+ url += `?page=${page}`;
+ }
+
+ try {
+ const response = await axios.get(url);
+ return response.data;
+ } catch (error) {
+ toast.error("Error fetching blogs:", error);
+ throw error;
+ }
+};
+
+const useBlogsData = (page) =>
+ useQuery({
+ queryKey: ["blogsdata"],
+ queryFn: () => fetchBlogsData(page),
+ refetchOnWindowFocus: false,
+ staleTime: 5 * 60 * 60, // A recall will be made after 30 seconds
+ });
+
+// Search blog
+const fetchSearchBlog = async (keyword) => {
+ // if (keyword === "") return;
+
+ const url = `${process.env.REACT_APP_API_BASE_URL}/blog/?keyword=${keyword}`;
+
+ try {
+ const response = await axios.get(url);
+ return response.data;
+ } catch (error) {
+ throw new Error(error);
+ }
+};
+
+const useSearchBlog = (keyword) =>
+ useQuery({
+ queryKey: ["searchBlog"],
+ queryFn: () => fetchSearchBlog(keyword),
+ refetchOnWindowFocus: false,
+ staleTime: 5 * 60 * 60,
+ });
+
+export { useBlogsData, useBlogCategories, useSearchBlog };
diff --git a/src/hooks/Queries/chapter/useIndividualChapter.jsx b/src/hooks/Queries/chapter/useIndividualChapter.jsx
index 8d85116b..a1b0e1d2 100644
--- a/src/hooks/Queries/chapter/useIndividualChapter.jsx
+++ b/src/hooks/Queries/chapter/useIndividualChapter.jsx
@@ -1,5 +1,6 @@
-import axios from "axios";
import { useQuery } from "@tanstack/react-query";
+import axios from "axios";
+import toast from "react-hot-toast";
// interface Organizer {
// id: number;
@@ -56,22 +57,23 @@ import { useQuery } from "@tanstack/react-query";
// }
const fetchChapterData = async (id) => {
- try {
- const response = await axios.get(`${process.env.REACT_APP_API_BASE_URL}/chapter/${id}/`);
- return response.data;
- } catch (error) {
- console.error('Error fetching chapter data:', error);
- throw error;
- }
-}
+ try {
+ const response = await axios.get(
+ `${process.env.REACT_APP_API_BASE_URL}/chapter/${id}/`
+ );
+ return response.data;
+ } catch (error) {
+ toast.error("Error fetching chapter data:", error);
+ throw error;
+ }
+};
-const useIndividualChapterData = (id) => {
- return useQuery({
- queryKey: ["oneChapter"],
- queryFn: () => fetchChapterData(id),
- refetchOnWindowFocus: false,
- staleTime: 5 * 60 * 60, // A recall will be made after 30 seconds
- });
- };
+const useIndividualChapterData = (id) =>
+ useQuery({
+ queryKey: ["oneChapter"],
+ queryFn: () => fetchChapterData(id),
+ refetchOnWindowFocus: false,
+ staleTime: 5 * 60 * 60, // A recall will be made after 30 seconds
+ });
export default useIndividualChapterData;
diff --git a/src/hooks/Queries/chapter/usePostAddChapter.jsx b/src/hooks/Queries/chapter/usePostAddChapter.jsx
index 6267432e..076d0e08 100644
--- a/src/hooks/Queries/chapter/usePostAddChapter.jsx
+++ b/src/hooks/Queries/chapter/usePostAddChapter.jsx
@@ -1,82 +1,80 @@
-import axios from 'axios';
-import React, { useEffect, useState } from 'react'
-
-const usePostAddChapter = () => {
- const [ chapterData, setChapterData ] = useState(null);
- const [ error, setError ] = useState(null);
- const [ status, setStatus ] = useState(null);
-
- const clearError = (error = 'all') => {
- error === 'all' && setError(null);
- // Clear one item's error?
- }
-
- const clearStatus = (status = 'all') => {
- status === 'all' && setStatus(null);
- // Clear one item's status?
- }
-
- useEffect(() => {
- if (chapterData) {
- const formData = new FormData();
-
- formData.append('country', chapterData.country);
- formData.append('city', chapterData.city);
- formData.append('name', chapterData.name);
- formData.append('about', chapterData.about);
- formData.append('socials', JSON.stringify(chapterData.socials));
- formData.append('banner', chapterData.banner);
-
- chapterData.organizers.forEach((organizer, index) => {
- const newOrganizer = {...organizer}
- formData.append(`organizer.${index}.image`, organizer.image);
- delete newOrganizer.image;
- formData.append(`organizers`, JSON.stringify(newOrganizer));
- });
-
- axios.post(
- `${process.env.REACT_APP_API_BASE_URL}/chapter/`,
- formData,
- {
- headers: {
- 'Content-Type': 'multipart/form-data'
- }
- }
- ).then(response => {
- if (response.status === 200 || response.status === 201) {
- setStatus("success");
- setChapterData(null);
- setError(null);
- } else {
- setStatus("error");
- setError(response.data);
- }
- }).catch((error) => {
- switch (error.code) {
- case 'ERR_NETWORK':
- setError({ axios: error.message });
- setStatus("error");
- break;
- case 'ERR_BAD_REQUEST':
- error.response ? (
- setError({
- chapter: error.response.data
- })
- ) : (
- setError({ server: "Problem contacting the server!" })
- );
- setStatus("error");
- break;
- default:
- setStatus("error");
- setError({ axios: "Please try again later."})
- break;
- }
- })
- }
- }, [chapterData]);
-
- return { setChapterData, error, clearError, status, clearStatus};
-}
-
-export default usePostAddChapter
\ No newline at end of file
+/* eslint-disable no-unused-expressions */
+import axios from "axios";
+import { useEffect, useState } from "react";
+
+const usePostAddChapter = () => {
+ const [chapterData, setChapterData] = useState(null);
+ const [error, setError] = useState(null);
+ const [status, setStatus] = useState(null);
+
+ const clearError = (errorArg = "all") => {
+ errorArg === "all" && setError(null);
+ // Clear one item's error?
+ };
+
+ const clearStatus = (statusArg = "all") => {
+ statusArg === "all" && setStatus(null);
+ // Clear one item's status?
+ };
+
+ useEffect(() => {
+ if (chapterData) {
+ const formData = new FormData();
+
+ formData.append("country", chapterData.country);
+ formData.append("city", chapterData.city);
+ formData.append("name", chapterData.name);
+ formData.append("about", chapterData.about);
+ formData.append("socials", JSON.stringify(chapterData.socials));
+ formData.append("banner", chapterData.banner);
+
+ chapterData.organizers.forEach((organizer, index) => {
+ const newOrganizer = { ...organizer };
+ formData.append(`organizer.${index}.image`, organizer.image);
+ delete newOrganizer.image;
+ formData.append("organizers", JSON.stringify(newOrganizer));
+ });
+
+ axios
+ .post(`${process.env.REACT_APP_API_BASE_URL}/chapter/`, formData, {
+ headers: {
+ "Content-Type": "multipart/form-data",
+ },
+ })
+ .then((response) => {
+ if (response.status === 200 || response.status === 201) {
+ setStatus("success");
+ setChapterData(null);
+ setError(null);
+ } else {
+ setStatus("error");
+ setError(response.data);
+ }
+ })
+ .catch((err) => {
+ switch (err.code) {
+ case "ERR_NETWORK":
+ setError({ axios: err.message });
+ setStatus("error");
+ break;
+ case "ERR_BAD_REQUEST":
+ err.response
+ ? setError({
+ chapter: err.response.data,
+ })
+ : setError({ server: "Problem contacting the server!" });
+ setStatus("error");
+ break;
+ default:
+ setStatus("error");
+ setError({ axios: "Please try again later." });
+ break;
+ }
+ });
+ }
+ }, [chapterData]);
+
+ return { setChapterData, error, clearError, status, clearStatus };
+};
+
+export default usePostAddChapter;
diff --git a/src/hooks/Queries/chapter/usePostJoinChapter.jsx b/src/hooks/Queries/chapter/usePostJoinChapter.jsx
index 58c5a700..0e2ab2b1 100644
--- a/src/hooks/Queries/chapter/usePostJoinChapter.jsx
+++ b/src/hooks/Queries/chapter/usePostJoinChapter.jsx
@@ -1,42 +1,48 @@
-import axios from 'axios';
-import React, { useEffect, useState } from 'react'
+import axios from "axios";
+import { useEffect, useState } from "react";
const usePostJoinChapter = (chapterId) => {
- const [ postEmail, setPostEmail ] = useState(null);
- const [ error, setError ] = useState(null);
- const [ status, setStatus ] = useState(null);
+ const [postEmail, setPostEmail] = useState(null);
+ const [error, setError] = useState(null);
+ const [status, setStatus] = useState(null);
const clearError = () => setError(null);
const clearStatus = () => setStatus(null);
useEffect(() => {
if (postEmail) {
- axios.post(`${process.env.REACT_APP_API_BASE_URL}/chapter/${chapterId}/members/`,
- JSON.stringify(postEmail),
- {headers: {
- "Content-Type": "application/json",
- }}
- ).then((response) => {
- if (response.status === 200 || response.status === 201) {
- setStatus("success");
- setPostEmail(null);
- setError(null);
- } else {
+ axios
+ .post(
+ `${process.env.REACT_APP_API_BASE_URL}/chapter/${chapterId}/members/`,
+ JSON.stringify(postEmail),
+ {
+ headers: {
+ "Content-Type": "application/json",
+ },
+ }
+ )
+ .then((response) => {
+ if (response.status === 200 || response.status === 201) {
+ setStatus("success");
+ setPostEmail(null);
+ setError(null);
+ } else {
+ setStatus("error");
+ setError(response.data);
+ }
+ })
+ .catch((err) => {
+ if (err.response && err.response.status === 400) {
+ setError(err.response.data);
+ }
setStatus("error");
- setError(response.data);
- }
- }).catch((error) => {
- if (error.response && error.response.status===400) {
- setError(error.response.data);
- }
- setStatus("error");
- // console.error("Error adding chapter: ", error);
- // throw error;
- })
+ // console.error("Error adding chapter: ", error);
+ throw err;
+ });
}
}, [postEmail, chapterId]);
-
+
return { setPostEmail, error, clearError, status, clearStatus };
-}
+};
-export default usePostJoinChapter
\ No newline at end of file
+export default usePostJoinChapter;
diff --git a/src/hooks/Queries/community/useChaptersData.jsx b/src/hooks/Queries/community/useChaptersData.jsx
index 7d21fa9a..5c69ed01 100644
--- a/src/hooks/Queries/community/useChaptersData.jsx
+++ b/src/hooks/Queries/community/useChaptersData.jsx
@@ -1,5 +1,6 @@
-import axios from "axios";
import { useQuery } from "@tanstack/react-query";
+import axios from "axios";
+import toast from "react-hot-toast";
// interface Chapter {
// id: number;
@@ -17,18 +18,17 @@ const fetchChaptersData = async () => {
);
return response.data;
} catch (error) {
- console.error("Error fetching chapters:", error);
+ toast.error("Error fetching chapters:", error);
throw error;
}
};
-const useChaptersData = () => {
- return useQuery({
+const useChaptersData = () =>
+ useQuery({
queryKey: ["allChapters"],
queryFn: () => fetchChaptersData(),
refetchOnWindowFocus: false,
staleTime: 5 * 60 * 60, // A recall will be made after 30 seconds
});
-};
export default useChaptersData;
diff --git a/src/hooks/Queries/eventsSection/useEventCategories.jsx b/src/hooks/Queries/eventsSection/useEventCategories.jsx
index e1602701..a83fef78 100644
--- a/src/hooks/Queries/eventsSection/useEventCategories.jsx
+++ b/src/hooks/Queries/eventsSection/useEventCategories.jsx
@@ -1,5 +1,6 @@
import { useQuery } from "@tanstack/react-query";
import axios from "axios";
+import toast from "react-hot-toast";
// interface EventCategory {
// id: number;
@@ -13,19 +14,18 @@ const fetchEventsCategories = async () => {
);
return response.data;
} catch (error) {
- console.error("Error fetching events categories: ", error);
+ toast.error("Error fetching events categories: ", error);
throw error;
}
};
-const useEventsCategories = () => {
- return useQuery({
+const useEventsCategories = () =>
+ useQuery({
queryKey: ["eventsCategories"],
queryFn: () => fetchEventsCategories(),
refetchOnWindowFocus: false,
staleTime: 5 * 60 * 60, // A recall will be made after 30 seconds
});
-};
// interface Event {
// id: number;
// name: string;
@@ -72,7 +72,7 @@ const fetchEvents = async (filterArray) => {
if (filterArray !== null) {
filterString += "?";
Object.keys(filterArray).forEach((key) => {
- filterString += key + "=" + filterArray[key] + "&";
+ filterString += `${key}=${filterArray[key]}&`;
});
url += filterString;
@@ -82,19 +82,18 @@ const fetchEvents = async (filterArray) => {
const response = await axios.get(url);
return response.data;
} catch (error) {
- console.error("Error fetching events: ", error);
+ toast.error("Error fetching events: ", error);
throw error;
}
};
-const useAllEvents = (filters) => {
- return useQuery({
+const useAllEvents = (filters) =>
+ useQuery({
queryKey: ["allEvents"],
queryFn: () => fetchEvents(filters),
refetchOnWindowFocus: false,
staleTime: 5 * 60 * 60, // A recall will be made after 30 seconds
});
-};
const fetchCities = async () => {
try {
@@ -103,18 +102,17 @@ const fetchCities = async () => {
);
return response.data;
} catch (error) {
- console.error("Error fetching cities: ", error);
+ toast.error("Error fetching cities: ", error);
throw error;
}
};
-const useAllCities = () => {
- return useQuery({
+const useAllCities = () =>
+ useQuery({
queryKey: ["topCities"],
queryFn: () => fetchCities(),
refetchOnWindowFocus: false,
staleTime: 5 * 60 * 60, // A recall will be made after 30 seconds
});
-};
export { useAllCities, useEventsCategories, useAllEvents, fetchEvents };
diff --git a/src/hooks/Queries/eventsSection/useEvents.jsx b/src/hooks/Queries/eventsSection/useEvents.jsx
index 412e4cc9..7de31169 100644
--- a/src/hooks/Queries/eventsSection/useEvents.jsx
+++ b/src/hooks/Queries/eventsSection/useEvents.jsx
@@ -1,5 +1,6 @@
import { useQuery } from "@tanstack/react-query";
import axios from "axios";
+import toast from "react-hot-toast";
const fetchEvents = async (catName = "") => {
try {
@@ -8,7 +9,7 @@ const fetchEvents = async (catName = "") => {
return response.data;
} catch (error) {
- console.error("Error fetching similar Events: ", error);
+ toast.error("Error fetching similar Events");
throw new Error(error);
}
};
diff --git a/src/hooks/Queries/eventsSection/usePostEvents.jsx b/src/hooks/Queries/eventsSection/usePostEvents.jsx
index 1bf46200..69b1ad7b 100644
--- a/src/hooks/Queries/eventsSection/usePostEvents.jsx
+++ b/src/hooks/Queries/eventsSection/usePostEvents.jsx
@@ -1,107 +1,111 @@
-import React, { useEffect, useState } from 'react'
-import axios from "axios";
-
-const usePostEvents = () => {
- const [ eventData, setEventData ] = useState(null);
- const [ error, setError ] = useState(null);
- const [ status, setStatus ] = useState(null);
-
- const clearError = (error = 'all') => {
- error === 'all' && setError(null);
- // Clear one items error?
- }
-
- const clearStatus = (status = 'all') => {
- status === 'all' && setStatus(null);
- // Clear one item's status
- }
-
- const postFunction = (formData) => {
- axios.post(
- `${process.env.REACT_APP_API_BASE_URL}/events/`,
- formData,
- {
- headers: {
- 'Content-Type': 'multipart/form-data'
- }
- }). then(response => {
- if (response.status == 200 || response.status ==201) {
- setStatus("success");
- setEventData(null);
- setError(null);
- } else {
- setStatus("error");
- setError(response.data);
- }
- }).catch(error => {
- console.log("The error", error)
- switch (error.code) {
- case 'ERR_NETWORK':
- setError({ axios: error.message });
- setStatus("error");
- break;
- case 'ERR_BAD_REQUEST':
- if (error.response) {
- if (error.response.status === 404) {
- setError( {axios: "Cannot post the event to the server."})
- } else {
- setError({ event: error.response.data })
- }
- } else {
- setError({ axios: "Problem contacting the server!" })
- }
- setStatus("error");
- break;
- default:
- setStatus("error");
- setError({ axios: "Please try again later."});
- break;
- }
- });
- }
-
- useEffect(() => {
- if (eventData) {
- const formData = new FormData();
-
- formData.append('name', eventData.name);
- formData.append('about', eventData.about);
- formData.append('link', eventData.link);
- formData.append('location', eventData.location);
- formData.append('mode', eventData.mode);
- formData.append('city', eventData.city);
- formData.append('country', eventData.country);
- formData.append('date', eventData.date);
- formData.append('start_time', eventData.start_time);
- formData.append('end_time', eventData.end_time);
- formData.append('poster', eventData.poster);
- formData.append('chapter_id', eventData.chapter);
-
- if (eventData.category_name) {
- axios.post(
- `${process.env.REACT_APP_API_BASE_URL}/events-categories/`,
- JSON.stringify({"name": eventData.category_name}),
- {
- headers: {
- 'Content-Type': 'application/json'
- }
- }).then(response => {
- if (response.status == 200 || response.status == 201) {
- formData.append('category_id', response.data.id);
- postFunction(formData);
- }
- }).catch (error => {
- setError({ server: "Problem creating the new event category!" })
- setStatus("error");
- });
- } else {
- formData.append("category_id", eventData.category);
- postFunction(formData);
- }
- }
- }, [eventData])
-
- return {setEventData, error, clearError, status, clearStatus}
-}
-
-export default usePostEvents
\ No newline at end of file
+/* eslint-disable no-unused-expressions */
+import axios from "axios";
+import { useEffect, useState } from "react";
+
+const usePostEvents = () => {
+ const [eventData, setEventData] = useState(null);
+ const [error, setError] = useState(null);
+ const [status, setStatus] = useState(null);
+
+ const clearError = (err = "all") => {
+ err === "all" && setError(null);
+ // Clear one items error?
+ };
+
+ const clearStatus = (statusArg = "all") => {
+ statusArg === "all" && setStatus(null);
+ // Clear one item's status
+ };
+
+ const postFunction = (formData) => {
+ axios
+ .post(`${process.env.REACT_APP_API_BASE_URL}/events/`, formData, {
+ headers: {
+ "Content-Type": "multipart/form-data",
+ },
+ })
+ .then((response) => {
+ if (response.status === 200 || response.status === 201) {
+ setStatus("success");
+ setEventData(null);
+ setError(null);
+ } else {
+ setStatus("error");
+ setError(response.data);
+ }
+ })
+ .catch((Error) => {
+ switch (Error.code) {
+ case "ERR_NETWORK":
+ setError({ axios: Error.message });
+ setStatus("error");
+ break;
+ case "ERR_BAD_REQUEST":
+ if (Error.response) {
+ if (Error.response.status === 404) {
+ setError({ axios: "Cannot post the event to the server." });
+ } else {
+ setError({ event: Error.response.data });
+ }
+ } else {
+ setError({ axios: "Problem contacting the server!" });
+ }
+ setStatus("error");
+ break;
+ default:
+ setStatus("error");
+ setError({ axios: "Please try again later." });
+ break;
+ }
+ });
+ };
+
+ useEffect(() => {
+ if (eventData) {
+ const formData = new FormData();
+
+ formData.append("name", eventData.name);
+ formData.append("about", eventData.about);
+ formData.append("link", eventData.link);
+ formData.append("location", eventData.location);
+ formData.append("mode", eventData.mode);
+ formData.append("city", eventData.city);
+ formData.append("country", eventData.country);
+ formData.append("date", eventData.date);
+ formData.append("start_time", eventData.start_time);
+ formData.append("end_time", eventData.end_time);
+ formData.append("poster", eventData.poster);
+ formData.append("chapter_id", eventData.chapter);
+
+ if (eventData.category_name) {
+ axios
+ .post(
+ `${process.env.REACT_APP_API_BASE_URL}/events-categories/`,
+ JSON.stringify({ name: eventData.category_name }),
+ {
+ headers: {
+ "Content-Type": "application/json",
+ },
+ }
+ )
+ .then((response) => {
+ if (response.status === 200 || response.status === 201) {
+ formData.append("category_id", response.data.id);
+ postFunction(formData);
+ }
+ })
+ .catch(() => {
+ setError({ server: "Problem creating the new event category!" });
+ setStatus("error");
+ });
+ } else {
+ formData.append("category_id", eventData.category);
+ postFunction(formData);
+ }
+ }
+ }, [eventData]);
+
+ return { setEventData, error, clearError, status, clearStatus };
+};
+
+export default usePostEvents;
diff --git a/src/hooks/Queries/eventsSection/useTopEvents.jsx b/src/hooks/Queries/eventsSection/useTopEvents.jsx
index d6e44d94..de845872 100644
--- a/src/hooks/Queries/eventsSection/useTopEvents.jsx
+++ b/src/hooks/Queries/eventsSection/useTopEvents.jsx
@@ -1,5 +1,6 @@
-import axios from "axios";
import { useQuery } from "@tanstack/react-query";
+import axios from "axios";
+import toast from "react-hot-toast";
// interface Filter {
// name: string;
@@ -12,25 +13,24 @@ const fetchEventData = async (filterArray) => {
if (filterArray) {
Object.keys(filterArray).forEach((key) => {
- filterArray[key] !== null &&
- (url += `&` + key + "=" + filterArray[key]);
+ // eslint-disable-next-line no-unused-expressions
+ filterArray[key] !== null && (url += `&${key}=${filterArray[key]}`);
});
}
const response = await axios.get(url);
return response.data;
} catch (error) {
- console.error("Error fetching events: ", error);
- // throw error;
+ toast.error("Error fetching events");
+ throw error;
}
};
-const useTopEvents = (filters) => {
- return useQuery({
+const useTopEvents = (filters) =>
+ useQuery({
queryKey: ["topEvents"],
queryFn: () => fetchEventData(filters),
refetchOnWindowFocus: true,
staleTime: 5 * 60 * 60, // A recall will be made after 30 seconds
});
-};
export default useTopEvents;
diff --git a/src/hooks/Queries/resources/useResourcesData.jsx b/src/hooks/Queries/resources/useResourcesData.jsx
index e5a09050..5926614b 100644
--- a/src/hooks/Queries/resources/useResourcesData.jsx
+++ b/src/hooks/Queries/resources/useResourcesData.jsx
@@ -1,29 +1,31 @@
-import axios from "axios";
-import { useQuery } from "@tanstack/react-query";
-
-// interface Resource {
-// id: number;
-// name: string;
-// description: string;
-// }
-
-const fetchResourcesData = async () => {
- try {
- const response = await axios.get(`${process.env.REACT_APP_API_BASE_URL}/resourcetypes/`);
- return response.data;
- } catch (error) {
- console.error("Error fetching resources:", error);
- throw error;
- }
-}
-
-const useResourcesData = (id) => {
- return useQuery({
- queryKey: ["resourcetypes"],
- queryFn: () => fetchResourcesData(),
- refetchOnWindowFocus: false,
- staleTime: 5 * 60 * 60, // A recall will be made after 30 seconds
- });
-};
-
-export default useResourcesData;
\ No newline at end of file
+import { useQuery } from "@tanstack/react-query";
+import axios from "axios";
+import toast from "react-hot-toast";
+
+// interface Resource {
+// id: number;
+// name: string;
+// description: string;
+// }
+
+const fetchResourcesData = async () => {
+ try {
+ const response = await axios.get(
+ `${process.env.REACT_APP_API_BASE_URL}/resourcetypes/`
+ );
+ return response.data;
+ } catch (error) {
+ toast.error("Error fetching resources");
+ throw error;
+ }
+};
+
+const useResourcesData = () =>
+ useQuery({
+ queryKey: ["resourcetypes"],
+ queryFn: () => fetchResourcesData(),
+ refetchOnWindowFocus: false,
+ staleTime: 5 * 60 * 60, // A recall will be made after 30 seconds
+ });
+
+export default useResourcesData;
diff --git a/src/hooks/Queries/shop/useCartProducts.jsx b/src/hooks/Queries/shop/useCartProducts.jsx
index 33f88a22..d3f9ee24 100644
--- a/src/hooks/Queries/shop/useCartProducts.jsx
+++ b/src/hooks/Queries/shop/useCartProducts.jsx
@@ -1,23 +1,24 @@
// https://apis.spaceyatech.com/api/cart/swaggs/
import { useQuery } from "@tanstack/react-query";
+import toast from "react-hot-toast";
import publicAxios from "../../../api/publicAxios";
const fetchProductsInCart = async () => {
- const authObject = JSON.parse(localStorage.getItem("auth")) || {};
- const { access } = authObject;
+ // const authObject = JSON.parse(localStorage.getItem("auth")) || {};
+ // const { access } = authObject;
try {
- const response = await publicAxios.get("/cart/swaggs/", {
+ const response = await publicAxios.get("/cart-items/", {
headers: {
"Content-Type": "application/json",
// Authorization: `Bearer ${access}`,
},
});
- console.log("fetchProductsInCart: ", response.data); // !!! Image doesn't have a prefixed URL domain i.e it comes as "/media/product_images/main-sample_copy.png" instead of "https://apis.spaceyatech.com/media/product_images/main-sample_copy.png"
return response.data;
} catch (error) {
- console.error("Error fetching products in cart: ", error);
+ toast.error("Error fetching products in cart");
+
// if (error.response.status === 401) {
// localStorage.removeItem("auth");
// }
@@ -26,7 +27,6 @@ const fetchProductsInCart = async () => {
};
const useProductsInCart = () =>
- // eslint-disable-next-line implicit-arrow-linebreak
useQuery({
queryKey: ["productsInCart"],
queryFn: () => fetchProductsInCart(),
diff --git a/src/hooks/Queries/shop/useOrdersList.jsx b/src/hooks/Queries/shop/useOrdersList.jsx
index a6e0924d..d36984af 100644
--- a/src/hooks/Queries/shop/useOrdersList.jsx
+++ b/src/hooks/Queries/shop/useOrdersList.jsx
@@ -1,5 +1,6 @@
// https://apis.spaceyatech.com/api/orders//
import { useQuery } from "@tanstack/react-query";
+import toast from "react-hot-toast";
import publicAxios from "../../../api/publicAxios";
const fetchOrders = async () => {
@@ -7,7 +8,7 @@ const fetchOrders = async () => {
const response = await publicAxios.get("/orders/");
return response.data;
} catch (error) {
- console.error("Error fetching order summary: ", error);
+ toast.error("Error fetching order summary");
throw error;
}
};
@@ -34,7 +35,7 @@ const fetchSingleOrder = async (id) => {
});
return response.data;
} catch (error) {
- console.error("Error fetching order item: ", error);
+ toast.error("Error fetching order item");
if (error.response.status === 401) {
localStorage.removeItem("auth");
}
@@ -44,7 +45,7 @@ const fetchSingleOrder = async (id) => {
const useSingleOrder = (id) =>
useQuery({
- queryKey: ["singleOrder"],
+ queryKey: ["singleOrder", id],
queryFn: () => fetchSingleOrder(id),
refetchOnWindowFocus: true,
staleTime: 5 * 60 * 60,
diff --git a/src/hooks/Queries/shop/useSwagList.jsx b/src/hooks/Queries/shop/useSwagList.jsx
index e07198d3..2201942f 100644
--- a/src/hooks/Queries/shop/useSwagList.jsx
+++ b/src/hooks/Queries/shop/useSwagList.jsx
@@ -1,15 +1,13 @@
-// https://apis.spaceyatech.com/api/swaggs/
import { useQuery } from "@tanstack/react-query";
+import toast from "react-hot-toast";
import publicAxios from "../../../api/publicAxios";
const fetchSwag = async () => {
try {
- const response = await publicAxios.get("/swaggs/");
- console.log("useSwagList", response.data);
-
+ const response = await publicAxios.get("/swaggsnew");
return response.data;
} catch (error) {
- console.error("Error fetching swag list: ", error);
+ toast.error("Error fetching swag list");
throw error;
}
};
@@ -23,19 +21,36 @@ const useSwagList = () =>
const fetchSingleSwag = async (id) => {
try {
- const response = await publicAxios.get(`/swaggs/${id}`);
+ const response = await publicAxios.get(`/swaggsnew/${id}`);
return response.data;
} catch (error) {
- console.error("Error fetching swag list: ", error);
+ toast.error("Error fetching swag list");
throw error;
}
};
const useSingleSwag = (id) =>
useQuery({
- queryKey: ["single swag"],
+ queryKey: ["singleSwag", id],
queryFn: () => fetchSingleSwag(id),
refetchOnWindowFocus: false,
});
-export { useSwagList, useSingleSwag };
+const fetchSwagCategories = async () => {
+ try {
+ const response = await publicAxios.get("/product-categories");
+ return response.data;
+ } catch (error) {
+ toast.error("Error fetching swag list");
+ throw error;
+ }
+};
+
+const useSwagCategory = () =>
+ useQuery({
+ queryKey: ["swagCategory"],
+ queryFn: () => fetchSwagCategories(),
+ refetchOnWindowFocus: false,
+ });
+
+export { useSingleSwag, useSwagList, useSwagCategory };
diff --git a/src/hooks/Queries/singleEvent/useSingleEvent.jsx b/src/hooks/Queries/singleEvent/useSingleEvent.jsx
index 96aff136..702ddfcc 100644
--- a/src/hooks/Queries/singleEvent/useSingleEvent.jsx
+++ b/src/hooks/Queries/singleEvent/useSingleEvent.jsx
@@ -1,5 +1,6 @@
-import axios from "axios";
import { useQuery } from "@tanstack/react-query";
+import axios from "axios";
+import toast from "react-hot-toast";
const fetchOneEvent = async (id) => {
try {
@@ -8,18 +9,17 @@ const fetchOneEvent = async (id) => {
);
return results.data;
} catch (error) {
- console.error("Error fetching event: ", error);
+ toast.error("Error fetching event");
throw error;
}
};
-const useOneEvent = (id) => {
- return useQuery({
+const useOneEvent = (id) =>
+ useQuery({
queryKey: ["oneEvent"],
queryFn: () => fetchOneEvent(id),
refetchOnWindowFocus: false,
staleTime: 5 * 60 * 60, // A recall will be made after 30 seconds
});
-};
-export { useOneEvent };
+export default useOneEvent;
diff --git a/src/index.css b/src/index.css
index 0849f9d8..a2049747 100644
--- a/src/index.css
+++ b/src/index.css
@@ -1,1330 +1,1394 @@
-@import url("https://fonts.googleapis.com/css2?family=Sora&display=swap");
-@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@200;500;600;700;800;900&display=swap");
-@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300..700&display=swap');
-
-@tailwind base;
-@tailwind components;
-@tailwind utilities;
-
-* {
- font-family: "Poppins", sans-serif;
- scroll-behavior: smooth;
-}
-
-::-webkit-scrollbar {
- width: 0;
- background: transparent;
-}
-
-.scrollbar::-webkit-scrollbar {
- width: 0;
- height: 6px;
- background: #009975;
-}
-
-.scrollbar::-webkit-scrollbar-thumb {
- background: #00664e;
-
- border-radius: 12px;
-}
-
-.scrollbar::-webkit-scrollbar-track {
- background: #009975;
- -webkit-box-shadow: inset 0 0 6px #009975;
- border-top: 2px solid #e5efec;
- border-bottom: 2px solid #e5efec;
-}
-
-@media (min-width: 768px) {
- .scrollbar::-webkit-scrollbar {
- width: 6px;
- height: 0;
- background: #009975;
- }
-
- .scrollbar::-webkit-scrollbar-thumb {
- background: #00664e;
-
- border-radius: 12px;
- }
-
- .scrollbar::-webkit-scrollbar-track {
- background: #009975;
- -webkit-box-shadow: inset 0 0 6px #009975;
- border-left: 2px solid #e5efec;
- border-right: 2px solid #e5efec;
- }
-}
-@layer utilities {
- .blur-1 {
- /* Vector */
-
- position: absolute;
- width: 68.01px;
- height: 67.84px;
- left: 500.9px;
- top: 66.87px;
-
- background: #009975;
- opacity: 0.3;
- filter: blur(15px);
- transform: rotate(-75deg);
- }
-
- .blur-sm-1 {
- /* Vector */
- position: absolute;
- width: 30.11px;
- height: 27.97px;
- left: 89px;
- top: 62.24px;
-
- /* Primary/Green/800 */
-
- background: #009975;
- opacity: 0.3;
- filter: blur(15px);
- transform: rotate(-75deg);
- }
-
- .blur-2 {
- /* Vector */
-
- position: absolute;
- width: 65.91px;
- height: 67.41px;
- left: 693.21px;
- top: 66px;
-
- /* Primary/Green/800 */
-
- background: #009975;
- opacity: 0.3;
- filter: blur(15px);
- transform: matrix(1, -0.03, -0.03, -1, 0, 0);
- }
-
- .blur-sm-2 {
- position: absolute;
- width: 32.1px;
- height: 32.83px;
- left: 158.08px;
- top: 70.87px;
-
- /* Primary/Green/800 */
-
- background: #009975;
- opacity: 0.3;
- filter: blur(15px);
- transform: matrix(1, -0.03, -0.03, -1, 0, 0);
- }
-
- .blur-3 {
- /* Vector */
-
- position: absolute;
- width: 51.81px;
- height: 69.5px;
- left: 885.84px;
- top: 66px;
-
- /* Primary/Green/800 */
-
- background: #009975;
- opacity: 0.3;
- filter: blur(15px);
- transform: rotate(-75deg);
- }
-
- .blur-sm-3 {
- /* Vector */
-
- position: absolute;
- width: 27.18px;
- height: 36.46px;
- left: 223px;
- top: 60.25px;
-
- /* Primary/Green/800 */
-
- background: #009975;
- opacity: 0.3;
- filter: blur(15px);
- transform: rotate(-75deg);
- }
-
- .bg-primary {
- background-color: #009975;
- }
-
- /* Footer */
- .flex-1 {
- flex-grow: 1;
- }
-
- .flex-3 {
- flex-grow: 3;
- }
-
- .flex-2 {
- flex-grow: 2;
- }
-
- .flex-center {
- display: flex;
- align-items: center;
- justify-content: center;
- }
-
- .flex-start {
- display: flex;
- align-items: flex-start;
- justify-content: center;
- }
- .flex-between {
- display: flex;
- align-items: center;
- justify-content: space-between;
- }
-
- .flex-half {
- flex: 1;
- }
-
- .first-letter::first-letter {
- font-weight: bold;
- font-size: 3rem;
- }
-
- /* blog bgImg */
- .bg-blog-image {
- background-image: url("../src/assets/images/blogs-page/blogBg.png");
- }
-}
-
-/* Hero Image */
-
-/* Creative Shapes */
-
-.creative-shapes {
- position: relative;
- width: 1432px;
- height: 519px;
- left: 0px;
- top: 0px;
-}
-
-.ellipse {
- position: absolute;
- border-radius: 50%;
- transition: transform 3s, filter 3s;
-}
-
-/* Ellipse 115 */
-
-.ellipse115 {
- position: absolute;
- width: 48px;
- height: 48px;
- left: 0px;
- top: 277px;
-
- background: #cfe2dc;
- opacity: 0.25;
-}
-
-/* Ellipse 116 */
-
-.ellipse116 {
- position: absolute;
- width: 28px;
- height: 28px;
- left: 87px;
- top: 207px;
-
- background: #63968b;
-}
-
-/* Ellipse 117 */
-
-.ellipse117 {
- position: absolute;
- width: 101px;
- height: 101px;
- left: 50px;
- top: 246px;
-
- background: url(.jpg), #d9d9d9;
-}
-
-/* Ellipse 118 */
-
-.ellipse118 {
- position: absolute;
- width: 131px;
- height: 137px;
- left: 151px;
- top: 221px;
-
- background: #d9d9d9;
-}
-
-/* Ellipse 132 */
-
-.ellipse132 {
- position: absolute;
- width: 98px;
- height: 102px;
- left: 184px;
- top: 331px;
-
- background: #d9d9d9;
-}
-
-/* Ellipse 119 */
-
-.ellipse119 {
- position: absolute;
- width: 33px;
- height: 35px;
- left: 134px;
- top: 347px;
-
- background: #63968b;
-}
-
-/* Ellipse 133 */
-
-.ellipse133 {
- position: absolute;
- width: 30px;
- height: 30px;
- left: 178px;
- top: 440px;
-
- background: #d9d9d9;
- opacity: 0.25;
-}
-
-/* Ellipse 134 */
-
-.ellipse134 {
- position: absolute;
- width: 30px;
- height: 30px;
- left: 300px;
- top: 394px;
-
- background: url(.jpg), #63968b;
-}
-
-/* Ellipse 172 */
-
-.ellipse172 {
- position: absolute;
- width: 42px;
- height: 42px;
- left: 435px;
- top: 458px;
-
- background: #63968b;
-}
-
-/* Ellipse 173 */
-
-.ellipse173 {
- position: absolute;
- width: 31px;
- height: 31px;
- left: 496px;
- top: 474px;
-
- background: #d9d9d9;
-}
-
-/* Ellipse 174 */
-
-.ellipse174 {
- position: absolute;
- width: 48px;
- height: 48px;
- left: 532px;
- top: 470px;
-
- background: url(.jpg);
- opacity: 0.25;
-}
-
-/* Ellipse 175 */
-
-.ellipse175 {
- position: absolute;
- width: 156px;
- height: 156px;
- left: 451px;
- top: 313px;
-
- background: #d9d9d9;
-}
-
-/* Ellipse 176 */
-
-.ellipse176 {
- position: absolute;
- width: 91px;
- height: 91px;
- left: 413px;
- top: 331px;
-
- background: url(.jpg), #d9d9d9;
-}
-
-/* Ellipse 135 */
-
-.ellipse135 {
- position: absolute;
- width: 59px;
- height: 59px;
- left: 283px;
- top: 335px;
-
- background: #63968b;
-}
-
-/* Ellipse 136 */
-
-.ellipse136 {
- position: absolute;
- width: 121px;
- height: 121px;
- left: 333px;
- top: 331px;
-
- background: #d9d9d9;
-}
-
-/* Ellipse 120 */
-
-.ellipse120 {
- position: absolute;
- width: 65px;
- height: 69px;
- left: 200px;
- top: 138px;
-
- background: url(.jpg), #d9d9d9;
-}
-
-/* Ellipse 124 */
-
-.ellipse124 {
- position: absolute;
- width: 69px;
- height: 69px;
- left: 200px;
- top: 138px;
-
- background: #d9d9d9;
-}
-
-/* Ellipse 125 */
-
-.ellipse125 {
- position: absolute;
- width: 69px;
- height: 69px;
- left: 278px;
- top: 177px;
-
- background: #d9d9d9;
- opacity: 0.25;
-}
-
-/* Ellipse 126 */
-
-.ellipse126 {
- position: absolute;
- width: 172px;
- height: 172px;
- left: 289px;
- top: 199px;
-
- background: #d9d9d9;
-}
-
-/* Ellipse 121 */
-
-.ellipse121 {
- position: absolute;
- width: 45px;
- height: 45px;
- left: 278px;
- top: 116px;
-
- background: #60968b;
-}
-
-/* Ellipse 127 */
-
-.ellipse127 {
- position: absolute;
- width: 91px;
- height: 91px;
- left: 328px;
- top: 116px;
-
- background: url(.jpg);
-}
-
-/* Ellipse 128 */
-
-.ellipse128 {
- position: absolute;
- width: 131px;
- height: 131px;
- left: 389px;
- top: 30px;
-
- background: #d9d9d9;
-}
-
-/* Ellipse 129 */
-
-.ellipse129 {
- position: absolute;
- width: 160px;
- height: 160px;
- left: 479px;
- top: 56px;
-
- background: #b3cbc4;
- opacity: 0.45;
-}
-
-/* Ellipse 130 */
-
-.ellipse130 {
- position: absolute;
- width: 79px;
- height: 79px;
- left: 406px;
- top: 152px;
-
- background: #63968b;
-}
-
-/* Ellipse 131 */
-
-.ellipse1311 {
- position: absolute;
- width: 150px;
- height: 150px;
- left: 450px;
- top: 199px;
-
- background: #609a8f;
- opacity: 0.75;
-}
-
-/* Ellipse 122 */
-
-.ellipse122 {
- position: absolute;
- width: 30px;
- height: 30px;
- left: 242px;
- top: 108px;
-
- background: url(.jpg), #60968b;
-}
-
-/* Ellipse 123 */
-
-.ellipse123 {
- position: absolute;
- width: 30px;
- height: 30px;
- left: 361px;
- top: 26px;
-
- background: #60968b;
-}
-
-/* Ellipse 137 */
-
-.ellipse137 {
- position: absolute;
- width: 30px;
- height: 30px;
- left: 575px;
- top: 30px;
-
- background: #60968b;
-}
-
-/* Ellipse 138 */
-
-.ellipse138 {
- position: absolute;
- width: 90px;
- height: 90px;
- left: 603px;
- top: 0px;
-
- background: #d9d9d9;
-}
-
-/* Ellipse 139 */
-
-.ellipse139 {
- position: absolute;
- width: 116px;
- height: 124px;
- left: 650px;
- top: 70px;
-
- background: url(.jpg), #d9d9d9;
-}
-
-/* Ellipse 140 */
-
-.ellipse140 {
- position: absolute;
- width: 124px;
- height: 124px;
- left: 650px;
- top: 70px;
-
- background: #d9d9d9;
-}
-
-/* Ellipse 141 */
-
-.ellipse141 {
- position: absolute;
- width: 80px;
- height: 80px;
- left: 580px;
- top: 136px;
-
- background: #d9d9d9;
-}
-
-/* Ellipse 142 */
-
-.ellipse142 {
- position: absolute;
- width: 210px;
- height: 210px;
- left: 602px;
- top: 184px;
-
- background: url(.jpg), #d9d9d9;
-}
-
-/* Ellipse 143 */
-
-.ellipse143 {
- position: absolute;
- width: 80px;
- height: 80px;
- left: 564px;
- top: 324px;
-
- background: #d9d9d9;
-}
-
-/* Ellipse 144 */
-
-.ellipse144 {
- position: absolute;
- width: 137px;
- height: 137px;
- left: 591px;
- top: 382px;
-
- background: #d9d9d9;
-}
-
-/* Ellipse 145 */
-
-.ellipse145 {
- position: absolute;
- width: 82px;
- height: 88px;
- left: 716px;
- top: 391px;
-
- background: #668c83;
-}
-
-/* Ellipse 177 */
-
-.ellipse177 {
- position: absolute;
- width: 59px;
- height: 63px;
- left: 762px;
- top: 336px;
-
- background: url(.jpg), #668c83;
-}
-
-/* Ellipse 178 */
-
-.ellipse178 {
- position: absolute;
- width: 59px;
- height: 63px;
- left: 775px;
- top: 264px;
-
- background: #d9d9d9;
-}
-
-/* Ellipse 146 */
-
-.ellipse146 {
- position: absolute;
- width: 141px;
- height: 151px;
- left: 792px;
- top: 360px;
-
- background: #d9d9d9;
-}
-
-/* Ellipse 156 */
-
-.ellipse156 {
- position: absolute;
- width: 61px;
- height: 61px;
- left: 937px;
- top: 420px;
-
- background: #d9d9d9;
- opacity: 0.35;
-}
-
-/* Ellipse 157 */
-
-.ellipse157 {
- position: absolute;
- width: 85px;
- height: 85px;
- left: 1002px;
- top: 404px;
-
- background: url(.jpg), #d9d9d9;
-}
-
-/* Ellipse 179 */
-
-.ellipse179 {
- position: absolute;
- width: 54px;
- height: 54px;
- left: 1019px;
- top: 336px;
-
- background: #6d837d;
-}
-
-/* Ellipse 158 */
-
-.ellipse158 {
- position: absolute;
- width: 121px;
- height: 121px;
- left: 1072px;
- top: 325px;
-
- background: #81918d;
- opacity: 0.85;
-}
-
-/* Ellipse 164 */
-
-.ellipse164 {
- position: absolute;
- width: 128px;
- height: 137px;
- left: 1105px;
- top: 223px;
-
- background: #d9d9d9;
-}
-
-/* Ellipse 165 */
-
-.ellipse165 {
- position: absolute;
- width: 121px;
- height: 121px;
- left: 1232px;
- top: 212px;
-
- background: url(.jpg), #d9d9d9;
-}
-
-/* Ellipse 167 */
-
-.ellipse167 {
- position: absolute;
- width: 84px;
- height: 84px;
- left: 1337px;
- top: 227px;
-
- background: #d9d9d9;
-}
-
-/* Ellipse 168 */
-
-.ellipse168 {
- position: absolute;
- width: 56px;
- height: 56px;
- left: 1266px;
- top: 325px;
-
- background: #acb0af;
- opacity: 0.55;
-}
-
-/* Ellipse 169 */
-
-.ellipse169 {
- position: absolute;
- width: 34px;
- height: 34px;
- left: 1193px;
- top: 350px;
-
- background: #707b79;
-}
-
-/* Ellipse 170 */
-
-.ellipse170 {
- position: absolute;
- width: 29px;
- height: 29px;
- left: 1091px;
- top: 450px;
-
- background: #6d837d;
-}
-
-/* Ellipse 171 */
-
-.ellipse171 {
- position: absolute;
- width: 29px;
- height: 29px;
- left: 1403px;
- top: 229px;
-
- background: #737574;
-}
-
-/* Ellipse 166 */
-
-.ellipse166 {
- position: absolute;
- width: 56px;
- height: 56px;
- left: 1260px;
- top: 171px;
-
- background: #d9d9d9;
-}
-
-/* Ellipse 147 */
-
-.ellipse147 {
- position: absolute;
- width: 150px;
- height: 150px;
- left: 817px;
- top: 213px;
-
- background: url(.jpg), #d9d9d9;
-}
-
-/* Ellipse 148 */
-
-.ellipse148 {
- position: absolute;
- width: 115px;
- height: 115px;
- left: 766px;
- top: 119px;
-
- background: #d9d9d9;
-}
-
-/* Ellipse 151 */
-
-.ellipse151 {
- position: absolute;
- width: 80px;
- height: 80px;
- left: 881px;
- top: 159px;
-
- background: #698981;
-}
-
-/* Ellipse 149 */
-
-.ellipse149 {
- position: absolute;
- width: 82px;
- height: 82px;
- left: 805px;
- top: 45px;
-
- background: #ced8d6;
- opacity: 0.55;
-}
-
-/* Ellipse 152 */
-
-.ellipse152 {
- position: absolute;
- width: 106px;
- height: 106px;
- left: 870px;
- top: 57px;
-
- background: url(.jpg), #d9d9d9;
-}
-
-/* Ellipse 153 */
-
-.ellipse153 {
- position: absolute;
- width: 125px;
- height: 125px;
- left: 956px;
- top: 69px;
-
- background: #d9d9d9;
-}
-
-/* Ellipse 159 */
-
-.ellipse159 {
- position: absolute;
- width: 160px;
- height: 160px;
- left: 1055px;
- top: 86px;
-
- background: url(.jpg);
-}
-
-/* Ellipse 160 */
-
-.ellipse160 {
- position: absolute;
- width: 105px;
- height: 105px;
- left: 1198px;
- top: 90px;
-
- background: #d9d9d9;
-}
-
-/* Ellipse 161 */
-
-.ellipse161 {
- position: absolute;
- width: 60px;
- height: 60px;
- left: 1039px;
- top: 39px;
-
- background: #d1d6d6;
- opacity: 0.25;
-}
-
-/* Ellipse 162 */
-
-.ellipse162 {
- position: absolute;
- width: 20px;
- height: 20px;
- left: 1005px;
- top: 45px;
-
- background: #6b8781;
-}
-
-/* Ellipse 163 */
-
-.ellipse163 {
- position: absolute;
- width: 20px;
- height: 20px;
- left: 1198px;
- top: 83px;
-
- background: #6f7e7b;
-}
-
-/* Ellipse 154 */
-
-.ellipse154 {
- position: absolute;
- width: 100px;
- height: 100px;
- left: 949px;
- top: 133px;
-
- background: #d9d9d9;
- opacity: 0.15;
-}
-
-/* Ellipse 155 */
-
-.ellipse155 {
- position: absolute;
- width: 160px;
- height: 160px;
- left: 966px;
- top: 210px;
-
- background: #d9d9d9;
-}
-
-/* Ellipse 150 */
-
-.ellipse150 {
- position: absolute;
- width: 52px;
- height: 52px;
- left: 741px;
- top: 54px;
-
- background: #649186;
-}
-
-/* Rectangle 18291 */
-
-/* .rectangle18291 {
- position: absolute;
- width: 1436px;
- height: 523px;
- left: 0px;
- top: 0px;
-
- background: linear-gradient(
- 96.14deg,
- #59a896 10.62%,
- #737373 96.48%,
- #00664e 96.48%
- );
-} */
-
-/* Ellipse 147 */
-
-.ellipse147 {
- position: absolute;
-width: 150px;
-height: 150px;
-left: 817px;
-top: 213px;
-
-background: url('./assets/Landing Page Images/Ellipse 147.png');
-}
-
-/* Ellipse 1411 */
-
-.ellipse1411 {
- position: absolute;
- width: 210px;
- height: 210px;
- left: 602px;
- top: 184px;
-
- background: url('./assets/Landing Page Images/Ellipse 1411.png');
-}
-
-/* Ellipse 128 */
-
-.ellipse128 {
- position: absolute;
- width: 131px;
- height: 131px;
- left: 389px;
- top: 30px;
-
- background: url('./assets/Landing Page Images/Ellipse 128.png');
-}
-
-/* Ellipse 142 */
-
-.ellipse142 {
- position: absolute;
- width: 101px;
- height: 101px;
- left: 50px;
- top: 246px;
-
- background: url('./assets/Landing Page Images/Ellipse 142.png'), #d9d9d9;
-}
-
-/* Ellipse 175 */
-
-.ellipse175 {
- position: absolute;
- width: 156px;
- height: 156px;
- left: 451px;
- top: 313px;
-
- background: url('./assets/Landing Page Images/Ellipse 175.png');
-}
-
-/* Ellipse 146 */
-
-.ellipse146 {
- position: absolute;
- width: 141px;
- height: 151px;
- left: 792px;
- top: 360px;
-
- background: url('./assets/Landing Page Images/Ellipse 146.png');
-}
-
-/* Ellipse 159 */
-
-.ellipse159 {
- position: absolute;
- width: 160px;
- height: 160px;
- left: 1055px;
- top: 86px;
-
- background: url('./assets/Landing Page Images/Ellipse 159.png');
-}
-
-/* Ellipse 167 */
-
-.ellipse167 {
- position: absolute;
- width: 84px;
- height: 84px;
- left: 1337px;
- top: 227px;
-
- background: url('./assets/Landing Page Images/Ellipse 167.png');
-}
-
-/* Ellipse 160 */
-
-.ellipse160 {
- position: absolute;
- width: 105px;
- height: 105px;
- left: 1198px;
- top: 90px;
-
- background: url('./assets/Landing Page Images/Ellipse 160.png'), #d9d9d9;
-}
-
-/* Ellipse 118 */
-
-.ellipse118 {
- position: absolute;
- width: 131px;
- height: 137px;
- left: 151px;
- top: 221px;
-
- background: url('./assets/Landing Page Images/Ellipse 118.png');
-}
-
-/* Ellipse 138 */
-
-.ellipse138 {
- position: absolute;
- width: 90px;
- height: 90px;
- left: 603px;
- top: 0px;
-
- background: url('./assets/Landing Page Images/Ellipse 138.png');
-}
-
-/* Ellipse 141 */
-
-.ellipse141 {
- position: absolute;
- width: 80px;
- height: 80px;
- left: 580px;
- top: 136px;
-
- background: url('./assets/Landing Page Images/Ellipse 141.png');
-}
-
-/* Ellipse 157 */
-
-.ellipse157 {
- position: absolute;
- width: 85px;
- height: 85px;
- left: 1002px;
- top: 404px;
-
- background: url('./assets/Landing Page Images/Ellipse 157.png');
-}
-
-/* Ellipse 132 */
-
-.ellipse132 {
- position: absolute;
- width: 98px;
- height: 102px;
- left: 184px;
- top: 331px;
-
- background: url('./assets/Landing Page Images/Ellipse 132.png'), #d9d9d9;
-}
-
-/* Ellipse 131 */
-
-.ellipse131 {
- position: absolute;
- width: 172px;
- height: 172px;
- left: 289px;
- top: 199px;
-
- background: url('./assets/Landing Page Images/Ellipse 131.png');
-}
-
-/* Ellipse 136 */
-
-.ellipse136 {
- position: absolute;
- width: 121px;
- height: 121px;
- left: 333px;
- top: 331px;
-
- background: url('./assets/Landing Page Images/Ellipse 136.png');
-}
-
-/* Ellipse 124 */
-
-.ellipse124 {
- position: absolute;
- width: 69px;
- height: 69px;
- left: 200px;
- top: 138px;
-
- background: url('./assets/Landing Page Images/Ellipse 124.png'), #d9d9d9;
-}
-
-/* Ellipse 164 */
-
-.ellipse164 {
- position: absolute;
- width: 128px;
- height: 137px;
- left: 1105px;
- top: 223px;
-
- background: url('./assets/Landing Page Images/Ellipse 164.png'), #d9d9d9;
-}
-
-/* Ellipse 165 */
-
-.ellipse165 {
- position: absolute;
- width: 121px;
- height: 121px;
- left: 1232px;
- top: 212px;
-
- background: url('./assets/Landing Page Images/Ellipse 165.png');
-}
-
-/* Ellipse 148 */
-
-.ellipse148 {
- position: absolute;
- width: 115px;
- height: 115px;
- left: 766px;
- top: 119px;
-
- background: url('./assets/Landing Page Images/Ellipse 148.png');
-}
-
-/* Ellipse 152 */
-
-.ellipse152 {
- position: absolute;
- width: 106px;
- height: 106px;
- left: 870px;
- top: 57px;
-
- background: url('./assets/Landing Page Images/Ellipse 152.png');
-}
-
-/* Ellipse 153 */
-
-.ellipse153 {
- position: absolute;
- width: 125px;
- height: 125px;
- left: 956px;
- top: 69px;
-
- background: url('./assets/Landing Page Images/Ellipse 153.png');
-}
-
-/* Ellipse 155 */
-
-.ellipse155 {
- position: absolute;
- width: 160px;
- height: 160px;
- left: 966px;
- top: 210px;
-
- background: url('./assets/Landing Page Images/Ellipse 155.png');
-}
-
-/* Ellipse 127 */
-
-.ellipse127 {
- position: absolute;
- width: 137px;
- height: 137px;
- left: 591px;
- top: 382px;
-
- background: url('./assets/Landing Page Images/Ellipse 127.png');
-}
-
-/* Ellipse 117 */
-
-.ellipse117 {
- position: absolute;
- width: 124px;
- height: 124px;
- left: 650px;
- top: 70px;
-
- background: url('./assets/Landing Page Images/Ellipse 117.png');
-}
+@import url("https://fonts.googleapis.com/css2?family=Sora&display=swap");
+@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@200;500;600;700;800;900&display=swap");
+@import url("https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300..700&display=swap");
+@import url("https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300..800;1,300..800&display=swap");
+@import url("https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap");
+
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+* {
+ font-family: "Poppins", sans-serif;
+ scroll-behavior: smooth;
+}
+
+::-webkit-scrollbar {
+ width: 0;
+ background: transparent;
+}
+
+.scrollbar-2::-webkit-scrollbar {
+ width: 6px;
+ height: 6px;
+ background: rgb(0 102 78 / 0.1);
+}
+
+.scrollbar-2::-webkit-scrollbar-thumb {
+ background: #00664e;
+
+ border-radius: 12px;
+}
+
+.scrollbar-2::-webkit-scrollbar-track {
+ background: rgb(0 102 78 / 0.1);
+ -webkit-box-shadow: inset 0 0 6px rgb(0 102 78 / 0.1);
+ border-top: 2px solid #f3f4f5;
+ border-bottom: 2px solid #f3f4f5;
+}
+
+.scrollbar::-webkit-scrollbar {
+ width: 0;
+ height: 6px;
+ background: rgb(0 102 78 / 0.1);
+}
+
+.scrollbar::-webkit-scrollbar-thumb {
+ background: #00664e;
+
+ border-radius: 12px;
+}
+
+.scrollbar::-webkit-scrollbar-track {
+ background: rgb(0 102 78 / 0.1);
+ -webkit-box-shadow: inset 0 0 6px rgb(0 102 78 / 0.1);
+ border-top: 2px solid #f3f4f5;
+ border-bottom: 2px solid #f3f4f5;
+}
+
+.hr-scrollbar::-webkit-scrollbar {
+ width: 0;
+ height: 6px;
+ background: rgb(0 102 78 / 0.1);
+}
+
+.hr-scrollbar::-webkit-scrollbar-thumb {
+ background: #00664e;
+ border-radius: 12px;
+}
+
+.hr-scrollbar::-webkit-scrollbar-track {
+ background: rgb(0 102 78 / 0.1);
+ -webkit-box-shadow: inset 0 0 6px rgb(0 102 78 / 0.1);
+ border-top: 2px solid #f3f4f5;
+ border-bottom: 2px solid #f3f4f5;
+}
+
+.PhoneInputInput {
+ background-color: transparent;
+ outline: none;
+}
+
+@media (min-width: 768px) {
+ .scrollbar::-webkit-scrollbar {
+ width: 6px;
+ height: 0;
+ background: rgb(0 102 78 / 0.1);
+ }
+
+ .scrollbar::-webkit-scrollbar-thumb {
+ background: #00664e;
+
+ border-radius: 12px;
+ }
+
+ .scrollbar::-webkit-scrollbar-track {
+ background: rgb(0 102 78 / 0.1);
+ -webkit-box-shadow: inset 0 0 6px rgb(0 102 78 / 0.1);
+ border-left: 2px solid #f3f4f5;
+ border-right: 2px solid #f3f4f5;
+ }
+
+ .hr-scrollbar::-webkit-scrollbar {
+ width: 6px;
+ background: rgb(0 102 78 / 0.1);
+ }
+
+ .hr-scrollbar::-webkit-scrollbar-thumb {
+ background: #00664e;
+
+ border-radius: 12px;
+ }
+
+ .hr-scrollbar::-webkit-scrollbar-track {
+ background: rgb(0 102 78 / 0.1);
+ -webkit-box-shadow: inset 0 0 6px rgb(0 102 78 / 0.1);
+ border-left: 2px solid #f3f4f5;
+ border-right: 2px solid #f3f4f5;
+ }
+}
+
+@layer utilities {
+ .blur-1 {
+ /* Vector */
+
+ position: absolute;
+ width: 68.01px;
+ height: 67.84px;
+ left: 500.9px;
+ top: 66.87px;
+
+ background: rgb(0 102 78 / 0.1);
+ opacity: 0.3;
+ filter: blur(15px);
+ transform: rotate(-75deg);
+ }
+
+ .blur-sm-1 {
+ /* Vector */
+ position: absolute;
+ width: 30.11px;
+ height: 27.97px;
+ left: 89px;
+ top: 62.24px;
+
+ /* Primary/Green/800 */
+
+ background: rgb(0 102 78 / 0.1);
+ opacity: 0.3;
+ filter: blur(15px);
+ transform: rotate(-75deg);
+ }
+
+ .blur-2 {
+ /* Vector */
+
+ position: absolute;
+ width: 65.91px;
+ height: 67.41px;
+ left: 693.21px;
+ top: 66px;
+
+ /* Primary/Green/800 */
+
+ background: rgb(0 102 78 / 0.1);
+ opacity: 0.3;
+ filter: blur(15px);
+ transform: matrix(1, -0.03, -0.03, -1, 0, 0);
+ }
+
+ .blur-sm-2 {
+ position: absolute;
+ width: 32.1px;
+ height: 32.83px;
+ left: 158.08px;
+ top: 70.87px;
+
+ /* Primary/Green/800 */
+
+ background: rgb(0 102 78 / 0.1);
+ opacity: 0.3;
+ filter: blur(15px);
+ transform: matrix(1, -0.03, -0.03, -1, 0, 0);
+ }
+
+ .blur-3 {
+ /* Vector */
+
+ position: absolute;
+ width: 51.81px;
+ height: 69.5px;
+ left: 885.84px;
+ top: 66px;
+
+ /* Primary/Green/800 */
+
+ background: rgb(0 102 78 / 0.1);
+ opacity: 0.3;
+ filter: blur(15px);
+ transform: rotate(-75deg);
+ }
+
+ .blur-sm-3 {
+ /* Vector */
+
+ position: absolute;
+ width: 27.18px;
+ height: 36.46px;
+ left: 223px;
+ top: 60.25px;
+
+ /* Primary/Green/800 */
+ background: rgb(0 102 78 / 0.1);
+ opacity: 0.3;
+ filter: blur(15px);
+ transform: rotate(-75deg);
+ }
+
+ .bg-primary-blue {
+ background-color: rgb(0 102 78 / 0.1);
+ }
+
+ /* Footer */
+ .flex-1 {
+ flex-grow: 1;
+ }
+
+ .flex-3 {
+ flex-grow: 3;
+ }
+
+ .flex-2 {
+ flex-grow: 2;
+ }
+
+ .flex-center {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ .flex-start {
+ display: flex;
+ align-items: flex-start;
+ justify-content: center;
+ }
+ .flex-between {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ }
+
+ .flex-half {
+ flex: 1;
+ }
+
+ .first-letter::first-letter {
+ font-weight: bold;
+ font-size: 3rem;
+ }
+
+ /* blog bgImg */
+ .bg-blog-image {
+ background-image: url("../src/assets/images/blogs-page/blogBg.png");
+ }
+}
+
+/* Hero Image */
+
+/* Creative Shapes */
+
+.creative-shapes {
+ position: relative;
+ width: 1432px;
+ height: 519px;
+ left: 0px;
+ top: 0px;
+}
+
+.ellipse {
+ position: absolute;
+ border-radius: 50%;
+ transition:
+ transform 3s,
+ filter 3s;
+}
+
+/* Ellipse 115 */
+
+.ellipse115 {
+ position: absolute;
+ width: 48px;
+ height: 48px;
+ left: 0px;
+ top: 277px;
+
+ background: #cfe2dc;
+ opacity: 0.25;
+}
+
+/* Ellipse 116 */
+
+.ellipse116 {
+ position: absolute;
+ width: 28px;
+ height: 28px;
+ left: 87px;
+ top: 207px;
+
+ background: #63968b;
+}
+
+/* Ellipse 117 */
+
+.ellipse117 {
+ position: absolute;
+ width: 101px;
+ height: 101px;
+ left: 50px;
+ top: 246px;
+
+ background: url(.jpg), #d9d9d9;
+}
+
+/* Ellipse 118 */
+
+.ellipse118 {
+ position: absolute;
+ width: 131px;
+ height: 137px;
+ left: 151px;
+ top: 221px;
+
+ background: #d9d9d9;
+}
+
+/* Ellipse 132 */
+
+.ellipse132 {
+ position: absolute;
+ width: 98px;
+ height: 102px;
+ left: 184px;
+ top: 331px;
+
+ background: #d9d9d9;
+}
+
+/* Ellipse 119 */
+
+.ellipse119 {
+ position: absolute;
+ width: 33px;
+ height: 35px;
+ left: 134px;
+ top: 347px;
+
+ background: #63968b;
+}
+
+/* Ellipse 133 */
+
+.ellipse133 {
+ position: absolute;
+ width: 30px;
+ height: 30px;
+ left: 178px;
+ top: 440px;
+
+ background: #d9d9d9;
+ opacity: 0.25;
+}
+
+/* Ellipse 134 */
+
+.ellipse134 {
+ position: absolute;
+ width: 30px;
+ height: 30px;
+ left: 300px;
+ top: 394px;
+
+ background: url(.jpg), #63968b;
+}
+
+/* Ellipse 172 */
+
+.ellipse172 {
+ position: absolute;
+ width: 42px;
+ height: 42px;
+ left: 435px;
+ top: 458px;
+
+ background: #63968b;
+}
+
+/* Ellipse 173 */
+
+.ellipse173 {
+ position: absolute;
+ width: 31px;
+ height: 31px;
+ left: 496px;
+ top: 474px;
+
+ background: #d9d9d9;
+}
+
+/* Ellipse 174 */
+
+.ellipse174 {
+ position: absolute;
+ width: 48px;
+ height: 48px;
+ left: 532px;
+ top: 470px;
+
+ background: url(.jpg);
+ opacity: 0.25;
+}
+
+/* Ellipse 175 */
+
+.ellipse175 {
+ position: absolute;
+ width: 156px;
+ height: 156px;
+ left: 451px;
+ top: 313px;
+
+ background: #d9d9d9;
+}
+
+/* Ellipse 176 */
+
+.ellipse176 {
+ position: absolute;
+ width: 91px;
+ height: 91px;
+ left: 413px;
+ top: 331px;
+
+ background: url(.jpg), #d9d9d9;
+}
+
+/* Ellipse 135 */
+
+.ellipse135 {
+ position: absolute;
+ width: 59px;
+ height: 59px;
+ left: 283px;
+ top: 335px;
+
+ background: #63968b;
+}
+
+/* Ellipse 136 */
+
+.ellipse136 {
+ position: absolute;
+ width: 121px;
+ height: 121px;
+ left: 333px;
+ top: 331px;
+
+ background: #d9d9d9;
+}
+
+/* Ellipse 120 */
+
+.ellipse120 {
+ position: absolute;
+ width: 65px;
+ height: 69px;
+ left: 200px;
+ top: 138px;
+
+ background: url(.jpg), #d9d9d9;
+}
+
+/* Ellipse 124 */
+
+.ellipse124 {
+ position: absolute;
+ width: 69px;
+ height: 69px;
+ left: 200px;
+ top: 138px;
+
+ background: #d9d9d9;
+}
+
+/* Ellipse 125 */
+
+.ellipse125 {
+ position: absolute;
+ width: 69px;
+ height: 69px;
+ left: 278px;
+ top: 177px;
+
+ background: #d9d9d9;
+ opacity: 0.25;
+}
+
+/* Ellipse 126 */
+
+.ellipse126 {
+ position: absolute;
+ width: 172px;
+ height: 172px;
+ left: 289px;
+ top: 199px;
+
+ background: #d9d9d9;
+}
+
+/* Ellipse 121 */
+
+.ellipse121 {
+ position: absolute;
+ width: 45px;
+ height: 45px;
+ left: 278px;
+ top: 116px;
+
+ background: #60968b;
+}
+
+/* Ellipse 127 */
+
+.ellipse127 {
+ position: absolute;
+ width: 91px;
+ height: 91px;
+ left: 328px;
+ top: 116px;
+
+ background: url(.jpg);
+}
+
+/* Ellipse 128 */
+
+.ellipse128 {
+ position: absolute;
+ width: 131px;
+ height: 131px;
+ left: 389px;
+ top: 30px;
+
+ background: #d9d9d9;
+}
+
+/* Ellipse 129 */
+
+.ellipse129 {
+ position: absolute;
+ width: 160px;
+ height: 160px;
+ left: 479px;
+ top: 56px;
+
+ background: #b3cbc4;
+ opacity: 0.45;
+}
+
+/* Ellipse 130 */
+
+.ellipse130 {
+ position: absolute;
+ width: 79px;
+ height: 79px;
+ left: 406px;
+ top: 152px;
+
+ background: #63968b;
+}
+
+/* Ellipse 131 */
+
+.ellipse1311 {
+ position: absolute;
+ width: 150px;
+ height: 150px;
+ left: 450px;
+ top: 199px;
+
+ background: #609a8f;
+ opacity: 0.75;
+}
+
+/* Ellipse 122 */
+
+.ellipse122 {
+ position: absolute;
+ width: 30px;
+ height: 30px;
+ left: 242px;
+ top: 108px;
+
+ background: url(.jpg), #60968b;
+}
+
+/* Ellipse 123 */
+
+.ellipse123 {
+ position: absolute;
+ width: 30px;
+ height: 30px;
+ left: 361px;
+ top: 26px;
+
+ background: #60968b;
+}
+
+/* Ellipse 137 */
+
+.ellipse137 {
+ position: absolute;
+ width: 30px;
+ height: 30px;
+ left: 575px;
+ top: 30px;
+
+ background: #60968b;
+}
+
+/* Ellipse 138 */
+
+.ellipse138 {
+ position: absolute;
+ width: 90px;
+ height: 90px;
+ left: 603px;
+ top: 0px;
+
+ background: #d9d9d9;
+}
+
+/* Ellipse 139 */
+
+.ellipse139 {
+ position: absolute;
+ width: 116px;
+ height: 124px;
+ left: 650px;
+ top: 70px;
+
+ background: url(.jpg), #d9d9d9;
+}
+
+/* Ellipse 140 */
+
+.ellipse140 {
+ position: absolute;
+ width: 124px;
+ height: 124px;
+ left: 650px;
+ top: 70px;
+
+ background: #d9d9d9;
+}
+
+/* Ellipse 141 */
+
+.ellipse141 {
+ position: absolute;
+ width: 80px;
+ height: 80px;
+ left: 580px;
+ top: 136px;
+
+ background: #d9d9d9;
+}
+
+/* Ellipse 142 */
+
+.ellipse142 {
+ position: absolute;
+ width: 210px;
+ height: 210px;
+ left: 602px;
+ top: 184px;
+
+ background: url(.jpg), #d9d9d9;
+}
+
+/* Ellipse 143 */
+
+.ellipse143 {
+ position: absolute;
+ width: 80px;
+ height: 80px;
+ left: 564px;
+ top: 324px;
+
+ background: #d9d9d9;
+}
+
+/* Ellipse 144 */
+
+.ellipse144 {
+ position: absolute;
+ width: 137px;
+ height: 137px;
+ left: 591px;
+ top: 382px;
+
+ background: #d9d9d9;
+}
+
+/* Ellipse 145 */
+
+.ellipse145 {
+ position: absolute;
+ width: 82px;
+ height: 88px;
+ left: 716px;
+ top: 391px;
+
+ background: #668c83;
+}
+
+/* Ellipse 177 */
+
+.ellipse177 {
+ position: absolute;
+ width: 59px;
+ height: 63px;
+ left: 762px;
+ top: 336px;
+
+ background: url(.jpg), #668c83;
+}
+
+/* Ellipse 178 */
+
+.ellipse178 {
+ position: absolute;
+ width: 59px;
+ height: 63px;
+ left: 775px;
+ top: 264px;
+
+ background: #d9d9d9;
+}
+
+/* Ellipse 146 */
+
+.ellipse146 {
+ position: absolute;
+ width: 141px;
+ height: 151px;
+ left: 792px;
+ top: 360px;
+
+ background: #d9d9d9;
+}
+
+/* Ellipse 156 */
+
+.ellipse156 {
+ position: absolute;
+ width: 61px;
+ height: 61px;
+ left: 937px;
+ top: 420px;
+
+ background: #d9d9d9;
+ opacity: 0.35;
+}
+
+/* Ellipse 157 */
+
+.ellipse157 {
+ position: absolute;
+ width: 85px;
+ height: 85px;
+ left: 1002px;
+ top: 404px;
+
+ background: url(.jpg), #d9d9d9;
+}
+
+/* Ellipse 179 */
+
+.ellipse179 {
+ position: absolute;
+ width: 54px;
+ height: 54px;
+ left: 1019px;
+ top: 336px;
+
+ background: #6d837d;
+}
+
+/* Ellipse 158 */
+
+.ellipse158 {
+ position: absolute;
+ width: 121px;
+ height: 121px;
+ left: 1072px;
+ top: 325px;
+
+ background: #81918d;
+ opacity: 0.85;
+}
+
+/* Ellipse 164 */
+
+.ellipse164 {
+ position: absolute;
+ width: 128px;
+ height: 137px;
+ left: 1105px;
+ top: 223px;
+
+ background: #d9d9d9;
+}
+
+/* Ellipse 165 */
+
+.ellipse165 {
+ position: absolute;
+ width: 121px;
+ height: 121px;
+ left: 1232px;
+ top: 212px;
+
+ background: url(.jpg), #d9d9d9;
+}
+
+/* Ellipse 167 */
+
+.ellipse167 {
+ position: absolute;
+ width: 84px;
+ height: 84px;
+ left: 1337px;
+ top: 227px;
+
+ background: #d9d9d9;
+}
+
+/* Ellipse 168 */
+
+.ellipse168 {
+ position: absolute;
+ width: 56px;
+ height: 56px;
+ left: 1266px;
+ top: 325px;
+
+ background: #acb0af;
+ opacity: 0.55;
+}
+
+/* Ellipse 169 */
+
+.ellipse169 {
+ position: absolute;
+ width: 34px;
+ height: 34px;
+ left: 1193px;
+ top: 350px;
+
+ background: #707b79;
+}
+
+/* Ellipse 170 */
+
+.ellipse170 {
+ position: absolute;
+ width: 29px;
+ height: 29px;
+ left: 1091px;
+ top: 450px;
+
+ background: #6d837d;
+}
+
+/* Ellipse 171 */
+
+.ellipse171 {
+ position: absolute;
+ width: 29px;
+ height: 29px;
+ left: 1403px;
+ top: 229px;
+
+ background: #737574;
+}
+
+/* Ellipse 166 */
+
+.ellipse166 {
+ position: absolute;
+ width: 56px;
+ height: 56px;
+ left: 1260px;
+ top: 171px;
+
+ background: #d9d9d9;
+}
+
+/* Ellipse 147 */
+
+.ellipse147 {
+ position: absolute;
+ width: 150px;
+ height: 150px;
+ left: 817px;
+ top: 213px;
+
+ background: url(.jpg), #d9d9d9;
+}
+
+/* Ellipse 148 */
+
+.ellipse148 {
+ position: absolute;
+ width: 115px;
+ height: 115px;
+ left: 766px;
+ top: 119px;
+
+ background: #d9d9d9;
+}
+
+/* Ellipse 151 */
+
+.ellipse151 {
+ position: absolute;
+ width: 80px;
+ height: 80px;
+ left: 881px;
+ top: 159px;
+
+ background: #698981;
+}
+
+/* Ellipse 149 */
+
+.ellipse149 {
+ position: absolute;
+ width: 82px;
+ height: 82px;
+ left: 805px;
+ top: 45px;
+
+ background: #ced8d6;
+ opacity: 0.55;
+}
+
+/* Ellipse 152 */
+
+.ellipse152 {
+ position: absolute;
+ width: 106px;
+ height: 106px;
+ left: 870px;
+ top: 57px;
+
+ background: url(.jpg), #d9d9d9;
+}
+
+/* Ellipse 153 */
+
+.ellipse153 {
+ position: absolute;
+ width: 125px;
+ height: 125px;
+ left: 956px;
+ top: 69px;
+
+ background: #d9d9d9;
+}
+
+/* Ellipse 159 */
+
+.ellipse159 {
+ position: absolute;
+ width: 160px;
+ height: 160px;
+ left: 1055px;
+ top: 86px;
+
+ background: url(.jpg);
+}
+
+/* Ellipse 160 */
+
+.ellipse160 {
+ position: absolute;
+ width: 105px;
+ height: 105px;
+ left: 1198px;
+ top: 90px;
+
+ background: #d9d9d9;
+}
+
+/* Ellipse 161 */
+
+.ellipse161 {
+ position: absolute;
+ width: 60px;
+ height: 60px;
+ left: 1039px;
+ top: 39px;
+
+ background: #d1d6d6;
+ opacity: 0.25;
+}
+
+/* Ellipse 162 */
+
+.ellipse162 {
+ position: absolute;
+ width: 20px;
+ height: 20px;
+ left: 1005px;
+ top: 45px;
+
+ background: #6b8781;
+}
+
+/* Ellipse 163 */
+
+.ellipse163 {
+ position: absolute;
+ width: 20px;
+ height: 20px;
+ left: 1198px;
+ top: 83px;
+
+ background: #6f7e7b;
+}
+
+/* Ellipse 154 */
+
+.ellipse154 {
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ left: 949px;
+ top: 133px;
+
+ background: #d9d9d9;
+ opacity: 0.15;
+}
+
+/* Ellipse 155 */
+
+.ellipse155 {
+ position: absolute;
+ width: 160px;
+ height: 160px;
+ left: 966px;
+ top: 210px;
+
+ background: #d9d9d9;
+}
+
+/* Ellipse 150 */
+
+.ellipse150 {
+ position: absolute;
+ width: 52px;
+ height: 52px;
+ left: 741px;
+ top: 54px;
+
+ background: #649186;
+}
+
+/* Rectangle 18291 */
+
+/* .rectangle18291 {
+ position: absolute;
+ width: 1436px;
+ height: 523px;
+ left: 0px;
+ top: 0px;
+
+ background: linear-gradient(
+ 96.14deg,
+ #59a896 10.62%,
+ #737373 96.48%,
+ #00664e 96.48%
+ );
+} */
+
+/* Ellipse 147 */
+
+.ellipse147 {
+ position: absolute;
+ width: 150px;
+ height: 150px;
+ left: 817px;
+ top: 213px;
+
+ background: url("./assets/Landing Page Images/Ellipse 147.png");
+}
+
+/* Ellipse 1411 */
+
+.ellipse1411 {
+ position: absolute;
+ width: 210px;
+ height: 210px;
+ left: 602px;
+ top: 184px;
+
+ background: url("./assets/Landing Page Images/Ellipse 1411.png");
+}
+
+/* Ellipse 128 */
+
+.ellipse128 {
+ position: absolute;
+ width: 131px;
+ height: 131px;
+ left: 389px;
+ top: 30px;
+
+ background: url("./assets/Landing Page Images/Ellipse 128.png");
+}
+
+/* Ellipse 142 */
+
+.ellipse142 {
+ position: absolute;
+ width: 101px;
+ height: 101px;
+ left: 50px;
+ top: 246px;
+
+ background: url("./assets/Landing Page Images/Ellipse 142.png"), #d9d9d9;
+}
+
+/* Ellipse 175 */
+
+.ellipse175 {
+ position: absolute;
+ width: 156px;
+ height: 156px;
+ left: 451px;
+ top: 313px;
+
+ background: url("./assets/Landing Page Images/Ellipse 175.png");
+}
+
+/* Ellipse 146 */
+
+.ellipse146 {
+ position: absolute;
+ width: 141px;
+ height: 151px;
+ left: 792px;
+ top: 360px;
+
+ background: url("./assets/Landing Page Images/Ellipse 146.png");
+}
+
+/* Ellipse 159 */
+
+.ellipse159 {
+ position: absolute;
+ width: 160px;
+ height: 160px;
+ left: 1055px;
+ top: 86px;
+
+ background: url("./assets/Landing Page Images/Ellipse 159.png");
+}
+
+/* Ellipse 167 */
+
+.ellipse167 {
+ position: absolute;
+ width: 84px;
+ height: 84px;
+ left: 1337px;
+ top: 227px;
+
+ background: url("./assets/Landing Page Images/Ellipse 167.png");
+}
+
+/* Ellipse 160 */
+
+.ellipse160 {
+ position: absolute;
+ width: 105px;
+ height: 105px;
+ left: 1198px;
+ top: 90px;
+
+ background: url("./assets/Landing Page Images/Ellipse 160.png"), #d9d9d9;
+}
+
+/* Ellipse 118 */
+
+.ellipse118 {
+ position: absolute;
+ width: 131px;
+ height: 137px;
+ left: 151px;
+ top: 221px;
+
+ background: url("./assets/Landing Page Images/Ellipse 118.png");
+}
+
+/* Ellipse 138 */
+
+.ellipse138 {
+ position: absolute;
+ width: 90px;
+ height: 90px;
+ left: 603px;
+ top: 0px;
+
+ background: url("./assets/Landing Page Images/Ellipse 138.png");
+}
+
+/* Ellipse 141 */
+
+.ellipse141 {
+ position: absolute;
+ width: 80px;
+ height: 80px;
+ left: 580px;
+ top: 136px;
+
+ background: url("./assets/Landing Page Images/Ellipse 141.png");
+}
+
+/* Ellipse 157 */
+
+.ellipse157 {
+ position: absolute;
+ width: 85px;
+ height: 85px;
+ left: 1002px;
+ top: 404px;
+
+ background: url("./assets/Landing Page Images/Ellipse 157.png");
+}
+
+/* Ellipse 132 */
+
+.ellipse132 {
+ position: absolute;
+ width: 98px;
+ height: 102px;
+ left: 184px;
+ top: 331px;
+
+ background: url("./assets/Landing Page Images/Ellipse 132.png"), #d9d9d9;
+}
+
+/* Ellipse 131 */
+
+.ellipse131 {
+ position: absolute;
+ width: 172px;
+ height: 172px;
+ left: 289px;
+ top: 199px;
+
+ background: url("./assets/Landing Page Images/Ellipse 131.png");
+}
+
+/* Ellipse 136 */
+
+.ellipse136 {
+ position: absolute;
+ width: 121px;
+ height: 121px;
+ left: 333px;
+ top: 331px;
+
+ background: url("./assets/Landing Page Images/Ellipse 136.png");
+}
+
+/* Ellipse 124 */
+
+.ellipse124 {
+ position: absolute;
+ width: 69px;
+ height: 69px;
+ left: 200px;
+ top: 138px;
+
+ background: url("./assets/Landing Page Images/Ellipse 124.png"), #d9d9d9;
+}
+
+/* Ellipse 164 */
+
+.ellipse164 {
+ position: absolute;
+ width: 128px;
+ height: 137px;
+ left: 1105px;
+ top: 223px;
+
+ background: url("./assets/Landing Page Images/Ellipse 164.png"), #d9d9d9;
+}
+
+/* Ellipse 165 */
+
+.ellipse165 {
+ position: absolute;
+ width: 121px;
+ height: 121px;
+ left: 1232px;
+ top: 212px;
+
+ background: url("./assets/Landing Page Images/Ellipse 165.png");
+}
+
+/* Ellipse 148 */
+
+.ellipse148 {
+ position: absolute;
+ width: 115px;
+ height: 115px;
+ left: 766px;
+ top: 119px;
+
+ background: url("./assets/Landing Page Images/Ellipse 148.png");
+}
+
+/* Ellipse 152 */
+
+.ellipse152 {
+ position: absolute;
+ width: 106px;
+ height: 106px;
+ left: 870px;
+ top: 57px;
+
+ background: url("./assets/Landing Page Images/Ellipse 152.png");
+}
+
+/* Ellipse 153 */
+
+.ellipse153 {
+ position: absolute;
+ width: 125px;
+ height: 125px;
+ left: 956px;
+ top: 69px;
+
+ background: url("./assets/Landing Page Images/Ellipse 153.png");
+}
+
+/* Ellipse 155 */
+
+.ellipse155 {
+ position: absolute;
+ width: 160px;
+ height: 160px;
+ left: 966px;
+ top: 210px;
+
+ background: url("./assets/Landing Page Images/Ellipse 155.png");
+}
+
+/* Ellipse 127 */
+
+.ellipse127 {
+ position: absolute;
+ width: 137px;
+ height: 137px;
+ left: 591px;
+ top: 382px;
+
+ background: url("./assets/Landing Page Images/Ellipse 127.png");
+}
+
+/* Ellipse 117 */
+
+.ellipse117 {
+ position: absolute;
+ width: 124px;
+ height: 124px;
+ left: 650px;
+ top: 70px;
+
+ background: url("./assets/Landing Page Images/Ellipse 117.png");
+}
diff --git a/src/APP/index.js b/src/index.js
similarity index 53%
rename from src/APP/index.js
rename to src/index.js
index 9f40cc62..81cf6eed 100644
--- a/src/APP/index.js
+++ b/src/index.js
@@ -1,37 +1,33 @@
-/* eslint-disable function-paren-newline */
-/* eslint-disable implicit-arrow-linebreak */
import { lazy } from "react";
const AboutUs = lazy(() => import("./pages/aboutUs/AboutUs"));
+const AdminLayout = lazy(() => import("./components/admin/AdminLayout"));
const AllBlogsPage = lazy(() => import("./pages/admin/blogs/AllBlogsPage"));
-const AddChapterPage = lazy(() =>
- import("./pages/admin/chapters/AddChapterPage")
+const AddChapterPage = lazy(
+ () => import("./pages/admin/chapters/AddChapterPage")
);
-const AllChaptersPage = lazy(() =>
- import("./pages/admin/chapters/AllChaptersPage")
+const AllChaptersPage = lazy(
+ () => import("./pages/admin/chapters/AllChaptersPage")
);
const AddEventPage = lazy(() => import("./pages/admin/events/AddEventPage"));
const AllEventsPage = lazy(() => import("./pages/admin/events/AllEventsPage"));
-const UpdateEventPage = lazy(() =>
- import("./pages/admin/events/UpdateEventPage")
+const UpdateEventPage = lazy(
+ () => import("./pages/admin/events/UpdateEventPage")
);
const ForgotPassword = lazy(() => import("./pages/auth/ForgotPassword"));
const LogIn = lazy(() => import("./pages/auth/LogIn"));
const ResetPassword = lazy(() => import("./pages/auth/ResetPassword"));
const SignUp = lazy(() => import("./pages/auth/SignUp"));
const Blog = lazy(() => import("./pages/blog/Blog"));
-const Blog2 = lazy(() => import("./pages/blog2/Blog2"));
const Blogs = lazy(() => import("./pages/blogs/Blogs"));
-const IndividualChapter = lazy(() =>
- import("./pages/chapter/pages/IndividualChapter")
-);
const CommunityPage = lazy(() => import("./pages/community/CommunityPage"));
-const SingleEvent = lazy(() =>
- import("./pages/community/sections/eventsPreview/SingleEvents/SingleEvent")
+const SingleEvent = lazy(
+ () =>
+ import("./pages/community/sections/eventsPreview/SingleEvents/SingleEvent")
);
const DonatePage = lazy(() => import("./pages/donate/DonatePage"));
-const SingleProductDonation = lazy(() =>
- import("./pages/donate/pages/SingleProductDonatePage")
+const SingleProductDonation = lazy(
+ () => import("./pages/donate/pages/SingleProductDonatePage")
);
const Error400 = lazy(() => import("./pages/errorPages/Error400"));
const Error403 = lazy(() => import("./pages/errorPages/Error403"));
@@ -39,57 +35,92 @@ const Error404 = lazy(() => import("./pages/errorPages/Error404"));
const Error500 = lazy(() => import("./pages/errorPages/Error500"));
const ErrorBoundary = lazy(() => import("./pages/errorPages/ErrorBoundary"));
const EventsPage = lazy(() => import("./pages/events/pages/EventsPage"));
-const EventsSection = lazy(() =>
- import("./pages/events/sections/eventsSection/EventsSection")
+const EventsSection = lazy(
+ () => import("./pages/events/sections/eventsSection/EventsSection")
);
const GalleryPage = lazy(() => import("./pages/gallery/GalleryPage"));
const LandingPage = lazy(() => import("./pages/landingPage/LandingPage"));
const Layout = lazy(() => import("./pages/Layout"));
-const Products = lazy(() => import("./pages/products2/Products"));
-const Resources = lazy(() => import("./pages/resources/Resources"));
+const Products = lazy(() => import("./pages/products/Products"));
+const MastercraftHome = lazy(
+ () => import("./pages/mastercraft-home/MastercraftHome")
+);
+const ResourcesHome = lazy(
+ () => import("./pages/resources-home/ResourcesHome")
+);
+const Resource = lazy(() => import("./pages/resource/Resource"));
+const MastercraftLayout = lazy(() => import("./pages/MastercraftLayout"));
+const MastercraftSearch = lazy(
+ () => import("./pages/resources-home/search/MastercraftSearch")
+);
const Homepage = lazy(() => import("./pages/shop/Homepage"));
const Checkout = lazy(() => import("./pages/shop/OrderSummaryPage"));
const ProductDisplay = lazy(() => import("./pages/shop/ProductDisplayPage"));
-const CategoriesProducts = lazy(() =>
- import("./pages/shop/sections/CategoriesProducts")
+const CategoriesProducts = lazy(
+ () => import("./pages/shop/sections/CategoriesProducts")
);
+const AllProducts = lazy(() => import("./pages/shop/sections/AllProducts"));
const SingleItemPage = lazy(() => import("./pages/shop/SingleItemPage"));
+const ShopDashboard = lazy(
+ () => import("./pages/admin/shop/dashboard/ShopDashboard")
+);
+const ShopSales = lazy(() => import("./pages/admin/shop/sales/ShopSales"));
+const InventoryReport = lazy(
+ () => import("./pages/admin/shop/inventory/InventoryReport")
+);
+
+const OrdersPage = lazy(() => import("./pages/admin/shop/OrdersPage"));
+const Mastercraft = lazy(() => import("./pages/mastercraft/Mastercraft"));
+const MastercraftEnroll = lazy(
+ () => import("./pages/mastercraft-enroll/MastercraftEnroll")
+);
+
export {
+ AboutUs,
AddChapterPage,
AddEventPage,
+ AdminLayout,
AllBlogsPage,
AllChaptersPage,
AllEventsPage,
- UpdateEventPage,
- LandingPage,
- Homepage,
- Checkout,
+ AllProducts,
+ Blog,
+ Blogs,
CategoriesProducts,
- SingleItemPage,
- Layout,
- Products,
- Resources,
- AboutUs,
+ Checkout,
CommunityPage,
DonatePage,
- SingleEvent,
- Blogs,
- Blog,
- Blog2,
- EventsPage,
- EventsSection,
- SingleProductDonation,
- IndividualChapter,
Error400,
Error403,
Error404,
Error500,
ErrorBoundary,
- ProductDisplay,
+ EventsPage,
+ EventsSection,
ForgotPassword,
+ GalleryPage,
+ Homepage,
+ InventoryReport,
+ LandingPage,
+ Layout,
LogIn,
+ Mastercraft,
+ MastercraftEnroll,
+ OrdersPage,
+ ProductDisplay,
+ Products,
ResetPassword,
+ Resource,
+ ResourcesHome,
+ MastercraftHome,
+ MastercraftLayout,
+ MastercraftSearch,
+ ShopDashboard,
+ ShopSales,
SignUp,
- GalleryPage,
+ SingleEvent,
+ SingleItemPage,
+ SingleProductDonation,
+ UpdateEventPage,
};
diff --git a/src/main.jsx b/src/main.jsx
index a61c49e6..0b05b17e 100644
--- a/src/main.jsx
+++ b/src/main.jsx
@@ -6,11 +6,12 @@ import { HelmetProvider } from "react-helmet-async";
import { Toaster } from "react-hot-toast";
import { RouterProvider } from "react-router-dom";
import "./index.css";
-import { ErrorBoundary } from "./APP";
import { AuthContextProvider } from "./context/AuthContext";
import { SearchBlogProvider } from "./context/searchBlog";
import router from "./router";
+import { ErrorBoundary } from ".";
import "react-lazy-load-image-component/src/effects/blur.css";
+import "react-phone-number-input/style.css";
const queryClient = new QueryClient({
defaultOptions: {
@@ -28,7 +29,12 @@ ReactDOM.createRoot(document.getElementById("root")).render(
-
+
diff --git a/src/APP/pages/Layout.jsx b/src/pages/Layout.jsx
similarity index 100%
rename from src/APP/pages/Layout.jsx
rename to src/pages/Layout.jsx
diff --git a/src/pages/MastercraftLayout.jsx b/src/pages/MastercraftLayout.jsx
new file mode 100644
index 00000000..5edbdbee
--- /dev/null
+++ b/src/pages/MastercraftLayout.jsx
@@ -0,0 +1,26 @@
+import { useEffect } from "react";
+import { Outlet, useLocation } from "react-router-dom";
+import { Header, ResourcesFooter } from "../components";
+
+function ScrollToTopOnLinkClick() {
+ const { pathname } = useLocation();
+
+ useEffect(() => {
+ window.scrollTo(0, 0);
+ }, [pathname]);
+
+ return null;
+}
+
+function MastercraftLayout() {
+ return (
+
+
+
+
+
+
+ );
+}
+
+export default MastercraftLayout;
diff --git a/src/APP/pages/aboutUs/AboutUs.jsx b/src/pages/aboutUs/AboutUs.jsx
similarity index 100%
rename from src/APP/pages/aboutUs/AboutUs.jsx
rename to src/pages/aboutUs/AboutUs.jsx
diff --git a/src/APP/pages/aboutUs/data.js b/src/pages/aboutUs/data.js
similarity index 93%
rename from src/APP/pages/aboutUs/data.js
rename to src/pages/aboutUs/data.js
index 02ecaf27..519b8474 100644
--- a/src/APP/pages/aboutUs/data.js
+++ b/src/pages/aboutUs/data.js
@@ -1,145 +1,146 @@
-import {
- catherine,
- fred,
- hudson,
- ian,
- james,
- juma,
- marlyn,
- murabula,
- sharon,
- waithaka,
-} from "../../../assets/images/aboutPage";
-
-export const LeadershipData = [
- {
- name: "Fred Ouko",
- title: "Founder",
- image: fred,
- linkedin: {
- href: "https://www.linkedin.com/in/fred-ouko-918293bb/",
- username: "Fred Ouko",
- },
- twitter: {
- href: "https://twitter.com/fredouko",
- username: "fredouko",
- },
- },
- {
- name: "Catherine Kiiru",
- title: "Dev Relations & Opensource Programs",
- image: catherine,
- linkedin: {
- href: "https://www.linkedin.com/in/catherine-kiiru-47b2688b/",
- username: "Catherine Kiiru",
- },
- twitter: {
- href: "",
- username: "",
- },
- },
- {
- name: "James Otieno",
- title: "Community Manager",
- image: james,
- linkedin: {
- href: "https://www.linkedin.com/in/james-oduor/",
- username: "James Oduor",
- },
- twitter: {
- href: "",
- username: "",
- },
- },
- {
- name: "Hudson Obai",
- title: "Head of Engineering",
- image: hudson,
- linkedin: {
- href: "https://www.linkedin.com/in/hudson-obai-3948aa204/",
- username: "Hudson Obai",
- },
- twitter: {
- href: "",
- username: "",
- },
- },
- {
- name: "Ian Mugenya",
- title: "Mentorship Program Lead",
- image: ian,
- linkedin: {
- href: "https://www.linkedin.com/in/ian-mugenya/",
- username: "Ian Mugenya",
- },
- twitter: {
- href: "",
- username: "",
- },
- },
- {
- name: "Marlyn Mayienga",
- title: "Program Manager",
- image: marlyn,
- linkedin: {
- href: "https://www.linkedin.com/in/marlyn-mayienga/",
- username: "Marlyn Mayienga",
- },
- twitter: {
- href: "",
- username: "",
- },
- },
- {
- name: "Sharon Jebitok",
- title: "Head of Chapters and Volunteers",
- image: sharon,
- linkedin: {
- href: "https://www.linkedin.com/in/sharon-jebitok/",
- username: "Sharon Jebitok",
- },
- twitter: {
- href: "",
- username: "",
- },
- },
- {
- name: "Waithaka Waweru",
- title: "Dev Relations and Events",
- image: waithaka,
- linkedin: {
- href: "https://www.linkedin.com/in/waithaka-waweru/",
- username: "Waithaka Waweru",
- },
- twitter: {
- href: "",
- username: "",
- },
- },
- {
- name: "Juma Lawrence",
- title: "Head of Communication",
- image: juma,
- linkedin: {
- href: "https://www.linkedin.com/in/jumalaw98/",
- username: "Juma Lawrence",
- },
- twitter: {
- href: "",
- username: "",
- },
- },
- {
- name: "Racheal Murabula",
- title: "Lead Android Engineer",
- image: murabula,
- linkedin: {
- href: "https://www.linkedin.com/in/rachel-murabula-148a74122/",
- username: "Rachel Murabula",
- },
- twitter: {
- href: "",
- username: "",
- },
- },
-];
+import {
+ catherine,
+ fred,
+ hudson,
+ ian,
+ james,
+ juma,
+ marlyn,
+ murabula,
+ sharon,
+ waithaka,
+} from "../../assets/images/aboutPage";
+
+// eslint-disable-next-line import/prefer-default-export
+export const LeadershipData = [
+ {
+ name: "Fred Ouko",
+ title: "Founder",
+ image: fred,
+ linkedin: {
+ href: "https://www.linkedin.com/in/fred-ouko-918293bb/",
+ username: "Fred Ouko",
+ },
+ twitter: {
+ href: "https://twitter.com/fredouko",
+ username: "fredouko",
+ },
+ },
+ {
+ name: "Catherine Kiiru",
+ title: "Dev Relations & Opensource Programs",
+ image: catherine,
+ linkedin: {
+ href: "https://www.linkedin.com/in/catherine-kiiru-47b2688b/",
+ username: "Catherine Kiiru",
+ },
+ twitter: {
+ href: "",
+ username: "",
+ },
+ },
+ {
+ name: "James Otieno",
+ title: "Community Manager",
+ image: james,
+ linkedin: {
+ href: "https://www.linkedin.com/in/james-oduor/",
+ username: "James Oduor",
+ },
+ twitter: {
+ href: "",
+ username: "",
+ },
+ },
+ {
+ name: "Hudson Obai",
+ title: "Head of Engineering",
+ image: hudson,
+ linkedin: {
+ href: "https://www.linkedin.com/in/hudson-obai-3948aa204/",
+ username: "Hudson Obai",
+ },
+ twitter: {
+ href: "",
+ username: "",
+ },
+ },
+ {
+ name: "Ian Mugenya",
+ title: "Mentorship Program Lead",
+ image: ian,
+ linkedin: {
+ href: "https://www.linkedin.com/in/ian-mugenya/",
+ username: "Ian Mugenya",
+ },
+ twitter: {
+ href: "",
+ username: "",
+ },
+ },
+ {
+ name: "Marlyn Mayienga",
+ title: "Program Manager",
+ image: marlyn,
+ linkedin: {
+ href: "https://www.linkedin.com/in/marlyn-mayienga/",
+ username: "Marlyn Mayienga",
+ },
+ twitter: {
+ href: "",
+ username: "",
+ },
+ },
+ {
+ name: "Sharon Jebitok",
+ title: "Head of Chapters and Volunteers",
+ image: sharon,
+ linkedin: {
+ href: "https://www.linkedin.com/in/sharon-jebitok/",
+ username: "Sharon Jebitok",
+ },
+ twitter: {
+ href: "",
+ username: "",
+ },
+ },
+ {
+ name: "Waithaka Waweru",
+ title: "Dev Relations and Events",
+ image: waithaka,
+ linkedin: {
+ href: "https://www.linkedin.com/in/waithaka-waweru/",
+ username: "Waithaka Waweru",
+ },
+ twitter: {
+ href: "",
+ username: "",
+ },
+ },
+ {
+ name: "Juma Lawrence",
+ title: "Head of Communication",
+ image: juma,
+ linkedin: {
+ href: "https://www.linkedin.com/in/jumalaw98/",
+ username: "Juma Lawrence",
+ },
+ twitter: {
+ href: "",
+ username: "",
+ },
+ },
+ {
+ name: "Racheal Murabula",
+ title: "Lead Android Engineer",
+ image: murabula,
+ linkedin: {
+ href: "https://www.linkedin.com/in/rachel-murabula-148a74122/",
+ username: "Rachel Murabula",
+ },
+ twitter: {
+ href: "",
+ username: "",
+ },
+ },
+];
diff --git a/src/APP/pages/aboutUs/sections/HeroSection.jsx b/src/pages/aboutUs/sections/HeroSection.jsx
similarity index 80%
rename from src/APP/pages/aboutUs/sections/HeroSection.jsx
rename to src/pages/aboutUs/sections/HeroSection.jsx
index a0e8e868..2a2449f6 100644
--- a/src/APP/pages/aboutUs/sections/HeroSection.jsx
+++ b/src/pages/aboutUs/sections/HeroSection.jsx
@@ -1,29 +1,31 @@
-/* eslint-disable react/jsx-one-expression-per-line */
-import { LazyLoadImage } from "react-lazy-load-image-component";
-import { SYTHero } from "../../../../assets/images/aboutPage";
-
-function HeroSection() {
- return (
-
-
-
-
- Empowering innovation in the{" "}
- African tech space
-
-
- A community fostering innovation across African borders for tech
- enthusiasts. With memberships across Kenya, Tanzania, Nigeria and
- pockets of Africa, we aim to give life and let live to innovative
- ideas in the tech ecosphere.
-
-
-
-
-
-
-
- );
-}
-
-export default HeroSection;
+import { LazyLoadImage } from "react-lazy-load-image-component";
+import { SYTHero } from "../../../assets/images/aboutPage";
+
+function HeroSection() {
+ return (
+
+
+
+
+ Empowering innovation in the{" "}
+ African tech space
+
+
+ A community fostering innovation across African borders for tech
+ enthusiasts. With memberships across Kenya, Tanzania, Nigeria and
+ pockets of Africa, we aim to give life and let live to innovative
+ ideas in the tech ecosphere.
+
+
+
+
+
+
+
+ );
+}
+
+export default HeroSection;
diff --git a/src/APP/pages/aboutUs/sections/LeadershipSection.jsx b/src/pages/aboutUs/sections/LeadershipSection.jsx
similarity index 86%
rename from src/APP/pages/aboutUs/sections/LeadershipSection.jsx
rename to src/pages/aboutUs/sections/LeadershipSection.jsx
index c06e92cb..95a8caab 100644
--- a/src/APP/pages/aboutUs/sections/LeadershipSection.jsx
+++ b/src/pages/aboutUs/sections/LeadershipSection.jsx
@@ -1,10 +1,11 @@
+/* eslint-disable no-underscore-dangle */
import emailjs from "@emailjs/browser";
import { Dialog, Transition } from "@headlessui/react";
-import React, { Fragment, useState, useRef } from "react";
+import { Fragment, useRef, useState } from "react";
+import toast from "react-hot-toast";
+import { AiOutlineClose } from "react-icons/ai"; // Import react-icons
import { LazyLoadImage } from "react-lazy-load-image-component";
-import { AiOutlineClose } from "react-icons/ai"; // Import react-icons
-
-import { PartnerWithUs } from "../../../../assets/images/aboutPage";
+import { PartnerWithUs } from "../../../assets/images/aboutPage";
import { Caroussel } from "../../../components";
import { LeadershipData } from "../data";
@@ -53,9 +54,8 @@ function LeadershipSection() {
`${PUBLIC_ID}`
)
.then(
- (result) => {
- alert("Thank you. We will get back to you as soon possible.");
-
+ () => {
+ toast.success("Thank you. We will get back to you as soon possible.");
setLoading(false);
setName("");
setEmail("");
@@ -63,11 +63,10 @@ function LeadershipSection() {
setPhoneNumber("");
closeModal();
},
- (error) => {
+ () => {
setLoading(false);
- console.log(error.text);
closeModal();
- alert("Sorry, something went wrong! 💀");
+ toast.error("Sorry, something went wrong!");
}
);
};
@@ -76,16 +75,19 @@ function LeadershipSection() {
-
+
A community is only as good
as the leadership
-
+
@@ -99,13 +101,13 @@ function LeadershipSection() {
/>
-
+
Partner with us
-
-
+
+
We collaborate with similar organizations to develop Africa’s
skilled workforce
-
+
Our main focus is on building tech capacity. We collaborate with
individuals, organizations, and public institutions to mentor and
@@ -117,8 +119,10 @@ function LeadershipSection() {
Partner with us
@@ -139,7 +143,10 @@ function LeadershipSection() {
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
-
+
@@ -154,7 +161,11 @@ function LeadershipSection() {
leaveTo="opacity-0 scale-95"
>
-
+
{loading ? "Submitting..." : "Submit"}
diff --git a/src/APP/pages/aboutUs/sections/MissionVisionSection.jsx b/src/pages/aboutUs/sections/MissionVisionSection.jsx
similarity index 85%
rename from src/APP/pages/aboutUs/sections/MissionVisionSection.jsx
rename to src/pages/aboutUs/sections/MissionVisionSection.jsx
index 2cf07e64..32637016 100644
--- a/src/APP/pages/aboutUs/sections/MissionVisionSection.jsx
+++ b/src/pages/aboutUs/sections/MissionVisionSection.jsx
@@ -1,80 +1,82 @@
-/* eslint-disable linebreak-style */
-import { LittleMore } from "../../../../assets/images/aboutPage";
-
-function MissionVisionSection() {
- return (
-
-
-
-
- A bit more about us
-
-
-
-
-
-
-
- Empowering the next generation of African innovators in tech
-
-
-
- Our activities center around designing and building software and
- hardware solutions for the most salient needs we see in the
- society, through a unique open-source model that gets our
- community members paid for their skills.
-
-
- SpaceYaTech also aims to develop capacity in the fields of
- software development and design to help build the future workforce
- and start-up founders in Africa.
-
-
-
-
-
- {/* Mission And vision */}
-
-
-
-
-
- Our Mission
-
-
-
- To help 10,000 young Africans to transition to tech in the next
- three years by being a pool of resources, mentorship and
- capacity building.
-
-
-
-
-
-
-
-
- Our Vision
-
-
-
- To be the best tech community, focused on innovation and
- actually leveraging on technology to build solutions for Africa
- and to help our community members to level up their tech skills
- in the process.
-
-
-
-
-
-
- );
-}
-
-export default MissionVisionSection;
+import { LittleMore } from "../../../assets/images/aboutPage";
+
+function MissionVisionSection() {
+ return (
+
+
+
+
+ A bit more about us
+
+
+
+
+
+
+
+ Empowering the next generation of African innovators in tech
+
+
+
+ Our activities center around designing and building software and
+ hardware solutions for the most salient needs we see in the
+ society, through a unique open-source model that gets our
+ community members paid for their skills.
+
+
+ SpaceYaTech also aims to develop capacity in the fields of
+ software development and design to help build the future workforce
+ and start-up founders in Africa.
+
+
+
+
+
+ {/* Mission And vision */}
+
+
+
+
+
+ Our Mission
+
+
+
+ To help 10,000 young Africans to transition to tech in the next
+ three years by being a pool of resources, mentorship and
+ capacity building.
+
+
+
+
+
+
+
+
+ Our Vision
+
+
+
+ To be the best tech community, focused on innovation and
+ actually leveraging on technology to build solutions for Africa
+ and to help our community members to level up their tech skills
+ in the process.
+
+
+
+
+
+
+ );
+}
+
+export default MissionVisionSection;
diff --git a/src/APP/pages/aboutUs/sections/PartnerCTA.jsx b/src/pages/aboutUs/sections/PartnerCTA.jsx
similarity index 71%
rename from src/APP/pages/aboutUs/sections/PartnerCTA.jsx
rename to src/pages/aboutUs/sections/PartnerCTA.jsx
index 4023866a..f2ae425b 100644
--- a/src/APP/pages/aboutUs/sections/PartnerCTA.jsx
+++ b/src/pages/aboutUs/sections/PartnerCTA.jsx
@@ -1,11 +1,16 @@
-import Report from "../../../../assets/documentation/spaceyatech-internship-program.pdf";
+import Report from "../../../assets/documentation/spaceyatech-internship-program.pdf";
function PartnerCTA() {
return (
;
+}
+
+export default AllBlogsPage;
diff --git a/src/APP/pages/admin/chapters/AddChapterPage.jsx b/src/pages/admin/chapters/AddChapterPage.jsx
similarity index 88%
rename from src/APP/pages/admin/chapters/AddChapterPage.jsx
rename to src/pages/admin/chapters/AddChapterPage.jsx
index 62ac9735..4461baa0 100644
--- a/src/APP/pages/admin/chapters/AddChapterPage.jsx
+++ b/src/pages/admin/chapters/AddChapterPage.jsx
@@ -1,8 +1,8 @@
import { useState, useEffect } from "react";
import { useNavigate } from "react-router-dom";
-import StepIndicator from "../../../components/admin/StepIndicator";
import AddChapterForm from "../../../components/admin/AddChapterForm";
-import usePostAddChapter from "../../../../hooks/Queries/chapter/usePostAddChapter";
+import StepIndicator from "../../../components/admin/StepIndicator";
+import usePostAddChapter from "../../../hooks/Queries/chapter/usePostAddChapter";
function AddChapterPage() {
const {
@@ -47,7 +47,9 @@ function AddChapterPage() {
};
const formComplete = (completeChapterData) => {
+ // eslint-disable-next-line no-unused-expressions
statusPostChapter === "error" && clearStatusPostChapter();
+ // eslint-disable-next-line no-unused-expressions
errorPostChapter && clearErrorPostChapter();
postChapter({ ...completeChapterData });
};
@@ -58,10 +60,9 @@ function AddChapterPage() {
setCurrentStep(0);
setCollectedChapter(null);
}
+ // eslint-disable-next-line react-hooks/exhaustive-deps
}, [statusPostChapter]);
- console.log(statusPostChapter);
-
return (
{
+ if (e.key === "Enter" || e.key === " ") {
+ clearStatusPostChapter();
+ postChapter(null);
+ }
+ }}
>
{
+ if (e.key === "Enter" || e.key === " ") {
+ clearErrorPostChapter();
+ clearStatusPostChapter();
+ }
+ }}
>
{
+ if (e.key === "Enter" || e.key === " ") {
+ clearErrorPostChapter();
+ clearStatusPostChapter();
+ }
+ }}
>
AllChaptersPage
;
+}
+
+export default AllChaptersPage;
diff --git a/src/APP/pages/admin/events/AddEventPage.jsx b/src/pages/admin/events/AddEventPage.jsx
similarity index 87%
rename from src/APP/pages/admin/events/AddEventPage.jsx
rename to src/pages/admin/events/AddEventPage.jsx
index 1a794008..0f8c261d 100644
--- a/src/APP/pages/admin/events/AddEventPage.jsx
+++ b/src/pages/admin/events/AddEventPage.jsx
@@ -1,4 +1,6 @@
-import React, { useEffect, useState } from "react";
+/* eslint-disable react/jsx-props-no-spreading */
+/* eslint-disable react/jsx-no-useless-fragment */
+import { useEffect, useState } from "react";
import { Controller, useForm } from "react-hook-form";
import {
BtnBold,
@@ -17,9 +19,9 @@ import {
Toolbar,
} from "react-simple-wysiwyg";
-import useChaptersData from "../../../../hooks/Queries/community/useChaptersData";
-import { useEventsCategories } from "../../../../hooks/Queries/eventsSection/useEventCategories";
-import usePostEvents from "../../../../hooks/Queries/eventsSection/usePostEvents";
+import useChaptersData from "../../../hooks/Queries/community/useChaptersData";
+import { useEventsCategories } from "../../../hooks/Queries/eventsSection/useEventCategories";
+import usePostEvents from "../../../hooks/Queries/eventsSection/usePostEvents";
function AddEventPage() {
const [selectedEventCategory, setSelectedEventCategory] = useState("1");
@@ -38,12 +40,6 @@ function AddEventPage() {
clearStatus: clearStatusPostEvent,
} = usePostEvents();
- const handleEventAboutChange = (e) => {
- setEditorState(e.target.value);
- setValue("about", e.target.value);
- clearErrors("about");
- };
-
const handleUploadImageClick = (e, id) => {
if ((e.type === "keydown" && e.key === "Enter") || e.type === "click")
document.getElementById(id).click();
@@ -68,14 +64,21 @@ function AddEventPage() {
context: { newCategory },
});
+ const handleEventAboutChange = (e) => {
+ setEditorState(e.target.value);
+ setValue("about", e.target.value);
+ clearErrors("about");
+ };
+
const onSubmit = (data) => {
+ // eslint-disable-next-line no-param-reassign
data.poster = poster;
postEvent({ ...data });
};
useEffect(() => {
- selectedEventCategory === "" ? setNewCategory(true) : setNewCategory(false);
+ setNewCategory(selectedEventCategory === "");
}, [selectedEventCategory]);
useEffect(() => {
@@ -89,6 +92,7 @@ function AddEventPage() {
setEditorState("");
setPoster("");
}
+ // eslint-disable-next-line react-hooks/exhaustive-deps
}, [statusPostEvent]);
return (
@@ -111,6 +115,12 @@ function AddEventPage() {
clearStatusPostEvent();
postEvent(null);
}}
+ onKeyDown={() => {
+ clearStatusPostEvent();
+ postEvent(null);
+ }}
+ role="button"
+ tabIndex="0"
>
{
+ if (e.key === "Enter") {
+ clearErrorPostEvent();
+ clearStatusPostEvent();
+ }
+ }}
+ role="button"
+ tabIndex="0"
>
{
+ if (e.key === "Enter") {
+ clearErrorPostEvent();
+ clearStatusPostEvent();
+ }
+ }}
+ role="button"
+ tabIndex="0"
>
- handleUploadImageClick(e, "poster")}
- onKeyDown={(e) => handleUploadImageClick(e, "poster")}
- tabIndex="0"
- role="button"
- >
-
(
- <>
- {
- field.onChange(e);
- setPoster(e.target.files[0]);
- }}
- style={{ display: "none" }}
- />
-
+
(
+ handleUploadImageClick(e, "poster")}
+ onKeyDown={(e) => handleUploadImageClick(e, "poster")}
+ tabIndex="0"
+ role="button"
+ >
+
{
+ field.onChange(e);
+ setPoster(e.target.files[0]);
+ }}
+ style={{ display: "none" }}
+ />
+
+
+
+ Upload Event Poster
+
+
+ {poster ? (
+
+ ) : (
-
- Upload Event Poster
+
+ PNG, JPG, JFIF
- {poster ? (
-
- ) : (
-
- )}
-
- >
- )}
- />
-
+ )}
+
+
+ )}
+ />
{errors.poster && (
{errors.poster.message}
diff --git a/src/APP/pages/admin/events/AllEventsPage.jsx b/src/pages/admin/events/AllEventsPage.jsx
similarity index 100%
rename from src/APP/pages/admin/events/AllEventsPage.jsx
rename to src/pages/admin/events/AllEventsPage.jsx
diff --git a/src/APP/pages/admin/events/UpdateEventPage.jsx b/src/pages/admin/events/UpdateEventPage.jsx
similarity index 99%
rename from src/APP/pages/admin/events/UpdateEventPage.jsx
rename to src/pages/admin/events/UpdateEventPage.jsx
index a699335e..09573adf 100644
--- a/src/APP/pages/admin/events/UpdateEventPage.jsx
+++ b/src/pages/admin/events/UpdateEventPage.jsx
@@ -1,4 +1,4 @@
-import React from "react";
+/* eslint-disable jsx-a11y/label-has-associated-control */
function UpdateEventPage() {
return (
diff --git a/src/pages/admin/shop/OrdersPage.jsx b/src/pages/admin/shop/OrdersPage.jsx
new file mode 100644
index 00000000..db3c3468
--- /dev/null
+++ b/src/pages/admin/shop/OrdersPage.jsx
@@ -0,0 +1,133 @@
+import { IoFilter } from "react-icons/io5";
+import columns from "../../../components/admin/shop/orders/Columns";
+import Orders from "../../../components/admin/shop/orders/Orders";
+import OrdersChart from "../../../components/admin/shop/orders/OrdersChart";
+import OrdersTrends from "../../../components/admin/shop/orders/OrdersTrends";
+
+function OrdersPage() {
+ const data = [
+ {
+ id: "ORD-101",
+ email: "ian@gmail.com",
+ date: "12-02-2023",
+ number: 2,
+ cost: 1000,
+ status: "Complete",
+ },
+ {
+ id: "ORD-102",
+ email: "pam@gmail.com",
+ date: "12-02-2023",
+ number: 1,
+ cost: 500,
+ status: "Unfulfilled",
+ },
+ {
+ id: "ORD-103",
+ email: "fred@gmail.com",
+ date: "12-02-2023",
+ number: 3,
+ cost: 1500,
+ status: "Unfulfilled",
+ },
+ {
+ id: "ORD-104",
+ email: "kelly@gmail.com",
+ date: "12-02-2023",
+ number: 5,
+ cost: 2500,
+ status: "Pending",
+ },
+ {
+ id: "ORD-105",
+ email: "emmy@gmail.com",
+ date: "12-02-2023",
+ number: 2,
+ cost: 100,
+ status: "Pending",
+ },
+ {
+ id: "ORD-106",
+ email: "sonia@gmail.com",
+ date: "12-02-2023",
+ number: 1,
+ cost: 350,
+ status: "Complete",
+ },
+ {
+ id: "ORD-107",
+ email: "emmy@gmail.com",
+ date: "12-02-2023",
+ number: 2,
+ cost: 100,
+ status: "Pending",
+ },
+ {
+ id: "ORD-108",
+ email: "sonia@gmail.com",
+ date: "12-02-2023",
+ number: 1,
+ cost: 350,
+ status: "Complete",
+ },
+ {
+ id: "ORD-109",
+ email: "emmy@gmail.com",
+ date: "12-02-2023",
+ number: 2,
+ cost: 100,
+ status: "Unfulfilled",
+ },
+ {
+ id: "ORD-110",
+ email: "bridgit@gmail.com",
+ date: "12-02-2023",
+ number: 1,
+ cost: 350,
+ status: "Complete",
+ },
+ ];
+
+ return (
+
+ Orders Report
+
+
Trends in Orders
+
+
+
+
+
+
Orders
+
+
+ Filter
+
+
+
+
+
+
+
+
Showing 1 to 10 of 20 results
+
+
+ Previous
+
+
+ Next
+
+
+
+
+
+ );
+}
+
+export default OrdersPage;
diff --git a/src/pages/admin/shop/dashboard/AdminMain.jsx b/src/pages/admin/shop/dashboard/AdminMain.jsx
new file mode 100644
index 00000000..7024a213
--- /dev/null
+++ b/src/pages/admin/shop/dashboard/AdminMain.jsx
@@ -0,0 +1,67 @@
+import AdminReportCard, {
+ BigChartComponent,
+ ChartComponent,
+ HighDemandCard,
+ InvenOrderCard,
+ InvenOrderCardTwo,
+ totalOrdersData,
+ totalSalesData,
+ totalVisitInnerCardData,
+ totalVisitInnerCardDataTwo,
+ TotalVisitsCustomCard,
+ totalVisitsData,
+} from "../../../../components/admin/AdminReportCard";
+
+function AdminMain() {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ Trends in Sales
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default AdminMain;
diff --git a/src/pages/admin/shop/dashboard/ShopDashboard.jsx b/src/pages/admin/shop/dashboard/ShopDashboard.jsx
new file mode 100644
index 00000000..5cd85a2e
--- /dev/null
+++ b/src/pages/admin/shop/dashboard/ShopDashboard.jsx
@@ -0,0 +1,51 @@
+import { Link } from "react-router-dom";
+import columns from "../../../../components/admin/shop/dashboard/OrderPreviewColumns";
+import OrdersPreviewTable from "../../../../components/admin/shop/dashboard/OrdersPreviewTable";
+import AdminMain from "./AdminMain";
+
+function ShopDashboard() {
+ const data = [
+ {
+ id: "728ed52",
+ email: "m@example.com",
+ item: "SYT Jacket",
+ cost: 100,
+ status: "complete",
+ },
+ {
+ id: "728d52f",
+ email: "m@example.com",
+ item: "SYT Jacket",
+ cost: 100,
+ status: "unfullfilled",
+ },
+ {
+ id: "728ed2f",
+ email: "m@example.com",
+ item: "SYT Jacket",
+ cost: 100,
+ status: "pending",
+ },
+ ];
+
+ return (
+
+
+
+
Orders
+
+ View All
+
+
+
+
+
+
+
+ );
+}
+
+export default ShopDashboard;
diff --git a/src/pages/admin/shop/inventory/InventoryReport.jsx b/src/pages/admin/shop/inventory/InventoryReport.jsx
new file mode 100644
index 00000000..1c7a9f0a
--- /dev/null
+++ b/src/pages/admin/shop/inventory/InventoryReport.jsx
@@ -0,0 +1,72 @@
+import { useState } from "react";
+import { IoFilterOutline } from "react-icons/io5";
+import InventoryCardComponent from "../../../../components/admin/shop/inventory/InventoryCardComponent";
+import columns from "../../../../components/admin/shop/inventory/InventoryPreviewColumn";
+import InventoryPreviewTable from "../../../../components/admin/shop/inventory/InventoryPreviewTable";
+import Modal from "../../../../components/admin/shop/inventory/Modal";
+import data from "./data";
+
+function InventoryReport() {
+ const [showModal, setShowModal] = useState(false);
+
+ const handleClick = () => {
+ setShowModal(true);
+ };
+
+ return (
+
+
+
+
+ Inventory Report
+
+
+ {" "}
+ ADD ITEM
+
+
+
+
+
+
+
+
+
Inventory
+
+ Filter
+
+
+
+
+
+
+
+ {showModal && (
+
setShowModal(false)} showModal={showModal} />
+ )}
+
+ );
+}
+
+export default InventoryReport;
diff --git a/src/pages/admin/shop/inventory/data.js b/src/pages/admin/shop/inventory/data.js
new file mode 100644
index 00000000..cdc7eb82
--- /dev/null
+++ b/src/pages/admin/shop/inventory/data.js
@@ -0,0 +1,58 @@
+const data = [
+ {
+ id: "ITM-101",
+ name: "SYT Beanie",
+ totalItems: 400,
+ noOfId: "No. of items: 350",
+ unitCost: "Unit Cost: KES 350",
+ totalSales: 1225000,
+ itemsRemaining: 50,
+ },
+ {
+ id: "ITM-102",
+ name: "SYT Hoodie",
+ totalItems: 50,
+ noOfId: "No. of items: 5",
+ unitCost: "Unit Cost: KES 1000",
+ totalSales: 5000,
+ itemsRemaining: 40,
+ },
+ {
+ id: "ITM-103",
+ name: "SYT Beanie",
+ totalItems: 400,
+ noOfId: "No. of items: 350",
+ unitCost: "Unit Cost: KES 350",
+ totalSales: 1225000,
+ itemsRemaining: 500,
+ },
+ {
+ id: "ITM-104",
+ name: "SYT Beanie",
+ totalItems: 400,
+ noOfId: "No. of items: 350",
+ unitCost: "Unit Cost: KES 350",
+ totalSales: 1225000,
+ itemsRemaining: 30,
+ },
+ {
+ id: "ITM-105",
+ name: "SYT Beanie",
+ totalItems: 400,
+ noOfId: "No. of items: 350",
+ unitCost: "Unit Cost: KES 350",
+ totalSales: 1225000,
+ itemsRemaining: 20,
+ },
+ {
+ id: "ITM-106",
+ name: "SYT Beanie",
+ totalItems: 400,
+ noOfId: "No. of items: 350",
+ unitCost: "Unit Cost: KES 350",
+ totalSales: 1225000,
+ itemsRemaining: 50,
+ },
+];
+
+export default data;
diff --git a/src/pages/admin/shop/sales/ShopSales.jsx b/src/pages/admin/shop/sales/ShopSales.jsx
new file mode 100644
index 00000000..a216d194
--- /dev/null
+++ b/src/pages/admin/shop/sales/ShopSales.jsx
@@ -0,0 +1,51 @@
+import { Link } from "react-router-dom";
+import { ChartComponent } from "../../../../components/admin/AdminReportCard";
+import columns from "../../../../components/admin/shop/sales/SalesPreviewColumn";
+import SalesPreviewTable from "../../../../components/admin/shop/sales/SalesPreviewTable";
+import data from "./data";
+import ShopSalesTrends from "./ShopSalesTrends";
+
+function ShopSales() {
+ return (
+
+
+ Sales Report
+
+
+ Trends In Sales
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Shop
+
+ View All
+
+
+
+
+
+
+
+ );
+}
+
+export default ShopSales;
diff --git a/src/pages/admin/shop/sales/ShopSalesTrends.jsx b/src/pages/admin/shop/sales/ShopSalesTrends.jsx
new file mode 100644
index 00000000..3e47f33c
--- /dev/null
+++ b/src/pages/admin/shop/sales/ShopSalesTrends.jsx
@@ -0,0 +1,6 @@
+import SalesGraph from "../../../../components/admin/shop/sales/SalesGraph";
+
+function ShopSalesTrends() {
+ return ;
+}
+export default ShopSalesTrends;
diff --git a/src/pages/admin/shop/sales/data.js b/src/pages/admin/shop/sales/data.js
new file mode 100644
index 00000000..cdc7eb82
--- /dev/null
+++ b/src/pages/admin/shop/sales/data.js
@@ -0,0 +1,58 @@
+const data = [
+ {
+ id: "ITM-101",
+ name: "SYT Beanie",
+ totalItems: 400,
+ noOfId: "No. of items: 350",
+ unitCost: "Unit Cost: KES 350",
+ totalSales: 1225000,
+ itemsRemaining: 50,
+ },
+ {
+ id: "ITM-102",
+ name: "SYT Hoodie",
+ totalItems: 50,
+ noOfId: "No. of items: 5",
+ unitCost: "Unit Cost: KES 1000",
+ totalSales: 5000,
+ itemsRemaining: 40,
+ },
+ {
+ id: "ITM-103",
+ name: "SYT Beanie",
+ totalItems: 400,
+ noOfId: "No. of items: 350",
+ unitCost: "Unit Cost: KES 350",
+ totalSales: 1225000,
+ itemsRemaining: 500,
+ },
+ {
+ id: "ITM-104",
+ name: "SYT Beanie",
+ totalItems: 400,
+ noOfId: "No. of items: 350",
+ unitCost: "Unit Cost: KES 350",
+ totalSales: 1225000,
+ itemsRemaining: 30,
+ },
+ {
+ id: "ITM-105",
+ name: "SYT Beanie",
+ totalItems: 400,
+ noOfId: "No. of items: 350",
+ unitCost: "Unit Cost: KES 350",
+ totalSales: 1225000,
+ itemsRemaining: 20,
+ },
+ {
+ id: "ITM-106",
+ name: "SYT Beanie",
+ totalItems: 400,
+ noOfId: "No. of items: 350",
+ unitCost: "Unit Cost: KES 350",
+ totalSales: 1225000,
+ itemsRemaining: 50,
+ },
+];
+
+export default data;
diff --git a/src/APP/pages/auth/ForgotPassword.jsx b/src/pages/auth/ForgotPassword.jsx
similarity index 86%
rename from src/APP/pages/auth/ForgotPassword.jsx
rename to src/pages/auth/ForgotPassword.jsx
index b6862e8c..194b2d48 100644
--- a/src/APP/pages/auth/ForgotPassword.jsx
+++ b/src/pages/auth/ForgotPassword.jsx
@@ -1,7 +1,6 @@
-import React from "react";
import { MdEmail, MdMessage } from "react-icons/md"; // Import react-icons
-import ForgotPasswordImg from "../../../assets/images/auth/forgot-password.svg";
import { LazyLoadImage } from "react-lazy-load-image-component";
+import ForgotPasswordImg from "../../assets/images/auth/forgot-password.svg";
function ForgotPassword() {
return (
@@ -28,11 +27,15 @@ function ForgotPassword() {
-
+
Via Email
@@ -40,9 +43,13 @@ function ForgotPassword() {
-
+
Via SMS
Let's create a new password for your account
-
Let's get you started
-
+
diff --git a/src/APP/pages/blog2/Blog2.jsx b/src/pages/blog/Blog.jsx
similarity index 92%
rename from src/APP/pages/blog2/Blog2.jsx
rename to src/pages/blog/Blog.jsx
index 02f68447..7d52c2cc 100644
--- a/src/APP/pages/blog2/Blog2.jsx
+++ b/src/pages/blog/Blog.jsx
@@ -1,12 +1,12 @@
-import React, { useEffect } from "react";
+import { useEffect } from "react";
import { useNavigate, useParams } from "react-router-dom";
-import useBlogData from "../../../hooks/Queries/blog/useBlogData";
import { Loader } from "../../components";
import SeoMetadata from "../../components/SeoMetadata";
+import useBlogData from "../../hooks/Queries/blog/useBlogData";
import { Advert, BlogHeader, BlogBody } from "./sections";
-function Blog2() {
+function Blog() {
const { titleSlug } = useParams();
const navigate = useNavigate();
@@ -69,4 +69,4 @@ function Blog2() {
);
}
-export default Blog2;
+export default Blog;
diff --git a/src/APP/pages/blog2/sections/Advert.jsx b/src/pages/blog/sections/Advert.jsx
similarity index 82%
rename from src/APP/pages/blog2/sections/Advert.jsx
rename to src/pages/blog/sections/Advert.jsx
index 5eea6687..4dd7e444 100644
--- a/src/APP/pages/blog2/sections/Advert.jsx
+++ b/src/pages/blog/sections/Advert.jsx
@@ -1,7 +1,7 @@
import React from "react";
import { LazyLoadImage } from "react-lazy-load-image-component";
-import { advert } from "../../../../assets/images/blogs-page";
+import { advert } from "../../../assets/images/blogs-page";
function Advert() {
return (
diff --git a/src/APP/pages/blog2/sections/BlogBody.jsx b/src/pages/blog/sections/BlogBody.jsx
similarity index 76%
rename from src/APP/pages/blog2/sections/BlogBody.jsx
rename to src/pages/blog/sections/BlogBody.jsx
index 81a75db1..09af54dd 100644
--- a/src/APP/pages/blog2/sections/BlogBody.jsx
+++ b/src/pages/blog/sections/BlogBody.jsx
@@ -2,19 +2,17 @@
import { useRef, useEffect } from "react";
import { LazyLoadImage } from "react-lazy-load-image-component";
-import { glovo } from "../../../../assets/images/blogs-page";
+import { glovo } from "../../../assets/images/blogs-page";
import NextRead from "./NextRead";
import RelatedBlogs from "./RelatedBlogs";
-import "./blogBody.css";
-
function BlogBody({ id, categoryId, blogBody }) {
const BodyRef = useRef(null);
useEffect(() => {
if (BodyRef.current) {
- BodyRef.current.innerHTML += blogBody ?? "";
+ BodyRef.current.innerHTML = blogBody ?? "";
}
}, [blogBody]);
@@ -22,8 +20,10 @@ function BlogBody({ id, categoryId, blogBody }) {
{/* read next */}
diff --git a/src/APP/pages/blog2/sections/BlogHeader.jsx b/src/pages/blog/sections/BlogHeader.jsx
similarity index 94%
rename from src/APP/pages/blog2/sections/BlogHeader.jsx
rename to src/pages/blog/sections/BlogHeader.jsx
index 81123941..15134755 100644
--- a/src/APP/pages/blog2/sections/BlogHeader.jsx
+++ b/src/pages/blog/sections/BlogHeader.jsx
@@ -2,10 +2,10 @@
import { formatDistanceToNow } from "date-fns";
import React from "react";
-import logo from "../../../../assets/images/sytLogo.png";
+import { LazyLoadImage } from "react-lazy-load-image-component";
+import logo from "../../../assets/images/sytLogo.png";
import BlogStats from "../../blogs/sections/BlogStats";
import ShareBlog from "./ShareBlog";
-import { LazyLoadImage } from "react-lazy-load-image-component";
function BlogHeader({
id,
@@ -33,7 +33,7 @@ function BlogHeader({
-
-
-
-
-
+
You might like these
-
+
{/* left */}
@@ -37,6 +37,7 @@ function NextRead() {
className="w-6 md:w-10 h-6 md:h-10"
type="button"
onClick={handlePrev}
+ aria-label="Previous"
>
- {
refetchRelatedBlogsData();
+ // eslint-disable-next-line react-hooks/exhaustive-deps
}, [titleSlug]);
const filteredRelatedBlogs = filterRelatedBlogs(
@@ -33,16 +33,16 @@ function RelatedBlogs({ blogId, categoryId }) {
{isSuccess && filteredRelatedBlogs.length > 0 && (
-
+
{filteredRelatedBlogs.length > 1
? "Related Articles"
: "Related Article"}
-
+
{Array.isArray(filteredRelatedBlogs) &&
filteredRelatedBlogs.length > 0 ? (
filteredRelatedBlogs
- .filter(function (blog) {
+ .filter((blog) => {
if (blog.id === blogId) {
return false;
}
@@ -60,3 +60,8 @@ function RelatedBlogs({ blogId, categoryId }) {
}
export default RelatedBlogs;
+
+RelatedBlogs.propTypes = {
+ blogId: PropTypes.number.isRequired,
+ categoryId: PropTypes.number.isRequired,
+};
diff --git a/src/APP/pages/blog2/sections/ShareBlog.jsx b/src/pages/blog/sections/ShareBlog.jsx
similarity index 86%
rename from src/APP/pages/blog2/sections/ShareBlog.jsx
rename to src/pages/blog/sections/ShareBlog.jsx
index 2dd934fd..88ad32e8 100644
--- a/src/APP/pages/blog2/sections/ShareBlog.jsx
+++ b/src/pages/blog/sections/ShareBlog.jsx
@@ -1,7 +1,5 @@
-/* eslint-disable react/prop-types */
-/* eslint-disable import/no-extraneous-dependencies */
+import PropTypes from "prop-types";
import React from "react";
-
import {
FacebookIcon,
FacebookShareButton,
@@ -16,7 +14,7 @@ import {
function ShareBlog({ url, title }) {
return (
-
share it
+
share it
-
Blogs
+ Blogs
e.preventDefault()}
>
-
+
diff --git a/src/APP/pages/blogs/sections/BlogCard.jsx b/src/pages/blogs/sections/BlogCard.jsx
similarity index 96%
rename from src/APP/pages/blogs/sections/BlogCard.jsx
rename to src/pages/blogs/sections/BlogCard.jsx
index 29fd9c5f..d6e3b3b8 100644
--- a/src/APP/pages/blogs/sections/BlogCard.jsx
+++ b/src/pages/blogs/sections/BlogCard.jsx
@@ -5,7 +5,7 @@ import React from "react";
import { LazyLoadImage } from "react-lazy-load-image-component";
import { Link } from "react-router-dom";
-import logo from "../../../../assets/images/sytLogo.png";
+import logo from "../../../assets/images/sytLogo.png";
import BlogStats from "./BlogStats";
function BlogCard({ blog }) {
diff --git a/src/APP/pages/blogs/sections/BlogPagination.jsx b/src/pages/blogs/sections/BlogPagination.jsx
similarity index 84%
rename from src/APP/pages/blogs/sections/BlogPagination.jsx
rename to src/pages/blogs/sections/BlogPagination.jsx
index 0f7abc96..19cdef4a 100644
--- a/src/APP/pages/blogs/sections/BlogPagination.jsx
+++ b/src/pages/blogs/sections/BlogPagination.jsx
@@ -1,17 +1,21 @@
-const BlogPagination = ({
+/* eslint-disable camelcase */
+import PropTypes from "prop-types";
+
+function BlogPagination({
count,
next,
previous,
current,
blogs_per_page,
onPageChange,
-}) => {
+}) {
let button_count = 0;
// Determine total pages
if (next === null) {
if (previous === null) {
// Do not show nav
} else {
+ // eslint-disable-next-line radix
const previous_page_count = parseInt(previous.split("=")[1]);
button_count = previous_page_count + 1;
}
@@ -24,10 +28,12 @@ const BlogPagination = ({
const buttons = [];
+ // eslint-disable-next-line no-plusplus
for (let index = 1; index <= button_count; index++) {
buttons.push(
onPageChange({ index })}
className="flex items-center justify-center px-4 h-10 leading-tight text-gray-500 bg-white border border-gray-300 hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white"
>
@@ -42,6 +48,7 @@ const BlogPagination = ({
onPageChange({ index: prevP })}
className="flex items-center justify-center px-4 h-10 ml-0 leading-tight text-gray-500 bg-white border border-gray-300 rounded-l-lg hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white"
>
@@ -66,6 +73,7 @@ const BlogPagination = ({
{buttons}
onPageChange({ index: nextP })}
className="flex items-center justify-center px-4 h-10 leading-tight text-gray-500 bg-white border border-gray-300 rounded-r-lg hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white"
>
@@ -90,6 +98,20 @@ const BlogPagination = ({
);
-};
+}
export default BlogPagination;
+
+BlogPagination.propTypes = {
+ count: PropTypes.number.isRequired,
+ next: PropTypes.string,
+ previous: PropTypes.string,
+ current: PropTypes.number.isRequired,
+ blogs_per_page: PropTypes.number.isRequired,
+ onPageChange: PropTypes.func.isRequired,
+};
+
+BlogPagination.defaultProps = {
+ previous: null,
+ next: null,
+};
diff --git a/src/APP/pages/blogs/sections/BlogStats.jsx b/src/pages/blogs/sections/BlogStats.jsx
similarity index 74%
rename from src/APP/pages/blogs/sections/BlogStats.jsx
rename to src/pages/blogs/sections/BlogStats.jsx
index c074109f..8a845171 100644
--- a/src/APP/pages/blogs/sections/BlogStats.jsx
+++ b/src/pages/blogs/sections/BlogStats.jsx
@@ -1,9 +1,9 @@
+import PropTypes from "prop-types";
import { useEffect, useState } from "react";
import { PiThumbsUp } from "react-icons/pi";
-import usePostLikeBlog from "../../../../hooks/Queries/blog/usePostLikeBlog";
-import { LazyLoadImage } from "react-lazy-load-image-component";
+import usePostLikeBlog from "../../../hooks/Queries/blog/usePostLikeBlog";
-const BlogStats = ({ blogId, likes }) => {
+function BlogStats({ blogId, likes }) {
const [updatedLikes, setUpdatedLikes] = useState(likes);
const {
@@ -14,12 +14,14 @@ const BlogStats = ({ blogId, likes }) => {
clearStatus: clearStatusLikeBlog,
} = usePostLikeBlog();
- const addLikeToBlog = (blogId) => {
+ const addLikeToBlog = (blogID) => {
+ // eslint-disable-next-line no-unused-expressions
statusLikeBlog === "error" && clearErrorLikeBlog();
+ // eslint-disable-next-line no-unused-expressions
errorLikeBlog && clearErrorLikeBlog();
const blogDetails = {
- id: blogId,
+ id: blogID,
};
likeBlog({ ...blogDetails });
@@ -32,6 +34,7 @@ const BlogStats = ({ blogId, likes }) => {
}
clearStatusLikeBlog();
clearErrorLikeBlog();
+ // eslint-disable-next-line react-hooks/exhaustive-deps
}, [likes, statusLikeBlog]);
return (
@@ -42,12 +45,13 @@ const BlogStats = ({ blogId, likes }) => {
*/}
-
{
+ // eslint-disable-next-line no-unused-expressions
blogId ? addLikeToBlog(blogId) : "";
}}
- />
+ />
{updatedLikes}
@@ -59,6 +63,11 @@ const BlogStats = ({ blogId, likes }) => {
*/}
);
-};
+}
export default BlogStats;
+
+BlogStats.propTypes = {
+ blogId: PropTypes.number.isRequired,
+ likes: PropTypes.number.isRequired,
+};
diff --git a/src/APP/pages/blogs/sections/BlogsWrapper.jsx b/src/pages/blogs/sections/BlogsWrapper.jsx
similarity index 87%
rename from src/APP/pages/blogs/sections/BlogsWrapper.jsx
rename to src/pages/blogs/sections/BlogsWrapper.jsx
index 875e508b..6f615697 100644
--- a/src/APP/pages/blogs/sections/BlogsWrapper.jsx
+++ b/src/pages/blogs/sections/BlogsWrapper.jsx
@@ -1,13 +1,14 @@
-import React, { useState, useEffect, useContext } from "react";
+import PropTypes from "prop-types";
+import { useContext, useEffect, useState } from "react";
-import { SearchBlogContext } from "../../../../context/searchBlog";
+import { Loader } from "../../../components";
+import { SearchBlogContext } from "../../../context/searchBlog";
import {
- useBlogsData,
useBlogCategories,
-} from "../../../../hooks/Queries/blogs/useAllBlogsData";
+ useBlogsData,
+} from "../../../hooks/Queries/blogs/useAllBlogsData";
-import { filterBlogsByCat } from "../../../../utilities/FilterBlogs";
-import { Loader } from "../../../components";
+import { filterBlogsByCat } from "../../../utilities/FilterBlogs";
import Error500 from "../../errorPages/Error500";
import BlogCard from "./BlogCard";
@@ -18,7 +19,7 @@ function SearchResults({ searchText }) {
return (
Showing results for
- "{searchText}"
+ "{searchText}"
);
}
@@ -41,9 +42,11 @@ function BlogsWrapper() {
useEffect(() => {
refetchBlogsData();
+ // eslint-disable-next-line react-hooks/exhaustive-deps
}, [page]);
const handlePageChange = ({ index }) => {
+ // eslint-disable-next-line no-unused-vars, no-param-reassign, no-return-assign
setPage((prevState) => (prevState = index));
};
@@ -140,3 +143,11 @@ function BlogsWrapper() {
}
export default BlogsWrapper;
+
+SearchResults.propTypes = {
+ searchText: PropTypes.string,
+};
+
+SearchResults.defaultProps = {
+ searchText: "",
+};
diff --git a/src/APP/pages/blogs/sections/FeaturedBlogs.jsx b/src/pages/blogs/sections/FeaturedBlogs.jsx
similarity index 92%
rename from src/APP/pages/blogs/sections/FeaturedBlogs.jsx
rename to src/pages/blogs/sections/FeaturedBlogs.jsx
index f0fb48e1..1b9b5847 100644
--- a/src/APP/pages/blogs/sections/FeaturedBlogs.jsx
+++ b/src/pages/blogs/sections/FeaturedBlogs.jsx
@@ -2,8 +2,8 @@
import React, { useState } from "react";
import { Link, useParams } from "react-router-dom";
-import { useBlogsData } from "../../../../hooks/Queries/blogs/useAllBlogsData";
-import { filteredReadNextBlogs } from "../../../../utilities/FilterBlogs";
+import { useBlogsData } from "../../../hooks/Queries/blogs/useAllBlogsData";
+import { filteredReadNextBlogs } from "../../../utilities/FilterBlogs";
function FeaturedBlogs() {
const [currentIndex, setCurrentIndex] = useState(0);
@@ -45,7 +45,7 @@ function FeaturedBlogCard({ blog, currentIndex, handleToggle }) {
backgroundImage: `linear-gradient(to top, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0)), url("${blog.image}")`,
}}
>
-
Featured
+
Featured
{
+function JoinSytSelectFields() {
return (
<>
{selectFields.map((field) => (
@@ -71,6 +71,6 @@ const JoinSytSelectFields = () => {
))}
>
);
-};
+}
export default JoinSytSelectFields;
diff --git a/src/APP/pages/community/sections/WelcomeSection.jsx b/src/pages/community/sections/WelcomeSection.jsx
similarity index 94%
rename from src/APP/pages/community/sections/WelcomeSection.jsx
rename to src/pages/community/sections/WelcomeSection.jsx
index 3df9d537..c043de36 100644
--- a/src/APP/pages/community/sections/WelcomeSection.jsx
+++ b/src/pages/community/sections/WelcomeSection.jsx
@@ -1,7 +1,7 @@
import { useState } from "react";
import { LazyLoadImage } from "react-lazy-load-image-component";
-import { NewHero } from "../../../../assets/images/community";
+import { NewHero } from "../../../assets/images/community";
import JoinSYTModal from "./JoinSYTModal";
function WelcomeSection() {
@@ -32,7 +32,6 @@ function WelcomeSection() {
Join SpaceYaTech
diff --git a/src/APP/pages/community/sections/eventsPreview/SingleEvents/SingleEvent.jsx b/src/pages/community/sections/eventsPreview/SingleEvents/SingleEvent.jsx
similarity index 93%
rename from src/APP/pages/community/sections/eventsPreview/SingleEvents/SingleEvent.jsx
rename to src/pages/community/sections/eventsPreview/SingleEvents/SingleEvent.jsx
index 96a5108d..828fa718 100644
--- a/src/APP/pages/community/sections/eventsPreview/SingleEvents/SingleEvent.jsx
+++ b/src/pages/community/sections/eventsPreview/SingleEvents/SingleEvent.jsx
@@ -1,10 +1,9 @@
-import React, { useEffect } from "react";
+import { useEffect } from "react";
import { useParams } from "react-router-dom";
-import SeoMetadata from "../../../../../components/SeoMetadata";
-
import { GoBackBtn, LandingWrapper, Loader } from "../../../../../components";
+import SeoMetadata from "../../../../../components/SeoMetadata";
+import useOneEvent from "../../../../../hooks/Queries/singleEvent/useSingleEvent";
import { EventDescription, Hero, SimilarEvents } from "./sections";
-import { useOneEvent } from "@/hooks/Queries/singleEvent/useSingleEvent";
function SingleEvent() {
const { id } = useParams();
diff --git a/src/pages/community/sections/eventsPreview/SingleEvents/sections/EventCard.jsx b/src/pages/community/sections/eventsPreview/SingleEvents/sections/EventCard.jsx
new file mode 100644
index 00000000..2f5282ba
--- /dev/null
+++ b/src/pages/community/sections/eventsPreview/SingleEvents/sections/EventCard.jsx
@@ -0,0 +1,121 @@
+import PropTypes from "prop-types";
+import { FaCalendarDay, FaGlobe } from "react-icons/fa";
+import { IoMdPricetag } from "react-icons/io";
+import { MdOutlineAccessTimeFilled } from "react-icons/md";
+import { Link } from "react-router-dom";
+import {
+ eventCardPhysical,
+ eventCardVirtual,
+} from "../../../../../../assets/images/community";
+import LocationTag from "./LocationTag";
+
+function EventCard({ event }) {
+ const isVirtual = event?.mode === "Virtual";
+
+ return (
+
+
+
+
+
+ {event?.name}
+
+
+
+
+
+
+
+
+
+ {event?.start_date}
+
+
+
+
+
+
+
+ {event?.start_time}
+
+
+
+
+
+
+
+ {event?.mode === "Physical" ? event?.location : event?.mode}
+
+
+
+
+
+
+
+ {event?.category.name}
+
+
+
+
+
+ Learn More
+
+
+
+ );
+}
+
+export default EventCard;
+
+EventCard.propTypes = {
+ event: PropTypes.shape({
+ id: PropTypes.number.isRequired,
+ name: PropTypes.string.isRequired,
+ about: PropTypes.string.isRequired,
+ link: PropTypes.string.isRequired,
+ location: PropTypes.string.isRequired,
+ mode: PropTypes.string.isRequired,
+ city: PropTypes.string.isRequired,
+ country: PropTypes.string.isRequired,
+ start_date: PropTypes.string.isRequired,
+ end_date: PropTypes.string.isRequired,
+ start_time: PropTypes.string.isRequired,
+ end_time: PropTypes.string.isRequired,
+ poster: PropTypes.string.isRequired,
+ category: PropTypes.shape({
+ id: PropTypes.number.isRequired,
+ name: PropTypes.string.isRequired,
+ }).isRequired,
+ chapter: PropTypes.shape({
+ id: PropTypes.number.isRequired,
+ name: PropTypes.string.isRequired,
+ about: PropTypes.string.isRequired,
+ city: PropTypes.string.isRequired,
+ country: PropTypes.string.isRequired,
+ socials: PropTypes.shape({
+ Twitter: PropTypes.string,
+ }),
+ members: PropTypes.number.isRequired,
+ }).isRequired,
+ created_at: PropTypes.string.isRequired,
+ updated_at: PropTypes.string.isRequired,
+ }),
+};
+
+EventCard.defaultProps = {
+ event: {},
+};
diff --git a/src/APP/pages/community/sections/eventsPreview/SingleEvents/sections/EventDescription.jsx b/src/pages/community/sections/eventsPreview/SingleEvents/sections/EventDescription.jsx
similarity index 50%
rename from src/APP/pages/community/sections/eventsPreview/SingleEvents/sections/EventDescription.jsx
rename to src/pages/community/sections/eventsPreview/SingleEvents/sections/EventDescription.jsx
index 9c725a9d..478d2b5f 100644
--- a/src/APP/pages/community/sections/eventsPreview/SingleEvents/sections/EventDescription.jsx
+++ b/src/pages/community/sections/eventsPreview/SingleEvents/sections/EventDescription.jsx
@@ -1,10 +1,11 @@
import PropTypes from "prop-types";
import React from "react";
+import formatEventDescription from "../../../../../../utilities/formatEventDescription";
function EventDescription({ eventDesc }) {
return (
-
- {eventDesc}
+
+ {formatEventDescription(eventDesc)}
);
}
diff --git a/src/APP/pages/community/sections/eventsPreview/SingleEvents/sections/EventRSVP.jsx b/src/pages/community/sections/eventsPreview/SingleEvents/sections/EventRSVP.jsx
similarity index 92%
rename from src/APP/pages/community/sections/eventsPreview/SingleEvents/sections/EventRSVP.jsx
rename to src/pages/community/sections/eventsPreview/SingleEvents/sections/EventRSVP.jsx
index bf52d17f..12a85fcf 100644
--- a/src/APP/pages/community/sections/eventsPreview/SingleEvents/sections/EventRSVP.jsx
+++ b/src/pages/community/sections/eventsPreview/SingleEvents/sections/EventRSVP.jsx
@@ -1,14 +1,14 @@
import { Dialog, Transition } from "@headlessui/react";
import { format, parseISO } from "date-fns";
-import React, { Fragment } from "react";
+import PropTypes from "prop-types";
+import { Fragment } from "react";
import { LazyLoadImage } from "react-lazy-load-image-component";
-
-import { rsvpEvent } from "../../../../../../../assets/images/community";
-import { sytLogoWhite } from "../../../../../../../assets/images/icons";
+import { rsvpEvent } from "../../../../../../assets/images/community";
+import { sytLogoWhite } from "../../../../../../assets/images/icons";
import RSVPForm from "./RSVPForm";
function EventRSVP({ isOpen, closeModal, event }) {
- const [hours, minutes] = event?.start_time.split(":");
+ const [hours, minutes] = (event?.start_time ?? "").split(":");
const time = new Date();
time.setHours(hours);
@@ -70,7 +70,7 @@ function EventRSVP({ isOpen, closeModal, event }) {
>
- {format(time, "HHmm") + " HRS"}
+ {`${format(time, "HHmm")} HRS`}
@@ -222,3 +222,17 @@ function EventRSVP({ isOpen, closeModal, event }) {
}
export default EventRSVP;
+
+EventRSVP.propTypes = {
+ isOpen: PropTypes.bool.isRequired,
+ closeModal: PropTypes.func.isRequired,
+ event: PropTypes.shape({
+ start_time: PropTypes.string.isRequired,
+ start_date: PropTypes.string.isRequired,
+ mode: PropTypes.string.isRequired,
+ location: PropTypes.string,
+ category: PropTypes.shape({
+ name: PropTypes.string.isRequired,
+ }).isRequired,
+ }).isRequired,
+};
diff --git a/src/APP/pages/community/sections/eventsPreview/SingleEvents/sections/Hero.jsx b/src/pages/community/sections/eventsPreview/SingleEvents/sections/Hero.jsx
similarity index 94%
rename from src/APP/pages/community/sections/eventsPreview/SingleEvents/sections/Hero.jsx
rename to src/pages/community/sections/eventsPreview/SingleEvents/sections/Hero.jsx
index bbd86d6c..45622b51 100644
--- a/src/APP/pages/community/sections/eventsPreview/SingleEvents/sections/Hero.jsx
+++ b/src/pages/community/sections/eventsPreview/SingleEvents/sections/Hero.jsx
@@ -1,18 +1,18 @@
/* eslint-disable react/no-unknown-property */
import PropTypes from "prop-types";
-import React, { useState } from "react";
+import { useState } from "react";
+import {
+ eventsPhysicalBg,
+ eventsVirtualBg,
+} from "../../../../../../assets/images/community";
import EventRSVP from "./EventRSVP";
-import { eventsPhysicalBg, eventsVirtualBg } from "@/assets/images/community";
function Hero({ event }) {
const isVirtual = event?.mode === "Virtual";
const [isOpen, setIsOpen] = useState(false);
- function closeModal() {
- setIsOpen(false);
- }
-
+ // eslint-disable-next-line no-unused-vars
function openModal() {
setIsOpen(true);
}
@@ -181,20 +181,26 @@ ${isVirtual ? "text-white" : "text-green-header"}
-
- Reserve for Free
-
+ Reserve Tickets
+
-
+ setIsOpen(false)}
+ event={event}
+ />
);
diff --git a/src/APP/pages/community/sections/eventsPreview/SingleEvents/sections/LocationTag.jsx b/src/pages/community/sections/eventsPreview/SingleEvents/sections/LocationTag.jsx
similarity index 100%
rename from src/APP/pages/community/sections/eventsPreview/SingleEvents/sections/LocationTag.jsx
rename to src/pages/community/sections/eventsPreview/SingleEvents/sections/LocationTag.jsx
diff --git a/src/APP/pages/community/sections/eventsPreview/SingleEvents/sections/RSVPForm.jsx b/src/pages/community/sections/eventsPreview/SingleEvents/sections/RSVPForm.jsx
similarity index 85%
rename from src/APP/pages/community/sections/eventsPreview/SingleEvents/sections/RSVPForm.jsx
rename to src/pages/community/sections/eventsPreview/SingleEvents/sections/RSVPForm.jsx
index f3c46142..07cb3492 100644
--- a/src/APP/pages/community/sections/eventsPreview/SingleEvents/sections/RSVPForm.jsx
+++ b/src/pages/community/sections/eventsPreview/SingleEvents/sections/RSVPForm.jsx
@@ -1,20 +1,21 @@
-import React from "react";
+/* eslint-disable jsx-a11y/label-has-associated-control */
+import PropTypes from "prop-types";
import { LazyLoadImage } from "react-lazy-load-image-component";
-
-import { sytLogoGreen } from "../../../../../../../assets/images/icons";
+import { sytLogoGreen } from "../../../../../../assets/images/icons";
function RSVPForm({ closeModal }) {
const handleSubmit = (e) => {
e.preventDefault();
const formData = new FormData(e.target);
+ // eslint-disable-next-line no-unused-vars
const name = formData.get("name");
+ // eslint-disable-next-line no-unused-vars
const email = formData.get("email");
- console.log("Name: ", name, "Email: ", email);
-
closeModal();
};
+
return (
-
+
A memory bank of our special
moments
-
+