@churchapps/apphelper 0.4.7 → 0.4.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) hide show
  1. package/CHUMS_COMPONENT_EXTRACTION_CANDIDATES.md +210 -0
  2. package/COMPONENT_USAGE_REPORT.md +322 -0
  3. package/b1app-specific-components.md +146 -0
  4. package/component-usage-analysis.md +169 -0
  5. package/dist/components/ImageEditor.d.ts +1 -1
  6. package/dist/components/ImageEditor.d.ts.map +1 -1
  7. package/dist/components/ImageEditor.js +1 -1
  8. package/dist/components/ImageEditor.js.map +1 -1
  9. package/dist/components/header/SecondaryMenu.js +3 -3
  10. package/dist/components/header/SecondaryMenu.js.map +1 -1
  11. package/dist/components/index.d.ts +0 -5
  12. package/dist/components/index.d.ts.map +1 -1
  13. package/dist/components/index.js +1 -10
  14. package/dist/components/index.js.map +1 -1
  15. package/dist/components/markdownEditor/IconNamesList.d.ts.map +1 -0
  16. package/dist/components/markdownEditor/IconNamesList.js +16 -0
  17. package/dist/components/markdownEditor/IconNamesList.js.map +1 -0
  18. package/dist/components/markdownEditor/plugins/customLink/CustomLinkNodeTransformer.js +1 -1
  19. package/dist/components/markdownEditor/plugins/customLink/CustomLinkNodeTransformer.js.map +1 -1
  20. package/dist/components/markdownEditor/plugins/emoji/EmojiNodeTransform.js +1 -1
  21. package/dist/components/markdownEditor/plugins/emoji/EmojiNodeTransform.js.map +1 -1
  22. package/dist/components/markdownEditor/plugins/emoji/EmojiPickerPlugin.js +1 -1
  23. package/dist/components/markdownEditor/plugins/emoji/EmojiPickerPlugin.js.map +1 -1
  24. package/dist/components/markdownEditor/plugins/emoji/EmojisPlugin.js +1 -1
  25. package/dist/components/markdownEditor/plugins/emoji/EmojisPlugin.js.map +1 -1
  26. package/dist/components/notes/index.d.ts +0 -2
  27. package/dist/components/notes/index.d.ts.map +1 -1
  28. package/dist/components/notes/index.js +1 -5
  29. package/dist/components/notes/index.js.map +1 -1
  30. package/dist/helpers/FileHelper.d.ts +1 -1
  31. package/dist/helpers/FileHelper.d.ts.map +1 -1
  32. package/dist/helpers/FileHelper.js +2 -6
  33. package/dist/helpers/FileHelper.js.map +1 -1
  34. package/dist/index.d.ts +0 -1
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +0 -1
  37. package/dist/index.js.map +1 -1
  38. package/package.json +1 -1
  39. package/src/components/ImageEditor.tsx +1 -1
  40. package/src/components/header/SecondaryMenu.tsx +3 -3
  41. package/src/components/index.tsx +0 -5
  42. package/src/components/markdownEditor/IconNamesList.ts +14 -0
  43. package/src/components/markdownEditor/plugins/customLink/CustomLinkNodeTransformer.tsx +1 -1
  44. package/src/components/markdownEditor/plugins/emoji/EmojiNodeTransform.ts +1 -1
  45. package/src/components/markdownEditor/plugins/emoji/EmojiPickerPlugin.tsx +1 -1
  46. package/src/components/markdownEditor/plugins/emoji/EmojisPlugin.tsx +1 -1
  47. package/src/components/notes/index.ts +0 -2
  48. package/src/helpers/FileHelper.ts +3 -6
  49. package/src/index.ts +0 -1
  50. package/dist/components/B1ShareModal.d.ts +0 -9
  51. package/dist/components/B1ShareModal.d.ts.map +0 -1
  52. package/dist/components/B1ShareModal.js +0 -77
  53. package/dist/components/B1ShareModal.js.map +0 -1
  54. package/dist/components/CreatePerson.d.ts +0 -15
  55. package/dist/components/CreatePerson.d.ts.map +0 -1
  56. package/dist/components/CreatePerson.js +0 -100
  57. package/dist/components/CreatePerson.js.map +0 -1
  58. package/dist/components/PersonAdd.d.ts +0 -16
  59. package/dist/components/PersonAdd.d.ts.map +0 -1
  60. package/dist/components/PersonAdd.js +0 -52
  61. package/dist/components/PersonAdd.js.map +0 -1
  62. package/dist/components/gallery/GalleryModal.d.ts +0 -9
  63. package/dist/components/gallery/GalleryModal.d.ts.map +0 -1
  64. package/dist/components/gallery/GalleryModal.js +0 -111
  65. package/dist/components/gallery/GalleryModal.js.map +0 -1
  66. package/dist/components/gallery/StockPhotos.d.ts +0 -9
  67. package/dist/components/gallery/StockPhotos.d.ts.map +0 -1
  68. package/dist/components/gallery/StockPhotos.js +0 -79
  69. package/dist/components/gallery/StockPhotos.js.map +0 -1
  70. package/dist/components/gallery/index.d.ts +0 -2
  71. package/dist/components/gallery/index.d.ts.map +0 -1
  72. package/dist/components/gallery/index.js +0 -6
  73. package/dist/components/gallery/index.js.map +0 -1
  74. package/dist/components/iconPicker/IconNamesList.d.ts.map +0 -1
  75. package/dist/components/iconPicker/IconNamesList.js +0 -2241
  76. package/dist/components/iconPicker/IconNamesList.js.map +0 -1
  77. package/dist/components/iconPicker/IconPicker.d.ts +0 -6
  78. package/dist/components/iconPicker/IconPicker.d.ts.map +0 -1
  79. package/dist/components/iconPicker/IconPicker.js +0 -142
  80. package/dist/components/iconPicker/IconPicker.js.map +0 -1
  81. package/dist/components/notes/Conversation.d.ts +0 -10
  82. package/dist/components/notes/Conversation.d.ts.map +0 -1
  83. package/dist/components/notes/Conversation.js +0 -55
  84. package/dist/components/notes/Conversation.js.map +0 -1
  85. package/dist/components/notes/Conversations.d.ts +0 -10
  86. package/dist/components/notes/Conversations.d.ts.map +0 -1
  87. package/dist/components/notes/Conversations.js +0 -54
  88. package/dist/components/notes/Conversations.js.map +0 -1
  89. package/dist/components/notes/NewConversation.d.ts +0 -12
  90. package/dist/components/notes/NewConversation.d.ts.map +0 -1
  91. package/dist/components/notes/NewConversation.js +0 -54
  92. package/dist/components/notes/NewConversation.js.map +0 -1
  93. package/dist/donationComponents/DonationPage.d.ts +0 -11
  94. package/dist/donationComponents/DonationPage.d.ts.map +0 -1
  95. package/dist/donationComponents/DonationPage.js +0 -150
  96. package/dist/donationComponents/DonationPage.js.map +0 -1
  97. package/dist/donationComponents/components/BankForm.d.ts +0 -14
  98. package/dist/donationComponents/components/BankForm.d.ts.map +0 -1
  99. package/dist/donationComponents/components/BankForm.js +0 -125
  100. package/dist/donationComponents/components/BankForm.js.map +0 -1
  101. package/dist/donationComponents/components/CardForm.d.ts +0 -13
  102. package/dist/donationComponents/components/CardForm.d.ts.map +0 -1
  103. package/dist/donationComponents/components/CardForm.js +0 -122
  104. package/dist/donationComponents/components/CardForm.js.map +0 -1
  105. package/dist/donationComponents/components/DonationForm.d.ts +0 -15
  106. package/dist/donationComponents/components/DonationForm.d.ts.map +0 -1
  107. package/dist/donationComponents/components/DonationForm.js +0 -200
  108. package/dist/donationComponents/components/DonationForm.js.map +0 -1
  109. package/dist/donationComponents/components/FundDonation.d.ts +0 -12
  110. package/dist/donationComponents/components/FundDonation.d.ts.map +0 -1
  111. package/dist/donationComponents/components/FundDonation.js +0 -32
  112. package/dist/donationComponents/components/FundDonation.js.map +0 -1
  113. package/dist/donationComponents/components/FundDonations.d.ts +0 -11
  114. package/dist/donationComponents/components/FundDonations.d.ts.map +0 -1
  115. package/dist/donationComponents/components/FundDonations.js +0 -33
  116. package/dist/donationComponents/components/FundDonations.js.map +0 -1
  117. package/dist/donationComponents/components/NonAuthDonation.d.ts +0 -12
  118. package/dist/donationComponents/components/NonAuthDonation.d.ts.map +0 -1
  119. package/dist/donationComponents/components/NonAuthDonation.js +0 -27
  120. package/dist/donationComponents/components/NonAuthDonation.js.map +0 -1
  121. package/dist/donationComponents/components/NonAuthDonationInner.d.ts +0 -12
  122. package/dist/donationComponents/components/NonAuthDonationInner.d.ts.map +0 -1
  123. package/dist/donationComponents/components/NonAuthDonationInner.js +0 -276
  124. package/dist/donationComponents/components/NonAuthDonationInner.js.map +0 -1
  125. package/dist/donationComponents/components/PaymentMethods.d.ts +0 -14
  126. package/dist/donationComponents/components/PaymentMethods.d.ts.map +0 -1
  127. package/dist/donationComponents/components/PaymentMethods.js +0 -86
  128. package/dist/donationComponents/components/PaymentMethods.js.map +0 -1
  129. package/dist/donationComponents/components/RecurringDonations.d.ts +0 -10
  130. package/dist/donationComponents/components/RecurringDonations.d.ts.map +0 -1
  131. package/dist/donationComponents/components/RecurringDonations.js +0 -93
  132. package/dist/donationComponents/components/RecurringDonations.js.map +0 -1
  133. package/dist/donationComponents/components/RecurringDonationsEdit.d.ts +0 -11
  134. package/dist/donationComponents/components/RecurringDonationsEdit.d.ts.map +0 -1
  135. package/dist/donationComponents/components/RecurringDonationsEdit.js +0 -66
  136. package/dist/donationComponents/components/RecurringDonationsEdit.js.map +0 -1
  137. package/dist/donationComponents/components/index.d.ts +0 -10
  138. package/dist/donationComponents/components/index.d.ts.map +0 -1
  139. package/dist/donationComponents/components/index.js +0 -22
  140. package/dist/donationComponents/components/index.js.map +0 -1
  141. package/dist/donationComponents/index.d.ts +0 -4
  142. package/dist/donationComponents/index.d.ts.map +0 -1
  143. package/dist/donationComponents/index.js +0 -10
  144. package/dist/donationComponents/index.js.map +0 -1
  145. package/dist/donationComponents/modals/DonationPreviewModal.d.ts +0 -15
  146. package/dist/donationComponents/modals/DonationPreviewModal.d.ts.map +0 -1
  147. package/dist/donationComponents/modals/DonationPreviewModal.js +0 -33
  148. package/dist/donationComponents/modals/DonationPreviewModal.js.map +0 -1
  149. package/src/components/B1ShareModal.tsx +0 -104
  150. package/src/components/CreatePerson.tsx +0 -135
  151. package/src/components/PersonAdd.tsx +0 -81
  152. package/src/components/gallery/GalleryModal.tsx +0 -139
  153. package/src/components/gallery/StockPhotos.tsx +0 -75
  154. package/src/components/gallery/index.ts +0 -1
  155. package/src/components/iconPicker/IconNamesList.ts +0 -2240
  156. package/src/components/iconPicker/IconPicker.tsx +0 -160
  157. package/src/components/notes/Conversation.tsx +0 -84
  158. package/src/components/notes/Conversations.tsx +0 -60
  159. package/src/components/notes/NewConversation.tsx +0 -80
  160. package/src/donationComponents/DonationPage.tsx +0 -215
  161. package/src/donationComponents/components/BankForm.tsx +0 -161
  162. package/src/donationComponents/components/CardForm.tsx +0 -106
  163. package/src/donationComponents/components/DonationForm.tsx +0 -255
  164. package/src/donationComponents/components/FundDonation.tsx +0 -58
  165. package/src/donationComponents/components/FundDonations.tsx +0 -44
  166. package/src/donationComponents/components/NonAuthDonation.tsx +0 -33
  167. package/src/donationComponents/components/NonAuthDonationInner.tsx +0 -295
  168. package/src/donationComponents/components/PaymentMethods.tsx +0 -137
  169. package/src/donationComponents/components/RecurringDonations.tsx +0 -123
  170. package/src/donationComponents/components/RecurringDonationsEdit.tsx +0 -95
  171. package/src/donationComponents/components/index.tsx +0 -9
  172. package/src/donationComponents/index.ts +0 -3
  173. package/src/donationComponents/modals/DonationPreviewModal.tsx +0 -68
  174. /package/dist/components/{iconPicker → markdownEditor}/IconNamesList.d.ts +0 -0
@@ -1,295 +0,0 @@
1
- "use client";
2
-
3
- import { CardElement, useElements, useStripe } from "@stripe/react-stripe-js";
4
- import React, { useState, useRef } from "react";
5
- import ReCAPTCHA from "react-google-recaptcha";
6
- import { ErrorMessages, InputBox } from "../../components";
7
- import { ApiHelper, DateHelper, CurrencyHelper, Locale } from "../../helpers";
8
- import { FundDonationInterface, FundInterface, PersonInterface, StripeDonationInterface, StripePaymentMethod, UserInterface, ChurchInterface } from "@churchapps/helpers";
9
- import { FundDonations } from "./FundDonations";
10
- import { Grid, Alert, TextField, Button, FormControl, InputLabel, Select, MenuItem, PaperProps, FormGroup, FormControlLabel, Checkbox, Typography } from "@mui/material"
11
- import { DonationHelper } from "../../helpers/DonationHelper";
12
-
13
- interface Props { churchId: string, mainContainerCssProps?: PaperProps, showHeader?: boolean, recaptchaSiteKey: string, churchLogo?: string }
14
-
15
- export const NonAuthDonationInner: React.FC<Props> = ({ mainContainerCssProps, showHeader = true, ...props }) => {
16
- const stripe = useStripe();
17
- const elements = useElements();
18
- const formStyling = { style: { base: { fontSize: "18px" } } };
19
- const [firstName, setFirstName] = React.useState("");
20
- const [lastName, setLastName] = React.useState("");
21
- const [email, setEmail] = React.useState("");
22
- const [fundsTotal, setFundsTotal] = React.useState<number>(0);
23
- const [transactionFee, setTransactionFee] = React.useState<number>(0);
24
- const [total, setTotal] = React.useState<number>(0);
25
- const [errors, setErrors] = React.useState([]);
26
- const [fundDonations, setFundDonations] = React.useState<FundDonationInterface[]>([]);
27
- const [funds, setFunds] = React.useState<FundInterface[]>([]);
28
- const [donationComplete, setDonationComplete] = React.useState(false);
29
- const [processing, setProcessing] = React.useState(false);
30
- const [donationType, setDonationType] = useState<"once" | "recurring">("once");
31
- const [interval, setInterval] = useState("one_month");
32
- const [startDate, setStartDate] = useState(new Date().toDateString());
33
- const [captchaResponse, setCaptchaResponse] = useState("");
34
- const [church, setChurch] = useState<ChurchInterface>();
35
- const [gateway, setGateway] = React.useState(null);
36
- const [searchParams, setSearchParams] = React.useState<any>();
37
- const captchaRef = useRef(null);
38
-
39
- const getUrlParam = (param: string) => {
40
- if (typeof window === "undefined") return null;
41
- const urlParams = new URLSearchParams(window.location.search);
42
- return urlParams.get(param);
43
- }
44
-
45
- const init = () => {
46
- const fundId = getUrlParam("fundId");
47
- const amount = getUrlParam("amount");
48
- setSearchParams({ fundId, amount });
49
-
50
- ApiHelper.get("/funds/churchId/" + props.churchId, "GivingApi").then(data => {
51
- setFunds(data);
52
- if (fundId && fundId !== "") {
53
- const selectedFund = data.find((f: FundInterface) => f.id === fundId);
54
- if (selectedFund) {
55
- setFundDonations([{ fundId: selectedFund.id, amount: (amount && amount !== "") ? parseFloat(amount) : 0}]);
56
- }
57
- } else if (data.length) {
58
- setFundDonations([{ fundId: data[0].id }]);
59
- }
60
- });
61
- ApiHelper.get("/churches/" + props.churchId, "MembershipApi").then(data => {
62
- setChurch(data);
63
- });
64
- ApiHelper.get("/gateways/churchId/" + props.churchId, "GivingApi").then(data => {
65
- if (data.length !== 0) setGateway(data[0]);
66
- });
67
- }
68
-
69
- const handleCaptchaChange = (value: string) => {
70
- const captchaToken = captchaRef.current.getValue();
71
- ApiHelper.postAnonymous("/donate/captcha-verify", { token: captchaToken }, "GivingApi").then((data) => { setCaptchaResponse(data.response); })
72
- }
73
-
74
- const handleCheckChange = (e: React.SyntheticEvent<Element, Event>, checked: boolean) => {
75
- let totalPayAmount = checked ? fundsTotal + transactionFee : fundsTotal;
76
- setTotal(totalPayAmount);
77
- }
78
-
79
- // const handleAutoPayFee = () => {
80
- // let totalPayAmount = fundsTotal + transactionFee;
81
- // setTotal(totalPayAmount);
82
- // }
83
-
84
- const handleSave = async () => {
85
- if (validate()) {
86
- setProcessing(true);
87
- ApiHelper.post("/users/loadOrCreate", { userEmail: email, firstName, lastName }, "MembershipApi")
88
- .catch(ex => { setErrors([ex.toString()]); setProcessing(false); })
89
- .then(async userData => {
90
- const personData = { churchId: props.churchId, firstName, lastName, email };
91
- const person = await ApiHelper.post("/people/loadOrCreate", personData, "MembershipApi")
92
- saveCard(userData, person)
93
- });
94
- }
95
- }
96
-
97
- const saveCard = async (user: UserInterface, person: PersonInterface) => {
98
- const cardData = elements.getElement(CardElement);
99
- const stripePM = await stripe.createPaymentMethod({ type: "card", card: cardData });
100
- if (stripePM.error) { setErrors([stripePM.error.message]); setProcessing(false); }
101
- else {
102
- const pm = { id: stripePM.paymentMethod.id, personId: person.id, email: email, name: person.name.display, churchId: props.churchId }
103
- await ApiHelper.post("/paymentmethods/addcard", pm, "GivingApi").then(result => {
104
- if (result?.raw?.message) {
105
- setErrors([result.raw.message]);
106
- setProcessing(false);
107
- } else {
108
- const d: { paymentMethod: StripePaymentMethod, customerId: string } = result;
109
- saveDonation(d.paymentMethod, d.customerId, person);
110
- }
111
- });
112
- }
113
- }
114
-
115
- const saveDonation = async (paymentMethod: StripePaymentMethod, customerId: string, person?: PersonInterface) => {
116
- let donation: StripeDonationInterface = {
117
- amount: total,
118
- id: paymentMethod.id,
119
- customerId: customerId,
120
- type: paymentMethod.type,
121
- churchId: props.churchId,
122
- funds: [],
123
- person: {
124
- id: person?.id,
125
- email: person?.contactInfo?.email,
126
- name: person?.name?.display
127
- }
128
- }
129
-
130
- if (donationType === "recurring") {
131
- donation.billing_cycle_anchor = + new Date(startDate);
132
- donation.interval = DonationHelper.getInterval(interval);
133
- }
134
-
135
- for (const fundDonation of fundDonations) {
136
- let fund = funds.find((fund: FundInterface) => fund.id === fundDonation.fundId);
137
- donation.funds.push({ id: fundDonation.fundId, amount: fundDonation.amount || 0, name: fund.name });
138
- }
139
-
140
- const churchObj = {
141
- name: church.name,
142
- subDomain: church.subDomain,
143
- churchURL: typeof window !== "undefined" && window.location.origin,
144
- logo: props?.churchLogo
145
- }
146
-
147
- let results;
148
- if (donationType === "once") results = await ApiHelper.post("/donate/charge/", { ...donation, church: churchObj }, "GivingApi");
149
- if (donationType === "recurring") results = await ApiHelper.post("/donate/subscribe/", { ...donation, church: churchObj }, "GivingApi");
150
-
151
- if (results?.status === "succeeded" || results?.status === "pending" || results?.status === "active") {
152
- setDonationComplete(true)
153
- }
154
- if (results?.raw?.message) {
155
- setErrors([results?.raw?.message]);
156
- setProcessing(false);
157
- }
158
- setProcessing(false);
159
- }
160
-
161
- const validate = () => {
162
- const result = [];
163
- if (!firstName) result.push(Locale.label("donation.donationForm.validate.firstName"));
164
- if (!lastName) result.push(Locale.label("donation.donationForm.validate.lastName"));
165
- if (!email) result.push(Locale.label("donation.donationForm.validate.email"));
166
- if (fundsTotal === 0) result.push(Locale.label("donation.donationForm.validate.amount"));
167
- if (result.length === 0) {
168
- if (!email.match(/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w+)+$/)) result.push(Locale.label("donation.donationForm.validate.validEmail")); //eslint-disable-line
169
- }
170
- //Todo - make sure the account doesn't exist. (loadOrCreate?)
171
- setErrors(result);
172
- return result.length === 0;
173
- }
174
-
175
- const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) => {
176
- const val = e.currentTarget.value;
177
- switch (e.currentTarget.name) {
178
- case "firstName": setFirstName(val); break;
179
- case "lastName": setLastName(val); break;
180
- case "email": setEmail(val); break;
181
- case "startDate": setStartDate(val); break;
182
- case "interval": setInterval(val); break;
183
- }
184
- }
185
-
186
- const handleFundDonationsChange = async (fd: FundDonationInterface[]) => {
187
- setFundDonations(fd);
188
- let totalAmount = 0;
189
- let selectedFunds: any = [];
190
- for (const fundDonation of fd) {
191
- totalAmount += fundDonation.amount || 0;
192
- let fund = funds.find((fund: FundInterface) => fund.id === fundDonation.fundId);
193
- selectedFunds.push({ id: fundDonation.fundId, amount: fundDonation.amount || 0, name: fund.name });
194
- }
195
- setFundsTotal(totalAmount);
196
- setTotal(totalAmount);
197
-
198
- const fee = await getTransactionFee(totalAmount);
199
- setTransactionFee(fee);
200
-
201
- if (gateway && gateway.payFees === true) {
202
- setTotal(totalAmount + fee);
203
- }
204
- }
205
-
206
- const getTransactionFee = async (amount: number) => {
207
- if (amount > 0) {
208
- try {
209
- const response = await ApiHelper.post("/donate/fee?churchId=" + props.churchId, { type: "creditCard", amount }, "GivingApi");
210
- return response.calculatedFee;
211
- } catch (error) {
212
- console.log("Error calculating transaction fee: ", error);
213
- return 0;
214
- }
215
- } else {
216
- return 0;
217
- }
218
- }
219
-
220
- const getFundList = () => {
221
- if (funds) return (<>
222
- <hr />
223
- <h4>{Locale.label("donation.donationForm.funds")}</h4>
224
- <FundDonations fundDonations={fundDonations} funds={funds} params={searchParams} updatedFunction={handleFundDonationsChange} />
225
- </>);
226
- }
227
-
228
- React.useEffect(init, []); //eslint-disable-line
229
-
230
- // React.useEffect(() => { gateway && gateway.payFees === true && handleAutoPayFee() }, [fundDonations]);
231
-
232
- if (donationComplete) return <Alert severity="success">{Locale.label("donation.donationForm.thankYou")}</Alert>
233
- else return (
234
- <InputBox headerIcon={showHeader ? "volunteer_activism" : ""} headerText={showHeader ? "Donate" : ""} saveFunction={handleSave} saveText="Donate" isSubmitting={processing || !captchaResponse || captchaResponse === "robot"} mainContainerCssProps={mainContainerCssProps}>
235
- <ErrorMessages errors={errors} />
236
- <Grid container spacing={3}>
237
- <Grid size={{ xs: 12, md: 6 }}>
238
- <Button aria-label="single-donation" size="small" fullWidth style={{ minHeight: "50px" }} variant={donationType === "once" ? "contained" : "outlined"} onClick={() => setDonationType("once")}>{Locale.label("donation.donationForm.make")}</Button>
239
- </Grid>
240
- <Grid size={{ xs: 12, md: 6 }}>
241
- <Button aria-label="recurring-donation" size="small" fullWidth style={{ minHeight: "50px" }} variant={donationType === "recurring" ? "contained" : "outlined"} onClick={() => setDonationType("recurring")}>{Locale.label("donation.donationForm.makeRecurring")}</Button>
242
- </Grid>
243
- <Grid size={{ xs: 12, md: 6 }}>
244
- <TextField fullWidth label={Locale.label("person.firstName")} name="firstName" value={firstName} onChange={handleChange} />
245
- </Grid>
246
- <Grid size={{ xs: 12, md: 6 }}>
247
- <TextField fullWidth label={Locale.label("person.lastName")} name="lastName" value={lastName} onChange={handleChange} />
248
- </Grid>
249
- <Grid size={{ xs: 12, md: 6 }}>
250
- <TextField fullWidth label={Locale.label("person.email")} name="email" value={email} onChange={handleChange} />
251
- </Grid>
252
- <Grid size={{ xs: 12, md: 6 }}>
253
- <ReCAPTCHA sitekey={props.recaptchaSiteKey} ref={captchaRef} onChange={handleCaptchaChange} />
254
- </Grid>
255
- </Grid>
256
- <div style={{ padding: 10, border: "1px solid #CCC", borderRadius: 5, marginTop: 10 }}>
257
- <CardElement options={formStyling} />
258
- </div>
259
- {donationType === "recurring"
260
- && <Grid container spacing={3} style={{ marginTop: 0 }}>
261
- <Grid size={{ xs: 12, md: 6 }}>
262
- <FormControl fullWidth>
263
- <InputLabel>{Locale.label("donation.donationForm.frequency")}</InputLabel>
264
- <Select label="Frequency" name="interval" aria-label="interval" value={interval} onChange={(e) => { setInterval(e.target.value) }}>
265
- <MenuItem value="one_week">{Locale.label("donation.donationForm.weekly")}</MenuItem>
266
- <MenuItem value="two_week">{Locale.label("donation.donationForm.biWeekly")}</MenuItem>
267
- <MenuItem value="one_month">{Locale.label("donation.donationForm.monthly")}</MenuItem>
268
- <MenuItem value="three_month">{Locale.label("donation.donationForm.quarterly")}</MenuItem>
269
- <MenuItem value="one_year">{Locale.label("donation.donationForm.annually")}</MenuItem>
270
- </Select>
271
- </FormControl>
272
- </Grid>
273
- <Grid size={{ xs: 12, md: 6 }}>
274
- <TextField fullWidth name="startDate" type="date" aria-label="startDate" label={Locale.label("donation.donationForm.startDate")} value={DateHelper.formatHtml5Date(new Date(startDate))} onChange={handleChange} />
275
- </Grid>
276
- </Grid>
277
- }
278
- {getFundList()}
279
- <div>
280
- {fundsTotal > 0
281
- && <>
282
- {(gateway && gateway.payFees === true)
283
- ? <Typography fontSize={14} fontStyle="italic">*{Locale.label("donation.donationForm.fees").replace("{}", CurrencyHelper.formatCurrency(transactionFee))}</Typography>
284
- : (
285
- <FormGroup>
286
- <FormControlLabel control={<Checkbox />} name="transaction-fee" label={Locale.label("donation.donationForm.cover").replace("{}", CurrencyHelper.formatCurrency(transactionFee))} onChange={handleCheckChange} />
287
- </FormGroup>
288
- )}
289
- <p>Total Donation Amount: ${total}</p>
290
- </>
291
- }
292
- </div>
293
- </InputBox>
294
- );
295
- }
@@ -1,137 +0,0 @@
1
- "use client";
2
-
3
- import React from "react";
4
- import { Stripe } from "@stripe/stripe-js";
5
- import { Elements } from "@stripe/react-stripe-js";
6
- import { CardForm, BankForm } from ".";
7
- import { DisplayBox, Loading } from "../../components";
8
- import { ApiHelper, Locale, UserHelper } from "../../helpers";
9
- import { PersonInterface, StripePaymentMethod, Permissions } from "@churchapps/helpers";
10
- import { Icon, Table, TableBody, TableCell, TableRow, IconButton, Menu, MenuItem } from "@mui/material";
11
-
12
- interface Props { person: PersonInterface, customerId: string, paymentMethods: StripePaymentMethod[], stripePromise: Promise<Stripe>, appName: string, dataUpdate: (message?: string) => void }
13
-
14
- export const PaymentMethods: React.FC<Props> = (props) => {
15
- const [editPaymentMethod, setEditPaymentMethod] = React.useState<StripePaymentMethod>(new StripePaymentMethod());
16
- const [mode, setMode] = React.useState("display");
17
- const [verify, setVerify] = React.useState<boolean>(false);
18
-
19
- const handleEdit = (pm?: StripePaymentMethod, verifyAccount?: boolean) => (e: React.MouseEvent) => {
20
- e.preventDefault();
21
- setEditPaymentMethod(pm);
22
- setVerify(verifyAccount)
23
- setMode("edit");
24
- }
25
-
26
- const handleDelete = async () => {
27
- let confirmed = window.confirm(Locale.label("donation.paymentMethods.confirmDelete"));
28
- if (confirmed) {
29
- ApiHelper.delete("/paymentmethods/" + editPaymentMethod.id + "/" + props.customerId, "GivingApi").then(() => {
30
- setMode("display");
31
- props.dataUpdate(Locale.label("donation.paymentMethods.deleted"));
32
- })
33
- }
34
- }
35
-
36
- const MenuIcon = () => {
37
- const [anchorEl, setAnchorEl] = React.useState(null);
38
- const open = Boolean(anchorEl);
39
- const handleClick = (e: React.MouseEvent) => {
40
- setAnchorEl(e.currentTarget);
41
- };
42
- const handleClose = () => {
43
- setAnchorEl(null);
44
- };
45
- return (
46
- <>
47
- <IconButton
48
- aria-label="add-button"
49
- id="addBtnGroup"
50
- aria-controls={open ? "add-menu" : undefined}
51
- aria-expanded={open ? "true" : undefined}
52
- aria-haspopup="true"
53
- onClick={handleClick}
54
- >
55
- <Icon color="primary">add</Icon>
56
- </IconButton>
57
- <Menu
58
- id="add-menu"
59
- MenuListProps={{
60
- "aria-labelledby": "addBtnGroup"
61
- }}
62
- anchorEl={anchorEl}
63
- open={open}
64
- onClose={handleClose}
65
- >
66
- <MenuItem aria-label="add-card" onClick={handleEdit(new StripePaymentMethod({ type: "card" }))}>
67
- <Icon sx={{mr: "3px"}}>credit_card</Icon> {Locale.label("donation.paymentMethods.addCard")}
68
- </MenuItem>
69
- <MenuItem aria-label="add-bank" onClick={handleEdit(new StripePaymentMethod({ type: "bank" }))}>
70
- <Icon sx={{mr: "3px"}}>account_balance</Icon> {Locale.label("donation.paymentMethods.addBank")}
71
- </MenuItem>
72
- </Menu>
73
- </>
74
- );
75
- }
76
-
77
- const getNewContent = () => {
78
- if (!UserHelper.checkAccess(Permissions.givingApi.settings.edit) && props.appName !== "B1App") return null;
79
- return <MenuIcon />;
80
- }
81
-
82
- const getEditOptions = (pm: StripePaymentMethod) => {
83
- if (!UserHelper.checkAccess(Permissions.givingApi.settings.edit) && props.appName !== "B1App") return null;
84
- return <a aria-label="edit-button" onClick={handleEdit(pm)} href="about:blank"><Icon>edit</Icon></a>;
85
- }
86
-
87
- const getPMIcon = (type: string) => (type === "card" ? <Icon>credit_card</Icon> : <Icon>account_balance</Icon>)
88
-
89
- const getPaymentRows = () => {
90
- let rows: React.ReactElement[] = [];
91
-
92
- props.paymentMethods.forEach((method: StripePaymentMethod) => {
93
- rows.push(
94
- <TableRow key={method.id}>
95
- <TableCell className="capitalize">{getPMIcon(method.type)} {method.name + " ****" + method.last4}</TableCell>
96
- <TableCell>{method?.status === "new" && <a href="about:blank" aria-label="verify-account" onClick={handleEdit(method, true)}>{Locale.label("donation.paymentMethods.verify")}</a>}</TableCell>
97
- <TableCell align="right">{getEditOptions(method)}</TableCell>
98
- </TableRow>
99
- );
100
- });
101
- return rows;
102
- }
103
-
104
- const PaymentMethodsTable = () => {
105
- if (!props.paymentMethods) return <Loading></Loading>
106
- if (props.paymentMethods.length) {
107
- return (
108
- <Table>
109
- <TableBody>
110
- {getPaymentRows()}
111
- </TableBody>
112
- </Table>
113
- );
114
- }
115
- else return <div>{Locale.label("donation.paymentMethods.noMethod")}</div>
116
- }
117
-
118
- const EditForm = () => (
119
- <Elements stripe={props.stripePromise}>
120
- {editPaymentMethod.type === "card" && <CardForm card={editPaymentMethod} customerId={props.customerId} person={props.person} setMode={setMode} deletePayment={handleDelete} updateList={(message) => { props.dataUpdate(message) }} />}
121
- {editPaymentMethod.type === "bank" && <BankForm bank={editPaymentMethod} showVerifyForm={verify} customerId={props.customerId} person={props.person} setMode={setMode} deletePayment={handleDelete} updateList={(message) => { props.dataUpdate(message) }} />}
122
- </Elements>
123
- )
124
-
125
- const PaymentMethods = () => {
126
- if (mode === "display") {
127
- return (
128
- <DisplayBox aria-label="payment-methods-box" headerIcon="credit_card" headerText="Payment Methods" editContent={getNewContent()}>
129
- <PaymentMethodsTable></PaymentMethodsTable>
130
- </DisplayBox>
131
- );
132
- }
133
- else return <EditForm></EditForm>;
134
- }
135
-
136
- return props.stripePromise ? <PaymentMethods></PaymentMethods> : null;
137
- }
@@ -1,123 +0,0 @@
1
- "use client";
2
-
3
- import React from "react";
4
- import { DisplayBox } from "../../components";
5
- import { ApiHelper, UserHelper, CurrencyHelper, DateHelper, Locale } from "../../helpers";
6
- import { Permissions, SubscriptionInterface } from "@churchapps/helpers";
7
- import { RecurringDonationsEdit } from ".";
8
- import { Icon, Table, TableBody, TableCell, TableRow, TableHead } from "@mui/material";
9
-
10
- interface Props { customerId: string, paymentMethods: any[], appName: string, dataUpdate: (message?: string) => void, };
11
-
12
- export const RecurringDonations: React.FC<Props> = (props) => {
13
- const [subscriptions, setSubscriptions] = React.useState<SubscriptionInterface[]>([]);
14
- const [mode, setMode] = React.useState("display");
15
- const [editSubscription, setEditSubscription] = React.useState<SubscriptionInterface>();
16
-
17
- const loadData = () => {
18
- if (props.customerId) {
19
- ApiHelper.get("/customers/" + props.customerId + "/subscriptions", "GivingApi").then(subResult => {
20
- const subs: SubscriptionInterface[] = [];
21
- const requests = subResult.data?.map((s: any) => ApiHelper.get("/subscriptionfunds?subscriptionId=" + s.id, "GivingApi").then(subFunds => {
22
- s.funds = subFunds;
23
- subs.push(s);
24
- }));
25
- return requests && Promise.all(requests).then(() => {
26
- setSubscriptions(subs);
27
- });
28
- });
29
- }
30
- }
31
-
32
- const handleUpdate = (message: string) => {
33
- loadData();
34
- setMode("display");
35
- if (message) props.dataUpdate(message);
36
- }
37
-
38
- const handleEdit = (sub: SubscriptionInterface) => (e: React.MouseEvent) => {
39
- e.preventDefault();
40
- setEditSubscription(sub);
41
- setMode("edit");
42
- }
43
-
44
- const getPaymentMethod = (sub: SubscriptionInterface) => {
45
- const pm = props.paymentMethods.find((pm: any) => pm.id === (sub.default_payment_method || sub.default_source));
46
- if (!pm) return <span style={{ color: "red" }}>{Locale.label("donation.recurring.notFound")}</span>;
47
- return `${pm.name} ****${pm.last4}`;
48
- }
49
-
50
- const getInterval = (subscription: SubscriptionInterface) => {
51
- let interval = subscription.plan.interval_count + " " + subscription.plan.interval;
52
- return subscription.plan.interval_count > 1 ? interval + "s" : interval;
53
- }
54
-
55
- const getFunds = (subscription: SubscriptionInterface) => {
56
- let result: React.ReactElement[] = [];
57
- subscription.funds.forEach((fund: any) => {
58
- result.push(
59
- <div key={subscription.id + fund.id}>
60
- {fund.name} <span style={{ float: "right" }}>{CurrencyHelper.formatCurrency(fund.amount)}</span>
61
- </div>
62
- );
63
- });
64
- const total = (subscription.plan.amount / 100);
65
- result.push(
66
- <div key={subscription.id + "-total"} style={{ borderTop: "solid #dee2e6 1px" }}>
67
- Total <span style={{ float: "right" }}>{CurrencyHelper.formatCurrency(total)}</span>
68
- </div>
69
- );
70
- return result;
71
- }
72
-
73
- const getEditOptions = (sub: SubscriptionInterface) => {
74
- if ((!UserHelper.checkAccess(Permissions.givingApi.settings.edit) && props.appName !== "B1App") || props?.paymentMethods?.length === 0) return null;
75
- return <a aria-label="edit-button" onClick={handleEdit(sub)} href="about:blank"><Icon>edit</Icon></a>;
76
- }
77
-
78
- const getTableHeader = () => {
79
- let result: React.ReactElement[] = [];
80
- result.push(<TableRow key="header" sx={{textAlign: "left"}}><TableCell><b>{Locale.label("donation.recurring.startDate")}</b></TableCell><TableCell><b>{Locale.label("donation.recurring.amount")}</b></TableCell><TableCell><b>{Locale.label("donation.recurring.interval")}</b></TableCell><TableCell><b>{Locale.label("donation.recurring.paymentMethod")}</b></TableCell>{props?.paymentMethods?.length > 0 && <TableCell></TableCell>}</TableRow>);
81
- return result;
82
- }
83
-
84
- const getTableRows = () => {
85
- let rows: React.ReactElement[] = [];
86
-
87
- subscriptions.forEach((sub: any) => {
88
- rows.push(
89
- <TableRow key={sub.id}>
90
- <TableCell>{DateHelper.prettyDate(new Date(sub.billing_cycle_anchor * 1000))}</TableCell>
91
- <TableCell>{getFunds(sub)}</TableCell>
92
- <TableCell>{Locale.label("donation.recurring.every")} {getInterval(sub)}</TableCell>
93
- <TableCell className="capitalize">{getPaymentMethod(sub)}</TableCell>
94
- <TableCell align="right">{getEditOptions(sub)}</TableCell>
95
- </TableRow>
96
- );
97
- });
98
- return rows;
99
- }
100
-
101
- const getSubscriptionsTable = () => (
102
- <Table>
103
- <TableHead>{getTableHeader()}</TableHead>
104
- <TableBody>{getTableRows()}</TableBody>
105
- </Table>
106
- )
107
-
108
- React.useEffect(loadData, []); //eslint-disable-line
109
-
110
- if (!subscriptions.length) return null;
111
- if (mode === "display") {
112
- return (
113
- <DisplayBox data-testid="recurring-donations" headerIcon="restart_alt" headerText="Recurring Donations">
114
- {getSubscriptionsTable()}
115
- </DisplayBox>
116
- );
117
- }
118
- if (mode === "edit" && editSubscription) {
119
- return (
120
- <RecurringDonationsEdit customerId={props.customerId} paymentMethods={props.paymentMethods} editSubscription={editSubscription} subscriptionUpdated={handleUpdate} />
121
- );
122
- }
123
- }
@@ -1,95 +0,0 @@
1
- "use client";
2
-
3
- import React from "react";
4
- import { ApiHelper, Locale } from "../../helpers";
5
- import { InputBox } from "../../components";
6
- import { StripePaymentMethod, SubscriptionInterface } from "@churchapps/helpers";
7
- import { FormControl, Grid, InputLabel, MenuItem, Select, SelectChangeEvent, TextField } from "@mui/material"
8
- import { DonationHelper } from "../../helpers"
9
-
10
- interface Props { subscriptionUpdated: (message?: string) => void, customerId: string, paymentMethods: StripePaymentMethod[], editSubscription: SubscriptionInterface };
11
-
12
- export const RecurringDonationsEdit: React.FC<Props> = (props) => {
13
- const [editSubscription, setEditSubscription] = React.useState<SubscriptionInterface>(props.editSubscription);
14
- const [interval, setInterval] = React.useState("one_month");
15
-
16
- const handleCancel = () => { props.subscriptionUpdated(); }
17
- const handleSave = () => {
18
- let sub = { ...editSubscription } as SubscriptionInterface;
19
- const pmFound = props.paymentMethods.find((pm: StripePaymentMethod) => pm.id === sub.id);
20
- if (!pmFound) {
21
- let pm = props.paymentMethods[0];
22
- sub.default_payment_method = pm.type === "card" ? pm.id : null;
23
- sub.default_source = pm.type === "bank" ? pm.id : null;
24
- }
25
- ApiHelper.post("/subscriptions", [sub], "GivingApi").then(() => props.subscriptionUpdated(Locale.label("donation.donationForm.recurringUpdated")))
26
- }
27
-
28
- const handleDelete = () => {
29
- const conf = window.confirm(Locale.label("donation.donationForm.confirmDelete"));
30
- if (!conf) return;
31
- let promises = [];
32
- promises.push(ApiHelper.delete("/subscriptions/" + props.editSubscription.id, "GivingApi"));
33
- promises.push(ApiHelper.delete("/subscriptionfunds/subscription/" + props.editSubscription.id, "GivingApi"));
34
- Promise.all(promises).then(() => props.subscriptionUpdated(Locale.label("donation.donationForm.cancelled")));
35
- }
36
-
37
- const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement> | SelectChangeEvent<string>) => {
38
- let sub = { ...editSubscription } as SubscriptionInterface;
39
- let value = e.target.value;
40
- switch (e.target.name) {
41
- case "method":
42
- let pm = props.paymentMethods.find((pm: StripePaymentMethod) => pm.id === value);
43
- sub.default_payment_method = pm.type === "card" ? value : null;
44
- sub.default_source = pm.type === "bank" ? value : null;
45
- break;
46
- case "interval":
47
- setInterval(value);
48
- const inter = DonationHelper.getInterval(value);
49
- sub.plan.interval_count = inter.interval_count;
50
- sub.plan.interval = inter.interval;
51
- break;
52
- }
53
- setEditSubscription(sub);
54
- }
55
-
56
- const getFields = () => (
57
- <>
58
- <Grid container spacing={3}>
59
- <Grid size={{ xs: 12, md: 6 }}>
60
- <FormControl fullWidth>
61
- <InputLabel>{Locale.label("donation.donationForm.method")}</InputLabel>
62
- <Select label={Locale.label("donation.donationForm.method")} name="method" aria-label="method" value={editSubscription.default_payment_method || editSubscription.default_source} className="capitalize" onChange={handleChange}>
63
- {props.paymentMethods.map((paymentMethod: any, i: number) => <MenuItem key={i} value={paymentMethod.id}>{paymentMethod.name} ****{paymentMethod.last4}</MenuItem>)}
64
- </Select>
65
- </FormControl>
66
- </Grid>
67
- <Grid size={{ xs: 12, md: 6 }}>
68
- <FormControl fullWidth>
69
- <InputLabel>{Locale.label("donation.donationForm.frequency")}</InputLabel>
70
- <Select label={Locale.label("donation.donationForm.frequency")} name="interval" aria-label="interval" value={interval} onChange={handleChange}>
71
- <MenuItem value="one_week">{Locale.label("donation.donationForm.weekly")}</MenuItem>
72
- <MenuItem value="two_week">{Locale.label("donation.donationForm.biWeekly")}</MenuItem>
73
- <MenuItem value="one_month">{Locale.label("donation.donationForm.monthly")}</MenuItem>
74
- <MenuItem value="three_month">{Locale.label("donation.donationForm.quarterly")}</MenuItem>
75
- <MenuItem value="one_year">{Locale.label("donation.donationForm.annually")}</MenuItem>
76
- </Select>
77
- </FormControl>
78
- </Grid>
79
- </Grid>
80
- </>
81
- )
82
-
83
- React.useEffect(() => {
84
- if (props.editSubscription) {
85
- const keyName = DonationHelper.getIntervalKeyName(props.editSubscription.plan.interval_count, props.editSubscription.plan.interval);
86
- setInterval(keyName);
87
- }
88
- }, [props.editSubscription]);
89
-
90
- return (
91
- <InputBox aria-label="person-details-box" headerIcon="person" headerText={Locale.label("donation.donationForm.editRecurring")} ariaLabelSave="save-button" ariaLabelDelete="delete-button" cancelFunction={handleCancel} deleteFunction={handleDelete} saveFunction={handleSave}>
92
- {getFields()}
93
- </InputBox>
94
- );
95
- }
@@ -1,9 +0,0 @@
1
- export { BankForm } from "./BankForm";
2
- export { CardForm } from "./CardForm";
3
- export { DonationForm } from "./DonationForm";
4
- export { NonAuthDonation } from "./NonAuthDonation";
5
- export { PaymentMethods } from "./PaymentMethods";
6
- export { RecurringDonations } from "./RecurringDonations";
7
- export { RecurringDonationsEdit } from "./RecurringDonationsEdit";
8
- export { FundDonations } from "./FundDonations";
9
- export { FundDonation } from "./FundDonation";
@@ -1,3 +0,0 @@
1
- export { FundDonations } from "./components/FundDonations";
2
- export { NonAuthDonation } from "./components/NonAuthDonation";
3
- export { DonationPage } from "./DonationPage";