Conversation
…dation, and CORS middleware for feedback system
Fix import function error
…estions/answers Upload Multiple Images in Questions/Explanations
Native Bug Report and Optional GitHub Submission
Porting Playground
Contributor
There was a problem hiding this comment.
Pull request overview
This PR expands FiveHive’s SEO and content rendering capabilities (server-rendered public chapters, metadata, sitemap/robots, and llms.txt), adds a new feedback/bug-report workflow with an admin dashboard, and improves question/media handling (SVG support, file ordering/alt text, and upload content types).
Changes:
- Server-render public subject chapters (when public) and generate richer per-subject metadata, plus add
sitemap.ts,robots.ts, andpublic/llms.txt. - Add feedback submission page and admin feedback triage pages (including “create GitHub issue” integration).
- Improve media handling: SVG display fixes, content-type resolution for Firebase uploads, and richer question attachment rendering (order/alt/inline placeholders).
Reviewed changes
Copilot reviewed 50 out of 51 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| src/types/questions.ts | Extends question file metadata (id/alt/order). |
| src/styles/globals.css | Adds .img-svg styling for responsive SVG sizing. |
| src/lib/utils.ts | Adds SVG filename detection + upload content-type resolver. |
| src/lib/sitemap-data.ts | Adds server-side Firestore REST helpers for subjects/chapters. |
| src/lib/search/guideSearch.ts | Excludes porting subject from search indexing. |
| src/lib/firebase.ts | Exports Firebase Storage instance. |
| src/lib/apPortingDefaults.ts | Introduces default “AP Porting” subject structure. |
| src/env.js | Adds optional GitHub env vars (server-side). |
| src/components/subject/table-of-contents.tsx | Makes pathname usage null-safe in links. |
| src/components/subject/progress-tracker.tsx | Marks as client component. |
| src/components/questions/testRenderer.tsx | Passes origin to content renderer. |
| src/components/questions/quizRenderer.tsx | Passes origin to content renderer + refactors option styling logic. |
| src/components/questions/digital-testing/ReviewPage.tsx | Makes pathname usage null-safe. |
| src/components/questions/digital-testing/QuestionPanel.tsx | Passes origin to content renderer in multiple locations. |
| src/components/questions/digital-testing/Header.tsx | Makes pathname usage null-safe. |
| src/components/questions/digital-testing/Footer.tsx | Makes pathname usage null-safe. |
| src/components/questions/checkForUnderstanding.tsx | Passes origin to content renderer. |
| src/components/hooks/UserContext.tsx | Refactors user fetching to avoid SSR gating; listens to auth state changes. |
| src/components/global/SearchBar.tsx | Makes pathname usage null-safe. |
| src/components/global/footer.tsx | Routes “Feedback” link to /feedback. |
| src/components/article-creator/Renderer.tsx | Improves table LaTeX parsing; tags SVG images for CSS. |
| src/components/article-creator/QuestionsHydrator.tsx | New client hydrator for interactive question blocks in SSR HTML. |
| src/components/article-creator/FetchArticleFunctions.tsx | Avoids reuploading already-hosted files; sets Firebase upload content-type. |
| src/components/article-creator/editorjs-render.ts | New DOM-free EditorJS → HTML renderer for server/client. |
| src/components/article-creator/Editor.tsx | Adds safer image deletion flow + content-type handling for uploads. |
| src/components/article-creator/custom_questions/RenderAdvancedTextbox.tsx | Adds inline placeholders + ordered/alt-tagged media rendering; SVG improvements. |
| src/components/article-creator/custom_questions/AdvancedTextbox.tsx | Adds richer file UX (previews/order/alt/inline insertion) + immediate uploads. |
| src/components/article-creator/ArticleCreator.tsx | Makes pathname usage null-safe. |
| src/app/subject/[slug]/layout.tsx | Adds per-subject server generateMetadata. |
| src/app/subject/[slug]/(sidebar)/page.tsx | Blocks unauthorized access to porting subject in client fetch path. |
| src/app/subject/[slug]/(sidebar)/layout.tsx | Avoids SSR gating; fetches sidebar subject data opportunistically. |
| src/app/subject/[slug]/(sidebar)/[unit]/chapter/[id]/[title]/page.tsx | Converts chapter page to SSR public path with client fallback for gated/failures. |
| src/app/subject/[slug]/(sidebar)/[unit]/chapter/[id]/[title]/ChapterScaffold.tsx | New shared chapter shell component for SSR + client paths. |
| src/app/subject/[slug]/(sidebar)/[unit]/chapter/[id]/[title]/ChapterClient.tsx | New client-only gated chapter renderer. |
| src/app/sitemap.ts | Adds dynamic sitemap including public chapters only. |
| src/app/robots.ts | Adds robots config with explicit AI crawler allowlist + disallow list. |
| src/app/layout.tsx | Expands global metadata/OpenGraph/Twitter/robots settings. |
| src/app/feedback/page.tsx | Adds a feedback submission form (bug/feature/general) with optional screenshot upload. |
| src/app/auth/action/page.tsx | Wraps search-params usage in Suspense; improves null safety. |
| src/app/admin/subject/[slug]/page.tsx | Adds “Reset Course” flow for porting subject. |
| src/app/admin/subject/[slug]/[unit]/test/[id]/page.tsx | Makes pathname usage null-safe. |
| src/app/admin/subject/[slug]/[unit]/chapter/[id]/page.tsx | Removes dynamic import; improves search params handling. |
| src/app/admin/page.tsx | Adds feedback dashboard link; minor safety updates. |
| src/app/admin/feedback/page.tsx | New admin feedback list with resolve/unresolve. |
| src/app/admin/feedback/[slug]/page.tsx | New feedback detail route (server wrapper passing config). |
| src/app/admin/feedback/[slug]/FeedbackDetailsClient.tsx | New client UI for feedback details + GitHub issue creation. |
| src/app/account/page.tsx | Disables unused-vars lint (local change). |
| public/llms.txt | Adds llms.txt for AI discovery/context. |
| package.json | Adds dompurify and marked. |
| package-lock.json | Updates lockfile for new dependencies/versions. |
| firestore.rules | Adds rules for /feedback collection. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+104
to
+108
| allow read: if isMemberOrAdmin; | ||
| allow list: if isMemberOrAdmin; | ||
| allow get: if isMemberOrAdmin(); | ||
| allow update, delete: if isMemberOrAdmin(); | ||
| } |
Comment on lines
+9
to
+16
| export default function FeedbackDetailsPage({ params }: PageProps) { | ||
| const config = { | ||
| gitHubAccessToken: process.env.GITHUB_ACCESS_TOKEN ?? '', | ||
| gitHubRepoOwner: process.env.GITHUB_REPO_OWNER ?? '', | ||
| gitHubRepoName: process.env.GITHUB_REPO_NAME ?? '', | ||
| }; | ||
|
|
||
| return <FeedbackDetailsClient slug={params.slug} config={config} />; |
Comment on lines
+76
to
+124
| const handleCreateGitHubIssue = async () => { | ||
| if (!bug) return; | ||
| if (!config.gitHubAccessToken || !config.gitHubRepoOwner || !config.gitHubRepoName) { | ||
| alert("GitHub integration is not fully configured. Please check your server environment variables."); | ||
| return; | ||
| } | ||
|
|
||
| setIsCreatingIssue(true); | ||
|
|
||
| try { | ||
| const owner = config.gitHubRepoOwner; | ||
| const repo = config.gitHubRepoName; | ||
| const url = `https://api.github.com/repos/${owner}/${repo}/issues`; | ||
|
|
||
| const imgMarkdown = bug.attachedImage && bug.attachedImage.startsWith('http') ? `\n\n[Attached Image](${bug.attachedImage})` : ''; | ||
|
|
||
| let issueBody = `### Feedback Context\n\n- **Type:** ${bug.type}\n- **Contact Email:** ${bug.email ?? 'anonymous'}\n`; | ||
| if (bug.bugUrl && bug.bugUrl !== 'N/A') { | ||
| issueBody += `- **Context URL:** ${bug.bugUrl}\n`; | ||
| } | ||
| if (bug.type === 'bug') { | ||
| issueBody += `- **Category:** ${bug.bugType ?? 'N/A'}\n`; | ||
| issueBody += `\n### Detailed Description & Steps to Reproduce\n\n${bug.message}\n${imgMarkdown}`; | ||
| } else if (bug.type === 'feature') { | ||
| issueBody += `\n### Feature Request Details\n`; | ||
| if (bug.featureProblem) issueBody += `- **Problem:** ${bug.featureProblem}\n`; | ||
| if (bug.featureAlternatives) issueBody += `- **Alternatives Considered:** ${bug.featureAlternatives}\n`; | ||
| if (bug.featureSolution) issueBody += `- **Proposed Solution:** ${bug.featureSolution}\n`; | ||
| issueBody += `\n### Additional Description\n\n${bug.message}\n${imgMarkdown}`; | ||
| } else { | ||
| issueBody += `\n### Description\n\n${bug.message}${imgMarkdown}`; | ||
| } | ||
|
|
||
| const title = bug.title && bug.title.trim().length > 0 ? bug.title : `${bug.type === 'bug' ? 'Bug' : 'Feature'}: ${bug.bugType || ''}`; | ||
| const payload = { | ||
| title, | ||
| body: issueBody.trim(), | ||
| labels: [bug.type === 'bug' ? 'bug' : 'enhancement'], | ||
| }; | ||
| console.log('Creating GitHub issue with payload:', payload); | ||
| const response = await fetch(url, { | ||
| method: 'POST', | ||
| headers: { | ||
| 'Content-Type': 'application/json', | ||
| 'Authorization': `Bearer ${config.gitHubAccessToken}`, | ||
| 'Accept': 'application/vnd.github.v3+json', | ||
| }, | ||
| body: JSON.stringify(payload), | ||
| }); |
Comment on lines
+6
to
+9
| import { db } from '@/lib/firebase'; | ||
| import { doc, getDoc, updateDoc, setDoc } from 'firebase/firestore'; | ||
| import { marked } from 'marked'; | ||
| import DOMPurify from 'dompurify'; |
Comment on lines
+146
to
+148
| blockData.content = Object.keys(rows) | ||
| .sort() | ||
| .map((key) => rows[key]); |
Comment on lines
+9
to
+10
| const rootMap = new Map<Element, Root>(); | ||
|
|
Comment on lines
+1
to
+3
| import type { Subject } from "@/types/firestore"; | ||
| import type { OutputData } from "@editorjs/editorjs"; | ||
|
|
Comment on lines
13
to
17
| if (!code) { | ||
| alert("Need an oobCode to access this page. If you don't know what that means just leave the page"); | ||
| alert( | ||
| "Need an oobCode to access this page. If you don't know what that means just leave the page", | ||
| ); | ||
| return; |
Comment on lines
52
to
56
| "katex": "^0.16.11", | ||
| "lucide-react": "^0.525.0", | ||
| "marked": "^18.0.5", | ||
| "next": "^14.2.5", | ||
| "next-themes": "^0.4.4", |
Comment on lines
+187
to
+191
| const batch = writeBatch(db); | ||
|
|
||
| for (const unitDoc of unitsSnap.docs) { | ||
| const chaptersCollectionRef = collection(db, "subjects", "porting", "units", unitDoc.id, "chapters"); | ||
| const chaptersSnap = await getDocs(chaptersCollectionRef); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.