Dark mode
This commit is contained in:
parent
527f4a8fb1
commit
be236b64df
11 changed files with 940 additions and 380 deletions
|
|
@ -16,15 +16,24 @@ import { useTablosList } from "@/hooks/tablos";
|
|||
import { ColorMap } from "@/constants/colors";
|
||||
import { UserTablo } from "@/types/tablos.types";
|
||||
import { SwipeableChannelPreview } from "@/components/SwipeableChannelPreview";
|
||||
import { useThemeColor } from "@/hooks/useThemeColor";
|
||||
import { useColorScheme } from "@/hooks/useColorScheme";
|
||||
|
||||
// Custom Avatar Component for Channel List
|
||||
|
||||
// Custom Title Component for bigger channel names
|
||||
const CustomChannelTitle = ({ channel }: { channel: Channel }) => {
|
||||
const channelName = channel?.data?.name || channel?.id || "Channel";
|
||||
const textColor = useThemeColor(
|
||||
{ light: "#1f2937", dark: "#f9fafb" },
|
||||
"text"
|
||||
);
|
||||
|
||||
return (
|
||||
<Text style={styles.customChannelTitle} numberOfLines={1}>
|
||||
<Text
|
||||
style={[styles.customChannelTitle, { color: textColor }]}
|
||||
numberOfLines={1}
|
||||
>
|
||||
{channelName}
|
||||
</Text>
|
||||
);
|
||||
|
|
@ -45,6 +54,54 @@ const CustomChannelPreview = (
|
|||
export default function HomeScreen() {
|
||||
const user = useUser();
|
||||
const { data: tablos, isLoading } = useTablosList();
|
||||
const colorScheme = useColorScheme();
|
||||
|
||||
// Theme-aware colors
|
||||
const backgroundColor = useThemeColor(
|
||||
{ light: "#f8fafc", dark: "#111827" },
|
||||
"background"
|
||||
);
|
||||
const textColor = useThemeColor(
|
||||
{ light: "#1f2937", dark: "#f9fafb" },
|
||||
"text"
|
||||
);
|
||||
const subtitleColor = useThemeColor(
|
||||
{ light: "#6b7280", dark: "#9ca3af" },
|
||||
"text"
|
||||
);
|
||||
const cardBackgroundColor = useThemeColor(
|
||||
{ light: "#ffffff", dark: "#1f2937" },
|
||||
"background"
|
||||
);
|
||||
const borderColor = colorScheme === "dark" ? "#374151" : "#e5e7eb";
|
||||
const placeholderColor = useThemeColor(
|
||||
{ light: "#9ca3af", dark: "#6b7280" },
|
||||
"text"
|
||||
);
|
||||
const iconColor = useThemeColor(
|
||||
{ light: "#6b7280", dark: "#9ca3af" },
|
||||
"text"
|
||||
);
|
||||
const emptyTextColor = useThemeColor(
|
||||
{ light: "#4b5563", dark: "#d1d5db" },
|
||||
"text"
|
||||
);
|
||||
const emptyIconColor = useThemeColor(
|
||||
{ light: "#d1d5db", dark: "#6b7280" },
|
||||
"text"
|
||||
);
|
||||
|
||||
// Theme-aware gradient colors
|
||||
const gradientColors: [string, string, string] =
|
||||
colorScheme === "dark"
|
||||
? ["#1f2937", "#374151", "#4b5563"]
|
||||
: ["#1e3a8a", "#3b82f6", "#60a5fa"];
|
||||
|
||||
const loadingColors = {
|
||||
container: colorScheme === "dark" ? "#1f2937" : "#f8fafc",
|
||||
item: colorScheme === "dark" ? "#374151" : "#e5e7eb",
|
||||
itemSecondary: colorScheme === "dark" ? "#4b5563" : "#f3f4f6",
|
||||
};
|
||||
|
||||
// const animations = useSharedValue<Record<string, number>>({});
|
||||
|
||||
|
|
@ -179,7 +236,9 @@ export default function HomeScreen() {
|
|||
/>
|
||||
|
||||
{/* Status indicator (online/active) */}
|
||||
<View style={styles.statusIndicator} />
|
||||
<View
|
||||
style={[styles.statusIndicator, { borderColor: cardBackgroundColor }]}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
|
@ -289,12 +348,15 @@ export default function HomeScreen() {
|
|||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<StatusBar barStyle="light-content" />
|
||||
<View style={[styles.container, { backgroundColor }]}>
|
||||
<StatusBar
|
||||
barStyle={colorScheme === "dark" ? "light-content" : "light-content"}
|
||||
backgroundColor={gradientColors[0]}
|
||||
/>
|
||||
|
||||
{/* Loading Header */}
|
||||
<LinearGradient
|
||||
colors={["#1e3a8a", "#3b82f6", "#60a5fa"]}
|
||||
colors={gradientColors}
|
||||
style={styles.headerGradient}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 1 }}
|
||||
|
|
@ -316,14 +378,34 @@ export default function HomeScreen() {
|
|||
</LinearGradient>
|
||||
|
||||
{/* Loading Content */}
|
||||
<View style={styles.loadingContentContainer}>
|
||||
<View
|
||||
style={[
|
||||
styles.loadingContentContainer,
|
||||
{ backgroundColor: loadingColors.container },
|
||||
]}
|
||||
>
|
||||
{/* Loading Skeleton Items */}
|
||||
{[1, 2, 3, 4, 5].map((item) => (
|
||||
<View key={item} style={styles.loadingItem}>
|
||||
<View style={styles.loadingAvatar} />
|
||||
<View
|
||||
style={[
|
||||
styles.loadingAvatar,
|
||||
{ backgroundColor: loadingColors.item },
|
||||
]}
|
||||
/>
|
||||
<View style={styles.loadingTextContainer}>
|
||||
<View style={styles.loadingTitle} />
|
||||
<View style={styles.loadingSubtitle} />
|
||||
<View
|
||||
style={[
|
||||
styles.loadingTitle,
|
||||
{ backgroundColor: loadingColors.item },
|
||||
]}
|
||||
/>
|
||||
<View
|
||||
style={[
|
||||
styles.loadingSubtitle,
|
||||
{ backgroundColor: loadingColors.itemSecondary },
|
||||
]}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
))}
|
||||
|
|
@ -333,12 +415,15 @@ export default function HomeScreen() {
|
|||
}
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<StatusBar barStyle="light-content" />
|
||||
<View style={[styles.container, { backgroundColor }]}>
|
||||
<StatusBar
|
||||
barStyle={colorScheme === "dark" ? "light-content" : "light-content"}
|
||||
backgroundColor={gradientColors[0]}
|
||||
/>
|
||||
|
||||
{/* Beautiful Header */}
|
||||
<LinearGradient
|
||||
colors={["#1e3a8a", "#3b82f6", "#60a5fa"]}
|
||||
colors={gradientColors}
|
||||
style={styles.headerGradient}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 1 }}
|
||||
|
|
@ -374,7 +459,7 @@ export default function HomeScreen() {
|
|||
</LinearGradient>
|
||||
|
||||
{/* Channel List with animated search */}
|
||||
<View style={styles.channelListContainer}>
|
||||
<View style={[styles.channelListContainer, { backgroundColor }]}>
|
||||
{/* <SearchHeader /> */}
|
||||
<ChannelList
|
||||
filters={filters}
|
||||
|
|
@ -409,7 +494,9 @@ export default function HomeScreen() {
|
|||
// Show loading state during search
|
||||
LoadingIndicator={() => (
|
||||
<View style={styles.searchLoadingContainer}>
|
||||
<Text style={styles.searchLoadingText}>
|
||||
<Text
|
||||
style={[styles.searchLoadingText, { color: subtitleColor }]}
|
||||
>
|
||||
{/* {debouncedSearchQuery
|
||||
? "Recherche en cours..."
|
||||
: "Chargement..."} */}
|
||||
|
|
@ -420,14 +507,18 @@ export default function HomeScreen() {
|
|||
// Show empty state when no results
|
||||
EmptyStateIndicator={() => (
|
||||
<View style={styles.emptySearchContainer}>
|
||||
<Search size={48} color="#d1d5db" />
|
||||
<Text style={styles.emptySearchTitle}>
|
||||
<Search size={48} color={emptyIconColor} />
|
||||
<Text
|
||||
style={[styles.emptySearchTitle, { color: emptyTextColor }]}
|
||||
>
|
||||
{/* {debouncedSearchQuery
|
||||
? "Aucun résultat"
|
||||
: "Aucune conversation"} */}
|
||||
Aucune conversation
|
||||
</Text>
|
||||
<Text style={styles.emptySearchMessage}>
|
||||
<Text
|
||||
style={[styles.emptySearchMessage, { color: subtitleColor }]}
|
||||
>
|
||||
{/* {debouncedSearchQuery
|
||||
? `Aucune conversation trouvée pour "${debouncedSearchQuery}"`
|
||||
: "Vous n'avez pas encore de conversations"} */}
|
||||
|
|
@ -444,7 +535,7 @@ export default function HomeScreen() {
|
|||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: "#f8fafc",
|
||||
// backgroundColor is set dynamically
|
||||
},
|
||||
headerGradient: {
|
||||
paddingTop: 50,
|
||||
|
|
@ -575,7 +666,7 @@ const styles = StyleSheet.create({
|
|||
},
|
||||
channelListContainer: {
|
||||
flex: 1,
|
||||
backgroundColor: "#f8fafc",
|
||||
// backgroundColor is set dynamically
|
||||
marginTop: -10,
|
||||
borderTopLeftRadius: 10,
|
||||
borderTopRightRadius: 10,
|
||||
|
|
@ -630,7 +721,7 @@ const styles = StyleSheet.create({
|
|||
borderRadius: 8,
|
||||
backgroundColor: "#10b981",
|
||||
borderWidth: 3,
|
||||
borderColor: "white",
|
||||
// borderColor is set dynamically to match background
|
||||
shadowColor: "#000",
|
||||
shadowOffset: { width: 0, height: 2 },
|
||||
shadowOpacity: 0.2,
|
||||
|
|
@ -664,26 +755,26 @@ const styles = StyleSheet.create({
|
|||
customChannelTitle: {
|
||||
fontSize: 18,
|
||||
fontWeight: "bold",
|
||||
color: "#1f2937",
|
||||
// color is set dynamically
|
||||
},
|
||||
|
||||
// Search Header Styles
|
||||
searchHeaderContainer: {
|
||||
backgroundColor: "#f8fafc",
|
||||
// backgroundColor is set dynamically
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: "#e5e7eb",
|
||||
// borderBottomColor is set dynamically
|
||||
overflow: "hidden",
|
||||
paddingHorizontal: 20,
|
||||
},
|
||||
searchInputContainer: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
backgroundColor: "white",
|
||||
// backgroundColor is set dynamically
|
||||
borderRadius: 8,
|
||||
paddingHorizontal: 12,
|
||||
paddingVertical: 8,
|
||||
borderWidth: 1,
|
||||
borderColor: "#e5e7eb",
|
||||
// borderColor is set dynamically
|
||||
marginTop: 15,
|
||||
},
|
||||
searchIcon: {
|
||||
|
|
@ -692,7 +783,7 @@ const styles = StyleSheet.create({
|
|||
searchInput: {
|
||||
flex: 1,
|
||||
fontSize: 16,
|
||||
color: "#374151",
|
||||
// color is set dynamically
|
||||
paddingVertical: 0,
|
||||
fontWeight: "500",
|
||||
},
|
||||
|
|
@ -705,7 +796,7 @@ const styles = StyleSheet.create({
|
|||
},
|
||||
searchInfoText: {
|
||||
fontSize: 14,
|
||||
color: "#6b7280",
|
||||
// color is set dynamically
|
||||
},
|
||||
searchLoadingContainer: {
|
||||
paddingVertical: 20,
|
||||
|
|
@ -713,7 +804,7 @@ const styles = StyleSheet.create({
|
|||
},
|
||||
searchLoadingText: {
|
||||
fontSize: 16,
|
||||
color: "#6b7280",
|
||||
// color is set dynamically
|
||||
},
|
||||
emptySearchContainer: {
|
||||
paddingVertical: 40,
|
||||
|
|
@ -721,12 +812,12 @@ const styles = StyleSheet.create({
|
|||
},
|
||||
emptySearchTitle: {
|
||||
fontSize: 20,
|
||||
color: "#4b5563",
|
||||
// color is set dynamically
|
||||
marginTop: 10,
|
||||
},
|
||||
emptySearchMessage: {
|
||||
fontSize: 16,
|
||||
color: "#6b7280",
|
||||
// color is set dynamically
|
||||
marginTop: 5,
|
||||
textAlign: "center",
|
||||
paddingHorizontal: 20,
|
||||
|
|
@ -735,7 +826,7 @@ const styles = StyleSheet.create({
|
|||
// Loading Skeleton Styles
|
||||
loadingContentContainer: {
|
||||
flex: 1,
|
||||
backgroundColor: "#f8fafc",
|
||||
// backgroundColor is set dynamically
|
||||
marginTop: -10,
|
||||
borderTopLeftRadius: 10,
|
||||
borderTopRightRadius: 10,
|
||||
|
|
@ -752,7 +843,7 @@ const styles = StyleSheet.create({
|
|||
width: 56,
|
||||
height: 56,
|
||||
borderRadius: 16,
|
||||
backgroundColor: "#e5e7eb",
|
||||
// backgroundColor is set dynamically
|
||||
marginRight: 12,
|
||||
},
|
||||
loadingTextContainer: {
|
||||
|
|
@ -760,14 +851,14 @@ const styles = StyleSheet.create({
|
|||
},
|
||||
loadingTitle: {
|
||||
height: 20,
|
||||
backgroundColor: "#e5e7eb",
|
||||
// backgroundColor is set dynamically
|
||||
borderRadius: 4,
|
||||
marginBottom: 8,
|
||||
width: "70%",
|
||||
},
|
||||
loadingSubtitle: {
|
||||
height: 16,
|
||||
backgroundColor: "#f3f4f6",
|
||||
// backgroundColor is set dynamically
|
||||
borderRadius: 4,
|
||||
width: "50%",
|
||||
},
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ import { EventAndTablo, EventInsert } from "@/types/events.types";
|
|||
import { useTablosList } from "@/hooks/tablos";
|
||||
import { UserTablo } from "@/types/tablos.types";
|
||||
import { ColorMap } from "@/constants/colors";
|
||||
import { useThemeColor } from "@/hooks/useThemeColor";
|
||||
import { useColorScheme } from "@/hooks/useColorScheme";
|
||||
|
||||
type ViewMode = "month" | "week";
|
||||
|
||||
|
|
@ -74,6 +76,33 @@ export default function PlanningScreen() {
|
|||
const { data: events } = useEventsByTablo(null);
|
||||
const { data: tablos } = useTablosList();
|
||||
const createEvent = useCreateEvent();
|
||||
const colorScheme = useColorScheme();
|
||||
|
||||
// Theme-aware colors
|
||||
const backgroundColor = useThemeColor(
|
||||
{ light: "#f8fafc", dark: "#111827" },
|
||||
"background"
|
||||
);
|
||||
const cardBackgroundColor = useThemeColor(
|
||||
{ light: "#ffffff", dark: "#1f2937" },
|
||||
"background"
|
||||
);
|
||||
const textColor = useThemeColor(
|
||||
{ light: "#1f2937", dark: "#f9fafb" },
|
||||
"text"
|
||||
);
|
||||
const subtitleColor = useThemeColor(
|
||||
{ light: "#6b7280", dark: "#9ca3af" },
|
||||
"text"
|
||||
);
|
||||
const borderColor = colorScheme === "dark" ? "#374151" : "#e5e7eb";
|
||||
const modalOverlayColor =
|
||||
colorScheme === "dark" ? "rgba(0, 0, 0, 0.8)" : "rgba(0, 0, 0, 0.5)";
|
||||
const inactiveDayColor = colorScheme === "dark" ? "#4b5563" : "#d1d5db";
|
||||
const emptyIconColor = colorScheme === "dark" ? "#6b7280" : "#d1d5db";
|
||||
const viewModeToggleColor = colorScheme === "dark" ? "#374151" : "#f3f4f6";
|
||||
const weekHeaderBorderColor = colorScheme === "dark" ? "#374151" : "#e5e7eb";
|
||||
const selectedOptionBgColor = colorScheme === "dark" ? "#1e3a8a" : "#eff6ff";
|
||||
|
||||
const filteredEvents: EventAndTablo[] =
|
||||
(selectedTablo === null
|
||||
|
|
@ -176,7 +205,7 @@ export default function PlanningScreen() {
|
|||
|
||||
const renderTabloOption = ({ item }: { item: UserTablo }) => (
|
||||
<TouchableOpacity
|
||||
style={styles.tabloOption}
|
||||
style={[styles.tabloOption, { borderBottomColor: borderColor }]}
|
||||
onPress={() => selectTablo(item)}
|
||||
>
|
||||
<View style={styles.tabloOptionLeft}>
|
||||
|
|
@ -189,7 +218,9 @@ export default function PlanningScreen() {
|
|||
]}
|
||||
/>
|
||||
<View style={styles.tabloOptionContent}>
|
||||
<Text style={styles.tabloOptionName}>{item.name}</Text>
|
||||
<Text style={[styles.tabloOptionName, { color: textColor }]}>
|
||||
{item.name}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
{selectedTablo?.id === item.id && <Check size={20} color="#3b82f6" />}
|
||||
|
|
@ -197,22 +228,31 @@ export default function PlanningScreen() {
|
|||
);
|
||||
|
||||
const renderEvent = ({ item }: { item: EventAndTablo }) => (
|
||||
<TouchableOpacity style={styles.eventCard}>
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.eventCard,
|
||||
{ backgroundColor: cardBackgroundColor, borderColor },
|
||||
]}
|
||||
>
|
||||
<View
|
||||
style={[styles.eventColorBar, { backgroundColor: item.tablo_color }]}
|
||||
/>
|
||||
<View style={styles.eventContent}>
|
||||
<Text style={styles.eventTitle}>{item.title}</Text>
|
||||
<Text style={[styles.eventTitle, { color: textColor }]}>
|
||||
{item.title}
|
||||
</Text>
|
||||
<View style={styles.eventDetails}>
|
||||
<View style={styles.eventDetailItem}>
|
||||
<Clock size={14} color="#6b7280" />
|
||||
<Text style={styles.eventDetailText}>
|
||||
<Clock size={14} color={subtitleColor} />
|
||||
<Text style={[styles.eventDetailText, { color: subtitleColor }]}>
|
||||
{item.start_time?.substring(0, 5)}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={styles.eventDetailItem}>
|
||||
<MapPin size={14} color="#6b7280" />
|
||||
<Text style={styles.eventDetailText}>{item.tablo_name}</Text>
|
||||
<MapPin size={14} color={subtitleColor} />
|
||||
<Text style={[styles.eventDetailText, { color: subtitleColor }]}>
|
||||
{item.tablo_name}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
|
@ -233,7 +273,8 @@ export default function PlanningScreen() {
|
|||
<Text
|
||||
style={[
|
||||
styles.dayText,
|
||||
!isCurrentMonth(date) && styles.inactiveDayText,
|
||||
{ color: textColor },
|
||||
!isCurrentMonth(date) && { color: inactiveDayColor },
|
||||
isSelected(date) && styles.selectedDayText,
|
||||
isToday(date) && !isSelected(date) && styles.todayDayText,
|
||||
]}
|
||||
|
|
@ -252,6 +293,7 @@ export default function PlanningScreen() {
|
|||
<TouchableOpacity
|
||||
style={[
|
||||
styles.weekDayHeader,
|
||||
{ backgroundColor: cardBackgroundColor },
|
||||
isToday(date) && styles.todayWeekDay,
|
||||
isSelected(date) && styles.selectedWeekDay,
|
||||
isToday(date) && isSelected(date) && styles.todaySelectedWeekDay,
|
||||
|
|
@ -261,6 +303,7 @@ export default function PlanningScreen() {
|
|||
<Text
|
||||
style={[
|
||||
styles.weekDayName,
|
||||
{ color: subtitleColor },
|
||||
isSelected(date) && { color: "white" },
|
||||
isToday(date) && isSelected(date) && { color: "white" },
|
||||
]}
|
||||
|
|
@ -270,6 +313,7 @@ export default function PlanningScreen() {
|
|||
<Text
|
||||
style={[
|
||||
styles.weekDayNumber,
|
||||
{ color: textColor },
|
||||
isSelected(date) && styles.selectedWeekDayText,
|
||||
isToday(date) && !isSelected(date) && styles.todayWeekDayText,
|
||||
isToday(date) &&
|
||||
|
|
@ -300,8 +344,15 @@ export default function PlanningScreen() {
|
|||
/>
|
||||
))}
|
||||
{dayEvents.length > 6 && (
|
||||
<View style={styles.weekEventMoreCircle}>
|
||||
<Text style={styles.weekEventMoreText}>
|
||||
<View
|
||||
style={[
|
||||
styles.weekEventMoreCircle,
|
||||
{ backgroundColor: borderColor },
|
||||
]}
|
||||
>
|
||||
<Text
|
||||
style={[styles.weekEventMoreText, { color: subtitleColor }]}
|
||||
>
|
||||
+{dayEvents.length - 6}
|
||||
</Text>
|
||||
</View>
|
||||
|
|
@ -318,14 +369,16 @@ export default function PlanningScreen() {
|
|||
return (
|
||||
<View style={styles.selectedDayEventsContainer}>
|
||||
<View style={styles.selectedDayHeader}>
|
||||
<Text style={styles.selectedDayTitle}>
|
||||
<Text style={[styles.selectedDayTitle, { color: textColor }]}>
|
||||
{selectedDate.toLocaleDateString("fr-FR", {
|
||||
weekday: "long",
|
||||
day: "numeric",
|
||||
month: "long",
|
||||
})}
|
||||
</Text>
|
||||
<Text style={styles.selectedDayEventsCount}>
|
||||
<Text
|
||||
style={[styles.selectedDayEventsCount, { color: subtitleColor }]}
|
||||
>
|
||||
{selectedDayEvents.length} événement
|
||||
{selectedDayEvents.length > 1 ? "s" : ""}
|
||||
</Text>
|
||||
|
|
@ -342,9 +395,11 @@ export default function PlanningScreen() {
|
|||
/>
|
||||
) : (
|
||||
<View style={styles.selectedDayEmptyState}>
|
||||
<CalendarIcon size={40} color="#d1d5db" />
|
||||
<Text style={styles.emptyStateTitle}>Aucun événement</Text>
|
||||
<Text style={styles.emptyStateText}>
|
||||
<CalendarIcon size={40} color={emptyIconColor} />
|
||||
<Text style={[styles.emptyStateTitle, { color: textColor }]}>
|
||||
Aucun événement
|
||||
</Text>
|
||||
<Text style={[styles.emptyStateText, { color: subtitleColor }]}>
|
||||
Vous n'avez aucun événement prévu pour cette date.
|
||||
</Text>
|
||||
</View>
|
||||
|
|
@ -358,12 +413,17 @@ export default function PlanningScreen() {
|
|||
const todayEvents = getEventsForDate(selectedDate);
|
||||
|
||||
return (
|
||||
<ScrollView style={styles.container} showsVerticalScrollIndicator={false}>
|
||||
<ScrollView
|
||||
style={[styles.container, { backgroundColor }]}
|
||||
showsVerticalScrollIndicator={false}
|
||||
>
|
||||
{/* Header */}
|
||||
<View style={styles.header}>
|
||||
<View>
|
||||
<Text style={styles.headerTitle}>Planning</Text>
|
||||
<Text style={styles.headerSubtitle}>
|
||||
<Text style={[styles.headerTitle, { color: textColor }]}>
|
||||
Planning
|
||||
</Text>
|
||||
<Text style={[styles.headerSubtitle, { color: subtitleColor }]}>
|
||||
{viewMode === "month"
|
||||
? months[currentMonth.getMonth()] +
|
||||
" " +
|
||||
|
|
@ -386,7 +446,12 @@ export default function PlanningScreen() {
|
|||
|
||||
{/* View Mode Toggle */}
|
||||
<View style={styles.viewModeContainer}>
|
||||
<View style={styles.viewModeToggle}>
|
||||
<View
|
||||
style={[
|
||||
styles.viewModeToggle,
|
||||
{ backgroundColor: viewModeToggleColor },
|
||||
]}
|
||||
>
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.viewModeButton,
|
||||
|
|
@ -396,11 +461,12 @@ export default function PlanningScreen() {
|
|||
>
|
||||
<Grid3x3
|
||||
size={18}
|
||||
color={viewMode === "month" ? "white" : "#6b7280"}
|
||||
color={viewMode === "month" ? "white" : subtitleColor}
|
||||
/>
|
||||
<Text
|
||||
style={[
|
||||
styles.viewModeText,
|
||||
{ color: viewMode === "month" ? "white" : subtitleColor },
|
||||
viewMode === "month" && styles.activeViewModeText,
|
||||
]}
|
||||
>
|
||||
|
|
@ -416,11 +482,12 @@ export default function PlanningScreen() {
|
|||
>
|
||||
<Rows3
|
||||
size={18}
|
||||
color={viewMode === "week" ? "white" : "#6b7280"}
|
||||
color={viewMode === "week" ? "white" : subtitleColor}
|
||||
/>
|
||||
<Text
|
||||
style={[
|
||||
styles.viewModeText,
|
||||
{ color: viewMode === "week" ? "white" : subtitleColor },
|
||||
viewMode === "week" && styles.activeViewModeText,
|
||||
]}
|
||||
>
|
||||
|
|
@ -433,13 +500,20 @@ export default function PlanningScreen() {
|
|||
{/* Tablo Selector */}
|
||||
<View style={styles.tabloSelectorContainer}>
|
||||
<TouchableOpacity
|
||||
style={styles.tabloSelector}
|
||||
style={[
|
||||
styles.tabloSelector,
|
||||
{ backgroundColor: cardBackgroundColor, borderColor },
|
||||
]}
|
||||
onPress={() => setShowTabloSelector(true)}
|
||||
>
|
||||
<View style={styles.tabloSelectorLeft}>
|
||||
<Table size={20} color="#6b7280" />
|
||||
<Table size={20} color={subtitleColor} />
|
||||
<View style={styles.tabloSelectorContent}>
|
||||
<Text style={styles.tabloSelectorLabel}>Tablo actuel</Text>
|
||||
<Text
|
||||
style={[styles.tabloSelectorLabel, { color: subtitleColor }]}
|
||||
>
|
||||
Tablo actuel
|
||||
</Text>
|
||||
<View style={styles.tabloSelectorRow}>
|
||||
<View
|
||||
style={[
|
||||
|
|
@ -447,22 +521,27 @@ export default function PlanningScreen() {
|
|||
{
|
||||
backgroundColor: selectedTablo?.color
|
||||
? ColorMap[selectedTablo.color]
|
||||
: "#6b7280",
|
||||
: subtitleColor,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<Text style={styles.tabloSelectorName}>
|
||||
<Text style={[styles.tabloSelectorName, { color: textColor }]}>
|
||||
{selectedTablo?.name ?? "Tous les tablos"}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
<ChevronDown size={20} color="#6b7280" />
|
||||
<ChevronDown size={20} color={subtitleColor} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{/* Calendar/Week View */}
|
||||
<Card containerStyle={styles.calendarCard}>
|
||||
<Card
|
||||
containerStyle={[
|
||||
styles.calendarCard,
|
||||
{ backgroundColor: cardBackgroundColor },
|
||||
]}
|
||||
>
|
||||
<View style={styles.calendarHeader}>
|
||||
<TouchableOpacity
|
||||
onPress={() =>
|
||||
|
|
@ -473,7 +552,7 @@ export default function PlanningScreen() {
|
|||
>
|
||||
<ChevronLeft size={24} color="#3b82f6" />
|
||||
</TouchableOpacity>
|
||||
<Text style={styles.calendarTitle}>
|
||||
<Text style={[styles.calendarTitle, { color: textColor }]}>
|
||||
{viewMode === "month"
|
||||
? `${
|
||||
months[currentMonth.getMonth()]
|
||||
|
|
@ -495,9 +574,17 @@ export default function PlanningScreen() {
|
|||
|
||||
{viewMode === "month" ? (
|
||||
<>
|
||||
<View style={styles.weekHeader}>
|
||||
<View
|
||||
style={[
|
||||
styles.weekHeader,
|
||||
{ borderBottomColor: weekHeaderBorderColor },
|
||||
]}
|
||||
>
|
||||
{daysOfWeek.map((day, i) => (
|
||||
<Text key={`${day}-${i}`} style={styles.weekDay}>
|
||||
<Text
|
||||
key={`${day}-${i}`}
|
||||
style={[styles.weekDay, { color: subtitleColor }]}
|
||||
>
|
||||
{day}
|
||||
</Text>
|
||||
))}
|
||||
|
|
@ -524,7 +611,7 @@ export default function PlanningScreen() {
|
|||
<View style={styles.eventsSection}>
|
||||
<View style={styles.eventsSectionHeader}>
|
||||
<CalendarIcon size={20} color="#3b82f6" />
|
||||
<Text style={styles.eventsSectionTitle}>
|
||||
<Text style={[styles.eventsSectionTitle, { color: textColor }]}>
|
||||
Événements du jour ({todayEvents.length})
|
||||
</Text>
|
||||
</View>
|
||||
|
|
@ -539,9 +626,11 @@ export default function PlanningScreen() {
|
|||
/>
|
||||
) : (
|
||||
<View style={styles.selectedDayEmptyState}>
|
||||
<CalendarIcon size={40} color="#d1d5db" />
|
||||
<Text style={styles.emptyStateTitle}>Aucun événement</Text>
|
||||
<Text style={styles.emptyStateText}>
|
||||
<CalendarIcon size={40} color={emptyIconColor} />
|
||||
<Text style={[styles.emptyStateTitle, { color: textColor }]}>
|
||||
Aucun événement
|
||||
</Text>
|
||||
<Text style={[styles.emptyStateText, { color: subtitleColor }]}>
|
||||
Vous n'avez aucun événement prévu pour cette date.
|
||||
</Text>
|
||||
</View>
|
||||
|
|
@ -557,13 +646,22 @@ export default function PlanningScreen() {
|
|||
onRequestClose={() => setShowTabloSelector(false)}
|
||||
>
|
||||
<TouchableOpacity
|
||||
style={styles.modalOverlay}
|
||||
style={[styles.modalOverlay, { backgroundColor: modalOverlayColor }]}
|
||||
activeOpacity={1}
|
||||
onPress={() => setShowTabloSelector(false)}
|
||||
>
|
||||
<View style={styles.modalContent}>
|
||||
<View style={styles.modalHeader}>
|
||||
<Text style={styles.modalTitle}>Choisir un tablo</Text>
|
||||
<View
|
||||
style={[
|
||||
styles.modalContent,
|
||||
{ backgroundColor: cardBackgroundColor, borderColor },
|
||||
]}
|
||||
>
|
||||
<View
|
||||
style={[styles.modalHeader, { borderBottomColor: borderColor }]}
|
||||
>
|
||||
<Text style={[styles.modalTitle, { color: textColor }]}>
|
||||
Choisir un tablo
|
||||
</Text>
|
||||
</View>
|
||||
<FlatList
|
||||
data={tablos ?? []}
|
||||
|
|
@ -572,7 +670,10 @@ export default function PlanningScreen() {
|
|||
showsVerticalScrollIndicator={false}
|
||||
ListHeaderComponent={
|
||||
<TouchableOpacity
|
||||
style={styles.tabloOption}
|
||||
style={[
|
||||
styles.tabloOption,
|
||||
{ borderBottomColor: borderColor },
|
||||
]}
|
||||
onPress={() => selectTablo(null)}
|
||||
>
|
||||
<View style={styles.tabloOptionLeft}>
|
||||
|
|
@ -580,12 +681,14 @@ export default function PlanningScreen() {
|
|||
style={[
|
||||
styles.tabloColorDot,
|
||||
{
|
||||
backgroundColor: "#6b7280",
|
||||
backgroundColor: subtitleColor,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<View style={styles.tabloOptionContent}>
|
||||
<Text style={styles.tabloOptionName}>
|
||||
<Text
|
||||
style={[styles.tabloOptionName, { color: textColor }]}
|
||||
>
|
||||
Tous les tablos
|
||||
</Text>
|
||||
</View>
|
||||
|
|
@ -606,15 +709,34 @@ export default function PlanningScreen() {
|
|||
animationType="slide"
|
||||
onRequestClose={() => setShowCreateEventModal(false)}
|
||||
>
|
||||
<View style={styles.createEventModalOverlay}>
|
||||
<View style={styles.createEventModalContent}>
|
||||
<View style={styles.createEventModalHeader}>
|
||||
<Text style={styles.createEventModalTitle}>Nouvel événement</Text>
|
||||
<View
|
||||
style={[
|
||||
styles.createEventModalOverlay,
|
||||
{ backgroundColor: modalOverlayColor },
|
||||
]}
|
||||
>
|
||||
<View
|
||||
style={[
|
||||
styles.createEventModalContent,
|
||||
{ backgroundColor: cardBackgroundColor },
|
||||
]}
|
||||
>
|
||||
<View
|
||||
style={[
|
||||
styles.createEventModalHeader,
|
||||
{ borderBottomColor: borderColor },
|
||||
]}
|
||||
>
|
||||
<Text
|
||||
style={[styles.createEventModalTitle, { color: textColor }]}
|
||||
>
|
||||
Nouvel événement
|
||||
</Text>
|
||||
<TouchableOpacity
|
||||
onPress={() => setShowCreateEventModal(false)}
|
||||
style={styles.createEventCloseButton}
|
||||
>
|
||||
<X size={24} color="#6b7280" />
|
||||
<X size={24} color={subtitleColor} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
|
|
@ -624,57 +746,92 @@ export default function PlanningScreen() {
|
|||
>
|
||||
{/* Title Field */}
|
||||
<View style={styles.formField}>
|
||||
<Text style={styles.formLabel}>Titre *</Text>
|
||||
<Text style={[styles.formLabel, { color: subtitleColor }]}>
|
||||
Titre *
|
||||
</Text>
|
||||
<TextInput
|
||||
style={styles.formInput}
|
||||
style={[
|
||||
styles.formInput,
|
||||
{
|
||||
backgroundColor: cardBackgroundColor,
|
||||
borderColor,
|
||||
color: textColor,
|
||||
},
|
||||
]}
|
||||
value={newEvent.title}
|
||||
onChangeText={(text) =>
|
||||
setNewEvent({ ...newEvent, title: text })
|
||||
}
|
||||
placeholder="Titre de l'événement"
|
||||
placeholderTextColor="#9ca3af"
|
||||
placeholderTextColor={subtitleColor}
|
||||
/>
|
||||
</View>
|
||||
|
||||
{/* Date Field */}
|
||||
<View style={styles.formField}>
|
||||
<Text style={styles.formLabel}>Date</Text>
|
||||
<Text style={[styles.formLabel, { color: subtitleColor }]}>
|
||||
Date
|
||||
</Text>
|
||||
<TextInput
|
||||
style={styles.formInput}
|
||||
style={[
|
||||
styles.formInput,
|
||||
{
|
||||
backgroundColor: cardBackgroundColor,
|
||||
borderColor,
|
||||
color: textColor,
|
||||
},
|
||||
]}
|
||||
value={newEvent.start_date}
|
||||
onChangeText={(text) =>
|
||||
setNewEvent({ ...newEvent, start_date: text })
|
||||
}
|
||||
placeholder="YYYY-MM-DD"
|
||||
placeholderTextColor="#9ca3af"
|
||||
placeholderTextColor={subtitleColor}
|
||||
/>
|
||||
</View>
|
||||
|
||||
{/* Time Field */}
|
||||
<View style={styles.formField}>
|
||||
<Text style={styles.formLabel}>Heure</Text>
|
||||
<Text style={[styles.formLabel, { color: subtitleColor }]}>
|
||||
Heure
|
||||
</Text>
|
||||
<TextInput
|
||||
style={styles.formInput}
|
||||
style={[
|
||||
styles.formInput,
|
||||
{
|
||||
backgroundColor: cardBackgroundColor,
|
||||
borderColor,
|
||||
color: textColor,
|
||||
},
|
||||
]}
|
||||
value={newEvent.start_time}
|
||||
onChangeText={(text) =>
|
||||
setNewEvent({ ...newEvent, start_time: text })
|
||||
}
|
||||
placeholder="HH:MM"
|
||||
placeholderTextColor="#9ca3af"
|
||||
placeholderTextColor={subtitleColor}
|
||||
/>
|
||||
</View>
|
||||
|
||||
{/* Tablo Selector */}
|
||||
<View style={styles.formField}>
|
||||
<Text style={styles.formLabel}>Tablo *</Text>
|
||||
<Text style={[styles.formLabel, { color: subtitleColor }]}>
|
||||
Tablo *
|
||||
</Text>
|
||||
<FlatList
|
||||
style={[
|
||||
styles.tabloListInForm,
|
||||
{ backgroundColor: cardBackgroundColor, borderColor },
|
||||
]}
|
||||
data={tablos ?? []}
|
||||
renderItem={({ item }) => (
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.tabloOptionInForm,
|
||||
newEvent.tablo_id === item.id &&
|
||||
styles.selectedTabloOptionInForm,
|
||||
{ borderBottomColor: borderColor },
|
||||
newEvent.tablo_id === item.id && {
|
||||
backgroundColor: selectedOptionBgColor,
|
||||
},
|
||||
]}
|
||||
onPress={() =>
|
||||
setNewEvent({ ...newEvent, tablo_id: item.id })
|
||||
|
|
@ -693,6 +850,12 @@ export default function PlanningScreen() {
|
|||
<Text
|
||||
style={[
|
||||
styles.tabloOptionNameInForm,
|
||||
{
|
||||
color:
|
||||
newEvent.tablo_id === item.id
|
||||
? "#3b82f6"
|
||||
: textColor,
|
||||
},
|
||||
newEvent.tablo_id === item.id &&
|
||||
styles.selectedTabloOptionNameInForm,
|
||||
]}
|
||||
|
|
@ -708,17 +871,23 @@ export default function PlanningScreen() {
|
|||
keyExtractor={(item) => item.id}
|
||||
showsVerticalScrollIndicator={false}
|
||||
scrollEnabled={false}
|
||||
style={styles.tabloListInForm}
|
||||
/>
|
||||
</View>
|
||||
</ScrollView>
|
||||
|
||||
<View style={styles.createEventModalActions}>
|
||||
<View
|
||||
style={[
|
||||
styles.createEventModalActions,
|
||||
{ borderTopColor: borderColor },
|
||||
]}
|
||||
>
|
||||
<TouchableOpacity
|
||||
style={styles.cancelButton}
|
||||
style={[styles.cancelButton, { borderColor }]}
|
||||
onPress={() => setShowCreateEventModal(false)}
|
||||
>
|
||||
<Text style={styles.cancelButtonText}>Annuler</Text>
|
||||
<Text style={[styles.cancelButtonText, { color: textColor }]}>
|
||||
Annuler
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
style={styles.saveButton}
|
||||
|
|
@ -738,7 +907,7 @@ export default function PlanningScreen() {
|
|||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: "#f8fafc",
|
||||
// backgroundColor is set dynamically
|
||||
},
|
||||
header: {
|
||||
flexDirection: "row",
|
||||
|
|
@ -751,12 +920,12 @@ const styles = StyleSheet.create({
|
|||
headerTitle: {
|
||||
fontSize: 28,
|
||||
fontWeight: "bold",
|
||||
color: "#1f2937",
|
||||
// color is set dynamically
|
||||
marginBottom: 4,
|
||||
},
|
||||
headerSubtitle: {
|
||||
fontSize: 16,
|
||||
color: "#6b7280",
|
||||
// color is set dynamically
|
||||
textTransform: "capitalize",
|
||||
},
|
||||
addButton: {
|
||||
|
|
@ -778,7 +947,7 @@ const styles = StyleSheet.create({
|
|||
},
|
||||
viewModeToggle: {
|
||||
flexDirection: "row",
|
||||
backgroundColor: "#f3f4f6",
|
||||
// backgroundColor is set dynamically
|
||||
borderRadius: 12,
|
||||
padding: 4,
|
||||
},
|
||||
|
|
@ -798,7 +967,7 @@ const styles = StyleSheet.create({
|
|||
viewModeText: {
|
||||
fontSize: 14,
|
||||
fontWeight: "500",
|
||||
color: "#6b7280",
|
||||
// color is set dynamically
|
||||
},
|
||||
activeViewModeText: {
|
||||
color: "white",
|
||||
|
|
@ -808,7 +977,7 @@ const styles = StyleSheet.create({
|
|||
marginBottom: 20,
|
||||
},
|
||||
tabloSelector: {
|
||||
backgroundColor: "white",
|
||||
// backgroundColor is set dynamically
|
||||
borderRadius: 12,
|
||||
padding: 16,
|
||||
flexDirection: "row",
|
||||
|
|
@ -831,7 +1000,7 @@ const styles = StyleSheet.create({
|
|||
},
|
||||
tabloSelectorLabel: {
|
||||
fontSize: 12,
|
||||
color: "#6b7280",
|
||||
// color is set dynamically
|
||||
marginBottom: 2,
|
||||
},
|
||||
tabloSelectorRow: {
|
||||
|
|
@ -841,7 +1010,7 @@ const styles = StyleSheet.create({
|
|||
tabloSelectorName: {
|
||||
fontSize: 16,
|
||||
fontWeight: "600",
|
||||
color: "#1f2937",
|
||||
// color is set dynamically
|
||||
marginLeft: 8,
|
||||
},
|
||||
tabloColorDot: {
|
||||
|
|
@ -870,7 +1039,7 @@ const styles = StyleSheet.create({
|
|||
calendarTitle: {
|
||||
fontSize: 18,
|
||||
fontWeight: "600",
|
||||
color: "#1f2937",
|
||||
// color is set dynamically
|
||||
},
|
||||
weekHeader: {
|
||||
flexDirection: "row",
|
||||
|
|
@ -878,12 +1047,12 @@ const styles = StyleSheet.create({
|
|||
marginBottom: 16,
|
||||
paddingBottom: 12,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: "#e5e7eb",
|
||||
// borderBottomColor is set dynamically
|
||||
},
|
||||
weekDay: {
|
||||
fontSize: 14,
|
||||
fontWeight: "500",
|
||||
color: "#6b7280",
|
||||
// color is set dynamically
|
||||
textAlign: "center",
|
||||
width: 40,
|
||||
},
|
||||
|
|
@ -900,11 +1069,11 @@ const styles = StyleSheet.create({
|
|||
},
|
||||
dayText: {
|
||||
fontSize: 16,
|
||||
color: "#1f2937",
|
||||
// color is set dynamically
|
||||
fontWeight: "500",
|
||||
},
|
||||
inactiveDayText: {
|
||||
color: "#d1d5db",
|
||||
// color is set dynamically
|
||||
},
|
||||
selectedDay: {
|
||||
backgroundColor: "#3b82f6",
|
||||
|
|
@ -947,7 +1116,7 @@ const styles = StyleSheet.create({
|
|||
marginHorizontal: 2,
|
||||
},
|
||||
weekDayHeader: {
|
||||
backgroundColor: "#f8fafc",
|
||||
// backgroundColor is set dynamically
|
||||
borderRadius: 8,
|
||||
padding: 8,
|
||||
alignItems: "center",
|
||||
|
|
@ -964,12 +1133,12 @@ const styles = StyleSheet.create({
|
|||
},
|
||||
weekDayName: {
|
||||
fontSize: 12,
|
||||
color: "#6b7280",
|
||||
// color is set dynamically
|
||||
fontWeight: "500",
|
||||
},
|
||||
weekDayNumber: {
|
||||
fontSize: 16,
|
||||
color: "#1f2937",
|
||||
// color is set dynamically
|
||||
fontWeight: "600",
|
||||
marginTop: 2,
|
||||
},
|
||||
|
|
@ -1037,14 +1206,14 @@ const styles = StyleSheet.create({
|
|||
width: 20,
|
||||
height: 20,
|
||||
borderRadius: 10,
|
||||
backgroundColor: "#e5e7eb",
|
||||
// backgroundColor is set dynamically
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
margin: 2,
|
||||
},
|
||||
weekEventMoreText: {
|
||||
fontSize: 10,
|
||||
color: "#6b7280",
|
||||
// color is set dynamically
|
||||
},
|
||||
weekEmptySlot: {
|
||||
flex: 1,
|
||||
|
|
@ -1069,11 +1238,10 @@ const styles = StyleSheet.create({
|
|||
eventsSectionTitle: {
|
||||
fontSize: 18,
|
||||
fontWeight: "600",
|
||||
color: "#1f2937",
|
||||
// color is set dynamically
|
||||
marginLeft: 8,
|
||||
},
|
||||
eventCard: {
|
||||
backgroundColor: "white",
|
||||
borderRadius: 12,
|
||||
marginBottom: 12,
|
||||
flexDirection: "row",
|
||||
|
|
@ -1082,6 +1250,7 @@ const styles = StyleSheet.create({
|
|||
shadowOpacity: 0.1,
|
||||
shadowRadius: 4,
|
||||
elevation: 3,
|
||||
borderWidth: 1,
|
||||
},
|
||||
eventColorBar: {
|
||||
width: 4,
|
||||
|
|
@ -1095,7 +1264,6 @@ const styles = StyleSheet.create({
|
|||
eventTitle: {
|
||||
fontSize: 16,
|
||||
fontWeight: "600",
|
||||
color: "#1f2937",
|
||||
marginBottom: 8,
|
||||
},
|
||||
eventDetails: {
|
||||
|
|
@ -1108,7 +1276,6 @@ const styles = StyleSheet.create({
|
|||
},
|
||||
eventDetailText: {
|
||||
fontSize: 14,
|
||||
color: "#6b7280",
|
||||
},
|
||||
emptyState: {
|
||||
display: "flex",
|
||||
|
|
@ -1121,25 +1288,24 @@ const styles = StyleSheet.create({
|
|||
emptyStateTitle: {
|
||||
fontSize: 18,
|
||||
fontWeight: "600",
|
||||
color: "#6b7280",
|
||||
// color is set dynamically
|
||||
marginTop: 8,
|
||||
marginBottom: 8,
|
||||
},
|
||||
emptyStateText: {
|
||||
fontSize: 14,
|
||||
color: "#9ca3af",
|
||||
// color is set dynamically
|
||||
textAlign: "center",
|
||||
lineHeight: 20,
|
||||
},
|
||||
modalOverlay: {
|
||||
flex: 1,
|
||||
backgroundColor: "rgba(0, 0, 0, 0.5)",
|
||||
// backgroundColor is set dynamically
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
paddingHorizontal: 20,
|
||||
},
|
||||
modalContent: {
|
||||
backgroundColor: "white",
|
||||
borderRadius: 16,
|
||||
width: "100%",
|
||||
maxWidth: 400,
|
||||
|
|
@ -1149,16 +1315,15 @@ const styles = StyleSheet.create({
|
|||
shadowOpacity: 0.25,
|
||||
shadowRadius: 20,
|
||||
elevation: 10,
|
||||
borderWidth: 1,
|
||||
},
|
||||
modalHeader: {
|
||||
padding: 20,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: "#e5e7eb",
|
||||
},
|
||||
modalTitle: {
|
||||
fontSize: 18,
|
||||
fontWeight: "600",
|
||||
color: "#1f2937",
|
||||
textAlign: "center",
|
||||
},
|
||||
tabloOption: {
|
||||
|
|
@ -1167,7 +1332,6 @@ const styles = StyleSheet.create({
|
|||
alignItems: "center",
|
||||
padding: 16,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: "#f3f4f6",
|
||||
},
|
||||
tabloOptionLeft: {
|
||||
flexDirection: "row",
|
||||
|
|
@ -1181,7 +1345,6 @@ const styles = StyleSheet.create({
|
|||
tabloOptionName: {
|
||||
fontSize: 16,
|
||||
fontWeight: "500",
|
||||
color: "#1f2937",
|
||||
marginBottom: 2,
|
||||
},
|
||||
tabloOptionCount: {
|
||||
|
|
@ -1204,11 +1367,11 @@ const styles = StyleSheet.create({
|
|||
selectedDayTitle: {
|
||||
fontSize: 18,
|
||||
fontWeight: "600",
|
||||
color: "#1f2937",
|
||||
// color is set dynamically
|
||||
},
|
||||
selectedDayEventsCount: {
|
||||
fontSize: 14,
|
||||
color: "#6b7280",
|
||||
// color is set dynamically
|
||||
},
|
||||
selectedDayEventsList: {
|
||||
paddingBottom: 10,
|
||||
|
|
@ -1222,11 +1385,10 @@ const styles = StyleSheet.create({
|
|||
// Create Event Modal Styles
|
||||
createEventModalOverlay: {
|
||||
flex: 1,
|
||||
backgroundColor: "rgba(0, 0, 0, 0.5)",
|
||||
// backgroundColor is set dynamically
|
||||
justifyContent: "flex-end",
|
||||
},
|
||||
createEventModalContent: {
|
||||
backgroundColor: "white",
|
||||
borderTopLeftRadius: 20,
|
||||
borderTopRightRadius: 20,
|
||||
maxHeight: "90%",
|
||||
|
|
@ -1242,12 +1404,10 @@ const styles = StyleSheet.create({
|
|||
alignItems: "center",
|
||||
padding: 20,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: "#e5e7eb",
|
||||
},
|
||||
createEventModalTitle: {
|
||||
fontSize: 20,
|
||||
fontWeight: "600",
|
||||
color: "#1f2937",
|
||||
},
|
||||
createEventCloseButton: {
|
||||
padding: 4,
|
||||
|
|
@ -1262,23 +1422,17 @@ const styles = StyleSheet.create({
|
|||
formLabel: {
|
||||
fontSize: 16,
|
||||
fontWeight: "500",
|
||||
color: "#374151",
|
||||
marginBottom: 8,
|
||||
},
|
||||
formInput: {
|
||||
borderWidth: 1,
|
||||
borderColor: "#d1d5db",
|
||||
borderRadius: 8,
|
||||
padding: 12,
|
||||
fontSize: 16,
|
||||
color: "#1f2937",
|
||||
backgroundColor: "white",
|
||||
},
|
||||
tabloListInForm: {
|
||||
borderWidth: 1,
|
||||
borderColor: "#d1d5db",
|
||||
borderRadius: 8,
|
||||
backgroundColor: "white",
|
||||
maxHeight: 150,
|
||||
},
|
||||
tabloOptionInForm: {
|
||||
|
|
@ -1287,15 +1441,13 @@ const styles = StyleSheet.create({
|
|||
alignItems: "center",
|
||||
padding: 12,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: "#f3f4f6",
|
||||
},
|
||||
selectedTabloOptionInForm: {
|
||||
backgroundColor: "#eff6ff",
|
||||
// backgroundColor is set dynamically
|
||||
},
|
||||
tabloOptionNameInForm: {
|
||||
fontSize: 16,
|
||||
fontWeight: "500",
|
||||
color: "#1f2937",
|
||||
marginLeft: 8,
|
||||
},
|
||||
selectedTabloOptionNameInForm: {
|
||||
|
|
@ -1306,7 +1458,6 @@ const styles = StyleSheet.create({
|
|||
justifyContent: "space-between",
|
||||
padding: 20,
|
||||
borderTopWidth: 1,
|
||||
borderTopColor: "#e5e7eb",
|
||||
gap: 12,
|
||||
},
|
||||
cancelButton: {
|
||||
|
|
@ -1315,14 +1466,12 @@ const styles = StyleSheet.create({
|
|||
paddingHorizontal: 20,
|
||||
borderRadius: 8,
|
||||
borderWidth: 1,
|
||||
borderColor: "#d1d5db",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
},
|
||||
cancelButtonText: {
|
||||
fontSize: 16,
|
||||
fontWeight: "500",
|
||||
color: "#6b7280",
|
||||
},
|
||||
saveButton: {
|
||||
flex: 1,
|
||||
|
|
|
|||
|
|
@ -29,15 +29,42 @@ import {
|
|||
Heart,
|
||||
} from "lucide-react-native";
|
||||
import { router } from "expo-router";
|
||||
import { useThemeColor } from "@/hooks/useThemeColor";
|
||||
import { useColorScheme } from "@/hooks/useColorScheme";
|
||||
|
||||
export default function SettingsScreen() {
|
||||
const signOut = useAuthStore((state) => state.signOut);
|
||||
const user = useUser();
|
||||
const colorScheme = useColorScheme();
|
||||
|
||||
// Theme-aware colors
|
||||
const backgroundColor = useThemeColor(
|
||||
{ light: "#f8fafc", dark: "#111827" },
|
||||
"background"
|
||||
);
|
||||
const cardBackgroundColor = useThemeColor(
|
||||
{ light: "#ffffff", dark: "#1f2937" },
|
||||
"background"
|
||||
);
|
||||
const textColor = useThemeColor(
|
||||
{ light: "#1f2937", dark: "#f9fafb" },
|
||||
"text"
|
||||
);
|
||||
const subtitleColor = useThemeColor(
|
||||
{ light: "#6b7280", dark: "#9ca3af" },
|
||||
"text"
|
||||
);
|
||||
const borderColor = colorScheme === "dark" ? "#374151" : "#e5e7eb";
|
||||
|
||||
// Theme-aware gradient colors
|
||||
const gradientColors: [string, string, string] =
|
||||
colorScheme === "dark"
|
||||
? ["#1f2937", "#374151", "#4b5563"]
|
||||
: ["#1e3a8a", "#3b82f6", "#60a5fa"];
|
||||
|
||||
// Settings state
|
||||
const [pushNotifications, setPushNotifications] = useState(true);
|
||||
const [emailNotifications, setEmailNotifications] = useState(true);
|
||||
const [darkMode, setDarkMode] = useState(false);
|
||||
const [biometricAuth, setBiometricAuth] = useState(false);
|
||||
|
||||
const handleSignOut = () => {
|
||||
|
|
@ -72,8 +99,17 @@ export default function SettingsScreen() {
|
|||
|
||||
const renderSettingsSection = (title: string, children: React.ReactNode) => (
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>{title}</Text>
|
||||
<View style={styles.sectionContent}>{children}</View>
|
||||
<Text style={[styles.sectionTitle, { color: subtitleColor }]}>
|
||||
{title}
|
||||
</Text>
|
||||
<View
|
||||
style={[
|
||||
styles.sectionContent,
|
||||
{ backgroundColor: cardBackgroundColor, borderColor },
|
||||
]}
|
||||
>
|
||||
{children}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
|
||||
|
|
@ -86,7 +122,7 @@ export default function SettingsScreen() {
|
|||
showArrow: boolean = true
|
||||
) => (
|
||||
<TouchableOpacity
|
||||
style={styles.settingsItem}
|
||||
style={[styles.settingsItem, { borderBottomColor: borderColor }]}
|
||||
onPress={onPress}
|
||||
disabled={!onPress}
|
||||
activeOpacity={onPress ? 0.7 : 1}
|
||||
|
|
@ -94,16 +130,26 @@ export default function SettingsScreen() {
|
|||
<View style={styles.settingsItemLeft}>
|
||||
<View style={styles.iconContainer}>{icon}</View>
|
||||
<View style={styles.settingsItemContent}>
|
||||
<Text style={styles.settingsItemTitle}>{title}</Text>
|
||||
<Text style={[styles.settingsItemTitle, { color: textColor }]}>
|
||||
{title}
|
||||
</Text>
|
||||
{subtitle && (
|
||||
<Text style={styles.settingsItemSubtitle}>{subtitle}</Text>
|
||||
<Text
|
||||
style={[styles.settingsItemSubtitle, { color: subtitleColor }]}
|
||||
>
|
||||
{subtitle}
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
<View style={styles.settingsItemRight}>
|
||||
{rightComponent}
|
||||
{showArrow && onPress && (
|
||||
<ChevronRight size={20} color="#9ca3af" style={{ marginLeft: 8 }} />
|
||||
<ChevronRight
|
||||
size={20}
|
||||
color={subtitleColor}
|
||||
style={{ marginLeft: 8 }}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
|
|
@ -124,20 +170,26 @@ export default function SettingsScreen() {
|
|||
<Switch
|
||||
value={value}
|
||||
onValueChange={onValueChange}
|
||||
trackColor={{ false: "#e5e7eb", true: "#3b82f6" }}
|
||||
trackColor={{
|
||||
false: colorScheme === "dark" ? "#374151" : "#e5e7eb",
|
||||
true: "#3b82f6",
|
||||
}}
|
||||
thumbColor={value ? "#ffffff" : "#ffffff"}
|
||||
ios_backgroundColor="#e5e7eb"
|
||||
ios_backgroundColor={colorScheme === "dark" ? "#374151" : "#e5e7eb"}
|
||||
/>,
|
||||
false
|
||||
);
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<StatusBar barStyle="light-content" />
|
||||
<View style={[styles.container, { backgroundColor }]}>
|
||||
<StatusBar
|
||||
barStyle={colorScheme === "dark" ? "light-content" : "light-content"}
|
||||
backgroundColor={gradientColors[0]}
|
||||
/>
|
||||
|
||||
{/* Header */}
|
||||
<LinearGradient
|
||||
colors={["#1e3a8a", "#3b82f6", "#60a5fa"]}
|
||||
colors={gradientColors}
|
||||
style={styles.headerGradient}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 1 }}
|
||||
|
|
@ -154,7 +206,10 @@ export default function SettingsScreen() {
|
|||
<View style={styles.decorativeCircle2} />
|
||||
</LinearGradient>
|
||||
|
||||
<ScrollView style={styles.content} showsVerticalScrollIndicator={false}>
|
||||
<ScrollView
|
||||
style={[styles.content, { backgroundColor }]}
|
||||
showsVerticalScrollIndicator={false}
|
||||
>
|
||||
{/* Account Section */}
|
||||
{renderSettingsSection(
|
||||
"Compte",
|
||||
|
|
@ -198,9 +253,14 @@ export default function SettingsScreen() {
|
|||
{renderSwitchItem(
|
||||
<Moon size={20} color="#6366f1" />,
|
||||
"Mode sombre",
|
||||
"Utiliser le thème sombre",
|
||||
darkMode,
|
||||
setDarkMode
|
||||
"Thème système automatique",
|
||||
colorScheme === "dark",
|
||||
() => {
|
||||
Alert.alert(
|
||||
"Thème automatique",
|
||||
"Le thème suit automatiquement les préférences de votre appareil. Modifiez le thème dans les paramètres de votre appareil."
|
||||
);
|
||||
}
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
|
@ -310,7 +370,6 @@ export default function SettingsScreen() {
|
|||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: "#f8fafc",
|
||||
},
|
||||
headerGradient: {
|
||||
paddingTop: 50,
|
||||
|
|
@ -353,7 +412,6 @@ const styles = StyleSheet.create({
|
|||
},
|
||||
content: {
|
||||
flex: 1,
|
||||
backgroundColor: "#f8fafc",
|
||||
marginTop: -10,
|
||||
borderTopLeftRadius: 10,
|
||||
borderTopRightRadius: 10,
|
||||
|
|
@ -366,12 +424,10 @@ const styles = StyleSheet.create({
|
|||
sectionTitle: {
|
||||
fontSize: 18,
|
||||
fontWeight: "600",
|
||||
color: "#1f2937",
|
||||
marginBottom: 12,
|
||||
marginLeft: 4,
|
||||
},
|
||||
sectionContent: {
|
||||
backgroundColor: "white",
|
||||
borderRadius: 16,
|
||||
shadowColor: "#000",
|
||||
shadowOffset: { width: 0, height: 2 },
|
||||
|
|
@ -379,6 +435,7 @@ const styles = StyleSheet.create({
|
|||
shadowRadius: 8,
|
||||
elevation: 3,
|
||||
overflow: "hidden",
|
||||
borderWidth: 1,
|
||||
},
|
||||
settingsItem: {
|
||||
flexDirection: "row",
|
||||
|
|
@ -387,7 +444,6 @@ const styles = StyleSheet.create({
|
|||
paddingHorizontal: 20,
|
||||
paddingVertical: 16,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: "#f3f4f6",
|
||||
},
|
||||
settingsItemLeft: {
|
||||
flexDirection: "row",
|
||||
|
|
@ -398,7 +454,7 @@ const styles = StyleSheet.create({
|
|||
width: 40,
|
||||
height: 40,
|
||||
borderRadius: 20,
|
||||
backgroundColor: "#f3f4f6",
|
||||
backgroundColor: "rgba(0, 0, 0, 0.05)",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
marginRight: 12,
|
||||
|
|
@ -409,12 +465,10 @@ const styles = StyleSheet.create({
|
|||
settingsItemTitle: {
|
||||
fontSize: 16,
|
||||
fontWeight: "500",
|
||||
color: "#1f2937",
|
||||
marginBottom: 2,
|
||||
},
|
||||
settingsItemSubtitle: {
|
||||
fontSize: 14,
|
||||
color: "#6b7280",
|
||||
},
|
||||
settingsItemRight: {
|
||||
flexDirection: "row",
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@ import {
|
|||
} from "lucide-react-native";
|
||||
import { router } from "expo-router";
|
||||
import { AVAILABLE_COLORS, ColorMap } from "@/constants/colors";
|
||||
import { useThemeColor } from "@/hooks/useThemeColor";
|
||||
import { useColorScheme } from "@/hooks/useColorScheme";
|
||||
|
||||
const { width } = Dimensions.get("window");
|
||||
const numColumns = 2;
|
||||
|
|
@ -46,6 +48,32 @@ export default function TablosScreen() {
|
|||
const [isCreateModalVisible, setIsCreateModalVisible] = useState(false);
|
||||
const { mutate: createTablo } = useCreateTablo();
|
||||
const { mutate: deleteTablo } = useDeleteTablo();
|
||||
const colorScheme = useColorScheme();
|
||||
|
||||
// Theme-aware colors
|
||||
const backgroundColor = useThemeColor(
|
||||
{ light: "#f8fafc", dark: "#111827" },
|
||||
"background"
|
||||
);
|
||||
const cardBackgroundColor = useThemeColor(
|
||||
{ light: "#ffffff", dark: "#1f2937" },
|
||||
"background"
|
||||
);
|
||||
const textColor = useThemeColor(
|
||||
{ light: "#1f2937", dark: "#f9fafb" },
|
||||
"text"
|
||||
);
|
||||
const subtitleColor = useThemeColor(
|
||||
{ light: "#6b7280", dark: "#9ca3af" },
|
||||
"text"
|
||||
);
|
||||
const borderColor = colorScheme === "dark" ? "#374151" : "#e5e7eb";
|
||||
|
||||
// Theme-aware gradient colors
|
||||
const gradientColors: [string, string, string] =
|
||||
colorScheme === "dark"
|
||||
? ["#1f2937", "#374151", "#4b5563"]
|
||||
: ["#1e3a8a", "#3b82f6", "#60a5fa"];
|
||||
|
||||
const [newTablo, setNewTablo] = useState<{
|
||||
name: string;
|
||||
|
|
@ -190,7 +218,11 @@ export default function TablosScreen() {
|
|||
<TouchableOpacity
|
||||
style={[
|
||||
styles.tabloCard,
|
||||
{ width: viewMode === "grid" ? itemWidth : "100%" },
|
||||
{
|
||||
width: viewMode === "grid" ? itemWidth : "100%",
|
||||
backgroundColor: cardBackgroundColor,
|
||||
borderColor: borderColor,
|
||||
},
|
||||
]}
|
||||
onPress={() => navigateToTablo(tablo)}
|
||||
onLongPress={() => handleDeleteTablo(tablo)}
|
||||
|
|
@ -216,7 +248,10 @@ export default function TablosScreen() {
|
|||
{/* Tablo Info */}
|
||||
<View style={styles.tabloInfo}>
|
||||
<View style={styles.nameRow}>
|
||||
<Text style={styles.tabloName} numberOfLines={2}>
|
||||
<Text
|
||||
style={[styles.tabloName, { color: textColor }]}
|
||||
numberOfLines={2}
|
||||
>
|
||||
{tablo.name}
|
||||
</Text>
|
||||
<View
|
||||
|
|
@ -257,13 +292,13 @@ export default function TablosScreen() {
|
|||
router.push(`/channel/${getChannelCid(tablo.id)}`)
|
||||
}
|
||||
>
|
||||
<MessageCircle size={16} color="#6b7280" />
|
||||
<MessageCircle size={16} color={subtitleColor} />
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
style={styles.cardActionButton}
|
||||
onPress={() => router.push("/planning")}
|
||||
>
|
||||
<Calendar size={16} color="#6b7280" />
|
||||
<Calendar size={16} color={subtitleColor} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
|
|
@ -275,7 +310,10 @@ export default function TablosScreen() {
|
|||
const renderListItem = ({ item: tablo }: { item: UserTablo }) => {
|
||||
return (
|
||||
<TouchableOpacity
|
||||
style={styles.listItem}
|
||||
style={[
|
||||
styles.listItem,
|
||||
{ backgroundColor: cardBackgroundColor, borderColor: borderColor },
|
||||
]}
|
||||
onPress={() => navigateToTablo(tablo)}
|
||||
onLongPress={() => handleDeleteTablo(tablo)}
|
||||
activeOpacity={0.8}
|
||||
|
|
@ -294,7 +332,9 @@ export default function TablosScreen() {
|
|||
<View style={styles.listItemContent}>
|
||||
<View style={styles.listNameRow}>
|
||||
<View style={styles.listNameContainer}>
|
||||
<Text style={styles.listName}>{tablo.name}</Text>
|
||||
<Text style={[styles.listName, { color: textColor }]}>
|
||||
{tablo.name}
|
||||
</Text>
|
||||
</View>
|
||||
<View
|
||||
style={[
|
||||
|
|
@ -333,13 +373,13 @@ export default function TablosScreen() {
|
|||
router.push(`/channel/${getChannelCid(tablo.id)}`)
|
||||
}
|
||||
>
|
||||
<MessageCircle size={16} color="#6b7280" />
|
||||
<MessageCircle size={16} color={subtitleColor} />
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
style={styles.listActionButton}
|
||||
onPress={() => router.push("/planning")}
|
||||
>
|
||||
<Calendar size={16} color="#6b7280" />
|
||||
<Calendar size={16} color={subtitleColor} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
|
|
@ -369,12 +409,15 @@ export default function TablosScreen() {
|
|||
}
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<StatusBar barStyle="light-content" />
|
||||
<View style={[styles.container, { backgroundColor }]}>
|
||||
<StatusBar
|
||||
barStyle={colorScheme === "dark" ? "light-content" : "light-content"}
|
||||
backgroundColor={gradientColors[0]}
|
||||
/>
|
||||
|
||||
{/* Beautiful Header */}
|
||||
<LinearGradient
|
||||
colors={["#1e3a8a", "#3b82f6", "#60a5fa"]}
|
||||
colors={gradientColors}
|
||||
style={styles.headerGradient}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 1 }}
|
||||
|
|
@ -423,10 +466,12 @@ export default function TablosScreen() {
|
|||
</LinearGradient>
|
||||
|
||||
{/* Content */}
|
||||
<View style={styles.contentContainer}>
|
||||
<View style={[styles.contentContainer, { backgroundColor }]}>
|
||||
{isLoading && !refreshing ? (
|
||||
<View style={styles.loadingContainer}>
|
||||
<Text style={styles.loadingText}>Chargement de vos tablos...</Text>
|
||||
<Text style={[styles.loadingText, { color: subtitleColor }]}>
|
||||
Chargement de vos tablos...
|
||||
</Text>
|
||||
</View>
|
||||
) : filteredTablos && filteredTablos.length > 0 ? (
|
||||
<FlatList
|
||||
|
|
@ -443,8 +488,10 @@ export default function TablosScreen() {
|
|||
/>
|
||||
) : (
|
||||
<View style={styles.emptyContainer}>
|
||||
<Text style={styles.emptyTitle}>Aucun tablo trouvé</Text>
|
||||
<Text style={styles.emptyMessage}>
|
||||
<Text style={[styles.emptyTitle, { color: textColor }]}>
|
||||
Aucun tablo trouvé
|
||||
</Text>
|
||||
<Text style={[styles.emptyMessage, { color: subtitleColor }]}>
|
||||
{filterStatus === "all"
|
||||
? "Vous n'avez encore aucun tablo. Créez votre premier tablo pour commencer !"
|
||||
: `Aucun tablo avec le statut "${getStatusLabel(
|
||||
|
|
@ -485,20 +532,37 @@ export default function TablosScreen() {
|
|||
behavior={Platform.OS === "ios" ? "padding" : "height"}
|
||||
style={styles.modalOverlay}
|
||||
>
|
||||
<View style={styles.modalContent}>
|
||||
<View
|
||||
style={[
|
||||
styles.modalContent,
|
||||
{ backgroundColor: cardBackgroundColor, borderColor },
|
||||
]}
|
||||
>
|
||||
<TouchableOpacity
|
||||
style={styles.modalCloseButton}
|
||||
onPress={() => setIsCreateModalVisible(false)}
|
||||
>
|
||||
<X size={24} color="#6b7280" />
|
||||
<X size={24} color={subtitleColor} />
|
||||
</TouchableOpacity>
|
||||
<Text style={styles.modalTitle}>Nouveau Tablo</Text>
|
||||
<Text style={[styles.modalTitle, { color: textColor }]}>
|
||||
Nouveau Tablo
|
||||
</Text>
|
||||
<ScrollView>
|
||||
<View style={styles.modalFormGroup}>
|
||||
<Text style={styles.modalLabel}>Nom du Tablo</Text>
|
||||
<Text style={[styles.modalLabel, { color: subtitleColor }]}>
|
||||
Nom du Tablo
|
||||
</Text>
|
||||
<TextInput
|
||||
style={styles.modalInput}
|
||||
style={[
|
||||
styles.modalInput,
|
||||
{
|
||||
backgroundColor: cardBackgroundColor,
|
||||
borderColor,
|
||||
color: textColor,
|
||||
},
|
||||
]}
|
||||
placeholder="Ex: Projet React Native"
|
||||
placeholderTextColor={subtitleColor}
|
||||
value={newTablo.name}
|
||||
onChangeText={(text) =>
|
||||
setNewTablo({ ...newTablo, name: text })
|
||||
|
|
@ -506,7 +570,9 @@ export default function TablosScreen() {
|
|||
/>
|
||||
</View>
|
||||
<View style={styles.modalFormGroup}>
|
||||
<Text style={styles.modalLabel}>Couleur</Text>
|
||||
<Text style={[styles.modalLabel, { color: subtitleColor }]}>
|
||||
Couleur
|
||||
</Text>
|
||||
<View style={styles.colorPicker}>
|
||||
{AVAILABLE_COLORS.map((color) => (
|
||||
<TouchableOpacity
|
||||
|
|
@ -522,7 +588,9 @@ export default function TablosScreen() {
|
|||
</View>
|
||||
</View>
|
||||
<View style={styles.modalFormGroup}>
|
||||
<Text style={styles.modalLabel}>Statut</Text>
|
||||
<Text style={[styles.modalLabel, { color: subtitleColor }]}>
|
||||
Statut
|
||||
</Text>
|
||||
<View style={styles.statusPicker}>
|
||||
{(["todo", "in_progress", "done"] as const).map((status) => (
|
||||
<TouchableOpacity
|
||||
|
|
@ -978,7 +1046,6 @@ const styles = StyleSheet.create({
|
|||
backgroundColor: "rgba(0, 0, 0, 0.5)",
|
||||
},
|
||||
modalContent: {
|
||||
backgroundColor: "white",
|
||||
borderRadius: 20,
|
||||
padding: 20,
|
||||
width: "90%",
|
||||
|
|
@ -988,6 +1055,7 @@ const styles = StyleSheet.create({
|
|||
shadowOpacity: 0.3,
|
||||
shadowRadius: 10,
|
||||
elevation: 10,
|
||||
borderWidth: 1,
|
||||
},
|
||||
modalCloseButton: {
|
||||
alignSelf: "flex-end",
|
||||
|
|
@ -996,7 +1064,6 @@ const styles = StyleSheet.create({
|
|||
modalTitle: {
|
||||
fontSize: 24,
|
||||
fontWeight: "bold",
|
||||
color: "#1f2937",
|
||||
marginBottom: 20,
|
||||
},
|
||||
modalFormGroup: {
|
||||
|
|
@ -1004,16 +1071,13 @@ const styles = StyleSheet.create({
|
|||
},
|
||||
modalLabel: {
|
||||
fontSize: 16,
|
||||
color: "#6b7280",
|
||||
marginBottom: 8,
|
||||
},
|
||||
modalInput: {
|
||||
borderWidth: 1,
|
||||
borderColor: "#e5e7eb",
|
||||
borderRadius: 12,
|
||||
padding: 12,
|
||||
fontSize: 16,
|
||||
color: "#1f2937",
|
||||
},
|
||||
colorPicker: {
|
||||
flexDirection: "row",
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ import {
|
|||
import { MessageCircle, Users, Smile } from "lucide-react-native";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useHeaderHeight } from "@react-navigation/elements";
|
||||
import { useThemeColor } from "@/hooks/useThemeColor";
|
||||
import { useColorScheme } from "@/hooks/useColorScheme";
|
||||
|
||||
export default function ChannelScreen() {
|
||||
const { cid } = useLocalSearchParams<{ cid: string }>();
|
||||
|
|
@ -25,9 +27,32 @@ export default function ChannelScreen() {
|
|||
const channel = client.channel(type, id);
|
||||
const [hasMessages, setHasMessages] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const colorScheme = useColorScheme();
|
||||
|
||||
const headerHeight = useHeaderHeight();
|
||||
|
||||
// Theme-aware colors
|
||||
const backgroundColor = useThemeColor(
|
||||
{ light: "#f8fafc", dark: "#111827" },
|
||||
"background"
|
||||
);
|
||||
const textColor = useThemeColor(
|
||||
{ light: "#1f2937", dark: "#f9fafb" },
|
||||
"text"
|
||||
);
|
||||
const subtitleColor = useThemeColor(
|
||||
{ light: "#6b7280", dark: "#9ca3af" },
|
||||
"text"
|
||||
);
|
||||
const iconColor = useThemeColor(
|
||||
{ light: "#d1d5db", dark: "#6b7280" },
|
||||
"icon"
|
||||
);
|
||||
const iconSecondaryColor = useThemeColor(
|
||||
{ light: "#e5e7eb", dark: "#4b5563" },
|
||||
"icon"
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (channel) {
|
||||
const checkMessages = async () => {
|
||||
|
|
@ -64,31 +89,35 @@ export default function ChannelScreen() {
|
|||
const EmptyState = () => (
|
||||
<View style={styles.emptyContainer}>
|
||||
<View style={styles.emptyIconContainer}>
|
||||
<MessageCircle size={64} color="#d1d5db" strokeWidth={1.5} />
|
||||
<MessageCircle size={64} color={iconColor} strokeWidth={1.5} />
|
||||
<View style={styles.decorativeElements}>
|
||||
<View style={styles.floatingIcon1}>
|
||||
<Users size={20} color="#e5e7eb" />
|
||||
<Users size={20} color={iconSecondaryColor} />
|
||||
</View>
|
||||
<View style={styles.floatingIcon2}>
|
||||
<Smile size={18} color="#e5e7eb" />
|
||||
<Smile size={18} color={iconSecondaryColor} />
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<Text style={styles.emptyTitle}>Commencez la conversation</Text>
|
||||
<Text style={styles.emptyMessage}>
|
||||
<Text style={[styles.emptyTitle, { color: textColor }]}>
|
||||
Commencez la conversation
|
||||
</Text>
|
||||
<Text style={[styles.emptyMessage, { color: subtitleColor }]}>
|
||||
Soyez le premier à envoyer un message dans ce canal !
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
|
||||
return (
|
||||
<SafeAreaView style={{ flex: 1, backgroundColor: "#f8fafc" }}>
|
||||
<SafeAreaView style={{ flex: 1, backgroundColor }}>
|
||||
<Channel channel={channel} keyboardVerticalOffset={headerHeight}>
|
||||
{isLoading ? (
|
||||
<View style={styles.loadingContainer}>
|
||||
<ActivityIndicator size="large" color="#3b82f6" />
|
||||
<Text style={styles.loadingText}>Chargement des messages...</Text>
|
||||
<Text style={[styles.loadingText, { color: subtitleColor }]}>
|
||||
Chargement des messages...
|
||||
</Text>
|
||||
</View>
|
||||
) : hasMessages ? (
|
||||
<MessageList />
|
||||
|
|
@ -112,12 +141,10 @@ const styles = StyleSheet.create({
|
|||
flex: 1,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
backgroundColor: "#f8fafc",
|
||||
gap: 16,
|
||||
},
|
||||
loadingText: {
|
||||
fontSize: 16,
|
||||
color: "#6b7280",
|
||||
fontWeight: "500",
|
||||
},
|
||||
emptyContainer: {
|
||||
|
|
@ -125,7 +152,6 @@ const styles = StyleSheet.create({
|
|||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
paddingHorizontal: 40,
|
||||
backgroundColor: "#f8fafc",
|
||||
},
|
||||
emptyIconContainer: {
|
||||
position: "relative",
|
||||
|
|
@ -144,7 +170,7 @@ const styles = StyleSheet.create({
|
|||
position: "absolute",
|
||||
top: 10,
|
||||
right: 5,
|
||||
backgroundColor: "white",
|
||||
backgroundColor: "rgba(255, 255, 255, 0.9)",
|
||||
borderRadius: 15,
|
||||
padding: 6,
|
||||
shadowColor: "#000",
|
||||
|
|
@ -157,7 +183,7 @@ const styles = StyleSheet.create({
|
|||
position: "absolute",
|
||||
bottom: 15,
|
||||
left: 8,
|
||||
backgroundColor: "white",
|
||||
backgroundColor: "rgba(255, 255, 255, 0.9)",
|
||||
borderRadius: 12,
|
||||
padding: 5,
|
||||
shadowColor: "#000",
|
||||
|
|
@ -169,24 +195,22 @@ const styles = StyleSheet.create({
|
|||
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",
|
||||
backgroundColor: "rgba(255, 255, 255, 0.9)",
|
||||
paddingHorizontal: 20,
|
||||
paddingVertical: 12,
|
||||
borderRadius: 20,
|
||||
borderWidth: 1,
|
||||
borderColor: "#e5e7eb",
|
||||
borderColor: "rgba(0, 0, 0, 0.1)",
|
||||
shadowColor: "#000",
|
||||
shadowOffset: { width: 0, height: 2 },
|
||||
shadowOpacity: 0.05,
|
||||
|
|
@ -195,14 +219,10 @@ const styles = StyleSheet.create({
|
|||
},
|
||||
emptyHintText: {
|
||||
fontSize: 14,
|
||||
color: "#9ca3af",
|
||||
fontWeight: "500",
|
||||
textAlign: "center",
|
||||
},
|
||||
keyboardContainer: {
|
||||
backgroundColor: "#f8fafc",
|
||||
},
|
||||
messageInputContainer: {
|
||||
backgroundColor: "#f8fafc",
|
||||
flexShrink: 0,
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ import {
|
|||
Settings,
|
||||
Shield,
|
||||
} from "lucide-react-native";
|
||||
import { Stack } from "expo-router";
|
||||
import { SafeAreaView } from "react-native-safe-area-context";
|
||||
|
||||
export default function ProfileScreen() {
|
||||
const signOut = useAuthStore((state) => state.signOut);
|
||||
|
|
@ -49,132 +51,140 @@ export default function ProfileScreen() {
|
|||
];
|
||||
|
||||
return (
|
||||
<ScrollView style={styles.container} showsVerticalScrollIndicator={false}>
|
||||
<LinearGradient
|
||||
colors={["#1e3a8a", "#3b82f6", "#60a5fa"]}
|
||||
style={styles.headerGradient}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 1 }}
|
||||
>
|
||||
<View style={styles.headerContent}>
|
||||
<Avatar
|
||||
size={120}
|
||||
rounded
|
||||
source={user.avatar_url ? { uri: user.avatar_url } : undefined}
|
||||
icon={
|
||||
!user.avatar_url
|
||||
? { name: "user", type: "font-awesome" }
|
||||
: undefined
|
||||
}
|
||||
containerStyle={styles.avatar}
|
||||
/>
|
||||
<Text style={styles.userName}>{user.name || "Utilisateur"}</Text>
|
||||
<Text style={styles.userEmail}>{user.email}</Text>
|
||||
</View>
|
||||
</LinearGradient>
|
||||
|
||||
{/* Contenu principal */}
|
||||
<View style={styles.content}>
|
||||
{/* Carte d'informations personnelles */}
|
||||
<Card containerStyle={styles.mainCard}>
|
||||
<View style={styles.cardHeader}>
|
||||
<User size={20} color="#3b82f6" />
|
||||
<Text style={styles.cardHeaderTitle}>
|
||||
Informations personnelles
|
||||
</Text>
|
||||
<SafeAreaView>
|
||||
<Stack.Screen options={{ headerShown: false }} />
|
||||
<ScrollView style={styles.container} showsVerticalScrollIndicator={false}>
|
||||
<LinearGradient
|
||||
colors={["#1e3a8a", "#3b82f6", "#60a5fa"]}
|
||||
style={styles.headerGradient}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 1 }}
|
||||
>
|
||||
<View style={styles.headerContent}>
|
||||
<Avatar
|
||||
size={120}
|
||||
rounded
|
||||
source={user.avatar_url ? { uri: user.avatar_url } : undefined}
|
||||
icon={
|
||||
!user.avatar_url
|
||||
? { name: "user", type: "font-awesome" }
|
||||
: undefined
|
||||
}
|
||||
containerStyle={styles.avatar}
|
||||
/>
|
||||
<Text style={styles.userName}>{user.name || "Utilisateur"}</Text>
|
||||
<Text style={styles.userEmail}>{user.email}</Text>
|
||||
</View>
|
||||
</LinearGradient>
|
||||
|
||||
<View style={styles.infoItem}>
|
||||
<View style={styles.infoIconContainer}>
|
||||
<Mail size={18} color="#6b7280" />
|
||||
{/* Contenu principal */}
|
||||
<View style={styles.content}>
|
||||
{/* Carte d'informations personnelles */}
|
||||
<Card containerStyle={styles.mainCard}>
|
||||
<View style={styles.cardHeader}>
|
||||
<User size={20} color="#3b82f6" />
|
||||
<Text style={styles.cardHeaderTitle}>
|
||||
Informations personnelles
|
||||
</Text>
|
||||
</View>
|
||||
<View style={styles.infoContent}>
|
||||
<Text style={styles.infoLabel}>Adresse e-mail</Text>
|
||||
<Text style={styles.infoValue}>{user.email}</Text>
|
||||
|
||||
<View style={styles.infoItem}>
|
||||
<View style={styles.infoIconContainer}>
|
||||
<Mail size={18} color="#6b7280" />
|
||||
</View>
|
||||
<View style={styles.infoContent}>
|
||||
<Text style={styles.infoLabel}>Adresse e-mail</Text>
|
||||
<Text style={styles.infoValue}>{user.email}</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={styles.divider} />
|
||||
<View style={styles.divider} />
|
||||
|
||||
<View style={styles.infoItem}>
|
||||
<View style={styles.infoIconContainer}>
|
||||
<User size={18} color="#6b7280" />
|
||||
</View>
|
||||
<View style={styles.infoContent}>
|
||||
<Text style={styles.infoLabel}>Nom d'affichage</Text>
|
||||
{isEditing ? (
|
||||
<Input
|
||||
placeholder="Entrez le nom d'affichage"
|
||||
value={displayName}
|
||||
onChangeText={setDisplayName}
|
||||
containerStyle={styles.inputContainer}
|
||||
inputStyle={styles.inputText}
|
||||
autoFocus
|
||||
/>
|
||||
) : (
|
||||
<Text style={styles.infoValue}>
|
||||
{user.name || "Non défini"}
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
<TouchableOpacity
|
||||
style={styles.editButton}
|
||||
onPress={() => {
|
||||
if (isEditing) {
|
||||
handleSaveDisplayName();
|
||||
} else {
|
||||
setDisplayName(user.name ?? "");
|
||||
setIsEditing(true);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{isEditing ? (
|
||||
<Check size={18} color="#10b981" />
|
||||
) : (
|
||||
<Edit3 size={18} color="#6b7280" />
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</Card>
|
||||
|
||||
{/* Éléments de menu */}
|
||||
<Card containerStyle={styles.menuCard}>
|
||||
<View style={styles.cardHeader}>
|
||||
<Settings size={20} color="#3b82f6" />
|
||||
<Text style={styles.cardHeaderTitle}>Préférences</Text>
|
||||
</View>
|
||||
|
||||
{menuItems.map((item, index) => (
|
||||
<View key={index}>
|
||||
<TouchableOpacity style={styles.menuItem} onPress={item.onPress}>
|
||||
<View style={styles.menuIconContainer}>
|
||||
<item.icon size={20} color="#6b7280" />
|
||||
</View>
|
||||
<View style={styles.menuContent}>
|
||||
<Text style={styles.menuTitle}>{item.title}</Text>
|
||||
<Text style={styles.menuSubtitle}>{item.subtitle}</Text>
|
||||
</View>
|
||||
<Text style={styles.menuArrow}>›</Text>
|
||||
<View style={styles.infoItem}>
|
||||
<View style={styles.infoIconContainer}>
|
||||
<User size={18} color="#6b7280" />
|
||||
</View>
|
||||
<View style={styles.infoContent}>
|
||||
<Text style={styles.infoLabel}>Nom d'affichage</Text>
|
||||
{isEditing ? (
|
||||
<Input
|
||||
placeholder="Entrez le nom d'affichage"
|
||||
value={displayName}
|
||||
onChangeText={setDisplayName}
|
||||
containerStyle={styles.inputContainer}
|
||||
inputStyle={styles.inputText}
|
||||
autoFocus
|
||||
/>
|
||||
) : (
|
||||
<Text style={styles.infoValue}>
|
||||
{user.name || "Non défini"}
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
<TouchableOpacity
|
||||
style={styles.editButton}
|
||||
onPress={() => {
|
||||
if (isEditing) {
|
||||
handleSaveDisplayName();
|
||||
} else {
|
||||
setDisplayName(user.name ?? "");
|
||||
setIsEditing(true);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{isEditing ? (
|
||||
<Check size={18} color="#10b981" />
|
||||
) : (
|
||||
<Edit3 size={18} color="#6b7280" />
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
{index < menuItems.length - 1 && <View style={styles.divider} />}
|
||||
</View>
|
||||
))}
|
||||
</Card>
|
||||
</Card>
|
||||
|
||||
{/* Bouton de déconnexion */}
|
||||
<TouchableOpacity style={styles.signOutContainer} onPress={signOut}>
|
||||
<LinearGradient
|
||||
colors={["#ef4444", "#dc2626"]}
|
||||
style={styles.signOutGradient}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 0 }}
|
||||
>
|
||||
<LogOut size={20} color="white" />
|
||||
<Text style={styles.signOutText}>Se déconnecter</Text>
|
||||
</LinearGradient>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</ScrollView>
|
||||
{/* Éléments de menu */}
|
||||
<Card containerStyle={styles.menuCard}>
|
||||
<View style={styles.cardHeader}>
|
||||
<Settings size={20} color="#3b82f6" />
|
||||
<Text style={styles.cardHeaderTitle}>Préférences</Text>
|
||||
</View>
|
||||
|
||||
{menuItems.map((item, index) => (
|
||||
<View key={index}>
|
||||
<TouchableOpacity
|
||||
style={styles.menuItem}
|
||||
onPress={item.onPress}
|
||||
>
|
||||
<View style={styles.menuIconContainer}>
|
||||
<item.icon size={20} color="#6b7280" />
|
||||
</View>
|
||||
<View style={styles.menuContent}>
|
||||
<Text style={styles.menuTitle}>{item.title}</Text>
|
||||
<Text style={styles.menuSubtitle}>{item.subtitle}</Text>
|
||||
</View>
|
||||
<Text style={styles.menuArrow}>›</Text>
|
||||
</TouchableOpacity>
|
||||
{index < menuItems.length - 1 && (
|
||||
<View style={styles.divider} />
|
||||
)}
|
||||
</View>
|
||||
))}
|
||||
</Card>
|
||||
|
||||
{/* Bouton de déconnexion */}
|
||||
<TouchableOpacity style={styles.signOutContainer} onPress={signOut}>
|
||||
<LinearGradient
|
||||
colors={["#ef4444", "#dc2626"]}
|
||||
style={styles.signOutGradient}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 0 }}
|
||||
>
|
||||
<LogOut size={20} color="white" />
|
||||
<Text style={styles.signOutText}>Se déconnecter</Text>
|
||||
</LinearGradient>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</ScrollView>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ import { Link } from "expo-router";
|
|||
import { Mail, Lock } from "lucide-react-native";
|
||||
import { GoogleLoginButton } from "@/components/GoogleLoginButton";
|
||||
import { AppleLoginButton } from "@/components/AppleLoginButton";
|
||||
import { useThemeColor } from "@/hooks/useThemeColor";
|
||||
import { useColorScheme } from "@/hooks/useColorScheme";
|
||||
|
||||
export default function Auth() {
|
||||
const [email, setEmail] = useState("");
|
||||
|
|
@ -14,12 +16,34 @@ export default function Auth() {
|
|||
const login = useAuthStore((state) => state.login);
|
||||
const authLoading = useAuthStore((state) => state.loading);
|
||||
const performOAuth = useAuthStore((state) => state.performOAuth);
|
||||
const colorScheme = useColorScheme();
|
||||
|
||||
// Theme-aware colors
|
||||
const backgroundColor = useThemeColor(
|
||||
{ light: "#f5f5f5", dark: "#111827" },
|
||||
"background"
|
||||
);
|
||||
const textColor = useThemeColor({ light: "#333", dark: "#f9fafb" }, "text");
|
||||
const subtitleColor = useThemeColor(
|
||||
{ light: "#666", dark: "#9ca3af" },
|
||||
"text"
|
||||
);
|
||||
const separatorColor = useThemeColor(
|
||||
{ light: "#ddd", dark: "#374151" },
|
||||
"text"
|
||||
);
|
||||
const linkColor = useThemeColor(
|
||||
{ light: "#3b82f6", dark: "#60a5fa" },
|
||||
"text"
|
||||
);
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View style={[styles.container, { backgroundColor }]}>
|
||||
<Image source={require("@/assets/images/logo.png")} style={styles.logo} />
|
||||
<Text style={styles.title}>Connexion XTablo</Text>
|
||||
<Text style={styles.subtitle}>Connectez-vous à votre compte</Text>
|
||||
<Text style={[styles.title, { color: textColor }]}>Connexion XTablo</Text>
|
||||
<Text style={[styles.subtitle, { color: subtitleColor }]}>
|
||||
Connectez-vous à votre compte
|
||||
</Text>
|
||||
<View style={[styles.verticallySpaced, styles.mt10]}>
|
||||
<Input
|
||||
label="Adresse email"
|
||||
|
|
@ -51,9 +75,9 @@ export default function Auth() {
|
|||
/>
|
||||
</View>
|
||||
<View style={styles.separatorContainer}>
|
||||
<View style={styles.separator} />
|
||||
<Text style={styles.separatorText}>ou</Text>
|
||||
<View style={styles.separator} />
|
||||
<View style={[styles.separator, { backgroundColor: separatorColor }]} />
|
||||
<Text style={[styles.separatorText, { color: subtitleColor }]}>ou</Text>
|
||||
<View style={[styles.separator, { backgroundColor: separatorColor }]} />
|
||||
</View>
|
||||
<View style={styles.verticallySpaced}>
|
||||
<GoogleLoginButton onPress={() => performOAuth("google")} />
|
||||
|
|
@ -62,8 +86,10 @@ export default function Auth() {
|
|||
<AppleLoginButton onPress={() => performOAuth("apple")} />
|
||||
</View>
|
||||
<View style={styles.linkContainer}>
|
||||
<Text style={styles.linkText}>Pas encore de compte ? </Text>
|
||||
<Link href="/signup" style={styles.link}>
|
||||
<Text style={[styles.linkText, { color: subtitleColor }]}>
|
||||
Pas encore de compte ?{" "}
|
||||
</Text>
|
||||
<Link href="/signup" style={[styles.link, { color: linkColor }]}>
|
||||
S'inscrire
|
||||
</Link>
|
||||
</View>
|
||||
|
|
@ -76,7 +102,6 @@ const styles = StyleSheet.create({
|
|||
flex: 1,
|
||||
justifyContent: "center",
|
||||
padding: 16,
|
||||
backgroundColor: "#f5f5f5", // Light grey background
|
||||
},
|
||||
logo: {
|
||||
width: 80,
|
||||
|
|
@ -90,13 +115,11 @@ const styles = StyleSheet.create({
|
|||
fontWeight: "bold",
|
||||
textAlign: "center",
|
||||
marginBottom: 3,
|
||||
color: "#333",
|
||||
},
|
||||
subtitle: {
|
||||
fontSize: 14,
|
||||
textAlign: "center",
|
||||
marginBottom: 16,
|
||||
color: "#666",
|
||||
},
|
||||
verticallySpaced: {
|
||||
paddingTop: 2,
|
||||
|
|
@ -132,11 +155,9 @@ const styles = StyleSheet.create({
|
|||
separator: {
|
||||
flex: 1,
|
||||
height: 1,
|
||||
backgroundColor: "#ddd",
|
||||
},
|
||||
separatorText: {
|
||||
marginHorizontal: 15,
|
||||
color: "#666",
|
||||
fontSize: 14,
|
||||
},
|
||||
linkContainer: {
|
||||
|
|
@ -144,11 +165,8 @@ const styles = StyleSheet.create({
|
|||
justifyContent: "center",
|
||||
marginTop: 12,
|
||||
},
|
||||
linkText: {
|
||||
color: "#666",
|
||||
},
|
||||
linkText: {},
|
||||
link: {
|
||||
color: "#007bff",
|
||||
fontWeight: "bold",
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { Button, Input } from "@rn-vui/themed";
|
|||
import { useAuthStore } from "@/stores/auth";
|
||||
import { Link } from "expo-router";
|
||||
import { Mail, Lock, User, Building2 } from "lucide-react-native";
|
||||
import { useThemeColor } from "@/hooks/useThemeColor";
|
||||
|
||||
export default function SignUp() {
|
||||
const [firstName, setFirstName] = useState("");
|
||||
|
|
@ -15,11 +16,30 @@ export default function SignUp() {
|
|||
const signUp = useAuthStore((state) => state.signUp);
|
||||
const authLoading = useAuthStore((state) => state.loading);
|
||||
|
||||
// Theme-aware colors
|
||||
const backgroundColor = useThemeColor(
|
||||
{ light: "#f5f5f5", dark: "#111827" },
|
||||
"background"
|
||||
);
|
||||
const textColor = useThemeColor({ light: "#333", dark: "#f9fafb" }, "text");
|
||||
const subtitleColor = useThemeColor(
|
||||
{ light: "#666", dark: "#9ca3af" },
|
||||
"text"
|
||||
);
|
||||
const linkColor = useThemeColor(
|
||||
{ light: "#3b82f6", dark: "#60a5fa" },
|
||||
"text"
|
||||
);
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View style={[styles.container, { backgroundColor }]}>
|
||||
<Image source={require("@/assets/images/logo.png")} style={styles.logo} />
|
||||
<Text style={styles.title}>Créer un compte XTablo</Text>
|
||||
<Text style={styles.subtitle}>Rejoignez-nous !</Text>
|
||||
<Text style={[styles.title, { color: textColor }]}>
|
||||
Créer un compte XTablo
|
||||
</Text>
|
||||
<Text style={[styles.subtitle, { color: subtitleColor }]}>
|
||||
Rejoignez-nous !
|
||||
</Text>
|
||||
<View style={[styles.verticallySpaced, styles.mt10]}>
|
||||
<Input
|
||||
label="Prénom"
|
||||
|
|
@ -84,8 +104,10 @@ export default function SignUp() {
|
|||
/>
|
||||
</View>
|
||||
<View style={styles.linkContainer}>
|
||||
<Text style={styles.linkText}>Vous avez déjà un compte ? </Text>
|
||||
<Link href="/login" style={styles.link}>
|
||||
<Text style={[styles.linkText, { color: subtitleColor }]}>
|
||||
Vous avez déjà un compte ?{" "}
|
||||
</Text>
|
||||
<Link href="/login" style={[styles.link, { color: linkColor }]}>
|
||||
Se connecter
|
||||
</Link>
|
||||
</View>
|
||||
|
|
@ -99,7 +121,6 @@ const styles = StyleSheet.create({
|
|||
flex: 1,
|
||||
justifyContent: "center",
|
||||
padding: 16,
|
||||
backgroundColor: "#f5f5f5", // Light grey background
|
||||
},
|
||||
logo: {
|
||||
width: 80,
|
||||
|
|
@ -113,13 +134,11 @@ const styles = StyleSheet.create({
|
|||
fontWeight: "bold",
|
||||
textAlign: "center",
|
||||
marginBottom: 3,
|
||||
color: "#333",
|
||||
},
|
||||
subtitle: {
|
||||
fontSize: 14,
|
||||
textAlign: "center",
|
||||
marginBottom: 16,
|
||||
color: "#666",
|
||||
},
|
||||
verticallySpaced: {
|
||||
paddingTop: 2,
|
||||
|
|
@ -167,11 +186,8 @@ const styles = StyleSheet.create({
|
|||
justifyContent: "center",
|
||||
marginTop: 12,
|
||||
},
|
||||
linkText: {
|
||||
color: "#666",
|
||||
},
|
||||
linkText: {},
|
||||
link: {
|
||||
color: "#007bff",
|
||||
fontWeight: "bold",
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -9,11 +9,26 @@ import Animated, {
|
|||
} from "react-native-reanimated";
|
||||
import { ThemedView } from "@/components/ThemedView";
|
||||
import { ThemedText } from "@/components/ThemedText";
|
||||
import { useThemeColor } from "@/hooks/useThemeColor";
|
||||
|
||||
export const LoadingView = () => {
|
||||
const rotation = useSharedValue(0);
|
||||
const width = useSharedValue(80);
|
||||
|
||||
// Theme-aware colors
|
||||
const backgroundColor = useThemeColor(
|
||||
{ light: "#f8fafc", dark: "#111827" },
|
||||
"background"
|
||||
);
|
||||
const textColor = useThemeColor(
|
||||
{ light: "#1f2937", dark: "#f9fafb" },
|
||||
"text"
|
||||
);
|
||||
const subtitleColor = useThemeColor(
|
||||
{ light: "#6b7280", dark: "#9ca3af" },
|
||||
"text"
|
||||
);
|
||||
|
||||
rotation.value = withRepeat(
|
||||
withTiming(360, { easing: Easing.linear, duration: 2000 }),
|
||||
-1,
|
||||
|
|
@ -37,7 +52,7 @@ export const LoadingView = () => {
|
|||
});
|
||||
|
||||
return (
|
||||
<ThemedView style={styles.loadingContainer}>
|
||||
<ThemedView style={[styles.loadingContainer, { backgroundColor }]}>
|
||||
<View style={styles.loadingContent}>
|
||||
<View style={styles.logoContainer}>
|
||||
<Animated.Image
|
||||
|
|
@ -45,10 +60,13 @@ export const LoadingView = () => {
|
|||
style={[styles.logo, animatedStyle]}
|
||||
/>
|
||||
</View>
|
||||
<ThemedText type="title" style={styles.title}>
|
||||
<ThemedText type="title" style={[styles.title, { color: textColor }]}>
|
||||
XTablo
|
||||
</ThemedText>
|
||||
<ThemedText type="subtitle" style={styles.subtitle}>
|
||||
<ThemedText
|
||||
type="subtitle"
|
||||
style={[styles.subtitle, { color: subtitleColor }]}
|
||||
>
|
||||
Initialisation de l'application...
|
||||
</ThemedText>
|
||||
</View>
|
||||
|
|
@ -61,7 +79,6 @@ const styles = StyleSheet.create({
|
|||
flex: 1,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
backgroundColor: "#f8fafc",
|
||||
},
|
||||
loadingContent: {
|
||||
alignItems: "center",
|
||||
|
|
@ -86,13 +103,11 @@ const styles = StyleSheet.create({
|
|||
fontWeight: "bold",
|
||||
textAlign: "center",
|
||||
marginBottom: 8,
|
||||
color: "#1f2937",
|
||||
},
|
||||
subtitle: {
|
||||
fontSize: 16,
|
||||
textAlign: "center",
|
||||
marginBottom: 32,
|
||||
color: "#6b7280",
|
||||
opacity: 0.8,
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ import Animated, {
|
|||
import { Archive } from "lucide-react-native";
|
||||
import { Channel } from "stream-chat";
|
||||
import { DefaultStreamChatGenerics } from "stream-chat-expo";
|
||||
import { useThemeColor } from "@/hooks/useThemeColor";
|
||||
import { useColorScheme } from "@/hooks/useColorScheme";
|
||||
|
||||
interface SwipeableChannelPreviewProps {
|
||||
channel: Channel<DefaultStreamChatGenerics>;
|
||||
|
|
@ -32,6 +34,19 @@ export const SwipeableChannelPreview: React.FC<
|
|||
SwipeableChannelPreviewProps
|
||||
> = ({ channel, children }) => {
|
||||
const translateX = useSharedValue(0);
|
||||
const colorScheme = useColorScheme();
|
||||
|
||||
// Theme-aware colors
|
||||
const backgroundColor = useThemeColor(
|
||||
{ light: "#ffffff", dark: "#1f1f1f" },
|
||||
"background"
|
||||
);
|
||||
const textColor = useThemeColor(
|
||||
{ light: "#ffffff", dark: "#ffffff" },
|
||||
"text"
|
||||
);
|
||||
const archiveButtonColor = colorScheme === "dark" ? "#0f4a3c" : "#166534";
|
||||
const iconColor = "#ffffff";
|
||||
|
||||
const handleArchiveChannel = async () => {
|
||||
try {
|
||||
|
|
@ -136,17 +151,31 @@ export const SwipeableChannelPreview: React.FC<
|
|||
<View style={styles.container}>
|
||||
{/* Right Actions Background */}
|
||||
<View style={styles.rightActionsContainer}>
|
||||
<Pressable style={styles.archiveButton} onPress={onArchivePress}>
|
||||
<Pressable
|
||||
style={[
|
||||
styles.archiveButton,
|
||||
{ backgroundColor: archiveButtonColor },
|
||||
]}
|
||||
onPress={onArchivePress}
|
||||
>
|
||||
<Animated.View style={[styles.actionContent, actionAnimatedStyle]}>
|
||||
<Archive size={24} color="white" />
|
||||
<Text style={styles.actionText}>Archiver</Text>
|
||||
<Archive size={24} color={iconColor} />
|
||||
<Text style={[styles.actionText, { color: textColor }]}>
|
||||
Archiver
|
||||
</Text>
|
||||
</Animated.View>
|
||||
</Pressable>
|
||||
</View>
|
||||
|
||||
{/* Channel Content */}
|
||||
<GestureDetector gesture={gestureHandler}>
|
||||
<Animated.View style={[styles.channelContainer, channelAnimatedStyle]}>
|
||||
<Animated.View
|
||||
style={[
|
||||
styles.channelContainer,
|
||||
channelAnimatedStyle,
|
||||
{ backgroundColor },
|
||||
]}
|
||||
>
|
||||
{children}
|
||||
</Animated.View>
|
||||
</GestureDetector>
|
||||
|
|
@ -160,7 +189,6 @@ const styles = StyleSheet.create({
|
|||
position: "relative",
|
||||
},
|
||||
channelContainer: {
|
||||
backgroundColor: "white",
|
||||
flex: 1,
|
||||
},
|
||||
rightActionsContainer: {
|
||||
|
|
@ -173,7 +201,6 @@ const styles = StyleSheet.create({
|
|||
alignItems: "center",
|
||||
},
|
||||
archiveButton: {
|
||||
backgroundColor: "#166534", // Dark green color for archive
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
width: ACTION_WIDTH,
|
||||
|
|
@ -186,7 +213,6 @@ const styles = StyleSheet.create({
|
|||
gap: 4,
|
||||
},
|
||||
actionText: {
|
||||
color: "white",
|
||||
fontSize: 12,
|
||||
fontWeight: "600",
|
||||
textAlign: "center",
|
||||
|
|
|
|||
|
|
@ -2,6 +2,10 @@ import { ActivityIndicator, View } from "react-native";
|
|||
import { Chat, OverlayProvider, useCreateChatClient } from "stream-chat-expo";
|
||||
import { useUser } from "@/providers/UserProvider";
|
||||
import { Text } from "react-native";
|
||||
import { useThemeColor } from "@/hooks/useThemeColor";
|
||||
import { useColorScheme } from "@/hooks/useColorScheme";
|
||||
import { useMemo } from "react";
|
||||
import type { DeepPartial, Theme } from "stream-chat-expo";
|
||||
|
||||
export default function ChatProvider({
|
||||
children,
|
||||
|
|
@ -9,6 +13,92 @@ export default function ChatProvider({
|
|||
children: React.ReactNode;
|
||||
}) {
|
||||
const user = useUser();
|
||||
const colorScheme = useColorScheme();
|
||||
|
||||
// Theme-aware colors
|
||||
const backgroundColor = useThemeColor(
|
||||
{ light: "#f8fafc", dark: "#111827" },
|
||||
"background"
|
||||
);
|
||||
const textColor = useThemeColor(
|
||||
{ light: "#1f2937", dark: "#f9fafb" },
|
||||
"text"
|
||||
);
|
||||
|
||||
// Aggressive Stream Chat theme to force correct backgrounds
|
||||
const streamChatTheme: DeepPartial<Theme> = useMemo(
|
||||
() => ({
|
||||
colors: {
|
||||
// Force ALL background-related colors to match page background
|
||||
white: backgroundColor,
|
||||
white_snow: backgroundColor,
|
||||
white_smoke: backgroundColor,
|
||||
grey_whisper: backgroundColor,
|
||||
// Keep text colors appropriate
|
||||
black: colorScheme === "dark" ? "#f9fafb" : "#1f2937",
|
||||
grey: colorScheme === "dark" ? "#9ca3af" : "#6b7280",
|
||||
grey_gainsboro: colorScheme === "dark" ? "#4b5563" : "#9ca3af",
|
||||
|
||||
// Accent colors
|
||||
accent_blue: "#3b82f6",
|
||||
accent_green: "#10b981",
|
||||
accent_red: "#ef4444",
|
||||
|
||||
// Overlays
|
||||
overlay:
|
||||
colorScheme === "dark" ? "rgba(0, 0, 0, 0.8)" : "rgba(0, 0, 0, 0.3)",
|
||||
// Border colors
|
||||
border: colorScheme === "dark" ? "#374151" : "#e5e7eb",
|
||||
},
|
||||
|
||||
// Force channel list backgrounds
|
||||
channelListMessenger: {
|
||||
flatList: {
|
||||
backgroundColor: backgroundColor,
|
||||
},
|
||||
flatListContent: {
|
||||
backgroundColor: backgroundColor,
|
||||
},
|
||||
container: {
|
||||
backgroundColor: backgroundColor,
|
||||
},
|
||||
},
|
||||
|
||||
// Force channel preview backgrounds
|
||||
channelPreview: {
|
||||
container: {
|
||||
backgroundColor: backgroundColor,
|
||||
},
|
||||
title: {
|
||||
color: colorScheme === "dark" ? "#f9fafb" : "#1f2937",
|
||||
},
|
||||
message: {
|
||||
color: colorScheme === "dark" ? "#9ca3af" : "#6b7280",
|
||||
},
|
||||
date: {
|
||||
color: colorScheme === "dark" ? "#6b7280" : "#9ca3af",
|
||||
},
|
||||
},
|
||||
|
||||
// Force message backgrounds
|
||||
messageSimple: {
|
||||
content: {
|
||||
container: {
|
||||
backgroundColor: backgroundColor,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// Force input backgrounds
|
||||
messageInput: {
|
||||
container: {
|
||||
backgroundColor: backgroundColor,
|
||||
borderTopColor: colorScheme === "dark" ? "#374151" : "#e5e7eb",
|
||||
},
|
||||
},
|
||||
}),
|
||||
[colorScheme, backgroundColor]
|
||||
);
|
||||
|
||||
const client = useCreateChatClient({
|
||||
apiKey: process.env.EXPO_PUBLIC_STREAM_CHAT_API_KEY as string,
|
||||
|
|
@ -22,8 +112,15 @@ export default function ChatProvider({
|
|||
|
||||
if (!user.streamToken) {
|
||||
return (
|
||||
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
|
||||
<Text>Chat Indisponible</Text>
|
||||
<View
|
||||
style={{
|
||||
flex: 1,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
backgroundColor,
|
||||
}}
|
||||
>
|
||||
<Text style={{ color: textColor }}>Chat Indisponible</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
|
@ -33,7 +130,7 @@ export default function ChatProvider({
|
|||
}
|
||||
|
||||
return (
|
||||
<OverlayProvider>
|
||||
<OverlayProvider value={{ style: streamChatTheme }}>
|
||||
<Chat client={client}>{children}</Chat>
|
||||
</OverlayProvider>
|
||||
);
|
||||
|
|
|
|||
Loading…
Reference in a new issue