work on car code
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
"use client";
|
||||
|
||||
import {Box, Slide} from "@mui/material";
|
||||
import {useState} from "react";
|
||||
import CarCode from "@/core/components/CarCode";
|
||||
|
||||
const PatrolDetail = ({tabState, setTabState}) => {
|
||||
const [patrolFounded, setPatrolFounded] = useState(false);
|
||||
const [carCode, setCarCode] = useState(null);
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
my: 3
|
||||
}}
|
||||
>
|
||||
<Box>
|
||||
<CarCode carCode={carCode} setCarCode={setCarCode}/>
|
||||
</Box>
|
||||
<Slide in={patrolFounded} sx={{my: 5, width: {xs: "100%", sm: "70%"}}}>
|
||||
<Box>
|
||||
</Box>
|
||||
</Slide>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default PatrolDetail;
|
||||
@@ -10,6 +10,7 @@ import HandymanIcon from '@mui/icons-material/Handyman';
|
||||
import VerifiedIcon from '@mui/icons-material/Verified';
|
||||
import PatrolTimeLine from "./PatrolTimeLine";
|
||||
import PhoneValidation from "./PhoneValidation";
|
||||
import PatrolDetail from "./PatrolDetail";
|
||||
|
||||
function TabPanel(props) {
|
||||
const {children, value, index} = props;
|
||||
@@ -53,10 +54,10 @@ const PatrolForms = () => {
|
||||
<DialogContent dividers sx={{display: "flex"}}>
|
||||
<Box sx={{flex: 1}}>
|
||||
<TabPanel value={tabState} index={0}>
|
||||
<PhoneValidation/>
|
||||
<PhoneValidation tabState={tabState} setTabState={setTabState}/>
|
||||
</TabPanel>
|
||||
<TabPanel value={tabState} index={1}>
|
||||
<>moshakhasat gasht</>
|
||||
<PatrolDetail/>
|
||||
</TabPanel>
|
||||
<TabPanel value={tabState} index={2}>
|
||||
<>moshakhasat rahdar</>
|
||||
|
||||
@@ -5,15 +5,18 @@ import React, {useEffect, useState} from "react";
|
||||
import ForwardToInboxIcon from '@mui/icons-material/ForwardToInbox';
|
||||
import QrCodeIcon from '@mui/icons-material/QrCode';
|
||||
import useRequest from "@/lib/hooks/useRequest";
|
||||
import {GET_OTP_TOKEN} from "@/core/utils/routes";
|
||||
import {GET_OTP_TOKEN, VERIFY_OTP} from "@/core/utils/routes";
|
||||
import {formatCounter} from "@/core/utils/formatCounter";
|
||||
|
||||
const PhoneValidation = () => {
|
||||
const PhoneValidation = ({tabState, setTabState}) => {
|
||||
const requestServer = useRequest({auth: true});
|
||||
const [phoneNumber, setPhoneNumber] = useState("");
|
||||
const [verificationCode, setVerificationCode] = useState("");
|
||||
const [validPhone, setValidPhone] = useState(false);
|
||||
const [delayPerRequest, setDelayPerRequest] = useState(false);
|
||||
const [counter, setCounter] = useState(120);
|
||||
const [otpSended, setOtpSended] = useState(false);
|
||||
const [readyToVerify, setReadyToVerify] = useState(false);
|
||||
|
||||
const handleNumericInput = (e) => {
|
||||
e.target.value = e.target.value.replace(/[^0-9]/g, '');
|
||||
@@ -21,18 +24,22 @@ const PhoneValidation = () => {
|
||||
|
||||
useEffect(() => {
|
||||
if (phoneNumber.length === 11) {
|
||||
setValidPhone(true)
|
||||
setValidPhone(true);
|
||||
} else {
|
||||
setValidPhone(false)
|
||||
setValidPhone(false);
|
||||
}
|
||||
}, [phoneNumber]);
|
||||
if (verificationCode.length === 6 && phoneNumber.length === 11) {
|
||||
setReadyToVerify(true);
|
||||
} else {
|
||||
setReadyToVerify(false);
|
||||
}
|
||||
}, [phoneNumber, verificationCode]);
|
||||
|
||||
useEffect(() => {
|
||||
if (counter === 0) {
|
||||
setDelayPerRequest(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (delayPerRequest && counter > 0) {
|
||||
const timer = setInterval(() => {
|
||||
setCounter(prevCounter => prevCounter - 1);
|
||||
@@ -55,12 +62,23 @@ const PhoneValidation = () => {
|
||||
setDelayPerRequest(true);
|
||||
};
|
||||
|
||||
// Format counter as MM:SS
|
||||
const formatCounter = (counter) => {
|
||||
const minutes = Math.floor(counter / 60).toString().padStart(2, '0');
|
||||
const seconds = (counter % 60).toString().padStart(2, '0');
|
||||
return `${minutes}:${seconds}`;
|
||||
};
|
||||
const phoneRegister = () => {
|
||||
const formData = new FormData();
|
||||
formData.append("phone_number", phoneNumber);
|
||||
formData.append("verification_code", verificationCode);
|
||||
|
||||
for (var pair of formData.entries()) {
|
||||
console.log(pair[0] + ', ' + pair[1]);
|
||||
}
|
||||
setTabState(tabState + 1)
|
||||
requestServer(VERIFY_OTP, "post", {
|
||||
data: formData,
|
||||
})
|
||||
.then(() => {
|
||||
})
|
||||
.catch(() => {
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<Box sx={{
|
||||
@@ -106,8 +124,10 @@ const PhoneValidation = () => {
|
||||
autoComplete="off"
|
||||
size="small"
|
||||
fullWidth
|
||||
type="text"
|
||||
value={verificationCode}
|
||||
onChange={(e) => setVerificationCode(e.target.value)}
|
||||
onInput={handleNumericInput}
|
||||
type="text"
|
||||
inputProps={{
|
||||
maxLength: 6,
|
||||
inputMode: "numeric",
|
||||
@@ -118,7 +138,8 @@ const PhoneValidation = () => {
|
||||
}}
|
||||
/>
|
||||
</FormControl>
|
||||
<Button fullWidth variant="contained" endIcon={<QrCodeIcon/>} sx={{mt: 2}}>
|
||||
<Button onClick={phoneRegister} disabled={!readyToVerify} fullWidth variant="contained"
|
||||
endIcon={<QrCodeIcon/>} sx={{mt: 2}}>
|
||||
بررسی کد و رفتن به مرحله بعد
|
||||
</Button>
|
||||
</Box>
|
||||
|
||||
86
src/core/components/CarCode.jsx
Normal file
86
src/core/components/CarCode.jsx
Normal file
@@ -0,0 +1,86 @@
|
||||
"use client";
|
||||
|
||||
import {Autocomplete, CircularProgress, TextField} from "@mui/material";
|
||||
import {useEffect, useState} from "react";
|
||||
import useRequest from "@/lib/hooks/useRequest";
|
||||
import {debounce} from "@mui/material/utils";
|
||||
|
||||
const CarCode = ({carCode, setCarCode}) => {
|
||||
const [inputValue, setInputValue] = useState('');
|
||||
const [options, setOptions] = useState([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const requestServer = useRequest();
|
||||
|
||||
const fetchCarCodes = (inputValue, controller) => {
|
||||
const debouncer = debounce((query) => {
|
||||
if (query.length < 2) {
|
||||
setOptions([]);
|
||||
return;
|
||||
}
|
||||
setLoading(true);
|
||||
requestServer(`car-code/api?${query}`, "get", {
|
||||
requestOptions: {signal: controller.signal}
|
||||
})
|
||||
.then((response) => {
|
||||
setOptions(response || []);
|
||||
})
|
||||
.catch(() => {
|
||||
setOptions([]);
|
||||
})
|
||||
.finally(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
}, 500)
|
||||
debouncer(inputValue)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const controller = new AbortController();
|
||||
fetchCarCodes(inputValue, controller);
|
||||
return () => controller.abort();
|
||||
}, [inputValue]);
|
||||
|
||||
return (
|
||||
<Autocomplete
|
||||
value={carCode}
|
||||
size="small"
|
||||
onChange={(event, newValue) => {
|
||||
setCarCode(newValue);
|
||||
}}
|
||||
inputValue={inputValue}
|
||||
onInputChange={(event, newInputValue) => {
|
||||
setInputValue(newInputValue);
|
||||
}}
|
||||
options={options}
|
||||
getOptionLabel={(option) =>
|
||||
typeof option === 'string' ? option : option.name || option.code
|
||||
}
|
||||
loading={loading}
|
||||
loadingText="درحال جستجوی کد خودرو"
|
||||
noOptionsText={
|
||||
inputValue.length < 2
|
||||
? "حداقل دو رقم از کد خودرو را وارد کنید"
|
||||
: "کد خودرویی یافت نشد"
|
||||
}
|
||||
sx={{width: 300}}
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
{...params}
|
||||
label="کد خودرو"
|
||||
fullWidth
|
||||
InputProps={{
|
||||
...params.InputProps,
|
||||
endAdornment: (
|
||||
<>
|
||||
{loading ? <CircularProgress size="25px" color="inherit"/> : null}
|
||||
{params.InputProps.endAdornment}
|
||||
</>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default CarCode;
|
||||
5
src/core/utils/formatCounter.js
Normal file
5
src/core/utils/formatCounter.js
Normal file
@@ -0,0 +1,5 @@
|
||||
export const formatCounter = (counter) => {
|
||||
const minutes = Math.floor(counter / 60).toString().padStart(2, '0');
|
||||
const seconds = (counter % 60).toString().padStart(2, '0');
|
||||
return `${minutes}:${seconds}`;
|
||||
};
|
||||
@@ -31,4 +31,7 @@ export const GET_OPERATOR_LIST = "/v3/api/fake-operator-list";
|
||||
export const EXPORT_OPERATOR_LIST = "https://rms.rmto.ir/v2/road_patrols/operator/cartable/report";
|
||||
export const GET_SUPERVISOR_LIST = "/v3/api/fake-supervisor-list";
|
||||
export const EXPORT_SUPERVISOR_LIST = "https://rms.rmto.ir/v2/road_patrols/supervisor/cartable/report";
|
||||
|
||||
////**** mohammad check here ****////
|
||||
export const GET_OTP_TOKEN = "https://rms.rmto.ir/v2/get_otp_token";
|
||||
export const VERIFY_OTP = "https://rms.rmto.ir/v2/verify_otp";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { errorResponse } from "@/core/utils/errorResponse";
|
||||
import { successRequest } from "@/core/utils/successRequest";
|
||||
import {errorResponse} from "@/core/utils/errorResponse";
|
||||
import {successRequest} from "@/core/utils/successRequest";
|
||||
import axios from "axios";
|
||||
import { useAuth } from "../contexts/auth";
|
||||
import {useAuth} from "../contexts/auth";
|
||||
|
||||
const defaultOptions = {
|
||||
data: {},
|
||||
@@ -16,13 +16,12 @@ const defaultOptions = {
|
||||
};
|
||||
|
||||
const useRequest = (initOptions) => {
|
||||
const { logout } = useAuth();
|
||||
const {logout} = useAuth();
|
||||
|
||||
const _options = Object.assign({}, defaultOptions, initOptions);
|
||||
|
||||
return async (url = "", method = "get", options) => {
|
||||
const mergedOptions = Object.assign({}, _options, options);
|
||||
|
||||
try {
|
||||
const response = await axios({
|
||||
url,
|
||||
|
||||
Reference in New Issue
Block a user