diff --git a/package.json b/package.json index 9b8b7b0..39f3ec4 100644 --- a/package.json +++ b/package.json @@ -16,9 +16,11 @@ "@mui/icons-material": "^5.11.16", "@mui/lab": "^5.0.0-alpha.152", "@mui/material": "^5.12.0", - "@witel/webapp-builder": "^1.0.6", + "@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", @@ -43,4 +45,4 @@ "@faker-js/faker": "^7.6.0", "eslint-config-next": "^13.3.0" } -} +} \ No newline at end of file diff --git a/public/locales/fa/app.json b/public/locales/fa/app.json index 0822e5f..7ebdf39 100644 --- a/public/locales/fa/app.json +++ b/public/locales/fa/app.json @@ -67,7 +67,8 @@ "dashboard": "داشبورد", "add-request-loan": "درخواست وام", "followUp-loan": "پیگیری درخواست", - "edit-request-loan": "ویرایش درخواست وام" + "edit-request-loan": "ویرایش درخواست وام", + "show": "نمایش" }, "Authorization": { "typography_your_login_is_valid_and_you_do_not_need_to_login_again": "شما دسترسی لازم به این صفحه را دارید نیاز به ورود مجدد نیست.", @@ -179,26 +180,38 @@ "error_message_city_id": "لطفا شهر خود را وارد کنید!", "add_loan_request_permission": "اکنون امکان ثبت درخواست جدید برای شما مقدور نیست" }, - "showLoan": { - "show_loan_page": "نمایش وام", + "ShowLoan": { + "show_loan_page": "نمایش وام | ناوگان", "text_field_national_code": "کد ملی", "text_field_postal_code": "کد پستی", "text_field_national_card_serial_num": "سریال پشت کارت ملی", "text_field_address": "آدرس", "text_field_birth_date": "تاریخ تولد", "text_field_navgan_id": "کد ناوگان", - "text_field_enter_your_national_code": "کد ملی خود را وارد کنید", - "text_field_enter_your_postal_code": "کد پستی خود را وارد کنید", - "text_field_enter_your_national_card_serial_num": "سریال پشت کارت ملی خود را وارد کنید", - "text_field_enter_your_address": "آدرس خود را وارد کنید", - "text_field_enter_your_birth_date": "تاریخ تولد خود را وارد کنید", - "text_field_enter_your_navgan_id": "کد ناوگان خود را وارد کنید", - "error_message_national_code": "لطفا کد ملی خود را وارد کنید!", - "error_message_postal_code": "لطفا کد پستی خود را وارد کنید!", - "error_message_national_card_serial_num": "لطفا سریال پشت کارت ملی خود را وارد کنید!", - "error_message_address": "لطفا آدرس خود را وارد کنید!", - "error_message_birth_date": "لطفا تاریخ تولد خود را وارد کنید!", - "error_message_navgan_id": "لطفا کد ناوگان خود را وارد کنید!", + "text_field_province_id": "استان", + "text_field_owner_full_name": "نام کامل مالک", + "text_field_navgan_type": "نوع ناوگان", + "text_field_vehicle_type": "نوع وسیله", + "text_field_enter_your_national_code": "کد ملی را وارد کنید", + "text_field_enter_your_postal_code": "کد پستی را وارد کنید", + "text_field_enter_your_national_card_serial_num": "سریال پشت کارت ملی را وارد کنید", + "text_field_enter_your_address": "آدرس را وارد کنید", + "text_field_enter_your_birth_date": "تاریخ تولد را وارد کنید", + "text_field_enter_your_navgan_id": "کد ناوگان را وارد کنید", + "text_field_enter_your_owner_full_name": "نام کامل مالک را وارد کنید", + "error_message_national_code": "لطفا کد ملی را وارد کنید!", + "error_message_postal_code": "لطفا کد پستی را وارد کنید!", + "error_message_national_card_serial_num": "لطفا سریال پشت کارت ملی را وارد کنید!", + "error_message_address": "لطفا آدرس را وارد کنید!", + "error_message_birth_date": "لطفا تاریخ تولد را وارد کنید!", + "error_message_navgan_id": "لطفا کد ناوگان را وارد کنید!", + "error_message_province_id": "لطفا استان را وارد کنید!", + "error_message_city_id": "لطفا شهر خود را وارد کنید!", + "error_message_owner_full_name": "لطفا نام کامل مالک را وارد کنید!", + "error_message_navgan_type": "لطفا نوع ناوگان را وارد کنید!", + "error_message_vehicle_type": "لطفا نوع وسیله را وارد کنید!", + "error_message_fixed_number": "لطفا تلفن ثابت را وارد کنید!", + "cityList_empty": "شهر یافت نشد", "button_submit": "ویرایش" }, "EditLoanRequest": { diff --git a/src/components/dashboard/navgan/add-request-loan/index.jsx b/src/components/dashboard/navgan/add-request-loan/index.jsx index cd9d359..356dfe1 100644 --- a/src/components/dashboard/navgan/add-request-loan/index.jsx +++ b/src/components/dashboard/navgan/add-request-loan/index.jsx @@ -1,29 +1,25 @@ -import CenterLayout from "@/layouts/CenterLayout"; -import DashboardLayouts from "@/layouts/dashboardLayouts"; -import useUser from "@/lib/app/hooks/useUser"; 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 ( - - - - - - - - - - + + + + + + + + ); }; diff --git a/src/components/dashboard/navgan/show/form/index.jsx b/src/components/dashboard/navgan/show/form/index.jsx index 446deb0..329a69c 100644 --- a/src/components/dashboard/navgan/show/form/index.jsx +++ b/src/components/dashboard/navgan/show/form/index.jsx @@ -5,9 +5,16 @@ import {useTranslations} from "next-intl"; import EditIcon from '@mui/icons-material/Edit'; import * as Yup from "yup"; import SelectBox from "@/core/components/SelectBox"; +import useProvince from "@/lib/app/hooks/useProvince"; +import useCities from "@/lib/app/hooks/useCities"; +import {useEffect} from "react"; +import PlateNumber from "@/core/components/PlateNumber"; +import MuiDatePicker from "@/core/components/MuiDatePicker"; const ShowLoanForm = () => { const t = useTranslations(); + const {provinceList, isLoadingProvinceList, errorProvinceList} = useProvince(); + const {cityList, cityTextField, setProvinceID, isLoadingCityList} = useCities(); // initial values const initialValues = { @@ -16,18 +23,38 @@ const ShowLoanForm = () => { national_card_serial_num: "0312288875", address: "تهران - ثنایی - مطهری ساختمان مهتاب", birth_date: "10/25/44", - navgan_id: "14575" + navgan_id: "14575", + province_id: "9", + city_id: "33", + owner_full_name: "حسن قلی ابدوالابادی", + navgan_type: "2", + vehicle_type: "1", + fixed_number: "02637317735", + plate_part1: "22", + plate_part2: "ب", + plate_part3: "333", + plate_part4: "12", }; // end initial values + useEffect(() => { + setProvinceID(initialValues.province_id); + }, [initialValues.province_id]); + // validation const validationSchema = Yup.object().shape({ - national_code: Yup.string().required(t("showLoan.error_message_national_code")), - postal_code: Yup.string().required(t("showLoan.error_message_postal_code")), - national_card_serial_num: Yup.string().required(t("showLoan.error_message_national_card_serial_num")), - address: Yup.string().required(t("showLoan.error_message_address")), - birth_date: Yup.string().required(t("showLoan.error_message_birth_date")), - navgan_id: Yup.string().required(t("showLoan.error_message_navgan_id")), + national_code: Yup.string().required(t("ShowLoan.error_message_national_code")), + postal_code: Yup.string().required(t("ShowLoan.error_message_postal_code")), + national_card_serial_num: Yup.string().required(t("ShowLoan.error_message_national_card_serial_num")), + address: Yup.string().required(t("ShowLoan.error_message_address")), + birth_date: Yup.string().required(t("ShowLoan.error_message_birth_date")), + navgan_id: Yup.string().required(t("ShowLoan.error_message_navgan_id")), + province_id: Yup.string().required(t("ShowLoan.error_message_province_id")), + city_id: Yup.string().required(t("ShowLoan.error_message_city_id")), + owner_full_name: Yup.string().required(t("ShowLoan.error_message_owner_full_name")), + navgan_type: Yup.string().required(t("ShowLoan.error_message_navgan_type")), + vehicle_type: Yup.string().required(t("ShowLoan.error_message_vehicle_type")), + fixed_number: Yup.string().required(t("ShowLoan.error_message_fixed_number")), }); // end validation @@ -40,6 +67,12 @@ const ShowLoanForm = () => { formData.append("address", values.address); formData.append("birth_date", values.birth_date); formData.append("navgan_id", values.navgan_id); + formData.append("province_id", values.province_id); + formData.append("city_id", values.city_id); + formData.append("owner_full_name", values.owner_full_name); + formData.append("navgan_type", values.navgan_type); + formData.append("vehicle_type", values.vehicle_type); + formData.append("fixed_number", values.fixed_number); }; // end submit @@ -82,8 +115,8 @@ const ShowLoanForm = () => { disabled variant="standard" size="small" - label={t("showLoan.text_field_national_code")} - placeholder={t("showLoan.text_field_enter_your_national_code")} + label={t("ShowLoan.text_field_national_code")} + placeholder={t("ShowLoan.text_field_enter_your_national_code")} type={"text"} error={!!(props.touched.national_code && props.errors.national_code)} fullWidth @@ -104,9 +137,9 @@ const ShowLoanForm = () => { disabled variant="standard" size="small" - label={t("showLoan.text_field_birth_date")} + label={t("ShowLoan.text_field_birth_date")} placeholder={t( - "showLoan.text_field_enter_your_birth_date" + "ShowLoan.text_field_enter_your_birth_date" )} type={"text"} error={!!(props.touched.birth_date && props.errors.birth_date)} @@ -117,6 +150,12 @@ const ShowLoanForm = () => { : null } /> + { disabled variant="standard" size="small" - label={t("showLoan.text_field_national_card_serial_num")} + label={t("ShowLoan.text_field_national_card_serial_num")} placeholder={t( - "showLoan.text_field_enter_your_national_card_serial_num" + "ShowLoan.text_field_enter_your_national_card_serial_num" )} type={"text"} error={!!(props.touched.national_card_serial_num && props.errors.national_card_serial_num)} @@ -147,6 +186,115 @@ const ShowLoanForm = () => { /> + + + + + + props.setFieldValue('vehicle_type', event.target.value)} + error={props.touched.vehicle_type && Boolean(props.errors.vehicle_type)} + helperText={props.touched.vehicle_type && props.errors.vehicle_type} + onBlur={props.handleBlur("vehicle_type")} + /> + + + { + props.setFieldValue('navgan_type', event.target.value) + }} + setFieldTouched={props.setFieldTouched} + error={props.touched.navgan_type && Boolean(props.errors.navgan_type)} + helperText={props.touched.navgan_type && props.errors.navgan_type} + onBlur={props.handleBlur("navgan_type")} + /> + + + + + + + { name="address" variant="outlined" size="small" - label={t("showLoan.text_field_address")} - placeholder={t("showLoan.text_field_enter_your_address")} + label={t("ShowLoan.text_field_address")} + placeholder={t("ShowLoan.text_field_enter_your_address")} type={"text"} error={!!(props.touched.address && props.errors.address)} fullWidth @@ -190,9 +338,9 @@ const ShowLoanForm = () => { name="postal_code" variant="outlined" size="small" - label={t("showLoan.text_field_postal_code")} + label={t("ShowLoan.text_field_postal_code")} placeholder={t( - "showLoan.text_field_enter_your_postal_code" + "ShowLoan.text_field_enter_your_postal_code" )} type={"text"} error={!!(props.touched.postal_code && props.errors.postal_code)} @@ -217,9 +365,9 @@ const ShowLoanForm = () => { name="navgan_id" variant="outlined" size="small" - label={t("showLoan.text_field_navgan_id")} + label={t("ShowLoan.text_field_navgan_id")} placeholder={t( - "showLoan.text_field_enter_your_navgan_id" + "ShowLoan.text_field_enter_your_navgan_id" )} type={"text"} error={!!(props.touched.navgan_id && props.errors.navgan_id)} @@ -248,22 +396,47 @@ const ShowLoanForm = () => { width: "100%", }} > - { + props.setFieldValue('province_id', event.target.value); + setProvinceID(event.target.value) + props.setFieldTouched("city_id", false, false); + props.setFieldValue("city_id", "") + }} setFieldTouched={props.setFieldTouched} - error={ - !!(props.touched.province_id && props.errors.province_id) - } - helperText={ - props.touched.province_id ? props.errors.province_id : null - } + error={props.touched.province_id && Boolean(props.errors.province_id)} + helperText={props.touched.province_id && props.errors.province_id} + onBlur={props.handleBlur("province_id")} + /> + + + props.setFieldValue('city_id', event.target.value)} + setFieldTouched={props.setFieldTouched} + error={props.touched.city_id && Boolean(props.errors.city_id)} + helperText={props.touched.city_id && props.errors.city_id} + onBlur={props.handleBlur("city_id")} /> @@ -287,7 +460,7 @@ const ShowLoanForm = () => { endIcon={} disabled={props.isSubmitting} > - {t("showLoan.button_submit")} + {t("ShowLoan.button_submit")} diff --git a/src/components/dashboard/navgan/show/index.jsx b/src/components/dashboard/navgan/show/index.jsx index ffab6b1..ae22139 100644 --- a/src/components/dashboard/navgan/show/index.jsx +++ b/src/components/dashboard/navgan/show/index.jsx @@ -12,9 +12,7 @@ const ShowLoan = () => { diff --git a/src/core/components/MuiDatePicker.jsx b/src/core/components/MuiDatePicker.jsx index e69de29..afe036e 100644 --- a/src/core/components/MuiDatePicker.jsx +++ b/src/core/components/MuiDatePicker.jsx @@ -0,0 +1,89 @@ +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 ( + + ); +} + +function ButtonDatePicker(props) { + const t = useTranslations(); + const [open, setOpen] = useState(false); + + return ( + setOpen(false)} + onOpen={() => setOpen(true)} + /> + ); +} + +export default function PickerWithButtonField({formik, error, helperText}) { + const [value, setValue] = useState(null); + return ( + + + { + const formattedBirthday = moment(newValue).locale("fa").format("YYYY-MM-DD") + formik.setFieldValue("birthday", formattedBirthday) + setValue(newValue) + console.log(formattedBirthday) + }} + + /> + + {formik.touched.birthday && formik.errors.birthday} + + ); +} \ No newline at end of file diff --git a/src/core/components/PlateNumber.jsx b/src/core/components/PlateNumber.jsx index 10ecd18..1466be7 100644 --- a/src/core/components/PlateNumber.jsx +++ b/src/core/components/PlateNumber.jsx @@ -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"; @@ -120,7 +120,7 @@ const plate_words = [ name: }, ] -const PlateNumber = ({formik}) => { +const PlateNumber = ({formik, disabled}) => { const t = useTranslations(); const [plateDrawer, setPlateDrawer] = useState(false); const [selectedWordName, setSelectedWordName] = useState("الف"); @@ -128,102 +128,84 @@ const PlateNumber = ({formik}) => { return ( <> - - - - ایران - - - - - - - - {/**/} - - setPlateDrawer(false)} + + event.target.value.length <= 2 ? formik.setFieldValue("plate_part4", event.target.value) : null} + size={'small'} + placeholder={'xx'} sx={{flexGrow: 2}} + inputProps={{sx: {textAlign: 'center'}}}/> + 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'}}}/> + + - ))} - - + {selectedWordName} + - - - - + setPlateDrawer(false)} + > + + {plate_words.map((item) => ( + + ))} + + + event.target.value.length <= 2 ? formik.setFieldValue("plate_part1", event.target.value) : null} + size={'small'} + placeholder={'xx'} + sx={{flexGrow: 2}} + inputProps={{sx: {textAlign: 'center'}}}/> + + + + + + {t("error_message_plate_number")} diff --git a/src/core/components/SelectBox.jsx b/src/core/components/SelectBox.jsx index a24484c..56c7770 100644 --- a/src/core/components/SelectBox.jsx +++ b/src/core/components/SelectBox.jsx @@ -1,52 +1,60 @@ import {FormControl, FormHelperText, InputLabel, MenuItem, Select,} from "@mui/material"; +import {useTranslations} from "next-intl"; function SelectBox({ select, - selectType, + name, selectors, label, - setFieldValue, - setFieldTouched, + handleChange, error, + onBlur, + disabled, helperText, + isLoading, + errorEcured, + variant }) { + const t = useTranslations(); - const selectId = String(select); - const handleChange = (event) => { - setFieldValue(selectType, event.target.value); - }; - const handleBlur = () => { - setFieldTouched(select, true); - }; return ( - {label} + {label} {helperText} ); } -export default SelectBox; +export default SelectBox; \ No newline at end of file diff --git a/src/core/data/apiRoutes.js b/src/core/data/apiRoutes.js index cd90a05..b2d08af 100644 --- a/src/core/data/apiRoutes.js +++ b/src/core/data/apiRoutes.js @@ -14,5 +14,6 @@ export const SEND_LOAN_REQUEST_WELFARE = BASE_URL + "/refahi/loan/store"; export const UPDATE_LOAN_REQUEST_WELFARE = BASE_URL + "/refahi/loan/update/"; export const DETAILS_LOAN_REQUEST_WELFARE = BASE_URL + "/refahi/loan/details/"; export const GET_PROVINCE_LIST = BASE_URL + "/provinces"; +export const GET_CITIES_LIST = BASE_URL + "/cities" diff --git a/src/lib/app/hooks/useCities.jsx b/src/lib/app/hooks/useCities.jsx index e69de29..90bb21d 100644 --- a/src/lib/app/hooks/useCities.jsx +++ b/src/lib/app/hooks/useCities.jsx @@ -0,0 +1,37 @@ +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 [isLoadingCityList, setIsLoadingCityList] = useState(false) + const [cityList, setCityList] = useState([]); + const [cityTextField, setCityTextField] = useState(t("LoanRequest.city_id")); + const requestServer = useRequest({auth: true, notification: false}) + + useEffect(() => { + if (provinceID === null) return + setIsLoadingCityList(true); + setCityTextField(t("LoanRequest.text_field_loading_cities_list")) + requestServer(`${GET_CITIES_LIST}?province_id=${provinceID}`, "get", {auth: true, notification: false}) + .then(({data}) => { + const result = data.data; + const formattedData = result.map((city, index) => ({ + id: index, + name: city.name, + value: city.id, + })); + setCityList(formattedData); + setCityTextField(t("LoanRequest.text_field_city_id")) + setIsLoadingCityList(false); + }).catch(() => { + setCityTextField(t("LoanRequest.text_field_error_fetching_cities")) + }); + }, [provinceID]) + + + return {cityList, cityTextField, setProvinceID, isLoadingCityList} +} +export default useCities \ No newline at end of file diff --git a/src/lib/app/hooks/useProvince.jsx b/src/lib/app/hooks/useProvince.jsx index d0fbda0..c1c2dcc 100644 --- a/src/lib/app/hooks/useProvince.jsx +++ b/src/lib/app/hooks/useProvince.jsx @@ -1,28 +1,33 @@ import {GET_PROVINCE_LIST} from "@/core/data/apiRoutes"; -import useRequest from "@/lib/app/hooks/useRequest"; -import useSWR from "swr"; +import {useRequest} from "@witel/webapp-builder"; +import {useEffect, useState} from "react"; const useProvince = () => { + const [isLoadingProvinceList, setIsLoadingProvinceList] = useState(false) + const [errorProvinceList, setErrorProvinceList] = useState(false) + const [provinceList, setProvinceList] = useState([]) const requestServer = useRequest({auth: true, notification: false}) - //swr config - const fetcher = (...args) => { - return requestServer(args, 'get').then(({data}) => { - return data; + useEffect(() => { + setIsLoadingProvinceList(true) + requestServer(GET_PROVINCE_LIST, 'get', {auth: true, notification: false}).then(({data}) => { + const formattedData = data.map((province, index) => ({ + id: index, + name: province.name, + value: province.id, + })); + setIsLoadingProvinceList(false) + setProvinceList(formattedData); }).catch(() => { + setIsLoadingProvinceList(false) + setErrorProvinceList(true) }) - }; - - const {data, isLoading} = useSWR(GET_PROVINCE_LIST, fetcher, { - revalidateIfStale: false, - revalidateOnFocus: false, - revalidateOnReconnect: false - }); + }, []) return { - provinceList: data, - isLoadingProvinceList: isLoading, - errorProvinceList: !data + provinceList, + isLoadingProvinceList, + errorProvinceList } }; diff --git a/src/pages/dashboard/navgan/[id]/show/index.jsx b/src/pages/dashboard/navgan/[id]/show/index.jsx index 202aa4d..108f7b1 100644 --- a/src/pages/dashboard/navgan/[id]/show/index.jsx +++ b/src/pages/dashboard/navgan/[id]/show/index.jsx @@ -12,7 +12,7 @@ export async function getServerSideProps({req, locale}) { return { props: { messages: (await import(`&/locales/${locale}/app.json`)).default, - title: "showLoan.show_loan_page", + title: "ShowLoan.show_loan_page", isBot, locale, layout: {name: 'DashboardLayout'}