Merge pull request #3615 from FreeCodeCamp/feature/commit
Add feature Commit
This commit is contained in:
@ -1,12 +1,19 @@
|
|||||||
var mapShareKey = 'map-shares';
|
var main = window.main || {};
|
||||||
|
|
||||||
|
main.mapShareKey = 'map-shares';
|
||||||
|
|
||||||
var lastCompleted = typeof lastCompleted !== 'undefined' ?
|
var lastCompleted = typeof lastCompleted !== 'undefined' ?
|
||||||
lastCompleted :
|
lastCompleted :
|
||||||
'';
|
'';
|
||||||
|
|
||||||
function getMapShares() {
|
function getMapShares() {
|
||||||
var alreadyShared = JSON.parse(localStorage.getItem(mapShareKey) || '[]');
|
var alreadyShared = JSON.parse(
|
||||||
|
localStorage.getItem(main.mapShareKey) ||
|
||||||
|
'[]'
|
||||||
|
);
|
||||||
|
|
||||||
if (!alreadyShared || !Array.isArray(alreadyShared)) {
|
if (!alreadyShared || !Array.isArray(alreadyShared)) {
|
||||||
localStorage.setItem(mapShareKey, JSON.stringify([]));
|
localStorage.setItem(main.mapShareKey, JSON.stringify([]));
|
||||||
alreadyShared = [];
|
alreadyShared = [];
|
||||||
}
|
}
|
||||||
return alreadyShared;
|
return alreadyShared;
|
||||||
@ -23,7 +30,7 @@ function setMapShare(id) {
|
|||||||
if (!found) {
|
if (!found) {
|
||||||
alreadyShared.push(id);
|
alreadyShared.push(id);
|
||||||
}
|
}
|
||||||
localStorage.setItem(mapShareKey, JSON.stringify(alreadyShared));
|
localStorage.setItem(main.mapShareKey, JSON.stringify(alreadyShared));
|
||||||
return alreadyShared;
|
return alreadyShared;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
55
common/models/pledge.json
Normal file
55
common/models/pledge.json
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
{
|
||||||
|
"name": "pledge",
|
||||||
|
"base": "PersistedModel",
|
||||||
|
"idInjection": true,
|
||||||
|
"trackChanges": false,
|
||||||
|
"properties": {
|
||||||
|
"nonprofit": {
|
||||||
|
"type": "string",
|
||||||
|
"index": true
|
||||||
|
},
|
||||||
|
"amount": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"dateStarted": {
|
||||||
|
"type": "date",
|
||||||
|
"defaultFn": "now"
|
||||||
|
},
|
||||||
|
"dateEnded": {
|
||||||
|
"type": "date"
|
||||||
|
},
|
||||||
|
"formerUserId": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"isOrphaned": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"isCompleted": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": "false"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"validations": [],
|
||||||
|
"relations": {
|
||||||
|
"user": {
|
||||||
|
"type": "hasMany",
|
||||||
|
"model": "user",
|
||||||
|
"foreignKey": "userId"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"acls": [
|
||||||
|
{
|
||||||
|
"accessType": "*",
|
||||||
|
"principalType": "ROLE",
|
||||||
|
"principalId": "$everyone",
|
||||||
|
"permission": "DENY"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"accessType": "READ",
|
||||||
|
"principalType": "ROLE",
|
||||||
|
"principalId": "$everyone",
|
||||||
|
"permission": "ALLOW"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"methods": []
|
||||||
|
}
|
@ -166,6 +166,11 @@
|
|||||||
"type": "hasMany",
|
"type": "hasMany",
|
||||||
"model": "userIdentity",
|
"model": "userIdentity",
|
||||||
"foreignKey": ""
|
"foreignKey": ""
|
||||||
|
},
|
||||||
|
"pledge": {
|
||||||
|
"type": "hasOne",
|
||||||
|
"model": "pledge",
|
||||||
|
"foreignKey": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"acls": [
|
"acls": [
|
||||||
|
@ -18,6 +18,10 @@ import {
|
|||||||
fullStackChallangeId
|
fullStackChallangeId
|
||||||
} from '../utils/constantStrings.json';
|
} from '../utils/constantStrings.json';
|
||||||
|
|
||||||
|
import {
|
||||||
|
completeCommitment$
|
||||||
|
} from '../utils/commit';
|
||||||
|
|
||||||
const debug = debugFactory('freecc:certification');
|
const debug = debugFactory('freecc:certification');
|
||||||
const sendMessageToNonUser = ifNoUserSend(
|
const sendMessageToNonUser = ifNoUserSend(
|
||||||
'must be logged in to complete.'
|
'must be logged in to complete.'
|
||||||
@ -114,7 +118,20 @@ export default function certificate(app) {
|
|||||||
completedDate: new Date(),
|
completedDate: new Date(),
|
||||||
challengeType
|
challengeType
|
||||||
});
|
});
|
||||||
return saveUser(user);
|
return saveUser(user)
|
||||||
|
// If user has commited to nonprofit,
|
||||||
|
// this will complete his pledge
|
||||||
|
.flatMap(
|
||||||
|
user => completeCommitment$(user),
|
||||||
|
(user, pledgeOrMessage) => {
|
||||||
|
if (typeof pledgeOrMessage === 'string') {
|
||||||
|
debug(pledgeOrMessage);
|
||||||
|
}
|
||||||
|
// we are only interested in the user object
|
||||||
|
// so we ignore return from completeCommitment$
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return Observable.just(user);
|
return Observable.just(user);
|
||||||
})
|
})
|
||||||
|
@ -1,15 +1,224 @@
|
|||||||
|
import _ from 'lodash';
|
||||||
|
import { Observable } from 'rx';
|
||||||
|
import debugFactory from 'debug';
|
||||||
|
import dedent from 'dedent';
|
||||||
|
|
||||||
|
import nonprofits from '../utils/commit.json';
|
||||||
|
import {
|
||||||
|
commitGoals,
|
||||||
|
completeCommitment$
|
||||||
|
} from '../utils/commit';
|
||||||
|
|
||||||
|
import {
|
||||||
|
unDasherize
|
||||||
|
} from '../utils';
|
||||||
|
|
||||||
|
import {
|
||||||
|
observeQuery,
|
||||||
|
saveInstance
|
||||||
|
} from '../utils/rx';
|
||||||
|
|
||||||
|
import {
|
||||||
|
ifNoUserRedirectTo
|
||||||
|
} from '../utils/middleware';
|
||||||
|
|
||||||
|
const sendNonUserToFront = ifNoUserRedirectTo('/');
|
||||||
|
const sendNonUserToCommit = ifNoUserRedirectTo(
|
||||||
|
'/commit',
|
||||||
|
'Must be signed in to update commit'
|
||||||
|
);
|
||||||
|
const debug = debugFactory('freecc:commit');
|
||||||
|
|
||||||
|
function findNonprofit(name) {
|
||||||
|
let nonprofit;
|
||||||
|
if (name) {
|
||||||
|
nonprofit = _.find(nonprofits, (nonprofit) => {
|
||||||
|
return name === nonprofit.name;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
nonprofit = nonprofit || nonprofits[0];
|
||||||
|
return nonprofit;
|
||||||
|
}
|
||||||
|
|
||||||
export default function commit(app) {
|
export default function commit(app) {
|
||||||
const router = app.loopback.Router();
|
const router = app.loopback.Router();
|
||||||
|
const { Pledge } = app.models;
|
||||||
|
|
||||||
router.get(
|
router.get(
|
||||||
'/commit',
|
'/commit',
|
||||||
commitToNonprofit
|
commitToNonprofit
|
||||||
);
|
);
|
||||||
|
|
||||||
|
router.get(
|
||||||
|
'/commit/pledge',
|
||||||
|
sendNonUserToFront,
|
||||||
|
pledge
|
||||||
|
);
|
||||||
|
|
||||||
|
router.get(
|
||||||
|
'/commit/directory',
|
||||||
|
renderDirectory
|
||||||
|
);
|
||||||
|
|
||||||
|
router.post(
|
||||||
|
'/commit/stop-commitment',
|
||||||
|
sendNonUserToCommit,
|
||||||
|
stopCommit
|
||||||
|
);
|
||||||
|
|
||||||
|
router.post(
|
||||||
|
'/commit/complete-goal',
|
||||||
|
sendNonUserToCommit,
|
||||||
|
completeCommitment
|
||||||
|
);
|
||||||
|
|
||||||
app.use(router);
|
app.use(router);
|
||||||
|
|
||||||
function commitToNonprofit(req, res) {
|
function commitToNonprofit(req, res, next) {
|
||||||
res.render('commit/', {
|
const { user } = req;
|
||||||
title: 'Commit to a nonprofit. Commit to your goal.'
|
let nonprofitName = unDasherize(req.query.nonprofit);
|
||||||
|
|
||||||
|
debug('looking for nonprofit', nonprofitName);
|
||||||
|
const nonprofit = findNonprofit(nonprofitName);
|
||||||
|
|
||||||
|
Observable.just(user)
|
||||||
|
.flatMap(user => {
|
||||||
|
if (user) {
|
||||||
|
debug('getting user pledge');
|
||||||
|
return observeQuery(user, 'pledge');
|
||||||
|
}
|
||||||
|
return Observable.just();
|
||||||
|
})
|
||||||
|
.subscribe(
|
||||||
|
pledge => {
|
||||||
|
if (pledge) {
|
||||||
|
debug('found previous pledge');
|
||||||
|
req.flash('info', {
|
||||||
|
msg: dedent`
|
||||||
|
Looks like you already have a pledge to ${pledge.displayName}.
|
||||||
|
Hitting commit here will replace your old commitment.
|
||||||
|
`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
res.render(
|
||||||
|
'commit/',
|
||||||
|
Object.assign(
|
||||||
|
{
|
||||||
|
title: 'Commit to a nonprofit. Commit to your goal.',
|
||||||
|
pledge,
|
||||||
|
frontEndCert: commitGoals.frontEndCert,
|
||||||
|
fullStackCert: commitGoals.fullStackCert
|
||||||
|
},
|
||||||
|
nonprofit
|
||||||
|
)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
next
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function pledge(req, res, next) {
|
||||||
|
const { user } = req;
|
||||||
|
const {
|
||||||
|
nonprofit: nonprofitName = 'girl develop it',
|
||||||
|
amount = '5',
|
||||||
|
goal = commitGoals.frontEndCert
|
||||||
|
} = req.query;
|
||||||
|
|
||||||
|
const nonprofit = findNonprofit(nonprofitName);
|
||||||
|
|
||||||
|
observeQuery(user, 'pledge')
|
||||||
|
.flatMap(oldPledge => {
|
||||||
|
// create new pledge for user
|
||||||
|
const pledge = Pledge(
|
||||||
|
Object.assign(
|
||||||
|
{
|
||||||
|
amount,
|
||||||
|
goal,
|
||||||
|
userId: user.id
|
||||||
|
},
|
||||||
|
nonprofit
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (oldPledge) {
|
||||||
|
debug('user already has pledge, creating a new one');
|
||||||
|
// we orphan last pledge since a user only has one pledge at a time
|
||||||
|
oldPledge.userId = '';
|
||||||
|
oldPledge.formerUser = user.id;
|
||||||
|
oldPledge.endDate = new Date();
|
||||||
|
oldPledge.isOrphaned = true;
|
||||||
|
return saveInstance(oldPledge)
|
||||||
|
.flatMap(() => {
|
||||||
|
return saveInstance(pledge);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return saveInstance(pledge);
|
||||||
|
})
|
||||||
|
.subscribe(
|
||||||
|
({ nonprofit, goal, amount }) => {
|
||||||
|
req.flash('success', {
|
||||||
|
msg: dedent`
|
||||||
|
Congratulations, you have committed to giving
|
||||||
|
${nonprofit} $${amount} each month until you have completed
|
||||||
|
your ${goal}.
|
||||||
|
`
|
||||||
|
});
|
||||||
|
res.redirect('/' + user.username);
|
||||||
|
},
|
||||||
|
next
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderDirectory(req, res) {
|
||||||
|
res.render('commit/directory', {
|
||||||
|
title: 'Commit Directory',
|
||||||
|
nonprofits
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function completeCommitment(req, res, next) {
|
||||||
|
const { user } = req;
|
||||||
|
|
||||||
|
return completeCommitment$(user)
|
||||||
|
.subscribe(
|
||||||
|
msgOrPledge => {
|
||||||
|
if (typeof msgOrPledge === 'string') {
|
||||||
|
return res.send(msgOrPledge);
|
||||||
|
}
|
||||||
|
return res.send(true);
|
||||||
|
},
|
||||||
|
next
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopCommit(req, res, next) {
|
||||||
|
const { user } = req;
|
||||||
|
|
||||||
|
observeQuery(user, 'pledge')
|
||||||
|
.flatMap(pledge => {
|
||||||
|
if (!pledge) {
|
||||||
|
return Observable.just();
|
||||||
|
}
|
||||||
|
|
||||||
|
pledge.formerUserId = pledge.userId;
|
||||||
|
pledge.userId = null;
|
||||||
|
pledge.isOrphaned = true;
|
||||||
|
pledge.dateEnded = new Date();
|
||||||
|
return saveInstance(pledge);
|
||||||
|
})
|
||||||
|
.subscribe(
|
||||||
|
pledge => {
|
||||||
|
let msg = `You have successfully stopped your pledge.`;
|
||||||
|
if (!pledge) {
|
||||||
|
msg = `No pledge found for user ${user.username}.`;
|
||||||
|
}
|
||||||
|
req.flash('errors', { msg });
|
||||||
|
return res.redirect(`/${user.username}`);
|
||||||
|
},
|
||||||
|
next
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -164,7 +164,10 @@ module.exports = function(app) {
|
|||||||
const username = req.params.username.toLowerCase();
|
const username = req.params.username.toLowerCase();
|
||||||
const { path } = req;
|
const { path } = req;
|
||||||
User.findOne(
|
User.findOne(
|
||||||
{ where: { username } },
|
{
|
||||||
|
where: { username },
|
||||||
|
include: 'pledge'
|
||||||
|
},
|
||||||
function(err, profileUser) {
|
function(err, profileUser) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return next(err);
|
return next(err);
|
||||||
@ -175,6 +178,7 @@ module.exports = function(app) {
|
|||||||
});
|
});
|
||||||
return res.redirect('/');
|
return res.redirect('/');
|
||||||
}
|
}
|
||||||
|
profileUser = profileUser.toJSON();
|
||||||
|
|
||||||
var cals = profileUser
|
var cals = profileUser
|
||||||
.progressTimestamps
|
.progressTimestamps
|
||||||
@ -217,7 +221,6 @@ module.exports = function(app) {
|
|||||||
return (obj.name || '').match(/^Waypoint/i);
|
return (obj.name || '').match(/^Waypoint/i);
|
||||||
});
|
});
|
||||||
|
|
||||||
debug('user is fec', profileUser.isFrontEndCert);
|
|
||||||
res.render('account/show', {
|
res.render('account/show', {
|
||||||
title: 'Camper ' + profileUser.username + '\'s portfolio',
|
title: 'Camper ' + profileUser.username + '\'s portfolio',
|
||||||
username: profileUser.username,
|
username: profileUser.username,
|
||||||
@ -227,6 +230,8 @@ module.exports = function(app) {
|
|||||||
isGithubCool: profileUser.isGithubCool,
|
isGithubCool: profileUser.isGithubCool,
|
||||||
isLocked: !!profileUser.isLocked,
|
isLocked: !!profileUser.isLocked,
|
||||||
|
|
||||||
|
pledge: profileUser.pledge,
|
||||||
|
|
||||||
isFrontEndCert: profileUser.isFrontEndCert,
|
isFrontEndCert: profileUser.isFrontEndCert,
|
||||||
isFullStackCert: profileUser.isFullStackCert,
|
isFullStackCert: profileUser.isFullStackCert,
|
||||||
isHonest: profileUser.isHonest,
|
isHonest: profileUser.isHonest,
|
||||||
|
@ -47,6 +47,10 @@
|
|||||||
"dataSource": "db",
|
"dataSource": "db",
|
||||||
"public": true
|
"public": true
|
||||||
},
|
},
|
||||||
|
"pledge": {
|
||||||
|
"dataSource": "db",
|
||||||
|
"public": true
|
||||||
|
},
|
||||||
"user": {
|
"user": {
|
||||||
"dataSource": "db",
|
"dataSource": "db",
|
||||||
"public": true
|
"public": true
|
||||||
|
4
server/utils/commit-goals.json
Normal file
4
server/utils/commit-goals.json
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"frontEndCert": "Front End Development Certification",
|
||||||
|
"fullStackCert": "Full Stack Development Certification"
|
||||||
|
}
|
36
server/utils/commit.js
Normal file
36
server/utils/commit.js
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import dedent from 'dedent';
|
||||||
|
import debugFactory from 'debug';
|
||||||
|
import { Observable } from 'rx';
|
||||||
|
|
||||||
|
import commitGoals from './commit-goals.json';
|
||||||
|
const debug = debugFactory('freecc:utils/commit');
|
||||||
|
|
||||||
|
export { commitGoals };
|
||||||
|
|
||||||
|
export function completeCommitment$(user) {
|
||||||
|
const { isFrontEndCert, isFullStackCert } = user;
|
||||||
|
return Observable.fromNodeCallback(user.pledge, user)()
|
||||||
|
.flatMap(pledge => {
|
||||||
|
if (!pledge) {
|
||||||
|
return Observable.just('No pledge found');
|
||||||
|
}
|
||||||
|
|
||||||
|
const { goal } = pledge;
|
||||||
|
|
||||||
|
if (
|
||||||
|
isFrontEndCert && goal === commitGoals.frontEndCert ||
|
||||||
|
isFullStackCert && goal === commitGoals.fullStackCert
|
||||||
|
) {
|
||||||
|
debug('marking goal complete');
|
||||||
|
pledge.isCompleted = true;
|
||||||
|
pledge.dateEnded = new Date();
|
||||||
|
pledge.formerUserId = pledge.userId;
|
||||||
|
pledge.userId = null;
|
||||||
|
return Observable.fromNodeCallback(pledge.save, pledge)();
|
||||||
|
}
|
||||||
|
return Observable.just(dedent`
|
||||||
|
You have not yet reached your goal of completing the ${goal}
|
||||||
|
Please retry when you have met the requirements.
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
}
|
18
server/utils/commit.json
Normal file
18
server/utils/commit.json
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "girl develop it",
|
||||||
|
"displayName": "Girl Develop It",
|
||||||
|
"donateUrl": "https://www.girldevelopit.com/donate",
|
||||||
|
"description": "Girl Develop It provides in-person classes for women to learn to code.",
|
||||||
|
"imgAlt": "Girl Develop It participants coding at tables.",
|
||||||
|
"imgUrl": "http://i.imgur.com/U1CyEuA.jpg"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "black girls code",
|
||||||
|
"displayName": "Black Girls CODE",
|
||||||
|
"donateUrl": "http://www.blackgirlscode.com/",
|
||||||
|
"description": "Black Girls CODE is devoted to showing the world that black girls can code, and do so much more.",
|
||||||
|
"imgAlt": "Girls developing code with instructor",
|
||||||
|
"imgUrl": "http://i.imgur.com/HBVrdaj.jpg"
|
||||||
|
}
|
||||||
|
]
|
@ -1,8 +1,14 @@
|
|||||||
export function ifNoUserRedirectTo(url) {
|
export function ifNoUserRedirectTo(url, message) {
|
||||||
return function(req, res, next) {
|
return function(req, res, next) {
|
||||||
|
const { path } = req;
|
||||||
if (req.user) {
|
if (req.user) {
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
req.flash('errors', {
|
||||||
|
msg: message || `You must be signed to go to ${path}`
|
||||||
|
});
|
||||||
|
|
||||||
return res.redirect(url);
|
return res.redirect(url);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -58,6 +58,13 @@ block content
|
|||||||
h1.flat-top.wrappable= name
|
h1.flat-top.wrappable= name
|
||||||
h1.flat-top.wrappable= location
|
h1.flat-top.wrappable= location
|
||||||
h1.flat-top.text-primary= "[ " + (progressTimestamps.length) + " ]"
|
h1.flat-top.text-primary= "[ " + (progressTimestamps.length) + " ]"
|
||||||
|
if pledge
|
||||||
|
.spacer
|
||||||
|
h4
|
||||||
|
| This camper has committed to giving $#{pledge.amount} to
|
||||||
|
a(href='#{pledge.donateUrl}?ref=freecodecamp.com' target='_blank') #{pledge.displayName}
|
||||||
|
| each month until they have completed their #{pledge.goal}.
|
||||||
|
.spacer
|
||||||
if isFrontEndCert
|
if isFrontEndCert
|
||||||
a.btn.btn-primary(href='/' + username + '/front-end-certification') View My Front End Development Certification
|
a.btn.btn-primary(href='/' + username + '/front-end-certification') View My Front End Development Certification
|
||||||
if isFullStackCert
|
if isFullStackCert
|
||||||
@ -154,6 +161,10 @@ block content
|
|||||||
.panel.panel-info
|
.panel.panel-info
|
||||||
.panel-heading.text-center Manage your account
|
.panel-heading.text-center Manage your account
|
||||||
.panel-body
|
.panel-body
|
||||||
|
.col-xs-12
|
||||||
|
a.btn.btn-lg.btn-block.btn-warning.btn-link-social(href='/logout')
|
||||||
|
span.ion-android-exit
|
||||||
|
| Sign me out of Free Code Camp
|
||||||
.col-xs-12
|
.col-xs-12
|
||||||
a.btn.btn-lg.btn-block.btn-primary.btn-link-social(href='mailto:team@freecodecamp.com')
|
a.btn.btn-lg.btn-block.btn-primary.btn-link-social(href='mailto:team@freecodecamp.com')
|
||||||
span.ion-email
|
span.ion-email
|
||||||
@ -169,9 +180,9 @@ block content
|
|||||||
span.ion-unlocked
|
span.ion-unlocked
|
||||||
| Let other people see all my solutions
|
| Let other people see all my solutions
|
||||||
.col-xs-12
|
.col-xs-12
|
||||||
a.btn.btn-lg.btn-block.btn-warning.btn-link-social(href='/logout')
|
a.btn.btn-lg.btn-block.btn-success.btn-link-social(href='/commit')
|
||||||
span.ion-android-exit
|
span.ion-edit
|
||||||
| Sign me out of Free Code Camp
|
| Edit my pledge
|
||||||
.col-xs-12
|
.col-xs-12
|
||||||
a.btn.btn-lg.btn-block.btn-danger.btn-link-social.confirm-deletion
|
a.btn.btn-lg.btn-block.btn-danger.btn-link-social.confirm-deletion
|
||||||
span.ion-trash-b
|
span.ion-trash-b
|
||||||
|
20
server/views/commit/directory.jade
Normal file
20
server/views/commit/directory.jade
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
extends ../layout
|
||||||
|
block content
|
||||||
|
.panel.panel-info
|
||||||
|
.panel-heading.text-center Commit to one of these nonprofits
|
||||||
|
.panel-body
|
||||||
|
.row
|
||||||
|
.col-xs-12.col-sm-10.col-sm-offset-1
|
||||||
|
for nonprofit in nonprofits
|
||||||
|
.col-xs-12.col-sm-6.col-md-4.story-section
|
||||||
|
.text-center
|
||||||
|
h2= nonprofit.displayName
|
||||||
|
img.testimonial-image.img-responsive.img-center(src=nonprofit.imgUrl)
|
||||||
|
.button-spacer
|
||||||
|
a.text-center(href='/commit?nonprofit=#{nonprofit.name}') Commmit to #{nonprofit.displayName}
|
||||||
|
p= nonprofit.description
|
||||||
|
.spacer
|
||||||
|
.col-xs-12
|
||||||
|
a.btn.btn-lg.btn-block.btn-primary.btn-link-social(href='mailto:team@freecodecamp.com?subject=Supporting%20Nonprofits')
|
||||||
|
span.ion-email
|
||||||
|
| Email us about adding your nonprofit here
|
@ -2,53 +2,70 @@ extends ../layout
|
|||||||
block content
|
block content
|
||||||
.panel.panel-info
|
.panel.panel-info
|
||||||
.panel-body
|
.panel-body
|
||||||
h3.text-center Commit to yourself. Commit to a nonprofit.
|
h2.text-center Commit to yourself. Commit to a nonprofit.
|
||||||
.col-xs-12.col-sm-6.col-sm-offset-3
|
.row
|
||||||
p Are you looking for a burst of motivation? Do you want to help nonprofits before you’re ready to code for them? You can do both by pledging a monthly donation to a nonprofit until you've earned either your Front End or Full Stack Development certificate. Join Commit below or click "maybe later".
|
.col-xs-12.col-sm-6.col-sm-offset-3
|
||||||
.col-xs-12.col-sm-6.col-sm-offset-3
|
p Give yourself external motivation and help nonprofits right away. Pledge a monthly donation to a nonprofit until you’ve earned either your Front End or Full Stack Development Certification.
|
||||||
h4 Step 1: Choose your goal
|
|
||||||
.radio
|
|
||||||
label
|
|
||||||
input(type='radio' id='front-end-development-certificate' name='goal')
|
|
||||||
| Front End Development Certificate (takes about 400 hours)
|
|
||||||
.radio
|
|
||||||
label
|
|
||||||
input(type='radio' id='full-stack-development-certificate' name='goal')
|
|
||||||
| Full Stack Development Certificate (takes about 800 hours)
|
|
||||||
.spacer
|
|
||||||
h4 Step 2: Choose one of our nonprofits
|
|
||||||
.row
|
|
||||||
.col-xs-12.col-sm-6
|
|
||||||
a(href="http://i.imgur.com/U1CyEuA.jpg" data-lightbox="img-enlarge")
|
|
||||||
img.img-responsive(src='http://i.imgur.com/U1CyEuA.jpg' alt="Girl Develop It participants coding at tables.")
|
|
||||||
.radio
|
|
||||||
label
|
|
||||||
input(type='radio' id='girl-develop-it' name='nonprofit')
|
|
||||||
| Girl Develop It is a nonprofit that provides in-person classes for women to learn to code.
|
|
||||||
.col-xs-12.col-sm-6
|
|
||||||
a(href="http://i.imgur.com/NERytFF.jpg" data-lightbox="img-enlarge")
|
|
||||||
img.img-responsive(src='http://i.imgur.com/NERytFF.jpg' alt="Vets in Tech participants standing together at a conference.")
|
|
||||||
.radio
|
|
||||||
label
|
|
||||||
input(type='radio' id='vets-in-tech' name='nonprofit')
|
|
||||||
| Vets in Tech is a nonprofit that helps veterans prepare for tech jobs.
|
|
||||||
.spacer
|
|
||||||
h4 Step 3: Choose your monthly pledge
|
|
||||||
.radio
|
|
||||||
label
|
|
||||||
input(type='radio' id='5-dollar-pledge' name='pledge-amount')
|
|
||||||
| $5 per month
|
|
||||||
.radio
|
|
||||||
label
|
|
||||||
input(type='radio' id='10-dollar-pledge' name='pledge-amount')
|
|
||||||
| $10 per month
|
|
||||||
.radio
|
|
||||||
label
|
|
||||||
input(type='radio' id='50-dollar-pledge' name='pledge-amount')
|
|
||||||
| $50 per month
|
|
||||||
|
|
||||||
|
.row
|
||||||
|
.col-xs-12.col-sm-6.col-sm-offset-3.text-center
|
||||||
|
h3 Pledge to #{displayName} 
|
||||||
|
.button-spacer
|
||||||
|
a(href='#{imgUrl}' data-lightbox='img-enlarge' alt='#{imgAlt}')
|
||||||
|
img.img-responsive(src='#{imgUrl}' alt='#{imgAlt}')
|
||||||
|
p.large-p
|
||||||
|
= description
|
||||||
|
a(href='/commit/directory') ...or see other nonprofits
|
||||||
|
.spacer
|
||||||
|
form.form(name='commit')
|
||||||
|
.hidden
|
||||||
|
input(type='text' value='#{name}' name='nonprofit')
|
||||||
|
.row
|
||||||
|
.col-xs-12.col-sm-6.col-sm-offset-3
|
||||||
|
h3 Choose your goal:
|
||||||
|
.btn-group.btn-group-justified(data-toggle='buttons' role='group')
|
||||||
|
label.btn.btn-primary.btn-lg.active
|
||||||
|
input(type='radio' id=frontEndCert value=frontEndCert name='goal' checked="checked")
|
||||||
|
| Front End Development Certification (takes about 400 hours)
|
||||||
|
label.btn.btn-primary.btn-lg
|
||||||
|
input(type='radio' id=fullStackCert value=fullStackCert name='goal')
|
||||||
|
| Full Stack Development Certification (takes about 800 hours)
|
||||||
.spacer
|
.spacer
|
||||||
a.button.btn.btn-block.btn-primary(href='https://www.paypal.com/us/cgi-bin/webscr?cmd=_flow&SESSION=T3x0DY-bLMFXuhmjYZXs-BhmDoiXfuNh5BWad5VBcMomkkDSZY0b_-_W3HS&dispatch=5885d80a13c0db1f8e263663d3faee8d0b9dcb01a9b6dc564e45f62871326a5e') Commit
|
.row
|
||||||
.button-spacer
|
.col-xs-12.col-sm-6.col-sm-offset-3
|
||||||
a.button.btn.btn-block.btn-warning(href='/') Maybe later
|
h3 Choose your monthly pledge:
|
||||||
|
.btn-group.btn-group-justified(data-toggle='buttons' role='group')
|
||||||
|
label.btn.btn-success
|
||||||
|
input(type='radio' id='5-dollar-pledge' value='5' name='amount')
|
||||||
|
| $5 per month
|
||||||
|
label.btn.btn-success.active
|
||||||
|
input(type='radio' id='10-dollar-pledge' value='10' name='amount' checked="checked")
|
||||||
|
| $10 per month
|
||||||
|
label.btn.btn-success
|
||||||
|
input(type='radio' id='25-dollar-pledge' value='25' name='amount' checked="checked")
|
||||||
|
| $25 per month
|
||||||
|
label.btn.btn-success
|
||||||
|
input(type='radio' id='50-dollar-pledge' value='50' name='amount')
|
||||||
|
| $50 per month
|
||||||
.spacer
|
.spacer
|
||||||
|
.row
|
||||||
|
.col-xs-12.col-sm-6.col-sm-offset-3.text-center
|
||||||
|
a#commit-btn-submit.btn.btn-block.btn-lg.signup-btn(href=donateUrl target='_blank') Commit (and open donate page)
|
||||||
|
|
||||||
|
if pledge
|
||||||
|
form.row(name='stop-pledge' action='/commit/stop-commitment' method='post')
|
||||||
|
.col-xs-12.col-sm-6.col-sm-offset-3.text-center
|
||||||
|
.button-spacer
|
||||||
|
button.btn.btn-block.btn-danger(name='submit' type='submit') Stop my current pledge
|
||||||
|
else
|
||||||
|
.row
|
||||||
|
.col-xs-12.col-sm-6.col-sm-offset-3.text-center
|
||||||
|
.button-spacer
|
||||||
|
a.btn.btn-block.btn-default(href='/') Maybe later
|
||||||
|
.spacer
|
||||||
|
script.
|
||||||
|
$(function() {
|
||||||
|
$('#commit-btn-submit').click(function() {
|
||||||
|
window.location.href = '/commit/pledge?' + $('form').serialize();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
15
server/views/commit/pledge.jade
Normal file
15
server/views/commit/pledge.jade
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
extends ../layout
|
||||||
|
block content
|
||||||
|
.panel.panel-info
|
||||||
|
.panel-body
|
||||||
|
h3.text-center You've commited!
|
||||||
|
.row
|
||||||
|
.col-xs-12.col-sm-6.col-sm-offset-3
|
||||||
|
p Congratulations, you have commit to giving
|
||||||
|
span(style='text-transform: capitalize') #{nonprofit}
|
||||||
|
| #{amount} dollars a month until you have reached your goal
|
||||||
|
| of completing your #{goal}
|
||||||
|
.row
|
||||||
|
.col-xs-12.col-sm-6.col-sm-offset-3
|
||||||
|
img.img-responsive(src='http://i.imgur.com/U1CyEuA.jpg' alt="Girl Develop It participants coding at tables.")
|
||||||
|
p Girl Develop It is a nonprofit that provides in-person classes for women to learn to code.
|
Reference in New Issue
Block a user