add postal code address and some validation

This commit is contained in:
2023-12-18 14:11:07 +03:30
parent 8cbe7a435c
commit 4b31247ca1
9 changed files with 247 additions and 175 deletions

View File

@@ -16,9 +16,11 @@
"@mui/icons-material": "^5.11.16",
"@mui/lab": "^5.0.0-alpha.152",
"@mui/material": "^5.12.0",
"@mui/x-date-pickers": "^6.18.5",
"@witel/webapp-builder": "^1.1.0",
"axios": "^1.4.0",
"colord": "^2.9.3",
"date-fns-jalali": "^2.13.0-0",
"eslint": "8.36.0",
"formik": "^2.2.9",
"fs-extra": "^11.1.1",

View File

@@ -1,7 +1,14 @@
{
"app_name": "سامانه جامع تسهیلات",
"app_short_name": "سامانه تسهیلات",
"birthday": "تاریخ تولد",
"birthday_error": "تاریخ تولد خود را وارد کنید!",
"dashboard": "داشبورد",
"text_field_city_id": "شهر",
"text_field_error_fetching_cities": "لطفا شهر خود را وارد کنید!",
"text_field_loading_cities_list": "درحال دریافت اطلاعات شهر ها...",
"text_field_loading": "درحال دریافت اطلاعات",
"text_field_error_fetching": "خطا در دریافت اطلاعات",
"first_page": "خوش آمدید",
"powered_by_witel": "توسعه یافته توسط وایتل",
"login": "ورود",
@@ -127,7 +134,7 @@
"no_request_found": "درخواستی یافت نشد"
},
"LoanRequest": {
"city_id": "شهر",
"cityList_empty": "ابتدا استان را وارد کنید",
"loan_request_page": "ثبت درخواست وام",
"personal_info": "اطلاعات شخصی",
"national_code_number": "کد ملی می بایست شامل اعداد باشد",
@@ -163,8 +170,6 @@
"text_field_enter_your_plate_part3": "بخش سوم پلاک را وارد کنید",
"text_field_enter_your_plate_part4": "بخش چهارم پلاک راوارد کنید",
"text_field_enter_your_address": "آدرس خود راوارد کنید",
"text_field_loading_cities_list": "درحال دریافت اطلاعات شهر ها...",
"text_field_city_id": "شهر",
"text_field_enter_your_name": "نام خود را وارد کنید",
"text_field_enter_your_postal_code": "کد پستی خود را وارد کنید",
"text_field_vehicle_type": "نوع وسیله نقلیه",
@@ -183,7 +188,6 @@
"text_field_enter_your_shenasname_serial": "سریال پشت کارت ملی خود را وارد کنید",
"text_field_plate_number": "شماره پلاک",
"text_field_enter_your_plate_number": "شماره پلاک خود را وارد کنید",
"text_field_error_fetching_cities": "شهر خود را وارد کنید!",
"button_submit": "ثبت درخواست",
"error_message_city_id": "لطفا شهر خود را وارد کنید!",
"add_loan_request_permission": "اکنون امکان ثبت درخواست جدید برای شما مقدور نیست"

View File

@@ -9,7 +9,7 @@ import {useRequest, useUser} from "@witel/webapp-builder";
import useProvince from "@/lib/app/hooks/useProvince";
import useCities from "@/lib/app/hooks/useCities";
import PlateNumber from "@/core/components/PlateNumber";
import MuiDatePicker from "@/core/MuiDatePicker";
import MuiDatePicker from "@/core/components/MuiDatePicker";
const AddFormComponent = () => {
const t = useTranslations();
@@ -34,6 +34,7 @@ const AddFormComponent = () => {
plate_part3 : "",
plate_part4 : "",
address : "",
date_of_birth : "",
};
const validationSchema = Yup.object().shape({
@@ -49,6 +50,9 @@ const AddFormComponent = () => {
address: Yup.string().required(
t("LoanRequest.error_message_address")
),
date_of_birth: Yup.string().required(
t("LoanRequest.error_message_date_of_birth")
),
postal_code: Yup.mixed()
.test("max", `${t("LoanRequest.postal_code_max")}`, (value) => value.toString().length === 10)
.required(
@@ -101,6 +105,7 @@ const AddFormComponent = () => {
formData.append("address", values.address);
formData.append("navgan_id", values.navgan_id);
formData.append("national_code", values.national_code);
formData.append("date_of_birth", values.date_of_birth);
formData.append("shenasname_serial", values.shenasname_serial);
requestServer(SEND_LOAN_REQUEST_NAVGAN, "post", {auth : true, notification : true}).then().catch(() => {
@@ -115,7 +120,7 @@ const AddFormComponent = () => {
<>
<Grid container spacing={2} sx={{padding : 2}}
>
<Grid item xs={12} sm={6}
<Grid item xs={12} sm={4}
>
<TextField
sx={{width: "100%"}}
@@ -134,8 +139,34 @@ const AddFormComponent = () => {
fullWidth
/>
</Grid>
<Grid item xs={12} sm={6}
<Grid item xs={12} sm={4}
>
<TextField
sx={{width: "100%"}}
name="shenasname_serial"
variant="outlined"
size="small"
label={t("LoanRequest.text_field_shenasname_serial")}
placeholder={t(
"LoanRequest.text_field_enter_your_shenasname_serial")}
fullWidth
onChange={formik.handleChange}
onBlur={formik.handleBlur("shenasname_serial")}
error={formik.touched.shenasname_serial && Boolean(formik.errors.shenasname_serial)}
helperText={formik.touched.shenasname_serial && formik.errors.shenasname_serial}
/>
</Grid>
<Grid item xs={12} sm={4}>
<MuiDatePicker
formik={formik}
error={formik.touched.date_of_birth && Boolean(formik.errors.date_of_birth)}
helperText={formik.touched.date_of_birth && formik.errors.date_of_birth}
onBlur={formik.handleBlur("date_of_birth")}
/>
</Grid>
</Grid>
<Grid container spacing={2} sx={{padding : 2}}>
<Grid item xs={12} sm={6}>
<TextField
sx={{width: "100%"}}
name="postal_code"
@@ -151,41 +182,6 @@ const AddFormComponent = () => {
helperText={formik.touched.postal_code && formik.errors.postal_code}
/>
</Grid>
</Grid>
<Grid container spacing={2} sx={{padding : 2}}>
<Grid item xs={12} sm={6}>
<SelectBox
name="vehicle_type"
label={t("LoanRequest.text_field_vehicle_type")}
size="small"
selectType="vehicle_type"
selectors={[{id : 0, value : 0, name : "اتوبوس"},
{id : 1, value: 1, name : "مینی بوس"}]}
select={formik.values.vehicle_type}
setFieldValue={formik.setFieldValue}
error={formik.touched.vehicle_type && Boolean(formik.errors.vehicle_type)}
helperText={formik.touched.vehicle_type && formik.errors.vehicle_type}
onBlur={formik.handleBlur("vehicle_type")}
/>
</Grid>
<Grid item xs={12} sm={6}>
<TextField
sx={{width: "100%"}}
name="navgan_id"
variant="outlined"
type={'number'}
onChange={formik.handleChange}
size="small"
label={t("LoanRequest.text_field_navgan_id")}
placeholder={t("LoanRequest.text_field_enter_your_navgan_id")}
fullWidth
onBlur={formik.handleBlur("navgan_id")}
error={formik.touched.navgan_id && Boolean(formik.errors.navgan_id)}
helperText={formik.touched.navgan_id && formik.errors.navgan_id}
/>
</Grid>
</Grid>
<Grid container spacing={2} sx={{padding: 2}}>
<Grid item xs={12} sm={6}>
<TextField
sx={{width: "100%"}}
@@ -204,6 +200,8 @@ const AddFormComponent = () => {
helperText={formik.touched.tel_number && formik.errors.tel_number}
/>
</Grid>
</Grid>
<Grid container spacing={2} sx={{padding: 2}}>
<Grid item xs={12} sm={6}>
<SelectBox
name="navgan_type"
@@ -219,6 +217,22 @@ const AddFormComponent = () => {
onBlur={formik.handleBlur("navgan_type")}
/>
</Grid>
<Grid item xs={12} sm={6}>
<TextField
sx={{width: "100%"}}
name="navgan_id"
variant="outlined"
type={'number'}
onChange={formik.handleChange}
size="small"
label={t("LoanRequest.text_field_navgan_id")}
placeholder={t("LoanRequest.text_field_enter_your_navgan_id")}
fullWidth
onBlur={formik.handleBlur("navgan_id")}
error={formik.touched.navgan_id && Boolean(formik.errors.navgan_id)}
helperText={formik.touched.navgan_id && formik.errors.navgan_id}
/>
</Grid>
</Grid>
<Grid container spacing={2} sx={{padding : 2}}>
<Grid item xs={12} sm={6}>
@@ -244,7 +258,7 @@ const AddFormComponent = () => {
<Grid item xs={12} sm={6}>
<SelectBox
name="city_id"
label={cityTextField}
label={cityList.length === 0 ? `${t("LoanRequest.cityList_empty")}`: cityTextField}
size="small"
selectType="city_id"
disabled={cityList.length === 0}
@@ -260,28 +274,22 @@ const AddFormComponent = () => {
</Grid>
<Grid container spacing={2} sx={{padding : 2}}>
<Grid item xs={12} sm={6}>
<TextField
sx={{width: "100%"}}
name="shenasname_serial"
variant="outlined"
<SelectBox
name="vehicle_type"
label={t("LoanRequest.text_field_vehicle_type")}
size="small"
label={t("LoanRequest.text_field_shenasname_serial")}
placeholder={t(
"LoanRequest.text_field_enter_your_shenasname_serial")}
fullWidth
onChange={formik.handleChange}
onBlur={formik.handleBlur("shenasname_serial")}
error={formik.touched.shenasname_serial && Boolean(formik.errors.shenasname_serial)}
helperText={formik.touched.shenasname_serial && formik.errors.shenasname_serial}
selectType="vehicle_type"
selectors={[{id : 0, value : 0, name : "اتوبوس"},
{id : 1, value: 1, name : "مینی بوس"}]}
select={formik.values.vehicle_type}
handleChange={(event)=>formik.setFieldValue('vehicle_type', event.target.value)}
error={formik.touched.vehicle_type && Boolean(formik.errors.vehicle_type)}
helperText={formik.touched.vehicle_type && formik.errors.vehicle_type}
onBlur={formik.handleBlur("vehicle_type")}
/>
</Grid>
<Grid item xs={12} sm={6}>
{/*<MuiDatePicker />*/}
</Grid>
</Grid>
<Grid container spacing={2} sx={{padding : 2}}>
<Grid item xs={12} sm={6}>
<PlateNumber formik={formik} />
<PlateNumber formik={formik}/>
</Grid>
</Grid>
<Grid container spacing={2} sx={{padding : 2}}>

View File

@@ -1,20 +1,16 @@
import {Box, Chip, Divider} from "@mui/material";
import {useTranslations} from "next-intl";
import AddFormComponent from "@/components/dashboard/navgan/add-request-loan/forms/AddForm";
import {CenterLayout, useUser} from "@witel/webapp-builder";
const LoanRequestComponent = () => {
const t = useTranslations();
const {user} = useUser();
return (
<>
<Box>
<Divider>
<Chip
label={`${t("LoanRequest.loan_request_page")} | ${
user.type_name
}`}
label={`${t("LoanRequest.loan_request_page")} | ${t("user_navy")} `}
/>
</Divider>
</Box>

View File

@@ -0,0 +1,85 @@
import * as React from 'react';
import {useState} from 'react';
import Button from '@mui/material/Button';
import {AdapterDateFnsJalali} from "@mui/x-date-pickers/AdapterDateFnsJalali";
import {LocalizationProvider} from '@mui/x-date-pickers/LocalizationProvider';
import {DatePicker} from '@mui/x-date-pickers/DatePicker';
import {useTranslations} from "next-intl";
import moment from "jalali-moment";
import {FormControl, FormHelperText} from "@mui/material";
function ButtonField(props) {
const t = useTranslations();
const {
setOpen,
label,
id,
disabled,
InputProps: {ref} = {},
inputProps: {'aria-label': ariaLabel} = {},
} = props;
return (
<Button
sx={{width: "100%", padding: 0.8}}
variant="outlined"
id={id}
disabled={disabled}
ref={ref}
aria-label={ariaLabel}
onClick={() => setOpen?.((prev) => !prev)}
>
{label ? `${t("birthday")}: ${label}` : `${t("birthday")}`}
</Button>
);
}
function ButtonDatePicker(props) {
const t = useTranslations();
const [open, setOpen] = useState(false);
return (
<DatePicker
slots={{field: ButtonField, ...props.slots}}
disableFuture
slotProps={{
field: {setOpen},
textField: {
helperText: props.formik.errors.date_of_birth ? `${t("birthday_error")}` : null
}
}}
{...props}
open={open}
onClose={() => setOpen(false)}
onOpen={() => setOpen(true)}
/>
);
}
export default function PickerWithButtonField({formik, error, helperText}) {
const [value, setValue] = useState(null);
return (
<LocalizationProvider dateAdapter={AdapterDateFnsJalali}>
<FormControl
variant={"outlined"}
fullWidth
size="small"
error={error}
>
<ButtonDatePicker
label={value == null ? null : moment(value)
.locale("fa")
.format("YYYY/MM/DD")}
value={value}
formik={formik}
onChange={(newValue) => {
setValue(newValue)
}}
/>
<FormHelperText>{helperText}</FormHelperText>
</FormControl>
</LocalizationProvider>
);
}

View File

@@ -1,4 +1,4 @@
import {Box, Button, Drawer, FormHelperText, TextField, Typography} from "@mui/material";
import {Box, Button, Drawer, FormHelperText, InputBase, Stack} from "@mui/material";
import {useTranslations} from "next-intl";
import AccessibleIcon from '@mui/icons-material/Accessible';
import {useState} from "react";
@@ -128,102 +128,80 @@ const PlateNumber = ({formik}) => {
return (
<>
<Box sx={{
display: "flex",
width: "fit-content",
flexDirection: "row",
alignItems: "end",
justifyContent: "end",
gap: 0.75
}}>
<Box sx={{display: "flex", flexDirection: "column", textAlign: "center", justifyContent: "center"}}>
<Typography variant="caption" sx={{fontWeight: 500}}>
ایران
</Typography>
<TextField
<Stack direction={'row'}
sx={{border: 1, overflow: 'hidden', borderColor: 'divider', borderRadius: 1}}>
<InputBase
type={'number'}
value={formik.values.plate_part4}
onInput={(event) => event.target.value.length <= 2 ? formik.setFieldValue("plate_part4", event.target.value) : null}
size={'small'}
placeholder={'xx'} sx={{flexGrow: 2}}
inputProps={{sx: {textAlign: 'center'}}}/>
<InputBase
type={'number'}
value={formik.values.plate_part3}
onInput={(event) => event.target.value.length <= 3 ? formik.setFieldValue("plate_part3", event.target.value) : null}
size={'small'} placeholder={'xxx'} sx={{
flexGrow: 3, borderLeft: 1, borderRadius: 0, borderColor: 'divider'
}} inputProps={{sx: {textAlign: 'center'}}}/>
<Box sx={{flexGrow: 1}}>
<Button
onClick={() => setPlateDrawer(true)}
sx={{borderRadius: 0, borderColor: 'divider'}}
size={'small'}
data-selected-word={selectedWordValue}
fullWidth
name="plate_part4"
variant="outlined"
size="small"
type='number'
onChange={formik.handleChange}
onBlur={formik.handleBlur("plate_part4")}
/>
</Box>
<Box>
<TextField
fullWidth
name="plate_part3"
variant="outlined"
size="small"
type='number'
onChange={formik.handleChange}
onBlur={formik.handleBlur("plate_part3")}
/>
</Box>
<Box>
{/*<TextField*/}
{/* sx={{width: "50px"}}*/}
{/* name="plate_part2"*/}
{/* variant="outlined"*/}
{/* type={'number'}*/}
{/* size="small"*/}
{/* onChange={formik.handleChange}*/}
{/* onBlur={formik.handleBlur("plate_part1")}*/}
{/*/>*/}
<Button onClick={() => setPlateDrawer(true)}
sx={{
borderColor: "divider",
fontSize: "16px"
}}
variant="outlined"
data-selected-word={selectedWordValue}
>{selectedWordName}</Button>
<Drawer
anchor={"bottom"}
open={plateDrawer}
onClose={() => setPlateDrawer(false)}
>
<Box sx={{
display: "flex",
flexWrap: "wrap",
mx: "auto",
my: 2,
gap: 2,
width: "60%",
justifyContent: "center"
}}>
{plate_words.map((item) => (
<Button
key={item.id}
onClick={() => {
setSelectedWordName(item.name);
setSelectedWordValue(item.value);
setPlateDrawer(false);
}}
sx={{
width: "fit-content"
}}
variant="contained"
>
{item.name}
</Button>
))}
</Box>
</Drawer>
{selectedWordName}
</Button>
</Box>
<Box>
<TextField
fullWidth
name="plate_part1"
variant="outlined"
type='number'
size="small"
onChange={formik.handleChange}
onBlur={formik.handleBlur("plate_part1")}
/>
</Box>
</Box>
<Drawer
anchor={"bottom"}
open={plateDrawer}
onClose={() => setPlateDrawer(false)}
>
<Box sx={{
display: "flex",
flexWrap: "wrap",
mx: "auto",
my: 2,
gap: 2,
width: "60%",
justifyContent: "center"
}}>
{plate_words.map((item) => (
<Button
key={item.id}
onClick={() => {
setSelectedWordName(item.name);
setSelectedWordValue(item.value);
formik.setFieldValue("plate_part2", item.value)
setPlateDrawer(false);
}}
sx={{
width: "fit-content"
}}
variant="contained"
>
{item.name}
</Button>
))}
</Box>
</Drawer>
<InputBase
type={'number'}
value={formik.values.plate_part1}
onInput={(event) => event.target.value.length <= 2 ? formik.setFieldValue("plate_part1", event.target.value) : null}
size={'small'}
placeholder={'xx'}
sx={{flexGrow: 2}}
inputProps={{sx: {textAlign: 'center'}}}/>
<Stack sx={{width: 24, borderLeft: 1, borderColor: 'divider'}}>
<Box sx={{flexGrow: 1, bgcolor: '#1ebc1e'}}></Box>
<Box sx={{flexGrow: 1, bgcolor: 'white'}}></Box>
<Box sx={{flexGrow: 1, bgcolor: '#f52121'}}></Box>
</Stack>
</Stack>
<FormHelperText>{t("error_message_plate_number")}</FormHelperText>
</>

View File

@@ -19,28 +19,26 @@ function SelectBox({
return (
<FormControl
disabled={disabled || false}
variant={name === "plate_part2" ? "standard" : "outlined"}
margin="normal"
variant={"outlined"}
fullWidth
size="small"
error={error}
sx={{mt: 0}}
>
<InputLabel>{label}</InputLabel>
<Select
label={label}
name={name}
size="small"
value={isLoading?"":select}
value={isLoading ? "" : select}
onChange={handleChange}
onBlur={onBlur}
>
{isLoading ? (
<MenuItem sx={{color : "primary.main"}}>{t("LoanRequest.text_field_loading_provinces_list")}</MenuItem>
<MenuItem sx={{color: "primary.main"}}>{t("text_field_loading")}</MenuItem>
) : errorEcured ? (
<MenuItem sx={{color : "secondary.main"}}>
{t("LoanRequest.text_field_error_fetching_provinces")}
<MenuItem sx={{color: "secondary.main"}}>
{t("text_field_error_fetching")}
</MenuItem>
) : (
selectors.map((selector) => (

View File

@@ -2,16 +2,17 @@ import {useEffect, useState} from "react";
import {useRequest} from "@witel/webapp-builder";
import {useTranslations} from "next-intl";
import {GET_CITIES_LIST} from "@/core/data/apiRoutes";
const useCities = () => {
const t = useTranslations();
const [provinceID, setProvinceID] = useState(null)
const [cityList, setCityList] = useState([]);
const [cityTextField, setCityTextField] = useState(t("LoanRequest.city_id"));
const [cityTextField, setCityTextField] = useState(t("text_field_city_id"));
const requestServer = useRequest({auth: true, notification: false})
useEffect(()=>{
if(provinceID === null) return
setCityTextField(t("LoanRequest.text_field_loading_cities_list"))
useEffect(() => {
if (provinceID === null) return
setCityTextField(t("text_field_loading_cities_list"))
requestServer(`${GET_CITIES_LIST}?province_id=${provinceID}`, "get", {auth: true, notification: false})
.then(({data}) => {
const result = data.data;
@@ -21,13 +22,13 @@ const useCities = () => {
value: city.id,
}));
setCityList(formattedData);
setCityTextField(t("LoanRequest.text_field_city_id"))
setCityTextField(t("text_field_city_id"))
}).catch(() => {
setCityTextField(t("LoanRequest.text_field_error_fetching_cities"))
setCityTextField(t("text_field_error_fetching_cities"))
});
},[provinceID])
}, [provinceID])
return{cityTextField, cityList, setProvinceID}
return {cityTextField, cityList, setProvinceID}
}
export default useCities