From 58f254d1c8f34366e39f21a7394a9ac5131bc7ba Mon Sep 17 00:00:00 2001 From: Roni Sarkar Date: Sat, 22 Feb 2025 18:55:29 +0530 Subject: [PATCH] search and http code done --- CODE_OF_CONDUCT.md | 4 +- package-lock.json | 71 +++++++++- package.json | 5 + src/app/http_codes/page.tsx | 8 ++ src/app/layout.tsx | 4 + src/app/page.tsx | 7 +- src/components/ai_model/ai_model.ts | 37 +++++ src/components/hero/hero.component.tsx | 48 +++++-- .../hero/next.generation.view.component.tsx | 2 +- src/components/http_codes/http_code_view.tsx | 37 +++++ src/components/issues/issue.helper.ts | 24 ++++ .../issues/issue_list.component.tsx | 129 ++++++++++++++++++ src/components/nav_bar.tsx | 11 ++ .../repository/repo.list.component.view.tsx | 10 +- .../repository/repository.component.tsx | 51 ++++++- .../view/repository-view.component.tsx | 2 +- src/http_status_code.json | 110 +++++++++++++++ src/model/issue.model.ts | 14 ++ src/prompt/prompt.ts | 33 +++++ 19 files changed, 579 insertions(+), 28 deletions(-) create mode 100644 src/app/http_codes/page.tsx create mode 100644 src/components/ai_model/ai_model.ts create mode 100644 src/components/http_codes/http_code_view.tsx create mode 100644 src/components/issues/issue.helper.ts create mode 100644 src/components/issues/issue_list.component.tsx create mode 100644 src/components/nav_bar.tsx create mode 100644 src/http_status_code.json create mode 100644 src/model/issue.model.ts create mode 100644 src/prompt/prompt.ts diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index faf147e..8adc454 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -60,7 +60,7 @@ representative at an online or offline event. Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at -subha9.5roy350@gmail.com +ronichandrasarkar@gmail.com All complaints will be reviewed and investigated promptly and fairly. All community leaders are obligated to respect the privacy and security of the @@ -115,7 +115,7 @@ the community. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], -version 2.0, available at +version 1.0, available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. Community Impact Guidelines were inspired by [Mozilla's code of conduct diff --git a/package-lock.json b/package-lock.json index d79b4e0..29244ab 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,11 @@ "name": "first-issue", "version": "0.1.0", "dependencies": { + "@fortawesome/fontawesome-svg-core": "^6.7.2", + "@fortawesome/free-brands-svg-icons": "^6.7.2", + "@fortawesome/free-solid-svg-icons": "^6.7.2", + "@fortawesome/react-fontawesome": "^0.2.2", + "@google/generative-ai": "^0.21.0", "date-fns": "^3.6.0", "next": "14.2.3", "react": "^18", @@ -104,6 +109,67 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@fortawesome/fontawesome-common-types": { + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.7.2.tgz", + "integrity": "sha512-Zs+YeHUC5fkt7Mg1l6XTniei3k4bwG/yo3iFUtZWd/pMx9g3fdvkSK9E0FOC+++phXOka78uJcYb8JaFkW52Xg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/fontawesome-svg-core": { + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.7.2.tgz", + "integrity": "sha512-yxtOBWDrdi5DD5o1pmVdq3WMCvnobT0LU6R8RyyVXPvFRd2o79/0NCuQoCjNTeZz9EzA9xS3JxNWfv54RIHFEA==", + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.7.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-brands-svg-icons": { + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.7.2.tgz", + "integrity": "sha512-zu0evbcRTgjKfrr77/2XX+bU+kuGfjm0LbajJHVIgBWNIDzrhpRxiCPNT8DW5AdmSsq7Mcf9D1bH0aSeSUSM+Q==", + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.7.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-solid-svg-icons": { + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.7.2.tgz", + "integrity": "sha512-GsBrnOzU8uj0LECDfD5zomZJIjrPhIlWU82AHwa2s40FKH+kcxQaBvBo3Z4TxyZHIyX8XTDxsyA33/Vx9eFuQA==", + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.7.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/react-fontawesome": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.2.tgz", + "integrity": "sha512-EnkrprPNqI6SXJl//m29hpaNzOp1bruISWaOiRtkMi/xSvHJlzc2j2JAYS7egxt/EbjSNV/k6Xy0AQI6vB2+1g==", + "dependencies": { + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "@fortawesome/fontawesome-svg-core": "~1 || ~6", + "react": ">=16.3" + } + }, + "node_modules/@google/generative-ai": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/@google/generative-ai/-/generative-ai-0.21.0.tgz", + "integrity": "sha512-7XhUbtnlkSEZK15kN3t+tzIMxsbKm/dSkKBFalj+20NvPKe1kBY7mR2P7vuijEn+f06z5+A8bVGKO0v39cr6Wg==", + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", @@ -3208,7 +3274,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -3670,7 +3735,6 @@ "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -3732,8 +3796,7 @@ "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "node_modules/read-cache": { "version": "1.0.0", diff --git a/package.json b/package.json index 1f40727..4791bdd 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,11 @@ "lint": "next lint" }, "dependencies": { + "@fortawesome/fontawesome-svg-core": "^6.7.2", + "@fortawesome/free-brands-svg-icons": "^6.7.2", + "@fortawesome/free-solid-svg-icons": "^6.7.2", + "@fortawesome/react-fontawesome": "^0.2.2", + "@google/generative-ai": "^0.21.0", "date-fns": "^3.6.0", "next": "14.2.3", "react": "^18", diff --git a/src/app/http_codes/page.tsx b/src/app/http_codes/page.tsx new file mode 100644 index 0000000..983b586 --- /dev/null +++ b/src/app/http_codes/page.tsx @@ -0,0 +1,8 @@ +import HttpCodeViewComponent from "@/components/http_codes/http_code_view"; +import React from "react"; + +const HttpCodePage = () => { + return ; +}; + +export default HttpCodePage; diff --git a/src/app/layout.tsx b/src/app/layout.tsx index b3470a9..cd791cf 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -36,6 +36,10 @@ export default function RootLayout({ gtag('js', new Date()); gtag('config', '${process.env.NEXT_PUBLIC_GA4_ID}');`} + {children} diff --git a/src/app/page.tsx b/src/app/page.tsx index 54a9d45..17fa47b 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,13 +1,16 @@ +"use client"; import HeaderComponent from "@/components/header/header.component"; import HeroComponent from "@/components/hero/hero.component"; import RepositoryComponent from "@/components/repository/repository.component"; +import { useState } from "react"; export default function Home() { + const [generateText, setGenerateText] = useState(""); return (
{/* */} - - + +
); } diff --git a/src/components/ai_model/ai_model.ts b/src/components/ai_model/ai_model.ts new file mode 100644 index 0000000..f32f8a0 --- /dev/null +++ b/src/components/ai_model/ai_model.ts @@ -0,0 +1,37 @@ +import { + GoogleGenerativeAI, + HarmCategory, + HarmBlockThreshold, +} from "@google/generative-ai"; + +const apiKey = process.env.NEXT_PUBLIC_GEMINI_API_KEY; +const genAI = new GoogleGenerativeAI(apiKey as string); + +const model = genAI.getGenerativeModel({ + model: "gemini-1.5-pro", +}); + +const generationConfig = { + temperature: 1, + topP: 0.95, + topK: 64, + maxOutputTokens: 8192, + responseMimeType: "text/plain", +}; + +const safetySettings = [ + { + category: HarmCategory.HARM_CATEGORY_HARASSMENT, + threshold: HarmBlockThreshold.BLOCK_LOW_AND_ABOVE, + }, + { + category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, + threshold: HarmBlockThreshold.BLOCK_LOW_AND_ABOVE, + }, +]; + +export const aiGenerateModel = model.startChat({ + generationConfig, + safetySettings, + history: [], +}); diff --git a/src/components/hero/hero.component.tsx b/src/components/hero/hero.component.tsx index 753b6ce..470b9d7 100644 --- a/src/components/hero/hero.component.tsx +++ b/src/components/hero/hero.component.tsx @@ -1,7 +1,17 @@ -import React from "react"; +import React, { useState } from "react"; import NextGenerationViewComponent from "./next.generation.view.component"; -const HeroComponent = () => { +interface IHeroComponentProps { + setGenerateText: (text: string) => void; +} + +const HeroComponent: React.FC = ({ setGenerateText }) => { + const [searchText, setSearchText] = useState(""); + const generateText = () => { + if (searchText.trim() === "") return; + setGenerateText(searchText); + setTimeout(() => setSearchText(""), 0); + }; return (
@@ -10,23 +20,29 @@ const HeroComponent = () => {
); diff --git a/src/components/http_codes/http_code_view.tsx b/src/components/http_codes/http_code_view.tsx new file mode 100644 index 0000000..1e9ce77 --- /dev/null +++ b/src/components/http_codes/http_code_view.tsx @@ -0,0 +1,37 @@ +import React from "react"; +import httpCodes from "../../http_status_code.json"; +import Link from "next/link"; +import NavBar from "../nav_bar"; + +const HttpCodeViewComponent = () => { + return ( +
+ +
+ +
+ + +
+ {httpCodes.map((httpCode) => { + return ( +
+
+

{httpCode.code}

+ {httpCode.message} +
+ + {httpCode.status} + +
+ ); + })} +
+
+ ); +}; + +export default HttpCodeViewComponent; diff --git a/src/components/issues/issue.helper.ts b/src/components/issues/issue.helper.ts new file mode 100644 index 0000000..8d22e38 --- /dev/null +++ b/src/components/issues/issue.helper.ts @@ -0,0 +1,24 @@ +export const extractRepoName = (url: string): string => { + const parts = url.split("repos/")[1]; + return parts; +}; + +export const getRelativeTime = (isoString: string): string => { + const date = new Date(isoString); + const now = new Date(); + const diffInSeconds = Math.floor((now.getTime() - date.getTime()) / 1000); + if (diffInSeconds < 60) return `${diffInSeconds} sec ago`; + const diffInMinutes = Math.floor(diffInSeconds / 60); + if (diffInMinutes < 60) return `${diffInMinutes} min ago`; + const diffInHours = Math.floor(diffInMinutes / 60); + if (diffInHours < 24) + return `${diffInHours} hour${diffInHours > 1 ? "s" : ""} ago`; + const diffInDays = Math.floor(diffInHours / 24); + if (diffInDays < 30) + return `${diffInDays} day${diffInDays > 1 ? "s" : ""} ago`; + const diffInMonths = Math.floor(diffInDays / 30); + if (diffInMonths < 12) + return `${diffInMonths} month${diffInMonths > 1 ? "s" : ""} ago`; + const diffInYears = Math.floor(diffInMonths / 12); + return `${diffInYears} year${diffInYears > 1 ? "s" : ""} ago`; +}; diff --git a/src/components/issues/issue_list.component.tsx b/src/components/issues/issue_list.component.tsx new file mode 100644 index 0000000..d225c55 --- /dev/null +++ b/src/components/issues/issue_list.component.tsx @@ -0,0 +1,129 @@ +import { Issue } from "@/model/issue.model"; +import React, { useState } from "react"; +import { extractRepoName, getRelativeTime } from "./issue.helper"; +import Link from "next/link"; + +interface IRepositoryComponentProps { + issues: Issue[]; + issuesPerPage?: number; +} + +const IssueListComponent: React.FC = ({ + issues, + issuesPerPage = 4, +}) => { + const [currentPage, setCurrentPage] = useState(1); + const totalPages = Math.ceil(issues.length / issuesPerPage); + + const startIndex = (currentPage - 1) * issuesPerPage; + const displayedIssues = issues.slice(startIndex, startIndex + issuesPerPage); + + const handlePrev = () => { + if (currentPage > 1) { + setCurrentPage(currentPage - 1); + } + }; + + const handleNext = () => { + if (currentPage < totalPages) { + setCurrentPage(currentPage + 1); + } + }; + + return ( +
+ {issues.length > 0 ? ( + displayedIssues.map((issue) => ( +
+
+
+
+
+ +
+
+ +
+ {extractRepoName(issue.repository_url)} +
+ + +
{issue.title}
+ +
+ + #{issue.number} opened{" "} + {getRelativeTime(issue.created_at)} by{" "} + + {issue.user.username} + + + + {issue.labels.map((label, index) => ( + + {label.name} + + ))} +
+
+
+ + + {issue.comment} + +
+
+
+
+
+ )) + ) : ( +
+ No issues available. Try searching for something else. +
+ )} + +
+
+
+ + Showing {startIndex + 1} -{" "} + {Math.min(startIndex + issuesPerPage, issues.length)} of{" "} + {issues.length} issues + +
+
+ + + Page {currentPage} of {totalPages} + + +
+
+
+
+ ); +}; + +export default IssueListComponent; diff --git a/src/components/nav_bar.tsx b/src/components/nav_bar.tsx new file mode 100644 index 0000000..31d8105 --- /dev/null +++ b/src/components/nav_bar.tsx @@ -0,0 +1,11 @@ +import React from "react"; + +const NavBar = () => { + return ( +
+ Back +
+ ); +}; + +export default NavBar; diff --git a/src/components/repository/repo.list.component.view.tsx b/src/components/repository/repo.list.component.view.tsx index 8fb625a..2b493d8 100644 --- a/src/components/repository/repo.list.component.view.tsx +++ b/src/components/repository/repo.list.component.view.tsx @@ -4,9 +4,12 @@ import Image from "next/image"; import contributors from "../../contributors.json"; import { getGitHubUserAvatar } from "./repository.helper"; import RepositoryListComponent from "./repository-list.component"; +import Link from "next/link"; +import NavBar from "../nav_bar"; const RepoListViewComponent = () => { - const [selectedUser, setSelectedUser] = useState("ronisarkarexe.json"); + const [selectedUser, setSelectedUser] = + useState("ronisarkarexe.json"); const [avatarUrl, setAvatarUrl] = useState<{ name: string; url: string }[]>( [] ); @@ -27,6 +30,11 @@ const RepoListViewComponent = () => { return (
+ +
+ +
+
{avatarUrl.map((user, index) => (
{ - return ( -
- +interface IRepositoryComponentProps { + generateText: string; +} + +const RepositoryComponent: React.FC = ({ + generateText, +}) => { + const [issues, setIssues] = useState([]); + const [loading, setLoading] = useState(false); - + useEffect(() => { + if (!generateText) return; + setLoading(true); + getOpenSourceSuggestions(generateText) + .then((data) => { + const extractedIssues: Issue[] = data.map((issue: any) => ({ + comment: issue.comments, + number: issue.number, + created_at: issue.created_at, + labels: issue.labels.map((label: any) => ({ + name: label.name, + color: label.color, + })), + status: issue.state, + title: issue.title, + url: issue.html_url, + repository_url: issue.repository_url, + user: { + username: issue.user.login, + url: issue.user.html_url, + }, + })); + setIssues(extractedIssues); + }) + .catch((error) => console.error("Error fetching data:", error)) + .finally(() => setLoading(false)); + }, [generateText]); + + return ( +
+ {/* */} +