Skip to content

Commit c3f985d

Browse files
authored
Merge pull request #207 from atlp-rwanda/ft-refine-bookAppointment
Refine Appointment Booking: Add Form Validation and Duration-Based Amount Calculation
2 parents 722b69a + 4a428be commit c3f985d

13 files changed

+197
-151
lines changed

app/(app)/ActionMenu/AllDoctorScreen.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { blueheart } from '@/assets/icons/blueHeart';
1111
import { star } from '@/assets/icons/star';
1212
import { search } from '@/assets/icons/search';
1313
import { more } from '@/assets/icons/more';
14-
import { leftArrow } from '@/assets/icons/left';
14+
import { LightleftArrow } from '@/assets/icons/left';
1515
import HeaderComponent from '@/components/HeaderComponent';
1616
import SearchComponent from '@/components/SearchComponent';
1717
import FoundDoctorCount from '@/components/FoundDoctorCount';

app/(app)/ActionMenu/Booking/BookingAppointment.tsx

+16-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, { useContext, useEffect, useState } from "react";
2-
import { Text, View, StyleSheet, ScrollView } from "react-native";
2+
import { Text, View, StyleSheet, ScrollView,Alert } from "react-native";
33
import { Colors } from "@/constants/Colors";
44
import { router } from "expo-router";
55
import { ThemeContext } from "@/ctx/ThemeContext";
@@ -17,9 +17,10 @@ export default function BookingAppointment() {
1717
const [timeSlots, setTimeSlots] = useState([""]);
1818
const [selectedDate, setSelectedDate] = useState("");
1919
const [selectedHour, setSelectedHour] = useState("");
20+
const [errorMessage,setErrorMessage]=useState<string>("")
2021
const { id } = useLocalSearchParams()
2122

22-
console.log("this is id from BookAppointment:", id)
23+
2324

2425
const generateTimeSlots = () => {
2526
let times = [];
@@ -40,8 +41,18 @@ export default function BookingAppointment() {
4041
generateTimeSlots();
4142
}, []);
4243

43-
console.log("this is slected hour:", selectedHour)
44-
console.log("this is selected date:",selectedDate)
44+
45+
const handleNextPress = () => {
46+
if (!selectedHour || !selectedDate) {
47+
Alert.alert("Please select both date and an hour")
48+
return;
49+
}
50+
setErrorMessage("")
51+
router.push({
52+
pathname: "(app)/ActionMenu/Booking/Select-package",
53+
params: { Doctor_id: id, hour: selectedHour, date: selectedDate },
54+
});
55+
}
4556

4657
return (
4758
<ScrollView
@@ -106,9 +117,7 @@ export default function BookingAppointment() {
106117
>
107118
<Button
108119
title="Next"
109-
onPress={() => {
110-
router.push({ pathname:"(app)/ActionMenu/Booking/Select-package",params:{Doctor_id:id,hour:selectedHour,date:selectedDate}});
111-
}}
120+
onPress={handleNextPress}
112121
/>
113122
</View>
114123
</ScrollView>

app/(app)/ActionMenu/Booking/EnterYourPin.tsx

+4-8
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,21 @@ import { supabase } from "@/lib/supabase";
2323
export default function EnterYourPin() {
2424
const [isDark, setIsDark] = useState(false);
2525
const modal = useModal();
26-
const {doctor_id,hour,date,packageTitle,packagePrice,problem,user_id,patient_id} = useLocalSearchParams()
26+
const {doctor_id,hour,date,packageTitle,packagePrice,problem,user_id,patient_id,duration} = useLocalSearchParams()
2727

2828
const { theme, changeTheme } = useContext(ThemeContext);
2929
async function bookAppointment() {
3030
const { error } = await supabase
3131
.from('appointment')
32-
.insert({ doctor_id: doctor_id, time:hour,date:date, package: packageTitle, price: packagePrice, illness_descr: problem,user_id:patient_id});
32+
.insert({ doctor_id: doctor_id, time:hour,date:date, package: packageTitle, price: packagePrice, illness_descr: problem,user_id:patient_id,duration:duration});
3333
if (error) {
3434
console.error("Error booking appointment:", error);
3535
}
3636
}
3737
console.log("this is from lastpage",doctor_id,hour,packageTitle,packagePrice,problem)
3838

3939
function successBooking() {
40-
router.push("(app)/Appointments/index");
40+
router.push("ActionMenu");;
4141
modal.hide();
4242
}
4343
async function handlePIN() {
@@ -99,11 +99,7 @@ export default function EnterYourPin() {
9999
></View>
100100
<Button
101101
title="View Appointment"
102-
onPress={() => {
103-
router.push("(app)/Appointments");
104-
modal.hide();
105-
106-
}}
102+
onPress={successBooking}
107103
/>
108104
<TouchableOpacity
109105
onPress={() => {

app/(app)/ActionMenu/Booking/Patient-details.tsx

+50-27
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
TouchableOpacity,
1212
Pressable,
1313
ScrollView,
14+
Alert
1415
} from "react-native";
1516
import Icon from "react-native-vector-icons/FontAwesome";
1617
import { ThemeContext } from "@/ctx/ThemeContext";
@@ -28,10 +29,12 @@ const PatientDetails = () => {
2829
const [text, setText] = useState("");
2930
const [height, setHeight] = useState(40);
3031
const { theme, changeTheme } = useContext(ThemeContext);
31-
const {Doctor_id,hour,date,packageTitle,packagePrice} = useLocalSearchParams()
32+
const {Doctor_id,hour,date,packageTitle,packagePrice,duration} = useLocalSearchParams()
3233
const [loggeduser, setLoggedUser] = useState<string>()
3334
const [profile, setProfile] = useState<any>(null)
34-
const [patient_id,setPatient_id]=useState<string>()
35+
const [patient_id, setPatient_id] = useState<string>()
36+
const [selectedGender, setSelectedGender] = useState<string>()
37+
const [selectedAge,setSelectedAge]=useState<string>("")
3538

3639
useEffect(() => {
3740
const fetchUser = async () => {
@@ -59,7 +62,15 @@ const PatientDetails = () => {
5962
} else {
6063
setProfile(data)
6164
setPatient_id(data.id)
62-
console.log(data)
65+
if (!data.age && data.date_of_birth) {
66+
const age = calculateAge(data.date_of_birth)
67+
setProfile((prevProfile:Date) => ({
68+
...prevProfile,
69+
age:age
70+
}))
71+
setSelectedAge(age.toString() || '')
72+
}
73+
6374

6475
}
6576

@@ -68,11 +79,35 @@ const PatientDetails = () => {
6879
}
6980
fetchUserProfile()
7081
}, [loggeduser])
71-
console.log("this is profile:",profile)
72-
console.log("this is logged user:", loggeduser)
73-
console.log("this is patient_id:",patient_id)
82+
83+
84+
const calculateAge = (dob: string) => {
85+
const birthDate = new Date(dob);
86+
const today = new Date();
87+
const age = today.getFullYear() - birthDate.getFullYear();
88+
const monthDifference = today.getMonth() - birthDate.getMonth();
89+
if (monthDifference < 0 || (monthDifference === 0 && today.getDate() < birthDate.getDate())) {
90+
return age - 1;
91+
}
92+
return age;
93+
};
94+
7495
const handleInputChange = (name: string, value: string) => {
7596
setProfile({ ...profile, [name]: value });
97+
};
98+
99+
100+
const handleNextPress = () => {
101+
if (!text) {
102+
Alert.alert("Please select all required data")
103+
104+
return;
105+
}
106+
107+
router.push({
108+
pathname: "/(app)/ActionMenu/Booking/SelectPayment",
109+
params:{doctor_id:Doctor_id,hour:hour,date:date,packageTitle:packageTitle,packagePrice:packagePrice,problem:text,user_id:loggeduser,patient_id:patient_id,duration:duration},
110+
});
76111
}
77112

78113
return (
@@ -121,14 +156,8 @@ const PatientDetails = () => {
121156
>
122157
Gender
123158
</Text>
124-
<DropDown
125-
data={[
126-
{ value: `${profile?.gender}`, label:`${profile?.gender} ` },
127-
{ value: "Male", label: "Male" },
128-
{ value: "Female", label: "Female" },
129-
]}
130-
defaultvalue={profile?.Gender}
131-
/>
159+
<Input onChange={handleInputChange} placeholder="Gender" value={`${profile?.gender}`} />
160+
132161
</View>
133162

134163
<View style={{ flexDirection: "column", gap: 10 }}>
@@ -145,15 +174,8 @@ const PatientDetails = () => {
145174
>
146175
Your Age
147176
</Text>
148-
<DropDown
149-
data={[
150-
{ value: `${profile?.age} Years`, label:`${profile?.age} Years` },
151-
{ value: "27 years", label: "27 years" },
152-
{ value: "28 years", label: "28 years" },
153-
154-
]}
155-
defaultvalue={profile?.age}
156-
/>
177+
<Input onChange={value => handleInputChange('age', value)} placeholder="Age" value={selectedAge} />
178+
157179
</View>
158180

159181
<View style={{ flexDirection: "column", gap: 10 }}>
@@ -170,7 +192,7 @@ const PatientDetails = () => {
170192
>
171193
Write Your Problem
172194
</Text>
173-
{/* <Input placeholder="Describe how you are feeling here ..." /> */}
195+
174196
<TextArea text={text} onChangeText={setText} />
175197
</View>
176198

@@ -182,9 +204,10 @@ const PatientDetails = () => {
182204
>
183205
<Button
184206
title="Next"
185-
onPress={() => {
186-
router.push({ pathname: "/(app)/ActionMenu/Booking/SelectPayment",params:{doctor_id:Doctor_id,hour:hour,date:date,packageTitle:packageTitle,packagePrice:packagePrice,problem:text,user_id:loggeduser,patient_id:patient_id} });
187-
}}
207+
onPress={handleNextPress}
208+
// onPress={() => {
209+
// router.push({ pathname: "/(app)/ActionMenu/Booking/SelectPayment",params:{doctor_id:Doctor_id,hour:hour,date:date,packageTitle:packageTitle,packagePrice:packagePrice,problem:text,user_id:loggeduser,patient_id:patient_id,duration:duration} });
210+
// }}
188211
/>
189212
</View>
190213
</ScrollView>

app/(app)/ActionMenu/Booking/Select-package.tsx

+21-6
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
Image,
1212
TouchableOpacity,
1313
ScrollView,
14+
Alert
1415
} from "react-native";
1516
import Icon from "react-native-vector-icons/FontAwesome";
1617
import { ThemeContext } from "@/ctx/ThemeContext";
@@ -33,8 +34,20 @@ import { StatusBar } from "expo-status-bar";
3334
const SelectPackage = () => {
3435
const { theme, changeTheme } = useContext(ThemeContext);
3536
const { Doctor_id, hour, date,patient_id } = useLocalSearchParams()
36-
const [selectedPackageTitle, setSelectedPackageTitle] = useState<{ title: string, price: string }>({title:"",price:""})
37-
console.log("this is new:",Doctor_id,hour,date)
37+
const [selectedPackageTitle, setSelectedPackageTitle] = useState<{ title: string, price: string }>({ title: "Messaging", price: "$20" })
38+
const [selectedDuration, setSelectedDuration] = useState<string>("1 hour")
39+
console.log("this is new:", Doctor_id, hour, date)
40+
const handleNextPress = () => {
41+
if (!selectedPackageTitle||!selectedDuration) {
42+
Alert.alert("Please select both Duration and package")
43+
return;
44+
}
45+
46+
router.push({
47+
pathname: "ActionMenu/Booking/Patient-details",
48+
params:{ Doctor_id:Doctor_id,hour:hour,date:date,packageTitle:selectedPackageTitle.title,packagePrice:selectedPackageTitle.price,patient_id:patient_id,duration: selectedDuration,},
49+
});
50+
}
3851

3952
const packages = [
4053
{
@@ -59,7 +72,8 @@ const SelectPackage = () => {
5972
icon: () => <SvgXml xml={videoIcon} />,
6073
},
6174
];
62-
75+
76+
6377
return (
6478
<>
6579
<StatusBar style={theme === "light" ? "dark" : "light"} />
@@ -88,12 +102,13 @@ const SelectPackage = () => {
88102
</Text>
89103
<DropDown
90104
data={[
91-
{ label: "1 hour", value: "30" },
105+
{ label: "1 hour", value: "1 hour" },
92106
{ label: "30 minutes", value: "30 minutes" },
93107
]}
94108
leftIcon={() => (
95109
<SvgXml xml={theme === "light" ? clockIcon : lightClockIcon} />
96110
)}
111+
onSelect={(value) => setSelectedDuration(value)}
97112
/>
98113
</View>
99114

@@ -129,8 +144,8 @@ const SelectPackage = () => {
129144
}}
130145
>
131146
<Button
132-
title="Next"
133-
onPress={() => router.push({ pathname:"ActionMenu/Booking/Patient-details",params:{ Doctor_id:Doctor_id,hour:hour,date:date,packageTitle:selectedPackageTitle.title,packagePrice:selectedPackageTitle.price,patient_id:patient_id}})}
147+
title="Next"
148+
onPress={handleNextPress}
134149
/>
135150
</View>
136151
</ScrollView>

app/(app)/ActionMenu/Booking/SelectPayment.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import { useLocalSearchParams } from "expo-router";
1515
export default function SelectPayment() {
1616
const { theme, changeTheme } = useContext(ThemeContext);
1717
const [selected, setSelected] = useState(false);
18-
const {doctor_id,hour,date,packageTitle,packagePrice,problem,user_id,patient_id}=useLocalSearchParams()
18+
const {doctor_id,hour,date,packageTitle,packagePrice,problem,user_id,patient_id,duration}=useLocalSearchParams()
1919

2020
return (
2121
<>
@@ -53,7 +53,7 @@ const {doctor_id,hour,date,packageTitle,packagePrice,problem,user_id,patient_id}
5353
<Button
5454
title="Next"
5555
onPress={() => {
56-
router.push({ pathname: "(app)/ActionMenu/Booking/reviewSummary",params: {doctor_id:doctor_id,hour:hour,date:date,packageTitle:packageTitle,packagePrice:packagePrice,problem:problem,user_id:user_id,patient_id:patient_id}});
56+
router.push({ pathname: "(app)/ActionMenu/Booking/reviewSummary",params: {doctor_id:doctor_id,hour:hour,date:date,packageTitle:packageTitle,packagePrice:packagePrice,problem:problem,user_id:user_id,patient_id:patient_id,duration:duration}});
5757
}}
5858
style={{ marginTop: "auto" }}
5959
/>

0 commit comments

Comments
 (0)