diff --git a/app/match/page.tsx b/app/match/page.tsx
new file mode 100644
index 0000000..42dac85
--- /dev/null
+++ b/app/match/page.tsx
@@ -0,0 +1,362 @@
+"use client"
+
+import { ReactNode, useEffect, useState } from "react"
+import { useRouter } from "next/navigation"
+import { useEncryptedStore } from "@/store/encrypted"
+import { usePasswordStore } from "@/store/password"
+import { MatchDocument } from "@/types"
+import RequireAuth from "@/components/helper/RequireAuth"
+import { Button } from "@/components/ui/button"
+
+
+const onMarkCompletionButton = async(userId: string | null) => {
+ // make post request to markcompletion
+ try {
+ const response = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/markcompletion`, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ userId,
+ }),
+ });
+
+ if (response.ok) {
+ // show alert and reload the page
+ window.alert("Success!");
+ window.location.reload();
+ } else {
+ // Handle error
+ window.alert("Error!");
+ }
+ } catch (error) {
+ console.error("Error marking completion:", error);
+ }
+ };
+
+const onCreateMatchButton = async(userId: string | null) => {
+ try {
+ const response = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/creatematch`, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ userId,
+ }),
+ });
+
+ if (response.ok) {
+ window.location.reload();
+ } else {
+ // show alert no match found
+ window.alert("No match found");
+ }
+ } catch (error) {
+ console.error("Error creating match:", error);
+ }
+ };
+
+
+const handleVerificationSubmit = async (matchId, userId, token) => {
+ const verifiedURLs = JSON.parse(localStorage.getItem("valid_urls")) || [];
+ const invalidURLs = JSON.parse(localStorage.getItem("invalid_urls")) || [];
+
+ try {
+ const response = await fetch(
+ `${process.env.NEXT_PUBLIC_API_URL}/updatematch`,
+ {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ Authorization: `Bearer ${token}`,
+ },
+ body: JSON.stringify({
+ matchId,
+ userId,
+ verifiedURLs,
+ }),
+ }
+ );
+
+ if (response.ok) {
+ // Handle a successful response, e.g., show a success message
+ } else {
+ // Handle the error response, e.g., show an error message
+ }
+ } catch (error) {
+ console.error("Error submitting verification:", error);
+ }
+};
+
+const handleCheckboxChange = (event, url, storageKey) => {
+ const isChecked = event.target.checked;
+
+ // Get the current state from local storage or initialize an empty array
+ let storedData = JSON.parse(localStorage.getItem(storageKey)) || [];
+
+ // Check if the URL is in the other list (valid_urls or invalid_urls) and remove it
+ const otherStorageKey = storageKey === "valid_urls" ? "invalid_urls" : "valid_urls";
+ storedData = storedData.filter((id) => !isInLocalStorage(id, otherStorageKey));
+
+ if (isChecked) {
+ // Add the URL ID to the array if checked
+ storedData.push(url);
+ } else {
+ // Remove the URL ID from the array if unchecked
+ const index = storedData.indexOf(url);
+ if (index !== -1) {
+ storedData.splice(index, 1);
+ }
+ }
+
+ // Save the updated state to local storage
+ localStorage.setItem(storageKey, JSON.stringify(storedData));
+};
+
+const isInLocalStorage = (urlId, storageKey) => {
+ const storedData = JSON.parse(localStorage.getItem(storageKey)) || [];
+ return storedData.includes(urlId);
+};
+
+const populateUrls = (urls, includeInputValue) => {
+ return urls.map((url, index) => (
+
+ Title: {url.title} | URL: {url.url}
+ {includeInputValue && (
+
+ handleCheckboxChange(e, url.url, "valid_urls")} />
+
+ handleCheckboxChange(e, url.url, "invalid_urls")} />
+
+
+ )}
+
+ ));
+};
+
+
+const MatchDetails = ({ matchData, userId, token, onVerificationSubmit }: {matchData: MatchDocument, userId : string | null, token: string | null, onVerificationSubmit: (matchId: string, userId : string | null , token: string | null) => void }) => {
+ let urlsToValidate = null;
+ let loggedInUserUrls = null;
+ if(userId != matchData.user1.id) {
+ urlsToValidate = populateUrls(matchData.user1.urls, true);
+ loggedInUserUrls = populateUrls(matchData.user2.urls, false);
+ }
+ else {
+ urlsToValidate = populateUrls(matchData.user2.urls, true);
+ loggedInUserUrls = populateUrls(matchData.user1.urls, false);
+ }
+
+ return (
+
+
Match Details
+
+ -
+ Status: {matchData.status}
+
+ -
+ Created At:{" "}
+ {new Date(matchData.createdAt).toLocaleString()}
+
+ -
+ Updated At:{" "}
+ {new Date(matchData.updatedAt).toLocaleString()}
+
+ -
+ Your urls :
+
+
+ -
+ URLs you have to validate :
+
+
+
+
+
+ );
+};
+
+const MatchResult = ({ matchData, onAgree, onClose }) => {
+ return (
+
+
Match Results
+
+ -
+ User 1 ID: {matchData.user1.id}
+
+ -
+
+ {matchData.user1.urls.map((url, index) => (
+ -
+ Title: {url.title} | URL:{" "}
+ {url.url} | Verified: {url.verified ? "Yes" : "No"}
+
+ ))}
+
+
+ -
+ User 1 Concur: {matchData.user1.concur}
+
+ -
+ User 1 Completed: {matchData.user1.completed ? 'Yes' : 'No'}
+
+ -
+ User 2 ID: {matchData.user2.id}
+
+ -
+
+ {matchData.user2.urls.map((url, index) => (
+ -
+ Title: {url.title} | URL:{" "}
+ {url.url} | Verified: {url.verified ? "Yes" : "No"}
+
+ ))}
+
+
+ -
+ User 2 Concur: {matchData.user2.concur}
+
+ -
+ User 2 Completed: {matchData.user2.completed ? 'Yes' : 'No'}
+
+ {/* Render other properties as needed */}
+
+
+
+
+
+
+ );
+};
+
+const handleAgree = async () => {
+ try {
+ const response = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/concur`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({ agree: true }),
+ });
+
+ if (response.ok) {
+ // Handle success, e.g., show a success message
+ console.log('Agree successful');
+ } else {
+ // Handle the error response, e.g., show an error message
+ console.error('Agree failed');
+ }
+ } catch (error) {
+ console.error('Error agreeing:', error);
+ }
+};
+
+const handleClose = async () => {
+ try {
+ const response = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/concur`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({ agree: false }),
+ });
+
+ if (response.ok) {
+ // Handle success, e.g., show a success message
+ console.log('Close successful');
+ } else {
+ // Handle the error response, e.g., show an error message
+ console.error('Close failed');
+ }
+ } catch (error) {
+ console.error('Error closing:', error);
+ }
+};
+
+
+
+const Match = () => {
+ const router = useRouter()
+ const [match, setMatch] = useState(null)
+ const [user1, setUser1] = useState(null);
+ const [user2, setUser2] = useState(null);
+ const { address } = useEncryptedStore()
+ const { userId, token } = usePasswordStore()
+
+ useEffect(() => {
+ ;(async () => {
+ try {
+ const { match } = await fetch(
+ `${process.env.NEXT_PUBLIC_API_URL}/getmatch/${userId}`,
+ {
+ method: "GET",
+ headers: {
+ "Content-Type": "application/json",
+ Authorization: `Bearer ${token}`,
+ },
+ }
+ ).then((res) => res.json())
+ if (match) {
+ console.log("match : ", match);
+ if (match.user1.id === userId) {
+ console.log("inside match.user1.id : ", userId);
+ setUser1(match.user1);
+ setUser2(match.user2);
+ } else {
+ setUser1(match.user2);
+ setUser2(match.user1);
+ }
+ setMatch(match); // Set the match state
+ }
+ } catch (error) {
+ console.log(error);
+ }
+ })()
+ }, [address, userId, token, router])
+
+
+
+ return (
+
+
+ My matches
+
+
+
+ your match
+ {match ? (
+
+ ) : (
+
+ )}
+
+
+ are you done validating?
+ Mark as complete
+ {match &&
+
+ }
+
+
+ {match && }
+
+
+
+
+ )
+}
+
+const Row = ({ children }: { children: ReactNode }) => {
+ return (
+
+ {children}
+
+ )
+}
+
+export default Match
diff --git a/config/site.ts b/config/site.ts
index 5e80ac6..c913f7f 100644
--- a/config/site.ts
+++ b/config/site.ts
@@ -17,6 +17,10 @@ export const siteConfig = {
title: "Add tag",
href: "/submit-tag",
},
+ {
+ title: "Match",
+ href: "/match",
+ },
{
title: "Me",
href: "/me",
diff --git a/types/index.ts b/types/index.ts
index 0ff6d8b..c2654ff 100644
--- a/types/index.ts
+++ b/types/index.ts
@@ -23,3 +23,21 @@ export interface NavItem {
disabled?: boolean
external?: boolean
}
+
+export interface MatchDocument {
+ _id: string,
+ user1: {
+ id: string,
+ urls: Array,
+ completed: boolean,
+},
+user2: {
+ id: string,
+ urls: Array,
+ completed: boolean,
+},
+status: string;
+threshold: number; // threshold is max limit of urls allowed to be validated, depnds on key in MatchGroup
+createdAt: Date;
+updatedAt: Date;
+}
\ No newline at end of file