Skip to content

Commit

Permalink
Merge pull request #37 from untilhamza/release/v1.5.0
Browse files Browse the repository at this point in the history
Release/v1.5.0
  • Loading branch information
untilhamza authored Mar 12, 2023
2 parents 1222c8f + a1ac761 commit d48abe6
Show file tree
Hide file tree
Showing 5 changed files with 197 additions and 45 deletions.
171 changes: 164 additions & 7 deletions src/components/BookingForm/BookingForm.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import React from "react";
import { useEffect, useState } from "react";
import { Formik, ErrorMessage } from "formik";
import { useHistory } from "react-router-dom";
import * as yup from "yup";
import Swal from "sweetalert2";
import moment from "moment";
import { Form, Button } from "react-bootstrap";
import { DatePicker } from "antd";
import TimeSelector from "../TimeSelector/TimeSelector";
import { RecaptchaVerifier, signInWithPhoneNumber, signOut } from "firebase/auth";
import { auth } from "../../database/firebase-config";

import "./BookingForm.css";

// const phoneRegex = /^([+]?[\s0-9]+)?(\d{3}|[(]?[0-9]+[)])?([-]?[\s]?[0-9])+$/i;
const koreanPhoneRegex = /^(0|(\+82))((10\d{7,8})|(2\d{8}))$/;
const koreanPhoneRegex = /^((\+82))((10\d{7,8})|(2\d{8}))$/;

const schema = yup.object().shape({
name: yup.string().required("Name is required!"),
Expand All @@ -20,6 +23,73 @@ const schema = yup.object().shape({
});

const BookingForm = ({ onCancel, onConfirm, oldData, slots, onGetSlots, slotStatus, settings }) => {
const [phoneIsVerified, setPhoneIsVerified] = useState(false);
const [isVerifyingPhone, setIsVerifyingPhone] = useState(false);
const [phoneVerificationCode, setPhoneVerificationCode] = useState("");
const [isRecaptchaVerified, setIsRecaptchaVerified] = useState(null);
const [phoneVerificationError, setPhoneVerificationError] = useState("");
const [phoneConfirmationObject, setPhoneConfirmationObject] = useState(null);
const history = useHistory();

const handleConfirmButtonClick = () => {
if (!phoneIsVerified) {
Swal.fire({
icon: "info",
title: "Phone not verified!",
text: "Please verify your phone number before confirming your booking.",
});
return;
}
};

const handlePhoneVerification = async (phoneNumber) => {
if (!koreanPhoneRegex.test(phoneNumber)) {
setPhoneVerificationError("Please enter a valid Korean phone number.");
Swal.fire({
icon: "info",
title: "Invalid phone number!",
text: "Please enter a valid Korean phone number starting with +82.",
});
return;
}
setIsVerifyingPhone(true);
try {
const appVerifier = window.recaptchaVerifier;
const confirmationResult = await signInWithPhoneNumber(auth, phoneNumber, appVerifier);
// SMS sent. Prompt user to type the code from the message, then sign the
// user in with confirmationResult.confirm(code).
setPhoneConfirmationObject(confirmationResult);
} catch (err) {
history.go(0);
}
};

function handlePhoneCode(e) {
e.preventDefault();
if (!phoneConfirmationObject) {
history.go(0);
return;
}
phoneConfirmationObject
.confirm(phoneVerificationCode)
.then((result) => {
// User signed in successfully with their phone.
const user = result.user; //not an admin user
setPhoneIsVerified(true);
setIsVerifyingPhone(false);
})
.catch((error) => {
// User couldn't sign in (bad verification code?)
setPhoneIsVerified(false);
setIsVerifyingPhone(false);
Swal.fire({
icon: "info",
title: "Invalid verification code!",
text: "Please enter a valid verification code sent to your phone.",
});
});
}

function handleGetSlots(date) {
onGetSlots(date);
}
Expand All @@ -31,6 +101,46 @@ const BookingForm = ({ onCancel, onConfirm, oldData, slots, onGetSlots, slotStat
return submittedValue.valueOf() < moment().add(-1, "day") || submittedValue.valueOf() >= moment().add(31, "day");
};

useEffect(() => {
if (isRecaptchaVerified !== null && !isRecaptchaVerified) {
history.push("/");
return;
}
}, [isRecaptchaVerified]);

useEffect(() => {
try {
window.recaptchaVerifier = new RecaptchaVerifier(
"sign-in-button",
{
size: "invisible",
callback: (response) => {
setIsRecaptchaVerified(true);
// reCAPTCHA solved, allow signInWithPhoneNumber.
console.log("reCAPTCHA solved, allow signInWithPhoneNumber.");
//Now handlePhoneVerification(phoneNumber);
},
"expired-callback": () => {
setIsRecaptchaVerified(false);
console.log("reCAPTCHA expired");
history.go(0);
},
},
auth
);

window.recaptchaVerifier.render().then(function (widgetId) {
window.recaptchaWidgetId = widgetId;
});
} catch (e) {
console.log("recapture error", e);
}

return () => {
window.recaptchaVerifier.clear();
};
}, []);

return (
<Formik
validationSchema={schema}
Expand All @@ -41,7 +151,7 @@ const BookingForm = ({ onCancel, onConfirm, oldData, slots, onGetSlots, slotStat
}}
initialValues={{
name: "",
phone: "",
phone: "+82",
email: "",
date: moment(),
time: "",
Expand All @@ -51,7 +161,14 @@ const BookingForm = ({ onCancel, onConfirm, oldData, slots, onGetSlots, slotStat
<Form
noValidate
// validated={!errors}
onSubmit={handleSubmit}
onSubmit={(e) => {
e.preventDefault();
if (phoneIsVerified) {
handleSubmit();
signOut(auth);
} else {
}
}}
className="appointmentForm mx-auto p-3 "
>
<Form.Group className="mb-3">
Expand All @@ -64,10 +181,42 @@ const BookingForm = ({ onCancel, onConfirm, oldData, slots, onGetSlots, slotStat

<Form.Group className="mb-3">
<Form.Label className="fw-bold">Phone Number</Form.Label>
<Form.Control type="tel" name="phone" placeholder="Phone number" value={values.phone} onChange={handleChange} isValid={touched.phone && !errors.phone} />
<Form.Control
type="tel"
name="phone"
placeholder="Phone number"
value={values.phone}
onChange={(e) => {
// setPhoneNumber("01098999793");
handleChange(e);
}}
isValid={touched.phone && !errors.phone}
/>
<div className="text-danger font-italic">
<ErrorMessage name="phone" />
</div>
{!phoneIsVerified && !isVerifyingPhone && (
<Button
id="sign-in-button"
onClick={() => {
handlePhoneVerification(values.phone);
}}
variant="outline-primary"
className="mt-2 btn-sm"
>
Verify phone number!
</Button>
)}
{isVerifyingPhone && !phoneIsVerified && <p className="mb-0">Enter verification code on your phone</p>}
{phoneIsVerified && !isVerifyingPhone && <p className="text-success ">Your phone was verified successfully! </p>}
{isVerifyingPhone && (
<div className="d-flex justify-content-between">
<input className="form-control form-control-sm w-50" type="text" value={phoneVerificationCode} onChange={(e) => setPhoneVerificationCode(e.target.value)} />
<button className="btn btn-outline-primary btn-sm w-50 ms-2" onClick={(e) => handlePhoneCode(e)}>
Verify code
</button>
</div>
)}
</Form.Group>

<Form.Group className="mb-3">
Expand Down Expand Up @@ -122,7 +271,15 @@ const BookingForm = ({ onCancel, onConfirm, oldData, slots, onGetSlots, slotStat
</Form.Group>

<div className="d-flex justify-content-around p-2">
<Button variant="success" type="submit" className="w-100 me-1" disabled={false}>
<Button
variant="success"
type="submit"
className="w-100 me-1"
onClick={() => {
handleConfirmButtonClick();
}}
// disabled={!phoneIsVerified}
>
Confirm Booking
</Button>

Expand Down
16 changes: 9 additions & 7 deletions src/database/firebase-config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { initializeApp } from "firebase/app"
import { getFirestore } from "@firebase/firestore"
import { getAuth } from "firebase/auth"
import { initializeApp } from "firebase/app";
import { getFirestore } from "@firebase/firestore";
import { getAuth } from "firebase/auth";

const firebaseConfig = {
apiKey: process.env.REACT_APP_API_KEY,
Expand All @@ -10,12 +10,14 @@ const firebaseConfig = {
messagingSenderId: process.env.REACT_APP_MESSAGING_SENDER_ID,
appId: process.env.REACT_APP_APPID,
measurementId: process.env.REACT_APP_MEASUREMENT_ID,
}
};

// Initialize Firebase
const app = initializeApp(firebaseConfig)
const app = initializeApp(firebaseConfig);

//get authetication service from the app and use it else where
export const auth = getAuth(app)
export const auth = getAuth(app);

export const db = getFirestore(app)
auth.languageCode = "en-US";

export const db = getFirestore(app);
30 changes: 15 additions & 15 deletions src/pages/NewBooking.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,21 @@ const NewBooking = () => {
sendRequest(bookingData);
}

useEffect(() => {
Swal.fire({
title: `Welcome! Incase there are no
slots`,
html: `<p>Please contact the owner on WhatsApp (+82 10-9539-9012) and he will help you make an appointment.</p> <a aria-label="Chat on WhatsApp" href="https://wa.me/821095399012">
<img alt="Chat on WhatsApp" src="assets/images/whatsapp/WhatsAppButtonGreenLarge.svg" />
</a>`,
icon: `info`,
iconHtml: `<span>&#128522;</span>`,
confirmButtonText: "Okay",
customClass: {
icon: "no-border",
},
});
}, []);
// useEffect(() => {
// Swal.fire({
// title: `Welcome! Incase there are no
// slots`,
// html: `<p>Please contact the owner on WhatsApp (+82 10-9539-9012) and he will help you make an appointment.</p> <a aria-label="Chat on WhatsApp" href="https://wa.me/821095399012">
// <img alt="Chat on WhatsApp" src="assets/images/whatsapp/WhatsAppButtonGreenLarge.svg" />
// </a>`,
// icon: `info`,
// iconHtml: `<span>&#128522;</span>`,
// confirmButtonText: "Okay",
// customClass: {
// icon: "no-border",
// },
// });
// }, []);

useEffect(() => {
//TODO: fetch for the date today or the provided date when modifying date
Expand Down
23 changes: 8 additions & 15 deletions src/store/auth-context.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,7 @@ const AuthContext = React.createContext({
});

export const AuthContextProvider = (props) => {
const [user, setUser] = useState({});
// const {
// status: getSettingsStatus,
// data: settings,
// error: getSettingsErrorMessage,
// sendRequest: getSettings,
// } = useHttp(httpGetSettings)

// useEffect(() => {
// //fetch the settings
// getSettings()
// }, [])
const [user, setUser] = useState(null);

const handleLogout = async () => {
try {
Expand Down Expand Up @@ -54,9 +43,13 @@ export const AuthContextProvider = (props) => {
};

onAuthStateChanged(auth, (currentUser) => {
//console.log("checking auth state");
setUser(currentUser);
//console.log(currentUser);
//TODO: admins should be put in firebase table not here
const ADMINS = ["Nwzxrf32Uee9i6hbTXSN2mWVzlC2", "lHxJifUfgHhJkECibwAudvf3MGp1", "lru8dL4JVWTycq0LHhHgyaWqX133"];
if (currentUser && ADMINS.includes(currentUser.uid)) {
setUser(currentUser);
} else {
setUser(null);
}
});
const contextValue = {
name: user?.displayname,
Expand Down
2 changes: 1 addition & 1 deletion version.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"version": "1.4.1"
"version": "1.5.0"
}

0 comments on commit d48abe6

Please sign in to comment.