6.18.5: Фиксированные кнопки в формах задачи и желания
Some checks failed
Build and Push Docker Image / build-and-push (push) Failing after 1m19s

This commit is contained in:
poignatov
2026-03-16 07:49:56 +03:00
parent 1876595005
commit 5ea58476cb
5 changed files with 86 additions and 28 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "play-life-web",
"version": "6.18.4",
"version": "6.18.5",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -1360,6 +1360,7 @@ function AppContent() {
wishlistId={tabParams.wishlistId}
returnTo={tabParams.returnTo}
returnWishlistId={tabParams.returnWishlistId}
isActive={activeTab === 'task-form'}
/>
</div>
</div>
@@ -1389,6 +1390,7 @@ function AppContent() {
editConditionIndex={tabParams.editConditionIndex}
newTaskId={tabParams.newTaskId}
boardId={tabParams.boardId}
isActive={activeTab === 'wishlist-form'}
/>
</div>
</div>

View File

@@ -1,4 +1,5 @@
import React, { useState, useEffect, useRef } from 'react'
import { createPortal } from 'react-dom'
import { useAuth } from './auth/AuthContext'
import Toast from './Toast'
import SubmitButton from './SubmitButton'
@@ -8,7 +9,7 @@ import './TaskForm.css'
const API_URL = '/api/tasks'
const PROJECTS_API_URL = '/projects'
function TaskForm({ onNavigate, taskId, wishlistId, returnTo, returnWishlistId }) {
function TaskForm({ onNavigate, taskId, wishlistId, returnTo, returnWishlistId, isActive }) {
const { authFetch } = useAuth()
const [name, setName] = useState('')
const [progressionBase, setProgressionBase] = useState('')
@@ -885,6 +886,7 @@ function TaskForm({ onNavigate, taskId, wishlistId, returnTo, returnWishlistId }
}
return (
<>
<div className="task-form">
<button className="close-x-button" onClick={handleCancel}>
@@ -900,7 +902,7 @@ function TaskForm({ onNavigate, taskId, wishlistId, returnTo, returnWishlistId }
<>
<h2>{taskId ? 'Редактировать задачу' : 'Новая задача'}</h2>
<form onSubmit={handleSubmit}>
<form id="task-form-element" onSubmit={handleSubmit}>
<div className="form-group">
<label htmlFor="name">Название задачи *</label>
<input
@@ -1393,23 +1395,6 @@ function TaskForm({ onNavigate, taskId, wishlistId, returnTo, returnWishlistId }
<div className="error-message">{error}</div>
)}
<div className="form-actions">
<SubmitButton
type="submit"
loading={loading}
disabled={isDeleting}
>
Сохранить
</SubmitButton>
{taskId && (
<DeleteButton
onClick={handleDelete}
loading={isDeleting}
disabled={loading}
title="Удалить задачу"
/>
)}
</div>
</form>
{toastMessage && (
<Toast
@@ -1421,6 +1406,41 @@ function TaskForm({ onNavigate, taskId, wishlistId, returnTo, returnWishlistId }
</>
)}
</div>
{isActive ? createPortal(
<div style={{
position: 'fixed',
bottom: 0,
left: 0,
right: 0,
padding: '0.75rem 1rem',
paddingBottom: 'max(0.75rem, env(safe-area-inset-bottom))',
background: 'linear-gradient(to top, white 60%, rgba(255,255,255,0))',
zIndex: 1500,
display: 'flex',
justifyContent: 'center',
gap: '0.75rem',
}}>
<SubmitButton
type="submit"
form="task-form-element"
loading={loading}
disabled={isDeleting}
style={{ flex: 1, maxWidth: '42rem' }}
>
Сохранить
</SubmitButton>
{taskId && (
<DeleteButton
onClick={handleDelete}
loading={isDeleting}
disabled={loading}
title="Удалить задачу"
/>
)}
</div>,
document.body
) : null}
</>
)
}

View File

@@ -1,4 +1,5 @@
import React, { useState, useEffect, useCallback, useRef } from 'react'
import { createPortal } from 'react-dom'
import Cropper from 'react-easy-crop'
import { useAuth } from './auth/AuthContext'
import Toast from './Toast'
@@ -16,7 +17,7 @@ const TASKS_API_URL = '/api/tasks'
const PROJECTS_API_URL = '/projects'
const WISHLIST_FORM_STATE_KEY = 'wishlistFormPendingState'
function WishlistForm({ onNavigate, wishlistId, editConditionIndex, newTaskId: newTaskIdProp, boardId }) {
function WishlistForm({ onNavigate, wishlistId, editConditionIndex, newTaskId: newTaskIdProp, boardId, isActive }) {
const { authFetch, user } = useAuth()
// newTaskId может прийти из props (через onNavigate) или из sessionStorage (через history.back)
@@ -791,6 +792,7 @@ function WishlistForm({ onNavigate, wishlistId, editConditionIndex, newTaskId: n
}
return (
<>
<div className="wishlist-form">
<button className="close-x-button" onClick={handleCancel}>
@@ -806,7 +808,7 @@ function WishlistForm({ onNavigate, wishlistId, editConditionIndex, newTaskId: n
<>
<h2>{wishlistId ? 'Редактировать желание' : 'Новое желание'}</h2>
<form onSubmit={handleSubmit}>
<form id="wishlist-form-element" onSubmit={handleSubmit}>
<div className="form-group">
<label htmlFor="link">Ссылка</label>
<div className="link-input-wrapper">
@@ -1038,11 +1040,6 @@ function WishlistForm({ onNavigate, wishlistId, editConditionIndex, newTaskId: n
{error && <div className="error-message">{error}</div>}
<div className="form-actions">
<button type="submit" disabled={loading} className="submit-button">
{loading ? 'Сохранение...' : 'Сохранить'}
</button>
</div>
</form>
{showConditionForm && (
@@ -1068,6 +1065,45 @@ function WishlistForm({ onNavigate, wishlistId, editConditionIndex, newTaskId: n
</>
)}
</div>
{isActive ? createPortal(
<div style={{
position: 'fixed',
bottom: 0,
left: 0,
right: 0,
padding: '0.75rem 1rem',
paddingBottom: 'max(0.75rem, env(safe-area-inset-bottom))',
background: 'linear-gradient(to top, white 60%, rgba(255,255,255,0))',
zIndex: 1500,
display: 'flex',
justifyContent: 'center',
}}>
<button
type="submit"
form="wishlist-form-element"
disabled={loading}
style={{
width: '100%',
maxWidth: '42rem',
padding: '0.875rem',
background: loading ? undefined : 'linear-gradient(to right, #10b981, #059669)',
backgroundColor: loading ? '#9ca3af' : undefined,
color: 'white',
border: 'none',
borderRadius: '0.5rem',
fontSize: '1rem',
fontWeight: 600,
cursor: loading ? 'not-allowed' : 'pointer',
opacity: loading ? 0.6 : 1,
transition: 'all 0.2s',
}}
>
{loading ? 'Сохранение...' : 'Сохранить'}
</button>
</div>,
document.body
) : null}
</>
)
}