Skip to content

Admin and settings#317

Merged
motirebuma merged 1 commit intomainfrom
Admin-and-Settings
Mar 23, 2026
Merged

Admin and settings#317
motirebuma merged 1 commit intomainfrom
Admin-and-Settings

Conversation

@motirebuma
Copy link
Copy Markdown
Collaborator

implemented admin dashboards and fixed settings functionality.

Copilot AI review requested due to automatic review settings March 23, 2026 20:24
@vercel
Copy link
Copy Markdown

vercel bot commented Mar 23, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
quotevote Ready Ready Preview, Comment Mar 23, 2026 8:24pm

@motirebuma motirebuma merged commit dd9c101 into main Mar 23, 2026
8 checks passed
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements a new admin “Control Panel” dashboard (with multiple moderation/management tabs), adds a user-facing “Manage Invites” page, and shifts the primary dashboard landing route from /dashboard/search to /dashboard/explore while updating navigation/tests accordingly.

Changes:

  • Added admin tabs for user reports, post moderation, featured posts, user management, and statistics (plus related GraphQL/types/UI primitives).
  • Added /dashboard/manage-invites with invite status actions.
  • Replaced /dashboard/search with /dashboard/explore across routing, middleware behavior, and tests; removed many /app/test/* pages.

Reviewed changes

Copilot reviewed 88 out of 88 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
quotevote-frontend/src/types/admin.ts Adds TypeScript types used by new admin/manage-invites features.
quotevote-frontend/src/graphql/queries.ts Adds GraphQL queries for invite requests and user reports.
quotevote-frontend/src/graphql/mutations.ts Adds mutation for updating invite status.
quotevote-frontend/src/components/ui/table.tsx Introduces a table UI primitive used by admin/manage screens.
quotevote-frontend/src/components/ui/switch.tsx Introduces a switch UI primitive for admin user toggles.
quotevote-frontend/src/components/ui/button.tsx Updates button variants/sizes and Radix Slot usage.
quotevote-frontend/src/components/ui/alert-dialog.tsx Adds alert dialog UI primitive used for destructive admin actions.
quotevote-frontend/src/components/StripePaymentDialog/index.ts Exports the new StripePaymentDialog component.
quotevote-frontend/src/components/StripePaymentDialog/StripePaymentDialog.tsx Adds Stripe “Buy Button” dialog and script loader.
quotevote-frontend/src/components/Post/PostSkeleton.tsx Updates post skeleton markup/styling.
quotevote-frontend/src/components/Comment/CommentList.tsx Updates comment list UI incl. empty/loading states.
quotevote-frontend/src/components/Comment/CommentInput.tsx Updates comment input UI and keyboard submit behavior.
quotevote-frontend/src/components/Comment/Comment.tsx Updates comment card layout and action styling.
quotevote-frontend/src/components/Admin/index.ts Exports newly added admin dashboard tabs.
quotevote-frontend/src/components/Admin/UserReportsTab.tsx Adds admin UI for viewing reports and disabling users.
quotevote-frontend/src/components/Admin/UserManagementTab.tsx Adds admin UI to toggle contributor badge.
quotevote-frontend/src/components/Admin/StatisticsTab.tsx Adds admin stats UI derived from invite/user data.
quotevote-frontend/src/components/Admin/PostModerationTab.tsx Adds admin UI for approving/rejecting posts.
quotevote-frontend/src/components/Admin/FeaturedPostsTab.tsx Adds admin UI to assign/remove featured slots.
quotevote-frontend/src/components/Admin/BotListTab.tsx Adds toast-based success/error feedback for bot actions.
quotevote-frontend/src/app/test/user-posts/page.tsx Removes test-only page.
quotevote-frontend/src/app/test/submit-post/page.tsx Removes test-only page.
quotevote-frontend/src/app/test/subheader/page.tsx Removes test-only page.
quotevote-frontend/src/app/test/signup/page.tsx Removes test-only page.
quotevote-frontend/src/app/test/sidebar/page.tsx Removes test-only page.
quotevote-frontend/src/app/test/reset/page.tsx Removes test-only page.
quotevote-frontend/src/app/test/request-invite-dialog/page.tsx Removes test-only page.
quotevote-frontend/src/app/test/request-access/page.tsx Removes test-only page.
quotevote-frontend/src/app/test/quotes/page.tsx Removes test-only page.
quotevote-frontend/src/app/test/profile/page.tsx Removes test-only page.
quotevote-frontend/src/app/test/popover-menu/page.tsx Removes test-only page.
quotevote-frontend/src/app/test/navigation-flow/page.tsx Removes test-only page.
quotevote-frontend/src/app/test/login/page.tsx Removes test-only page.
quotevote-frontend/src/app/test/icons/page.tsx Removes test-only page.
quotevote-frontend/src/app/test/highlight-text/page.tsx Removes test-only page.
quotevote-frontend/src/app/test/error-boundary/page.tsx Removes test-only page.
quotevote-frontend/src/app/test/content-list/page.tsx Removes test-only page.
quotevote-frontend/src/app/test/common/page.tsx Removes test-only page.
quotevote-frontend/src/app/test/comments/page.tsx Removes test-only page.
quotevote-frontend/src/app/test/carousel/page.tsx Removes test-only page.
quotevote-frontend/src/app/test/buttons/page.tsx Removes test-only page.
quotevote-frontend/src/app/test/buddy-list/page.tsx Removes test-only page.
quotevote-frontend/src/app/test/auth-flow/page.tsx Removes test-only page.
quotevote-frontend/src/app/test/admin/page.tsx Removes test-only page.
quotevote-frontend/src/app/test/activity/page.tsx Removes test-only page.
quotevote-frontend/src/app/test-postchat/page.tsx Removes test-only page.
quotevote-frontend/src/app/error/PageContent.tsx Updates “back” navigation target to /dashboard/explore.
quotevote-frontend/src/app/dashboard/settings/page.tsx Adds Settings page wrapper + metadata (client page split).
quotevote-frontend/src/app/dashboard/search/page.tsx Removes old Search page route (replaced by Explore).
quotevote-frontend/src/app/dashboard/search/loading.tsx Removes old Search loading UI (replaced by Explore).
quotevote-frontend/src/app/dashboard/post/[group]/[title]/[postId]/page.tsx Updates post detail layout + tabs styling and sidebar behavior.
quotevote-frontend/src/app/dashboard/manage-invites/page.tsx Adds Manage Invites route wrapper + metadata.
quotevote-frontend/src/app/dashboard/manage-invites/ManageInvitesClient.tsx Adds invite management UI and actions.
quotevote-frontend/src/app/dashboard/layout.tsx Updates nav to Explore, adds Manage Invites, uses removeToken on logout.
quotevote-frontend/src/app/dashboard/explore/page.tsx Adds new Explore page route + Suspense skeleton.
quotevote-frontend/src/app/dashboard/explore/loading.tsx Adds Explore route loading UI.
quotevote-frontend/src/app/dashboard/control-panel/page.tsx Converts Control Panel page to client wrapper.
quotevote-frontend/src/app/dashboard/control-panel/ControlPanelClient.tsx Adds admin-only tabbed control panel client implementation.
quotevote-frontend/src/app/components/LandingPage/LandingPageContent.tsx Redirects signed-in users to /dashboard/explore.
quotevote-frontend/src/app/auths/signup/PageContent.tsx Redirects after signup to /dashboard/explore.
quotevote-frontend/src/app/auths/login/PageContent.tsx Redirects after login to /dashboard/explore.
quotevote-frontend/src/app/auths/investor-thanks/page.tsx Updates metadata/content copy and layout sizing.
quotevote-frontend/src/tests/foundation/middleware.test.ts Updates middleware tests for Explore route.
quotevote-frontend/src/tests/components/StripePaymentDialog/StripePaymentDialog.test.tsx Adds tests for StripePaymentDialog.
quotevote-frontend/src/tests/components/Post/PostSkeleton.test.tsx Updates tests to match new skeleton markup.
quotevote-frontend/src/tests/components/Admin/UserReportsTab.test.tsx Adds tests for UserReportsTab.
quotevote-frontend/src/tests/components/Admin/PostModerationTab.test.tsx Adds tests for PostModerationTab.
quotevote-frontend/src/tests/components/Admin/BotListTab.test.tsx Adds tests for BotListTab.
quotevote-frontend/src/tests/app/page.test.tsx Updates landing page redirect expectations to Explore route.
quotevote-frontend/src/tests/app/dashboard/settings/page.test.tsx Adds tests covering settings page behavior.
quotevote-frontend/src/tests/app/dashboard/search/page.test.tsx Refactors test to validate Explore page instead of Search.
quotevote-frontend/src/tests/app/dashboard/manage-invites/page.test.tsx Adds tests for Manage Invites page client.
quotevote-frontend/src/tests/app/dashboard/explore/page.test.tsx Adds tests for Explore page wrapper.
quotevote-frontend/src/tests/app/dashboard/control-panel/page.test.tsx Updates control panel tests for new client implementation + admin gating.
quotevote-frontend/src/tests/app/auths/login.test.tsx Updates login redirect expectation to Explore route.
quotevote-frontend/public/sitemap.xml Adds a static sitemap.
quotevote-frontend/public/robots.txt Adds robots directives and sitemap link.
quotevote-frontend/package.json Adjusts dev scripts (webpack default + turbopack alt).
quotevote-frontend/next.config.ts Updates CSP connect/font sources (and still defines CSP).
quotevote-frontend/middleware.ts Adds admin-only middleware gating for control panel + Explore redirect updates.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

const parts = token.split('.');
if (parts.length !== 3) return null;
const payload = parts[1];
const decoded = atob(payload.replace(/-/g, '+').replace(/_/g, '/'));
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

decodeJwtPayload base64url-decodes the JWT payload without adding required padding. For many JWTs this will throw and silently return null. Add proper base64url padding before atob (or use a small base64url decode helper) so admin routing works reliably.

Suggested change
const decoded = atob(payload.replace(/-/g, '+').replace(/_/g, '/'));
// Convert from base64url to base64 and add required padding
let base64 = payload.replace(/-/g, '+').replace(/_/g, '/');
const paddingNeeded = base64.length % 4;
if (paddingNeeded > 0) {
base64 = base64 + '='.repeat(4 - paddingNeeded);
}
const decoded = atob(base64);

Copilot uses AI. Check for mistakes.
Comment on lines +38 to +43
// Admin-only route protection for /dashboard/control-panel
if (pathname.startsWith('/dashboard/control-panel')) {
const payload = decodeJwtPayload(token);
if (!payload || payload.admin !== true) {
return NextResponse.redirect(new URL('/dashboard/explore', request.url));
}
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Route protection for /dashboard/control-panel relies on an unverified JWT payload (decodeJwtPayload explicitly does not verify signatures). A user can forge a token with { admin: true } and bypass this middleware check. Prefer verifying the JWT signature (e.g. with jose in the edge runtime) or enforce admin access exclusively via server-side authorization and redirect based on a trusted backend check.

Copilot uses AI. Check for mistakes.
Comment on lines +180 to +186
<AlertDialogAction
onClick={() =>
handleDisable(
report.reportedUser?._id,
report.reportedUser?.username
)
}
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

handleDisable expects (userId: string, username: string), but the click handler passes report.reportedUser?._id / report.reportedUser?.username, which are typed as string | undefined due to optional chaining. With strict enabled this should be a type error (and at runtime could toast “@undefined”). Since reportedUser is non-optional in UserReport, use non-optional access (report.reportedUser._id, report.reportedUser.username) or guard explicitly before rendering the action.

Copilot uses AI. Check for mistakes.
Comment on lines +106 to +112
const handleSave = async (id: string) => {
const slot = selection[id]
try {
await updateSlot({
variables: { postId: id, featuredSlot: slot ? Number(slot) : null },
})
toast.success(slot ? `Post assigned to slot ${slot}` : 'Post removed from featured')
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SelectItem uses value="none", but handleSave treats any truthy slot as a number (Number(slot)), so choosing “None” will send featuredSlot: NaN to the GraphQL mutation (expected Int). Treat the “none” selection as null (e.g., normalize slot === 'none' || slot === '' to null) and ensure the Select’s unselected value matches that normalization.

Copilot uses AI. Check for mistakes.
Comment on lines +19 to +21
const STRIPE_BUY_BUTTON_ID = 'buy_btn_1RY6bhP3PjIJfZEbu5CpTDjo'
const STRIPE_PUBLISHABLE_KEY =
'pk_live_51RXriSP3PjIJfZEb1tqnEGBOGFZBHREUxqWHeO22GASJ5It6MKfpakOE3oDtL7II20j5idUR6NuXrBlaKXvszY6q00nn8KxROy'
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This component hardcodes a live Stripe publishable key and buy button ID in the client bundle. Move these to environment variables (e.g. NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY / NEXT_PUBLIC_STRIPE_BUY_BUTTON_ID) so they can be rotated and so non-production deployments don’t accidentally point at live Stripe configuration.

Copilot uses AI. Check for mistakes.
Comment on lines +42 to +46
const existing = document.querySelector('script[src*="buy-button.js"]')
if (existing) {
stripeLoaded = true
listeners.forEach((cb) => cb())
return
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ensureStripeScript marks Stripe as loaded if a matching <script> tag exists, even if it hasn’t finished loading yet. That can cause StripeBuyButton to render before the custom element is registered. Consider tracking a separate “script tag present” vs “loaded” state, or checking customElements.get('stripe-buy-button'), or attaching an onload handler to the existing script instead of immediately setting stripeLoaded = true.

Copilot uses AI. Check for mistakes.
Comment on lines 54 to 61
"default-src 'self'",
"script-src 'self' 'unsafe-eval' 'unsafe-inline'",
"style-src 'self' 'unsafe-inline'",
"img-src 'self' data: https:",
"font-src 'self' data:",
"connect-src 'self' http://localhost:4000 ws://localhost:4000",
"font-src 'self' data: https://fonts.gstatic.com",
"connect-src 'self' http://localhost:4000 ws://localhost:4000 https://fonts.googleapis.com https://fonts.gstatic.com",
"frame-ancestors 'none'",
].join("; "),
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CSP currently restricts script-src to 'self' (plus unsafe-*). The Stripe Buy Button script is loaded from https://js.stripe.com/..., which will be blocked in production. Update CSP to allow https://js.stripe.com in script-src and add appropriate frame-src/connect-src entries for Stripe checkout endpoints used by the buy button.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants