Files
nahodka-front/src/components/profile/ProfileFormFields.jsx
2026-07-09 00:09:45 +03:00

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 };