Skip to content

Commit

Permalink
feat: Ar Inspect
Browse files Browse the repository at this point in the history
  • Loading branch information
ConstIX committed Aug 21, 2024
1 parent 92f6f65 commit 942699e
Show file tree
Hide file tree
Showing 17 changed files with 194 additions and 128 deletions.
221 changes: 125 additions & 96 deletions packages/nextjs/app/myrentals/myrentals.tsx
Original file line number Diff line number Diff line change
@@ -1,51 +1,5 @@
// 'use client'
// import React, { useEffect, useState } from 'react';

// // Define the type for rental objects
// interface Rental {
// productTitle: string;
// productId: number;
// bookingDate: string;
// bookingTime: string;
// endDate: string;
// endTime: string;
// }

// const MyRental: React.FC = () => {
// const [rentals, setRentals] = useState<Rental[]>([]); // Use the Rental type for the state

// useEffect(() => {
// // Fetch rentals from localStorage
// const storedRentals: Rental[] = JSON.parse(localStorage.getItem('rentals') || '[]');
// setRentals(storedRentals);
// }, []);

// return (
// <div className="pt-20 p-2">
// <h2 className="text-2xl font-bold mb-4">My Rentals</h2>
// {rentals.length > 0 ? (
// <ul className="space-y-4">
// {rentals.map((rental, index) => (
// <li key={index} className="border p-4 rounded shadow">
// <p className="font-bold text-lg">{rental.productTitle}</p>
// <p>Start Date: {rental.bookingDate}</p>
// <p>Start Time: {rental.bookingTime}</p>
// <p>End Date: {rental.endDate}</p>
// <p>End Time: {rental.endTime}</p>
// {/* <p>Product ID: {rental.productId}</p> */}
// </li>
// ))}
// </ul>
// ) : (
// <p>No rentals found.</p>
// )}
// </div>
// );
// };

// export default MyRental;
'use client'
import React, { useEffect, useState } from 'react';
import React, { useEffect, useState, useRef } from 'react';

// Define the type for rental objects
interface Rental {
Expand All @@ -60,35 +14,63 @@ interface Rental {

const MyRental: React.FC = () => {
const [rentals, setRentals] = useState<Rental[]>([]); // Use the Rental type for the state
const [selectedFiles, setSelectedFiles] = useState<{ [key: number]: File[] }>({}); // State to track selected files for each rental
const [showCamera, setShowCamera] = useState<{ [key: number]: boolean }>({}); // State to show camera per rental
const [capturedImage, setCapturedImage] = useState<{ [key: number]: string }>({}); // State to store captured image per rental
const [selectedFile, setSelectedFile] = useState<{ [key: number]: string }>({}); // State to store selected file per rental
const videoRef = useRef<HTMLVideoElement>(null);
const canvasRef = useRef<HTMLCanvasElement>(null);

useEffect(() => {
// Fetch rentals from localStorage
const storedRentals: Rental[] = JSON.parse(localStorage.getItem('rentals') || '[]');
setRentals(storedRentals);
}, []);

const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>, rentalId: number) => {
const files = e.target.files ? Array.from(e.target.files) : [];
setSelectedFiles((prev) => ({
...prev,
[rentalId]: files,
}));
const startCamera = async (rentalId: number) => {
setShowCamera((prev) => ({ ...prev, [rentalId]: true }));
if (navigator.mediaDevices.getUserMedia) {
try {
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
if (videoRef.current) {
videoRef.current.srcObject = stream;
}
} catch (err) {
console.error("Error accessing camera:", err);
}
}
};

const handleReturnRental = (rentalId: number) => {
const files = selectedFiles[rentalId];

if (!files || files.length === 0) {
alert('Please upload either an image or a video for safe return.');
return;
const captureImage = (rentalId: number) => {
if (canvasRef.current && videoRef.current) {
const context = canvasRef.current.getContext('2d');
if (context) {
context.drawImage(videoRef.current, 0, 0, canvasRef.current.width, canvasRef.current.height);
const imageData = canvasRef.current.toDataURL('image/png');
setCapturedImage((prev) => ({ ...prev, [rentalId]: imageData }));

// Stop the camera after capturing the image
const stream = videoRef.current.srcObject as MediaStream;
const tracks = stream.getTracks();
tracks.forEach(track => track.stop());
setShowCamera((prev) => ({ ...prev, [rentalId]: false }));
}
}
};

// Check if at least one image or video file is uploaded
const hasValidFile = files.some(file => file.type.startsWith('image/') || file.type.startsWith('video/'));
const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>, rentalId: number) => {
const file = event.target.files?.[0];
if (file) {
const reader = new FileReader();
reader.onload = (e) => {
setSelectedFile((prev) => ({ ...prev, [rentalId]: e.target?.result as string }));
};
reader.readAsDataURL(file);
}
};

if (!hasValidFile) {
alert('Please make sure to upload a valid image or video file.');
const handleReturnRental = (rentalId: number) => {
if (!capturedImage[rentalId] && !selectedFile[rentalId]) {
alert('Please capture an image or choose a file for safe return.');
return;
}

Expand All @@ -108,38 +90,85 @@ const MyRental: React.FC = () => {
{rentals.length > 0 ? (
<ul className="space-y-4">
{rentals.map((rental, index) => (
<li key={index} className="border p-4 rounded shadow">
<p className="font-bold text-lg">{rental.productTitle}</p>
<p>Start Date: {rental.bookingDate}</p>
<p>Start Time: {rental.bookingTime}</p>
<p>End Date: {rental.endDate}</p>
<p>End Time: {rental.endTime}</p>

{/* Only show return option if the rental is not yet returned */}
{!rental.isReturned && (
<div className="mt-4">
<label className="block mb-2 font-semibold">Upload Image/Video for Safe Return:</label>
<input
type="file"
accept="image/*,video/*"
multiple
onChange={(e) => handleFileChange(e, rental.productId)}
className="mb-4"
/>

<button
onClick={() => handleReturnRental(rental.productId)}
className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
>
Return Rental
</button>
</div>
)}

{/* Show a message if the rental has been returned */}
{rental.isReturned && (
<p className="mt-4 text-green-500 font-semibold">Rental returned successfully!</p>
)}
<li key={index} className="border p-4 rounded shadow flex justify-between gap-x-4 items-center w-full">
<div>
<p className="font-bold text-lg">{rental.productTitle}</p>
<p>Start Date: {rental.bookingDate}</p>
<p>Start Time: {rental.bookingTime}</p>
<p>End Date: {rental.endDate}</p>
<p>End Time: {rental.endTime}</p>
</div>

<div>
{/* Only show return option if the rental is not yet returned */}
{!rental.isReturned && (
<div className="mt-4">
{!showCamera[rental.productId] ? (
<>
<button
onClick={() => startCamera(rental.productId)}
className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
>
AR Inspect
</button>
{capturedImage[rental.productId] && (
<div className="mt-4">
<p className="text-green-500 font-semibold">Image captured successfully!</p>
<img src={capturedImage[rental.productId]} alt="Captured" className="mt-2 border rounded" />
<button
onClick={() => handleReturnRental(rental.productId)}
className="px-4 py-2 bg-green-500 text-white rounded hover:bg-green-600 mt-4"
>
Confirm Return
</button>
</div>
)}
</>
) : (
<div>
<video ref={videoRef} autoPlay className="border rounded mb-4 !w-72 !h-auto"></video>
<canvas ref={canvasRef} width="300" height="200" className="hidden !w-72 !h-72"></canvas>
<button
onClick={() => captureImage(rental.productId)}
className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
>
Capture Image
</button>
</div>
)}

<div className="mt-4">
<label htmlFor={`fileInput-${rental.productId}`} className="block mb-2 font-semibold">
Choose File (Image/Video)
</label>
<input
type="file"
accept="image/*,video/*"
id={`fileInput-${rental.productId}`}
onChange={(e) => handleFileChange(e, rental.productId)}
className="mb-4"
/>
{selectedFile[rental.productId] && (
<div className="mt-4">
<p className="text-green-500 font-semibold">File selected successfully!</p>
{/* <img src={selectedFile[rental.productId]} alt="Selected" className="mt-2 border rounded h-52 w-52 object-contain" /> */}
<button
onClick={() => handleReturnRental(rental.productId)}
className="px-4 py-2 bg-green-500 text-white rounded hover:bg-green-600 mt-4"
>
Confirm Return
</button>
</div>
)}
</div>
</div>
)}

{/* Show a message if the rental has been returned */}
{rental.isReturned && (
<p className="mt-4 text-green-500 font-semibold">Rental returned successfully!</p>
)}
</div>
</li>
))}
</ul>
Expand Down
4 changes: 3 additions & 1 deletion packages/nextjs/app/socialfi/Social.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,9 @@ export default function SocialFi() {

<div className={styles.social__column}>
{items.map(obj => (
<div key={obj.id}>{tab === `${obj.id}` && obj.children}</div>
<div key={obj.id}>{tab === `${obj.id}` && obj.children}

</div>
))}
</div>
</div>
Expand Down
56 changes: 42 additions & 14 deletions packages/nextjs/components/product-details/ProductDescription.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@ const ProductDescription: FC<
const [endTime, setEndTime] = useState("");
const [endDate, setEndDate] = useState("");
const [totalKPrice, setTotalKPrice] = useState(0);
const [totalXPrice, setTotalXPrice] = useState(0);
const [totalPrice, setTotalPrice] = useState(0); // State to track the calculated price
const router = useRouter();

const hourlyRate = 8;
const hourlyKRate = 378000; // Example rate: $8 per hour
const hourlyRate = 5;
const hourlyKRate = 378000;
const hourlyXRate = 8; // Example rate: $8 per hour

useEffect(() => {
// Set current date and time in the proper format
Expand All @@ -40,6 +42,22 @@ const ProductDescription: FC<
setCurrentTime(formattedTime);
}, []);

const calculatedXPrice = () => {
if (!bookingDate || !bookingTime || !endDate || !endTime) {
return 0;
}

const start = new Date(`${bookingDate}T${bookingTime}`);
const end = new Date(`${endDate}T${endTime}`);
const durationInHours = (end.getTime() - start.getTime()) / (1000 * 60 * 60); // Duration in hours

// Ensure the duration is positive
if (durationInHours > 0) {
return durationInHours * hourlyXRate;
}

return 0;
};
const calculatedKPrice = () => {
if (!bookingDate || !bookingTime || !endDate || !endTime) {
return 0;
Expand Down Expand Up @@ -89,6 +107,7 @@ const ProductDescription: FC<
const calculatedPrice = calculatePrice();
setTotalPrice(calculatedPrice);
setTotalKPrice(calculatedKPrice);
setTotalXPrice(calculatedXPrice);
setShowModal(true); // Show modal on button click
};

Expand Down Expand Up @@ -123,19 +142,25 @@ const ProductDescription: FC<
<h2>{title}</h2>
<p>{text}</p>
<div className="my-3">
<p className="flex items-center gap-[6px] font-semibold">
<p className="flex flex-wrap gap-[6px] font-semibold">
Price: ${hourlyRate} -
<span className="flex items-center">
<Image src="/k9-logo.png" alt="xfi" width={15} height={15} />
<Image src="/xfi-logo.png" alt="xfi" width={15} height={15} /> K9 {hourlyKRate}
<Image src="/k9-logo.png" alt="xfi" width={15} height={15} /> K9 {hourlyKRate}
</span>{" "}
-
<span className="flex items-center">
<Image src="/xfi-logo.png" alt="xfi" width={15} height={15} /> XFI {hourlyXRate}
</span>
(per hour)
</p>
<p className="flex items-center gap-[6px] font-semibold">
<p className="flex flex-wrap gap-[6px] gap-y-0 font-semibold">
Total Price: ${totalPrice.toFixed(2)} -
<span className="flex items-center">
<Image src="/k9-logo.png" alt="xfi" width={15} height={15} />
<Image src="/xfi-logo.png" alt="xfi" width={15} height={15} /> K9 {totalKPrice.toFixed(2)}
<Image src="/k9-logo.png" alt="xfi" width={15} height={15} /> K9 {totalKPrice.toFixed(2)}
</span>{" "}
-
<span className="flex items-center">
<Image src="/xfi-logo.png" alt="xfi" width={15} height={15} /> XFI {totalXPrice.toFixed(2)}
</span>
</p>
</div>
Expand Down Expand Up @@ -214,7 +239,7 @@ const ProductDescription: FC<

{showModal && (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50">
<div className="w-full max-w-md rounded-lg bg-white p-8 shadow-lg">
<div className="w-full max-w-[500px] rounded-lg bg-white p-8 shadow-lg">
<h2 className="mb-4 text-xl font-bold">{title}</h2>
<p className="mb-4 text-gray-700">{text}</p>
<div className="mb-4">
Expand All @@ -230,24 +255,27 @@ const ProductDescription: FC<
<p>
<strong>End Time:</strong> {endTime}
</p>
<p className="flex items-center gap-[5px]">
<p className="flex flex-wrap items-center gap-[5px] gap-y-0">
<strong>Total Price: </strong> ${totalPrice.toFixed(2)} -
<span className="flex items-center">
<Image src="/k9-logo.png" alt="xfi" width={15} height={15} />
<Image src="/xfi-logo.png" alt="xfi" width={15} height={15} /> K9 {totalKPrice.toFixed(2)}
<Image src="/k9-logo.png" alt="xfi" width={15} height={15} /> K9 {totalKPrice.toFixed(2)}
</span>{" "}
-
<span className="flex items-center">
<Image src="/xfi-logo.png" alt="xfi" width={15} height={15} /> XFI {totalXPrice.toFixed(2)}
</span>
</p>
</div>
<div className="flex justify-end space-x-4">
<button
onClick={() => setShowModal(false)}
className="rounded bg-gray-300 px-4 py-2 text-gray-700 hover:bg-gray-400"
className="rounded !bg-red-400 px-4 py-2 text-gray-700 hover:!bg-red-500"
>
Cancel
</button>
<button
onClick={handleConfirmBooking}
className="rounded bg-blue-500 px-4 py-2 text-white hover:bg-blue-600"
className="rounded !bg-green-500 px-4 py-2 text-white hover:!bg-green-600"
>
Confirm Booking
</button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
}

&__description {
flex: 0 1 35%;
flex: 0 1 45%;
display: flex;
flex-direction: column;
height: 100%;
Expand Down
Loading

0 comments on commit 942699e

Please sign in to comment.