-
-
-
-
-
-
-
-
-
-
+ const socialIcons = [
+ {
+ href: "https://mail.google.com/mail/u/0/?fs=1&tf=cm&to=info@projxon.com",
+ ariaLabel: "Email",
+ icon: FaEnvelope,
+ newTab: false
+ },
+ {
+ href: "https://twitter.com/projxon",
+ ariaLabel: "Twitter",
+ icon: FaTwitter,
+ newTab: true
+ },
+ {
+ href: "https://linkedin.com/company/projxon",
+ ariaLabel: "LinkedIn",
+ icon: FaLinkedin,
+ newTab: true
+ }
+ ]
+
+ //Note: I assume that all of these href values are supposed to be different and go to different pages/subpages, or different sections of the same page (like /services#marketing-social) and the fact that each subsection of the footer gave all of them the same href was just a placeholder. But when copying over the code, I kept the href links exactly how they originally were.
+ const footerLinks = [
+ {
+ heading: "Services",
+ links: [
+ {
+ href: "/services",
+ text: "Marketing + Social"
+ },
+ {
+ href: "/services",
+ text: "E-commerce Solutions"
+ },
+ {
+ href: "/services",
+ text: "Business Optimization"
+ },
+ {
+ href: "/services",
+ text: "Project Management"
+ },
+ {
+ href: "/services",
+ text: "IT Interactions"
+ }
+ ]
+ },
+ {
+ heading: "About",
+ links: [
+ {
+ href: "/about",
+ text: "Vision"
+ },
+ {
+ href: "/about",
+ text: "Mission"
+ },
+ {
+ href: "/about",
+ text: "Core Value"
+ },
+ {
+ href: "/about",
+ text: "Meet the Team"
+ },
+ {
+ href: "/about",
+ text: "Our Journey"
+ }
+ ]
+ },
+ {
+ heading: "Partnerships",
+ links: [
+ {
+ href: "/servicepartners",
+ text: "Service Partners"
+ },
+ {
+ href: "/referralpartners",
+ text: "Referral Partners"
+ }
+ ]
+ },
+ {
+ heading: "Connect",
+ links: [
+ {
+ href: "/contact",
+ text: "Contact"
+ },
+ {
+ href: "/contact",
+ text: "Social"
+ },
+ {
+ href: "/contact",
+ text: "Appoint"
+ },
+ {
+ href: "/contact",
+ text: "Inquiries"
+ },
+ {
+ href: "/contact",
+ text: "Address (Google)"
+ }
+ ]
+ },
+ {
+ heading: "Research",
+ links: [
+ {
+ href: "/research",
+ text: "Blog"
+ },
+ {
+ href: "/research",
+ text: "Events"
+ },
+ {
+ href: "/research",
+ text: "Articles"
+ },
+ {
+ href: "/research",
+ text: "Newsletter"
+ }
+ ]
+ },
+ {
+ heading: "Careers",
+ links: [
+ {
+ href: "/career",
+ text: "Join Our Team"
+ },
+ {
+ href: "/career",
+ text: "Internship Program"
+ }
+ ]
+ }
+ ]
+
+ return (
- );
+
+
+ © {new Date().getFullYear()} PROJXON. All rights reserved.
+
+
+
+ )
};
export default Footer;
diff --git a/components/Leads.jsx b/components/Leads.jsx
new file mode 100644
index 0000000..eade833
--- /dev/null
+++ b/components/Leads.jsx
@@ -0,0 +1,132 @@
+"use client"
+
+import {
+ FaLinkedin,
+ FaGlobe,
+} from "react-icons/fa";
+import LeadsGroup from "@/components/LeadsGroup";
+
+export default function Leads() {
+ const consultingLeads = [
+ {
+ image: "/assets/about/team/phelan.webp",
+ name: "Mark Phelan",
+ title: "Senior Consultant,",
+ specialty: "E-Commerce Solutions",
+ socials: [
+ {
+ icon: FaLinkedin,
+ href: "https://www.linkedin.com/in/phelanmarkw",
+ },
+ {
+ icon: FaGlobe,
+ href: "https://www.thephelanfocus.com/",
+ },
+ ],
+ },
+ {
+ image: "/assets/about/team/kathy.webp",
+ name: "Kathy Seaton",
+ title: "Senior Consultant,",
+ specialty: "Non Profit Development",
+ socials: [
+ {
+ icon: FaLinkedin,
+ href: "https://www.linkedin.com/in/klseaton",
+ },
+ {
+ icon: FaGlobe,
+ href: "https://www.klseatonconsulting.com/",
+ },
+ ],
+ },
+ {
+ image: "/assets/about/team/donavon.webp",
+ name: "Donavon Roberson",
+ title: "Senior Consultant,",
+ specialty: "Tech + Software Solutions",
+ socials: [
+ {
+ icon: FaLinkedin,
+ href: "https://www.linkedin.com/in/donavonroberson",
+ },
+ {
+ icon: FaGlobe,
+ href: "https://medium.com/@thejourneyofthedreamer",
+ },
+ ],
+ },
+ {
+ image: "/assets/about/team/melissa.webp",
+ name: "Melissa Eboli",
+ title: "Senior Consultant,",
+ specialty: "Health + Wellness Solutions",
+ socials: [
+ {
+ icon: FaLinkedin,
+ href: "https://www.linkedin.com/in/viamelissa",
+ },
+ {
+ icon: FaGlobe,
+ href: "https://www.viaskitchen.com/"
+ },
+ ],
+ },
+ ];
+
+ const teamLeads = [
+ {
+ image: "/assets/about/team/bast.webp",
+ name: "Bast Herrera",
+ title: "Team Lead,",
+ specialty: "Program Development",
+ socials: [
+ {
+ icon: FaLinkedin,
+ href: "https://www.linkedin.com/in/vincentcherrera",
+ },
+ ],
+ },
+ {
+ image: "/assets/about/team/dania.webp",
+ name: "Dania Ali",
+ title: "Team Lead,",
+ specialty: "Operations + Strategy",
+ socials: [
+ {
+ icon: FaLinkedin,
+ href: "https://www.linkedin.com/in/syeda-dania-ali",
+ },
+ ],
+ },
+ {
+ image: "/assets/about/team/megha.webp",
+ name: "Megha Vinjamuru",
+ title: "Team Lead,",
+ specialty: "Project Management",
+ socials: [
+ {
+ icon: FaLinkedin,
+ href: "https://www.linkedin.com/in/meghanethra",
+ },
+ ],
+ },
+ {
+ image: "/assets/about/team/alexandria.webp",
+ name: "Alexandria Boreman",
+ title: "Team Lead,",
+ specialty: "Marketing + Creative",
+ socials: [
+ {
+ icon: FaLinkedin,
+ href: "https://www.linkedin.com/in/alexandriaboreman",
+ },
+ ],
+ },
+ ];
+
+ return (<>
+
+
+ >)
+}
\ No newline at end of file
diff --git a/components/LeadsGroup.jsx b/components/LeadsGroup.jsx
new file mode 100644
index 0000000..81147c2
--- /dev/null
+++ b/components/LeadsGroup.jsx
@@ -0,0 +1,46 @@
+"use client"
+
+import { Row, Col } from "react-bootstrap";
+import Image from "next/image";
+import renderIcon from "@/lib/renderIcon";
+
+export default function LeadsGroup({ heading, leads }) {
+ return (<>
+
{heading}
+
+ {leads.map((member, i) => (
+
+
+
+
+
{member.name}
+
{member.title}
+
{member.specialty}
+
+
+
+
+ ))}
+
+ >)
+}
\ No newline at end of file
diff --git a/components/OurValues.jsx b/components/OurValues.jsx
new file mode 100644
index 0000000..923c560
--- /dev/null
+++ b/components/OurValues.jsx
@@ -0,0 +1,49 @@
+"use client"
+
+import { Container, Row } from "react-bootstrap";
+import BlackCard from "@/components/BlackCard";
+import {
+ FaLightbulb,
+ FaBalanceScale,
+ FaUsers
+} from "react-icons/fa";
+
+export default function OurValues() {
+ const values = [
+ {
+ icon: FaLightbulb,
+ title: "Innovation",
+ description:
+ "We constantly seek out new ideas and approaches to stay ahead of industry trends and provide our clients with cutting-edge solutions.",
+ },
+ {
+ icon: FaBalanceScale,
+ title: "Integrity",
+ description:
+ "We believe in doing business with honesty and transparency, building trust with our clients and partners through ethical practices.",
+ },
+ {
+ icon: FaUsers,
+ title: "Collaboration",
+ description:
+ "We work closely with our clients and partners, fostering a collaborative environment that drives success for everyone involved.",
+ },
+ ];
+
+ return (
+
+
+ Our Core Values
+
+
+ {values.map((value, index) => (
+
+ ))}
+
+
+ )
+}
\ No newline at end of file
diff --git a/components/ServiceCards.jsx b/components/ServiceCards.jsx
index 61d6d3f..c35da2e 100644
--- a/components/ServiceCards.jsx
+++ b/components/ServiceCards.jsx
@@ -1,56 +1,33 @@
"use client";
-import { Card, Col, Row } from "react-bootstrap";
+import { Card, Col } from "react-bootstrap";
+import renderIcon from "@/lib/renderIcon";
-const ServiceCards = ({ services }) => {
- return (
-
-
-
- {services.slice(0, 3).map((service, index) => (
-
-
- {service.icon}
- {service.title}
- {service.description}
-
-
- ))}
-
-
-
-
- {services.slice(3, 5).map((service, index) => (
-
-
- {service.icon}
- {service.title}
- {service.description}
-
-
- ))}
-
-
-
- );
+const ServiceCards = ({ services, divClasses }) => {
+ return (
+
+ {services.map((service, index) => (
+
+
+
+ {renderIcon(service.icon, 40)}
+
+ {service.title}
+ {service.description}
+
+
+ ))}
+
+ );
};
export default ServiceCards;
diff --git a/components/Services.jsx b/components/Services.jsx
new file mode 100644
index 0000000..7202449
--- /dev/null
+++ b/components/Services.jsx
@@ -0,0 +1,54 @@
+"use client"
+
+import {
+ FaMobile,
+ FaCogs,
+ FaProjectDiagram,
+ FaShoppingCart,
+ FaLaptopCode,
+} from "react-icons/fa";
+import { Row } from "react-bootstrap";
+import ServiceCards from "@/components/ServiceCards";
+
+export default function Services() {
+ const services = [
+ {
+ image: "/assets/homepage/services-img/market.webp",
+ icon: FaMobile,
+ title: "Marketing + Social Media",
+ description:
+ "Amplify your brand's impact with expert marketing and social media strategies. Engage your audience, accelerate growth, and redefine your digital presence.",
+ },
+ {
+ image: "/assets/homepage/services-img/ecom.webp",
+ icon: FaShoppingCart,
+ title: "E-commerce Solutions",
+ description:
+ "Transform your online business with tailored e-commerce solutions. Optimize performance, boost sales, and enhance customer satisfaction.",
+ },
+ {
+ image: "/assets/homepage/services-img/business.webp",
+ icon: FaCogs,
+ title: "Business Process Optimization",
+ description: "Streamline your operations and enhance efficiency with our business optimization services. Achieve greater productivity and profitability.",
+ },
+ {
+ image: "/assets/homepage/services-img/manage.webp",
+ icon: FaProjectDiagram,
+ title: "Project Management",
+ description:
+ "Ensure timely, budget-friendly project delivery with our expert management services. We focus on seamless project process management with an emphasis on continuity to improve efficiency and achieve your goals.",
+ },
+ {
+ image: "/assets/homepage/services-img/it.webp",
+ icon: FaLaptopCode,
+ title: "IT + Tech Integrations",
+ description: "Boost your business with our innovative IT solutions. We design custom IT and tech packages to increase efficiencies and maximize output.",
+ },
+ ];
+
+ return (
+
+
+
)
+}
\ No newline at end of file
diff --git a/lib/getBlogs.js b/lib/getBlogs.js
new file mode 100644
index 0000000..33da5cd
--- /dev/null
+++ b/lib/getBlogs.js
@@ -0,0 +1,25 @@
+export default async function getBlogs(slug = null) {
+ try {
+ const endpoint = slug ? `/posts?_embed&slug=${slug}` : `/posts?_embed`;
+
+ console.log(`Fetching from: ${process.env.WORDPRESS_API_URL}${endpoint}`);
+
+ const res = await fetch(`${process.env.WORDPRESS_API_URL}${endpoint}`, {
+ headers: {
+ Authorization:
+ "Basic " +
+ btoa(
+ `${process.env.WORDPRESS_API_USERNAME}:${process.env.WORDPRESS_API_PASSWORD}`
+ ),
+ },
+ next: { revalidate: 60 }
+ });
+
+ if (!res.ok) throw new Error(`Failed to fetch data: ${res.statusText}`)
+
+ return await res.json();
+ } catch (error) {
+ console.error("Error fetching blogs:", error);
+ return slug ? null : []
+ }
+}
\ No newline at end of file
diff --git a/lib/getClients.js b/lib/getClients.js
new file mode 100644
index 0000000..6158494
--- /dev/null
+++ b/lib/getClients.js
@@ -0,0 +1,14 @@
+export default async function getClients(id = null, isStatic = true) {
+ try {
+ const fetchOptions = isStatic ? { next: { revalidate: 60 } } : { cache: "no-store" }
+ const res = await fetch(`${process.env.WORDPRESS_CUSTOM_API_URL}/clients`, fetchOptions);
+
+ if (!res.ok) throw new Error(`Failed to fetch clients. Status: ${res.status}`)
+ const data = await res.json();
+
+ return id ? data.find(c => c.id === id) : data
+ } catch (error) {
+ console.error("Error fetching client")
+ return id ? null : []
+ }
+}
\ No newline at end of file
diff --git a/lib/renderIcon.js b/lib/renderIcon.js
new file mode 100644
index 0000000..cbeddf4
--- /dev/null
+++ b/lib/renderIcon.js
@@ -0,0 +1,3 @@
+export default function renderIcon(Icon, size, className = null) {
+ return
+}
\ No newline at end of file
diff --git a/package.json b/package.json
index 065df0e..8c37a54 100644
--- a/package.json
+++ b/package.json
@@ -5,7 +5,7 @@
"main": "index.js",
"scripts": {
"dev": "next dev",
- "build": "node --max-old-space-size=4096 node_modules/.bin/next build",
+ "build": "next build",
"start": "next start",
"lint": "next lint",
"generate-sitemap": "node generate-sitemap.js",
@@ -32,4 +32,4 @@
"react-icons": "^5.5.0",
"react-intersection-observer": "^9.16.0"
}
-}
+}
\ No newline at end of file
diff --git a/public/PROJXON.png b/public/PROJXON.png
new file mode 100644
index 0000000..9a4756d
Binary files /dev/null and b/public/PROJXON.png differ
diff --git a/services/blogService.js b/services/blogService.js
index 8693faa..88c9341 100644
--- a/services/blogService.js
+++ b/services/blogService.js
@@ -1,29 +1,18 @@
-// services/blogService.js
+import getBlogs from '@/lib/getBlogs'
export const fetchBlogs = async () => {
try {
- const response = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/blog`); // Full URL
-
- if (!response.ok) {
- throw new Error("Failed to fetch blogs");
- }
-
- return await response.json();
+ return await getBlogs()
} catch (error) {
console.error("❌ Error fetching blogs:", error);
return []; // Return empty array if error occurs
}
};
-export const fetchBlog = async (id) => {
+export const fetchBlog = async id => {
try {
- const response = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/blog?slug=${id}`); // Full URL
-
- if (!response.ok) {
- throw new Error(`Failed to fetch blog with id: ${id}`);
- }
- const data = await response.json();
- return data[0];
+ const data = await getBlogs(id)
+ return data[0]
} catch (error) {
console.error("❌ Error fetching blog:", error);
return null;
diff --git a/services/clientService.js b/services/clientService.js
index 36af768..a84f764 100644
--- a/services/clientService.js
+++ b/services/clientService.js
@@ -1,38 +1,14 @@
-// services/clientService.js
-
-// We will modify the clientService.js to fetch data internally instead of externally
+import getClients from '@/lib/getClients'
import axios from 'axios';
-const api = axios.create({
- baseURL: process.env.WORDPRESS_CUSTOM_API_URL,
- headers: {
- 'Content-Type': 'application/json',
- },
-});
+export const fetchClients = async () => await getClients()
-export const fetchClients = async () => {
- const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/client`); // Internal API route
- if (!res.ok) {
- throw new Error("Error fetching clients");
- }
- return res.json(); // Parse the JSON response
-};
+export const fetchClient = async id => await getClients(id)
-export const fetchClient = async (id) => {
- const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/client/${id}`); // Internal API route with dynamic id
- if (!res.ok) {
- throw new Error("Error fetching client");
- }
- return res.json(); // Parse the JSON response
-};
-
-export const addClient = async (clientData) => {
+export const addClient = async clientData => {
try {
const token = localStorage.getItem("authToken");
-
- if (!token) {
- throw new Error("Unauthorized - No token found");
- }
+ if (!token) throw new Error("Unauthorized - No token found")
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/client`, {
method: "POST",
@@ -44,20 +20,21 @@ export const addClient = async (clientData) => {
});
if (!res.ok) {
- const errorResponse = await res.json();
- throw new Error(`Error adding client: ${errorResponse.message || res.statusText}`);
+ const errorResponse = await res.json();
+ console.error("Error from WordPress API:", errorResponse); // Log error response from WordPress
+ throw new Error(`Failed to add client. Status code: ${res.status}`);
}
- return res.json();
+ return await res.json()
} catch (error) {
- console.error("❌ Error adding client:", error.message);
- return null;
+ console.error("Error adding client")
+ throw error
}
};
-export const uploadFile = async (file) => {
+export const uploadFile = async file => {
const token = localStorage.getItem("authToken");
-
+
if (!token) {
throw new Error("No token found");
}
@@ -66,25 +43,22 @@ export const uploadFile = async (file) => {
formData.append('file', file);
try {
- const response = await axios.post('/api/upload', formData, {
- headers: {
- 'Authorization': `Bearer ${token}`,
- },
- });
- return response.data.url;
+ const response = await axios.post('/api/upload', formData, {
+ headers: {
+ 'Authorization': `Bearer ${token}`,
+ },
+ });
+ return response.data.url;
} catch (error) {
- console.error('Error uploading file:', error);
- throw error;
+ console.error('Error uploading file:', error);
+ throw error;
}
};
-export const deleteClient = async (id) => {
+export const deleteClient = async id => {
try {
const token = localStorage.getItem("authToken");
-
- if (!token) {
- throw new Error("Unauthorized - No token found");
- }
+ if (!token) throw new Error("Unauthorized - No token found")
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/client/${id}`, {
method: "DELETE",
@@ -94,11 +68,7 @@ export const deleteClient = async (id) => {
},
});
- if (!res.ok) {
- throw new Error("Error deleting client");
- }
-
- return res.status === 200 || res.status === 204;
+ return res.ok
} catch (error) {
console.error("❌ Error deleting client:", error);
return false;
diff --git a/services/loginService.js b/services/loginService.js
index c903964..aa8087a 100644
--- a/services/loginService.js
+++ b/services/loginService.js
@@ -1,5 +1,3 @@
-import axiosInstance from "../utils/axiosInstance";
-
const login = async (username, password) => {
try {
const response = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/auth`, {