Skip to content

Commit f8316e9

Browse files
mr3nz1Irirwanirira
authored andcommitted
fix: fixed popup errors on app startup, and in profile section
*ft(booking):add FlutteWave payment method *ft: allow user to end chats and leave a review *ft: patient notification context *feature: populate initial notifications and add new ones upon being added to the db *ft: fetched notifications and reworked on the notifications screen and notification Listing component *fix: device notification on notification creation *rf: refactored some erros *ft(notifications):add logic to insert notifications on every key action *ft(notifications):add logic to insert notifications on every booking
1 parent ca4e979 commit f8316e9

27 files changed

+3093
-1208
lines changed

Diff for: app/(app)/ActionMenu/AllDoctorScreen.tsx

+289-273
Large diffs are not rendered by default.

Diff for: app/(app)/ActionMenu/Booking/EnterYourPin.tsx

+33-11
Original file line numberDiff line numberDiff line change
@@ -22,26 +22,51 @@ import { supabase } from "@/lib/supabase";
2222
export default function EnterYourPin() {
2323
const [isDark, setIsDark] = useState(false);
2424
const modal = useModal();
25-
const {doctor_id,hour,date,packageTitle,packagePrice,problem,user_id,patient_id,duration} = useLocalSearchParams()
25+
const {
26+
doctor_id,
27+
hour,
28+
date,
29+
packageTitle,
30+
packagePrice,
31+
problem,
32+
user_id,
33+
patient_id,
34+
duration,
35+
} = useLocalSearchParams();
2636

2737
const { theme, changeTheme } = useContext(ThemeContext);
2838
async function bookAppointment() {
2939
const { error } = await supabase
30-
.from('appointment')
31-
.insert({ doctor_id: doctor_id, time:hour,date:date, package: packageTitle, price: packagePrice, illness_descr: problem,user_id:patient_id,duration:duration});
40+
.from("appointment")
41+
.insert({
42+
doctor_id: doctor_id,
43+
time: hour,
44+
date: date,
45+
package: packageTitle,
46+
price: packagePrice,
47+
illness_descr: problem,
48+
user_id: patient_id,
49+
duration: duration,
50+
});
3251
if (error) {
3352
console.error("Error booking appointment:", error);
3453
}
3554
}
36-
console.log("this is from lastpage",doctor_id,hour,packageTitle,packagePrice,problem)
55+
console.log(
56+
"this is from lastpage",
57+
doctor_id,
58+
hour,
59+
packageTitle,
60+
packagePrice,
61+
problem
62+
);
3763

3864
function successBooking() {
39-
router.push("ActionMenu");;
65+
router.push("ActionMenu");
4066
modal.hide();
4167
}
4268
async function handlePIN() {
43-
44-
await bookAppointment()
69+
await bookAppointment();
4570
modal.show({
4671
children: (
4772
<View
@@ -96,10 +121,7 @@ export default function EnterYourPin() {
96121
justifyContent: "center",
97122
}}
98123
></View>
99-
<Button
100-
title="View Appointment"
101-
onPress={successBooking}
102-
/>
124+
<Button title="View Appointment" onPress={successBooking} />
103125
<TouchableOpacity
104126
onPress={() => {
105127
router.push("ActionMenu");

Diff for: app/(app)/ActionMenu/Booking/SelectPayment.tsx

+123-79
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Colors } from "@/constants/Colors";
22
import { StatusBar } from "expo-status-bar";
3-
import { useContext, useState } from "react";
4-
import { ScrollView,TouchableOpacity,View,Image } from "react-native";
3+
import { useContext, useState } from "react";
4+
import { ScrollView, TouchableOpacity, View, Image } from "react-native";
55
import { Text } from "react-native";
66
import { ThemeContext } from "@/ctx/ThemeContext";
77
import Typography from "@/constants/Typography";
@@ -12,76 +12,118 @@ import PaymentChooseContainer from "@/components/UI/PaymentChooseContainer/Index
1212
import { router } from "expo-router";
1313
import React from "react";
1414
import { useLocalSearchParams } from "expo-router";
15-
import { PayWithFlutterwave } from 'flutterwave-react-native'
15+
import { PayWithFlutterwave } from "flutterwave-react-native";
1616
import { supabase } from "@/lib/supabase";
1717
import { useModal } from "@/ctx/ModalContext";
1818
export default function SelectPayment() {
1919
const { theme, changeTheme } = useContext(ThemeContext);
2020
const [selected, setSelected] = useState(false);
21-
const [loggedEmail,setLoggedEmail]=useState<string>("")
22-
const { doctor_id, hour, date, packageTitle, packagePrice, problem, user_id, patient_id, duration } = useLocalSearchParams()
21+
const [loggedEmail, setLoggedEmail] = useState<string>("");
22+
const {
23+
doctor_id,
24+
hour,
25+
date,
26+
packageTitle,
27+
packagePrice,
28+
problem,
29+
user_id,
30+
patient_id,
31+
duration,
32+
} = useLocalSearchParams();
33+
34+
const modal = useModal();
35+
const flutterKey = process.env.EXPO_PUBLIC_FLUTTERWAVE_KEY ?? "";
36+
console.log("this is packageprice from slect Payment:", packagePrice);
2337

24-
const modal = useModal()
25-
const flutterKey = process.env.EXPO_PUBLIC_FLUTTERWAVE_KEY ?? ""
26-
2738
interface RedirectParams {
28-
status: "successful" | "cancelled";
29-
transaction_id?: string;
30-
tx_ref: string;
39+
status: "successful" | "cancelled";
40+
transaction_id?: string;
41+
tx_ref: string;
3142
}
32-
let num:number=1;
43+
let num: number = 1;
3344
if (duration === "30 minutes") {
34-
num=1
45+
num = 1;
3546
} else {
36-
num=2
47+
num = 2;
3748
}
3849
let price: number = 0;
3950
if (packagePrice === "Rwf20") {
40-
price=20
51+
price = 20;
4152
} else if (packagePrice === "Rwf40") {
42-
price=40
53+
price = 40;
4354
} else if (packagePrice === "Rwf60") {
44-
price =60
55+
price = 60;
4556
}
46-
const total:number=price*num
47-
57+
const total: number = price * num;
58+
4859
useEffect(() => {
4960
const fetchUser = async () => {
50-
51-
const { data: { user },error } = await supabase.auth.getUser()
61+
const {
62+
data: { user },
63+
error,
64+
} = await supabase.auth.getUser();
5265
if (error) {
53-
console.error("error fetching user")
66+
console.error("error fetching user");
5467
} else {
55-
setLoggedEmail(user?.email||"logged Email")
68+
setLoggedEmail(user?.email || "logged Email");
5669
}
57-
}
58-
fetchUser()
59-
60-
}, [loggedEmail])
70+
};
71+
fetchUser();
72+
}, [loggedEmail]);
6173
async function bookAppointment() {
6274
try {
63-
const { error } = await supabase
64-
.from('appointment')
65-
.insert({
75+
const { error } = await supabase.from("appointment").insert({
6676
doctor_id: doctor_id,
67-
time: hour, date: date,
77+
time: hour,
78+
date: date,
6879
package: packageTitle,
6980
price: packagePrice,
7081
illness_descr: problem,
7182
user_id: patient_id,
72-
duration: duration
83+
duration: duration,
7384
});
7485
} catch (error) {
75-
console.log("Error while inserting data in booking ",error)
76-
}
77-
86+
console.log("Error while inserting data in booking ", error);
87+
}
7888
}
89+
const addNotification = async (doctorName: string) => {
90+
try {
91+
const { error } = await supabase.from("notifications").insert({
92+
title: "Appointment Booked",
93+
description: `You have successfully booked an appointment with Dr. ${doctorName}`,
94+
patient_id: patient_id,
95+
type: "appointment_booked",
96+
doctor_id: doctor_id,
97+
viewed: false,
98+
});
99+
console.log("Notification will be pushed");
100+
if (error) {
101+
console.log("Error while inserting notification ", error);
102+
}
103+
} catch (error) {
104+
console.log("Error while inserting notification ", error);
105+
}
106+
};
107+
const fetchDoctorName = async (doctorId: string) => {
108+
const { data, error } = await supabase
109+
.from("doctors")
110+
.select("first_name")
111+
.eq("id", doctorId)
112+
.single();
113+
114+
if (error) {
115+
console.log("Error fetching doctor's name: ", error);
116+
return "";
117+
}
118+
119+
return data.first_name;
120+
};
79121
function successBooking() {
80-
router.push("ActionMenu");;
122+
router.push("ActionMenu");
81123
modal.hide();
82124
}
83125
const showSuccefulModal = () => {
84-
modal.show({
126+
modal.show({
85127
children: (
86128
<View
87129
style={{
@@ -135,13 +177,7 @@ const total:number=price*num
135177
justifyContent: "center",
136178
}}
137179
></View>
138-
<Button
139-
title="View Appointment"
140-
onPress={()=> {
141-
successBooking()
142-
router.push("(app)/Appointments")
143-
}}
144-
/>
180+
<Button title="View Appointment" onPress={successBooking} />
145181
<TouchableOpacity
146182
onPress={() => {
147183
router.push("ActionMenu");
@@ -173,29 +209,31 @@ const total:number=price*num
173209
</View>
174210
),
175211
});
176-
}
177-
const handleOnRedirect = (data: RedirectParams) => {
178-
179-
console.log("redire data:", data)
212+
};
213+
const handleOnRedirect = async (data: RedirectParams) => {
180214
if (data.status === "successful") {
181-
bookAppointment()
182-
showSuccefulModal()
215+
bookAppointment();
216+
if (typeof doctor_id === "string") {
217+
const doctorName = await fetchDoctorName(doctor_id);
218+
await addNotification(doctorName);
219+
}
220+
showSuccefulModal();
183221
} else {
184-
alert("Payment Failed or cancelled ,please try again")
222+
alert("Payment Failed or cancelled ,please try again");
185223
}
186-
}
224+
};
187225
const generateRef = (length: number): string => {
188-
const characters = flutterKey;
189-
const charactersArray = characters.split('');
190-
let result = '';
226+
const characters = flutterKey;
227+
const charactersArray = characters.split("");
228+
let result = "";
191229

192-
for (let i = 0; i < length; i++) {
193-
const randomIndex = Math.floor(Math.random() * charactersArray.length);
194-
result += charactersArray[randomIndex];
195-
}
230+
for (let i = 0; i < length; i++) {
231+
const randomIndex = Math.floor(Math.random() * charactersArray.length);
232+
result += charactersArray[randomIndex];
233+
}
196234

197-
return result;
198-
};
235+
return result;
236+
};
199237

200238
return (
201239
<>
@@ -222,25 +260,31 @@ const total:number=price*num
222260
>
223261
Comfirm the payment by click the button below.
224262
</Text>
225-
<View style={{width:"100%",height:"70%",display:"flex",flexDirection:"row",alignItems:"center",justifyContent:"center"}}>
226-
<PayWithFlutterwave
227-
onRedirect={handleOnRedirect}
228-
options={{
229-
tx_ref: generateRef(11),
230-
authorization: 'FLWPUBK_TEST-3c390392d62e44fc5788cb0859823f05-X',
231-
customer: {
232-
email: loggedEmail
233-
},
234-
amount: total,
235-
currency: 'RWF',
236-
payment_options: 'card'
237-
}}
238-
/>
239-
263+
<View
264+
style={{
265+
width: "100%",
266+
height: "70%",
267+
display: "flex",
268+
flexDirection: "row",
269+
alignItems: "center",
270+
justifyContent: "center",
271+
}}
272+
>
273+
<PayWithFlutterwave
274+
onRedirect={handleOnRedirect}
275+
options={{
276+
tx_ref: generateRef(11),
277+
authorization: "FLWPUBK_TEST-3c390392d62e44fc5788cb0859823f05-X",
278+
customer: {
279+
email: loggedEmail,
280+
},
281+
amount: total,
282+
currency: "RWF",
283+
payment_options: "card",
284+
}}
285+
/>
240286
</View>
241-
242-
243287
</ScrollView>
244288
</>
245289
);
246-
}
290+
}

Diff for: app/(app)/ActionMenu/Booking/SelectPaymentFlutter.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,11 @@ class MyCart extends React.Component<{}, MyCartState> {
4646
this.abortController.signal
4747
);
4848
// use payment link
49+
4950
this.usePaymentLink(paymentLink);
5051
} catch (error: any) {
5152
// do nothing if our payment initialization was aborted
52-
if (error.code === 'ABORTERROR') {
53+
if (error.code === "ABORTERROR") {
5354
return;
5455
}
5556
// handle other errors

Diff for: app/(app)/ActionMenu/Booking/_layout.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,10 @@ export default function BookingLayout() {
5353
name="SelectPayment"
5454
options={{ header: () => <Header title="Payments" /> }}
5555
/>
56-
{/* <Stack.Screen
56+
<Stack.Screen
5757
name="SelectPaymentFlutter"
5858
options={{ header: () => <Header title="Payments" /> }}
59-
/> */}
59+
/>
6060
</Stack>
6161
</>
6262
);

0 commit comments

Comments
 (0)