feat: implement dashboard layout, settings system, and documentation infrastructure#8
Conversation
…d Sendable logo; update global styles - Added SVG icons for Google Calendar, Gmail, MS Outlook, and Slack. - Included a PNG logo for Sendable. - Updated global CSS styles to enhance theme variables and shadow effects. - Improved dark and light mode color schemes for better accessibility.
…nts; update shared index export
…s; update schemas and API integration
…ialog components for user account management
… Footer with theme toggle and updated styles
…ser feedback with toast notifications
…d SecuritySection components for user settings management
…update pricing, hero, and final CTA sections for better user experience
…hance dashboard layout with skeleton loading states
- Changed font from Manrope to Inter in layout.tsx for better typography. - Updated metadata title and added icon for branding. - Wrapped children in TooltipProvider and added Toaster for enhanced user experience. - Refactored NotFound component styles to use new color scheme and improved accessibility. - Updated Home page background and imported Footer from new path.
…nerator into feature/dashboard-settings
…ice with improved error handling
…tor welcome messages
… styling and messaging for user engagement
- Introduced a new page for dynamic MDX content handling in `src/app/docs/[[...mdxPath]]/page.tsx`. - Created a custom layout for documentation in `src/app/docs/layout.tsx`, including a navbar and footer. - Added CSS styles for a blurred navbar effect in `src/app/docs/docs.css`. - Adjusted the settings page tab positioning in `src/app/(auth)/settings/page.tsx`.
…components - Added semicolons to the end of statements for consistency. - Reformatted code to ensure consistent spacing and indentation. - Updated import statements to follow a uniform style. - Enhanced readability by ensuring consistent use of curly braces and parentheses. - Minor adjustments to comments for clarity.
…nents, and improve error handling in email services
|
🤖 Auto-generated PR description has been added! The title and description were generated based on your commits and file changes.
See our Contributing Guidelines for best practices. |
Dependency ReviewThe following issues were found:
|
| @@ -1,11 +1,13 @@ | |||
| "use node"; | |||
Check warning
Code scanning / CodeQL
Unknown directive Warning
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 11 days ago
In general, to fix an unknown directive problem, either correct the string to a valid, intended directive (for example, change "usestrict" to "use strict") or remove the stray directive-like string if no directive is needed. The goal is to avoid meaningless directive prologue entries that can confuse readers and static analysis tools while preserving runtime behavior.
For convex/auth/helpers.ts, there is no standard "use node" directive in JavaScript/TypeScript, and nothing in the snippet suggests that strict mode or any other directive is required. The simplest change that avoids altering behavior is to delete the first line containing "use node";. Since it is currently just an unused expression statement, removing it will not affect the logic of the module or any imports/exports. You only need to edit line 1 of convex/auth/helpers.ts, removing that line and leaving the rest of the file (imports and code) unchanged.
| @@ -1,5 +1,3 @@ | ||
| "use node"; | ||
|
|
||
| import { components, api } from "../_generated/api"; | ||
| import authSchema from "../betterAuth/schema"; | ||
| import { createClient, GenericCtx } from "@convex-dev/better-auth"; |
| @@ -0,0 +1,95 @@ | |||
| "use node"; | |||
Check warning
Code scanning / CodeQL
Unknown directive Warning
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 11 days ago
In general, to fix an "Unknown directive" issue, either (1) correct the directive to a valid, supported one (such as "use strict";) if that was the intent, or (2) remove the stray directive-like string literal if it serves no functional purpose. This avoids misleading future readers and static analyzers and ensures that if strict mode was intended, it is actually enabled.
For this file, the top-of-file "use node"; is not a valid directive and has no effect. The rest of the file is regular TypeScript meant to run in a Node environment; TypeScript compilation will already target Node, and the comment below the line explains the environment. The best minimal change that doesn’t alter existing functionality is to replace "use node"; with "use strict";, thereby enabling strict mode for the generated JavaScript and eliminating the "unknown directive" warning. No other parts of the file need to change, and no new imports or helpers are required.
Specifically, in convex/lib/logger.ts, line 1 should be changed from "use node"; to "use strict";. All subsequent lines remain as they are.
| @@ -1,4 +1,4 @@ | ||
| "use node"; | ||
| "use strict"; | ||
|
|
||
| /** | ||
| * Logger utility for Convex backend. |
There was a problem hiding this comment.
Pull request overview
This PR introduces a broad set of foundational product features (dashboard/authenticated layout, settings infrastructure, documentation via MDX/Nextra, and logging), alongside a large shadcn-style UI component expansion and a landing/auth UI refresh.
Changes:
- Added a new authenticated app shell (header/sidebar) plus shared UI utilities and many new UI primitives.
- Introduced a documentation site under
/docsusing Nextra + MDX content structure. - Added frontend + Convex-side logging utilities and expanded email template styling/content.
Reviewed changes
Copilot reviewed 140 out of 152 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| src/types/logger.ts | Adds shared logger types. |
| src/types/integrations.ts | Adds integration key union type. |
| src/types/index.ts | Central export barrel for types. |
| src/types/auth.ts | Adds auth-related types (verification/session). |
| src/lib/logger.ts | Adds frontend logger utility. |
| src/hooks/use-mobile.ts | Adds mobile breakpoint detection hook. |
| src/components/ui/tooltip.tsx | New tooltip primitive wrapper. |
| src/components/ui/toggle.tsx | New toggle primitive wrapper. |
| src/components/ui/toggle-group.tsx | New toggle-group wrappers. |
| src/components/ui/textarea.tsx | New textarea component wrapper. |
| src/components/ui/tabs.tsx | New tabs primitive wrapper. |
| src/components/ui/table.tsx | New table component wrappers. |
| src/components/ui/switch.tsx | New switch primitive wrapper. |
| src/components/ui/spinner.tsx | Adds spinner component. |
| src/components/ui/sonner.tsx | Adds themed toaster wrapper. |
| src/components/ui/slider.tsx | New slider primitive wrapper. |
| src/components/ui/skeleton.tsx | Adds skeleton loading component. |
| src/components/ui/sheet.tsx | New sheet (dialog-based) wrappers. |
| src/components/ui/separator.tsx | Minor class ordering change. |
| src/components/ui/scroll-area.tsx | New scroll-area wrappers. |
| src/components/ui/resizable.tsx | Adds resizable panel wrappers. |
| src/components/ui/radio-group.tsx | Adds radio-group wrappers. |
| src/components/ui/progress.tsx | Adds progress component wrapper. |
| src/components/ui/popover.tsx | Adds popover wrappers. |
| src/components/ui/password-input.tsx | Adds password input with strength UI and visibility toggle. |
| src/components/ui/pagination.tsx | Adds pagination components. |
| src/components/ui/native-select.tsx | Adds styled native select wrapper. |
| src/components/ui/kbd.tsx | Adds keyboard key/kbd components. |
| src/components/ui/item.tsx | Adds “item” layout primitives. |
| src/components/ui/input.tsx | Updates input styling/classes. |
| src/components/ui/input-otp.tsx | Adds OTP input wrapper components. |
| src/components/ui/hover-card.tsx | Adds hover-card wrappers. |
| src/components/ui/form.tsx | Adds react-hook-form wrappers. |
| src/components/ui/field.tsx | Class order/style tweaks. |
| src/components/ui/empty.tsx | Adds empty state component. |
| src/components/ui/drawer.tsx | Adds drawer wrappers via vaul. |
| src/components/ui/direction.tsx | Adds direction provider wrapper. |
| src/components/ui/dialog.tsx | Adds dialog wrappers with close controls. |
| src/components/ui/command.tsx | Adds cmdk-based command palette components. |
| src/components/ui/collapsible.tsx | Adds collapsible wrappers. |
| src/components/ui/checkbox.tsx | Refactors checkbox wrapper implementation. |
| src/components/ui/card.tsx | Minor class ordering/style tweaks. |
| src/components/ui/button.tsx | Refactors button variants/sizes and Slot usage. |
| src/components/ui/button-group.tsx | Adds grouped button layout utilities. |
| src/components/ui/breadcrumb.tsx | Adds breadcrumb components. |
| src/components/ui/badge.tsx | Adds badge component. |
| src/components/ui/avatar.tsx | Adds avatar primitives (incl. group/badge). |
| src/components/ui/aspect-ratio.tsx | Adds aspect ratio wrapper. |
| src/components/ui/alert.tsx | Adds alert component. |
| src/components/ui/accordion.tsx | Adds accordion wrappers. |
| src/components/shared/index.ts | Adds shared-components barrel export. |
| src/components/shared/UserMenu.tsx | Adds authenticated user menu dropdown. |
| src/components/shared/ThemeSwitcher.tsx | Adds theme toggle button. |
| src/components/shared/NotificationCenter.tsx | Adds notification center dropdown (static sample). |
| src/components/shared/Logo.tsx | Adds reusable logo component. |
| src/components/shared/CommandMenu.tsx | Adds command menu UI and routing actions. |
| src/components/pages/(unauth)/home/pricing.tsx | Refreshes pricing section styling/theme tokens. |
| src/components/pages/(unauth)/home/logo-marquee.tsx | Refreshes logo marquee styling/theme tokens. |
| src/components/pages/(unauth)/home/hero.tsx | Refreshes hero section styling and image usage. |
| src/components/pages/(unauth)/home/final-cta.tsx | Refreshes final CTA styling/theme tokens. |
| src/components/layout/footer.tsx | Refreshes footer styling and adds theme toggle switch. |
| src/components/layout/Header.tsx | Refactors navbar/header to use Logo and theme tokens. |
| src/components/layout/AppHeader.tsx | Replaces old header with app-shell header (sidebar trigger + menus). |
| src/components/dialogs/DeleteAccountDialog.tsx | Adds delete-account confirmation dialog. |
| src/components/dialogs/ChangeEmailDialog.tsx | Adds change-email dialog flow. |
| src/components/auth/TwoFactorVerification.tsx | Refactors verification type import + error handling. |
| src/components/auth/SignInForm.tsx | Switches to PasswordInput + comments out social sign-in block. |
| src/components/auth/ResetPassword.tsx | Switches to PasswordInput + strength UI, refactors error handling. |
| src/components/auth/ForgotPassword.tsx | Improves error handling and fixes apostrophes in UI text. |
| src/app/page.tsx | Switches to updated Navbar import and background theme tokens. |
| src/app/not-found.tsx | Updates 404 page styling/theme tokens and escaping. |
| src/app/layout.tsx | Switches font, adds TooltipProvider, updates Toaster import, updates metadata/icons. |
| src/app/docs/layout.tsx | Adds Nextra docs layout with logo and repo links. |
| src/app/docs/docs.css | Adds docs navbar blur styling. |
| src/app/docs/[[...mdxPath]]/page.tsx | Adds dynamic MDX routing via Nextra importPage. |
| src/app/(unauth)/sign-up/page.tsx | Simplifies signup page layout and adds Logo. |
| src/app/(unauth)/sign-in/page.tsx | Simplifies sign-in page layout and adds Logo. |
| src/app/(unauth)/reset-password/page.tsx | Fixes ResetPassword import path alias. |
| src/app/(unauth)/layout.tsx | Redirects authenticated users to /dashboard. |
| src/app/(unauth)/forget-password/page.tsx | Simplifies forgot-password page layout and adds Logo. |
| src/app/(auth)/layout.tsx | Adds authenticated app shell (sidebar provider + preload user query). |
| src/app/(auth)/dashboard/page.tsx | Adds dashboard skeleton UI (placeholder). |
| public/icons/slack.svg | Adds Slack icon asset. |
| public/icons/ms-outlook.svg | Adds Outlook icon asset. |
| public/icons/google-gmail.svg | Adds Gmail icon asset. |
| public/icons/google-calendar.svg | Adds Google Calendar icon asset. |
| public/icons/edge.svg | Adds Edge icon asset. |
| public/icons/discord.svg | Adds Discord icon asset. |
| public/icons/chrome.svg | Adds Chrome icon asset. |
| package.json | Adds deps for docs/UI/forms/logging; adjusts lint/typecheck scripts. |
| next.config.ts | Wraps Next config with Nextra integration. |
| mdx-components.tsx | Exposes Nextra MDX components hook. |
| eslint.config.mjs | Adds ignores for Convex generated code. |
| convex/users/schema.ts | Simplifies users tables export. |
| convex/userPreferences/upload.ts | Adds profile image upload mutations. |
| convex/userPreferences/schema.ts | Adds user preferences table schema + index. |
| convex/userPreferences/queries.ts | Adds query for fetching preferences. |
| convex/userPreferences/mutations.ts | Adds preferences upsert + notification update mutations. |
| convex/schema.ts | Registers userPreferences tables. |
| convex/polyfills.ts | Tweaks MessagePort stub methods. |
| convex/lib/logger.ts | Adds backend logger with BetterStack (Logtail) optional forwarding. |
| convex/emails/templates/VerifyOTP.tsx | Updates OTP verification email template content/styling. |
| convex/emails/templates/VerifyEmail.tsx | Updates email verification template content/styling. |
| convex/emails/templates/ResetPassword.tsx | Updates reset password template content/styling. |
| convex/emails/templates/MagicLink.tsx | Updates magic link template content/styling. |
| convex/emails/templates/BaseLayout.tsx | Refreshes base email layout typography and footer. |
| convex/emails/templates/AlertEmail.tsx | Updates alert email template styling/content. |
| convex/emails/email.tsx | Integrates logger and refactors provider fallback logging. |
| convex/betterAuth/users.ts | Removes placeholder comments. |
| convex/betterAuth/schema.ts | Removes unused custom index. |
| convex/auth/queries.ts | Restricts user profile lookup to authenticated users. |
| convex/_generated/api.d.ts | Updates generated API typings for new modules. |
| content/index.mdx | Adds docs landing page content. |
| content/getting-started.mdx | Adds getting started documentation content. |
| content/features/email-generation.mdx | Adds email-generation documentation. |
| content/features/authentication.mdx | Adds authentication documentation. |
| content/features/_meta.ts | Adds features navigation metadata. |
| content/_meta.ts | Adds docs navigation metadata. |
| components.json | Updates shadcn css path to src/app/globals.css. |
| CONTRIBUTING.md | Updates project name references to “Sendable”. |
| .github/workflows/welcome.yml | Updates welcome messages to “Sendable”. |
| .env.example | Expands and documents environment variable set. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const Comp = asChild ? Slot.Root : "button"; | ||
|
|
There was a problem hiding this comment.
Slot is imported from "radix-ui" and used as Slot.Root. The Radix Slot primitive is typically a component export (e.g., from @radix-ui/react-slot) and doesn’t expose a .Root property; this pattern is likely to break at build/runtime. Consider switching back to the standard Radix Slot import and render the Slot component directly when asChild is true.
| import { cn } from "@/lib/utils"; | ||
| import { buttonVariants, type Button } from "@/components/ui/button"; | ||
|
|
There was a problem hiding this comment.
This file imports type Button from @/components/ui/button, but Button is a value export (not a type export). This will cause a TypeScript error and also breaks React.ComponentProps<typeof Button> below. Import Button as a value (or export a dedicated ButtonProps type) and adjust the Pick<...> accordingly.
| <Command className="**:data-[slot=command-input-wrapper]:h-12 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]]:px-2 [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5"> | ||
| {children} |
There was a problem hiding this comment.
The className string contains **:data-[slot=command-input-wrapper]:h-12, which doesn’t appear to be a valid Tailwind variant selector. If this is intended to style descendants, use a supported selector form (e.g. [&_[data-slot=command-input-wrapper]]:h-12 or a project-standard equivalent), otherwise Tailwind will drop the rule and the input height won’t be applied.
| const useFormField = () => { | ||
| const fieldContext = React.useContext(FormFieldContext); | ||
| const itemContext = React.useContext(FormItemContext); | ||
| const { getFieldState } = useFormContext(); | ||
| const formState = useFormState({ name: fieldContext.name }); | ||
| const fieldState = getFieldState(fieldContext.name, formState); | ||
|
|
||
| if (!fieldContext) { | ||
| throw new Error("useFormField should be used within <FormField>"); | ||
| } |
There was a problem hiding this comment.
useFormField checks if (!fieldContext) but FormFieldContext is initialized with {} cast as FormFieldContextValue, so fieldContext is always truthy even when used outside a provider. This means misuse won’t throw early and will instead fail later with confusing errors (e.g., fieldContext.name undefined). Consider initializing the context with null and validating both fieldContext and itemContext before using them.
| React.useEffect(() => { | ||
| if (!showStrengthOnSubmit) return; | ||
| const form = (ref as React.RefObject<HTMLInputElement>)?.current?.closest( | ||
| "form", | ||
| ); | ||
| if (!form) return; | ||
| const handler = () => setAttempted(true); | ||
| form.addEventListener("submit", handler); | ||
| return () => form.removeEventListener("submit", handler); | ||
| }, [showStrengthOnSubmit, ref]); |
There was a problem hiding this comment.
The effect casts the forwarded ref to React.RefObject and reads .current, but callers can pass a callback ref, in which case .current will be undefined and the submit listener won’t attach. Use an internal useRef for the input element and merge it with the forwarded ref (or use a ref callback) before calling .closest("form").
| onError: (ctx) => { | ||
| setLoading(false); | ||
| console.error("Reset password error:", ctx?.error); | ||
| const message = ctx?.error?.message || "Failed to reset password."; | ||
| toast.error(message); | ||
| toast.error(ctx.error.message); | ||
| }, |
There was a problem hiding this comment.
onError assumes ctx.error.message is always present. If ctx or ctx.error is undefined (or the shape changes), this will throw and mask the real failure. Please guard with optional chaining and provide a fallback error message (similar to other auth flows in this PR).
| import { Toaster } from "sonner"; | ||
| import { Skeleton } from "@/components/ui/skeleton"; |
There was a problem hiding this comment.
This page renders a Toaster even though src/app/layout.tsx already mounts the app-wide toaster (and your themed wrapper is @/components/ui/sonner, not sonner). This can lead to duplicated toasts and inconsistent theming. Consider removing the page-level Toaster and relying on the root layout toaster.
| const withNextra = nextra({ | ||
| contentDirBasePath: "/docs", | ||
| }); |
There was a problem hiding this comment.
Nextra is configured with contentDirBasePath: "/docs", but the MDX content in this PR lives under the top-level content/ directory. If contentDirBasePath is meant to point to the filesystem directory for MDX, this mismatch will prevent docs pages from being discovered/built. Consider updating the config to point at the actual content directory (or removing this option if Nextra’s default already matches your layout).
| if (emailProvider === "smtp") { | ||
| console.log(`[EmailService] Prioritizing SMTP delivery to ${to}`); | ||
| try { | ||
| return await sendViaSmtp(finalFrom, to, subject, html); | ||
| } catch (smtpError) { | ||
| console.error("[EmailService] SMTP delivery failed:", smtpError); | ||
| console.log("[EmailService] Attempting Resend fallback..."); | ||
| } catch { | ||
| logger.warn("SMTP delivery failed, attempting Resend fallback"); | ||
| } | ||
| } | ||
|
|
||
| const canUseResend = !verifiedRecipient || to.toLowerCase() === verifiedRecipient.toLowerCase(); | ||
| console.log(`[EmailService] Can use Resend for ${to}: ${canUseResend}`); | ||
|
|
||
| if (canUseResend) { | ||
| try { | ||
| console.log(`[EmailService] Attempting Resend to ${to}...`); | ||
| await resend.sendEmail(ctx, { | ||
| from: finalFrom, | ||
| to, | ||
| subject, | ||
| html, | ||
| }); | ||
| console.log(`[EmailService] Success via Resend to ${to}`); | ||
| return; | ||
| } catch (resendError) { | ||
| console.error("[EmailService] Resend delivery failed:", resendError); | ||
| console.log("[EmailService] Attempting SMTP fallback..."); | ||
| } catch { | ||
| logger.warn("Resend delivery failed, attempting SMTP fallback"); | ||
| } |
There was a problem hiding this comment.
sendEmailWithFallback swallows the caught error details when falling back between SMTP and Resend. This makes production troubleshooting difficult (you lose the provider error + recipient/subject context). Consider logging the caught error (and relevant context like to, subject, emailProvider) via logger.warn(..., { error: ..., to, subject }) and similarly include the error in logger.error in sendEmailVerification.
Description
This PR introduces a comprehensive implementation of the dashboard, settings, documentation, and logging infrastructure for the application. It includes major UI/UX improvements, authentication enhancements, and foundational components for user management.
Key Highlights:
Type of Change
Related Issues
Changes Made
Dashboard & Layout
AppHeaderandAppSidebarcomponents for authenticated layoutsHeader) with improved styling and functionalitySettings Page
ChangeEmailDialog,DeleteAccountDialog,TwoFactorSetupDialogDocumentation
docs.css)Logger Infrastructure
convex/lib/logger.tsandsrc/lib/logger.ts)Email Templates
AlertEmail,MagicLink,ResetPassword,VerifyEmail,VerifyOTPBaseLayoutfor consistent email stylingAuthentication Improvements
UI Components (Shadcn)
select,combobox,radio-group,slider,switchsidebar,sheet,drawer,resizablealert,alert-dialog,sonner,progress,spinnerbreadcrumb,menubar,navigation-menu,paginationtable,chart,calendar,carouselLanding Page Updates
Backend/Convex Updates
Configuration & Documentation
.env.examplewith comprehensive environment variablesCONTRIBUTING.mdandREADME.mdShared Components
CommandMenu,Logo,NotificationCenter,ThemeSwitcher,UserMenucomponents/shared/index.tsTesting Done
Test Steps
/dashboard/settingsand test all four sections:/docsto view documentation pagesDocumentation
Breaking Changes
No breaking changes. All changes are additive and backward compatible.
Code Review Checklist
Additional Notes
Dependencies Added:
Statistics:
Branch:
feature/dashboard-settingsBase:
developThis PR represents significant progress on the core user-facing features of the application. The dashboard, settings, and documentation infrastructure are now in place and ready for further iteration.