chore: initial import for test contour

This commit is contained in:
sova-bootstrap
2026-05-27 19:36:33 +03:00
commit ffd4cf9031
105 changed files with 10772 additions and 0 deletions
+328
View File
@@ -0,0 +1,328 @@
import { useEffect, useState, useRef } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import { useSelector } from 'react-redux';
import { apiUrl } from '@/config/api';
import { useGetFilialsQuery, useUpdateFilialMutation, useUploadFilialPictureMutation } from '../api/apiFilial';
import { selectUtils } from '../store/slice/utilsSlice';
import { selectRegions } from '../store/slice/regionSlice';
/**/
import { LoadingComponent } from '../components/Placeholders/LoadingComponent';
import { ErrorComponent } from '../components/Placeholders/ErrorComponent';
import { NotFindElement } from '../components/Placeholders/NotFindElement';
import { EditElementForm } from '../components/Forms/EditElementForm';
import { ResponseModals } from '../components/Modals/ResponseModals';
import { PhoneInput } from '../components/Input/PhoneInput';
export const EditFilialPage = () => {
const { id } = useParams();
const { data: filialsRaw = [], isLoading, loadingError } = useGetFilialsQuery();
const PHOTO_PLACEHOLDER = '/src/assets/photo-placeholder.png';
const photoInputRef = useRef(null);
const filials = filialsRaw.length === 0 ? [] : filialsRaw.data;
const filial = filials.find( ( filial ) => String( filial.fid ) === id );
const regions = useSelector( selectRegions );
const RELOAD_TIMEOUT = useSelector(selectUtils).RELOAD_TIMEOUT;
const [ updateFilial ] = useUpdateFilialMutation();
const [uploadPicture] = useUploadFilialPictureMutation();
const navigate = useNavigate();
const navigateBack = () => navigate( `/filials` );
const [ form, setForm ] = useState({
id: '',
regionId: '',
address: '',
name: '',
siteId: '',
company: '',
phone: '',
active: '',
email: '',
fid: '',
origin: '',
picture: null,
policy: '',
});
const updateField = ( key, value ) => {
const normalized = value === undefined || value === null ? '' : value;
setForm(prev => ({ ...prev, [key]: normalized }));
};
const [ modal, setModal ] = useState( undefined );
const [previewFile, setPreviewFile] = useState(null);
useEffect(() => {
if (!filial) return;
const filialData = {
id: filial.id,
regionId: filial.regionId,
address: filial.address,
name: filial.name,
siteId: filial.siteId,
company: filial.company,
phone: filial.phone,
active: filial.active,
email: filial.email,
fid: filial.fid,
origin: filial.origin,
picture: apiUrl(filial.pictureLink),
policy: filial.policy,
}
setForm({... filialData})
}, [ filial ]);
const isValidImage = (file) => {
const allowedTypes = ['image/jpeg', 'image/jpg', 'image/png'];
if (allowedTypes.includes(file.type)) return true;
const ext = file.name.split('.').pop().toLowerCase();
return ['jpg', 'jpeg', 'png'].includes(ext);
};
const handlePhotoUpload = () => {
const file = photoInputRef.current.files[0]
if (!file) return window.alert('Файл не выбран')
if (!isValidImage(file)) {
return window.alert('Изображения должны быть только формата JPG, JPEG или PNG');
}
updateField('picture', window.URL.createObjectURL(file));
setPreviewFile(file);
}
const handleSave = async () => {
setModal('loading');
const data = {
id: form.id,
fid: form.fid,
active: form.active,
regionId: Number(form.regionId),
address: form.address || '',
name: form.name || '',
company: form.company || '',
phone: form.phone ? form.phone.replaceAll(' ', '') : '',
email: form.email || '',
policy: form.policy || '',
origin: form.origin || '',
};
try {
await updateFilial( { filialId: form.fid, data: form.siteId ? { ...data, siteId: form.siteId } : data } ).unwrap();
if (previewFile) {
await uploadPicture({ id: form.id, file: previewFile }).unwrap();
console.log('success photo update')
}
setModal('success');
window.setTimeout(() => { window.location.reload() }, RELOAD_TIMEOUT);
}
catch ( error ) {
setModal('error')
console.error('Filial update error:', error);
}
}
if ( isLoading ) return <LoadingComponent />
if ( loadingError ) return <ErrorComponent />
if ( !filial ) return (
<NotFindElement
message={ `Филиал с ID=${id} не найден.` }
navigateBack={ navigateBack }
/>
)
return (
<EditElementForm
navigateBack={ navigateBack }
header={ `Редактировать филиал #${ filial.fid }` }
handleSave={ handleSave }
isAddSpecialist={ true }
>
<div style={{ display: 'flex', gap: '1rem' }} className='photo-filial-block'>
<div className='align-self-start'>
<div className="form-group d-flex flex-column" style={{ gap: '0.75rem' }}>
<img
src={ form.picture }
alt="Фото врача"
style={{ width: '12rem', height: '12rem', objectFit: 'cover', borderRadius: '3%' }}
className=""
onError={ e => e.currentTarget.src = PHOTO_PLACEHOLDER }
/>
<button
type="button"
className="btn btn-outline-secondary"
style={{ width: '100%' }}
onClick={ () => photoInputRef.current.click() }
>
Загрузить фото
</button>
<input
type="file"
accept="image/*"
ref={ photoInputRef }
style={{ display: 'none' }}
onChange={handlePhotoUpload}
/>
</div>
</div>
<div style={{ flexGrow: 1 }}>
<div style={{ flexGrow: 1 }}>
<div className='d-flex filial-input-string' style={{ gap: '1rem' }}>
<div className="form-group">
<label htmlFor="regionSelect">
Город
</label>
<select
id="regionSelect"
className="form-control w-auto"
value={ form.regionId }
onChange={( e ) => updateField( 'regionId', e.target.value )}
>
{
Object.entries( regions ).map(( [ key, label ] ) => (
<option key={ key } value={ key }>
{ label }
</option>
))
}
</select>
</div>
<div className="form-group" style={{ flexGrow: 1 }}>
<label>
ID филиала
</label>
<input
type="text"
className="form-control"
value={ form.fid }
onChange={( e ) => updateField( 'fid', e.target.value )}
/>
</div>
<div className="form-group" style={{ flexGrow: 1 }}>
<label>
Calltouch ID
</label>
<input
type="text"
className="form-control"
value={ form.siteId }
onChange={( e ) => updateField( 'siteId', e.target.value )}
/>
</div>
</div>
</div>
<div>
<div className="form-group">
<label>
Название
</label>
<input
type="text"
className="form-control"
value={ form.name }
onChange={( e ) => updateField( 'name', e.target.value )}
/>
</div>
<div className="form-group">
<label>
Компания
</label>
<input
type="text"
className="form-control"
value={ form.company }
onChange={( e ) => updateField( 'company', e.target.value )}
/>
</div>
</div>
</div>
</div>
<div className="form-group">
<label>
Адрес
</label>
<input
type="text"
className="form-control"
value={ form.address }
onChange={( e ) => updateField( 'address', e.target.value )}
/>
</div>
<div className="form-group">
<label>
Телефон
</label>
<PhoneInput
value={form.phone}
onChange={(val) => updateField('phone', val)}
/>
</div>
<div className="form-group">
<label>
Электронная почта филиала
</label>
<input
type="text"
className="form-control"
value={ form.email }
onChange={( e ) => updateField( 'email', e.target.value )}
/>
</div>
<div className="form-group">
<label>
Ссылка на сайт
</label>
<input
type="text"
className="form-control"
value={ form.origin }
onChange={( e ) => updateField( 'origin', e.target.value )}
/>
</div>
<div className="form-group">
<label>
Ссылка на политику кониденциальности
</label>
<input
type="text"
className="form-control"
value={ form.policy }
onChange={( e ) => updateField( 'policy', e.target.value )}
/>
</div>
<ResponseModals
modal={ modal }
setModal={ setModal }
/>
</EditElementForm>
)
}