feat: implement post-booking confirmation page#70
Conversation
- Add dynamic route /booking/confirmation/[bookingId] - Display booking details (ID, property, dates, guests, price) - Show host contact information with action buttons - Implement real-time escrow status updates with polling - Add success message with checkmark icon - Include navigation to My Bookings dashboard - Support responsive design with light/dark themes - Handle invalid booking IDs with error page - Add comprehensive unit tests Resolves Stellar-Rent#38
WalkthroughThis change introduces a complete post-booking confirmation feature. It adds a new confirmation page route, supporting components for displaying booking details, escrow status (with live updates), host contact, and navigation actions. Supporting hooks manage data fetching and polling. The update also includes a test suite for the confirmation page component. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant NextPage as BookingConfirmationPageRoute
participant useBookingDetails
participant BookingConfirmationPage
participant useEscrowStatus
participant EscrowStatusCard
User->>NextPage: Visit /booking/confirmation/[bookingId]
NextPage->>useBookingDetails: Fetch booking data (by bookingId)
useBookingDetails-->>NextPage: Return bookingData/loading/error
NextPage->>BookingConfirmationPage: Render with bookingData
BookingConfirmationPage->>EscrowStatusCard: Pass escrow status, transaction hash, etc.
EscrowStatusCard->>useEscrowStatus: Poll for escrow status updates
useEscrowStatus-->>EscrowStatusCard: Return updated escrow status
User->>BookingConfirmationPage: Interact with navigation/host contact buttons
Assessment against linked issues
Assessment against linked issues: Out-of-scope changesNo out-of-scope changes detected. All code additions are directly related to the objectives described in the linked issue. Suggested reviewers
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (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.
Actionable comments posted: 20
♻️ Duplicate comments (1)
apps/web/src/hooks/useBookingDetails.ts (1)
5-24: Interface duplication detected.This
BookingDatainterface is identical to the one inBookingConfirmationPage.tsx, creating a maintenance risk.Please refer to the previous comment about extracting shared interfaces to a common types file.
🧹 Nitpick comments (10)
apps/web/src/app/booking/confirmation/[bookingId]/page.tsx (1)
19-31: Extract repeated layout structure into a reusable component.The same layout pattern (
min-h-screen bg-background pt-20container structure) is repeated across all three states. This violates the DRY principle and makes maintenance harder.+ function BookingPageLayout({ children }: { children: React.ReactNode }) { + return ( + <div className="min-h-screen bg-background pt-20"> + <div className="container mx-auto px-4 py-8"> + <div className="max-w-2xl mx-auto"> + {children} + </div> + </div> + </div> + ); + } export default function BookingConfirmationPageRoute() { // ... existing logic ... if (loading) { return ( - <div className="min-h-screen bg-background pt-20"> - <div className="container mx-auto px-4 py-8"> - <div className="max-w-2xl mx-auto"> + <BookingPageLayout> <Card className="p-8"> {/* loading content */} </Card> - </div> - </div> - </div> + </BookingPageLayout> ); } if (error || !bookingData) { return ( - <div className="min-h-screen bg-background pt-20"> - <div className="container mx-auto px-4 py-8"> - <div className="max-w-2xl mx-auto"> + <BookingPageLayout> <Card className="p-8"> {/* error content */} </Card> - </div> - </div> - </div> + </BookingPageLayout> ); } return ( - <div className="min-h-screen bg-background pt-20"> - <div className="container mx-auto px-4 py-8"> + <BookingPageLayout> <BookingConfirmationPage bookingData={bookingData} /> - </div> - </div> + </BookingPageLayout> ); }Also applies to: 36-67, 71-76
apps/web/src/components/booking/confirmation/NavigationActions.tsx (1)
15-17: Replace placeholder implementation for PDF download.The download confirmation functionality is currently a placeholder with only a console.log statement.
const handleDownloadConfirmation = () => { - console.log('Download confirmation PDF'); + // TODO: Implement PDF generation and download + // Consider using libraries like jsPDF or react-pdf + throw new Error('PDF download not implemented yet'); };Would you like me to help implement the PDF generation functionality or create an issue to track this task?
apps/web/src/hooks/useBookingDetails.ts (2)
49-68: Improve mock data realism.The mock data contains several unrealistic elements that could cause confusion during development and testing:
- Hardcoded dates from 2024 which may be outdated
- Extremely long transaction hash (54 characters) that doesn't match typical blockchain transaction formats
- Fixed property and host details
Consider making the mock data more dynamic and realistic:
const mockData: BookingData = { id: bookingId, property: { - title: 'Luxury Beachfront Villa', + title: `Property ${bookingId.slice(-3)}`, image: '/images/property-placeholder.jpg', }, dates: { - from: new Date('2024-03-15'), - to: new Date('2024-03-20'), + from: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), // 1 week from now + to: new Date(Date.now() + 12 * 24 * 60 * 60 * 1000), // 12 days from now }, guests: 2, totalAmount: 750, - transactionHash: 'ABC123DEF456GHI789JKL012MNO345PQR678STU901VWX234YZ', + transactionHash: `${bookingId.toLowerCase()}${'0'.repeat(32 - bookingId.length)}`, escrowStatus: 'pending', host: { - name: 'John Smith', - email: 'john.smith@example.com', + name: `Host ${bookingId.slice(-2)}`, + email: `host-${bookingId.toLowerCase()}@example.com`, phone: '+1 (555) 123-4567', }, };
33-93: Consider early validation optimization.The hook could be optimized to avoid unnecessary loading states when the booking ID is invalid from the start.
Add early validation:
export function useBookingDetails(bookingId: string): UseBookingDetailsReturn { const [bookingData, setBookingData] = useState<BookingData | null>(null); - const [loading, setLoading] = useState(true); + const [loading, setLoading] = useState(!bookingId || isValidBookingId(bookingId)); const [error, setError] = useState<string | null>(null); + // Early validation + useEffect(() => { + if (!isValidBookingId(bookingId)) { + setError('Invalid booking ID'); + setLoading(false); + setBookingData(null); + return; + } + }, [bookingId]);apps/web/src/components/booking/confirmation/HostContactCard.tsx (1)
28-30: Implement messaging functionality.The
handleMessageHostfunction only logs to console, indicating incomplete functionality that could confuse users.This TODO functionality should be implemented before production. Would you like me to help design the messaging interface or create a modal component for in-app messaging?
apps/web/src/components/booking/confirmation/EscrowStatusCard.tsx (3)
5-5: Remove unused import.The
getEstimatedTimeToNextStatusfunction is imported but never used in this component.-import { getEstimatedTimeToNextStatus, useEscrowStatus } from '@/hooks/useEscrowStatus'; +import { useEscrowStatus } from '@/hooks/useEscrowStatus';
105-118: Simplify progress bar logic.The current progress bar implementation using nested ternary operators is hard to read and maintain.
Simplify using a more straightforward approach:
- <div - className={`bg-[#4A90E2] h-2 rounded-full transition-all duration-500 ease-out ${ - statusConfig.progress === 25 - ? 'w-1/4' - : statusConfig.progress === 75 - ? 'w-3/4' - : statusConfig.progress === 100 - ? 'w-full' - : 'w-0' - }`} - /> + <div + className="bg-primary h-2 rounded-full transition-all duration-500 ease-out" + style={{ width: `${statusConfig.progress}%` }} + />
86-89: Improve timestamp display context.Showing only the time without date context could be confusing, especially for bookings that span multiple days.
Include more context in the timestamp:
<div className="text-xs text-muted-foreground"> - Updated: {lastUpdated.toLocaleTimeString()} + Updated: {lastUpdated.toLocaleString(undefined, { + month: 'short', + day: 'numeric', + hour: '2-digit', + minute: '2-digit' + })} </div>apps/web/src/hooks/useEscrowStatus.ts (2)
39-42: Consider making mock data configurable or dynamic.The hard-coded transaction hash and amount values make testing and different scenarios difficult. Consider making these configurable or generating dynamic values.
- transactionHash: 'ABC123DEF456GHI789JKL012MNO345PQR678STU901VWX234YZ', - amount: 750, + transactionHash: `0x${Math.random().toString(16).substring(2, 18)}...`, + amount: Math.floor(Math.random() * 1000) + 500, // Random amount between 500-1500
130-153: Consider extracting magic numbers to constants.The time calculations use hard-coded values that should be extracted to named constants for better maintainability and consistency.
+const PENDING_TO_CONFIRMED_MINUTES = 5; + export function getEstimatedTimeToNextStatus( currentStatus: EscrowStatus, lastUpdated: Date ): string | null { const now = new Date(); const timeSinceUpdate = now.getTime() - lastUpdated.getTime(); const minutesSinceUpdate = timeSinceUpdate / (1000 * 60); switch (currentStatus) { case 'pending': { - const remainingMinutes = Math.max(0, 5 - minutesSinceUpdate); + const remainingMinutes = Math.max(0, PENDING_TO_CONFIRMED_MINUTES - minutesSinceUpdate); if (remainingMinutes > 0) { return `~${Math.ceil(remainingMinutes)} minutes until confirmation`; } return 'Confirmation expected soon'; }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
apps/web/src/app/booking/confirmation/[bookingId]/page.tsx(1 hunks)apps/web/src/components/booking/confirmation/BookingConfirmationPage.tsx(1 hunks)apps/web/src/components/booking/confirmation/BookingDetailsCard.tsx(1 hunks)apps/web/src/components/booking/confirmation/EscrowStatusCard.tsx(1 hunks)apps/web/src/components/booking/confirmation/HostContactCard.tsx(1 hunks)apps/web/src/components/booking/confirmation/NavigationActions.tsx(1 hunks)apps/web/src/components/booking/confirmation/__tests__/BookingConfirmationPage.test.tsx(1 hunks)apps/web/src/hooks/useBookingDetails.ts(1 hunks)apps/web/src/hooks/useEscrowStatus.ts(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
apps/web/src/components/booking/confirmation/BookingDetailsCard.tsx (2)
apps/web/src/components/ui/card.tsx (2)
Card(85-85)CardHeader(86-86)apps/web/src/components/ui/calendar.tsx (1)
Calendar(70-70)
apps/web/src/components/booking/confirmation/HostContactCard.tsx (3)
apps/web/src/components/ui/card.tsx (2)
Card(85-85)CardHeader(86-86)apps/backend/src/types/auth.types.ts (1)
User(11-15)apps/web/src/components/ui/button.tsx (1)
Button(59-59)
🔇 Additional comments (6)
apps/web/src/components/booking/confirmation/__tests__/BookingConfirmationPage.test.tsx (3)
7-16: Well-implemented mock for useEscrowStatus hook.The mock properly returns the expected structure with status, loading state, and utility function. This ensures consistent test behavior.
18-37: Comprehensive and realistic mock booking data.The mock data covers all necessary fields with realistic values, including proper date objects and various data types. This provides good test coverage for different scenarios.
39-77: Thorough test coverage of component functionality.The test suite covers all major areas: success message, booking details, host contact, escrow status, and navigation actions. Each test is focused and uses appropriate assertions.
apps/web/src/components/booking/confirmation/BookingConfirmationPage.tsx (1)
34-72: Well-structured component with good responsive design.The component follows React best practices with proper TypeScript typing, semantic HTML structure, and responsive grid layout. The modular approach using child components promotes maintainability.
apps/web/src/hooks/useEscrowStatus.ts (2)
77-87: Polling implementation looks correct.The polling logic properly stops for terminal states and cleans up intervals. The dependency array is appropriate and will restart polling when escrow data changes.
97-128: Well-designed status information utility.The
getEscrowStatusInfofunction provides comprehensive UI metadata with consistent structure. The progress values and color coding make sense for each status.
apps/web/src/components/booking/confirmation/NavigationActions.tsx
Outdated
Show resolved
Hide resolved
apps/web/src/components/booking/confirmation/NavigationActions.tsx
Outdated
Show resolved
Hide resolved
apps/web/src/components/booking/confirmation/EscrowStatusCard.tsx
Outdated
Show resolved
Hide resolved
…uality - Create shared types file for BookingData and related interfaces - Fix infinite re-render issue in useEscrowStatus hook - Replace hardcoded colors with design system variables - Improve type safety for route parameters with proper validation - Add error handling for clipboard API operations - Extract reusable BookingPageLayout component - Make Stellar explorer URL configurable - Improve mock data to be more dynamic and realistic - Fix timing inconsistencies between hook and utility functions - Remove unused imports and parameters - Enhance timestamp display with better context - Simplify progress bar logic - Update all components to use centralized type definitions Resolves all major CodeRabbit AI feedback items for better maintainability and type safety.
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (4)
apps/web/src/components/booking/confirmation/EscrowStatusCard.tsx (4)
22-24: Good validation, but consider user experience.The error throwing approach for missing bookingId ensures data integrity, but throwing an error in a UI component might lead to a poor user experience with unhandled crashes.
Consider returning a graceful error state instead:
- if (!bookingId) { - throw new Error('BookingId is required for EscrowStatusCard'); - } + if (!bookingId) { + return ( + <Card className="overflow-hidden"> + <div className="p-6 text-center text-red-500"> + <XCircle className="w-8 h-8 mx-auto mb-2" /> + <p>Unable to load payment status: Missing booking ID</p> + </div> + </Card> + ); + }
30-74: Optimize status configuration for performance.The
getStatusConfigfunction is recreated on every render, which is unnecessary since the configurations are static.Move the status configurations outside the component or use
useMemo:+const STATUS_CONFIGS = { + pending: { + icon: Clock, + color: 'text-yellow-500', + bgColor: 'bg-yellow-50 dark:bg-yellow-900/20', + borderColor: 'border-yellow-200 dark:border-yellow-800', + title: 'Payment Pending', + description: 'Your payment is being processed and will be held in escrow until check-in.', + progress: 25, + }, + // ... other configurations +} as const; export function EscrowStatusCard({ // ... props }: EscrowStatusCardProps) { // ... other code - const getStatusConfig = (status: EscrowStatus) => { - switch (status) { - case 'pending': - return { - // ... configuration - }; - // ... other cases - } - }; - const statusConfig = getStatusConfig(currentStatus); + const statusConfig = STATUS_CONFIGS[currentStatus];
83-85: Consider security implications of external links.While the base URL is controlled, opening external links should include security considerations.
Add security attributes to the window.open call:
const openTransactionExplorer = () => { - window.open(`${STELLAR_EXPLORER_BASE_URL}/tx/${transactionHash}`, '_blank'); + window.open(`${STELLAR_EXPLORER_BASE_URL}/tx/${transactionHash}`, '_blank', 'noopener,noreferrer'); };
148-150: Transaction hash display could be more user-friendly.The full transaction hash might be overwhelming for users and could be truncated with an option to expand.
Consider showing a truncated version with expand option:
-<div className="p-2 bg-muted rounded text-xs font-mono break-all text-muted-foreground"> - {transactionHash} -</div> +<div className="p-2 bg-muted rounded text-xs font-mono text-muted-foreground"> + <span className="break-all"> + {transactionHash.length > 20 + ? `${transactionHash.slice(0, 10)}...${transactionHash.slice(-10)}` + : transactionHash + } + </span> + {transactionHash.length > 20 && ( + <button + onClick={() => navigator.clipboard.writeText(transactionHash)} + className="ml-2 text-primary hover:text-primary/80" + title="Copy full transaction hash" + > + Copy + </button> + )} +</div>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (10)
apps/web/src/app/booking/confirmation/[bookingId]/page.tsx(1 hunks)apps/web/src/components/booking/confirmation/BookingConfirmationPage.tsx(1 hunks)apps/web/src/components/booking/confirmation/BookingDetailsCard.tsx(1 hunks)apps/web/src/components/booking/confirmation/EscrowStatusCard.tsx(1 hunks)apps/web/src/components/booking/confirmation/HostContactCard.tsx(1 hunks)apps/web/src/components/booking/confirmation/NavigationActions.tsx(1 hunks)apps/web/src/components/booking/confirmation/__tests__/BookingConfirmationPage.test.tsx(1 hunks)apps/web/src/hooks/useBookingDetails.ts(1 hunks)apps/web/src/hooks/useEscrowStatus.ts(1 hunks)apps/web/src/types/booking.ts(1 hunks)
✅ Files skipped from review due to trivial changes (2)
- apps/web/src/components/booking/confirmation/tests/BookingConfirmationPage.test.tsx
- apps/web/src/types/booking.ts
🚧 Files skipped from review as they are similar to previous changes (7)
- apps/web/src/hooks/useBookingDetails.ts
- apps/web/src/components/booking/confirmation/NavigationActions.tsx
- apps/web/src/hooks/useEscrowStatus.ts
- apps/web/src/app/booking/confirmation/[bookingId]/page.tsx
- apps/web/src/components/booking/confirmation/BookingConfirmationPage.tsx
- apps/web/src/components/booking/confirmation/HostContactCard.tsx
- apps/web/src/components/booking/confirmation/BookingDetailsCard.tsx
🧰 Additional context used
🧬 Code Graph Analysis (1)
apps/web/src/components/booking/confirmation/EscrowStatusCard.tsx (4)
apps/web/src/types/booking.ts (1)
EscrowStatus(1-1)apps/web/src/hooks/useEscrowStatus.ts (1)
useEscrowStatus(10-88)apps/web/src/components/ui/card.tsx (2)
Card(85-85)CardHeader(86-86)apps/web/src/components/ui/button.tsx (1)
Button(59-59)
🔇 Additional comments (2)
apps/web/src/components/booking/confirmation/EscrowStatusCard.tsx (2)
79-85: Explorer URL configuration looks good.The configurable explorer URL addresses the previous review feedback effectively, providing flexibility for different networks while maintaining a sensible default.
87-190: Overall component structure is well-designed.The component provides a comprehensive view of the escrow status with good visual hierarchy, appropriate use of UI components, and clear information architecture. The responsive design and dark mode support enhance the user experience.
…ccessibility - Replace error throwing with graceful UI error state in EscrowStatusCard - Add accessibility attributes (aria-label, title) to explorer button - Enhance timeline logic to properly handle cancelled booking status - Add security attributes (noopener, noreferrer) to external links - Optimize status configuration for better performance - Improve user experience with better error handling Addresses all remaining CodeRabbit AI suggestions for production readiness.
|
@respp All done and Coderabbit reviews passed |
|
Great work! Thanks for contributing to StellarRent! |
|
@respp When should i expect my reward on Onlydust |
Resolves #38
Pull Request | StellarRent
📝 Summary
Provide a brief description of what this PR accomplishes.
🔗 Related Issues
Closes #(issue number) (Replace with the actual issue number).
🔄 Changes Made
Provide a general description of the changes. Include any relevant background information or context to help reviewers understand the purpose of this PR.
🖼️ Current Output
Provide visual evidence of the changes:
🧪 Testing
If applicable, describe the tests performed. Include screenshots, test outputs, or any resources that help reviewers understand how the changes were tested.
✅ Testing Checklist
List any possible issues that might arise with this change.
🚀 Next Steps & Improvements
This change lays a solid foundation for further optimizations. Some areas that could benefit from future improvements include:
💬 Comments
Any additional context, questions, or considerations for reviewers.
Summary by CodeRabbit
New Features
Bug Fixes
Tests