diff --git a/public/images/social-media/pypi-svg.svg b/public/images/social-media/pypi-svg.svg
new file mode 100644
index 00000000..884887dc
--- /dev/null
+++ b/public/images/social-media/pypi-svg.svg
@@ -0,0 +1,78 @@
+
+
diff --git a/src/app/packages/page.tsx b/src/app/packages/page.tsx
index 8a38f3f1..55f4a710 100644
--- a/src/app/packages/page.tsx
+++ b/src/app/packages/page.tsx
@@ -4,6 +4,7 @@ import React, { useEffect, useState, Fragment } from "react";
import statsList from "../projects/assets/stats.json";
import Link from "next/link";
import npm from "../../../public/images/social-media/npm-svgrepo-com.svg";
+import pypi from "../../../public/images/social-media/pypi-svg.svg";
import filter from "../../../public/images/social-media/bx-filter-alt.svg";
import download from "../../../public/images/bxs-download.svg";
import github from "../../../public/images/bxl-github.svg";
@@ -11,31 +12,32 @@ import Image from "next/image";
import { Dialog, Transition } from "@headlessui/react";
import moment from "moment";
-type stats = {
- downloads: download[];
+type Package = {
+ name: string;
+ type: "npm" | "pypi";
+ day?: number;
+ week?: number;
+ year?: number;
+ total?: number;
+ last_day?: number;
+ last_week?: number;
+ last_month?: number;
};
-type download = {
- downloads: number;
- day: string;
+type NpmStats = {
+ downloads: { downloads: number; day: string }[];
};
const Stats = () => {
const [startDate, setStartDate] = useState(moment().format("YYYY-MM-DD"));
const [endDate, setEndDate] = useState(moment().format("YYYY-MM-DD"));
- const [loading, setLoading] = useState(false); // State to track loading status
+ const [loading, setLoading] = useState(false);
const [count, setCount] = useState(0);
const [selectedRange, setSelectedRange] = useState(false);
const [isOpen, setIsOpen] = useState(false);
- const [npmPackage, setNpmPackage] = useState({
- name: "fmdapi-node-weaver",
- day: 0,
- week: 3,
- year: 70,
- total: 70,
- });
+ const [selectedPackage, setSelectedPackage] = useState(null);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
- const [packages, setPackages] = useState(statsList);
+ const [packages, setPackages] = useState(statsList as Package[]);
function closeModal() {
setIsOpen(false);
@@ -43,18 +45,28 @@ const Stats = () => {
}
useEffect(() => {
- if (npmPackage) {
- setCount(npmPackage.total); //update total count when npmPackage is updated
+ if (selectedPackage) {
+ setCount(
+ selectedPackage?.type === "npm"
+ ? selectedPackage.total || 0
+ : selectedPackage?.last_month || 0
+ ); //update total count when npmPackage is updated
}
- }, [npmPackage]);
+ }, [selectedPackage]);
function openModal() {
setIsOpen(true);
- setCount(npmPackage.total);
+ setCount(
+ selectedPackage?.type === "npm"
+ ? selectedPackage.total || 0
+ : selectedPackage?.last_month || 0
+ );
}
- // Function to fetch download statistics for a given package and period
- async function fetchDownloadStats(packageName: string, period: string) {
+ async function fetchNpmStats(
+ packageName: string,
+ period: string
+ ): Promise {
setLoading(true);
const url = `https://api.npmjs.org/downloads/range/${period}/@mindfiredigital/${packageName}`;
const response = await fetch(url);
@@ -64,6 +76,7 @@ const Stats = () => {
`Failed to fetch download stats for ${packageName} (${period}): ${response.statusText}`
);
setLoading(false);
+ throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
@@ -71,67 +84,37 @@ const Stats = () => {
return data;
}
- function calculateDownloads(stats: stats): number {
+ function calculateDownloads(stats: NpmStats): number {
if (!stats || !stats.downloads) {
- return 0; // Return 0 if stats or stats.downloads is undefined
+ return 0;
}
return stats.downloads.reduce(
- (accumulator, download) => accumulator + download.downloads,
+ (acc, download) => acc + download.downloads,
0
);
}
- // Function to fetch and process statistics for a package and period
- async function getStats(packageName: string, period: string) {
- try {
- // Fetch download statistics
- const stats = await fetchDownloadStats(packageName, period);
+ function handleChange(event: React.ChangeEvent) {
+ if (!selectedPackage) return;
- // Check if stats exist
- if (!stats || !stats.package) return 0;
+ const range = getDateRange(event.target.value);
- // Calculate average downloads
- return stats;
- } catch (error) {
- // Log and handle errors
- console.error(`${packageName} not present`);
- return 0;
- }
- }
- function handleChange(
- event: React.ChangeEvent,
- _package: {
- name: string;
- day: number;
- week: number;
- year: number;
- total: number;
- }
- ) {
- const range: { start: string; end: string } = getDateRange(
- event.target.value as string
- );
-
- getStats(_package.name, `${range?.start}:${range?.end}`).then((res) => {
- setLoading(true);
- const count = calculateDownloads(res);
- // console.log(count);
-
- packages.map((npmPackage) => {
- if (npmPackage.name === _package.name) {
+ if (selectedPackage.type === "npm") {
+ fetchNpmStats(selectedPackage.name, `${range.start}:${range.end}`).then(
+ (res) => {
+ setLoading(true);
+ const count = calculateDownloads(res);
setCount(count);
setLoading(false);
}
- return npmPackage;
- });
- });
+ );
+ } else if (selectedPackage.type === "pypi") {
+ setCount(Number(event.target.value) || 0);
+ }
}
function formatDate(date: Date) {
- const year = date.getFullYear();
- const month = String(date.getMonth() + 1).padStart(2, "0");
- const day = String(date.getDate()).padStart(2, "0");
- return `${year}-${month}-${day}`;
+ return date.toISOString().split("T")[0];
}
function getDateRange(range: string) {
@@ -141,13 +124,12 @@ const Stats = () => {
const currentDay = currentDate.getDate();
switch (range.toLowerCase()) {
- case "today": {
+ case "today":
setSelectedRange(false);
return {
start: formatDate(new Date(currentYear, currentMonth, currentDay)),
end: formatDate(new Date(currentYear, currentMonth, currentDay)),
};
- }
case "yesterday": {
setSelectedRange(false);
const yesterdayDate = new Date(
@@ -169,9 +151,17 @@ const Stats = () => {
end: formatDate(lastMonthEndDate),
};
}
+ case "this month": {
+ setSelectedRange(false);
+ const thisMonthStartDate = new Date(currentYear, currentMonth, 1);
+ return {
+ start: formatDate(thisMonthStartDate),
+ end: formatDate(currentDate),
+ };
+ }
case "last quarter": {
setSelectedRange(false);
- const quarterStartMonth = Math.floor(currentMonth / 3) * 3; // Get the start month of the current quarter
+ const quarterStartMonth = Math.floor(currentMonth / 3) * 3;
const lastQuarterStartDate = new Date(
currentYear,
quarterStartMonth - 3,
@@ -191,14 +181,6 @@ const Stats = () => {
end: formatDate(currentDate),
};
}
- case "this month": {
- setSelectedRange(false);
- const thisMonthStartDate = new Date(currentYear, currentMonth, 1);
- return {
- start: formatDate(thisMonthStartDate),
- end: formatDate(currentDate),
- };
- }
case "custom": {
setSelectedRange(true);
setCount(0);
@@ -207,26 +189,31 @@ const Stats = () => {
end: formatDate(new Date(currentYear, currentMonth, currentDay)),
};
}
- default:
+ default: {
setSelectedRange(false);
return {
start: "1000-01-01",
end: "3000-01-01",
};
+ }
}
}
const generateChart = async () => {
- const stats = await fetchDownloadStats(
- npmPackage.name,
- `${startDate}:${endDate}`
- );
- setCount(calculateDownloads(stats));
+ if (selectedPackage?.type === "npm") {
+ const stats = await fetchNpmStats(
+ selectedPackage.name,
+ `${startDate}:${endDate}`
+ );
+ setCount(calculateDownloads(stats));
+ }
};
useEffect(() => {
- generateChart();
- }, [startDate, endDate]);
+ if (selectedRange && selectedPackage?.type === "npm") {
+ generateChart();
+ }
+ }, [startDate, endDate, selectedRange, selectedPackage]);
return (
@@ -238,16 +225,16 @@ const Stats = () => {
Elevate your projects with Mindfire's game-changing open-source
packages.
-
- {packages.map((package_list) => (
+
+ {packages.map((package_item) => (
- {package_list.name.replaceAll("-", " ")}
+ {package_item.name.replaceAll("-", " ")}
@@ -255,7 +242,7 @@ const Stats = () => {
@@ -298,15 +287,19 @@ const Stats = () => {
@@ -314,7 +307,7 @@ const Stats = () => {
@@ -322,7 +315,7 @@ const Stats = () => {
src={github}
height={30}
width={30}
- alt='npm_img'
+ alt='github_img'
loading='lazy'
quality={75}
/>
@@ -385,31 +378,45 @@ const Stats = () => {
as='h1'
className='text-lg font-large leading-6 text-gray-900 capitalize text-center mb-4 font-extrabold'
>
- {npmPackage.name.replaceAll("-", " ")}
+ {selectedPackage?.name.replaceAll("-", " ")}
-
+
Select
-
+ {selectedPackage?.type === "npm" ? (
+
+ ) : (
+
+ )}
- {selectedRange === true ? (
-
+ {selectedRange && selectedPackage?.type === "npm" ? (
+
-
-
-
-
-
-
- {loading ? (
- // Render loading indicator while count is being fetched
-
-
-
- ) : (
- // Render count when it is available
-
- {count}
-
- )}
+
+ ) : null}
+
+
+
+
+
+
+ {loading ? (
+
+
-
-
+ ) : (
+
+ {count}
+
+ )}
-
-
- ) : (
-
-
-
-
-
-
- {loading ? (
- // Render loading indicator while count is being fetched
-
-
-
- ) : (
- // Render count when it is available
-
- {count}
-
- )}
-
-
-
+
- )}
+
diff --git a/src/app/projects/assets/stats.json b/src/app/projects/assets/stats.json
index e03009ca..d02b9782 100644
--- a/src/app/projects/assets/stats.json
+++ b/src/app/projects/assets/stats.json
@@ -19,5 +19,12 @@
"week": 7,
"year": 1063,
"total": 1063
+ },
+ {
+ "name": "neo-pusher",
+ "type": "pypi",
+ "last_day": 1,
+ "last_week": 70,
+ "last_month": 1000
}
]
diff --git a/updateProject.mjs b/updateProject.mjs
index 40569664..78695a72 100644
--- a/updateProject.mjs
+++ b/updateProject.mjs
@@ -221,6 +221,39 @@ async function fetchDownloadStats(packageName, period) {
return data;
}
+// Function to fetch download statistics for a PyPI package
+async function fetchPypiDownloadStats(packageName) {
+ const url = `https://pypistats.org/api/packages/${packageName}/recent`;
+ const response = await fetch(url);
+
+ if (!response.ok) {
+ console.log(
+ `Failed to fetch download stats for ${packageName}: ${response.statusText}`
+ );
+ return null;
+ }
+
+ const data = await response.json();
+ return data.data;
+}
+
+// Function to fetch and process statistics for a PyPI package
+async function getPypiStats(packageName) {
+ try {
+ const stats = await fetchPypiDownloadStats(packageName);
+ if (!stats) return null;
+
+ return {
+ last_day: stats.last_day,
+ last_week: stats.last_week,
+ last_month: stats.last_month,
+ };
+ } catch (error) {
+ console.error(`Error fetching PyPI stats for ${packageName}:`, error);
+ return null;
+ }
+}
+
// Function to calculate average downloads from the statistics
function calculateAverageDownloads(stats) {
return stats.downloads.reduce(
@@ -253,29 +286,40 @@ async function getAllStats(npmPackages) {
// Fetch stats for each package and period
await Promise.all(
- npmPackages.map(async (packageName) => {
+ npmPackages.map(async (packageData) => {
try {
- // Fetch stats for different periods
- const [dayStats, weekStats, yearStats, totalStats] = await Promise.all([
- getStats(packageName, "last-day"),
- getStats(packageName, "last-week"),
- getStats(packageName, "last-year"),
- getStats(packageName, "1000-01-01:3000-01-01"),
- ]);
-
- // If any stats exist, add to the map
- if (dayStats !== 0 || weekStats !== 0 || yearStats !== 0) {
- statsMap.push({
- name: packageName,
+ let stats;
+ if (packageData.type === "npm") {
+ const [dayStats, weekStats, yearStats, totalStats] =
+ await Promise.all([
+ getStats(packageData.name, "last-day"),
+ getStats(packageData.name, "last-week"),
+ getStats(packageData.name, "last-year"),
+ getStats(packageData.name, "1000-01-01:3000-01-01"),
+ ]);
+
+ stats = {
+ name: packageData.name,
+ type: "npm",
day: dayStats,
week: weekStats,
year: yearStats,
total: totalStats,
- });
+ };
+ } else if (packageData.type === "pypi") {
+ const pypiStats = await getPypiStats(packageData.name);
+ stats = {
+ name: packageData.name,
+ type: "pypi",
+ ...pypiStats,
+ };
+ }
+
+ if (stats) {
+ statsMap.push(stats);
}
} catch (error) {
- // Log and handle errors
- console.error(`Error fetching stats for ${packageName}:`, error);
+ console.error(`Error fetching stats for ${packageData.name}:`, error);
}
})
);