import React, { useEffect, useContext, useState, useMemo } from "react"; import { TaxiOrder_type, TaxiOrder_initial } from '../types/taxiOrderType'; import { addDays, format } from 'date-fns'; import { getCsrfToken } from "../../../../../resources/js/services/getCsrfService"; import { Button, TextInput, Select, Option } from '@SharePoint/rencredit_uikit'; import FormValidErr, { FormValidErrObject } from "../../../../../resources/js/components/formValidErr/FormValidErr"; import { PopupContext } from "../../../../../resources/js/contexts/PopupContext"; import { EntityHistoryProps } from "../../../../../resources/js/components/entityHistory/EntityHistory"; import { PreloaderContext } from "../../../../../resources/js/contexts/PreloaderContext"; //Гаврилов типы для пропсов? // export default function TaxiOrder( {rqstId, setPreloaderProp}: {rqstId: number | undefined, setPreloaderProp: CallableFunction} ) export default function TaxiOrder( {rqstId}: {rqstId: number | undefined} ) { let newDate = new Date('2024-06-05'); newDate.setHours(0, 0, 0); let fakeObjArr: EntityHistoryProps[] = [ { changeAction: 'insert', changeAuthor: 'login', changeDate: newDate, changeDetails: [ { propName: 'поле', propValue: 'значение' }, { propName: 'поле', propValue: 'значение' }, { propName: 'поле', propValue: 'значение' }, { propName: 'поле2', propValue: 'значение2' } ] }, { changeAction: 'insert', changeAuthor: 'login', changeDate: new Date('2024-06-05'), changeDetails: [ { propName: 'поле', propValue: 'значение' }, { propName: 'поле', propValue: 'значение' }, { propName: 'поле', propValue: 'значение' }, { propName: 'поле2', propValue: 'значение2' } ] }, { changeAction: 'insert', changeAuthor: 'login', changeDate: new Date('2024-06-05'), changeDetails: [ { propName: 'поле', propValue: 'значение' }, { propName: 'поле', propValue: 'значение' }, { propName: 'поле', propValue: 'значение' }, { propName: 'поле2', propValue: 'значение2' } ] }, { changeAction: 'update', changeAuthor: 'login2', changeDate: new Date('2025-06-05'), changeDetails: [ { propName: 'поле3', propValue: 'значение4' }, { propName: 'поле3', propValue: 'значение4' }, { propName: 'поле3', propValue: 'значение4' }, { propName: 'поле3', propValue: 'значение4' }, { propName: 'поле5', propValue: 'значение6' } ] }, { changeAction: 'update', changeAuthor: 'login2', changeDate: new Date('2025-06-05'), changeDetails: [ { propName: 'поле3', propValue: 'значение4' }, { propName: 'поле3', propValue: 'значение4' }, { propName: 'поле3', propValue: 'значение4' }, { propName: 'поле3', propValue: 'значение4' }, { propName: 'поле5', propValue: 'значение6' } ] } ]; const preloaderContext = useContext(PreloaderContext); //ГАВРИЛОВ ПОСТОЯННЫЙ ПЕРЕРЕНДЕРИНГ СПРОСИТЬ У САШИ. ЭЛЕМЕНТ НЕ МИГАЕТ В КОНСОЛИ, НО ПИШЕТ ПОСТОЯННО ПЕРЕРЕНДЕР console.log('🔁 TaxiForm перерендерился!'); interface UserData { emp_id: number, emp_address: string, emp_lastname: string, emp_name: string, emp_surname: string, emp_login: string | null emp_phone: string, //Все остальные поля объекта могут быть пустыми [key: string]: unknown, full_name: string, }; const UserData_initial: UserData = { emp_id: 0, emp_address: '', emp_lastname: '', emp_name: '', emp_surname: '', emp_login: '', emp_phone: '', full_name: '', // _token: getCsrfToken() }; //Проверка загрузки необходимых для начала работ данных. После успешного получения всех данных происходит рендеринг const [checkLoad, setCheckLoad] = useState( { ccEmp: false, orderData: false, checkEditOrderUserData: false, getTimePeriods: false, checkOfficeAddress: false, } ); const todayDate = new Date(); //Данные по всем пользователям const [ccEmp, setCcEmp] = useState( [UserData_initial] ); //Данные по редактируемому запросу (если вызвано редактирование) const [orderData, setOrderData] = useState(TaxiOrder_initial); //Данные по пользователю, чей запрос редактируется (если вызвано редактирование запроса) const [editOrderUserData, setEditOrderUserData] = useState(UserData_initial); //Данные по временным промежуткам const [orderTimePeriods, setOrderTimePeriods] = useState< {time_period: string, is_morning_time: number}[] >( [ {time_period: '', is_morning_time: 0} ] ); //Массив доступных для заказа такси дат для их дальнейшего преобразования в теги option селекта const [dateOrderArr, setDateOrderArr] = useState( [ format(todayDate, "yyyy-MM-dd"), format(addDays(todayDate, 1), "yyyy-MM-dd") ] ); const popupContext = useContext(PopupContext); useEffect ( () => { setFormCreateVisible(true); setFormCreateValidObj([{fieldName: 'testField', fieldErrors: ['errOne']}]); console.log(popupContext) // console.log() // setTimeout(() => { // popupContext.addPopupArrTest([ // {message: 'для информации', timeOut: true, type: 'attention'} // ]) // }, 1000); // setTimeout(() => { // setPopupArrProp([ // {message: 'для информации', timeOut: true, type: 'attention'}, // ]) // }, 1000); // setTimeout(() => { // setPopupArrProp([ // {message: 'для информации', timeOut: false, type: 'info'}, // ]) // }, 2000); // setTimeout(() => { // setPopupArrProp([ // {message: 'для информации', timeOut: false, type: 'info'}, // ]) // }, 3000); // setPopupArrProp([ // {message: 'для информации', timeOut: false, type: 'info'}, // {message: 'успешно', timeOut: true, type: 'success'}, // {message: 'ошибка', timeOut: true, type: 'error'}, // {message: 'обратить внимание', timeOut: true, type: 'attention'} // ]) }, []) const [formCreateVisible, setFormCreateVisible] = useState(false); const [formCreateValidErrObj, setFormCreateValidObj] = useState([{fieldName: null, fieldErrors: []}]) //ГАВРИЛОВ ДОБАВИТЬ ВСПЛЫВАЮЩЕЕ ОКНО ЕСЛИ ПРОИСХОДИТ НЕСООТВЕТСТВИЕ ВРЕМЕНИ И ДАТЫ ЗАКАЗА ТАКСИ? А НЕ ПРОСТО УДАЛЯТЬ ЗНАЧЕНИЕ ИЗ СОСЕДНЕГО ПОЛЯ? //Адреса офисов const [officeAddressInfo, setOfficeAddressInfo] = useState< {place: string, address: string}[] >( [ {place: '', address: ''} ] ); //Адрес офиса, где работает сотрудник. Определяется на этапе выбора логина const [empOfficeAddress, setEmpOfficeAddress] = useState(null); //const [orderTime, setOrderTime] = useState(null); //const [orderDate, setOrderDate] = useState(null); // const [orderAddressFrom, setOrderAddressFrom] = useState(null); // const [orderAddressTo, setOrderAddressTo] = useState(null); function gotoHome() { document.location.href = '/public/taxi/home'; } //Гаврилов. Не передаешь CSRF токен //Отправка заказа на такси function sendTaxiOrder () { console.log(orderData) console.log(editOrderUserData) //return // setPreloaderProp(true, 'создаем заявку') preloaderContext.setPreloaderVisible(true); preloaderContext.setPreloaderText('создаем заявку'); let popupType; fetch('/public/api/taxi/' + (rqstId ? `editOrder/${rqstId}` : 'createRqst'), { credentials: 'include', method: (rqstId ? "PATCH" : "POST"), body: JSON.stringify(orderData), headers: { 'content-type': 'application/json', 'Accept': 'application/json' } }).then(result => { preloaderContext.setPreloaderVisible(false); // setPreloaderProp(false) result.json().then(jsonResult => { console.log(jsonResult) if (!result.ok) { //ГАВРИЛОВ здесь обработка ошибок валидации формы if (result.status == 422) { // setPopupArrProp( // [ // //ГАВРИЛОВ обработка ошибки // {message: 'Произошла ошибка! Заявка не создана', type: 'error'}, // ] // ) } else { // setPopupArrProp( // [ // //ГАВРИЛОВ обработка ошибки // {message: jsonResult.result_msg, type: 'error'}, // ] // ) } popupType = 'error' } else { popupType = 'success' } popupContext.addPopupArrTest( [ {message: jsonResult.message, type: popupType}, ] ) }) }) } //Функция, собирающая нужный массив для формирования из него списка option для select function transformToOptionsFunc ( dataArr: T[], dataKey?: keyof T ): Option[] { let optionArr = dataArr.map(item => { //Без проверки ниже, Typescript ругается на условный атрибут dataKey, который может отсутствовать, но при этом укаан как относящийся к Дженерику const value = dataKey !== undefined ? item[dataKey] : item; return { caption: String(value), value: String(value), id: String(value) }; }); return optionArr; } /** * Метод проверки соответствует ли дата и время заказа логике. Наприме, если дата заказа сегодняшняя - нельзя выбрать утренний промежуток времени * @param orderTime время заказа такси * @param orderDate дата заказа такси * @returns результат проверки соответствия даты и времени заказа */ function checkTimeAndDate (orderTime: string|null, orderDate: string|null): boolean { // console.log(orderTime) // console.log(!orderTime) // console.log(orderDate) // console.log(!orderDate) if (!orderTime || !orderDate) { //console.log(1) return true; } let isMorningTimeCheck = orderTimePeriods.filter( e => e.time_period == orderTime )[0].is_morning_time; // console.log(isMorningTimeCheck) //Если выбранная дата заказа больше текущей - заказ на завтра, можно выбирать любую дату if (!(new Date(orderDate) > todayDate)) { //console.log(2) return !isMorningTimeCheck; } return true; } // const ccEmpList: Option[] = useMemo(() => { // return ccEmp.map(empData => { // return { // caption: empData.emp_login, // value: empData.emp_login, // id: empData.emp_login // } // }) // }, [ccEmp]); // console.log(ccEmpList) const ccEmpList = useMemo( () => { return transformToOptionsFunc(ccEmp, 'emp_login'); }, [ccEmp]); const orderDateList = useMemo( () => { return transformToOptionsFunc(dateOrderArr); }, [dateOrderArr]); const orderTimeList = useMemo( () => { return transformToOptionsFunc(orderTimePeriods, 'time_period') }, [orderTimePeriods]); //Загрузка данных для старта работ useEffect ( () => { //Получаем информацию по сотруднику при загрузке страницы fetch('/public/api/taxi/getEmpInfo', { credentials: 'include', method: 'GET', // headers: new Headers({ // 'Authorization': `Bearer ${sanctumToken()}` // }) }).then(empInfo_resp => empInfo_resp.json().then(empInfo_json => { console.log(empInfo_json) console.log(editOrderUserData) setCcEmp(empInfo_json); setCheckLoad(loadObj => ( {...loadObj, ccEmp: true} )); })); //Получаем доступные временные промежутки для заказа такси fetch('/public/api/taxi/getTimePeriods', { method: 'GET', credentials: 'include', // headers: new Headers({ // 'Authorization': `Bearer ${sanctumToken()}` // }) }).then(timePeriods_resp => timePeriods_resp.json().then(timePeriods_json => { setOrderTimePeriods(timePeriods_json); setCheckLoad(loadObj => ( {...loadObj, getTimePeriods: true} )); })); //ГАВРИЛОВ. ВЕЗДЕ В FETCH ЗАПРОСАХ ПЕРЕХВАТЫВАЙ ОШИБКИ И ВЫВОДИ СООБЩЕНИЯ ОБ ОШИБКЕ. НАПРИМЕМР С 401. В ЭТОМ СЛУЧАЕ НУЖНО ПЕРЕБРАСЫВАТЬ ПОЛЬЗОВАТЕЛЯ НА СТРАНИЦУ АУТЕНТИФИКАЦИИ //Получае адреса всех офисов, куда могут заказываться такси? fetch('/public/api/taxi/getOfficeAddress', { method: 'GET', credentials: 'include', }).then(officeAddress_resp => {officeAddress_resp.json().then(officeAddress_json => { setOfficeAddressInfo(officeAddress_json); setCheckLoad(loadObj => ( {...loadObj, checkOfficeAddress: true} )); })}); //Если в пропсах передается rqstId, происходит редактирование заявки, а не создание новой - получаем данные по редактируемой заявке на такси if (rqstId) { fetch(`/public/api/taxi/getOrderById/${rqstId}`, { method: 'GET', credentials: 'include', // headers: new Headers({ // 'Authorization': `Bearer ${sanctumToken()}` // }) }).then(orderData_resp => orderData_resp.json().then( orderData_json => { console.log(orderData_json) setOrderData(orderData_json); setCheckLoad(loadObj => ({...loadObj, orderData: true})); })); } }, []) //гаврилов. Нужно ввести объект с данными по запросу и туда класть только нужные данные , а не все параметры пользователя. и тогда не нужно нигде проверять rqstId. Внизу в методе класть в этот объект все нужные параметры useEffect ( () => { //Гаврилов. Причем тут проверка логина? Зачем она? if (rqstId && orderData.emp_login) { //Если передан id запроса на редактирование, устанавливаем значение с данными пользователя редактируемого запроса fetch(`/public/api/taxi/getEmpInfo/${orderData.emp_login}`).then(userData_resp => userData_resp.json().then(userData_json => { //гаврилов. Вот здесь нужно класть данные в orderData, а также заполнять адрес из и адрес куда setEditOrderUserData(userData_json[0]); //setOrderData(prevData => ({...prevData, userData_json[0]})); //setEmpAddress(editOrderUserData['emp_address']); setCheckLoad(loadObj => ( {...loadObj, checkEditOrderUserData: true} )); //ГАВРИЛОВ. вынеси в отедльную функцию определение адреса офиса? setEmpOfficeAddress(officeAddressInfo.filter(addressInfo => addressInfo.place == userData_json[0].emp_area)[0].address); })); } }, [orderData.emp_login]) //Итоговая проверка все ли необходимые данные для рендеринга получены const isReady = rqstId ? checkLoad.ccEmp && checkLoad.checkEditOrderUserData && checkLoad.orderData && checkLoad.checkOfficeAddress && checkLoad.getTimePeriods : checkLoad.ccEmp; //Регулировка видимости прелоадера в зависимости от того все ли данные для рендеринга получены или нет useEffect ( () => { //isReady ? setPreloaderProp(false) : setPreloaderProp(true); isReady ? preloaderContext.setPreloaderVisible(false) : preloaderContext.setPreloaderVisible(true); }, [isReady]) if (!isReady) { return; } return (
{/* */}

{rqstId ? 'Редактирование' : 'Создание'} заявки на такси

{/* */}
{/* ГАВРИЛОВ как защищаешься от csrf если комментируешь поле ниже? */} {/* */}
dateData.value === orderData.taxi_time) : null} size = 'm' onChange = {(_, sel:{caption:string, id:string, value:string}) => { let selOrderTime = (sel ? sel.value : null); setOrderData(prevData => ( {...prevData, taxi_time: selOrderTime} )); //Проверяем относится ли выбранный промежуток времени заказа к утру или нет. Если выбран утренний промежуток, дата откуда - адрес сотрудника, адрес куда - офис, если выбран вечерний промежуток - наоборот if (orderTimePeriods.filter( e => selOrderTime == e.time_period )[0].is_morning_time == 1) { console.log(1) setOrderData(prevData => ( {...prevData, taxi_address_from: editOrderUserData.emp_address, taxi_address_to: empOfficeAddress} )); } else { console.log(2) console.log(empOfficeAddress) setOrderData(prevData => ( {...prevData, taxi_address_from: empOfficeAddress, taxi_address_to: editOrderUserData.emp_address} )); } //Если проверка соответствия и времени заказа не выполняется, сбрасываем дату if (!checkTimeAndDate(selOrderTime, orderData.taxi_date)) { popupContext.addPopupArrTest( [{message: 'Несоответствие времени и даты', type: 'error'}] ) setOrderData(prevData => ({...prevData, taxi_date: null})); } }} />