Files
hipmi-mobile/docs/PAGEWRAPPER-USAGE.md
bagasbanuna e3b5d3ddb1 feat: Implement PageWrapper and migrate all Job screens
Create PageWrapper component that routes to:
- iOS: NewWrapper (stable, tested)
- Android: NewWrapper_V2 (keyboard handling fix)

New Files:
- components/_ShareComponent/PageWrapper.tsx
- docs/PAGEWRAPPER-USAGE.md

Migrated Job Screens (10):
- screens/Job/ScreenJobCreate.tsx: NewWrapper_V2 → PageWrapper
- screens/Job/ScreenJobEdit.tsx: NewWrapper_V2 → PageWrapper
- screens/Job/ScreenArchive.tsx: ViewWrapper → PageWrapper
- screens/Job/ScreenArchive2.tsx: NewWrapper_V2 → PageWrapper
- screens/Job/ScreenBeranda2.tsx: NewWrapper_V2 → PageWrapper
- screens/Job/MainViewStatus2.tsx: NewWrapper_V2 → PageWrapper
- app/(application)/(user)/job/[id]/index.tsx: ViewWrapper → PageWrapper
- app/(application)/(user)/job/[id]/archive.tsx: ViewWrapper → PageWrapper
- app/(application)/(user)/job/[id]/[status]/detail.tsx: NewWrapper_V2 → PageWrapper

Benefits:
- iOS users (70%+) get stable NewWrapper
- Android users get keyboard handling fix
- Clean API - no Platform.OS checks in screens
- Easy future migration path

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-04-06 14:41:54 +08:00

7.2 KiB

PageWrapper - Platform-Specific Wrapper

📋 Overview

PageWrapper adalah wrapper component yang secara otomatis memilih wrapper yang tepat berdasarkan platform:

  • iOS: Menggunakan NewWrapper (stable, tested)
  • Android: Menggunakan NewWrapper_V2 (dengan keyboard handling fix)

🎯 Kapan Menggunakan PageWrapper?

Gunakan PageWrapper untuk:

  • Screen baru yang kamu buat
  • Migrasi screen existing dari NewWrapper/ViewWrapper
  • Form screens dengan TextInput/TextArea
  • List screens dengan pagination

Jangan gunakan PageWrapper untuk:

  • Screen yang sudah menggunakan NewWrapper_V2 langsung dan sudah tested di iOS
  • Custom wrapper requirements

📝 Usage

Basic Usage (Static Content)

import { PageWrapper } from "@/components";

export function MyScreen() {
  return (
    <PageWrapper
      footerComponent={<ButtonFooter />}
    >
      <StackCustom>
        <TextInputCustom label="Name" />
        <TextAreaCustom label="Description" />
      </StackCustom>
    </PageWrapper>
  );
}

With Keyboard Handling (Android Only)

<PageWrapper
  enableKeyboardHandling
  keyboardScrollOffset={100}
  contentPaddingHorizontal={16}
  footerComponent={<ButtonFooter />}
>
  <StackCustom>
    <View onStartShouldSetResponder={() => true}>
      <TextInputCustom label="Name" />
    </View>
    <View onStartShouldSetResponder={() => true}>
      <TextAreaCustom label="Description" />
    </View>
  </StackCustom>
</PageWrapper>

List Mode (Pagination)

<PageWrapper
  listData={pagination.listData}
  renderItem={renderItem}
  onEndReached={pagination.loadMore}
  ListEmptyComponent={ListEmptyComponent}
  ListFooterComponent={ListFooterComponent}
  refreshControl={
    <RefreshControl refreshing={refreshing} onRefresh={onRefresh} />
  }
/>

🔧 Props

Common Props (iOS & Android)

Prop Type Default Description
footerComponent ReactNode - Fixed footer component
headerComponent ReactNode - Header component (sticky)
floatingButton ReactNode - Floating button overlay
hideFooter boolean false Hide footer footer
withBackground boolean false Use background image
style ViewStyle - Custom container style
refreshControl RefreshControl - Pull-to-refresh control

Android-Only Props (Ignored di iOS)

Prop Type Default Description
enableKeyboardHandling boolean false Enable keyboard auto-scroll
keyboardScrollOffset number 100 Scroll offset when keyboard appears
contentPaddingBottom number 80 Bottom padding for content
contentPaddingTop number 8 Top padding for content
contentPaddingHorizontal number 0 Horizontal padding for content

📊 Platform Behavior

Feature iOS (NewWrapper) Android (NewWrapper_V2)
Keyboard Handling No auto-scroll Auto-scroll to input
Footer Position Fixed bottom Fixed bottom (absolute)
Safe Area Handled Handled
Content Padding Default Customizable
List Mode Supported Supported

🔄 Migration Guide

From NewWrapper

// BEFORE
import { NewWrapper } from "@/components";

<NewWrapper footerComponent={footer}>
  {children}
</NewWrapper>

// AFTER
import { PageWrapper } from "@/components";

<PageWrapper footerComponent={footer}>
  {children}
</PageWrapper>

From NewWrapper_V2

// BEFORE
import { NewWrapper_V2 } from "@/components";

<NewWrapper_V2
  enableKeyboardHandling
  keyboardScrollOffset={100}
  footerComponent={footer}
>
  <View onStartShouldSetResponder={() => true}>
    <TextInputCustom />
  </View>
</NewWrapper_V2>

// AFTER
import { PageWrapper } from "@/components";

<PageWrapper
  enableKeyboardHandling
  keyboardScrollOffset={100}
  footerComponent={footer}
>
  <View onStartShouldSetResponder={() => true}>
    <TextInputCustom />
  </View>
</PageWrapper>

⚠️ Important Notes

For Form Screens (Android)

Jika menggunakan enableKeyboardHandling, WAJIB wrap semua input dengan View onStartShouldSetResponder:

<View onStartShouldSetResponder={() => true}>
  <TextInputCustom label="Name" />
</View>

Kenapa?

  • Mencegah keyboard handling conflict
  • Memastikan tap outside dismiss keyboard
  • Konsisten behavior di Android

For iOS Users

Props berikut diabaikan di iOS:

  • enableKeyboardHandling
  • keyboardScrollOffset
  • contentPaddingBottom
  • contentPaddingTop
  • contentPaddingHorizontal

iOS menggunakan NewWrapper yang sudah stable tanpa keyboard handling.


🎨 Examples

Example 1: Simple Form

import { PageWrapper, TextInputCustom, StackCustom } from "@/components";

export function SimpleForm() {
  return (
    <PageWrapper
      enableKeyboardHandling
      keyboardScrollOffset={100}
      footerComponent={<SubmitButton />}
    >
      <StackCustom>
        <View onStartShouldSetResponder={() => true}>
          <TextInputCustom label="Name" />
        </View>
        <View onStartShouldSetResponder={() => true}>
          <TextInputCustom label="Email" />
        </View>
      </StackCustom>
    </PageWrapper>
  );
}

Example 2: List with Pagination

import { PageWrapper } from "@/components";

export function UserList() {
  const pagination = usePagination({ fetchFunction: fetchUsers });

  return (
    <PageWrapper
      listData={pagination.listData}
      renderItem={({ item }) => <UserCard item={item} />}
      onEndReached={pagination.loadMore}
      ListEmptyComponent={<EmptyState />}
      ListFooterComponent={<LoadingFooter />}
      refreshControl={
        <RefreshControl
          refreshing={pagination.refreshing}
          onRefresh={pagination.refresh}
        />
      }
    />
  );
}
import { PageWrapper } from "@/components";

export function DetailScreen() {
  return (
    <PageWrapper hideFooter>
      <StackCustom>
        <TextCustom>Title</TextCustom>
        <TextCustom>Description</TextCustom>
      </StackCustom>
    </PageWrapper>
  );
}

🚀 Future Plans

Phase 1: Current (Now)

  • PageWrapper created
  • iOS → NewWrapper (stable)
  • Android → NewWrapper_V2 (keyboard fix)

Phase 2: iOS Migration (1-2 months)

  • Fix iOS bugs di NewWrapper_V2
  • Test NewWrapper_V2 di iOS devices
  • Update PageWrapper untuk use V2 untuk iOS juga

Phase 3: Unify (3 months)

  • Deprecate NewWrapper lama
  • Rename NewWrapper_V2NewWrapper
  • Update PageWrapper untuk always use V2

  • components/_ShareComponent/PageWrapper.tsx - Main component
  • components/_ShareComponent/NewWrapper.tsx - iOS wrapper
  • components/_ShareComponent/NewWrapper_V2.tsx - Android wrapper
  • hooks/useKeyboardForm.ts - Keyboard handling hook

Last Updated: 2026-04-06
Created by: AI Assistant
Status: Ready to use