diff --git a/client/assets/transparentSend.png b/client/assets/transparentSend.png new file mode 100644 index 000000000..e3a3380cc Binary files /dev/null and b/client/assets/transparentSend.png differ diff --git a/client/package.json b/client/package.json index 40ebdff7d..8de8eb7a2 100644 --- a/client/package.json +++ b/client/package.json @@ -22,6 +22,7 @@ "expo-linear-gradient": "~12.3.0", "expo-linking": "~5.0.2", "expo-location": "~16.1.0", + "expo-network": "~5.4.0", "expo-router": "^2.0.0", "expo-secure-store": "~12.3.1", "expo-status-bar": "~1.6.0", @@ -30,14 +31,19 @@ "react": "18.2.0", "react-native": "0.72.6", "react-native-dotenv": "^3.4.9", + "react-native-feather": "^1.1.2", "react-native-fs": "^2.20.0", "react-native-safe-area-context": "4.6.3", "react-native-screens": "~3.22.0", "react-native-uuid": "^2.0.1", "react-native-web": "~0.19.6", "socket.io-client": "^4.7.4", +<<<<<<< HEAD "expo-network": "~5.4.0", "undefined": "@expo/vector-icons/FontAwesome" +======= + "react-native-svg": "13.9.0" +>>>>>>> a15bd2c79af0ae980877f70f54f541fc55ae7ff0 }, "devDependencies": { "@babel/core": "^7.20.0", diff --git a/client/src/components/Chat/ChatScreen.tsx b/client/src/components/Chat/ChatScreen.tsx index 2939a47cb..12c9548e2 100644 --- a/client/src/components/Chat/ChatScreen.tsx +++ b/client/src/components/Chat/ChatScreen.tsx @@ -24,6 +24,7 @@ import { useSettings } from "../../contexts/SettingsContext"; import { useLocation } from "../../contexts/LocationContext"; import { useUser } from "../../contexts/UserContext"; // imported for when it needs to be used import { AuthStore } from "../../services/store"; +import { ChatScreenFooter } from "../Common/ChatScreenFooter" const ChatScreen = () => { const settings = useSettings(); @@ -108,13 +109,13 @@ const ChatScreen = () => { - { setMessageContent(text); }} + onSend={onHandleSubmit} /> - @@ -147,16 +148,17 @@ const styles = StyleSheet.create({ footerContainer: { width: "95%", - minHeight: Dimensions.get("window").height * 0.1, + maxHeight: Dimensions.get("window").height * 0.15, display: "flex", flexDirection: "row", alignItems: "flex-end", justifyContent: "space-evenly", - paddingBottom: Dimensions.get("window").height * 0.02, - paddingTop: Dimensions.get("window").height * 0.02, - marginTop: 10, - borderTopWidth: 1, + paddingBottom: Dimensions.get("window").height * 0.003, + paddingTop: Dimensions.get("window").height * 0.004, + marginTop: 0, + borderTopWidth: 0, + borderColor: "#8E8E8E", }, }); diff --git a/client/src/components/Common/ChatScreenFooter.tsx b/client/src/components/Common/ChatScreenFooter.tsx new file mode 100644 index 000000000..af9998ed5 --- /dev/null +++ b/client/src/components/Common/ChatScreenFooter.tsx @@ -0,0 +1,88 @@ +import React from 'react' +import { TextInput, View, StyleSheet, Dimensions, Platform, TouchableOpacity } from 'react-native' +import { ChatSendButton } from './CustomButtons' +import { Smile, Image } from "react-native-feather"; + +interface ChatInputProps { + value?: string, + onChangeText?: (text: string) => void + invalid?: boolean, + onSend?: () => void, +} + +export const ChatScreenFooter: React.FC = ({ value, onChangeText, onSend }) => { + + + + return ( + + + + + + + + + + + + + + + ) +}; + +const styles = StyleSheet.create({ + + container: { + flexDirection: 'row', + flex: 1, + alignItems: 'center', + borderColor: "#8E8E8E", + borderWidth: 1, + borderRadius: Dimensions.get('window').width * 0.058, + marginHorizontal: Dimensions.get('window').width * 0.005, + marginBottom: Platform.OS === 'ios' ? 0 : 5, + minHeight: Dimensions.get('window').width * 0.113, + maxHeight: Dimensions.get('window').width * 0.3, + }, + messageInput: { + fontSize: 16, + flex: 1, + marginBottom: Platform.OS === 'ios' ? 5 : 4, + marginTop: Platform.OS === 'ios' ? 2 : 4, + marginHorizontal: Dimensions.get('window').width * 0.018, + + + }, + icons: { + marginHorizontal: Dimensions.get('window').width * 0.008, + }, + iconContainer: { + marginLeft: Dimensions.get('window').width * 0.02, + marginBottom: Dimensions.get('window').width * 0.025, + marginTop: Dimensions.get('window').width * 0.025, + flexDirection: 'row', + alignItems: "flex-end", + justifyContent: "flex-end", + alignSelf: "stretch", + + + }, + sendButtonContainer: { + alignItems: "flex-end", + justifyContent: "flex-end", + flexDirection: "row", + alignSelf: "stretch", + marginRight: Dimensions.get('window').width * 0.01, + marginBottom: Dimensions.get('window').width * 0.01, + marginTop: Dimensions.get('window').width * 0.01, + } + +}); \ No newline at end of file diff --git a/client/src/components/Common/CustomButtons.tsx b/client/src/components/Common/CustomButtons.tsx index 6474e4c56..1b9cd5cb7 100644 --- a/client/src/components/Common/CustomButtons.tsx +++ b/client/src/components/Common/CustomButtons.tsx @@ -8,25 +8,26 @@ interface ChatSendButtonProps { export const ChatSendButton: React.FC = ({ onPress }) => { return ( - + ) } const styles = StyleSheet.create({ sendButton: { - height: Dimensions.get('window').height * 0.055, - width: Dimensions.get('window').height * 0.055, - borderRadius: 30, - backgroundColor: 'blue', + height: Dimensions.get('window').width * 0.09, + width: Dimensions.get('window').width * 0.09, + borderRadius: 100, + backgroundColor: '#34D1BF', justifyContent: 'center', alignItems: 'center', }, sendButtonImage:{ - height: Dimensions.get('window').height * 0.033, - width: Dimensions.get('window').height * 0.033, - marginLeft: Dimensions.get('window').width * 0.01, + height: "64%", + width: "64%", + marginLeft: "13%", + tintColor: 'white', }, }) diff --git a/client/src/components/Common/CustomInputs.tsx b/client/src/components/Common/CustomInputs.tsx index 525258263..71871be41 100644 --- a/client/src/components/Common/CustomInputs.tsx +++ b/client/src/components/Common/CustomInputs.tsx @@ -1,10 +1,12 @@ import React from 'react' import { TextInput, View, StyleSheet, Dimensions, Platform } from 'react-native' +import { ChatSendButton } from './CustomButtons' interface ChatInputProps { value?: string, onChangeText?: (text: string) => void invalid?: boolean, + onSend?: () => void, } export const WelcomeEmailInput: React.FC = ({ value, onChangeText }) => { @@ -80,17 +82,23 @@ export const SignUpConfirmPasswordInput: React.FC = ({ value, on ) } -export const ChatInput: React.FC = ({ value, onChangeText }) => { +export const ChatInput: React.FC = ({ value, onChangeText, onSend }) => { return ( - + + + + + + ) }; @@ -115,7 +123,24 @@ const styles = StyleSheet.create({ paddingLeft: 15, paddingRight: 15, }, - + messsageContainer: { + width: Dimensions.get('window').width * 0.75, + borderWidth: 1, + borderRadius: 30, + paddingTop: Dimensions.get('window').height * 0.006, + paddingBottom: Dimensions.get('window').height * 0.006, + paddingLeft: 15, + paddingRight: Dimensions.get('window').height * 0.006, + flexDirection: 'row', + flex: 1, + justifyContent: 'space-between', + alignItems: 'center', + borderColor: "#8E8E8E" + }, + messageInput: { + width: Dimensions.get('window').height * 0.35, + fontSize: 16, + }, invalidLoginInput: { borderColor: 'red', }, diff --git a/client/src/contexts/SocketContext.tsx b/client/src/contexts/SocketContext.tsx index a51fdf4ad..7dfa1ea23 100644 --- a/client/src/contexts/SocketContext.tsx +++ b/client/src/contexts/SocketContext.tsx @@ -31,6 +31,10 @@ export const SocketProvider = ({ children }: { children: React.ReactNode }) => { } }); +<<<<<<< HEAD +======= + socketIo.connect() +>>>>>>> a15bd2c79af0ae980877f70f54f541fc55ae7ff0 setSocket(socketIo); setMounted(true); } diff --git a/server/config_example.md b/server/config_example.md index 184fd8709..8ffb34245 100644 --- a/server/config_example.md +++ b/server/config_example.md @@ -1,13 +1,10 @@ # dotenv config file (copy config to a new file named `.env`) # **Do not delete this file** -# Firebase config -API_KEY = place_your_apiKey_here -AUTH_DOMAIN = place_your_authDomain_here -PROJECT_ID = place_your_projectId_here -STORAGE_BUCKET = place_your_storageBucket_here -MESSAGING_SENDER_ID = place_your_messagingSenderId_here -APP_ID = place_your_appId_here +# To configure firebase: +# - Go to project settings > service accounts, +# - Make a new private key for the Node.js SDK +# - Paste all contents into ".firebase-secrets.json" in server/ # Location message_outreach_radius = 100 # meters diff --git a/server/src/actions/createConnectedUser.ts b/server/src/actions/createConnectedUser.ts index d06cf6854..f47fc38bf 100644 --- a/server/src/actions/createConnectedUser.ts +++ b/server/src/actions/createConnectedUser.ts @@ -1,6 +1,10 @@ // Uploads a new document in the ConnectedUsers collection. import { ConnectedUser } from '../types/User' +<<<<<<< HEAD import { connectedUsersCollection } from '../utilities/adminInit'; +======= +import { connectedUsersCollection } from '../utilities/firebaseInit'; +>>>>>>> a15bd2c79af0ae980877f70f54f541fc55ae7ff0 export const createUser = async (connectedUser: ConnectedUser) => { try { diff --git a/server/src/actions/createMessage.ts b/server/src/actions/createMessage.ts index 8494db672..f9ea0726b 100644 --- a/server/src/actions/createMessage.ts +++ b/server/src/actions/createMessage.ts @@ -1,6 +1,10 @@ // Uploads a new document in the Messages collection. import { Message } from '../types/Message' +<<<<<<< HEAD import { messagesCollection } from '../utilities/adminInit' +======= +import { messagesCollection } from '../utilities/firebaseInit' +>>>>>>> a15bd2c79af0ae980877f70f54f541fc55ae7ff0 export const createMessage = async (msg : Message) => { try { diff --git a/server/src/actions/deleteConnectedUser.ts b/server/src/actions/deleteConnectedUser.ts index a6a968780..a4398a529 100644 --- a/server/src/actions/deleteConnectedUser.ts +++ b/server/src/actions/deleteConnectedUser.ts @@ -1,5 +1,9 @@ // Delete a ConnectedUser document given a document's index. This should typically be a socketId, but it can also be something else. +<<<<<<< HEAD import { connectedUsersCollection } from '../utilities/adminInit' +======= +import { connectedUsersCollection } from '../utilities/firebaseInit' +>>>>>>> a15bd2c79af0ae980877f70f54f541fc55ae7ff0 export const deleteConnectedUserByUID = async (socketID: string) => { try { diff --git a/server/src/actions/getConnectedUsers.ts b/server/src/actions/getConnectedUsers.ts index c2567abd0..06856e493 100644 --- a/server/src/actions/getConnectedUsers.ts +++ b/server/src/actions/getConnectedUsers.ts @@ -1,5 +1,9 @@ import { distanceBetween, geohashForLocation, geohashQueryBounds } from 'geofire-common' +<<<<<<< HEAD import { connectedUsersCollection } from '../utilities/adminInit' +======= +import { connectedUsersCollection } from '../utilities/firebaseInit' +>>>>>>> a15bd2c79af0ae980877f70f54f541fc55ae7ff0 export const findNearbyUsers = async (centerLat: number, centerLon: number, radius: number) => { // Return an array of nearby userIds (which are also socket ids) given a center latitude and longitude. diff --git a/server/src/actions/updateConnectedUser.ts b/server/src/actions/updateConnectedUser.ts index c935ae7c6..47da535a8 100644 --- a/server/src/actions/updateConnectedUser.ts +++ b/server/src/actions/updateConnectedUser.ts @@ -1,5 +1,9 @@ import { geohashForLocation} from 'geofire-common' +<<<<<<< HEAD import { connectedUsersCollection } from '../utilities/adminInit' +======= +import { connectedUsersCollection } from '../utilities/firebaseInit' +>>>>>>> a15bd2c79af0ae980877f70f54f541fc55ae7ff0 export const toggleUserConnectionStatus = async (socketID: string) => { try { diff --git a/server/src/types/Message.ts b/server/src/types/Message.ts index 64af59b4c..41b6e0966 100644 --- a/server/src/types/Message.ts +++ b/server/src/types/Message.ts @@ -8,4 +8,5 @@ export interface Message { lon: number geohash?: string } + visibleToUids?: Array } diff --git a/server/src/utilities/firebaseInit.ts b/server/src/utilities/firebaseInit.ts new file mode 100644 index 000000000..beeb3f717 --- /dev/null +++ b/server/src/utilities/firebaseInit.ts @@ -0,0 +1,15 @@ +const admin = require('firebase-admin'); +const serviceAccount = require("../../.firebase-secrets.json"); + +export const adminApp = admin.initializeApp({ + credential: admin.credential.cert(serviceAccount), +}); + +export const db = admin.firestore(); +export const connectedUsersCollection = db.collection('ConnectedUsers'); +export const messagesCollection = db.collection('Messages'); + +console.log("[FIREBASE] Firestore synced.") + +// TODO: refactor file name to 'firebase' for accuracy. +// TODO: move key info to .env