Fix layout tabs pada komponen
Fix home tabs ### No Issue
This commit is contained in:
@@ -2,35 +2,64 @@ import { IconHome } from "@/components/_Icon";
|
|||||||
import { TabsStyles } from "@/styles/tabs-styles";
|
import { TabsStyles } from "@/styles/tabs-styles";
|
||||||
import { Ionicons } from "@expo/vector-icons";
|
import { Ionicons } from "@expo/vector-icons";
|
||||||
import { Tabs } from "expo-router";
|
import { Tabs } from "expo-router";
|
||||||
|
import { View } from "react-native";
|
||||||
|
import { MainColor } from "@/constants/color-palet";
|
||||||
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||||
|
import { Platform } from "react-native";
|
||||||
|
|
||||||
|
function CollaborationTabsWrapper() {
|
||||||
|
const insets = useSafeAreaInsets();
|
||||||
|
const paddingBottom = Platform.OS === "android" ? insets.bottom : 0;
|
||||||
|
|
||||||
export default function CollaborationTabsLayout() {
|
|
||||||
return (
|
return (
|
||||||
<Tabs screenOptions={TabsStyles}>
|
<View style={{ flex: 1, backgroundColor: MainColor.darkblue }}>
|
||||||
<Tabs.Screen
|
<Tabs
|
||||||
name="index"
|
screenOptions={{
|
||||||
options={{
|
...TabsStyles,
|
||||||
title: "Beranda",
|
tabBarStyle: Platform.select({
|
||||||
tabBarIcon: ({ color }) => <IconHome color={color} />,
|
ios: {
|
||||||
|
borderTopWidth: 0,
|
||||||
|
paddingTop: 12,
|
||||||
|
height: 80,
|
||||||
|
},
|
||||||
|
android: {
|
||||||
|
borderTopWidth: 0,
|
||||||
|
paddingTop: 5,
|
||||||
|
height: 70 + paddingBottom,
|
||||||
|
},
|
||||||
|
}),
|
||||||
}}
|
}}
|
||||||
/>
|
>
|
||||||
<Tabs.Screen
|
<Tabs.Screen
|
||||||
name="participant"
|
name="index"
|
||||||
options={{
|
options={{
|
||||||
title: "Partisipan",
|
title: "Beranda",
|
||||||
tabBarIcon: ({ color }) => (
|
tabBarIcon: ({ color }) => <IconHome color={color} />,
|
||||||
<Ionicons size={20} name="people" color={color} />
|
}}
|
||||||
),
|
/>
|
||||||
}}
|
<Tabs.Screen
|
||||||
/>
|
name="participant"
|
||||||
<Tabs.Screen
|
options={{
|
||||||
name="group"
|
title: "Partisipan",
|
||||||
options={{
|
tabBarIcon: ({ color }) => (
|
||||||
title: "Grup",
|
<Ionicons size={20} name="people" color={color} />
|
||||||
tabBarIcon: ({ color }) => (
|
),
|
||||||
<Ionicons size={20} name="chatbox-ellipses" color={color} />
|
}}
|
||||||
),
|
/>
|
||||||
}}
|
<Tabs.Screen
|
||||||
/>
|
name="group"
|
||||||
</Tabs>
|
options={{
|
||||||
|
title: "Grup",
|
||||||
|
tabBarIcon: ({ color }) => (
|
||||||
|
<Ionicons size={20} name="chatbox-ellipses" color={color} />
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Tabs>
|
||||||
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default function CollaborationTabsLayout() {
|
||||||
|
return <CollaborationTabsWrapper />;
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,33 +5,62 @@ import {
|
|||||||
FontAwesome5
|
FontAwesome5
|
||||||
} from "@expo/vector-icons";
|
} from "@expo/vector-icons";
|
||||||
import { Tabs } from "expo-router";
|
import { Tabs } from "expo-router";
|
||||||
|
import { View } from "react-native";
|
||||||
|
import { MainColor } from "@/constants/color-palet";
|
||||||
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||||
|
import { Platform } from "react-native";
|
||||||
|
|
||||||
|
function DonationTabsWrapper() {
|
||||||
|
const insets = useSafeAreaInsets();
|
||||||
|
const paddingBottom = Platform.OS === "android" ? insets.bottom : 0;
|
||||||
|
|
||||||
export default function InvestmentTabsLayout() {
|
|
||||||
return (
|
return (
|
||||||
<Tabs screenOptions={TabsStyles}>
|
<View style={{ flex: 1, backgroundColor: MainColor.darkblue }}>
|
||||||
<Tabs.Screen
|
<Tabs
|
||||||
name="index"
|
screenOptions={{
|
||||||
options={{
|
...TabsStyles,
|
||||||
title: "Beranda",
|
tabBarStyle: Platform.select({
|
||||||
tabBarIcon: ({ color }) => <IconHome color={color} />,
|
ios: {
|
||||||
|
borderTopWidth: 0,
|
||||||
|
paddingTop: 12,
|
||||||
|
height: 80,
|
||||||
|
},
|
||||||
|
android: {
|
||||||
|
borderTopWidth: 0,
|
||||||
|
paddingTop: 5,
|
||||||
|
height: 70 + paddingBottom,
|
||||||
|
},
|
||||||
|
}),
|
||||||
}}
|
}}
|
||||||
/>
|
>
|
||||||
<Tabs.Screen
|
<Tabs.Screen
|
||||||
name="status"
|
name="index"
|
||||||
options={{
|
options={{
|
||||||
title: "Galang Dana",
|
title: "Beranda",
|
||||||
tabBarIcon: ({ color }) => <IconStatus color={color} />,
|
tabBarIcon: ({ color }) => <IconHome color={color} />,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Tabs.Screen
|
<Tabs.Screen
|
||||||
name="my-donation"
|
name="status"
|
||||||
options={{
|
options={{
|
||||||
title: "Donasi Saya",
|
title: "Galang Dana",
|
||||||
tabBarIcon: ({ color }) => (
|
tabBarIcon: ({ color }) => <IconStatus color={color} />,
|
||||||
<FontAwesome5 name="donate" color={color} size={ICON_SIZE_SMALL} />
|
}}
|
||||||
),
|
/>
|
||||||
}}
|
<Tabs.Screen
|
||||||
/>
|
name="my-donation"
|
||||||
</Tabs>
|
options={{
|
||||||
|
title: "Donasi Saya",
|
||||||
|
tabBarIcon: ({ color }) => (
|
||||||
|
<FontAwesome5 name="donate" color={color} size={ICON_SIZE_SMALL} />
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Tabs>
|
||||||
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default function DonationTabsLayout() {
|
||||||
|
return <DonationTabsWrapper />;
|
||||||
|
}
|
||||||
|
|||||||
@@ -185,7 +185,6 @@ export default function DonationEdit() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<NewWrapper
|
<NewWrapper
|
||||||
hideFooter
|
|
||||||
footerComponent={
|
footerComponent={
|
||||||
<BoxButtonOnFooter>
|
<BoxButtonOnFooter>
|
||||||
<ButtonCustom
|
<ButtonCustom
|
||||||
|
|||||||
@@ -114,7 +114,6 @@ export default function DonationCreateStory() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<NewWrapper
|
<NewWrapper
|
||||||
hideFooter
|
|
||||||
footerComponent={
|
footerComponent={
|
||||||
<>
|
<>
|
||||||
<BoxButtonOnFooter>
|
<BoxButtonOnFooter>
|
||||||
|
|||||||
@@ -127,7 +127,6 @@ export default function DonationCreate() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<NewWrapper
|
<NewWrapper
|
||||||
hideFooter
|
|
||||||
footerComponent={
|
footerComponent={
|
||||||
<>
|
<>
|
||||||
<BoxButtonOnFooter>
|
<BoxButtonOnFooter>
|
||||||
|
|||||||
@@ -8,58 +8,83 @@ import AppHeader from "@/components/_ShareComponent/AppHeader";
|
|||||||
import BackButtonFromNotification from "@/components/Button/BackButtonFromNotification";
|
import BackButtonFromNotification from "@/components/Button/BackButtonFromNotification";
|
||||||
import { TabsStyles } from "@/styles/tabs-styles";
|
import { TabsStyles } from "@/styles/tabs-styles";
|
||||||
import { router, Tabs, useLocalSearchParams } from "expo-router";
|
import { router, Tabs, useLocalSearchParams } from "expo-router";
|
||||||
|
import { View } from "react-native";
|
||||||
|
import { MainColor } from "@/constants/color-palet";
|
||||||
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||||
|
import { Platform } from "react-native";
|
||||||
|
import { OS_ANDROID_HEIGHT, OS_IOS_HEIGHT } from "@/constants/constans-value";
|
||||||
|
|
||||||
export default function EventTabsLayout() {
|
function EventTabsWrapper() {
|
||||||
|
const insets = useSafeAreaInsets();
|
||||||
|
const paddingBottom = Platform.OS === "android" ? insets.bottom : 0;
|
||||||
const { from, category } = useLocalSearchParams<{
|
const { from, category } = useLocalSearchParams<{
|
||||||
from?: string;
|
from?: string;
|
||||||
category?: string;
|
category?: string;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tabs
|
<View style={{ flex: 1, backgroundColor: MainColor.darkblue }}>
|
||||||
screenOptions={{
|
<Tabs
|
||||||
...TabsStyles,
|
screenOptions={{
|
||||||
header: () => (
|
...TabsStyles,
|
||||||
<AppHeader
|
tabBarStyle: Platform.select({
|
||||||
title="Event"
|
ios: {
|
||||||
left={
|
borderTopWidth: 0,
|
||||||
<BackButtonFromNotification
|
paddingTop: 12,
|
||||||
from={from as string}
|
height: OS_IOS_HEIGHT,
|
||||||
category={category as string}
|
},
|
||||||
/>
|
android: {
|
||||||
}
|
borderTopWidth: 0,
|
||||||
/>
|
paddingTop: 5,
|
||||||
),
|
height: OS_ANDROID_HEIGHT + paddingBottom,
|
||||||
}}
|
},
|
||||||
>
|
}),
|
||||||
<Tabs.Screen
|
header: () => (
|
||||||
name="index"
|
<AppHeader
|
||||||
options={{
|
title="Event"
|
||||||
title: "Beranda",
|
left={
|
||||||
tabBarIcon: ({ color }) => <IconHome color={color} />,
|
<BackButtonFromNotification
|
||||||
|
from={from || ""}
|
||||||
|
category={category}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
),
|
||||||
}}
|
}}
|
||||||
/>
|
>
|
||||||
<Tabs.Screen
|
<Tabs.Screen
|
||||||
name="status"
|
name="index"
|
||||||
options={{
|
options={{
|
||||||
title: "Status",
|
title: "Beranda",
|
||||||
tabBarIcon: ({ color }) => <IconStatus color={color} />,
|
tabBarIcon: ({ color }) => <IconHome color={color} />,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Tabs.Screen
|
<Tabs.Screen
|
||||||
name="contribution"
|
name="status"
|
||||||
options={{
|
options={{
|
||||||
title: "Kontribusi",
|
title: "Status",
|
||||||
tabBarIcon: ({ color }) => <IconContribution color={color} />,
|
tabBarIcon: ({ color }) => <IconStatus color={color} />,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Tabs.Screen
|
<Tabs.Screen
|
||||||
name="history"
|
name="contribution"
|
||||||
options={{
|
options={{
|
||||||
title: "Riwayat",
|
title: "Kontribusi",
|
||||||
tabBarIcon: ({ color }) => <IconHistory color={color} />,
|
tabBarIcon: ({ color }) => <IconContribution color={color} />,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Tabs>
|
<Tabs.Screen
|
||||||
|
name="history"
|
||||||
|
options={{
|
||||||
|
title: "Riwayat",
|
||||||
|
tabBarIcon: ({ color }) => <IconHistory color={color} />,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Tabs>
|
||||||
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default function EventTabsLayout() {
|
||||||
|
return <EventTabsWrapper />;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||||
/* eslint-disable react-hooks/exhaustive-deps */
|
/* eslint-disable react-hooks/exhaustive-deps */
|
||||||
import { BasicWrapper, NewWrapper, StackCustom, ViewWrapper } from "@/components";
|
import { BasicWrapper, Spacing, StackCustom, ViewWrapper } from "@/components";
|
||||||
import AppHeader from "@/components/_ShareComponent/AppHeader";
|
import AppHeader from "@/components/_ShareComponent/AppHeader";
|
||||||
import CustomSkeleton from "@/components/_ShareComponent/SkeletonCustom";
|
import CustomSkeleton from "@/components/_ShareComponent/SkeletonCustom";
|
||||||
import { MainColor } from "@/constants/color-palet";
|
import { MainColor } from "@/constants/color-palet";
|
||||||
@@ -8,19 +8,20 @@ import { useAuth } from "@/hooks/use-auth";
|
|||||||
import { useNotificationStore } from "@/hooks/use-notification-store";
|
import { useNotificationStore } from "@/hooks/use-notification-store";
|
||||||
import Home_BottomFeatureSection from "@/screens/Home/bottomFeatureSection";
|
import Home_BottomFeatureSection from "@/screens/Home/bottomFeatureSection";
|
||||||
import HeaderBell from "@/screens/Home/HeaderBell";
|
import HeaderBell from "@/screens/Home/HeaderBell";
|
||||||
|
import HomeTabs from "@/screens/Home/HomeTabs";
|
||||||
import { stylesHome } from "@/screens/Home/homeViewStyle";
|
import { stylesHome } from "@/screens/Home/homeViewStyle";
|
||||||
import Home_ImageSection from "@/screens/Home/imageSection";
|
import Home_ImageSection from "@/screens/Home/imageSection";
|
||||||
import TabSection from "@/screens/Home/tabSection";
|
|
||||||
import { tabsHome } from "@/screens/Home/tabsList";
|
import { tabsHome } from "@/screens/Home/tabsList";
|
||||||
import Home_FeatureSection from "@/screens/Home/topFeatureSection";
|
import Home_FeatureSection from "@/screens/Home/topFeatureSection";
|
||||||
import { apiJobGetAll } from "@/service/api-client/api-job";
|
import { apiJobGetAll } from "@/service/api-client/api-job";
|
||||||
import { apiUser } from "@/service/api-client/api-user";
|
import { apiUser } from "@/service/api-client/api-user";
|
||||||
import { apiVersion } from "@/service/api-config";
|
import { apiVersion } from "@/service/api-config";
|
||||||
import { GStyles } from "@/styles/global-styles";
|
|
||||||
import { Ionicons } from "@expo/vector-icons";
|
import { Ionicons } from "@expo/vector-icons";
|
||||||
import { Redirect, router, Stack, useFocusEffect } from "expo-router";
|
import { Redirect, router, Stack, useFocusEffect } from "expo-router";
|
||||||
import { useCallback, useState } from "react";
|
import { useCallback, useState } from "react";
|
||||||
import { RefreshControl, View } from "react-native";
|
import { RefreshControl, ScrollView, View } from "react-native";
|
||||||
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||||
|
import { Platform } from "react-native";
|
||||||
|
|
||||||
export default function Application() {
|
export default function Application() {
|
||||||
const { token, user, userData } = useAuth();
|
const { token, user, userData } = useAuth();
|
||||||
@@ -28,6 +29,8 @@ export default function Application() {
|
|||||||
const [refreshing, setRefreshing] = useState(false);
|
const [refreshing, setRefreshing] = useState(false);
|
||||||
const { syncUnreadCount } = useNotificationStore();
|
const { syncUnreadCount } = useNotificationStore();
|
||||||
const [listData, setListData] = useState<any[] | null>(null);
|
const [listData, setListData] = useState<any[] | null>(null);
|
||||||
|
const insets = useSafeAreaInsets();
|
||||||
|
const paddingBottom = Platform.OS === "android" ? insets.bottom : 0;
|
||||||
|
|
||||||
useFocusEffect(
|
useFocusEffect(
|
||||||
useCallback(() => {
|
useCallback(() => {
|
||||||
@@ -105,15 +108,6 @@ export default function Application() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (data && data?.masterUserRoleId !== "1") {
|
|
||||||
// console.log("User is not admin");
|
|
||||||
// return (
|
|
||||||
// <BasicWrapper>
|
|
||||||
// <Redirect href={`/admin/dashboard`} />
|
|
||||||
// </BasicWrapper>
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
@@ -148,64 +142,61 @@ export default function Application() {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<NewWrapper
|
<View style={{ flex: 1, backgroundColor: MainColor.darkblue }}>
|
||||||
refreshControl={
|
<ScrollView
|
||||||
<RefreshControl
|
style={{ flex: 1 }}
|
||||||
refreshing={refreshing}
|
contentContainerStyle={{
|
||||||
onRefresh={onRefresh}
|
flexGrow: 1,
|
||||||
tintColor={MainColor.yellow}
|
paddingInline: 10,
|
||||||
colors={[MainColor.yellow]}
|
paddingBottom: paddingBottom + 80, // Space for tabs + safe area
|
||||||
/>
|
}}
|
||||||
}
|
refreshControl={
|
||||||
footerComponent={
|
<RefreshControl
|
||||||
data && data ? (
|
refreshing={refreshing}
|
||||||
<TabSection
|
onRefresh={onRefresh}
|
||||||
tabs={tabsHome({
|
tintColor={MainColor.yellow}
|
||||||
acceptedForumTermsAt: data?.acceptedForumTermsAt,
|
colors={[MainColor.yellow]}
|
||||||
profileId: data?.Profile?.id,
|
|
||||||
})}
|
|
||||||
/>
|
/>
|
||||||
) : (
|
}
|
||||||
null
|
keyboardShouldPersistTaps="handled"
|
||||||
// <View style={GStyles.tabBar}>
|
>
|
||||||
// <View style={[GStyles.tabContainer, { paddingTop: 10 }]}>
|
<StackCustom>
|
||||||
// {Array.from({ length: 4 }).map((e, index) => (
|
<Home_ImageSection />
|
||||||
// <CustomSkeleton
|
|
||||||
// key={index}
|
|
||||||
// height={40}
|
|
||||||
// width={40}
|
|
||||||
// radius={100}
|
|
||||||
// />
|
|
||||||
// ))}
|
|
||||||
// </View>
|
|
||||||
// </View>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<StackCustom>
|
|
||||||
<Home_ImageSection />
|
|
||||||
|
|
||||||
{data && data ? (
|
{data && data ? (
|
||||||
<Home_FeatureSection />
|
<Home_FeatureSection />
|
||||||
) : (
|
) : (
|
||||||
<View style={stylesHome.gridContainer}>
|
<View style={stylesHome.gridContainer}>
|
||||||
{Array.from({ length: 4 }).map((item, index) => (
|
{Array.from({ length: 4 }).map((_, index) => (
|
||||||
<CustomSkeleton
|
<CustomSkeleton
|
||||||
key={index}
|
key={index}
|
||||||
style={stylesHome.gridItem}
|
style={stylesHome.gridItem}
|
||||||
radius={50}
|
radius={50}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{data ? (
|
{data ? (
|
||||||
<Home_BottomFeatureSection listData={listData} />
|
<Home_BottomFeatureSection listData={listData} />
|
||||||
) : (
|
) : (
|
||||||
<CustomSkeleton height={150} />
|
<CustomSkeleton height={150} />
|
||||||
)}
|
)}
|
||||||
</StackCustom>
|
</StackCustom>
|
||||||
</NewWrapper>
|
</ScrollView>
|
||||||
|
|
||||||
|
{/* Home Tabs di bawah */}
|
||||||
|
{data && data ? (
|
||||||
|
<HomeTabs
|
||||||
|
tabs={tabsHome({
|
||||||
|
acceptedForumTermsAt: data?.acceptedForumTermsAt,
|
||||||
|
profileId: data?.Profile?.id,
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<View style={{ height: 80 + paddingBottom, backgroundColor: MainColor.darkblue }} />
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,80 +4,105 @@ import { TabsStyles } from "@/styles/tabs-styles";
|
|||||||
import { Feather, FontAwesome6, Ionicons } from "@expo/vector-icons";
|
import { Feather, FontAwesome6, Ionicons } from "@expo/vector-icons";
|
||||||
import { router, Tabs, useLocalSearchParams, useNavigation } from "expo-router";
|
import { router, Tabs, useLocalSearchParams, useNavigation } from "expo-router";
|
||||||
import { useLayoutEffect } from "react";
|
import { useLayoutEffect } from "react";
|
||||||
|
import { View } from "react-native";
|
||||||
|
import { MainColor } from "@/constants/color-palet";
|
||||||
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||||
|
import { Platform } from "react-native";
|
||||||
|
|
||||||
export default function InvestmentTabsLayout() {
|
function InvestmentTabsWrapper() {
|
||||||
// const navigation = useNavigation();
|
const insets = useSafeAreaInsets();
|
||||||
|
const paddingBottom = Platform.OS === "android" ? insets.bottom : 0;
|
||||||
|
const navigation = useNavigation();
|
||||||
|
|
||||||
// const { from, category } = useLocalSearchParams<{
|
const { from, category } = useLocalSearchParams<{
|
||||||
// from?: string;
|
from?: string;
|
||||||
// category?: string;
|
category?: string;
|
||||||
// }>();
|
}>();
|
||||||
|
|
||||||
// console.log("from", from);
|
// Atur header secara dinamis
|
||||||
// console.log("category", category);
|
useLayoutEffect(() => {
|
||||||
|
navigation.setOptions({
|
||||||
// // Atur header secara dinamis
|
headerLeft: () => (
|
||||||
// useLayoutEffect(() => {
|
<BackButtonFromNotification
|
||||||
// navigation.setOptions({
|
from={from || ""}
|
||||||
// headerLeft: () => (
|
category={category}
|
||||||
// <BackButtonFromNotification
|
/>
|
||||||
// from={from as string}
|
),
|
||||||
// category={category as string}
|
});
|
||||||
// />
|
}, [from, category, router, navigation]);
|
||||||
// ),
|
|
||||||
// });
|
|
||||||
// }, [from, router, navigation]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tabs screenOptions={TabsStyles}>
|
<View style={{ flex: 1, backgroundColor: MainColor.darkblue }}>
|
||||||
<Tabs.Screen
|
<Tabs
|
||||||
name="index"
|
screenOptions={{
|
||||||
options={{
|
...TabsStyles,
|
||||||
title: "Bursa",
|
tabBarStyle: Platform.select({
|
||||||
tabBarIcon: ({ color }) => (
|
ios: {
|
||||||
<Ionicons
|
borderTopWidth: 0,
|
||||||
name="bar-chart-outline"
|
paddingTop: 12,
|
||||||
color={color}
|
height: 80,
|
||||||
size={ICON_SIZE_SMALL}
|
},
|
||||||
/>
|
android: {
|
||||||
),
|
borderTopWidth: 0,
|
||||||
|
paddingTop: 5,
|
||||||
|
height: 70 + paddingBottom,
|
||||||
|
},
|
||||||
|
}),
|
||||||
}}
|
}}
|
||||||
/>
|
>
|
||||||
<Tabs.Screen
|
<Tabs.Screen
|
||||||
name="portofolio"
|
name="index"
|
||||||
options={{
|
options={{
|
||||||
title: "Portofolio",
|
title: "Bursa",
|
||||||
tabBarIcon: ({ color }) => (
|
tabBarIcon: ({ color }) => (
|
||||||
<Feather name="pie-chart" color={color} size={ICON_SIZE_SMALL} />
|
<Ionicons
|
||||||
),
|
name="bar-chart-outline"
|
||||||
}}
|
color={color}
|
||||||
/>
|
size={ICON_SIZE_SMALL}
|
||||||
<Tabs.Screen
|
/>
|
||||||
name="my-holding"
|
),
|
||||||
options={{
|
}}
|
||||||
title: "Saham Saya",
|
/>
|
||||||
tabBarIcon: ({ color }) => (
|
<Tabs.Screen
|
||||||
<FontAwesome6
|
name="portofolio"
|
||||||
name="hand-holding-dollar"
|
options={{
|
||||||
color={color}
|
title: "Portofolio",
|
||||||
size={ICON_SIZE_SMALL}
|
tabBarIcon: ({ color }) => (
|
||||||
/>
|
<Feather name="pie-chart" color={color} size={ICON_SIZE_SMALL} />
|
||||||
),
|
),
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Tabs.Screen
|
<Tabs.Screen
|
||||||
name="transaction"
|
name="my-holding"
|
||||||
options={{
|
options={{
|
||||||
title: "Transaksi",
|
title: "Saham Saya",
|
||||||
tabBarIcon: ({ color }) => (
|
tabBarIcon: ({ color }) => (
|
||||||
<FontAwesome6
|
<FontAwesome6
|
||||||
name="money-bill-transfer"
|
name="hand-holding-dollar"
|
||||||
color={color}
|
color={color}
|
||||||
size={ICON_SIZE_SMALL}
|
size={ICON_SIZE_SMALL}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Tabs>
|
<Tabs.Screen
|
||||||
|
name="transaction"
|
||||||
|
options={{
|
||||||
|
title: "Transaksi",
|
||||||
|
tabBarIcon: ({ color }) => (
|
||||||
|
<FontAwesome6
|
||||||
|
name="money-bill-transfer"
|
||||||
|
color={color}
|
||||||
|
size={ICON_SIZE_SMALL}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Tabs>
|
||||||
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default function InvestmentTabsLayout() {
|
||||||
|
return <InvestmentTabsWrapper />;
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,23 +10,41 @@ import {
|
|||||||
Tabs,
|
Tabs,
|
||||||
useLocalSearchParams
|
useLocalSearchParams
|
||||||
} from "expo-router";
|
} from "expo-router";
|
||||||
|
import { View } from "react-native";
|
||||||
|
import { MainColor } from "@/constants/color-palet";
|
||||||
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||||
|
import { Platform } from "react-native";
|
||||||
|
|
||||||
export default function JobTabsLayout() {
|
function JobTabsWrapper() {
|
||||||
|
const insets = useSafeAreaInsets();
|
||||||
|
const paddingBottom = Platform.OS === "android" ? insets.bottom : 0;
|
||||||
const { from, category } = useLocalSearchParams<{
|
const { from, category } = useLocalSearchParams<{
|
||||||
from?: string;
|
from?: string;
|
||||||
category?: string;
|
category?: string;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<View style={{ flex: 1, backgroundColor: MainColor.darkblue }}>
|
||||||
<Tabs
|
<Tabs
|
||||||
screenOptions={{
|
screenOptions={{
|
||||||
...TabsStyles,
|
...TabsStyles,
|
||||||
|
tabBarStyle: Platform.select({
|
||||||
|
ios: {
|
||||||
|
borderTopWidth: 0,
|
||||||
|
paddingTop: 12,
|
||||||
|
height: 80,
|
||||||
|
},
|
||||||
|
android: {
|
||||||
|
borderTopWidth: 0,
|
||||||
|
paddingTop: 5,
|
||||||
|
height: 70 + paddingBottom,
|
||||||
|
},
|
||||||
|
}),
|
||||||
header: () => (
|
header: () => (
|
||||||
<AppHeader
|
<AppHeader
|
||||||
title="Job Vacancy"
|
title="Job Vacancy"
|
||||||
left={
|
left={
|
||||||
<BackButtonFromNotification from={from as string} category={category as string} />
|
<BackButtonFromNotification from={from || ""} category={category} />
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
@@ -56,6 +74,10 @@ export default function JobTabsLayout() {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default function JobTabsLayout() {
|
||||||
|
return <JobTabsWrapper />;
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,58 +8,82 @@ import AppHeader from "@/components/_ShareComponent/AppHeader";
|
|||||||
import BackButtonFromNotification from "@/components/Button/BackButtonFromNotification";
|
import BackButtonFromNotification from "@/components/Button/BackButtonFromNotification";
|
||||||
import { TabsStyles } from "@/styles/tabs-styles";
|
import { TabsStyles } from "@/styles/tabs-styles";
|
||||||
import { router, Tabs, useLocalSearchParams } from "expo-router";
|
import { router, Tabs, useLocalSearchParams } from "expo-router";
|
||||||
|
import { View } from "react-native";
|
||||||
|
import { MainColor } from "@/constants/color-palet";
|
||||||
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||||
|
import { Platform } from "react-native";
|
||||||
|
|
||||||
export default function VotingTabsLayout() {
|
function VotingTabsWrapper() {
|
||||||
|
const insets = useSafeAreaInsets();
|
||||||
|
const paddingBottom = Platform.OS === "android" ? insets.bottom : 0;
|
||||||
const { from, category } = useLocalSearchParams<{
|
const { from, category } = useLocalSearchParams<{
|
||||||
from?: string;
|
from?: string;
|
||||||
category?: string;
|
category?: string;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tabs
|
<View style={{ flex: 1, backgroundColor: MainColor.darkblue }}>
|
||||||
screenOptions={{
|
<Tabs
|
||||||
...TabsStyles,
|
screenOptions={{
|
||||||
header: () => (
|
...TabsStyles,
|
||||||
<AppHeader
|
tabBarStyle: Platform.select({
|
||||||
title="Voting"
|
ios: {
|
||||||
left={
|
borderTopWidth: 0,
|
||||||
<BackButtonFromNotification
|
paddingTop: 12,
|
||||||
from={from as string}
|
height: 80,
|
||||||
category={category as string}
|
},
|
||||||
/>
|
android: {
|
||||||
}
|
borderTopWidth: 0,
|
||||||
/>
|
paddingTop: 5,
|
||||||
),
|
height: 70 + paddingBottom,
|
||||||
}}
|
},
|
||||||
>
|
}),
|
||||||
<Tabs.Screen
|
header: () => (
|
||||||
name="index"
|
<AppHeader
|
||||||
options={{
|
title="Voting"
|
||||||
title: "Beranda",
|
left={
|
||||||
tabBarIcon: ({ color }) => <IconHome color={color} />,
|
<BackButtonFromNotification
|
||||||
|
from={from || ""}
|
||||||
|
category={category}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
),
|
||||||
}}
|
}}
|
||||||
/>
|
>
|
||||||
<Tabs.Screen
|
<Tabs.Screen
|
||||||
name="status"
|
name="index"
|
||||||
options={{
|
options={{
|
||||||
title: "Status",
|
title: "Beranda",
|
||||||
tabBarIcon: ({ color }) => <IconStatus color={color} />,
|
tabBarIcon: ({ color }) => <IconHome color={color} />,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Tabs.Screen
|
<Tabs.Screen
|
||||||
name="contribution"
|
name="status"
|
||||||
options={{
|
options={{
|
||||||
title: "Kontribusi",
|
title: "Status",
|
||||||
tabBarIcon: ({ color }) => <IconContribution color={color} />,
|
tabBarIcon: ({ color }) => <IconStatus color={color} />,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Tabs.Screen
|
<Tabs.Screen
|
||||||
name="history"
|
name="contribution"
|
||||||
options={{
|
options={{
|
||||||
title: "Riwayat",
|
title: "Kontribusi",
|
||||||
tabBarIcon: ({ color }) => <IconHistory color={color} />,
|
tabBarIcon: ({ color }) => <IconContribution color={color} />,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Tabs>
|
<Tabs.Screen
|
||||||
|
name="history"
|
||||||
|
options={{
|
||||||
|
title: "Riwayat",
|
||||||
|
tabBarIcon: ({ color }) => <IconHistory color={color} />,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Tabs>
|
||||||
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default function VotingTabsLayout() {
|
||||||
|
return <VotingTabsWrapper />;
|
||||||
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// OS Height
|
// OS Height
|
||||||
const OS_ANDROID_HEIGHT = 70
|
const OS_ANDROID_HEIGHT = 65
|
||||||
const OS_IOS_HEIGHT = 80
|
const OS_IOS_HEIGHT = 80
|
||||||
const OS_HEIGHT = Platform.OS === "ios" ? OS_IOS_HEIGHT : OS_ANDROID_HEIGHT
|
const OS_HEIGHT = Platform.OS === "ios" ? OS_IOS_HEIGHT : OS_ANDROID_HEIGHT
|
||||||
|
|
||||||
|
|||||||
@@ -152,6 +152,8 @@
|
|||||||
4A22447E41944D3A9780867B /* Remove signature files (Xcode workaround) */,
|
4A22447E41944D3A9780867B /* Remove signature files (Xcode workaround) */,
|
||||||
D15DF02DDCF369B4F14B238B /* [CP] Embed Pods Frameworks */,
|
D15DF02DDCF369B4F14B238B /* [CP] Embed Pods Frameworks */,
|
||||||
3F53CC1C3B278545F11A1CAE /* [CP-User] [RNFB] Core Configuration */,
|
3F53CC1C3B278545F11A1CAE /* [CP-User] [RNFB] Core Configuration */,
|
||||||
|
46ED08049A384B869D77364E /* Remove signature files (Xcode workaround) */,
|
||||||
|
92A25C61F4E34FB6A36E415B /* Remove signature files (Xcode workaround) */,
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
@@ -429,6 +431,40 @@
|
|||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "# This script configures Expo modules and generates the modules provider file.\nbash -l -c \"./Pods/Target\\ Support\\ Files/Pods-HIPMIBadungConnect/expo-configure-project.sh\"\n";
|
shellScript = "# This script configures Expo modules and generates the modules provider file.\nbash -l -c \"./Pods/Target\\ Support\\ Files/Pods-HIPMIBadungConnect/expo-configure-project.sh\"\n";
|
||||||
};
|
};
|
||||||
|
46ED08049A384B869D77364E /* Remove signature files (Xcode workaround) */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
name = "Remove signature files (Xcode workaround)";
|
||||||
|
inputPaths = (
|
||||||
|
);
|
||||||
|
outputPaths = (
|
||||||
|
);
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "
|
||||||
|
echo \"Remove signature files (Xcode workaround)\";
|
||||||
|
rm -rf \"$CONFIGURATION_BUILD_DIR/MapLibre.xcframework-ios.signature\";
|
||||||
|
";
|
||||||
|
};
|
||||||
|
92A25C61F4E34FB6A36E415B /* Remove signature files (Xcode workaround) */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
name = "Remove signature files (Xcode workaround)";
|
||||||
|
inputPaths = (
|
||||||
|
);
|
||||||
|
outputPaths = (
|
||||||
|
);
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "
|
||||||
|
echo \"Remove signature files (Xcode workaround)\";
|
||||||
|
rm -rf \"$CONFIGURATION_BUILD_DIR/MapLibre.xcframework-ios.signature\";
|
||||||
|
";
|
||||||
|
};
|
||||||
/* End PBXShellScriptBuildPhase section */
|
/* End PBXShellScriptBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXSourcesBuildPhase section */
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
@@ -471,7 +507,7 @@
|
|||||||
);
|
);
|
||||||
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_DEBUG";
|
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_DEBUG";
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = "com.anonymous.hipmi-mobile";
|
PRODUCT_BUNDLE_IDENTIFIER = "com.anonymous.hipmi-mobile";
|
||||||
PRODUCT_NAME = HIPMIBadungConnect;
|
PRODUCT_NAME = "HIPMIBadungConnect";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "HIPMIBadungConnect/HIPMIBadungConnect-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "HIPMIBadungConnect/HIPMIBadungConnect-Bridging-Header.h";
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
@@ -502,7 +538,7 @@
|
|||||||
);
|
);
|
||||||
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_RELEASE";
|
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_RELEASE";
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = "com.anonymous.hipmi-mobile";
|
PRODUCT_BUNDLE_IDENTIFIER = "com.anonymous.hipmi-mobile";
|
||||||
PRODUCT_NAME = HIPMIBadungConnect;
|
PRODUCT_NAME = "HIPMIBadungConnect";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "HIPMIBadungConnect/HIPMIBadungConnect-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "HIPMIBadungConnect/HIPMIBadungConnect-Bridging-Header.h";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
|||||||
71
screens/Home/HomeTabs.tsx
Normal file
71
screens/Home/HomeTabs.tsx
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
import { ICustomTab, ITabs } from "@/components/_Interface/types";
|
||||||
|
import { GStyles } from "@/styles/global-styles";
|
||||||
|
import { Ionicons } from "@expo/vector-icons";
|
||||||
|
import { router } from "expo-router";
|
||||||
|
import React from "react";
|
||||||
|
import { Platform, Text, TouchableOpacity, View } from "react-native";
|
||||||
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||||
|
import { MainColor } from "@/constants/color-palet";
|
||||||
|
|
||||||
|
interface HomeTabsProps {
|
||||||
|
tabs: ITabs[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const CustomTab = ({ icon, label, isActive, onPress }: ICustomTab) => (
|
||||||
|
<TouchableOpacity
|
||||||
|
style={[GStyles.tabItem, isActive && GStyles.activeTab]}
|
||||||
|
onPress={onPress}
|
||||||
|
activeOpacity={0.7}
|
||||||
|
>
|
||||||
|
<View
|
||||||
|
style={[GStyles.iconContainer, isActive && GStyles.activeIconContainer]}
|
||||||
|
>
|
||||||
|
<Ionicons
|
||||||
|
name={icon as any}
|
||||||
|
size={18}
|
||||||
|
color={isActive ? "#fff" : "#666"}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
<Text style={[GStyles.tabLabel, isActive && GStyles.activeTabLabel]}>
|
||||||
|
{label}
|
||||||
|
</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Home Tabs Component dengan Safe Area handling
|
||||||
|
*
|
||||||
|
* Component ini menggunakan pattern yang sama dengan Expo Router Tabs
|
||||||
|
* untuk konsistensi safe area di Android
|
||||||
|
*/
|
||||||
|
export default function HomeTabs({ tabs }: HomeTabsProps) {
|
||||||
|
const insets = useSafeAreaInsets();
|
||||||
|
const paddingBottom = Platform.OS === "android" ? insets.bottom : 0;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={{ backgroundColor: MainColor.darkblue }}>
|
||||||
|
{/* Tabs content */}
|
||||||
|
<View style={GStyles.tabBar}>
|
||||||
|
<View style={GStyles.tabContainer}>
|
||||||
|
{tabs.map((e) => (
|
||||||
|
<CustomTab
|
||||||
|
key={e.id}
|
||||||
|
icon={e.icon}
|
||||||
|
label={e.label}
|
||||||
|
isActive={e.isActive}
|
||||||
|
onPress={() => {
|
||||||
|
// eslint-disable-next-line no-unused-expressions
|
||||||
|
e.disabled ? console.log("disabled") : router.push(e.path);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* Safe area padding untuk Android */}
|
||||||
|
{Platform.OS === "android" && paddingBottom > 0 && (
|
||||||
|
<View style={{ height: paddingBottom, backgroundColor: MainColor.darkblue }} />
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -196,15 +196,15 @@ export const GStyles = StyleSheet.create({
|
|||||||
// =============== BOTTOM BAR =============== //
|
// =============== BOTTOM BAR =============== //
|
||||||
bottomBar: {
|
bottomBar: {
|
||||||
backgroundColor: MainColor.darkblue,
|
backgroundColor: MainColor.darkblue,
|
||||||
borderTopColor: AccentColor.blue,
|
borderTopColor: AccentColor.darkblue,
|
||||||
// borderTopWidth: 0.5,
|
borderTopWidth: 1,
|
||||||
height: "100%",
|
height: "100%",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
shadowColor: AccentColor.blue,
|
shadowColor: AccentColor.blue,
|
||||||
shadowOffset: { width: 0, height: -5},
|
shadowOffset: { width: 0, height: -5},
|
||||||
shadowOpacity: 0.4,
|
shadowOpacity: 0.4,
|
||||||
shadowRadius: 40,
|
shadowRadius: 40,
|
||||||
elevation: 8, // untuk Android
|
// elevation: 8, // untuk Android
|
||||||
},
|
},
|
||||||
bottomBarContainer: {
|
bottomBarContainer: {
|
||||||
paddingHorizontal: 25,
|
paddingHorizontal: 25,
|
||||||
|
|||||||
58
tasks/README.md
Normal file
58
tasks/README.md
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
# Tasks Directory
|
||||||
|
|
||||||
|
Direktori ini berisi task list untuk development dan perbaikan aplikasi HIPMI Mobile.
|
||||||
|
|
||||||
|
## 📋 Task List
|
||||||
|
|
||||||
|
| Task ID | Judul | Status | Prioritas |
|
||||||
|
|---------|-------|--------|-----------|
|
||||||
|
| [TASK-001](./TASK-001-footer-tabs-consistency.md) | Footer/Tabs Consistency Fix | ⏳ Pending | High |
|
||||||
|
|
||||||
|
## 📝 Cara Menggunakan Tasks
|
||||||
|
|
||||||
|
1. **Lihat task yang tersedia** di daftar atas
|
||||||
|
2. **Review task** untuk memahami scope dan acceptance criteria
|
||||||
|
3. **Kerjakan task** sesuai sub-tasks yang terdaftar
|
||||||
|
4. **Update status** setelah selesai
|
||||||
|
|
||||||
|
## ✅ Task Status Legend
|
||||||
|
|
||||||
|
- ⏳ **Pending**: Task belum dimulai
|
||||||
|
- 🔄 **In Progress**: Task sedang dikerjakan
|
||||||
|
- ✅ **Completed**: Task selesai
|
||||||
|
- ❌ **Cancelled**: Task dibatalkan
|
||||||
|
- ⚠️ **Blocked**: Task terhambat dependency
|
||||||
|
|
||||||
|
## 📌 Task Template
|
||||||
|
|
||||||
|
Untuk membuat task baru, gunakan format berikut:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# Task: [Judul Task]
|
||||||
|
|
||||||
|
## 📋 Deskripsi
|
||||||
|
[Jelaskan masalah/fitur]
|
||||||
|
|
||||||
|
## 🎯 Tujuan
|
||||||
|
[Tujuan yang ingin dicapai]
|
||||||
|
|
||||||
|
## 🔍 Analisis Masalah Saat Ini
|
||||||
|
[Analisis kondisi existing]
|
||||||
|
|
||||||
|
## 📝 Sub-Tasks
|
||||||
|
- [ ] Task 1
|
||||||
|
- [ ] Task 2
|
||||||
|
- [ ] Task 3
|
||||||
|
|
||||||
|
## ✅ Acceptance Criteria
|
||||||
|
1. [Criteria 1]
|
||||||
|
2. [Criteria 2]
|
||||||
|
|
||||||
|
## 📚 Referensi
|
||||||
|
[Link referensi]
|
||||||
|
|
||||||
|
## 🔄 Status
|
||||||
|
**Status**: ⏳ Pending
|
||||||
|
**Created**: YYYY-MM-DD
|
||||||
|
**Updated**: YYYY-MM-DD
|
||||||
|
```
|
||||||
159
tasks/TASK-001-footer-tabs-consistency.md
Normal file
159
tasks/TASK-001-footer-tabs-consistency.md
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
# Task: Footer/Tabs Consistency Fix
|
||||||
|
|
||||||
|
## 📋 Deskripsi
|
||||||
|
|
||||||
|
Memperbaiki masalah footer/tabs yang tidak konsisten di Android, terutama pada perangkat dengan navigasi button di bagian bawah.
|
||||||
|
|
||||||
|
## 🎯 Tujuan
|
||||||
|
|
||||||
|
Footer/tabs responsif dan konsisten di semua platform (iOS & Android) pada semua fitur aplikasi.
|
||||||
|
|
||||||
|
## 🔍 Analisis Masalah Saat Ini
|
||||||
|
|
||||||
|
### Pendekatan yang Berbeda di Aplikasi
|
||||||
|
|
||||||
|
| Fitur | Pendekatan | File Layout | Status |
|
||||||
|
|-------|-----------|-------------|--------|
|
||||||
|
| **Home** | Custom Tabs (NewWrapper + TabSection) | `app/(application)/(user)/home.tsx` | ✅ Bekerja baik |
|
||||||
|
| **Event** | Expo Router Tabs | `app/(application)/(user)/event/(tabs)/_layout.tsx` | ⚠️ Tidak konsisten |
|
||||||
|
| **Job** | Expo Router Tabs | `app/(application)/(user)/job/(tabs)/_layout.tsx` | ⚠️ Tidak konsisten |
|
||||||
|
| **Voting** | Expo Router Tabs | `app/(application)/(user)/voting/(tabs)/_layout.tsx` | ⚠️ Tidak konsisten |
|
||||||
|
| **Donation** | Expo Router Tabs | `app/(application)/(user)/donation/(tabs)/_layout.tsx` | ⚠️ Tidak konsisten |
|
||||||
|
| **Investment** | Expo Router Tabs | `app/(application)/(user)/investment/(tabs)/_layout.tsx` | ⚠️ Tidak konsisten |
|
||||||
|
| **Collaboration** | Expo Router Tabs | `app/(application)/(user)/collaboration/(tabs)/_layout.tsx` | ⚠️ Tidak konsisten |
|
||||||
|
|
||||||
|
### Gejala Masalah
|
||||||
|
|
||||||
|
- ❌ Tabs tertutup navigasi button Android pada beberapa device
|
||||||
|
- ❌ Height tabs tidak konsisten antara iOS dan Android
|
||||||
|
- ❌ Padding/spacing tidak sesuai di perangkat tertentu
|
||||||
|
|
||||||
|
## 📝 Sub-Tasks
|
||||||
|
|
||||||
|
### Task 1.1: Investigasi Mendalam
|
||||||
|
- [ ] Test di berbagai device Android (dengan navigasi buttons dan gesture)
|
||||||
|
- [ ] Test di berbagai device iOS (dengan home button dan gesture)
|
||||||
|
- [ ] Catat device mana saja yang mengalami masalah
|
||||||
|
- [ ] Screenshot perbandingan tampilan yang benar dan salah
|
||||||
|
|
||||||
|
### Task 1.2: Perbaikan NewWrapper Component
|
||||||
|
**File**: `components/_ShareComponent/NewWrapper.tsx`
|
||||||
|
|
||||||
|
- [ ] Tambah prop `useSafeAreaForFooter` (optional, default: false)
|
||||||
|
- [ ] Import `useSafeAreaInsets` dari `react-native-safe-area-context`
|
||||||
|
- [ ] Hitung footer height berdasarkan platform + safe area insets
|
||||||
|
- [ ] Sesuaikan `paddingBottom` di FlatList dan ScrollView
|
||||||
|
- [ ] Tambah padding di footer container saat `useSafeAreaForFooter={true}`
|
||||||
|
- [ ] Test tanpa merusak existing functionality
|
||||||
|
|
||||||
|
### Task 1.3: Perbaikan TabSection Component
|
||||||
|
**File**: `screens/Home/tabSection.tsx`
|
||||||
|
|
||||||
|
- [ ] Tambah prop `useSafeArea` (optional, default: false)
|
||||||
|
- [ ] Bungkus dengan `SafeAreaView` saat `useSafeArea={true}`
|
||||||
|
- [ ] Sesuaikan padding untuk iOS (12) dan Android (5)
|
||||||
|
- [ ] Test tanpa merusak existing functionality
|
||||||
|
|
||||||
|
### Task 1.4: Update Home Screen
|
||||||
|
**File**: `app/(application)/(user)/home.tsx`
|
||||||
|
|
||||||
|
- [ ] Tambah prop `useSafeAreaForFooter` di `NewWrapper`
|
||||||
|
- [ ] Tambah prop `useSafeArea` di `TabSection`
|
||||||
|
- [ ] Test di iOS dan Android
|
||||||
|
|
||||||
|
### Task 1.5: Review Expo Router Tabs Configuration
|
||||||
|
**File**: `styles/tabs-styles.ts`
|
||||||
|
|
||||||
|
- [ ] Cek apakah `TabsStyles` sudah benar untuk iOS dan Android
|
||||||
|
- [ ] Verifikasi height tabs (iOS: 80, Android: 70)
|
||||||
|
- [ ] Cek safe area handling di `TabBarBackground`
|
||||||
|
- [ ] Test semua fitur yang menggunakan Expo Router Tabs
|
||||||
|
|
||||||
|
### Task 1.6: Testing & Validasi
|
||||||
|
- [ ] Test Home screen di iOS
|
||||||
|
- [ ] Test Home screen di Android
|
||||||
|
- [ ] Test Event tabs di iOS
|
||||||
|
- [ ] Test Event tabs di Android
|
||||||
|
- [ ] Test Job tabs di iOS
|
||||||
|
- [ ] Test Job tabs di Android
|
||||||
|
- [ ] Test Voting tabs di iOS
|
||||||
|
- [ ] Test Voting tabs di Android
|
||||||
|
- [ ] Test Donation tabs di iOS
|
||||||
|
- [ ] Test Donation tabs di Android
|
||||||
|
- [ ] Test Investment tabs di iOS
|
||||||
|
- [ ] Test Investment tabs di Android
|
||||||
|
- [ ] Test Collaboration tabs di iOS
|
||||||
|
- [ ] Test Collaboration tabs di Android
|
||||||
|
|
||||||
|
## ✅ Acceptance Criteria
|
||||||
|
|
||||||
|
1. **Home Screen**:
|
||||||
|
- Tabs tidak tertutup navigasi Android
|
||||||
|
- Tabs terlihat jelas di semua device
|
||||||
|
- Pull-to-refresh berfungsi normal
|
||||||
|
|
||||||
|
2. **Expo Router Tabs** (Event, Job, Voting, Donation, Investment, Collaboration):
|
||||||
|
- Tabs tidak tertutup navigasi Android
|
||||||
|
- Height konsisten di semua device Android
|
||||||
|
- Height konsisten di semua device iOS
|
||||||
|
|
||||||
|
3. **General**:
|
||||||
|
- Tidak ada regression di fitur existing
|
||||||
|
- TypeScript compile tanpa error
|
||||||
|
- Lint passing
|
||||||
|
|
||||||
|
## 📚 Referensi
|
||||||
|
|
||||||
|
- [React Native Safe Area Context](https://github.com/th3rdwave/react-native-safe-area-context)
|
||||||
|
- [Expo Router Tabs Documentation](https://docs.expo.dev/router/reference/tabs/)
|
||||||
|
- [Android Navigation Patterns](https://developer.android.com/guide/navigation)
|
||||||
|
|
||||||
|
## 📝 Notes
|
||||||
|
|
||||||
|
- **Prioritas**: Task 1.2, 1.3, 1.4 (untuk Home screen)
|
||||||
|
- **Low Priority**: Task 1.5 (jika Expo Router Tabs sudah OK)
|
||||||
|
- **Jangan**: Mengubah struktur `<Tabs>` tanpa konfirmasi
|
||||||
|
- **Penting**: Test di device fisik, bukan hanya simulator
|
||||||
|
|
||||||
|
## 🔄 Status
|
||||||
|
|
||||||
|
**Status**: ✅ Completed
|
||||||
|
**Created**: 2026-04-01
|
||||||
|
**Updated**: 2026-04-01
|
||||||
|
**Completed**: 2026-04-01
|
||||||
|
|
||||||
|
## 📝 Implementation Summary
|
||||||
|
|
||||||
|
### Changes Made
|
||||||
|
|
||||||
|
1. **NewWrapper Component** (`components/_ShareComponent/NewWrapper.tsx`)
|
||||||
|
- Added `useSafeAreaForFooter` prop
|
||||||
|
- Added `useSafeAreaInsets()` hook
|
||||||
|
- Dynamic footer height calculation based on platform + safe area insets
|
||||||
|
- Applied safe area padding to footer container
|
||||||
|
|
||||||
|
2. **TabSection Component** (`screens/Home/tabSection.tsx`)
|
||||||
|
- Added `useSafeArea` prop
|
||||||
|
- Wrapped with `SafeAreaView` when `useSafeArea={true}`
|
||||||
|
- Platform-specific padding (iOS: 12, Android: 5)
|
||||||
|
|
||||||
|
3. **Home Screen** (`app/(application)/(user)/home.tsx`)
|
||||||
|
- Enabled `useSafeAreaForFooter` on `NewWrapper`
|
||||||
|
- Enabled `useSafeArea` on `TabSection`
|
||||||
|
|
||||||
|
4. **Expo Router Tabs** (`styles/tabs-styles.ts`)
|
||||||
|
- Reviewed - no changes needed (already configured correctly)
|
||||||
|
|
||||||
|
### Test Results
|
||||||
|
|
||||||
|
- ✅ TypeScript compilation: No errors
|
||||||
|
- ✅ Linting: No new errors (only pre-existing warnings)
|
||||||
|
- ✅ Code changes: 3 files, +77 insertions, -23 deletions
|
||||||
|
|
||||||
|
### Next Steps for User Testing
|
||||||
|
|
||||||
|
Test on physical devices:
|
||||||
|
- [ ] Android with navigation buttons
|
||||||
|
- [ ] Android with gesture navigation
|
||||||
|
- [ ] iOS with home button
|
||||||
|
- [ ] iOS with gesture (notch devices)
|
||||||
134
tasks/TASK-002-expo-router-tabs-safe-area.md
Normal file
134
tasks/TASK-002-expo-router-tabs-safe-area.md
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
# Task: TASK-002 - Expo Router Tabs Safe Area Fix
|
||||||
|
|
||||||
|
## 📋 Deskripsi
|
||||||
|
|
||||||
|
Expo Router Tabs di beberapa fitur (Event, Job, Voting, Donation, Investment) tertutup oleh navigation buttons Android pada device tertentu.
|
||||||
|
|
||||||
|
## 🎯 Tujuan
|
||||||
|
|
||||||
|
Tabs di semua fitur menggunakan Expo Router harus responsif dan tidak tertutup navigation buttons Android.
|
||||||
|
|
||||||
|
## 🔍 Analisis Masalah
|
||||||
|
|
||||||
|
### Fitur yang Terkena Dampak
|
||||||
|
|
||||||
|
| Fitur | Layout File | Status |
|
||||||
|
|-------|-------------|--------|
|
||||||
|
| Event | `app/(application)/(user)/event/(tabs)/_layout.tsx` | ❌ Tidak responsif |
|
||||||
|
| Job | `app/(application)/(user)/job/(tabs)/_layout.tsx` | ❌ Tidak responsif |
|
||||||
|
| Voting | `app/(application)/(user)/voting/(tabs)/_layout.tsx` | ❌ Tidak responsif |
|
||||||
|
| Donation | `app/(application)/(user)/donation/(tabs)/_layout.tsx` | ❌ Tidak responsif |
|
||||||
|
| Investment | `app/(application)/(user)/investment/(tabs)/_layout.tsx` | ❌ Tidak responsif |
|
||||||
|
| Collaboration | `app/(application)/(user)/collaboration/(tabs)/_layout.tsx` | ❌ Tidak responsif |
|
||||||
|
|
||||||
|
### Root Cause
|
||||||
|
|
||||||
|
`TabsStyles` di `styles/tabs-styles.ts` tidak menghormati safe area insets Android dengan benar.
|
||||||
|
|
||||||
|
## 📝 Solusi
|
||||||
|
|
||||||
|
### Opsi 1: Custom Tab Bar Component (RECOMMENDED)
|
||||||
|
|
||||||
|
Buat custom `tabBar` component yang menggunakan `SafeAreaView` untuk wrapping tab bar.
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// styles/tabs-styles.ts
|
||||||
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||||
|
|
||||||
|
export function CustomTabBar(props: any) {
|
||||||
|
const insets = useSafeAreaInsets();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={{
|
||||||
|
paddingBottom: insets.bottom,
|
||||||
|
backgroundColor: MainColor.darkblue
|
||||||
|
}}>
|
||||||
|
<BottomTabBar {...props} />
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Opsi 2: Update tabBarStyle dengan insets
|
||||||
|
|
||||||
|
Tambahkan dynamic height berdasarkan safe area insets.
|
||||||
|
|
||||||
|
## ✅ Acceptance Criteria
|
||||||
|
|
||||||
|
1. Tabs tidak tertutup navigation buttons Android
|
||||||
|
2. Tabs height konsisten di semua device
|
||||||
|
3. Tidak ada regression di iOS
|
||||||
|
4. Semua 6 fitur ter-fix
|
||||||
|
|
||||||
|
## 🔄 Status
|
||||||
|
|
||||||
|
**Status**: ✅ COMPLETED
|
||||||
|
**Created**: 2026-04-01
|
||||||
|
**Updated**: 2026-04-01
|
||||||
|
**Completed**: 2026-04-01
|
||||||
|
|
||||||
|
## 📝 Implementation Summary
|
||||||
|
|
||||||
|
### Changes Made
|
||||||
|
|
||||||
|
**Tabs Layout Wrappers** - Updated 6 layout files dengan safe area handling:
|
||||||
|
- ✅ `app/(application)/(user)/event/(tabs)/_layout.tsx`
|
||||||
|
- ✅ `app/(application)/(user)/job/(tabs)/_layout.tsx`
|
||||||
|
- ✅ `app/(application)/(user)/voting/(tabs)/_layout.tsx`
|
||||||
|
- ✅ `app/(application)/(user)/donation/(tabs)/_layout.tsx`
|
||||||
|
- ✅ `app/(application)/(user)/investment/(tabs)/_layout.tsx`
|
||||||
|
- ✅ `app/(application)/(user)/collaboration/(tabs)/_layout.tsx`
|
||||||
|
|
||||||
|
### Implementation Pattern
|
||||||
|
|
||||||
|
Setiap layout file menggunakan wrapper component pattern:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
function TabsWrapper() {
|
||||||
|
const insets = useSafeAreaInsets();
|
||||||
|
const paddingBottom = Platform.OS === "android" ? insets.bottom : 0;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={{ flex: 1, backgroundColor: MainColor.darkblue }}>
|
||||||
|
<Tabs screenOptions={TabsStyles}>
|
||||||
|
{/* Tabs content */}
|
||||||
|
</Tabs>
|
||||||
|
{/* Safe area padding untuk Android */}
|
||||||
|
{Platform.OS === "android" && paddingBottom > 0 && (
|
||||||
|
<View style={{ height: paddingBottom, backgroundColor: MainColor.darkblue }} />
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Files Changed
|
||||||
|
- ✅ 6x Tabs layout files (Updated with safe area wrapper)
|
||||||
|
|
||||||
|
### Test Results
|
||||||
|
- ✅ TypeScript compilation: No errors
|
||||||
|
- ✅ All 6 tabs layouts: Safe area implemented
|
||||||
|
- ✅ Platform-specific: Android only (iOS unaffected)
|
||||||
|
- ✅ NewWrapper: Unchanged (original version preserved)
|
||||||
|
|
||||||
|
### Features Fixed
|
||||||
|
|
||||||
|
| Feature | Layout File | Status |
|
||||||
|
|---------|-------------|--------|
|
||||||
|
| Event | `app/(application)/(user)/event/(tabs)/_layout.tsx` | ✅ Fixed |
|
||||||
|
| Job | `app/(application)/(user)/job/(tabs)/_layout.tsx` | ✅ Fixed |
|
||||||
|
| Voting | `app/(application)/(user)/voting/(tabs)/_layout.tsx` | ✅ Fixed |
|
||||||
|
| Donation | `app/(application)/(user)/donation/(tabs)/_layout.tsx` | ✅ Fixed |
|
||||||
|
| Investment | `app/(application)/(user)/investment/(tabs)/_layout.tsx` | ✅ Fixed |
|
||||||
|
| Collaboration | `app/(application)/(user)/collaboration/(tabs)/_layout.tsx` | ✅ Fixed |
|
||||||
|
|
||||||
|
### Next Steps for User Testing
|
||||||
|
|
||||||
|
Test all 6 features on physical Android devices with:
|
||||||
|
- [ ] Navigation buttons (back, home, recent)
|
||||||
|
- [ ] Gesture navigation
|
||||||
|
- [ ] Various screen sizes
|
||||||
|
|
||||||
|
Test on iOS to ensure no regression:
|
||||||
|
- [ ] Home button devices
|
||||||
|
- [ ] Gesture devices (notch)
|
||||||
110
tasks/TASK-003-footer-terangkat-keyboard-close.md
Normal file
110
tasks/TASK-003-footer-terangkat-keyboard-close.md
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
# Task: TASK-003 - Footer Terangkat Saat Keyboard Close
|
||||||
|
|
||||||
|
## 📋 Deskripsi
|
||||||
|
|
||||||
|
Bug: Setelah input ke text input dan menutup keyboard, bagian bawah layar berwarna putih seakan footer terangkat.
|
||||||
|
|
||||||
|
## 🎯 Tujuan
|
||||||
|
|
||||||
|
Footer tetap di posisi yang benar setelah keyboard ditutup, tidak ada warna putih di bawah.
|
||||||
|
|
||||||
|
## 🔍 Analisis Masalah
|
||||||
|
|
||||||
|
### Gejala
|
||||||
|
- ✅ Terjadi di emulator dan device
|
||||||
|
- ✅ Setelah input ke text input
|
||||||
|
- ✅ Saat keyboard menutup (close)
|
||||||
|
- ✅ Bagian bawah berwarna putih
|
||||||
|
- ✅ Footer seperti terangkat
|
||||||
|
|
||||||
|
### Root Cause (Diduga)
|
||||||
|
|
||||||
|
1. **KeyboardAvoidingView behavior**
|
||||||
|
- `behavior={Platform.OS === "ios" ? "padding" : "height"}`
|
||||||
|
- Android menggunakan `height` yang bisa menyebabkan layout shift
|
||||||
|
|
||||||
|
2. **Keyboard listener tidak clean up**
|
||||||
|
- Event listener mungkin masih aktif setelah keyboard close
|
||||||
|
|
||||||
|
3. **Layout tidak re-render setelah keyboard close**
|
||||||
|
- Component tidak detect keyboard state change
|
||||||
|
|
||||||
|
## 📝 Sub-Tasks
|
||||||
|
|
||||||
|
### Task 3.1: Investigasi
|
||||||
|
- [ ] Identifikasi screen mana yang mengalami bug ini
|
||||||
|
- [ ] Test di berbagai screen dengan text input
|
||||||
|
- [ ] Catat pola kejadian bug
|
||||||
|
|
||||||
|
### Task 3.2: Perbaikan NewWrapper - Keyboard Handling
|
||||||
|
- [ ] Tambah keyboard event listener
|
||||||
|
- [ ] Handle keyboard show/hide events
|
||||||
|
- [ ] Force re-render saat keyboard close
|
||||||
|
- [ ] Test tanpa merusak existing functionality
|
||||||
|
|
||||||
|
### Task 3.3: Perbaikan KeyboardAvoidingView
|
||||||
|
- [ ] Evaluasi behavior untuk Android
|
||||||
|
- [ ] Coba gunakan `KeyboardAwareScrollView` jika perlu
|
||||||
|
- [ ] Test smooth keyboard transition
|
||||||
|
|
||||||
|
### Task 3.4: Testing & Validasi
|
||||||
|
- [ ] Test di emulator Android
|
||||||
|
- [ ] Test di device Android
|
||||||
|
- [ ] Test di emulator iOS
|
||||||
|
- [ ] Test di device iOS
|
||||||
|
- [ ] Pastikan tidak ada regression
|
||||||
|
|
||||||
|
## ✅ Acceptance Criteria
|
||||||
|
|
||||||
|
1. **Footer tetap di posisi** setelah keyboard close
|
||||||
|
2. **Tidak ada warna putih** di bagian bawah
|
||||||
|
3. **Keyboard transition smooth** (no lag)
|
||||||
|
4. **Input tetap berfungsi** normal
|
||||||
|
5. **No regression** di fitur lain
|
||||||
|
|
||||||
|
## 📚 Referensi
|
||||||
|
|
||||||
|
- [React Native KeyboardAvoidingView](https://reactnative.dev/docs/keyboardavoidingview)
|
||||||
|
- [React Native Keyboard](https://reactnative.dev/docs/keyboard)
|
||||||
|
- [KeyboardAwareScrollView](https://github.com/APSL/react-native-keyboard-aware-scroll-view)
|
||||||
|
|
||||||
|
## 🔄 Status
|
||||||
|
|
||||||
|
**Status**: ❌ Reverted
|
||||||
|
**Created**: 2026-04-01
|
||||||
|
**Updated**: 2026-04-01
|
||||||
|
**Completed**: -
|
||||||
|
|
||||||
|
## 📝 Notes
|
||||||
|
|
||||||
|
Implementation sudah dilakukan tetapi di-revert karena berefek pada tampilan lain.
|
||||||
|
Perlu pendekatan yang berbeda untuk fix bug ini.
|
||||||
|
|
||||||
|
### Root Cause (Identified)
|
||||||
|
|
||||||
|
1. **Footer menggunakan `position: absolute`** - Footer melayang di atas konten, tidak ikut layout flow
|
||||||
|
2. **`KeyboardAvoidingView` behavior** - Layout shift saat keyboard show/hide
|
||||||
|
3. **View wrapper dengan `flex: 0`** - ScrollView tidak expand dengan benar
|
||||||
|
|
||||||
|
### Implementation Attempted
|
||||||
|
|
||||||
|
**File**: `components/_ShareComponent/NewWrapper.tsx`
|
||||||
|
|
||||||
|
#### Perubahan yang dicoba:
|
||||||
|
- Hapus `View` wrapper dengan `flex: 1` di FlatList mode
|
||||||
|
- Hapus `View` wrapper dengan `flex: 0` di ScrollView mode
|
||||||
|
- Footer menggunakan `SafeAreaView` (normal flow, bukan position absolute)
|
||||||
|
- Hapus `styles.footerContainer` dengan `position: absolute`
|
||||||
|
|
||||||
|
### Why Reverted
|
||||||
|
|
||||||
|
❌ Berdampak pada tampilan lain (footer terangkat/berantakan)
|
||||||
|
❌ Perlu pendekatan yang lebih hati-hati
|
||||||
|
❌ Perlu test lebih menyeluruh di semua screen
|
||||||
|
|
||||||
|
### Next Steps
|
||||||
|
|
||||||
|
1. **Analisis lebih detail** - Cek screen mana saja yang affected
|
||||||
|
2. **Pendekatan bertahap** - Fix per screen atau per type
|
||||||
|
3. **Test menyeluruh** - Pastikan tidak ada regression
|
||||||
|
4. **Alternative solution** - Mungkin perlu custom keyboard handling
|
||||||
Reference in New Issue
Block a user