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 React, { useEffect, useState } from "react";
|
||||
import {
|
||||
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 { PanningDirectionsEnum } from "react-native-ui-lib/src/incubator/panView";
|
||||
import CloseXIcon from "@/assets/svgs/CloseXIcon";
|
||||
import { Dimensions, StyleSheet } from "react-native";
|
||||
import { Dimensions, Keyboard, StyleSheet } from "react-native";
|
||||
|
||||
import DropModalIcon from "@/assets/svgs/DropModalIcon";
|
||||
import MenuIcon from "@/assets/svgs/MenuIcon";
|
||||
import { useBrainDumpContext } from "@/contexts/DumpContext";
|
||||
|
||||
interface IAddBrainDumpProps {
|
||||
isVisible: boolean;
|
||||
setIsVisible: (value: boolean) => void;
|
||||
}
|
||||
|
||||
const AddBrainDump = ({
|
||||
addBrainDumpProps,
|
||||
}: {
|
||||
@ -20,7 +27,10 @@ const AddBrainDump = ({
|
||||
const { addBrainDump } = useBrainDumpContext();
|
||||
const [dumpTitle, setDumpTitle] = 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(() => {
|
||||
setDumpDesc("");
|
||||
@ -34,14 +44,7 @@ const AddBrainDump = ({
|
||||
width={width}
|
||||
panDirection={PanningDirectionsEnum.DOWN}
|
||||
onDismiss={() => addBrainDumpProps.setIsVisible(false)}
|
||||
containerStyle={{
|
||||
borderTopRightRadius: 15,
|
||||
borderTopLeftRadius: 15,
|
||||
backgroundColor: "white",
|
||||
padding: 0,
|
||||
paddingTop: 3,
|
||||
margin: 0,
|
||||
}}
|
||||
containerStyle={styles.dialogContainer}
|
||||
visible={addBrainDumpProps.isVisible}
|
||||
>
|
||||
<View row spread style={styles.topBtns} marginB-20>
|
||||
@ -53,16 +56,15 @@ const AddBrainDump = ({
|
||||
addBrainDumpProps.setIsVisible(false);
|
||||
}}
|
||||
/>
|
||||
<DropModalIcon
|
||||
style={{ marginTop: 15 }}
|
||||
onPress={() => addBrainDumpProps.setIsVisible(false)}
|
||||
/>
|
||||
<TouchableOpacity onPress={() => addBrainDumpProps.setIsVisible(false)}>
|
||||
<DropModalIcon style={{ marginTop: 15 }} />
|
||||
</TouchableOpacity>
|
||||
<Button
|
||||
color="#05a8b6"
|
||||
label="Save"
|
||||
style={styles.topBtn}
|
||||
onPress={() => {
|
||||
addBrainDump({ id: 99, title: dumpTitle, description: dumpDesc });
|
||||
addBrainDump({ id: 99, title: dumpTitle.trimEnd().trimStart(), description: dumpDesc.trimEnd().trimStart() });
|
||||
addBrainDumpProps.setIsVisible(false);
|
||||
}}
|
||||
/>
|
||||
@ -70,20 +72,37 @@ const AddBrainDump = ({
|
||||
<View marginH-20>
|
||||
<TextField
|
||||
value={dumpTitle}
|
||||
autoFocus
|
||||
placeholder="Set Title"
|
||||
text60R
|
||||
onChangeText={(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 />
|
||||
<TextField
|
||||
ref={descriptionRef}
|
||||
value={dumpDesc}
|
||||
placeholder="Write Description"
|
||||
text70
|
||||
onChangeText={(text) => {
|
||||
setDumpDesc(text);
|
||||
}}
|
||||
style={styles.description}
|
||||
multiline
|
||||
numberOfLines={4}
|
||||
maxLength={255}
|
||||
onEndEditing={() => {
|
||||
descriptionRef.current?.blur();
|
||||
}}
|
||||
returnKeyType="done"
|
||||
/>
|
||||
</View>
|
||||
</Dialog>
|
||||
@ -91,11 +110,28 @@ const AddBrainDump = ({
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
dialogContainer: {
|
||||
borderTopRightRadius: 15,
|
||||
borderTopLeftRadius: 15,
|
||||
backgroundColor: "white",
|
||||
padding: 0,
|
||||
paddingTop: 3,
|
||||
margin: 0,
|
||||
},
|
||||
topBtns: {},
|
||||
topBtn: {
|
||||
backgroundColor: "white",
|
||||
color: "#05a8b6",
|
||||
},
|
||||
title: {
|
||||
fontSize: 22,
|
||||
fontFamily: "Manrope_500Medium",
|
||||
},
|
||||
description: {
|
||||
fontFamily: "Manrope_400Regular",
|
||||
fontSize: 14,
|
||||
textAlignVertical: 'top'
|
||||
},
|
||||
});
|
||||
|
||||
export default AddBrainDump;
|
||||
|
||||
@ -98,19 +98,18 @@ const MoveBrainDump = (props: {
|
||||
<TextField
|
||||
textAlignVertical="top"
|
||||
multiline
|
||||
autoFocus
|
||||
fieldStyle={{
|
||||
width: "94%",
|
||||
}}
|
||||
style={{
|
||||
fontFamily: "Manrope_400Regular",
|
||||
fontSize: 14,
|
||||
}}
|
||||
style={styles.description}
|
||||
placeholder="Add description"
|
||||
numberOfLines={3}
|
||||
value={description}
|
||||
onChangeText={(value) => {
|
||||
setDescription(value);
|
||||
}}
|
||||
returnKeyType="default"
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.divider} />
|
||||
@ -192,6 +191,10 @@ const styles = StyleSheet.create({
|
||||
fontSize: 22,
|
||||
fontFamily: "Manrope_500Medium",
|
||||
},
|
||||
description:{
|
||||
fontFamily: "Manrope_400Regular",
|
||||
fontSize: 14,
|
||||
}
|
||||
});
|
||||
|
||||
export default MoveBrainDump;
|
||||
|
||||
@ -225,6 +225,7 @@ export const ManuallyAddEventModal = ({
|
||||
<TextField
|
||||
placeholder="Add event title"
|
||||
value={title}
|
||||
autoFocus
|
||||
onChangeText={(text) => {
|
||||
setTitle(text);
|
||||
}}
|
||||
@ -232,6 +233,7 @@ export const ManuallyAddEventModal = ({
|
||||
style={{ fontFamily: "Manrope_500Medium", fontSize: 22 }}
|
||||
paddingT-15
|
||||
paddingL-30
|
||||
returnKeyType="next"
|
||||
/>
|
||||
<View style={styles.divider} marginT-8 />
|
||||
<View marginL-30 centerV>
|
||||
|
||||
@ -23,7 +23,7 @@ const CategoryDropdown = (props: {
|
||||
padding: 10,
|
||||
}}
|
||||
>
|
||||
<Text>{category}</Text>
|
||||
<Text style={{fontFamily: "Manrope_400Regular"}}>{category}</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
))}
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
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 {GroceryCategory, useGroceryContext,} from "@/contexts/GroceryContext";
|
||||
import CategoryDropdown from "./CategoryDropdown";
|
||||
|
||||
interface IEditGrocery {
|
||||
id?: string;
|
||||
@ -17,6 +18,7 @@ interface IEditGrocery {
|
||||
const EditGroceryItem = ({editGrocery}: { editGrocery: IEditGrocery }) => {
|
||||
const {fuzzyMatchGroceryCategory} = useGroceryContext();
|
||||
const inputRef = useRef<TextFieldRef>(null);
|
||||
const [category, setCategory] = useState<GroceryCategory>(GroceryCategory.None);
|
||||
|
||||
useEffect(() => {
|
||||
if (editGrocery.setCategory)
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
import React, { useState } from "react";
|
||||
import React, { useRef, useState } from "react";
|
||||
import {
|
||||
Button,
|
||||
ButtonSize,
|
||||
Checkbox,
|
||||
Text,
|
||||
TextField,
|
||||
TextFieldRef,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
} from "react-native-ui-lib";
|
||||
@ -13,7 +14,13 @@ import { ProfileType } from "@/contexts/AuthContext";
|
||||
import { StyleSheet } from "react-native";
|
||||
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 [firstName, setFirstName] = 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 { mutateAsync: signUp } = useSignUp();
|
||||
|
||||
const lnameRef = useRef<TextFieldRef>(null);
|
||||
const emailRef = useRef<TextFieldRef>(null);
|
||||
const passwordRef = useRef<TextFieldRef>(null);
|
||||
|
||||
const handleSignUp = async () => {
|
||||
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>
|
||||
<TextField
|
||||
marginT-60
|
||||
autoFocus
|
||||
placeholder="First name"
|
||||
value={firstName}
|
||||
onChangeText={setFirstName}
|
||||
style={styles.textfield}
|
||||
onSubmitEditing={() => {lnameRef.current?.focus()}}
|
||||
blurOnSubmit={false}
|
||||
/>
|
||||
<TextField
|
||||
ref={lnameRef}
|
||||
placeholder="Last name"
|
||||
value={lastName}
|
||||
onChangeText={setLastName}
|
||||
style={styles.textfield}
|
||||
onSubmitEditing={() => {emailRef.current?.focus()}}
|
||||
blurOnSubmit={false}
|
||||
/>
|
||||
<TextField
|
||||
ref={emailRef}
|
||||
placeholder="Email"
|
||||
value={email}
|
||||
onChangeText={setEmail}
|
||||
style={styles.textfield}
|
||||
onSubmitEditing={() => {passwordRef.current?.focus()}}
|
||||
blurOnSubmit={false}
|
||||
/>
|
||||
<TextField
|
||||
ref={passwordRef}
|
||||
placeholder="Password"
|
||||
value={password}
|
||||
onChangeText={setPassword}
|
||||
|
||||
@ -9,6 +9,7 @@ import { AuthContextProvider } from "@/contexts/AuthContext";
|
||||
import ProfileIcon from "@/assets/svgs/ProfileIcon";
|
||||
import CalendarIcon from "@/assets/svgs/CalendarIcon";
|
||||
import PrivacyPolicyIcon from "@/assets/svgs/PrivacyPolicyIcon";
|
||||
import ArrowRightIcon from "@/assets/svgs/ArrowRightIcon";
|
||||
|
||||
const pageIndex = {
|
||||
main: 0,
|
||||
@ -26,23 +27,29 @@ const SettingsPage = () => {
|
||||
<Button
|
||||
backgroundColor="white"
|
||||
style={styles.mainBtn}
|
||||
label="Manage My Profile"
|
||||
labelStyle={styles.label}
|
||||
color="#07b8c7"
|
||||
iconSource={() => (
|
||||
<ProfileIcon style={{marginRight: 10}} color="#07b9c8" />
|
||||
)}
|
||||
children={
|
||||
<View row centerV width={"100%"}>
|
||||
<ProfileIcon style={{ marginRight: 10 }} color="#07b9c8" />
|
||||
<Text style={styles.label} color="#07b8c7">
|
||||
Manage My Profile
|
||||
</Text>
|
||||
<ArrowRightIcon style={{ marginLeft: "auto" }} />
|
||||
</View>
|
||||
}
|
||||
onPress={() => setSelectedPage(pageIndex.user)}
|
||||
/>
|
||||
<Button
|
||||
backgroundColor="white"
|
||||
style={styles.mainBtn}
|
||||
label="Calendar Settings"
|
||||
labelStyle={styles.label}
|
||||
color="#fd1775"
|
||||
iconSource={() => (
|
||||
<CalendarIcon style={{marginRight: 10}}/>
|
||||
)}
|
||||
children={
|
||||
<View row centerV width={"100%"}>
|
||||
<CalendarIcon style={{ marginRight: 10 }} />
|
||||
<Text style={styles.label} color="#fd1775">
|
||||
Calendar Settings
|
||||
</Text>
|
||||
<ArrowRightIcon style={{ marginLeft: "auto" }} />
|
||||
</View>
|
||||
}
|
||||
onPress={() => {
|
||||
setSelectedPage(pageIndex.calendar);
|
||||
}}
|
||||
@ -50,28 +57,34 @@ const SettingsPage = () => {
|
||||
<Button
|
||||
backgroundColor="white"
|
||||
style={styles.mainBtn}
|
||||
label="To-Do Reward Settings"
|
||||
labelStyle={styles.label}
|
||||
color="#ff9900"
|
||||
iconSource={() => (
|
||||
children={
|
||||
<View row centerV width={"100%"}>
|
||||
<Octicons
|
||||
name="gear"
|
||||
size={24}
|
||||
color="#ff9900"
|
||||
style={{ marginRight: 10 }}
|
||||
/>
|
||||
)}
|
||||
<Text style={styles.label} color="#ff9900">
|
||||
To-Do Reward Settings
|
||||
</Text>
|
||||
<ArrowRightIcon style={{ marginLeft: "auto" }} />
|
||||
</View>
|
||||
}
|
||||
onPress={() => setSelectedPage(pageIndex.chore)}
|
||||
/>
|
||||
<Button
|
||||
backgroundColor="white"
|
||||
style={styles.mainBtn}
|
||||
label="Cally Privacy Policy"
|
||||
labelStyle={styles.label}
|
||||
iconSource={() => (
|
||||
<PrivacyPolicyIcon style={{marginRight: 10}}/>
|
||||
)}
|
||||
color="#6c645b"
|
||||
children={
|
||||
<View row centerV width={"100%"}>
|
||||
<PrivacyPolicyIcon style={{ marginRight: 10 }} />
|
||||
<Text style={styles.label} color="#6c645b">
|
||||
Cally Privacy Policy
|
||||
</Text>
|
||||
<ArrowRightIcon style={{ marginLeft: "auto" }} />
|
||||
</View>
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
@ -92,14 +105,14 @@ export default SettingsPage;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
mainBtn: {
|
||||
width: "100%",
|
||||
width: 311,
|
||||
justifyContent: "flex-start",
|
||||
marginBottom: 20,
|
||||
height: 60,
|
||||
height: 57.61,
|
||||
},
|
||||
label:{
|
||||
label: {
|
||||
fontFamily: "Poppins_400Regular",
|
||||
fontSize: 14.71,
|
||||
textAlignVertical: 'center'
|
||||
}
|
||||
textAlignVertical: "center",
|
||||
},
|
||||
});
|
||||
|
||||
@ -9,17 +9,23 @@ import {
|
||||
Picker,
|
||||
Text,
|
||||
TextField,
|
||||
TextFieldRef,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
} from "react-native-ui-lib";
|
||||
import React, {useState} from "react";
|
||||
import {ScrollView, StyleSheet} from "react-native";
|
||||
import {PickerSingleValue} from "react-native-ui-lib/src/components/picker/types";
|
||||
import {useCreateSubUser} from "@/hooks/firebase/useCreateSubUser";
|
||||
import {ProfileType} from "@/contexts/AuthContext";
|
||||
import {useGetFamilyMembers} from "@/hooks/firebase/useGetFamilyMembers";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { Dimensions, ScrollView, StyleSheet } from "react-native";
|
||||
import { PickerSingleValue } from "react-native-ui-lib/src/components/picker/types";
|
||||
import { useCreateSubUser } from "@/hooks/firebase/useCreateSubUser";
|
||||
import { ProfileType } from "@/contexts/AuthContext";
|
||||
import { useGetFamilyMembers } from "@/hooks/firebase/useGetFamilyMembers";
|
||||
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 [showAddUserDialog, setShowAddUserDialog] = useState(false);
|
||||
@ -31,10 +37,13 @@ const MyGroup = () => {
|
||||
const [lastName, setLastName] = useState("");
|
||||
const [email, setEmail] = useState("");
|
||||
|
||||
const lNameRef = useRef<TextFieldRef>(null);
|
||||
const emailRef = useRef<TextFieldRef>(null);
|
||||
|
||||
const [showQRCodeDialog, setShowQRCodeDialog] = useState("");
|
||||
|
||||
const {mutateAsync: createSubUser, isLoading, isError} = useCreateSubUser();
|
||||
const {data: familyMembers} = useGetFamilyMembers(true);
|
||||
const { mutateAsync: createSubUser, isLoading, isError } = useCreateSubUser();
|
||||
const { data: familyMembers } = useGetFamilyMembers(true);
|
||||
|
||||
const parents =
|
||||
familyMembers?.filter((x) => x.userType === ProfileType.PARENT) ?? [];
|
||||
@ -43,10 +52,14 @@ const MyGroup = () => {
|
||||
const caregivers =
|
||||
familyMembers?.filter((x) => x.userType === ProfileType.CAREGIVER) ?? [];
|
||||
const familyDevices =
|
||||
familyMembers?.filter((x) => x.userType === ProfileType.FAMILY_DEVICE) ?? [];
|
||||
familyMembers?.filter((x) => x.userType === ProfileType.FAMILY_DEVICE) ??
|
||||
[];
|
||||
|
||||
const handleCreateSubUser = async () => {
|
||||
if (!firstName || (selectedStatus !== ProfileType.FAMILY_DEVICE && !lastName)) {
|
||||
if (
|
||||
!firstName ||
|
||||
(selectedStatus !== ProfileType.FAMILY_DEVICE && !lastName)
|
||||
) {
|
||||
console.error("First name and last name are required");
|
||||
return;
|
||||
}
|
||||
@ -68,23 +81,28 @@ const MyGroup = () => {
|
||||
password: uuidv4(),
|
||||
userType: selectedStatus as ProfileType,
|
||||
});
|
||||
console.log(res)
|
||||
console.log(res);
|
||||
|
||||
if (!isError) {
|
||||
setShowNewUserInfoDialog(false);
|
||||
|
||||
if(res?.data?.userId) {
|
||||
if (res?.data?.userId) {
|
||||
setTimeout(() => {
|
||||
setShowQRCodeDialog(res.data.userId)
|
||||
}, 500)
|
||||
setShowQRCodeDialog(res.data.userId);
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setFirstName("");
|
||||
setLastName("");
|
||||
setEmail("");
|
||||
}, [])
|
||||
|
||||
|
||||
return (
|
||||
<View style={{flex: 1}}>
|
||||
<View style={{ flex: 1, minHeight: 500 }}>
|
||||
<View>
|
||||
<ScrollView style={styles.card}>
|
||||
{!parents.length && !children.length && !caregivers.length && (
|
||||
@ -109,7 +127,7 @@ const MyGroup = () => {
|
||||
padding-10
|
||||
>
|
||||
<Avatar
|
||||
source={{uri: "https://via.placeholder.com/60"}}
|
||||
source={{ uri: "https://via.placeholder.com/60" }}
|
||||
size={40}
|
||||
backgroundColor={Colors.grey60}
|
||||
/>
|
||||
@ -124,9 +142,13 @@ const MyGroup = () => {
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<View flex-1/>
|
||||
<View flex-1 />
|
||||
|
||||
<UserMenu setShowQRCodeDialog={(val) => setShowQRCodeDialog("")} showQRCodeDialog={showQRCodeDialog === member?.uid} userId={member?.uid!}/>
|
||||
<UserMenu
|
||||
setShowQRCodeDialog={(val) => setShowQRCodeDialog("")}
|
||||
showQRCodeDialog={showQRCodeDialog === member?.uid}
|
||||
userId={member?.uid!}
|
||||
/>
|
||||
</Card>
|
||||
))}
|
||||
</>
|
||||
@ -148,7 +170,7 @@ const MyGroup = () => {
|
||||
padding-10
|
||||
>
|
||||
<Avatar
|
||||
source={{uri: "https://via.placeholder.com/60"}}
|
||||
source={{ uri: "https://via.placeholder.com/60" }}
|
||||
size={40}
|
||||
backgroundColor={Colors.grey60}
|
||||
/>
|
||||
@ -161,7 +183,11 @@ const MyGroup = () => {
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<UserMenu setShowQRCodeDialog={(val) => setShowQRCodeDialog("")} showQRCodeDialog={showQRCodeDialog === member?.uid} userId={member?.uid!}/>
|
||||
<UserMenu
|
||||
setShowQRCodeDialog={(val) => setShowQRCodeDialog("")}
|
||||
showQRCodeDialog={showQRCodeDialog === member?.uid}
|
||||
userId={member?.uid!}
|
||||
/>
|
||||
</Card>
|
||||
))}
|
||||
</>
|
||||
@ -183,20 +209,22 @@ const MyGroup = () => {
|
||||
padding-10
|
||||
>
|
||||
<Avatar
|
||||
source={{uri: "https://via.placeholder.com/60"}}
|
||||
source={{ uri: "https://via.placeholder.com/60" }}
|
||||
size={40}
|
||||
backgroundColor={Colors.grey60}
|
||||
/>
|
||||
<View marginL-10>
|
||||
<Text text70M>
|
||||
{member.firstName}
|
||||
</Text>
|
||||
<Text text70M>{member.firstName}</Text>
|
||||
<Text text90 grey40>
|
||||
Family Device
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<UserMenu setShowQRCodeDialog={(val) => setShowQRCodeDialog("")} showQRCodeDialog={showQRCodeDialog === member?.uid} userId={member?.uid!}/>
|
||||
<UserMenu
|
||||
setShowQRCodeDialog={(val) => setShowQRCodeDialog("")}
|
||||
showQRCodeDialog={showQRCodeDialog === member?.uid}
|
||||
userId={member?.uid!}
|
||||
/>
|
||||
</Card>
|
||||
))}
|
||||
</>
|
||||
@ -211,6 +239,7 @@ const MyGroup = () => {
|
||||
button={{
|
||||
label: "+ Add a user device",
|
||||
onPress: () => setShowAddUserDialog(true),
|
||||
style: styles.bottomButton,
|
||||
}}
|
||||
/>
|
||||
|
||||
@ -219,13 +248,26 @@ const MyGroup = () => {
|
||||
onDismiss={() => setShowAddUserDialog(false)}
|
||||
panDirection={PanningProvider.Directions.DOWN}
|
||||
>
|
||||
<Card padding-25 gap-10>
|
||||
<Text>Add a new user device</Text>
|
||||
<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"}>
|
||||
<Text white>Show a QR Code</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);
|
||||
@ -234,11 +276,18 @@ const MyGroup = () => {
|
||||
}, 500);
|
||||
}}
|
||||
>
|
||||
<Text white>Enter email address</Text>
|
||||
<EmailIcon />
|
||||
<Text style={styles.dialogBtnLbl} marginL-7>
|
||||
Enter email address
|
||||
</Text>
|
||||
</Button>
|
||||
|
||||
<TouchableOpacity onPress={() => setShowAddUserDialog(false)} center>
|
||||
<Text>Return to user settings</Text>
|
||||
<TouchableOpacity
|
||||
onPress={() => setShowAddUserDialog(false)}
|
||||
center
|
||||
marginT-30
|
||||
>
|
||||
<Text style={styles.dialogBackBtn}>Return to user settings</Text>
|
||||
</TouchableOpacity>
|
||||
</Card>
|
||||
</Dialog>
|
||||
@ -250,28 +299,34 @@ const MyGroup = () => {
|
||||
>
|
||||
<Card padding-25 style={styles.dialogCard}>
|
||||
<View row spread>
|
||||
<Text text60M>New User Information</Text>
|
||||
<TouchableOpacity onPress={() => setShowAddUserDialog(false)}>
|
||||
<Text>X</Text>
|
||||
<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>
|
||||
<Avatar
|
||||
imageStyle={{borderRadius: 10}}
|
||||
containerStyle={{borderRadius: 10}}
|
||||
size={60}
|
||||
<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 style={{color: Colors.green10}}>
|
||||
<TouchableOpacity onPress={() => {}}>
|
||||
<Text color="#50be0c" style={styles.jakarta13} marginL-15>
|
||||
Upload User Profile Photo
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
<Text style={styles.label}>Member Status</Text>
|
||||
<Text style={styles.jakarta12}>Member Status</Text>
|
||||
<Picker
|
||||
editable={!isLoading}
|
||||
value={selectedStatus}
|
||||
@ -281,40 +336,55 @@ const MyGroup = () => {
|
||||
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.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 style={styles.jakarta12}>
|
||||
{selectedStatus === ProfileType.FAMILY_DEVICE
|
||||
? "Device Name"
|
||||
: "First Name"}
|
||||
</Text>
|
||||
<TextField
|
||||
editable={!isLoading}
|
||||
placeholder={selectedStatus === ProfileType.FAMILY_DEVICE ? "Device name" : "First name"}
|
||||
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.label}>Last Name</Text>
|
||||
<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.label}>Email Address (Optional)</Text>
|
||||
<Text style={styles.jakarta12}>Email Address (Optional)</Text>
|
||||
<TextField
|
||||
ref={emailRef}
|
||||
editable={!isLoading}
|
||||
placeholder="Email address"
|
||||
value={email}
|
||||
@ -327,10 +397,20 @@ const MyGroup = () => {
|
||||
)}
|
||||
|
||||
<Button
|
||||
disabled={!firstName || (selectedStatus !== ProfileType.FAMILY_DEVICE && !lastName) || isLoading}
|
||||
disabled={
|
||||
!firstName ||
|
||||
(selectedStatus !== ProfileType.FAMILY_DEVICE && !lastName) ||
|
||||
isLoading
|
||||
}
|
||||
label={isLoading ? "Adding..." : "Add group member"}
|
||||
backgroundColor="#FD1775"
|
||||
style={{marginTop: 20}}
|
||||
backgroundColor="#fd1775"
|
||||
labelStyle={{
|
||||
fontFamily: "PlusJakartaSans_500Medium",
|
||||
fontSize: 15,
|
||||
marginLeft: 7,
|
||||
}}
|
||||
style={{ marginTop: 20, backgroundColor: "#fd1775" }}
|
||||
iconSource={() => <NavToDosIcon width={22} color={"white"} />}
|
||||
onPress={handleCreateSubUser}
|
||||
/>
|
||||
</Card>
|
||||
@ -340,6 +420,16 @@ const MyGroup = () => {
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
dialogBtn: {
|
||||
height: 47,
|
||||
width: 279,
|
||||
},
|
||||
dialogTitle: { fontFamily: "Manrope_600SemiBold", fontSize: 22 },
|
||||
dialogBackBtn: {
|
||||
fontFamily: "PlusJakartaSans_500Medium",
|
||||
fontSize: 15,
|
||||
color: "#a7a7a7",
|
||||
},
|
||||
card: {
|
||||
marginVertical: 15,
|
||||
backgroundColor: "white",
|
||||
@ -347,6 +437,11 @@ const styles = StyleSheet.create({
|
||||
borderRadius: 15,
|
||||
padding: 20,
|
||||
},
|
||||
bottomButton: {
|
||||
position: "absolute",
|
||||
bottom: 80,
|
||||
width: "100%",
|
||||
},
|
||||
familyCard: {
|
||||
marginBottom: 10,
|
||||
borderRadius: 10,
|
||||
@ -354,6 +449,9 @@ const styles = StyleSheet.create({
|
||||
width: "100%",
|
||||
},
|
||||
inputField: {
|
||||
fontFamily: "PlusJakartaSans_500Medium",
|
||||
fontSize: 13,
|
||||
color: "#565656",
|
||||
borderRadius: 50,
|
||||
paddingVertical: 12,
|
||||
paddingHorizontal: 16,
|
||||
@ -387,6 +485,21 @@ const styles = StyleSheet.create({
|
||||
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;
|
||||
|
||||
@ -30,7 +30,7 @@ const UserMenu = ({
|
||||
customContent={
|
||||
<View height={18}>
|
||||
<ListItem onPress={handleShowQRCode}>
|
||||
<Text>Show Login QR Code</Text>
|
||||
<Text style={{fontFamily: "Manrope_500Medium"}}>Show Login QR Code</Text>
|
||||
</ListItem>
|
||||
</View>
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
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 { repeatOptions, useToDosContext } from "@/contexts/ToDosContext";
|
||||
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 DropModalIcon from "@/assets/svgs/DropModalIcon";
|
||||
import { IToDo } from "@/hooks/firebase/types/todoData";
|
||||
import AssigneesDisplay from "@/components/shared/AssigneesDisplay";
|
||||
|
||||
interface IAddChoreDialog {
|
||||
isVisible: boolean;
|
||||
@ -111,6 +112,7 @@ const AddChoreDialog = (addChoreDialogProps: IAddChoreDialog) => {
|
||||
</View>
|
||||
<TextField
|
||||
placeholder="Add a To Do"
|
||||
autoFocus
|
||||
value={todo?.title}
|
||||
onChangeText={(text) => {
|
||||
setTodo((oldValue: IToDo) => ({ ...oldValue, title: text }));
|
||||
@ -197,25 +199,8 @@ const AddChoreDialog = (addChoreDialogProps: IAddChoreDialog) => {
|
||||
label="Assign"
|
||||
/>
|
||||
</View>
|
||||
<View row marginH-13 marginT-13>
|
||||
<View
|
||||
marginL-30
|
||||
style={{
|
||||
aspectRatio: 1,
|
||||
width: 50,
|
||||
backgroundColor: "red",
|
||||
borderRadius: 50,
|
||||
}}
|
||||
/>
|
||||
<View
|
||||
marginL-30
|
||||
style={{
|
||||
aspectRatio: 1,
|
||||
width: 50,
|
||||
backgroundColor: "red",
|
||||
borderRadius: 50,
|
||||
}}
|
||||
/>
|
||||
<View row marginL-27 marginT-0>
|
||||
<AssigneesDisplay />
|
||||
</View>
|
||||
<View row centerV style={styles.rotateSwitch}>
|
||||
<Text text80>Take Turns</Text>
|
||||
|
||||
Reference in New Issue
Block a user