Big improvements on the app

This commit is contained in:
Arthur Belleville 2025-07-18 23:10:09 +02:00
parent 5edc860019
commit 1ab7c2a180
No known key found for this signature in database
11 changed files with 1826 additions and 66 deletions

View file

@ -1,46 +1,112 @@
import { Tabs } from "expo-router";
import React from "react";
import { Platform } from "react-native";
import { HapticTab } from "@/components/HapticTab";
import TabBarBackground from "@/components/ui/TabBarBackground";
import { Colors } from "@/constants/Colors";
import { useColorScheme } from "@/hooks/useColorScheme";
import { MessageCircle, Calendar, User } from "lucide-react-native";
import {
MessageCircle,
Calendar,
List,
Home,
Grid3X3,
} from "lucide-react-native";
export default function TabLayout() {
const colorScheme = useColorScheme();
const isDark = colorScheme === "dark";
return (
<Tabs
screenOptions={{
tabBarActiveTintColor: Colors[colorScheme ?? "light"].tint,
// Colors and theming
tabBarActiveTintColor: "#3b82f6", // Modern blue color
tabBarInactiveTintColor: isDark ? "#9CA3AF" : "#6B7280",
headerShown: false,
tabBarButton: HapticTab,
tabBarBackground: TabBarBackground,
// Enhanced styling
tabBarStyle: {
backgroundColor: isDark ? "#1F2937" : "#FFFFFF",
borderTopWidth: 0,
elevation: 20,
shadowColor: "#000000",
shadowOffset: { width: 0, height: -4 },
shadowOpacity: 0.1,
shadowRadius: 20,
height: Platform.OS === "ios" ? 88 : 70,
paddingTop: 8,
paddingBottom: Platform.OS === "ios" ? 16 : 8,
paddingHorizontal: 12,
borderTopLeftRadius: 24,
borderTopRightRadius: 24,
position: "absolute",
overflow: "hidden",
},
// Label styling
tabBarLabelStyle: {
fontSize: 12,
fontWeight: "600",
marginTop: 4,
marginBottom: Platform.OS === "ios" ? 0 : 4,
},
// Icon styling
tabBarIconStyle: {
marginTop: 2,
},
// Animation and interaction
tabBarHideOnKeyboard: true,
tabBarAllowFontScaling: false,
}}
>
<Tabs.Screen
name="index"
options={{
title: "Discussions",
tabBarIcon: ({ size, color }) => (
<MessageCircle size={size} color={color} />
tabBarIcon: ({ focused, color, size }) => (
<MessageCircle
size={focused ? 24 : 22}
color={color}
strokeWidth={focused ? 2.2 : 2}
/>
),
tabBarLabel: "Discussions",
}}
/>
<Tabs.Screen
name="planning"
options={{
title: "Planning",
tabBarIcon: ({ size, color }) => (
<Calendar size={size} color={color} />
tabBarIcon: ({ focused, color, size }) => (
<Calendar
size={focused ? 24 : 22}
color={color}
strokeWidth={focused ? 2.2 : 2}
/>
),
tabBarLabel: "Planning",
}}
/>
<Tabs.Screen
name="profile"
name="tablos"
options={{
title: "Profile",
tabBarIcon: ({ size, color }) => <User size={size} color={color} />,
title: "Tablos",
tabBarIcon: ({ focused, color, size }) => (
<Grid3X3
size={focused ? 24 : 22}
color={color}
strokeWidth={focused ? 2.2 : 2}
/>
),
tabBarLabel: "Tablos",
// Optional: Add a badge for notifications
tabBarBadge: undefined, // You can set this to a number for notifications
}}
/>
</Tabs>

View file

@ -1,17 +1,384 @@
import { router } from "expo-router";
import { ChannelList } from "stream-chat-expo";
import { useUser } from "@/providers/UserProvider";
import {
View,
Text,
StyleSheet,
TouchableOpacity,
StatusBar,
} from "react-native";
import { LinearGradient } from "expo-linear-gradient";
import { Search } from "lucide-react-native";
import React from "react";
import { useTablosList } from "@/hooks/tablos";
import { ColorMap } from "@/constants/colors";
import { UserTablo } from "@/types/tablos.types";
// Custom Avatar Component for Channel List
const CustomChannelAvatar = ({
channel,
tablos,
}: {
channel: any;
tablos: UserTablo[];
}) => {
const tabloId = channel?.id || "";
const tablo = tablos?.find((t) => t.id === tabloId);
const tabloColor = tablo?.color || "bg-blue-500";
const tabloName = tablo?.name || channel?.data?.name || "Tablo";
// Get members info
const members = channel?.state?.members || {};
const memberCount = Object.keys(members).length;
// Generate initials from tablo name
const getInitials = (name: string) => {
return name
.split(" ")
.map((word) => word.charAt(0))
.join("")
.toUpperCase()
.slice(0, 2);
};
// // Create gradient colors based on tablo color
const getTabloGradientColors = (colorKey: string): [string, string] => {
const baseColor = ColorMap[colorKey] || ColorMap["bg-blue-500"];
// Create a lighter version for gradient effect
const lightenColor = (hex: string, percent: number): string => {
const num = parseInt(hex.replace("#", ""), 16);
const amt = Math.round(2.55 * percent);
const R = Math.min(255, Math.max(0, (num >> 16) + amt));
const G = Math.min(255, Math.max(0, ((num >> 8) & 0x00ff) + amt));
const B = Math.min(255, Math.max(0, (num & 0x0000ff) + amt));
return "#" + ((1 << 24) + (R << 16) + (G << 8) + B).toString(16).slice(1);
};
// Create a darker version for gradient effect
const darkenColor = (hex: string, percent: number): string => {
const num = parseInt(hex.replace("#", ""), 16);
const amt = Math.round(2.55 * percent);
const R = Math.min(255, Math.max(0, (num >> 16) - amt));
const G = Math.min(255, Math.max(0, ((num >> 8) & 0x00ff) - amt));
const B = Math.min(255, Math.max(0, (num & 0x0000ff) - amt));
return "#" + ((1 << 24) + (R << 16) + (G << 8) + B).toString(16).slice(1);
};
const lightColor = lightenColor(baseColor, 15);
const darkColor = darkenColor(baseColor, 10);
return [lightColor, darkColor];
};
const initials = getInitials(tabloName);
const gradientColors = getTabloGradientColors(tabloColor);
return (
<View style={styles.avatarContainer}>
<LinearGradient
colors={gradientColors}
style={styles.avatarGradient}
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 1 }}
>
<Text style={styles.avatarInitials}>{initials}</Text>
{/* Member count indicator for group channels */}
{memberCount > 2 && (
<View style={styles.memberCountBadge}>
<Text style={styles.memberCountText}>{memberCount}</Text>
</View>
)}
</LinearGradient>
{/* Decorative ring */}
<View
style={[
styles.avatarRing,
{ borderColor: `${ColorMap[tabloColor]}30` },
]}
/>
{/* Status indicator (online/active) */}
<View style={styles.statusIndicator} />
</View>
);
};
export default function HomeScreen() {
const user = useUser();
const { data: tablos } = useTablosList();
const filters = { members: { $in: [user.id] }, type: "messaging" };
// Create a wrapper component for the avatar that has access to tablos data
const AvatarWithTablos = ({ channel }: { channel: any }) => (
<CustomChannelAvatar channel={channel} tablos={tablos || []} />
);
return (
<ChannelList
filters={filters}
onSelect={(channel) => {
router.push(`/channel/${channel.cid}`);
}}
/>
<View style={styles.container}>
<StatusBar barStyle="light-content" />
{/* Beautiful Header */}
<LinearGradient
colors={["#1e3a8a", "#3b82f6", "#60a5fa"]}
style={styles.headerGradient}
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 1 }}
>
<View style={styles.headerContent}>
<View style={styles.headerBottom}>
<View style={styles.titleContainer}>
<Text style={styles.headerTitle}>Discussions</Text>
<Text style={styles.headerSubtitle}>
Gérez les conversations de vos tablos
</Text>
</View>
<TouchableOpacity style={styles.searchButton}>
<Search size={20} color="#3b82f6" />
</TouchableOpacity>
</View>
</View>
{/* Decorative Elements
<View style={styles.decorativeCircle1} />
<View style={styles.decorativeCircle2} /> */}
</LinearGradient>
{/* Channel List */}
<View style={styles.channelListContainer}>
<ChannelList
filters={filters}
onSelect={(channel) => {
router.push(`/channel/${channel.cid}`);
}}
PreviewAvatar={AvatarWithTablos}
/>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#f8fafc",
},
headerGradient: {
paddingTop: 50,
paddingBottom: 25,
paddingHorizontal: 20,
position: "relative",
overflow: "hidden",
},
headerContent: {
zIndex: 10,
},
headerTop: {
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
marginBottom: 20,
},
userInfo: {
flexDirection: "row",
alignItems: "center",
flex: 1,
},
avatar: {
marginRight: 12,
shadowColor: "#000",
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.3,
shadowRadius: 4,
elevation: 5,
borderWidth: 3,
borderColor: "rgba(255, 255, 255, 0.3)",
},
greetingContainer: {
flex: 1,
},
greeting: {
fontSize: 16,
color: "rgba(255, 255, 255, 0.9)",
fontWeight: "500",
},
userName: {
fontSize: 20,
color: "white",
fontWeight: "bold",
marginTop: 2,
},
headerActions: {
flexDirection: "row",
alignItems: "center",
gap: 15,
},
actionButton: {
width: 44,
height: 44,
borderRadius: 22,
backgroundColor: "rgba(255, 255, 255, 0.2)",
justifyContent: "center",
alignItems: "center",
position: "relative",
},
notificationBadge: {
position: "absolute",
top: -2,
right: -2,
backgroundColor: "#ef4444",
borderRadius: 10,
minWidth: 20,
height: 20,
justifyContent: "center",
alignItems: "center",
borderWidth: 2,
borderColor: "white",
},
badgeText: {
color: "white",
fontSize: 12,
fontWeight: "bold",
},
headerBottom: {
flexDirection: "row",
justifyContent: "space-between",
alignItems: "flex-end",
},
titleContainer: {
flex: 1,
},
headerTitle: {
fontSize: 28,
color: "white",
fontWeight: "bold",
marginBottom: 4,
},
headerSubtitle: {
fontSize: 16,
color: "rgba(255, 255, 255, 0.8)",
fontWeight: "400",
},
searchButton: {
width: 44,
height: 44,
borderRadius: 22,
backgroundColor: "white",
justifyContent: "center",
alignItems: "center",
shadowColor: "#000",
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.15,
shadowRadius: 8,
elevation: 4,
},
decorativeCircle1: {
position: "absolute",
top: -50,
right: -30,
width: 120,
height: 120,
borderRadius: 60,
backgroundColor: "rgba(255, 255, 255, 0.1)",
},
decorativeCircle2: {
position: "absolute",
bottom: -20,
left: -20,
width: 80,
height: 80,
borderRadius: 40,
backgroundColor: "rgba(255, 255, 255, 0.08)",
},
channelListContainer: {
flex: 1,
backgroundColor: "#f8fafc",
marginTop: -10,
borderTopLeftRadius: 10,
borderTopRightRadius: 10,
paddingTop: 10,
},
// Custom Avatar Styles
avatarContainer: {
position: "relative",
width: 56,
height: 56,
marginRight: 12,
},
avatarGradient: {
width: 56,
height: 56,
borderRadius: 16,
justifyContent: "center",
alignItems: "center",
shadowColor: "#000",
shadowOffset: { width: 0, height: 4 },
shadowOpacity: 0.15,
shadowRadius: 8,
elevation: 6,
position: "relative",
},
avatarInitials: {
fontSize: 18,
fontWeight: "bold",
color: "white",
textShadowColor: "rgba(0, 0, 0, 0.3)",
textShadowOffset: { width: 0, height: 1 },
textShadowRadius: 2,
},
avatarRing: {
position: "absolute",
top: -2,
left: -2,
width: 60,
height: 60,
borderRadius: 18,
borderWidth: 2,
borderColor: "rgba(59, 130, 246, 0.2)",
backgroundColor: "transparent",
},
statusIndicator: {
position: "absolute",
bottom: 2,
right: 2,
width: 16,
height: 16,
borderRadius: 8,
backgroundColor: "#10b981",
borderWidth: 3,
borderColor: "white",
shadowColor: "#000",
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.2,
shadowRadius: 4,
elevation: 3,
},
memberCountBadge: {
position: "absolute",
top: -4,
right: -4,
backgroundColor: "#3b82f6",
borderRadius: 10,
minWidth: 20,
height: 20,
justifyContent: "center",
alignItems: "center",
borderWidth: 2,
borderColor: "white",
shadowColor: "#000",
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.2,
shadowRadius: 4,
elevation: 3,
},
memberCountText: {
color: "white",
fontSize: 11,
fontWeight: "bold",
},
});

View file

@ -30,6 +30,7 @@ import { useEventsByTablo, useCreateEvent } from "@/hooks/events";
import { EventAndTablo, EventInsert } from "@/types/events.types";
import { useTablosList } from "@/hooks/tablos";
import { UserTablo } from "@/types/tablos.types";
import { ColorMap } from "@/constants/colors";
type ViewMode = "month" | "week";
@ -54,7 +55,6 @@ const getDateFormatted = (date: Date) => {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, "0");
const day = String(date.getDate()).padStart(2, "0");
console.log({ year, month, day });
return `${year}-${month}-${day}`;
};
@ -175,23 +175,6 @@ export default function PlanningScreen() {
setShowCreateEventModal(false);
};
const colorMap: Record<string, string> = {
"bg-blue-500": "#3b82f6",
"bg-green-500": "#10b981",
"bg-red-500": "#ef4444",
"bg-yellow-500": "#f59e0b",
"bg-purple-500": "#8b5cf6",
"bg-pink-500": "#ec4899",
"bg-gray-500": "#6b7280",
"bg-orange-500": "#f5100b",
"bg-teal-500": "#0d9488",
"bg-indigo-500": "#6366f1",
"bg-lime-500": "#84cc16",
"bg-emerald-500": "#10b981",
"bg-cyan-500": "#06b6d4",
"bg-fuchsia-500": "#d946ef",
};
const renderTabloOption = ({ item }: { item: UserTablo }) => (
<TouchableOpacity
style={styles.tabloOption}
@ -202,7 +185,7 @@ export default function PlanningScreen() {
style={[
styles.tabloColorDot,
{
backgroundColor: colorMap[item.color ?? "bg-gray-500"],
backgroundColor: ColorMap[item.color ?? "bg-gray-500"],
},
]}
/>
@ -312,7 +295,7 @@ export default function PlanningScreen() {
styles.weekEventCircle,
{
backgroundColor:
colorMap[event.tablo_color ?? "bg-gray-500"],
ColorMap[event.tablo_color ?? "bg-gray-500"],
},
]}
/>
@ -464,7 +447,7 @@ export default function PlanningScreen() {
styles.tabloColorDot,
{
backgroundColor:
colorMap[selectedTablo?.color ?? "bg-gray-500"],
ColorMap[selectedTablo?.color ?? "bg-gray-500"],
},
]}
/>
@ -703,7 +686,7 @@ export default function PlanningScreen() {
styles.tabloColorDot,
{
backgroundColor:
colorMap[item.color ?? "bg-gray-500"],
ColorMap[item.color ?? "bg-gray-500"],
},
]}
/>

File diff suppressed because it is too large Load diff

View file

@ -1,38 +1,192 @@
import { useLocalSearchParams } from "expo-router";
import { useEffect, useState } from "react";
import { ActivityIndicator, SafeAreaView } from "react-native";
import { Channel as ChannelType } from "stream-chat";
import {
ActivityIndicator,
SafeAreaView,
View,
Text,
StyleSheet,
} from "react-native";
import {
Channel,
MessageInput,
MessageList,
useChatContext,
useChannelContext,
} from "stream-chat-expo";
import { MessageCircle, Users, Smile } from "lucide-react-native";
import { useEffect, useState } from "react";
export default function ChannelScreen() {
const [channel, setChannel] = useState<ChannelType | null>(null);
const { cid } = useLocalSearchParams<{ cid: string }>();
const [type, id] = cid.split(":");
const { client } = useChatContext();
const channel = client.channel(type, id);
const [hasMessages, setHasMessages] = useState(false);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
const fetchChannel = async () => {
const channels = await client.queryChannels({ cid });
setChannel(channels[0]);
};
fetchChannel();
}, [cid]);
if (channel) {
const checkMessages = async () => {
try {
// Get channel state to check for messages
await channel.watch();
const messages = channel.state.messages || [];
setHasMessages(messages.length > 0);
} catch (error) {
} finally {
setIsLoading(false);
}
};
checkMessages();
// Listen for new messages
const handleNewMessage = () => {
setHasMessages(true);
};
channel.on("message.new", handleNewMessage);
return () => {
channel.off("message.new", handleNewMessage);
};
}
}, [channel]);
if (!channel) {
return <ActivityIndicator />;
}
const EmptyState = () => (
<View style={styles.emptyContainer}>
<View style={styles.emptyIconContainer}>
<MessageCircle size={64} color="#d1d5db" strokeWidth={1.5} />
<View style={styles.decorativeElements}>
<View style={styles.floatingIcon1}>
<Users size={20} color="#e5e7eb" />
</View>
<View style={styles.floatingIcon2}>
<Smile size={18} color="#e5e7eb" />
</View>
</View>
</View>
<Text style={styles.emptyTitle}>Commencez la conversation</Text>
<Text style={styles.emptyMessage}>
Soyez le premier à envoyer un message dans ce canal !
</Text>
</View>
);
return (
<Channel channel={channel}>
<MessageList />
{isLoading ? (
<View style={styles.loadingContainer}>
<ActivityIndicator size="large" color="#3b82f6" />
<Text style={styles.loadingText}>Chargement des messages...</Text>
</View>
) : hasMessages ? (
<MessageList />
) : (
<EmptyState />
)}
<SafeAreaView>
<MessageInput />
</SafeAreaView>
</Channel>
);
}
const styles = StyleSheet.create({
loadingContainer: {
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#f8fafc",
gap: 16,
},
loadingText: {
fontSize: 16,
color: "#6b7280",
fontWeight: "500",
},
emptyContainer: {
flex: 1,
justifyContent: "center",
alignItems: "center",
paddingHorizontal: 40,
backgroundColor: "#f8fafc",
},
emptyIconContainer: {
position: "relative",
marginBottom: 32,
width: 120,
height: 120,
justifyContent: "center",
alignItems: "center",
},
decorativeElements: {
position: "absolute",
width: "100%",
height: "100%",
},
floatingIcon1: {
position: "absolute",
top: 10,
right: 5,
backgroundColor: "white",
borderRadius: 15,
padding: 6,
shadowColor: "#000",
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
elevation: 2,
},
floatingIcon2: {
position: "absolute",
bottom: 15,
left: 8,
backgroundColor: "white",
borderRadius: 12,
padding: 5,
shadowColor: "#000",
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
elevation: 2,
},
emptyTitle: {
fontSize: 24,
fontWeight: "bold",
color: "#1f2937",
marginBottom: 12,
textAlign: "center",
},
emptyMessage: {
fontSize: 16,
color: "#6b7280",
textAlign: "center",
lineHeight: 24,
marginBottom: 32,
},
emptyHint: {
backgroundColor: "white",
paddingHorizontal: 20,
paddingVertical: 12,
borderRadius: 20,
borderWidth: 1,
borderColor: "#e5e7eb",
shadowColor: "#000",
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.05,
shadowRadius: 4,
elevation: 1,
},
emptyHintText: {
fontSize: 14,
color: "#9ca3af",
fontWeight: "500",
textAlign: "center",
},
});

View file

@ -1,6 +1,70 @@
// This is a shim for web and Android where the tab bar is generally opaque.
export default undefined;
import React from "react";
import { StyleSheet, View } from "react-native";
import { LinearGradient } from "expo-linear-gradient";
import { useColorScheme } from "@/hooks/useColorScheme";
export default function TabBarBackground() {
const colorScheme = useColorScheme();
const isDark = colorScheme === "dark";
return (
<View style={StyleSheet.absoluteFill}>
<LinearGradient
colors={
isDark
? ["#1F2937", "#111827", "#0F172A"]
: ["#FFFFFF", "#F8FAFC", "#F1F5F9"]
}
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 1 }}
style={StyleSheet.absoluteFill}
/>
{/* Subtle top border gradient */}
<LinearGradient
colors={
isDark
? ["rgba(59, 130, 246, 0.3)", "transparent"]
: ["rgba(59, 130, 246, 0.1)", "transparent"]
}
start={{ x: 0, y: 0 }}
end={{ x: 0, y: 1 }}
style={styles.topBorder}
/>
{/* Optional: Add some decorative elements */}
<View
style={[
styles.decorativeCircle,
{
backgroundColor: isDark
? "rgba(59, 130, 246, 0.05)"
: "rgba(59, 130, 246, 0.03)",
},
]}
/>
</View>
);
}
export function useBottomTabOverflow() {
return 0;
return 24; // Account for the rounded corners
}
const styles = StyleSheet.create({
topBorder: {
position: "absolute",
top: 0,
left: 0,
right: 0,
height: 2,
},
decorativeCircle: {
position: "absolute",
top: -20,
right: 20,
width: 80,
height: 80,
borderRadius: 40,
},
});

View file

@ -3,24 +3,50 @@
* There are many other ways to style your app. For example, [Nativewind](https://www.nativewind.dev/), [Tamagui](https://tamagui.dev/), [unistyles](https://reactnativeunistyles.vercel.app), etc.
*/
const tintColorLight = '#0a7ea4';
const tintColorDark = '#fff';
const tintColorLight = "#0a7ea4";
const tintColorDark = "#fff";
export const Colors = {
light: {
text: '#11181C',
background: '#fff',
text: "#11181C",
background: "#fff",
tint: tintColorLight,
icon: '#687076',
tabIconDefault: '#687076',
icon: "#687076",
tabIconDefault: "#687076",
tabIconSelected: tintColorLight,
},
dark: {
text: '#ECEDEE',
background: '#151718',
text: "#ECEDEE",
background: "#151718",
tint: tintColorDark,
icon: '#9BA1A6',
tabIconDefault: '#9BA1A6',
icon: "#9BA1A6",
tabIconDefault: "#9BA1A6",
tabIconSelected: tintColorDark,
},
};
export const AVAILABLE_COLORS = [
"bg-blue-500",
"bg-green-500",
"bg-purple-500",
"bg-red-500",
"bg-yellow-500",
"bg-indigo-500",
"bg-pink-500",
"bg-teal-500",
"bg-orange-500",
"bg-cyan-500",
];
export const ColorMap: Record<(typeof AVAILABLE_COLORS)[number], string> = {
"bg-blue-500": "#3b82f6",
"bg-green-500": "#10b981",
"bg-red-500": "#ef4444",
"bg-yellow-500": "#f59e0b",
"bg-purple-500": "#8b5cf6",
"bg-pink-500": "#ec4899",
"bg-orange-500": "#f97316",
"bg-teal-500": "#0d9488",
"bg-indigo-500": "#6366f1",
"bg-cyan-500": "#06b6d4",
};

View file

@ -0,0 +1,52 @@
/**
* Below are the colors that are used in the app. The colors are defined in the light and dark mode.
* There are many other ways to style your app. For example, [Nativewind](https://www.nativewind.dev/), [Tamagui](https://tamagui.dev/), [unistyles](https://reactnativeunistyles.vercel.app), etc.
*/
const tintColorLight = "#0a7ea4";
const tintColorDark = "#fff";
export const Colors = {
light: {
text: "#11181C",
background: "#fff",
tint: tintColorLight,
icon: "#687076",
tabIconDefault: "#687076",
tabIconSelected: tintColorLight,
},
dark: {
text: "#ECEDEE",
background: "#151718",
tint: tintColorDark,
icon: "#9BA1A6",
tabIconDefault: "#9BA1A6",
tabIconSelected: tintColorDark,
},
};
export const AVAILABLE_COLORS = [
"bg-blue-500",
"bg-green-500",
"bg-purple-500",
"bg-red-500",
"bg-yellow-500",
"bg-indigo-500",
"bg-pink-500",
"bg-teal-500",
"bg-orange-500",
"bg-cyan-500",
];
export const ColorMap: Record<(typeof AVAILABLE_COLORS)[number], string> = {
"bg-blue-500": "#3b82f6",
"bg-green-500": "#10b981",
"bg-red-500": "#ef4444",
"bg-yellow-500": "#f59e0b",
"bg-purple-500": "#8b5cf6",
"bg-pink-500": "#ec4899",
"bg-orange-500": "#f97316",
"bg-teal-500": "#0d9488",
"bg-indigo-500": "#6366f1",
"bg-cyan-500": "#06b6d4",
};

View file

@ -4,6 +4,7 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { TabloInsert, UserTablo } from "@/types/tablos.types";
import { api } from "@/lib/api";
import { useAuth } from "@/stores/auth";
import { Alert } from "react-native";
// type TabloInsert = Tablo["Insert"];
// type TabloUpdate = Tablo["Update"];
@ -22,6 +23,7 @@ export const useTablosList = () => {
const tablos = data as UserTablo[];
return tablos;
},
refetchInterval: 1000 * 60 * 5, // 5 minutes
});
};
@ -44,7 +46,7 @@ export const useCreateTablo = () => {
queryClient.invalidateQueries({ queryKey: ["tablos"] });
},
onError: (error) => {
console.error(error);
Alert.alert("Erreur", "Impossible de créer le tablo.");
},
});
};

View file

@ -3,14 +3,14 @@
* https://docs.expo.dev/guides/color-schemes/
*/
import { Colors } from '@/constants/Colors';
import { useColorScheme } from '@/hooks/useColorScheme';
import { Colors } from "@/constants/colors";
import { useColorScheme } from "@/hooks/useColorScheme";
export function useThemeColor(
props: { light?: string; dark?: string },
colorName: keyof typeof Colors.light & keyof typeof Colors.dark
) {
const theme = useColorScheme() ?? 'light';
const theme = useColorScheme() ?? "light";
const colorFromProps = props[theme];
if (colorFromProps) {