feat: implement invite link generation and deep-link onboarding (#16)#19
Conversation
…-Org#16) Add "Invite Member" link generation and the deep-link onboarding router. Invite links & sharing: - InviteButton generates a unique short URL (/invite/<code>) for a group - Web Share API on mobile, plus WhatsApp deep link and copy-to-clipboard - groupsService mock (localStorage) creates/resolves invite codes Deep-link onboarding router: - /invite/[code] async page (Next 16 awaited params) -> InviteConfirm - unauthenticated visitors are routed through signup first, then returned to the group Join confirmation via ?redirect=, preserving context - register/login honor ?redirect= with an open-redirect guard Supporting mocks (swappable at TODO seams; no backend/auth exists yet): - minimal localStorage auth via useSyncExternalStore (SSR-safe) - seeded demo groups on the /groups dashboard Verified: lint, tsc --noEmit, prettier --check, and next build all pass.
|
@adetomiwa21 is attempting to deploy a commit to the omodunni241-4260's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (3)
📝 WalkthroughWalkthroughThe change replaces placeholder authentication and groups pages with localStorage-backed auth, seeded group and invite services, reusable authentication forms, group invitation sharing, and invite deep-link onboarding with authenticated group joining. ChangesAuthentication and group invite flow
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant GroupDashboard
participant InviteButton
participant InviteConfirm
participant groupsService
participant AuthForm
GroupDashboard->>InviteButton: generate invite
InviteButton->>groupsService: createInvite(group.id)
InviteButton-->>InviteConfirm: share /invite/code
InviteConfirm->>groupsService: getInvite(code)
InviteConfirm->>AuthForm: redirect unauthenticated visitor with redirect
AuthForm-->>InviteConfirm: return authenticated visitor to invite route
InviteConfirm->>groupsService: joinGroup(group.id)
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint install timed out. The project may have too many dependencies for the sandbox. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (2)
src/context/AuthContext.tsx (1)
60-60: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
clientSnapshot.isLoadingis alwaysfalse— the|| clientSnapshot.isLoadingcheck is dead code.
clientSnapshotis initialized withisLoading: false(line 50) and the only assignment (line 68) also setsisLoading: false. This means the|| clientSnapshot.isLoadingbranch never triggers, making it misleading. If the intent was to start withisLoading: trueand transition on first read, the initial value on line 50 should betrue; otherwise, simplify the condition to justraw !== cachedRaw.♻️ Simplify the condition
- if (raw !== cachedRaw || clientSnapshot.isLoading) { + if (raw !== cachedRaw) {🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/context/AuthContext.tsx` at line 60, Remove the dead clientSnapshot.isLoading check from the condition in AuthContext, leaving the cache update path driven solely by raw !== cachedRaw; keep the existing isLoading: false initialization and assignment unchanged.src/components/groups/InviteConfirm/InviteConfirm.tsx (1)
49-54: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winRedirect target embeds
codeunescaped in the query string.
/register?redirect=/invite/${code}isn't passed throughencodeURIComponent; a code containing&/=/#would corrupt the query string and break the round-trip back to this invite (mitigated only incidentally bysafeRedirect's fallback to/dashboard).♻️ Proposed fix
- router.replace(`/register?redirect=/invite/${code}`); + router.replace(`/register?redirect=${encodeURIComponent(`/invite/${code}`)}`);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/groups/InviteConfirm/InviteConfirm.tsx` around lines 49 - 54, Update the unauthenticated redirect in InviteConfirm to encode the invite code with encodeURIComponent before embedding it in the /register redirect query parameter. Preserve the existing return-to-invite behavior and router.replace flow.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/components/auth/AuthForm/AuthForm.tsx`:
- Around line 114-118: Update safeRedirect to reject redirect values beginning
with "/\\" in addition to protocol-relative "//" paths, ensuring
backslash-prefixed paths return null while valid same-site relative redirects
remain accepted.
- Line 3: Update the safeRedirect validation in AuthForm so redirect values
containing backslashes are rejected before router.replace, while preserving
valid same-origin single-slash paths and rejecting protocol-relative URLs.
In `@src/components/groups/InviteConfirm/InviteConfirm.tsx`:
- Around line 64-70: Update handleJoin to wrap groupsService.joinGroup in error
handling and always reset joining state when the request settles. Keep the
joined phase transition only on success, and preserve the existing behavior for
a missing group.
- Around line 39-62: Handle promise rejection in the invite-loading effect
around groupsService.getInvite and update phase to the existing error state when
retrieval fails, while respecting the active guard so stale requests cannot
update state after cleanup. Preserve the current success, invalid-invite,
authentication redirect, and confirmation flows.
---
Nitpick comments:
In `@src/components/groups/InviteConfirm/InviteConfirm.tsx`:
- Around line 49-54: Update the unauthenticated redirect in InviteConfirm to
encode the invite code with encodeURIComponent before embedding it in the
/register redirect query parameter. Preserve the existing return-to-invite
behavior and router.replace flow.
In `@src/context/AuthContext.tsx`:
- Line 60: Remove the dead clientSnapshot.isLoading check from the condition in
AuthContext, leaving the cache update path driven solely by raw !== cachedRaw;
keep the existing isLoading: false initialization and assignment unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 803eaa8d-11bd-48a9-bccf-23cade3a50e1
📒 Files selected for processing (17)
src/app/(auth)/login/page.tsxsrc/app/(auth)/register/page.tsxsrc/app/(dashboard)/groups/page.tsxsrc/app/invite/[code]/page.tsxsrc/app/layout.tsxsrc/components/auth/AuthForm/AuthForm.tsxsrc/components/auth/AuthForm/index.tssrc/components/groups/InviteButton/InviteButton.tsxsrc/components/groups/InviteButton/index.tssrc/components/groups/InviteConfirm/InviteConfirm.tsxsrc/components/groups/InviteConfirm/index.tssrc/context/AuthContext.tsxsrc/hooks/useAuth.tssrc/services/api/groups.tssrc/types/group.tssrc/types/invite.tssrc/utils/invite.ts
|
@adetomiwa21 please fix the review coderabbitai i dropped, you can use the Prompt for all review comments with AI agents given to make it seamless |
|
i will work on it now, thanks for the feedback |
- reject any backslash in safeRedirect (open-redirect hardening) - handle invite resolution failure instead of infinite loading - add try/catch/finally + error feedback to group join - encode invite code in signup redirect round-trip - drop dead clientSnapshot.isLoading branch in AuthContext
|
@Queenode kindly review the changes has been made |
|
Thank you for your contribution @adetomiwa21 . |
Closes #16
Add "Invite Member" link generation and the deep-link onboarding router.
Invite links & sharing:
) for a groupDeep-link onboarding router:
Supporting mocks (swappable at TODO seams; no backend/auth exists yet):
Verified: lint, tsc --noEmit, prettier --check, and next build all pass.
Summary by CodeRabbit