diff --git a/app/Appointments/voice-call/writeReview.tsx b/app/Appointments/voice-call/writeReview.tsx index 1539b5dd..4d606fad 100644 --- a/app/Appointments/voice-call/writeReview.tsx +++ b/app/Appointments/voice-call/writeReview.tsx @@ -1,8 +1,9 @@ import React, { useState, useEffect } from "react"; import { View, Text, TouchableOpacity, Image, TextInput, StyleSheet, Modal, ScrollView, SafeAreaView, Pressable } from "react-native"; -import { router } from "expo-router"; +import { router, useLocalSearchParams } from "expo-router"; import { useFonts } from 'expo-font'; import FiveStarRating from "../doctorcard/star"; +import { supabase } from "@/app/supabase"; interface CustomCheckBoxProps { selected: boolean; @@ -21,12 +22,9 @@ export default function Writereview() { const [isModalVisible, setIsModalVisible] = useState(false); const [isoption, setIsoption] = useState(""); const [text, setText] = useState(''); - const [fontLoaded] = useFonts({ - 'UrbanistBold': require('../../../assets/fonts/Urbanist-Bold.ttf'), - 'UrbanistRegular': require("../../../assets/fonts/Urbanist-Regular.ttf"), - 'Urbanist-SemiBold': require("../../../assets/fonts/Urbanist-SemiBold.ttf"), - 'UrbanistMedium': require("../../../assets/fonts/Urbanist-Medium.ttf") - }); + const [name, setName]=useState(""); + const [image, setImage]=useState(""); + const {appointmentId}=useLocalSearchParams(); const handleChangeText = (value: string) => { setText(value); @@ -34,12 +32,20 @@ export default function Writereview() { const isSubmitEnabled = text.trim().length > 0 && isoption.length > 0; - if (!fontLoaded) { - return null; - } + const Options = ["Yes", "No"]; + useEffect(()=>{ + const fetchDoctor=async()=>{ + const {data, error}=await supabase.from("doctor").select("*").eq("id",appointmentId).single(); + if(data){ + setName(data.name); + console.log(data.name); + setImage(data.image) + } + if (error) throw error} + fetchDoctor()},[]) return ( <> Write a Review - + How was your experience - with Dr. Drake Boeson? + with {name}? @@ -92,7 +98,7 @@ export default function Writereview() { placeholder="Your review here..." style={styles.textInput} /> - Would you recommend Dr. Drake Boeson to your friends? + Would you recommend {name} to your friends? {Options.map((option, index) => ( @@ -184,4 +190,10 @@ const styles = StyleSheet.create({ width: '100%', minHeight: 100, }, + doctorImage: { + width: 120, + height: 120, + borderRadius: 60, + marginBottom: 10, + }, }); diff --git a/app/chat-history/VideoCall.tsx b/app/chat-history/VideoCall.tsx index bca03a5b..a8e720cc 100644 --- a/app/chat-history/VideoCall.tsx +++ b/app/chat-history/VideoCall.tsx @@ -1,64 +1,45 @@ -import React from "react"; +import React, {useState, useEffect} from "react"; import { View, ScrollView } from "react-native"; import DoctorVideo from "@/components/cards/DoctorVideo"; import { useRouter } from "expo-router"; -import { DoctorCard } from "./types"; // Import the types - +import { DoctorCard } from "./types"; +import { supabase } from "../supabase"; const VideoCall = () => { const router = useRouter(); + const [appointment, setAppointment]=useState([]); - const docCards: DoctorCard[] = [ - { - name: "Dr. Randy Wigham", - callDay: "Wednesday", - callTime: "1:00 PM", - images: require("../../assets/doctors/doc2.png"), - }, - { - name: "Dr. Jenny Watson", - callDay: "Wednesday", - callTime: "1:00 PM", - images: require("../../assets/doctors/doc3.png"), - }, - { - name: "Dr. Raul Zirkind", - callDay: "Wednesday", - callTime: "1:00 PM", - images: require("../../assets/doctors/doc1.png"), - }, - { - name: "Dr. Elijah Baranick", - callDay: "Wednesday", - callTime: "1:00 PM", - images: require("../../assets/doctors/doc2.png"), - }, - { - name: "Dr. Stephen Shute", - callDay: "Wednesday", - callTime: "1:00 PM", - images: require("../../assets/doctors/doc5.png"), - }, - ]; - - const handlePress = (doctor: DoctorCard) => { + useEffect(()=>{ + const fetchAppointments=async()=>{ + const {data, error}=await supabase.auth.getUser(); + if(error) throw error; + const userId=data?.user?.id; + const {data:AppointmentData, error:Error}=await supabase.from("appointment").select("*, doctor(name,image)").eq("patient_id", userId).eq("package","Video Call").eq("status", "Completed") + if(Error) throw Error + if(AppointmentData){ + setAppointment(AppointmentData); + } + } + fetchAppointments(); + },[]) + + const handlePress = (appointmentId:any) => { router.push({ pathname: "/chat-history/VideoRecord", - params: { doctor: JSON.stringify(doctor) }, + params: {appointmentId}, }); }; - return ( - {docCards.map((doctor, index) => ( + {appointment.map((appointments, index) => ( handlePress(doctor)} - doctorName={doctor.name} - doctorImage={doctor.images} - callType="Video Call" - callDay={doctor.callDay} - callTime={doctor.callTime} + onPress={() => handlePress(appointments.id)} + doctorName={appointments.doctor.name} + doctorImage={appointments.doctor.image} + callType={appointments.package} + callDay={appointments.appointment_date} + callTime={appointments.appointment_time.slice(0,5)} isVideoCallScreen={false} /> ))} diff --git a/app/chat-history/VideoRecord.tsx b/app/chat-history/VideoRecord.tsx index a11bc7ce..f6317a02 100644 --- a/app/chat-history/VideoRecord.tsx +++ b/app/chat-history/VideoRecord.tsx @@ -14,20 +14,22 @@ import PlayButton from "@/components/cards/PlayButton"; import { useRouter, useLocalSearchParams } from "expo-router"; import { SvgXml } from "react-native-svg"; import AsyncStorage from "@react-native-async-storage/async-storage"; - -import { DoctorCard } from "./types"; import { moreTransparent } from "@/assets/icons/more"; import { back } from "@/assets/icons/userprofile/icons"; +import { supabase } from "../supabase"; const VideoRecord: React.FC = () => { const router = useRouter(); - const { doctor: doctorString } = useLocalSearchParams(); - const doctor: DoctorCard = doctorString - ? JSON.parse(doctorString as string) - : null; - + + +const {appointmentId}=useLocalSearchParams(); const [modalVisible, setModalVisible] = useState(false); const [videoDuration, setVideoDuration] = useState(0); + const[ name, setName]=useState(""); + const[date, setDate]=useState(""); + const[time, setTime]=useState(""); + const[packageType, setPackage]=useState(""); + const[image, setImage]=useState(""); useEffect(() => { const fetchDuration = async () => { @@ -40,9 +42,7 @@ const VideoRecord: React.FC = () => { fetchDuration(); }, []); - if (!doctor) { - return null; - } + const handlePress = () => { router.push("/chat-history/PlayRecord"); @@ -64,7 +64,7 @@ const VideoRecord: React.FC = () => { setModalVisible(false); }; - const { name, images, callDay, callTime } = doctor; + const formatTime = (timeInSeconds: number) => { const hours = Math.floor(timeInSeconds / 3600); @@ -79,6 +79,21 @@ const VideoRecord: React.FC = () => { return `${minutes}:${String(seconds).padStart(2, "0")} minutes`; } }; + useEffect(()=>{ + const fetchAppointments=async()=>{ + const {data:AppointmentData, error:Error}=await supabase.from("appointment").select("*, doctor(name,image)").eq("id",appointmentId).single(); + if(Error) throw Error + if(AppointmentData){ + setName(AppointmentData.doctor.name); + setPackage(AppointmentData.package); + setImage(AppointmentData.doctor.image); + setTime(AppointmentData.appointment_time); + setDate(AppointmentData.appointment_date); + + } + } + fetchAppointments(); + },[appointmentId]) return ( @@ -89,12 +104,12 @@ const VideoRecord: React.FC = () => { - { + const [messages, setMessage]=useState([]); + const [userId, setUserId] = useState(""); + const [appointment, setAppointment]=useState([]); + const [selectedAppointmentId, setSelectedAppointmentId] = useState(null); + + const handleDocName = (doc: string, appointmentId: string) => { setDocname(doc); + setSelectedAppointmentId(appointmentId); setIsModalVisible(true); }; - const renderItems = ({ item }: { item: MessagesType }) => { + + useEffect(()=>{ +const fetchAppointments=async()=>{ +const {data, error}=await supabase.auth.getUser(); +if(error) throw error; +const userId=data?.user?.id; +setUserId(userId); +const {data:AppointmentData, error:Error}=await supabase.from("appointment").select("*, doctor(name,image)").eq("patient_id", userId).eq("package","Messaging") +if(Error) throw Error +if(AppointmentData){ +setAppointment(AppointmentData); +} +const{data:MessageData, error:MessageError}=await supabase.from("messages").select("*") +if(MessageData){ + setMessage(MessageData); +} +if(MessageError)throw MessageError; + +} +fetchAppointments(); + },[]) + + const handleDeleteMessages = async () => { + try { + const { error } = await supabase + .from("messages") + .delete() + .eq("appointment_id", selectedAppointmentId); + + if (error) { + console.error("Error deleting messages:", error); + Alert.alert("Delete Messages", "Failed to delete messages!"); + } else { + Alert.alert("Delete Messages", "Messages deleted successfully!"); + } + } catch (error) { + console.error("Error deleting messages:", error); + Alert.alert("Delete Messages", "Failed to delete messages!"); + } + }; + + const handleExportMessages = async () => { + try { + const { data, error } = await supabase + .from("messages") + .select("*") + .eq("appointment_id", selectedAppointmentId); + + if (error) { + console.error("Error exporting messages:", error); + Alert.alert("Export Messages", "Failed to export messages!"); + } else { + // Implement your logic to export data, e.g., create a CSV file + console.log("Exported messages:", data); + Alert.alert("Export Messages", "Messages exported successfully!"); + } + } catch (error) { + console.error("Error exporting messages:", error); + Alert.alert("Export Messages", "Failed to export messages!"); + } + }; + + const handleClearChat = async () => { + try { + await AsyncStorage.removeItem("chatMessages"); // Assuming messages are stored in AsyncStorage + Alert.alert("Clear Chat", "Chat cleared successfully!"); + } catch (error) { + console.error("Error clearing chat:", error); + Alert.alert("Clear Chat", "Failed to clear chat!"); + } + }; + + + + const renderHistory = (appointment: any, index:number) => { return ( - + - + handleDocName(item.name)} + onPress={() => handleDocName(appointment.doctor.name, appointment.id)} > - {item.name} + {appointment.doctor.name} - {item.message} + ... - {item.date} + {appointment.appointment_date} - {item.time} + {appointment.appointment_time.slice(0,5)} @@ -71,12 +154,12 @@ export default function Chathistory() { > - + Clear chat - + Export chat @@ -85,6 +168,7 @@ export default function Chathistory() { className="flex-row gap-2 pt-3" onPress={() => { setVisible(false); + handleDeleteMessages }} > @@ -124,58 +208,28 @@ export default function Chathistory() { - - - - - - - + {messages + .filter((message: any) => message.appointment_id === selectedAppointmentId) + .map((message: any, index: any) => ( + + ))} + + + + Session Ended + + + + - - - - - {/* - 16:03 PM - - */} @@ -249,16 +303,12 @@ export default function Chathistory() { - {selected === "Messages" && ( - + + {appointment.map((appointmentItem,index) => renderHistory(appointmentItem,index))} + )} - +{selected==="Calls"&&} {selected === "Videos" && } diff --git a/app/chat-history/singleCall.tsx b/app/chat-history/singleCall.tsx index 10cf37da..e9e68204 100644 --- a/app/chat-history/singleCall.tsx +++ b/app/chat-history/singleCall.tsx @@ -9,9 +9,10 @@ import { useCallback, useEffect, useRef, useState } from 'react'; import { play } from "@/assets/icons/playBtn"; import { download } from '@/assets/icons/download'; import { deleteRed } from '@/assets/icons/delete'; -import { router } from 'expo-router'; +import { router, useLocalSearchParams } from 'expo-router'; import { AVPlaybackSource, AVPlaybackStatus, AVPlaybackStatusSuccess, Audio } from "expo-av"; import { Sound } from 'expo-av/build/Audio'; +import { supabase } from '../supabase'; const { width } = Dimensions.get('window'); const WAVEFORM_ELEMENTS_COUNT = 50; @@ -23,18 +24,26 @@ export default function SingleCall() { const [duration, setDuration] = useState(1); const [sound, setSound] = useState(null); const progressAnim = useRef(new Animated.Value(0)).current; + const { appointmentId } = useLocalSearchParams(); const intervalRef = useRef(null); const [waveformHeights, setWaveformHeights] = useState([]); - + const [appointment, setAppointment] = useState([]); + const [name, setName] = useState(""); + const [date, setDate] = useState(""); + const [time, setTime] = useState(""); + const [packageType, setPackage] = useState(""); + const [image, setImage] = useState(""); const generateWaveformHeights = () => { + return Array.from({ length: WAVEFORM_ELEMENTS_COUNT }, () => Math.random() * 50 + 10); }; - const handleLoad= async()=>{ + const handleLoad = async () => { const { sound } = await Audio.Sound.createAsync(require('@/assets/Travis-Mafia.mp3')); + setSound(sound); await sound.loadAsync(require('@/assets/Travis-Mafia.mp3')); const status = await sound.getStatusAsync(); - if (status.isLoaded){ + if (status.isLoaded) { setDuration(status.durationMillis); } } @@ -80,12 +89,12 @@ export default function SingleCall() { const formatTime = (millis: number) => { const minutes = Math.floor(millis / 60 / 1000); - const seconds= Math.round(((millis/60/1000)-minutes)*60); - return seconds<10? `${minutes} minutes and 0${seconds} seconds`:`${minutes} minutes and ${seconds} seconds`;; + const seconds = Math.round(((millis / 60 / 1000) - minutes) * 60); + return seconds < 10 ? `${minutes} minutes and 0${seconds} seconds` : `${minutes} minutes and ${seconds} seconds`;; } - useEffect(()=>{ + useEffect(() => { handleLoad(); - },[]) + }, []) useEffect(() => { intervalRef.current = setInterval(() => { handleProgress(); @@ -111,6 +120,20 @@ export default function SingleCall() { setWaveformHeights(generateWaveformHeights()); }, [sound]); + useEffect(() => { + const fetchAppointments = async () => { + const { data: AppointmentData, error: Error } = await supabase.from("appointment").select("*, doctor(name,image)").eq("id", appointmentId).single() + if (AppointmentData) { + setName(AppointmentData.doctor.name); + setPackage(AppointmentData.package); + setImage(AppointmentData.doctor.image); + setTime(AppointmentData.appointment_time); + setDate(AppointmentData.appointment_date); + } + } + fetchAppointments(); + }, [appointmentId]) + return ( <> @@ -138,13 +161,12 @@ export default function SingleCall() { setVisible(!visible)} /> - @@ -160,13 +182,13 @@ export default function SingleCall() { {waveformHeights.map((height, index) => { const barWidth = width * 0.75 / WAVEFORM_ELEMENTS_COUNT; const barProgress = progressAnim.interpolate({ - inputRange: [0, (index ) / WAVEFORM_ELEMENTS_COUNT * width], + inputRange: [0, (index) / WAVEFORM_ELEMENTS_COUNT * width], outputRange: [0, 1], extrapolate: 'clamp', }); const backgroundColor = barProgress.interpolate({ inputRange: [0, 1], - outputRange: ['#E9F0FF','#246BFD'] + outputRange: ['#E9F0FF', '#246BFD'] }); return ( { +export default function VoiceCalls() { + const[appointment, setAppointment]=useState([]); + + useEffect(()=>{ + const fetchAppointments=async()=>{ + const {data, error}=await supabase.auth.getUser(); + if(error) throw error; + const userId=data?.user?.id; + const {data:AppointmentData, error:Error}=await supabase.from("appointment").select("*, doctor(name,image)").eq("patient_id", userId).eq("package","Voice Call").eq("status", "Completed") + if(Error) throw Error + if(AppointmentData){ + setAppointment(AppointmentData); + } + } + fetchAppointments(); + },[]) + const renderItems = (appointment: any, index:any) => { return ( <> router.push('chat-history/singleCall')} + key={index} + name={appointment.doctor.name} + type={appointment.package} + date={appointment.appointment_date} + time={appointment.appointment_time.slice(0,5)} + image={appointment.doctor.image} + onPress={()=>router.push({pathname:'chat-history/singleCall', params:{appointmentId:appointment.id}})} /> ) } - const image = require('@/assets/doctors/doc1.png'); return ( <> - + {appointment.map((appointmentItem,index) => renderItems(appointmentItem,index))} ) } \ No newline at end of file diff --git a/components/cards/DoctorVideo.tsx b/components/cards/DoctorVideo.tsx index 086bd55e..409257ef 100644 --- a/components/cards/DoctorVideo.tsx +++ b/components/cards/DoctorVideo.tsx @@ -23,7 +23,7 @@ export default function DoctorCard(props: DocCardProps) { - + {props.doctorName} diff --git a/components/chats/voiceCard.tsx b/components/chats/voiceCard.tsx index ad2fc2af..7f25a80f 100644 --- a/components/chats/voiceCard.tsx +++ b/components/chats/voiceCard.tsx @@ -1,5 +1,4 @@ import { leftArrowBlue, leftFilledArrowIcon } from "@/assets/icons/arrow"; -import { heart, heartFilledIcon } from "@/assets/icons/heart"; import { Image, ImageSourcePropType, @@ -16,7 +15,7 @@ export type CallsType = { time: string; date: string; icon?: any; - image: ImageSourcePropType; + image: any; onPress?: () => void; }; @@ -25,7 +24,7 @@ export default function CallsCard(props: CallsType) { - +