Big improvements on the app
This commit is contained in:
parent
af75776dae
commit
5edc860019
19 changed files with 1884 additions and 140 deletions
|
|
@ -17,7 +17,7 @@ export default function Auth() {
|
|||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Image source={require("@/assets/images/logo.jpg")} style={styles.logo} />
|
||||
<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>
|
||||
<View style={[styles.verticallySpaced, styles.mt10]}>
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ export default function SignUp() {
|
|||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Image source={require("@/assets/images/logo.jpg")} style={styles.logo} />
|
||||
<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>
|
||||
<View style={[styles.verticallySpaced, styles.mt10]}>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { HapticTab } from "@/components/HapticTab";
|
|||
import TabBarBackground from "@/components/ui/TabBarBackground";
|
||||
import { Colors } from "@/constants/Colors";
|
||||
import { useColorScheme } from "@/hooks/useColorScheme";
|
||||
import { Home, User } from "lucide-react-native";
|
||||
import { MessageCircle, Calendar, User } from "lucide-react-native";
|
||||
|
||||
export default function TabLayout() {
|
||||
const colorScheme = useColorScheme();
|
||||
|
|
@ -13,7 +13,7 @@ export default function TabLayout() {
|
|||
<Tabs
|
||||
screenOptions={{
|
||||
tabBarActiveTintColor: Colors[colorScheme ?? "light"].tint,
|
||||
headerShown: true,
|
||||
headerShown: false,
|
||||
tabBarButton: HapticTab,
|
||||
tabBarBackground: TabBarBackground,
|
||||
}}
|
||||
|
|
@ -21,8 +21,19 @@ export default function TabLayout() {
|
|||
<Tabs.Screen
|
||||
name="index"
|
||||
options={{
|
||||
title: "Home",
|
||||
tabBarIcon: ({ size, color }) => <Home size={size} color={color} />,
|
||||
title: "Discussions",
|
||||
tabBarIcon: ({ size, color }) => (
|
||||
<MessageCircle size={size} color={color} />
|
||||
),
|
||||
}}
|
||||
/>
|
||||
<Tabs.Screen
|
||||
name="planning"
|
||||
options={{
|
||||
title: "Planning",
|
||||
tabBarIcon: ({ size, color }) => (
|
||||
<Calendar size={size} color={color} />
|
||||
),
|
||||
}}
|
||||
/>
|
||||
<Tabs.Screen
|
||||
|
|
|
|||
1360
xtablo-expo/app/(home)/(tabs)/planning.tsx
Normal file
1360
xtablo-expo/app/(home)/(tabs)/planning.tsx
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1,9 +1,25 @@
|
|||
import { View, StyleSheet } from "react-native";
|
||||
import {
|
||||
View,
|
||||
StyleSheet,
|
||||
ScrollView,
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
} from "react-native";
|
||||
import { useAuth } from "@/stores/auth";
|
||||
import { Avatar, Button, Input } from "@rn-vui/themed";
|
||||
import { Card, ListItem } from "@rn-vui/themed";
|
||||
import { Avatar, Input } from "@rn-vui/themed";
|
||||
import { Card } from "@rn-vui/themed";
|
||||
import { useState } from "react";
|
||||
import { useUser } from "@/providers/UserProvider";
|
||||
import { LinearGradient } from "expo-linear-gradient";
|
||||
import {
|
||||
User,
|
||||
Mail,
|
||||
Edit3,
|
||||
Check,
|
||||
LogOut,
|
||||
Settings,
|
||||
Shield,
|
||||
} from "lucide-react-native";
|
||||
|
||||
export default function ProfileScreen() {
|
||||
const signOut = useAuth((state) => state.signOut);
|
||||
|
|
@ -12,145 +28,334 @@ export default function ProfileScreen() {
|
|||
const [displayName, setDisplayName] = useState(user.name || "");
|
||||
const [isEditing, setIsEditing] = useState(false);
|
||||
|
||||
const handleSaveDisplayName = () => {
|
||||
// TODO: Implémenter la fonctionnalité de sauvegarde
|
||||
setIsEditing(false);
|
||||
};
|
||||
|
||||
const menuItems = [
|
||||
{
|
||||
icon: Settings,
|
||||
title: "Paramètres du compte",
|
||||
subtitle: "Gérez vos préférences de compte",
|
||||
onPress: () => console.log("Paramètres"),
|
||||
},
|
||||
{
|
||||
icon: Shield,
|
||||
title: "Confidentialité et sécurité",
|
||||
subtitle: "Contrôlez vos paramètres de confidentialité",
|
||||
onPress: () => console.log("Confidentialité"),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Card containerStyle={styles.card}>
|
||||
<Avatar
|
||||
size="xlarge"
|
||||
rounded
|
||||
icon={{ name: "user", type: "font-awesome" }}
|
||||
containerStyle={styles.avatar}
|
||||
/>
|
||||
|
||||
<Card.Title style={styles.cardTitle}>{user.name}</Card.Title>
|
||||
<Card.Divider />
|
||||
|
||||
<ListItem key="email" bottomDivider containerStyle={styles.listItem}>
|
||||
<ListItem.Content>
|
||||
<ListItem.Title style={styles.listItemTitle}>Email</ListItem.Title>
|
||||
<ListItem.Subtitle style={styles.listItemSubtitle}>
|
||||
{user.email}
|
||||
</ListItem.Subtitle>
|
||||
</ListItem.Content>
|
||||
</ListItem>
|
||||
|
||||
<ListItem
|
||||
key="display-name"
|
||||
bottomDivider
|
||||
containerStyle={styles.listItem}
|
||||
>
|
||||
<ListItem.Content>
|
||||
<ListItem.Title style={styles.listItemTitle}>
|
||||
Display Name
|
||||
</ListItem.Title>
|
||||
{isEditing ? (
|
||||
<Input
|
||||
placeholder="Enter display name"
|
||||
value={displayName}
|
||||
onChangeText={setDisplayName}
|
||||
containerStyle={styles.inputContainer}
|
||||
inputStyle={styles.inputText}
|
||||
autoFocus
|
||||
/>
|
||||
) : (
|
||||
<ListItem.Subtitle style={styles.listItemSubtitle}>
|
||||
{user.name || "Not Set"}
|
||||
</ListItem.Subtitle>
|
||||
)}
|
||||
</ListItem.Content>
|
||||
<Button
|
||||
icon={{
|
||||
name: isEditing ? "check" : "edit",
|
||||
type: "font-awesome",
|
||||
size: 18,
|
||||
}}
|
||||
type="clear"
|
||||
onPress={() => {
|
||||
if (isEditing) {
|
||||
// handleSaveDisplayName();
|
||||
} else {
|
||||
setDisplayName(user.name ?? "");
|
||||
setIsEditing(true);
|
||||
}
|
||||
}}
|
||||
<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}
|
||||
/>
|
||||
</ListItem>
|
||||
<Text style={styles.userName}>{user.name || "Utilisateur"}</Text>
|
||||
<Text style={styles.userEmail}>{user.email}</Text>
|
||||
</View>
|
||||
</LinearGradient>
|
||||
|
||||
<Button
|
||||
title="Sign Out"
|
||||
onPress={signOut}
|
||||
buttonStyle={styles.signOutButton}
|
||||
titleStyle={styles.signOutText}
|
||||
icon={{
|
||||
name: "sign-out",
|
||||
type: "font-awesome",
|
||||
color: "white",
|
||||
size: 18,
|
||||
}}
|
||||
iconRight
|
||||
/>
|
||||
</Card>
|
||||
</View>
|
||||
{/* 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.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 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>
|
||||
</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>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
padding: 15,
|
||||
backgroundColor: "#f8f9fa",
|
||||
backgroundColor: "#f8fafc",
|
||||
},
|
||||
card: {
|
||||
borderRadius: 10,
|
||||
headerGradient: {
|
||||
paddingTop: 60,
|
||||
paddingBottom: 40,
|
||||
paddingHorizontal: 20,
|
||||
},
|
||||
headerContent: {
|
||||
alignItems: "center",
|
||||
},
|
||||
avatar: {
|
||||
marginBottom: 16,
|
||||
shadowColor: "#000",
|
||||
shadowOffset: { width: 0, height: 4 },
|
||||
shadowOpacity: 0.3,
|
||||
shadowRadius: 8,
|
||||
elevation: 8,
|
||||
borderWidth: 4,
|
||||
borderColor: "white",
|
||||
},
|
||||
userName: {
|
||||
fontSize: 24,
|
||||
fontWeight: "bold",
|
||||
color: "white",
|
||||
marginBottom: 4,
|
||||
textAlign: "center",
|
||||
},
|
||||
userEmail: {
|
||||
fontSize: 16,
|
||||
color: "rgba(255, 255, 255, 0.9)",
|
||||
textAlign: "center",
|
||||
},
|
||||
content: {
|
||||
padding: 20,
|
||||
margin: 0,
|
||||
marginTop: -20,
|
||||
},
|
||||
mainCard: {
|
||||
borderRadius: 16,
|
||||
padding: 0,
|
||||
marginBottom: 20,
|
||||
shadowColor: "#000",
|
||||
shadowOffset: { width: 0, height: 2 },
|
||||
shadowOpacity: 0.1,
|
||||
shadowRadius: 4,
|
||||
elevation: 3,
|
||||
shadowRadius: 8,
|
||||
elevation: 4,
|
||||
borderWidth: 0,
|
||||
},
|
||||
avatar: {
|
||||
menuCard: {
|
||||
borderRadius: 16,
|
||||
padding: 0,
|
||||
marginBottom: 20,
|
||||
backgroundColor: "#e0e0e0",
|
||||
shadowColor: "#000",
|
||||
shadowOffset: { width: 0, height: 2 },
|
||||
shadowOpacity: 0.1,
|
||||
shadowRadius: 8,
|
||||
elevation: 4,
|
||||
borderWidth: 0,
|
||||
},
|
||||
cardTitle: {
|
||||
fontSize: 20,
|
||||
fontWeight: "bold",
|
||||
marginBottom: 15,
|
||||
cardHeader: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
padding: 20,
|
||||
paddingBottom: 16,
|
||||
},
|
||||
listItem: {
|
||||
paddingVertical: 15,
|
||||
width: "100%",
|
||||
},
|
||||
listItemTitle: {
|
||||
cardHeaderTitle: {
|
||||
fontSize: 18,
|
||||
fontWeight: "600",
|
||||
marginBottom: 5,
|
||||
color: "#555",
|
||||
color: "#1f2937",
|
||||
marginLeft: 12,
|
||||
},
|
||||
listItemSubtitle: {
|
||||
color: "#333",
|
||||
infoItem: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
paddingHorizontal: 20,
|
||||
paddingVertical: 16,
|
||||
},
|
||||
infoIconContainer: {
|
||||
width: 40,
|
||||
height: 40,
|
||||
borderRadius: 20,
|
||||
backgroundColor: "#f3f4f6",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
marginRight: 12,
|
||||
},
|
||||
infoContent: {
|
||||
flex: 1,
|
||||
},
|
||||
infoLabel: {
|
||||
fontSize: 14,
|
||||
color: "#6b7280",
|
||||
marginBottom: 4,
|
||||
fontWeight: "500",
|
||||
},
|
||||
infoValue: {
|
||||
fontSize: 16,
|
||||
color: "#1f2937",
|
||||
fontWeight: "500",
|
||||
},
|
||||
editButton: {
|
||||
width: 36,
|
||||
height: 36,
|
||||
borderRadius: 18,
|
||||
backgroundColor: "#f3f4f6",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
},
|
||||
inputContainer: {
|
||||
paddingHorizontal: 0,
|
||||
height: 40,
|
||||
marginTop: 4,
|
||||
},
|
||||
inputText: {
|
||||
fontSize: 16,
|
||||
color: "#1f2937",
|
||||
},
|
||||
signOutButton: {
|
||||
marginTop: 30,
|
||||
backgroundColor: "#dc3545",
|
||||
paddingVertical: 12,
|
||||
divider: {
|
||||
height: 1,
|
||||
backgroundColor: "#e5e7eb",
|
||||
marginLeft: 72,
|
||||
},
|
||||
menuItem: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
paddingHorizontal: 20,
|
||||
borderRadius: 8,
|
||||
width: "80%",
|
||||
paddingVertical: 16,
|
||||
},
|
||||
menuIconContainer: {
|
||||
width: 40,
|
||||
height: 40,
|
||||
borderRadius: 20,
|
||||
backgroundColor: "#f3f4f6",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
marginRight: 12,
|
||||
},
|
||||
menuContent: {
|
||||
flex: 1,
|
||||
},
|
||||
menuTitle: {
|
||||
fontSize: 16,
|
||||
fontWeight: "500",
|
||||
color: "#1f2937",
|
||||
marginBottom: 2,
|
||||
},
|
||||
menuSubtitle: {
|
||||
fontSize: 14,
|
||||
color: "#6b7280",
|
||||
},
|
||||
menuArrow: {
|
||||
fontSize: 20,
|
||||
color: "#9ca3af",
|
||||
fontWeight: "300",
|
||||
},
|
||||
signOutContainer: {
|
||||
marginTop: 10,
|
||||
marginBottom: 40,
|
||||
},
|
||||
signOutGradient: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
paddingVertical: 16,
|
||||
paddingHorizontal: 24,
|
||||
borderRadius: 12,
|
||||
shadowColor: "#ef4444",
|
||||
shadowOffset: { width: 0, height: 4 },
|
||||
shadowOpacity: 0.3,
|
||||
shadowRadius: 8,
|
||||
elevation: 6,
|
||||
},
|
||||
signOutText: {
|
||||
color: "#fff",
|
||||
color: "white",
|
||||
fontSize: 16,
|
||||
fontWeight: "600",
|
||||
marginLeft: 10,
|
||||
marginLeft: 8,
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import {
|
|||
ThemeProvider,
|
||||
} from "@react-navigation/native";
|
||||
import { useFonts } from "expo-font";
|
||||
import { router, Stack } from "expo-router";
|
||||
import { Stack } from "expo-router";
|
||||
import * as SplashScreen from "expo-splash-screen";
|
||||
import { StatusBar } from "expo-status-bar";
|
||||
import { useEffect } from "react";
|
||||
|
|
@ -23,9 +23,10 @@ SplashScreen.preventAutoHideAsync();
|
|||
const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
staleTime: 5 * 60 * 1000, // 5 minutes
|
||||
retry: 1,
|
||||
refetchOnWindowFocus: false,
|
||||
// 3 total attempts (1 initial + 2 retries)
|
||||
retry: 2,
|
||||
// 0s -> 1s, 1s → 5s. Little resiliency 😁
|
||||
retryDelay: (attemptIndex) => Math.min(1000 * 5 ** attemptIndex, 10000),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 22 KiB |
BIN
xtablo-expo/assets/images/logo.png
Normal file
BIN
xtablo-expo/assets/images/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 84 KiB |
59
xtablo-expo/hooks/events.ts
Normal file
59
xtablo-expo/hooks/events.ts
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { supabase } from "@/lib/supabase";
|
||||
import { EventAndTablo, EventInsert } from "@/types/events.types";
|
||||
import { useUser } from "@/providers/UserProvider";
|
||||
|
||||
export const useEventsByTablo = (tabloId: string | null) => {
|
||||
return useQuery({
|
||||
queryKey: ["events", tabloId],
|
||||
queryFn: async () => {
|
||||
if (!tabloId) {
|
||||
const { data, error } = await supabase
|
||||
.from("events_and_tablos")
|
||||
.select("*")
|
||||
.order("start_date", { ascending: true })
|
||||
.order("start_time", { ascending: true });
|
||||
|
||||
if (error) throw error;
|
||||
return data as EventAndTablo[];
|
||||
}
|
||||
const { data, error } = await supabase
|
||||
.from("events_and_tablos")
|
||||
.select("*")
|
||||
.eq("tablo_id", tabloId)
|
||||
.order("start_date", { ascending: true })
|
||||
.order("start_time", { ascending: true });
|
||||
|
||||
if (error) throw error;
|
||||
return data as EventAndTablo[];
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const useCreateEvent = () => {
|
||||
const user = useUser();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const { mutate } = useMutation({
|
||||
mutationFn: async (event: Omit<EventInsert, "created_by">) => {
|
||||
const { data, error } = await supabase
|
||||
.from("events")
|
||||
.insert({
|
||||
...event,
|
||||
created_by: user.id,
|
||||
})
|
||||
.select()
|
||||
.single();
|
||||
|
||||
if (error) throw error;
|
||||
return data as Event;
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ["events"] });
|
||||
},
|
||||
onError: (err) => {
|
||||
console.error(err);
|
||||
},
|
||||
});
|
||||
return mutate;
|
||||
};
|
||||
50
xtablo-expo/hooks/tablos.ts
Normal file
50
xtablo-expo/hooks/tablos.ts
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
import { supabase } from "@/lib/supabase";
|
||||
import { useUser } from "@/providers/UserProvider";
|
||||
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";
|
||||
|
||||
// type TabloInsert = Tablo["Insert"];
|
||||
// type TabloUpdate = Tablo["Update"];
|
||||
|
||||
// Fetch all tablos
|
||||
export const useTablosList = () => {
|
||||
const user = useUser();
|
||||
return useQuery({
|
||||
queryKey: ["tablos"],
|
||||
queryFn: async () => {
|
||||
const { data, error } = await supabase
|
||||
.from("user_tablos")
|
||||
.select("*")
|
||||
.eq("user_id", user.id);
|
||||
if (error) throw error;
|
||||
const tablos = data as UserTablo[];
|
||||
return tablos;
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const useCreateTablo = () => {
|
||||
const session = useAuth((state) => state.session);
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async (
|
||||
tablo: Pick<TabloInsert, "name" | "color" | "image" | "status">
|
||||
) => {
|
||||
const { data } = await api.post("/api/v1/tablos/create", tablo, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${session?.access_token}`,
|
||||
},
|
||||
});
|
||||
return data;
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ["tablos"] });
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error(error);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
@ -1,31 +1,29 @@
|
|||
import { api } from "@/lib/api";
|
||||
import { Tables } from "@/lib/database.types";
|
||||
import { Tables } from "@/types/database.types";
|
||||
import { useAuth } from "@/stores/auth";
|
||||
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
|
||||
type User = Tables<"profiles"> & {
|
||||
streamToken: string | null;
|
||||
};
|
||||
|
||||
export const useGetUser = (): { user: User | null; isLoading: boolean } => {
|
||||
const { session } = useAuth();
|
||||
const queryClient = useQueryClient();
|
||||
console.log("session in useGetUser", session);
|
||||
const { data, isLoading } = useQuery<User | null>(
|
||||
{
|
||||
queryKey: ["user"],
|
||||
queryFn: async () => {
|
||||
console.log("queryFn");
|
||||
const session = useAuth((state) => state.session);
|
||||
const { data, isLoading } = useQuery<User | null>({
|
||||
queryKey: ["user"],
|
||||
queryFn: async () => {
|
||||
try {
|
||||
const { data: user } = await api.get<User>("/api/v1/users/me", {
|
||||
headers: {
|
||||
Authorization: `Bearer ${session?.access_token}`,
|
||||
},
|
||||
});
|
||||
return user;
|
||||
},
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
queryClient
|
||||
);
|
||||
});
|
||||
|
||||
return { user: data ?? null, isLoading };
|
||||
};
|
||||
|
|
|
|||
11
xtablo-expo/package-lock.json
generated
11
xtablo-expo/package-lock.json
generated
|
|
@ -27,6 +27,7 @@
|
|||
"expo-haptics": "~14.1.4",
|
||||
"expo-image-manipulator": "~13.1.7",
|
||||
"expo-image-picker": "~16.1.4",
|
||||
"expo-linear-gradient": "~14.1.5",
|
||||
"expo-linking": "~7.1.4",
|
||||
"expo-router": "~5.1.3",
|
||||
"expo-secure-store": "~14.2.3",
|
||||
|
|
@ -5597,6 +5598,16 @@
|
|||
"react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/expo-linear-gradient": {
|
||||
"version": "14.1.5",
|
||||
"resolved": "https://registry.npmjs.org/expo-linear-gradient/-/expo-linear-gradient-14.1.5.tgz",
|
||||
"integrity": "sha512-BSN3MkSGLZoHMduEnAgfhoj3xqcDWaoICgIr4cIYEx1GcHfKMhzA/O4mpZJ/WC27BP1rnAqoKfbclk1eA70ndQ==",
|
||||
"peerDependencies": {
|
||||
"expo": "*",
|
||||
"react": "*",
|
||||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/expo-linking": {
|
||||
"version": "7.1.7",
|
||||
"resolved": "https://registry.npmjs.org/expo-linking/-/expo-linking-7.1.7.tgz",
|
||||
|
|
|
|||
|
|
@ -57,7 +57,8 @@
|
|||
"stream-chat-expo": "^6.7.3",
|
||||
"zustand": "^5.0.4",
|
||||
"expo-crypto": "~14.1.5",
|
||||
"expo-auth-session": "~6.2.1"
|
||||
"expo-auth-session": "~6.2.1",
|
||||
"expo-linear-gradient": "~14.1.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.25.2",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { createStore, StoreApi, useStore } from "zustand";
|
||||
import React from "react";
|
||||
import { Tables } from "@/lib/database.types";
|
||||
import { Tables } from "@/types/database.types";
|
||||
import { ActivityIndicator } from "react-native";
|
||||
import { Redirect } from "expo-router";
|
||||
import { useGetUser } from "@/hooks/user";
|
||||
|
|
@ -22,8 +22,6 @@ export const UserStoreProvider = ({
|
|||
return <ActivityIndicator />;
|
||||
}
|
||||
|
||||
console.log("user in UserStoreProvider", user);
|
||||
|
||||
if (!user) {
|
||||
return <Redirect href="/(auth)/login" />;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,15 +38,12 @@ export const useAuth = create<AuthState>((set, get) => ({
|
|||
data: { session },
|
||||
} = await supabase.auth.getSession();
|
||||
|
||||
console.log("session", session);
|
||||
|
||||
set({
|
||||
session,
|
||||
});
|
||||
|
||||
supabase.auth.onAuthStateChange(async (event, session) => {
|
||||
console.log("event", event);
|
||||
queryClient.invalidateQueries();
|
||||
queryClient.invalidateQueries({ queryKey: ["user"] });
|
||||
set({
|
||||
session,
|
||||
});
|
||||
|
|
|
|||
22
xtablo-expo/types/events.types.ts
Normal file
22
xtablo-expo/types/events.types.ts
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import { Tables, TablesInsert, TablesUpdate } from "@/types/database.types";
|
||||
import { RemoveNullFromObject } from "@/types/removeNull";
|
||||
|
||||
export type Event = RemoveNullFromObject<
|
||||
Tables<"events">,
|
||||
"created_at" | "end_time"
|
||||
>;
|
||||
export type EventInsert = TablesInsert<"events">;
|
||||
export type EventUpdate = TablesUpdate<"events">;
|
||||
|
||||
export type EventAndTablo = RemoveNullFromObject<
|
||||
Tables<"events_and_tablos">,
|
||||
| "event_id"
|
||||
| "tablo_id"
|
||||
| "tablo_name"
|
||||
| "tablo_color"
|
||||
| "tablo_status"
|
||||
| "start_time"
|
||||
| "end_time"
|
||||
| "title"
|
||||
| "start_date"
|
||||
>;
|
||||
11
xtablo-expo/types/removeNull.ts
Normal file
11
xtablo-expo/types/removeNull.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
/**
|
||||
* Utility type to remove null from a type
|
||||
*/
|
||||
export type RemoveNull<T> = T extends null ? never : T;
|
||||
|
||||
/**
|
||||
* Utility type to remove null from all properties of an object type
|
||||
*/
|
||||
export type RemoveNullFromObject<T, K extends keyof T = keyof T> = {
|
||||
[L in keyof T]: L extends K ? RemoveNull<T[L]> : T[L];
|
||||
};
|
||||
20
xtablo-expo/types/tablos.types.ts
Normal file
20
xtablo-expo/types/tablos.types.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import { Database } from "@/types/database.types";
|
||||
import { RemoveNullFromObject } from "@/types/removeNull";
|
||||
|
||||
export type UserTablo = RemoveNullFromObject<
|
||||
Database["public"]["Views"]["user_tablos"]["Row"],
|
||||
| "id"
|
||||
| "access_level"
|
||||
| "is_admin"
|
||||
| "created_at"
|
||||
| "deleted_at"
|
||||
| "position"
|
||||
| "user_id"
|
||||
| "name"
|
||||
| "status"
|
||||
>;
|
||||
|
||||
export type Tablo = Database["public"]["Tables"]["tablos"];
|
||||
|
||||
export type TabloInsert = Tablo["Insert"];
|
||||
export type TabloUpdate = Tablo["Update"];
|
||||
Loading…
Reference in a new issue