DEV Community

Lin
Lin

Posted on

Imitation Box Horse - Product Details Page (10)

Technical Stack
Appgallery Connect

Development Preparation
In the previous section, we implemented a custom title bar and data reception for the product details page. This section focuses on enriching the product details page with comprehensive information, including product attributes, images, specifications, promotion details, and fixed bottom actions (Add to Cart and Buy Now) with real-time cart updates.

Functional Analysis
Layout Requirements:
Scrollable content area for extensive product information.
Fixed bottom section with Add to Cart and Buy Now buttons.
Real-time cart item count update upon adding products.
Quick navigation to the cart page.

Interactive Features:
Specification selection (size, color, quantity).
Promotion display (discounts, purchase limits).
Smooth scrolling and responsive UI.

Code Implementation

  1. Enhanced Product Details Page (ProductDetailsPage.ets) typescript import { CommonTopBar } from '../widget/CommonTopBar'; import router from '@ohos.router'; import { HomeProductList } from '../entity/home_product_list'; import promptAction from '@ohos.promptAction';

@Entry
@Component
struct ProductDetailsPage {
@State productParams: HomeProductList = {} as HomeProductList;
@State selectedSpec: string = 'Default';
@State cartCount: number = 0;
private scroller: Scroller = new Scroller();

aboutToAppear(): void {
const params = router.getParams() as HomeProductList;
if (params) {
this.productParams = params;
// Simulate cart count from local storage or global state
this.cartCount = 2; // Replace with actual cart data retrieval
}
}

// Add product to cart
addToCart() {
if (!this.selectedSpec || this.selectedSpec === 'Default') {
promptAction.showToast({
message: 'Please select a specification',
duration: 2000
});
return;
}

// Update cart count (simulation)
this.cartCount += 1;
promptAction.showToast({
  message: 'Added to cart',
  duration: 2000
});

// Save to local storage or update global cart state
// e.g., storage.set('cartCount', this.cartCount);
Enter fullscreen mode Exit fullscreen mode

}

// Navigate to cart page
goToCart() {
router.pushUrl({
url: 'pages/CartPage'
});
}

build() {
Stack({ alignContent: Alignment.Bottom }) {
Scroll(this.scroller) {
Column() {
CommonTopBar({
title: this.productParams.name || "Product Details",
alpha: 0,
titleAlignment: TextAlign.Center,
backButton: true
});

      // Product image gallery
      Image(this.productParams.url || 'https://via.placeholder.com/750x400')
        .width('100%')
        .height(300)
        .objectFit(ImageFit.Cover);

      Column({ space: 10 }) {
        // Price section
        Row() {
          if (this.productParams.promotion_spread_price > 0) {
            Text() {
              Span("¥")
                .fontSize(14)
                .fontColor(Color.Red);
              Span((this.productParams.price - this.productParams.promotion_spread_price).toString())
                .fontSize(20)
                .fontColor(Color.Red);
            }
          } else {
            Text() {
              Span("¥")
                .fontSize(14)
                .fontColor(Color.Red);
              Span(this.productParams.price.toString())
                .fontSize(20)
                .fontColor(Color.Red);
            }
          }

          Text("¥" + this.productParams.original_price)
            .fontColor('#999')
            .decoration({
              type: TextDecorationType.LineThrough,
              color: Color.Gray
            })
            .fontSize(16)
            .margin({ left: 10 });

          if (this.productParams.promotion_spread_price > 0) {
            Row() {
              Text("Save ¥" + this.productParams.promotion_spread_price)
                .fontSize(14)
                .backgroundColor("#FB424C")
                .borderRadius(20)
                .padding(3)
                .textAlign(TextAlign.Center);
              Text("Limit " + this.productParams.max_loop_amount + " per person")
                .margin({ left: 5 })
                .fontSize(14)
                .backgroundColor("#FB424C")
                .borderRadius(20)
                .padding(3)
                .textAlign(TextAlign.Center);
            }
            .padding({ top: 2, bottom: 2, left: 10 });
          }
        }
        .padding(10);

        if (this.productParams.promotion_spread_price > 0) {
          Text(this.productParams.endTime)
            .fontSize(14)
            .backgroundColor("#FB424C")
            .borderRadius(20)
            .padding(3)
            .margin({ left: 10 })
            .textAlign(TextAlign.Center);
        }

        // Product name and details
        Text(this.productParams.name || 'Product Name')
          .fontSize(20)
          .fontColor(Color.Black)
          .margin({ left: 10 })
          .fontWeight(FontWeight.Bold);
        Text(this.productParams.text_message || 'Product description')
          .fontSize(14)
          .fontColor(Color.Black)
          .margin({ left: 10 });
        Row() {
          Text("Sales: " + this.productParams.sales_volume)
            .fontSize(14)
            .fontColor(Color.Black);
        }
        .padding(10)
        .width('100%')
        .justifyContent(FlexAlign.Start);

        // Delivery information
        Divider().width('100%').height(5).backgroundColor("#f7f7f7");
        Row() {
          Text("Delivery")
            .fontColor(Color.Gray)
            .fontSize(14);
          Text(this.productParams.delivery_time || 'Shipped within 24h')
            .margin({ left: 20 })
            .fontSize(14)
            .fontColor(Color.Black);
        }
        .padding(10)
        .width('100%')
        .justifyContent(FlexAlign.Start);

        // Product parameters
        Divider().width('100%').height(5).backgroundColor("#f7f7f7");
        Row() {
          Text("Parameters")
            .fontColor(Color.Gray)
            .fontSize(14);
          Text("Storage: ")
            .margin({ left: 20 })
            .fontSize(14)
            .fontColor(Color.Black);
          Text(this.productParams.parameter || 'Refrigerated')
            .fontSize(14)
            .fontColor(Color.Black);
        }
        .padding(10)
        .width('100%')
        .justifyContent(FlexAlign.Start);

        // Specification selection
        Divider().width('100%').height(5).backgroundColor("#f7f7f7");
        Row() {
          Text("Specifications")
            .fontColor(Color.Gray)
            .fontSize(14);
          Text(this.selectedSpec || 'Please select a specification')
            .margin({ left: 20 })
            .fontSize(14)
            .fontColor(Color.Black);
        }
        .padding(10)
        .width('100%')
        .justifyContent(FlexAlign.Start);

        // Sample specification options (replace with dynamic data)
        Divider().width('100%').height(5).backgroundColor("#f7f7f7");
        Text("Available Specifications")
          .fontSize(16)
          .fontWeight(FontWeight.Bold)
          .margin({ left: 10, top: 5, bottom: 5 });
        Row() {
          // Sample specifications (e.g., size, color)
          ForEach(['500g', '1kg', '2kg'], (spec: string) => {
            Text(spec)
              .padding(8)
              .backgroundColor(this.selectedSpec === spec ? '#FB424C' : '#F0F0F0')
              .fontColor(this.selectedSpec === spec ? Color.White : Color.Black)
              .borderRadius(8)
              .onClick(() => this.selectedSpec = spec);
          })
        }
        .padding(10)
        .width('100%')
        .justifyContent(FlexAlign.Start)
        .spacing(10);
      }
      .alignItems(HorizontalAlign.Start)
      .width('100%');
    }
    .alignItems(HorizontalAlign.Start)
    .backgroundColor(Color.White);
  }
  .padding({ bottom: 80 })
  .height('100%')
  .width('100%');

  // Fixed bottom action bar
  Row() {
    Stack() {
      Image($r('app.media.shopping_cart'))
        .width(35)
        .height(35)
        .objectFit(ImageFit.Contain);
      if (this.cartCount > 0) {
        Text(this.cartCount.toString())
          .fontSize(10)
          .backgroundColor(Color.Red)
          .borderRadius(10)
          .padding(4)
          .position({ x: 20, y: -10 });
      }
    }
    .onClick(() => this.goToCart())
    .width(50)
    .height(50);

    Blank();

    Text("Add to Cart")
      .padding(10)
      .width(100)
      .textAlign(TextAlign.Center)
      .backgroundColor("#FCDB29")
      .fontColor(Color.White)
      .borderRadius({ topLeft: 15, bottomLeft: 15 })
      .onClick(() => this.addToCart());

    Text("Buy Now")
      .padding(10)
      .textAlign(TextAlign.Center)
      .width(100)
      .backgroundColor(Color.Red)
      .fontColor(Color.White)
      .borderRadius({ topRight: 15, bottomRight: 15 })
      .onClick(() => {
        if (this.selectedSpec === 'Default') {
          promptAction.showToast({
            message: 'Please select a specification',
            duration: 2000
          });
          return;
        }
        // Navigate to checkout
        router.pushUrl({
          url: 'pages/CheckoutPage',
          params: { ...this.productParams, spec: this.selectedSpec }
        });
      });
  }
  .padding(15)
  .justifyContent(FlexAlign.SpaceBetween)
  .width('100%')
  .backgroundColor(Color.White)
  .shadow({ radius: 2, color: '#EEEEEE', offsetX: 0, offsetY: -1 });
}
.backgroundColor(Color.White);
Enter fullscreen mode Exit fullscreen mode

}
}

This implementation provides a comprehensive product details page with essential e-commerce features, ready for further integration with backend services and user authentication.

Top comments (0)