Manage User#6
Conversation
refactor: restructure layout components for public and protected routes fix: update HeaderUser component to include admin options and improve navigation chore: update auth-client to include admin client plugin
…dd Legend State for state management
…ponents; add pagination
…een; add toast notification for login errors; implement session-based redirection in LandingScreen
…gination component to use react-native
…g; update user management model to support filters
…rch criteria to email; refactor UsersList component for improved loading and error handling
…us filter from user management model and related components
…te dialog primitives
…to include new dependencies
…ing state; update container guidelines in documentation
…ion; update admin layout for navigation
… file paths to align with Expo Router structure
…agement; update imports in manage users list container
…row to include view details button
…etail screen and update navigation for user details
…n 1.3.4; refactor UserDetailContainer and UserDetailModel for improved state management and form handling
…ONS in user detail model
…ainer for improved UI and functionality
…tModel$ prop for improved consistency and functionality
…Model; update UI handling in UserDetailContainer
…consistent state management
…ate UI in UserDetailContainer
Reviewer's GuideThis PR refactors the 'Manage Users' feature by moving list subcomponents into a container structure, renaming the model prop, and integrating expo-router hooks for data refresh; enhances table rows with navigable action buttons; updates dependencies; and introduces a comprehensive user detail screen backed by a new UserDetailModel and corresponding UI components, as well as new generic Badge and Separator primitives. Sequence diagram for navigating from user list to user detailsequenceDiagram
actor Admin
participant UsersList
participant UserTableRow
participant Router
participant UserDetailContainer
participant UserDetailModel
Admin->>UsersList: View list of users
UsersList->>UserTableRow: Render each user row
Admin->>UserTableRow: Tap 'View User' button
UserTableRow->>Router: router.push('/admin/user-detail/:id')
Router->>UserDetailContainer: Mount with user id
UserDetailContainer->>UserDetailModel: fetchUserById({ id })
UserDetailContainer->>UserDetailModel: fetchUserSessionsById({ id })
UserDetailModel-->>UserDetailContainer: Provide user data and sessions
UserDetailContainer-->>Admin: Display user detail screen
Class diagram for new Badge and Separator UI primitivesclassDiagram
class Badge {
+variant: 'default' | 'secondary' | 'destructive' | 'outline'
+asChild: boolean
+children
}
class Separator {
+orientation: 'horizontal' | 'vertical'
+decorative: boolean
}
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
PR Reviewer Guide 🔍Here are some key observations to aid the review process:
|
There was a problem hiding this comment.
Hey @chakrihacker - I've reviewed your changes - here's some feedback:
- The UserDetailModel class is quite large (~760 lines); consider splitting it into smaller modules (e.g. separate API service, form state, and utility helpers) to improve readability and maintainability.
- The
$suffix onuserListModel$(and similar model props) is a new convention—make sure it’s documented and applied consistently so other developers immediately recognize these as observables. - The useFocusEffect hook will re‐fetch users on every focus if any data exists; you may want to add a more precise condition (e.g. compare a last‐updated timestamp or track navigation params) to avoid redundant API calls.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The UserDetailModel class is quite large (~760 lines); consider splitting it into smaller modules (e.g. separate API service, form state, and utility helpers) to improve readability and maintainability.
- The `$` suffix on `userListModel$` (and similar model props) is a new convention—make sure it’s documented and applied consistently so other developers immediately recognize these as observables.
- The useFocusEffect hook will re‐fetch users on every focus if any data exists; you may want to add a more precise condition (e.g. compare a last‐updated timestamp or track navigation params) to avoid redundant API calls.Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
PR Code Suggestions ✨Explore these optional code suggestions:
|
||||||||||||||
|
Caution Review failedThe pull request is closed. 📝 WalkthroughWalkthroughThis update introduces a detailed admin user detail feature, including new UI components, a stateful model for user/session management, and a full user detail container. It refactors admin user management components, adds reusable UI primitives (badge, separator), updates dependencies, and improves documentation with method parameter guidelines and naming conventions. The codebase now supports user detail viewing, editing, session management, ban/delete flows, and enhanced user list filtering. Changes
Sequence Diagram(s)sequenceDiagram
participant Admin as Admin User
participant Screen as UserDetailScreen
participant Container as UserDetailContainer
participant Model as UserDetailModel
participant API as Backend API
Admin->>Screen: Navigates to /admin/user-detail/[id]
Screen->>Container: Render UserDetailContainer
Container->>Model: Initialize, fetchUserById(id)
Model->>API: GET /users/:id
API-->>Model: User data
Model->>Container: Update observable state
Container->>Admin: Display user info, sessions, actions
Admin->>Container: Edit user fields / trigger actions
Container->>Model: Call update/ban/delete/session methods
Model->>API: Perform corresponding API calls
API-->>Model: Response
Model->>Container: Update state, show feedback
Container->>Admin: Update UI, modals, notifications
Estimated code review effort🎯 4 (Complex) | ⏱️ ~40 minutes Possibly related PRs
Poem
Note ⚡️ Unit Test Generation is now available in beta!Learn more here, or try it out under "Finishing Touches" below. 📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (4)
✨ Finishing Touches
🧪 Generate unit tests
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. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (5)
src/models/admin/user-detail.model.ts (2)
136-143: Consider using a dedicated endpoint for fetching a single user if available.Using
listUserswith a filter to fetch a single user may be less efficient than a dedicated endpoint. If Better Auth provides agetUseror similar method, consider using that instead.
464-465: Add radix parameter to parseInt for clarity.Always specify the radix parameter when using
parseIntto avoid potential parsing issues.- const days = parseInt(banDuration); + const days = parseInt(banDuration, 10);src/containers/admin/user-detail.container.tsx (3)
6-27: Use the prescribed path-alias for UI importsCoding guidelines specify importing UI primitives via
@/src/components/ui/*, whereas this file uses~/components/ui/*.
Please align the alias to avoid fragmented import styles across the codebase.
56-62: Trim unnecessary dependencies inuseEffect
userDetailModel$is a stable ref; keeping it in the dependency array causes the effect to re-register needlessly on every render (eslint will still flag but the value is constant).-}, [id, userDetailModel$]); +}, [id]);This avoids superfluous executions while preserving correctness.
63-65: Avoid repeated date parsing on every render
formatDateis recreated each render and each call instantiatesDate, which can be hot when many rows re-render (e.g. long session lists). Consider:const formatDate = useCallback( (d: string | Date) => dayjs(d).format('LLL'), [], );or memoise pre-formatted fields in the model.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
bun.lockis excluded by!**/*.lock
📒 Files selected for processing (12)
.github/copilot-instructions.md(1 hunks)package.json(2 hunks)src/app/(public)/(protected)/admin/manage-users.tsx(1 hunks)src/app/(public)/(protected)/admin/user-detail/[id].tsx(1 hunks)src/components/admin/users-list-filters.tsx(0 hunks)src/components/ui/badge.tsx(1 hunks)src/components/ui/separator.tsx(1 hunks)src/containers/admin/components/user-table-row.tsx(3 hunks)src/containers/admin/components/users-list-filters.tsx(1 hunks)src/containers/admin/manage-users-list.container.tsx(2 hunks)src/containers/admin/user-detail.container.tsx(1 hunks)src/models/admin/user-detail.model.ts(1 hunks)
💤 Files with no reviewable changes (1)
- src/components/admin/users-list-filters.tsx
🧰 Additional context used
📓 Path-based instructions (4)
src/app/**/*.tsx
📄 CodeRabbit Inference Engine (.github/copilot-instructions.md)
src/app/**/*.tsx: src/app/ contains all routes using Expo Router file-based routing
Expo Router requires specific file naming conventions for routing
Files:
src/app/(public)/(protected)/admin/manage-users.tsxsrc/app/(public)/(protected)/admin/user-detail/[id].tsx
src/**/*.{ts,tsx}
📄 CodeRabbit Inference Engine (.github/copilot-instructions.md)
src/**/*.{ts,tsx}: Use Platform.OS and process.env.EXPO_OS for conditional logic
Consider all platforms (iOS/Android/Web) when using native APIs
Files:
src/app/(public)/(protected)/admin/manage-users.tsxsrc/containers/admin/components/user-table-row.tsxsrc/app/(public)/(protected)/admin/user-detail/[id].tsxsrc/components/ui/badge.tsxsrc/containers/admin/user-detail.container.tsxsrc/containers/admin/components/users-list-filters.tsxsrc/models/admin/user-detail.model.tssrc/containers/admin/manage-users-list.container.tsxsrc/components/ui/separator.tsx
src/**/*.tsx
📄 CodeRabbit Inference Engine (.github/copilot-instructions.md)
Import UI components from @/src/components/ui/ using path aliases
Files:
src/app/(public)/(protected)/admin/manage-users.tsxsrc/containers/admin/components/user-table-row.tsxsrc/app/(public)/(protected)/admin/user-detail/[id].tsxsrc/components/ui/badge.tsxsrc/containers/admin/user-detail.container.tsxsrc/containers/admin/components/users-list-filters.tsxsrc/containers/admin/manage-users-list.container.tsxsrc/components/ui/separator.tsx
src/components/ui/**/*.tsx
📄 CodeRabbit Inference Engine (.github/copilot-instructions.md)
src/components/ui/**/*.tsx: UI components use NativeWind's className prop with Tailwind utility classes
Use cva (class-variance-authority) for creating variant-based component APIs
Access theme values through CSS custom properties and Tailwind utilities
UI components in src/components/ui/ follow React.forwardRef pattern with displayName
Use Tailwind's responsive prefixes (sm:, md:, lg:) and NativeWind's responsive utilities
Use web: prefix for web-only styles, and conditional rendering for native-specific components
Place UI components in src/components/ui/ with proper TypeScript interfaces
Always use NativeWind's className prop with Tailwind utility classes
Define variants using cva (class-variance-authority) for type-safe component APIs
Use Tailwind's spacing utilities (p-4, m-2, gap-3, etc.)
Use Tailwind's typography utilities (text-lg, font-semibold, etc.)
Toggle between light/dark themes using className conditionals and CSS variables
Use platform-specific prefixes (web:, ios:, android:) for conditional styles
Files:
src/components/ui/badge.tsxsrc/components/ui/separator.tsx
🧬 Code Graph Analysis (6)
src/app/(public)/(protected)/admin/manage-users.tsx (1)
src/containers/admin/manage-users-list.container.tsx (1)
UsersList(92-153)
src/containers/admin/components/user-table-row.tsx (2)
src/components/ui/button.tsx (1)
Button(80-80)src/components/ui/text.tsx (1)
Text(26-26)
src/app/(public)/(protected)/admin/user-detail/[id].tsx (1)
src/containers/admin/user-detail.container.tsx (1)
UserDetailContainer(34-538)
src/components/ui/badge.tsx (2)
src/components/ui/text.tsx (1)
TextClassContext(26-26)src/lib/utils.ts (1)
cn(4-6)
src/containers/admin/components/users-list-filters.tsx (5)
src/models/admin/manage-users-list.model.ts (1)
ManageUsersListModel(151-381)src/components/ui/select.tsx (5)
SelectTrigger(188-188)Select(180-180)SelectValue(189-189)SelectContent(181-181)SelectItem(183-183)src/components/ui/text.tsx (1)
Text(26-26)src/components/ui/input.tsx (1)
Input(25-25)src/components/ui/button.tsx (1)
Button(80-80)
src/components/ui/separator.tsx (1)
src/lib/utils.ts (1)
cn(4-6)
🔇 Additional comments (19)
package.json (1)
15-15: LGTM! Dependency updates are appropriate.The minor version updates to
better-authpackages and the addition of@rn-primitives/separatoralign well with the PR's admin user management enhancements.Also applies to: 32-32, 38-38
.github/copilot-instructions.md (1)
8-23: Excellent addition to the coding guidelines!The method parameters section clearly documents the object destructuring pattern that improves code maintainability and type safety. The examples effectively illustrate the preferred approach.
src/models/admin/user-detail.model.ts (1)
749-749: Good security practice!Resetting
emailVerifiedtofalsewhen the email is changed ensures users must re-verify their new email address.src/app/(public)/(protected)/admin/manage-users.tsx (1)
16-16: LGTM! Prop name updated to match the component interface.The prop name change to
userListModel$aligns with the updatedUsersListcomponent interface and follows the observable naming convention.src/app/(public)/(protected)/admin/user-detail/[id].tsx (1)
1-5: LGTM! Clean implementation following Expo Router patterns.The screen component correctly wraps the
UserDetailContainerand follows the established pattern of separating route components from containers.src/containers/admin/components/user-table-row.tsx (2)
1-2: LGTM! Import statements follow coding guidelines.The imports correctly use path aliases and follow the established patterns for UI components and navigation.
Also applies to: 5-5
35-38: LGTM! Clean navigation handler implementation.The handler function properly implements navigation to the user detail screen with a clear route structure.
src/containers/admin/manage-users-list.container.tsx (4)
4-4: LGTM! Import updates are consistent with the refactoring.The addition of
useFocusEffectand updated import paths align with the component reorganization and new data refresh requirements.Also applies to: 11-13
17-17: LGTM! Prop naming follows observable conventions.The rename from
modeltouserListModel$improves clarity and follows the observable naming pattern consistently throughout the component.Also applies to: 93-93, 125-125
99-108: LGTM! Well-implemented focus effect for data freshness.The conditional refresh logic prevents unnecessary API calls while ensuring data stays current when navigating back to the screen.
110-118: LGTM! Efficient column width calculation with proper memoization.The column width logic is well-structured with appropriate performance optimizations and clear minimum width definitions.
src/containers/admin/components/users-list-filters.tsx (4)
42-50: LGTM! Well-implemented debouncing with proper cleanup.The 300ms debounce delay and conditional search trigger provide good UX while preventing excessive API calls.
31-39: LGTM! Proper platform-specific safe area handling.The different bottom inset calculations for iOS and Android appropriately handle platform-specific UI behaviors.
52-65: LGTM! Comprehensive role selection with good UX.The select implementation provides clear options, proper value binding, and visual feedback when filters are active.
Also applies to: 87-115
67-134: LGTM! Well-structured responsive layout with clear separation of concerns.The filter and action button layout provides good UX with proper spacing, responsive behavior, and logical grouping.
src/components/ui/badge.tsx (3)
7-36: LGTM! Comprehensive variant system with proper web accessibility.The badge and text variants provide good coverage with appropriate hover states, focus rings, and consistent color schemes.
45-47: LGTM! Proper TextClassContext integration for automatic text styling.The context provider ensures child Text components automatically receive appropriate styling based on the badge variant.
38-49: LGTM! Well-structured component with proper TypeScript typing and composition support.The component follows established patterns with good asChild support, proper exports, and clean implementation.
Also applies to: 51-52
src/containers/admin/user-detail.container.tsx (1)
174-202: ConfirmSelectvalueshape aligns with component API
valueis passed an{ value, label }object, but laterSelectItemsupplies only stringvalues.
If the control expects a primitive (common in our UI kit), this will break selection & controlled-value behaviour. Double-check the prop contract or cast tostring.
| function Separator({ | ||
| className, | ||
| orientation = 'horizontal', | ||
| decorative = true, | ||
| ...props | ||
| }: SeparatorPrimitive.RootProps & { | ||
| ref?: React.RefObject<SeparatorPrimitive.RootRef>; | ||
| }) { | ||
| return ( | ||
| <SeparatorPrimitive.Root | ||
| decorative={decorative} | ||
| orientation={orientation} | ||
| className={cn( | ||
| 'shrink-0 bg-border', | ||
| orientation === 'horizontal' ? 'h-[1px] w-full' : 'h-full w-[1px]', | ||
| className | ||
| )} | ||
| {...props} | ||
| /> | ||
| ); | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Consider using React.forwardRef for proper ref handling.
The component accepts a ref prop but doesn't use React.forwardRef, which may not forward the ref correctly to the underlying primitive.
Apply this diff to properly handle ref forwarding:
-function Separator({
- className,
- orientation = 'horizontal',
- decorative = true,
- ...props
-}: SeparatorPrimitive.RootProps & {
- ref?: React.RefObject<SeparatorPrimitive.RootRef>;
-}) {
+const Separator = React.forwardRef<
+ SeparatorPrimitive.RootRef,
+ SeparatorPrimitive.RootProps
+>(({ className, orientation = 'horizontal', decorative = true, ...props }, ref) => {
return (
<SeparatorPrimitive.Root
+ ref={ref}
decorative={decorative}
orientation={orientation}
className={cn(
'shrink-0 bg-border',
orientation === 'horizontal' ? 'h-[1px] w-full' : 'h-full w-[1px]',
className
)}
{...props}
/>
);
-}
+});
+
+Separator.displayName = 'Separator';🤖 Prompt for AI Agents
In src/components/ui/separator.tsx around lines 5 to 25, the Separator component
accepts a ref prop but does not use React.forwardRef, so the ref is not
forwarded to the underlying SeparatorPrimitive.Root element. To fix this, wrap
the Separator function with React.forwardRef and pass the ref as the second
argument, then forward this ref to SeparatorPrimitive.Root via its ref prop.
Adjust the component signature accordingly to support ref forwarding properly.
| <Label>Ban Reason *</Label> | ||
| <Input | ||
| value={formData.banReason} | ||
| onChangeText={(text) => | ||
| userDetailModel$.setFormData({ banReason: text }) | ||
| } | ||
| placeholder="Enter reason for ban" | ||
| multiline | ||
| numberOfLines={3} | ||
| /> |
There was a problem hiding this comment.
Enforce non-empty “Ban Reason” before submission
The dialog labels the field as mandatory (*), yet handleBanUser can be triggered while it’s empty. Validate in the model or disable the action until a reason is provided.
🤖 Prompt for AI Agents
In src/containers/admin/user-detail.container.tsx around lines 441 to 450, the
"Ban Reason" input is marked mandatory but the submission handler handleBanUser
allows empty values. To fix this, add validation in the userDetailModel$ to
check that banReason is non-empty before allowing submission, or disable the ban
action button until formData.banReason contains text. This ensures the user
cannot submit without providing a ban reason.
…tus handling in UserDetailModel
- Implement EmailModel for handling email verification and password reset functionalities. - Create FormModel to manage user detail editing forms and track changes. - Develop ModerationModel for user moderation actions including ban, unban, and delete operations. - Introduce SessionModel for managing user sessions, including fetching, revoking, and displaying session details. - Add UserModel for core user data operations, including fetching and updating user information and roles. - Implement utility function getErrorMessage for standardized error handling across models.
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (12)
src/utils/error.ts (1)
7-9: Consider enhancing error type handling.The current implementation handles
Errorinstances well, but could be more robust by also handling string errors and objects with message properties.Consider this enhanced version:
export function getErrorMessage(error: unknown, fallback: string): string { - return error instanceof Error ? error.message : fallback; + if (error instanceof Error) { + return error.message; + } + if (typeof error === 'string') { + return error; + } + if (error && typeof error === 'object' && 'message' in error && typeof error.message === 'string') { + return error.message; + } + return fallback; }src/models/admin/user-detail/form.model.ts (2)
14-20: Use consistent role constants.The default role value
"user"is hardcoded but should use a constant for consistency with role validation elsewhere in the codebase.+import { ROLE_OPTIONS } from "./user.model"; + constructor() { this.obs = observable({ name: "", email: "", - role: "user", + role: ROLE_OPTIONS[0].value, }); }
22-30: Consider adding input validation.The
setFormDatamethod accepts any partial updates without validation. Consider adding validation for email format and role values to prevent invalid states.setFormData( updates: Partial<{ name: string; email: string; role: string; }>, ): void { + // Validate email format if provided + if (updates.email && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(updates.email)) { + throw new Error('Invalid email format'); + } + + // Validate role if provided + if (updates.role && !ROLE_OPTIONS.some(option => option.value === updates.role)) { + throw new Error('Invalid role value'); + } + this.obs.assign(updates); }src/models/admin/user-detail/email.model.ts (3)
26-26: Simplify parameter destructuring.The method uses object destructuring for a single parameter. Consider using a direct parameter for simplicity.
-async resendVerificationEmail({ email }: { email: string }): Promise<void> { +async resendVerificationEmail(email: string): Promise<void> {This would require updating the caller as well.
51-51: Simplify parameter destructuring.Same suggestion as above - consider using a direct parameter for consistency and simplicity.
-async resetPassword({ email }: { email: string }): Promise<void> { +async resetPassword(email: string): Promise<void> {
29-46: Consider extracting common error handling pattern.Both async methods follow an identical error handling pattern. Consider extracting this to reduce code duplication.
You could create a private helper method:
private async executeEmailOperation<T>( statusKey: 'resendVerificationStatus' | 'resetPasswordStatus', operation: () => Promise<T>, successMessage: string, errorMessage: string ): Promise<void> { this.obs[statusKey].set("loading"); try { const result = await operation(); this.obs[statusKey].set("success"); toast.success(successMessage); return result; } catch (error) { const errorMsg = getErrorMessage(error, errorMessage); this.obs[statusKey].set("error"); toast.error(errorMsg); throw error; } }src/models/admin/user-detail/user.model.ts (3)
8-20: Enhance User interface type safety.Consider making some fields more type-safe and adding JSDoc comments for clarity.
+/** + * Extended user interface with admin-specific fields + */ export interface User { id: string; email: string; name?: string; banned?: boolean; banReason?: string; banExpires?: string; lastLogin?: string; - role?: string; + role?: "user" | "admin"; emailVerified?: boolean; createdAt: string; updatedAt?: string; }
75-79: Improve type safety in user data transformation.The type assertion
as Usercould be avoided with better typing.this.obs.user.set({ ...user, createdAt: user.createdAt.toISOString(), updatedAt: user.updatedAt?.toISOString(), -} as User); +});The type assertion isn't needed if the User interface properly matches the API response structure.
129-132: Remove unnecessary type casting.The role parameter is already typed as string in the method signature, so the type assertion is redundant.
const { error } = await authClient.admin.setRole({ userId, - role: role as "user" | "admin", + role, });If type safety is needed, validate the role value instead of casting:
if (role !== "user" && role !== "admin") { throw new Error("Invalid role value"); }src/models/admin/user-detail/moderation.model.ts (3)
82-85: Extract magic numbers to constants.The duration conversion uses magic numbers that could be extracted for better maintainability.
+const SECONDS_PER_DAY = 60 * 60 * 24; + if (banDuration && banDuration !== "permanent") { const days = parseInt(banDuration); - banExpiresIn = 60 * 60 * 24 * days; // Convert days to seconds + banExpiresIn = SECONDS_PER_DAY * days; }
70-76: Add validation for ban duration.Consider validating that the ban duration is a valid option from
BAN_DURATIONS.const { banReason, banDuration } = this.banFormData$.peek(); if (!banReason.trim()) { toast.error("Ban reason is required"); return; } +if (banDuration && !BAN_DURATIONS.some(d => d.value === banDuration)) { + toast.error("Invalid ban duration selected"); + return; +}
157-161: Consider making resetBanForm public.The
resetBanFormmethod is private but might be useful for external components to reset the form state without performing a ban operation.-private resetBanForm(): void { +resetBanForm(): void {
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (10)
.github/copilot-instructions.md(3 hunks)src/containers/admin/components/user-table-row.tsx(3 hunks)src/containers/admin/user-detail.container.tsx(1 hunks)src/models/admin/user-detail.model.ts(1 hunks)src/models/admin/user-detail/email.model.ts(1 hunks)src/models/admin/user-detail/form.model.ts(1 hunks)src/models/admin/user-detail/moderation.model.ts(1 hunks)src/models/admin/user-detail/session.model.ts(1 hunks)src/models/admin/user-detail/user.model.ts(1 hunks)src/utils/error.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- src/containers/admin/components/user-table-row.tsx
- .github/copilot-instructions.md
- src/containers/admin/user-detail.container.tsx
🧰 Additional context used
📓 Path-based instructions (1)
src/**/*.{ts,tsx}
📄 CodeRabbit Inference Engine (.github/copilot-instructions.md)
src/**/*.{ts,tsx}: Use Platform.OS and process.env.EXPO_OS for conditional logic
Consider all platforms (iOS/Android/Web) when using native APIs
Files:
src/utils/error.tssrc/models/admin/user-detail/email.model.tssrc/models/admin/user-detail.model.tssrc/models/admin/user-detail/form.model.tssrc/models/admin/user-detail/moderation.model.tssrc/models/admin/user-detail/user.model.tssrc/models/admin/user-detail/session.model.ts
🧠 Learnings (4)
📚 Learning: applies to {src/lib/auth-client.ts,src/app/(auth)/**/*.tsx} : use authclient hooks for auth state ma...
Learnt from: CR
PR: fyndx/expo-universal-starter#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-07-28T12:52:53.959Z
Learning: Applies to {src/lib/auth-client.ts,src/app/(auth)/**/*.tsx} : Use authClient hooks for auth state management
Applied to files:
src/models/admin/user-detail/email.model.tssrc/models/admin/user-detail/user.model.tssrc/models/admin/user-detail/session.model.ts
📚 Learning: applies to {src/lib/auth-client.ts,src/app/(auth)/**/*.tsx} : use authclient.usesession() hook for s...
Learnt from: CR
PR: fyndx/expo-universal-starter#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-07-28T12:52:53.959Z
Learning: Applies to {src/lib/auth-client.ts,src/app/(auth)/**/*.tsx} : Use authClient.useSession() hook for session state
Applied to files:
src/models/admin/user-detail/session.model.ts
📚 Learning: applies to src/lib/auth-client.ts : auth client in src/lib/auth-client.ts with platform-specific plu...
Learnt from: CR
PR: fyndx/expo-universal-starter#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-07-28T12:52:53.959Z
Learning: Applies to src/lib/auth-client.ts : Auth client in src/lib/auth-client.ts with platform-specific plugins
Applied to files:
src/models/admin/user-detail/session.model.ts
📚 Learning: applies to src/lib/auth-client.ts : better auth requires platform-specific plugin setup for native v...
Learnt from: CR
PR: fyndx/expo-universal-starter#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-07-28T12:52:53.959Z
Learning: Applies to src/lib/auth-client.ts : Better Auth requires platform-specific plugin setup for native vs web storage
Applied to files:
src/models/admin/user-detail/session.model.ts
🧬 Code Graph Analysis (4)
src/models/admin/user-detail/email.model.ts (1)
src/utils/error.ts (1)
getErrorMessage(7-9)
src/models/admin/user-detail/moderation.model.ts (1)
src/utils/error.ts (1)
getErrorMessage(7-9)
src/models/admin/user-detail/user.model.ts (1)
src/utils/error.ts (1)
getErrorMessage(7-9)
src/models/admin/user-detail/session.model.ts (1)
src/utils/error.ts (1)
getErrorMessage(7-9)
🔇 Additional comments (4)
src/models/admin/user-detail/form.model.ts (1)
53-77: Excellent change detection logic.The
getChangesmethod correctly handles:
- Trimming whitespace for accurate comparison
- Handling optional/nullable fields with fallbacks
- Automatically setting
emailVerifiedto false when email changes- Returning structured data for different types of changes
src/models/admin/user-detail/user.model.ts (1)
51-87: Robust user fetching implementation.The
fetchUserByIdmethod correctly:
- Sets loading states
- Handles API errors appropriately
- Validates that a user was found
- Transforms date fields to ISO strings
- Provides proper error feedback
src/models/admin/user-detail/moderation.model.ts (2)
9-17: Well-structured ban duration options.The
BAN_DURATIONSconstant provides a good range of options with clear labels and values.
133-152: Excellent user deletion implementation.The
deleteUsermethod correctly:
- Sets appropriate loading states
- Handles API errors properly
- Provides user feedback via toast
- Navigates back after successful deletion
- Follows consistent error handling patterns
… in UserDetailModel and SessionModel
PR Type
Enhancement
Description
Add comprehensive user detail management screen with CRUD operations
Implement user session management and revocation functionality
Add UI components (Badge, Separator) and enhance table navigation
Restructure admin components and update dependencies
Diagram Walkthrough
File Walkthrough
9 files
Add comprehensive user detail management modelUpdate prop name for UsersList componentAdd user detail screen routeAdd Badge component with variantsAdd Separator component for UI dividersAdd view details button with navigationRestructure filters component with add user navigationAdd focus refresh and restructure component importsImplement comprehensive user detail management interface1 files
Add method parameter guidelines for object destructuring1 files
Update Better Auth and add Separator dependency1 files
Remove old filters component file1 files
Summary by CodeRabbit
New Features
Improvements
$suffix for clarity.Bug Fixes
Chores