-
Notifications
You must be signed in to change notification settings - Fork 473
fix: Scrum 34 storage fixes #778
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
Conversation
AS-1 - project backend setup
β¦and Zustand (#6) * feat: Setup e-commerce frontend with React, TypeScript, Material-UI, and Zustand - Initialize React + TypeScript + Vite project structure - Implement feature-based architecture with isolated modules - Add Material-UI for UI components with custom theme - Setup Zustand state management with 4 stores (auth, cart, products, UI) - Create API service layer with Axios client and interceptors - Implement path aliases for clean imports (@components, @features, @store, etc.) - Add comprehensive folder structure for scalability - Create placeholder pages for all major features - Setup authentication flow with token management - Implement shopping cart with persistence - Add common utilities (formatters, validators) and hooks - Configure TypeScript with strict mode and path mapping - Add ESLint configuration for code quality - Create comprehensive documentation (README, STRUCTURE, ZUSTAND_GUIDE) - Setup development environment with hot reload Features implemented: - Authentication (login, register, forgot-password) - Products (list, detail, search) - Shopping cart with item management - Checkout flow - Order management (list, detail) - User profile (profile, wishlist, addresses) Tech stack: - React 18 - TypeScript 5.2 - Vite 5.0 - Material-UI 5.14 - Zustand 5.0 - React Router 6.20 - Axios 1.6 * intentionally a typo * fixed minor typo in the import * added suggestion of replacing href with router link * added the suggestion to replace href with component * fixed issues mentioned by the bot * added prettier on the client side * fixed the issue of possible undefined config headers * added changes for the refresh token * fix: Critical bug fixes for API client authentication and interceptors Fixed 3 critical issues in the API client: 1. Headers Runtime Error (Medium Severity) - Added defensive initialization of config.headers before assignment - Prevents runtime error when headers object is undefined - Fixed in both request and response interceptors 2. Infinite Loop on Token Refresh (CRITICAL) - Prevented infinite recursion when refresh endpoint returns 401 - Added endpoint check to skip retry logic for refresh calls - Use separate axios instance without interceptors for refresh - Prevents browser freeze/crash from stack overflow 3. Auth Store Synchronization (CRITICAL) - Fixed mismatch between Zustand store and API client token storage - API client now reads tokens from Zustand store instead of localStorage - Ensures authentication headers are properly added to all requests - Token refresh now updates Zustand store correctly - Logout properly clears all auth state Technical Details: - Import useAuthStore in API client - Use useAuthStore.getState() to access tokens outside React components - Single source of truth for authentication state - Zustand persist middleware handles localStorage automatically Impact: - Authentication now works correctly - No infinite loops or browser crashes - Proper token refresh handling - Clean logout functionality - All protected API requests include auth headers Documentation: - Added BUGFIX_AUTH_SYNC.md for auth synchronization fix - Updated CRITICAL_BUGFIX_SUMMARY.md with all fixes - Updated PRETTIER_SETUP.md with formatting info - Applied Prettier formatting to all documentation files * fix: Ensure auth service uses Zustand store for logout to prevent state drift Fixed state synchronization issue in auth service: Problem: - authService.logout() was directly manipulating localStorage - This bypassed the Zustand store, causing state drift - Zustand store would still show user as authenticated - Inconsistent state between localStorage and Zustand Solution: - Import useAuthStore in authService.ts - Use useAuthStore.getState().logout() instead of direct localStorage manipulation - Ensures single source of truth for authentication state - Zustand persist middleware automatically syncs to localStorage Impact: - Consistent logout behavior across the application - No state drift between Zustand and localStorage - Single source of truth maintained - All auth state properly cleared on logout Files Modified: - src/services/api/auth/authService.ts (logout function) - BUGFIX_AUTH_SYNC.md (added authService fix documentation) - CRITICAL_BUGFIX_SUMMARY.md (updated with new fix) This completes the auth synchronization fixes across the entire codebase. * feat: Add info pages to prevent dead links in footer Added 5 new informational pages to align with footer links: Pages Created: 1. About Page (/about) - Company information and mission 2. Contact Page (/contact) - Contact form and business information 3. Help Page (/help) - FAQ with 10 common questions 4. Returns Page (/returns) - Return policy and refund information 5. Shipping Page (/shipping) - Shipping rates and delivery information Features: - All pages use Material-UI components for consistency - Responsive design with proper spacing - Professional content with placeholder information - Contact page includes interactive form (ready for backend integration) - Help page uses accordion components for FAQs - Shipping/Returns pages include detailed tables and policies Routes Added: - /about β AboutPage - /contact β ContactPage - /help β HelpPage - /returns β ReturnsPage - /shipping β ShippingPage Impact: - No more dead links in footer - All footer links now navigate to proper pages - Improved user experience - Professional appearance - Ready for content updates Files Created: - src/features/info/about/components/AboutPage.tsx - src/features/info/contact/components/ContactPage.tsx - src/features/info/help/components/HelpPage.tsx - src/features/info/returns/components/ReturnsPage.tsx - src/features/info/shipping/components/ShippingPage.tsx Files Modified: - src/routes/AppRoutes.tsx (added 5 new routes) --------- Co-authored-by: Shehryar Raza <[email protected]>
β¦d a minor PEP8 fix in settings.py - Improved the docstring for the asgi.py module. - Fixed the line length violation within the settings.py file, involving the 'AUTH_PASSWORD_VALIDATORS' constant by the use of parentheses for line breaking.
#21) * feat: Add beautifully animated sidebar with categories and burger menu Created a stunning animated sidebar with the following features: Sidebar Component: - Beautiful gradient background (purple to violet) - Smooth slide-in/slide-out animations - 7 main categories with icons: * Electronics (Devices icon) * Fashion (Checkroom icon) * Home & Garden (Home icon) * Sports & Outdoors (Fitness icon) * Gaming (Gaming icon) * Books & Media (Book icon) * Pet Supplies (Pets icon) - Each category has 5 subcategories - Expandable/collapsible subcategories with smooth animations - Click outside to close functionality - Close button in header - Professional styling with Material-UI Features: β Burger menu button in header (left side) β Smooth drawer animation from left β Click outside sidebar to close β Expandable categories with subcategories β Beautiful gradient background β Icon for each category β Navigation to products with category filters β Responsive design β Professional shadows and spacing UI Store Updates: - Added openSidebar() method - Added closeSidebar() method - Existing toggleSidebar() method Header Updates: - Added burger menu icon button - Integrated with UI store - Positioned on left side of header Layout Updates: - Integrated Sidebar component in MainLayout - Sidebar available on all pages Technical Details: - Uses Material-UI Drawer component - Zustand for state management - React Router for navigation - Click-outside detection with useEffect - Smooth collapse animations for subcategories - Gradient background with rgba overlays Files Created: - src/components/Sidebar.tsx (300+ lines) Files Modified: - src/components/Header.tsx (added burger menu) - src/components/index.ts (export Sidebar) - src/layouts/MainLayout.tsx (integrated Sidebar) - src/store/uiStore.ts (added open/close methods) * refactor: Remove unnecessary click-outside logic, rely on Drawer's built-in backdrop Fixed implementation issue in Sidebar component: Problem: - Custom click-outside detection using ref and useEffect was incorrect - SlideProps ref doesn't reference the drawer paper DOM element - Custom implementation was redundant and wouldn't work as intended Solution: - Removed useRef and useEffect for click-outside detection - Removed SlideProps with ref prop - Rely on Material-UI Drawer's built-in backdrop behavior - The onClose prop already handles click-outside via backdrop Benefits: β Simpler, cleaner code β Relies on Material-UI's tested implementation β Removes unnecessary imports (useEffect, useRef) β Better performance (no custom event listeners) β More maintainable β Follows Material-UI best practices The Drawer component's backdrop already provides: - Click outside to close functionality - Proper event handling - Accessibility features - Tested and reliable behavior Changes: - Removed: import useEffect, useRef - Removed: sidebarRef variable - Removed: useEffect hook with click-outside logic - Removed: SlideProps prop from Drawer - Kept: onClose prop (handles backdrop clicks) Impact: - Functionality remains the same - Code is cleaner and more maintainable - Follows Material-UI conventions - No breaking changes --------- Co-authored-by: Shehryar Raza <[email protected]>
AS-2 - implement authentication endpoint register and login
β¦ment_and_pep8_fix Improved the top-level docstring for the asgi.py module and introduced a minor PEP8 fix in settings.py
feat: AS-3 - implement github workflow and user role permissions
* feat: Implement centralized color system with Colors class
Created a comprehensive, centralized color system to replace all hardcoded colors
throughout the application. This provides a single source of truth for all colors,
ensuring consistency and making it easy to update the color scheme.
Colors Class Features:
β
Primary colors (main, light, dark, contrastText)
β
Secondary colors (main, light, dark, contrastText)
β
Semantic colors (error, warning, info, success)
β
Neutral colors (white, black, gray50-gray900)
β
Background colors (default, paper, light, dark)
β
Text colors (primary, secondary, disabled, hint, white)
β
Gradient colors (6 pre-defined gradients)
β
Overlay colors (light/dark with various opacity levels)
β
Shadow colors (light, medium, heavy, card)
β
Border colors (light, medium, dark, white)
β
Brand colors (sidebar, header, footer specific colors)
Utility Methods:
β
rgba() - Create custom rgba colors
β
hexWithAlpha() - Add transparency to hex colors
β
linearGradient() - Create custom gradients
β
boxShadow() - Create custom box shadows
Benefits:
β
Single source of truth for all colors
β
Type-safe with TypeScript
β
Easy to update color scheme globally
β
Consistent color usage across the app
β
Better maintainability
β
Autocomplete support in IDEs
β
No hardcoded colors in components
Integration:
β
Integrated with Material-UI theme
β
All theme colors now use Colors class
β
Footer component updated to use Colors class
β
Ready for use in all components
Documentation:
β
Comprehensive COLOR_SYSTEM.md guide
β
Usage examples for all color categories
β
Best practices and migration guide
β
Type exports for TypeScript
Files Created:
- src/config/colors.ts (280+ lines)
- COLOR_SYSTEM.md (comprehensive documentation)
Files Modified:
- src/config/theme.ts (integrated Colors class)
- src/components/Footer.tsx (replaced hardcoded color)
Impact:
- All future components should use Colors class
- Easy to implement dark mode in the future
- Consistent branding across the application
- Simplified color management
* fix: Correct duplicate gradient and add input validation to hexWithAlpha
Fixed two issues in the Colors class:
1. Duplicate Gradient Values:
Problem: gradient.blueIndigo had the same value as gradient.purpleViolet
- Old: linear-gradient(135deg, #667eea 0%, #764ba2 100%)
- New: linear-gradient(135deg, #4e54c8 0%, #8f94fb 100%)
Impact: Now provides a distinct blue-indigo gradient
2. Input Validation for hexWithAlpha():
Problem: No validation for hex format or alpha range
- Invalid hex values (3-digit, 8-digit, malformed) would produce NaN
- Invalid alpha values could be passed without error
Solution: Added comprehensive validation
- Validates hex format (must be exactly 6 hex digits)
- Validates alpha range (must be 0-1)
- Throws descriptive errors for invalid inputs
- Supports both '#RRGGBB' and 'RRGGBB' formats
Changes:
β
Fixed gradient.blueIndigo to use distinct colors
β
Added regex validation for hex format: /^[0-9A-Fa-f]{6}$/
β
Added alpha range validation (0-1)
β
Added descriptive error messages
β
Updated documentation with validation details
β
Added usage examples for both hex formats
Files Modified:
- src/config/colors.ts (fixed gradient, added validation)
- COLOR_SYSTEM.md (updated gradient docs, added validation notes)
Benefits:
β
Prevents runtime errors from invalid hex values
β
Clear error messages for debugging
β
Type-safe with proper validation
β
Distinct gradients for better variety
β
Better developer experience
---------
Co-authored-by: Shehryar Raza <[email protected]>
feat: AS-3 - implement API for products category and brands
β¦ecovery flow (#27) * feat: Implement modern, animated login and register forms Created professional, modern authentication forms with the latest design standards and smooth animations. Both forms support email/password authentication with comprehensive validation and social login placeholders. Login Page Features: β Modern gradient background (purple-violet) β Slide-up animation on page load β Email and password fields with icons β Show/hide password toggle β Real-time form validation β Email format validation β Password length validation (min 6 characters) β Error messages with fade-in animation β Loading state with spinner β Forgot password link β Social login buttons (Google, Facebook, GitHub) β Sign up link for new users β Responsive design β Gradient button with hover effect Register Page Features: β Modern gradient background (blue-indigo) β Slide-up animation on page load β First name and last name fields (2-column grid) β Email field with validation β Password field with strength requirements β Confirm password field with match validation β Show/hide password toggles for both fields β Terms and conditions checkbox β Comprehensive validation: - First/last name: min 2 characters - Email: valid format - Password: min 8 chars, uppercase, lowercase, number - Confirm password: must match - Terms: must be accepted β Real-time error clearing on input β Loading state with spinner β Social signup buttons (Google, Facebook, GitHub) β Sign in link for existing users β Responsive design with grid layout β Gradient button with hover effect Design Standards: β Material-UI components throughout β Centralized Colors class for consistency β Gradient backgrounds for visual appeal β Icon-enhanced input fields β Smooth animations (Slide, Fade) β High elevation paper for depth β Rounded corners (borderRadius: 3) β Proper spacing and padding β Accessible form labels β Error states with color coding β Disabled states during submission Validation Features: β Client-side validation before API call β Real-time error clearing on input β Field-specific error messages β API error handling with user-friendly messages β Form submission prevention when invalid β Visual feedback for all states User Experience: β Smooth page transitions β Instant feedback on errors β Clear call-to-action buttons β Easy navigation between login/register β Social login options for convenience β Password visibility toggle β Loading indicators during submission β Dismissible error alerts Integration: β Connected to authService API β Integrated with Zustand auth store β Automatic navigation after success β Token storage via Zustand persist β Error state management β Loading state management Technical Implementation: β TypeScript for type safety β React hooks (useState) β Form validation logic β Error handling with try-catch β Async/await for API calls β Proper cleanup in finally blocks β ESLint compliant (0 errors, 0 warnings) β Prettier formatted Social Login: β Google login button β Facebook login button β GitHub login button β Placeholder implementation (TODO) β Consistent styling across providers Files Modified: - src/features/auth/login/components/LoginPage.tsx (335 lines) - src/features/auth/register/components/RegisterPage.tsx (470 lines) Impact: - Professional, modern authentication UI - Improved user experience - Better form validation - Ready for production use - Easy to extend with social auth - Consistent with design system * refactor: Remove social login options from auth forms Removed Google, Facebook, and GitHub social login buttons from both login and register pages as requested. The forms now only support email/password authentication. Changes: - Removed social login buttons from LoginPage - Removed social login buttons from RegisterPage - Removed unused icon imports (Google, Facebook, GitHub) - Removed unused Divider import - Removed handleSocialLogin and handleSocialSignup functions - Cleaned up imports The forms now have a cleaner, simpler interface focused on email/password authentication only. Social login can be added back in the future if needed. * feat: Implement forgot password and reset password pages Created comprehensive password recovery flow with modern, animated UI matching the design standards of the login and register pages. Forgot Password Page Features: β Modern gradient background (purple-violet) β Slide-up animation on page load β Email input field with validation β Email format validation β Success message after submission β Error handling with user-friendly messages β Loading state with spinner β Back to login link with arrow icon β Responsive design β Gradient button with hover effect β Dismissible alerts (success/error) Reset Password Page Features: β Modern gradient background (blue-indigo) β Slide-up animation on page load β Token validation from URL query params β New password field with show/hide toggle β Confirm password field with show/hide toggle β Password strength requirements: - Minimum 8 characters - Uppercase letter - Lowercase letter - Number β Password match validation β Visual password requirements display β Success message with auto-redirect to login β Error handling for invalid/expired tokens β Loading state with spinner β Responsive design β Gradient button with hover effect β Dismissible alerts (success/error) User Flow: 1. User clicks "Forgot Password" on login page 2. User enters email on forgot password page 3. System sends reset instructions to email 4. User clicks reset link in email (with token) 5. User enters new password on reset password page 6. Password is reset successfully 7. User is redirected to login page Integration: β Connected to authService API β Uses forgotPassword() method β Uses resetPassword() method β Token passed via URL query params β Automatic redirect after success β Error state management β Loading state management Routes Added: β /forgot-password - Forgot password page β /reset-password?token=xxx - Reset password page Design Standards: β Material-UI components throughout β Centralized Colors class for consistency β Gradient backgrounds for visual appeal β Icon-enhanced input fields β Smooth animations (Slide, Fade) β High elevation paper for depth β Rounded corners (borderRadius: 3) β Proper spacing and padding β Accessible form labels β Error states with color coding β Disabled states during submission Validation Features: β Client-side validation before API call β Real-time error clearing on input β Field-specific error messages β API error handling with user-friendly messages β Form submission prevention when invalid β Visual feedback for all states β Token validation on page load Files Created: - src/features/auth/forgot-password/components/ForgotPasswordPage.tsx (213 lines) - src/features/auth/forgot-password/components/ResetPasswordPage.tsx (293 lines) Files Modified: - src/routes/AppRoutes.tsx (added 2 routes) Technical Implementation: β TypeScript for type safety β React hooks (useState, useEffect) β React Router (useNavigate, useSearchParams) β Form validation logic β Error handling with try-catch β Async/await for API calls β Proper cleanup in finally blocks β ESLint compliant (0 errors, 0 warnings) β Prettier formatted Impact: - Complete password recovery flow - Professional, modern UI - Improved user experience - Better security with token validation - Ready for production use - Consistent with design system * feat: Add password requirements display to login and register pages Added visible password requirements at the bottom of both login and register forms to inform users upfront about password constraints before they attempt to submit the form. Login Page: β Added password requirements box below submit button β Single line format: "Password must contain uppercase, lowercase, and number" β Light gray background box for visibility β Positioned above sign-up link Register Page: β Added detailed password requirements box below submit button β Multi-line format with bullet points: β’ At least 8 characters β’ One uppercase letter β’ One lowercase letter β’ One number β Light gray background box for visibility β Positioned above sign-in link Design: β Uses Colors.background.light for subtle background β Typography variant="caption" for smaller text β Text color: text.secondary for reduced emphasis β Rounded corners (borderRadius: 1) β Proper padding (p: 2) β Consistent spacing (mt: 3) Benefits: β Users know password requirements before typing β Reduces form submission errors β Better user experience β Clearer expectations β Matches reset password page design Files Modified: - src/features/auth/login/components/LoginPage.tsx - src/features/auth/register/components/RegisterPage.tsx * refactor: Reduce height of text input fields across all auth pages Reduced the height of all text input fields by adding size="small" prop to TextField components across all authentication pages for a more compact and modern appearance. Changes Applied: β Login Page - Email and Password fields β Register Page - First Name, Last Name, Email, Password, Confirm Password fields β Forgot Password Page - Email field β Reset Password Page - New Password and Confirm Password fields Technical Details: - Added size="small" prop to all TextField components - Reduces default height from 56px to 40px - Maintains all functionality (icons, validation, error messages) - Consistent across all auth pages - Better visual density - More modern, compact appearance Benefits: β More compact form layout β Better use of vertical space β Modern, streamlined appearance β Consistent sizing across all pages β Improved visual hierarchy β Better mobile experience Files Modified: - src/features/auth/login/components/LoginPage.tsx (2 fields) - src/features/auth/register/components/RegisterPage.tsx (5 fields) - src/features/auth/forgot-password/components/ForgotPasswordPage.tsx (1 field) - src/features/auth/forgot-password/components/ResetPasswordPage.tsx (2 fields) Total: 10 text fields updated across 4 files * refactor: Reduce size of input icons across all auth pages Reduced the size of all input field icons to match the smaller TextField components by adding fontSize="small" to all icons and size="small" to all IconButtons. Icons Updated: β Email icons - All email input fields β Lock icons - All password input fields β Person icons - First name and last name fields β Visibility/VisibilityOff icons - Password toggle buttons β IconButtons - All password visibility toggle buttons Changes by Page: Login Page (3 icons): - Email icon (fontSize="small") - Lock icon (fontSize="small") - Visibility/VisibilityOff icons (fontSize="small") - IconButton (size="small") Register Page (9 icons): - Person icon x2 (firstName, lastName) (fontSize="small") - Email icon (fontSize="small") - Lock icon x2 (password, confirmPassword) (fontSize="small") - Visibility/VisibilityOff icons x2 (fontSize="small") - IconButton x2 (size="small") Forgot Password Page (1 icon): - Email icon (fontSize="small") Reset Password Page (6 icons): - Lock icon x2 (newPassword, confirmPassword) (fontSize="small") - Visibility/VisibilityOff icons x2 (fontSize="small") - IconButton x2 (size="small") Technical Details: - fontSize="small" reduces icon size from 24px to 20px - size="small" reduces IconButton padding - Better visual proportion with size="small" TextFields - Maintains all functionality and accessibility - Consistent sizing across all auth pages Benefits: β Better visual balance with smaller input fields β More compact, modern appearance β Consistent icon sizing across all pages β Improved visual hierarchy β Better proportions overall β Professional, polished look Total Icons Updated: 19 icons across 4 files * fix: Remove password strength validation from login and cleanup setTimeout Fixed two critical issues in authentication pages: 1. Login Page - Removed Password Strength Requirements: - Removed minimum length validation (was blocking valid credentials) - Login should only check if password is provided, not enforce strength - Removed password requirements text box from UI - Users can now login with any valid password they previously set Problem: validateForm was enforcing 6-character minimum on login, which: - Can block legitimate logins if user's password doesn't meet criteria - Is inconsistent with the requirements text shown (uppercase, lowercase, number) - Should only be enforced during registration, not login Solution: Only check if password field is not empty during login validation 2. Reset Password Page - Fixed setTimeout Cleanup: - Moved setTimeout to useEffect with proper cleanup - Prevents navigation after component unmounts - Avoids unexpected navigation if user navigates away before timeout Problem: setTimeout in handleSubmit had no cleanup, so if component unmounts before 2 seconds (e.g., user navigates away), it would still navigate unexpectedly. Solution: Use useEffect with cleanup function to clear timeout on unmount Technical Details: Login Page Changes: - validateForm(): Removed password.length < 6 check - Removed password requirements Box from UI (lines 237-242) - Only validates that password field is not empty - Comment added explaining no strength requirements on login Reset Password Page Changes: - Added new useEffect hook to handle redirect with cleanup - useEffect triggers when successMessage is set - Returns cleanup function: () => clearTimeout(timeoutId) - Removed setTimeout from handleSubmit - Added comment: "Redirect handled by useEffect with cleanup" Benefits: β Users can login with any password (no false rejections) β No unexpected navigation after unmount β Proper React lifecycle management β Better user experience β Consistent validation logic Files Modified: - src/features/auth/login/components/LoginPage.tsx - src/features/auth/forgot-password/components/ResetPasswordPage.tsx * feat: Add Terms and Privacy pages with proper routing Fixed broken links in RegisterPage by creating proper Terms and Privacy pages and adding corresponding routes to AppRoutes. Problem: - RegisterPage had links to /terms and /privacy routes that didn't exist - These undefined routes would redirect users to / (home page) - Users couldn't view terms or privacy policy before agreeing - Links used href instead of React Router navigation Solution: 1. Created TermsPage component with comprehensive terms and conditions 2. Created PrivacyPage component with detailed privacy policy 3. Added /terms and /privacy routes to AppRoutes 4. Updated RegisterPage links to use RouterLink for proper navigation New Pages Created: 1. TermsPage (src/features/info/terms/components/TermsPage.tsx): - Comprehensive terms and conditions (12 sections) - Covers: Acceptance, License, Account Terms, Products, Pricing, Shipping, Returns, Liability, Privacy, Modifications, Governing Law - Professional layout with Material-UI Paper and Typography - Uses Colors class for consistent styling - Responsive container with proper spacing - Last updated date displayed 2. PrivacyPage (src/features/info/privacy/components/PrivacyPage.tsx): - Detailed privacy policy (11 sections) - Covers: Introduction, Data Collection, Usage, Security, Retention, Legal Rights, Cookies, Third-Party Links, Children's Privacy, Changes - Lists all types of data collected (Identity, Contact, Financial, etc.) - Explains user rights under data protection laws - Professional layout matching TermsPage design - Uses Colors class for consistent styling - Last updated date displayed Routes Added to AppRoutes.tsx: - /terms -> TermsPage (public route with MainLayout) - /privacy -> PrivacyPage (public route with MainLayout) RegisterPage Changes: - Updated Terms link: href="/terms" -> component={RouterLink} to="/terms" - Updated Privacy link: href="/privacy" -> component={RouterLink} to="/privacy" - Both links open in new tab (target="_blank") - Proper React Router navigation instead of full page reload Benefits: β Users can now view terms and privacy policy β Links work correctly without redirecting to home β Proper React Router navigation (no page reload) β Professional, comprehensive legal pages β Consistent styling with design system β Opens in new tab for better UX β SEO-friendly routes β Compliant with legal requirements Technical Details: - Both pages use Material-UI Container, Paper, Typography, Box - Responsive layout (maxWidth: lg, padding: 6) - Paper elevation: 2 for subtle shadow - Colors.text.primary for headings - Colors.text.secondary for body text - Proper semantic HTML (h1, ul, li) - Last updated date auto-generated with new Date() Files Created: - src/features/info/terms/components/TermsPage.tsx (179 lines) - src/features/info/privacy/components/PrivacyPage.tsx (189 lines) Files Modified: - src/routes/AppRoutes.tsx (added 2 imports, 2 routes) - src/features/auth/register/components/RegisterPage.tsx (updated links) --------- Co-authored-by: Shehryar Raza <[email protected]>
feat: AS-4 - implement file model and aws s3 config
β¦ the test cases
* feat: Add product search bar to header with debounced search - Created SearchBar common component with debounced search functionality - Integrated SearchBar into Header component - Installed lodash and @types/lodash for debouncing - Search displays product results with image, title, and price - Includes loading states, error handling, and empty states - Responsive design (hidden on mobile, visible on desktop) - Click on result navigates to product detail page - Auto-closes on click away or result selection Files changed: - src/components/common/SearchBar.tsx (new) - src/components/Header.tsx (updated) - package.json (added lodash dependencies) * fix: Optimize SearchBar to prevent icon re-renders on every keystroke - Memoized SearchIcon, ClearButton, and LoadingSpinner components - Optimized endAdornment to only render when needed (searchQuery || isLoading) - Memoized handleClear function to prevent re-creation on every render - Added IconButton wrapper for better UX on clear button Performance improvements: - Icons no longer re-render on every keystroke - Reduced unnecessary component re-renders - Better React performance with memo and useMemo - Cleaner conditional rendering logic Files changed: - src/components/common/SearchBar.tsx * docs: Add dummy product data and testing guide for SearchBar - Added dummyProducts.json with 15 electronic products - Products include smartphones, laptops, headphones, cameras, and accessories - All products have Unsplash images for realistic testing - Created comprehensive TESTING_SEARCHBAR.md guide - Guide includes 3 testing options: mock service, DevTools, backend integration - Instructions for performance testing and troubleshooting Files added: - src/data/dummyProducts.json (15 products with images) - TESTING_SEARCHBAR.md (comprehensive testing guide) * fix: Completely eliminate close icon flickering in SearchBar The previous fix didn't fully resolve the issue because the endAdornment was being recreated on every keystroke due to the changing condition. Solution: - Created memoized EndAdornment component that wraps the entire end section - Component only re-renders when isLoading or hasQuery props actually change - Used useCallback for handleClear to ensure stable reference - EndAdornment component handles conditional rendering internally This ensures that: - The close icon never flickers or re-renders on keystroke - Only the TextField value updates, not the adornments - Better performance with proper React.memo usage Files changed: - src/components/common/SearchBar.tsx * fix: Properly prevent close icon re-rendering with hasQuery state The previous attempts still had the issue because useMemo was depending on searchQuery (string) which changes on every keystroke. Solution: - Added hasQuery boolean state that only changes when going empty <-> non-empty - Memoized entire InputProps object with useMemo - InputProps only re-creates when hasQuery, isLoading, or handleClear changes - Separated ClearButtonAdornment and LoadingAdornment as distinct memoized components This ensures: - Close icon only appears/disappears when needed - No re-rendering while typing (hasQuery stays true) - Stable component references throughout typing - handleClear has stable reference via useCallback Files changed: - src/components/common/SearchBar.tsx * feat: Add mock product service and fix icon re-rendering completely Added mock product service: - Created mockProductService.ts with searchProducts, getProducts, etc. - Uses dummyProducts.json data with 300ms simulated network delay - SearchBar now uses mock service instead of real API - No more network errors when backend is not running Fixed icon re-rendering (final solution): - Renamed hasQuery to showClearButton for clarity - Only update showClearButton when transitioning empty <-> non-empty - Added conditional check to prevent unnecessary state updates - Memoized endAdornment with useMemo depending on stable values - Simplified component structure, removed unnecessary wrapper components The close icon now truly only renders when: - Appearing (first character typed) - Disappearing (all text cleared) - Loading state changes It does NOT re-render on every keystroke while typing. Files changed: - src/services/api/products/mockProductService.ts (new) - src/components/common/SearchBar.tsx (optimized) * fix: Add @DaTa path alias for JSON imports - Added @DaTa alias to vite.config.ts - Added @DaTa alias to tsconfig.json paths - Updated mockProductService to use @data/dummyProducts.json - Fixes 'Failed to resolve import' error Files changed: - vite.config.ts (added @DaTa alias) - tsconfig.json (added @DaTa path mapping) - mockProductService.ts (updated import path) * fix: Add gap between product image and text in search results - Added gap: 2 (16px) to ListItemButton for spacing - Added px: 2 for better horizontal padding - Set ListItemAvatar minWidth to 'auto' to remove default spacing - Improves visual spacing and readability of search results Files changed: - src/components/common/SearchBar.tsx * fix: Prevent stale search results race condition Added latestQueryRef to track the most recent search query and prevent stale results from overwriting current results. Race condition scenario (BEFORE): 1. User types 'iphone' -> Request A starts (slow) 2. User types 'mac' -> Request B starts (fast) 3. Request B completes -> Shows MacBook results β 4. Request A completes -> Overwrites with iPhone results β (WRONG!) Solution (AFTER): - Track latest query in latestQueryRef - Before updating state, check if response matches latest query - Discard stale responses that don't match current query - Prevents dropdown from reopening with outdated results Benefits: - No stale results shown - No dropdown reopening after clearing - Consistent UI state - Better UX when typing quickly Files changed: - src/components/common/SearchBar.tsx * fix: Keep dropdown open to show 'No products found' message Previously, the dropdown would close when searchResults.length === 0, preventing users from seeing the 'No products found' feedback. Changes: - Always set isOpen to true after search completes (success or error) - Dropdown now shows 'No products found' when query returns 0 results - Dropdown shows error message when search fails - Only closes when user explicitly clears or clicks away User feedback improvements: - β Search 'xyz123' -> Shows 'No products found' - β Network error -> Shows error message - β Clear button -> Closes dropdown - β Click away -> Closes dropdown This aligns with the testing guide expectations and provides better UX with explicit feedback for all search states. Files changed: - src/components/common/SearchBar.tsx * feat: Add accessibility improvements and prevent setState on unmounted component Accessibility improvements (WCAG compliance): - Added aria-label='Search products' to input for screen readers - Added aria-describedby with hidden description text - Added aria-autocomplete='list' to indicate autocomplete behavior - Added aria-controls and aria-expanded for dropdown state - Added role='listbox' to results list - Added role='option' to each result item - Added descriptive aria-label to each product button Cleanup improvements: - Added isMountedRef to track component mount state - Guard all setState calls with isMountedRef.current check - Prevents 'Can't perform a React state update on an unmounted component' warnings - Set isMountedRef.current = false in cleanup effect - Prevents memory leaks from in-flight requests Benefits: - β Screen readers announce 'Search products' instead of just placeholder - β Screen readers announce dropdown state (expanded/collapsed) - β Screen readers can navigate results with arrow keys - β Each product is properly announced with name and price - β No setState warnings when component unmounts during search - β No memory leaks from async operations Files changed: - src/components/common/SearchBar.tsx * fix: Separate mount tracking from debounce cleanup and use visually-hidden for aria-describedby Issue 1: isMountedRef incorrectly set to false on dependency changes --------------------------------------------------------------------- Problem: - Previous cleanup ran when debouncedSearch changed (debounceDelay/maxResults) - Set isMountedRef.current = false while component still mounted - Blocked all future state updates even though component was mounted Solution: - Separated mount/unmount tracking into dedicated useEffect with empty deps [] - Only sets isMountedRef.current = true on mount - Only sets isMountedRef.current = false on unmount - Debounce cleanup in separate useEffect that only cancels pending calls Before (BROKEN): useEffect(() => { return () => { isMountedRef.current = false // β Runs on dependency change! debouncedSearch.cancel() } }, [debouncedSearch]) // β Runs when debounceDelay/maxResults change After (FIXED): useEffect(() => { isMountedRef.current = true return () => { isMountedRef.current = false // β Only on unmount } }, []) // β Empty deps - only mount/unmount useEffect(() => { return () => { debouncedSearch.cancel() // β Cancel debounce separately } }, [debouncedSearch]) Issue 2: aria-describedby element hidden from screen readers ------------------------------------------------------------- Problem: - Used style={{ display: 'none' }} - CSS display:none hides from screen readers AND visual users - aria-describedby description was never announced Solution: - Used visually-hidden technique (sr-only pattern) - Positions element off-screen but keeps it in accessibility tree - Screen readers can read it, but visual users don't see it Before (BROKEN): <span style={{ display: 'none' }}> {/* β Hidden from screen readers */} Description text </span> After (FIXED): <Box sx={{ position: 'absolute', width: '1px', height: '1px', padding: 0, margin: '-1px', overflow: 'hidden', clip: 'rect(0, 0, 0, 0)', whiteSpace: 'nowrap', border: 0, }}> {/* β Visually hidden but accessible */} Description text </Box> Benefits: - β isMountedRef only changes on actual mount/unmount - β State updates work correctly when props change - β Debounce still properly cleaned up - β Screen readers announce the description - β WCAG 2.1 compliant visually-hidden technique - β No visual clutter for sighted users Files changed: - src/components/common/SearchBar.tsx * Fix: Cancel pending debounced search when clearing search input - Add debouncedSearch.cancel() call in handleClear to prevent stale results - Prevents queued search requests from repopulating dropdown after clear - Fixes race condition when user clicks clear within debounce window * Fix: Only set aria-controls when search results list is rendered - Change aria-controls condition from isOpen to isOpen && searchResults.length > 0 - Prevents invalid ARIA reference when dropdown shows error or empty states - Ensures aria-controls only references search-results-list when it exists in DOM * Fix: Prevent dropdown from reopening after click-away and remove non-existent placeholder - Add userDismissedRef to track when user explicitly dismisses dropdown - Only call setIsOpen(true) in search handlers if user hasn't dismissed - Reset userDismissedRef when user types or clears search - Remove '/placeholder-product.png' fallback that may not exist - Let MUI Avatar handle missing images with built-in fallback - Prevents unexpected dropdown reopening when search completes after click-away * Docs: Update TESTING_SEARCHBAR.md to reflect current mock service setup - Clarify that SearchBar already uses mock service by default - Remove outdated instructions about 'temporarily replacing the import' - Add clear section on how to switch to real backend service when ready - Reorganize sections to reflect current implementation - Make testing instructions more accurate and easier to follow * Fix: Cancel debounced search on result click and add return type to getCategories SearchBar changes: - Add debouncedSearch.cancel() in handleResultClick to cancel pending searches - Reset latestQueryRef.current to prevent in-flight requests from updating state - Prevents dropdown from reopening after navigation when search completes mockProductService changes: - Add Promise<Category[]> return type to getCategories method - Add Category to imports from @features/products/types - Add type parameter to Map<string, Category> for type safety - Ensures mock service matches real service contract for interchangeability * Fix: Use unique IDs per SearchBar instance to avoid duplicate-id accessibility issues - Import and use React's useId hook to generate unique IDs per instance - Replace hard-coded 'search-products-description' with descriptionId - Replace hard-coded 'search-results-list' with resultsListId - Prevents duplicate ID collisions when multiple SearchBar components are mounted - Ensures valid ARIA references for aria-describedby and aria-controls - Improves accessibility compliance for screen readers --------- Co-authored-by: Shehryar Raza <[email protected]>
* feat: Add shop page with filters and sorting - Add ProductFilters and SortBy types to product types - Create 20 mock products across 5 categories (Electronics, Clothing, Home & Kitchen, Sports, Books) - Implement PriceRangeFilter component with two-way slider (adjustable min/max) - Implement RatingFilter component with two-way slider (0-5 stars range) - Create ProductCard component with: - Product image, name, category, rating, price - Discount badge and out-of-stock indicator - Low stock warning - Hover effects and navigation - Create SortDropdown component with options: - Newest First - Price: Low to High - Price: High to Low - Highest Rated - Implement ShopPage with: - Left sidebar with filters (desktop) / drawer (mobile) - Center product grid (responsive 3-column on desktop, 2 on tablet, 1 on mobile) - Top bar with product count and sort dropdown - Filter and sort logic applied to products - Empty state with reset filters option - Add /shop route to AppRoutes and ROUTES constants - All components fully responsive with mobile support * fix: Add @DaTa path alias to tsconfig and vite config - Add @data/* path alias to tsconfig.json - Add @DaTa alias to vite.config.ts - Fixes import resolution for mockProducts in ShopPage * feat: Improve slider responsiveness with drag support - Add local state to both PriceRangeFilter and RatingFilter for smooth dragging - Use onChangeCommitted to only update filters when drag is complete (better performance) - Add step={1} for price slider and step={0.5} for rating slider - Add disableSwap to prevent thumbs from crossing - Enhance visual feedback with hover and active states - Increase track and rail height for better touch/mouse interaction - Add visual feedback with shadow effects on hover and drag - Display values update in real-time while dragging - Filters only apply when user releases the slider (prevents lag) * fix: Improve slider drag support and add product animations Slider improvements: - Fix trackpad dragging by using useEffect instead of direct state comparison - Properly sync local state with prop changes - Ensure smooth dragging on all input devices (mouse, trackpad, touch) Routing changes: - Replace /shop route with /products route - Use ShopPage component for /products instead of ProductListPage - Remove SHOP constant from routes Animation improvements: - Add Fade animation to ProductCard components - Stagger animation timing based on card index (30ms delay per card) - 300ms base fade-in duration for smooth appearance - Products now fade in sequentially when loaded or filtered * renamed file * removed unused import * fix: Use sx prop for warning color in Typography - Change color='warning.main' to sx={{ color: 'warning.main' }} - Fixes TypeScript error as Typography color prop only accepts specific string values - Maintains the same visual appearance with proper type safety * fix: Import React for SyntheticEvent type annotation - Add React import to PriceRangeFilter.tsx - Add React import to RatingFilter.tsx - Fixes TypeScript error where React.SyntheticEvent was referenced without importing React - Maintains proper type safety for event handlers * refactor: Import SyntheticEvent directly instead of React namespace - Import SyntheticEvent directly from 'react' in PriceRangeFilter - Import SyntheticEvent directly from 'react' in RatingFilter - Cleaner imports without needing React namespace - Improved code formatting and consistency * fix: Use nullish coalescing for numeric filter defaults - Replace || with ?? for minPrice, maxPrice, minRating, maxRating - Prevents 0 values from being incorrectly treated as falsy - Allows users to filter with 0 as a valid bound (e.g., /opt/homebrew/bin/bash price, 0 rating) - Also fix discountPrice fallback to use ?? instead of || - Only defaults to fallback value when undefined/null, not when 0 * revert: Restore color prop for Typography warning text - Revert back to using color='warning.main' prop - Previous change to sx={{ color: 'warning.main' }} was unnecessary - MUI Typography does support theme color paths in color prop * revert: Restore || operator for filter defaults - Revert nullish coalescing (??) back to logical OR (||) - Restore original behavior for minPrice, maxPrice, minRating, maxRating - Restore discountPrice fallback using || --------- Co-authored-by: Shehryar Raza <[email protected]>
feat: AS-5 - add image field to product, brand and category. Also implementβ¦
feat: AS-5 - implement account endpoint and test cases
* feat: Implement comprehensive cart page with full functionality
Cart Store Enhancements:
- Added removeItems() method to remove multiple items at once
- Supports bulk deletion for selected items
Cart Page Features:
- Product display with image, title, description, and price
- Quantity controls (increase/decrease with +/- buttons)
- Direct quantity input with stock validation
- Checkbox selection for individual items
- Select all checkbox for bulk operations
- Remove selected items functionality
- Clear entire cart functionality
- Stock warnings when quantity exceeds available stock
- Empty cart state with call-to-action
Order Summary:
- Subtotal calculation
- Tax calculation (10%)
- Shipping cost (free over $50)
- Total amount
- Free shipping progress indicator
- Proceed to Checkout button
- Continue Shopping button
UI/UX:
- Responsive layout (mobile and desktop)
- Sticky order summary on desktop
- Table layout for cart items
- Product images with proper sizing
- Hover effects on table rows
- Selected row highlighting
- Disabled states for buttons and controls
- Stock validation for quantity changes
- Professional styling with MUI components
All features integrated with Zustand cart store for state management
* debug: Add console logging to cart page for debugging
- Added console logs to see cart state
- Logs cart object, items array, and item count
- This will help identify why items aren't showing
* debug: Add more detailed console logging
- Added check for cart.items existence
- Added items length log
- Added empty check boolean log
- Added log when showing empty state
- Added log when rendering items
- This will help identify exact issue
* feat: Implement full CartDrawer with product display and management
CartDrawer Features:
- Display all cart items with product images (80x80 avatars)
- Product name, price per unit, and subtotal
- Quantity controls (increase/decrease with +/- buttons)
- Direct quantity input with stock validation
- Remove item button for each product
- Stock limit warnings
- Empty cart state with icon and message
Order Summary in Drawer:
- Subtotal display
- Tax calculation (10%)
- Shipping cost (free over $50)
- Total amount with prominent styling
Action Buttons:
- Proceed to Checkout (navigates to /checkout)
- View Full Cart (navigates to /cart page)
- Continue Shopping (closes drawer)
UI/UX:
- Scrollable list for cart items
- Sticky header and footer
- Responsive width (100% mobile, 420px desktop)
- Clean dividers between items
- Professional MUI styling
- Proper spacing and typography
All features integrated with Zustand cart store
* debug: Add console logging to addItem in cart store
- Log item being added with quantity
- Log existing vs new quantity when updating
- Log final quantity after stock validation
- This will help identify quantity mismatch issue
* fix: Replace cart item quantity instead of adding to it
Changed behavior:
- When adding a product that's already in cart, the quantity is now REPLACED instead of ADDED
- Example: If cart has 5 items, and you add 3 from product page, cart will show 3 (not 8)
- This matches expected UX where the product page quantity selector sets the desired quantity
Technical changes:
- Modified addItem() in cartStore to replace existing item quantity
- Removed quantity addition logic (existingItem.quantity + item.quantity)
- Now directly uses item.quantity for existing items
- Stock validation still applies
- Removed debug console logs
* debug: Add detailed logging to addItem function
- Log item being added and its product ID
- Log current cart items and their product IDs
- Log whether replacing or adding new item
- Log old vs new quantity
- Log final updated items
- This will help identify why quantity isn't updating in CartDrawer
* feat: Change product page to show Update Cart button when item in cart
UX Changes:
- When product is NOT in cart: Shows 'Add to Cart' button
- When product IS in cart: Shows 'Update Cart' button + 'Remove' button
- Both buttons are displayed side by side when product is in cart
- Clicking 'Update Cart' calls addItem() which replaces the quantity
- Clicking 'Remove' removes the product from cart
This allows users to:
- Add product to cart initially
- Change quantity on product page and click 'Update Cart' to update
- Remove product from cart with separate 'Remove' button
Fixes the issue where users couldn't update quantity from product page
* feat: Add confirmation dialogs for remove and clear cart actions
Product Detail Page:
- Added confirmation dialog when clicking 'Remove' button
- Dialog asks 'Remove from Cart?' with Cancel/Remove options
- Prevents accidental removal of products from cart
Cart Page:
- Added confirmation dialog when clicking 'Clear Cart' button
- Dialog asks 'Clear Cart?' with warning about irreversible action
- Prevents accidental clearing of entire cart
Implementation:
- Used MUI Dialog, DialogTitle, DialogContent, DialogActions components
- Added state management for dialog open/close
- Split handlers into click/confirm/cancel functions
- Consistent UX across both dialogs
- Auto-focus on confirm button for keyboard accessibility
UX Improvements:
- Users must confirm before destructive actions
- Clear messaging about what will happen
- Easy to cancel if clicked by mistake
* feat: Add confirmation dialog for removing items in CartDrawer
CartDrawer Changes:
- Added confirmation dialog when clicking delete icon on cart items
- Dialog shows product name being removed
- Prevents accidental removal of items from cart drawer
Implementation:
- Added useState for dialog state and item to remove
- Created handleRemoveClick to open dialog with item details
- Created handleRemoveConfirm to actually remove the item
- Created handleRemoveCancel to close dialog without removing
- Updated delete IconButton to call handleRemoveClick
- Added Dialog component at end of CartDrawer
Dialog Features:
- Title: 'Remove Item?'
- Message: Shows product name in bold
- Cancel button (primary color)
- Remove button (error/red, auto-focused)
- Keyboard accessible (Enter/Escape)
- ARIA labels for accessibility
UX Consistency:
- Matches confirmation dialogs in ProductDetailPage and CartPage
- Same visual style and interaction pattern
- Prevents accidental deletions across all cart interfaces
* feat: Add confirmation dialog for individual item deletion in CartPage
CartPage Changes:
- Added confirmation dialog when clicking delete icon on cart items in table
- Dialog shows product name being removed
- Prevents accidental removal of individual items from cart page
Implementation:
- Added state for removeItemDialogOpen and itemToRemove
- Created handleRemoveItemClick to open dialog with item details
- Created handleRemoveItemConfirm to remove item and update selected items
- Created handleRemoveItemCancel to close dialog without removing
- Updated delete IconButton onClick to call handleRemoveItemClick
- Added second Dialog component for individual item removal
Dialog Features:
- Title: 'Remove Item?'
- Message: Shows product name in bold
- Cancel button (primary color)
- Remove button (error/red, auto-focused)
- Keyboard accessible (Enter/Escape)
- ARIA labels for accessibility
- Also removes item from selectedItems array if it was selected
Complete Coverage:
- All four deletion points now have confirmation dialogs:
1. Product Detail Page - Remove button
2. Cart Page - Clear Cart button
3. Cart Page - Individual delete icons (NEW!)
4. Cart Drawer - Individual delete icons
- Consistent UX across entire cart system
- No accidental deletions possible anywhere
* refactor: Remove debug logs and fix quantity initialization
Removed Debug Logs:
- Removed all console.log statements from CartPage
- Removed all debug logging from cartStore addItem function
- Cleaner production code without noise in logs
Fixed Quantity Initialization:
- Product detail page now initializes quantity from existing cart item
- When product is already in cart, quantity selector shows current cart quantity
- Prevents accidental quantity reduction when clicking 'Update Cart'
- Added useEffect to sync quantity state with cartItem changes
- Resets to 1 when product is removed from cart
Benefits:
- No more unintentional quantity changes
- Better UX - users see their current cart quantity
- Cleaner console logs in production
- More predictable behavior when updating cart from product page
* feat: Add confirmation dialog for bulk deletion (Remove Selected)
CartPage Changes:
- Added confirmation dialog for 'Remove Selected' button
- Prevents accidental bulk deletion of multiple cart items
- Completes the goal of confirmations for ALL destructive actions
Implementation:
- Added removeSelectedDialogOpen state
- Renamed handleRemoveSelected to handleRemoveSelectedClick
- Created handleRemoveSelectedConfirm to execute bulk deletion
- Created handleRemoveSelectedCancel to close dialog
- Updated 'Remove Selected' button onClick handler
- Added Dialog component with dynamic item count
Dialog Features:
- Title: 'Remove Selected Items?'
- Message: Shows count of selected items (e.g., '3 selected items')
- Proper singular/plural handling ('1 item' vs '3 items')
- Cancel button (primary color)
- Remove button shows count (e.g., 'Remove 3 Items')
- Error color for destructive action
- Auto-focused confirm button
- Keyboard accessible (Enter/Escape)
- ARIA labels for accessibility
Complete Coverage - All 5 Destructive Actions Now Protected:
1. Product Detail Page - Remove button β
2. Cart Page - Clear Cart button β
3. Cart Page - Individual delete icons β
4. Cart Page - Remove Selected (bulk) β
NEW!
5. Cart Drawer - Individual delete icons β
No accidental deletions possible anywhere in the cart system!
* feat: Improve quantity TextField with type=number and inputMode=numeric
CartPage and CartDrawer Changes:
- Added type="number" to quantity TextField inputs
- Added inputMode="numeric" to inputProps
- Browsers now enforce numeric input validation
- Min/max constraints are properly honored by browser
Benefits:
- Prevents entering non-numeric characters (letters, symbols)
- Mobile devices show numeric keyboard instead of full keyboard
- Better UX - users can't accidentally enter invalid values
- Browser-native validation for min/max values
- Improved accessibility with proper input type
- Consistent behavior across both cart page and drawer
Technical Details:
- type="number" enables browser numeric validation
- inputMode="numeric" optimizes mobile keyboard layout
- Works with existing min/max inputProps (1 to stock)
- Maintains existing onChange validation as fallback
* refactor: Disable quantity TextField to rely on +/- buttons only
CartPage and CartDrawer Changes:
- Added disabled attribute to quantity TextField inputs
- Removed onChange handlers (no longer needed)
- Users must now use +/- IconButtons to change quantity
- Quantity field is now read-only display
Rationale:
- Prepares for real-time stock API integration
- Prevents manual input validation issues
- Ensures quantity changes go through controlled +/- buttons
- Better UX - clear, predictable interaction pattern
- Stock validation happens only in +/- button handlers
- Avoids edge cases with direct text input
Benefits:
- Simpler validation logic (only in increment/decrement)
- Prevents users from typing invalid values
- Consistent with common e-commerce UX patterns
- Ready for API service integration for real-time stock
- Cleaner code - no onChange validation needed
- Better mobile experience - no keyboard popup
Future-Ready:
- When API service is implemented, stock updates will be real-time
- +/- buttons will check live stock availability
- Disabled field prevents race conditions with API updates
- Clear visual indication that quantity is controlled
---------
Co-authored-by: Shehryar Raza <[email protected]>
feat: SCRUM-30 - implement product search and ordering
fix: SCRUM-16 - allow cors
feat: SCRUM-32 - implement cart and cart item model
feat: SRUM-18 - implement logout endpoint
* feat: API base setup with Django backend integration - Integrate Django authentication APIs (login, register, token refresh) - Add email verification flow after registration - Configure CORS for frontend-backend communication - Implement token-based authentication with JWT - Add user profile API integration - Setup API client with automatic token refresh interceptors - Configure Zustand store for auth state management - Add success/error banners for auth pages - Update API endpoints to match Django URL patterns - Transform data between camelCase (frontend) and snake_case (backend) Auth Flow: - Registration: User registers β Email verification page β Verify email β Login - Login: Fetch tokens β Fetch user profile β Store in Zustand β Redirect - Token Refresh: Auto-refresh expired tokens via interceptor - Logout: Clear tokens and user data from store Backend Changes: - Add django-cors-headers for CORS support - Configure CORS allowed origins for local development - Update RegisterSerializer to return user data only (no tokens) Frontend Changes: - Create VerifyEmailPage component for email verification - Update LoginPage with enhanced error handling - Update RegisterPage to redirect to email verification - Add LoginResponseAPI and RegisterResponseAPI types - Update authService to handle Django response formats - Update API client token refresh logic - Update auth store authentication logic based on accessToken presence * fix: add support for 'details' error key in auth error handling - Add handling for 'details' key to match Django NON_FIELD_ERRORS_KEY config - Update LoginPage and RegisterPage error handling - Maintain backward compatibility with non_field_errors and detail keys - Handle both array and string formats for details field * fix: prevent duplicate form submissions during redirect delay - Remove finally block that resets isSubmitting state - Only reset isSubmitting on error to re-enable form - Keep form disabled during success redirect to prevent duplicate submissions - Affects LoginPage and RegisterPage with 1.5s redirect delays * fix: ensure client auth state clears even when logout API fails - Wrap logout API call in try-catch-finally block - Always clear Zustand auth state in finally block - Prevents users from being stuck logged in if /auth/logout/ returns 404 - Update Header component to use authService.logout() instead of direct store access - Ensures reliable logout even when backend endpoint is not implemented --------- Co-authored-by: Shehryar Raza <[email protected]>
β¦trol feat: Scrum 18 email verification control
feat: SCRUM-33 - implement cart endpoints
β¦ess (#47) * feat: API base setup with Django backend integration - Integrate Django authentication APIs (login, register, token refresh) - Add email verification flow after registration - Configure CORS for frontend-backend communication - Implement token-based authentication with JWT - Add user profile API integration - Setup API client with automatic token refresh interceptors - Configure Zustand store for auth state management - Add success/error banners for auth pages - Update API endpoints to match Django URL patterns - Transform data between camelCase (frontend) and snake_case (backend) Auth Flow: - Registration: User registers β Email verification page β Verify email β Login - Login: Fetch tokens β Fetch user profile β Store in Zustand β Redirect - Token Refresh: Auto-refresh expired tokens via interceptor - Logout: Clear tokens and user data from store Backend Changes: - Add django-cors-headers for CORS support - Configure CORS allowed origins for local development - Update RegisterSerializer to return user data only (no tokens) Frontend Changes: - Create VerifyEmailPage component for email verification - Update LoginPage with enhanced error handling - Update RegisterPage to redirect to email verification - Add LoginResponseAPI and RegisterResponseAPI types - Update authService to handle Django response formats - Update API client token refresh logic - Update auth store authentication logic based on accessToken presence * feat: implement login flow with route protection and guest access - Add ProtectedRoute component to guard authenticated routes - Add PublicRoute component to prevent logged-in users from accessing auth pages - Update AppRoutes with route protection for auth and protected routes - Add 'Continue as Guest' button on login page for unauthenticated browsing - Login redirects to home page (/) after successful authentication - Protected routes (/checkout, /orders, /profile, /wishlist) require authentication - Auth routes (/login, /register) redirect to home if already logged in - Guest users can browse products but must login for protected features * fix: add support for 'details' error key in auth error handling - Add handling for 'details' key to match Django NON_FIELD_ERRORS_KEY config - Update LoginPage and RegisterPage error handling - Maintain backward compatibility with non_field_errors and detail keys - Handle both array and string formats for details field * fix: prevent duplicate form submissions during redirect delay - Remove finally block that resets isSubmitting state - Only reset isSubmitting on error to re-enable form - Keep form disabled during success redirect to prevent duplicate submissions - Affects LoginPage and RegisterPage with 1.5s redirect delays * fix: ensure client auth state clears even when logout API fails - Wrap logout API call in try-catch-finally block - Always clear Zustand auth state in finally block - Prevents users from being stuck logged in if /auth/logout/ returns 404 - Update Header component to use authService.logout() instead of direct store access - Ensures reliable logout even when backend endpoint is not implemented * added change * added protected gate * fix: prevent premature route redirects before auth state hydration - Add hasHydrated flag to authStore to track persist rehydration status - Update ProtectedRoute to wait for hydration before checking auth state - Update PublicRoute to wait for hydration before redirecting - Prevents authenticated users from being redirected to /login on initial page load - Fixes race condition where routing decisions were made before localStorage state loaded - Uses Zustand persist onRehydrateStorage callback to set hydration flag --------- Co-authored-by: Shehryar Raza <[email protected]>
* feat: API base setup with Django backend integration
- Integrate Django authentication APIs (login, register, token refresh)
- Add email verification flow after registration
- Configure CORS for frontend-backend communication
- Implement token-based authentication with JWT
- Add user profile API integration
- Setup API client with automatic token refresh interceptors
- Configure Zustand store for auth state management
- Add success/error banners for auth pages
- Update API endpoints to match Django URL patterns
- Transform data between camelCase (frontend) and snake_case (backend)
Auth Flow:
- Registration: User registers β Email verification page β Verify email β Login
- Login: Fetch tokens β Fetch user profile β Store in Zustand β Redirect
- Token Refresh: Auto-refresh expired tokens via interceptor
- Logout: Clear tokens and user data from store
Backend Changes:
- Add django-cors-headers for CORS support
- Configure CORS allowed origins for local development
- Update RegisterSerializer to return user data only (no tokens)
Frontend Changes:
- Create VerifyEmailPage component for email verification
- Update LoginPage with enhanced error handling
- Update RegisterPage to redirect to email verification
- Add LoginResponseAPI and RegisterResponseAPI types
- Update authService to handle Django response formats
- Update API client token refresh logic
- Update auth store authentication logic based on accessToken presence
* feat: implement login flow with route protection and guest access
- Add ProtectedRoute component to guard authenticated routes
- Add PublicRoute component to prevent logged-in users from accessing auth pages
- Update AppRoutes with route protection for auth and protected routes
- Add 'Continue as Guest' button on login page for unauthenticated browsing
- Login redirects to home page (/) after successful authentication
- Protected routes (/checkout, /orders, /profile, /wishlist) require authentication
- Auth routes (/login, /register) redirect to home if already logged in
- Guest users can browse products but must login for protected features
* fix: add support for 'details' error key in auth error handling
- Add handling for 'details' key to match Django NON_FIELD_ERRORS_KEY config
- Update LoginPage and RegisterPage error handling
- Maintain backward compatibility with non_field_errors and detail keys
- Handle both array and string formats for details field
* fix: prevent duplicate form submissions during redirect delay
- Remove finally block that resets isSubmitting state
- Only reset isSubmitting on error to re-enable form
- Keep form disabled during success redirect to prevent duplicate submissions
- Affects LoginPage and RegisterPage with 1.5s redirect delays
* fix: ensure client auth state clears even when logout API fails
- Wrap logout API call in try-catch-finally block
- Always clear Zustand auth state in finally block
- Prevents users from being stuck logged in if /auth/logout/ returns 404
- Update Header component to use authService.logout() instead of direct store access
- Ensures reliable logout even when backend endpoint is not implemented
* added change
* added protected gate
* fix: prevent premature route redirects before auth state hydration
- Add hasHydrated flag to authStore to track persist rehydration status
- Update ProtectedRoute to wait for hydration before checking auth state
- Update PublicRoute to wait for hydration before redirecting
- Prevents authenticated users from being redirected to /login on initial page load
- Fixes race condition where routing decisions were made before localStorage state loaded
- Uses Zustand persist onRehydrateStorage callback to set hydration flag
* feat: implement user profile page with API integration
- Add comprehensive ProfilePage component with view/edit modes
- Implement GET /accounts/profile/ API integration
- Implement PATCH /accounts/profile/ API integration for updates
- Add UserProfileAPI and UpdateProfileRequestAPI types matching backend
- Add API response/request format conversion (snake_case <-> camelCase)
- Support all profile fields: username, firstName, lastName, mobile, gender
- Add profile header with avatar showing user initials
- Add inline editing with Edit/Save/Cancel buttons
- Add loading states and error handling
- Add success message with auto-hide after 3 seconds
- Display read-only fields: email, role, account status, member since date
- Use MUI Grid layout for responsive form fields
- Apply consistent styling with Colors config
* fix: use PUT instead of PATCH for profile update API call
- Change updateProfile to use apiClient.put instead of apiClient.patch
- Matches backend API endpoint that accepts PUT method
* fix: use PATCH and only send changed fields in profile update
- Change back to PATCH method for profile updates
- Only send fields that have actually changed (not empty and different from current)
- Add validation to check if there are any changes before sending request
- Show 'No changes to save' error if user tries to save without modifications
- Prevents sending empty username field that causes backend errors
- Ensures PATCH semantics: only modified fields are sent
* refactor: consolidate UserProfile to use backend API format (snake_case)
- Remove duplicate UserProfileAPI and UpdateProfileRequestAPI interfaces
- Use single UserProfile interface matching backend format with snake_case
- Remove conversion helper functions (convertProfileFromAPI, convertProfileToAPI)
- Update ProfilePage to use snake_case field names (first_name, last_name, etc.)
- Simplify userService by removing format conversion layer
- Direct API response/request mapping without transformation
- Benefits: simpler code, fewer conversions, single source of truth
* feat: integrate Mantine form with validation for ProfilePage
- Install @mantine/core, @mantine/hooks, @mantine/form packages
- Add MantineProvider to App.tsx wrapping MUI ThemeProvider
- Replace manual form state management with Mantine's useForm hook
- Add comprehensive validation rules:
- Username: required, min 3 chars, max 150 chars
- First name: required, min 2 chars, max 150 chars
- Last name: required, min 2 chars, max 150 chars
- Mobile: optional, max 20 chars
- Keep all UI components as MUI (TextField, Button, Grid, etc.)
- Use Mantine form's getInputProps() for field binding
- Display validation errors inline with MUI TextField error/helperText
- Form validates on submit, prevents submission if invalid
- Validation only shows when in edit mode
- Remove manual formData state and handleInputChange
- Use form.onSubmit() for handleSave with automatic validation
* refactor: move 'changed fields' validation logic into useForm hook
- Convert validate from object to function for access to all form values
- Add validation to check if any field has actually changed from profile
- Prevent form submission if no changes detected
- Show error message 'No changes detected' on username field if nothing changed
- Remove redundant 'No changes to save' check from handleSave
- Validation now handles both field-level and form-level validation
- API will only be called if at least one field has been modified
- Cleaner handleSave function with validation logic centralized in useForm
* refactor: modularize ProfilePage validation logic
- Create profileValidation.ts utility module with:
- VALIDATION_MESSAGES: centralized error messages
- VALIDATION_CONSTRAINTS: validation rules (min/max lengths)
- validateUsername, validateFirstName, validateLastName, validateMobile: individual field validators
- hasProfileChanges: check if any field changed from original
- getChangedFields: extract only modified fields for API call
- validateProfileForm: main validation function combining all validators
- Create useProfileForm custom hook:
- Encapsulates Mantine form initialization
- Integrates validateProfileForm for validation
- Provides setProfileValues and resetToProfile helper methods
- Cleaner separation of form logic from component
- Update ProfilePage component:
- Replace inline validation with useProfileForm hook
- Use setProfileValues in fetchProfile
- Use resetToProfile in handleCancel
- Use getChangedFields in handleSave
- Reduced component from ~200 lines to ~100 lines
- Much cleaner and more maintainable code
Benefits:
- Reusable validation functions
- Testable validation logic in isolation
- Centralized validation messages and constraints
- Easier to maintain and extend
- Better separation of concerns
- Type-safe validation utilities
* refactor: implement Zod for profile validation
- Install zod package for schema-based validation
- Replace manual validation functions with Zod schema (profileUpdateSchema)
- Create zodResolver helper to convert Zod errors to Mantine form format
- Export ProfileUpdateFormValues type inferred from Zod schema
- Update validateProfileForm to use zodResolver
- Maintain custom business logic (change detection) alongside Zod validation
Benefits of Zod:
- Type-safe validation with automatic TypeScript inference
- Declarative schema definition (easier to read and maintain)
- Built-in error messages with custom overrides
- Composable schemas for complex validation
- Runtime type checking aligned with TypeScript types
- Better error handling and reporting
- Industry standard for schema validation
- Reduces boilerplate code significantly
Schema features:
- Username: required, trimmed, 3-150 chars
- First name: required, trimmed, 2-150 chars
- Last name: required, trimmed, 2-150 chars
- Mobile: optional, max 20 chars
- Gender: enum (Male, Female, Other), optional
- Custom validation: no changes detection
* refactor: remove @mantine/core and @mantine/hooks packages
- Uninstall @mantine/core and @mantine/hooks
- Keep only @mantine/form for form management
- Remove MantineProvider from App.tsx
- Remove @mantine/core/styles.css import
- Use MUI exclusively for UI components
- Use @mantine/form only for form state and validation logic
Benefits:
- Smaller bundle size (removed 22 packages)
- No UI library conflicts
- Cleaner dependency tree
- MUI for all UI components (consistent design)
- Mantine form for validation logic only
- Best of both worlds: MUI UI + Mantine form management
* fix: allow clearing optional fields and support 'Not specified' gender
Issue 1: getChangedFields used truthy checks preventing cleared values
- Changed from truthy checks (values.mobile &&) to !== undefined
- Now allows sending empty string to clear mobile field
- Consistent with hasProfileChanges which uses !== undefined
- Prevents skipping updates when intended value is empty
Issue 2: Gender schema didn't allow empty string for 'Not specified'
- Updated gender schema to accept empty string: .or(z.literal(''))
- Aligns with MenuItem value='' for 'Not specified' option
- Prevents validation error when user selects 'Not specified'
- Allows clearing gender field
Before:
- if (values.mobile && values.mobile !== ...) // Truthy check
- gender: z.enum(['Male', 'Female', 'Other']).optional()
After:
- if (values.mobile !== undefined && values.mobile !== ...) // Explicit check
- gender: z.enum(['Male', 'Female', 'Other']).optional().or(z.literal(''))
Benefits:
- Users can now clear optional fields (mobile, gender)
- 'Not specified' gender option works without validation errors
- Consistent validation logic across all fields
- Empty strings are properly sent to API for clearing values
* fix: add in-flight guard to prevent concurrent save submissions
Issue: Double-clicking Save button causes multiple PATCH requests
- Multiple API calls can create race conditions
- Duplicate updates sent to backend
- No visual feedback during save operation
- Cancel button remains clickable during save
Solution: Add isSaving state to track save operation
- Early return if already saving: if (isSaving) return
- Set isSaving=true at start of save operation
- Set isSaving=false in finally block (always executes)
- Disable both Save and Cancel buttons while saving
- Show loading spinner in Save button during save
- Change button text to 'Saving...' for visual feedback
Implementation:
1. Added isSaving state: useState(false)
2. Guard clause in handleSave: if (isSaving) return
3. Set isSaving in try/finally blocks
4. Disabled buttons: disabled={isSaving}
5. Loading indicator: startIcon={isSaving ? <CircularProgress /> : <Save />}
6. Dynamic text: {isSaving ? 'Saving...' : 'Save Changes'}
Benefits:
- β
Prevents duplicate API requests
- β
Prevents race conditions
- β
Clear visual feedback (spinner + text)
- β
Buttons disabled during save
- β
Better UX with loading state
- β
Guaranteed cleanup with finally block
* fix: align gender field types with backend contract
Issue: Type mismatch between UI, validation, and backend
- UI allowed empty string '' for 'Not specified' option
- Zod schema allowed empty string: .or(z.literal(''))
- TypeScript types only allowed: 'Male' | 'Female' | 'Other'
- Backend gender field is NOT nullable (no null=True)
- Backend has default value of 'Other'
- Backend ALWAYS returns one of: 'Male' | 'Female' | 'Other'
Problem:
- If user selects 'Not specified' (empty string), backend rejects it
- Backend never returns empty string, so 'Not specified' state is impossible
- Type inconsistency between frontend and backend contract
- Potential runtime errors when backend returns non-empty gender
Solution: Align frontend with backend contract
1. Removed 'Not specified' option from UI
2. Updated Zod schema to require gender (removed .or(z.literal('')))
3. Updated form initial value: gender: 'Other' (matches backend default)
4. Updated setProfileValues: gender: profileData.gender (no fallback to undefined)
5. Gender is now always one of: 'Male' | 'Female' | 'Other'
Changes:
- ProfilePage.tsx: Removed <MenuItem value=""> for 'Not specified'
- profileValidation.ts: Changed gender schema from .optional().or(z.literal('')) to required enum
- useProfileForm.ts: Changed initial gender from undefined to 'Other'
- useProfileForm.ts: Removed fallback in setProfileValues (backend always returns value)
Backend Contract (Django):
Benefits:
- β
Frontend types match backend contract
- β
No type inconsistencies
- β
No runtime errors from unexpected empty strings
- β
Validation aligns with backend constraints
- β
Default value matches backend default ('Other')
- β
Simpler UI - no ambiguous 'Not specified' state
* fix: prevent memory leak from success message timeout on unmount
Issue: Success message timeout not cleared on unmount
- setTimeout creates a timeout that triggers setSuccessMessage after 3 seconds
- If user navigates away within 3 seconds, timeout still fires
- Causes 'setState on unmounted component' warning
- Minor memory leak from uncancelled timeout
Problem:
1. No cleanup function to clear timeout on unmount
2. Using setTimeout instead of lodash delay
3. No reference to timeout ID for cleanup
Solution: Add cleanup effect and use lodash delay
1. Import useRef from React
2. Import delay from lodash/delay
3. Add successTimeoutRef to store timeout ID
4. Clear existing timeout before setting new one in handleSave
5. Use lodash delay instead of setTimeout
6. Add cleanup useEffect to clear timeout on unmount
Changes:
- Added import: useRef from 'react'
- Added import: delay from 'lodash/delay'
- Added ref: successTimeoutRef = useRef<number | null>(null)
- Added cleanup effect: clears timeout on unmount
- Updated handleSave: clears existing timeout before setting new one
- Replaced setTimeout with lodash delay
- Store timeout ID in successTimeoutRef.current
Benefits:
- β
No setState on unmounted component warnings
- β
No memory leaks from uncancelled timeouts
- β
Proper cleanup on component unmount
- β
Using lodash delay (consistent with project patterns)
- β
Prevents multiple timeouts if user saves multiple times quickly
Code Flow:
1. User saves profile β setSuccessMessage('...')
2. Store timeout ID: successTimeoutRef.current = delay(...)
3. If user saves again before 3s β clear old timeout, set new one
4. If user navigates away β cleanup effect clears timeout
5. No setState on unmounted component β
---------
Co-authored-by: Shehryar Raza <[email protected]>
feat: SCRUM-34 - add default pagination
|
@sageliteoff is attempting to deploy a commit to the dunsin's projects Team on Vercel. A member of the Team first needs to authorize it. |
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.
PR Compliance Checks
Thank you for your Pull Request! We have run several checks on this pull request in order to make sure it's suitable for merging into this project. The results are listed in the following section.
Fixes Issue
My PR closes #issue_number_here
π¨βπ» Changes proposed(What did you do ?)
βοΈ Check List (Check all the applicable boxes)
Note to reviewers
π· Screenshots