Исправления задач-желаний и версия 3.22.0
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 50s
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 50s
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "play-life-web",
|
"name": "play-life-web",
|
||||||
"version": "3.21.0",
|
"version": "3.22.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -643,8 +643,8 @@ function TaskForm({ onNavigate, taskId, wishlistId, isTest: isTestFromProps = fa
|
|||||||
// При создании: отправляем currentWishlistId если указан (уже число)
|
// При создании: отправляем currentWishlistId если указан (уже число)
|
||||||
// При редактировании: отправляем null только если была привязка (currentWishlistId) и пользователь отвязал (!wishlistInfo)
|
// При редактировании: отправляем null только если была привязка (currentWishlistId) и пользователь отвязал (!wishlistInfo)
|
||||||
// Если не было привязки или привязка осталась - не отправляем поле (undefined)
|
// Если не было привязки или привязка осталась - не отправляем поле (undefined)
|
||||||
wishlist_id: taskId
|
wishlist_id: taskId
|
||||||
? (currentWishlistId && !wishlistInfo ? null : undefined)
|
? currentWishlistId // При редактировании сохраняем текущую привязку к желанию
|
||||||
: (currentWishlistId || undefined),
|
: (currentWishlistId || undefined),
|
||||||
reward_policy: (wishlistInfo || currentWishlistId) ? rewardPolicy : undefined,
|
reward_policy: (wishlistInfo || currentWishlistId) ? rewardPolicy : undefined,
|
||||||
rewards: rewards.map(r => ({
|
rewards: rewards.map(r => ({
|
||||||
@@ -806,16 +806,6 @@ function TaskForm({ onNavigate, taskId, wishlistId, isTest: isTestFromProps = fa
|
|||||||
<span className="wishlist-link-text">
|
<span className="wishlist-link-text">
|
||||||
Связана с желанием: <strong>{wishlistInfo.name}</strong>
|
Связана с желанием: <strong>{wishlistInfo.name}</strong>
|
||||||
</span>
|
</span>
|
||||||
{taskId && currentWishlistId && (
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={handleUnlinkWishlist}
|
|
||||||
className="wishlist-unlink-x"
|
|
||||||
title="Отвязать от желания"
|
|
||||||
>
|
|
||||||
✕
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
<div className="form-group" style={{ marginTop: '12px' }}>
|
<div className="form-group" style={{ marginTop: '12px' }}>
|
||||||
<label htmlFor="reward_policy">Политика награждения:</label>
|
<label htmlFor="reward_policy">Политика награждения:</label>
|
||||||
@@ -837,7 +827,7 @@ function TaskForm({ onNavigate, taskId, wishlistId, isTest: isTestFromProps = fa
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{!isTest && (
|
{!isTest && !wishlistInfo && (
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<label htmlFor="progression_base">Прогрессия</label>
|
<label htmlFor="progression_base">Прогрессия</label>
|
||||||
<input
|
<input
|
||||||
@@ -920,6 +910,7 @@ function TaskForm({ onNavigate, taskId, wishlistId, isTest: isTestFromProps = fa
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{!wishlistInfo && (
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<label htmlFor="repetition_period">Повторения</label>
|
<label htmlFor="repetition_period">Повторения</label>
|
||||||
{(() => {
|
{(() => {
|
||||||
@@ -1007,6 +998,7 @@ function TaskForm({ onNavigate, taskId, wishlistId, isTest: isTestFromProps = fa
|
|||||||
)
|
)
|
||||||
})()}
|
})()}
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<label htmlFor="reward_message">Сообщение награды</label>
|
<label htmlFor="reward_message">Сообщение награды</label>
|
||||||
|
|||||||
@@ -636,16 +636,16 @@ function TaskList({ onNavigate, data, loading, backgroundLoading, error, onRetry
|
|||||||
<path d="M12 12c0 2.5 1.5 4.5 3.5 4.5S19 14.5 19 12s-1.5-4.5-3.5-4.5S12 9.5 12 12z"/>
|
<path d="M12 12c0 2.5 1.5 4.5 3.5 4.5S19 14.5 19 12s-1.5-4.5-3.5-4.5S12 9.5 12 12z"/>
|
||||||
</svg>
|
</svg>
|
||||||
)}
|
)}
|
||||||
{isOneTime && (
|
{isOneTime && !isWishlist && (
|
||||||
<svg
|
<svg
|
||||||
className="task-onetime-icon"
|
className="task-onetime-icon"
|
||||||
width="16"
|
width="16"
|
||||||
height="16"
|
height="16"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
strokeWidth="2"
|
strokeWidth="2"
|
||||||
strokeLinecap="round"
|
strokeLinecap="round"
|
||||||
strokeLinejoin="round"
|
strokeLinejoin="round"
|
||||||
title="Одноразовая задача"
|
title="Одноразовая задача"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -170,69 +170,34 @@ function WishlistDetail({ wishlistId, onNavigate, onRefresh, boardId }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleUnlinkTask = async (e) => {
|
const handleDeleteTask = async (e) => {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
if (!wishlistItem?.linked_task) return
|
if (!wishlistItem?.linked_task) return
|
||||||
|
|
||||||
|
if (!window.confirm('Удалить задачу, связанную с желанием?')) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Загружаем текущую задачу
|
// Удаляем задачу (помечаем как удалённую)
|
||||||
const taskResponse = await authFetch(`/api/tasks/${wishlistItem.linked_task.id}`)
|
const deleteResponse = await authFetch(`/api/tasks/${wishlistItem.linked_task.id}`, {
|
||||||
if (!taskResponse.ok) {
|
method: 'DELETE',
|
||||||
throw new Error('Ошибка при загрузке задачи')
|
|
||||||
}
|
|
||||||
const taskData = await taskResponse.json()
|
|
||||||
const task = taskData.task
|
|
||||||
|
|
||||||
// Формируем payload для обновления задачи
|
|
||||||
const payload = {
|
|
||||||
name: task.name,
|
|
||||||
reward_message: task.reward_message || null,
|
|
||||||
progression_base: task.progression_base || null,
|
|
||||||
repetition_period: task.repetition_period || null,
|
|
||||||
repetition_date: task.repetition_date || null,
|
|
||||||
wishlist_id: null, // Отвязываем от желания
|
|
||||||
rewards: (task.rewards || []).map(r => ({
|
|
||||||
position: r.position,
|
|
||||||
project_name: r.project_name,
|
|
||||||
value: r.value,
|
|
||||||
use_progression: r.use_progression || false
|
|
||||||
})),
|
|
||||||
subtasks: (task.subtasks || []).map(st => ({
|
|
||||||
id: st.id,
|
|
||||||
name: st.name || null,
|
|
||||||
reward_message: st.reward_message || null,
|
|
||||||
rewards: (st.rewards || []).map(r => ({
|
|
||||||
position: r.position,
|
|
||||||
project_name: r.project_name,
|
|
||||||
value: r.value,
|
|
||||||
use_progression: r.use_progression || false
|
|
||||||
}))
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Обновляем задачу, отвязывая от желания
|
|
||||||
const updateResponse = await authFetch(`/api/tasks/${wishlistItem.linked_task.id}`, {
|
|
||||||
method: 'PUT',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
body: JSON.stringify(payload),
|
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!updateResponse.ok) {
|
if (!deleteResponse.ok) {
|
||||||
const errorData = await updateResponse.json().catch(() => ({}))
|
const errorData = await deleteResponse.json().catch(() => ({}))
|
||||||
throw new Error(errorData.message || errorData.error || 'Ошибка при отвязке задачи')
|
throw new Error(errorData.message || errorData.error || 'Ошибка при удалении задачи')
|
||||||
}
|
}
|
||||||
|
|
||||||
setToastMessage({ text: 'Задача отвязана от желания', type: 'success' })
|
setToastMessage({ text: 'Задача удалена', type: 'success' })
|
||||||
// Обновляем данные желания
|
// Обновляем данные желания
|
||||||
fetchWishlistDetail()
|
fetchWishlistDetail()
|
||||||
if (onRefresh) {
|
if (onRefresh) {
|
||||||
onRefresh()
|
onRefresh()
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Error unlinking task:', err)
|
console.error('Error deleting task:', err)
|
||||||
setToastMessage({ text: err.message || 'Ошибка при отвязке задачи', type: 'error' })
|
setToastMessage({ text: err.message || 'Ошибка при удалении задачи', type: 'error' })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -461,11 +426,17 @@ function WishlistDetail({ wishlistId, onNavigate, onRefresh, boardId }) {
|
|||||||
</div>
|
</div>
|
||||||
<div className="task-actions">
|
<div className="task-actions">
|
||||||
<button
|
<button
|
||||||
className="task-unlink-button"
|
className="task-delete-button"
|
||||||
onClick={handleUnlinkTask}
|
onClick={handleDeleteTask}
|
||||||
title="Отвязать от желания"
|
title="Удалить задачу"
|
||||||
>
|
>
|
||||||
✕
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||||
|
<path d="M3 6h18"></path>
|
||||||
|
<path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"></path>
|
||||||
|
<path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"></path>
|
||||||
|
<line x1="10" y1="11" x2="10" y2="17"></line>
|
||||||
|
<line x1="14" y1="11" x2="14" y2="17"></line>
|
||||||
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user