Merge branch 'dev' of https://github.com/urosran/cally into dev

This commit is contained in:
ivic00
2024-10-22 19:35:06 +02:00
11 changed files with 143 additions and 94 deletions

View File

@ -16,7 +16,7 @@
"supportsTablet": true, "supportsTablet": true,
"bundleIdentifier": "com.cally.app", "bundleIdentifier": "com.cally.app",
"googleServicesFile": "./ios/GoogleService-Info.plist", "googleServicesFile": "./ios/GoogleService-Info.plist",
"buildNumber": "34", "buildNumber": "40",
"usesAppleSignIn": true "usesAppleSignIn": true
}, },
"android": { "android": {

View File

@ -48,7 +48,7 @@ export const EventCalendar: React.FC<EventCalendarProps> = React.memo(({calendar
}, [events, mode]); }, [events, mode]);
const handlePressEvent = useCallback((event: CalendarEvent) => { const handlePressEvent = useCallback((event: CalendarEvent) => {
if (mode === "day") { if (mode === "day" || mode === "week") {
setEditVisible(true); setEditVisible(true);
console.log({event}) console.log({event})
setEventForEdit(event); setEventForEdit(event);
@ -60,7 +60,7 @@ export const EventCalendar: React.FC<EventCalendarProps> = React.memo(({calendar
const handlePressCell = useCallback( const handlePressCell = useCallback(
(date: Date) => { (date: Date) => {
if (mode === "day") { if (mode === "day" || mode === "week") {
setSelectedNewEndDate(date); setSelectedNewEndDate(date);
} else { } else {
setMode("day") setMode("day")

View File

@ -9,6 +9,7 @@ import ProfileIcon from "@/assets/svgs/ProfileIcon";
import CalendarIcon from "@/assets/svgs/CalendarIcon"; import CalendarIcon from "@/assets/svgs/CalendarIcon";
import PrivacyPolicyIcon from "@/assets/svgs/PrivacyPolicyIcon"; import PrivacyPolicyIcon from "@/assets/svgs/PrivacyPolicyIcon";
import ArrowRightIcon from "@/assets/svgs/ArrowRightIcon"; import ArrowRightIcon from "@/assets/svgs/ArrowRightIcon";
import {ProfileType, useAuthContext} from "@/contexts/AuthContext";
const pageIndex = { const pageIndex = {
main: 0, main: 0,
@ -19,18 +20,22 @@ const pageIndex = {
}; };
const SettingsPage = () => { const SettingsPage = () => {
const {profileData} = useAuthContext()
const isntParent = profileData?.userType !== ProfileType.PARENT
const [selectedPage, setSelectedPage] = useState<number>(0); const [selectedPage, setSelectedPage] = useState<number>(0);
return ( return (
<View flexG> <View flexG>
{selectedPage == 0 && ( {selectedPage == 0 && (
<View flexG centerH marginH-30 marginT-30> <View flexG centerH marginH-30 marginT-30>
<Button <Button
disabled={isntParent}
backgroundColor="white" backgroundColor="white"
style={styles.mainBtn} style={styles.mainBtn}
children={ children={
<View row centerV width={"100%"}> <View row centerV width={"100%"}>
<ProfileIcon style={{marginRight: 10}} color="#07b9c8"/> <ProfileIcon style={{marginRight: 10}} color="#07b9c8"/>
<Text style={styles.label} color="#07b8c7"> <Text style={[styles.label, isntParent && styles.disabledText]}>
Manage My Profile Manage My Profile
</Text> </Text>
<ArrowRightIcon style={{marginLeft: "auto"}}/> <ArrowRightIcon style={{marginLeft: "auto"}}/>
@ -39,12 +44,13 @@ const SettingsPage = () => {
onPress={() => setSelectedPage(pageIndex.user)} onPress={() => setSelectedPage(pageIndex.user)}
/> />
<Button <Button
disabled={isntParent}
backgroundColor="white" backgroundColor="white"
style={styles.mainBtn} style={styles.mainBtn}
children={ children={
<View row centerV width={"100%"}> <View row centerV width={"100%"}>
<CalendarIcon style={{marginRight: 10}}/> <CalendarIcon style={{marginRight: 10}}/>
<Text style={styles.label} color="#fd1775"> <Text style={[styles.label, isntParent && styles.disabledText]}>
Calendar Settings Calendar Settings
</Text> </Text>
<ArrowRightIcon style={{marginLeft: "auto"}}/> <ArrowRightIcon style={{marginLeft: "auto"}}/>
@ -55,6 +61,7 @@ const SettingsPage = () => {
}} }}
/> />
<Button <Button
disabled={isntParent}
backgroundColor="white" backgroundColor="white"
style={styles.mainBtn} style={styles.mainBtn}
children={ children={
@ -65,7 +72,7 @@ const SettingsPage = () => {
color="#ff9900" color="#ff9900"
style={{marginRight: 10}} style={{marginRight: 10}}
/> />
<Text style={styles.label} color="#ff9900"> <Text style={[styles.label, isntParent && styles.disabledText]}>
To-Do Reward Settings To-Do Reward Settings
</Text> </Text>
<ArrowRightIcon style={{marginLeft: "auto"}}/> <ArrowRightIcon style={{marginLeft: "auto"}}/>
@ -79,7 +86,7 @@ const SettingsPage = () => {
children={ children={
<View row centerV width={"100%"}> <View row centerV width={"100%"}>
<PrivacyPolicyIcon style={{marginRight: 10}}/> <PrivacyPolicyIcon style={{marginRight: 10}}/>
<Text style={styles.label} color="#6c645b"> <Text style={styles.label}>
Cally Privacy Policy Cally Privacy Policy
</Text> </Text>
<ArrowRightIcon style={{marginLeft: "auto"}}/> <ArrowRightIcon style={{marginLeft: "auto"}}/>
@ -115,4 +122,7 @@ const styles = StyleSheet.create({
fontSize: 14.71, fontSize: 14.71,
textAlignVertical: "center", textAlignVertical: "center",
}, },
disabledText: {
color: '#A9A9A9', // Example of a gray color for disabled text
},
}); });

View File

@ -43,7 +43,7 @@ const MyGroup = () => {
const lNameRef = useRef<TextFieldRef>(null); const lNameRef = useRef<TextFieldRef>(null);
const emailRef = useRef<TextFieldRef>(null); const emailRef = useRef<TextFieldRef>(null);
const [showQRCodeDialog, setShowQRCodeDialog] = useState(""); const [showQRCodeDialog, setShowQRCodeDialog] = useState<string | boolean>(false);
const {mutateAsync: createSubUser, isLoading, isError} = useCreateSubUser(); const {mutateAsync: createSubUser, isLoading, isError} = useCreateSubUser();
const {data: familyMembers} = useGetFamilyMembers(true); const {data: familyMembers} = useGetFamilyMembers(true);
@ -149,7 +149,7 @@ const MyGroup = () => {
<View flex-1/> <View flex-1/>
<UserMenu <UserMenu
setShowQRCodeDialog={(val) => setShowQRCodeDialog("")} setShowQRCodeDialog={(val) => setShowQRCodeDialog(val)}
showQRCodeDialog={showQRCodeDialog === member?.uid} showQRCodeDialog={showQRCodeDialog === member?.uid}
userId={member?.uid!} userId={member?.uid!}
/> />
@ -187,8 +187,10 @@ const MyGroup = () => {
</Text> </Text>
</View> </View>
<View flex-1/>
<UserMenu <UserMenu
setShowQRCodeDialog={(val) => setShowQRCodeDialog("")} setShowQRCodeDialog={(val) => setShowQRCodeDialog(val)}
showQRCodeDialog={showQRCodeDialog === member?.uid} showQRCodeDialog={showQRCodeDialog === member?.uid}
userId={member?.uid!} userId={member?.uid!}
/> />
@ -224,8 +226,10 @@ const MyGroup = () => {
</Text> </Text>
</View> </View>
<View flex-1/>
<UserMenu <UserMenu
setShowQRCodeDialog={(val) => setShowQRCodeDialog("")} setShowQRCodeDialog={(val) => setShowQRCodeDialog(val)}
showQRCodeDialog={showQRCodeDialog === member?.uid} showQRCodeDialog={showQRCodeDialog === member?.uid}
userId={member?.uid!} userId={member?.uid!}
/> />
@ -242,7 +246,7 @@ const MyGroup = () => {
visible visible
button={{ button={{
label: "+ Add a user device", label: "+ Add a user device",
onPress: () => setShowAddUserDialog(true), onPress: () => setShowNewUserInfoDialog(true),
style: styles.bottomButton, style: styles.bottomButton,
}} }}
/> />

View File

@ -1,7 +1,8 @@
import React, {useState} from 'react'; import React from 'react';
import {Button, Card, Colors, Dialog, Hint, ListItem, Text, View} from 'react-native-ui-lib'; import {Button, Card, Dialog, Text, TouchableOpacity} from 'react-native-ui-lib';
import QRCode from 'react-native-qrcode-svg'; import QRCode from 'react-native-qrcode-svg';
import {PanningDirectionsEnum} from "react-native-ui-lib/src/components/panningViews/panningProvider"; import {PanningDirectionsEnum} from "react-native-ui-lib/src/components/panningViews/panningProvider";
import Ionicons from "@expo/vector-icons/Ionicons";
const UserMenu = ({ const UserMenu = ({
userId, userId,
@ -10,40 +11,20 @@ const UserMenu = ({
}: { }: {
userId: string, userId: string,
showQRCodeDialog: boolean, showQRCodeDialog: boolean,
setShowQRCodeDialog: (value: boolean) => void setShowQRCodeDialog: (value: string | boolean) => void
}) => { }) => {
const [showHint, setShowHint] = useState(false);
const handleShowQRCode = () => { const handleShowQRCode = () => {
setShowHint(false); setShowQRCodeDialog(userId);
setTimeout(() => {
setShowQRCodeDialog(true);
}, 500);
}; };
return ( return (
<> <>
<Hint <TouchableOpacity
onBackgroundPress={() => setShowHint(false)} onPress={handleShowQRCode}
onPress={() => setShowHint(true)}
color={Colors.white}
customContent={
<View height={18}>
<ListItem onPress={handleShowQRCode}>
<Text style={{fontFamily: "Manrope_500Medium"}}>Show Login QR Code</Text>
</ListItem>
</View>
}
enableShadow
visible={showHint}
backdropColor="transparent"
> >
<View> <Ionicons name="qr-code-outline" size={24} color="black"/>
<Button link onPress={() => setShowHint(!showHint)}> </TouchableOpacity>
<Text>...</Text>
</Button>
</View>
</Hint>
<Dialog <Dialog
visible={showQRCodeDialog} visible={showQRCodeDialog}

View File

@ -1,11 +1,11 @@
import { import {
View, View,
Text, Text,
Checkbox, Checkbox,
TouchableOpacity, TouchableOpacity,
Dialog, Dialog,
Button, Button,
ButtonSize, ButtonSize
} from "react-native-ui-lib"; } from "react-native-ui-lib";
import React, { useState } from "react"; import React, { useState } from "react";
import { useToDosContext } from "@/contexts/ToDosContext"; import { useToDosContext } from "@/contexts/ToDosContext";
@ -14,9 +14,11 @@ import PointsSlider from "@/components/shared/PointsSlider";
import { IToDo } from "@/hooks/firebase/types/todoData"; import { IToDo } from "@/hooks/firebase/types/todoData";
import { ImageBackground } from "react-native"; import { ImageBackground } from "react-native";
import AddChoreDialog from "@/components/pages/todos/AddChoreDialog"; import AddChoreDialog from "@/components/pages/todos/AddChoreDialog";
import { useGetFamilyMembers } from "@/hooks/firebase/useGetFamilyMembers";
const ToDoItem = (props: { item: IToDo; isSettings?: boolean }) => { const ToDoItem = (props: { item: IToDo; isSettings?: boolean }) => {
const { updateToDo } = useToDosContext(); const { updateToDo } = useToDosContext();
const {data: members} = useGetFamilyMembers();
const [visible, setVisible] = useState<boolean>(false); const [visible, setVisible] = useState<boolean>(false);
const [points, setPoints] = useState(props.item.points); const [points, setPoints] = useState(props.item.points);
const [pointsModalVisible, setPointsModalVisible] = useState<boolean>(false); const [pointsModalVisible, setPointsModalVisible] = useState<boolean>(false);
@ -30,6 +32,12 @@ const ToDoItem = (props: { item: IToDo; isSettings?: boolean }) => {
setPoints(0); setPoints(0);
} }
}; };
const getInitials = (firstName: string, lastName: string) => {
return `${firstName.charAt(0)}${lastName.charAt(0)}`;
};
const selectedMembers = members?.filter((x) => props?.item?.assignees?.includes(x?.uid!));
return ( return (
<View <View
centerV centerV
@ -96,15 +104,44 @@ const ToDoItem = (props: { item: IToDo; isSettings?: boolean }) => {
) : ( ) : (
<View /> <View />
)} )}
<ImageBackground <View row style={{ gap: 3 }}>
source={require("../../../assets/images/child-picture.png")} {selectedMembers?.map((member) => {
style={{ return member?.pfp ? (
height: 24.64, <ImageBackground
aspectRatio: 1, source={require("../../../assets/images/child-picture.png")}
borderRadius: 22, style={{
overflow: "hidden", height: 24.64,
}} aspectRatio: 1,
/> borderRadius: 22,
overflow: "hidden",
}}
/>
) : (
<View style={{
position: 'relative',
width: 24.64,
aspectRatio: 1
}}>
<View style={{
backgroundColor: '#ccc',
justifyContent: 'center',
alignItems: 'center',
borderRadius: 100, // Circular shape
width: '100%',
height: '100%'
}}>
<Text style={{
color: '#fff',
fontSize: 12,
fontWeight: 'bold'
}}>
{getInitials(member.firstName, member.lastName ?? "")}
</Text>
</View>
</View>
)}
)}
</View>
</View> </View>
<Dialog <Dialog
visible={pointsModalVisible} visible={pointsModalVisible}

View File

@ -1,41 +1,43 @@
import { View, Text } from "react-native-ui-lib"; import {Image, Text, View} from "react-native-ui-lib";
import React from "react"; import React from "react";
import { useAuthContext } from "@/contexts/AuthContext"; import {useAuthContext} from "@/contexts/AuthContext";
import { ImageBackground } from "react-native";
const HeaderTemplate = (props: { const HeaderTemplate = (props: {
message: string; message: string;
isWelcome: boolean; isWelcome: boolean;
children?: React.ReactNode; children?: React.ReactNode;
link?: React.ReactNode; link?: React.ReactNode;
}) => { }) => {
const { user, profileData } = useAuthContext(); const {user, profileData} = useAuthContext();
const headerHeight:number = 72; const headerHeight: number = 72;
return ( return (
<View row centerV marginV-15> <View row centerV marginV-15>
<ImageBackground <Image
source={require("../../assets/images/profile-picture.png")} source={{uri: profileData?.pfp}}
style={{ style={{
height: headerHeight, height: headerHeight,
aspectRatio: 1, aspectRatio: 1,
borderRadius: 22, borderRadius: 22,
overflow: "hidden", overflow: "hidden",
marginRight: 20, marginRight: 20,
}} }}
/> />
<View gap-3> <View gap-3>
{props.isWelcome && ( {props.isWelcome && (
<Text text70L style={{fontSize: 19, fontFamily: "Manrope_400Regular"}}>Welcome, {profileData?.firstName}!</Text> <Text text70L style={{
)} fontSize: 19,
<Text text70B style={{ fontSize: 18 , fontFamily: "Manrope_600SemiBold" }}> fontFamily: "Manrope_400Regular"
{props.message} }}>Welcome, {profileData?.firstName}!</Text>
</Text> )}
{props.children && <View>{props.children}</View>} <Text text70B style={{fontSize: 18, fontFamily: "Manrope_600SemiBold"}}>
{props.link && <View marginT-8>{props.link}</View>} {props.message}
</View> </Text>
</View> {props.children && <View>{props.children}</View>}
); {props.link && <View marginT-8>{props.link}</View>}
</View>
</View>
);
}; };
export default HeaderTemplate; export default HeaderTemplate;

View File

@ -6,6 +6,7 @@ import {IToDo} from "@/hooks/firebase/types/todoData";
export const useGetTodos = () => { export const useGetTodos = () => {
const { user, profileData } = useAuthContext(); const { user, profileData } = useAuthContext();
//TODO: Add role based filtering for todos
return useQuery({ return useQuery({
queryKey: ["todos", user?.uid], queryKey: ["todos", user?.uid],

View File

@ -47,7 +47,7 @@
</dict> </dict>
</array> </array>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>34</string> <string>40</string>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>
<true/> <true/>
<key>NSAppTransportSecurity</key> <key>NSAppTransportSecurity</key>
@ -114,6 +114,10 @@
<string>$(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route</string> <string>$(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route</string>
<string>$(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route</string> <string>$(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route</string>
<string>$(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route</string> <string>$(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route</string>
<string>$(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route</string>
<string>$(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route</string>
<string>$(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route</string>
<string>$(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route</string>
</array> </array>
<key>UILaunchStoryboardName</key> <key>UILaunchStoryboardName</key>
<string>SplashScreen</string> <string>SplashScreen</string>

10
package-lock.json generated
View File

@ -19,6 +19,7 @@
"@react-native-firebase/crashlytics": "^20.3.0", "@react-native-firebase/crashlytics": "^20.3.0",
"@react-native-firebase/firestore": "^20.4.0", "@react-native-firebase/firestore": "^20.4.0",
"@react-native-firebase/functions": "^20.4.0", "@react-native-firebase/functions": "^20.4.0",
"@react-native-firebase/storage": "^21.0.0",
"@react-navigation/drawer": "^6.7.2", "@react-navigation/drawer": "^6.7.2",
"@react-navigation/native": "^6.0.2", "@react-navigation/native": "^6.0.2",
"date-fns": "^3.6.0", "date-fns": "^3.6.0",
@ -4896,6 +4897,15 @@
"@react-native-firebase/app": "20.4.0" "@react-native-firebase/app": "20.4.0"
} }
}, },
"node_modules/@react-native-firebase/storage": {
"version": "21.0.0",
"resolved": "https://registry.npmjs.org/@react-native-firebase/storage/-/storage-21.0.0.tgz",
"integrity": "sha512-meft5Pu0nI7zxhpnP49ko9Uw8GaIy9hXGJfa/fCFrpf2vA9OXdTr3CvgloH/b9DpbkwQGcGTshRqltuttXI67w==",
"license": "Apache-2.0",
"peerDependencies": {
"@react-native-firebase/app": "21.0.0"
}
},
"node_modules/@react-native/assets-registry": { "node_modules/@react-native/assets-registry": {
"version": "0.74.85", "version": "0.74.85",
"resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.74.85.tgz", "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.74.85.tgz",

View File

@ -2427,7 +2427,7 @@
"@react-native-firebase/storage@^21.0.0": "@react-native-firebase/storage@^21.0.0":
version "21.0.0" version "21.0.0"
resolved "https://registry.yarnpkg.com/@react-native-firebase/storage/-/storage-21.0.0.tgz#0905fd67c74629d947f176bfb988d7cc4d85e244" resolved "https://registry.npmjs.org/@react-native-firebase/storage/-/storage-21.0.0.tgz"
integrity sha512-meft5Pu0nI7zxhpnP49ko9Uw8GaIy9hXGJfa/fCFrpf2vA9OXdTr3CvgloH/b9DpbkwQGcGTshRqltuttXI67w== integrity sha512-meft5Pu0nI7zxhpnP49ko9Uw8GaIy9hXGJfa/fCFrpf2vA9OXdTr3CvgloH/b9DpbkwQGcGTshRqltuttXI67w==
"@react-native/assets-registry@0.74.85": "@react-native/assets-registry@0.74.85":
@ -8896,7 +8896,7 @@ react-native-linear-gradient@^2.8.3:
react-native-onboarding-swiper@^1.3.0: react-native-onboarding-swiper@^1.3.0:
version "1.3.0" version "1.3.0"
resolved "https://registry.yarnpkg.com/react-native-onboarding-swiper/-/react-native-onboarding-swiper-1.3.0.tgz#a97f945f03a036845242b3e1f319c6fdb262bc2b" resolved "https://registry.npmjs.org/react-native-onboarding-swiper/-/react-native-onboarding-swiper-1.3.0.tgz"
integrity sha512-2ZPMrZrJFgR5dmVWIj60x/vTBWrm0BZPuc2w7Cz2Sq/8ChypCi3oL8F7GYMrzky1fmknCS6Z0WPphfZVpnLUnQ== integrity sha512-2ZPMrZrJFgR5dmVWIj60x/vTBWrm0BZPuc2w7Cz2Sq/8ChypCi3oL8F7GYMrzky1fmknCS6Z0WPphfZVpnLUnQ==
dependencies: dependencies:
tinycolor2 "^1.4.1" tinycolor2 "^1.4.1"