Skip to content

Commit

Permalink
Merge pull request #137 from alphamanuscript/118-more-site-info
Browse files Browse the repository at this point in the history
Update information on home page and fix minor issues
  • Loading branch information
habbes authored Oct 3, 2020
2 parents d6f1696 + 11e1b2c commit 906e822
Show file tree
Hide file tree
Showing 12 changed files with 273 additions and 87 deletions.
2 changes: 1 addition & 1 deletion server/src/core/payment/manual-payment-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export class ManualPaymentProvider implements PaymentProvider {
async sendFundsToUser(user: User, amount: number, metadata: any): Promise<SendFundsResult> {
const args: ManualPayCreateTransactionArgs = {
amount: amount,
recipientName: user.email || '',
recipientName: user.name || user.email || '',
recipientPhone: user.phone,
metadata,
};
Expand Down
19 changes: 17 additions & 2 deletions server/src/core/stat/stat-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,23 @@ export class Statistics implements StatsService {
{ $count: 'numBeneficiaries' }
],
totalContributedPipeline: [
{ $match: { type: 'donation', status: 'success' } },
{ $group: { _id: null, totalContributed: { $sum: "$amount" } } },
{
$match: {
$or: [
{ type: 'donation', status: 'success' },
{ type: 'refund', status: 'success' }
]
}
},
{
$group: {
_id: { $cond: { if: { $eq: ['$type', 'donation'] }, then: 1, else: -1 } },
total: { $sum: "$amount" }
}
},
{
$group: { _id: null, totalContributed: { $sum: { $multiply: ['$_id', '$total'] } } }
},
{ $project: { _id: 0, totalContributed: 1 } }
],
totalDistributedPipeline: [
Expand Down
101 changes: 61 additions & 40 deletions server/src/core/stat/tests/fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,91 +2,112 @@ export const transactions = [
{
_id: 'transaction1',
expectedAmount: 250,
to: "id 1",
from:"",
type: "donation",
status: "paymentRequested",
to: 'id 1',
from:'',
type: 'donation',
status: 'paymentRequested',
amount: 0,
},
{
_id: 'transaction2',
expectedAmount: 470,
to: "id 1",
from:"",
type: "donation",
status: "success",
to: 'id 1',
from:'',
type: 'donation',
status: 'success',
amount: 470,
},
{
_id: 'transaction3',
expectedAmount: 1000,
to: "id 2",
from:"",
type: "donation",
status: "success",
to: 'id 2',
from:'',
type: 'donation',
status: 'success',
amount: 1000,
},
{
_id: 'transaction4',
expectedAmount: 500,
to: "id 3",
from:"",
type: "donation",
status: "paymentRequested",
to: 'id 3',
from:'',
type: 'donation',
status: 'paymentRequested',
amount: 0,
},
{
_id: 'transaction5',
expectedAmount: 250,
to: "id 3",
from:"id 2",
type: "distribution",
status: "success",
to: 'id 3',
from:'id 2',
type: 'distribution',
status: 'success',
amount: 250,
},
{
_id: 'transaction6',
expectedAmount: 250,
to: "id 4",
from:"id 2",
type: "distribution",
status: "success",
to: 'id 4',
from:'id 2',
type: 'distribution',
status: 'success',
amount: 250,
},
{
_id: 'transaction7',
expectedAmount: 250,
to: "id 5",
from:"id 2",
type: "distribution",
status: "success",
to: 'id 5',
from:'id 2',
type: 'distribution',
status: 'success',
amount: 250,
},
{
_id: 'transaction8',
expectedAmount: 250,
to: "id 6",
from:"id 2",
type: "distribution",
status: "pending",
to: 'id 6',
from:'id 2',
type: 'distribution',
status: 'pending',
amount: 250,
},
{
_id: 'transaction9',
expectedAmount: 130,
to: "id 7",
from:"id 1",
type: "distribution",
status: "success",
to: 'id 7',
from:'id 1',
type: 'distribution',
status: 'success',
amount: 130,
},
{
_id: 'transaction10',
expectedAmount: 500,
to: "id 2",
from:"",
type: "donation",
status: "success",
to: 'id 2',
from:'',
type: 'donation',
status: 'success',
amount: 500,
},
{
_id: 'transaction11',
expectedAmount: 1000,
to: 'id 2',
from: '',
type: 'donation',
status: 'success',
amount: 1000
},
// this refund should cancel out the previous donation
{
_id: 'transaction12',
expectedAmount: 1000,
from: 'id 2',
to: '',
type: 'refund',
status: 'success',
amount: 1000,
toExternal: true,
fromExternal: false
}
]
4 changes: 3 additions & 1 deletion server/src/core/user-notification/user-notification.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { EmailProvider } from '../email';
import { EventBus, Event} from '../event';
import { UserService, UserInvitationEventData } from '../user';
import { TransactionCompletedEventData, Transaction } from '../payment';
import { extractFirstName } from '../util';

export interface UserNotificationsArgs {
smsProvider: SmsProvider;
Expand Down Expand Up @@ -72,7 +73,8 @@ export class UserNotifications {
const donor = await this.users.getById(transaction.from);
const beneficiary = await this.users.getById(transaction.to);

const donorMessage = `Hello ${donor.name}, Ksh ${transaction.amount} has been transferred from your SocialRelief donation to your beneficiary ${beneficiary.name}.`;
// Do not reveal beneficiary's full name to the donor
const donorMessage = `Hello ${donor.name}, Ksh ${transaction.amount} has been transferred from your SocialRelief donation to your beneficiary ${extractFirstName(beneficiary.name)}.`;
const beneficiaryMessage = `Hello ${beneficiary.name}, you have received Ksh ${transaction.amount} from your SocialRelief donors.`;

await Promise.all([
Expand Down
8 changes: 8 additions & 0 deletions server/src/core/util/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,12 @@ export async function verifyGoogleIdToken(token: string): Promise<GoogleUserData
catch (e) {
throw createLoginError(ERROR_GOOGLE_LOGIN_FAILED)
}
}

/**
* extracts the first name from the specified full name
* @param fullName
*/
export function extractFirstName(fullName: string) {
return fullName && fullName.split(' ')[0];
}
74 changes: 74 additions & 0 deletions webapp/src/data/faqs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { FAQ } from '../types';

export const faqs: FAQ[] = [
{
question: 'How does SocialRelief work?',
answer: 'When a donor donates some money, the money is deposited to a virtual wallet linked to the donor.'
+ ' Everyday an automated process goes through all eligible beneficiaries and transfers funds '
+ 'from the donors\' accounts to the beneficiaries Mobile Money accounts.'
},
{
question: 'Who runs SocialRelief?',
answer: 'SocialRelief is developed and run by Alpha Manuscript, a small, pre-revenue tech startup based in Nairobi.'
},
{
question: 'Who are the beneficiaries and how are they enrolled to the program?',
answer: 'We target adults who live in great financial distress and are having difficulty to cope and recover from economic impacts of the Covid-19 Pandemic.' +
' Our field officers meet potential beneficiaries in person and interview them as part of the enrolment process.' +
' We conduct additional follow-up visits or phone calls to verify the that beneficiaries legitimately need the assistance.' +
' Once verified, the beneficiaries are eligible to receive funds through the platform.' +
' Currently all our beneficiaries reside in Kibera, but we seek to partner with other organisations in order to expand our reach.'
},
{
question: 'How are donations sent to beneficiaries?',
answer: 'We have an automated distribution process that runs every day.' +
' This process finds all eligible beneficiaries and allocates available funds for each of them, potentially from different donors.' +
' It then transfers the funds directly to beneficiaries via M-Pesa transfer.' +
' The process ensures that no beneficiary receives more than 2,000Ksh within a 30-day period.' +
' It is possible for some beneficiaries not to reach the target 2,000Ksh per month or not to receive any funds at all if there is not enough money to go around'
},
{
question: 'When will I know whether my donation has been used?',
answer: 'The platform will send you an SMS and email each time your money is sent to a beneficiary.' +
' The message will include the amount transferred and the first name of the beneficiary.'
},
{
question: 'Is my entire donation sent to beneficiaries?',
answer: 'The full amount that is donated by donors is transferred in full to beneficiaries.' +
' A transaction fee is added on top of each donation by the payment provider and is paid by the donor.' +
' Alpha Manuscript covers the remainder of expenses such as transaction fee when sending money to beneficiaries, ' +
' technology fees, paying field officers and other operational expenses.'
},
{
question: 'Why should I trust SocialRelief?',
answer: 'From the onset of the project, we have aspired to provide a credible, transparent and effective means of distributing donations to those who need it,' +
' and to gain the trust of both donors and beneficiaries.' +
' These goals inform the design of the platform, our processes for enrolment and follow-up and the way we handle data.' +
' Some of the features we have put in place to improve the credibility and transparency of the platform include:' +
' A donor will get a notification each time a part of their donation is sent to a beneficiary.' +
' If you create an account as a donor, you will be able to see a detailed history of all the transactions made from your account.' +
' There is an option to request a refund.'
},
{
question: 'Can I get my money back if I change my mind about the donation?',
answer: 'In order to make the platform more credible and trustworthy, we have an added an option for donors to request refunds.' +
' In order to access this feature, you must first sign-up for an account and login to the account.' +
' In your account dashboard, you will see a "Request Refund" button on the left sidebar (or under the main menu drop-down if on a phone).' +
' Clicking this button will initiate the refund request. The refund amount is automatically calculated by the platform.' +
' It corresponds to the total amount that you have donated that has not yet been allocated to a beneficiary.' +
' The calculated amount will be sent via Mobile-Money to your registered phone number.' +
' If you request a refund more than 3 times, you account will be blocked and we will no longer accept donations from you.'
},
{
question: 'How are testimonials collected?',
answer: 'After beneficiaries have received funds, we conduct follow-ups to assess the impact of the funds received.' +
' During this process, the beneficiaries provide information about their current situation and how they used the funds.' +
' We respect beneficiaries\' privacy and only share the information that they allow us to share.' +
' We use the response that they give to the following questions as testimonial:' +
' "How has the money you received from SocialRelief impacted you?"'
},
{
question: 'How long will the program run?',
answer: 'We aim to run the program from October to December 2020. We run a pilot program and field tests in the months of August and September.'
}
];
2 changes: 2 additions & 0 deletions webapp/src/data/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { testimonials } from './testimonials';
export { faqs } from './faqs';
26 changes: 26 additions & 0 deletions webapp/src/data/testimonials.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Testimonial } from '../types';

export const testimonials: Testimonial[] = [
{
name: 'Anne',
message: 'I want to thank the Social Relief people for sacrificing themselves to give us something ' +
'especially during this time of Covid-19. The money has helped me so much because I was broke.' +
' I had nothing to give my kids and at least I managed to sustain them in terms of food.',
date: new Date(2020, 8, 20)
},
{
name: 'Margaret',
message: 'The money allowed me to buy food, to buy medicine - I was sick - and used part of it for my business.',
date: new Date(2020, 8, 20)
},
{
name: 'Patricia',
message: 'I used half of the money to buy food and the other half to buy vegetables to sell.',
date: new Date(2020, 8, 20)
},
{
name: 'Shalvine',
message: 'The donation that I received impacted me in that I was able to pay my house rent.',
date: new Date(2020, 8, 24)
}
];
5 changes: 4 additions & 1 deletion webapp/src/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import Vuex from 'vuex';
import getters from './getters';
import mutations from './mutations';
import actions from './actions';
import { faqs, testimonials } from '../data';
import { AppState } from '../types';

Vue.use(Vuex)
Expand All @@ -18,7 +19,9 @@ const state: AppState = {
currentInvitation: undefined,
message: { type: '', message: '' },
lastPaymentRequest: undefined,
stats: undefined
stats: undefined,
testimonials,
faqs
}

const store = new Vuex.Store({
Expand Down
13 changes: 13 additions & 0 deletions webapp/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,17 @@ export interface Stats {
updatedAt: Date
}

export interface Testimonial {
name: string;
message: string;
date: Date;
}

export interface FAQ {
question: string;
answer: string;
};

export interface AppState {
user?: User;
anonymousUser?: User;
Expand All @@ -164,4 +175,6 @@ export interface AppState {
// keeps track of payment request that has just been created
lastPaymentRequest?: Transaction;
stats?: Stats;
testimonials: Testimonial[];
faqs: FAQ[]
}
Loading

0 comments on commit 906e822

Please sign in to comment.