From 32ae6dfe1ef3e744a0835ab887d4dcb25beb04b1 Mon Sep 17 00:00:00 2001 From: munezeromicha Date: Thu, 11 Jul 2024 21:20:13 +0200 Subject: [PATCH] ft-audio-call-added ft-audio-call-added --- api.ts | 15 + app.json | 14 +- .../Appointments/Review/ReviewBlankform.tsx | 638 ++++++++++-------- .../VideoCallAppointment/VideoCallRinging.tsx | 228 +++---- .../MyAppointmentVoiceCall.tsx | 279 -------- .../VoiceCallAppointment/SessionEnded.tsx | 232 ++++--- .../VoiceCallAppointment/VoiceCall.tsx | 519 ++++++++++++++ .../VoiceCallAppointment/VoiceCallRinging.tsx | 112 --- .../VoiceCallAppointment/index.tsx | 24 +- app/(app)/Appointments/_layout.tsx | 4 +- app/(app)/Appointments/index.tsx | 6 +- app/(app)/Profile/index.tsx | 2 +- assets/images/Completed.png | Bin 0 -> 1147 bytes components/Icons/Icons.ts | 13 + package-lock.json | 202 +++++- package.json | 7 + 16 files changed, 1380 insertions(+), 915 deletions(-) create mode 100644 api.ts delete mode 100644 app/(app)/Appointments/VoiceCallAppointment/MyAppointmentVoiceCall.tsx create mode 100644 app/(app)/Appointments/VoiceCallAppointment/VoiceCall.tsx delete mode 100644 app/(app)/Appointments/VoiceCallAppointment/VoiceCallRinging.tsx create mode 100644 assets/images/Completed.png diff --git a/api.ts b/api.ts new file mode 100644 index 00000000..453dcf84 --- /dev/null +++ b/api.ts @@ -0,0 +1,15 @@ +export const token: string = process.env.EXPO_PUBLIC_TOKEN; + +export const createMeeting = async ({ token }: { token: string }): Promise => { + const res = await fetch(`https://api.videosdk.live/v2/rooms`, { + method: "POST", + headers: { + authorization: `${token}`, + "Content-Type": "application/json", + }, + body: JSON.stringify({}), + }); + + const { roomId } = await res.json(); + return roomId; +} \ No newline at end of file diff --git a/app.json b/app.json index 8dc28e95..ab01d79d 100644 --- a/app.json +++ b/app.json @@ -1,7 +1,7 @@ { "expo": { "name": "matadors-rn-medica", - "slug": "matadors-rn-medica", + "slug": "medica-158", "scheme": "com.medica", "version": "1.0.0", "orientation": "portrait", @@ -70,6 +70,14 @@ { "microphonePermission": "$(PRODUCT_NAME) would like to use your microphone for voice recording." } + ], + "@videosdk.live/expo-config-plugin", + [ + "@config-plugins/react-native-webrtc", + { + "cameraPermission": "Allow $(PRODUCT_NAME) to access your camera", + "microphonePermission": "Allow $(PRODUCT_NAME) to access your microphone" + } ] ], "experiments": { @@ -80,7 +88,7 @@ "origin": false }, "eas": { - "projectId": "3a6a34bd-fe90-43f9-9508-8c6cf7700ef6" + "projectId": "e682bd39-ab6e-4861-9be2-39cbe02bb93e" } }, "runtimeVersion": { @@ -89,6 +97,6 @@ "updates": { "url": "https://u.expo.dev/3a17d659-91e3-4105-837b-5f88bdee8d37" }, - "owner": "apiimperfect" + "owner": "actrox" } } diff --git a/app/(app)/Appointments/Review/ReviewBlankform.tsx b/app/(app)/Appointments/Review/ReviewBlankform.tsx index 5565f2d1..eb938cbf 100644 --- a/app/(app)/Appointments/Review/ReviewBlankform.tsx +++ b/app/(app)/Appointments/Review/ReviewBlankform.tsx @@ -1,320 +1,366 @@ import { - StyleSheet, - Text, - View, - Image, - TouchableOpacity, - TextInput, - KeyboardAvoidingView, - Platform, - ColorSchemeName, - Appearance - } from "react-native"; - import React, { useContext, useEffect, useState } from "react"; - import Typography from "@/constants/Typography"; - import { ThemeContext } from "@/ctx/ThemeContext"; - import { backArrowBlack, backArrowWhite } from "@/components/UI/icons/backArrow"; - import { SvgXml } from "react-native-svg"; - import StarRating from "react-native-star-rating-widget"; - import { DivLine } from "@/assets/icons/DivLine"; - import { RadioButton } from "react-native-paper"; - import { StatusBar } from "expo-status-bar"; - import { router, useLocalSearchParams } from "expo-router"; - import Popup from "./Popup"; + StyleSheet, + Text, + View, + Image, + TouchableOpacity, + TextInput, + KeyboardAvoidingView, + Platform, + ColorSchemeName, + Appearance, +} from "react-native"; +import React, { useContext, useEffect, useState } from "react"; +import Typography from "@/constants/Typography"; +import { ThemeContext } from "@/ctx/ThemeContext"; +import { + backArrowBlack, + backArrowWhite, +} from "@/components/UI/icons/backArrow"; +import { SvgXml } from "react-native-svg"; +import StarRating from "react-native-star-rating-widget"; +import { DivLine } from "@/assets/icons/DivLine"; +import { RadioButton } from "react-native-paper"; +import { StatusBar } from "expo-status-bar"; +import { router, useLocalSearchParams } from "expo-router"; +import Popup from "./Popup"; import { supabase } from "@/lib/supabase"; import Index from "../.."; - - interface Review{ - id:string; - doctor_id:string; - patient_id:string; - review:string; - recommend:boolean; - - } interface Doctor { - id: string; - first_name: string; - last_name: string; - image: string; - }; - const ReviewBlankform: React.FC = () => { - const { theme, changeTheme } = useContext(ThemeContext); - const [rating, setRating] = useState(0); - const [value, setValue] = useState("Yes"); - const [doctor, setDoctor] = useState([]); - const [showPopup, setShowPopup] = useState(false); - const [loggedUser, setLoggedUser] = useState(); - const [profile, setProfile] = useState(null); - const [text, setText] = useState(""); + +interface Review { + id: string; + doctor_id: string; + patient_id: string; + review: string; + recommend: boolean; +} +interface Doctors { + id: string; + first_name: string; + last_name: string; + image: string; +} +type Doctor = Doctors | null; +type FetchError = string | null; + +const ReviewBlankform: React.FC = () => { + const { theme, changeTheme } = useContext(ThemeContext); + const [rating, setRating] = useState(0); + const [value, setValue] = useState("Yes"); + const [doctor, setDoctor] = useState(null); + const [FetchError, setFetchError] = useState(null); + const [showPopup, setShowPopup] = useState(false); + const [loggedUser, setLoggedUser] = useState(); + const [profile, setProfile] = useState(null); + const [text, setText] = useState(""); const [patientId, setPatientId] = useState(); - const ColorScheme = Appearance.getColorScheme(); - + const ColorScheme = Appearance.getColorScheme(); - const submitHandler = () => { - insertReview(); - setShowPopup(true); - }; - - const closePopup = () => { - setShowPopup(false); + const submitHandler = () => { + insertReview(); + setShowPopup(true); + }; + + const closePopup = () => { + setShowPopup(false); + }; + useEffect(() => { + const fetchUser = async () => { + const { + data: { user }, + error, + } = await supabase.auth.getUser(); + if (error) { + console.error("Error fetching user:", error); + } else { + setLoggedUser(user?.id); + } }; - useEffect(() => { - const fetchUser = async () => { - const { data: { user }, error } = await supabase.auth.getUser(); + fetchUser(); + }, []); + useEffect(() => { + const fetchUserProfile = async () => { + if (loggedUser) { + const { data, error } = await supabase + .from("patients") + .select("*") + .eq("auth_id", loggedUser) + .single(); if (error) { - console.error("Error fetching user:", error); + console.error("Error retrieving profile:", error); } else { - setLoggedUser(user?.id); + setProfile(data); + setPatientId(data.id); + console.log(data.id); } - }; - fetchUser(); - }, []); - useEffect(() => { - const fetchUserProfile = async () => { - if (loggedUser) { - const { data, error } = await supabase - .from("patients") - .select("*") - .eq('auth_id', loggedUser) - .single(); - if (error) { - console.error("Error retrieving profile:", error); - } else { - setProfile(data); - setPatientId(data.id); - console.log(data.id); - - } + } + }; + fetchUserProfile(); + }, [loggedUser]); + + const { id } = useLocalSearchParams(); + const tableName = "doctors"; + + useEffect(() => { + const FetchDoctors = async () => { + try { + const { data, error } = await supabase + .from(tableName) + .select("*") + .eq("id", `${id}`) + .single(); + + if (data) { + setDoctor(data); + setFetchError(null); } - }; - fetchUserProfile(); - }, [loggedUser]); - - const {doctor_id} = useLocalSearchParams(); - async function Fetchdoctor() { - const { data: doctorsData, error: doctorsError } = await supabase - .from("doctors") - .select("*") - .eq("id", doctor_id); - - if (doctorsError) { - // setIsLoading(false); - console.error("Error fetching doctors:", doctorsError); - return; - } - const Data = doctorsData.map(doctor => { - const doctors = doctorsData.find(doc => doc.id === doctor.doctor_id); - setDoctor(doctor); - - }); - - - } - Fetchdoctor(); - - async function insertReview() { - const { data, error } = await supabase - .from('reviews') - .insert([ - { patient_id: patientId, doctor_id: doctor_id, review: text, recommend: value === 'Yes' ,stars:rating } - ]); - - if (error) { - console.error('Error inserting data:', error); - } else { - console.log('Data inserted:', data); + if (error) { + setDoctor(null); + setFetchError("could not fetch description articles in database"); + return null; + } + } catch (error) { + console.error(error); + setFetchError("An unexpected error occurred"); + return null; } + }; + FetchDoctors(); + }, []); + + async function insertReview() { + const { data, error } = await supabase.from("reviews").insert([ + { + patient_id: patientId, + doctor_id: `${id}`, + review: text, + recommend: value === "Yes", + stars: rating, + }, + ]); + + if (error) { + console.error("Error inserting data:", error); + } else { + console.log("Data inserted:", data); } - - - - return ( - - - - - router.back()}> - - - - - Write a Review - - - {doctor && ( - <> - - - - How was your experience with {doctor.first_name} {doctor.last_name}? - - - - - - - - - - - - - - - Write Your Review - - + {FetchError && {FetchError}} + {doctor && ( + + + - + router.back()}> + + - + + Write a Review + + - - - - - Would you recommend {doctor.first_name} {doctor.last_name} to your friends? - - - setValue(value)} - value={value} - > - - - - Yes - - - - - No - - - - - - - router.push('Appointments')} + + - Cancel + How was your experience with {doctor.first_name}{" "} + {doctor.last_name}? - - - - Submit + + + + + + + + + + + + + Write Your Review + + + + + + + + + Would you recommend {doctor.first_name} {doctor.last_name} to your + friends? - - - + + setValue(value)} + value={value} + > + + + + + Yes + + + + + + + No + + + + + + + + router.push("Appointments")} + > + + Cancel + + + + + Submit + + + + - - - )} - - - ); - }; - - export default ReviewBlankform; - - const styles = StyleSheet.create({ - darkKeyboard: { - backgroundColor: '#000000', - color: '#ffffff', - }, - lightKeyboard: { - backgroundColor: '#ffffff', - color: '#000000', - }, - }); - \ No newline at end of file + )} + + ); +}; + +export default ReviewBlankform; + +const styles = StyleSheet.create({ + darkKeyboard: { + backgroundColor: "#000000", + color: "#ffffff", + }, + lightKeyboard: { + backgroundColor: "#ffffff", + color: "#000000", + }, +}); diff --git a/app/(app)/Appointments/VideoCallAppointment/VideoCallRinging.tsx b/app/(app)/Appointments/VideoCallAppointment/VideoCallRinging.tsx index 7be517c6..ca87045a 100644 --- a/app/(app)/Appointments/VideoCallAppointment/VideoCallRinging.tsx +++ b/app/(app)/Appointments/VideoCallAppointment/VideoCallRinging.tsx @@ -1,122 +1,122 @@ import { - StyleSheet, - Text, - View, - ImageBackground, - Image, - Pressable, - TouchableOpacity, - } from "react-native"; - import React from "react"; - import { BackArrow, Speaker, Record, hungup,BigVideoIcon } from "@/components/Icons/Icons"; - import { SvgXml } from "react-native-svg"; - import Typography from "@/constants/Typography"; - import { router } from "expo-router"; - const VoiceCallRinging = () => { - return ( - <> - - - router.back()}> - - - - - - - - - - - Dr. Maria Foose - - - Ringing... - - - - - - - - + StyleSheet, + Text, + View, + ImageBackground, + Image, + Pressable, + TouchableOpacity, +} from "react-native"; +import React from "react"; +import { BackArrow, Speaker, Record, hungup,BigVideoIcon } from "@/components/Icons/Icons"; +import { SvgXml } from "react-native-svg"; +import Typography from "@/constants/Typography"; +import { router } from "expo-router"; +const VoiceCallRinging = () => { + return ( + <> + + + router.back()}> + + + + + + + - router.push('(app)/Appointments/VideoCallAppointment/VideoCall')}> - - - - - - - - router.push('(app)/Appointments/Review/ReviewBlankform')}> - - + + + Dr. Maria Foose + + + Ringing... + - - - ); - }; - - export default VoiceCallRinging; - - const styles = StyleSheet.create({ - speaker:{ + + + + + + + + router.push('(app)/Appointments/VideoCallAppointment/VideoCall')}> + + + + + + + + router.push('(app)/Appointments/Review/ReviewBlankform')}> + + + + + + ); +}; + +export default VoiceCallRinging; + +const styles = StyleSheet.create({ + speaker:{ + backgroundColor: '#F0F0F0', + borderRadius: 100, + padding: 20, + opacity: 0.6 + }, + Video:{ backgroundColor: '#F0F0F0', borderRadius: 100, padding: 20, opacity: 0.6 }, - Video:{ - backgroundColor: '#F0F0F0', - borderRadius: 100, - padding: 20, - opacity: 0.6 - }, - Record:{ - backgroundColor: '#F0F0F0', - borderRadius: 100, - padding: 23, - opacity: 0.6 - }, - hangup:{ - backgroundColor: '#F75555', - borderRadius: 100, - padding: 20, - - }, - Bottom: { - flexDirection: "row", - justifyContent: "center", - alignItems: "center", - gap: 20, - }, - middlePart: { - justifyContent: "center", - alignItems: "center", - gap: 24, - }, - middleText: { - justifyContent: "center", - alignItems: "center", - gap: 24, - }, - backArrow: { - alignSelf: "flex-start", - marginTop: "5%" - }, - Background: { - flex: 1, - justifyContent: "center", - alignItems: "center", - paddingTop: 24, - paddingBottom: 48, - paddingLeft: 24, - paddingRight: 24, - gap: 140, - }, - }); \ No newline at end of file + Record:{ + backgroundColor: '#F0F0F0', + borderRadius: 100, + padding: 23, + opacity: 0.6 + }, + hangup:{ + backgroundColor: '#F75555', + borderRadius: 100, + padding: 20, + + }, + Bottom: { + flexDirection: "row", + justifyContent: "center", + alignItems: "center", + gap: 20, + }, + middlePart: { + justifyContent: "center", + alignItems: "center", + gap: 24, + }, + middleText: { + justifyContent: "center", + alignItems: "center", + gap: 24, + }, + backArrow: { + alignSelf: "flex-start", + marginTop: "5%" + }, + Background: { + flex: 1, + justifyContent: "center", + alignItems: "center", + paddingTop: 24, + paddingBottom: 48, + paddingLeft: 24, + paddingRight: 24, + gap: 140, + }, +}); \ No newline at end of file diff --git a/app/(app)/Appointments/VoiceCallAppointment/MyAppointmentVoiceCall.tsx b/app/(app)/Appointments/VoiceCallAppointment/MyAppointmentVoiceCall.tsx deleted file mode 100644 index 13ed2f2a..00000000 --- a/app/(app)/Appointments/VoiceCallAppointment/MyAppointmentVoiceCall.tsx +++ /dev/null @@ -1,279 +0,0 @@ -import React, { useContext, useState } from "react"; -import { - SafeAreaView, - Text, - View, - StyleSheet, - Pressable, - Platform, - TouchableWithoutFeedback, - Image, -} from "react-native"; -import { Colors } from "@/constants/Colors"; -import { router } from "expo-router"; -import { MaterialIcons } from "@expo/vector-icons"; -import { ThemeContext } from "@/ctx/ThemeContext"; -import { StatusBar } from "expo-status-bar"; -import Typography from "@/constants/Typography"; -import { SvgXml } from "react-native-svg"; -import { circleWithDots } from "@/components/UI/icons/circleWithDots"; -import { WhiteMenuCircle } from "@/components/UI/icons/WhiteMenuCircle"; -import DoctorCard from "@/components/DoctorCard"; -import { Call, CallWhiteIcon } from "@/components/Icons/Icons" -import { BackArrow, blackArrow } from "@/components/Icons/Icons"; - -interface PatientType{ - id: string - name: string - gender: "male" | "female" - age: string - problem: string, - appointmentMethod: "Messaging" | "Voice Call" | "video call" - appointmentDate:string - time: string - price: string - paid: boolean, -} - -function AppointmentMessaging() { - const { theme, changeTheme } = useContext(ThemeContext); - const ios = Platform.OS === "ios"; - - - const PatientDetails: PatientType[] = [ - { - id: "23", - name: "Rhys manners", - gender: "male", - age: "23", - problem: - "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor", - appointmentMethod: "Voice Call", - appointmentDate: "Today December 22,, 2022", - time: "14:00 PM", - price: "20", - paid: true, - }, - ]; - - return ( - - - - - - - - - router.back()} - style={{ - flexDirection: "row", - alignItems: "center", - justifyContent: "space-between", - gap: 30, - - }} - > - - - - - My Appointment - - - - - - - - {PatientDetails && - PatientDetails.map((data: PatientType) => ( - - - - - - - - Scheduled appointment - - - - {data.appointmentDate} - {data.time} - - - - - Patient Information - - - - Full Name: {data?.name} - - - Gender: {data?.gender} - - - Age: {data?.age} - - - Problem: {data?.problem} - - - - - - Your Package - - - - - - - - - {data.appointmentMethod} - - Voice call with doctor - - - - - ${data.price} - - {data.paid ? "(paid)" : "not paid"} - - - - - router.push("(app)/Appointments/VoiceCallAppointment/VoiceCallRinging")} - style={{ - backgroundColor: Colors.main.primary._500, - borderRadius: 100, - }} - > - - - - {data?.appointmentMethod}( - Start at {data?.time}) - - - - - ))} - - - - ); -} - -export default AppointmentMessaging; - diff --git a/app/(app)/Appointments/VoiceCallAppointment/SessionEnded.tsx b/app/(app)/Appointments/VoiceCallAppointment/SessionEnded.tsx index 5121dd22..01e4370a 100644 --- a/app/(app)/Appointments/VoiceCallAppointment/SessionEnded.tsx +++ b/app/(app)/Appointments/VoiceCallAppointment/SessionEnded.tsx @@ -1,74 +1,117 @@ import { StyleSheet, Text, View, TouchableOpacity, Image } from "react-native"; -import React, { useContext } from "react"; -import { BackArrow, blackArrow, Timer, line, lineTwo } from "@/components/Icons/Icons"; +import React, { useContext, useEffect, useState } from "react"; +import { + BackArrow, + blackArrow, + Timer, + line, + lineTwo, +} from "@/components/Icons/Icons"; import { SvgXml } from "react-native-svg"; -import { router } from "expo-router"; -import Typography from "@/constants/Typography"; +import { router, useGlobalSearchParams } from "expo-router"; +import Typography from "@/constants/Typography"; import { ThemeContext } from "@/ctx/ThemeContext"; import { StatusBar } from "expo-status-bar"; +import { supabase } from "@/lib/supabase"; -interface doctor { +interface Doctors { + hospital_name: string; + specialization: string; + first_name: string; + last_name: string; + created_at: string; + image: string; id: string; - name: string; - title: string; - location: string; } +type FetchDoctor = Doctors | null; +type FetchError = string | null; + +const tableName = "doctors"; + const SessionEnded = () => { const { theme, changeTheme } = useContext(ThemeContext); - const doctorDetails: doctor[] = [ - { - id: "22", - name: "Dr. Jenny Watson", - title: "Immunologists", - location: "Alka Hospital in Seoul, South Korea", - }, - ]; + const [FetchDoctor, setFetchDoctor] = useState(null); + const [FetchError, setFetchError] = useState(null); + const { id } = useGlobalSearchParams(); + + useEffect(() => { + const FetchDoctors = async () => { + try { + const { data, error } = await supabase + .from(tableName) + .select("*") + .eq("id", `${id}`) + .single(); + + if (data) { + setFetchDoctor(data); + setFetchError(null); + } + + if (error) { + setFetchDoctor(null); + setFetchError("could not fetch description articles in database"); + return null; + } + } catch (error) { + console.error(error); + setFetchError("An unexpected error occurred"); + return null; + } + }; + FetchDoctors(); + }, []); return ( - - - - router.back()}> - - - - - - - - - The consultation session has ended. - - - Recordings have been saved in activity. - - + <> + {FetchError && {FetchError}} + {FetchDoctor && ( + + + + router.back()}> + + + - - - - + + + + + The consultation session has ended. + + + Recordings have been saved in activity. + + + + + + + + + + - - - {doctorDetails && - doctorDetails.map((data: doctor) => ( { { color: theme === "dark" ? "#FFFFFF" : "#212121" }, ]} > - {data.name} + {FetchDoctor.first_name} {FetchDoctor.last_name} { { color: theme === "dark" ? "#FFFFFF" : "#212121" }, ]} > - {data.title} + {FetchDoctor.specialization} { { color: theme === "dark" ? "#FFFFFF" : "#212121" }, ]} > - {data.location} + {FetchDoctor.hospital_name} - ))} - - - - + + + + - - router.push("Appointments")} - style={[ - styles.backButton, - { backgroundColor: theme === "dark" ? "#35383F" : "#E9F0FF" }, - ]} - > - - Back to Home - - - - router.push('(app)/Appointments/Review/ReviewBlankform')}> - - Leave a Review - - - - + + router.push("Appointments")} + style={[ + styles.backButton, + { backgroundColor: theme === "dark" ? "#35383F" : "#E9F0FF" }, + ]} + > + + Back to Home + + + + + router.push({ + pathname:"(app)/Appointments/Review/ReviewBlankform", + params: {id: id} + }) + } + > + + Leave a Review + + + + + )} + ); }; diff --git a/app/(app)/Appointments/VoiceCallAppointment/VoiceCall.tsx b/app/(app)/Appointments/VoiceCallAppointment/VoiceCall.tsx new file mode 100644 index 00000000..1e58b774 --- /dev/null +++ b/app/(app)/Appointments/VoiceCallAppointment/VoiceCall.tsx @@ -0,0 +1,519 @@ +import React, { useContext, useEffect, useState } from "react"; +import { + SafeAreaView, + TouchableOpacity, + Text, + View, + FlatList, + ImageBackground, + StyleSheet, + Image, + TextInput, +} from "react-native"; +import { MeetingProvider, useMeeting } from "@videosdk.live/react-native-sdk"; +import { createMeeting, token } from "@/api"; +import Typography from "@/constants/Typography"; +import { SvgXml } from "react-native-svg"; +import { + hungup, + Record, + MicOff, + BackArrow, + blackArrow, + CallWhite +} from "@/components/Icons/Icons"; +import { router, useGlobalSearchParams } from "expo-router"; +import { supabase } from "@/lib/supabase"; +import { ThemeContext } from "@/ctx/ThemeContext"; + +interface JoinScreenProps { + getMeetingId: (id?: string) => void; +} + +const JoinScreen: React.FC = ({ getMeetingId }) => { + const [meetingVal, setMeetingVal] = useState(""); + const [meetingFocused, setMeetingFocused] = useState(false); + const { theme, changeTheme } = useContext(ThemeContext); + + const handleEmailFocus = () => { + setMeetingFocused(true); + }; + + const handleEmailBlur = () => { + setMeetingFocused(false); + }; + + return ( + + + router.back()}> + + + + + + + + { + getMeetingId(); + }} + style={{ + justifyContent: "center", + alignItems: "center", + width: 380, + height: 58, + backgroundColor: "#246BFD", + borderRadius: 100, + }} + > + + Create Room + + + + OR + + + + + + { + getMeetingId(meetingVal); + }} + > + + Join the Room + + + + + ); +}; + +const styles = StyleSheet.create({ + inputOneFocused: { + borderColor: "#246BFD", + borderWidth: 2, + borderRadius: 100, + width: 380, + }, + meetingFocused: { + color: "#868a94", + fontSize: 16, + }, + input: { + padding: 12, + borderWidth: 0, + borderRadius: 6, + alignSelf: "center", + fontFamily: "italic", + }, + Background: { + flex: 1, + justifyContent: "center", + alignItems: "center", + paddingTop: 100, + paddingBottom: 48, + paddingLeft: 24, + paddingRight: 24, + }, + backArrow: { + alignSelf: "flex-start", + }, +}); + +interface ButtonProps { + onPress: () => void; + buttonText: string; + backgroundColor: string; +} + +const Button: React.FC = ({ + onPress, + buttonText, + backgroundColor, +}) => { + return ( + + {buttonText} + + ); +}; + +interface ControlsContainerProps { + join: () => void; + leave: () => void; + toggleMic: () => void; +} + +const ControlsContainer: React.FC = ({ + join, + leave, + toggleMic, +}) => { + const [isButtonDisabled, setButtonDisabled] = useState(false); + const [isMicOn, setIsMicOn] = useState(true); + const { id, AppointmentID } = useGlobalSearchParams(); + const [isLoading, setIsLoading] = useState(false); + + const HandleUpdate = async () => { + try { + setIsLoading(true); + const { error } = await supabase + .from("appointment") + .update({ status: "Completed" }) + .eq("id", AppointmentID); + if (error) { + console.log(error); + } else { + setIsLoading(false); + } + } catch (error) { + console.log(error); + } + }; + + const handleMicPress = () => { + setIsMicOn((prevState) => !prevState); + }; + + const handleButtonDisable = () => { + setButtonDisabled(true); + }; + return ( + + { + join(); + handleButtonDisable(); + }} + disabled={isButtonDisabled} + > + + + + { + toggleMic(); + handleMicPress(); + }} + > + + + + + + + { + leave(); + HandleUpdate(); + router.push({ + pathname: "(app)/Appointments/VoiceCallAppointment/SessionEnded", + params: { id: id }, + }); + }} + > + + + + ); +}; + +interface ParticipantViewProps { + participantId: string; + meetingId: string | null; +} + +interface Doctors { + first_name: string; + last_name: string; + created_at: string; + image: string; + id: string; +} + +type FetchDoctor = Doctors | null; +type FetchError = string | null; + +const tableName = "doctors"; + +const ParticipantView: React.FC = () => { + const [FetchDoctor, setFetchDoctor] = useState(null); + const [FetchError, setFetchError] = useState(null); + const { id } = useGlobalSearchParams(); + useEffect(() => { + const FetchDoctors = async () => { + try { + const { data, error } = await supabase + .from(tableName) + .select("*") + .eq("id", `${id}`) + .single(); + + if (data) { + setFetchDoctor(data); + setFetchError(null); + } + + if (error) { + setFetchDoctor(null); + setFetchError("could not fetch description articles in database"); + return null; + } + } catch (error) { + console.error(error); + setFetchError("An unexpected error occurred"); + return null; + } + }; + FetchDoctors(); + }, []); + return ( + + {FetchError && {FetchError}} + + {FetchDoctor && ( + + + + + + {FetchDoctor.first_name} {FetchDoctor.last_name} + + + + + )} + + ); +}; + +interface ParticipantListProps { + participants: string[]; + meetingId: string | null; +} + +interface Doctors { + first_name: string; + last_name: string; + created_at: string; + image: string; + id: string; +} + +const ParticipantList: React.FC = ({ participants,meetingId }) => { + const [FetchDoctor, setFetchDoctor] = useState(null); + const [FetchError, setFetchError] = useState(null); + const { id } = useGlobalSearchParams(); + useEffect(() => { + const FetchDoctors = async () => { + try { + const { data, error } = await supabase + .from(tableName) + .select("*") + .eq("id", `${id}`) + .single(); + + if (data) { + setFetchDoctor(data); + setFetchError(null); + } + + if (error) { + setFetchDoctor(null); + setFetchError("could not fetch description articles in database"); + console.error("Error fetching item:", error); + return null; + } + } catch (error) { + console.error(error); + setFetchError("An unexpected error occurred"); + return null; + } + }; + FetchDoctors(); + }, []); + + return participants.length > 0 ? ( + { + return ; + }} + /> + ) : ( + + {FetchError && {FetchError}} + + {FetchDoctor && ( + + + + + + {FetchDoctor.first_name} {FetchDoctor.last_name} + + + + Tap to call + + + )} + + ); +}; + +const MeetingView: React.FC<{ meetingId: string | null }> = ({ meetingId }) => { + const { join, leave, toggleMic, participants } = useMeeting({}); + const participantsArrId = [...participants.keys()]; + + return ( + + + + + + + ); +}; + +const VoiceCall: React.FC = () => { + const [meetingId, setMeetingId] = useState(null); + const { AppointmentID } = useGlobalSearchParams(); + + const getMeetingId = async (id?: string) => { + const newMeetingId = id == null ? await createMeeting({ token }) : id; + setMeetingId(newMeetingId); + if (newMeetingId) { + try { + const { error } = await supabase + .from("appointment") + .update({ meetingId: newMeetingId }) + .eq("id", AppointmentID); + if (error) { + console.error("Error updating meeting ID:", error); + } + } catch (error) { + console.error("Unexpected error updating meeting ID:", error); + } + } + }; + + return meetingId ? ( + + + + + + ) : ( + + ); +}; + +export default VoiceCall; diff --git a/app/(app)/Appointments/VoiceCallAppointment/VoiceCallRinging.tsx b/app/(app)/Appointments/VoiceCallAppointment/VoiceCallRinging.tsx deleted file mode 100644 index 4ca01562..00000000 --- a/app/(app)/Appointments/VoiceCallAppointment/VoiceCallRinging.tsx +++ /dev/null @@ -1,112 +0,0 @@ -import { - StyleSheet, - Text, - View, - ImageBackground, - Image, - Pressable, - TouchableOpacity, -} from "react-native"; -import React from "react"; -import { BackArrow, Speaker, Record, hungup } from "@/components/Icons/Icons"; -import { SvgXml } from "react-native-svg"; -import Typography from "@/constants/Typography"; -import { router } from "expo-router"; -const VoiceCallRinging = () => { - return ( - <> - - - router.back()}> - - - - - - - - - - - Dr. Jenny Watson - - - Ringing... - - - - - - - - - - - - - - router.push('(app)/Appointments/VoiceCallAppointment/SessionEnded')}> - - - - - - ); -}; - -export default VoiceCallRinging; - -const styles = StyleSheet.create({ - speaker:{ - backgroundColor: '#F0F0F0', - borderRadius: 100, - padding: 20, - opacity: 0.6 - }, - Record:{ - backgroundColor: '#F0F0F0', - borderRadius: 100, - padding: 23, - opacity: 0.6 - }, - hangup:{ - backgroundColor: '#F75555', - borderRadius: 100, - padding: 20, - - }, - Bottom: { - flexDirection: "row", - justifyContent: "center", - alignItems: "center", - gap: 20, - }, - middlePart: { - justifyContent: "center", - alignItems: "center", - gap: 24, - }, - middleText: { - justifyContent: "center", - alignItems: "center", - gap: 24, - }, - backArrow: { - alignSelf: "flex-start", - marginTop: "5%" - }, - Background: { - flex: 1, - justifyContent: "center", - alignItems: "center", - paddingTop: 24, - paddingBottom: 48, - paddingLeft: 24, - paddingRight: 24, - gap: 140, - }, -}); diff --git a/app/(app)/Appointments/VoiceCallAppointment/index.tsx b/app/(app)/Appointments/VoiceCallAppointment/index.tsx index 933b9f19..685c140c 100644 --- a/app/(app)/Appointments/VoiceCallAppointment/index.tsx +++ b/app/(app)/Appointments/VoiceCallAppointment/index.tsx @@ -3,30 +3,21 @@ import { SafeAreaView, Text, View, - StyleSheet, Pressable, Platform, - TouchableWithoutFeedback, - Image, TouchableOpacity, } from "react-native"; import { Colors } from "@/constants/Colors"; import { router, useLocalSearchParams } from "expo-router"; -import { MaterialIcons } from "@expo/vector-icons"; import { ThemeContext } from "@/ctx/ThemeContext"; import { StatusBar } from "expo-status-bar"; import Typography from "@/constants/Typography"; import { SvgXml } from "react-native-svg"; import DoctorCard from "@/components/DoctorCard"; -import { - WhiteMessageIcon, - blueMessageIcon, -} from "@/components/UI/icons/blueMessage"; import { backArrowWhite } from "@/components/UI/icons/backArrow"; import { WhiteMenuCircle } from "@/components/UI/icons/WhiteMenuCircle"; import { MoreIcon } from "@/assets/icons/MoreCircleSvg"; import { backArrowBlackIcon } from '@/constants/icon' -import { fetchPatientData, getPatientData } from "@/utils/LoggedInUser"; import { supabase } from "@/lib/supabase"; import { CallWhiteIcon } from "@/components/Icons/Icons"; import { BlueVoiceCall } from "@/components/UI/icons/callIcon"; @@ -55,13 +46,13 @@ function AppointmentVoiceCall() { const ios = Platform.OS === "ios"; const [patientData, setPatientData] = useState(null); const [userData, setUserData] = useState<[]>([]); - const { id } = useLocalSearchParams() + const { id } = useLocalSearchParams(); const [isLoading, setIsLoading] = useState(false); const [appointment, setAppointment] = useState([]); const [loggeduser, setLoggedUser] = useState() const [patient_id,setPatient_id]=useState() const [profile, setProfile] = useState(null) - + const [doctorID, setDoctorsID] = useState(); @@ -72,7 +63,6 @@ function AppointmentVoiceCall() { .from("appointment") .select("*") .eq("id", id); - if (appointmentsError) { setIsLoading(false); console.error("Error fetching data:", appointmentsError); @@ -80,6 +70,7 @@ function AppointmentVoiceCall() { } const doctorIds = appointmentsData.map(appointment => appointment.doctor_id); + setDoctorsID(doctorIds[0]); const userIds = appointmentsData.map(appointment => appointment.user_id); try { @@ -125,6 +116,8 @@ try { fetchData(); }, [appointment]); + + useEffect(() => { const fetchUser = async () => { @@ -418,8 +411,11 @@ try { - router.push( - "(app)/Appointments/VoiceCallAppointment/VoiceCallRinging" + router.push({ + pathname:"(app)/Appointments/VoiceCallAppointment/VoiceCall", + params:{id:doctorID, AppointmentID:id} + } + ) } style={{ diff --git a/app/(app)/Appointments/_layout.tsx b/app/(app)/Appointments/_layout.tsx index 8732083f..f3d5788d 100644 --- a/app/(app)/Appointments/_layout.tsx +++ b/app/(app)/Appointments/_layout.tsx @@ -1,6 +1,8 @@ import { Stack } from "expo-router"; import React from "react"; +import { register } from "@videosdk.live/react-native-sdk"; +register(); export default function Layout() { return ( @@ -11,7 +13,7 @@ export default function Layout() { - + diff --git a/app/(app)/Appointments/index.tsx b/app/(app)/Appointments/index.tsx index 9594e541..b8ed487a 100644 --- a/app/(app)/Appointments/index.tsx +++ b/app/(app)/Appointments/index.tsx @@ -116,10 +116,14 @@ const AppointmentScreen: React.FC = () => { ? "(app)/Appointments/MessagingAppointment" : appointment.package === "Video Call" ? "(app)/Appointments/VideoCallAppointment" - : "(app)/Appointments/VoiceCallAppointment"; + : appointment.package === "Voice Call" + ? "(app)/Appointments/VoiceCallAppointment" + : " " router.push({ pathname: route, params: { id: appointment.id } }); } + + useEffect(() => { async function fetchData() { if (!patientId) return; diff --git a/app/(app)/Profile/index.tsx b/app/(app)/Profile/index.tsx index 25fca51a..14bd02f3 100644 --- a/app/(app)/Profile/index.tsx +++ b/app/(app)/Profile/index.tsx @@ -130,7 +130,7 @@ const index = () => { > 1cdvEP))C$nI&~HVpw(<#Voxt%^(Kw3a6GS5oaMvNG+K7bN;c4v1uoSpf&2xrJ0)N>#2m`x-o1M+nnLD09> z?oRLjvmc63elq{n^OVwEZl0nAH)Fj1u+kdBEkow0QML#*L@MFLuZ(_c4FU(HJ6k6N z*q&6IE-V3=PQxXjM_J_;(RuNE4Ye*!symNiiF2f1HM-=(v0`jmOKn(U4(P)+YA7kr zLIv+$vj+DLf$%1{Mo7t(3%(=7?o8)tEs0Jd2RSdE z7Sb;puWj1A{&dH@O?9^Ra^353lm#fubTr$OUt6E7Q>K5EoS z;jfGMQozI=vquUFNHjzR?x^y2o1?AEuOLSNd65&-3FcgnfQa8DxJ*p9gE9OJteX!e zBWQ^{b<}XBIl0$#nYcY;hFeF#p(T1gtu~(odS{IVIA!f;y@zH`s$&z*g6k=g0{%{|4^Kh#c5HZkKc$J zjtO-YnxaI7iR2#1L)>5c3B9%P`p%kSJM{ls8{@mpO6VMM1l#8#>PqnNycRjS&RcLp zbYGeV96VY5SJ-#EGc-M7Ag8b5!|rAhK|K zprzxWEplrQRV4R>dFT_F17WuuAuGmUKDvIU`vr^K&7LpFn&EmJwTF-p zu^p5(-aaq7AzMw_vZpx&|D9DDdc)i5fygD1vw`%pGaba88}v*!$P>u-?97OPJtE5C z*n6CP=RM@7>}8eM@&y?f4f)}RKC|EPdb46Z+vbqyMCc&6fjF;X*G2Z?fKTu^x$8dMP#E6Rz4x9e@O=+{0HVj6Hwm-T zMeHj+_c+!Xp1~4xut+sUu&cNVwS+TpmR~yQ48p!qsnV#rvp+kuXQD;qcZF0j3vS=W z12o}a?|(4`jl7!_=7p6D!JPXBlcN9v%S2F^=&i&tJEWIUUMu8Up8 `; +export const MicOff = ` + + +` +export const Completed = ` + + + +` +export const CallWhite = ` + + +`; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 4f79e5f8..87f28e16 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@commitlint/cli": "^19.3.0", "@commitlint/config-conventional": "^19.2.2", + "@config-plugins/react-native-webrtc": "^9.0.0", "@expo/metro-runtime": "~3.2.1", "@expo/ngrok": "^4.1.3", "@expo/vector-icons": "^14.0.2", @@ -25,6 +26,11 @@ "@simform_solutions/react-native-audio-waveform": "^1.0.1", "@stream-io/flat-list-mvcp": "^0.10.3", "@supabase/supabase-js": "^2.43.4", + "@videosdk.live/expo-config-plugin": "^0.0.2", + "@videosdk.live/react-native-foreground-service": "^0.0.3", + "@videosdk.live/react-native-incallmanager": "^0.1.3", + "@videosdk.live/react-native-sdk": "^0.1.12", + "@videosdk.live/react-native-webrtc": "^0.0.11", "buffer": "^6.0.3", "countries-list": "^3.1.0", "dotenv": "^16.4.5", @@ -94,6 +100,7 @@ "run": "^1.5.0", "sdk": "^0.5.0", "start": "^5.1.0", + "stream-chat": "^8.37.0", "stream-chat-expo": "^5.33.0", "uuid": "^10.0.0", "vector-icons": "^0.1.0" @@ -2859,6 +2866,17 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/@config-plugins/react-native-webrtc": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@config-plugins/react-native-webrtc/-/react-native-webrtc-9.0.0.tgz", + "integrity": "sha512-XHqEIR3iejek1YGZT5441j7i7LI1YdI4yM7nP4PMgswT/hzBnII4Ra9uiIaG105dmqioYgkn2TcScqyOf2MCtQ==", + "dependencies": { + "expo-build-properties": "~0.12.1" + }, + "peerDependencies": { + "expo": "^51" + } + }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", @@ -12038,6 +12056,105 @@ "wonka": "^6.3.2" } }, + "node_modules/@videosdk.live/expo-config-plugin": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@videosdk.live/expo-config-plugin/-/expo-config-plugin-0.0.2.tgz", + "integrity": "sha512-tVjzuWdgUJWmzcXjYqh3gfLldnAJ51oof36ZlUOpEZUY2F1vCh8KpDNV0mcsTBROqVPoF0WAl2GbKPShXQ0Qpw==", + "dependencies": { + "expo-build-properties": "~0.12.1" + }, + "peerDependencies": { + "expo": ">50" + } + }, + "node_modules/@videosdk.live/js-sdk": { + "version": "0.0.90", + "resolved": "https://registry.npmjs.org/@videosdk.live/js-sdk/-/js-sdk-0.0.90.tgz", + "integrity": "sha512-GiUoJtrhiKW7ibE9uCx8HrBM9cHQ+OKj632dkU3FSJg3c8TaESEUmo4iNRi3oRcrLCjX55zxFk7BzDhlLtOl/Q==" + }, + "node_modules/@videosdk.live/react-native-foreground-service": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@videosdk.live/react-native-foreground-service/-/react-native-foreground-service-0.0.3.tgz", + "integrity": "sha512-jpv5K6CGP8tvBPkbpgucPity6Hvf7LDdeatJhVw/712n6DXxnSmNDrme1xbNCNyMce68LL5o0uaD/Rauvs+HrQ==" + }, + "node_modules/@videosdk.live/react-native-incallmanager": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@videosdk.live/react-native-incallmanager/-/react-native-incallmanager-0.1.3.tgz", + "integrity": "sha512-zl7wVEJc+hatW2Qykx6os4ZKASJ5uzEGE4qoeiK2MvyitrTFhl2x9Icv/gZsG8tpie54rmEl7Ind64hJ3RqLrQ==", + "peerDependencies": { + "react-native": ">=0.60.0" + } + }, + "node_modules/@videosdk.live/react-native-sdk": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/@videosdk.live/react-native-sdk/-/react-native-sdk-0.1.12.tgz", + "integrity": "sha512-gEFaaZbEU3L0XC386FOUxEK/AZY+gdLdLNxJiNATHXxasH0HLRFJp/G6IT/WQRou78auGw2hcrCMlt5n27AiNg==", + "dependencies": { + "@videosdk.live/react-native-foreground-service": "0.0.3", + "@videosdk.live/react-native-incallmanager": "^0.1.3", + "@videosdk.live/react-native-webrtc": "0.0.11", + "@videosdk.live/react-sdk": "^0.1.91", + "axios": "^1.6.2" + }, + "peerDependencies": { + "@videosdk.live/react-native-foreground-service": "0.0.3", + "@videosdk.live/react-native-incallmanager": "^0.1.3", + "@videosdk.live/react-native-webrtc": "0.0.11", + "@videosdk.live/react-sdk": "^0.1.91" + } + }, + "node_modules/@videosdk.live/react-native-webrtc": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/@videosdk.live/react-native-webrtc/-/react-native-webrtc-0.0.11.tgz", + "integrity": "sha512-VzJ47aPfneXlCypVgI9jSiovIjDNN0z62OWrC/g+/GEl49Rc2Pu80rT7uRh9yZ6xHNj4OX45xvKwFmVDNYJMJw==", + "dependencies": { + "base64-js": "1.5.1", + "debug": "4.3.4", + "event-target-shim": "6.0.2" + }, + "peerDependencies": { + "react-native": ">=0.60.0" + } + }, + "node_modules/@videosdk.live/react-native-webrtc/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@videosdk.live/react-native-webrtc/node_modules/event-target-shim": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-6.0.2.tgz", + "integrity": "sha512-8q3LsZjRezbFZ2PN+uP+Q7pnHUMmAOziU2vA2OwoFaKIXxlxl38IylhSSgUorWu/rf4er67w0ikBqjBFk/pomA==", + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/@videosdk.live/react-sdk": { + "version": "0.1.94", + "resolved": "https://registry.npmjs.org/@videosdk.live/react-sdk/-/react-sdk-0.1.94.tgz", + "integrity": "sha512-aa4i0BBtOyVn91Djukt6y32acyjWac2i1CAb9eSpM4nXFSB7EDromM3Fy5PHbt7FXGw/Jv5vdxLlerAjMA7pBA==", + "dependencies": { + "@videosdk.live/js-sdk": "0.0.90", + "events": "^3.3.0" + }, + "peerDependencies": { + "react": "^16.13.1 || ^17 || ^18" + } + }, "node_modules/@web3-storage/multipart-parser": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@web3-storage/multipart-parser/-/multipart-parser-1.0.0.tgz", @@ -16753,6 +16870,14 @@ "node": ">=6" } }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "engines": { + "node": ">=0.8.x" + } + }, "node_modules/exec-async": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/exec-async/-/exec-async-2.2.0.tgz", @@ -16901,6 +17026,29 @@ "expo": "*" } }, + "node_modules/expo-build-properties": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/expo-build-properties/-/expo-build-properties-0.12.3.tgz", + "integrity": "sha512-ihMKJyCHnKaiadI56UFYp2IdTxUhYa7e0ekHDfT+T3H2fk3jDYfh3n3wlUxFVeGyT7BE78tBTQ7QhMT6lluX2A==", + "dependencies": { + "ajv": "^8.11.0", + "semver": "^7.6.0" + }, + "peerDependencies": { + "expo": "*" + } + }, + "node_modules/expo-build-properties/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/expo-camera": { "version": "15.0.14", "resolved": "https://registry.npmjs.org/expo-camera/-/expo-camera-15.0.14.tgz", @@ -34053,10 +34201,9 @@ } }, "node_modules/stream-chat": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/stream-chat/-/stream-chat-8.31.0.tgz", - "integrity": "sha512-lORUtfDYljoAgRv7QHUADH1QTGydSWo+U8KmUKwv7BZyUZ2JGwh6VZbu9WL4Nmo7PDU7N/Ug0Q5PE59S6WE+OA==", - "license": "SEE LICENSE IN LICENSE", + "version": "8.37.0", + "resolved": "https://registry.npmjs.org/stream-chat/-/stream-chat-8.37.0.tgz", + "integrity": "sha512-62JkhFwauZK/xWydCOu4J+Z4FxaFoCT1MWNI9VQ0dQbbmZb+JoS0dCCl5Nh4LkfsT9Ddo/sFcC31SN/g0e5IJw==", "dependencies": { "@babel/runtime": "^7.16.3", "@types/jsonwebtoken": "~9.0.0", @@ -34140,6 +34287,14 @@ } } }, + "node_modules/stream-chat-react-native-core/node_modules/@types/ws": { + "version": "7.4.7", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", + "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/stream-chat-react-native-core/node_modules/dayjs": { "version": "1.10.5", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.5.tgz", @@ -34158,6 +34313,45 @@ "react-native": "*" } }, + "node_modules/stream-chat-react-native-core/node_modules/stream-chat": { + "version": "8.31.0", + "resolved": "https://registry.npmjs.org/stream-chat/-/stream-chat-8.31.0.tgz", + "integrity": "sha512-lORUtfDYljoAgRv7QHUADH1QTGydSWo+U8KmUKwv7BZyUZ2JGwh6VZbu9WL4Nmo7PDU7N/Ug0Q5PE59S6WE+OA==", + "dependencies": { + "@babel/runtime": "^7.16.3", + "@types/jsonwebtoken": "~9.0.0", + "@types/ws": "^7.4.0", + "axios": "^1.6.0", + "base64-js": "^1.5.1", + "form-data": "^4.0.0", + "isomorphic-ws": "^4.0.1", + "jsonwebtoken": "~9.0.0", + "ws": "^7.4.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/stream-chat-react-native-core/node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/stream-chat/node_modules/@types/ws": { "version": "7.4.7", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", diff --git a/package.json b/package.json index 72bc22fd..60d8049f 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "dependencies": { "@commitlint/cli": "^19.3.0", "@commitlint/config-conventional": "^19.2.2", + "@config-plugins/react-native-webrtc": "^9.0.0", "@expo/metro-runtime": "~3.2.1", "@expo/ngrok": "^4.1.3", "@expo/vector-icons": "^14.0.2", @@ -35,6 +36,11 @@ "@simform_solutions/react-native-audio-waveform": "^1.0.1", "@stream-io/flat-list-mvcp": "^0.10.3", "@supabase/supabase-js": "^2.43.4", + "@videosdk.live/expo-config-plugin": "^0.0.2", + "@videosdk.live/react-native-foreground-service": "^0.0.3", + "@videosdk.live/react-native-incallmanager": "^0.1.3", + "@videosdk.live/react-native-sdk": "^0.1.12", + "@videosdk.live/react-native-webrtc": "^0.0.11", "buffer": "^6.0.3", "countries-list": "^3.1.0", "dotenv": "^16.4.5", @@ -104,6 +110,7 @@ "run": "^1.5.0", "sdk": "^0.5.0", "start": "^5.1.0", + "stream-chat": "^8.37.0", "stream-chat-expo": "^5.33.0", "uuid": "^10.0.0", "vector-icons": "^0.1.0"