Jade, you're supposed to be so minimalist. But today... Today, I did this. I am sorry.

This commit is contained in:
Nick Winter 2014-05-31 22:09:41 -07:00
parent 852053022a
commit 400fddc294
7 changed files with 471 additions and 136 deletions

View file

@ -198,6 +198,8 @@
education: "Education"
our_notes: "Our Notes"
projects: "Projects"
active: "Looking for interview offers now"
inactive: "Not looking for offers right now"
employers:
want_to_hire_our_players: "Want to hire expert CodeCombat players?"

View file

@ -77,7 +77,7 @@ UserSchema = c.object {},
name: c.shortString {title: 'Name', description: 'Name you want employers to see, like "Nick Winter".'}
city: c.shortString {title: 'City', description: 'City you want to work in (or live in now), like "San Francisco" or "Lubbock, TX".', default: 'Defaultsville, CA', format: 'city'}
country: c.shortString {title: 'Country', description: 'Country you want to work in (or live in now), like "USA" or "France".', default: 'USA', format: 'country'}
skills: c.array {title: 'Skills', description: 'Tag relevant developer skills in order of proficiency. Employers will see the first five at a glance.', default: ['javascript'], minItems: 1, maxItems: 30, uniqueItems: true},
skills: c.array {title: 'Skills', description: 'Tag relevant developer skills in order of proficiency.', default: ['javascript'], minItems: 1, maxItems: 30, uniqueItems: true},
{type: 'string', minLength: 1, maxLength: 20, description: 'Ex.: "objective-c", "mongodb", "rails", "android", "javascript"', format: 'skill'}
experience: {type: 'integer', title: 'Years of Experience', minimum: 0, description: 'How many years of professional experience (getting paid) developing software do you have?'}
shortDescription: {type: 'string', maxLength: 140, title: 'Short Description', description: 'Who are you, and what are you looking for? 140 characters max.', default: 'Programmer seeking to build great software.'}
@ -103,7 +103,7 @@ UserSchema = c.object {},
link: c.url {title: 'Link', description: 'Link to the project.', default: 'http://example.com'}
links: c.array {title: 'Personal and Social Links', description: 'Link any other sites or profiles you want to highlight, like your GitHub, your LinkedIn, or your blog.'},
c.object {title: 'Link', description: 'A link to another site you want to highlight, like your GitHub, your LinkedIn, or your blog.', required: ['name', 'link']},
name: {type: 'string', maxLength: 30, title: 'Link Name', description: 'What are you linking to? Ex: "Personal Website", "Twitter"', format: 'link-name'}
name: {type: 'string', maxLength: 30, title: 'Link Name', description: 'What are you linking to? Ex: "Personal Website", "GitHub"', format: 'link-name'}
link: c.url {title: 'Link', description: 'The URL.', default: 'http://example.com'}
photoURL: {type: 'string', format: 'image-file', title: 'Profile Picture', description: 'Upload a 256x256px or larger image if you want to show a different profile picture to employers than your normal avatar.'}

View file

@ -7,12 +7,28 @@
background-color: rgb(78, 78, 78)
width: 100%
text-align: center
max-height: 70px
button.edit-settings-button
button
margin: 2px
i
margin-right: 5px
.sample-profile
position: absolute
right: 5px
.profile-completion-progress
width: 100%
display: inline-block
height: 33px
margin-bottom: 0
border-radius: 0
.progress-bar
line-height: 33px
font-size: 16px
.approved, .not-approved
display: none
@ -201,28 +217,27 @@
left: 0
z-index: 1
.project-image
width: 230px
height: 115px
background-size: cover
background-repeat: no-repeat
background-position: center
.project-image
width: 230px
height: 115px
background-size: cover
background-repeat: no-repeat
background-position: center
-webkit-filter: grayscale(100%)
-webkit-transition: .5s ease-in-out
-moz-filter: grayscale(100%)
-moz-transition: .5s ease-in-out
-o-filter: grayscale(100%)
-o-transition: .5s ease-in-out
filter: grayscale(100%)
transition: .5s ease-in-out
-webkit-filter: grayscale(100%)
-webkit-transition: .5s ease-in-out
-moz-filter: grayscale(100%)
-moz-transition: .5s ease-in-out
-o-filter: grayscale(100%)
-o-transition: .5s ease-in-out
filter: grayscale(100%)
transition: .5s ease-in-out
li:hover
.project-image
-webkit-filter: grayscale(0%)
-moz-filter: grayscale(0%)
-o-filter: grayscale(0%)
filter: grayscale(0%)
ul.projects li:hover .project-image, .project-image:hover
-webkit-filter: grayscale(0%)
-moz-filter: grayscale(0%)
-o-filter: grayscale(0%)
filter: grayscale(0%)
.main-content-area
@ -235,6 +250,18 @@
background-color: white
padding: 5px 5px 5px 5px
.skill-array-item
display: inline-block
input
width: 120px
margin: 5px
.project-image
width: 210px
height: 105px
cursor: pointer
.editable-icon
display: none
@ -260,6 +287,15 @@
.edit-label
color: $blue
.edit-example-button
background-color: transparentize($blue, 0.25)
.edit-example-text
color: $blue
code.edit-example-tag
color: $blue
.editable-section.deemphasized, .our-notes-section.deemphasized
opacity: 0.5

View file

@ -1,15 +1,26 @@
extends /templates/base
block content
- var profile = user.get('jobProfile');
if allowedToEditJobProfile
.profile-control-bar
button.btn.edit-settings-button#toggle-editing
i.icon-cog
if editing
if editing
button.btn.btn-success#toggle-editing
i.icon-ok
span(data-i18n="account_profile.done_editing_settings") Done Editing
else
else
button.btn#toggle-editing
i.icon-cog
span(data-i18n="account_profile.edit_settings") Edit Settings
if profile.active
button.btn.btn-success#toggle-job-profile-active
i.icon-eye-open
span(data-i18n="account_profile.active") Looking for interview offers now
else
button.btn#toggle-job-profile-active
i.icon-eye-close
span(data-i18n="account_profile.inactive") Not looking for offers right now
if me.isAdmin() && user.get('jobProfile')
button.btn.edit-settings-button#toggle-job-profile-approved
i.icon-cog
@ -17,9 +28,16 @@ block content
span(data-i18n='account_profile.not_approved').not-approved Not Approved
if !myProfile
button.btn.edit-settings-button#enter-espionage-mode 007
if editing && myProfile
a.sample-profile(href="http://codecombat.com/images/pages/account/profile/sample_profile.png", target="_blank")
button.btn
i.icon-user
span(data-i18n="account_settings.sample_profile") See a sample profile
if editing || myProfile
.progress.profile-completion-progress
.progress-bar.progress-bar-success(style="width: #{100 * progress}%")
if user.get('jobProfile') && allowedToViewJobProfile
- var profile = user.get('jobProfile');
if profile && allowedToViewJobProfile
div(class="job-profile-container" + (editing ? " editable-profile" : ""))
.job-profile-row
.left-column.full-height-column
@ -29,8 +47,8 @@ block content
img.profile-photo(src=user.getPhotoURL(240, true))
.profile-caption= profile.jobTitle || 'Software Developer'
.links-container.editable-section(title="Click to add social and personal links")
.editable-display(title="Click to edit your basic info")
.links-container.editable-section
.editable-display(title="Click to add social and personal links")
.editable-icon.glyphicon.glyphicon-pencil
if profileLinks.length
ul.links.editable-thinner
@ -44,12 +62,14 @@ block content
button.btn.btn-large.btn-inverse.flat-button= link.name
else if editing
h3.edit-label(data-i18n="account_profile.add_links") Add some links
button.btn.btn-large.btn-inverse.flat-button.edit-example-button Your Blog
button.btn.btn-large.btn-inverse.flat-button.edit-example-button Your GitHub
form.editable-form
.editable-icon.glyphicon.glyphicon-remove
h3 Personal Links
p.help-block Link any other sites or profiles you want to highlight, like your GitHub, your LinkedIn, or your blog.
.editable-array
.editable-array(data-property='links')
for link, index in profile.links.concat({})
.array-item.link-container.well.well-sm
.form-group
@ -65,9 +85,10 @@ block content
button.btn.btn-success.btn-block.save-section(data-i18n="common.save") Save
.basic-info-container.editable-section
.editable-display(title="Click to edit your basic info")
- var editableDefaults = editing && profile.city == jobProfileSchema.properties.city.default
div(class="editable-display" + (editableDefaults ? " edit-example-text" : ""), title="Click to edit your basic info")
.editable-icon.glyphicon.glyphicon-pencil
if editing && profile.city == "Defaultsville, CA"
if editableDefaults
h3.edit-label Update basic info
div= profile.city + ', ' + profile.country
div= profile.visa
@ -100,6 +121,12 @@ block content
label.control-label Country
input.form-control(type='country', maxlength='100', data-schemaformat='country', name='root[country]', value=profile.country)
p.help-block Country you want to work in (or live in now), like "USA" or "France".
.form-group
label.control-label US Work Status
select.form-control(name='root[visa]')
option(value='Authorized to work in the US', selected=profile.visa == 'Authorized to work in the US') Authorized to work in the US
option(value='Need visa sponsorship', selected=profile.visa == 'Need visa sponsorship') Need visa sponsorship
p.help-block Are you authorized to work in the US, or do you need visa sponsorship?
.form-group
label.control-label Looking For
select.form-control(name='root[lookingFor]')
@ -111,72 +138,208 @@ block content
p.help-block What kind of developer position do you want?
button.btn.btn-success.btn-block.save-section(data-i18n="common.save") Save
button#contact-candidate.btn.btn-large.btn-inverse.flat-button(disabled=editing)
span(data-i18n="account_profile.contact") Contact
| #{profile.name.split(' ')[0]}
if !editing
button#contact-candidate.btn.btn-large.btn-inverse.flat-button
span(data-i18n="account_profile.contact") Contact
| #{profile.name.split(' ')[0]}
.middle-column.full-height-column
.sub-column
.name-container.editable-section(title="Click to fill in your name")
.editable-icon.glyphicon.glyphicon-pencil
h3= profile.name || (editing ? "Fill in your name" : "Anonymous Developer")
.name-container.editable-section
.editable-display(title="Click to fill in your name")
.editable-icon.glyphicon.glyphicon-pencil
h3(class=editing && !profile.name ? "edit-label" : "")= profile.name || (editing ? "Fill in your name" : "Anonymous Developer")
form.editable-form
.editable-icon.glyphicon.glyphicon-remove
.form-group
label.control-label Name
input.form-control(type='text', maxlength='100', name='root[name]', value=profile.name)
p.help-block Name you want employers to see, like "Nick Winter".
button.btn.btn-success.btn-block.save-section(data-i18n="common.save") Save
.short-description-container.editable-section(title="Click to write your short description")
.editable-icon.glyphicon.glyphicon-pencil
if editing && (!profile.shortDescription || profile.shortDescription == jobProfileSchema.properties.shortDescription.default)
h3.edit-label(data-i18n="account_profile.add_short_description") Write a short description of yourself
else if profile.shortDescription
p.editable-thinner= profile.shortDescription
.short-description-container.editable-section
.editable-display(title="Click to write your short description")
.editable-icon.glyphicon.glyphicon-pencil
if editing && (!profile.shortDescription || profile.shortDescription == jobProfileSchema.properties.shortDescription.default)
h3.edit-label(data-i18n="account_profile.add_short_description") Write a short description of yourself
p.edit-example-text Add a blurb here that will show, at a glance, whether you might be just the developer that an employer is looking for.
else if profile.shortDescription
p.editable-thinner= profile.shortDescription
form.editable-form
.editable-icon.glyphicon.glyphicon-remove
.form-group
label.control-label Short Description
textarea.form-control(rows=3, maxlength='140', name='root[shortDescription]')= profile.shortDescription
p.help-block Who are you, and what are you looking for? 140 characters max.
button.btn.btn-success.btn-block.save-section(data-i18n="common.save") Save
.skills-container.editable-section.editable-thinner(title="Click to tag your programming skills")
.editable-icon.glyphicon.glyphicon-pencil
if editing && profile.skills.length == 1 && profile.skills[0] == 'javascript'
h3.edit-label Tag your programming skills
else
each skill in profile.skills
code= skill
span
.skills-container.editable-section
.editable-display.editable-thinner(title="Click to tag your programming skills")
.editable-icon.glyphicon.glyphicon-pencil
if editing && !profile.skills.length || (profile.skills.length == 1 && profile.skills[0] == 'javascript')
h3.edit-label Tag your programming skills
each skill in ["python", "coffeescript", "node", "ios", "objective-c", "javascript", "app-engine", "mongodb", "web dev", "django", "backbone"]
code.edit-example-tag= skill
span
else
each skill in profile.skills
code= skill
span
.long-description-container.editable-section(title="Click to start writing your longer description")
.editable-icon.glyphicon.glyphicon-pencil
if editing && (!profile.longDescription || profile.longDescription == jobProfileSchema.properties.longDescription.default)
h3.edit-label Detail your desired position
else if profile.longDescription
div.long-description.editable-thinner!= marked(profile.longDescription)
form.editable-form
.editable-icon.glyphicon.glyphicon-remove
h3 Skills
p.help-block
| Tag relevant developer skills in order of proficiency.
| Ex.: "objective-c", "mongodb", "rails", "android", "javascript"
.editable-array(data-property='skills')
for skill, index in profile.skills.concat('')
.array-item.skill-array-item
input.form-control(type='skill', maxlength='20', pattern='.{1,}', data-schemaformat='skill', name='root[skills][0]', value=skill)
button.btn.btn-success.btn-block.save-section(data-i18n="common.save") Save
.long-description-container.editable-section
.editable-display(title="Click to start writing your longer description")
.editable-icon.glyphicon.glyphicon-pencil
if editing && (!profile.longDescription || profile.longDescription == jobProfileSchema.properties.longDescription.default)
h3.edit-label Detail your desired position
p.edit-example-text Write a little longer section here to describe the role you would like to pursue next.
p.edit-example-text Talk about how awesome you are and why it would be a good idea to hire you.
else if profile.longDescription
div.long-description.editable-thinner!= marked(profile.longDescription)
.work-container.editable-section(title="Click to add work experience")
.editable-icon.glyphicon.glyphicon-pencil
if profile.work.length
h3.experience-header
img.header-icon(src="/images/pages/account/profile/work.png", alt="")
span(data-i18n="account_profile.work_experience") Work Experience
each job in profile.work
if job.role && job.employer
div.experience-entry
div.duration.pull-right= job.duration
| #{job.role} at #{job.employer}
form.editable-form
.editable-icon.glyphicon.glyphicon-remove
.form-group
label.control-label Description
textarea.form-control(rows=20, maxlength='600', data-schemaformat='markdown', name='root[longDescription]')= profile.longDescription
p.help-block
| Describe yourself to potential employers. Keep it short and to the point. We recommend outlining the position that would most interest you. Tasteful markdown okay; 600 characters max.
button.btn.btn-success.btn-block.save-section(data-i18n="common.save") Save
.work-container.editable-section
.editable-display(title="Click to add work experience")
.editable-icon.glyphicon.glyphicon-pencil
if profile.work.length
h3.experience-header
img.header-icon(src="/images/pages/account/profile/work.png", alt="")
span(data-i18n="account_profile.work_experience") Work Experience
| - #{profile.experience} years
each job in profile.work
if job.role && job.employer
div.experience-entry
div.duration.pull-right= job.duration
| #{job.role} at #{job.employer}
.clearfix
if job.description
div!= marked(job.description)
else if editing
h3.experience-header.edit-label Chronicle your work history
div.experience-entry.edit-example-text
div.duration.pull-right June, 2012 - present
| UX Designer at Hooli
.clearfix
if job.description
div!= marked(job.description)
else if editing
h3.edit-label Chronicle your work history
.education-container.editable-section(title="Click to add academic experience")
.editable-icon.glyphicon.glyphicon-pencil
if profile.education.length
h3.experience-header
img.header-icon(src="/images/pages/account/profile/education.png", alt="")
span(data-i18n="account_profile.education") Education
each school in profile.education
if school.degree && school.school
div.experience-entry
div.duration.pull-right= school.duration
| #{school.degree} at #{school.school}
div Revolutionized CSS, refactored flattening, and designed all the things.
div.experience-entry.edit-example-text
div.duration.pull-right 1999 - 2012
| Software Engineer at Initrode
.clearfix
if school.description
div!= marked(school.description)
else if editing
h3.edit-label Recount your academic ordeals
div Architected a peer-to-peer streaming automatic TPS report fulfillment system.
form.editable-form
.editable-icon.glyphicon.glyphicon-remove
h3
span Work Experience
.form-group
label.control-label Years of Experience
input.form-control(type='text', name='root[experience]')
p.help-block
| How many years of professional experience (getting paid) developing software do you have?
p List your relevant work experience, most recent first.
.editable-array(data-property='work')
for job, index in profile.work.concat({})
.array-item.well.well-sm
.form-group
label.control-label Employer
input.form-control(type='text', maxlength='100', name='root[work][0][employer]', value=job.employer)
p.help-block Name of your employer.
.form-group
label.control-label Job Title
input.form-control(type='text', maxlength='100', name='root[work][0][role]', value=job.role)
p.help-block What was your job title or role?
.form-group
label.control-label Duration
input.form-control(type='text', maxlength='100', name='root[work][0][duration]', value=job.duration)
p.help-block When did you hold this gig? Ex.: "Feb 2013 - present".
.form-group
label.control-label Description
textarea.form-control(rows=3, maxlength='140', name='root[work][0][description]')= job.description
p.help-block What did you do there? (140 chars; optional)
button.btn.btn-success.btn-block.save-section(data-i18n="common.save") Save
.education-container.editable-section
.editable-display(title="Click to add academic experience")
.editable-icon.glyphicon.glyphicon-pencil
if profile.education.length
h3.experience-header
img.header-icon(src="/images/pages/account/profile/education.png", alt="")
span(data-i18n="account_profile.education") Education
each school in profile.education
if school.degree && school.school
div.experience-entry
div.duration.pull-right= school.duration
| #{school.degree} at #{school.school}
.clearfix
if school.description
div!= marked(school.description)
else if editing
h3.experience-header.edit-label Recount your academic ordeals
div.experience-entry.edit-example-text
div.duration.pull-right 1995 - 1997
| Ph.D. Janitorial Science at MIT
.clearfix
div Anonymously solved difficult problems in algebraic graph theory. Swept the floors.
form.editable-form
.editable-icon.glyphicon.glyphicon-remove
h3
span Education
.btn-group(style='margin-left: 10px;')
button.btn.btn-default.json-editor-btn-collapse(title='Collapse', style='display: none;')
i.glyphicon.glyphicon-chevron-down
p List your academic ordeals.
.editable-array(data-property='education')
for school, index in profile.education.concat({})
.array-item.well.well-sm
.form-group
label.control-label School
input.form-control(type='text', maxlength='100', name='root[education][0][school]', value=school.school)
p.help-block Name of your school.
.form-group
label.control-label Degree
input.form-control(type='text', maxlength='100', name='root[education][0][degree]', value=school.degree)
p.help-block
| What was your degree and field of study? Ex. Ph.D. Human-Computer Interaction (incomplete)
.form-group
label.control-label Dates
input.form-control(type='text', maxlength='100', name='root[education][0][duration]', value=school.duration)
p.help-block When? Ex.: "Aug 2004 - May 2008".
.form-group
label.control-label Description
textarea.form-control(rows=3, maxlength='140', name='root[education][0][description]')= school.description
p.help-block Highlight anything about this educational experience. (140 chars; optional)
button.btn.btn-success.btn-block.save-section(data-i18n="common.save") Save
if user.get('jobProfileNotes') || me.isAdmin()
div(class="our-notes-section" + (editing ? " deemphasized" : ""))
@ -190,22 +353,62 @@ block content
.right-column.full-height-column
.sub-column
.projects-container.editable-section(title="Click to add your projects")
.editable-icon.glyphicon.glyphicon-pencil
if profile.projects.length
h3(data-i18n="account_profile.projects") Projects
ul.projects
each project in profile.projects
if project.name
li
if project.link && project.link.length && project.link != 'http://example.com'
a(href=project.link)
if project.picture
.project-image(style="background-image: url('/file/" + project.picture + "')")
p= project.name
div!= marked(project.description)
else if editing
h3.edit-label Add 3 projects
.projects-container.editable-section
.editable-display(title="Click to add your projects")
.editable-icon.glyphicon.glyphicon-pencil
if profile.projects.length
h3(data-i18n="account_profile.projects") Projects
ul.projects
each project in profile.projects
if project.name
li
if project.link && project.link.length && project.link != 'http://example.com'
a(href=project.link)
if project.picture
.project-image(style="background-image: url('/file/" + project.picture + "')")
p= project.name
div!= marked(project.description)
else if editing
h3.edit-label Add 3 projects
ul.projects
li.edit-example-text
.project-image(style="background-image: url('/file/db/user/52a57252a89409700d0000d9/godzilla_babies.jpg')")
p HTML5 Godzilla Babies
div I orchestrated a combat between a young Godzilla and nine thousand young human baby infants, filmed for fun and profit, using Shadow DOM.
li.edit-example-text
.project-image(style="background-image: url('/images/level/hud_center.png')")
p Node.js Framework Framework
div Yo dawg, I heard you like web frameworks, so I made a web framework framework...
li.edit-example-text
.project-image(style="background-image: url('/images/level/popover_background.png')")
p Unfinished 2.5D MMORPGFPS
div A real-time multiplayer game engine with cross-platform streaming shader support and hand-drawn characters.
form.editable-form
.editable-icon.glyphicon.glyphicon-remove
h3 Projects (Top 3)
p Highlight your projects to amaze employers.
for index in [0, 1, 2]
- var project = profile.projects[index] || {};
.array-item.well.well-sm
.form-group
label.control-label Project Name
input.form-control(type='text', maxlength='100', name="root[projects][#{index}][name]", value=project.name)
p.help-block What was the project called?
.form-group
label.control-label Description
textarea.form-control(rows=6, maxlength='400', data-schemaformat='markdown', name="root[projects][#{index}][description]")= project.description
p.help-block Briefly describe the project.
.form-group
label.control-label Picture
.project-image(style="background-image: url('" + (src=project.picture ? "/file/" + project.picture : "/images/jquery.minicolors.png") + "')")
input(type="hidden", name="root[projects][#{index}][picture]", value=project.picture)
p.help-block Upload a 230x115px or larger image showing off the project.
.form-group
label.control-label Link
input.form-control(type='url', pattern='^(ht|f)tp(s?)://[0-9a-zA-Z]([-.w]*[0-9a-zA-Z])*(:(0-9)*)*(/?)([a-zA-Z0-9-.?,\'/\+&%$#_=]*)?$', data-schemaformat='url', name="root[projects][#{index}][link]", value=project.link)
p.help-block Link to the project.
button.btn.btn-success.btn-block.save-section(data-i18n="common.save") Save
else if allowedToViewJobProfile
.public-profile-container

View file

@ -54,7 +54,7 @@ module.exports = class JobProfileView extends CocoView
next = null
for metric in metrics = @getProgressMetrics()
done = metric.fn()
completed += metric.weight ? 1 if done
completed += metric.weight if done
totalWeight += metric.weight
next = metric.name unless next or done
progress = Math.round 100 * completed / totalWeight

View file

@ -6,23 +6,27 @@ JobProfileContactView = require 'views/modal/job_profile_contact_modal'
module.exports = class ProfileView extends View
id: "profile-view"
template: template
editing: false
events:
'click #toggle-editing': 'toggleEditing'
'click #toggle-job-profile-active': 'toggleJobProfileActive'
'click #toggle-job-profile-approved': 'toggleJobProfileApproved'
'click save-notes-button': 'onJobProfileNotesChanged'
'click #contact-candidate': 'onContactCandidate'
'click #enter-espionage-mode': 'enterEspionageMode'
'click .editable-profile .profile-photo': 'onEditProfilePhoto'
'click .editable-profile .project-image': 'onEditProjectImage'
'click .editable-profile .editable-display': 'onEditSection'
'click .editable-profile .save-section': 'onSaveSection'
'click .editable-profile .glyphicon-remove': 'onCancelSectionEdit'
'change .editable-profile .editable-array input': 'onEditArray'
'keyup .editable-profile .editable-array input': 'onEditArray'
'click .editable-profile a': 'onClickLinkWhileEditing'
constructor: (options, @userID) ->
@onJobProfileNotesChanged = _.debounce @onJobProfileNotesChanged, 1000
super options
@uploadFilePath = "db/user/#{@userID}"
if @userID is me.id
@user = me
else if me.isAdmin() or "employer" in me.get('permissions')
@ -37,12 +41,17 @@ module.exports = class ProfileView extends View
context.myProfile = @user.id is context.me.id
context.allowedToViewJobProfile = me.isAdmin() or "employer" in me.get('permissions') or context.myProfile
context.allowedToEditJobProfile = me.isAdmin() or context.myProfile
context.progress = @progress ? @updateProgress()
@editing ?= context.progress < 0.8
context.editing = @editing
context.jobProfileSchema = me.schema().properties.jobProfile
context.marked = marked
context.moment = moment
context.iconForLink = @iconForLink
if links = @user.get('jobProfile')?.links
unless jobProfile = @user.get 'jobProfile'
@user.set 'jobProfile', jobProfile = {}
jobProfile.name ?= (@user.get('firstName') + ' ' + @user.get('lastName')).trim() if @user.get('firstName')
if links = jobProfile.links
links = ($.extend(true, {}, link) for link in links)
link.icon = @iconForLink link for link in links
context.profileLinks = _.sortBy links, (link) -> not link.icon # icons first
@ -56,6 +65,7 @@ module.exports = class ProfileView extends View
@$el.find('.middle-column').addClass('double-column')
unless @editing
@$el.find('.editable-display').attr('title', '')
@progress = @updateProgress()
updateProfileApproval: ->
approved = @user.get 'jobProfileApproved'
@ -72,6 +82,11 @@ module.exports = class ProfileView extends View
@user.save()
@updateProfileApproval()
toggleJobProfileActive: ->
active = not @user.get('jobProfile').active
@user.get('jobProfile').active = active
@saveEdits()
enterEspionageMode: ->
postData = emailLower: @user.get('email').toLowerCase(), usernameLower: @user.get('name').toLowerCase()
$.ajax
@ -122,24 +137,35 @@ module.exports = class ProfileView extends View
@render()
onEditProfilePhoto: (e) ->
filepicker.pick {mimetypes: 'image/*'}, @onProfilePhotoChosen
onSaving = =>
@$el.find('.profile-photo').addClass('saving')
onSaved = (uploadingPath) =>
@user.get('jobProfile').photoURL = uploadingPath
@saveEdits()
filepicker.pick {mimetypes: 'image/*'}, @onImageChosen(onSaving, onSaved)
onProfilePhotoChosen: (inkBlob) =>
filePath = "db/user/#{@user.id}"
body =
url: inkBlob.url
filename: inkBlob.filename
mimetype: inkBlob.mimetype
path: filePath
force: true
onEditProjectImage: (e) ->
img = $(e.target)
onSaving = =>
img.addClass('saving')
onSaved = (uploadingPath) =>
img.parent().find('input').val(uploadingPath)
img.css('background-image', "url('/file/#{uploadingPath}')")
img.removeClass('saving')
filepicker.pick {mimetypes: 'image/*'}, @onImageChosen(onSaving, onSaved)
@uploadingPath = [filePath, inkBlob.filename].join('/')
@$el.find('.profile-photo').addClass('saving')
$.ajax '/file', type: 'POST', data: body, success: @onFileUploaded
formatImagePostData: (inkBlob) ->
url: inkBlob.url, filename: inkBlob.filename, mimetype: inkBlob.mimetype, path: @uploadFilePath, force: true
onFileUploaded: (e) =>
@user.get('jobProfile').photoURL = @uploadingPath
@saveEdits()
onImageChosen: (onSaving, onSaved) ->
(inkBlob) =>
onSaving()
uploadingPath = [@uploadFilePath, inkBlob.filename].join('/')
$.ajax '/file', type: 'POST', data: @formatImagePostData(inkBlob), success: @onImageUploaded(onSaved, uploadingPath)
onImageUploaded: (onSaved, uploadingPath) ->
(e) =>
onSaved uploadingPath
onEditSection: (e) ->
section = $(e.target).closest('.editable-section')
@ -155,26 +181,38 @@ module.exports = class ProfileView extends View
onSaveSection: (e) ->
e.preventDefault()
section = $(e.target).closest('.editable-section')
form = $(e.target).closest('form')
isEmpty = @arrayItemIsEmpty
section.find('.editable-array .array-item').each ->
section.find('.array-item').each ->
console.log "removing", @ if isEmpty @
$(@).remove() if isEmpty @
resetOnce = false # We have to clear out arrays if we're going to redo them
for field in $(e.target).closest('form').serializeArray()
serialized = form.serializeArray()
jobProfile = @user.get 'jobProfile'
rootPropertiesSeen = {}
for field in serialized
keyChain = @extractFieldKeyChain field.name
value = @extractFieldValue keyChain[0], field.value
console.log "Should save", keyChain, value
parent = @user.get('jobProfile')
parent = jobProfile
for key, i in keyChain
console.log key, i
rootPropertiesSeen[key] = true unless i
break if i is keyChain.length - 1
child = parent[key]
if _.isArray(child) and not resetOnce
child = parent[key] = []
resetOnce = true
console.log " resetting"
else unless child?
child = parent[key] = {}
parent = child
console.log " Setting", parent, "prop", key, "to", value
parent[key] = value
form.find('.editable-array').each ->
key = $(@).data('property')
unless rootPropertiesSeen[key]
jobProfile[key] = []
if section.hasClass('projects-container') and not section.find('.array-item').length
jobProfile.projects = []
section.addClass 'saving'
@saveEdits()
@ -185,14 +223,16 @@ module.exports = class ProfileView extends View
extractFieldValue: (key, value) ->
switch key
when 'active' then Boolean value
when 'experience' then parseInt value or '0'
else value
arrayItemIsEmpty: (arrayItem) ->
for input in $(arrayItem).find('input')
return false if $(input).val()
for input in $(arrayItem).find('input[type!=hidden], textarea')
return false if $(input).val().trim()
true
onEditArray: (e) ->
# We make sure there's always an empty array item at the end for the user to add to, deleting interstitial empties.
array = $(e.target).closest('.editable-array')
arrayItems = array.find('.array-item')
toRemove = []
@ -200,13 +240,67 @@ module.exports = class ProfileView extends View
empty = @arrayItemIsEmpty arrayItem
if index is arrayItems.length - 1
lastEmpty = empty
else if empty
else if empty and not $(arrayItem).find('input:focus, textarea:focus').length
toRemove.unshift index
$(arrayItems[emptyIndex]).remove() for emptyIndex in toRemove
unless lastEmpty
clone = $(arrayItem).clone(true)
clone.find('input').each -> $(@).val('')
clone.find('textarea').each -> $(@).text('')
array.append clone
for arrayItem, index in array.find('.array-item')
for input in $(arrayItem).find('input')
for input in $(arrayItem).find('input, textarea')
$(input).attr('name', $(input).attr('name').replace(/\[\d+\]/, "[#{index}]"))
onClickLinkWhileEditing: (e) ->
e.preventDefault()
updateProgress: ->
completed = 0
totalWeight = 0
next = null
for metric in metrics = @getProgressMetrics()
done = metric.fn()
completed += metric.weight if done
totalWeight += metric.weight
next = metric.name unless next or done
progress = Math.round 100 * completed / totalWeight
bar = @$el.find('.profile-completion-progress .progress-bar')
bar.css 'width', "#{progress}%"
text = ""
if next and progress > 40
text = "#{progress}% complete. Next: #{next}"
else if next and progress > 30
text = "#{progress}%. Next: #{next}"
else if next and progress > 20
text = "#{progress}%: #{next}"
else if progress > 11
text = "#{progress}% complete."
else if progress > 3
text = "#{progress}%"
bar.text text
bar.parent().toggle Boolean progress
completed / totalWeight
getProgressMetrics: ->
return @progressMetrics if @progressMetrics
schema = me.schema().properties.jobProfile
jobProfile = @user.get('jobProfile')
exists = (field) -> -> jobProfile[field]
modified = (field) -> -> jobProfile[field] and jobProfile[field] isnt schema.properties[field].default
listStarted = (field, subfields) -> -> jobProfile[field]?.length and _.every subfields, (subfield) -> jobProfile[field][0][subfield]
@progressMetrics = [
{name: "job title?", weight: 0, fn: exists 'jobTitle'}
{name: "choose your city.", weight: 1, fn: modified 'city'}
{name: "pick your country.", weight: 0, fn: exists 'country'}
{name: "provide your name.", weight: 1, fn: modified 'name'}
{name: "summarize yourself at a glance.", weight: 2, fn: modified 'shortDescription'}
{name: "list at least five skills.", weight: 2, fn: -> jobProfile.skills.length >= 5}
{name: "describe the work you're looking for.", weight: 3, fn: modified 'longDescription'}
{name: "list your work experience.", weight: 3, fn: listStarted 'work', ['role', 'employer']}
{name: "recount your educational ordeals.", weight: 3, fn: listStarted 'education', ['degree', 'school']}
{name: "show off up to three projects you've worked on.", weight: 3, fn: listStarted 'projects', ['name']}
{name: "add any personal or social links.", weight: 2, fn: listStarted 'links', ['link', 'name']}
{name: "add an optional professional photo.", weight: 2, fn: modified 'photoURL'}
{name: "mark yourself open to offers to show up in searches.", weight: 1, fn: modified 'active'}
]

View file

@ -32,7 +32,7 @@ module.exports = class LadderView extends RootView
events:
'click .play-button': 'onClickPlayButton'
'click a': 'onClickedLink'
'click a:not([data-toggle])': 'onClickedLink'
constructor: (options, @levelID) ->
super(options)