diff --git a/plugins/plugin-site/package.json b/plugins/plugin-site/package.json
index 0cf9bca22..720c5d42e 100644
--- a/plugins/plugin-site/package.json
+++ b/plugins/plugin-site/package.json
@@ -71,6 +71,7 @@
"cheerio": "1.0.0",
"classnames": "2.5.1",
"copy-to-clipboard": "3.3.3",
+ "dayjs": "^1.11.13",
"find-package-json": "1.2.0",
"gatsby-plugin-canonical-urls": "5.14.0",
"gatsby-plugin-extract-schema": "0.2.2",
@@ -87,6 +88,7 @@
"github-syntax-light": "0.5.0",
"isomorphic-fetch": "3.0.0",
"jest-environment-jsdom": "29.7.0",
+ "papaparse": "^5.4.1",
"postcss-calc": "10.1.0",
"postcss-css-variables": "0.19.0",
"postcss-import": "16.1.0",
diff --git a/plugins/plugin-site/src/components/ThankAContributorNote.css b/plugins/plugin-site/src/components/ThankAContributorNote.css
new file mode 100644
index 000000000..16f67c0e7
--- /dev/null
+++ b/plugins/plugin-site/src/components/ThankAContributorNote.css
@@ -0,0 +1,49 @@
+.thank-you-note-container {
+ padding: 40px 16px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+.thank-you-note-contents {
+ padding: 24px;
+ border-radius: 40px;
+ max-width: fit-content;
+ height: fit-content;
+ background-color: rgb(218, 209, 198, 0.3);
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ @media (max-width: 768px) {
+ padding: 16px;
+ }
+}
+
+.thank-you-note-card {
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+ align-items: center;
+ gap: 24px;
+ @media (max-width: 768px) {
+ gap: 8px;
+ }
+}
+
+.thank-you-note-img-container {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+.thank-you-note-img {
+ margin-top: auto;
+ margin-bottom: auto;
+}
+
+.thank-you-note-text {
+ font-size: medium;
+ @media (max-width: 768px) {
+ font-size: small;
+ }
+}
diff --git a/plugins/plugin-site/src/components/ThankAContributorNote.jsx b/plugins/plugin-site/src/components/ThankAContributorNote.jsx
new file mode 100644
index 000000000..beae8719d
--- /dev/null
+++ b/plugins/plugin-site/src/components/ThankAContributorNote.jsx
@@ -0,0 +1,151 @@
+/* eslint-disable react/jsx-one-expression-per-line */
+
+import React, {useEffect, useState} from 'react';
+import axios from 'axios';
+import dayjs from 'dayjs';
+import Papa from 'papaparse';
+import {useMediaQuery} from '../hooks/useMediaQuery';
+import './ThankAContributorNote.css';
+
+function ThankAContributorNote() {
+ const isMobile = useMediaQuery('man-width: 768px)');
+ const isDesktop = useMediaQuery('(min-width: 1024px)');
+
+ const [thankYou, setThankYou] = useState({});
+
+ const dataUrl = 'https://raw.githubusercontent.com/jenkins-infra/jenkins-contribution-stats/main/data/honored_contributor.csv';
+
+ useEffect(() => {
+ axios
+ .get(
+ dataUrl,
+ {responseType: 'text'}
+ )
+ .then((response) => {
+ if (Papa.parse(response.data)?.data[1]) {
+ const data = Papa.parse(response.data)?.data[1];
+ setThankYou(Papa.parse(response.data)?.data[1] ? {
+ 'RUN_DATE': data[0],
+ 'MONTH': data[1],
+ 'GH_HANDLE': data[2],
+ 'FULL_NAME': data[3],
+ 'COMPANY': data[4],
+ 'GH_HANDLE_URL': data[5],
+ 'GH_HANDLE_AVATAR': data[6],
+ 'NBR_PRS': data[7],
+ 'REPOSITORIES': data[8],
+ }: {});
+ }
+ });
+
+ const interval = setInterval(() => {
+ axios
+ .get(
+ dataUrl,
+ {responseType: 'text'}
+ )
+ .then((response) => {
+ if (Papa.parse(response.data)?.data[1]) {
+ const data = Papa.parse(response.data)?.data[1];
+ setThankYou(Papa.parse(response.data)?.data[1] ? {
+ 'RUN_DATE': data[0],
+ 'MONTH': data[1],
+ 'GH_HANDLE': data[2],
+ 'FULL_NAME': data[3],
+ 'COMPANY': data[4],
+ 'GH_HANDLE_URL': data[5],
+ 'GH_HANDLE_AVATAR': data[6],
+ 'NBR_PRS': data[7],
+ 'REPOSITORIES': data[8],
+ }: {});
+ }
+ });
+ }, 3600000);
+
+ return () => clearInterval(interval);
+ }, []);
+
+
+ return (
+
+
+
+
+
+
+
+ Thank you{' '}
+ {Object.values(thankYou)?.filter((item) => item?.trim() === '')
+ .length === 0 && (
{thankYou['FULL_NAME']?.replace(/['"]+/g, '').trim() ? thankYou['FULL_NAME']?.replace(/['"]+/g, '') : thankYou['GH_HANDLE']?.replace(/['"]+/g, '')}
+ )}
+
for making {thankYou['NBR_PRS']?.replace(
+ /['"]+/g,
+ ''
+ )} pull{' '}
+ {parseInt(thankYou['NBR_PRS']?.replace(/['"]+/g, '')) >= 2
+ ? 'requests'
+ : 'request'}
+
to{' '}
+ {thankYou['REPOSITORIES']?.split(' ')?.length >= 4
+ ? `${parseInt(thankYou['REPOSITORIES']?.split(' ')?.length)} Jenkins `
+ : 'the '}
+ {thankYou['REPOSITORIES']?.split(' ').length < 4 &&
+ thankYou['REPOSITORIES']
+ ?.replace(/['"]+/g, '')
+ .split(/\s+/)
+ .filter(Boolean)
+ .map((repo, idx) => (
+ <>
+ {thankYou['REPOSITORIES']?.split(' ').length >
+ 2 &&
+ idx ===
+ thankYou['REPOSITORIES']?.split(' ')
+ .length -
+ 2 &&
+ ' and '
+ }
+
+ {repo?.split('/')[1]}
+
+ {thankYou['REPOSITORIES']?.split(' ').length >=
+ 2 && idx < thankYou['REPOSITORIES']?.split(' ').length - 2 ? (<>,>) : (<>{' '}>)}
+ >
+ ))}{' '}
+ {thankYou['REPOSITORIES']?.split(' ').length > 2
+ ? 'repos'
+ : 'repo'}{' '}
+ in{' '}
+ {dayjs(thankYou['MONTH']?.replace(/['"]+/g, '')).format(
+ 'MMMM YYYY'
+ )}
+ !
+
+
+
+
+ );
+}
+
+export default ThankAContributorNote;
diff --git a/plugins/plugin-site/src/hooks/useMediaQuery.js b/plugins/plugin-site/src/hooks/useMediaQuery.js
new file mode 100644
index 000000000..f0ce4c2f0
--- /dev/null
+++ b/plugins/plugin-site/src/hooks/useMediaQuery.js
@@ -0,0 +1,19 @@
+import {useEffect, useState} from 'react';
+
+export function useMediaQuery(query) {
+ const [matches, setMatches] = useState(false);
+
+ useEffect(() => {
+ const matchQueryList = window.matchMedia(query);
+ function handleChange(e) {
+ setMatches(e.matches);
+ }
+ matchQueryList.addEventListener('change', handleChange);
+
+ return () => {
+ matchQueryList.removeEventListener('change', handleChange);
+ };
+ }, [query]);
+
+ return matches;
+}
diff --git a/plugins/plugin-site/src/templates/index.jsx b/plugins/plugin-site/src/templates/index.jsx
index 5b123cf3b..6e0ad3c85 100644
--- a/plugins/plugin-site/src/templates/index.jsx
+++ b/plugins/plugin-site/src/templates/index.jsx
@@ -9,6 +9,7 @@ import SearchBox from '../components/SearchBox';
import JenkinsVoltron from '../components/JenkinsVoltron';
import './index.css';
+import ThankAContributorNote from '../components/ThankAContributorNote';
function IndexPage() {
@@ -36,6 +37,7 @@ function IndexPage() {
+
);
}
diff --git a/yarn.lock b/yarn.lock
index 1eeb6edee..1413c729f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4205,6 +4205,7 @@ __metadata:
cheerio: "npm:1.0.0"
classnames: "npm:2.5.1"
copy-to-clipboard: "npm:3.3.3"
+ dayjs: "npm:^1.11.13"
dotenv: "npm:16.4.7"
eslint: "npm:9.17.0"
eslint-config-standard: "npm:17.1.0"
@@ -4242,6 +4243,7 @@ __metadata:
jest-environment-jsdom: "npm:29.7.0"
jest-junit: "npm:16.0.0"
lint-staged: "npm:15.3.0"
+ papaparse: "npm:^5.4.1"
postcss-calc: "npm:10.1.0"
postcss-css-variables: "npm:0.19.0"
postcss-import: "npm:16.1.0"
@@ -9299,6 +9301,13 @@ __metadata:
languageName: node
linkType: hard
+"dayjs@npm:^1.11.13":
+ version: 1.11.13
+ resolution: "dayjs@npm:1.11.13"
+ checksum: 10c0/a3caf6ac8363c7dade9d1ee797848ddcf25c1ace68d9fe8678ecf8ba0675825430de5d793672ec87b24a69bf04a1544b176547b2539982275d5542a7955f35b7
+ languageName: node
+ linkType: hard
+
"debug@npm:2, debug@npm:2.6.9, debug@npm:^2.6.0":
version: 2.6.9
resolution: "debug@npm:2.6.9"
@@ -17624,6 +17633,13 @@ __metadata:
languageName: node
linkType: hard
+"papaparse@npm:^5.4.1":
+ version: 5.4.1
+ resolution: "papaparse@npm:5.4.1"
+ checksum: 10c0/201f37c4813453fed5bfb4c01816696b099d2db9ff1e8fb610acc4771fdde91d2a22b6094721edb0fedb21ca3c46f04263f68be4beb3e35b8c72278f0cedc7b7
+ languageName: node
+ linkType: hard
+
"param-case@npm:^3.0.4":
version: 3.0.4
resolution: "param-case@npm:3.0.4"