diff --git a/VERSION b/VERSION index 4d9fbcf..06edb38 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.25.0 +4.26.0 diff --git a/play-life-backend/main.go b/play-life-backend/main.go index 45daf78..514c99e 100644 --- a/play-life-backend/main.go +++ b/play-life-backend/main.go @@ -8551,6 +8551,49 @@ func (a *App) updateTaskHandler(w http.ResponseWriter, r *http.Request) { rewardPolicyValue = nil // NULL для задач, не связанных с желаниями } + // Получаем текущие значения repetition_period, repetition_date и next_show_at из БД + // для проверки, изменились ли поля повторения + var currentRepetitionPeriod sql.NullString + var currentRepetitionDate sql.NullString + var currentNextShowAt sql.NullTime + err = a.DB.QueryRow("SELECT repetition_period, repetition_date, next_show_at FROM tasks WHERE id = $1", taskID).Scan( + ¤tRepetitionPeriod, + ¤tRepetitionDate, + ¤tNextShowAt, + ) + if err != nil { + log.Printf("Error getting current repetition values: %v", err) + sendErrorWithCORS(w, fmt.Sprintf("Error getting task: %v", err), http.StatusInternalServerError) + return + } + + // Проверяем, изменились ли поля повторения + repetitionChanged := false + if repetitionPeriod.Valid { + // Новое значение есть - проверяем, отличается ли от текущего + if !currentRepetitionPeriod.Valid || currentRepetitionPeriod.String != repetitionPeriod.String { + repetitionChanged = true + } + // Также проверяем, что текущее repetition_date было не NULL (если было, значит изменился тип повторения) + if currentRepetitionDate.Valid { + repetitionChanged = true + } + } else if repetitionDate.Valid { + // Новое значение есть - проверяем, отличается ли от текущего + if !currentRepetitionDate.Valid || currentRepetitionDate.String != repetitionDate.String { + repetitionChanged = true + } + // Также проверяем, что текущее repetition_period было не NULL (если было, значит изменился тип повторения) + if currentRepetitionPeriod.Valid { + repetitionChanged = true + } + } else { + // Оба поля NULL - проверяем, были ли они NULL до этого + if currentRepetitionPeriod.Valid || currentRepetitionDate.Valid { + repetitionChanged = true + } + } + // Используем условный SQL для обработки NULL значений var updateSQL string var updateArgs []interface{} @@ -8564,24 +8607,46 @@ func (a *App) updateTaskHandler(w http.ResponseWriter, r *http.Request) { } if repetitionPeriod.Valid { - // Для repetition_period выставляем сегодняшнюю дату - now := time.Now().In(loc) + // Для repetition_period выставляем сегодняшнюю дату только если поле изменилось + var nextShowAtValue interface{} + if repetitionChanged { + now := time.Now().In(loc) + nextShowAtValue = now + } else { + // Поле не изменилось - сохраняем текущее значение next_show_at + if currentNextShowAt.Valid { + nextShowAtValue = currentNextShowAt.Time + } else { + nextShowAtValue = nil + } + } updateSQL = ` UPDATE tasks SET name = $1, reward_message = $2, progression_base = $3, repetition_period = $4::INTERVAL, repetition_date = NULL, next_show_at = $5, wishlist_id = $6, reward_policy = $7, group_name = $8 WHERE id = $9 ` - updateArgs = []interface{}{strings.TrimSpace(req.Name), rewardMessage, progressionBase, repetitionPeriod.String, now, newWishlistID, rewardPolicyValue, req.GroupName, taskID} + updateArgs = []interface{}{strings.TrimSpace(req.Name), rewardMessage, progressionBase, repetitionPeriod.String, nextShowAtValue, newWishlistID, rewardPolicyValue, req.GroupName, taskID} } else if repetitionDate.Valid { - // Вычисляем next_show_at для задачи с repetition_date - nextShowAt := calculateNextShowAtFromRepetitionDate(repetitionDate.String, time.Now().In(loc)) - if nextShowAt != nil { + // Вычисляем next_show_at для задачи с repetition_date только если поле изменилось + var nextShowAtValue interface{} + if repetitionChanged { + nextShowAt := calculateNextShowAtFromRepetitionDate(repetitionDate.String, time.Now().In(loc)) + nextShowAtValue = nextShowAt + } else { + // Поле не изменилось - сохраняем текущее значение next_show_at + if currentNextShowAt.Valid { + nextShowAtValue = currentNextShowAt.Time + } else { + nextShowAtValue = nil + } + } + if nextShowAtValue != nil { updateSQL = ` UPDATE tasks SET name = $1, reward_message = $2, progression_base = $3, repetition_period = NULL, repetition_date = $4, next_show_at = $5, wishlist_id = $6, reward_policy = $7, group_name = $8 WHERE id = $9 ` - updateArgs = []interface{}{strings.TrimSpace(req.Name), rewardMessage, progressionBase, repetitionDate.String, nextShowAt, newWishlistID, rewardPolicyValue, req.GroupName, taskID} + updateArgs = []interface{}{strings.TrimSpace(req.Name), rewardMessage, progressionBase, repetitionDate.String, nextShowAtValue, newWishlistID, rewardPolicyValue, req.GroupName, taskID} } else { updateSQL = ` UPDATE tasks @@ -8591,12 +8656,24 @@ func (a *App) updateTaskHandler(w http.ResponseWriter, r *http.Request) { updateArgs = []interface{}{strings.TrimSpace(req.Name), rewardMessage, progressionBase, repetitionDate.String, newWishlistID, rewardPolicyValue, req.GroupName, taskID} } } else { + // Оба поля NULL - устанавливаем next_show_at в NULL только если поля повторения изменились + var nextShowAtValue interface{} + if repetitionChanged { + nextShowAtValue = nil + } else { + // Поля не изменились - сохраняем текущее значение next_show_at + if currentNextShowAt.Valid { + nextShowAtValue = currentNextShowAt.Time + } else { + nextShowAtValue = nil + } + } updateSQL = ` UPDATE tasks - SET name = $1, reward_message = $2, progression_base = $3, repetition_period = NULL, repetition_date = NULL, next_show_at = NULL, wishlist_id = $4, reward_policy = $5, group_name = $6 - WHERE id = $7 + SET name = $1, reward_message = $2, progression_base = $3, repetition_period = NULL, repetition_date = NULL, next_show_at = $4, wishlist_id = $5, reward_policy = $6, group_name = $7 + WHERE id = $8 ` - updateArgs = []interface{}{strings.TrimSpace(req.Name), rewardMessage, progressionBase, newWishlistID, rewardPolicyValue, req.GroupName, taskID} + updateArgs = []interface{}{strings.TrimSpace(req.Name), rewardMessage, progressionBase, nextShowAtValue, newWishlistID, rewardPolicyValue, req.GroupName, taskID} } _, err = tx.Exec(updateSQL, updateArgs...) diff --git a/play-life-web/package.json b/play-life-web/package.json index faddf70..3113baf 100644 --- a/play-life-web/package.json +++ b/play-life-web/package.json @@ -1,6 +1,6 @@ { "name": "play-life-web", - "version": "4.25.0", + "version": "4.26.0", "type": "module", "scripts": { "dev": "vite", diff --git a/play-life-web/src/App.jsx b/play-life-web/src/App.jsx index 3e7d4f4..3381669 100644 --- a/play-life-web/src/App.jsx +++ b/play-life-web/src/App.jsx @@ -104,6 +104,9 @@ function AppContent() { // Модальное окно выбора типа задачи const [showAddModal, setShowAddModal] = useState(false) + + // Ref для функции открытия модала добавления записи в CurrentWeek + const currentWeekAddModalRef = useRef(null) // Кеширование данных const [currentWeekData, setCurrentWeekData] = useState(null) @@ -995,6 +998,9 @@ function AppContent() { onRetry={fetchCurrentWeekData} allProjectsData={fullStatisticsData} onNavigate={handleNavigate} + onOpenAddModal={(setOpenFn) => { + currentWeekAddModalRef.current = setOpenFn + }} /> @@ -1206,7 +1212,10 @@ function AppContent() { {loadedTabs.tracking && (
- +
)} @@ -1290,6 +1299,32 @@ function AppContent() { )} + {/* Кнопка добавления записи (только для таба current - экран прогресса) */} + {!isFullscreenTab && activeTab === 'current' && ( + + )} + {/* Кнопка добавления словаря (только для таба dictionaries) */} {activeTab === 'dictionaries' && ( + + +
+ {/* Поле ввода сообщения */} +
+ +