158 lines
5.3 KiB
JavaScript
158 lines
5.3 KiB
JavaScript
import React from "react";
|
|
import { useTranslation } from 'react-i18next';
|
|
import CloseIcon from "../icons/CloseIcon";
|
|
|
|
// ─── Input field component ───────────────────────────────────────────────────
|
|
function InputField({ label, error, ...props }) {
|
|
return (
|
|
<div className="f-m-group">
|
|
<label className="f-m-label">{label}</label>
|
|
<input
|
|
className={`f-m-field${error ? " err" : ""}`}
|
|
{...props}
|
|
/>
|
|
{error && <p className="f-err-msg">{error}</p>}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// ─── Image upload component ──────────────────────────────────────────────────
|
|
function ImageUpload({
|
|
displayImage,
|
|
imgError,
|
|
compressing,
|
|
fileInputRef,
|
|
onFileChange,
|
|
onRemove,
|
|
}) {
|
|
const { t } = useTranslation();
|
|
const MAX_SIZE_MB = 5;
|
|
|
|
return (
|
|
<div className="f-m-group">
|
|
<label className="f-m-label">{t('profile.photoLabel')}</label>
|
|
{displayImage ? (
|
|
<div className="f-img-preview-wrap">
|
|
<img src={displayImage} alt="profile" className="f-img-preview" />
|
|
<button
|
|
className="f-img-remove"
|
|
onClick={onRemove}
|
|
type="button"
|
|
aria-label={t('profile.deletePhoto')}
|
|
>
|
|
<CloseIcon />
|
|
</button>
|
|
</div>
|
|
) : (
|
|
<label className="f-img-upload-label" aria-disabled={compressing}>
|
|
<input
|
|
ref={fileInputRef}
|
|
type="file"
|
|
accept="image/jpeg,image/png,image/webp"
|
|
onChange={onFileChange}
|
|
className="f-img-input"
|
|
disabled={compressing}
|
|
/>
|
|
{compressing ? <span>{t('profile.processing')}</span> : <span>{t('profile.addPhoto')}</span>}
|
|
</label>
|
|
)}
|
|
{imgError && <p className="f-err-msg">{imgError}</p>}
|
|
<p className="f-hint">{t('profile.photoHint', { maxSize: MAX_SIZE_MB })}</p>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// ─── Login field ─────────────────────────────────────────────────────────────
|
|
function LoginField({ form, errors, onChange }) {
|
|
const { t } = useTranslation();
|
|
return (
|
|
<InputField
|
|
label={t('profile.loginLabel')}
|
|
placeholder="username"
|
|
value={form.login}
|
|
error={errors.login}
|
|
onChange={(e) => onChange("login", e.target.value)}
|
|
/>
|
|
);
|
|
}
|
|
|
|
// ─── Name fields row ─────────────────────────────────────────────────────────
|
|
function NameFieldsRow({ form, errors, onChange }) {
|
|
const { t } = useTranslation();
|
|
return (
|
|
<div className="f-m-row">
|
|
<InputField
|
|
label={t('profile.nameLabel')}
|
|
placeholder={t('profile.namePlaceholder')}
|
|
value={form.firstName}
|
|
error={errors.firstName}
|
|
onChange={(e) => onChange("firstName", e.target.value)}
|
|
/>
|
|
<InputField
|
|
label={t('profile.surnameLabel')}
|
|
placeholder={t('profile.surnamePlaceholder')}
|
|
value={form.lastName}
|
|
error={errors.lastName}
|
|
onChange={(e) => onChange("lastName", e.target.value)}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// ─── Contact fields ─────────────────────────────────────────────────────────
|
|
function ContactFields({ form, errors, onChange, onPhoneChange }) {
|
|
const { t } = useTranslation();
|
|
return (
|
|
<>
|
|
<InputField
|
|
label={t('profile.phoneLabel')}
|
|
type="tel"
|
|
placeholder="+7 (___) ___-__-__"
|
|
value={form.phone}
|
|
error={errors.phone}
|
|
onChange={(e) => onPhoneChange(e.target.value)}
|
|
/>
|
|
<InputField
|
|
label={t('profile.emailLabel')}
|
|
type="email"
|
|
placeholder="example@email.com"
|
|
value={form.email}
|
|
error={errors.email}
|
|
onChange={(e) => onChange("email", e.target.value)}
|
|
/>
|
|
</>
|
|
);
|
|
}
|
|
|
|
// ─── Submit button ──────────────────────────────────────────────────────────
|
|
function SubmitButton({ loading, onSubmit }) {
|
|
const { t } = useTranslation();
|
|
return (
|
|
<button
|
|
className="f-m-submit"
|
|
onClick={onSubmit}
|
|
disabled={loading}
|
|
>
|
|
<div className="f-m-submit-row">
|
|
{loading && <div className="f-m-spinner" />}
|
|
{t('profile.save')}
|
|
</div>
|
|
</button>
|
|
);
|
|
}
|
|
|
|
// ─── Modal header ──────────────────────────────────────────────────────────
|
|
function ModalHeader({ onClose }) {
|
|
const { t } = useTranslation();
|
|
return (
|
|
<div className="f-modal-head">
|
|
<span className="f-modal-title">{t('profile.editTitle')}</span>
|
|
<button className="f-close-btn" onClick={onClose}>
|
|
<CloseIcon />
|
|
</button>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export { InputField, ImageUpload, LoginField, NameFieldsRow, ContactFields, SubmitButton, ModalHeader };
|