Files
sgw-owner-app/Task.md
2025-12-03 16:22:25 +07:00

88 lines
5.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Prompt: Tạo bottom sheet kéo/thả trên Map ở `app/(tabs)/index.tsx`
## Mục tiêu
- Thêm một component dạng bottom sheet nổi trên `MapView`, có thể nhấn (click) để mở nhanh và kéo (swipe) để thay đổi chiều cao mượt mà.
## Ngữ cảnh
- Dự án Expo React Native (TypeScript) với màn hình map tại: `app/(tabs)/index.tsx`.
- Cần chèn một panel nổi (overlay) bám đáy màn hình, hiển thị trên MapView.
## Yêu cầu chức năng
- Chiều cao ban đầu: 10% chiều cao màn hình.
- Chiều cao tối đa: 50% chiều cao màn hình.
- Có một nút ở góc trên bên phải của panel để “mở/thu” (move up/down).
- Khi người dùng click vào panel hoặc click nút: panel mở ngay lập tức lên 50%.
- Khi người dùng vuốt (kéo) panel lên/xuống: chiều cao thay đổi dần, bị chặn trong khoảng [10%, 50%].
- Hiệu ứng chuyển đổi chiều cao phải mượt mà, không gây khó chịu (ease-in-out, 180300ms).
- Panel chỉ nhận touch trong vùng của nó, không chặn thao tác trên map ở các vùng khác.
## Yêu cầu UI/UX
- Panel bám đáy màn hình, bo tròn góc trên (ví dụ: borderTopLeftRadius/borderTopRightRadius = 1620).
- Có bóng đổ nhẹ để nổi trên map.
- Có “khu vực kéo” (drag handle) ở header panel (có thể là dải ngang mảnh) + nút toggle ở góc trên bên phải.
- Nội dung bên trong panel có thể là placeholder đơn giản (ví dụ một vài dòng text) để kiểm chứng hành vi.
## Ràng buộc kỹ thuật
- Ưu tiên dùng `react-native-gesture-handler` + `react-native-reanimated` để có tương tác kéo mượt (UI thread). Nếu không khả dụng, fallback sang `Animated` + `PanResponder` vẫn được.
- Không thêm UI library bên thứ ba cho bottom sheet (ví dụ `@gorhom/bottom-sheet`) — tự triển khai component nhẹ.
- TypeScript, functional components, tuân thủ style hiện có (không thay đổi kiến trúc không cần thiết).
## Hướng triển khai (gợi ý)
1. Tạo component `components/DraggablePanel.tsx` với các props:
- `minHeightPct?: number` (mặc định 0.1)
- `maxHeightPct?: number` (mặc định 0.5)
- `initialState?: 'min' | 'max'` (mặc định 'min')
- `onExpandedChange?: (expanded: boolean) => void`
2. Trong `DraggablePanel`, tính chiều cao theo phần trăm màn hình bằng `useWindowDimensions` hoặc `Dimensions.get('window').height`.
3. Nếu dùng Reanimated: dùng `useSharedValue` cho height hoặc translateY, `withTiming` khi click, và `withSpring`/`withTiming` khi kéo. Clamp giá trị vào [min, max].
4. Nếu dùng Animated: dùng `Animated.Value` + `Animated.timing``PanResponder` để cập nhật height theo cử chỉ, clamp trong [min, max].
5. Thêm header có drag handle và nút toggle ở góc trên phải:
- Click header hoặc click nút: toggle giữa min (10%) và max (50%).
- Vuốt: cập nhật theo delta cử chỉ; khi thả tay nếu vượt ngưỡng giữa thì snap về 50%, ngược lại về 10%.
6. Đặt panel overlay lên Map ở `app/(tabs)/index.tsx` bằng `position: 'absolute'`, `left: 0`, `right: 0`, `bottom: 0`, `height` do animation điều khiển. Đảm bảo `pointerEvents` phù hợp để không chặn thao tác trên map bên ngoài panel.
## Tiêu chí chấp nhận (Acceptance Criteria)
- Panel xuất hiện trên Map, bám đáy, bo góc trên, có bóng đổ nhẹ.
- Chiều cao ban đầu là ~10% màn hình; click mở hoặc click nút toggle lập tức chuyển lên ~50% (animation ~200ms, mượt).
- Vuốt kéo panel thay đổi chiều cao theo ngón tay, bị chặn trong khoảng [10%, 50%]. Thả tay, panel snap về 10% hoặc 50% theo vị trí/độ nhanh.
- Nút ở góc trên phải hoạt động đúng: chuyển qua lại giữa 10% và 50%.
- Tương tác map vẫn bình thường ở vùng ngoài panel; trong panel, vuốt không làm map pan.
- Không crash, không warning/ lỗi TypeScript mới do thay đổi này.
## Bàn giao
- File mới: `components/DraggablePanel.tsx`.
- Sửa file: `app/(tabs)/index.tsx` để chèn panel overlay.
- Không thay đổi các phần không liên quan.
- Nếu cần cài đặt `react-native-reanimated`/`react-native-gesture-handler`, cung cấp hướng dẫn và chỉnh cấu hình cần thiết cho Expo (nhưng chỉ thực hiện nếu bắt buộc).
## Gợi ý kiểm thử thủ công
- iOS và Android (nếu có):
- Mở app, xác nhận panel đang ở 10%.
- Click vào panel hoặc nút: panel mở lên 50% với animation mượt.
- Kéo lên/xuống nhiều lần: độ cao thay đổi mượt, không vượt quá 50% hoặc thấp hơn 10%.
- Pan/zoom Map ở vùng ngoài panel: vẫn hoạt động bình thường.
- Xoay màn hình (nếu hỗ trợ): panel tính lại theo chiều cao mới.
## Lưu ý
- Giữ code gọn, tách logic cử chỉ/animation khỏi phần trình bày nếu hợp lý.
- Đặt tên biến/props rõ ràng, không dùng one-letter variable.
- Không thêm license header hoặc thay đổi cấu trúc dự án nếu không cần thiết.
- Mục tiêu: Tạo một component có thể di chuyển lên xuống
- Bài toán: Ở giao diện index.tsx, đã có component MapView
- Giờ mình muốn thêm một component nổi lên trên map, ban đầu sẽ có chiều cao 10% chiều cao màn hình, giống như modal của Expo
- Trên giao diện cho một nút di chuyển lên/ xuống ở góc trên bên phải
- Khi người dùng click vào hoặc vuốt component lên thì chiều cao của thẻ cũng thay đổi, max là 50% chiều cao màn hình
- Khi click thì chiều cao sẽ đổi thành 50% luôn, còn vuốt thì chiều cao sẽ tăng dần
- Hiệu ứng thay đổi chiều cao mượt mà, không gây khó chịu cho người dùng