2014-01-14 01:29:58 -05:00
|
|
|
View = require 'views/kinds/RootView'
|
|
|
|
template = require 'templates/employers'
|
2014-04-07 18:21:05 -04:00
|
|
|
app = require 'application'
|
2014-04-06 20:01:56 -04:00
|
|
|
User = require 'models/User'
|
2014-06-17 16:03:08 -04:00
|
|
|
UserRemark = require 'models/UserRemark'
|
2014-04-24 20:36:07 -04:00
|
|
|
{me} = require 'lib/auth'
|
2014-04-22 15:42:26 -04:00
|
|
|
CocoCollection = require 'collections/CocoCollection'
|
2014-04-11 15:49:44 -04:00
|
|
|
EmployerSignupView = require 'views/modal/employer_signup_modal'
|
2014-04-06 20:01:56 -04:00
|
|
|
|
|
|
|
class CandidatesCollection extends CocoCollection
|
|
|
|
url: '/db/user/x/candidates'
|
|
|
|
model: User
|
|
|
|
|
2014-06-17 16:03:08 -04:00
|
|
|
class UserRemarksCollection extends CocoCollection
|
|
|
|
url: '/db/user.remark?project=contact,contactName,user'
|
|
|
|
model: UserRemark
|
|
|
|
|
2014-01-14 01:29:58 -05:00
|
|
|
module.exports = class EmployersView extends View
|
|
|
|
id: "employers-view"
|
|
|
|
template: template
|
2014-04-05 20:05:03 -04:00
|
|
|
|
2014-04-07 18:21:05 -04:00
|
|
|
events:
|
2014-04-07 20:58:02 -04:00
|
|
|
'click tbody tr': 'onCandidateClicked'
|
2014-07-02 18:48:26 -04:00
|
|
|
'change #filters input': 'onFilterChanged'
|
2014-07-03 13:14:32 -04:00
|
|
|
'click #filter-button': 'applyFilters'
|
2014-07-03 14:39:44 -04:00
|
|
|
'change #select_all_checkbox': 'handleSelectAllChange'
|
2014-07-03 17:40:39 -04:00
|
|
|
'click .get-started-button': 'openSignupModal'
|
|
|
|
'click .navbar-brand': 'restoreBodyColor'
|
2014-07-03 18:10:09 -04:00
|
|
|
'click #login-link': 'onClickAuthbutton'
|
2014-07-03 19:30:27 -04:00
|
|
|
'click #filter-link': 'swapFolderIcon'
|
2014-04-07 18:21:05 -04:00
|
|
|
|
2014-04-06 20:01:56 -04:00
|
|
|
constructor: (options) ->
|
|
|
|
super options
|
|
|
|
@getCandidates()
|
2014-07-02 18:48:26 -04:00
|
|
|
@setFilterDefaults()
|
|
|
|
|
2014-07-03 14:39:44 -04:00
|
|
|
|
2014-04-05 20:05:03 -04:00
|
|
|
afterRender: ->
|
|
|
|
super()
|
2014-04-06 20:01:56 -04:00
|
|
|
@sortTable() if @candidates.models.length
|
|
|
|
|
2014-04-29 18:12:50 -04:00
|
|
|
afterInsert: ->
|
|
|
|
super()
|
|
|
|
_.delay @checkForEmployerSignupHash, 500
|
2014-07-03 17:40:39 -04:00
|
|
|
#fairly hacky, change this in the future
|
|
|
|
@originalBackgroundColor = $("body").css 'background-color'
|
|
|
|
$("body").css 'background-color', '#B4B4B4'
|
2014-07-03 14:39:44 -04:00
|
|
|
|
2014-07-03 17:40:39 -04:00
|
|
|
restoreBodyColor: ->
|
|
|
|
$("body").css 'background-color', @originalBackgroundColor
|
2014-07-03 19:30:27 -04:00
|
|
|
|
|
|
|
swapFolderIcon: ->
|
|
|
|
$("#folder-icon").toggleClass("glyphicon-folder-close").toggleClass("glyphicon-folder-open")
|
2014-07-03 14:39:44 -04:00
|
|
|
onFilterChanged: ->
|
2014-07-02 18:48:26 -04:00
|
|
|
@resetFilters()
|
|
|
|
that = @
|
|
|
|
$("#filters :input").each ->
|
|
|
|
input = $(this)
|
|
|
|
checked = input.prop 'checked'
|
|
|
|
name = input.attr 'name'
|
2014-07-03 14:39:44 -04:00
|
|
|
value = input.val()
|
|
|
|
if name is "phoneScreenFilter"
|
|
|
|
value = JSON.parse(input.prop 'value')
|
2014-07-02 18:48:26 -04:00
|
|
|
if checked
|
2014-07-03 14:39:44 -04:00
|
|
|
that.filters[name] = _.union that.filters[name], [value]
|
|
|
|
else
|
|
|
|
that.filters[name] = _.difference that.filters[name], [value]
|
2014-07-03 16:59:10 -04:00
|
|
|
|
|
|
|
for filterName, filterValues of @filters
|
|
|
|
if filterValues.length is 0
|
|
|
|
@filters[filterName] = @defaultFilters[filterName]
|
|
|
|
|
2014-07-03 17:40:39 -04:00
|
|
|
openSignupModal: ->
|
|
|
|
@openModalView new EmployerSignupView
|
2014-07-03 14:39:44 -04:00
|
|
|
handleSelectAllChange: (e) ->
|
|
|
|
checkedState = e.currentTarget.checked
|
|
|
|
$("#filters :input").each ->
|
|
|
|
$(this).prop 'checked', checkedState
|
|
|
|
@onFilterChanged()
|
|
|
|
|
2014-07-02 18:48:26 -04:00
|
|
|
resetFilters: ->
|
|
|
|
for filterName, filterValues of @filters
|
|
|
|
@filters[filterName] = []
|
|
|
|
|
2014-07-02 19:47:02 -04:00
|
|
|
applyFilters: ->
|
|
|
|
candidateList = _.sortBy @candidates.models, (c) -> c.get('jobProfile').updated
|
|
|
|
candidateList = _.filter candidateList, (c) -> c.get('jobProfileApproved')
|
|
|
|
|
2014-07-03 14:39:44 -04:00
|
|
|
filteredCandidates = candidateList
|
2014-07-02 18:48:26 -04:00
|
|
|
for filterName, filterValues of @filters
|
|
|
|
if filterName is "visa"
|
2014-07-03 14:39:44 -04:00
|
|
|
filteredCandidates = _.difference filteredCandidates, _.filter(filteredCandidates, (c) ->
|
2014-07-02 18:48:26 -04:00
|
|
|
fieldValue = c.get('jobProfile').visa
|
2014-07-03 14:39:44 -04:00
|
|
|
return not (_.contains filterValues, fieldValue)
|
2014-07-02 18:48:26 -04:00
|
|
|
)
|
|
|
|
else
|
2014-07-03 14:39:44 -04:00
|
|
|
filteredCandidates = _.difference filteredCandidates, _.filter(filteredCandidates, (c) ->
|
|
|
|
unless c.get('jobProfile').curated then return true
|
2014-07-02 18:48:26 -04:00
|
|
|
fieldValue = c.get('jobProfile').curated?[filterName]
|
2014-07-03 14:39:44 -04:00
|
|
|
return not (_.contains filterValues, fieldValue)
|
2014-07-02 18:48:26 -04:00
|
|
|
)
|
2014-07-02 19:47:02 -04:00
|
|
|
candidateIDsToShow = _.pluck filteredCandidates, 'id'
|
|
|
|
$("#candidate-table tr").each -> $(this).hide()
|
|
|
|
candidateIDsToShow.forEach (id) ->
|
|
|
|
$("[data-candidate-id=#{id}]").show()
|
2014-07-03 19:30:27 -04:00
|
|
|
$("#results").text(candidateIDsToShow.length + " results")
|
2014-07-02 19:47:02 -04:00
|
|
|
|
|
|
|
|
2014-07-02 18:48:26 -04:00
|
|
|
return filteredCandidates
|
|
|
|
setFilterDefaults: ->
|
|
|
|
@filters =
|
2014-07-03 14:39:44 -04:00
|
|
|
phoneScreenFilter: [true, false]
|
2014-07-02 18:48:26 -04:00
|
|
|
visa: ['Authorized to work in the US', 'Need visa sponsorship']
|
|
|
|
schoolFilter: ['Top 20 Eng.', 'Other US', 'Other Intl.']
|
|
|
|
locationFilter: ['Bay Area', 'New York', 'Other US', 'International']
|
|
|
|
roleFilter: ['Web Developer', 'Software Developer', 'iOS Developer', 'Android Developer', 'Project Manager']
|
|
|
|
seniorityFilter: ['College Student', 'Recent Grad', 'Junior', 'Senior', 'Management']
|
2014-07-03 16:59:10 -04:00
|
|
|
@defaultFilters = _.cloneDeep @filters
|
|
|
|
|
2014-07-02 18:48:26 -04:00
|
|
|
|
2014-04-06 20:01:56 -04:00
|
|
|
getRenderData: ->
|
2014-06-10 01:17:53 -04:00
|
|
|
ctx = super()
|
|
|
|
ctx.isEmployer = @isEmployer()
|
2014-07-03 19:30:27 -04:00
|
|
|
ctx.candidates = _.sortBy @candidates.models, (c) -> -1 * c.get('jobProfile').experience
|
2014-06-10 01:17:53 -04:00
|
|
|
ctx.activeCandidates = _.filter ctx.candidates, (c) -> c.get('jobProfile').active
|
|
|
|
ctx.inactiveCandidates = _.reject ctx.candidates, (c) -> c.get('jobProfile').active
|
|
|
|
ctx.featuredCandidates = _.filter ctx.activeCandidates, (c) -> c.get('jobProfileApproved')
|
2014-07-03 16:59:10 -04:00
|
|
|
unless @isEmployer() or me.isAdmin()
|
|
|
|
ctx.featuredCandidates = _.filter ctx.featuredCandidates, (c) -> c.get('jobProfile').curated
|
|
|
|
ctx.featuredCandidates = ctx.featuredCandidates.slice(0,7)
|
2014-06-10 01:17:53 -04:00
|
|
|
ctx.otherCandidates = _.reject ctx.activeCandidates, (c) -> c.get('jobProfileApproved')
|
2014-06-17 16:03:08 -04:00
|
|
|
ctx.remarks = {}
|
|
|
|
ctx.remarks[remark.get('user')] = remark for remark in @remarks.models
|
2014-06-10 01:17:53 -04:00
|
|
|
ctx.moment = moment
|
|
|
|
ctx._ = _
|
2014-07-03 19:30:27 -04:00
|
|
|
ctx.numberOfCandidates = ctx.featuredCandidates.length
|
2014-06-10 01:17:53 -04:00
|
|
|
ctx
|
2014-04-25 11:47:31 -04:00
|
|
|
|
2014-06-10 01:17:53 -04:00
|
|
|
isEmployer: ->
|
|
|
|
userPermissions = me.get('permissions') ? []
|
|
|
|
_.contains userPermissions, "employer"
|
2014-04-06 20:01:56 -04:00
|
|
|
|
|
|
|
getCandidates: ->
|
|
|
|
@candidates = new CandidatesCollection()
|
|
|
|
@candidates.fetch()
|
2014-06-17 16:03:08 -04:00
|
|
|
@remarks = new UserRemarksCollection()
|
|
|
|
@remarks.fetch()
|
2014-04-06 20:01:56 -04:00
|
|
|
# Re-render when we have fetched them, but don't wait and show a progress bar while loading.
|
2014-05-01 19:56:39 -04:00
|
|
|
@listenToOnce @candidates, 'all', @renderCandidatesAndSetupScrolling
|
2014-06-17 16:03:08 -04:00
|
|
|
@listenToOnce @remarks, 'all', @renderCandidatesAndSetupScrolling
|
2014-05-01 19:56:39 -04:00
|
|
|
|
|
|
|
renderCandidatesAndSetupScrolling: =>
|
|
|
|
@render()
|
|
|
|
$(".nano").nanoScroller()
|
2014-07-03 19:40:00 -04:00
|
|
|
#if window.history?.state?.lastViewedCandidateID
|
|
|
|
# $(".nano").nanoScroller({scrollTo:$("#" + window.history.state.lastViewedCandidateID)})
|
|
|
|
#else if window.location.hash.length is 25
|
|
|
|
# $(".nano").nanoScroller({scrollTo:$(window.location.hash)})
|
2014-04-05 20:05:03 -04:00
|
|
|
|
2014-06-10 01:17:53 -04:00
|
|
|
checkForEmployerSignupHash: =>
|
|
|
|
if window.location.hash is "#employerSignupLoggingIn" and not ("employer" in me.get("permissions"))
|
|
|
|
@openModalView application.router.getView("modal/employer_signup","_modal")
|
|
|
|
window.location.hash = ""
|
|
|
|
|
2014-04-05 20:05:03 -04:00
|
|
|
sortTable: ->
|
|
|
|
# http://mottie.github.io/tablesorter/docs/example-widget-bootstrap-theme.html
|
|
|
|
$.extend $.tablesorter.themes.bootstrap,
|
|
|
|
# these classes are added to the table. To see other table classes available,
|
|
|
|
# look here: http://twitter.github.com/bootstrap/base-css.html#tables
|
|
|
|
table: "table table-bordered"
|
|
|
|
caption: "caption"
|
|
|
|
header: "bootstrap-header" # give the header a gradient background
|
|
|
|
footerRow: ""
|
|
|
|
footerCells: ""
|
|
|
|
icons: "" # add "icon-white" to make them white; this icon class is added to the <i> in the header
|
|
|
|
sortNone: "bootstrap-icon-unsorted"
|
|
|
|
sortAsc: "icon-chevron-up" # glyphicon glyphicon-chevron-up" # we are still using v2 icons
|
|
|
|
sortDesc: "icon-chevron-down" # glyphicon-chevron-down" # we are still using v2 icons
|
|
|
|
active: "" # applied when column is sorted
|
|
|
|
hover: "" # use custom css here - bootstrap class may not override it
|
|
|
|
filterRow: "" # filter row class
|
|
|
|
even: "" # odd row zebra striping
|
|
|
|
odd: "" # even row zebra striping
|
|
|
|
|
2014-04-24 14:08:42 -04:00
|
|
|
|
|
|
|
# e = exact text from cell
|
|
|
|
# n = normalized value returned by the column parser
|
|
|
|
# f = search filter input value
|
|
|
|
# i = column index
|
|
|
|
# $r = ???
|
|
|
|
filterSelectExactMatch = (e, n, f, i, $r) -> e is f
|
|
|
|
|
2014-04-05 20:05:03 -04:00
|
|
|
# call the tablesorter plugin and apply the uitheme widget
|
2014-04-24 14:08:42 -04:00
|
|
|
@$el.find(".tablesorter").tablesorter
|
2014-04-05 20:05:03 -04:00
|
|
|
theme: "bootstrap"
|
|
|
|
widthFixed: true
|
|
|
|
headerTemplate: "{content} {icon}"
|
2014-04-24 14:08:42 -04:00
|
|
|
textSorter:
|
|
|
|
6: (a, b, direction, column, table) ->
|
|
|
|
days = []
|
|
|
|
for s in [a, b]
|
|
|
|
n = parseInt s
|
|
|
|
n = 0 unless _.isNumber n
|
2014-06-07 21:58:06 -04:00
|
|
|
n = 1 if /^a/.test s
|
2014-04-24 14:08:42 -04:00
|
|
|
for [duration, factor] in [
|
|
|
|
[/second/i, 1 / (86400 * 1000)]
|
|
|
|
[/minute/i, 1 / 1440]
|
|
|
|
[/hour/i, 1 / 24]
|
|
|
|
[/week/i, 7]
|
|
|
|
[/month/i, 30.42]
|
|
|
|
[/year/i, 365.2425]
|
|
|
|
]
|
|
|
|
if duration.test s
|
|
|
|
n *= factor
|
|
|
|
break
|
|
|
|
if /^in /i.test s
|
|
|
|
n *= -1
|
|
|
|
days.push n
|
|
|
|
days[0] - days[1]
|
2014-06-10 01:17:53 -04:00
|
|
|
sortList: if @isEmployer() or me.isAdmin() then [[6, 0]] else [[0, 1]]
|
2014-04-05 20:05:03 -04:00
|
|
|
# widget code contained in the jquery.tablesorter.widgets.js file
|
|
|
|
# use the zebra stripe widget if you plan on hiding any rows (filter widget)
|
2014-04-24 14:08:42 -04:00
|
|
|
widgets: ["uitheme", "zebra", "filter"]
|
2014-04-05 20:05:03 -04:00
|
|
|
widgetOptions:
|
|
|
|
# using the default zebra striping class name, so it actually isn't included in the theme variable above
|
|
|
|
# this is ONLY needed for bootstrap theming if you are using the filter widget, because rows are hidden
|
2014-04-24 14:08:42 -04:00
|
|
|
zebra: ["even", "odd"]
|
|
|
|
|
|
|
|
# extra css class applied to the table row containing the filters & the inputs within that row
|
|
|
|
filter_cssFilter: ""
|
|
|
|
|
|
|
|
# If there are child rows in the table (rows with class name from "cssChildRow" option)
|
|
|
|
# and this option is true and a match is found anywhere in the child row, then it will make that row
|
|
|
|
# visible; default is false
|
|
|
|
filter_childRows: false
|
|
|
|
|
|
|
|
# if true, filters are collapsed initially, but can be revealed by hovering over the grey bar immediately
|
|
|
|
# below the header row. Additionally, tabbing through the document will open the filter row when an input gets focus
|
|
|
|
filter_hideFilters: false
|
|
|
|
|
|
|
|
# Set this option to false to make the searches case sensitive
|
|
|
|
filter_ignoreCase: true
|
|
|
|
|
|
|
|
# jQuery selector string of an element used to reset the filters
|
2014-04-05 20:05:03 -04:00
|
|
|
filter_reset: ".reset"
|
2014-04-24 14:08:42 -04:00
|
|
|
|
|
|
|
# Use the $.tablesorter.storage utility to save the most recent filters
|
|
|
|
filter_saveFilters: true
|
|
|
|
|
|
|
|
# Delay in milliseconds before the filter widget starts searching; This option prevents searching for
|
|
|
|
# every character while typing and should make searching large tables faster.
|
|
|
|
filter_searchDelay: 150
|
|
|
|
|
|
|
|
# Set this option to true to use the filter to find text from the start of the column
|
|
|
|
# So typing in "a" will find "albert" but not "frank", both have a's; default is false
|
|
|
|
filter_startsWith: false
|
|
|
|
|
|
|
|
filter_functions:
|
|
|
|
2:
|
|
|
|
"Full-time": filterSelectExactMatch
|
|
|
|
"Part-time": filterSelectExactMatch
|
|
|
|
"Contracting": filterSelectExactMatch
|
|
|
|
"Remote": filterSelectExactMatch
|
|
|
|
"Internship": filterSelectExactMatch
|
|
|
|
5:
|
|
|
|
"0-1": (e, n, f, i, $r) -> n <= 1
|
|
|
|
"2-5": (e, n, f, i, $r) -> 2 <= n <= 5
|
|
|
|
"6+": (e, n, f, i, $r) -> 6 <= n
|
|
|
|
6:
|
|
|
|
"Last day": (e, n, f, i, $r) ->
|
|
|
|
days = parseFloat $($r.find('td')[i]).data('profile-age')
|
|
|
|
days <= 1
|
|
|
|
"Last week": (e, n, f, i, $r) ->
|
|
|
|
days = parseFloat $($r.find('td')[i]).data('profile-age')
|
|
|
|
days <= 7
|
|
|
|
"Last 4 weeks": (e, n, f, i, $r) ->
|
|
|
|
days = parseFloat $($r.find('td')[i]).data('profile-age')
|
|
|
|
days <= 28
|
2014-06-17 16:03:08 -04:00
|
|
|
8:
|
2014-04-24 14:08:42 -04:00
|
|
|
"✓": filterSelectExactMatch
|
|
|
|
"✗": filterSelectExactMatch
|
2014-04-07 18:21:05 -04:00
|
|
|
|
|
|
|
onCandidateClicked: (e) ->
|
|
|
|
id = $(e.target).closest('tr').data('candidate-id')
|
2014-07-03 18:10:09 -04:00
|
|
|
if id and (@isEmployer() or me.isAdmin())
|
2014-05-08 14:17:15 -04:00
|
|
|
if window.history
|
|
|
|
oldState = _.cloneDeep window.history.state ? {}
|
|
|
|
oldState["lastViewedCandidateID"] = id
|
|
|
|
window.history.replaceState(oldState,"")
|
2014-06-07 21:58:06 -04:00
|
|
|
else
|
2014-05-08 14:17:15 -04:00
|
|
|
window.location.hash = id
|
2014-04-07 18:21:05 -04:00
|
|
|
url = "/account/profile/#{id}"
|
2014-05-14 13:37:16 -04:00
|
|
|
window.open url,"_blank"
|
2014-04-07 18:21:05 -04:00
|
|
|
else
|
2014-04-11 15:49:44 -04:00
|
|
|
@openModalView new EmployerSignupView
|