5.12.0: Желания в карточках проектов на неделе
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 1m21s
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 1m21s
This commit is contained in:
@@ -144,6 +144,7 @@ type TestConfigsAndDictionariesResponse struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type WeeklyProjectStats struct {
|
type WeeklyProjectStats struct {
|
||||||
|
ProjectID int `json:"project_id"`
|
||||||
ProjectName string `json:"project_name"`
|
ProjectName string `json:"project_name"`
|
||||||
TotalScore float64 `json:"total_score"`
|
TotalScore float64 `json:"total_score"`
|
||||||
MinGoalScore float64 `json:"min_goal_score"`
|
MinGoalScore float64 `json:"min_goal_score"`
|
||||||
@@ -166,6 +167,7 @@ type WeeklyStatsResponse struct {
|
|||||||
GroupProgress2 *float64 `json:"group_progress_2,omitempty"`
|
GroupProgress2 *float64 `json:"group_progress_2,omitempty"`
|
||||||
GroupProgress0 *float64 `json:"group_progress_0,omitempty"`
|
GroupProgress0 *float64 `json:"group_progress_0,omitempty"`
|
||||||
Projects []WeeklyProjectStats `json:"projects"`
|
Projects []WeeklyProjectStats `json:"projects"`
|
||||||
|
Wishes []WishlistItem `json:"wishes,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type MessagePostRequest struct {
|
type MessagePostRequest struct {
|
||||||
@@ -2866,6 +2868,8 @@ func (a *App) getWeeklyStatsHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
project.ProjectID = projectID
|
||||||
|
|
||||||
// Объединяем данные: если есть данные текущей недели, используем их вместо MV
|
// Объединяем данные: если есть данные текущей недели, используем их вместо MV
|
||||||
if currentWeekScore, exists := currentWeekScores[projectID]; exists {
|
if currentWeekScore, exists := currentWeekScores[projectID]; exists {
|
||||||
project.TotalScore = currentWeekScore
|
project.TotalScore = currentWeekScore
|
||||||
@@ -2955,12 +2959,20 @@ func (a *App) getWeeklyStatsHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
// Вычисляем общий процент выполнения
|
// Вычисляем общий процент выполнения
|
||||||
total := calculateOverallProgress(groupsProgress, groups)
|
total := calculateOverallProgress(groupsProgress, groups)
|
||||||
|
|
||||||
|
// Загружаем желания пользователя
|
||||||
|
wishes, err := a.getWishlistItemsWithConditions(userID, false)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error getting wishlist items for weekly stats: %v", err)
|
||||||
|
wishes = []WishlistItem{}
|
||||||
|
}
|
||||||
|
|
||||||
response := WeeklyStatsResponse{
|
response := WeeklyStatsResponse{
|
||||||
Total: total,
|
Total: total,
|
||||||
GroupProgress1: groupsProgress.Group1,
|
GroupProgress1: groupsProgress.Group1,
|
||||||
GroupProgress2: groupsProgress.Group2,
|
GroupProgress2: groupsProgress.Group2,
|
||||||
GroupProgress0: groupsProgress.Group0,
|
GroupProgress0: groupsProgress.Group0,
|
||||||
Projects: projects,
|
Projects: projects,
|
||||||
|
Wishes: wishes,
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
@@ -3585,6 +3597,8 @@ func (a *App) getWeeklyStatsData() (*WeeklyStatsResponse, error) {
|
|||||||
return nil, fmt.Errorf("error scanning weekly stats row: %w", err)
|
return nil, fmt.Errorf("error scanning weekly stats row: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
project.ProjectID = projectID
|
||||||
|
|
||||||
// Объединяем данные: если есть данные текущей недели, используем их вместо MV
|
// Объединяем данные: если есть данные текущей недели, используем их вместо MV
|
||||||
if currentWeekScore, exists := currentWeekScores[projectID]; exists {
|
if currentWeekScore, exists := currentWeekScores[projectID]; exists {
|
||||||
project.TotalScore = currentWeekScore
|
project.TotalScore = currentWeekScore
|
||||||
@@ -3756,6 +3770,8 @@ func (a *App) getWeeklyStatsDataForUser(userID int) (*WeeklyStatsResponse, error
|
|||||||
return nil, fmt.Errorf("error scanning weekly stats row: %w", err)
|
return nil, fmt.Errorf("error scanning weekly stats row: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
project.ProjectID = projectID
|
||||||
|
|
||||||
// Объединяем данные: если есть данные текущей недели, используем их вместо MV
|
// Объединяем данные: если есть данные текущей недели, используем их вместо MV
|
||||||
if currentWeekScore, exists := currentWeekScores[projectID]; exists {
|
if currentWeekScore, exists := currentWeekScores[projectID]; exists {
|
||||||
project.TotalScore = currentWeekScore
|
project.TotalScore = currentWeekScore
|
||||||
@@ -3844,12 +3860,20 @@ func (a *App) getWeeklyStatsDataForUser(userID int) (*WeeklyStatsResponse, error
|
|||||||
// Вычисляем общий процент выполнения
|
// Вычисляем общий процент выполнения
|
||||||
total := calculateOverallProgress(groupsProgress, groups)
|
total := calculateOverallProgress(groupsProgress, groups)
|
||||||
|
|
||||||
|
// Загружаем желания пользователя
|
||||||
|
wishes, err := a.getWishlistItemsWithConditions(userID, false)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error getting wishlist items for weekly stats: %v", err)
|
||||||
|
wishes = []WishlistItem{}
|
||||||
|
}
|
||||||
|
|
||||||
response := WeeklyStatsResponse{
|
response := WeeklyStatsResponse{
|
||||||
Total: total,
|
Total: total,
|
||||||
GroupProgress1: groupsProgress.Group1,
|
GroupProgress1: groupsProgress.Group1,
|
||||||
GroupProgress2: groupsProgress.Group2,
|
GroupProgress2: groupsProgress.Group2,
|
||||||
GroupProgress0: groupsProgress.Group0,
|
GroupProgress0: groupsProgress.Group0,
|
||||||
Projects: projects,
|
Projects: projects,
|
||||||
|
Wishes: wishes,
|
||||||
}
|
}
|
||||||
|
|
||||||
return &response, nil
|
return &response, nil
|
||||||
@@ -12284,6 +12308,17 @@ func (a *App) getWishlistItemsWithConditions(userID int, includeCompleted bool)
|
|||||||
condition.CurrentPoints = &totalScore
|
condition.CurrentPoints = &totalScore
|
||||||
conditionMet = totalScore >= requiredPoints
|
conditionMet = totalScore >= requiredPoints
|
||||||
}
|
}
|
||||||
|
// Рассчитываем и форматируем срок разблокировки для заблокированных условий
|
||||||
|
if condition.ProjectID != nil && condition.RequiredPoints != nil {
|
||||||
|
weeks := a.calculateProjectUnlockWeeks(
|
||||||
|
projectID,
|
||||||
|
requiredPoints,
|
||||||
|
startDate,
|
||||||
|
conditionOwnerID,
|
||||||
|
)
|
||||||
|
weeksText := formatWeeksText(weeks)
|
||||||
|
condition.WeeksText = &weeksText
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -16763,6 +16798,8 @@ func (a *App) getWeeklyStatsDataForUserAndWeek(userID int, year int, week int) (
|
|||||||
return nil, fmt.Errorf("error scanning weekly stats row: %w", err)
|
return nil, fmt.Errorf("error scanning weekly stats row: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
project.ProjectID = projectID
|
||||||
|
|
||||||
// Объединяем данные: если это текущая неделя и есть данные, используем их вместо MV
|
// Объединяем данные: если это текущая неделя и есть данные, используем их вместо MV
|
||||||
if isCurrentWeek {
|
if isCurrentWeek {
|
||||||
if currentWeekScore, exists := currentWeekScores[projectID]; exists {
|
if currentWeekScore, exists := currentWeekScores[projectID]; exists {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "play-life-web",
|
"name": "play-life-web",
|
||||||
"version": "5.11.2",
|
"version": "5.12.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -427,12 +427,16 @@ function AppContent() {
|
|||||||
groupProgress0 = jsonData.group_progress_0 !== undefined ? jsonData.group_progress_0 : null
|
groupProgress0 = jsonData.group_progress_0 !== undefined ? jsonData.group_progress_0 : null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Получаем желания из ответа
|
||||||
|
const wishes = jsonData?.wishes || []
|
||||||
|
|
||||||
setCurrentWeekData({
|
setCurrentWeekData({
|
||||||
projects: Array.isArray(projects) ? projects : [],
|
projects: Array.isArray(projects) ? projects : [],
|
||||||
total: total,
|
total: total,
|
||||||
group_progress_1: groupProgress1,
|
group_progress_1: groupProgress1,
|
||||||
group_progress_2: groupProgress2,
|
group_progress_2: groupProgress2,
|
||||||
group_progress_0: groupProgress0
|
group_progress_0: groupProgress0,
|
||||||
|
wishes: wishes
|
||||||
})
|
})
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setCurrentWeekError(err.message)
|
setCurrentWeekError(err.message)
|
||||||
|
|||||||
@@ -174,3 +174,96 @@
|
|||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Внешний контейнер для карточки проекта */
|
||||||
|
.project-card-wrapper {
|
||||||
|
border: 1px solid #e0e4ed;
|
||||||
|
border-radius: 1.5rem;
|
||||||
|
transition: all 0.3s;
|
||||||
|
box-shadow: 0 1px 3px 0 rgb(99 102 241 / 0.08);
|
||||||
|
background-color: #eef0f7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-card-wrapper:hover {
|
||||||
|
box-shadow: 0 2px 6px 0 rgb(99 102 241 / 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Стили для горизонтального скролла желаний в карточке проекта */
|
||||||
|
.project-wishes-scroll {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.5rem;
|
||||||
|
overflow-x: auto;
|
||||||
|
overflow-y: hidden;
|
||||||
|
padding: 0.5rem 1rem 0.75rem 1rem;
|
||||||
|
scrollbar-width: none;
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.project-wishes-scroll::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Мини-карточка желания */
|
||||||
|
.mini-wish-card {
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 50px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: transform 0.2s, opacity 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mini-wish-card:hover {
|
||||||
|
transform: scale(1.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mini-wish-card:active {
|
||||||
|
transform: scale(0.95);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mini-wish-image {
|
||||||
|
width: 50px;
|
||||||
|
height: 60px;
|
||||||
|
background: #f0f0f0;
|
||||||
|
border-radius: 8px;
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mini-wish-image img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mini-wish-overlay {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: rgba(255, 255, 255, 0.4);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mini-wish-placeholder {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
background: white;
|
||||||
|
border: 1px solid #e5e7eb;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mini-wish-name {
|
||||||
|
font-size: 0.625rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #6b7280;
|
||||||
|
margin-top: 0.125rem;
|
||||||
|
line-height: 1.1;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { useAuth } from './auth/AuthContext'
|
|||||||
import ProjectProgressBar from './ProjectProgressBar'
|
import ProjectProgressBar from './ProjectProgressBar'
|
||||||
import LoadingError from './LoadingError'
|
import LoadingError from './LoadingError'
|
||||||
import Toast from './Toast'
|
import Toast from './Toast'
|
||||||
|
import WishlistDetail from './WishlistDetail'
|
||||||
import { getAllProjectsSorted, getProjectColor } from '../utils/projectUtils'
|
import { getAllProjectsSorted, getProjectColor } from '../utils/projectUtils'
|
||||||
import { CircularProgressbar, buildStyles } from 'react-circular-progressbar'
|
import { CircularProgressbar, buildStyles } from 'react-circular-progressbar'
|
||||||
import 'react-circular-progressbar/dist/styles.css'
|
import 'react-circular-progressbar/dist/styles.css'
|
||||||
@@ -94,8 +95,31 @@ function CircularProgressBar({ progress, size = 120, strokeWidth = 8, showCheckm
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Компонент мини-карточки желания для отображения внутри карточки проекта
|
||||||
|
function MiniWishCard({ wish, onClick }) {
|
||||||
|
const handleClick = (e) => {
|
||||||
|
e.stopPropagation()
|
||||||
|
if (onClick) {
|
||||||
|
onClick(wish)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mini-wish-card" onClick={handleClick}>
|
||||||
|
<div className="mini-wish-image">
|
||||||
|
{wish.image_url ? (
|
||||||
|
<img src={wish.image_url} alt={wish.name} />
|
||||||
|
) : (
|
||||||
|
<div className="mini-wish-placeholder">🎁</div>
|
||||||
|
)}
|
||||||
|
<div className="mini-wish-overlay"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// Компонент карточки проекта с круглым прогрессбаром
|
// Компонент карточки проекта с круглым прогрессбаром
|
||||||
function ProjectCard({ project, projectColor, onProjectClick }) {
|
function ProjectCard({ project, projectColor, onProjectClick, wishes = [], onWishClick }) {
|
||||||
const { project_name, total_score, min_goal_score, max_goal_score, priority, today_change } = project
|
const { project_name, total_score, min_goal_score, max_goal_score, priority, today_change } = project
|
||||||
|
|
||||||
// Вычисляем прогресс по оригинальной логике из ProjectProgressBar
|
// Вычисляем прогресс по оригинальной логике из ProjectProgressBar
|
||||||
@@ -176,10 +200,13 @@ function ProjectCard({ project, projectColor, onProjectClick }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const hasWishes = wishes && wishes.length > 0
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<div className="project-card-wrapper">
|
||||||
<div
|
<div
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
className="bg-white rounded-3xl py-3 px-4 shadow-sm hover:shadow-md transition-all duration-300 cursor-pointer border border-gray-200 hover:border-indigo-300"
|
className="bg-white rounded-3xl py-3 px-4 transition-all duration-300 cursor-pointer"
|
||||||
>
|
>
|
||||||
{/* Верхняя часть с названием и прогрессом */}
|
{/* Верхняя часть с названием и прогрессом */}
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
@@ -217,11 +244,25 @@ function ProjectCard({ project, projectColor, onProjectClick }) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Горизонтальный список желаний */}
|
||||||
|
{hasWishes && (
|
||||||
|
<div className="project-wishes-scroll">
|
||||||
|
{wishes.map((wish) => (
|
||||||
|
<MiniWishCard
|
||||||
|
key={wish.id}
|
||||||
|
wish={wish}
|
||||||
|
onClick={onWishClick}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Компонент группы проектов по приоритету
|
// Компонент группы проектов по приоритету
|
||||||
function PriorityGroup({ title, subtitle, projects, allProjects, onProjectClick }) {
|
function PriorityGroup({ title, subtitle, projects, allProjects, onProjectClick, getWishesForProject, onWishClick }) {
|
||||||
if (projects.length === 0) return null
|
if (projects.length === 0) return null
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -239,6 +280,7 @@ function PriorityGroup({ title, subtitle, projects, allProjects, onProjectClick
|
|||||||
if (!project || !project.project_name) return null
|
if (!project || !project.project_name) return null
|
||||||
|
|
||||||
const projectColor = getProjectColor(project.project_name, allProjects, project.color)
|
const projectColor = getProjectColor(project.project_name, allProjects, project.color)
|
||||||
|
const projectWishes = getWishesForProject ? getWishesForProject(project.project_id) : []
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ProjectCard
|
<ProjectCard
|
||||||
@@ -246,6 +288,8 @@ function PriorityGroup({ title, subtitle, projects, allProjects, onProjectClick
|
|||||||
project={project}
|
project={project}
|
||||||
projectColor={projectColor}
|
projectColor={projectColor}
|
||||||
onProjectClick={onProjectClick}
|
onProjectClick={onProjectClick}
|
||||||
|
wishes={projectWishes}
|
||||||
|
onWishClick={onWishClick}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
@@ -509,6 +553,49 @@ function CurrentWeek({ onProjectClick, data, loading, error, onRetry, allProject
|
|||||||
const { authFetch } = useAuth()
|
const { authFetch } = useAuth()
|
||||||
const [isAddModalOpen, setIsAddModalOpen] = useState(false)
|
const [isAddModalOpen, setIsAddModalOpen] = useState(false)
|
||||||
const [toastMessage, setToastMessage] = useState(null)
|
const [toastMessage, setToastMessage] = useState(null)
|
||||||
|
const [selectedWishlistId, setSelectedWishlistId] = useState(null)
|
||||||
|
|
||||||
|
// Желания приходят вместе с данными проектов
|
||||||
|
const wishes = data?.wishes || []
|
||||||
|
|
||||||
|
// Функция для получения числового значения срока из текста
|
||||||
|
const getWeeksValue = (weeksText) => {
|
||||||
|
if (!weeksText) return Infinity
|
||||||
|
if (weeksText === '<1 недели') return 0
|
||||||
|
if (weeksText === '1 неделя') return 1
|
||||||
|
const match = weeksText.match(/(\d+)/)
|
||||||
|
return match ? parseInt(match[1], 10) : Infinity
|
||||||
|
}
|
||||||
|
|
||||||
|
// Функция фильтрации желаний для проекта
|
||||||
|
const getWishesForProject = (projectId) => {
|
||||||
|
const filtered = wishes.filter(wish => {
|
||||||
|
if (wish.unlocked || wish.completed) return false
|
||||||
|
if (wish.locked_conditions_count !== 1) return false
|
||||||
|
const condition = wish.first_locked_condition
|
||||||
|
if (!condition || condition.project_id !== projectId) return false
|
||||||
|
const weeksText = condition.weeks_text
|
||||||
|
if (!weeksText) return false
|
||||||
|
return weeksText === '1 неделя' || weeksText === '<1 недели'
|
||||||
|
})
|
||||||
|
|
||||||
|
// Сортируем по сроку разблокировки (от меньшего к большему)
|
||||||
|
return filtered.sort((a, b) => {
|
||||||
|
const weeksA = getWeeksValue(a.first_locked_condition?.weeks_text)
|
||||||
|
const weeksB = getWeeksValue(b.first_locked_condition?.weeks_text)
|
||||||
|
return weeksA - weeksB
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Обработчик клика на желание
|
||||||
|
const handleWishClick = (wish) => {
|
||||||
|
setSelectedWishlistId(wish.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Закрытие модального окна детализации желания
|
||||||
|
const handleCloseWishDetail = () => {
|
||||||
|
setSelectedWishlistId(null)
|
||||||
|
}
|
||||||
|
|
||||||
// Экспортируем функцию открытия модала для использования из App.jsx
|
// Экспортируем функцию открытия модала для использования из App.jsx
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -667,6 +754,8 @@ function CurrentWeek({ onProjectClick, data, loading, error, onRetry, allProject
|
|||||||
projects={priorityGroups.main}
|
projects={priorityGroups.main}
|
||||||
allProjects={allProjects}
|
allProjects={allProjects}
|
||||||
onProjectClick={onProjectClick}
|
onProjectClick={onProjectClick}
|
||||||
|
getWishesForProject={getWishesForProject}
|
||||||
|
onWishClick={handleWishClick}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<PriorityGroup
|
<PriorityGroup
|
||||||
@@ -675,6 +764,8 @@ function CurrentWeek({ onProjectClick, data, loading, error, onRetry, allProject
|
|||||||
projects={priorityGroups.important}
|
projects={priorityGroups.important}
|
||||||
allProjects={allProjects}
|
allProjects={allProjects}
|
||||||
onProjectClick={onProjectClick}
|
onProjectClick={onProjectClick}
|
||||||
|
getWishesForProject={getWishesForProject}
|
||||||
|
onWishClick={handleWishClick}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<PriorityGroup
|
<PriorityGroup
|
||||||
@@ -683,9 +774,21 @@ function CurrentWeek({ onProjectClick, data, loading, error, onRetry, allProject
|
|||||||
projects={priorityGroups.others}
|
projects={priorityGroups.others}
|
||||||
allProjects={allProjects}
|
allProjects={allProjects}
|
||||||
onProjectClick={onProjectClick}
|
onProjectClick={onProjectClick}
|
||||||
|
getWishesForProject={getWishesForProject}
|
||||||
|
onWishClick={handleWishClick}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Модальное окно детализации желания */}
|
||||||
|
{selectedWishlistId && (
|
||||||
|
<WishlistDetail
|
||||||
|
wishlistId={selectedWishlistId}
|
||||||
|
onNavigate={onNavigate}
|
||||||
|
onClose={handleCloseWishDetail}
|
||||||
|
onRefresh={refreshData}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Модальное окно добавления записи */}
|
{/* Модальное окно добавления записи */}
|
||||||
{isAddModalOpen && (
|
{isAddModalOpen && (
|
||||||
<AddEntryModal
|
<AddEntryModal
|
||||||
|
|||||||
Reference in New Issue
Block a user