Skip to content

Commit 82d604b

Browse files
committed
Adds a field for giving tip while making payment
1 parent 3645717 commit 82d604b

File tree

4 files changed

+107
-33
lines changed

4 files changed

+107
-33
lines changed

src/components/common/PaymentForm.tsx

Lines changed: 86 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,28 @@ interface Props {
1515
isPayment?: boolean;
1616
}
1717

18+
interface FormState {
19+
amount: number;
20+
hours_spent: number;
21+
hours_spent_cost: number;
22+
tip: number;
23+
email: string;
24+
phone: string;
25+
name: string;
26+
}
27+
1828
export const PaymentForm: FunctionComponent<Props> = ({ campaign, inlineForm = false, isPayment = false }) => {
19-
const maxAmount = campaign ? campaign.required_amount : Number.MAX_SAFE_INTEGER;
20-
const hours_spent = 2;
21-
const amount = 100 > maxAmount ? maxAmount : 100;
22-
const initialState = { amount, hours_spent, email: '', phone: '', name: '' };
29+
const maxAmount: number = campaign ? campaign.required_amount : Number.MAX_SAFE_INTEGER;
30+
const amount: number = 100 > maxAmount ? maxAmount : 100;
31+
const initialState: FormState = {
32+
amount,
33+
hours_spent: 2,
34+
hours_spent_cost: amount,
35+
tip: 0,
36+
email: '',
37+
phone: '',
38+
name: '',
39+
};
2340
const [form, setFormValue] = useState(initialState);
2441
const [isSubmitting, setIsSubmitting] = useState(false);
2542
const [isModalOpen, toggleModal] = useState(false);
@@ -29,11 +46,22 @@ export const PaymentForm: FunctionComponent<Props> = ({ campaign, inlineForm = f
2946
const value = e.target.value;
3047
if (e.target.name === 'hours_spent') {
3148
const hours_spent = Number(value);
32-
const cost = hours_spent > 3 ? hours_spent * 30 : hours_spent * 50;
49+
const hours_spent_cost = hours_spent > 3 ? hours_spent * 30 : hours_spent * 50;
3350
return setFormValue(form => ({
3451
...form,
3552
[e.target.name]: value,
36-
'amount': cost < Number(maxAmount) ? cost : maxAmount,
53+
hours_spent_cost: hours_spent_cost,
54+
amount:
55+
Number(form.tip) + hours_spent_cost < Number(maxAmount) ? Number(form.tip) + hours_spent_cost : maxAmount,
56+
}));
57+
}
58+
if (e.target.name === 'tip') {
59+
const tip = Number(value);
60+
return setFormValue(form => ({
61+
...form,
62+
[e.target.name]: value,
63+
amount:
64+
tip + Number(form.hours_spent_cost) < Number(maxAmount) ? tip + Number(form.hours_spent_cost) : maxAmount,
3765
}));
3866
}
3967
if (e.target.name === 'amount') {
@@ -45,7 +73,7 @@ export const PaymentForm: FunctionComponent<Props> = ({ campaign, inlineForm = f
4573
setFormValue(form => ({ ...form, [e.target.name]: value }));
4674
}
4775

48-
function validateForm(form: { name: string; email: string; phone: string; amount: number, hours_spent: number }) {
76+
function validateForm(form: { name: string; email: string; phone: string; amount: number; hours_spent: number }) {
4977
if (!form.amount || !form.email || !form.phone || !form.name || !form.hours_spent) {
5078
return alert(`Please enter all required fields`);
5179
}
@@ -90,9 +118,11 @@ export const PaymentForm: FunctionComponent<Props> = ({ campaign, inlineForm = f
90118
await openRzp({
91119
...form,
92120
hours_spent: Number(form.hours_spent),
121+
hours_spent_cost: Number(form.hours_spent_cost),
122+
tip: Number(form.tip),
93123
amount: Number(form.amount),
94124
campaign: campaign ? campaign.slug : undefined,
95-
isPayment
125+
isPayment,
96126
});
97127
setIsSubmitting(false);
98128
setFormValue(initialState);
@@ -105,27 +135,52 @@ export const PaymentForm: FunctionComponent<Props> = ({ campaign, inlineForm = f
105135

106136
return (
107137
<div className={clsx(!inlineForm && 'px-4', inlineForm && 'md:px-0')}>
108-
<p className="text-lg mb-4 text-gray-700 leading-relaxed">{ isPayment ? 'Please make payment for hackerspace here' : 'We truly appreciate your generosity' }</p>
138+
<p className="text-lg mb-4 text-gray-700 leading-relaxed">
139+
{isPayment ? 'Please make payment for hackerspace here' : 'We truly appreciate your generosity'}
140+
</p>
109141
<form name="payment" onSubmit={onSubmit}>
110-
<div className="mb-4 mt-4">
111-
<label htmlFor="amount" className="text-sm text-gray-800 mb-1 block">
112-
Hours spent <sup className="text-red-500">*</sup>
113-
</label>
114-
<div>
115-
<input
116-
className="bg-white focus:outline-0 border border-gray-300 rounded py-2 px-2 block w-full appearance-none leading-normal"
117-
type="number"
118-
name="hours_spent"
119-
id="hours_spent"
120-
value={form.hours_spent}
121-
onChange={onChange}
122-
required
123-
autoFocus={!inlineForm}
124-
min="1"
125-
disabled={isSubmitting}
126-
/>
142+
{isPayment && (
143+
<div className="mb-4 mt-4">
144+
<label htmlFor="hours_spent" className="text-sm text-gray-800 mb-1 block">
145+
Hours spent <sup className="text-red-500">*</sup>
146+
</label>
147+
<div>
148+
<input
149+
className="bg-white focus:outline-0 border border-gray-300 rounded py-2 px-2 block w-full appearance-none leading-normal"
150+
type="number"
151+
name="hours_spent"
152+
id="hours_spent"
153+
value={form.hours_spent}
154+
onChange={onChange}
155+
required
156+
autoFocus={!inlineForm}
157+
min="1"
158+
disabled={isSubmitting}
159+
/>
160+
</div>
127161
</div>
128-
</div>
162+
)}
163+
{isPayment && (
164+
<div className="mb-4 mt-4">
165+
<label htmlFor="tip" className="text-sm text-gray-800 mb-1 block">
166+
How much was the peer learning worth today?
167+
</label>
168+
<div>
169+
<input
170+
className="bg-white focus:outline-0 border border-gray-300 rounded py-2 px-2 block w-full appearance-none leading-normal"
171+
type="number"
172+
name="tip"
173+
id="tip"
174+
value={form.tip}
175+
onChange={onChange}
176+
required
177+
autoFocus={!inlineForm}
178+
min="1"
179+
disabled={isSubmitting}
180+
/>
181+
</div>
182+
</div>
183+
)}
129184
<div className="mb-4 mt-4">
130185
<label htmlFor="amount" className="text-sm text-gray-800 mb-1 block">
131186
Amount <sup className="text-red-500">*</sup>
@@ -199,7 +254,9 @@ export const PaymentForm: FunctionComponent<Props> = ({ campaign, inlineForm = f
199254
<div className="flex justify-center mb-3">
200255
<Button type="submit" isLoading={isSubmitting} disabled={isSubmitting}>
201256
<IconCards width={27} height={22} />
202-
<span className="ml-4 inline-block font-bold">{ isPayment ? 'Pay' : 'Contribute' }{finalAmount.toFixed(2)}</span>
257+
<span className="ml-4 inline-block font-bold">
258+
{isPayment ? 'Pay' : 'Contribute'}{finalAmount.toFixed(2)}
259+
</span>
203260
</Button>
204261
</div>
205262
<p className="text-xs text-gray-600 text-center">
@@ -216,7 +273,7 @@ export const PaymentForm: FunctionComponent<Props> = ({ campaign, inlineForm = f
216273
<PaymentSuccess />
217274
</div>
218275
<p className="text-center py-1 font-semibold text-xl text-pink-600">
219-
Thanks for your {campaign ? 'contribution' : isPayment ? 'payment' : 'donation'}.
276+
Thanks for your {campaign ? 'contribution' : isPayment ? 'payment' : 'donation'}.
220277
</p>
221278
<p className="text-center text-sm text-gray-600">We truly appreciate your generosity :D</p>
222279
</Modal>

src/pages/api/rzp.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,18 @@ const razorpay = new Razorpay(rzpCredentials);
1818

1919
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
2020
try {
21-
const { email, name, amount, hours_spent, phone, paymentMethod = 'Razorpay', campaign, isPayment } = req.body;
21+
const {
22+
email,
23+
name,
24+
amount,
25+
hours_spent,
26+
hours_spent_cost,
27+
tip,
28+
phone,
29+
paymentMethod = 'Razorpay',
30+
campaign,
31+
isPayment,
32+
} = req.body;
2233
const id = cuid();
2334
const data: { id: string; status: PaymentStatus } = await razorpay.orders.create({
2435
amount: getFinalAmount(Number(amount)) * 100, // in paise
@@ -30,7 +41,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
3041
phone,
3142
name,
3243
campaign,
33-
isPayment
44+
isPayment,
3445
},
3546
});
3647
if (campaign) {
@@ -49,14 +60,16 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
4960
},
5061
{ typecast: true }
5162
);
52-
} else if(isPayment) {
63+
} else if (isPayment) {
5364
await paymentsBase.create(
5465
{
5566
id,
5667
name,
5768
email,
5869
phone,
5970
hours_spent: Number(hours_spent),
71+
hours_spent_cost: Number(hours_spent_cost),
72+
tip: Number(tip),
6073
paid_amount: Number(amount),
6174
payment_method: paymentMethod,
6275
status: PaymentStatus.created,

src/services/airtable.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ export interface Donation extends RZPPayment {
3939
export interface Payment extends RZPPayment {
4040
paid_amount: number;
4141
hours_spent: number;
42+
hours_spent_cost: number;
43+
tip: number;
4244
}
4345

4446
export interface Funding extends Donation {

src/services/rzp.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ interface RzpData {
66
name: string;
77
email: string;
88
hours_spent: number;
9+
hours_spent_cost: number;
10+
tip: number;
911
amount: number;
1012
phone: string;
1113
campaign?: string;
@@ -62,7 +64,7 @@ export async function openRzp(data: RzpData) {
6264
razorpay_order_id: order.id,
6365
status: 'failed',
6466
campaign: data.campaign,
65-
isPayment: data.isPayment
67+
isPayment: data.isPayment,
6668
});
6769
reject(new Error(`Payment widget is closed without completing payment. Please try again!`));
6870
},

0 commit comments

Comments
 (0)