diff --git a/.env b/.env new file mode 100644 index 00000000..1869deb4 --- /dev/null +++ b/.env @@ -0,0 +1,8 @@ + +VITE_APP_API_URL= https://aptest.mysalona.ir + +VITE_APP_SITE_URL= https://app.mysalona.ir + +VITE_CARD_API_URL= https://cardtest.mysalona.ir + +VITE_VAPID_PUBLIC_KEY= BH7oB1WAQjCJwjMYmb7sB0GkDrcP4T92J2sM12EL1jwGIcF3Hr315g3Bpwxn7iarBnUp6zUwN4OnnHB18Q2Gj0o diff --git a/src/components/OTPForm.tsx b/src/components/OTPForm.tsx index f06b32ed..b68c7de6 100644 --- a/src/components/OTPForm.tsx +++ b/src/components/OTPForm.tsx @@ -1,28 +1,29 @@ -import { useSearchParams } from 'react-router-dom'; -import { Button } from '@/components/ui/button'; -import { Card, CardContent, CardHeader } from '@/components/ui/card'; -import { useEffect, useRef, useState } from 'react'; -import { REGEXP_ONLY_DIGITS } from 'input-otp'; -import toast from 'react-hot-toast'; -import { RotateCcw } from 'lucide-react'; -import useAutofillSMS from '@/hooks/useAutofillSMS'; -import { numberOnInputHandler } from '@/utils/fa-to-en-numbers'; -import { UseMutateFunction } from '@tanstack/react-query'; -import { AxiosResponse } from 'axios'; -import { ILoginForm, IOTPForm } from '@/apps/appointment/utils/types'; +import { useSearchParams } from "react-router-dom"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent, CardHeader } from "@/components/ui/card"; +import { useEffect, useRef, useState } from "react"; +import { REGEXP_ONLY_DIGITS } from "input-otp"; +import toast from "react-hot-toast"; +import { RotateCcw } from "lucide-react"; +import useAutofillSMS from "@/hooks/useAutofillSMS"; +import { numberOnInputHandler } from "@/utils/fa-to-en-numbers"; +import { UseMutateFunction } from "@tanstack/react-query"; +import { AxiosResponse } from "axios"; +import { ILoginForm, IOTPForm } from "@/apps/appointment/utils/types"; import { InputOTP, InputOTPGroup, InputOTPSlot, -} from '@/components/ui/input-otp'; +} from "@/components/ui/input-otp"; const formatTime = (seconds: number) => { const minutes = Math.floor(seconds / 60); const remainingSeconds = seconds % 60; - return `${String(minutes).padStart(2, '0')}:${String( - remainingSeconds, - ).padStart(2, '0')}`; + return `${String(minutes).padStart(2, "0")}:${String( + remainingSeconds + ).padStart(2, "0")}`; }; + const remainedTo90Sec = (startTime?: string): number => { if (!startTime) return 0; const startDate = new Date(startTime); @@ -44,10 +45,10 @@ const OTPForm = ({ isResendLoading: boolean; }) => { const [searchParams, setSearchParams] = useSearchParams(); - const mobile = searchParams.get('mobile') ?? ''; - const [OTP, setOTP] = useState(''); + const mobile = searchParams.get("mobile") ?? ""; + const [OTP, setOTP] = useState(""); const [OTPReqDateTime, setOTPReqDateTime] = useState( - new Date().toISOString(), + new Date().toISOString() ); useAutofillSMS(setOTP); const [timer, setTimer] = useState(90); @@ -56,11 +57,12 @@ const OTPForm = ({ const confirmOTPHandler = (e: React.FormEvent) => { e.preventDefault(); if (OTP.length !== 6) { - toast.error('مقادیر وارد شده صحیح نیست.'); + toast.error("مقادیر وارد شده صحیح نیست."); return; } onConfirm({ phone_number: mobile, otp_code: OTP }); }; + const resendOTPHandler = () => { if (timer > 0) return; onResend( @@ -72,14 +74,16 @@ const OTPForm = ({ setOTPReqDateTime(new Date().toISOString()); } }, - }, + } ); }; + const editMobileHandler = () => { const newSearchParams = new URLSearchParams(searchParams); - newSearchParams.delete('mobile'); + newSearchParams.delete("mobile"); setSearchParams(newSearchParams); }; + useEffect(() => { if (OTPReqDateTime) { const remained = remainedTo90Sec(OTPReqDateTime); @@ -91,9 +95,11 @@ const OTPForm = ({ } } }, [OTPReqDateTime]); + useEffect(() => { if (timer <= 0) clearInterval(timerTimeoutRef.current); }, [timer]); + useEffect(() => { return () => { clearInterval(timerTimeoutRef.current); @@ -101,8 +107,14 @@ const OTPForm = ({ }, []); return ( - - + +
{" "} + + {" "}

کد تایید به شماره موبایل {mobile} ارسال شد.

@@ -113,68 +125,69 @@ const OTPForm = ({ ویرایش شماره موبایل
- -
-
- - - - - - - - - - + + {" "} + +
+
+ + + {[...Array(6)].map((_, index) => ( + + ))} + + +
+
+ {timer > 0 && ( +

+ {formatTime(timer)} +

+ )} + +
-
- {timer > 0 && ( -

- {formatTime(timer)} -

- )} + +
+ {" "} +
- diff --git a/src/pages/question/index.tsx b/src/pages/question/index.tsx new file mode 100644 index 00000000..e0796d0b --- /dev/null +++ b/src/pages/question/index.tsx @@ -0,0 +1,155 @@ +import { Button } from "@/components/ui/button"; +import { Card, CardContent } from "@/components/ui/card"; +import { useGetQuestions } from "@/services/Account"; +import { useState } from "react"; +import { useNavigate } from "react-router-dom"; +import WavesSVG from "@/components/WavesSVG"; + +const QuestionsForm = () => { + const q = useGetQuestions(); + const questionArray = q.data?.questions ?? []; + const [currentStep, setCurrentStep] = useState(0); + const [answers, setAnswers] = useState<{ [questionId: number]: string }>({}); + const navigate = useNavigate(); + + const currentQuestion = questionArray[currentStep]; + const selectedAnswer = answers[currentQuestion?.question_id] || ""; + + const handleOptionSelect = (value: string) => { + setAnswers({ + ...answers, + [currentQuestion.question_id]: value, + }); + }; + + const handleNext = () => { + if (currentStep < questionArray.length - 1) { + setCurrentStep(currentStep + 1); + } else { + console.log("Answers:", answers); + navigate("/"); //route home page + } + }; + + return ( + +
+ + +
+ {currentQuestion ? ( +
+

+ {currentQuestion.question_text} +

+
    + {currentQuestion.options.map((option, index) => ( +
  • + +
  • + ))} +
+
+ ) : ( +

+ در حال بارگذاری سوالات... +

+ )} + + +
+
+ + + ); +}; + +export default QuestionsForm; + +// =====================old code================================= +// =====================without step================================= + +// import { Button } from "@/components/ui/button"; +// import { Card, CardContent } from "@/components/ui/card"; +// import { useGetQuestions } from "@/services/Account"; +// import { useState } from "react"; +// import WavesSVG from "@/components/WavesSVG"; + +// const QuestionsForm = () => { +// const q = useGetQuestions(); +// const questionArray = q.data?.questions ?? []; +// const [isContinue, setIsContinue] = useState(true); + +// return ( +// +//
+ +// +//
+//
+// {questionArray.length > 0 ? ( +// questionArray.map((question) => ( +//
+//

+// {question.question_text} +//

+//
    +// {question.options.map((option, index) => ( +//
  • +// {option} +//
  • +// ))} +//
+//
+// )) +// ) : ( +//

+// در حال بارگذاری سوالات... +//

+// )} +//
+ +// +//
+//
+// +// +// ); +// }; + +// export default QuestionsForm; diff --git a/src/pages/register/+components/registerForm.tsx b/src/pages/register/+components/registerForm.tsx index 9382e2c8..55af438b 100644 --- a/src/pages/register/+components/registerForm.tsx +++ b/src/pages/register/+components/registerForm.tsx @@ -1,32 +1,30 @@ -import { useRef, useState } from 'react'; -import { Link, useSearchParams } from 'react-router-dom'; -import { Button } from '@/components/ui/button'; +import { useRef, useState } from "react"; +import { Link, useSearchParams } from "react-router-dom"; +import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, -} from '@/components/ui/card'; -import { Input } from '@/components/ui/input'; -import ROUTES_OBJECT from '@/routes/RoutesObject'; -import { useForm } from 'react-hook-form'; -import toast from 'react-hot-toast'; -import WavesSVG from '@/components/WavesSVG'; -import { ContactIcon} from 'lucide-react'; -import { useGenerateRegisterOTP, useRegisterUser } from '@/services/Account'; -import { numberOnInputHandler } from '@/utils/fa-to-en-numbers'; -import { MOBILE_REGEX_PATTERN } from '@/utils/constants'; -import Captcha from '@/components/Captcha'; -import { validateCaptcha } from 'react-simple-captcha'; - -const RegisterForm = () => -{ +} from "@/components/ui/card"; +import { Input } from "@/components/ui/input"; +import ROUTES_OBJECT from "@/routes/RoutesObject"; +import { useForm } from "react-hook-form"; +import toast from "react-hot-toast"; +import WavesSVG from "@/components/WavesSVG"; +import { ContactIcon } from "lucide-react"; +import { useGenerateRegisterOTP, useRegisterUser } from "@/services/Account"; +import { numberOnInputHandler } from "@/utils/fa-to-en-numbers"; +import { MOBILE_REGEX_PATTERN } from "@/utils/constants"; +import Captcha from "@/components/Captcha"; +import { validateCaptcha } from "react-simple-captcha"; +const RegisterForm = () => { const [searchParams, setSearchParams] = useSearchParams(); - const ref = searchParams.get('ref') ?? ''; + const ref = searchParams.get("ref") ?? ""; const [showReferralInput, setShowReferralInput] = useState(!!ref); - const [captchaValue, setCaptchaValue] = useState(''); + const [captchaValue, setCaptchaValue] = useState(""); const captchaInputRef = useRef(null); const { register, @@ -38,8 +36,8 @@ const RegisterForm = () => referral_code: string; }>({ defaultValues: { - name: '', - mobile: '', + name: "", + mobile: "", referral_code: ref, }, }); @@ -51,14 +49,14 @@ const RegisterForm = () => if (!captchaValue) { if (captchaInputRef.current) captchaInputRef.current.focus(); return toast.error( - 'تکمیل کپچا برای جلوگیری از ورود ربات ها ضروری میباشد.', + "تکمیل کپچا برای جلوگیری از ورود ربات ها ضروری میباشد." ); } const isValidCaptcha = validateCaptcha(captchaValue); if (!isValidCaptcha) { - setCaptchaValue(''); + setCaptchaValue(""); return toast.error( - 'مقادیر وارد شده برای کپچا اشتباه است. لطفا ورودی های خود را مجددا بررسی نمایید.', + "مقادیر وارد شده برای کپچا اشتباه است. لطفا ورودی های خود را مجددا بررسی نمایید." ); } registerUser( @@ -71,7 +69,7 @@ const RegisterForm = () => onSuccess: (response) => { if (response.status >= 200 && response.status < 300) { toast.success( - response.data.message ?? 'ثبت نام با موفقیت انجام شد', + response.data.message ?? "ثبت نام با موفقیت انجام شد" ); generateRegisterOTP( { phone_number: data.mobile }, @@ -79,24 +77,29 @@ const RegisterForm = () => onSuccess: (response) => { if (response.status >= 200 && response.status < 300) { toast.success( - `کد احراز هویت به شماره ${data.mobile} ارسال شد.`, + `کد احراز هویت به شماره ${data.mobile} ارسال شد.` ); setSearchParams({ mobile: data.mobile }); } }, - }, + } ); } }, - }, + } ); }); return ( + {/* + > */}
@@ -104,17 +107,17 @@ const RegisterForm = () => خوش آمدید - +
id="mobile" // type="number" inputMode="tel" - {...register('mobile', { + {...register("mobile", { required: true, pattern: MOBILE_REGEX_PATTERN, })} @@ -141,14 +144,14 @@ const RegisterForm = () => />