diff --git a/client/src/components/NavBar/NavBar.tsx b/client/src/components/NavBar/NavBar.tsx index b140fd3..bae89a4 100644 --- a/client/src/components/NavBar/NavBar.tsx +++ b/client/src/components/NavBar/NavBar.tsx @@ -1,167 +1,3 @@ -// import React, { useState } from "react"; -// import { Link, NavLink } from "react-router-dom"; -// import "./NavBar.css"; - -// const NavBar: React.FC = () => { -// const [isCollapsed, setIsCollapsed] = useState(true); - -// const toggleNavbar = () => setIsCollapsed(!isCollapsed); - -// return ( -// -// ); -// }; - -// export default NavBar; - -// import React, { useState, useEffect } from "react"; -// import { Link, NavLink, useNavigate } from "react-router-dom"; -// import "./NavBar.css"; - -// const NavBar: React.FC = () => { -// const [isCollapsed, setIsCollapsed] = useState(true); -// const [isLoggedIn, setIsLoggedIn] = useState(false); -// const navigate = useNavigate(); - -// const toggleNavbar = () => setIsCollapsed(!isCollapsed); - -// // Check login status on mount -// useEffect(() => { -// const token = localStorage.getItem("token"); -// setIsLoggedIn(!!token); -// }, []); - -// // Logout handler -// const handleLogout = () => { -// localStorage.removeItem("token"); -// localStorage.removeItem("userId"); -// setIsLoggedIn(false); -// navigate("/Login"); -// }; - -// return ( -// -// ); -// }; - -// export default NavBar; - -// NavBar.tsx import React, { useState, useEffect } from "react"; import { Link, NavLink, useNavigate, useLocation } from "react-router-dom"; import "./NavBar.css"; diff --git a/client/src/containers/AboutUs/globalassetdispatching/DispatchAgreement/Agreement/PostForm.jsx b/client/src/containers/AboutUs/globalassetdispatching/DispatchAgreement/Agreement/PostForm.jsx index 4c7dca3..e91a896 100644 --- a/client/src/containers/AboutUs/globalassetdispatching/DispatchAgreement/Agreement/PostForm.jsx +++ b/client/src/containers/AboutUs/globalassetdispatching/DispatchAgreement/Agreement/PostForm.jsx @@ -1,306 +1,3 @@ -// import React, { useState, useRef } from "react"; -// // import PropTypes from 'prop-types' -// import SignatureCanvas from "react-signature-canvas"; -// import Axios from "axios"; - -// const PostForm = () => { -// let sigPad = useRef({}); -// const url = "/api/agreement/need2work"; -// const [signature, setSign] = useState(); -// const [data, setData] = useState({ -// email: "", -// description: "", -// date: "", -// numberMC: 0, -// invoiceRate: 0, -// company: "", -// signature: "", -// }); -// const [showResults, setShowResults] = React.useState(false); -// const onClick = () => setShowResults(true); - -// const clear = (e) => { -// sigPad.current.clear(); -// }; -// const save = (e) => { -// setSign(sigPad.current.getTrimmedCanvas().toDataURL("image/png")); -// // data["numberMC"]=Number -// // console.log("signature", signature); -// }; - -// // Test -// // const obj = [data, sigPad, { signature }]; -// // const obj = [{data}, {signature}] -// // console.log(obj); - -// function submit(e) { -// e.preventDefault(e); -// const body = { data, signature }; -// // console.log("data", data.email); -// // console.log("My e.target", e.target.email.value); -// // console.log(sigPad); -// // console.log(signature); -// Axios.post(url, body) -// .then((res) => { -// setData({ ...data, [e.target.name]: e.target.value }); -// // console.log("My Data from Res: ", res); -// window.location.replace("/AboutUs"); -// }) -// .catch((err) => console.log(err)); -// } - -// function handle(e) { -// const newData = { ...data }; -// newData[e.target.id] = e.target.value; -// setData(newData); -// // console.log(`data from handle: ${JSON.stringify(data)}`); -// // console.log(newData); -// } - -// return ( -// <> -// {/* FIXME */} -// {/* redirect to home page or the next agreement */} -//
submit(e)} -// > -// {/* Create a PDF to send to the admin email after customer fills it out */} -//
Agreement
-//
-// Email Address: -//
-// handle(e)} -// id="email" -// value={data.email} -// placeholder="email" -// type="email" -// >{" "} -//
-//
-// This Dispatcher-Carrier Agreement hereinafter "Agreement' is made and -// entered on{" "} -// handle(e)} -// id="date" -// value={data.date} -// placeholder="date" -// type="date" -// > -// (the "effective date") by and between Berhenny Dean Co, a New Jersey -// limited liability Company, and, a Registered Motor Carrier with its -// principal office at -// handle(e)} -// id="description" -// value={data.description} -// placeholder="description" -// type="text" -// >{" "} -// ("Carrier"): collectively referred to as the "Parties".
-//
-// WHEREAS, DISPATCHER is an Independent Contractor conducting Load -// Tendering Transitions between Freight Shippers or Freight Holders, and -// Carriers authorized by the Federal Motor Carrier Safety Administration -// ("FMCS") to operate as a Registered Property Carriers Pursuant to -// Licenses issued. DISPATCHER is not a broker nor acting as a broker to -// the CARRIER.
-//
-// WHEREAS, CARRIER, an independent contractor, is licensed by the FMCS to -// operate as a for-hire motor carrier pursuant authority issued in Number -// MC- -// handle(e)} -// id="numberMC" -// value={data.numberMC} -// placeholder="numberMC" -// type="number" -// >{" "} -//
-//
-// WHEREAS, the transportation service provided by CARRIER for Freight -// Shippers, whether on regulated, unregulated, or intrastate traffic, is -// intended by the Parties to be contract carriage between the CARRIER and -// Freight Shippers/Holders as defined in 49 U.S.C. $13102 (4) and §14101 -// (b) and not between DISPATCHER, and the Parties hereto intend that the -// contractual arrangement be continuous in nature until this agreement is, -// by its terms, terminated; and
-//
-// WHEREAS, both DISPATCHER and CARRIER enter into this Agreement for the -// purpose of providing and receiving specified services under specified -// rates and conditions, DISPATCHER and CARRIER deem it essential to their -// respective interest to establish and maintain an Independent Contractor -// relationship in the execution and performance of this agreement; and{" "} -//
-//
-// DISPATCHER is NOT responsible for the following: billing issues, load -// problems, advances (all advances will have to be handled directly -// between CARRIER and shipper/broker), handling and storage of paperwork -// all documents will be sent to CARRIER, (at Carrier's expense), and DOT -// compliance issues;
-//
-// NOW, THEREFORE, for and in consideration of the mutual covenants and -// undertakings herein, and subject to the terms and conditions hereinafter -// set forth, the Parties hereto warrant, covenant, and agree as follows:{" "} -//
-//
-// CARRIER desires to retain DISPATCHER by executing a Limited, Power of -// Attorney to find, negotiate, and procure freight for and dispatch -// CARRIER's equipment at a flat rate of{" "} -// handle(e)} -// id="freightRate" -// value={data.freightRate} -// placeholder="freightRate" -// type="number" -// >{" "} -// the gross of each load. Additional billing services may be procured at a -// rate of $ -// handle(e)} -// id="invoiceRate" -// value={data.invoiceRate} -// placeholder="invoiceRate" -// type="number" -// >{" "} -// invoice. All DISPATCHER fees must be paid after each load has been -// booked and accepted by the CARRIER. CARRIER must, prior to the -// implementation, of this agreement furnish to DISPATCHER the following:{" "} -//
-//
-//
    -//
  1. A signed Limited Power of Attorney form (optional)
  2. -//
  3. Copy of CARRIER's Motor Carrier Authority
  4. -//
  5. This AGREEMENT form is completed dated and signed
  6. -//
  7. -// Copy of Insurance Certificates, listing DISPATCHER as a certificate -// holder. **DISPATCHER requires at least $1,000,000 liability -// insurance and at least $100;000 cargo coverage. **Power-only -// carriers must also have $40,000 non-owned trailer or interchange -// insurance. -//
  8. -//
  9. A signed W-9
  10. -//
  11. -// Company Profile Sheet (including a list if three established -// references) -//
  12. -//
  13. -// Cell phone or contact phone number and name of main company contact -//
  14. -//
-//
-//
-//
-// -//
-// {/* The API methods are mostly just wrappers around signature_pad's API. on() and off() will, in addition, bind/unbind the window resize event handler. -// getCanvas(), getTrimmedCanvas(), and getSignaturePad() are new. */} -// {/* getTrimmedCanvas(): canvas, creates a copy of the canvas and returns a trimmed version of it, with all whitespace removed. -// getSignaturePad(): SignaturePad, returns the underlying SignaturePad reference. */} -//
-//

GADZConnect LLC.

-//
-// -//
-// ___________________________ -//
-//
-// -//
-// ___________________________ -//
-//
-// -//
-//
-//
-//

-// -//
-// handle(e)} -// id="company" -// value={data.company} -// placeholder="company" -// type="text" -// >{" "} -//
-//
-// -//
-// {" "} -//
-// -//
-// handle(e)} -// id="print" -// value={data.print} -// placeholder="print" -// type="text" -// >{" "} -//
-// -//
-// handle(e)} -// id="date" -// value={data.date} -// placeholder="date" -// type="date" -// >{" "} -//
-//
-// {/* https://github.com/agilgur5/react-signature-canvas/blob/gh-pages/example/app.js */} -//
-// {/* Please Hide this until the customer click save below. */} -// {/* {" "} */} -// {"Please Click Save to save signature Before Submitting this form"} -// {/* The Test */} -//
-// {/* */} -// {showResults ? ( -// -// ) : null} -//
-// -// {/* Fix the value if there is a problem */} -// -//
-// -//
-// -// ); -// }; - -// // PostForm.propTypes = { -// // id: PropTypes.string.isRequired, -// // onChange: PropTypes.func.isRequired, -// // } - -// export default PostForm; - import React, { useState, useRef } from "react"; import SignatureCanvas from "react-signature-canvas"; import Axios from "axios"; diff --git a/client/src/containers/Admin/B2BMessages/B2BMessages.tsx b/client/src/containers/Admin/B2BMessages/B2BMessages.tsx index 9acc1be..5e39e4c 100644 --- a/client/src/containers/Admin/B2BMessages/B2BMessages.tsx +++ b/client/src/containers/Admin/B2BMessages/B2BMessages.tsx @@ -1,3 +1,82 @@ +// import React, { useEffect, useState } from "react"; +// import axios from "axios"; + +// type Message = { +// updatedAt: string; +// createdAt: string; +// sender: string; +// receiver: string; +// content: string; +// }; + +// const B2BMessages: React.FC = () => { +// const [messages, setMessages] = useState([]); +// const [error, setError] = useState(null); +// useEffect(() => { +// axios +// .get("/api/message/cheat") +// .then((response) => { +// setMessages(response.data); +// setError(null); +// }) +// .catch((error) => { +// console.error("Error fetching messages:", error); +// setError("Failed to fetch messages. Please try again later."); +// }); +// }, []); + +// return ( +//
+//

Admin Dashboard

+// {error &&

{error}

} +// +// +// +// +// +// +// +// +// +// +// +// {messages.map((message, index) => ( +// +// +// +// +// +// +// +// ))} +// +//
+// Sender +// +// Receiver +// +// Content +// +// Date & Time +// +// Updated +//
+// {message.sender} +// +// {message.receiver} +// +// {message.content} +// +// {message.createdAt} +// +// {message.updatedAt} +//
+//
+// ); +// }; + +// export default B2BMessages; + import React, { useEffect, useState } from "react"; import axios from "axios"; @@ -11,68 +90,84 @@ type Message = { const B2BMessages: React.FC = () => { const [messages, setMessages] = useState([]); + const [loading, setLoading] = useState(true); const [error, setError] = useState(null); + useEffect(() => { - axios - .get("/api/message/cheat") - .then((response) => { - setMessages(response.data); + const fetchMessages = async () => { + try { + const res = await axios.get("/api/message/cheat"); + setMessages(res.data); setError(null); - }) - .catch((error) => { - console.error("Error fetching messages:", error); + } catch (err) { + console.error("Error fetching messages:", err); setError("Failed to fetch messages. Please try again later."); - }); + } finally { + setLoading(false); + } + }; + + fetchMessages(); }, []); + const formatDate = (dateStr: string) => { + const d = new Date(dateStr); + return d.toLocaleString(); + }; + return (
-

Admin Dashboard

- {error &&

{error}

} - - - - - - - - - - - - {messages.map((message, index) => ( - - - - - - +

Admin Dashboard

+ + {/* Loading Indicator */} + {loading && ( +

+ Loading + messages… +

+ )} + + {/* Error Message */} + {error &&

{error}

} + + {/* No Messages */} + {!loading && !error && messages.length === 0 && ( +

No messages found.

+ )} + + {/* Message Table */} + {!loading && messages.length > 0 && ( +
- Sender - - Receiver - - Content - - Date & Time - - Updated -
- {message.sender} - - {message.receiver} - - {message.content} - - {message.createdAt} - - {message.updatedAt} -
+ + + + + + + - ))} - -
SenderReceiverContentCreatedUpdated
+ + + {messages.map((msg, i) => ( + + {msg.sender} + {msg.receiver} + {msg.content} + {formatDate(msg.createdAt)} + {formatDate(msg.updatedAt)} + + ))} + + + )}
); }; +const cellStyle = { + border: "1px solid #ddd", + padding: "8px", + fontSize: "14px", +}; + export default B2BMessages; diff --git a/client/src/containers/Admin/Tickets/TicketsCreated.css b/client/src/containers/Admin/Tickets/TicketsCreated.css index 71f8339..cdd988c 100644 --- a/client/src/containers/Admin/Tickets/TicketsCreated.css +++ b/client/src/containers/Admin/Tickets/TicketsCreated.css @@ -1,4 +1,4 @@ -.tickets-header { +/* .tickets-header { text-align: center; margin-bottom: 20px; } @@ -46,4 +46,115 @@ td a:hover { margin-top: 20px; text-align: center; color: #007bff; +} */ + +.tickets-wrapper { + padding: 20px; +} + +.tickets-title { + text-align: center; + margin-bottom: 20px; + color: #333; +} + +/* Search Bar */ +.search-container { + text-align: center; + margin-bottom: 20px; +} + +.search-container input { + width: 90%; + max-width: 400px; + padding: 10px 12px; + border-radius: 8px; + border: 1px solid #ccc; +} + +/* Table */ +.table-container { + width: 100%; + overflow-x: auto; +} + +.tickets-table { + width: 100%; + border-collapse: collapse; +} + +.tickets-table th, +.tickets-table td { + padding: 10px; + border: 1px solid #ddd; +} + +.tickets-table th { + background-color: #f8f8f8; + text-align: left; +} + +.archive-btn { + background: #c62828; + color: white; + border: none; + padding: 6px 10px; + border-radius: 5px; + cursor: pointer; +} + +.archive-btn:hover { + background: #b71c1c; +} + +/* Pagination */ +.pagination { + display: flex; + justify-content: center; + align-items: center; + margin-top: 20px; + gap: 15px; +} + +.pagination button { + padding: 8px 12px; + border: none; + background: #007bff; + color: white; + border-radius: 6px; + cursor: pointer; +} + +.pagination button:disabled { + opacity: 0.5; + cursor: default; +} + +/* Home link */ +.home-link { + display: block; + margin-top: 30px; + text-align: center; + color: #007bff; + text-decoration: none; +} + +.home-link:hover { + text-decoration: underline; +} + +/* Mobile Responsive */ +@media (max-width: 600px) { + .tickets-table th, + .tickets-table td { + padding: 6px; + } + + .search-container input { + width: 95%; + } + + .pagination span { + font-size: 14px; + } } diff --git a/client/src/containers/Admin/Tickets/TicketsCreated.tsx b/client/src/containers/Admin/Tickets/TicketsCreated.tsx index b3f8ed2..100a74a 100644 --- a/client/src/containers/Admin/Tickets/TicketsCreated.tsx +++ b/client/src/containers/Admin/Tickets/TicketsCreated.tsx @@ -1,19 +1,113 @@ +// import React, { useEffect, useState } from "react"; +// import axios from "axios"; +// import { Link } from "react-router-dom"; +// import "./TicketsCreated.css"; // Importing CSS for styling + +// // Define the ticket type +// interface Ticket { +// name?: string; +// subject?: string; +// description?: string; +// } + +// const TicketsCreated: React.FC = () => { +// const [itTickets, setItTickets] = useState([]); +// const [userTickets, setUserTickets] = useState([]); + +// const fetchItTickets = async () => { +// try { +// const { data } = await axios.get(`/api/it-help/view`); +// setItTickets(data); +// } catch (error) { +// console.error("Error fetching IT tickets:", error); +// } +// }; + +// const fetchUserTickets = async () => { +// try { +// const { data } = await axios.get(`/api/employee-help/view`); +// setUserTickets(data); +// } catch (error) { +// console.error("Error fetching user tickets:", error); +// } +// }; + +// useEffect(() => { +// fetchItTickets(); +// fetchUserTickets(); +// }, []); + +// const renderTickets = (tickets: Ticket[], title: string) => ( +//
+//

{title}

+// +// +// +// +// +// +// +// +// +// +// {tickets.length > 0 ? ( +// tickets.map((ticket, index) => ( +// +// +// +// +// +// +// )) +// ) : ( +// +// +// +// )} +// +//
View TicketNameSubjectDescription
+// View +// {ticket.name || "No Name"}{ticket.subject || "No Subject"}{ticket.description || "No Information"}
No tickets available
+//
+// ); + +// return ( +// <> +//
+//

All Tickets

+//
+// {renderTickets(itTickets, "View All Tickets Created for IT Issues")} +// {renderTickets(userTickets, "View All Tickets Created for User Issues")} +// Home +// +// ); +// }; + +// export default TicketsCreated; + import React, { useEffect, useState } from "react"; import axios from "axios"; import { Link } from "react-router-dom"; -import "./TicketsCreated.css"; // Importing CSS for styling +import "./TicketsCreated.css"; -// Define the ticket type interface Ticket { + _id: string; name?: string; subject?: string; description?: string; + createdAt?: string; } +const ITEMS_PER_PAGE = 10; + const TicketsCreated: React.FC = () => { const [itTickets, setItTickets] = useState([]); const [userTickets, setUserTickets] = useState([]); + const [search, setSearch] = useState(""); + const [filtered, setFiltered] = useState([]); + const [page, setPage] = useState(1); + // Fetch IT tickets const fetchItTickets = async () => { try { const { data } = await axios.get(`/api/it-help/view`); @@ -23,6 +117,7 @@ const TicketsCreated: React.FC = () => { } }; + // Fetch User tickets const fetchUserTickets = async () => { try { const { data } = await axios.get(`/api/employee-help/view`); @@ -37,49 +132,116 @@ const TicketsCreated: React.FC = () => { fetchUserTickets(); }, []); - const renderTickets = (tickets: Ticket[], title: string) => ( -
-

{title}

- - - - - - - - - - - {tickets.length > 0 ? ( - tickets.map((ticket, index) => ( - - - - - - - )) - ) : ( - - - - )} - -
View TicketNameSubjectDescription
- View - {ticket.name || "No Name"}{ticket.subject || "No Subject"}{ticket.description || "No Information"}
No tickets available
-
- ); + // Combine both ticket sources + useEffect(() => { + const combined = [...itTickets, ...userTickets]; + + const cleanSearch = search.toLowerCase(); + const filteredTickets = combined.filter((t) => { + return ( + (t.name?.toLowerCase().includes(cleanSearch) ?? false) || + (t.subject?.toLowerCase().includes(cleanSearch) ?? false) || + (t.description?.toLowerCase().includes(cleanSearch) ?? false) + ); + }); + + setFiltered(filteredTickets); + setPage(1); // reset to first page on search + }, [search, itTickets, userTickets]); + + const startIndex = (page - 1) * ITEMS_PER_PAGE; + const pageTickets = filtered.slice(startIndex, startIndex + ITEMS_PER_PAGE); + const pages = Math.ceil(filtered.length / ITEMS_PER_PAGE); + + const handleArchive = async (id: string) => { + try { + await axios.put(`/api/tickets/archive/${id}`); + setItTickets(itTickets.filter((t) => t._id !== id)); + setUserTickets(userTickets.filter((t) => t._id !== id)); + } catch (error) { + console.error("Error archiving ticket:", error); + } + }; return ( - <> -
-

All Tickets

+
+

All Tickets

+ + {/* Search Bar */} +
+ setSearch(e.target.value)} + /> +
+ +
+ + + + + + + + + + + + + {pageTickets.length > 0 ? ( + pageTickets.map((ticket) => ( + + + + + + + + + )) + ) : ( + + + + )} + +
ViewNameSubjectDescriptionCreatedArchive
+ Open + {ticket.name ?? "—"}{ticket.subject ?? "—"}{ticket.description ?? "—"}{ticket.createdAt ? new Date(ticket.createdAt).toLocaleString() : "—"} + +
+ No tickets found +
- {renderTickets(itTickets, "View All Tickets Created for IT Issues")} - {renderTickets(userTickets, "View All Tickets Created for User Issues")} - Home - + + {/* Pagination */} + {pages > 1 && ( +
+ + + + Page {page} of {pages} + + + +
+ )} + + + Back Home + +
); }; diff --git a/client/src/containers/EmployeeLogin/EmployeeLogin.test.tsx b/client/src/containers/EmployeeLogin/EmployeeLogin.test.tsx new file mode 100644 index 0000000..083a69a --- /dev/null +++ b/client/src/containers/EmployeeLogin/EmployeeLogin.test.tsx @@ -0,0 +1,9 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import EmployeeLogin from './EmployeeLogin'; + +test('renders Home', () => { + render(); + const linkElement = screen.getByText(/EmployeeLogin/i); + expect(linkElement).toBeInTheDocument(); +}); \ No newline at end of file diff --git a/client/src/containers/EmployeeLogin/EmployeeLogin.tsx b/client/src/containers/EmployeeLogin/EmployeeLogin.tsx new file mode 100644 index 0000000..7cfde8d --- /dev/null +++ b/client/src/containers/EmployeeLogin/EmployeeLogin.tsx @@ -0,0 +1,190 @@ +import React, { useState } from "react"; +// import AuthContext from "../../utils/ContextAPI/AuthContext"; +import axios from "axios"; +import { useNavigate } from "react-router-dom"; +import Button from "react-bootstrap/Button"; + +const EmployeeLogin = () => { + // TODO: Fix the state, signin and login is twisted together somehow. + const [email, setEmail] = useState(""); + const [password, setPassword] = useState(""); + // const [email, setEmail] = useState(""); + // const [password, setPassword] = useState(""); + // const history = useHistory(); + // const { setJwt } = useContext(AuthContext); + const navigate = useNavigate(); + + const handle2Submit = (e: any) => { + e.preventDefault(); + // const email = e.target.email; + // const password = e.target.password; + axios + // FIXME: After creating an account, it pushes on local but it do not push to the home page/ login in Production + .post("/api/employee/employeeSignUp", { email, password }) + .then((response) => { + console.log(response.data); + // setJwt(response.data.data); + navigate("/employee"); + // history.push("/"); + // window.location = "/home"; + // this.props.history.push("/home"); + }) + .catch((err) => { + console.log(err); + }); + }; + + const handleSubmit = (e: any) => { + e.preventDefault(); + // const { email, password } = e.target; + axios + // TODO: change to /api/login + .post("/api/employee/employeeLogin", { email, password }) + .then((response) => { + // setJwt(response.data.data); + console.log(response.data.data); + console.log(response.data); + console.log(response); + navigate("/employee"); + // history.push("/"); + // window.location = "/home"; + // this.props.history.push("/home"); + }) + .catch((err) => { + console.log(err); + }); + }; + + + + return ( +
+
+
+
+
+
+ { + setEmail(e.target.value); + }} + /> +
+
+
+
+ { + setPassword(e.target.value); + }} + /> +
+
+ +
+
+
+ +
+
+
+
+

Sign Up

+

+ Ready to experience the future of logistics management? Sign up + for GADZ CONNECT today and take your business to new heights. + Let’s embark on this journey together, and unlock the full + potential of your logistics operations. +

+
+
+
+
+ { + setEmail(e.target.value); + }} + /> +
+ +
+
+ { + setPassword(e.target.value); + }} + /> +
+ +
+ {/*
+ +
*/} + +
+ + By clicking Sign up, you agree to the terms of use. + +
+
+
+
+
+
+ ); +}; + +export default EmployeeLogin; diff --git a/client/src/containers/Home/Home.jsx b/client/src/containers/Home/Home.jsx index 6454919..3d9d5dc 100644 --- a/client/src/containers/Home/Home.jsx +++ b/client/src/containers/Home/Home.jsx @@ -1,191 +1,3 @@ -// import React from "react"; -// import "./Home.css"; // Import your custom styles - -// const Home = () => { -// return ( -//
-//
-//
-//
Welcome To GADZConnect!
-// Big World of Connections -//
-//
-// The innovative solution revolutionizing the transportation and -// logistics industry. We’re here to transform the way you manage your -// logistics operations, offering a seamless platform that connects -// buyers and sellers, carriers and shippers, and every player in -// between! -//
- -//
-// - -// -//
- -//
It's A New World
- -//
-// Big Town top view -//

What We Offer?

-//
-//

-// You have the loads, we got the GADZ. Connect your assets and manage -// them easily. Make loads available to the public or make yourself -// assessable as a driver. -//

-//
- -//
-//

We are Global

-//
-//
-//
-//

-// At GADZCONNECT, we’re redefining the way businesses manage their -// logistics operations. Say goodbye to the complexities and -// inefficiencies of traditional logistics processes- and hello to -// a world of seamless connectivity, real-time visibility, and -// unparalleled efficiency. -//

-//
-//
-// Logistics -//
-//
-//
-//
-//
-// ); -// }; - -// export default Home; - -// import React from "react"; -// import "./Home.css"; - -// const Home = () => { -// return ( -//
-// {/* Hero Section */} -//
-//
-//

🚀 Welcome To GADZConnect

-//

-// The innovative solution revolutionizing the transportation and -// logistics industry. Connecting shippers, carriers, and businesses -// worldwide on one seamless platform. -//

-//
-// -// -//
-//
-//
-// Global Logistics -//
-//
- -// {/* Social Section */} -//
-// -// -//
- -// {/* What We Offer */} -//
-//
-// Big Town top view -//
-//

What We Offer

-//

-// You have the loads, we got the GADZ. Connect your assets and manage -// them effortlessly. Make loads available to the public or make -// yourself accessible as a driver. Efficiency, connectivity, and -// simplicity—all in one place. -//

-//
-//
-//
- -// {/* Global Section */} -//
-//

We Are Global 🌍

-//
-//
-//

-// At GADZCONNECT, we’re redefining the way businesses manage their -// logistics operations. Say goodbye to complexity and inefficiency, -// and hello to seamless connectivity, real-time visibility, and -// unparalleled efficiency—anywhere in the world. -//

-//
-//
-// Global Logistics Map -//
-//
-//
- -// {/* CTA Section */} -//
-//

It’s A New World with GADZConnect

-//

-// Join thousands of logistics professionals already transforming the way -// they manage operations. The future of logistics is here. -//

-// -//
-//
-// ); -// }; - -// export default Home; - -import React from "react"; import { Link } from "react-router-dom"; import "./Home.css"; @@ -204,6 +16,11 @@ const Home = () => { worldwide on one seamless platform.

+ {localStorage.getItem("userId") && ( + + + + )} {/* */} {/* */} diff --git a/client/src/containers/User/AvailableTable/AvailableTable.tsx b/client/src/containers/User/AvailableTable/AvailableTable.tsx index 6c880d8..ce6effd 100644 --- a/client/src/containers/User/AvailableTable/AvailableTable.tsx +++ b/client/src/containers/User/AvailableTable/AvailableTable.tsx @@ -4604,6 +4604,56 @@ const AvailableTable: React.FC = () => { } }; + const fetchLoadboardData = useCallback( + async () => { + if (!code) { + setError("Missing authorization code — please connect your account first."); + return; + } + + setLoading(true); + setError(null); + + try { + const resp = await axios.get(`${API_BASE}/auth/callback/`, { + params: { code }, + }); + + // Save token from cookie if server sets it + const cookieToken = getCookie("lb_access_token"); + if (cookieToken) { + localStorage.setItem("lb_access_token", cookieToken); + setToken(cookieToken); + } + + let apiLoads: any[] = []; + const d = resp.data; + + if (Array.isArray(d)) apiLoads = d; + else if (Array.isArray(d.loads)) apiLoads = d.loads; + else if (Array.isArray(d.data)) apiLoads = d.data; + else if (Array.isArray(d.results)) apiLoads = d.results; + else if (Array.isArray(d.payload)) apiLoads = d.payload; + + if (apiLoads.length > 0) { + setSearchResults(apiLoads.map(mapApiLoadToDisplay)); + setSuccess(true); + + // Scroll into view after results load + setTimeout(() => { + resultsRef.current?.scrollIntoView({ behavior: "smooth" }); + }, 150); + } + } catch (err) { + console.error("Error fetching 123Loadboard data:", err); + setError("Failed to fetch 123Loadboard data. Please reauthorize or try again."); + } finally { + setLoading(false); + } + }, + [code, mapApiLoadToDisplay] + ); + // ---------- Render ---------- return (
@@ -4808,14 +4858,49 @@ const AvailableTable: React.FC = () => { */} - */} + {/* */} + + +
{loading &&

Loading search results...

} diff --git a/client/src/containers/User/AvailableTable/UserProfile/UserProfile.tsx b/client/src/containers/User/AvailableTable/UserProfile/UserProfile.tsx index b7e0f24..b55a36d 100644 --- a/client/src/containers/User/AvailableTable/UserProfile/UserProfile.tsx +++ b/client/src/containers/User/AvailableTable/UserProfile/UserProfile.tsx @@ -1,323 +1,3 @@ -// import React, { useEffect, useState } from "react"; -// import { useParams, Link } from "react-router-dom"; -// import axios from "axios"; -// import styles from "./UserProfile.module.css"; - -// const ServerPort = -// process.env.REACT_APP_SOCKET_IO_CLIENT_PORT || "http://localhost:3001"; - -// const UserProfile = () => { -// const { userId } = useParams<{ userId: string }>(); -// const [userData, setUserData] = useState(null); -// const [loading, setLoading] = useState(true); -// const [error, setError] = useState(""); - -// interface Load { -// id: number; -// loadId: string; // Add loadId property -// description: string; -// company: string; -// } - -// interface Driver { -// id: number; -// driverId: string; // Add driverId property -// name: string; -// experience: string; -// } - -// useEffect(() => { -// const fetchUserData = async () => { -// try { -// const [userRes, loadsRes, driversRes] = await Promise.all([ -// axios.get(`${ServerPort}/api/user/view/${userId}`), -// axios.get(`${ServerPort}/api/loads/user/${userId}`), -// axios.get(`${ServerPort}/api/drivers/user/${userId}`), -// ]); - -// setUserData({ -// ...userRes.data, -// loads: Array.isArray(loadsRes.data) ? loadsRes.data : [], -// drivers: Array.isArray(driversRes.data) ? driversRes.data : [], -// }); -// } catch (error) { -// console.error("Error fetching user profile data:", error); -// setError("Failed to load user profile data."); -// } finally { -// setLoading(false); -// } -// }; - -// fetchUserData(); -// }, [userId]); - -// if (loading) { -// return
Loading user profile...
; -// } - -// if (error) { -// return
{error}
; -// } - -// return ( -//
-//

User Profile

-//
-// {/* Loads Section on the Left */} -//
-//

Loads ({userData.loads.length}):

-// {Array.isArray(userData.loads) && userData.loads.length > 0 ? ( -// userData.loads.map((load: Load) => ( -//
-//

{load.description}

-//

Company: {load.company}

-//

Load ID: {load.id}

{/* Display loadId */} -// -// View Driver Profile -// -//
-// )) -// ) : ( -//

No loads available

-// )} -//
- -// {/* Driver Details Section on the Right */} -//
-//

Available Status: {userData.loadStatus}

-// {userData.qrPNG && ( -// {`${userData.firstName} -// )} -//

-// Name: {userData.firstName} {userData.lastName} -//

-//

-// Customer Since: {new Date(userData.availableFrom).toLocaleDateString()} -//

-//

Type of Owner: {userData.userType}

-//

-// All Services Available: {userData.loadReferences ? userData.loadReferences.split(",") : "None"} -//

-//

-// Locations: {userData.location ? userData.location.split(",") : "None"} -//

-//

Phone Number: {userData.phoneNumber || "Not provided"}

-//

Address: {userData.address || "Not provided"}

-//
- -// {/* Drivers Section in the Third Column */} -//
-//

Drivers ({userData.drivers.length}):

-// {Array.isArray(userData.drivers) && userData.drivers.length > 0 ? ( -// userData.drivers.map((driver: Driver) => ( -//
-//

{driver.name}

-//

Experience: {driver.experience}

-//

Driver ID: {driver.id}

{/* Display driverId */} -//
-// )) -// ) : ( -//

No drivers available

-// )} -//
-//
- -// {/* "Add Business" Button */} -// - -// {/* Navigation buttons */} -//
-// -// Home -// -// -// Message User -// -//
-//
-// ); -// }; - -// export default UserProfile; - -// import React, { useEffect, useState } from "react"; -// import { useParams, Link } from "react-router-dom"; -// import axios from "axios"; -// import styles from "./UserProfile.module.css"; - -// const SERVER_PORT = process.env.REACT_APP_SOCKET_IO_CLIENT_PORT || "http://localhost:3001"; - -// interface Load { -// id: number; -// loadId: string; -// description: string; -// company: string; -// } - -// interface Driver { -// id: number; -// driverId: string; -// name: string; -// experience: string; -// } - -// interface UserData { -// firstName: string; -// lastName: string; -// email: string; -// phoneNumber?: string; -// address?: string; -// loadStatus?: string; -// availableFrom?: string; -// userType?: string; -// loadReferences?: string; -// location?: string; -// qrPNG?: string; -// loads: Load[]; -// drivers: Driver[]; -// } - -// const UserProfile: React.FC = () => { -// const { userId } = useParams<{ userId: string }>(); -// const [userData, setUserData] = useState(null); -// const [loading, setLoading] = useState(true); -// const [error, setError] = useState(""); - -// useEffect(() => { -// if (!userId) { -// setError("User ID not provided in URL."); -// setLoading(false); -// return; -// } - -// const fetchUserData = async () => { -// try { -// const [userRes, loadsRes, driversRes] = await Promise.all([ -// axios.get(`${SERVER_PORT}/api/user/view/${userId}`), -// axios.get(`${SERVER_PORT}/api/loads/user/${userId}`), -// axios.get(`${SERVER_PORT}/api/drivers/user/${userId}`), -// ]); - -// setUserData({ -// ...userRes.data, -// loads: Array.isArray(loadsRes.data) ? loadsRes.data : [], -// drivers: Array.isArray(driversRes.data) ? driversRes.data : [], -// }); -// } catch (err) { -// console.error("Error fetching user profile data:", err); -// setError("Failed to load user profile data."); -// } finally { -// setLoading(false); -// } -// }; - -// fetchUserData(); -// }, [userId]); - -// if (loading) return
Loading user profile...
; -// if (error) return
{error}
; -// if (!userData) return
No user data available.
; - -// const { -// firstName, -// lastName, -// email, -// phoneNumber, -// address, -// loadStatus, -// availableFrom, -// userType, -// loadReferences, -// location, -// qrPNG, -// loads, -// drivers, -// } = userData; - -// return ( -//
-//

User Profile

-//
-// {/* Loads Section */} -//
-//

Loads ({loads.length})

-// {loads.length > 0 ? ( -// loads.map((load) => ( -//
-//

{load.description}

-//

Company: {load.company}

-//

Load ID: {load.loadId}

-// -// View Load Details -// -//
-// )) -// ) : ( -//

No loads available

-// )} -//
- -// {/* User Profile Section */} -//
-// {qrPNG && ( -// {`${firstName} -// )} -//

{firstName} {lastName}

-//

Email: {email}

-//

Phone: {phoneNumber || "Not provided"}

-//

Address: {address || "Not provided"}

-//

Status: {loadStatus || "N/A"}

-//

Customer Since: {availableFrom ? new Date(availableFrom).toLocaleDateString() : "N/A"}

-//

Type of Owner: {userType || "N/A"}

-//

Services: {loadReferences ? loadReferences.split(",").join(", ") : "None"}

-//

Locations: {location ? location.split(",").join(", ") : "None"}

-//
- -// {/* Drivers Section */} -//
-//

Drivers ({drivers.length})

-// {drivers.length > 0 ? ( -// drivers.map((driver) => ( -//
-//

{driver.name}

-//

Experience: {driver.experience}

-//

Driver ID: {driver.driverId}

-//
-// )) -// ) : ( -//

No drivers available

-// )} -//
-//
- -// {/* Action Buttons */} -//
-// -// Home -// Message User -//
-//
-// ); -// }; - -// export default UserProfile; - -// UserProfile.tsx import React, { useEffect, useState } from "react"; import { useParams, Link } from "react-router-dom"; import axios from "axios"; diff --git a/client/src/containers/User/Profile/ProfileUpdate.tsx b/client/src/containers/User/Profile/ProfileUpdate.tsx index e62d333..3389107 100644 --- a/client/src/containers/User/Profile/ProfileUpdate.tsx +++ b/client/src/containers/User/Profile/ProfileUpdate.tsx @@ -1,1682 +1,3 @@ -// import React, { useState, useEffect } from "react"; -// import axios from "axios"; -// import Button from "react-bootstrap/Button"; -// import Col from "react-bootstrap/Col"; -// import Form from "react-bootstrap/Form"; -// import Row from "react-bootstrap/Row"; -// import Alert from "react-bootstrap/Alert"; -// import Card from "react-bootstrap/Card"; -// import Spinner from "react-bootstrap/Spinner"; -// import { Link } from "react-router-dom"; - -// type User = { -// id: string; -// email: string; -// password?: string; -// description: string; -// userType: string; -// experienceLevel: string; -// location: string; -// availableFrom: string; -// newPassword?: string; -// profileImage?: string; -// phoneNumber: string; -// driversLicense: string; -// comments: string; -// qrCode?: string; // ✅ added QR support -// }; - -// const ServerPort = -// process.env.REACT_APP_SOCKET_IO_CLIENT_PORT || "http://localhost:3001"; - -// // ✅ Replace these with your actual Cloudinary credentials -// // const CLOUDINARY_UPLOAD_URL = `https://api.cloudinary.com/v1_1//image/upload`; -// // const CLOUDINARY_UPLOAD_PRESET = ""; -// const CLOUDINARY_UPLOAD_URL = `https://api.cloudinary.com/v1_1/${process.env.REACT_APP_CLOUDINARY_CLOUD_NAME}/image/upload`; -// const CLOUDINARY_UPLOAD_PRESET = process.env.REACT_APP_CLOUDINARY_UPLOAD_PRESET; - -// const ProfileUpdate: React.FC = () => { -// const userId = localStorage.getItem("userId"); -// const [error, setError] = useState(null); -// const [loading, setLoading] = useState(false); -// const [successMessage, setSuccessMessage] = useState(null); -// const [isSubmitting, setIsSubmitting] = useState(false); -// const [imagePreview, setImagePreview] = useState(null); -// const [qrCodeImage, setQrCodeImage] = useState(null); // ✅ QR code state - -// const [formData, setFormData] = useState({ -// id: "", -// email: "", -// password: "", -// description: "", -// userType: "", -// experienceLevel: "", -// location: "", -// availableFrom: "", -// newPassword: "", -// profileImage: "", -// phoneNumber: "", -// driversLicense: "", -// comments: "", -// qrCode: "", -// }); - -// const [formErrors, setFormErrors] = useState>({}); - -// // ✅ Load user profile -// useEffect(() => { -// const fetchUserData = async () => { -// setLoading(true); -// const token = localStorage.getItem("token"); -// if (!token) { -// setError("No token found. Please log in."); -// setLoading(false); -// return; -// } - -// try { -// const response = await axios.get(`${ServerPort}/api/user/view/${userId}`, { -// headers: { Authorization: `Bearer ${token}` }, -// }); - -// if (response.status === 200) { -// const userData = response.data; -// const availableFromDate = -// typeof userData.availableFrom === "string" -// ? userData.availableFrom.split("T")[0] -// : ""; - -// setFormData({ -// ...userData, -// availableFrom: availableFromDate, -// password: "", -// newPassword: "", -// }); - -// setImagePreview(userData.profileImage || null); -// setQrCodeImage(userData.qrCode || null); -// } -// } catch (err) { -// handleApiError(err); -// } finally { -// setLoading(false); -// } -// }; - -// if (userId) fetchUserData(); -// }, [userId]); - -// // ✅ Upload image to Cloudinary -// const handleImageUpload = async (file: File) => { -// setLoading(true); -// try { -// const data = new FormData(); -// data.append("file", file); -// data.append("upload_preset", CLOUDINARY_UPLOAD_PRESET!); - -// const res = await axios.post(CLOUDINARY_UPLOAD_URL, data); -// const imageUrl = res.data.secure_url; - -// setFormData({ ...formData, profileImage: imageUrl }); -// setImagePreview(imageUrl); -// } catch (err) { -// console.error("Upload error:", err); -// setError("Image upload failed. Please try again."); -// } finally { -// setLoading(false); -// } -// }; - -// // ✅ Validate before sending update -// const validateForm = () => { -// const errors: any = {}; -// if (!formData.email) errors.email = "Email is required"; -// else if (!/\S+@\S+\.\S+/.test(formData.email)) -// errors.email = "Invalid email format"; -// if (!formData.description) errors.description = "Description is required"; -// if (!formData.userType) errors.userType = "User Type is required"; -// if (!formData.experienceLevel) -// errors.experienceLevel = "Experience Level is required"; -// if (!formData.location) errors.location = "Location is required"; -// if (!formData.availableFrom) -// errors.availableFrom = "Available From date is required"; -// if (!formData.phoneNumber) errors.phoneNumber = "Phone Number is required"; -// if (!formData.driversLicense) -// errors.driversLicense = "Drivers License is required"; -// if (!formData.comments) errors.comments = "Comments are required"; -// setFormErrors(errors); -// return Object.keys(errors).length === 0; -// }; - -// // ✅ Submit update to backend -// const handleUserUpdate = async (e: React.FormEvent) => { -// e.preventDefault(); -// if (!validateForm()) return; - -// setIsSubmitting(true); -// setLoading(true); -// setError(null); -// setSuccessMessage(null); - -// const token = localStorage.getItem("token"); - -// // Remove password if not updating it -// const updatedData: Partial = { ...formData }; -// if (!formData.newPassword) delete updatedData.password; - -// try { -// const response = await axios.put( -// `${ServerPort}/api/user/update/${userId}`, -// updatedData, -// { -// headers: { -// "Content-Type": "application/json", -// Authorization: `Bearer ${token}`, -// }, -// } -// ); - -// if (response.status === 200) { -// setSuccessMessage("✅ Profile updated successfully!"); -// setQrCodeImage(response.data.qrCode || qrCodeImage); // ✅ refresh QR code if regenerated -// setFormData({ ...formData, newPassword: "" }); -// } -// } catch (err) { -// handleApiError(err); -// } finally { -// setLoading(false); -// setIsSubmitting(false); -// } -// }; - -// // ✅ Handle API errors -// const handleApiError = (error: any) => { -// if (axios.isAxiosError(error)) { -// setError(error.response?.data?.message || error.message); -// } else { -// setError("An unknown error occurred"); -// } -// }; - -// return ( -// -//

Update Your Profile

-// {loading && } -// {error && {error}} -// {successMessage && {successMessage}} - -//
-// {/* Profile Image Upload */} -//
-// Profile -// { -// const target = e.target as HTMLInputElement; -// if (target.files?.[0]) { -// handleImageUpload(target.files[0]); -// } -// }} -// /> -//
- -// {/* ✅ QR Code Section */} -// {qrCodeImage && ( -//
-//
Your QR Code
-// QR Code -//
-// )} - -// {/* Email + Description */} -// -// -// Email -// -// setFormData({ ...formData, email: e.target.value }) -// } -// isInvalid={!!formErrors.email} -// /> -// -// {formErrors.email} -// -// - -// -// Description -// -// setFormData({ ...formData, description: e.target.value }) -// } -// isInvalid={!!formErrors.description} -// /> -// -// {formErrors.description} -// -// -// - -// {/* User Type + Experience */} -// -// -// User Type -// -// setFormData({ ...formData, userType: e.target.value }) -// } -// isInvalid={!!formErrors.userType} -// /> -// -// {formErrors.userType} -// -// - -// -// Experience Level -// -// setFormData({ ...formData, experienceLevel: e.target.value }) -// } -// isInvalid={!!formErrors.experienceLevel} -// /> -// -// {formErrors.experienceLevel} -// -// -// - -// {/* Location + Available From */} -// -// -// Location -// -// setFormData({ ...formData, location: e.target.value }) -// } -// isInvalid={!!formErrors.location} -// /> -// -// {formErrors.location} -// -// - -// -// Available From -// -// setFormData({ ...formData, availableFrom: e.target.value }) -// } -// isInvalid={!!formErrors.availableFrom} -// /> -// -// {formErrors.availableFrom} -// -// -// - -// {/* Phone + License */} -// -// -// Phone Number -// -// setFormData({ ...formData, phoneNumber: e.target.value }) -// } -// isInvalid={!!formErrors.phoneNumber} -// /> -// -// {formErrors.phoneNumber} -// -// - -// -// Driver’s License -// -// setFormData({ ...formData, driversLicense: e.target.value }) -// } -// isInvalid={!!formErrors.driversLicense} -// /> -// -// {formErrors.driversLicense} -// -// -// - -// {/* Comments */} -// -// Comments -// -// setFormData({ ...formData, comments: e.target.value }) -// } -// isInvalid={!!formErrors.comments} -// /> -// -// {formErrors.comments} -// -// - -// {/* Password Update */} -// -// New Password -// -// setFormData({ ...formData, newPassword: e.target.value }) -// } -// /> -// - -// {/* Buttons */} -//
-// -// -// -// -//
-//
-//
-// ); -// }; - -// export default ProfileUpdate; - -// import React, { useState, useEffect } from "react"; -// import axios from "axios"; -// import { -// Button, -// Col, -// Form, -// Row, -// Alert, -// Card, -// Spinner, -// } from "react-bootstrap"; - -// type User = { -// id: string; -// email: string; -// password?: string; -// description: string; -// userType: string; -// experienceLevel: string; -// location: string; -// availableFrom: string; -// newPassword?: string; -// profileImage?: string; -// phoneNumber: string; -// driversLicense: string; -// comments: string; -// qrCode?: string; -// }; - -// const ServerPort = -// process.env.REACT_APP_SOCKET_IO_CLIENT_PORT || "http://localhost:3001"; - -// const CLOUDINARY_UPLOAD_URL = `https://api.cloudinary.com/v1_1/${process.env.REACT_APP_CLOUDINARY_CLOUD_NAME}/image/upload`; -// const CLOUDINARY_UPLOAD_PRESET = process.env.REACT_APP_CLOUDINARY_UPLOAD_PRESET; - -// const ProfileUpdate: React.FC = () => { -// const userId = localStorage.getItem("userId"); - -// const [formData, setFormData] = useState({ -// id: "", -// email: "", -// password: "", -// description: "", -// userType: "", -// experienceLevel: "", -// location: "", -// availableFrom: "", -// newPassword: "", -// profileImage: "", -// phoneNumber: "", -// driversLicense: "", -// comments: "", -// qrCode: "", -// }); - -// const [imagePreview, setImagePreview] = useState(null); -// const [qrCodeImage, setQrCodeImage] = useState(null); -// const [formErrors, setFormErrors] = useState>({}); -// const [loading, setLoading] = useState(false); -// const [isSubmitting, setIsSubmitting] = useState(false); -// const [error, setError] = useState(null); -// const [successMessage, setSuccessMessage] = useState(null); - -// // ------------------------- -// // LOAD USER PROFILE -// // ------------------------- -// useEffect(() => { -// const fetchUserData = async () => { -// setLoading(true); - -// try { -// const token = localStorage.getItem("token"); -// if (!token) return setError("No token found."); - -// const response = await axios.get( -// `${ServerPort}/api/user/view/${userId}`, -// { headers: { Authorization: `Bearer ${token}` } } -// ); - -// const user = response.data; - -// setFormData({ -// ...user, -// availableFrom: user.availableFrom?.split("T")[0] || "", -// password: "", -// newPassword: "", -// }); - -// setImagePreview(user.profileImage || null); -// setQrCodeImage(user.qrCode || null); -// } catch (err) { -// handleApiError(err); -// } - -// setLoading(false); -// }; - -// if (userId) fetchUserData(); -// }, [userId]); - -// // ------------------------- -// // IMAGE UPLOAD TO CLOUDINARY -// // ------------------------- -// const handleImageUpload = async (file: File) => { -// setLoading(true); - -// try { -// const data = new FormData(); -// data.append("file", file); -// data.append("upload_preset", CLOUDINARY_UPLOAD_PRESET!); - -// const uploadRes = await axios.post(CLOUDINARY_UPLOAD_URL, data); -// const secureUrl = uploadRes.data.secure_url; - -// setFormData((prev) => ({ ...prev, profileImage: secureUrl })); -// setImagePreview(secureUrl); -// } catch (err) { -// setError("Image upload failed. Try again."); -// } - -// setLoading(false); -// }; - -// // ------------------------- -// // FORM VALIDATION -// // ------------------------- -// const validateForm = () => { -// const errors: Record = {}; -// const required = [ -// "email", -// "description", -// "userType", -// "experienceLevel", -// "location", -// "availableFrom", -// "phoneNumber", -// "driversLicense", -// "comments", -// ]; - -// required.forEach((field) => { -// // @ts-ignore -// if (!formData[field]) errors[field] = "This field is required"; -// }); - -// if (formData.email && !/\S+@\S+\.\S+/.test(formData.email)) -// errors.email = "Invalid email"; - -// setFormErrors(errors); - -// return Object.keys(errors).length === 0; -// }; - -// // ------------------------- -// // UPDATE USER -// // ------------------------- -// const handleUserUpdate = async (e: React.FormEvent) => { -// e.preventDefault(); -// if (!validateForm()) return; - -// setLoading(true); -// setIsSubmitting(true); -// setError(null); -// setSuccessMessage(null); - -// try { -// const token = localStorage.getItem("token"); - -// const payload = { ...formData }; -// if (!formData.newPassword) delete payload.password; - -// const res = await axios.put( -// `${ServerPort}/api/user/update/${userId}`, -// payload, -// { -// headers: { -// Authorization: `Bearer ${token}`, -// "Content-Type": "application/json", -// }, -// } -// ); - -// if (res.status === 200) { -// setSuccessMessage("Profile successfully updated!"); -// setQrCodeImage(res.data.qrCode || qrCodeImage); -// setFormData((prev) => ({ ...prev, newPassword: "" })); -// } -// } catch (err) { -// handleApiError(err); -// } - -// setIsSubmitting(false); -// setLoading(false); -// }; - -// // ------------------------- -// // ERROR HANDLER -// // ------------------------- -// const handleApiError = (error: any) => { -// if (axios.isAxiosError(error)) { -// setError(error.response?.data?.message || "Something went wrong."); -// } else { -// setError("An unexpected error occurred."); -// } -// }; - -// // ------------------------- -// // UI RENDER -// // ------------------------- -// return ( -// -//

Update Profile

- -// {loading && ( -// -// )} -// {error && {error}} -// {successMessage && {successMessage}} - -//
-// {/* PROFILE IMAGE UPLOAD */} -//
-// Profile - -// ) => { -// const file = e.target.files?.[0]; -// if (file) handleImageUpload(file); -// }} -// /> -//
- -// {/* QR CODE */} -// {qrCodeImage && ( -//
-//
Your QR Code
-// QR Code -//
-// )} - -// {/* FORM ROWS */} -// -// -// Email -// -// setFormData({ ...formData, email: e.target.value }) -// } -// /> -// -// {formErrors.email} -// -// - -// -// Description -// -// setFormData({ ...formData, description: e.target.value }) -// } -// /> -// -// {formErrors.description} -// -// -// - -// -// -// User Type -// -// setFormData({ ...formData, userType: e.target.value }) -// } -// /> -// -// {formErrors.userType} -// -// - -// -// Experience Level -// -// setFormData({ -// ...formData, -// experienceLevel: e.target.value, -// }) -// } -// /> -// -// {formErrors.experienceLevel} -// -// -// - -// -// -// Location -// -// setFormData({ ...formData, location: e.target.value }) -// } -// /> -// -// {formErrors.location} -// -// - -// -// Available From -// -// setFormData({ ...formData, availableFrom: e.target.value }) -// } -// /> -// -// {formErrors.availableFrom} -// -// -// - -// -// -// Phone Number -// -// setFormData({ ...formData, phoneNumber: e.target.value }) -// } -// /> -// -// {formErrors.phoneNumber} -// -// - -// -// Driver’s License -// -// setFormData({ -// ...formData, -// driversLicense: e.target.value, -// }) -// } -// /> -// -// {formErrors.driversLicense} -// -// -// - -// -// Comments -// -// setFormData({ ...formData, comments: e.target.value }) -// } -// /> -// -// {formErrors.comments} -// -// - -// -// New Password -// -// setFormData({ ...formData, newPassword: e.target.value }) -// } -// /> -// - -//
-// -//
-//
-//
-// ); -// }; - -// export default ProfileUpdate; - -// import React, { useEffect, useState } from "react"; -// import axios from "axios"; -// import { -// Button, -// Col, -// Form, -// Row, -// Alert, -// Card, -// Spinner, -// } from "react-bootstrap"; -// import { Link } from "react-router-dom"; - -// type User = { -// id: string; -// email: string; -// password?: string; -// description: string; -// userType: string; -// experienceLevel: string; -// location: string; -// availableFrom: string; -// newPassword?: string; -// profileImage?: string; -// phoneNumber: string; -// driversLicense: string; -// comments: string; -// qrCode?: string; -// }; - -// const ServerPort = -// process.env.REACT_APP_SOCKET_IO_CLIENT_PORT || "http://localhost:3001"; - -// const ProfileUpdate: React.FC = () => { -// const userId = localStorage.getItem("userId") || ""; - -// const [formData, setFormData] = useState({ -// id: "", -// email: "", -// password: "", -// description: "", -// userType: "", -// experienceLevel: "", -// location: "", -// availableFrom: "", -// newPassword: "", -// profileImage: "", -// phoneNumber: "", -// driversLicense: "", -// comments: "", -// qrCode: "", -// }); - -// const [selectedFile, setSelectedFile] = useState(null); -// const [imagePreview, setImagePreview] = useState(null); -// const [qrCodeImage, setQrCodeImage] = useState(null); -// const [formErrors, setFormErrors] = useState>({}); -// const [loading, setLoading] = useState(false); -// const [isSubmitting, setIsSubmitting] = useState(false); -// const [error, setError] = useState(null); -// const [successMessage, setSuccessMessage] = useState(null); - -// // load user profile -// useEffect(() => { -// const fetchUserData = async () => { -// setLoading(true); -// try { -// const token = localStorage.getItem("token"); -// if (!token) { -// setError("No token found."); -// setLoading(false); -// return; -// } - -// const res = await axios.get(`${ServerPort}/api/user/view/${userId}`, { -// headers: { Authorization: `Bearer ${token}` }, -// }); - -// if (res.status === 200) { -// const user = res.data; -// setFormData({ -// ...user, -// availableFrom: user.availableFrom?.split("T")[0] || "", -// password: "", -// newPassword: "", -// }); -// setImagePreview(user.profileImage || null); -// setQrCodeImage(user.qrPNG || user.qrCode || null); -// } else { -// setError("Failed to fetch user data."); -// } -// } catch (err) { -// handleApiError(err); -// } finally { -// setLoading(false); -// } -// }; - -// if (userId) fetchUserData(); -// // eslint-disable-next-line react-hooks/exhaustive-deps -// }, [userId]); - -// // cleanup object URL when component unmounts / file changes -// useEffect(() => { -// return () => { -// if (imagePreview && imagePreview.startsWith("blob:")) { -// URL.revokeObjectURL(imagePreview); -// } -// }; -// }, [imagePreview]); - -// // handle native file input change (use plain input to avoid bootstrap issues) -// const handleFileChange = (e: React.ChangeEvent) => { -// const file = e.target.files?.[0] ?? null; -// if (file) { -// // revoke previous blob url if any -// if (imagePreview && imagePreview.startsWith("blob:")) { -// URL.revokeObjectURL(imagePreview); -// } -// setSelectedFile(file); -// setImagePreview(URL.createObjectURL(file)); -// // don't mutate formData.profileImage here — backend will return permanent URL -// } else { -// setSelectedFile(null); -// } -// }; - -// const validateForm = () => { -// const errors: Record = {}; -// const required = [ -// "email", -// "description", -// "userType", -// "experienceLevel", -// "location", -// "availableFrom", -// "phoneNumber", -// "driversLicense", -// "comments", -// ] as const; - -// for (const field of required) { -// // @ts-ignore -// if (!formData[field]) errors[field] = "This field is required"; -// } - -// if (formData.email && !/\S+@\S+\.\S+/.test(formData.email)) { -// errors.email = "Invalid email"; -// } - -// setFormErrors(errors); -// return Object.keys(errors).length === 0; -// }; - -// // Submit: if selectedFile exists -> send multipart/form-data to backend, -// // otherwise send JSON. Backend should accept multipart and handle saving to Cloudinary. -// const handleUserUpdate = async (e: React.FormEvent) => { -// e.preventDefault(); -// setError(null); -// setSuccessMessage(null); - -// if (!validateForm()) return; - -// setLoading(true); -// setIsSubmitting(true); - -// try { -// const token = localStorage.getItem("token"); -// if (!token) throw new Error("No token - please sign in."); - -// if (selectedFile) { -// // send multipart to backend; backend must use multer to accept `profileImage` -// const form = new FormData(); - -// // append scalar fields -// Object.entries(formData).forEach(([k, v]) => { -// if (v !== undefined && v !== null) form.append(k, String(v)); -// }); - -// form.append("profileImage", selectedFile); - -// const res = await axios.put( -// `${ServerPort}/api/user/update/${userId}`, -// form, -// { -// headers: { -// Authorization: `Bearer ${token}`, -// "Content-Type": "multipart/form-data", -// }, -// } -// ); - -// if (res.status === 200) { -// const updatedUser = res.data.user ?? res.data; -// setFormData((prev) => ({ -// ...prev, -// ...updatedUser, -// newPassword: "", -// })); -// // server should return permanent image URL (profileImage) -// setImagePreview(updatedUser.profileImage || imagePreview); -// setQrCodeImage(updatedUser.qrPNG || updatedUser.qrCode || qrCodeImage); -// setSuccessMessage("Profile updated and image uploaded."); -// setSelectedFile(null); -// } else { -// setError("Unexpected server response when uploading image."); -// } -// } else { -// // no file selected — send JSON update -// const payload: Partial = { ...formData }; -// if (!formData.newPassword) delete payload.password; - -// const res = await axios.put( -// `${ServerPort}/api/user/update/${userId}`, -// payload, -// { -// headers: { -// Authorization: `Bearer ${token}`, -// "Content-Type": "application/json", -// }, -// } -// ); - -// if (res.status === 200) { -// const updatedUser = res.data.user ?? res.data; -// setFormData((prev) => ({ -// ...prev, -// ...updatedUser, -// newPassword: "", -// })); -// setImagePreview(updatedUser.profileImage || imagePreview); -// setQrCodeImage(updatedUser.qrPNG || updatedUser.qrCode || qrCodeImage); -// setSuccessMessage("Profile updated."); -// } else { -// setError("Unexpected server response when updating profile."); -// } -// } -// } catch (err) { -// handleApiError(err); -// } finally { -// setIsSubmitting(false); -// setLoading(false); -// } -// }; - -// const handleApiError = (err: any) => { -// if (axios.isAxiosError(err)) { -// const msg = -// (err.response && (err.response.data?.message || err.response.data)) || -// err.message || -// "Server error"; -// setError(String(msg)); -// } else { -// setError(String(err || "Unknown error")); -// } -// }; - -// return ( -// -//

Update Profile

- -// {loading && ( -// -// )} -// {error && {error}} -// {successMessage && {successMessage}} - -//
-// {/* IMAGE PREVIEW + NATIVE FILE INPUT (avoid Form.Control for file) */} -//
-// Profile -//
-// -// {selectedFile && ( -//
-// Selected: {selectedFile.name} -//
-// )} -//
-//
- -// {/* QR CODE */} -// {qrCodeImage && ( -//
-//
Your QR Code
-// QR Code -//
-// )} - -// {/* FORM FIELDS */} -// -// -// Email -// setFormData({ ...formData, email: e.target.value })} -// /> -// -// {formErrors.email} -// -// - -// -// Description -// setFormData({ ...formData, description: e.target.value })} -// /> -// -// {formErrors.description} -// -// -// - -// -// -// User Type -// setFormData({ ...formData, userType: e.target.value })} -// /> -// -// {formErrors.userType} -// -// - -// -// Experience Level -// -// setFormData({ ...formData, experienceLevel: e.target.value }) -// } -// /> -// -// {formErrors.experienceLevel} -// -// -// - -// -// -// Location -// setFormData({ ...formData, location: e.target.value })} -// /> -// -// {formErrors.location} -// -// - -// -// Available From -// setFormData({ ...formData, availableFrom: e.target.value })} -// /> -// -// {formErrors.availableFrom} -// -// -// - -// -// -// Phone Number -// setFormData({ ...formData, phoneNumber: e.target.value })} -// /> -// -// {formErrors.phoneNumber} -// -// - -// -// Driver’s License -// setFormData({ ...formData, driversLicense: e.target.value })} -// /> -// -// {formErrors.driversLicense} -// -// -// - -// -// Comments -// setFormData({ ...formData, comments: e.target.value })} -// /> -// -// {formErrors.comments} -// -// - -// -// New Password -// setFormData({ ...formData, newPassword: e.target.value })} -// /> -// - -//
-// -// -// -// -//
-//
-//
-// ); -// }; - -// export default ProfileUpdate; - - -// import React, { useEffect, useState } from "react"; -// import axios from "axios"; -// import { Button, Col, Form, Row, Alert, Card, Spinner } from "react-bootstrap"; -// import { Link } from "react-router-dom"; - -// type User = { -// id: string; -// email: string; -// password?: string; -// newPassword?: string; -// description: string; -// userType: string; -// experienceLevel: string; -// location: string; -// availableFrom: string; -// profileImage?: string; -// phoneNumber: string; -// driversLicense: string; -// comments: string; -// qrCode?: string; -// }; - -// const ServerPort = process.env.REACT_APP_SOCKET_IO_CLIENT_PORT || "http://localhost:3001"; - -// const ProfileUpdate: React.FC = () => { -// const userId = localStorage.getItem("userId") || ""; - -// const [formData, setFormData] = useState({ -// id: "", -// email: "", -// password: "", -// newPassword: "", -// description: "", -// userType: "", -// experienceLevel: "", -// location: "", -// availableFrom: "", -// profileImage: "", -// phoneNumber: "", -// driversLicense: "", -// comments: "", -// qrCode: "", -// }); - -// const [imagePreview, setImagePreview] = useState(null); -// const [selectedFile, setSelectedFile] = useState(null); -// const [formErrors, setFormErrors] = useState>({}); -// const [loading, setLoading] = useState(false); -// const [isSubmitting, setIsSubmitting] = useState(false); -// const [error, setError] = useState(null); -// const [successMessage, setSuccessMessage] = useState(null); - -// useEffect(() => { -// const fetchUserData = async () => { -// setLoading(true); -// try { -// const token = localStorage.getItem("token"); -// if (!token) { -// setError("No token found."); -// setLoading(false); -// return; -// } - -// const res = await axios.get(`${ServerPort}/api/user/view/${userId}`, { -// headers: { Authorization: `Bearer ${token}` }, -// }); - -// if (res.status === 200) { -// const user = res.data; -// setFormData({ -// ...user, -// availableFrom: user.availableFrom?.split("T")[0] || "", -// password: "", -// newPassword: "", -// }); -// setImagePreview(user.profileImage || null); -// } else { -// setError("Failed to fetch user data."); -// } -// } catch (err) { -// handleApiError(err); -// } finally { -// setLoading(false); -// } -// }; - -// if (userId) fetchUserData(); -// }, [userId]); - -// const handleFileChange = (e: React.ChangeEvent) => { -// const file = e.target.files?.[0] ?? null; -// if (file) { -// setSelectedFile(file); -// setImagePreview(URL.createObjectURL(file)); -// } else { -// setSelectedFile(null); -// } -// }; - -// const fileToBase64 = (file: File): Promise => -// new Promise((resolve, reject) => { -// const reader = new FileReader(); -// reader.readAsDataURL(file); -// reader.onload = () => resolve(reader.result as string); -// reader.onerror = (err) => reject(err); -// }); - -// const validateForm = () => { -// const errors: Record = {}; -// const requiredFields: (keyof User)[] = [ -// "email", -// "description", -// "userType", -// "experienceLevel", -// "location", -// "availableFrom", -// "phoneNumber", -// "driversLicense", -// "comments", -// ]; - -// requiredFields.forEach((field) => { -// if (!formData[field]) errors[field] = "This field is required"; -// }); - -// if (formData.email && !/\S+@\S+\.\S+/.test(formData.email)) { -// errors.email = "Invalid email"; -// } - -// setFormErrors(errors); -// return Object.keys(errors).length === 0; -// }; - -// const handleUserUpdate = async (e: React.FormEvent) => { -// e.preventDefault(); -// setError(null); -// setSuccessMessage(null); - -// if (!validateForm()) return; - -// setLoading(true); -// setIsSubmitting(true); - -// try { -// const token = localStorage.getItem("token"); -// if (!token) throw new Error("No token found"); - -// const payload: any = { ...formData }; - -// if (!formData.newPassword) delete payload.password; - -// if (selectedFile) { -// payload.profileImage = await fileToBase64(selectedFile); -// } - -// const res = await axios.put( -// `${ServerPort}/api/user/update/${userId}`, -// payload, -// { headers: { Authorization: `Bearer ${token}` } } -// ); - -// if (res.status === 200) { -// const updatedUser = res.data.user ?? res.data; -// setFormData((prev) => ({ ...prev, ...updatedUser, newPassword: "" })); -// setImagePreview(updatedUser.profileImage || imagePreview); -// setSelectedFile(null); -// setSuccessMessage("Profile updated and image uploaded."); -// } else { -// setError("Unexpected server response."); -// } -// } catch (err) { -// handleApiError(err); -// } finally { -// setLoading(false); -// setIsSubmitting(false); -// } -// }; - -// const handleApiError = (err: any) => { -// if (axios.isAxiosError(err)) { -// const msg = -// (err.response && (err.response.data?.message || err.response.data)) || -// err.message || -// "Server error"; -// setError(String(msg)); -// } else { -// setError(String(err || "Unknown error")); -// } -// }; - -// return ( -// -//

Update Profile

- -// {loading && } -// {error && {error}} -// {successMessage && {successMessage}} - -//
-// {/* Profile Image */} -//
-// Profile -//
-// -// {selectedFile &&
{selectedFile.name}
} -//
-//
- -// {/* ALL FORM FIELDS */} -// -// -// Email -// setFormData({ ...formData, email: e.target.value })} -// /> -// {formErrors.email} -// - -// -// Description -// setFormData({ ...formData, description: e.target.value })} -// /> -// {formErrors.description} -// -// - -// -// -// User Type -// setFormData({ ...formData, userType: e.target.value })} -// /> -// {formErrors.userType} -// - -// -// Experience Level -// setFormData({ ...formData, experienceLevel: e.target.value })} -// /> -// {formErrors.experienceLevel} -// -// - -// -// -// Location -// setFormData({ ...formData, location: e.target.value })} -// /> -// {formErrors.location} -// - -// -// Available From -// setFormData({ ...formData, availableFrom: e.target.value })} -// /> -// {formErrors.availableFrom} -// -// - -// -// -// Phone Number -// setFormData({ ...formData, phoneNumber: e.target.value })} -// /> -// {formErrors.phoneNumber} -// - -// -// Driver’s License -// setFormData({ ...formData, driversLicense: e.target.value })} -// /> -// {formErrors.driversLicense} -// -// - -// -// Comments -// setFormData({ ...formData, comments: e.target.value })} -// /> -// {formErrors.comments} -// - -// -// New Password -// setFormData({ ...formData, newPassword: e.target.value })} -// /> -// - -//
-// -// -// -// -//
-//
-//
-// ); -// }; - -// export default ProfileUpdate; - -// src/pages/ProfileUpdate.tsx import React, { useEffect, useState } from "react"; import axios from "axios"; import { Button, Col, Form, Row, Alert, Card, Spinner } from "react-bootstrap"; diff --git a/client/src/containers/User/UserDash/Dash.tsx b/client/src/containers/User/UserDash/Dash.tsx index f40c394..e97828a 100644 --- a/client/src/containers/User/UserDash/Dash.tsx +++ b/client/src/containers/User/UserDash/Dash.tsx @@ -1,792 +1,3 @@ -// import React, { useEffect, useState } from "react"; -// import { Link } from "react-router-dom"; -// import { -// PieChart, -// Pie, -// BarChart, -// Bar, -// Brush, -// ReferenceLine, -// XAxis, -// YAxis, -// CartesianGrid, -// Tooltip, -// Legend, -// } from "recharts"; -// import axios from "axios"; -// import "./Dash.css"; // Make sure to update styles in this file - -// const ServerPort = -// process.env.REACT_APP_SOCKET_IO_CLIENT_PORT || "http://localhost:3001"; - -// const Dash = () => { -// const [userData, setUserData] = useState(null); -// const [loading, setLoading] = useState(true); -// const [error, setError] = useState(""); - -// useEffect(() => { -// const userId = localStorage.getItem("userId"); // Get user ID from local storage -// const fetchUserData = async () => { -// try { -// const res = await axios.get(`${ServerPort}/api/user/view/${userId}`); -// setUserData(res.data); -// } catch (error) { -// console.error("Error fetching user data:", error); -// setError("Failed to load user data."); -// } finally { -// setLoading(false); -// } -// }; - -// if (userId) { -// fetchUserData(); -// } else { -// setError("User ID not found in local storage."); -// setLoading(false); -// } -// }, []); - -// const data = [ -// // Your existing data for bar chart -// { name: "1", uv: 300, pv: 456 }, -// { name: "2", uv: -145, pv: 230 }, -// // ... other data points -// ]; - -// const data2 = [ -// { name: "Group A", value: 400 }, -// { name: "Group B", value: 300 }, -// // ... other data points -// ]; - -// if (loading) { -// return
Loading user data...
; -// } - -// if (error) { -// return
{error}
; -// } - -// return ( -// <> -//
-//

Dashboard

-//
- -//
-//

User Information

-//

Name: {userData.firstName} {userData.lastName}

-//

Email: {userData.email}

-//

Phone Number: {userData.phoneNumber || "Not provided"}

-//

Address: {userData.address || "Not provided"}

-//

Available Status: {userData.loadStatus}

-//

Customer Since: {new Date(userData.availableFrom).toLocaleDateString()}

-//

Type of Owner: {userData.userType}

-//
- -//
-//

Charts

-//
-// {Array(4) -// .fill(null) -// .map((_, index) => ( -//
-// -// -// -//
-// ))} -//
- -//
-// -// -// -// -// -// -// -// -// -// -// -//
-//
- -// -// Home -// -// -// ); -// }; - -// export default Dash; - -// import React, { useEffect, useState } from "react"; -// import { Link } from "react-router-dom"; -// import { -// PieChart, -// Pie, -// Cell, -// BarChart, -// Bar, -// XAxis, -// YAxis, -// CartesianGrid, -// Tooltip, -// Legend, -// ReferenceLine, -// Brush, -// } from "recharts"; -// import axios from "axios"; -// import "./Dash.css"; - -// const SERVER_PORT = process.env.REACT_APP_SOCKET_IO_CLIENT_PORT || "http://localhost:3001"; - -// // Colors for pie charts -// const PIE_COLORS = ["#0088FE", "#00C49F", "#FFBB28", "#FF8042"]; - -// const Dash = () => { -// const [userData, setUserData] = useState(null); -// const [loading, setLoading] = useState(true); -// const [error, setError] = useState(""); - -// // Fetch user data -// useEffect(() => { -// const userId = localStorage.getItem("userId"); -// if (!userId) { -// setError("User ID not found in local storage."); -// setLoading(false); -// return; -// } - -// const fetchUserData = async () => { -// try { -// const res = await axios.get(`${SERVER_PORT}/api/user/view/${userId}`); -// setUserData(res.data); -// } catch (err) { -// console.error("Error fetching user data:", err); -// setError("Failed to load user data."); -// } finally { -// setLoading(false); -// } -// }; - -// fetchUserData(); -// }, []); - -// if (loading) return
Loading user data...
; -// if (error) return
{error}
; - -// // Prepare chart data -// const barData = userData?.loadDetails?.map((load: any, idx: number) => ({ -// name: `Load ${idx + 1}`, -// weight: load.weight || 0, -// value: load.value || 0, -// })) || [{ name: "No Data", weight: 0, value: 0 }]; - -// const pieData = [ -// { name: "Available", value: userData.availableFrom ? 1 : 0 }, -// { name: "Unavailable", value: userData.availableFrom ? 0 : 1 }, -// ]; - -// return ( -//
-//
-//

Dashboard

-//

Welcome back, {userData.firstName}!

-//
- -// {/* User Info */} -//
-//

User Information

-//
-//
-// Name: {userData.firstName} {userData.lastName} -//
-//
-// Email: {userData.email} -//
-//
-// Phone: {userData.phoneNumber || "Not provided"} -//
-//
-// Address: {userData.address || "Not provided"} -//
-//
-// Status: {userData.loadStatus || "N/A"} -//
-//
-// Customer Since:{" "} -// {userData.availableFrom -// ? new Date(userData.availableFrom).toLocaleDateString() -// : "N/A"} -//
-//
-// Type of Owner: {userData.userType || "N/A"} -//
-//
-// Experience Level: {userData.experienceLevel || "N/A"} -//
-//
-// Preferred Load: {userData.preferredLoadType || "N/A"} -//
-//
-// Company: {userData.company || "N/A"} -//
-//
-// Subscribed: {userData.subscribed ? "Yes" : "No"} -//
-//
-// Rating: {userData.rating || "N/A"} -//
-//
-//
- -// {/* Charts */} -//
-//

Analytics

- -// {/* Pie Chart */} -//
-// -// -// {pieData.map((entry, index) => ( -// -// ))} -// -// -// -//
- -// {/* Bar Chart */} -//
-// -// -// -// -// -// -// -// -// -// -// -//
-//
- -// -// Back to Home -// -//
-// ); -// }; - -// export default Dash; - -// import React, { useEffect, useState } from "react"; -// import { Link } from "react-router-dom"; -// import { -// PieChart, -// Pie, -// Cell, -// BarChart, -// Bar, -// XAxis, -// YAxis, -// CartesianGrid, -// Tooltip, -// Legend, -// ReferenceLine, -// Brush, -// } from "recharts"; -// import axios from "axios"; -// import "./Dash.css"; - -// const SERVER_PORT = process.env.REACT_APP_SOCKET_IO_CLIENT_PORT || "http://localhost:3001"; - -// // Colors for pie charts -// const PIE_COLORS = ["#0088FE", "#00C49F", "#FFBB28", "#FF8042"]; - -// interface LoadData { -// weight: number; -// value: number; -// rating: number; -// } - -// interface UserData { -// firstName: string; -// lastName: string; -// email: string; -// phoneNumber?: string; -// address?: string; -// loadStatus?: string; -// availableFrom?: string; -// userType?: string; -// experienceLevel?: string; -// preferredLoadType?: string; -// company?: string; -// subscribed?: boolean; -// rating?: number; -// profileImage?: string; -// loadDetails?: LoadData[]; -// } - -// const Dash: React.FC = () => { -// const [userData, setUserData] = useState(null); -// const [loading, setLoading] = useState(true); -// const [error, setError] = useState(""); - -// useEffect(() => { -// const userId = localStorage.getItem("userId"); -// if (!userId) { -// setError("User ID not found in local storage."); -// setLoading(false); -// return; -// } - -// const fetchUserData = async () => { -// try { -// const res = await axios.get(`${SERVER_PORT}/api/user/view/${userId}`); -// setUserData(res.data); -// } catch (err) { -// console.error("Error fetching user data:", err); -// setError("Failed to load user data."); -// } finally { -// setLoading(false); -// } -// }; - -// fetchUserData(); -// }, []); - -// if (loading) return
Loading user data...
; -// if (error) return
{error}
; -// if (!userData) return
No user data available.
; - -// const barData: LoadData[] = -// userData?.loadDetails?.map((load) => ({ -// weight: load.weight || 0, -// value: load.value || 0, -// rating: load.rating || 0, -// })) || [{ weight: 0, value: 0, rating: 0 }]; - -// const pieData = [ -// { name: "Available", value: userData.availableFrom ? 1 : 0 }, -// { name: "Unavailable", value: userData.availableFrom ? 0 : 1 }, -// ]; - -// // Find top-rated load for highlight -// const topLoadIndex = barData.reduce((maxIdx: number, currentLoad: LoadData, idx: number, arr: LoadData[]) => -// currentLoad.rating > arr[maxIdx].rating ? idx : maxIdx -// , 0); - -// return ( -//
-//
-// {userData.profileImage && ( -// Profile -// )} -//

Dashboard

-//

Welcome back, {userData.firstName}!

-//
- -//
-//

User Information

-//
-//
-// Name: {userData.firstName} {userData.lastName} -//
-//
-// Email: {userData.email} -//
-//
-// Phone: {userData.phoneNumber || "Not provided"} -//
-//
-// Address: {userData.address || "Not provided"} -//
-//
-// Status: {userData.loadStatus || "N/A"} -//
-//
-// Customer Since:{" "} -// {userData.availableFrom ? new Date(userData.availableFrom).toLocaleDateString() : "N/A"} -//
-//
-// Type of Owner: {userData.userType || "N/A"} -//
-//
-// Experience Level: {userData.experienceLevel || "N/A"} -//
-//
-// Preferred Load: {userData.preferredLoadType || "N/A"} -//
-//
-// Company: {userData.company || "N/A"} -//
-//
-// Subscribed: {userData.subscribed ? "Yes" : "No"} -//
-//
-// Rating: {userData.rating || "N/A"} -//
-//
-//
- -//
-//

Analytics

- -//
-// -// -// {pieData.map((slice, index) => ( -// -// ))} -// -// -// -//
- -//
-// -// -// -// -// -// -// -// -// -// {barData.map((_, idx) => -// idx === topLoadIndex ? : null -// )} -// -// -// -//
-//
- -// -// Back to Home -// -//
-// ); -// }; - -// export default Dash; - -// import React, { useEffect, useState } from "react"; -// import { Link } from "react-router-dom"; -// import { -// PieChart, -// Pie, -// Cell, -// BarChart, -// Bar, -// XAxis, -// YAxis, -// CartesianGrid, -// Tooltip, -// Legend, -// ReferenceLine, -// Brush, -// } from "recharts"; -// import axios from "axios"; -// import "./Dash.css"; - -// const SERVER_PORT = process.env.REACT_APP_SOCKET_IO_CLIENT_PORT || "http://localhost:3001"; - -// const PIE_COLORS = ["#0088FE", "#00C49F", "#FFBB28", "#FF8042"]; - -// interface LoadData { -// weight: number; -// value: number; -// rating: number; -// name?: string; // optional name for display on chart -// } - -// interface UserData { -// firstName: string; -// lastName: string; -// email: string; -// phoneNumber?: string; -// address?: string; -// qrCode?: string; -// qrCodeId?: string; -// qrData?: string; -// qrPNG?: string; -// loadStatus?: string; -// availableFrom?: string; -// userType?: string; -// experienceLevel?: string; -// preferredLoadType?: string; -// company?: string; -// subscribed?: boolean; -// rating?: number; -// profileImage?: string; -// loadDetails?: LoadData[]; -// } - -// const Dash: React.FC = () => { -// const [userData, setUserData] = useState(null); -// const [loading, setLoading] = useState(true); -// const [error, setError] = useState(""); - -// useEffect(() => { -// const userId = localStorage.getItem("userId"); -// if (!userId) { -// setError("User ID not found in local storage."); -// setLoading(false); -// return; -// } - -// const fetchUserData = async () => { -// try { -// const res = await axios.get(`${SERVER_PORT}/api/user/view/${userId}`); -// setUserData(res.data); -// } catch (err) { -// console.error("Error fetching user data:", err); -// setError("Failed to load user data."); -// } finally { -// setLoading(false); -// } -// }; - -// fetchUserData(); -// }, []); - -// if (loading) return
Loading user data...
; -// if (error) return
{error}
; -// if (!userData) return
No user data available.
; - -// // ✅ TypeScript knows userData is not null here -// const { -// firstName, -// lastName, -// email, -// phoneNumber, -// address, -// qrCode, -// qrCodeId, -// qrData, -// qrPNG, -// loadStatus, -// availableFrom, -// userType, -// experienceLevel, -// preferredLoadType, -// company, -// subscribed, -// rating, -// profileImage, -// loadDetails, -// } = userData; - -// const barData: LoadData[] = -// loadDetails?.map((load, idx) => ({ -// ...load, -// name: `Load ${idx + 1}`, // optional for x-axis -// })) || [{ weight: 0, value: 0, rating: 0, name: "N/A" }]; - -// const pieData = [ -// { name: "Available", value: availableFrom ? 1 : 0 }, -// { name: "Unavailable", value: availableFrom ? 0 : 1 }, -// ]; - -// const topLoadIndex = barData.reduce( -// (maxIdx: number, currentLoad: LoadData, idx: number, arr: LoadData[]) => -// currentLoad.rating > arr[maxIdx].rating ? idx : maxIdx, -// 0 -// ); - -// return ( -//
-//
-// {profileImage && Profile} -//

Dashboard

-//

Welcome back, {firstName}!

-//
- -//
-//

User Information

-//
-//
-// Name: {firstName} {lastName} -//
-//
-// Email: {email} -//
-//
-// Phone: {phoneNumber || "Not provided"} -//
-//
-// Address: {address || "Not provided"} -//
-//
-// QR Code: {qrCode || "N/A"} -//
-//
-// QR Code ID: {qrCodeId || "N/A"} -//
-//
-// QR Data: {qrData || "N/A"} -//
-//
-// QR PNG: {qrPNG || "N/A"} -//
-// {/* QR Code Card */} -//
-//

Your QR Code

- -// {qrPNG ? ( -// QR Code -// ) : ( -//

No QR code available

-// )} -//
- -//
-// Status: {loadStatus || "N/A"} -//
-//
-// Customer Since: {availableFrom ? new Date(availableFrom).toLocaleDateString() : "N/A"} -//
-//
-// Type of Owner: {userType || "N/A"} -//
-//
-// Experience Level: {experienceLevel || "N/A"} -//
-//
-// Preferred Load: {preferredLoadType || "N/A"} -//
-//
-// Company: {company || "N/A"} -//
-//
-// Subscribed: {subscribed ? "Yes" : "No"} -//
-//
-// Rating: {rating || "N/A"} -//
-//
-//
- -//
-//

Analytics

- -//
-// -// -// {pieData.map((slice, index) => ( -// -// ))} -// -// -// -//
- -//
-// -// -// -// -// -// -// -// -// -// {barData.map((_, idx) => -// idx === topLoadIndex ? : null -// )} -// -// -// -//
-//
- -// -// Back to Home -// -//
-// ); -// }; - -// export default Dash; - import React, { useEffect, useState } from "react"; import { Link } from "react-router-dom"; import { diff --git a/controllers/UserAPIRoutes.js b/controllers/UserAPIRoutes.js index 57b8e20..4ca577b 100644 --- a/controllers/UserAPIRoutes.js +++ b/controllers/UserAPIRoutes.js @@ -48,128 +48,6 @@ router.get("/view/:id", (req, res) => { }); }); -// router.put("/update/:id", upload.single("profileImage"), async (req, res) => { -// try { -// // 1️⃣ Fetch the user -// const user = await db.User.findByPk(req.params.id); -// if (!user) { -// return res.status(404).send({ success: false, message: "User not found" }); -// } - -// // 2️⃣ Handle password update -// const updateData = { ...req.body }; - -// if (updateData.newPassword) { -// const hashedPassword = await bcrypt.hash(updateData.newPassword, 10); -// updateData.password = hashedPassword; -// delete updateData.newPassword; -// } - -// // 3️⃣ Handle image upload (optional) -// let imageUrl = user.profileImage; // keep previous image by default - -// if (req.file) { -// try { -// const result = await cloudinary.uploader.upload(req.file.path, { -// folder: "users", -// public_id: `user_${user.id}_${Date.now()}`, -// transformation: [{ width: 500, height: 500, crop: "fill" }], -// }); - -// imageUrl = result.secure_url; -// } catch (err) { -// console.error("Cloudinary Upload Error:", err); -// return res.status(500).json({ -// success: false, -// message: "Image upload failed", -// }); -// } -// } - -// updateData.profileImage = imageUrl; - -// // 4️⃣ Update the user -// const [updatedRows] = await db.User.update(updateData, { -// where: { id: req.params.id }, -// }); - -// if (updatedRows === 0) { -// return res.status(404).send({ success: false, message: "No updates made" }); -// } - -// // 5️⃣ Fetch updated user -// const updatedUser = await db.User.findByPk(req.params.id); - -// res.status(200).send({ -// success: true, -// message: "User updated successfully", -// user: updatedUser, -// }); - -// } catch (error) { -// console.error("Error updating user:", error); -// res.status(500).send({ success: false, message: "Internal Server Error" }); -// } -// // }); -// router.put("/update/:id", async (req, res) => { -// try { -// const user = await db.User.findByPk(req.params.id); -// if (!user) return res.status(404).json({ success: false, message: "User not found" }); - -// const updateData = { ...req.body }; - -// // Handle new password -// if (updateData.newPassword) { -// const hashed = await bcrypt.hash(updateData.newPassword, 10); -// updateData.password = hashed; -// delete updateData.newPassword; -// } - -// // Handle profile image upload to Cloudinary -// if (updateData.profileImage) { -// try { -// // Normalize profileImage input: -// // - if it's already a data URI (starts with "data:"), use it as-is -// // - if it's a remote URL (starts with http/https), use it as-is -// // - otherwise assume it's a raw base64 string and prefix with a JPEG data URI header -// let uploadSource = updateData.profileImage; -// if (typeof uploadSource === "string") { -// const trimmed = uploadSource.trim(); -// if (!/^data:/.test(trimmed) && !/^https?:\/\//i.test(trimmed)) { -// // treat as raw base64 -// uploadSource = `data:image/jpeg;base64,${trimmed}`; -// } else { -// uploadSource = trimmed; -// } -// } else { -// // If not a string, avoid passing invalid input to Cloudinary -// throw new Error("Invalid profileImage format"); -// } - -// const result = await cloudinary.uploader.upload(uploadSource, { -// folder: "users", -// public_id: `user_${user.id}_${Date.now()}`, -// transformation: [{ width: 500, height: 500, crop: "fill" }], -// }); -// updateData.profileImage = result.secure_url; -// } catch (err) { -// console.error("Cloudinary upload failed:", err); -// return res.status(400).json({ success: false, message: "Image upload failed", error: err.message }); -// } -// } - -// // Update user -// const [updatedRows] = await db.User.update(updateData, { where: { id: req.params.id } }); -// if (updatedRows === 0) return res.status(404).json({ success: false, message: "No updates made" }); - -// const updatedUser = await db.User.findByPk(req.params.id); -// res.status(200).json({ success: true, message: "User updated", user: updatedUser }); - -// } catch (err) { -// console.error("Error updating user:", err); -// res.status(500).json({ success: false, message: "Internal server error" }); -// } -// }); router.put("/update/:id", async (req, res) => { try { // 1️⃣ Find user @@ -370,71 +248,4 @@ router.post("/login", (req, res) => { }); }); -// router.put("/user/update/:userId", upload.single("image"), async (req, res) => { -// try { -// const { newPassword } = req.body; - -// // 1️⃣ Fetch user -// const user = await db.User.findByPk(req.params.userId); -// if (!user) { -// return res.status(404).json({ success: false, message: "User not found" }); -// } - -// // 2️⃣ Handle password change -// if (newPassword) { -// const hashedPassword = await bcrypt.hash(newPassword, 10); -// req.body.password = hashedPassword; -// delete req.body.newPassword; -// } - -// // 3️⃣ Handle image upload if provided -// let imageUrl = user.image; // Keep old image if none uploaded -// if (req.file) { -// try { -// const result = await cloudinary.uploader.upload(req.file.path, { -// folder: "users", -// public_id: `user_${user.id}_${Date.now()}`, -// transformation: [{ width: 500, height: 500, crop: "fill" }], -// }); -// imageUrl = result.secure_url; -// } catch (uploadErr) { -// console.error("Cloudinary upload failed:", uploadErr); -// return res.status(500).json({ -// success: false, -// message: "Image upload failed", -// }); -// } -// } - -// // 4️⃣ Prepare update data -// const updateData = { ...req.body, image: imageUrl }; - -// // 5️⃣ Update user -// const [updatedRows] = await db.User.update(updateData, { -// where: { id: req.params.userId }, -// }); - -// if (updatedRows === 0) { -// return res -// .status(400) -// .json({ success: false, message: "No updates made" }); -// } - -// // 6️⃣ Fetch updated user -// const updatedUser = await db.User.findByPk(req.params.userId); - -// res.status(200).json({ -// success: true, -// message: "User updated successfully", -// user: updatedUser, -// }); -// } catch (error) { -// console.error("Error updating user:", error); -// res.status(500).json({ -// success: false, -// message: "Internal Server Error", -// }); -// } -// }); - module.exports = router;