v3.9.5: Добавлена возможность копирования желаний, исправлена замена изображений
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 48s
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 48s
This commit is contained in:
@@ -8,7 +8,7 @@ const API_URL = '/api/wishlist'
|
||||
const TASKS_API_URL = '/api/tasks'
|
||||
const PROJECTS_API_URL = '/projects'
|
||||
|
||||
function WishlistForm({ onNavigate, wishlistId }) {
|
||||
function WishlistForm({ onNavigate, wishlistId, editConditionIndex }) {
|
||||
const { authFetch } = useAuth()
|
||||
const [name, setName] = useState('')
|
||||
const [price, setPrice] = useState('')
|
||||
@@ -21,6 +21,7 @@ function WishlistForm({ onNavigate, wishlistId }) {
|
||||
const [croppedAreaPixels, setCroppedAreaPixels] = useState(null)
|
||||
const [unlockConditions, setUnlockConditions] = useState([])
|
||||
const [showConditionForm, setShowConditionForm] = useState(false)
|
||||
const [editingConditionIndex, setEditingConditionIndex] = useState(null)
|
||||
const [tasks, setTasks] = useState([])
|
||||
const [projects, setProjects] = useState([])
|
||||
const [loading, setLoading] = useState(false)
|
||||
@@ -28,6 +29,7 @@ function WishlistForm({ onNavigate, wishlistId }) {
|
||||
const [toastMessage, setToastMessage] = useState(null)
|
||||
const [loadingWishlist, setLoadingWishlist] = useState(false)
|
||||
const [fetchingMetadata, setFetchingMetadata] = useState(false)
|
||||
const fileInputRef = useRef(null)
|
||||
|
||||
// Загрузка задач и проектов
|
||||
useEffect(() => {
|
||||
@@ -62,6 +64,14 @@ function WishlistForm({ onNavigate, wishlistId }) {
|
||||
}
|
||||
}, [wishlistId, tasks, projects])
|
||||
|
||||
// Открываем форму редактирования условия, если передан editConditionIndex
|
||||
useEffect(() => {
|
||||
if (editConditionIndex !== undefined && editConditionIndex !== null && unlockConditions.length > editConditionIndex) {
|
||||
setEditingConditionIndex(editConditionIndex)
|
||||
setShowConditionForm(true)
|
||||
}
|
||||
}, [editConditionIndex, unlockConditions])
|
||||
|
||||
const loadWishlist = async () => {
|
||||
setLoadingWishlist(true)
|
||||
try {
|
||||
@@ -74,6 +84,7 @@ function WishlistForm({ onNavigate, wishlistId }) {
|
||||
setPrice(data.price ? String(data.price) : '')
|
||||
setLink(data.link || '')
|
||||
setImageUrl(data.image_url || null)
|
||||
setImageFile(null) // Сбрасываем imageFile при загрузке существующего желания
|
||||
if (data.unlock_conditions) {
|
||||
setUnlockConditions(data.unlock_conditions.map((cond, idx) => ({
|
||||
type: cond.type,
|
||||
@@ -256,12 +267,32 @@ function WishlistForm({ onNavigate, wishlistId }) {
|
||||
}
|
||||
|
||||
const handleAddCondition = () => {
|
||||
setEditingConditionIndex(null)
|
||||
setShowConditionForm(true)
|
||||
}
|
||||
|
||||
const handleEditCondition = (index) => {
|
||||
setEditingConditionIndex(index)
|
||||
setShowConditionForm(true)
|
||||
}
|
||||
|
||||
const handleConditionSubmit = (condition) => {
|
||||
setUnlockConditions([...unlockConditions, { ...condition, display_order: unlockConditions.length }])
|
||||
if (editingConditionIndex !== null) {
|
||||
// Редактирование существующего условия
|
||||
setUnlockConditions(prev => prev.map((cond, idx) =>
|
||||
idx === editingConditionIndex ? { ...condition, display_order: idx } : cond
|
||||
))
|
||||
} else {
|
||||
// Добавление нового условия
|
||||
setUnlockConditions([...unlockConditions, { ...condition, display_order: unlockConditions.length }])
|
||||
}
|
||||
setShowConditionForm(false)
|
||||
setEditingConditionIndex(null)
|
||||
}
|
||||
|
||||
const handleConditionCancel = () => {
|
||||
setShowConditionForm(false)
|
||||
setEditingConditionIndex(null)
|
||||
}
|
||||
|
||||
const handleRemoveCondition = (index) => {
|
||||
@@ -331,6 +362,12 @@ function WishlistForm({ onNavigate, wishlistId }) {
|
||||
|
||||
if (!imageResponse.ok) {
|
||||
setToastMessage({ text: 'Желание сохранено, но ошибка при загрузке картинки', type: 'warning' })
|
||||
} else {
|
||||
// Обновляем imageUrl после успешной загрузки
|
||||
const imageData = await imageResponse.json()
|
||||
if (imageData.image_url) {
|
||||
setImageUrl(imageData.image_url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -429,7 +466,13 @@ function WishlistForm({ onNavigate, wishlistId }) {
|
||||
<label>Картинка</label>
|
||||
{imageUrl && !showCropper && (
|
||||
<div className="image-preview">
|
||||
<img src={imageUrl} alt="Preview" />
|
||||
<img
|
||||
src={imageUrl}
|
||||
alt="Preview"
|
||||
onClick={() => fileInputRef.current?.click()}
|
||||
style={{ cursor: 'pointer' }}
|
||||
title="Нажмите, чтобы изменить"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
@@ -442,14 +485,14 @@ function WishlistForm({ onNavigate, wishlistId }) {
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
{!imageUrl && (
|
||||
<input
|
||||
type="file"
|
||||
accept="image/*"
|
||||
onChange={handleImageSelect}
|
||||
className="form-input"
|
||||
/>
|
||||
)}
|
||||
<input
|
||||
ref={fileInputRef}
|
||||
type="file"
|
||||
accept="image/*"
|
||||
onChange={handleImageSelect}
|
||||
className="form-input"
|
||||
style={{ display: imageUrl ? 'none' : 'block' }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{showCropper && (
|
||||
@@ -495,7 +538,10 @@ function WishlistForm({ onNavigate, wishlistId }) {
|
||||
<div className="conditions-list">
|
||||
{unlockConditions.map((cond, idx) => (
|
||||
<div key={idx} className="condition-item">
|
||||
<span>
|
||||
<span
|
||||
className="condition-item-text"
|
||||
onClick={() => handleEditCondition(idx)}
|
||||
>
|
||||
{cond.type === 'task_completion'
|
||||
? `Задача: ${tasks.find(t => t.id === cond.task_id)?.name || 'Не выбрана'}`
|
||||
: `Баллы: ${cond.required_points} в ${projects.find(p => p.project_id === cond.project_id)?.project_name || 'Не выбран'}${cond.start_date ? ` с ${new Date(cond.start_date + 'T00:00:00').toLocaleDateString('ru-RU')}` : ' за всё время'}`}
|
||||
@@ -516,7 +562,7 @@ function WishlistForm({ onNavigate, wishlistId }) {
|
||||
onClick={handleAddCondition}
|
||||
className="add-condition-button"
|
||||
>
|
||||
Добавить условие
|
||||
Добавить цель
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -534,7 +580,8 @@ function WishlistForm({ onNavigate, wishlistId }) {
|
||||
tasks={tasks}
|
||||
projects={projects}
|
||||
onSubmit={handleConditionSubmit}
|
||||
onCancel={() => setShowConditionForm(false)}
|
||||
onCancel={handleConditionCancel}
|
||||
editingCondition={editingConditionIndex !== null ? unlockConditions[editingConditionIndex] : null}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -627,13 +674,15 @@ function DateSelector({ value, onChange, placeholder = "За всё время"
|
||||
)
|
||||
}
|
||||
|
||||
// Компонент формы условия разблокировки
|
||||
function ConditionForm({ tasks, projects, onSubmit, onCancel }) {
|
||||
const [type, setType] = useState('project_points')
|
||||
const [taskId, setTaskId] = useState('')
|
||||
const [projectId, setProjectId] = useState('')
|
||||
const [requiredPoints, setRequiredPoints] = useState('')
|
||||
const [startDate, setStartDate] = useState('')
|
||||
// Компонент формы цели
|
||||
function ConditionForm({ tasks, projects, onSubmit, onCancel, editingCondition }) {
|
||||
const [type, setType] = useState(editingCondition?.type || 'project_points')
|
||||
const [taskId, setTaskId] = useState(editingCondition?.task_id?.toString() || '')
|
||||
const [projectId, setProjectId] = useState(editingCondition?.project_id?.toString() || '')
|
||||
const [requiredPoints, setRequiredPoints] = useState(editingCondition?.required_points?.toString() || '')
|
||||
const [startDate, setStartDate] = useState(editingCondition?.start_date || '')
|
||||
|
||||
const isEditing = editingCondition !== null
|
||||
|
||||
const handleSubmit = (e) => {
|
||||
e.preventDefault()
|
||||
@@ -666,7 +715,7 @@ function ConditionForm({ tasks, projects, onSubmit, onCancel }) {
|
||||
return (
|
||||
<div className="condition-form-overlay" onClick={onCancel}>
|
||||
<div className="condition-form" onClick={(e) => e.stopPropagation()}>
|
||||
<h3>Добавить условие разблокировки</h3>
|
||||
<h3>{isEditing ? 'Редактировать цель' : 'Добавить цель'}</h3>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="form-group">
|
||||
<label>Тип условия</label>
|
||||
@@ -742,7 +791,7 @@ function ConditionForm({ tasks, projects, onSubmit, onCancel }) {
|
||||
Отмена
|
||||
</button>
|
||||
<button type="submit" className="submit-button">
|
||||
Добавить
|
||||
{isEditing ? 'Сохранить' : 'Добавить'}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
Reference in New Issue
Block a user