package welfare_activity import ( "context" "time" ) func (s *service) ListJoinableActivitiesForUser(ctx context.Context, userID int64) ([]JoinableActivityItem, error) { now := time.Now() var activities []Activity if err := s.repo.GetDbR().WithContext(ctx).Where("deleted_at IS NULL AND status = ? AND start_time <= ? AND end_time > ? AND draw_time > ?", StatusActive, now, now, now).Order("draw_time ASC, id ASC").Find(&activities).Error; err != nil { return nil, err } if len(activities) == 0 { return []JoinableActivityItem{}, nil } paidByType := map[string]int64{} periodByType := map[string]string{} for _, activity := range activities { if _, ok := paidByType[activity.Type]; ok { continue } start, end, period := periodRange(activity.Type, now) paid, err := s.sumPaidAmount(ctx, userID, start, end) if err != nil { return nil, err } paidByType[activity.Type] = paid periodByType[activity.Type] = period } activityIDs := make([]int64, 0, len(activities)) for _, activity := range activities { activityIDs = append(activityIDs, activity.ID) } var participants []Participant if err := s.repo.GetDbR().WithContext(ctx).Where("user_id = ? AND activity_id IN ?", userID, activityIDs).Find(&participants).Error; err != nil { return nil, err } joinedMap := map[int64]map[string]bool{} for _, participant := range participants { if _, ok := joinedMap[participant.ActivityID]; !ok { joinedMap[participant.ActivityID] = map[string]bool{} } joinedMap[participant.ActivityID][participant.PeriodKey] = true } items := make([]JoinableActivityItem, 0, len(activities)) for _, activity := range activities { currentPaid := paidByType[activity.Type] periodKey := periodByType[activity.Type] joined := joinedMap[activity.ID][periodKey] canJoin := !joined && currentPaid >= activity.ThresholdAmount items = append(items, JoinableActivityItem{ ActivityID: activity.ID, Title: activity.Title, Type: activity.Type, ThresholdAmount: activity.ThresholdAmount, CurrentPaid: currentPaid, CanJoin: canJoin, Joined: joined, StartTime: activity.StartTime, EndTime: activity.EndTime, DrawTime: activity.DrawTime, }) } return items, nil }