theme update latest project
This commit is contained in:
@@ -1,178 +1,400 @@
|
||||
// src/screens/ManagementScreen.tsx
|
||||
import React, { useState, useCallback, FC, useEffect } from "react";
|
||||
import React, { useState, useMemo, useEffect, useCallback } from 'react';
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
StyleSheet,
|
||||
FlatList,
|
||||
TouchableOpacity,
|
||||
ActivityIndicator,
|
||||
Alert,
|
||||
ScrollView,
|
||||
ToastAndroid,
|
||||
} from "react-native";
|
||||
import { useNavigation, useFocusEffect, useRoute, RouteProp } from "@react-navigation/native";
|
||||
import { StackNavigationProp } from "@react-navigation/stack";
|
||||
import { APPROVE_REQUEST_URL, DECLINE_REQUEST_URL, GET_JOINED_GROUP_URL, MY_GROUPS_URL, REQUESTS_URL, USER_REQUEST } from "../../utils/ApiUrls";
|
||||
import colors from "../../components/colors";
|
||||
import AppView from "../../components/AppView";
|
||||
import { apiCall } from "../../utils/ApiHelper";
|
||||
import { MyGroup, JoinedGroup, JoinRequest, ApiResponse, UserJoinRequest } from '../../types';
|
||||
import { MyGroupCard } from "../../components/MyGroupCard";
|
||||
import { JoinedGroupCard } from "../../components/JoinedGroupCard";
|
||||
import { RequestCard } from "../../components/RequestCard";
|
||||
import { useSelector } from "react-redux";
|
||||
import { UserRequested } from "../../components/UserRequested";
|
||||
import { RootTabParamList } from "../../navigation/BottomTabs";
|
||||
import { RootStackParamList } from "../../navigation/AppNavigator";
|
||||
RefreshControl,
|
||||
} from 'react-native';
|
||||
import { useNavigation, useRoute, RouteProp, useFocusEffect } from '@react-navigation/native';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { responsiveFontSize } from 'react-native-responsive-dimensions';
|
||||
import LucideIcon from '../../components/common/LucideIcon';
|
||||
import {
|
||||
APPROVE_REQUEST_URL,
|
||||
DECLINE_REQUEST_URL,
|
||||
GET_JOINED_GROUP_URL,
|
||||
MY_GROUPS_URL,
|
||||
REQUESTS_URL,
|
||||
USER_REQUEST
|
||||
} from '../../utils/ApiUrls';
|
||||
import AppView from '../../components/AppView';
|
||||
import { useTheme } from '../../hooks/ui/useTheme';
|
||||
import { useFetch } from '../../hooks/core/useFetch';
|
||||
import { useUpdate } from '../../hooks/core/useUpdate';
|
||||
import { MyGroup, JoinRequest } from '../../types';
|
||||
import MyGroupCard from '../../components/MyGroupCard';
|
||||
import { JoinedGroupCard } from '../../components/JoinedGroupCard';
|
||||
import { RequestCard } from '../../components/RequestCard';
|
||||
import { UserRequested } from '../../components/UserRequested';
|
||||
import SkeletonLoader from '../../components/common/SkeletonLoader';
|
||||
import FontsFamily from '../../constents/FontsFamily';
|
||||
import { RootTabParamList } from '../../navigation/BottomTabs';
|
||||
|
||||
// --- TYPE DEFINITIONS ---
|
||||
type GroupManagementNavProp = StackNavigationProp<RootStackParamList, 'ManagementTabs'>;
|
||||
type ManagementRouteProp = RouteProp<RootTabParamList, 'Management'>;
|
||||
type ActiveTab = "My Groups" | "Joined Groups" | "Requests" | "Your Requests";
|
||||
type ActiveTab = 'My Groups' | 'Joined Groups' | 'Requests' | 'Your Requests';
|
||||
type GroupStatusFilter = 'PENDING' | 'APPROVED' | 'ACTIVE' | 'DELAY' | 'COMPLETED' | 'REJECTED' | 'CANCELLED';
|
||||
|
||||
const ManagementScreen: FC = () => {
|
||||
const GROUP_STATUS_FILTERS: GroupStatusFilter[] = [
|
||||
'PENDING',
|
||||
'APPROVED',
|
||||
'ACTIVE',
|
||||
'DELAY',
|
||||
'COMPLETED',
|
||||
'REJECTED',
|
||||
'CANCELLED',
|
||||
];
|
||||
|
||||
const JOINED_GROUP_STATUS_FILTERS: GroupStatusFilter[] = [
|
||||
'ACTIVE',
|
||||
'DELAY',
|
||||
'COMPLETED',
|
||||
];
|
||||
|
||||
const getListFromResponse = <T,>(response: any): T[] => {
|
||||
if (!response) return [];
|
||||
if (Array.isArray(response?.data?.content)) return response.data.content;
|
||||
if (Array.isArray(response?.data)) return response.data;
|
||||
return [];
|
||||
};
|
||||
|
||||
const ManagementScreen: React.FC = () => {
|
||||
const theme = useTheme();
|
||||
const user = useSelector((state: any) => state.user);
|
||||
const navigation = useNavigation<GroupManagementNavProp>();
|
||||
const navigation = useNavigation<any>();
|
||||
const route = useRoute<ManagementRouteProp>();
|
||||
const [activeTab, setActiveTab] = useState<ActiveTab>(user.role === "USER" ? "Joined Groups" : "My Groups");
|
||||
const [myGroups, setMyGroups] = useState<MyGroup[]>([]);
|
||||
const [joinedGroups, setJoinedGroups] = useState<JoinedGroup[]>([]);
|
||||
const [requests, setRequests] = useState<JoinRequest[]>([]);
|
||||
const [userRequest, setUserRequest] = useState<UserJoinRequest[]>([]);
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const [activeTab, setActiveTab] = useState<ActiveTab>(
|
||||
user.role === 'ORGANIZER' ? 'My Groups' : 'Joined Groups'
|
||||
);
|
||||
const [myGroupStatusFilter, setMyGroupStatusFilter] = useState<GroupStatusFilter>('APPROVED');
|
||||
const [joinedGroupStatusFilter, setJoinedGroupStatusFilter] = useState<GroupStatusFilter>('ACTIVE');
|
||||
|
||||
useEffect(() => {
|
||||
const passedTab = route.params?.actionTab;
|
||||
if (passedTab) {
|
||||
const availableTabs = user.role === 'ORGANIZER' ? ["My Groups", "Joined Groups", "Requests"] : ["Joined Groups", "Your Requests"];
|
||||
if (availableTabs.includes(passedTab)) {
|
||||
setActiveTab(passedTab);
|
||||
}
|
||||
}
|
||||
}, [route.params?.actionTab, user.role]);
|
||||
if (!route.params?.actionTab) return;
|
||||
const routeTab = route.params.actionTab as ActiveTab;
|
||||
setActiveTab(routeTab);
|
||||
}, [route.params?.actionTab]);
|
||||
|
||||
const myGroupsParams = useMemo(
|
||||
() => ({ status: myGroupStatusFilter, page: 0, size: 10 }),
|
||||
[myGroupStatusFilter]
|
||||
);
|
||||
|
||||
const fetchData = useCallback(async () => {
|
||||
const joinedGroupsParams = useMemo(
|
||||
() => ({ status: joinedGroupStatusFilter, page: 0, size: 10 }),
|
||||
[joinedGroupStatusFilter]
|
||||
);
|
||||
|
||||
if (loading) return;
|
||||
// Data Fetching
|
||||
const { data: myGroupsRes, isLoading: myLoading, refetch: refetchMy } = useFetch<any>(
|
||||
MY_GROUPS_URL,
|
||||
myGroupsParams,
|
||||
{ enabled: user.role === 'ORGANIZER' }
|
||||
);
|
||||
const { data: joinedRes, isLoading: joinedLoading, refetch: refetchJoined } = useFetch<any>(
|
||||
GET_JOINED_GROUP_URL,
|
||||
joinedGroupsParams
|
||||
);
|
||||
const { data: requestsRes, isLoading: requestsLoading, refetch: refetchRequests } = useFetch<any>(
|
||||
REQUESTS_URL,
|
||||
undefined,
|
||||
{ enabled: user.role === 'ORGANIZER' }
|
||||
);
|
||||
const { data: userReqRes, isLoading: userReqLoading, refetch: refetchUserReq } = useFetch<any>(
|
||||
USER_REQUEST,
|
||||
undefined,
|
||||
{ enabled: user.role !== 'ORGANIZER' }
|
||||
);
|
||||
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
try {
|
||||
if (user.role === "ORGANIZER") {
|
||||
const [myGroupsRes, joinedGroupsRes, requestsRes] = await Promise.all([
|
||||
apiCall(MY_GROUPS_URL, "GET") as Promise<ApiResponse<MyGroup[]>>,
|
||||
apiCall(GET_JOINED_GROUP_URL, "GET") as Promise<ApiResponse<JoinedGroup[]>>,
|
||||
apiCall(REQUESTS_URL, "GET") as Promise<ApiResponse<JoinRequest[]>>,
|
||||
]);
|
||||
setMyGroups(myGroupsRes.data || []);
|
||||
setJoinedGroups(joinedGroupsRes.data || []);
|
||||
setRequests(requestsRes.data || []);
|
||||
} else {
|
||||
const [joinedGroupsRes, userRequestRes] = await Promise.all([
|
||||
apiCall(GET_JOINED_GROUP_URL, "GET") as Promise<ApiResponse<JoinedGroup[]>>,
|
||||
apiCall(USER_REQUEST, "GET") as Promise<ApiResponse<UserJoinRequest[]>>,
|
||||
]);
|
||||
console.log("GET_JOINED_GROUP_URL",joinedGroupsRes)
|
||||
setJoinedGroups(joinedGroupsRes.data || []);
|
||||
setUserRequest(userRequestRes.data || []);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Fetch Data Error:", e);
|
||||
setError("Failed to fetch data. Please pull to refresh.");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
const { mutate: updateRequest } = useUpdate<any, any>('');
|
||||
|
||||
}, [user.role]);
|
||||
const myGroups = useMemo(() => getListFromResponse<MyGroup>(myGroupsRes), [myGroupsRes]);
|
||||
const joinedGroups = useMemo(() => getListFromResponse<any>(joinedRes), [joinedRes]);
|
||||
const incomingRequests = useMemo(() => getListFromResponse<JoinRequest>(requestsRes), [requestsRes]);
|
||||
const myRequests = useMemo(() => getListFromResponse<any>(userReqRes), [userReqRes]);
|
||||
|
||||
const [refreshing, setRefreshing] = useState(false);
|
||||
const onRefresh = useCallback(() => {
|
||||
setRefreshing(true);
|
||||
Promise.all([
|
||||
refetchMy(),
|
||||
refetchJoined(),
|
||||
refetchRequests(),
|
||||
refetchUserReq(),
|
||||
]).finally(() => {
|
||||
setRefreshing(false);
|
||||
});
|
||||
}, [refetchMy, refetchJoined, refetchRequests, refetchUserReq]);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
fetchData();
|
||||
}, [fetchData])
|
||||
onRefresh();
|
||||
}, [])
|
||||
);
|
||||
|
||||
const handleViewGroup = (item: JoinedGroup) => {
|
||||
const tabs: ActiveTab[] = useMemo(() =>
|
||||
user.role === 'ORGANIZER'
|
||||
? ['My Groups', 'Joined Groups', 'Requests']
|
||||
: ['Joined Groups', 'Your Requests'],
|
||||
[user.role]);
|
||||
|
||||
const handleApprove = (req: JoinRequest) => {
|
||||
updateRequest({ resource: `${APPROVE_REQUEST_URL}${req.requestId}/approve`, payload: {} } as any, {
|
||||
onSuccess: () => {
|
||||
ToastAndroid.show('Request approved successfully', ToastAndroid.SHORT);
|
||||
refetchRequests();
|
||||
},
|
||||
onError: (err) => ToastAndroid.show(err.message || 'Failed to approve', ToastAndroid.SHORT),
|
||||
});
|
||||
};
|
||||
|
||||
const handleAction = async (url: string, successMessage: string, failureMessage: string) => {
|
||||
try {
|
||||
// No need to set loading here if the whole screen is already loading
|
||||
const res = await apiCall(url, "PUT", {}) as ApiResponse<null> | null;
|
||||
if (res && res.statusCode === 200) {
|
||||
ToastAndroid.show("Success", ToastAndroid.SHORT);
|
||||
fetchData(); // Refresh data after action
|
||||
} else {
|
||||
throw new Error(res?.message || failureMessage);
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error("Action Error:", err);
|
||||
ToastAndroid.show(err.message || failureMessage, ToastAndroid.SHORT);
|
||||
}
|
||||
|
||||
const handleDecline = (req: JoinRequest) => {
|
||||
updateRequest({ resource: `${DECLINE_REQUEST_URL}${req.requestId}/reject?reason=/`, payload: {} } as any, {
|
||||
onSuccess: () => {
|
||||
ToastAndroid.show('Request declined', ToastAndroid.SHORT);
|
||||
refetchRequests();
|
||||
},
|
||||
onError: (err) => ToastAndroid.show(err.message || 'Failed to decline', ToastAndroid.SHORT),
|
||||
});
|
||||
};
|
||||
|
||||
const handleApprove = (req: JoinRequest) => handleAction(APPROVE_REQUEST_URL + req.requestId + "/approve", `${req.userName} has been added.`, "Failed to approve request.");
|
||||
const handleDecline = (req: JoinRequest) => handleAction(DECLINE_REQUEST_URL + req.requestId + "/reject?reason=/", `Request from ${req.userName} has been declined.`, "Failed to decline request.");
|
||||
const handleManageGroup = (group: MyGroup) => navigation.navigate('ManagementTabs', { groupId: group.id });
|
||||
|
||||
const renderContent = () => {
|
||||
if (error) return <Text style={styles.emptyText}>{error}</Text>;
|
||||
|
||||
if (loading && myGroups.length === 0 && joinedGroups.length === 0 && requests.length === 0) {
|
||||
return <ActivityIndicator size="large" color={colors.primary} style={styles.loader} />;
|
||||
}
|
||||
const renderSkeletons = () => (
|
||||
<View style={styles.skeletonContainer}>
|
||||
{[1, 2, 3].map(i => (
|
||||
<SkeletonLoader key={i} width="100%" height={120} style={{ marginBottom: 16, borderRadius: 16 }} />
|
||||
))}
|
||||
</View>
|
||||
);
|
||||
|
||||
const getFilteredData = () => {
|
||||
switch (activeTab) {
|
||||
case "My Groups":
|
||||
return <FlatList data={myGroups} renderItem={({ item }) => <MyGroupCard item={item} onManage={handleManageGroup} />} keyExtractor={(item) => item.id} ListEmptyComponent={<Text style={styles.emptyText}>You haven't created any groups yet.</Text>} onRefresh={fetchData} refreshing={loading} contentContainerStyle={{ paddingBottom: 100 }} />;
|
||||
case "Joined Groups":
|
||||
return <FlatList data={joinedGroups} renderItem={({ item }) => <JoinedGroupCard item={item} onViewPress={() => {
|
||||
handleViewGroup(item)}} />} keyExtractor={(item) => item.id} ListEmptyComponent={<Text style={styles.emptyText}>You haven't joined any groups yet.</Text>} onRefresh={fetchData} refreshing={loading} contentContainerStyle={{ paddingBottom: 100 }} />;
|
||||
case "Requests":
|
||||
return <FlatList data={requests} renderItem={({ item }) => <RequestCard item={item} onApprove={handleApprove} onDecline={handleDecline} />} keyExtractor={(item) => item.requestId} ListEmptyComponent={<Text style={styles.emptyText}>No pending join requests.</Text>} onRefresh={fetchData} refreshing={loading} contentContainerStyle={{ paddingBottom: 100 }} />;
|
||||
case "Your Requests":
|
||||
return <FlatList data={userRequest} renderItem={({ item }) => <UserRequested item={item} />} keyExtractor={(item) => item.requestId} ListEmptyComponent={<Text style={styles.emptyText}>You haven't sent any join requests.</Text>} onRefresh={fetchData} refreshing={loading} contentContainerStyle={{ paddingBottom: 100 }} />;
|
||||
default: return null;
|
||||
case 'My Groups': return myGroups;
|
||||
case 'Joined Groups': return joinedGroups;
|
||||
case 'Requests': return incomingRequests;
|
||||
case 'Your Requests': return myRequests;
|
||||
default: return [];
|
||||
}
|
||||
};
|
||||
|
||||
const tabs: ActiveTab[] = user.role === 'ORGANIZER' ? ["My Groups", "Joined Groups", "Requests"] : ["Joined Groups", "Your Requests"];
|
||||
const isLoading = myLoading || joinedLoading || requestsLoading || userReqLoading;
|
||||
|
||||
return (
|
||||
<AppView style={styles.container} paddingHorizontal={0}>
|
||||
<AppView paddingHorizontal={0}>
|
||||
<View style={styles.header}>
|
||||
<Text style={styles.title}>Group Management</Text>
|
||||
<Text style={[styles.title, { color: theme.colors.textPrimary }]}>Account Hub</Text>
|
||||
<Text style={[styles.subtitle, { color: theme.colors.textSecondary }]}>Manage your circles and requests</Text>
|
||||
</View>
|
||||
<View style={styles.segmentedControl}>
|
||||
|
||||
<View style={[styles.tabContainer, { backgroundColor: theme.colors.borderLight }]}>
|
||||
{tabs.map((tab) => (
|
||||
<TouchableOpacity key={tab} style={[styles.segmentButton, activeTab === tab && styles.segmentActive]} onPress={() => setActiveTab(tab)}>
|
||||
<Text style={[styles.segmentText, activeTab === tab && styles.segmentTextActive]}>{tab}</Text>
|
||||
<TouchableOpacity
|
||||
key={tab}
|
||||
onPress={() => setActiveTab(tab)}
|
||||
style={[
|
||||
styles.tab,
|
||||
activeTab === tab && { backgroundColor: theme.colors.card, borderRadius: 12, shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1, shadowRadius: 4, elevation: 2 }
|
||||
]}
|
||||
>
|
||||
<Text style={[
|
||||
styles.tabText,
|
||||
{ color: activeTab === tab ? theme.colors.textPrimary : theme.colors.textMuted },
|
||||
activeTab === tab && { fontFamily: FontsFamily.nunitoBold }
|
||||
]}>
|
||||
{tab}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
))}
|
||||
</View>
|
||||
<View style={styles.contentArea}>
|
||||
{renderContent()}
|
||||
</View>
|
||||
|
||||
{user.role === 'ORGANIZER' && activeTab === 'My Groups' && (
|
||||
<View style={styles.statusFilterContainer}>
|
||||
<ScrollView
|
||||
horizontal
|
||||
showsHorizontalScrollIndicator={false}
|
||||
contentContainerStyle={styles.statusFilterRow}
|
||||
>
|
||||
{GROUP_STATUS_FILTERS.map((status, index) => {
|
||||
const isActive = myGroupStatusFilter === status;
|
||||
return (
|
||||
<TouchableOpacity
|
||||
key={status}
|
||||
onPress={() => setMyGroupStatusFilter(status)}
|
||||
style={[
|
||||
styles.statusFilterChip,
|
||||
index !== GROUP_STATUS_FILTERS.length - 1 && styles.statusFilterChipSpaced,
|
||||
{
|
||||
borderColor: isActive ? theme.colors.primary : theme.colors.border,
|
||||
backgroundColor: isActive ? theme.colors.primarySoft : theme.colors.surface,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Text
|
||||
style={[
|
||||
styles.statusFilterText,
|
||||
{
|
||||
color: isActive ? theme.colors.textPrimary : theme.colors.textSecondary,
|
||||
},
|
||||
]}
|
||||
>
|
||||
{status}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
})}
|
||||
</ScrollView>
|
||||
</View>
|
||||
)}
|
||||
|
||||
{activeTab === 'Joined Groups' && (
|
||||
<View style={styles.statusFilterContainer}>
|
||||
<ScrollView
|
||||
horizontal
|
||||
showsHorizontalScrollIndicator={false}
|
||||
contentContainerStyle={styles.statusFilterRow}
|
||||
>
|
||||
{JOINED_GROUP_STATUS_FILTERS.map((status, index) => {
|
||||
const isActive = joinedGroupStatusFilter === status;
|
||||
return (
|
||||
<TouchableOpacity
|
||||
key={status}
|
||||
onPress={() => setJoinedGroupStatusFilter(status)}
|
||||
style={[
|
||||
styles.statusFilterChip,
|
||||
index !== JOINED_GROUP_STATUS_FILTERS.length - 1 && styles.statusFilterChipSpaced,
|
||||
{
|
||||
borderColor: isActive ? theme.colors.primary : theme.colors.border,
|
||||
backgroundColor: isActive ? theme.colors.primarySoft : theme.colors.surface,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Text
|
||||
style={[
|
||||
styles.statusFilterText,
|
||||
{
|
||||
color: isActive ? theme.colors.textPrimary : theme.colors.textSecondary,
|
||||
},
|
||||
]}
|
||||
>
|
||||
{status}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
})}
|
||||
</ScrollView>
|
||||
</View>
|
||||
)}
|
||||
|
||||
<FlatList
|
||||
data={getFilteredData()}
|
||||
contentContainerStyle={styles.listContent}
|
||||
keyExtractor={(item, index) => String(item.id || item.requestId || index)}
|
||||
renderItem={({ item }) => {
|
||||
if (activeTab === 'My Groups') return <MyGroupCard item={item} onManage={handleManageGroup} />;
|
||||
if (activeTab === 'Joined Groups') return <JoinedGroupCard item={item} />;
|
||||
if (activeTab === 'Requests') return <RequestCard item={item} onApprove={handleApprove} onDecline={handleDecline} />;
|
||||
if (activeTab === 'Your Requests') return <UserRequested item={item} />;
|
||||
return null;
|
||||
}}
|
||||
refreshControl={
|
||||
<RefreshControl
|
||||
refreshing={refreshing}
|
||||
onRefresh={onRefresh}
|
||||
colors={[theme.colors.primary]}
|
||||
/>
|
||||
}
|
||||
ListEmptyComponent={
|
||||
!isLoading ? (
|
||||
<View style={styles.emptyState}>
|
||||
<LucideIcon name="documents-outline" size={64} color={theme.colors.textMuted} />
|
||||
<Text style={[styles.emptyText, { color: theme.colors.textSecondary }]}>Nothing to show here</Text>
|
||||
</View>
|
||||
) : renderSkeletons()
|
||||
}
|
||||
/>
|
||||
</AppView>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: { flex: 1, backgroundColor: '#f5f6fa' },
|
||||
header: { paddingHorizontal: 20, paddingBottom: 15, paddingTop: 10 },
|
||||
title: { fontSize: 22, fontWeight: "600"},
|
||||
segmentedControl: { flexDirection: 'row',borderRadius: 10,marginBottom: 20, padding: 3 },
|
||||
segmentButton: { flex: 1, paddingVertical: 12, alignItems: 'center', borderRadius: 8 },
|
||||
segmentActive: { backgroundColor: colors.pastelOrange, elevation: 5,borderRadius:15, shadowColor: '#000', shadowOpacity: 0.1, shadowRadius: 5 },
|
||||
segmentText: { fontSize: 14, fontWeight: '600', color: '#6c757d' },
|
||||
segmentTextActive: { color: colors.textDark },
|
||||
contentArea: { flex: 1},
|
||||
loader: { marginTop: 50 },
|
||||
emptyText: { textAlign: 'center', marginTop: 60, fontSize: 16, color: '#6c757d' },
|
||||
header: {
|
||||
paddingHorizontal: 14,
|
||||
paddingTop: 10,
|
||||
paddingBottom: 12,
|
||||
zIndex: 10,
|
||||
},
|
||||
title: {
|
||||
fontSize: responsiveFontSize(3.2),
|
||||
fontFamily: FontsFamily.nunitoBold,
|
||||
},
|
||||
subtitle: {
|
||||
fontSize: responsiveFontSize(1.6),
|
||||
fontFamily: FontsFamily.nunitoRegular,
|
||||
marginTop: 4,
|
||||
},
|
||||
tabContainer: {
|
||||
flexDirection: 'row',
|
||||
marginHorizontal: 12,
|
||||
padding: 5,
|
||||
borderRadius: 16,
|
||||
marginBottom: 12,
|
||||
zIndex: 10,
|
||||
},
|
||||
tab: {
|
||||
flex: 1,
|
||||
paddingVertical: 10,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
tabText: {
|
||||
fontSize: responsiveFontSize(1.4),
|
||||
fontFamily: FontsFamily.nunitoMedium,
|
||||
},
|
||||
statusFilterContainer: {
|
||||
minHeight: 46,
|
||||
maxHeight: 46,
|
||||
marginBottom: 10,
|
||||
},
|
||||
statusFilterRow: {
|
||||
paddingHorizontal: 12,
|
||||
alignItems: 'center',
|
||||
},
|
||||
statusFilterChip: {
|
||||
borderWidth: 1,
|
||||
borderRadius: 999,
|
||||
minHeight: 34,
|
||||
paddingHorizontal: 14,
|
||||
paddingVertical: 0,
|
||||
justifyContent: 'center',
|
||||
alignSelf: 'center',
|
||||
},
|
||||
statusFilterChipSpaced: {
|
||||
marginRight: 8,
|
||||
},
|
||||
statusFilterText: {
|
||||
fontSize: responsiveFontSize(1.25),
|
||||
fontFamily: FontsFamily.nunitoSemiBold,
|
||||
},
|
||||
listContent: {
|
||||
paddingBottom: 86,
|
||||
},
|
||||
skeletonContainer: {
|
||||
paddingHorizontal: 12,
|
||||
},
|
||||
emptyState: {
|
||||
alignItems: 'center',
|
||||
marginTop: 64,
|
||||
},
|
||||
emptyText: {
|
||||
marginTop: 16,
|
||||
fontSize: responsiveFontSize(1.6),
|
||||
fontFamily: FontsFamily.nunitoMedium,
|
||||
},
|
||||
});
|
||||
|
||||
export default ManagementScreen;
|
||||
|
||||
Reference in New Issue
Block a user