-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Improve onboarding #2666
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve onboarding #2666
Conversation
|
The latest updates on your projects. Learn more about Vercel for Git βοΈ
|
WalkthroughThis update introduces support for uploading and storing workspace logos during workspace creation. Changes span backend API handling, validation schemas, and the frontend form, including logic for initializing and uploading logo images. Additionally, email domain logic is refactored to generalize generic email detection, and UI text and error handling are updated. New API routes for favicon checking and workspace slug availability were added or modified, and onboarding and modal UI text was enhanced. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Frontend
participant API
participant DB
participant R2Storage
User->>Frontend: Fill workspace form (with optional logo)
Frontend->>API: POST /workspaces (name, slug, logo)
API->>DB: Create workspace (with logo URL if provided)
DB-->>API: Workspace created
API->>R2Storage: (Async) Upload logo image to storage
API-->>Frontend: Respond with workspace details
Estimated code review effort3 (~45 minutes) Possibly related PRs
Poem
π Recent review detailsConfiguration used: CodeRabbit UI π Files selected for processing (1)
π§ Files skipped from review as they are similar to previous changes (1)
β° Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
β¨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. πͺ§ TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
π§Ή Nitpick comments (4)
apps/web/lib/emails.ts (1)
1-13: Consider optimizing for better performance and maintainability.The current implementation works correctly but could be improved:
- Performance: Multiple
endsWithcalls can be optimized with a Set lookup- Case sensitivity: Email domains should be handled case-insensitively
- Maintainability: Extract the domain list to a constant
+const GENERIC_EMAIL_DOMAINS = new Set([ + "gmail.com", + "yahoo.com", + "hotmail.com", + "outlook.com", + "icloud.com", + "aol.com", + "comcast.net", + "verizon.net", + "att.net" +]); + export const isGenericEmail = (email: string) => { - return ( - email.endsWith("@gmail.com") || - email.endsWith("@yahoo.com") || - email.endsWith("@hotmail.com") || - email.endsWith("@outlook.com") || - email.endsWith("@icloud.com") || - email.endsWith("@aol.com") || - email.endsWith("@comcast.net") || - email.endsWith("@verizon.net") || - email.endsWith("@att.net") - ); + const domain = email.split("@")[1]?.toLowerCase(); + return domain ? GENERIC_EMAIL_DOMAINS.has(domain) : false; };apps/web/lib/zod/schemas/misc.ts (1)
111-117: Consider restricting to HTTPS for better security.The schema currently allows both HTTP and HTTPS URLs. For better security, consider restricting to HTTPS only, especially since this is used for workspace logos.
export const publicHostedImageSchema = z .string() .url() .trim() - .refine((url) => url.startsWith("http://") || url.startsWith("https://"), { - message: "Image URL must start with http:// or https://", + .refine((url) => url.startsWith("https://"), { + message: "Image URL must use HTTPS protocol for security", });apps/web/ui/workspaces/create-workspace-form.tsx (2)
45-52: Consider adding validation and error handling for favicon URLs.The logo initialization logic is well-structured but could benefit from validation to ensure the favicon URLs are accessible and meaningful.
Consider adding validation for the favicon URL:
useEffect(() => { if (session?.user?.email && !isGenericEmail(session.user.email)) { const emailDomain = session.user.email.split("@")[1]; - setValue("logo", `${GOOGLE_FAVICON_URL}${emailDomain}`); + const faviconUrl = `${GOOGLE_FAVICON_URL}${emailDomain}`; + // Optionally validate the favicon URL before setting it + setValue("logo", faviconUrl); } else if (session?.user?.image) { setValue("logo", session.user.image); } }, [session?.user]);Alternatively, you could implement a fallback mechanism that tests the favicon URL and falls back to the user's profile image if the favicon fails to load.
186-229: Logo upload implementation looks solid with good UX considerations.The FileUpload component integration is well-configured with appropriate file size limits, target resolution, and error styling. The use of Controller properly integrates with react-hook-form.
Consider the performance implications of
readFile={true}which converts images to base64. For larger images, this could impact memory usage and form submission payload size. The current 2MB limit helps mitigate this, but you might want to consider server-side processing for optimal performance.
π Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
π Files selected for processing (6)
apps/web/app/api/workspaces/route.ts(6 hunks)apps/web/app/app.dub.co/(onboarding)/onboarding/(steps)/workspace/page.tsx(1 hunks)apps/web/lib/actions/send-otp.ts(2 hunks)apps/web/lib/emails.ts(1 hunks)apps/web/lib/zod/schemas/misc.ts(1 hunks)apps/web/ui/workspaces/create-workspace-form.tsx(4 hunks)
π§° Additional context used
π§ Learnings (3)
apps/web/app/api/workspaces/route.ts (2)
Learnt from: TWilson023
PR: #2538
File: apps/web/ui/partners/overview/blocks/commissions-block.tsx:16-27
Timestamp: 2025-06-18T20:26:25.177Z
Learning: In the Dub codebase, components that use workspace data (workspaceId, defaultProgramId) are wrapped in WorkspaceAuth which ensures these values are always available, making non-null assertions safe. This is acknowledged as a common pattern in their codebase, though not ideal.
Learnt from: devkiran
PR: #2433
File: apps/web/ui/modals/add-payment-method-modal.tsx:60-62
Timestamp: 2025-05-29T09:49:19.604Z
Learning: The /api/workspaces/${slug}/billing/payment-methods POST endpoint in the billing API returns either an error (handled by response.ok check) or a response object containing a url property for successful requests.
apps/web/ui/workspaces/create-workspace-form.tsx (2)
Learnt from: TWilson023
PR: #2471
File: apps/web/ui/auth/reset-password-form.tsx:52-65
Timestamp: 2025-06-04T15:09:51.562Z
Learning: In the Dub codebase, server-side validation errors for password fields are handled via toast notifications rather than using react-hook-form's setError method to display field-specific errors. This architectural pattern separates client-side validation feedback (inline) from server-side error handling (toast).
Learnt from: devkiran
PR: #2433
File: apps/web/ui/modals/add-payment-method-modal.tsx:60-62
Timestamp: 2025-05-29T09:49:19.604Z
Learning: The /api/workspaces/${slug}/billing/payment-methods POST endpoint in the billing API returns either an error (handled by response.ok check) or a response object containing a url property for successful requests.
apps/web/app/app.dub.co/(onboarding)/onboarding/(steps)/workspace/page.tsx (1)
Learnt from: TWilson023
PR: #2614
File: apps/web/ui/partners/design/previews/lander-preview.tsx:181-181
Timestamp: 2025-07-09T20:52:56.592Z
Learning: In apps/web/ui/partners/design/previews/lander-preview.tsx, the ellipsis wave animation delay calculation 3 - i * -0.15 is intentionally designed to create negative delays that offset each dot's animation cycle. This pattern works correctly for the intended ellipsis effect and should not be changed to positive incremental delays.
β° Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
π Additional comments (11)
apps/web/lib/zod/schemas/misc.ts (1)
123-123: Schema integration looks correct.The addition of
publicHostedImageSchemato theuploadedImageSchemaunion is properly implemented and maintains the existing functionality while extending support for publicly hosted images.apps/web/lib/actions/send-otp.ts (1)
39-39: Good refactoring to generalize email validation.The change from Gmail-specific validation to using
isGenericEmail()is a logical improvement that:
- Maintains consistency with the new utility function
- Extends the plus sign restriction to all major generic email providers
- Improves code maintainability
apps/web/app/app.dub.co/(onboarding)/onboarding/(steps)/workspace/page.tsx (1)
9-18: Excellent UX improvement for onboarding clarity.The updated description provides better context by explaining what a workspace is before directing users to learn more. The styling choices are appropriate:
cursor-helpindicates interactive help contentdecoration-dottedclearly shows this is a help linkfont-mediumprovides proper visual hierarchyapps/web/app/api/workspaces/route.ts (3)
66-68: LGTM: Proper schema parsing with logo support.The addition of
logoto the request parsing correctly extends the API to support workspace logo uploads while maintaining proper validation through the schema.
103-113: Good approach: Workspace ID reuse and URL construction.The implementation correctly:
- Generates the workspace ID once and reuses it for consistency
- Constructs a logical URL structure using workspace ID and random suffix
- Conditionally sets the logo field only when a logo is provided
174-177: Verify error handling for storage upload failures.The async logo upload approach improves response times, but consider the scenario where the database transaction succeeds but the storage upload fails. The workspace would have a logo URL that doesn't exist.
Is this acceptable behavior, or should there be additional error handling/retry logic for storage upload failures? Since the logo field is optional, failed uploads might be handled gracefully by the frontend when displaying the logo.
apps/web/ui/workspaces/create-workspace-form.tsx (5)
3-3: LGTM! Import changes are well-structured.The new imports are properly organized and all are utilized in the implementation for the logo upload functionality.
Also applies to: 5-6, 11-12
19-19: LGTM! Type definition correctly reflects optional logo field.The optional logo field is appropriately typed as string to handle URL or base64 data.
29-29: LGTM! Session update destructuring is correctly added.The
updatefunction is properly extracted and used in the success handler to refresh session data.
39-39: LGTM! Form control properly added for Controller integration.The
controlis correctly extracted and used with theControllercomponent for the FileUpload field.
172-183: LGTM! Error message styling is well-implemented.The conditional rendering between error messages and helper text provides good user feedback with consistent styling.
|
@CodeRabbit final review please |
|
Tip For best results, initiate chat on the files or code changes. π§© Analysis chainπ Script executed: Length of output: 22744 @steven-tey, I've conducted a comprehensive final review of the workspace logo upload functionality. Overall, this is a well-implemented feature with good architecture and security considerations. Here are my findings: β Excellent Implementation AspectsBackend Architecture:
Frontend UX:
Validation & Security:
π Minor ObservationsProduction Readiness: // Consider removing debug logs before production
console.log("Logo URL is valid:", data.url);
console.log("Logo URL returned error:", data.status, data.url);Potential Enhancement: Email Domain Coverage: π― Code Quality Assessment
The refactoring from Gmail-specific to generic email detection is a good improvement that makes the codebase more maintainable and logical. β¨ Final VerdictThis PR successfully implements workspace logo upload with excellent attention to:
The code is production-ready and follows best practices. Great work on improving the onboarding experience! π |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
π§Ή Nitpick comments (1)
apps/web/app/api/misc/check-favicon/route.ts (1)
30-39: Consider adding timeout to the fetch request.The error handling is comprehensive, but the fetch request lacks a timeout which could cause the API to hang on slow or unresponsive domains.
Add a timeout to prevent hanging requests:
const response = await fetch(faviconUrl, { method: "HEAD", headers: { "User-Agent": "Mozilla/5.0 (compatible; Dub/1.0)", }, + signal: AbortSignal.timeout(5000), // 5 second timeout });
π Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
π Files selected for processing (4)
apps/web/app/api/misc/check-favicon/route.ts(1 hunks)apps/web/app/api/misc/check-workspace-slug/route.ts(1 hunks)apps/web/ui/modals/add-workspace-modal.tsx(1 hunks)apps/web/ui/workspaces/create-workspace-form.tsx(5 hunks)
π§ Learnings (2)
apps/web/ui/modals/add-workspace-modal.tsx (1)
Learnt from: TWilson023
PR: #2538
File: apps/web/ui/partners/overview/blocks/commissions-block.tsx:16-27
Timestamp: 2025-06-18T20:26:25.177Z
Learning: In the Dub codebase, components that use workspace data (workspaceId, defaultProgramId) are wrapped in WorkspaceAuth which ensures these values are always available, making non-null assertions safe. This is acknowledged as a common pattern in their codebase, though not ideal.
apps/web/app/api/misc/check-workspace-slug/route.ts (1)
Learnt from: devkiran
PR: #2433
File: apps/web/ui/modals/add-payment-method-modal.tsx:60-62
Timestamp: 2025-05-29T09:49:19.604Z
Learning: The /api/workspaces/${slug}/billing/payment-methods POST endpoint in the billing API returns either an error (handled by response.ok check) or a response object containing a url property for successful requests.
π§ Files skipped from review as they are similar to previous changes (1)
- apps/web/ui/workspaces/create-workspace-form.tsx
π§° Additional context used
π§ Learnings (2)
apps/web/ui/modals/add-workspace-modal.tsx (1)
Learnt from: TWilson023
PR: #2538
File: apps/web/ui/partners/overview/blocks/commissions-block.tsx:16-27
Timestamp: 2025-06-18T20:26:25.177Z
Learning: In the Dub codebase, components that use workspace data (workspaceId, defaultProgramId) are wrapped in WorkspaceAuth which ensures these values are always available, making non-null assertions safe. This is acknowledged as a common pattern in their codebase, though not ideal.
apps/web/app/api/misc/check-workspace-slug/route.ts (1)
Learnt from: devkiran
PR: #2433
File: apps/web/ui/modals/add-payment-method-modal.tsx:60-62
Timestamp: 2025-05-29T09:49:19.604Z
Learning: The /api/workspaces/${slug}/billing/payment-methods POST endpoint in the billing API returns either an error (handled by response.ok check) or a response object containing a url property for successful requests.
β° Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
π Additional comments (5)
apps/web/app/api/misc/check-workspace-slug/route.ts (1)
9-25: LGTM! Clean slug availability logic.The implementation correctly checks reserved slugs, default redirects, and existing projects. The database query is efficient with minimal field selection, and the return values are consistent.
apps/web/app/api/misc/check-favicon/route.ts (2)
8-13: Good input validation implementation.Proper validation of the required
domainparameter with appropriate error response.
18-23: Efficient favicon existence check.Using a HEAD request is the optimal approach for checking favicon existence without downloading the full resource. The custom User-Agent header is a good practice for identifying the requesting service.
apps/web/ui/modals/add-workspace-modal.tsx (2)
43-52: Excellent onboarding improvement with descriptive text.The updated header content provides clear guidance about workspaces and includes a well-styled "Learn more" link with proper hover effects and accessibility considerations (underline decoration and color transitions).
57-66: Good fix for consistent modal behavior.Moving
setShowAddWorkspaceModal(false)outside the conditional branches ensures the modal always closes after workspace creation, regardless of whether the OAuth flow or regular flow is triggered.
|
@CodeRabbit made some final changes to uploadedImageSchema, can you checK? |
|
Tip For best results, initiate chat on the files or code changes. π§© Analysis chainπ Script executed: Length of output: 4153 @steven-tey, I've reviewed the final β Schema Design AssessmentUnion Structure: uploadedImageSchema = z.union([
base64ImageSchema, // Base64 encoded images with async validation
storedR2ImageUrlSchema, // R2 storage URLs
GOOGLE_FAVICON_URL schema // Google favicon URLs
])Strong Points:
Validation Coverage:
π Production ReadyThe schema is well-architected and handles all workspace logo use cases:
Perfect implementation for the logo upload feature! The union approach provides flexibility while maintaining strict validation. π |
Summary by CodeRabbit
New Features
Enhancements
Bug Fixes