Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# GitHub API Configuration
# Used by the server-side /api/github-discussions endpoint.
# Prefer GITHUB_TOKEN for new setups. DOCUSAURUS_GIT_TOKEN is still supported as a legacy fallback.
# Create a Classic PAT at: https://github.com/settings/tokens
# Recommended scopes: public_repo, read:org, read:discussion
# GitHub API Configuration (Optional)
# To avoid rate limits, you can add a GitHub Personal Access Token
# Create one at: https://github.com/settings/tokens
# No special permissions needed for public repositories
GITHUB_TOKEN=your_github_token_here

# Legacy fallback for existing deployments. Optional if GITHUB_TOKEN is already set.
# GitHub token used by Docusaurus for dynamic features (discussions, stats, leaderboard)
# This must be set for the discussions section to fetch live data from GitHub
# Create a Classic PAT with read:discussion scope at https://github.com/settings/tokens
DOCUSAURUS_GIT_TOKEN=your_github_token_here

# Shopify Configuration (for Merch Store)
Expand Down
166 changes: 0 additions & 166 deletions api/github-discussions.js

This file was deleted.

14 changes: 10 additions & 4 deletions docusaurus.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const config: Config = {
projectName: "recode-website",

onBrokenLinks: "throw",
// onBrokenMarkdownLinks moved to markdown.hooks

// Google Analytics and Theme Scripts
scripts: [
Expand Down Expand Up @@ -264,11 +265,10 @@ const config: Config = {

markdown: {
mermaid: true,
hooks: {
onBrokenMarkdownLinks: "warn",
},
},

// Migrated legacy setting to markdown.hooks.onBrokenMarkdownLinks

themes: ["@docusaurus/theme-mermaid"],

plugins: [
Expand All @@ -284,16 +284,22 @@ const config: Config = {
],
],

// ✅ Add this customFields object to expose the token to the client-side
customFields: {
gitToken: process.env.DOCUSAURUS_GIT_TOKEN,
// Shopify credentials for merch store
SHOPIFY_STORE_DOMAIN:
process.env.SHOPIFY_STORE_DOMAIN || "junh9v-gw.myshopify.com",
SHOPIFY_STOREFRONT_ACCESS_TOKEN:
process.env.SHOPIFY_STOREFRONT_ACCESS_TOKEN,
process.env.SHOPIFY_STOREFRONT_ACCESS_TOKEN ||
"2503dfbf93132b42e627e7d53b3ba3e9",
// EmailJS credentials for Contact Us page (public values only)
EMAILJS_PUBLIC_KEY: process.env.EMAILJS_PUBLIC_KEY || "",
EMAILJS_SERVICE_ID: process.env.EMAILJS_SERVICE_ID || "",
EMAILJS_TEMPLATE_ID: process.env.EMAILJS_TEMPLATE_ID || "",
hooks: {
onBrokenMarkdownLinks: "warn",
},
},
};

Expand Down
3 changes: 0 additions & 3 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@ import tsPlugin from "@typescript-eslint/eslint-plugin";
import reactPlugin from "eslint-plugin-react";

export default [
{
ignores: ["node_modules/", "build/", ".docusaurus/", "static/", "dist/"],
},
{
files: ["**/*.{ts,tsx}"],
ignores: ["node_modules/", "build/", ".docusaurus/", "static/", "dist/"],
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
"write-translations": "docusaurus write-translations",
"write-heading-ids": "docusaurus write-heading-ids",
"typecheck": "tsc",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"lint": "eslint \"**/*.{js,jsx,ts,tsx}\"",
"lint:fix": "eslint \"**/*.{js,jsx,ts,tsx}\" --fix",
"format": "prettier --write \"**/*.{js,jsx,ts,tsx,json,css}\"",
"format:check": "prettier --check .",
"prepare": "husky"
Expand Down
38 changes: 23 additions & 15 deletions src/lib/statsProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import React, {
useState,
type ReactNode,
} from "react";
import { githubService } from "../services/githubService";
import { githubService, type GitHubOrgStats } from "../services/githubService";
import useDocusaurusContext from "@docusaurus/useDocusaurusContext";

// Time filter types
export type TimeFilter = "week" | "month" | "year" | "all";
Expand All @@ -21,7 +22,7 @@ interface ICommunityStatsContext {
githubForksCountText: string;
githubReposCount: number;
githubReposCountText: string;
githubDiscussionsCount: number | null;
githubDiscussionsCount: number;
githubDiscussionsCountText: string;
loading: boolean;
error: string | null;
Expand Down Expand Up @@ -159,15 +160,18 @@ const isPRInTimeRange = (mergedAt: string, filter: TimeFilter): boolean => {
export function CommunityStatsProvider({
children,
}: CommunityStatsProviderProps) {
const {
siteConfig: { customFields },
} = useDocusaurusContext();
const token = customFields?.gitToken || "";

const [loading, setLoading] = useState(false); // Start with false to avoid hourglass
const [error, setError] = useState<string | null>(null);
const [githubStarCount, setGithubStarCount] = useState(984); // Placeholder value - updated to match production
const [githubContributorsCount, setGithubContributorsCount] = useState(467); // Placeholder value - updated to match production
const [githubForksCount, setGithubForksCount] = useState(1107); // Placeholder value - updated to match production
const [githubReposCount, setGithubReposCount] = useState(10); // Placeholder value - updated to match production
const [githubDiscussionsCount, setGithubDiscussionsCount] = useState<
number | null
>(null);
const [githubDiscussionsCount, setGithubDiscussionsCount] = useState(0);
const [lastUpdated, setLastUpdated] = useState<Date | null>(null);

// Time filter state
Expand Down Expand Up @@ -429,24 +433,32 @@ export function CommunityStatsProvider({

setError(null);

if (!token) {
setError(
"GitHub token not found. Please set customFields.gitToken in docusaurus.config.js.",
);
setLoading(false);
return;
}

try {
const headers: Record<string, string> = {
Authorization: `token ${token}`,
Accept: "application/vnd.github.v3+json",
};

// Fetch both org stats and repos in parallel
const [orgStats, repos, discussionsCount] = await Promise.all([
const [orgStats, repos] = await Promise.all([
githubService.fetchOrganizationStats(signal),
fetchAllOrgRepos(headers),
githubService.fetchDiscussionsCount(signal),
]);

// Set org stats immediately
setGithubStarCount(orgStats.totalStars);
setGithubContributorsCount(orgStats.totalContributors);
setGithubForksCount(orgStats.totalForks);
setGithubReposCount(orgStats.publicRepositories);
setGithubDiscussionsCount(discussionsCount ?? orgStats.discussionsCount);
setGithubDiscussionsCount(orgStats.discussionsCount);
setLastUpdated(new Date(orgStats.lastUpdated));

// Process leaderboard data with concurrent processing
Expand Down Expand Up @@ -479,13 +491,13 @@ export function CommunityStatsProvider({
setGithubContributorsCount(140);
setGithubForksCount(0);
setGithubReposCount(20);
setGithubDiscussionsCount(null);
setGithubDiscussionsCount(0);
}
} finally {
setLoading(false);
}
},
[fetchAllOrgRepos, processBatch, cache],
[token, fetchAllOrgRepos, processBatch, cache],
);

const clearCache = useCallback(() => {
Expand Down Expand Up @@ -565,11 +577,7 @@ export const useCommunityStatsContext = (): ICommunityStatsContext => {
return context;
};

export const convertStatToText = (num: number | null): string => {
if (num === null) {
return "N/A";
}

export const convertStatToText = (num: number): string => {
const hasIntlSupport =
typeof Intl === "object" && Intl && typeof Intl.NumberFormat === "function";

Expand Down
Loading
Loading