added english language
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import {useCallback, useEffect, useState} from "react";
|
||||
import CloseIcon from "./icons/CloseIcon";
|
||||
import { EMPTY_FORM, CATEGORIES } from "../config/feedConstants";
|
||||
import { EMPTY_FORM, CATEGORY_KEYS } from "../config/feedConstants";
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { usePostMutation } from "../hooks/usePostMutation";
|
||||
import { useImageUpload, ACCEPT } from "../hooks/useImageUpload";
|
||||
import { validatePostForm } from "../utils/validatePostForm";
|
||||
@@ -19,6 +20,7 @@ const MAX_SIZE_MB = 5;
|
||||
export default function CreateUpdatePost({ onClose, onSuccess, initialData }) {
|
||||
// Режим: редактирование (true) или создание нового (false)
|
||||
const isEdit = !!initialData;
|
||||
const { t } = useTranslation();
|
||||
|
||||
// Поля формы; при редактировании заполняем из initialData
|
||||
const [form, setForm] = useState(
|
||||
@@ -88,7 +90,7 @@ export default function CreateUpdatePost({ onClose, onSuccess, initialData }) {
|
||||
}
|
||||
|
||||
if (coords && !addressRef.current) {
|
||||
setErrors(prev => ({ ...prev, map: "Подождите, адрес загружается..." }));
|
||||
setErrors(prev => ({ ...prev, map: t('post.mapLoading') }));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -136,7 +138,7 @@ export default function CreateUpdatePost({ onClose, onSuccess, initialData }) {
|
||||
{/* Шапка модалки */}
|
||||
<div className="f-modal-head">
|
||||
<span className="f-modal-title">
|
||||
{isEdit ? "Редактировать объявление" : "Новое объявление"}
|
||||
{isEdit ? t('post.editTitle') : t('post.newTitle')}
|
||||
</span>
|
||||
<button className="f-close-btn" onClick={onClose}>
|
||||
<CloseIcon/>
|
||||
@@ -145,31 +147,31 @@ export default function CreateUpdatePost({ onClose, onSuccess, initialData }) {
|
||||
|
||||
{/* Тип: Потеря / Находка */}
|
||||
<div className="f-m-group">
|
||||
<label className="f-m-label">Тип объявления</label>
|
||||
<label className="f-m-label">{t('post.typeLabel')}</label>
|
||||
<div className="f-type-toggle">
|
||||
<button
|
||||
className={`f-type-opt${form.type === "loss" ? " loss" : ""}`}
|
||||
onClick={() => set("type", "loss")}
|
||||
>
|
||||
Потеря
|
||||
{t('post.loss')}
|
||||
</button>
|
||||
<button
|
||||
className={`f-type-opt${form.type === "found" ? " found"
|
||||
: ""}`}
|
||||
onClick={() => set("type", "found")}
|
||||
>
|
||||
Находка
|
||||
{t('post.found')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Название */}
|
||||
<div className="f-m-group">
|
||||
<label className="f-m-label">Название</label>
|
||||
<label className="f-m-label">{t('post.titleLabel')}</label>
|
||||
<input
|
||||
className={`f-m-field${errors.title ? " err" : ""}`}
|
||||
type="text"
|
||||
placeholder="Например: Кошелёк чёрный кожаный"
|
||||
placeholder={t('post.titlePlaceholder')}
|
||||
value={form.title}
|
||||
onChange={e => set("title", e.target.value)}
|
||||
/>
|
||||
@@ -178,11 +180,11 @@ export default function CreateUpdatePost({ onClose, onSuccess, initialData }) {
|
||||
|
||||
{/* Описание */}
|
||||
<div className="f-m-group">
|
||||
<label className="f-m-label">Описание</label>
|
||||
<label className="f-m-label">{t('post.descriptionLabel')}</label>
|
||||
<textarea
|
||||
className={`f-m-field${errors.description ? " err" : ""}`}
|
||||
rows={3}
|
||||
placeholder="Подробно опишите предмет — цвет, размер, особые приметы..."
|
||||
placeholder={t('post.descriptionPlaceholder')}
|
||||
value={form.description}
|
||||
onChange={e => set("description", e.target.value)}
|
||||
/>
|
||||
@@ -192,7 +194,7 @@ export default function CreateUpdatePost({ onClose, onSuccess, initialData }) {
|
||||
|
||||
{/* Фотографии: сетка превью + кнопка добавления */}
|
||||
<div className="f-m-group">
|
||||
<label className="f-m-label">Фотографии</label>
|
||||
<label className="f-m-label">{t('post.photosLabel')}</label>
|
||||
|
||||
{uploadedImages.length > 0 && (
|
||||
<div className="f-img-grid">
|
||||
@@ -203,7 +205,7 @@ export default function CreateUpdatePost({ onClose, onSuccess, initialData }) {
|
||||
className="f-img-remove"
|
||||
onClick={() => removeImage(img.id)}
|
||||
type="button"
|
||||
aria-label="Удалить фото"
|
||||
aria-label={t('post.deletePhoto')}
|
||||
>
|
||||
<CloseIcon/>
|
||||
</button>
|
||||
@@ -226,27 +228,27 @@ export default function CreateUpdatePost({ onClose, onSuccess, initialData }) {
|
||||
disabled={compressing}
|
||||
/>
|
||||
{compressing ? (
|
||||
<span>Обработка...</span>
|
||||
<span>{t('post.processing')}</span>
|
||||
) : (
|
||||
<span>{uploadedImages.length > 0 ? "➕ Добавить ещё" : "📷 Добавить фото"}</span>
|
||||
<span>{uploadedImages.length > 0 ? t('post.addMore') : t('post.addPhoto')}</span>
|
||||
)}
|
||||
</label>
|
||||
|
||||
{imgError && <p className="f-err-msg">{imgError}</p>}
|
||||
<p className="f-hint">JPEG / PNG / WebP · до {MAX_SIZE_MB} МБ · можно несколько</p>
|
||||
<p className="f-hint">{t('post.photoHint', { maxSize: MAX_SIZE_MB })}</p>
|
||||
</div>
|
||||
|
||||
{/* Категория */}
|
||||
<div className="f-m-row">
|
||||
<div className="f-m-group">
|
||||
<label className="f-m-label">Категория</label>
|
||||
<label className="f-m-label">{t('post.categoryLabel')}</label>
|
||||
<select
|
||||
className={`f-m-field${errors.category ? " err" : ""}`}
|
||||
value={form.category}
|
||||
onChange={e => set("category", e.target.value)}
|
||||
>
|
||||
<option value="">Выбрать...</option>
|
||||
{CATEGORIES.map(c => <option key={c} value={c}>{c}</option>)}
|
||||
<option value="">{t('categories.select')}</option>
|
||||
{CATEGORY_KEYS.map(k => <option key={k} value={t(k)}>{t(k)}</option>)}
|
||||
</select>
|
||||
{errors.category && <p
|
||||
className="f-err-msg">{errors.category}</p>}
|
||||
@@ -255,7 +257,7 @@ export default function CreateUpdatePost({ onClose, onSuccess, initialData }) {
|
||||
|
||||
{/* Карта */}
|
||||
<div className="f-m-group">
|
||||
<label className="f-m-label">Место на карте</label>
|
||||
<label className="f-m-label">{t('post.mapLabel')}</label>
|
||||
<div style={{
|
||||
width: "100%",
|
||||
height: 260,
|
||||
@@ -265,17 +267,16 @@ export default function CreateUpdatePost({ onClose, onSuccess, initialData }) {
|
||||
<div ref={mapRef} style={{width: "100%", height: "100%"}}/>
|
||||
</div>
|
||||
|
||||
{!coords && <p className="f-hint">Нажмите на карту, чтобы отметить
|
||||
место</p>}
|
||||
{!coords && <p className="f-hint">{t('post.mapHint')}</p>}
|
||||
{errors.map && <p className="f-err-msg">{errors.map}</p>}
|
||||
</div>
|
||||
|
||||
<div className="f-m-group">
|
||||
<label className="f-m-label">Адрес</label>
|
||||
<label className="f-m-label">{t('post.addressLabel')}</label>
|
||||
<input
|
||||
className={`f-m-field${errors.address ? " err" : ""}`}
|
||||
type="text"
|
||||
placeholder="Например: Москва, ул. Ленина, 5"
|
||||
placeholder={t('post.addressPlaceholder')}
|
||||
value={form.address}
|
||||
onChange={e => set("address", e.target.value)}
|
||||
/>
|
||||
@@ -284,11 +285,11 @@ export default function CreateUpdatePost({ onClose, onSuccess, initialData }) {
|
||||
|
||||
{/* Телефон с автоматической маской */}
|
||||
<div className="f-m-group">
|
||||
<label className="f-m-label">Номер телефона</label>
|
||||
<label className="f-m-label">{t('post.phoneLabel')}</label>
|
||||
<input
|
||||
className={`f-m-field${errors.phone ? " err" : ""}`}
|
||||
type="tel"
|
||||
placeholder="+7 (___) ___-__-__"
|
||||
placeholder={t('post.phonePlaceholder')}
|
||||
value={form.phone}
|
||||
onChange={e => set("phone", formatPhone(e.target.value))}
|
||||
/>
|
||||
@@ -302,7 +303,7 @@ export default function CreateUpdatePost({ onClose, onSuccess, initialData }) {
|
||||
disabled={loading}>
|
||||
<div className="f-m-submit-row">
|
||||
{loading && <div className="f-m-spinner"/>}
|
||||
{isEdit ? "Сохранить изменения" : "Разместить объявление"}
|
||||
{isEdit ? t('post.saveChanges') : t('post.publish')}
|
||||
</div>
|
||||
</button>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user