Added i18n, error handling, autocomplete, highlighting the next section, animation for completing sections, and complete example skeleton.

This commit is contained in:
Nick Winter 2014-06-01 16:45:19 -07:00
parent d19b6760da
commit 10754e6825
5 changed files with 313 additions and 155 deletions
app
locale
styles/account
templates/account
views/account

View file

@ -26,6 +26,14 @@
minutes: "minutes" minutes: "minutes"
hour: "hour" hour: "hour"
hours: "hours" hours: "hours"
day: "day"
days: "days"
week: "week"
weeks: "weeks"
month: "month"
months: "months"
year: "year"
years: "years"
modal: modal:
close: "Close" close: "Close"
@ -194,12 +202,99 @@
looking_for: "Looking for:" looking_for: "Looking for:"
last_updated: "Last updated:" last_updated: "Last updated:"
contact: "Contact" contact: "Contact"
work_experience: "Work Experience"
education: "Education"
our_notes: "Our Notes"
projects: "Projects"
active: "Looking for interview offers now" active: "Looking for interview offers now"
inactive: "Not looking for offers right now" inactive: "Not looking for offers right now"
complete: "complete"
next: "Next"
next_city: "city?"
next_country: "pick your country."
next_name: "name?"
next_short_description: "summarize yourself at a glance."
next_long_description: "describe the work you're looking for."
next_skills: "list at least five skills."
next_work: "list your work experience."
next_education: "recount your educational ordeals."
next_projects: "show off up to three projects you've worked on."
next_links: "add any personal or social links."
next_photo: "add an optional professional photo."
next_active: "mark yourself open to offers to show up in searches."
example_blog: "Your Blog"
example_github: "Your GitHub"
links_header: "Personal Links"
links_blurb: "Link any other sites or profiles you want to highlight, like your GitHub, your LinkedIn, or your blog."
links_name: "Link Name"
links_name_help: "What are you linking to?"
links_link_blurb: "Link URL"
basics_header: "Update basic info"
basics_active: "Open to Offers"
basics_active_help: "Want interview offers right now?"
basics_job_title: "Desired Job Title"
basics_job_title_help: "What role are you looking for?"
basics_city: "City"
basics_city_help: "City you want to work in (or live in now)."
basics_country: "Country"
basics_country_help: "Country you want to work in (or live in now)."
basics_visa: "US Work Status"
basics_visa_help: "Are you authorized to work in the US, or do you need visa sponsorship?"
basics_looking_for: "Looking For"
basics_looking_for_full_time: "Full-time"
basics_looking_for_part_time: "Part-time"
basics_looking_for_remote: "Remote"
basics_looking_for_contracting: "Contracting"
basics_looking_for_internship: "Internship"
basics_looking_for_help: "What kind of developer position do you want?"
name_header: "Fill in your name"
name_anonymous: "Anonymous Developer"
name_help: "Name you want employers to see, like 'Nick Winter'."
short_description_header: "Write a short description of yourself"
short_description_blurb: "Add a blurb here that will show, at a glance, whether you might be just the developer that an employer is looking for."
short_description: "Short Description"
short_description_help: "Who are you, and what are you looking for? 140 characters max."
skills_header: "Skills"
skills_help: "Tag relevant developer skills in order of proficiency."
long_description_header: "Detail your desired position"
long_description_blurb_1: "Write a little longer section here to describe the role you would like to pursue next."
long_description_blurb_2: "Talk about how awesome you are and why it would be a good idea to hire you."
long_description: "Description"
long_description_help: "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."
work_experience: "Work Experience"
work_header: "Chronicle your work history"
work_years: "Years of Experience"
work_years_help: "How many years of professional experience (getting paid) developing software do you have?"
work_blurb: "List your relevant work experience, most recent first."
work_employer: "Employer"
work_employer_help: "Name of your employer."
work_role: "Job Title"
work_role_help: "What was your job title or role?"
work_duration: "Duration"
work_duration_help: "When did you hold this gig?"
work_description: "Description"
work_description_help: "What did you do there? (140 chars; optional)"
education: "Education"
education_header: "Recount your academic ordeals"
education_blurb: "List your academic ordeals."
education_school: "School"
education_school_help: "Name of your school."
education_degree: "Degree"
education_degree_help: "What was your degree and field of study?"
education_duration: "Dates"
education_duration_help: "When?"
education_description: "Description"
education_description_help: "Highlight anything about this educational experience. (140 chars; optional)"
our_notes: "Our Notes"
projects: "Projects"
projects_header: "Add 3 projects"
projects_header_2: "Projects (Top 3)"
projects_blurb: "Highlight your projects to amaze employers."
project_name: "Project Name"
project_name_help: "What was the project called?"
project_description: "Description"
project_description_help: "Briefly describe the project."
project_picture: "Picture"
project_picture_help: "Upload a 230x115px or larger image showing off the project."
project_link: "Link"
project_link_help: "Link to the project."
employers: employers:
want_to_hire_our_players: "Want to hire expert CodeCombat players?" want_to_hire_our_players: "Want to hire expert CodeCombat players?"

View file

@ -24,10 +24,14 @@
height: 33px height: 33px
margin-bottom: 0 margin-bottom: 0
border-radius: 0 border-radius: 0
background-color: $sideBackground
.progress-bar .progress-bar
line-height: 33px line-height: 33px
font-size: 16px font-size: 16px
text-overflow: ellipsis
overflow: hidden
white-space: nowrap
.main-content-area .main-content-area
padding: 0 padding: 0
@ -92,7 +96,7 @@
width: $side-width - 2 * $side-padding width: $side-width - 2 * $side-padding
overflow-wrap: break-word overflow-wrap: break-word
.profile-photo-container #profile-photo-container
position: relative position: relative
margin-bottom: 10px margin-bottom: 10px
@ -241,6 +245,11 @@
.job-profile-container .job-profile-container
.editable-section .editable-section
position: relative position: relative
transition: box-shadow 0.5s easeInOutQuad
&.just-saved
box-shadow: 0px 0px 80px 0px #080
z-index: 1
.editable-form .editable-form
display: none display: none
@ -294,7 +303,7 @@
code.edit-example-tag code.edit-example-tag
color: $blue color: $blue
.editable-section.deemphasized, .our-notes-section.deemphasized .editable-section.deemphasized:not(.just-saved), .our-notes-section.deemphasized
opacity: 0.5 opacity: 0.5
.editable-section:hover .editable-section:hover

View file

@ -1,8 +1,6 @@
extends /templates/base extends /templates/base
block content block content
- var profile = user.get('jobProfile');
if allowedToEditJobProfile if allowedToEditJobProfile
.profile-control-bar .profile-control-bar
if editing if editing
@ -36,7 +34,7 @@ block content
button.btn button.btn
i.icon-user i.icon-user
span(data-i18n="account_settings.sample_profile") See a sample profile span(data-i18n="account_settings.sample_profile") See a sample profile
if editing || myProfile if editing
.progress.profile-completion-progress .progress.profile-completion-progress
.progress-bar.progress-bar-success(style="width: #{100 * progress}%") .progress-bar.progress-bar-success(style="width: #{100 * progress}%")
@ -45,12 +43,12 @@ block content
.job-profile-row .job-profile-row
.left-column.full-height-column .left-column.full-height-column
.sub-column .sub-column
.profile-photo-container.editable-section(title="Click to change your photo") #profile-photo-container.editable-section(title="Click to change your photo")
.editable-icon.glyphicon.glyphicon-pencil .editable-icon.glyphicon.glyphicon-pencil
img.profile-photo(src=user.getPhotoURL(240, true)) img.profile-photo(src=user.getPhotoURL(240, true))
.profile-caption= profile.jobTitle || 'Software Developer' .profile-caption= profile.jobTitle || 'Software Developer'
.links-container.editable-section #links-container.editable-section
.editable-display(title="Click to add social and personal links") .editable-display(title="Click to add social and personal links")
.editable-icon.glyphicon.glyphicon-pencil .editable-icon.glyphicon.glyphicon-pencil
if profileLinks && profileLinks.length if profileLinks && profileLinks.length
@ -65,26 +63,28 @@ block content
button.btn.btn-large.btn-inverse.flat-button= link.name button.btn.btn-large.btn-inverse.flat-button= link.name
else if editing else if editing
h3.edit-label(data-i18n="account_profile.add_links") Add some links 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(data-i18n="account_profile.example_blog") Your Blog
button.btn.btn-large.btn-inverse.flat-button.edit-example-button Your GitHub button.btn.btn-large.btn-inverse.flat-button.edit-example-button(data-i18n="account_profile.example_githu") Your GitHub
form.editable-form form.editable-form
.editable-icon.glyphicon.glyphicon-remove .editable-icon.glyphicon.glyphicon-remove
h3 Personal Links h3(data-i18n="account_profile.links_header") Personal Links
p.help-block Link any other sites or profiles you want to highlight, like your GitHub, your LinkedIn, or your blog. p.help-block(data-i18n="account_profile.links_blurb") Link any other sites or profiles you want to highlight, like your GitHub, your LinkedIn, or your blog.
.editable-array(data-property='links') .editable-array(data-property='links')
for link, index in (profile.links || []).concat({}) for link, index in (profile.links || []).concat({})
.array-item.link-container.well.well-sm .array-item.link-container.well.well-sm
.form-group .form-group
label.control-label Link Name label.control-label(data-i18n="account_profile.links_name") Link Name
input.form-control(type='link-name', maxlength='30', data-schemaformat='link-name', name='root[links][' + index + '][name]', value=link.name) input.form-control(type='link-name', maxlength='30', data-schemaformat='link-name', name="root[links][#{index}][name]", value=link.name, data-autocomplete="commonLinkNames", data-autocomplete-min-length=0)
if !index if !index
p.help-block What are you linking to? Ex: "Personal Website", "GitHub" p.help-block
span(data-i18n="account_profile.links_name_help") What are you linking to?
| Ex.: 'Personal Website', 'GitHub'
.form-group .form-group
label.control-label Link URL label.control-label(data-i18n="account_profile.links_link") Link URL
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[links][' + index + '][link]', value=link.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[links][#{index}][link]", value=link.link)
if !index if !index
p.help-block Ex.: "https://github.com/nwinter" p.help-block Ex.: "https://github.com/nwinter"
button.btn.btn-success.btn-block.save-section(data-i18n="common.save") Save button.btn.btn-success.btn-block.save-section(data-i18n="common.save") Save
.editable-section.basic-info-container .editable-section.basic-info-container
@ -92,7 +92,7 @@ block content
div(class="editable-display" + (editableDefaults ? " edit-example-text" : ""), title="Click to edit your basic info") div(class="editable-display" + (editableDefaults ? " edit-example-text" : ""), title="Click to edit your basic info")
.editable-icon.glyphicon.glyphicon-pencil .editable-icon.glyphicon.glyphicon-pencil
if editableDefaults if editableDefaults
h3.edit-label Update basic info h3.edit-label(data-i18n="account_profile.basics_header") Update basic info
div= profile.city + ', ' + profile.country div= profile.city + ', ' + profile.country
div= profile.visa div= profile.visa
div div
@ -105,40 +105,44 @@ block content
form.editable-form form.editable-form
.editable-icon.glyphicon.glyphicon-remove .editable-icon.glyphicon.glyphicon-remove
.form-group .form-group
label.control-label Open to Offers label.control-label(data-i18n="account_profile.basics_active") Open to Offers
select.form-control(name='root[active]') select.form-control(name='root[active]')
option(value='1', selected=profile.active) Yes, I want interviews option(value='1', selected=profile.active, data-i18n="account_profile.active") Looking for interview offers now
option(value='', selected=!profile.active) No, not right now option(value='', selected=!profile.active, data-i18n="account_profile.inactive") Not looking for offers right now
p.help-block Want interview offers right now? p.help-block(data-i18n="account_profile.basics_active_help") Want interview offers right now?
.form-group .form-group
label.control-label Desired Job Title label.control-label(data-i18n="account_profile.basics_job_title") Desired Job Title
input.form-control(type='text', maxlength='50', name='root[jobTitle]', value=profile.jobTitle) input.form-control(type='text', maxlength='50', name='root[jobTitle]', value=profile.jobTitle)
p.help-block p.help-block
| What role are you looking for? Ex.: "Full Stack Engineer", "Front-End Developer", "iOS Developer" span(data-i18n="account_profile.basics_job_title_help") What role are you looking for?
| Ex.: "Full Stack Engineer", "Front-End Developer", "iOS Developer"
.form-group .form-group
label.control-label City label.control-label(data-i18n="account_profile.basics_city") City
input.form-control(type='city', maxlength='100', data-schemaformat='city', name='root[city]', value=profile.city) input.form-control(type='city', maxlength='100', data-schemaformat='city', name='root[city]', value=profile.city, data-autocomplete="commonCities", data-autocomplete-min-length=1)
p.help-block p.help-block
| City you want to work in (or live in now), like "San Francisco" or "Lubbock, TX". span(data-i18n="account_profile.basics_city_help") City you want to work in (or live in now).
| Ex.: "San Francisco", "Lubbock, TX"
.form-group .form-group
label.control-label Country label.control-label(data-i18n="account_profile.basics_country") Country
input.form-control(type='country', maxlength='100', data-schemaformat='country', name='root[country]', value=profile.country) input.form-control(type='country', maxlength='100', data-schemaformat='country', name='root[country]', value=profile.country, data-autocomplete="commonCountries", data-autocomplete-min-length=1)
p.help-block Country you want to work in (or live in now), like "USA" or "France". p.help-block
span(data-i18n="account_profile.basics_country_help") Country you want to work in (or live in now).
| Ex.: "USA", "France"
.form-group .form-group
label.control-label US Work Status label.control-label(data-i18n="account_profile.basics_visa") US Work Status
select.form-control(name='root[visa]') 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='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 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? p.help-block(data-i18n="account_profile.basics_visa_help") Are you authorized to work in the US, or do you need visa sponsorship?
.form-group .form-group
label.control-label Looking For label.control-label(data-i18n="account_profile.basics_looking_for") Looking For
select.form-control(name='root[lookingFor]') select.form-control(name='root[lookingFor]')
option(value='Full-time', selected=profile.lookingFor == "Full-time") Full-time option(value='Full-time', selected=profile.lookingFor == "Full-time", data-i18n="account_profile.basics_looking_for_full_time") Full-time
option(value='Part-time', selected=profile.lookingFor == "Part-time") Part-time option(value='Part-time', selected=profile.lookingFor == "Part-time", data-i18n="account_profile.basics_looking_for_part_time") Part-time
option(value='Remote', selected=profile.lookingFor == "Remote") Remote option(value='Remote', selected=profile.lookingFor == "Remote", data-i18n="account_profile.basics_looking_for_remote") Remote
option(value='Contracting', selected=profile.lookingFor == "Contracting") Contracting option(value='Contracting', selected=profile.lookingFor == "Contracting", data-i18n="account_profile.basics_looking_for_contracting") Contracting
option(value='Internship', selected=profile.lookingFor == "Internship") Internship option(value='Internship', selected=profile.lookingFor == "Internship", data-i18n="account_profile.basics_looking_for_internship") Internship
p.help-block What kind of developer position do you want? p.help-block(data-i18n="account_profile.basics_looking_for_help") What kind of developer position do you want?
button.btn.btn-success.btn-block.save-section(data-i18n="common.save") Save button.btn.btn-success.btn-block.save-section(data-i18n="common.save") Save
if !editing if !editing
@ -148,26 +152,31 @@ block content
.middle-column.full-height-column .middle-column.full-height-column
.sub-column .sub-column
.name-container.editable-section #name-container.editable-section
.editable-display(title="Click to fill in your name") .editable-display(title="Click to fill in your name")
.editable-icon.glyphicon.glyphicon-pencil .editable-icon.glyphicon.glyphicon-pencil
h3(class=editing && !profile.name ? "edit-label" : "")= profile.name || (editing ? "Fill in your name" : "Anonymous Developer") if editing && !profile.name
h3.edit-label(data-i18n="account_profile.name_header") Fill in your name
else if profile.name
h3= profile.name
else
h3(data-i18n="account_profile.name_anonymous") Anonymous Developer
form.editable-form form.editable-form
.editable-icon.glyphicon.glyphicon-remove .editable-icon.glyphicon.glyphicon-remove
.form-group .form-group
label.control-label Name label.control-label(data-i18n="general.name") Name
input.form-control(type='text', maxlength='100', name='root[name]', value=profile.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". p.help-block(data-i18n="account_profile.name_help") Name you want employers to see, like 'Nick Winter'.
button.btn.btn-success.btn-block.save-section(data-i18n="common.save") Save button.btn.btn-success.btn-block.save-section(data-i18n="common.save") Save
.short-description-container.editable-section #short-description-container.editable-section
.editable-display(title="Click to write your short description") .editable-display(title="Click to write your short description")
.editable-icon.glyphicon.glyphicon-pencil .editable-icon.glyphicon.glyphicon-pencil
if editing && (!profile.shortDescription || profile.shortDescription == jobProfileSchema.properties.shortDescription.default) 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 h3.edit-label(data-i18n="account_profile.short_description_header") 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. p.edit-example-text(data-i18n="account_profile.short_description_blurb") 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 else if profile.shortDescription
p.editable-thinner= profile.shortDescription p.editable-thinner= profile.shortDescription
@ -175,13 +184,13 @@ block content
form.editable-form form.editable-form
.editable-icon.glyphicon.glyphicon-remove .editable-icon.glyphicon.glyphicon-remove
.form-group .form-group
label.control-label Short Description label.control-label(data-i18n="account_profile.short_description") Short Description
textarea.form-control(rows=3, maxlength='140', name='root[shortDescription]')= profile.shortDescription 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. p.help-block(data-i18n="account_profile.short_description_help") 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 button.btn.btn-success.btn-block.save-section(data-i18n="common.save") Save
.skills-container.editable-section #skills-container.editable-section
.editable-display.editable-thinner(title="Click to tag your programming skills") .editable-display.editable-thinner(title="Click to tag your programming skills")
.editable-icon.glyphicon.glyphicon-pencil .editable-icon.glyphicon.glyphicon-pencil
if editing && (!profile.skills || !profile.skills.length || (profile.skills.length == 1 && profile.skills[0] == 'javascript')) if editing && (!profile.skills || !profile.skills.length || (profile.skills.length == 1 && profile.skills[0] == 'javascript'))
@ -196,44 +205,44 @@ block content
form.editable-form form.editable-form
.editable-icon.glyphicon.glyphicon-remove .editable-icon.glyphicon.glyphicon-remove
h3 Skills h3(data-i18n="account_profile.skills_header") Skills
p.help-block p.help-block
| Tag relevant developer skills in order of proficiency. span(data-i18n="account_profile.skills_help") Tag relevant developer skills in order of proficiency.
| Ex.: "objective-c", "mongodb", "rails", "android", "javascript" | Ex.: "objective-c", "mongodb", "rails", "android", "javascript"
.editable-array(data-property='skills') .editable-array(data-property='skills')
for skill, index in (profile.skills || []).concat('') for skill, index in (profile.skills || []).concat('')
.array-item.skill-array-item .array-item.skill-array-item
input.form-control(type='skill', maxlength='20', pattern='.{1,}', data-schemaformat='skill', name='root[skills][0]', value=skill) input.form-control(type='skill', maxlength='20', pattern='.{1,}', data-schemaformat='skill', name="root[skills][#{index}]", value=skill, data-autocomplete="commonSkills", data-autocomplete-min-length=1)
button.btn.btn-success.btn-block.save-section(data-i18n="common.save") Save button.btn.btn-success.btn-block.save-section(data-i18n="common.save") Save
.long-description-container.editable-section #long-description-container.editable-section
.editable-display(title="Click to start writing your longer description") .editable-display(title="Click to start writing your longer description")
.editable-icon.glyphicon.glyphicon-pencil .editable-icon.glyphicon.glyphicon-pencil
if editing && (!profile.longDescription || profile.longDescription == jobProfileSchema.properties.longDescription.default) if editing && (!profile.longDescription || profile.longDescription == jobProfileSchema.properties.longDescription.default)
h3.edit-label Detail your desired position h3.edit-label(data-i18n="account_profile.long_description_header") 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(data-i18n="account_profile.long_description_blurb_1") 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. p.edit-example-text(data-i18n="account_profile.long_description_blurb_2") Talk about how awesome you are and why it would be a good idea to hire you.
else if profile.longDescription else if profile.longDescription
div.long-description.editable-thinner!= marked(profile.longDescription) div.long-description.editable-thinner!= marked(profile.longDescription)
form.editable-form form.editable-form
.editable-icon.glyphicon.glyphicon-remove .editable-icon.glyphicon.glyphicon-remove
.form-group .form-group
label.control-label Description label.control-label(data-i18n="account_profile.long_description") Description
textarea.form-control(rows=20, maxlength='600', data-schemaformat='markdown', name='root[longDescription]')= profile.longDescription textarea.form-control(rows=20, maxlength='600', data-schemaformat='markdown', name='root[longDescription]')= profile.longDescription
p.help-block p.help-block(data-i18n="account_profile.long_description_help") 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.
| 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 button.btn.btn-success.btn-block.save-section(data-i18n="common.save") Save
.work-container.editable-section #work-container.editable-section
.editable-display(title="Click to add work experience") .editable-display(title="Click to add work experience")
.editable-icon.glyphicon.glyphicon-pencil .editable-icon.glyphicon.glyphicon-pencil
if profile.work && profile.work.length if profile.work && profile.work.length
h3.experience-header h3.experience-header
img.header-icon(src="/images/pages/account/profile/work.png", alt="") img.header-icon(src="/images/pages/account/profile/work.png", alt="")
span(data-i18n="account_profile.work_experience") Work Experience span(data-i18n="account_profile.work_experience") Work Experience
| - #{profile.experience} years | - #{profile.experience}
span(data-i18n=profile.experience == 1 ? "units.year" : "units.years")
each job in profile.work each job in profile.work
if job.role && job.employer if job.role && job.employer
div.experience-entry div.experience-entry
@ -243,7 +252,7 @@ block content
if job.description if job.description
div!= marked(job.description) div!= marked(job.description)
else if editing else if editing
h3.experience-header.edit-label Chronicle your work history h3.experience-header.edit-label(data-i18n="account_profile.work_header") Chronicle your work history
div.experience-entry.edit-example-text div.experience-entry.edit-example-text
div.duration.pull-right June, 2012 - present div.duration.pull-right June, 2012 - present
@ -259,36 +268,37 @@ block content
form.editable-form form.editable-form
.editable-icon.glyphicon.glyphicon-remove .editable-icon.glyphicon.glyphicon-remove
h3 Work Experience h3(data-i18n="account_profile.work_experience") Work Experience
.form-group .form-group
label.control-label Years of Experience label.control-label(data-i18n="account_profile.work_years") Years of Experience
input.form-control(type='text', name='root[experience]') input.form-control(type='text', name='root[experience]')
p.help-block p.help-block(data-i18n="account_profile.work_years_help") How many years of professional experience (getting paid) developing software do you have?
| How many years of professional experience (getting paid) developing software do you have? p(data-i18n="account_profile.work_blurb") List your relevant work experience, most recent first.
p List your relevant work experience, most recent first.
.editable-array(data-property='work') .editable-array(data-property='work')
for job, index in (profile.work || []).concat({}) for job, index in (profile.work || []).concat({})
.array-item.well.well-sm .array-item.well.well-sm
.form-group .form-group
label.control-label Employer label.control-label(data-i18n="account_profile.work_employer") Employer
input.form-control(type='text', maxlength='100', name='root[work][0][employer]', value=job.employer) input.form-control(type='text', maxlength='100', name="root[work][#{index}][employer]", value=job.employer)
p.help-block Name of your employer. p.help-block(data-i18n="account_profile.work_employer_help") Name of your employer.
.form-group .form-group
label.control-label Job Title label.control-label(data-i18n="account_profile.work_role") Job Title
input.form-control(type='text', maxlength='100', name='root[work][0][role]', value=job.role) input.form-control(type='text', maxlength='100', name="root[work][#{index}][role]", value=job.role)
p.help-block What was your job title or role? p.help-block(data-i18n="account_profile.work_role_help") What was your job title or role?
.form-group .form-group
label.control-label Duration label.control-label(data-i18n="account_profile.work_duration") Duration
input.form-control(type='text', maxlength='100', name='root[work][0][duration]', value=job.duration) input.form-control(type='text', maxlength='100', name="root[work][#{index}][duration]", value=job.duration)
p.help-block When did you hold this gig? Ex.: "Feb 2013 - present". p.help-block
span(data-i18n="account_profile.work_duration_help") When did you hold this gig?
| Ex.: "Feb 2013 - present".
.form-group .form-group
label.control-label Description label.control-label(data-i18n="account_profile.work_description") Description
textarea.form-control(rows=3, maxlength='140', name='root[work][0][description]')= job.description textarea.form-control(rows=3, maxlength='140', name="root[work][#{index}][description]")= job.description
p.help-block What did you do there? (140 chars; optional) p.help-block(data-i18n="account_profile.work_description_help") What did you do there? (140 chars; optional)
button.btn.btn-success.btn-block.save-section(data-i18n="common.save") Save button.btn.btn-success.btn-block.save-section(data-i18n="common.save") Save
.education-container.editable-section #education-container.editable-section
.editable-display(title="Click to add academic experience") .editable-display(title="Click to add academic experience")
.editable-icon.glyphicon.glyphicon-pencil .editable-icon.glyphicon.glyphicon-pencil
if profile.education && profile.education.length if profile.education && profile.education.length
@ -304,7 +314,7 @@ block content
if school.description if school.description
div!= marked(school.description) div!= marked(school.description)
else if editing else if editing
h3.experience-header.edit-label Recount your academic ordeals h3.experience-header.edit-label(data-i18n="account_profile.education_header") Recount your academic ordeals
div.experience-entry.edit-example-text div.experience-entry.edit-example-text
div.duration.pull-right 1995 - 1997 div.duration.pull-right 1995 - 1997
@ -314,28 +324,31 @@ block content
form.editable-form form.editable-form
.editable-icon.glyphicon.glyphicon-remove .editable-icon.glyphicon.glyphicon-remove
h3 Education h3(data-i18n="accont_profile.education") Education
p List your academic ordeals. p(data-i18n="account_profile.education_blurb") List your academic ordeals.
.editable-array(data-property='education') .editable-array(data-property='education')
for school, index in (profile.education || []).concat({}) for school, index in (profile.education || []).concat({})
.array-item.well.well-sm .array-item.well.well-sm
.form-group .form-group
label.control-label School label.control-label(data-i18n="account_profile.education_school") School
input.form-control(type='text', maxlength='100', name='root[education][0][school]', value=school.school) input.form-control(type='text', maxlength='100', name="root[education][#{index}][school]", value=school.school)
p.help-block Name of your school. p.help-block(data-i18n="account_profile.education_school_help") Name of your school.
.form-group .form-group
label.control-label Degree label.control-label(data-i18n="account_profile.education_degree") Degree
input.form-control(type='text', maxlength='100', name='root[education][0][degree]', value=school.degree) input.form-control(type='text', maxlength='100', name="root[education][#{index}][degree]", value=school.degree)
p.help-block p.help-block
| What was your degree and field of study? Ex. Ph.D. Human-Computer Interaction (incomplete) span(data-i18n="account_profile.education_degree_help") What was your degree and field of study?
| Ex.: "Ph.D. Human-Computer Interaction (incomplete)"
.form-group .form-group
label.control-label Dates label.control-label(data-i18n="account_profile.education_duration") Dates
input.form-control(type='text', maxlength='100', name='root[education][0][duration]', value=school.duration) input.form-control(type='text', maxlength='100', name="root[education][#{index}][duration]", value=school.duration)
p.help-block When? Ex.: "Aug 2004 - May 2008". p.help-block
span(data-i18n="account_profile.education_duration_help") When?
| Ex.: "Aug 2004 - May 2008".
.form-group .form-group
label.control-label Description label.control-label(data-i18n="account_profile.education_description") Description
textarea.form-control(rows=3, maxlength='140', name='root[education][0][description]')= school.description textarea.form-control(rows=3, maxlength='140', name="root[education][#{index}][description]")= school.description
p.help-block Highlight anything about this educational experience. (140 chars; optional) p.help-block(data-i18n="account_profile.education_description_help") Highlight anything about this educational experience. (140 chars; optional)
button.btn.btn-success.btn-block.save-section(data-i18n="common.save") Save button.btn.btn-success.btn-block.save-section(data-i18n="common.save") Save
@ -345,13 +358,13 @@ block content
- var notes = user.get('jobProfileNotes') || ''; - var notes = user.get('jobProfileNotes') || '';
if me.isAdmin() if me.isAdmin()
textarea#job-profile-notes!= notes textarea#job-profile-notes!= notes
button.btn.btn-primary#save-notes-button Save Notes button.btn.btn-primary#save-notes-button(data-i18n="common.save") Save
else else
div!= marked(notes) div!= marked(notes)
.right-column.full-height-column .right-column.full-height-column
.sub-column .sub-column
.projects-container.editable-section #projects-container.editable-section
.editable-display(title="Click to add your projects") .editable-display(title="Click to add your projects")
.editable-icon.glyphicon.glyphicon-pencil .editable-icon.glyphicon.glyphicon-pencil
if profile.projects && profile.projects.length if profile.projects && profile.projects.length
@ -367,7 +380,7 @@ block content
p= project.name p= project.name
div!= marked(project.description) div!= marked(project.description)
else if editing else if editing
h3.edit-label Add 3 projects h3.edit-label(data-i18n="account_profile.projects_header") Add 3 projects
ul.projects ul.projects
li.edit-example-text li.edit-example-text
.project-image(style="background-image: url('/file/db/user/52a57252a89409700d0000d9/godzilla_babies.jpg')") .project-image(style="background-image: url('/file/db/user/52a57252a89409700d0000d9/godzilla_babies.jpg')")
@ -384,28 +397,28 @@ block content
form.editable-form form.editable-form
.editable-icon.glyphicon.glyphicon-remove .editable-icon.glyphicon.glyphicon-remove
h3 Projects (Top 3) h3(data-i18n="account_profile.projects_header_2") Projects (Top 3)
p Highlight your projects to amaze employers. p(data-i18n="account_profile.projects_blurb") Highlight your projects to amaze employers.
for index in [0, 1, 2] for index in [0, 1, 2]
- var project = (profile.projects || [])[index] || {}; - var project = (profile.projects || [])[index] || {};
.array-item.well.well-sm .array-item.well.well-sm
.form-group .form-group
label.control-label Project Name label.control-label(data-i18n="account_profile.projects_name") Project Name
input.form-control(type='text', maxlength='100', name="root[projects][#{index}][name]", value=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? p.help-block(data-i18n="account_profile.projects_name_help") What was the project called?
.form-group .form-group
label.control-label Description label.control-label(data-i18n="account_profile.projects_description") Description
textarea.form-control(rows=6, maxlength='400', data-schemaformat='markdown', name="root[projects][#{index}][description]")= project.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. p.help-block(data-i18n="account_profile.projects_description_help") Briefly describe the project.
.form-group .form-group
label.control-label Picture label.control-label(data-i18n="account_profile.projects_picture") Picture
.project-image(style="background-image: url('" + (src=project.picture ? "/file/" + project.picture : "/images/jquery.minicolors.png") + "')") .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) input(type="hidden", name="root[projects][#{index}][picture]", value=project.picture)
p.help-block Upload a 230x115px or larger image showing off the project. p.help-block(data-i18n="account_profile.projects_picture_help") Upload a 230x115px or larger image showing off the project.
.form-group .form-group
label.control-label Link label.control-label(data-i18n="account_profile.projects_link") 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) 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. p.help-block(data-i18n="account_profile.projects_link_help") Link to the project.
button.btn.btn-success.btn-block.save-section(data-i18n="common.save") Save button.btn.btn-success.btn-block.save-section(data-i18n="common.save") Save
else if allowedToViewJobProfile else if allowedToViewJobProfile

File diff suppressed because one or more lines are too long

View file

@ -2,6 +2,8 @@ View = require 'views/kinds/RootView'
template = require 'templates/account/profile' template = require 'templates/account/profile'
User = require 'models/User' User = require 'models/User'
JobProfileContactView = require 'views/modal/job_profile_contact_modal' JobProfileContactView = require 'views/modal/job_profile_contact_modal'
JobProfileView = require 'views/account/job_profile_view'
forms = require 'lib/forms'
module.exports = class ProfileView extends View module.exports = class ProfileView extends View
id: "profile-view" id: "profile-view"
@ -24,9 +26,11 @@ module.exports = class ProfileView extends View
'click .editable-profile a': 'onClickLinkWhileEditing' 'click .editable-profile a': 'onClickLinkWhileEditing'
constructor: (options, @userID) -> constructor: (options, @userID) ->
@userID ?= me.id
@onJobProfileNotesChanged = _.debounce @onJobProfileNotesChanged, 1000 @onJobProfileNotesChanged = _.debounce @onJobProfileNotesChanged, 1000
super options super options
@uploadFilePath = "db/user/#{@userID}" @uploadFilePath = "db/user/#{@userID}"
@highlightedContainers = []
if @userID is me.id if @userID is me.id
@user = me @user = me
else if me.isAdmin() or "employer" in me.get('permissions') else if me.isAdmin() or "employer" in me.get('permissions')
@ -34,9 +38,19 @@ module.exports = class ProfileView extends View
@user.fetch() @user.fetch()
@listenTo @user, "sync", => @listenTo @user, "sync", =>
@render() @render()
else
@user = User.getByID(@userID)
getRenderData: -> getRenderData: ->
context = super() context = super()
context.jobProfileSchema = me.schema().properties.jobProfile
unless jobProfile = @user.get 'jobProfile'
jobProfile = {}
for prop, schema of context.jobProfileSchema.properties
jobProfile[prop] = _.clone schema.default if schema.default?
@user.set 'jobProfile', jobProfile
jobProfile.name ?= (@user.get('firstName') + ' ' + @user.get('lastName')).trim() if @user.get('firstName')
context.profile = jobProfile
context.user = @user context.user = @user
context.myProfile = @user.id is context.me.id context.myProfile = @user.id is context.me.id
context.allowedToViewJobProfile = me.isAdmin() or "employer" in me.get('permissions') or context.myProfile context.allowedToViewJobProfile = me.isAdmin() or "employer" in me.get('permissions') or context.myProfile
@ -45,13 +59,9 @@ module.exports = class ProfileView extends View
context.progress = @progress ? @updateProgress() context.progress = @progress ? @updateProgress()
@editing ?= context.progress < 0.8 @editing ?= context.progress < 0.8
context.editing = @editing context.editing = @editing
context.jobProfileSchema = me.schema().properties.jobProfile
context.marked = marked context.marked = marked
context.moment = moment context.moment = moment
context.iconForLink = @iconForLink context.iconForLink = @iconForLink
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 if links = jobProfile.links
links = ($.extend(true, {}, link) for link in links) links = ($.extend(true, {}, link) for link in links)
link.icon = @iconForLink link for link in links link.icon = @iconForLink link for link in links
@ -65,7 +75,18 @@ module.exports = class ProfileView extends View
@$el.find('.middle-column').addClass('double-column') @$el.find('.middle-column').addClass('double-column')
unless @editing unless @editing
@$el.find('.editable-display').attr('title', '') @$el.find('.editable-display').attr('title', '')
_.defer => @progress = @updateProgress() @initializeAutocomplete()
highlightNext = @highlightNext
justSavedSection = @$el.find('#' + @justSavedSectionID).addClass "just-saved"
_.defer =>
@progress = @updateProgress highlightNext
_.delay ->
justSavedSection.removeClass "just-saved", duration: 1500, easing: 'easeOutQuad'
, 500
initializeAutocomplete: (container) ->
(container ? @$el).find('input[data-autocomplete]').each ->
$(@).autocomplete(source: JobProfileView[$(@).data('autocomplete')], minLength: parseInt($(@).data('autocomplete-min-length')), delay: 0, autoFocus: true)
toggleEditing: -> toggleEditing: ->
@editing = not @editing @editing = not @editing
@ -115,21 +136,31 @@ module.exports = class ProfileView extends View
onContactCandidate: (e) -> onContactCandidate: (e) ->
@openModalView new JobProfileContactView recipientID: @user.id @openModalView new JobProfileContactView recipientID: @user.id
saveEdits: (e) -> showErrors: (errors) ->
res = @user.validate() section = @$el.find '.saving'
if res? console.error "Couldn't save because of validation errors:", errors
console.error "Couldn't save because of validation errors:", res section.removeClass 'saving'
# TODO: show some sort of problem message here forms.clearFormAlerts section
return # This is pretty lame, since we don't easily match which field had the error like forms.applyErrorsToForm can.
section.find('form').addClass('has-error').find('.save-section').before($("<span class='help-block error-help-block'>#{errors[0].message}</span>"))
saveEdits: (highlightNext) ->
errors = @user.validate()
return @showErrors errors if errors
jobProfile = @user.get('jobProfile') jobProfile = @user.get('jobProfile')
jobProfile.updated = (new Date()).toISOString() jobProfile.updated = (new Date()).toISOString()
@user.set 'jobProfile', jobProfile @user.set 'jobProfile', jobProfile
return unless res = @user.save() return unless res = @user.save()
res.error -> res.error =>
errors = JSON.parse(res.responseText) return if @destroyed
# TODO: show some sort of problem message here @showErrors [message: res.responseText]
res.success (model, response, options) => res.success (model, response, options) =>
return if @destroyed
@justSavedSectionID = @$el.find('.editable-section.saving').removeClass('saving').attr('id')
@highlightNext = highlightNext
@render() @render()
@highlightNext = false
@justSavedSectionID = null
onEditProfilePhoto: (e) -> onEditProfilePhoto: (e) ->
onSaving = => onSaving = =>
@ -163,8 +194,8 @@ module.exports = class ProfileView extends View
onSaved uploadingPath onSaved uploadingPath
onEditSection: (e) -> onEditSection: (e) ->
section = $(e.target).closest('.editable-section') section = $(e.target).closest('.editable-section').removeClass 'deemphasized'
section.find('.editable-form').show() section.find('.editable-form').show().find('select, input, textarea').first().focus()
section.find('.editable-display').hide() section.find('.editable-display').hide()
@$el.find('.editable-section').not(section).addClass 'deemphasized' @$el.find('.editable-section').not(section).addClass 'deemphasized'
column = section.closest('.full-height-column') column = section.closest('.full-height-column')
@ -198,7 +229,10 @@ module.exports = class ProfileView extends View
else unless child? else unless child?
child = parent[key] = {} child = parent[key] = {}
parent = child parent = child
parent[key] = value if key is 'link' and keyChain[0] is 'projects' and not value
delete parent[key]
else
parent[key] = value
form.find('.editable-array').each -> form.find('.editable-array').each ->
key = $(@).data('property') key = $(@).data('property')
unless rootPropertiesSeen[key] unless rootPropertiesSeen[key]
@ -206,7 +240,7 @@ module.exports = class ProfileView extends View
if section.hasClass('projects-container') and not section.find('.array-item').length if section.hasClass('projects-container') and not section.find('.array-item').length
jobProfile.projects = [] jobProfile.projects = []
section.addClass 'saving' section.addClass 'saving'
@saveEdits() @saveEdits true
extractFieldKeyChain: (key) -> extractFieldKeyChain: (key) ->
# "root[projects][0][name]" -> ["projects", "0", "name"] # "root[projects][0][name]" -> ["projects", "0", "name"]
@ -236,10 +270,11 @@ module.exports = class ProfileView extends View
toRemove.unshift index toRemove.unshift index
$(arrayItems[emptyIndex]).remove() for emptyIndex in toRemove $(arrayItems[emptyIndex]).remove() for emptyIndex in toRemove
unless lastEmpty unless lastEmpty
clone = $(arrayItem).clone(true) clone = $(arrayItem).clone(false)
clone.find('input').each -> $(@).val('') clone.find('input').each -> $(@).val('')
clone.find('textarea').each -> $(@).text('') clone.find('textarea').each -> $(@).text('')
array.append clone array.append clone
@initializeAutocomplete clone
for arrayItem, index in array.find('.array-item') for arrayItem, index in array.find('.array-item')
for input in $(arrayItem).find('input, textarea') for input in $(arrayItem).find('input, textarea')
$(input).attr('name', $(input).attr('name').replace(/\[\d+\]/, "[#{index}]")) $(input).attr('name', $(input).attr('name').replace(/\[\d+\]/, "[#{index}]"))
@ -247,7 +282,7 @@ module.exports = class ProfileView extends View
onClickLinkWhileEditing: (e) -> onClickLinkWhileEditing: (e) ->
e.preventDefault() e.preventDefault()
updateProgress: -> updateProgress: (highlightNext) ->
completed = 0 completed = 0
totalWeight = 0 totalWeight = 0
next = null next = null
@ -255,21 +290,26 @@ module.exports = class ProfileView extends View
done = metric.fn() done = metric.fn()
completed += metric.weight if done completed += metric.weight if done
totalWeight += metric.weight totalWeight += metric.weight
next = metric.name unless next or done next = metric unless next or done
progress = Math.round 100 * completed / totalWeight progress = Math.round 100 * completed / totalWeight
bar = @$el.find('.profile-completion-progress .progress-bar') bar = @$el.find('.profile-completion-progress .progress-bar')
bar.css 'width', "#{progress}%" bar.css 'width', "#{progress}%"
text = "" text = ""
t = $.i18n.t
if next and progress > 40 if next and progress > 40
text = "#{progress}% complete. Next: #{next}" text = "#{progress}% #{t 'account_profile.complete'}. #{t 'account_profile.next'}: #{next.name}"
else if next and progress > 30 else if next and progress > 30
text = "#{progress}%. Next: #{next}" text = "#{progress}%. #{t 'account_profile.next'}: #{next.name}"
else if next and progress > 11 else if next and progress > 11
text = "#{progress}%: #{next}" text = "#{progress}%: #{next.name}"
else if progress > 3 else if progress > 3
text = "#{progress}%" text = "#{progress}%"
bar.text text bar.text text
bar.parent().toggle Boolean progress bar.parent().toggle Boolean progress
if highlightNext and next?.container and not (next.container in @highlightedContainers)
@onEditSection target: next.container
@highlightedContainers.push next.container
$('#page-container').scrollTop 0
completed / totalWeight completed / totalWeight
getProgressMetrics: -> getProgressMetrics: ->
@ -278,17 +318,18 @@ module.exports = class ProfileView extends View
exists = (field) -> -> jobProfile[field] exists = (field) -> -> jobProfile[field]
modified = (field) -> -> jobProfile[field] and jobProfile[field] isnt schema.properties[field].default 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] listStarted = (field, subfields) -> -> jobProfile[field]?.length and _.every subfields, (subfield) -> jobProfile[field][0][subfield]
t = $.i18n.t
@progressMetrics = [ @progressMetrics = [
{name: "city?", weight: 1, container: 'basic-info-container', fn: modified 'city'} {name: t('account_profile.next_city'), weight: 1, container: '#basic-info-container', fn: modified 'city'}
{name: "pick your country.", weight: 0, container: 'basic-info-container', fn: exists 'country'} {name: t('account_profile.next_country'), weight: 0, container: '#basic-info-container', fn: exists 'country'}
{name: "provide your name.", weight: 1, container: 'name-container', fn: modified 'name'} {name: t('account_profile.next_name'), weight: 1, container: '#name-container', fn: modified 'name'}
{name: "summarize yourself at a glance.", weight: 2, container: 'short-description-container', fn: modified 'shortDescription'} {name: t('account_profile.next_short_description'), weight: 2, container: '#short-description-container', fn: modified 'shortDescription'}
{name: "list at least five skills.", weight: 2, container: 'skills-container', fn: -> jobProfile.skills?.length >= 5} {name: t('account_profile.next_skills'), weight: 2, container: '#skills-container', fn: -> jobProfile.skills?.length >= 5}
{name: "describe the work you're looking for.", weight: 3, container: 'long-description-container', fn: modified 'longDescription'} {name: t('account_profile.next_long_description'), weight: 3, container: '#long-description-container', fn: modified 'longDescription'}
{name: "list your work experience.", weight: 3, container: 'work-container', fn: listStarted 'work', ['role', 'employer']} {name: t('account_profile.next_work'), weight: 3, container: '#work-container', fn: listStarted 'work', ['role', 'employer']}
{name: "recount your educational ordeals.", weight: 3, container: 'education-container', fn: listStarted 'education', ['degree', 'school']} {name: t('account_profile.next_education'), weight: 3, container: '#education-container', fn: listStarted 'education', ['degree', 'school']}
{name: "show off up to three projects you've worked on.", weight: 3, container: 'projects-container', fn: listStarted 'projects', ['name']} {name: t('account_profile.next_projects'), weight: 3, container: '#projects-container', fn: listStarted 'projects', ['name']}
{name: "add any personal or social links.", weight: 2, container: 'links-container', fn: listStarted 'links', ['link', 'name']} {name: t('account_profile.next_links'), weight: 2, container: '#links-container', fn: listStarted 'links', ['link', 'name']}
{name: "add an optional professional photo.", weight: 2, container: 'profile-photo-container', fn: modified 'photoURL'} {name: t('account_profile.next_photo'), weight: 2, container: '#profile-photo-container', fn: modified 'photoURL'}
{name: "mark yourself open to offers to show up in searches.", weight: 1, fn: modified 'active'} {name: t('account_profile.next_active'), weight: 1, fn: modified 'active'}
] ]