mirror of
https://github.com/urosran/cally.git
synced 2025-11-26 08:24:55 +00:00
added focus, ui changes
This commit is contained in:
19
assets/svgs/ArrowRightIcon.tsx
Normal file
19
assets/svgs/ArrowRightIcon.tsx
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import * as React from "react"
|
||||||
|
import Svg, { SvgProps, Path } from "react-native-svg"
|
||||||
|
const ArrowRightIcon = (props: SvgProps) => (
|
||||||
|
<Svg
|
||||||
|
width={9}
|
||||||
|
height={15}
|
||||||
|
viewBox="0 0 9 15"
|
||||||
|
fill="none"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<Path
|
||||||
|
stroke="#ACACAC"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeWidth={2}
|
||||||
|
d="M1.272 1.803 7.16 7.69a.16.16 0 0 1 0 .226l-5.887 5.887"
|
||||||
|
/>
|
||||||
|
</Svg>
|
||||||
|
)
|
||||||
|
export default ArrowRightIcon
|
||||||
22
assets/svgs/CircledXIcon.tsx
Normal file
22
assets/svgs/CircledXIcon.tsx
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import * as React from "react";
|
||||||
|
import Svg, { SvgProps, Path } from "react-native-svg";
|
||||||
|
const CircledXIcon = (props: SvgProps) => (
|
||||||
|
<Svg
|
||||||
|
width={props.width || 22}
|
||||||
|
height={props.height || 21}
|
||||||
|
viewBox="0 0 22 21"
|
||||||
|
fill="none"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<Path
|
||||||
|
stroke={props.color || "#BBB"}
|
||||||
|
d="M11 20.5c5.523 0 10-4.477 10-10S16.523.5 11 .5 1 4.977 1 10.5s4.477 10 10 10Z"
|
||||||
|
/>
|
||||||
|
<Path
|
||||||
|
stroke={props.color || "#BBB"}
|
||||||
|
strokeLinecap="round"
|
||||||
|
d="m13.75 7.75-5.5 5.5m0-5.5 5.5 5.5"
|
||||||
|
/>
|
||||||
|
</Svg>
|
||||||
|
);
|
||||||
|
export default CircledXIcon;
|
||||||
17
assets/svgs/EmailIcon.tsx
Normal file
17
assets/svgs/EmailIcon.tsx
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import * as React from "react"
|
||||||
|
import Svg, { SvgProps, Path } from "react-native-svg"
|
||||||
|
const EmailIcon = (props: SvgProps) => (
|
||||||
|
<Svg
|
||||||
|
width={props.width || 20}
|
||||||
|
height={props.height || 16}
|
||||||
|
viewBox="0 0 20 16"
|
||||||
|
fill="none"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<Path
|
||||||
|
fill={props.color || "#fff"}
|
||||||
|
d="M19.948 2.385a2.767 2.767 0 0 0-.76-1.422A2.768 2.768 0 0 0 17.225.15H2.774A2.772 2.772 0 0 0 0 2.925v10.15c0 .389.083.763.23 1.101a2.719 2.719 0 0 0 .774 1.035c.48.398 1.1.638 1.77.638h14.452a2.755 2.755 0 0 0 1.961-.813c.245-.245.447-.537.586-.86v-.002c.147-.338.227-.71.227-1.1V2.925c0-.182-.018-.363-.052-.539ZM1.817 1.967a1.34 1.34 0 0 1 .957-.397h14.452a1.335 1.335 0 0 1 1.079.54l-7.575 6.6a1.11 1.11 0 0 1-1.46 0L1.698 2.107c.034-.048.075-.095.119-.139Zm-.398 11.107V3.575l5.482 4.782-5.479 4.777c-.003-.018-.003-.039-.003-.06Zm15.807 1.355H2.774c-.245 0-.475-.064-.67-.178l5.78-5.037.54.47a2.406 2.406 0 0 0 3.155 0l.54-.47 5.778 5.037a1.338 1.338 0 0 1-.671.178Zm1.355-1.354c0 .02 0 .04-.003.059L13.1 8.36l5.48-4.782v9.497Z"
|
||||||
|
/>
|
||||||
|
</Svg>
|
||||||
|
)
|
||||||
|
export default EmailIcon
|
||||||
20
assets/svgs/QRIcon.tsx
Normal file
20
assets/svgs/QRIcon.tsx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import * as React from "react"
|
||||||
|
import Svg, { SvgProps, Path } from "react-native-svg"
|
||||||
|
const QRIcon = (props: SvgProps) => (
|
||||||
|
<Svg
|
||||||
|
width={props.width || 19}
|
||||||
|
height={props.height || 20}
|
||||||
|
viewBox="0 0 19 20"
|
||||||
|
fill="none"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<Path
|
||||||
|
stroke={props.color || "#fff"}
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeWidth={1.764}
|
||||||
|
d="M5.086 10.441h4.41v4.41m-7.93-4.41h-.008m4.418 4.41h-.008m3.536 3.528h-.008m7.946-7.938h-.008m-15.876 4.41H2.88m9.702-4.41h1.764M1.557 18.38h4.41M9.497 1.621v5.292m4.939 11.466h1.587c.494 0 .741 0 .93-.096.166-.085.3-.22.385-.386.097-.188.097-.435.097-.93V15.38c0-.494 0-.74-.097-.93a.882.882 0 0 0-.385-.385c-.189-.096-.436-.096-.93-.096h-1.587c-.494 0-.741 0-.93.096a.881.881 0 0 0-.385.386c-.096.188-.096.435-.096.93v1.587c0 .494 0 .74.096.93.084.166.22.3.385.385.189.096.436.096.93.096Zm0-11.466h1.587c.494 0 .741 0 .93-.096.166-.085.3-.22.385-.385.097-.19.097-.436.097-.93V3.914c0-.494 0-.74-.097-.93a.882.882 0 0 0-.385-.385c-.189-.096-.436-.096-.93-.096h-1.587c-.494 0-.741 0-.93.096a.881.881 0 0 0-.385.386c-.096.188-.096.435-.096.93v1.587c0 .494 0 .74.096.93.084.165.22.3.385.385.189.096.436.096.93.096Zm-11.466 0h1.587c.494 0 .741 0 .93-.096.166-.085.3-.22.385-.385.097-.19.097-.436.097-.93V3.914c0-.494 0-.74-.097-.93a.882.882 0 0 0-.385-.385c-.189-.096-.436-.096-.93-.096H2.97c-.494 0-.741 0-.93.096a.882.882 0 0 0-.385.386c-.096.188-.096.435-.096.93v1.587c0 .494 0 .74.096.93.084.165.22.3.385.385.189.096.436.096.93.096Z"
|
||||||
|
/>
|
||||||
|
</Svg>
|
||||||
|
)
|
||||||
|
export default QRIcon
|
||||||
@ -1,17 +1,24 @@
|
|||||||
import { View, Text, Button, TextField } from "react-native-ui-lib";
|
import {
|
||||||
import React, { useEffect, useState } from "react";
|
View,
|
||||||
|
Text,
|
||||||
|
Button,
|
||||||
|
TextField,
|
||||||
|
TextFieldRef,
|
||||||
|
TouchableOpacity,
|
||||||
|
} from "react-native-ui-lib";
|
||||||
|
import React, { useEffect, useState, useRef } from "react";
|
||||||
import { Dialog } from "react-native-ui-lib";
|
import { Dialog } from "react-native-ui-lib";
|
||||||
import { PanningDirectionsEnum } from "react-native-ui-lib/src/incubator/panView";
|
import { PanningDirectionsEnum } from "react-native-ui-lib/src/incubator/panView";
|
||||||
import CloseXIcon from "@/assets/svgs/CloseXIcon";
|
import { Dimensions, Keyboard, StyleSheet } from "react-native";
|
||||||
import { Dimensions, StyleSheet } from "react-native";
|
|
||||||
import DropModalIcon from "@/assets/svgs/DropModalIcon";
|
import DropModalIcon from "@/assets/svgs/DropModalIcon";
|
||||||
import MenuIcon from "@/assets/svgs/MenuIcon";
|
|
||||||
import { useBrainDumpContext } from "@/contexts/DumpContext";
|
import { useBrainDumpContext } from "@/contexts/DumpContext";
|
||||||
|
|
||||||
interface IAddBrainDumpProps {
|
interface IAddBrainDumpProps {
|
||||||
isVisible: boolean;
|
isVisible: boolean;
|
||||||
setIsVisible: (value: boolean) => void;
|
setIsVisible: (value: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const AddBrainDump = ({
|
const AddBrainDump = ({
|
||||||
addBrainDumpProps,
|
addBrainDumpProps,
|
||||||
}: {
|
}: {
|
||||||
@ -20,7 +27,10 @@ const AddBrainDump = ({
|
|||||||
const { addBrainDump } = useBrainDumpContext();
|
const { addBrainDump } = useBrainDumpContext();
|
||||||
const [dumpTitle, setDumpTitle] = useState<string>("");
|
const [dumpTitle, setDumpTitle] = useState<string>("");
|
||||||
const [dumpDesc, setDumpDesc] = useState<string>("");
|
const [dumpDesc, setDumpDesc] = useState<string>("");
|
||||||
const { width, height } = Dimensions.get("screen");
|
const { width } = Dimensions.get("screen");
|
||||||
|
|
||||||
|
// Refs for the two TextFields
|
||||||
|
const descriptionRef = useRef<TextFieldRef>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setDumpDesc("");
|
setDumpDesc("");
|
||||||
@ -34,14 +44,7 @@ const AddBrainDump = ({
|
|||||||
width={width}
|
width={width}
|
||||||
panDirection={PanningDirectionsEnum.DOWN}
|
panDirection={PanningDirectionsEnum.DOWN}
|
||||||
onDismiss={() => addBrainDumpProps.setIsVisible(false)}
|
onDismiss={() => addBrainDumpProps.setIsVisible(false)}
|
||||||
containerStyle={{
|
containerStyle={styles.dialogContainer}
|
||||||
borderTopRightRadius: 15,
|
|
||||||
borderTopLeftRadius: 15,
|
|
||||||
backgroundColor: "white",
|
|
||||||
padding: 0,
|
|
||||||
paddingTop: 3,
|
|
||||||
margin: 0,
|
|
||||||
}}
|
|
||||||
visible={addBrainDumpProps.isVisible}
|
visible={addBrainDumpProps.isVisible}
|
||||||
>
|
>
|
||||||
<View row spread style={styles.topBtns} marginB-20>
|
<View row spread style={styles.topBtns} marginB-20>
|
||||||
@ -53,16 +56,15 @@ const AddBrainDump = ({
|
|||||||
addBrainDumpProps.setIsVisible(false);
|
addBrainDumpProps.setIsVisible(false);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<DropModalIcon
|
<TouchableOpacity onPress={() => addBrainDumpProps.setIsVisible(false)}>
|
||||||
style={{ marginTop: 15 }}
|
<DropModalIcon style={{ marginTop: 15 }} />
|
||||||
onPress={() => addBrainDumpProps.setIsVisible(false)}
|
</TouchableOpacity>
|
||||||
/>
|
|
||||||
<Button
|
<Button
|
||||||
color="#05a8b6"
|
color="#05a8b6"
|
||||||
label="Save"
|
label="Save"
|
||||||
style={styles.topBtn}
|
style={styles.topBtn}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
addBrainDump({ id: 99, title: dumpTitle, description: dumpDesc });
|
addBrainDump({ id: 99, title: dumpTitle.trimEnd().trimStart(), description: dumpDesc.trimEnd().trimStart() });
|
||||||
addBrainDumpProps.setIsVisible(false);
|
addBrainDumpProps.setIsVisible(false);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@ -70,20 +72,37 @@ const AddBrainDump = ({
|
|||||||
<View marginH-20>
|
<View marginH-20>
|
||||||
<TextField
|
<TextField
|
||||||
value={dumpTitle}
|
value={dumpTitle}
|
||||||
|
autoFocus
|
||||||
placeholder="Set Title"
|
placeholder="Set Title"
|
||||||
text60R
|
text60R
|
||||||
onChangeText={(text) => {
|
onChangeText={(text) => {
|
||||||
setDumpTitle(text);
|
setDumpTitle(text);
|
||||||
}}
|
}}
|
||||||
|
onSubmitEditing={() => {
|
||||||
|
// Move focus to the description field
|
||||||
|
descriptionRef.current?.focus();
|
||||||
|
}}
|
||||||
|
style={styles.title}
|
||||||
|
blurOnSubmit={false} // Keep the keyboard open when moving focus
|
||||||
|
returnKeyType="next"
|
||||||
/>
|
/>
|
||||||
<View height={2} backgroundColor="#b3b3b3" width={"100%"} marginB-20 />
|
<View height={2} backgroundColor="#b3b3b3" width={"100%"} marginB-20 />
|
||||||
<TextField
|
<TextField
|
||||||
|
ref={descriptionRef}
|
||||||
value={dumpDesc}
|
value={dumpDesc}
|
||||||
placeholder="Write Description"
|
placeholder="Write Description"
|
||||||
text70
|
text70
|
||||||
onChangeText={(text) => {
|
onChangeText={(text) => {
|
||||||
setDumpDesc(text);
|
setDumpDesc(text);
|
||||||
}}
|
}}
|
||||||
|
style={styles.description}
|
||||||
|
multiline
|
||||||
|
numberOfLines={4}
|
||||||
|
maxLength={255}
|
||||||
|
onEndEditing={() => {
|
||||||
|
descriptionRef.current?.blur();
|
||||||
|
}}
|
||||||
|
returnKeyType="done"
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
@ -91,11 +110,28 @@ const AddBrainDump = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
|
dialogContainer: {
|
||||||
|
borderTopRightRadius: 15,
|
||||||
|
borderTopLeftRadius: 15,
|
||||||
|
backgroundColor: "white",
|
||||||
|
padding: 0,
|
||||||
|
paddingTop: 3,
|
||||||
|
margin: 0,
|
||||||
|
},
|
||||||
topBtns: {},
|
topBtns: {},
|
||||||
topBtn: {
|
topBtn: {
|
||||||
backgroundColor: "white",
|
backgroundColor: "white",
|
||||||
color: "#05a8b6",
|
color: "#05a8b6",
|
||||||
},
|
},
|
||||||
|
title: {
|
||||||
|
fontSize: 22,
|
||||||
|
fontFamily: "Manrope_500Medium",
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
fontFamily: "Manrope_400Regular",
|
||||||
|
fontSize: 14,
|
||||||
|
textAlignVertical: 'top'
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export default AddBrainDump;
|
export default AddBrainDump;
|
||||||
|
|||||||
@ -98,19 +98,18 @@ const MoveBrainDump = (props: {
|
|||||||
<TextField
|
<TextField
|
||||||
textAlignVertical="top"
|
textAlignVertical="top"
|
||||||
multiline
|
multiline
|
||||||
|
autoFocus
|
||||||
fieldStyle={{
|
fieldStyle={{
|
||||||
width: "94%",
|
width: "94%",
|
||||||
}}
|
}}
|
||||||
style={{
|
style={styles.description}
|
||||||
fontFamily: "Manrope_400Regular",
|
|
||||||
fontSize: 14,
|
|
||||||
}}
|
|
||||||
placeholder="Add description"
|
placeholder="Add description"
|
||||||
numberOfLines={3}
|
numberOfLines={3}
|
||||||
value={description}
|
value={description}
|
||||||
onChangeText={(value) => {
|
onChangeText={(value) => {
|
||||||
setDescription(value);
|
setDescription(value);
|
||||||
}}
|
}}
|
||||||
|
returnKeyType="default"
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.divider} />
|
<View style={styles.divider} />
|
||||||
@ -192,6 +191,10 @@ const styles = StyleSheet.create({
|
|||||||
fontSize: 22,
|
fontSize: 22,
|
||||||
fontFamily: "Manrope_500Medium",
|
fontFamily: "Manrope_500Medium",
|
||||||
},
|
},
|
||||||
|
description:{
|
||||||
|
fontFamily: "Manrope_400Regular",
|
||||||
|
fontSize: 14,
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export default MoveBrainDump;
|
export default MoveBrainDump;
|
||||||
|
|||||||
@ -225,6 +225,7 @@ export const ManuallyAddEventModal = ({
|
|||||||
<TextField
|
<TextField
|
||||||
placeholder="Add event title"
|
placeholder="Add event title"
|
||||||
value={title}
|
value={title}
|
||||||
|
autoFocus
|
||||||
onChangeText={(text) => {
|
onChangeText={(text) => {
|
||||||
setTitle(text);
|
setTitle(text);
|
||||||
}}
|
}}
|
||||||
@ -232,6 +233,7 @@ export const ManuallyAddEventModal = ({
|
|||||||
style={{ fontFamily: "Manrope_500Medium", fontSize: 22 }}
|
style={{ fontFamily: "Manrope_500Medium", fontSize: 22 }}
|
||||||
paddingT-15
|
paddingT-15
|
||||||
paddingL-30
|
paddingL-30
|
||||||
|
returnKeyType="next"
|
||||||
/>
|
/>
|
||||||
<View style={styles.divider} marginT-8 />
|
<View style={styles.divider} marginT-8 />
|
||||||
<View marginL-30 centerV>
|
<View marginL-30 centerV>
|
||||||
|
|||||||
@ -23,7 +23,7 @@ const CategoryDropdown = (props: {
|
|||||||
padding: 10,
|
padding: 10,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Text>{category}</Text>
|
<Text style={{fontFamily: "Manrope_400Regular"}}>{category}</Text>
|
||||||
</View>
|
</View>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
import {Text, View} from "react-native";
|
import {Text, View} from "react-native";
|
||||||
import React, {useEffect, useRef} from "react";
|
import React, {useEffect, useRef, useState} from "react";
|
||||||
import {TextField, TextFieldRef} from "react-native-ui-lib";
|
import {TextField, TextFieldRef} from "react-native-ui-lib";
|
||||||
import {GroceryCategory, useGroceryContext,} from "@/contexts/GroceryContext";
|
import {GroceryCategory, useGroceryContext,} from "@/contexts/GroceryContext";
|
||||||
|
import CategoryDropdown from "./CategoryDropdown";
|
||||||
|
|
||||||
interface IEditGrocery {
|
interface IEditGrocery {
|
||||||
id?: string;
|
id?: string;
|
||||||
@ -17,6 +18,7 @@ interface IEditGrocery {
|
|||||||
const EditGroceryItem = ({editGrocery}: { editGrocery: IEditGrocery }) => {
|
const EditGroceryItem = ({editGrocery}: { editGrocery: IEditGrocery }) => {
|
||||||
const {fuzzyMatchGroceryCategory} = useGroceryContext();
|
const {fuzzyMatchGroceryCategory} = useGroceryContext();
|
||||||
const inputRef = useRef<TextFieldRef>(null);
|
const inputRef = useRef<TextFieldRef>(null);
|
||||||
|
const [category, setCategory] = useState<GroceryCategory>(GroceryCategory.None);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (editGrocery.setCategory)
|
if (editGrocery.setCategory)
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useRef, useState } from "react";
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
ButtonSize,
|
ButtonSize,
|
||||||
Checkbox,
|
Checkbox,
|
||||||
Text,
|
Text,
|
||||||
TextField,
|
TextField,
|
||||||
|
TextFieldRef,
|
||||||
TouchableOpacity,
|
TouchableOpacity,
|
||||||
View,
|
View,
|
||||||
} from "react-native-ui-lib";
|
} from "react-native-ui-lib";
|
||||||
@ -13,7 +14,13 @@ import { ProfileType } from "@/contexts/AuthContext";
|
|||||||
import { StyleSheet } from "react-native";
|
import { StyleSheet } from "react-native";
|
||||||
import { AntDesign } from "@expo/vector-icons";
|
import { AntDesign } from "@expo/vector-icons";
|
||||||
|
|
||||||
const SignUpPage = ({setTab}: { setTab: React.Dispatch<React.SetStateAction<"register" | "login" | "reset-password">> }) => {
|
const SignUpPage = ({
|
||||||
|
setTab,
|
||||||
|
}: {
|
||||||
|
setTab: React.Dispatch<
|
||||||
|
React.SetStateAction<"register" | "login" | "reset-password">
|
||||||
|
>;
|
||||||
|
}) => {
|
||||||
const [email, setEmail] = useState<string>("");
|
const [email, setEmail] = useState<string>("");
|
||||||
const [firstName, setFirstName] = useState<string>("");
|
const [firstName, setFirstName] = useState<string>("");
|
||||||
const [lastName, setLastName] = useState<string>("");
|
const [lastName, setLastName] = useState<string>("");
|
||||||
@ -24,6 +31,10 @@ const SignUpPage = ({setTab}: { setTab: React.Dispatch<React.SetStateAction<"re
|
|||||||
const [acceptTerms, setAcceptTerms] = useState<boolean>(false);
|
const [acceptTerms, setAcceptTerms] = useState<boolean>(false);
|
||||||
const { mutateAsync: signUp } = useSignUp();
|
const { mutateAsync: signUp } = useSignUp();
|
||||||
|
|
||||||
|
const lnameRef = useRef<TextFieldRef>(null);
|
||||||
|
const emailRef = useRef<TextFieldRef>(null);
|
||||||
|
const passwordRef = useRef<TextFieldRef>(null);
|
||||||
|
|
||||||
const handleSignUp = async () => {
|
const handleSignUp = async () => {
|
||||||
await signUp({ email, password, firstName, lastName });
|
await signUp({ email, password, firstName, lastName });
|
||||||
};
|
};
|
||||||
@ -36,24 +47,34 @@ const SignUpPage = ({setTab}: { setTab: React.Dispatch<React.SetStateAction<"re
|
|||||||
<Text center>Please enter your details.</Text>
|
<Text center>Please enter your details.</Text>
|
||||||
<TextField
|
<TextField
|
||||||
marginT-60
|
marginT-60
|
||||||
|
autoFocus
|
||||||
placeholder="First name"
|
placeholder="First name"
|
||||||
value={firstName}
|
value={firstName}
|
||||||
onChangeText={setFirstName}
|
onChangeText={setFirstName}
|
||||||
style={styles.textfield}
|
style={styles.textfield}
|
||||||
|
onSubmitEditing={() => {lnameRef.current?.focus()}}
|
||||||
|
blurOnSubmit={false}
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
|
ref={lnameRef}
|
||||||
placeholder="Last name"
|
placeholder="Last name"
|
||||||
value={lastName}
|
value={lastName}
|
||||||
onChangeText={setLastName}
|
onChangeText={setLastName}
|
||||||
style={styles.textfield}
|
style={styles.textfield}
|
||||||
|
onSubmitEditing={() => {emailRef.current?.focus()}}
|
||||||
|
blurOnSubmit={false}
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
|
ref={emailRef}
|
||||||
placeholder="Email"
|
placeholder="Email"
|
||||||
value={email}
|
value={email}
|
||||||
onChangeText={setEmail}
|
onChangeText={setEmail}
|
||||||
style={styles.textfield}
|
style={styles.textfield}
|
||||||
|
onSubmitEditing={() => {passwordRef.current?.focus()}}
|
||||||
|
blurOnSubmit={false}
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
|
ref={passwordRef}
|
||||||
placeholder="Password"
|
placeholder="Password"
|
||||||
value={password}
|
value={password}
|
||||||
onChangeText={setPassword}
|
onChangeText={setPassword}
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import { AuthContextProvider } from "@/contexts/AuthContext";
|
|||||||
import ProfileIcon from "@/assets/svgs/ProfileIcon";
|
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";
|
||||||
|
|
||||||
const pageIndex = {
|
const pageIndex = {
|
||||||
main: 0,
|
main: 0,
|
||||||
@ -20,71 +21,83 @@ const pageIndex = {
|
|||||||
const SettingsPage = () => {
|
const SettingsPage = () => {
|
||||||
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
|
||||||
backgroundColor="white"
|
backgroundColor="white"
|
||||||
style={styles.mainBtn}
|
style={styles.mainBtn}
|
||||||
label="Manage My Profile"
|
children={
|
||||||
labelStyle={styles.label}
|
<View row centerV width={"100%"}>
|
||||||
color="#07b8c7"
|
<ProfileIcon style={{ marginRight: 10 }} color="#07b9c8" />
|
||||||
iconSource={() => (
|
<Text style={styles.label} color="#07b8c7">
|
||||||
<ProfileIcon style={{marginRight: 10}} color="#07b9c8" />
|
Manage My Profile
|
||||||
)}
|
</Text>
|
||||||
onPress={() => setSelectedPage(pageIndex.user)}
|
<ArrowRightIcon style={{ marginLeft: "auto" }} />
|
||||||
/>
|
</View>
|
||||||
<Button
|
}
|
||||||
backgroundColor="white"
|
onPress={() => setSelectedPage(pageIndex.user)}
|
||||||
style={styles.mainBtn}
|
/>
|
||||||
label="Calendar Settings"
|
<Button
|
||||||
labelStyle={styles.label}
|
backgroundColor="white"
|
||||||
color="#fd1775"
|
style={styles.mainBtn}
|
||||||
iconSource={() => (
|
children={
|
||||||
<CalendarIcon style={{marginRight: 10}}/>
|
<View row centerV width={"100%"}>
|
||||||
)}
|
<CalendarIcon style={{ marginRight: 10 }} />
|
||||||
onPress={() => {
|
<Text style={styles.label} color="#fd1775">
|
||||||
setSelectedPage(pageIndex.calendar);
|
Calendar Settings
|
||||||
}}
|
</Text>
|
||||||
/>
|
<ArrowRightIcon style={{ marginLeft: "auto" }} />
|
||||||
<Button
|
</View>
|
||||||
backgroundColor="white"
|
}
|
||||||
style={styles.mainBtn}
|
onPress={() => {
|
||||||
label="To-Do Reward Settings"
|
setSelectedPage(pageIndex.calendar);
|
||||||
labelStyle={styles.label}
|
}}
|
||||||
color="#ff9900"
|
/>
|
||||||
iconSource={() => (
|
<Button
|
||||||
|
backgroundColor="white"
|
||||||
|
style={styles.mainBtn}
|
||||||
|
children={
|
||||||
|
<View row centerV width={"100%"}>
|
||||||
<Octicons
|
<Octicons
|
||||||
name="gear"
|
name="gear"
|
||||||
size={24}
|
size={24}
|
||||||
color="#ff9900"
|
color="#ff9900"
|
||||||
style={{ marginRight: 10 }}
|
style={{ marginRight: 10 }}
|
||||||
/>
|
/>
|
||||||
)}
|
<Text style={styles.label} color="#ff9900">
|
||||||
onPress={() => setSelectedPage(pageIndex.chore)}
|
To-Do Reward Settings
|
||||||
/>
|
</Text>
|
||||||
<Button
|
<ArrowRightIcon style={{ marginLeft: "auto" }} />
|
||||||
backgroundColor="white"
|
</View>
|
||||||
style={styles.mainBtn}
|
}
|
||||||
label="Cally Privacy Policy"
|
onPress={() => setSelectedPage(pageIndex.chore)}
|
||||||
labelStyle={styles.label}
|
/>
|
||||||
iconSource={() => (
|
<Button
|
||||||
<PrivacyPolicyIcon style={{marginRight: 10}}/>
|
backgroundColor="white"
|
||||||
)}
|
style={styles.mainBtn}
|
||||||
color="#6c645b"
|
children={
|
||||||
/>
|
<View row centerV width={"100%"}>
|
||||||
</View>
|
<PrivacyPolicyIcon style={{ marginRight: 10 }} />
|
||||||
)}
|
<Text style={styles.label} color="#6c645b">
|
||||||
{selectedPage == pageIndex.calendar && (
|
Cally Privacy Policy
|
||||||
<CalendarSettingsPage setSelectedPage={setSelectedPage} />
|
</Text>
|
||||||
)}
|
<ArrowRightIcon style={{ marginLeft: "auto" }} />
|
||||||
{selectedPage == pageIndex.chore && (
|
</View>
|
||||||
<ChoreRewardSettings setSelectedPage={setSelectedPage} />
|
}
|
||||||
)}
|
/>
|
||||||
{selectedPage == pageIndex.user && (
|
</View>
|
||||||
<UserSettings setSelectedPage={setSelectedPage} />
|
)}
|
||||||
)}
|
{selectedPage == pageIndex.calendar && (
|
||||||
</View>
|
<CalendarSettingsPage setSelectedPage={setSelectedPage} />
|
||||||
|
)}
|
||||||
|
{selectedPage == pageIndex.chore && (
|
||||||
|
<ChoreRewardSettings setSelectedPage={setSelectedPage} />
|
||||||
|
)}
|
||||||
|
{selectedPage == pageIndex.user && (
|
||||||
|
<UserSettings setSelectedPage={setSelectedPage} />
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -92,14 +105,14 @@ export default SettingsPage;
|
|||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
mainBtn: {
|
mainBtn: {
|
||||||
width: "100%",
|
width: 311,
|
||||||
justifyContent: "flex-start",
|
justifyContent: "flex-start",
|
||||||
marginBottom: 20,
|
marginBottom: 20,
|
||||||
height: 60,
|
height: 57.61,
|
||||||
},
|
},
|
||||||
label:{
|
label: {
|
||||||
fontFamily: "Poppins_400Regular",
|
fontFamily: "Poppins_400Regular",
|
||||||
fontSize: 14.71,
|
fontSize: 14.71,
|
||||||
textAlignVertical: 'center'
|
textAlignVertical: "center",
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,392 +1,505 @@
|
|||||||
import {
|
import {
|
||||||
Avatar,
|
Avatar,
|
||||||
Button,
|
Button,
|
||||||
Card,
|
Card,
|
||||||
Colors,
|
Colors,
|
||||||
Dialog,
|
Dialog,
|
||||||
FloatingButton,
|
FloatingButton,
|
||||||
PanningProvider,
|
PanningProvider,
|
||||||
Picker,
|
Picker,
|
||||||
Text,
|
Text,
|
||||||
TextField,
|
TextField,
|
||||||
TouchableOpacity,
|
TextFieldRef,
|
||||||
View,
|
TouchableOpacity,
|
||||||
|
View,
|
||||||
} from "react-native-ui-lib";
|
} from "react-native-ui-lib";
|
||||||
import React, {useState} from "react";
|
import React, { useEffect, useRef, useState } from "react";
|
||||||
import {ScrollView, StyleSheet} from "react-native";
|
import { Dimensions, ScrollView, StyleSheet } from "react-native";
|
||||||
import {PickerSingleValue} from "react-native-ui-lib/src/components/picker/types";
|
import { PickerSingleValue } from "react-native-ui-lib/src/components/picker/types";
|
||||||
import {useCreateSubUser} from "@/hooks/firebase/useCreateSubUser";
|
import { useCreateSubUser } from "@/hooks/firebase/useCreateSubUser";
|
||||||
import {ProfileType} from "@/contexts/AuthContext";
|
import { ProfileType } from "@/contexts/AuthContext";
|
||||||
import {useGetFamilyMembers} from "@/hooks/firebase/useGetFamilyMembers";
|
import { useGetFamilyMembers } from "@/hooks/firebase/useGetFamilyMembers";
|
||||||
import UserMenu from "@/components/pages/settings/user_settings_views/UserMenu";
|
import UserMenu from "@/components/pages/settings/user_settings_views/UserMenu";
|
||||||
import {uuidv4} from "@firebase/util";
|
import { uuidv4 } from "@firebase/util";
|
||||||
|
import QRIcon from "@/assets/svgs/QRIcon";
|
||||||
|
import EmailIcon from "@/assets/svgs/EmailIcon";
|
||||||
|
import CircledXIcon from "@/assets/svgs/CircledXIcon";
|
||||||
|
import ProfileIcon from "@/assets/svgs/ProfileIcon";
|
||||||
|
import NavToDosIcon from "@/assets/svgs/NavToDosIcon";
|
||||||
|
|
||||||
const MyGroup = () => {
|
const MyGroup = () => {
|
||||||
const [showAddUserDialog, setShowAddUserDialog] = useState(false);
|
const [showAddUserDialog, setShowAddUserDialog] = useState(false);
|
||||||
const [showNewUserInfoDialog, setShowNewUserInfoDialog] = useState(false);
|
const [showNewUserInfoDialog, setShowNewUserInfoDialog] = useState(false);
|
||||||
const [selectedStatus, setSelectedStatus] = useState<
|
const [selectedStatus, setSelectedStatus] = useState<
|
||||||
string | PickerSingleValue
|
string | PickerSingleValue
|
||||||
>(ProfileType.CHILD);
|
>(ProfileType.CHILD);
|
||||||
const [firstName, setFirstName] = useState("");
|
const [firstName, setFirstName] = useState("");
|
||||||
const [lastName, setLastName] = useState("");
|
const [lastName, setLastName] = useState("");
|
||||||
const [email, setEmail] = useState("");
|
const [email, setEmail] = useState("");
|
||||||
|
|
||||||
const [showQRCodeDialog, setShowQRCodeDialog] = useState("");
|
const lNameRef = useRef<TextFieldRef>(null);
|
||||||
|
const emailRef = useRef<TextFieldRef>(null);
|
||||||
|
|
||||||
const {mutateAsync: createSubUser, isLoading, isError} = useCreateSubUser();
|
const [showQRCodeDialog, setShowQRCodeDialog] = useState("");
|
||||||
const {data: familyMembers} = useGetFamilyMembers(true);
|
|
||||||
|
|
||||||
const parents =
|
const { mutateAsync: createSubUser, isLoading, isError } = useCreateSubUser();
|
||||||
familyMembers?.filter((x) => x.userType === ProfileType.PARENT) ?? [];
|
const { data: familyMembers } = useGetFamilyMembers(true);
|
||||||
const children =
|
|
||||||
familyMembers?.filter((x) => x.userType === ProfileType.CHILD) ?? [];
|
|
||||||
const caregivers =
|
|
||||||
familyMembers?.filter((x) => x.userType === ProfileType.CAREGIVER) ?? [];
|
|
||||||
const familyDevices =
|
|
||||||
familyMembers?.filter((x) => x.userType === ProfileType.FAMILY_DEVICE) ?? [];
|
|
||||||
|
|
||||||
const handleCreateSubUser = async () => {
|
const parents =
|
||||||
if (!firstName || (selectedStatus !== ProfileType.FAMILY_DEVICE && !lastName)) {
|
familyMembers?.filter((x) => x.userType === ProfileType.PARENT) ?? [];
|
||||||
console.error("First name and last name are required");
|
const children =
|
||||||
return;
|
familyMembers?.filter((x) => x.userType === ProfileType.CHILD) ?? [];
|
||||||
}
|
const caregivers =
|
||||||
|
familyMembers?.filter((x) => x.userType === ProfileType.CAREGIVER) ?? [];
|
||||||
|
const familyDevices =
|
||||||
|
familyMembers?.filter((x) => x.userType === ProfileType.FAMILY_DEVICE) ??
|
||||||
|
[];
|
||||||
|
|
||||||
if (selectedStatus !== ProfileType.FAMILY_DEVICE && !email) {
|
const handleCreateSubUser = async () => {
|
||||||
console.error("Email is required for non-family device users");
|
if (
|
||||||
return;
|
!firstName ||
|
||||||
}
|
(selectedStatus !== ProfileType.FAMILY_DEVICE && !lastName)
|
||||||
|
) {
|
||||||
|
console.error("First name and last name are required");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (email && !email.includes("@")) {
|
if (selectedStatus !== ProfileType.FAMILY_DEVICE && !email) {
|
||||||
console.error("Invalid email address");
|
console.error("Email is required for non-family device users");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await createSubUser({
|
if (email && !email.includes("@")) {
|
||||||
firstName,
|
console.error("Invalid email address");
|
||||||
lastName: selectedStatus === ProfileType.FAMILY_DEVICE ? "" : lastName,
|
return;
|
||||||
email: email || `placeholder_${uuidv4().split("-")[0]}@family.device`,
|
}
|
||||||
password: uuidv4(),
|
|
||||||
userType: selectedStatus as ProfileType,
|
|
||||||
});
|
|
||||||
console.log(res)
|
|
||||||
|
|
||||||
if (!isError) {
|
const res = await createSubUser({
|
||||||
setShowNewUserInfoDialog(false);
|
firstName,
|
||||||
|
lastName: selectedStatus === ProfileType.FAMILY_DEVICE ? "" : lastName,
|
||||||
|
email: email || `placeholder_${uuidv4().split("-")[0]}@family.device`,
|
||||||
|
password: uuidv4(),
|
||||||
|
userType: selectedStatus as ProfileType,
|
||||||
|
});
|
||||||
|
console.log(res);
|
||||||
|
|
||||||
if(res?.data?.userId) {
|
if (!isError) {
|
||||||
setTimeout(() => {
|
setShowNewUserInfoDialog(false);
|
||||||
setShowQRCodeDialog(res.data.userId)
|
|
||||||
}, 500)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (res?.data?.userId) {
|
||||||
|
setTimeout(() => {
|
||||||
|
setShowQRCodeDialog(res.data.userId);
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
};
|
useEffect(() => {
|
||||||
|
setFirstName("");
|
||||||
|
setLastName("");
|
||||||
|
setEmail("");
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={{flex: 1}}>
|
<View style={{ flex: 1, minHeight: 500 }}>
|
||||||
<View>
|
<View>
|
||||||
<ScrollView style={styles.card}>
|
<ScrollView style={styles.card}>
|
||||||
{!parents.length && !children.length && !caregivers.length && (
|
{!parents.length && !children.length && !caregivers.length && (
|
||||||
<Text text70 marginV-10>
|
<Text text70 marginV-10>
|
||||||
{isLoading ? "Loading...." : "No user devices added"}
|
{isLoading ? "Loading...." : "No user devices added"}
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{(!!parents.length || !!children.length) && (
|
{(!!parents.length || !!children.length) && (
|
||||||
<>
|
<>
|
||||||
<Text style={styles.subTit} marginV-10>
|
<Text style={styles.subTit} marginV-10>
|
||||||
Family
|
Family
|
||||||
</Text>
|
</Text>
|
||||||
{[...parents, ...children]?.map((member, index) => (
|
{[...parents, ...children]?.map((member, index) => (
|
||||||
<Card
|
<Card
|
||||||
enableShadow={false}
|
enableShadow={false}
|
||||||
elevation={0}
|
elevation={0}
|
||||||
key={`${member.firstName}_${member.lastName}_${index}`}
|
key={`${member.firstName}_${member.lastName}_${index}`}
|
||||||
style={styles.familyCard}
|
style={styles.familyCard}
|
||||||
row
|
row
|
||||||
centerV
|
centerV
|
||||||
padding-10
|
padding-10
|
||||||
>
|
>
|
||||||
<Avatar
|
<Avatar
|
||||||
source={{uri: "https://via.placeholder.com/60"}}
|
source={{ uri: "https://via.placeholder.com/60" }}
|
||||||
size={40}
|
size={40}
|
||||||
backgroundColor={Colors.grey60}
|
backgroundColor={Colors.grey60}
|
||||||
/>
|
/>
|
||||||
<View marginL-10>
|
<View marginL-10>
|
||||||
<Text text70M>
|
<Text text70M>
|
||||||
{member.firstName} {member.lastName}
|
{member.firstName} {member.lastName}
|
||||||
</Text>
|
|
||||||
<Text text90 grey40>
|
|
||||||
{member.userType === ProfileType.PARENT
|
|
||||||
? "Admin (You)"
|
|
||||||
: "Child"}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View flex-1/>
|
|
||||||
|
|
||||||
<UserMenu setShowQRCodeDialog={(val) => setShowQRCodeDialog("")} showQRCodeDialog={showQRCodeDialog === member?.uid} userId={member?.uid!}/>
|
|
||||||
</Card>
|
|
||||||
))}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{!!caregivers.length && (
|
|
||||||
<>
|
|
||||||
<Text text70 marginB-10 marginT-15>
|
|
||||||
Caregivers
|
|
||||||
</Text>
|
|
||||||
{caregivers?.map((member) => (
|
|
||||||
<Card
|
|
||||||
enableShadow={false}
|
|
||||||
elevation={0}
|
|
||||||
key={`${member.firstName}_${member.lastName}`}
|
|
||||||
style={styles.familyCard}
|
|
||||||
row
|
|
||||||
centerV
|
|
||||||
padding-10
|
|
||||||
>
|
|
||||||
<Avatar
|
|
||||||
source={{uri: "https://via.placeholder.com/60"}}
|
|
||||||
size={40}
|
|
||||||
backgroundColor={Colors.grey60}
|
|
||||||
/>
|
|
||||||
<View marginL-10>
|
|
||||||
<Text text70M>
|
|
||||||
{member.firstName} {member.lastName}
|
|
||||||
</Text>
|
|
||||||
<Text text90 grey40>
|
|
||||||
Caregiver
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<UserMenu setShowQRCodeDialog={(val) => setShowQRCodeDialog("")} showQRCodeDialog={showQRCodeDialog === member?.uid} userId={member?.uid!}/>
|
|
||||||
</Card>
|
|
||||||
))}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{!!familyDevices.length && (
|
|
||||||
<>
|
|
||||||
<Text text70 marginB-10 marginT-15>
|
|
||||||
Family Devices
|
|
||||||
</Text>
|
|
||||||
{familyDevices?.map((member, index) => (
|
|
||||||
<Card
|
|
||||||
enableShadow={false}
|
|
||||||
elevation={0}
|
|
||||||
key={`${member.firstName}_${member.lastName}_${index}`}
|
|
||||||
style={styles.familyCard}
|
|
||||||
row
|
|
||||||
centerV
|
|
||||||
padding-10
|
|
||||||
>
|
|
||||||
<Avatar
|
|
||||||
source={{uri: "https://via.placeholder.com/60"}}
|
|
||||||
size={40}
|
|
||||||
backgroundColor={Colors.grey60}
|
|
||||||
/>
|
|
||||||
<View marginL-10>
|
|
||||||
<Text text70M>
|
|
||||||
{member.firstName}
|
|
||||||
</Text>
|
|
||||||
<Text text90 grey40>
|
|
||||||
Family Device
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<UserMenu setShowQRCodeDialog={(val) => setShowQRCodeDialog("")} showQRCodeDialog={showQRCodeDialog === member?.uid} userId={member?.uid!}/>
|
|
||||||
</Card>
|
|
||||||
))}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</ScrollView>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<FloatingButton
|
|
||||||
fullWidth
|
|
||||||
hideBackgroundOverlay
|
|
||||||
visible
|
|
||||||
button={{
|
|
||||||
label: "+ Add a user device",
|
|
||||||
onPress: () => setShowAddUserDialog(true),
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Dialog
|
|
||||||
visible={showAddUserDialog}
|
|
||||||
onDismiss={() => setShowAddUserDialog(false)}
|
|
||||||
panDirection={PanningProvider.Directions.DOWN}
|
|
||||||
>
|
|
||||||
<Card padding-25 gap-10>
|
|
||||||
<Text>Add a new user device</Text>
|
|
||||||
|
|
||||||
<Button backgroundColor={"#FD1775"}>
|
|
||||||
<Text white>Show a QR Code</Text>
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
backgroundColor={"#05A8B6"}
|
|
||||||
onPress={() => {
|
|
||||||
setShowAddUserDialog(false);
|
|
||||||
setTimeout(() => {
|
|
||||||
setShowNewUserInfoDialog(true);
|
|
||||||
}, 500);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Text white>Enter email address</Text>
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<TouchableOpacity onPress={() => setShowAddUserDialog(false)} center>
|
|
||||||
<Text>Return to user settings</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
</Card>
|
|
||||||
</Dialog>
|
|
||||||
|
|
||||||
<Dialog
|
|
||||||
panDirection={PanningProvider.Directions.DOWN}
|
|
||||||
visible={showNewUserInfoDialog}
|
|
||||||
onDismiss={() => setShowNewUserInfoDialog(false)}
|
|
||||||
>
|
|
||||||
<Card padding-25 style={styles.dialogCard}>
|
|
||||||
<View row spread>
|
|
||||||
<Text text60M>New User Information</Text>
|
|
||||||
<TouchableOpacity onPress={() => setShowAddUserDialog(false)}>
|
|
||||||
<Text>X</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View row centerV gap-20 marginV-20>
|
|
||||||
<Avatar
|
|
||||||
imageStyle={{borderRadius: 10}}
|
|
||||||
containerStyle={{borderRadius: 10}}
|
|
||||||
size={60}
|
|
||||||
backgroundColor={Colors.grey60}
|
|
||||||
/>
|
|
||||||
<TouchableOpacity onPress={() => {
|
|
||||||
}}>
|
|
||||||
<Text style={{color: Colors.green10}}>
|
|
||||||
Upload User Profile Photo
|
|
||||||
</Text>
|
|
||||||
</TouchableOpacity>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<Text style={styles.label}>Member Status</Text>
|
|
||||||
<Picker
|
|
||||||
editable={!isLoading}
|
|
||||||
value={selectedStatus}
|
|
||||||
//@ts-ignore
|
|
||||||
onChange={(item) => setSelectedStatus(item)}
|
|
||||||
style={styles.picker}
|
|
||||||
showSearch
|
|
||||||
floatingPlaceholder
|
|
||||||
>
|
|
||||||
<Picker.Item label="Child" value={ProfileType.CHILD}/>
|
|
||||||
<Picker.Item label="Parent" value={ProfileType.PARENT}/>
|
|
||||||
<Picker.Item label="Caregiver" value={ProfileType.CAREGIVER}/>
|
|
||||||
<Picker.Item label="Family Device" value={ProfileType.FAMILY_DEVICE}/>
|
|
||||||
</Picker>
|
|
||||||
|
|
||||||
<Text style={styles.label}>
|
|
||||||
{selectedStatus === ProfileType.FAMILY_DEVICE ? "Device Name" : "First Name"}
|
|
||||||
</Text>
|
</Text>
|
||||||
<TextField
|
<Text text90 grey40>
|
||||||
editable={!isLoading}
|
{member.userType === ProfileType.PARENT
|
||||||
placeholder={selectedStatus === ProfileType.FAMILY_DEVICE ? "Device name" : "First name"}
|
? "Admin (You)"
|
||||||
value={firstName}
|
: "Child"}
|
||||||
onChangeText={setFirstName}
|
</Text>
|
||||||
style={styles.inputField}
|
</View>
|
||||||
/>
|
|
||||||
|
|
||||||
{selectedStatus !== ProfileType.FAMILY_DEVICE && (
|
<View flex-1 />
|
||||||
<>
|
|
||||||
<Text style={styles.label}>Last Name</Text>
|
|
||||||
<TextField
|
|
||||||
editable={!isLoading}
|
|
||||||
placeholder="Last name"
|
|
||||||
value={lastName}
|
|
||||||
onChangeText={setLastName}
|
|
||||||
style={styles.inputField}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{selectedStatus !== ProfileType.FAMILY_DEVICE && (
|
<UserMenu
|
||||||
<>
|
setShowQRCodeDialog={(val) => setShowQRCodeDialog("")}
|
||||||
<Text style={styles.label}>Email Address (Optional)</Text>
|
showQRCodeDialog={showQRCodeDialog === member?.uid}
|
||||||
<TextField
|
userId={member?.uid!}
|
||||||
editable={!isLoading}
|
/>
|
||||||
placeholder="Email address"
|
|
||||||
value={email}
|
|
||||||
onChangeText={setEmail}
|
|
||||||
keyboardType="email-address"
|
|
||||||
autoCapitalize="none"
|
|
||||||
style={styles.inputField}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Button
|
|
||||||
disabled={!firstName || (selectedStatus !== ProfileType.FAMILY_DEVICE && !lastName) || isLoading}
|
|
||||||
label={isLoading ? "Adding..." : "Add group member"}
|
|
||||||
backgroundColor="#FD1775"
|
|
||||||
style={{marginTop: 20}}
|
|
||||||
onPress={handleCreateSubUser}
|
|
||||||
/>
|
|
||||||
</Card>
|
</Card>
|
||||||
</Dialog>
|
))}
|
||||||
</View>
|
</>
|
||||||
);
|
)}
|
||||||
|
|
||||||
|
{!!caregivers.length && (
|
||||||
|
<>
|
||||||
|
<Text text70 marginB-10 marginT-15>
|
||||||
|
Caregivers
|
||||||
|
</Text>
|
||||||
|
{caregivers?.map((member) => (
|
||||||
|
<Card
|
||||||
|
enableShadow={false}
|
||||||
|
elevation={0}
|
||||||
|
key={`${member.firstName}_${member.lastName}`}
|
||||||
|
style={styles.familyCard}
|
||||||
|
row
|
||||||
|
centerV
|
||||||
|
padding-10
|
||||||
|
>
|
||||||
|
<Avatar
|
||||||
|
source={{ uri: "https://via.placeholder.com/60" }}
|
||||||
|
size={40}
|
||||||
|
backgroundColor={Colors.grey60}
|
||||||
|
/>
|
||||||
|
<View marginL-10>
|
||||||
|
<Text text70M>
|
||||||
|
{member.firstName} {member.lastName}
|
||||||
|
</Text>
|
||||||
|
<Text text90 grey40>
|
||||||
|
Caregiver
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<UserMenu
|
||||||
|
setShowQRCodeDialog={(val) => setShowQRCodeDialog("")}
|
||||||
|
showQRCodeDialog={showQRCodeDialog === member?.uid}
|
||||||
|
userId={member?.uid!}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!!familyDevices.length && (
|
||||||
|
<>
|
||||||
|
<Text text70 marginB-10 marginT-15>
|
||||||
|
Family Devices
|
||||||
|
</Text>
|
||||||
|
{familyDevices?.map((member, index) => (
|
||||||
|
<Card
|
||||||
|
enableShadow={false}
|
||||||
|
elevation={0}
|
||||||
|
key={`${member.firstName}_${member.lastName}_${index}`}
|
||||||
|
style={styles.familyCard}
|
||||||
|
row
|
||||||
|
centerV
|
||||||
|
padding-10
|
||||||
|
>
|
||||||
|
<Avatar
|
||||||
|
source={{ uri: "https://via.placeholder.com/60" }}
|
||||||
|
size={40}
|
||||||
|
backgroundColor={Colors.grey60}
|
||||||
|
/>
|
||||||
|
<View marginL-10>
|
||||||
|
<Text text70M>{member.firstName}</Text>
|
||||||
|
<Text text90 grey40>
|
||||||
|
Family Device
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<UserMenu
|
||||||
|
setShowQRCodeDialog={(val) => setShowQRCodeDialog("")}
|
||||||
|
showQRCodeDialog={showQRCodeDialog === member?.uid}
|
||||||
|
userId={member?.uid!}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</ScrollView>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<FloatingButton
|
||||||
|
fullWidth
|
||||||
|
hideBackgroundOverlay
|
||||||
|
visible
|
||||||
|
button={{
|
||||||
|
label: "+ Add a user device",
|
||||||
|
onPress: () => setShowAddUserDialog(true),
|
||||||
|
style: styles.bottomButton,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Dialog
|
||||||
|
visible={showAddUserDialog}
|
||||||
|
onDismiss={() => setShowAddUserDialog(false)}
|
||||||
|
panDirection={PanningProvider.Directions.DOWN}
|
||||||
|
>
|
||||||
|
<Card
|
||||||
|
paddingH-25
|
||||||
|
paddingT-40
|
||||||
|
paddingB-20
|
||||||
|
gap-10
|
||||||
|
centerH
|
||||||
|
borderRadius={20}
|
||||||
|
>
|
||||||
|
<Text style={styles.dialogTitle} marginB-35>
|
||||||
|
Add a new user device
|
||||||
|
</Text>
|
||||||
|
|
||||||
|
<Button backgroundColor={"#FD1775"} style={styles.dialogBtn}>
|
||||||
|
<QRIcon />
|
||||||
|
<Text style={styles.dialogBtnLbl} marginL-7>
|
||||||
|
Show a QR Code
|
||||||
|
</Text>
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
style={styles.dialogBtn}
|
||||||
|
backgroundColor={"#05A8B6"}
|
||||||
|
onPress={() => {
|
||||||
|
setShowAddUserDialog(false);
|
||||||
|
setTimeout(() => {
|
||||||
|
setShowNewUserInfoDialog(true);
|
||||||
|
}, 500);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<EmailIcon />
|
||||||
|
<Text style={styles.dialogBtnLbl} marginL-7>
|
||||||
|
Enter email address
|
||||||
|
</Text>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<TouchableOpacity
|
||||||
|
onPress={() => setShowAddUserDialog(false)}
|
||||||
|
center
|
||||||
|
marginT-30
|
||||||
|
>
|
||||||
|
<Text style={styles.dialogBackBtn}>Return to user settings</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</Card>
|
||||||
|
</Dialog>
|
||||||
|
|
||||||
|
<Dialog
|
||||||
|
panDirection={PanningProvider.Directions.DOWN}
|
||||||
|
visible={showNewUserInfoDialog}
|
||||||
|
onDismiss={() => setShowNewUserInfoDialog(false)}
|
||||||
|
>
|
||||||
|
<Card padding-25 style={styles.dialogCard}>
|
||||||
|
<View row spread>
|
||||||
|
<Text style={{ fontFamily: "Manrope_500Medium", fontSize: 16 }}>
|
||||||
|
New User Information
|
||||||
|
</Text>
|
||||||
|
<TouchableOpacity onPress={() => {setShowNewUserInfoDialog(false)}}>
|
||||||
|
<CircledXIcon />
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
<View style={styles.divider} spread />
|
||||||
|
|
||||||
|
<View row centerV gap-20 marginV-20>
|
||||||
|
<View
|
||||||
|
height={65.54}
|
||||||
|
width={65.54}
|
||||||
|
children={
|
||||||
|
<ProfileIcon color={"#d6d6d6"} width={37} height={37} />
|
||||||
|
}
|
||||||
|
backgroundColor={Colors.grey60}
|
||||||
|
style={{ borderRadius: 25 }}
|
||||||
|
center
|
||||||
|
/>
|
||||||
|
<TouchableOpacity onPress={() => {}}>
|
||||||
|
<Text color="#50be0c" style={styles.jakarta13} marginL-15>
|
||||||
|
Upload User Profile Photo
|
||||||
|
</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<Text style={styles.jakarta12}>Member Status</Text>
|
||||||
|
<Picker
|
||||||
|
editable={!isLoading}
|
||||||
|
value={selectedStatus}
|
||||||
|
//@ts-ignore
|
||||||
|
onChange={(item) => setSelectedStatus(item)}
|
||||||
|
style={styles.picker}
|
||||||
|
showSearch
|
||||||
|
floatingPlaceholder
|
||||||
|
>
|
||||||
|
<Picker.Item label="Child" value={ProfileType.CHILD} />
|
||||||
|
<Picker.Item label="Parent" value={ProfileType.PARENT} />
|
||||||
|
<Picker.Item label="Caregiver" value={ProfileType.CAREGIVER} />
|
||||||
|
<Picker.Item
|
||||||
|
label="Family Device"
|
||||||
|
value={ProfileType.FAMILY_DEVICE}
|
||||||
|
/>
|
||||||
|
</Picker>
|
||||||
|
|
||||||
|
<Text style={styles.jakarta12}>
|
||||||
|
{selectedStatus === ProfileType.FAMILY_DEVICE
|
||||||
|
? "Device Name"
|
||||||
|
: "First Name"}
|
||||||
|
</Text>
|
||||||
|
<TextField
|
||||||
|
editable={!isLoading}
|
||||||
|
placeholder={
|
||||||
|
selectedStatus === ProfileType.FAMILY_DEVICE
|
||||||
|
? "Device name"
|
||||||
|
: "First name"
|
||||||
|
}
|
||||||
|
value={firstName}
|
||||||
|
onChangeText={setFirstName}
|
||||||
|
style={styles.inputField}
|
||||||
|
onSubmitEditing={() => {lNameRef.current?.focus()}}
|
||||||
|
blurOnSubmit={false}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{selectedStatus !== ProfileType.FAMILY_DEVICE && (
|
||||||
|
<>
|
||||||
|
<Text style={styles.jakarta12}>Last Name</Text>
|
||||||
|
<TextField
|
||||||
|
ref={lNameRef}
|
||||||
|
editable={!isLoading}
|
||||||
|
placeholder="Last name"
|
||||||
|
value={lastName}
|
||||||
|
onChangeText={setLastName}
|
||||||
|
style={styles.inputField}
|
||||||
|
onSubmitEditing={() => {emailRef.current?.focus()}}
|
||||||
|
blurOnSubmit={false}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{selectedStatus !== ProfileType.FAMILY_DEVICE && (
|
||||||
|
<>
|
||||||
|
<Text style={styles.jakarta12}>Email Address (Optional)</Text>
|
||||||
|
<TextField
|
||||||
|
ref={emailRef}
|
||||||
|
editable={!isLoading}
|
||||||
|
placeholder="Email address"
|
||||||
|
value={email}
|
||||||
|
onChangeText={setEmail}
|
||||||
|
keyboardType="email-address"
|
||||||
|
autoCapitalize="none"
|
||||||
|
style={styles.inputField}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Button
|
||||||
|
disabled={
|
||||||
|
!firstName ||
|
||||||
|
(selectedStatus !== ProfileType.FAMILY_DEVICE && !lastName) ||
|
||||||
|
isLoading
|
||||||
|
}
|
||||||
|
label={isLoading ? "Adding..." : "Add group member"}
|
||||||
|
backgroundColor="#fd1775"
|
||||||
|
labelStyle={{
|
||||||
|
fontFamily: "PlusJakartaSans_500Medium",
|
||||||
|
fontSize: 15,
|
||||||
|
marginLeft: 7,
|
||||||
|
}}
|
||||||
|
style={{ marginTop: 20, backgroundColor: "#fd1775" }}
|
||||||
|
iconSource={() => <NavToDosIcon width={22} color={"white"} />}
|
||||||
|
onPress={handleCreateSubUser}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
</Dialog>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
card: {
|
dialogBtn: {
|
||||||
marginVertical: 15,
|
height: 47,
|
||||||
backgroundColor: "white",
|
width: 279,
|
||||||
width: "100%",
|
},
|
||||||
borderRadius: 15,
|
dialogTitle: { fontFamily: "Manrope_600SemiBold", fontSize: 22 },
|
||||||
padding: 20,
|
dialogBackBtn: {
|
||||||
},
|
fontFamily: "PlusJakartaSans_500Medium",
|
||||||
familyCard: {
|
fontSize: 15,
|
||||||
marginBottom: 10,
|
color: "#a7a7a7",
|
||||||
borderRadius: 10,
|
},
|
||||||
backgroundColor: Colors.white,
|
card: {
|
||||||
width: "100%",
|
marginVertical: 15,
|
||||||
},
|
backgroundColor: "white",
|
||||||
inputField: {
|
width: "100%",
|
||||||
borderRadius: 50,
|
borderRadius: 15,
|
||||||
paddingVertical: 12,
|
padding: 20,
|
||||||
paddingHorizontal: 16,
|
},
|
||||||
backgroundColor: Colors.grey80,
|
bottomButton: {
|
||||||
marginBottom: 16,
|
position: "absolute",
|
||||||
borderColor: Colors.grey50,
|
bottom: 80,
|
||||||
borderWidth: 1,
|
width: "100%",
|
||||||
height: 40,
|
},
|
||||||
},
|
familyCard: {
|
||||||
picker: {
|
marginBottom: 10,
|
||||||
borderRadius: 50,
|
borderRadius: 10,
|
||||||
paddingVertical: 12,
|
backgroundColor: Colors.white,
|
||||||
paddingHorizontal: 16,
|
width: "100%",
|
||||||
backgroundColor: Colors.grey80,
|
},
|
||||||
marginBottom: 16,
|
inputField: {
|
||||||
borderColor: Colors.grey50,
|
fontFamily: "PlusJakartaSans_500Medium",
|
||||||
borderWidth: 1,
|
fontSize: 13,
|
||||||
marginTop: -20,
|
color: "#565656",
|
||||||
height: 40,
|
borderRadius: 50,
|
||||||
},
|
paddingVertical: 12,
|
||||||
label: {
|
paddingHorizontal: 16,
|
||||||
marginBottom: 5,
|
backgroundColor: Colors.grey80,
|
||||||
fontSize: 12,
|
marginBottom: 16,
|
||||||
color: Colors.grey40,
|
borderColor: Colors.grey50,
|
||||||
},
|
borderWidth: 1,
|
||||||
dialogCard: {
|
height: 40,
|
||||||
borderRadius: 10,
|
},
|
||||||
gap: 10,
|
picker: {
|
||||||
},
|
borderRadius: 50,
|
||||||
subTit: {
|
paddingVertical: 12,
|
||||||
fontFamily: "Manrope_500Medium",
|
paddingHorizontal: 16,
|
||||||
fontSize: 15,
|
backgroundColor: Colors.grey80,
|
||||||
},
|
marginBottom: 16,
|
||||||
|
borderColor: Colors.grey50,
|
||||||
|
borderWidth: 1,
|
||||||
|
marginTop: -20,
|
||||||
|
height: 40,
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
marginBottom: 5,
|
||||||
|
fontSize: 12,
|
||||||
|
color: Colors.grey40,
|
||||||
|
},
|
||||||
|
dialogCard: {
|
||||||
|
borderRadius: 10,
|
||||||
|
gap: 10,
|
||||||
|
},
|
||||||
|
subTit: {
|
||||||
|
fontFamily: "Manrope_500Medium",
|
||||||
|
fontSize: 15,
|
||||||
|
},
|
||||||
|
dialogBtnLbl: {
|
||||||
|
fontFamily: "PlusJakartaSans_500Medium",
|
||||||
|
fontSize: 15,
|
||||||
|
color: "white",
|
||||||
|
},
|
||||||
|
divider: { height: 0.7, backgroundColor: "#e6e6e6", width: "100%" },
|
||||||
|
jakarta12: {
|
||||||
|
fontFamily: "PlusJakartaSans_500Medium",
|
||||||
|
fontSize: 12,
|
||||||
|
color: "#a1a1a1",
|
||||||
|
},
|
||||||
|
jakarta13: {
|
||||||
|
fontFamily: "PlusJakartaSans_500Medium",
|
||||||
|
fontSize: 13,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export default MyGroup;
|
export default MyGroup;
|
||||||
|
|||||||
@ -30,7 +30,7 @@ const UserMenu = ({
|
|||||||
customContent={
|
customContent={
|
||||||
<View height={18}>
|
<View height={18}>
|
||||||
<ListItem onPress={handleShowQRCode}>
|
<ListItem onPress={handleShowQRCode}>
|
||||||
<Text>Show Login QR Code</Text>
|
<Text style={{fontFamily: "Manrope_500Medium"}}>Show Login QR Code</Text>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
</View>
|
</View>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { View, Text, Button, Switch } from "react-native-ui-lib";
|
import { View, Text, Button, Switch } from "react-native-ui-lib";
|
||||||
import React, { useState } from "react";
|
import React, { useRef, useState } from "react";
|
||||||
import PointsSlider from "@/components/shared/PointsSlider";
|
import PointsSlider from "@/components/shared/PointsSlider";
|
||||||
import { repeatOptions, useToDosContext } from "@/contexts/ToDosContext";
|
import { repeatOptions, useToDosContext } from "@/contexts/ToDosContext";
|
||||||
import { Feather, AntDesign, Ionicons } from "@expo/vector-icons";
|
import { Feather, AntDesign, Ionicons } from "@expo/vector-icons";
|
||||||
@ -14,6 +14,7 @@ import { PanningDirectionsEnum } from "react-native-ui-lib/src/incubator/panView
|
|||||||
import { Dimensions, StyleSheet } from "react-native";
|
import { Dimensions, StyleSheet } from "react-native";
|
||||||
import DropModalIcon from "@/assets/svgs/DropModalIcon";
|
import DropModalIcon from "@/assets/svgs/DropModalIcon";
|
||||||
import { IToDo } from "@/hooks/firebase/types/todoData";
|
import { IToDo } from "@/hooks/firebase/types/todoData";
|
||||||
|
import AssigneesDisplay from "@/components/shared/AssigneesDisplay";
|
||||||
|
|
||||||
interface IAddChoreDialog {
|
interface IAddChoreDialog {
|
||||||
isVisible: boolean;
|
isVisible: boolean;
|
||||||
@ -111,6 +112,7 @@ const AddChoreDialog = (addChoreDialogProps: IAddChoreDialog) => {
|
|||||||
</View>
|
</View>
|
||||||
<TextField
|
<TextField
|
||||||
placeholder="Add a To Do"
|
placeholder="Add a To Do"
|
||||||
|
autoFocus
|
||||||
value={todo?.title}
|
value={todo?.title}
|
||||||
onChangeText={(text) => {
|
onChangeText={(text) => {
|
||||||
setTodo((oldValue: IToDo) => ({ ...oldValue, title: text }));
|
setTodo((oldValue: IToDo) => ({ ...oldValue, title: text }));
|
||||||
@ -197,25 +199,8 @@ const AddChoreDialog = (addChoreDialogProps: IAddChoreDialog) => {
|
|||||||
label="Assign"
|
label="Assign"
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
<View row marginH-13 marginT-13>
|
<View row marginL-27 marginT-0>
|
||||||
<View
|
<AssigneesDisplay />
|
||||||
marginL-30
|
|
||||||
style={{
|
|
||||||
aspectRatio: 1,
|
|
||||||
width: 50,
|
|
||||||
backgroundColor: "red",
|
|
||||||
borderRadius: 50,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<View
|
|
||||||
marginL-30
|
|
||||||
style={{
|
|
||||||
aspectRatio: 1,
|
|
||||||
width: 50,
|
|
||||||
backgroundColor: "red",
|
|
||||||
borderRadius: 50,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</View>
|
</View>
|
||||||
<View row centerV style={styles.rotateSwitch}>
|
<View row centerV style={styles.rotateSwitch}>
|
||||||
<Text text80>Take Turns</Text>
|
<Text text80>Take Turns</Text>
|
||||||
|
|||||||
Reference in New Issue
Block a user