User & Buyer Profile Page

The BuyerProfilePage acts as a dual-purpose interface within the Socon-MKT platform. When a user views their own profile, it serves as a private dashboard for managing orders, reviewing followed stores, and configuring account settings. When viewed by other members of the community, it acts as a public social footprint, displaying the user's personal posts, reviews, and profile details.

The page is constrained to an 800px maximum width, providing a focused, centralized view of the user's activity.


Component Architecture

The profile relies on a dynamic tabbed navigation system that conditionally renders management tools based on the profile.is_own boolean returned by the backend.

1. BuyerProfileHeader

Renders the user's public identity and context-sensitive administrative controls.

  • Identity Details: Displays the user's avatar, @username, location (combining city and address), biography, and join date.
  • Share Functionality: Integrates the browser's native Web Share API with a clipboard copy fallback (navigator.clipboard.writeText) to share profile URLs.
  • Action Buttons:
  • If is_own is true, renders an "Edit Profile" button that opens the EditProfileModal overlay for updating personal details, locations, and profile photos.
  • If the user also holds a registered merchant account (profile.seller_profile), a "Business Profile" button routes directly to their storefront (/sellers/:id).

2. UserPostsTab

Displays an infinitely scrolling feed of the user's standard social posts (excluding marketplace listings).

  • Post Deletion Flow: If the logged-in user owns the profile (is_own), each post card reveals a delete button (FiTrash2).
  • 5-Second Undo Banner: Clicking delete triggers a soft-deletion state. The post is immediately hidden from view and a sticky top notification initiates a 5-second countdown timer. If the user clicks "Undo", the timer is cleared and the post is restored. If the countdown reaches zero (or the component unmounts), the deletePostApi mutation executes permanently.

3. OrdersTab (Private)

Visible strictly when profile.is_own is true.

  • Order History: Lists all items the user has negotiated and purchased across the platform, complete with current negotiation and delivery status pills (NEGOTIATING, AGREED, DELIVERING, COMPLETED).
  • Review Submission: Once an order reaches the COMPLETED state, a "Write Review" button triggers an interactive review modal allowing the buyer to rate the item (1 to 5 stars) and leave written feedback.

4. FollowingTab

Displays an infinitely scrolling list of all verified seller storefronts the user currently follows.

  • Soft-Unfollow with Undo: Clicking "Following" enters an optimistic unlinking state. Rather than immediately removing the store from the database, the card displays an inline "Undo" prompt. A 5-second timeout delays the actual toggleFollow API call, allowing users to reverse accidental clicks seamlessly.

5. MyReviewsTab

Fetches and displays all reviews written by the profile owner across different marketplace products, featuring star ratings and direct links back to the reviewed listings.


State Management & Optimistic UI

The profile page heavily leverages @tanstack/react-query to maintain high interface responsiveness across nested tabs.

  • Optimistic Post Deletion (useDeletePost): When a post deletion countdown completes, the mutation cancels active queries and snapshots both the global ["posts"] feed and user-specific ["user_posts"] query caches. It removes the post item from the local cache arrays immediately, only rolling back if the server returns an error.
  • Delayed Timeout Mutators: Both post deletions and unfollow actions employ a timeout-deferred mutation pattern. Local component state immediately alters the interface, while background timeouts (setTimeout) manage the eventual server execution, preventing unnecessary network traffic if the action is undone.
  • Infinite Scrolling: UserPostsTab, OrdersTab, FollowingTab, and MyReviewsTab each independently leverage react-intersection-observer sentinels to request the next page of results via cursor pagination (c).

API Endpoints & Data Structures

The profile system interacts with the following endpoints through the configured Axios authApi instance:

1. Fetch User Profile

Retrieves the target profile details, nested user record, and seller profile references.

  • Endpoint: Configured via useProfileFetch(profileId)
  • Authorization: Required (Bearer Token)
  • Response Structure (UserProfileResponse):
    {
      "user": {
        "id": "string",
        "username": "string",
        "email": "string"
      },
      "profile_id": "string",
      "profile_pic": "string_url | null",
      "created_at": "ISO 8601 string",
      "full_name": "string",
      "city": "string | null",
      "address": "string | null",
      "bio": "string | null",
      "website": "string_url | null",
      "is_own": true,
      "seller_profile": {
        "id": "string",
        "business_title": "string",
        "is_verified": true,
        "business_logo": "string_url | null"
      }
    }
    

2. Fetch User Social Posts (Infinite)

Retrieves the paginated list of social posts created by a specific user.

  • Endpoint: GET /posts/user_posts/
  • Query Parameters:
  • userId: The target profile's user ID.
  • is_product: false (limits results to non-marketplace content).
  • c: Cursor string for pagination.
  • Response Structure (PaginatedUserPostsResponse):
    {
      "next": "url_string | null",
      "previous": "url_string | null",
      "results": [
        {
          "id": "string",
          "caption": "string",
          "is_product": false,
          "is_own": true,
          "created_at": "ISO 8601 string",
          "media": [
            {
              "id": "string",
              "file": "string_url",
              "media_type": "photo | video",
              "thumbnail": "string_url | null"
            }
          ]
        }
      ]
    }
    

3. Delete Post

Permanently removes a user post from the platform.

  • Endpoint: DELETE /posts/post_delete/:postId/
  • Authorization: Required (Bearer Token)

4. Fetch Buyer Orders (Infinite - Private)

Retrieves the purchasing history for the authenticated user.

  • Endpoint: GET /posts/order/
  • Query Parameters: c (Cursor string for pagination)
  • Authorization: Required (Bearer Token)
  • Response Structure (PaginatedOrders):
    {
      "next": "url_string | null",
      "previous": "url_string | null",
      "results": [
        {
          "id": "string",
          "status": "NEGOTIATING | AGREED | DELIVERING | COMPLETED",
          "created_at": "ISO 8601 string",
          "product_obj": {
            "id": "string",
            "title": "string",
            "price": "string",
            "media": [
              {
                "file": "string_url",
                "thumbnail": "string_url | null"
              }
            ],
            "author": {
              "username": "string",
              "profile": {
                "seller_profile": {
                  "id": "string",
                  "business_title": "string"
                }
              }
            }
          }
        }
      ]
    }
    

5. Submit Product Review

Allows buyers to publish ratings and feedback for purchased products.

  • Endpoint: POST /posts/review/
  • Payload (SellerReviewRequest):
    {
      "product": "product_id_string",
      "text": "Review text content",
      "rating": 5
    }
    
  • Authorization: Required (Bearer Token)

6. Fetch Following Storefronts (Infinite)

Retrieves the merchants followed by the active user.

  • Endpoint: GET /users/sellers_following/
  • Query Parameters: c or pagination link string
  • Authorization: Required (Bearer Token)