thêm tab "Xem chi tiết chuyến đi", "Xem chi tiết thành viên chuyến đi", tái sử dụng lại components modal tripForm
This commit is contained in:
@@ -2,15 +2,14 @@ import { Tabs, useSegments } from "expo-router";
|
||||
|
||||
import { HapticTab } from "@/components/haptic-tab";
|
||||
import { IconSymbol } from "@/components/ui/icon-symbol";
|
||||
import { Colors } from "@/constants/theme";
|
||||
import { queryProfile } from "@/controller/AuthController";
|
||||
import { useI18n } from "@/hooks/use-i18n";
|
||||
import { useColorScheme } from "@/hooks/use-theme-context";
|
||||
import { useThemeContext } from "@/hooks/use-theme-context";
|
||||
import { addUserStorage } from "@/utils/storage";
|
||||
import { useEffect, useRef } from "react";
|
||||
|
||||
export default function TabLayout() {
|
||||
const colorScheme = useColorScheme();
|
||||
const { colors, colorScheme } = useThemeContext();
|
||||
const segments = useSegments() as string[];
|
||||
const prev = useRef<string | null>(null);
|
||||
const currentSegment = segments[1] ?? segments[segments.length - 1] ?? null;
|
||||
@@ -51,9 +50,18 @@ export default function TabLayout() {
|
||||
return (
|
||||
<Tabs
|
||||
screenOptions={{
|
||||
tabBarActiveTintColor: Colors[colorScheme ?? "light"].tint,
|
||||
tabBarActiveTintColor: colors.tint,
|
||||
headerShown: false,
|
||||
tabBarButton: HapticTab,
|
||||
// Set tab bar styles based on theme - prevents white flash
|
||||
tabBarStyle: {
|
||||
backgroundColor: colors.background,
|
||||
borderTopColor: colors.separator,
|
||||
},
|
||||
// Set screen content background
|
||||
sceneStyle: {
|
||||
backgroundColor: colors.background,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Tabs.Screen
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
} from "react-native";
|
||||
import { SafeAreaView } from "react-native-safe-area-context";
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
import { useRouter } from "expo-router";
|
||||
import FilterButton from "@/components/diary/FilterButton";
|
||||
import TripCard from "@/components/diary/TripCard";
|
||||
import FilterModal, { FilterValues } from "@/components/diary/FilterModal";
|
||||
@@ -23,10 +24,10 @@ import { useThemeContext } from "@/hooks/use-theme-context";
|
||||
export default function diary() {
|
||||
const { t } = useI18n();
|
||||
const { colors } = useThemeContext();
|
||||
const router = useRouter();
|
||||
const [showFilterModal, setShowFilterModal] = useState(false);
|
||||
const [showAddTripModal, setShowAddTripModal] = useState(false);
|
||||
const [editingTrip, setEditingTrip] = useState<Model.Trip | null>(null);
|
||||
const [viewingTrip, setViewingTrip] = useState<Model.Trip | null>(null);
|
||||
const [filters, setFilters] = useState<FilterValues>({
|
||||
status: null,
|
||||
startDate: null,
|
||||
@@ -40,6 +41,10 @@ export default function diary() {
|
||||
const [hasMore, setHasMore] = useState(true);
|
||||
const isInitialLoad = useRef(true);
|
||||
const flatListRef = useRef<FlatList>(null);
|
||||
|
||||
// Refs to prevent duplicate API calls from React Compiler/Strict Mode
|
||||
const hasInitializedThings = useRef(false);
|
||||
const hasInitializedTrips = useRef(false);
|
||||
|
||||
// Body call API things (đang fix cứng)
|
||||
const payloadThings: Model.SearchThingBody = {
|
||||
@@ -55,6 +60,8 @@ export default function diary() {
|
||||
// Gọi API things
|
||||
const { getThings } = useThings();
|
||||
useEffect(() => {
|
||||
if (hasInitializedThings.current) return;
|
||||
hasInitializedThings.current = true;
|
||||
getThings(payloadThings);
|
||||
}, []);
|
||||
|
||||
@@ -79,10 +86,10 @@ export default function diary() {
|
||||
|
||||
const { tripsList, getTripsList, loading } = useTripsList();
|
||||
|
||||
// console.log("Payload trips:", payloadTrips);
|
||||
|
||||
// Gọi API trips lần đầu
|
||||
useEffect(() => {
|
||||
if (hasInitializedTrips.current) return;
|
||||
hasInitializedTrips.current = true;
|
||||
isInitialLoad.current = true;
|
||||
setAllTrips([]);
|
||||
setHasMore(true);
|
||||
@@ -157,7 +164,11 @@ export default function diary() {
|
||||
|
||||
// Hàm load more data khi scroll đến cuối
|
||||
const handleLoadMore = useCallback(() => {
|
||||
if (isLoadingMore || !hasMore) {
|
||||
// Không load more nếu:
|
||||
// - Đang loading (ban đầu hoặc loadMore)
|
||||
// - Không còn data để load
|
||||
// - Chưa có data nào (tránh FlatList tự trigger khi list rỗng)
|
||||
if (isLoadingMore || loading || !hasMore || allTrips.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -169,7 +180,7 @@ export default function diary() {
|
||||
};
|
||||
setPayloadTrips(updatedPayload);
|
||||
getTripsList(updatedPayload);
|
||||
}, [isLoadingMore, hasMore, payloadTrips]);
|
||||
}, [isLoadingMore, loading, hasMore, allTrips.length, payloadTrips]);
|
||||
|
||||
// const handleTripPress = (tripId: string) => {
|
||||
// // TODO: Navigate to trip detail
|
||||
@@ -177,11 +188,16 @@ export default function diary() {
|
||||
// };
|
||||
|
||||
const handleViewTrip = (tripId: string) => {
|
||||
// Find the trip from allTrips and open modal in view mode
|
||||
// Navigate to trip detail page instead of opening modal
|
||||
const tripToView = allTrips.find((trip) => trip.id === tripId);
|
||||
if (tripToView) {
|
||||
setViewingTrip(tripToView);
|
||||
setShowAddTripModal(true);
|
||||
router.push({
|
||||
pathname: "/trip-detail",
|
||||
params: {
|
||||
tripId: tripToView.id,
|
||||
tripData: JSON.stringify(tripToView)
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -195,8 +211,13 @@ export default function diary() {
|
||||
};
|
||||
|
||||
const handleViewTeam = (tripId: string) => {
|
||||
console.log("View team:", tripId);
|
||||
// TODO: Navigate to team management
|
||||
const trip = allTrips.find((t) => t.id === tripId);
|
||||
if (trip) {
|
||||
router.push({
|
||||
pathname: "/trip-crew",
|
||||
params: { tripId: trip.id, tripName: trip.name || "" },
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleSendTrip = (tripId: string) => {
|
||||
@@ -260,7 +281,13 @@ export default function diary() {
|
||||
onDelete={() => handleDeleteTrip(item.id)}
|
||||
/>
|
||||
),
|
||||
[handleViewTrip, handleEditTrip, handleViewTeam, handleSendTrip, handleDeleteTrip]
|
||||
[
|
||||
handleViewTrip,
|
||||
handleEditTrip,
|
||||
handleViewTeam,
|
||||
handleSendTrip,
|
||||
handleDeleteTrip,
|
||||
]
|
||||
);
|
||||
|
||||
// Key extractor cho FlatList
|
||||
@@ -301,10 +328,15 @@ export default function diary() {
|
||||
};
|
||||
|
||||
return (
|
||||
<SafeAreaView style={[styles.safeArea, themedStyles.safeArea]} edges={["top"]}>
|
||||
<SafeAreaView
|
||||
style={[styles.safeArea, themedStyles.safeArea]}
|
||||
edges={["top"]}
|
||||
>
|
||||
<View style={styles.container}>
|
||||
{/* Header */}
|
||||
<Text style={[styles.titleText, themedStyles.titleText]}>{t("diary.title")}</Text>
|
||||
<Text style={[styles.titleText, themedStyles.titleText]}>
|
||||
{t("diary.title")}
|
||||
</Text>
|
||||
|
||||
{/* Filter & Add Button Row */}
|
||||
<View style={styles.actionRow}>
|
||||
@@ -358,17 +390,16 @@ export default function diary() {
|
||||
onApply={handleApplyFilters}
|
||||
/>
|
||||
|
||||
{/* Add/Edit/View Trip Modal */}
|
||||
{/* Add/Edit Trip Modal */}
|
||||
<AddTripModal
|
||||
visible={showAddTripModal}
|
||||
onClose={() => {
|
||||
setShowAddTripModal(false);
|
||||
setEditingTrip(null);
|
||||
setViewingTrip(null);
|
||||
}}
|
||||
onSuccess={handleTripAddSuccess}
|
||||
mode={viewingTrip ? 'view' : editingTrip ? 'edit' : 'add'}
|
||||
tripData={viewingTrip || editingTrip || undefined}
|
||||
mode={editingTrip ? "edit" : "add"}
|
||||
tripData={editingTrip || undefined}
|
||||
/>
|
||||
</SafeAreaView>
|
||||
);
|
||||
@@ -394,17 +425,10 @@ const styles = StyleSheet.create({
|
||||
}),
|
||||
},
|
||||
actionRow: {
|
||||
flexDirection: "row",
|
||||
justifyContent: "flex-start",
|
||||
alignItems: "center",
|
||||
gap: 12,
|
||||
marginBottom: 12,
|
||||
},
|
||||
headerRow: {
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
marginTop: 20,
|
||||
gap: 12,
|
||||
marginBottom: 12,
|
||||
},
|
||||
countText: {
|
||||
@@ -421,7 +445,7 @@ const styles = StyleSheet.create({
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
paddingHorizontal: 16,
|
||||
paddingVertical: 8,
|
||||
height: 40,
|
||||
borderRadius: 8,
|
||||
gap: 6,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user