mirror of
https://github.com/urosran/cally.git
synced 2025-07-10 07:07:16 +00:00
user settings, points slider
This commit is contained in:
@ -1,12 +1,15 @@
|
|||||||
import SettingsPage from "@/components/pages/settings/SettingsPage";
|
import SettingsPage from "@/components/pages/settings/SettingsPage";
|
||||||
|
import { AuthContextProvider } from "@/contexts/AuthContext";
|
||||||
import { SettingsContextProvider } from "@/contexts/SettingsContext";
|
import { SettingsContextProvider } from "@/contexts/SettingsContext";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { View } from "react-native-ui-lib";
|
import { View } from "react-native-ui-lib";
|
||||||
|
|
||||||
export default function Screen() {
|
export default function Screen() {
|
||||||
return (
|
return (
|
||||||
<SettingsContextProvider>
|
<AuthContextProvider>
|
||||||
<SettingsPage />
|
<SettingsContextProvider>
|
||||||
</SettingsContextProvider>
|
<SettingsPage />
|
||||||
|
</SettingsContextProvider>
|
||||||
|
</AuthContextProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ const SignUpPage = (props: { unsetRegister: () => any }) => {
|
|||||||
const { mutateAsync: signUp } = useSignUp();
|
const { mutateAsync: signUp } = useSignUp();
|
||||||
|
|
||||||
const handleSignUp = async () => {
|
const handleSignUp = async () => {
|
||||||
await signUp({ email, password });
|
await signUp({ email, password, firstName, lastName });
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -5,6 +5,7 @@ import { Entypo, Ionicons, Octicons } from "@expo/vector-icons";
|
|||||||
import CalendarSettingsPage from "./CalendarSettingsPage";
|
import CalendarSettingsPage from "./CalendarSettingsPage";
|
||||||
import ChoreRewardSettings from "./ChoreRewardSettings";
|
import ChoreRewardSettings from "./ChoreRewardSettings";
|
||||||
import UserSettings from "./UserSettings";
|
import UserSettings from "./UserSettings";
|
||||||
|
import { AuthContextProvider } from "@/contexts/AuthContext";
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
mainBtn: {
|
mainBtn: {
|
||||||
@ -24,74 +25,82 @@ const pageIndex = {
|
|||||||
const SettingsPage = () => {
|
const SettingsPage = () => {
|
||||||
const [selectedPage, setSelectedPage] = useState<number>(0);
|
const [selectedPage, setSelectedPage] = useState<number>(0);
|
||||||
return (
|
return (
|
||||||
<View>
|
<View>
|
||||||
{selectedPage == 0 && (
|
{selectedPage == 0 && (
|
||||||
<View centerH marginH-30 marginT-30>
|
<View centerH marginH-30 marginT-30>
|
||||||
<Button
|
<Button
|
||||||
backgroundColor="white"
|
backgroundColor="white"
|
||||||
style={styles.mainBtn}
|
style={styles.mainBtn}
|
||||||
label="Manage my profile"
|
label="Manage my profile"
|
||||||
color="#07b8c7"
|
color="#07b8c7"
|
||||||
iconSource={() => (
|
iconSource={() => (
|
||||||
<Ionicons
|
<Ionicons
|
||||||
name="person-circle-sharp"
|
name="person-circle-sharp"
|
||||||
size={24}
|
size={24}
|
||||||
color="#07b8c7"
|
color="#07b8c7"
|
||||||
style={{ marginRight: 10 }}
|
style={{ marginRight: 10 }}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
onPress={() => setSelectedPage(pageIndex.user)}
|
onPress={() => setSelectedPage(pageIndex.user)}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
backgroundColor="white"
|
backgroundColor="white"
|
||||||
style={styles.mainBtn}
|
style={styles.mainBtn}
|
||||||
label="Calendar settings"
|
label="Calendar settings"
|
||||||
color="#fd1775"
|
color="#fd1775"
|
||||||
iconSource={() => (
|
iconSource={() => (
|
||||||
<Ionicons
|
<Ionicons
|
||||||
name="home-outline"
|
name="home-outline"
|
||||||
size={24}
|
size={24}
|
||||||
color="#fd1775"
|
color="#fd1775"
|
||||||
style={{ marginRight: 10 }}
|
style={{ marginRight: 10 }}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
onPress={() => {setSelectedPage(pageIndex.calendar)}}
|
onPress={() => {
|
||||||
/>
|
setSelectedPage(pageIndex.calendar);
|
||||||
<Button
|
}}
|
||||||
backgroundColor="white"
|
/>
|
||||||
style={styles.mainBtn}
|
<Button
|
||||||
label="Chore reward settings"
|
backgroundColor="white"
|
||||||
color="#ff9900"
|
style={styles.mainBtn}
|
||||||
iconSource={() => (
|
label="Chore reward settings"
|
||||||
<Octicons
|
color="#ff9900"
|
||||||
name="gear"
|
iconSource={() => (
|
||||||
size={24}
|
<Octicons
|
||||||
color="#ff9900"
|
name="gear"
|
||||||
style={{ marginRight: 10 }}
|
size={24}
|
||||||
/>
|
color="#ff9900"
|
||||||
)}
|
style={{ marginRight: 10 }}
|
||||||
onPress={() => setSelectedPage(pageIndex.chore)}
|
/>
|
||||||
/>
|
)}
|
||||||
<Button
|
onPress={() => setSelectedPage(pageIndex.chore)}
|
||||||
backgroundColor="white"
|
/>
|
||||||
style={styles.mainBtn}
|
<Button
|
||||||
label="Kaly privacy policy"
|
backgroundColor="white"
|
||||||
iconSource={() => (
|
style={styles.mainBtn}
|
||||||
<Entypo
|
label="Kaly privacy policy"
|
||||||
name="text-document"
|
iconSource={() => (
|
||||||
size={24}
|
<Entypo
|
||||||
color="#6c645b"
|
name="text-document"
|
||||||
style={{ marginRight: 10 }}
|
size={24}
|
||||||
/>
|
color="#6c645b"
|
||||||
)}
|
style={{ marginRight: 10 }}
|
||||||
color="#6c645b"
|
/>
|
||||||
/>
|
)}
|
||||||
</View>
|
color="#6c645b"
|
||||||
)}
|
/>
|
||||||
{selectedPage == pageIndex.calendar && <CalendarSettingsPage setSelectedPage={setSelectedPage} />}
|
</View>
|
||||||
{selectedPage == pageIndex.chore && <ChoreRewardSettings setSelectedPage={setSelectedPage} />}
|
)}
|
||||||
{selectedPage == pageIndex.user && <UserSettings setSelectedPage={setSelectedPage} />}
|
{selectedPage == pageIndex.calendar && (
|
||||||
</View>
|
<CalendarSettingsPage setSelectedPage={setSelectedPage} />
|
||||||
|
)}
|
||||||
|
{selectedPage == pageIndex.chore && (
|
||||||
|
<ChoreRewardSettings setSelectedPage={setSelectedPage} />
|
||||||
|
)}
|
||||||
|
{selectedPage == pageIndex.user && (
|
||||||
|
<UserSettings setSelectedPage={setSelectedPage} />
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import { Ionicons } from "@expo/vector-icons";
|
|||||||
import { ScrollView, StyleSheet } from "react-native";
|
import { ScrollView, StyleSheet } from "react-native";
|
||||||
import MyProfile from "./user_settings_views/MyProfile";
|
import MyProfile from "./user_settings_views/MyProfile";
|
||||||
import MyGroup from "./user_settings_views/MyGroup";
|
import MyGroup from "./user_settings_views/MyGroup";
|
||||||
|
import { useAuthContext } from "@/contexts/AuthContext";
|
||||||
|
|
||||||
const UserSettings = (props: { setSelectedPage: (page: number) => void }) => {
|
const UserSettings = (props: { setSelectedPage: (page: number) => void }) => {
|
||||||
const [selectedView, setSelectedView] = useState<boolean>(true);
|
const [selectedView, setSelectedView] = useState<boolean>(true);
|
||||||
|
@ -1,8 +1,19 @@
|
|||||||
import { View, Text, TextField } from "react-native-ui-lib";
|
import { View, Text, TextField } from "react-native-ui-lib";
|
||||||
import React from "react";
|
import React, { useState } from "react";
|
||||||
import { StyleSheet } from "react-native";
|
import { StyleSheet } from "react-native";
|
||||||
import { ScrollView } from "react-native-gesture-handler";
|
import { ScrollView } from "react-native-gesture-handler";
|
||||||
|
import { useAuthContext } from "@/contexts/AuthContext";
|
||||||
|
import { useSettingsContext } from "@/contexts/SettingsContext";
|
||||||
|
import { useUpdateUserData } from "@/hooks/firebase/useUpdateUserData";
|
||||||
const MyProfile = () => {
|
const MyProfile = () => {
|
||||||
|
const { user, profileData } = useAuthContext();
|
||||||
|
|
||||||
|
const [lastName, setLastName] = useState<string>(profileData?.lastName || "");
|
||||||
|
const [firstName, setFirstName] = useState<string>(
|
||||||
|
profileData?.firstName || ""
|
||||||
|
);
|
||||||
|
|
||||||
|
const { mutateAsync: updateUserData } = useUpdateUserData();
|
||||||
return (
|
return (
|
||||||
<View>
|
<View>
|
||||||
<View style={styles.card}>
|
<View style={styles.card}>
|
||||||
@ -18,15 +29,38 @@ const MyProfile = () => {
|
|||||||
<Text text80 marginT-10 marginB-7 color="#a1a1a1">
|
<Text text80 marginT-10 marginB-7 color="#a1a1a1">
|
||||||
First name
|
First name
|
||||||
</Text>
|
</Text>
|
||||||
<TextField text70 placeholder="First name" style={styles.txtBox} />
|
<TextField
|
||||||
|
text70
|
||||||
|
placeholder="First name"
|
||||||
|
style={styles.txtBox}
|
||||||
|
value={firstName}
|
||||||
|
onChangeText={async (value) => {
|
||||||
|
setFirstName(value);
|
||||||
|
await updateUserData({ newUserData: { firstName: value } });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
<Text text80 marginT-10 marginB-7 color="#a1a1a1">
|
<Text text80 marginT-10 marginB-7 color="#a1a1a1">
|
||||||
Last name
|
Last name
|
||||||
</Text>
|
</Text>
|
||||||
<TextField text70 placeholder="Last name" style={styles.txtBox} />
|
<TextField
|
||||||
|
text70
|
||||||
|
placeholder="Last name"
|
||||||
|
style={styles.txtBox}
|
||||||
|
value={lastName}
|
||||||
|
onChangeText={async (value) => {
|
||||||
|
setLastName(value);
|
||||||
|
await updateUserData({ newUserData: { lastName: value } });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
<Text text80 marginT-10 marginB-7 color="#a1a1a1">
|
<Text text80 marginT-10 marginB-7 color="#a1a1a1">
|
||||||
Email address
|
Email address
|
||||||
</Text>
|
</Text>
|
||||||
<TextField text70 placeholder="Email address" style={styles.txtBox} />
|
<TextField
|
||||||
|
text70
|
||||||
|
placeholder="Email address"
|
||||||
|
value={user?.email?.toString()}
|
||||||
|
style={styles.txtBox}
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
@ -35,7 +69,7 @@ const MyProfile = () => {
|
|||||||
<Text text80 marginT-20 marginB-7 color="#a1a1a1">
|
<Text text80 marginT-20 marginB-7 color="#a1a1a1">
|
||||||
Time Zone
|
Time Zone
|
||||||
</Text>
|
</Text>
|
||||||
<TextField text70 placeholder="Email address" style={styles.txtBox} />
|
<TextField text70 placeholder="Time Zone" style={styles.txtBox} />
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
@ -20,6 +20,7 @@ import LinearGradient from "react-native-linear-gradient";
|
|||||||
import { PanningDirectionsEnum } from "react-native-ui-lib/src/components/panningViews/panningProvider";
|
import { PanningDirectionsEnum } from "react-native-ui-lib/src/components/panningViews/panningProvider";
|
||||||
import { repeatOptions, useToDosContext } from "@/contexts/ToDosContext";
|
import { repeatOptions, useToDosContext } from "@/contexts/ToDosContext";
|
||||||
import { setDate } from "date-fns";
|
import { setDate } from "date-fns";
|
||||||
|
import PointsSlider from "@/components/shared/PointsSlider";
|
||||||
|
|
||||||
const AddChore = () => {
|
const AddChore = () => {
|
||||||
const { addToDo, toDos } = useToDosContext();
|
const { addToDo, toDos } = useToDosContext();
|
||||||
@ -232,36 +233,11 @@ const AddChore = () => {
|
|||||||
Reward Points
|
Reward Points
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
<View marginH-30 row spread>
|
<PointsSlider
|
||||||
<View width={"80%"}>
|
points={points}
|
||||||
<Slider
|
setPoints={setPoints}
|
||||||
value={points}
|
handleChange={handleChange}
|
||||||
onValueChange={(value) => setPoints(value)}
|
/>
|
||||||
minimumValue={0}
|
|
||||||
step={10}
|
|
||||||
maximumValue={100}
|
|
||||||
/>
|
|
||||||
<View row spread>
|
|
||||||
<Text>0</Text>
|
|
||||||
<Text>50</Text>
|
|
||||||
<Text>100</Text>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
<View style={{ marginLeft: "auto" }}>
|
|
||||||
<TextField
|
|
||||||
value={points.toString()}
|
|
||||||
onChangeText={(text) => {
|
|
||||||
handleChange(text);
|
|
||||||
}}
|
|
||||||
containerStyle={{
|
|
||||||
borderWidth: 1,
|
|
||||||
borderColor: "#d9d9d9",
|
|
||||||
width: 45,
|
|
||||||
borderRadius: 5,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</LinearGradient>
|
</LinearGradient>
|
||||||
);
|
);
|
||||||
|
43
components/shared/PointsSlider.tsx
Normal file
43
components/shared/PointsSlider.tsx
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import { View, Text, Slider, TextField } from "react-native-ui-lib";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
const PointsSlider = (props: {
|
||||||
|
points: number;
|
||||||
|
setPoints(value: number): void;
|
||||||
|
handleChange(value: string): void;
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<View marginH-30 row spread>
|
||||||
|
<View width={"80%"}>
|
||||||
|
<Slider
|
||||||
|
value={props.points}
|
||||||
|
onValueChange={(value) => props.setPoints(value)}
|
||||||
|
minimumValue={0}
|
||||||
|
step={10}
|
||||||
|
maximumValue={100}
|
||||||
|
/>
|
||||||
|
<View row spread>
|
||||||
|
<Text>0</Text>
|
||||||
|
<Text>50</Text>
|
||||||
|
<Text>100</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<View style={{ marginLeft: "auto" }}>
|
||||||
|
<TextField
|
||||||
|
value={props.points.toString()}
|
||||||
|
onChangeText={(text) => {
|
||||||
|
props.handleChange(text);
|
||||||
|
}}
|
||||||
|
containerStyle={{
|
||||||
|
borderWidth: 1,
|
||||||
|
borderColor: "#d9d9d9",
|
||||||
|
width: 45,
|
||||||
|
borderRadius: 5,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PointsSlider;
|
@ -1,4 +1,5 @@
|
|||||||
import { createContext, FC, ReactNode, useContext, useState } from "react";
|
import { createContext, FC, ReactNode, useContext, useState } from "react";
|
||||||
|
import { useAuthContext } from "./AuthContext";
|
||||||
|
|
||||||
export const colorMap = {
|
export const colorMap = {
|
||||||
pink: "#ea156c",
|
pink: "#ea156c",
|
||||||
@ -8,8 +9,16 @@ export const colorMap = {
|
|||||||
purple: "#7305d4",
|
purple: "#7305d4",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
interface IUserDetails {
|
||||||
|
email: string | undefined;
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
|
}
|
||||||
|
|
||||||
interface ISettingsContext {
|
interface ISettingsContext {
|
||||||
calendarColor: string;
|
calendarColor: string;
|
||||||
|
userDetails: IUserDetails;
|
||||||
|
editUserDetails: (details: Partial<IUserDetails>) => void;
|
||||||
setCalendarColor: (color: string) => void;
|
setCalendarColor: (color: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -18,10 +27,24 @@ const SettingsContext = createContext<ISettingsContext>(undefined!);
|
|||||||
export const SettingsContextProvider: FC<{ children: ReactNode }> = ({
|
export const SettingsContextProvider: FC<{ children: ReactNode }> = ({
|
||||||
children,
|
children,
|
||||||
}) => {
|
}) => {
|
||||||
|
const { user } = useAuthContext();
|
||||||
|
const [userDetails, setUserDetails] = useState<IUserDetails>({
|
||||||
|
email: user?.email?.toString(),
|
||||||
|
firstName: "",
|
||||||
|
lastName: "",
|
||||||
|
});
|
||||||
const [calendarColor, setCalendarColor] = useState<string>(colorMap.pink);
|
const [calendarColor, setCalendarColor] = useState<string>(colorMap.pink);
|
||||||
|
|
||||||
|
const editUserDetails = (details: Partial<IUserDetails>) => {
|
||||||
|
setUserDetails((prevDetails) => ({
|
||||||
|
...prevDetails,
|
||||||
|
...details,
|
||||||
|
}));
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<SettingsContext.Provider value={{ calendarColor, setCalendarColor }}>
|
<SettingsContext.Provider
|
||||||
|
value={{ calendarColor, setCalendarColor, userDetails, editUserDetails }}
|
||||||
|
>
|
||||||
{children}
|
{children}
|
||||||
</SettingsContext.Provider>
|
</SettingsContext.Provider>
|
||||||
);
|
);
|
||||||
|
@ -13,7 +13,7 @@ service cloud.firestore {
|
|||||||
// all client requests to your Firestore database will be denied until you Update
|
// all client requests to your Firestore database will be denied until you Update
|
||||||
// your rules
|
// your rules
|
||||||
match /{document=**} {
|
match /{document=**} {
|
||||||
allow read, write: if request.time < timestamp.date(2024, 9, 5);
|
allow read, write;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -7,7 +7,8 @@ export interface User {
|
|||||||
|
|
||||||
export interface UserProfile {
|
export interface UserProfile {
|
||||||
userType: ProfileType;
|
userType: ProfileType;
|
||||||
name: string;
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
childrenIds?: string[];
|
childrenIds?: string[];
|
||||||
birthday?: Date;
|
birthday?: Date;
|
||||||
parentId?: string;
|
parentId?: string;
|
||||||
|
@ -8,9 +8,9 @@ export const useSignUp = () => {
|
|||||||
|
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationKey: ["signUp"],
|
mutationKey: ["signUp"],
|
||||||
mutationFn: async ({email, password}: { email: string, password: string }) => {
|
mutationFn: async ({email, password, firstName, lastName}: { email: string, password: string, firstName: string, lastName: string }) => {
|
||||||
const res = await auth().createUserWithEmailAndPassword(email, password);
|
const res = await auth().createUserWithEmailAndPassword(email, password);
|
||||||
await updateUserData({newUserData: {userType: ProfileType.PARENT}, customUser: res.user});
|
await updateUserData({newUserData: {userType: ProfileType.PARENT, firstName: firstName, lastName: lastName}, customUser: res.user});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
@ -17,7 +17,7 @@ export const useUpdateUserData = () => {
|
|||||||
await firestore()
|
await firestore()
|
||||||
.collection("Profiles")
|
.collection("Profiles")
|
||||||
.doc(user.uid)
|
.doc(user.uid)
|
||||||
.set(newUserData);
|
.update(newUserData);
|
||||||
|
|
||||||
const profileData = await firestore().collection("Profiles").doc(user?.uid!).get()
|
const profileData = await firestore().collection("Profiles").doc(user?.uid!).get()
|
||||||
setProfileData(profileData.data() as UserProfile)
|
setProfileData(profileData.data() as UserProfile)
|
||||||
|
Reference in New Issue
Block a user