mirror of
https://github.com/urosran/cally.git
synced 2025-07-14 17:25:46 +00:00
tablet view fixes, grocery item fix
This commit is contained in:
@ -9,6 +9,7 @@ import { useGetFamilyMembers } from "@/hooks/firebase/useGetFamilyMembers";
|
||||
import { ImageBackground, StyleSheet } from "react-native";
|
||||
import { colorMap } from "@/constants/colorMap";
|
||||
import { ScrollView } from "react-native-gesture-handler";
|
||||
import { ProfileType } from "@/contexts/AuthContext";
|
||||
|
||||
const TabletChoresPage = () => {
|
||||
const { data: users } = useGetFamilyMembers();
|
||||
@ -32,20 +33,23 @@ const TabletChoresPage = () => {
|
||||
<TabletContainer>
|
||||
<ScrollView horizontal>
|
||||
<View row gap-25 padding-25>
|
||||
{users?.map((user, index) => (
|
||||
<View>
|
||||
{users
|
||||
?.filter(member => member.userType !== ProfileType.FAMILY_DEVICE)
|
||||
.map((user, index) => (
|
||||
<View key={index}>
|
||||
<View row centerV>
|
||||
{user.pfp ? (
|
||||
<ImageBackground
|
||||
source={{ uri: user.pfp }}
|
||||
style={[
|
||||
styles.pfp,
|
||||
(user.eventColor && {
|
||||
borderWidth: 2,
|
||||
borderColor: user.eventColor,
|
||||
}) ||
|
||||
undefined,
|
||||
]}
|
||||
style={
|
||||
styles.pfp
|
||||
}
|
||||
imageStyle={(user.eventColor && {
|
||||
borderWidth: 2,
|
||||
borderColor: user.eventColor,
|
||||
}) ||
|
||||
undefined
|
||||
}
|
||||
borderRadius={13.33}
|
||||
/>
|
||||
) : (
|
||||
|
@ -1,53 +1,57 @@
|
||||
import { View, Text } from "react-native-ui-lib";
|
||||
import React from "react";
|
||||
import React, { useEffect } from "react";
|
||||
import { useGetFamilyMembers } from "@/hooks/firebase/useGetFamilyMembers";
|
||||
import { ImageBackground, StyleSheet } from "react-native";
|
||||
import { colorMap } from "@/constants/colorMap";
|
||||
import { ProfileType } from "@/contexts/AuthContext";
|
||||
|
||||
const UsersList = () => {
|
||||
const { data: familyMembers } = useGetFamilyMembers();
|
||||
const { data: familyMembers, refetch: refetchFamilyMembers } =
|
||||
useGetFamilyMembers();
|
||||
|
||||
useEffect(() => {
|
||||
refetchFamilyMembers();
|
||||
}, []);
|
||||
|
||||
const capitalizeFirstLetter = (str: string) => {
|
||||
if (!str) return '';
|
||||
if (!str) return "";
|
||||
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
|
||||
};
|
||||
|
||||
return (
|
||||
<View centerH paddingT-10>
|
||||
{familyMembers?.map((member, index) => (
|
||||
<>
|
||||
{member.pfp ? (
|
||||
<ImageBackground
|
||||
key={index}
|
||||
source={{ uri: member.pfp }}
|
||||
style={[
|
||||
styles.pfp,
|
||||
(member.eventColor && {
|
||||
borderWidth: 2,
|
||||
borderColor: member.eventColor,
|
||||
}) ||
|
||||
undefined,
|
||||
]}
|
||||
borderRadius={100}
|
||||
/>
|
||||
) : (
|
||||
<View
|
||||
key={index}
|
||||
style={styles.pfp}
|
||||
center
|
||||
backgroundColor={member.eventColor || colorMap.teal}
|
||||
children={
|
||||
<Text color="white">
|
||||
{member.firstName.at(0)}
|
||||
{member.lastName.at(0)}
|
||||
</Text>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<Text style={styles.fName}>{member.firstName}</Text>
|
||||
<Text style={styles.role}>{capitalizeFirstLetter(member.userType)}</Text>
|
||||
</>
|
||||
))}
|
||||
{familyMembers
|
||||
?.filter((member) => member.userType !== ProfileType.FAMILY_DEVICE)
|
||||
.map((member, index) => (
|
||||
<>
|
||||
{member.pfp ? (
|
||||
<ImageBackground
|
||||
key={index}
|
||||
source={{ uri: member.pfp }}
|
||||
style={styles.pfp}
|
||||
borderRadius={200}
|
||||
imageStyle={{ borderWidth: 2, borderColor: "red" }}
|
||||
/>
|
||||
) : (
|
||||
<View
|
||||
key={index}
|
||||
style={styles.pfp}
|
||||
center
|
||||
backgroundColor={member.eventColor || colorMap.teal}
|
||||
children={
|
||||
<Text color="white">
|
||||
{member.firstName.at(0)}
|
||||
{member.lastName.at(0)}
|
||||
</Text>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<Text style={styles.fName}>{member.firstName}</Text>
|
||||
<Text style={styles.role}>
|
||||
{capitalizeFirstLetter(member.userType)}
|
||||
</Text>
|
||||
</>
|
||||
))}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
@ -6,9 +6,9 @@ import EditGroceryFrequency from "./EditGroceryFrequency";
|
||||
import EditGroceryItem from "./EditGroceryItem";
|
||||
import { ImageBackground, StyleSheet } from "react-native";
|
||||
import { IGrocery } from "@/hooks/firebase/types/groceryData";
|
||||
import firestore from "@react-native-firebase/firestore";
|
||||
import { UserProfile } from "@/hooks/firebase/types/profileTypes";
|
||||
import { ProfileType, useAuthContext } from "@/contexts/AuthContext";
|
||||
import { useGetUserById } from "@/hooks/firebase/useGetUserById";
|
||||
|
||||
const GroceryItem = ({
|
||||
item,
|
||||
@ -21,6 +21,7 @@ const GroceryItem = ({
|
||||
}) => {
|
||||
const { updateGroceryItem } = useGroceryContext();
|
||||
const { profileData } = useAuthContext();
|
||||
const { data: creator } = useGetUserById(item.creatorId);
|
||||
const isParent = profileData?.userType === ProfileType.PARENT;
|
||||
|
||||
const [openFreqEdit, setOpenFreqEdit] = useState<boolean>(false);
|
||||
@ -29,37 +30,8 @@ const GroceryItem = ({
|
||||
const [category, setCategory] = useState<GroceryCategory>(
|
||||
item.category ?? GroceryCategory.None
|
||||
);
|
||||
const [itemCreator, setItemCreator] = useState<UserProfile>(null);
|
||||
|
||||
const closeEdit = () => {
|
||||
setIsEditingTitle(false);
|
||||
};
|
||||
|
||||
const handleTitleChange = (newTitle: string) => {
|
||||
updateGroceryItem({ id: item?.id, title: newTitle });
|
||||
};
|
||||
|
||||
const handleCategoryChange = (newCategory: GroceryCategory) => {
|
||||
updateGroceryItem({ id: item?.id, category: newCategory });
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
console.log(item);
|
||||
getItemCreator(item?.creatorId);
|
||||
}, []);
|
||||
|
||||
const getItemCreator = async (uid: string | undefined) => {
|
||||
if (uid) {
|
||||
const documentSnapshot = await firestore()
|
||||
.collection("Profiles")
|
||||
.doc(uid)
|
||||
.get();
|
||||
|
||||
if (documentSnapshot.exists) {
|
||||
setItemCreator(documentSnapshot.data() as UserProfile);
|
||||
}
|
||||
}
|
||||
};
|
||||
const closeEdit = () => setIsEditingTitle(false);
|
||||
|
||||
const getInitials = (firstName: string, lastName: string) => {
|
||||
return `${firstName.charAt(0)}${lastName.charAt(0)}`;
|
||||
@ -71,23 +43,27 @@ const GroceryItem = ({
|
||||
style={{
|
||||
borderRadius: 17,
|
||||
marginVertical: 5,
|
||||
paddingHorizontal: isEditingTitle ? 0 : 13,
|
||||
paddingVertical: isEditingTitle ? 0 : 10,
|
||||
height: 44.64,
|
||||
backgroundColor: item.bought ? "#cbcbcb" : "white",
|
||||
overflow: "hidden",
|
||||
}}
|
||||
backgroundColor="white"
|
||||
centerV
|
||||
>
|
||||
<View row spread>
|
||||
<View
|
||||
row
|
||||
spread
|
||||
centerV
|
||||
style={{
|
||||
paddingHorizontal: isEditingTitle ? 0 : 13,
|
||||
paddingVertical: isEditingTitle ? 0 : 10,
|
||||
minHeight: 44.64,
|
||||
}}
|
||||
>
|
||||
<EditGroceryFrequency
|
||||
visible={openFreqEdit}
|
||||
key={item.id}
|
||||
item={item}
|
||||
onClose={() => {
|
||||
setOpenFreqEdit(false);
|
||||
}}
|
||||
onClose={() => setOpenFreqEdit(false)}
|
||||
/>
|
||||
|
||||
{isEditingTitle ? (
|
||||
<EditGroceryItem
|
||||
editGrocery={{
|
||||
@ -102,12 +78,11 @@ const GroceryItem = ({
|
||||
onInputFocus={onInputFocus}
|
||||
/>
|
||||
) : (
|
||||
<View>
|
||||
<View flex>
|
||||
{isParent ? (
|
||||
<TouchableOpacity onPress={() => setIsEditingTitle(true)}>
|
||||
<Text
|
||||
text70T
|
||||
black
|
||||
style={[
|
||||
styles.title,
|
||||
{
|
||||
@ -121,7 +96,6 @@ const GroceryItem = ({
|
||||
) : (
|
||||
<Text
|
||||
text70T
|
||||
black
|
||||
style={[styles.title, { color: item.bought ? "red" : "black" }]}
|
||||
>
|
||||
{item.title}
|
||||
@ -129,31 +103,25 @@ const GroceryItem = ({
|
||||
)}
|
||||
</View>
|
||||
)}
|
||||
|
||||
{!item.approved ? (
|
||||
<View row centerV marginB-10>
|
||||
<View row centerV>
|
||||
{isParent && (
|
||||
<>
|
||||
<AntDesign
|
||||
name="check"
|
||||
size={24}
|
||||
style={{
|
||||
color: "green",
|
||||
marginRight: 15,
|
||||
}}
|
||||
onPress={
|
||||
isParent
|
||||
? () => handleItemApproved(item.id, { approved: true })
|
||||
: null
|
||||
style={{ color: "green", marginRight: 15 }}
|
||||
onPress={() =>
|
||||
handleItemApproved(item.id, { approved: true })
|
||||
}
|
||||
/>
|
||||
<AntDesign
|
||||
name="close"
|
||||
size={24}
|
||||
style={{ color: "red" }}
|
||||
onPress={
|
||||
isParent
|
||||
? () => handleItemApproved(item.id, { approved: false })
|
||||
: null
|
||||
onPress={() =>
|
||||
handleItemApproved(item.id, { approved: false })
|
||||
}
|
||||
/>
|
||||
</>
|
||||
@ -176,69 +144,69 @@ const GroceryItem = ({
|
||||
)
|
||||
)}
|
||||
</View>
|
||||
|
||||
{!item.approved && (
|
||||
<View>
|
||||
<View centerH>
|
||||
<View height={0.7} backgroundColor="#e7e7e7" width={"98%"} />
|
||||
<>
|
||||
<View paddingH-20>
|
||||
<View height={0.7} backgroundColor="#e7e7e7" width="100%" />
|
||||
</View>
|
||||
<View paddingL-0 paddingT-12 flexS row centerV>
|
||||
{profileData?.pfp ? (
|
||||
<View
|
||||
row
|
||||
centerV
|
||||
style={{
|
||||
paddingHorizontal: 13,
|
||||
paddingVertical: 10,
|
||||
}}
|
||||
>
|
||||
{creator?.pfp ? (
|
||||
<ImageBackground
|
||||
source={require("../../../assets/images/child-picture.png")}
|
||||
source={{ uri: creator.pfp }}
|
||||
style={{
|
||||
height: 24.64,
|
||||
aspectRatio: 1,
|
||||
borderRadius: 22,
|
||||
overflow: "hidden",
|
||||
borderWidth: 2,
|
||||
borderColor: profileData.eventColor
|
||||
borderColor: creator.eventColor || undefined,
|
||||
marginRight: 8,
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<View
|
||||
style={{
|
||||
position: "relative",
|
||||
width: 24.64,
|
||||
aspectRatio: 1,
|
||||
marginRight: 4,
|
||||
marginRight: 8,
|
||||
backgroundColor: "#ccc",
|
||||
borderRadius: 100,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
backgroundColor: "#ccc",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
borderRadius: 100, // Circular shape
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
}}
|
||||
<Text
|
||||
style={{ color: "#fff", fontSize: 12, fontWeight: "bold" }}
|
||||
>
|
||||
<Text
|
||||
style={{
|
||||
color: "#fff",
|
||||
fontSize: 12,
|
||||
fontWeight: "bold",
|
||||
}}
|
||||
>
|
||||
{itemCreator
|
||||
? getInitials(itemCreator.firstName, itemCreator.lastName)
|
||||
: ""}
|
||||
</Text>
|
||||
</View>
|
||||
{creator
|
||||
? getInitials(creator.firstName, creator.lastName)
|
||||
: ""}
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
<Text color="#858585" style={styles.authorTxt}>
|
||||
Requested by {itemCreator?.firstName}
|
||||
Requested by {creator?.firstName}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
authorTxt: { fontFamily: "Manrope_500Medium", fontSize: 12 },
|
||||
authorTxt: {
|
||||
fontFamily: "Manrope_500Medium",
|
||||
fontSize: 12,
|
||||
},
|
||||
checkbox: {
|
||||
borderRadius: 50,
|
||||
borderWidth: 0.7,
|
||||
|
@ -11,7 +11,12 @@ import {
|
||||
} from "react-native-ui-lib";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { useSignIn } from "@/hooks/firebase/useSignIn";
|
||||
import { Dimensions, KeyboardAvoidingView, Platform, StyleSheet } from "react-native";
|
||||
import {
|
||||
Dimensions,
|
||||
KeyboardAvoidingView,
|
||||
Platform,
|
||||
StyleSheet,
|
||||
} from "react-native";
|
||||
import Toast from "react-native-toast-message";
|
||||
import KeyboardManager from "react-native-keyboard-manager";
|
||||
import { SafeAreaView } from "react-native-safe-area-context";
|
||||
@ -28,24 +33,24 @@ const SignInPage = () => {
|
||||
|
||||
const isTablet: boolean = Device.deviceType === DeviceType.TABLET;
|
||||
const [isPortrait, setIsPortrait] = useState(() => {
|
||||
const dim = Dimensions.get('screen');
|
||||
const dim = Dimensions.get("screen");
|
||||
return dim.height >= dim.width;
|
||||
});
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const subscription = Dimensions.addEventListener('change', ({ screen }) => {
|
||||
useEffect(() => {
|
||||
const subscription = Dimensions.addEventListener("change", ({ screen }) => {
|
||||
setIsPortrait(screen.height >= screen.width);
|
||||
});
|
||||
|
||||
return () => subscription.remove();
|
||||
}, []);
|
||||
}, []);
|
||||
|
||||
const getTopPadding = () => {
|
||||
const getTopPadding = () => {
|
||||
if (Device.deviceType === DeviceType.TABLET) {
|
||||
return isPortrait ? "50%" : "15%";
|
||||
}
|
||||
return "20%"; // non-tablet case, regardless of orientation
|
||||
};
|
||||
};
|
||||
|
||||
const { mutateAsync: signIn, error, isError, isLoading } = useSignIn();
|
||||
|
||||
@ -68,9 +73,12 @@ const SignInPage = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<SafeAreaView style={{ flex: 1, alignItems: isTablet ? "center" : undefined}}>
|
||||
<SafeAreaView style={{ flex: 1 }}>
|
||||
<KeyboardAwareScrollView
|
||||
contentContainerStyle={{ flexGrow: 1 }}
|
||||
contentContainerStyle={{
|
||||
flexGrow: 1,
|
||||
alignItems: isTablet ? "center" : undefined,
|
||||
}}
|
||||
enableOnAndroid
|
||||
>
|
||||
<View
|
||||
@ -79,7 +87,7 @@ const SignInPage = () => {
|
||||
padding: 21,
|
||||
paddingBottom: 45,
|
||||
paddingTop: isLoading ? "20%" : getTopPadding(),
|
||||
width: isLoading ? '100%' : (isTablet ? 629 : undefined),
|
||||
width: isLoading ? "100%" : isTablet ? 629 : undefined,
|
||||
}}
|
||||
>
|
||||
<View gap-13 width={"100%"} marginB-20>
|
||||
@ -92,9 +100,9 @@ const SignInPage = () => {
|
||||
</View>
|
||||
|
||||
<KeyboardAvoidingView
|
||||
style={{ width: "100%" }}
|
||||
style={{ width: "100%", flex: 1 }}
|
||||
contentContainerStyle={{ justifyContent: "center" }}
|
||||
keyboardVerticalOffset={50}
|
||||
keyboardVerticalOffset={Platform.OS === "ios" ? 50 : 200}
|
||||
behavior={Platform.OS === "ios" ? "padding" : "height"}
|
||||
>
|
||||
<TextField
|
||||
@ -187,6 +195,7 @@ const SignInPage = () => {
|
||||
<LoaderScreen
|
||||
overlay
|
||||
message={"Signing in..."}
|
||||
containerStyle={{ width: Dimensions.get('screen').width }}
|
||||
backgroundColor={Colors.white}
|
||||
color={Colors.grey40}
|
||||
/>
|
||||
|
@ -75,12 +75,12 @@ const SignUpPage = () => {
|
||||
<SafeAreaView
|
||||
style={{
|
||||
flex: 1,
|
||||
alignItems: isTablet ? "center" : undefined,
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
<KeyboardAwareScrollView
|
||||
contentContainerStyle={{ flexGrow: 1 }}
|
||||
contentContainerStyle={{ flexGrow: 1,
|
||||
alignItems: isTablet ? "center" : undefined,
|
||||
width: '100%' }}
|
||||
enableOnAndroid
|
||||
>
|
||||
<View
|
||||
|
31
hooks/firebase/useGetUserById.ts
Normal file
31
hooks/firebase/useGetUserById.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import { useQuery } from "react-query";
|
||||
import { UserProfile } from "@/hooks/firebase/types/profileTypes";
|
||||
import firestore from "@react-native-firebase/firestore";
|
||||
|
||||
export const useGetUserById = (uid: string | undefined) => {
|
||||
return useQuery({
|
||||
queryKey: ["getUserById", uid],
|
||||
queryFn: async (): Promise<UserProfile | null> => {
|
||||
if (!uid) return null;
|
||||
|
||||
try {
|
||||
const doc = await firestore()
|
||||
.collection("Profiles")
|
||||
.doc(uid)
|
||||
.get();
|
||||
|
||||
if (!doc.exists) return null;
|
||||
|
||||
const data = doc.data();
|
||||
return {
|
||||
...data,
|
||||
uid: doc.id,
|
||||
} as UserProfile;
|
||||
} catch (error) {
|
||||
console.error("Error retrieving user:", error);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
enabled: !!uid
|
||||
});
|
||||
};
|
Reference in New Issue
Block a user