cloudspokes / arena-web

Web arena for SRMs
44 stars 32 forks source link

fixes #921 overlapping solved #988

Closed gus-costa closed 9 years ago

gus-costa commented 9 years ago

Issue #921 fixed.

arena

Use the code below to perform tests on your local environment, when you don't have enough rooms to display the pagination.

app\js\controllers\activeContestsCtrl.js

@@ -269,6 +269,9 @@ var activeContestsCtrl = ['$scope', '$rootScope', '$state', 'socket', 'appHelper
      * @returns {$rootScope.roundData.coderRooms|*} the room list
      */
     $scope.getRoomsList = function (contest) {
+      var rooms = [];
+      for (var i = 1; i < 75; i++) rooms.push({roomID : i, roomType : 2, roomTitle : "Room "+i, roundID : 1000000, divisionID : 2, $$hashKey : "0"+i});
+      return rooms;
         if (contest) {
             return contest.coderRooms;
         }
huangqun commented 9 years ago

I tried this but I still don't see the rooms. I just updated $scope.getRoomsList to add the 3 new lines and updated the round id. Anything I'm missing here?

gus-costa commented 9 years ago

Can you see the Rooms tab?? What happens when you click on it?

huangqun commented 9 years ago

Yes I can see the tab, when I click it I can only see 1 room (room 1).

gus-costa commented 9 years ago

It should be working. Please check if the browser loaded the correct bundle.js file.

huangqun commented 9 years ago

Can you attach your modified activeContestsCtrl.js file here? Or email it to me (Wendell@copilots.topcoder.com)?

gus-costa commented 9 years ago
/*
 * Copyright (C) 2014 TopCoder Inc., All Rights Reserved.
 */
/**
 * This controller handles active contests related logic.
 *
 * Changes in version 1.1 (Module Assembly - Web Arena UI - Coding IDE Part 2):
 * - Moved socket handler of RoomInfoResponse to resolver.js
 *
 * Changes in version 1.2 (Module Assembly - Web Arena UI Fix):
 * - Removed updating $rootScope.now and moved to tcTimeCtrl.
 *
 * Changes in version 1.3 (Module Assembly - Web Arena UI - Chat Widget):
 * - Updated the contest entering logic, moved handlers to resolvers.
 * - Updated to use scope broadcasting to handle registration responses.
 *
 * Changes in version 1.4 (Module Assembly - Web Arena UI - Phase I Bug Fix):
 * - Updated to use the global popup modal in baseCtrl.js.
 * - Updated the countdown message formats in Active Contest Widget.
 *
 * Changes in version 1.4 (Module Assembly - Web Arena UI - Phase I Bug Fix):
 * - Removed mystatus tab related logic
 *
 * Changes in version 1.5 (Module Assembly - Web Arena UI - Phase I Bug Fix 3):
 * - Hide the register button if user already registered.
 *
 * Changes in version 1.6 (Module Assembly - Web Arena UI - Rooms Tab):
 * - Added logic for rooms tab.
 *
 * Changes in version 1.7 (Module Assembly - Web Arena UI - Phase I Bug Fix 4):
 * - Show the registered text if user already registered.
 *
 * Changes in version 1.8 (Module Assembly - Web Arena UI - Suvery and Questions Support For Contest Registration):
 * - Updated the logic to support registration survey and questions.
 *
 * Changes in version 1.9 (Module Assembly - Web Arena Bug Fix 20140909):
 * - Changed the text in registration error popup.
 *
 * Changes in version 1.10 (PoC Assembly - Invite friends To Participate On A Match From Facebook and Twitter):
 * - Added facebook / twitter invitation logic.
 *
 * @author amethystlei, dexy, flytoj2ee, TCASSEMBLER
 * @version 1.10
 */
'use strict';
/*global module, angular, require*/
/*jslint plusplus: true*/
/**
 * The helper.
 *
 * @type {exports}
 */
var helper = require('../helper'),
    config = require('../config');

/**
 * The controller for the active contests widget in the dashboard.
 *
 * @type {*[]}
 */
var activeContestsCtrl = ['$scope', '$rootScope', '$state', 'socket', 'appHelper', '$modal', 'Facebook', function ($scope, $rootScope, $state, socket, appHelper, $modal, Facebook) {
    var getPhase = function (contest, phaseTypeId) {
        var i;
        if (!contest.phases) {
            return null;
        }
        for (i = 0; i < contest.phases.length; i += 1) {
            if (contest.phases[i].phaseType === phaseTypeId) {
                return contest.phases[i];
            }
        }
        return null;
    },
        updateContest = function (contest) {
            contest.detailIndex = 1;
            contest.action = (contest.phaseData.phaseType >= helper.PHASE_TYPE_ID.AlmostContestPhase
                            && contest.coderRooms && contest.coderRooms.length > 0) ? 'Enter' : '';
        },
        // show the active tab name when active contest widget is narrow
        tabNames = ['Match Summary', 'Match Schedule', 'My Status', 'Rooms'],
        popupDetailModalCtrl;

    $scope.getPhaseTime = appHelper.getPhaseTime;
    $scope.range = appHelper.range;
    $scope.currentContest = 0;
    $scope.tweetText = config.tweetText;
    $scope.tweetUrl = config.tweetUrl;

    /**
     * Send facebook message.
     */
    $scope.sendFacebookMessage = function () {
        Facebook.ui({
            method: 'send',
            link: config.facebookLink
        });
    };

    /*jslint unparam:true*/
    $scope.$on(helper.EVENT_NAME.CreateRoomListResponse, function (event, data) {
        updateContest($rootScope.roundData[data.roundID]);
    });
    $scope.$on(helper.EVENT_NAME.PhaseDataResponse, function (event, data) {
        var contest = $rootScope.roundData[data.phaseData.roundID];
        setTimeout(function () {
            if ($scope.isRegistrationOpen(contest)) {
                /*jslint unparam: true*/
                $scope.$on(helper.EVENT_NAME.PopUpGenericResponse, function (event, data) {
                    // remove the listener
                    $scope.$$listeners[helper.EVENT_NAME.PopUpGenericResponse] = [];
                    if (data.message.indexOf('You are already registered') === -1) {
                        contest.isRegisterable = true;
                    } else {
                        contest.isRegistered = true;
                    }
                });
                socket.emit(helper.EVENT_NAME.RegisterInfoRequest, {roundID: contest.roundID});
            }
        }, 5100);
        updateContest(contest);
    });

    // Test whether registration phase is open
    $scope.isRegistrationOpen = function (contest) {
        if (!contest) {
            return false;
        }
        var phase = getPhase(contest, helper.PHASE_TYPE_ID.RegistrationPhase);
        if (!phase) {
            return false;
        }
        return phase.startTime <= $rootScope.now && $rootScope.now <= phase.endTime;
    };

    /*jslint unparam:false*/
    angular.forEach($rootScope.roundData, function (contest) {
        if ($scope.isRegistrationOpen(contest)) {
            /*jslint unparam: true*/
            $scope.$on(helper.EVENT_NAME.PopUpGenericResponse, function (event, data) {
                // remove the listener
                $scope.$$listeners[helper.EVENT_NAME.PopUpGenericResponse] = [];
                if (data.message.indexOf('You are already registered') === -1) {
                    contest.isRegisterable = true;
                } else {
                    contest.isRegistered = true;
                }
            });
            socket.emit(helper.EVENT_NAME.RegisterInfoRequest, {roundID: contest.roundID});
        }
        updateContest(contest);
    });

    // handle update round list response
    socket.on(helper.EVENT_NAME.UpdateRoundListResponse, function (data) {
        if (data.action === 1) {
            $rootScope.roundData[data.roundData.roundID] = data.roundData;
            updateContest($rootScope.roundData[data.roundData.roundID]);
        } else if (data.action === 2) {
            delete $rootScope.roundData[data.roundData.roundID];
        }
    });

    // handle round enable response
    socket.on(helper.EVENT_NAME.EnableRoundResponse, function (data) {
        $rootScope.roundData[data.roundID].action = 'Enter';
    });

    $scope.getContests = function () {
        var result = [];
        angular.forEach($rootScope.roundData, function (contest) {
            result.push(contest);
        });
        return result;
    };

    $scope.isShown = function (contest) {
        if (contest.action !== 'Enter') {
            contest.action = ($scope.isRegistrationOpen(contest) && contest.isRegisterable === true) ? 'Register' : '';
        }
        return contest.action !== '';
    };

    /**
     * Returns the shown registered text condition.
     * @param contest - the contest
     * @returns {*|boolean} the result.
     */
    $scope.isShownRegistered = function (contest) {
        return ($scope.isRegistrationOpen(contest) && contest.isRegistered === true);
    };

    /**
     * Returns the flag whether to show the rooms tab.
     *
     * @param contest - the contest
     * @returns {boolean|$rootScope.roundData.coderRooms|*} the flag.
     */
    $scope.isShownRooms = function (contest) {
        return contest.phaseData.phaseType >= helper.PHASE_TYPE_ID.AlmostContestPhase
            && contest.coderRooms && contest.coderRooms.length > 0;
    };

    // sets the current contest for viewing
    $scope.setCurrentContest = function (newContest) {
        $scope.currentContest = newContest;
    };

    // gets the current action available
    $scope.getAction = function (contest) {
        return contest.action;
    };

    socket.on(helper.EVENT_NAME.EnableRoundResponse, function (data) {
        angular.forEach($scope.contests, function (contest) {
            if (data.roundID === contest.id) {
                contest.action = 'Enter';
            }
        });
    });

    // default to 50
    $scope.pageSize = 50;

    $scope.currentPage = 1;

    /**
     * Moves to the room.
     *
     * @param contest - the contest
     * @param roomId - the room id.
     */
    $scope.moveToRoom = function (contest, roomId) {
        $rootScope.competingRoomID = roomId;
        // requests will be sent by the resolvers
        $state.go(helper.STATE_NAME.Contest, {
            contestId: contest.roundID
        }, {reload: true});
    };
    /**
     * Returns the number of pages.
     *
     * @param contest - the contest instance
     * @returns {number} - the page number
     */
    $scope.numberOfPages = function (contest) {
        return Math.ceil($scope.getRoomsList(contest).length / $scope.pageSize);
    };

    /**
     * Moves to next page.
     */
    $scope.nextPage = function () {
        $scope.currentPage = $scope.currentPage + 1;
        $scope.$broadcast('rebuild:roomslist');
    };

    /**
     * Moves to previous page.
     */
    $scope.prevPage = function () {
        $scope.currentPage = $scope.currentPage - 1;
        $scope.$broadcast('rebuild:roomslist');
    };

    /**
     * Returns the rooms list.
     *
     * @param contest - the contest instance.
     * @returns {$rootScope.roundData.coderRooms|*} the room list
     */
    $scope.getRoomsList = function (contest) {
      var rooms = [];
      for (var i = 1; i < 75; i++) rooms.push({roomID : i, roomType : 2, roomTitle : "Room "+i, roundID : 1000000, divisionID : 2, $$hashKey : "0"+i});
      return rooms;
        if (contest) {
            return contest.coderRooms;
        }

        return [];

    };

    popupDetailModalCtrl = ['$scope', '$modalInstance', 'data', 'ok', 'cancel', '$timeout', function ($scope, $modalInstance, data, ok, cancel, $timeout) {
        $scope.title = data.title;
        $scope.message = data.detail;
        $scope.buttons = data.buttons && data.buttons.length > 0 ? data.buttons : ['Close'];
        $scope.enableClose = true;

        $timeout(function () {
            $scope.$broadcast('rebuild:inputValidation');
        }, 100);

        /**
         * Close the dialog.
         */
        $scope.ok = function () {
            ok();
            $modalInstance.close();
        };

        /**
         * Cancel handler.
         */
        $scope.cancel = function () {
            cancel();
            $modalInstance.dismiss('cancel');
        };
    }];
    /**
     * Open the registration detail modal.
     * @param data - the data value
     * @param handle - the handle function
     * @param finish - the finish function
     */
    $scope.openDetailModal = function (data, handle, finish) {
        if ($rootScope.currentDetailModal) {
            $rootScope.currentDetailModal.dismiss('cancel');
            $rootScope.currentDetailModal = undefined;
        }

        $rootScope.currentDetailModal = $modal.open({
            templateUrl: 'popupValidationDetail.html',
            controller: popupDetailModalCtrl,
            backdrop: 'static',
            resolve: {
                data: function () {
                    return data;
                },
                ok: function () {
                    return function () {
                        if (angular.isFunction(handle)) {
                            handle();
                        }
                        $rootScope.currentDetailModal = undefined;
                    };
                },
                cancel: function () {
                    return function () {
                        if (angular.isFunction(finish)) {
                            finish();
                        }
                        $rootScope.currentDetailModal = undefined;
                    };
                }
            }
        });
    };

    // action for 'Register' or 'Enter'
    $scope.doAction = function (contest) {
        var roundID = contest.roundID;
        $scope.okDisabled = true;
        // in the real app, we should perform real actions.
        if (contest.action === 'Enter') {
            $rootScope.competingRoomID = -1;
            // requests will be sent by the resolvers
            $state.go(helper.STATE_NAME.Contest, {
                contestId: contest.roundID
            }).then(function () {
                $scope.okDisabled = false;
            });
        } else {
            /*jslint unparam: true*/
            // define the listener for showing the popup
            $scope.$on(helper.EVENT_NAME.PopUpGenericResponse, function (event, data) {
                // remove the listener
                $scope.$$listeners[helper.EVENT_NAME.PopUpGenericResponse] = [];
                angular.extend(data, {enableClose: true});
                $rootScope.currentDetailModal = undefined;
                $scope.openModal(data, function () {
                    var surveyData = [], i, j, item = {}, flag, validationError = [], detail;
                    for (i = 0; i < $rootScope.eligibilityQuestions.length; i++) {
                        item = {questionID: $rootScope.eligibilityQuestions[i].questionID, eligible: "true", type: $rootScope.eligibilityQuestions[i].questionType,
                            answers: [], choices: []};
                        if ($rootScope.eligibilityQuestions[i].questionType === helper.QUESTION_TYPE.LONG_TEXT ||
                                $rootScope.eligibilityQuestions[i].questionType === helper.QUESTION_TYPE.SHORT_TEXT) {
                            if ($rootScope.eligibilityQuestions[i].answer !== '') {
                                item.answers.push($rootScope.eligibilityQuestions[i].answer);
                            } else {
                                validationError.push($rootScope.eligibilityQuestions[i].questionText);
                            }
                        }

                        if ($rootScope.eligibilityQuestions[i].questionType === helper.QUESTION_TYPE.SINGLE_CHOICE) {
                            if ($rootScope.eligibilityQuestions[i].answer !== '') {
                                item.choices.push({text: $rootScope.eligibilityQuestions[i].answer});
                                item.answers.push($rootScope.eligibilityQuestions[i].answer);
                            } else {
                                validationError.push($rootScope.eligibilityQuestions[i].questionText);
                            }

                        }
                        if ($rootScope.eligibilityQuestions[i].questionType === helper.QUESTION_TYPE.MULTI_CHOICE) {
                            flag = false;
                            for (j = 0; j < $rootScope.eligibilityQuestions[i].answers.length; j++) {
                                if ($rootScope.eligibilityQuestions[i].answers[j] === true) {
                                    item.choices.push({text: $rootScope.eligibilityQuestions[i].answerText[j]});
                                    item.answers.push($rootScope.eligibilityQuestions[i].answerText[j]);
                                    flag = true;
                                }
                            }

                            if (flag === false) {
                                validationError.push($rootScope.eligibilityQuestions[i].questionText);
                            }

                        }
                        surveyData.push(item);
                    }

                    for (i = 0; i < $rootScope.generalQuestions.length; i++) {
                        item = {questionID: $rootScope.generalQuestions[i].questionID, type: $rootScope.generalQuestions[i].questionType,
                            answers: [], choices: []};
                        if ($rootScope.generalQuestions[i].questionType === helper.QUESTION_TYPE.LONG_TEXT ||
                                $rootScope.generalQuestions[i].questionType === helper.QUESTION_TYPE.SHORT_TEXT) {
                            if ($rootScope.generalQuestions[i].answer !== '') {
                                item.answers.push($rootScope.generalQuestions[i].answer);
                            } else {
                                validationError.push($rootScope.generalQuestions[i].questionText);
                            }
                        }

                        if ($rootScope.generalQuestions[i].questionType === helper.QUESTION_TYPE.SINGLE_CHOICE) {
                            if ($rootScope.generalQuestions[i].answer !== '') {
                                item.choices.push({text: $rootScope.generalQuestions[i].answer});
                                item.answers.push($rootScope.generalQuestions[i].answer);
                            } else {
                                validationError.push($rootScope.generalQuestions[i].questionText);
                            }

                        }
                        if ($rootScope.generalQuestions[i].questionType === helper.QUESTION_TYPE.MULTI_CHOICE) {
                            flag = false;
                            for (j = 0; j < $rootScope.generalQuestions[i].answers.length; j++) {
                                if ($rootScope.generalQuestions[i].answers[j] === true) {
                                    item.choices.push({text: $rootScope.generalQuestions[i].answerText[j]});
                                    item.answers.push($rootScope.generalQuestions[i].answerText[j]);
                                    flag = true;
                                }
                            }

                            if (flag === false) {
                                validationError.push($rootScope.generalQuestions[i].questionText);
                            }

                        }
                        surveyData.push(item);
                    }

                    if (validationError.length > 0) {
                        detail = '<p class="textColor">You must answer the following question' + (validationError.length > 1 ? 's' : '') + ':</p>';
                        for (i = 0; i < validationError.length; i++) {
                            detail = detail + '<p> --- ' + validationError[i] + "</p>";
                        }
                        $rootScope.currentDetailModal = undefined;
                        $scope.openDetailModal({'title': 'Error', 'detail': detail});
                    } else {
                        /*jslint unparam: true*/
                        // Agreed to register, listen to registration results.
                        $scope.$on(helper.EVENT_NAME.PopUpGenericResponse, function (event, data) {
                            // Remove the listener.
                            $scope.$$listeners[helper.EVENT_NAME.PopUpGenericResponse] = [];
                            angular.extend(data, {enableClose: true, registrantCallBack: true});
                            $scope.openModal(data);
                            if (data.message.indexOf('You have successfully registered for the match.') !== -1) {
                                contest.isRegisterable = false;
                                contest.isRegistered = true;
                                if ($rootScope.currentModal !== undefined && $rootScope.currentModal !== null) {
                                    $rootScope.currentModal = undefined;
                                }
                                $scope.setDetailIndex(contest, 2);
                            }
                        });

                        /*jslint unparam: false*/
                        socket.emit(helper.EVENT_NAME.RegisterRequest, {"roundID": roundID, "surveyData": surveyData});
                    }
                }, function () {
                    contest.isRegisterable = true;
                    contest.isRegistered = false;
                    $rootScope.currentModal = undefined;
                    $rootScope.currentDetailModal = undefined;
                }, 'partials/user.contest.registration.html');
                $scope.okDisabled = false;
            });
            /*jslint unparam: false*/
            socket.emit(helper.EVENT_NAME.RegisterInfoRequest, {roundID: roundID});
        }
    };

    // sets the tab index to view contest details
    $scope.setDetailIndex = function (contest, index) {
        if (index < 0 ||
                ($scope.isRegistrationOpen(contest) && index >= 2) ||
                (!$scope.isRegistrationOpen(contest) && index >= 4)) {
            // invalid index for detail tabs
            return;
        }

        if (index === 3) {
            $scope.$broadcast('rebuild:roomslist');
        }

        contest.detailIndex = index;
    };

    /**
     * Check if the contest is counting down.
     *
     * @param  {Object}  contest the contest object
     * @return {boolean}         it is counting down or not
     */
    $scope.isCountingDown = function (contest) {
        if (!contest || !contest.phaseData) {
            return false;
        }
        return contest.phaseData.phaseType < helper.PHASE_TYPE_ID.CodingPhase;
    };

    /**
     * Get the prefix of the countdown message based on different phases.
     *
     * @param  {Object} contest the contest object
     * @return {string}         the prefix the countdown message
     */
    $scope.countdownPrefix = function (contest) {
        if (!contest || !contest.phaseData) {
            return '';
        }
        if (contest.phaseData.phaseType < helper.PHASE_TYPE_ID.CodingPhase) {
            return 'will start in';
        }
        if (contest.phaseData.phaseType >= helper.PHASE_TYPE_ID.ContestCompletePhase) {
            return 'is completed.';
        }
        return 'is live!';
    };

    /**
     * Render the contest countdown message.
     *
     * @param  {Object} contest the contest object
     * @return {string}         the countdown message
     */
    $scope.displayCountDown = function (contest) {
        if (!contest) {
            return '';
        }
        var phase, left, hours, minutes, seconds, result = '', LAST_MINUTES = 5,
            displayHour = function (hours) {
                if (hours === 0) {
                    return '';
                }
                // single: 1 hour, plural: 0 hours, 2 hours...
                return hours + ' ' + (hours === 1 ? 'hour' : 'hours');
            },
            displayMinute = function (minutes) {
                return minutes + ' ' + (minutes === 1 ? 'minute' : 'minutes');
            },
            displaySecond = function (seconds) {
                return seconds + ' ' + (seconds === 1 ? 'second' : 'seconds');
            };
        if (!contest.phaseData) {
            return '';
        }
        phase = getPhase(contest, helper.PHASE_TYPE_ID.CodingPhase);
        if (!phase) {
            return '';
        }
        left = contest.phases[1].startTime - $rootScope.now;
        hours = Math.floor(left / 3600000);
        minutes = Math.floor(left % 3600000 / 60000);
        seconds = Math.floor(left % 60000 / 1000);
        if (hours > 0) {
            result += displayHour(hours) + ' ';
        }
        if (hours > 0 || minutes > 0) {
            result += displayMinute(minutes);
        }
        if (hours === 0) {
            if (minutes < LAST_MINUTES && minutes > 0) {
                result += ' and ';
            }
            if (minutes < LAST_MINUTES) {
                result += displaySecond(seconds);
            }
        }
        return result;
    };

    // show the active tab name when active contest widget is narrow
    $scope.getTabName = function (index) {
        return index >= 0 && index < tabNames.length ? tabNames[index] : 'Click to show tabs';
    };
}];

module.exports = activeContestsCtrl;
huangqun commented 9 years ago

Still just see one room, I checked and bundle.js is loaded properly (unless changes are needed to it as well?). We'll have to reject this and handle it in the next bug bounty.