work on car code

This commit is contained in:
2024-12-18 11:34:21 +03:30
parent 9fccf770d5
commit aedeb62849
7 changed files with 168 additions and 21 deletions

View File

@@ -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;

View File

@@ -10,6 +10,7 @@ import HandymanIcon from '@mui/icons-material/Handyman';
import VerifiedIcon from '@mui/icons-material/Verified'; import VerifiedIcon from '@mui/icons-material/Verified';
import PatrolTimeLine from "./PatrolTimeLine"; import PatrolTimeLine from "./PatrolTimeLine";
import PhoneValidation from "./PhoneValidation"; import PhoneValidation from "./PhoneValidation";
import PatrolDetail from "./PatrolDetail";
function TabPanel(props) { function TabPanel(props) {
const {children, value, index} = props; const {children, value, index} = props;
@@ -53,10 +54,10 @@ const PatrolForms = () => {
<DialogContent dividers sx={{display: "flex"}}> <DialogContent dividers sx={{display: "flex"}}>
<Box sx={{flex: 1}}> <Box sx={{flex: 1}}>
<TabPanel value={tabState} index={0}> <TabPanel value={tabState} index={0}>
<PhoneValidation/> <PhoneValidation tabState={tabState} setTabState={setTabState}/>
</TabPanel> </TabPanel>
<TabPanel value={tabState} index={1}> <TabPanel value={tabState} index={1}>
<>moshakhasat gasht</> <PatrolDetail/>
</TabPanel> </TabPanel>
<TabPanel value={tabState} index={2}> <TabPanel value={tabState} index={2}>
<>moshakhasat rahdar</> <>moshakhasat rahdar</>

View File

@@ -5,15 +5,18 @@ import React, {useEffect, useState} from "react";
import ForwardToInboxIcon from '@mui/icons-material/ForwardToInbox'; import ForwardToInboxIcon from '@mui/icons-material/ForwardToInbox';
import QrCodeIcon from '@mui/icons-material/QrCode'; import QrCodeIcon from '@mui/icons-material/QrCode';
import useRequest from "@/lib/hooks/useRequest"; 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 requestServer = useRequest({auth: true});
const [phoneNumber, setPhoneNumber] = useState(""); const [phoneNumber, setPhoneNumber] = useState("");
const [verificationCode, setVerificationCode] = useState("");
const [validPhone, setValidPhone] = useState(false); const [validPhone, setValidPhone] = useState(false);
const [delayPerRequest, setDelayPerRequest] = useState(false); const [delayPerRequest, setDelayPerRequest] = useState(false);
const [counter, setCounter] = useState(120); const [counter, setCounter] = useState(120);
const [otpSended, setOtpSended] = useState(false); const [otpSended, setOtpSended] = useState(false);
const [readyToVerify, setReadyToVerify] = useState(false);
const handleNumericInput = (e) => { const handleNumericInput = (e) => {
e.target.value = e.target.value.replace(/[^0-9]/g, ''); e.target.value = e.target.value.replace(/[^0-9]/g, '');
@@ -21,18 +24,22 @@ const PhoneValidation = () => {
useEffect(() => { useEffect(() => {
if (phoneNumber.length === 11) { if (phoneNumber.length === 11) {
setValidPhone(true) setValidPhone(true);
} else { } else {
setValidPhone(false) setValidPhone(false);
} }
}, [phoneNumber]); if (verificationCode.length === 6 && phoneNumber.length === 11) {
setReadyToVerify(true);
} else {
setReadyToVerify(false);
}
}, [phoneNumber, verificationCode]);
useEffect(() => { useEffect(() => {
if (counter === 0) { if (counter === 0) {
setDelayPerRequest(false); setDelayPerRequest(false);
return; return;
} }
if (delayPerRequest && counter > 0) { if (delayPerRequest && counter > 0) {
const timer = setInterval(() => { const timer = setInterval(() => {
setCounter(prevCounter => prevCounter - 1); setCounter(prevCounter => prevCounter - 1);
@@ -55,12 +62,23 @@ const PhoneValidation = () => {
setDelayPerRequest(true); setDelayPerRequest(true);
}; };
// Format counter as MM:SS const phoneRegister = () => {
const formatCounter = (counter) => { const formData = new FormData();
const minutes = Math.floor(counter / 60).toString().padStart(2, '0'); formData.append("phone_number", phoneNumber);
const seconds = (counter % 60).toString().padStart(2, '0'); formData.append("verification_code", verificationCode);
return `${minutes}:${seconds}`;
}; for (var pair of formData.entries()) {
console.log(pair[0] + ', ' + pair[1]);
}
setTabState(tabState + 1)
requestServer(VERIFY_OTP, "post", {
data: formData,
})
.then(() => {
})
.catch(() => {
});
}
return ( return (
<Box sx={{ <Box sx={{
@@ -106,8 +124,10 @@ const PhoneValidation = () => {
autoComplete="off" autoComplete="off"
size="small" size="small"
fullWidth fullWidth
type="text" value={verificationCode}
onChange={(e) => setVerificationCode(e.target.value)}
onInput={handleNumericInput} onInput={handleNumericInput}
type="text"
inputProps={{ inputProps={{
maxLength: 6, maxLength: 6,
inputMode: "numeric", inputMode: "numeric",
@@ -118,7 +138,8 @@ const PhoneValidation = () => {
}} }}
/> />
</FormControl> </FormControl>
<Button fullWidth variant="contained" endIcon={<QrCodeIcon/>} sx={{mt: 2}}> <Button onClick={phoneRegister} disabled={!readyToVerify} fullWidth variant="contained"
endIcon={<QrCodeIcon/>} sx={{mt: 2}}>
بررسی کد و رفتن به مرحله بعد بررسی کد و رفتن به مرحله بعد
</Button> </Button>
</Box> </Box>

View 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;

View 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}`;
};

View File

@@ -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 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 GET_SUPERVISOR_LIST = "/v3/api/fake-supervisor-list";
export const EXPORT_SUPERVISOR_LIST = "https://rms.rmto.ir/v2/road_patrols/supervisor/cartable/report"; 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 GET_OTP_TOKEN = "https://rms.rmto.ir/v2/get_otp_token";
export const VERIFY_OTP = "https://rms.rmto.ir/v2/verify_otp";

View File

@@ -1,7 +1,7 @@
import { errorResponse } from "@/core/utils/errorResponse"; import {errorResponse} from "@/core/utils/errorResponse";
import { successRequest } from "@/core/utils/successRequest"; import {successRequest} from "@/core/utils/successRequest";
import axios from "axios"; import axios from "axios";
import { useAuth } from "../contexts/auth"; import {useAuth} from "../contexts/auth";
const defaultOptions = { const defaultOptions = {
data: {}, data: {},
@@ -16,13 +16,12 @@ const defaultOptions = {
}; };
const useRequest = (initOptions) => { const useRequest = (initOptions) => {
const { logout } = useAuth(); const {logout} = useAuth();
const _options = Object.assign({}, defaultOptions, initOptions); const _options = Object.assign({}, defaultOptions, initOptions);
return async (url = "", method = "get", options) => { return async (url = "", method = "get", options) => {
const mergedOptions = Object.assign({}, _options, options); const mergedOptions = Object.assign({}, _options, options);
try { try {
const response = await axios({ const response = await axios({
url, url,