Improve activity log UX and team membership sync#111
Merged
Conversation
Improve local dev reliability by aligning API/socket base URLs, reducing duplicate sync/session requests, and wiring frontend/backend startup flow to avoid repeated connection failures. Made-with: Cursor
Apply multi-color circular team emblems and align button/navbar styling so team identity remains consistent across settings and people screens. Made-with: Cursor
Throttle activity fetch bursts and improve data wiring for current user/team context so activity filters receive stable owner and membership metadata. Made-with: Cursor
Refine owner-only team selection, transparent selector styling, and member/profile resolution so team and user analytics remain accurate and visually consistent. Made-with: Cursor
Normalize owner/member fields and sync create/join events to Firestore user/team documents so ownership and membership stay in sync across clients. Made-with: Cursor
Add backend team lifecycle hooks for Firestore consistency (join/leave/remove/delete/ transfer) and fix Firebase Admin initialization plus client write throttling safeguards. Made-with: Cursor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Pull request overview
This PR improves Activity Log/People/Settings UX and strengthens team membership synchronization between the backend and Firestore, while also stabilizing local development by separating socket base URLs and tuning sync/write behavior.
Changes:
- Introduces
SOCKET_BASE_URLand updates multiple socket.io clients/providers to use it with consistent transport/reconnect settings. - Improves Activity Log filtering UX (team/member selectors with logos) and adds more robust team/user resolution and Firestore team persistence syncing.
- Adds backend-to-Firestore team lifecycle sync helpers and relaxes dev rate limits; updates dev script to run frontend+backend together.
Reviewed changes
Copilot reviewed 25 out of 26 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| src/services/taskSocketService.ts | Switch tasks socket to SOCKET_BASE_URL and adjust transports/reconnect behavior. |
| src/services/chatSocketService.ts | Switch chat socket to SOCKET_BASE_URL and adjust transports/reconnect behavior. |
| src/pages/ProjectDetails.tsx | Uses SOCKET_BASE_URL for project socket connection with reconnect options. |
| src/lib/utils.ts | Adds SOCKET_BASE_URL env resolution (dev/prod). |
| src/lib/team-logos.ts | Reworks team logos into generated SVG icons + color palettes for consistent rendering. |
| src/lib/SocketIOProvider.ts | Notes socket now uses SOCKET_BASE_URL + reconnect options. |
| src/hooks/useTeamPersistence.ts | Adds normalization + upsert/sync helpers to keep Firestore team/user metadata aligned with backend. |
| src/hooks/useTaskPersistence.ts | Adds throttling/fingerprinting/cooldown to reduce Firestore task-stat write pressure. |
| src/hooks/usePresence.ts | Presence socket now uses SOCKET_BASE_URL with reconnection options. |
| src/hooks/useNotePresence.ts | Note presence socket now uses SOCKET_BASE_URL. |
| src/hooks/use-user-sync.ts | Adds dev gating and swallows backend-sync errors to keep dev UX stable. |
| src/hooks/use-activity-tracker.ts | Avoids duplicate session start by reusing localStorage session id. |
| src/components/views/SettingsView.tsx | UI styling updates + team rename UX adjustments and logo rendering. |
| src/components/views/PeopleView.tsx | UI styling updates + team logo rendering in sidebar/team header. |
| src/components/views/JoinTeamDialog.tsx | Passes joined team payload to Firestore sync when available. |
| src/components/views/DesktopView.tsx | Throttles activity refetches, normalizes API responses, and passes richer team/user context into Activity Log. |
| src/components/views/CreateTeamDialog.tsx | Aligns with backend create response shape and updates logo picker rendering. |
| src/components/views/ActivityLogView.tsx | Major Activity Log filter UX + robust team/member resolution + Firestore sync from API payloads. |
| package.json | npm run dev now runs frontend+backend concurrently. |
| package-lock.json | Adds concurrently dependency. |
| backend/services/teamFirebaseSync.js | New Firestore sync service for team lifecycle events (create/join/leave/remove/delete/transfer). |
| backend/services/firebaseAdmin.js | New shared firebase-admin init helper for Firestore sync. |
| backend/routes/userRoutes.js | Hardens /sync by requiring/deriving email and simplifying upsert handling. |
| backend/routes/teamRoutes.js | Hooks Firestore sync into team lifecycle routes with guarded “runSync”. |
| backend/middleware/authMiddleware.js | Centralizes firebase-admin init via shared helper + ADC fallback. |
| backend/index.js | Adjusts rate limiting for dev vs production. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| }; | ||
|
|
||
| const getFirestoreAdmin = () => { | ||
| if (firestoreInstance) return firestoreInstance; |
| if (!admin.apps.length) { | ||
| admin.initializeApp({ | ||
| credential: admin.credential.cert(serviceAccount), | ||
| projectId: serviceAccount.project_id || process.env.VITE_FIREBASE_PROJECT_ID, |
Comment on lines
+88
to
+91
| // Coalesce frequent writes caused by rapid UI/state updates. | ||
| if (now - lastSavedAtRef.current < SAVE_DEBOUNCE_MS) { | ||
| return; | ||
| } |
Comment on lines
+1068
to
+1077
| <Select | ||
| value={selectedTeamId === 'all' ? undefined : selectedTeamId} | ||
| onValueChange={(v) => { | ||
| setSelectedTeamId(v); | ||
| if (v === 'all') { | ||
| setSelectedUserId(currentUserId || 'all'); | ||
| } else { | ||
| setSelectedUserId('all'); | ||
| } | ||
| }} |
Comment on lines
1128
to
+1130
| <Select value={selectedUserId} onValueChange={setSelectedUserId}> | ||
| <SelectTrigger className="w-[140px] h-9 bg-white/5 border-white/10 text-[11px] text-text2"> | ||
| <SelectValue placeholder="Select Member" /> | ||
| <SelectTrigger className="w-[170px] h-9 bg-white/[0.04] border-white/20 text-[11px] text-text2 backdrop-blur-md hover:bg-white/[0.08]"> | ||
| {selectedUserId !== 'all' && selectedMemberOption ? ( |
Comment on lines
15
to
27
| const unsubscribe = auth.onAuthStateChanged(async (user) => { | ||
| if (user && !sessionIdRef.current) { | ||
| // DesktopView already owns session start. | ||
| // Reuse the persisted active session to avoid duplicate /sessions/start calls. | ||
| try { | ||
| const token = await user.getIdToken(); | ||
| const res = await fetch(`${API_BASE_URL}/api/sessions/start`, { | ||
| method: 'POST', | ||
| headers: { | ||
| 'Content-Type': 'application/json', | ||
| 'Authorization': `Bearer ${token}` | ||
| }, | ||
| body: JSON.stringify({ userId: user.uid }), | ||
| }); | ||
| if (res.ok) { | ||
| const session = await res.json(); | ||
| sessionIdRef.current = session._id; | ||
| const raw = localStorage.getItem('currentSession'); | ||
| if (raw) { | ||
| const parsed = JSON.parse(raw); | ||
| sessionIdRef.current = parsed?.id || null; | ||
| } | ||
| } catch (e) { | ||
| console.error("Failed to start session:", e); | ||
| } catch { | ||
| sessionIdRef.current = null; | ||
| } |
Comment on lines
+106
to
+132
| await setDoc(doc(db, "teams", team.id), { | ||
| name: team.name, | ||
| ownerId: team.ownerId, | ||
| leaderId: team.ownerId, | ||
| members: team.members, | ||
| inviteCode: team.inviteCode, | ||
| logoId: team.logoId || "rocket", | ||
| createdAt: team.createdAt || new Date().toISOString(), | ||
| updatedAt: new Date().toISOString(), | ||
| }, { merge: true }); | ||
|
|
||
| if (team.ownerId) { | ||
| await setDoc(doc(db, "users", team.ownerId), { | ||
| uid: team.ownerId, | ||
| ownedTeamIds: arrayUnion(team.id), | ||
| teamMemberships: arrayUnion(team.id), | ||
| updatedAt: new Date().toISOString(), | ||
| }, { merge: true }); | ||
| } | ||
|
|
||
| for (const memberId of team.members) { | ||
| await setDoc(doc(db, "users", memberId), { | ||
| uid: memberId, | ||
| teamMemberships: arrayUnion(team.id), | ||
| updatedAt: new Date().toISOString(), | ||
| }, { merge: true }); | ||
| } |
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.
Summary
Test plan
teams/usersmetadata.