Skip to content

Commit

Permalink
Merge pull request #86 from andreasalstrup/qr-and-notice
Browse files Browse the repository at this point in the history
Notice Board and QR codes
  • Loading branch information
andreasalstrup authored Dec 17, 2023
2 parents 71764d9 + 96063ef commit b2fde0d
Show file tree
Hide file tree
Showing 16 changed files with 618 additions and 94 deletions.
6 changes: 6 additions & 0 deletions ambient.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,10 @@ type WeekTexts = {

type MealPlan = {
[key: string]: WeekTexts;
}

type User = {
fullName: string,
phoneNumber: string,
email: string
}
3 changes: 1 addition & 2 deletions app/(login)/(groupScreen)/group.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { Redirect } from 'expo-router';
import { ImageBackground, Pressable, View, Text, TextInput } from 'react-native';
import styles from '../styles';
import { useState, useRef } from 'react';
Expand Down Expand Up @@ -65,7 +64,7 @@ export default function GroupScreen() {
function getNonMainScreenTextComponent() {
return (
<View style={{alignItems: "center"}}>
<Pressable onPress={() => setCurrentState(State.buttons)}><Text style={styles.descriptiveText}>Go back</Text></Pressable>
<Pressable onPress={() => setCurrentState(State.buttons)}><Text style={[styles.descriptiveText, {marginBottom: 6}]}>Go back</Text></Pressable>
<Pressable onPress={() => logout()}><Text style={styles.descriptiveText}>Log out</Text></Pressable>
</View>
)
Expand Down
52 changes: 47 additions & 5 deletions app/(login)/(groupScreen)/joinGroup.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,37 @@
import { useState, useRef } from "react"
import { useState, useRef, useEffect } from "react"
import { View, Text, Pressable, TextInput } from "react-native"
import styles from "../styles"
import { groupHandle } from '../../../handlers/group';
import { router } from "expo-router";
import Modal from "react-native-modal";
import { BarCodeScanner } from 'expo-barcode-scanner';
import { AntDesign } from "@expo/vector-icons";

export default function getCreateComponent(){
const group = useRef(groupHandle(gun));
const [uuid, setUuid] = useState("");
const [processing, setProcessing] = useState(false)
const [error, setError] = useState(false)

function joinGroup(groupName : string){
group.current.join(groupName, (ack: Boolean) => {
const [hasPermission, setHasPermission] = useState<boolean | null>(null);
const [isModalVisible, setIsModalVisible] = useState(false);

useEffect(() => {
const getBarCodeScannerPermissions = async () => {
const { granted } = await BarCodeScanner.requestPermissionsAsync();
setHasPermission(granted);
};

getBarCodeScannerPermissions();
}, []);

const handleBarCodeScanned = ({ type, data }: { type: string, data: string }): void => {
setUuid(data)
setIsModalVisible(false)
};

function joinGroup(groupId : string){
group.current.join(groupId, (ack: Boolean) => {
if (ack){
router.replace('/shoppingList')
} else{
Expand All @@ -26,7 +46,17 @@ export default function getCreateComponent(){
<View style={{alignItems:"center"}}><Text style={styles.explainerText}> Join a group by typing its unique id </Text></View>
<Text style={styles.descriptiveText}>Group id</Text>
<View style={styles.inputBox}>
<TextInput style={styles.inputField} autoCapitalize='none' value={uuid} onChangeText={(uuid) =>{setUuid(uuid)}}/>
<TextInput style={styles.inputField} autoCapitalize='none' value={uuid} onChangeText={(uuid) =>{setUuid(uuid)}}/>
{hasPermission && <Pressable
style={styles.qrCodeIcon}
onPress={()=>{
setIsModalVisible(true)
}}>
<AntDesign
name="qrcode"
size={26}
color={'gray'}/>
</Pressable>}
</View>
<Pressable style={styles.button} onPress={() => {
if (!processing){
Expand All @@ -36,7 +66,19 @@ export default function getCreateComponent(){
}}>
<Text style={styles.descriptiveText}>Join group</Text></Pressable>
{error && <Text style={styles.error}>Wrong id</Text>}
<View style={{height:10}}/>

<Modal
animationIn='zoomIn'
animationOut='zoomOut'
isVisible={isModalVisible}
onBackdropPress={() => setIsModalVisible(false)}>
<View style={styles.modalContainer}>
<BarCodeScanner
barCodeTypes={[BarCodeScanner.Constants.BarCodeType.qr]}
onBarCodeScanned={handleBarCodeScanned}
style={{flex:1}}/>
</View>
</Modal>
</>
)
}
9 changes: 9 additions & 0 deletions app/(login)/styles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,15 @@ const styles = StyleSheet.create({
paddingBottom: 10,
backgroundColor: 'transparent',
},
qrCodeIcon: {
width: 32,
},
modalContainer: {
justifyContent: 'center',
borderRadius: 10,
padding: 20,
height: 400
},
});

export default styles
21 changes: 9 additions & 12 deletions app/(tabs)/expenses/balance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ function expenseListCmp(cmp1 : Expense[], cmp2 : Expense[]){
return true
}


export default function BalanceScreen() {
const expenses = useRef(expensesHandle(gun));
const colorScheme = useColorScheme() ?? 'light';
Expand All @@ -33,20 +32,18 @@ export default function BalanceScreen() {
}
}

function getGroupMembers(_members: string[]): void{
if (_members != members){
setMembers(_members);
}
function getGroupMembers(member: string): void{
setMembers(prev => {
if(!prev.includes(member)){
return [...prev, member]
}
return prev
})
}

let userGroup = '';
gun.user(userPub).get('group').get('groupId').once((id: string) => {
userGroup = id;
});

useEffect(() => {
expenses.current.getExpenses(userGroup, getExpenses);
expenses.current.getGroupMembers(userGroup, getGroupMembers);
expenses.current.getExpenses(getExpenses);
expenses.current.getGroupMembers(getGroupMembers);
}, [])

let previousBalance: { user: string, amount: number }[] = [];
Expand Down
29 changes: 10 additions & 19 deletions app/(tabs)/expenses/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ function expenseListCmp(cmp1 : Expense[], cmp2 : Expense[]){
return true
};



export default function SettleScreen() {
const expenses = useRef(expensesHandle(gun));
const colorScheme = useColorScheme() ?? 'light';
Expand All @@ -51,25 +49,18 @@ export default function SettleScreen() {
}
}

function getGroupMembers(_members: string[]): void{
if (_members != members){
setMembers(_members);
}
function getGroupMembers(member: string): void{
setMembers(prev => {
if(!prev.includes(member)){
return [...prev, member]
}
return prev
})
}

let userGroup = '';
gun.user(userPub).get('group').get('groupId').once((id: string) => {
userGroup = id;
});

let username = '';
gun.user(userPub).get('fullName').once((name: string) => {
username = name;
});

useEffect(() => {
expenses.current.getExpenses(userGroup, getExpenses);
expenses.current.getGroupMembers(userGroup, getGroupMembers);
expenses.current.getExpenses(getExpenses);
expenses.current.getGroupMembers(getGroupMembers);
}, [])

let previousBalance: { user: string, amount: number }[] = [];
Expand Down Expand Up @@ -123,7 +114,7 @@ export default function SettleScreen() {
}}
onYes={() =>{
if(selectedItem != null){
expenses.current.settleExpenses(userGroup, selectedItem);
expenses.current.settleExpenses(selectedItem);
}
closeModal()
}}
Expand Down
83 changes: 70 additions & 13 deletions app/(tabs)/notice.tsx
Original file line number Diff line number Diff line change
@@ -1,50 +1,95 @@
import React, { useEffect, useRef, useState } from 'react';
import { StyleSheet, TextInput, useColorScheme, SafeAreaView, ScrollView } from 'react-native';
import { StyleSheet, TextInput, useColorScheme, SafeAreaView, ScrollView, Pressable } from 'react-native';
import { Text, View } from '../../components/Themed';
import Colors from '../../constants/Colors';
import { groupHandle } from '../../handlers/group';
import { noticeHandle } from '../../handlers/notice';
import { AntDesign } from '@expo/vector-icons';
import Modal from "react-native-modal";
import { QrCodeSvg } from 'react-native-qr-svg';

export default function NoticeScreen() {
const colorScheme = useColorScheme() ?? 'light';
const group = useRef(groupHandle(gun)).current;
const group = useRef(groupHandle(gun));
const notice = useRef(noticeHandle(gun));
const [isModalVisible, setIsModalVisible] = useState(false);
const [houseRules, setHouseRules] = useState('');
const [groupId, setGroupId] = useState('')
const [groupName, setGroupName] = useState('')
const users = [
{ name: 'Test Bruger', phone: '12 34 56 78', email: '[email protected]' },
{ name: 'Andreas Alstrup', phone: '87 65 43 21', email: '[email protected]' },
];
const [users, setUsers] = useState<User[]>([])

useEffect(() => {
group.getUUID(setGroupId)
group.getGName(setGroupName)
group.current.getUUID((id) => setGroupId(id))
group.current.getGName((name) => setGroupName(name))
notice.current.onUsersUpdate((data: User) => {
setUsers(prev => {
if(!prev.includes(data)){
return [...prev, data]
}
return prev
})
})
notice.current.onHouseRulesUpdate((rules) => setHouseRules(rules))
}, [])

return (
<SafeAreaView style={[styles.container, {backgroundColor: Colors[colorScheme].background}]}>
<ScrollView>
<View>
<Text style={styles.title}>Household Rules</Text>
{groupName != '' && <Text>Group name: {groupName}</Text>}
{groupId != '' && <Text selectable={true}>Group ID: {groupId}</Text>}
<View style={styles.groupInfo}>
<View>
<Text>Group name: {groupName}</Text>
<Text selectable={true}>ID: {groupId}</Text>
</View>
<View style={{flex: 1}}>
<Pressable
style={styles.qrCodeIcon}
onPress={()=>{
setIsModalVisible(true)
}}>
<AntDesign
name="qrcode"
size={30}
color={'gray'}/>
</Pressable>
</View>
</View>
<TextInput
style={[styles.input, {color: Colors[colorScheme].text}]}
placeholder="Click to make rules"
placeholderTextColor={'gray'}
value={houseRules}
onChangeText={(text) => setHouseRules(text)}
onChangeText={(text) => {
notice.current.updateHouseRules(text)
setHouseRules(text)
}}
editable
multiline
/>
<Text style={styles.title}>Contact Information</Text>
{users.map((user, index) => (
<View key={index} style={styles.userCard}>
<Text style={styles.userName}>{user.name}</Text>
<Text>Phone: {user.phone}</Text>
<Text style={styles.userName}>{user.fullName}</Text>
<Text>Phone: {user.phoneNumber}</Text>
<Text>Email: {user.email}</Text>
</View>
))}
</View>
</ScrollView>
<Modal
style={styles.modalContainer}
animationIn='zoomIn'
animationOut='zoomOut'
isVisible={isModalVisible}
onBackdropPress={() => setIsModalVisible(false)}>
<QrCodeSvg
style={styles.modalContainer}
value={groupId}
frameSize={200}
dotColor={Colors[colorScheme].text}
backgroundColor={Colors[colorScheme].background}/>
</Modal>
</SafeAreaView>
);
}
Expand Down Expand Up @@ -81,4 +126,16 @@ const styles = StyleSheet.create({
fontSize: 16,
fontWeight: 'bold',
},
groupInfo: {
flexDirection: 'row'
},
qrCodeIcon: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
modalContainer: {
justifyContent: 'center',
alignItems: 'center',
},
});
18 changes: 11 additions & 7 deletions app/(tabs)/shoppingList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export default function ToBeBoughtScreen() {
const toggleCheckbox = () => setAlreadyBought(() => !alreadyBought);

let username = '';
gun.user(userPub).get('fullName').open((data: any) => {
gun.user(userPub).get('fullName').on((data: string) => {
username = data;
});

Expand All @@ -81,12 +81,16 @@ export default function ToBeBoughtScreen() {
)

shoppingListDB.current.onUsersUpdate(
(data : string[]) => {
setMembers(data)
if(members.length == 0)
{
setSelectedUsers(data)
}
(data : string) => {
setMembers(prev => {
if(!prev.includes(data)){
setSelectedUsers(prevSel => {
return [...prevSel, data]
})
return [...prev, data]
}
return prev
})
}
)
}, [])
Expand Down
Loading

0 comments on commit b2fde0d

Please sign in to comment.