chore: initial import for test contour
This commit is contained in:
@@ -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>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user