@churchapps/helpers 1.2.24 → 1.2.26
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.
- package/dist/interfaces/Messaging.d.ts +21 -0
- package/dist/interfaces/Messaging.d.ts.map +1 -1
- package/dist/interfaces/Permissions.d.ts +9 -0
- package/dist/interfaces/Permissions.d.ts.map +1 -1
- package/dist/interfaces/Permissions.js +5 -0
- package/dist/interfaces/Permissions.js.map +1 -1
- package/package.json +10 -5
- package/.github/FUNDING.yml +0 -1
- package/.yarnrc.yml +0 -6
- package/eslint.config.js +0 -48
- package/scripts/build-cjs.js +0 -33
- package/src/ApiHelper.ts +0 -169
- package/src/AppearanceHelper.ts +0 -69
- package/src/ArrayHelper.ts +0 -139
- package/src/CommonEnvironmentHelper.ts +0 -104
- package/src/CurrencyHelper.ts +0 -66
- package/src/DateHelper.ts +0 -180
- package/src/DonationHelper.ts +0 -25
- package/src/ErrorHelper.ts +0 -38
- package/src/EventHelper.ts +0 -83
- package/src/FileHelper.ts +0 -57
- package/src/PersonHelper.ts +0 -80
- package/src/PlanHelper.ts +0 -135
- package/src/UniqueIdHelper.ts +0 -159
- package/src/UserHelper.ts +0 -61
- package/src/contentProviders/ContentProvider.ts +0 -15
- package/src/contentProviders/LessonsContentProvider.ts +0 -278
- package/src/contentProviders/index.ts +0 -2
- package/src/index.ts +0 -16
- package/src/interfaces/Access.ts +0 -138
- package/src/interfaces/Attendance.ts +0 -45
- package/src/interfaces/Content.ts +0 -84
- package/src/interfaces/Doing.ts +0 -142
- package/src/interfaces/Donation.ts +0 -193
- package/src/interfaces/Error.ts +0 -17
- package/src/interfaces/Lessons.ts +0 -61
- package/src/interfaces/Membership.ts +0 -184
- package/src/interfaces/Messaging.ts +0 -96
- package/src/interfaces/Permissions.ts +0 -78
- package/src/interfaces/Reporting.ts +0 -41
- package/src/interfaces/UserContextInterface.ts +0 -13
- package/src/interfaces/index.ts +0 -14
- package/tsconfig.json +0 -36
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
export class CommonEnvironmentHelper {
|
|
3
|
-
public static AttendanceApi = "";
|
|
4
|
-
public static DoingApi = "";
|
|
5
|
-
public static GivingApi = "";
|
|
6
|
-
public static MembershipApi = "";
|
|
7
|
-
public static ReportingApi = "";
|
|
8
|
-
public static MessagingApi = "";
|
|
9
|
-
public static MessagingApiSocket = "";
|
|
10
|
-
public static ContentApi = "";
|
|
11
|
-
public static AskApi = "";
|
|
12
|
-
public static GoogleAnalyticsTag = "";
|
|
13
|
-
|
|
14
|
-
static ContentRoot = "";
|
|
15
|
-
static B1Root = "";
|
|
16
|
-
static B1AdminRoot = "";
|
|
17
|
-
static LessonsRoot = "";
|
|
18
|
-
|
|
19
|
-
static init = (stage: string) => {
|
|
20
|
-
switch (stage) {
|
|
21
|
-
case "demo": CommonEnvironmentHelper.initDemo(); break;
|
|
22
|
-
case "staging": CommonEnvironmentHelper.initStaging(); break;
|
|
23
|
-
case "prod": CommonEnvironmentHelper.initProd(); break;
|
|
24
|
-
default: CommonEnvironmentHelper.initDev(); break;
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
static initDev = () => {
|
|
29
|
-
this.initStaging(); //Use staging values for anything not provided
|
|
30
|
-
CommonEnvironmentHelper.AttendanceApi = process.env.REACT_APP_ATTENDANCE_API || process.env.NEXT_PUBLIC_ATTENDANCE_API || CommonEnvironmentHelper.AttendanceApi;
|
|
31
|
-
CommonEnvironmentHelper.DoingApi = process.env.REACT_APP_DOING_API || process.env.NEXT_PUBLIC_DOING_API || CommonEnvironmentHelper.DoingApi;
|
|
32
|
-
CommonEnvironmentHelper.GivingApi = process.env.REACT_APP_GIVING_API || process.env.NEXT_PUBLIC_GIVING_API || CommonEnvironmentHelper.GivingApi;
|
|
33
|
-
CommonEnvironmentHelper.MembershipApi = process.env.REACT_APP_MEMBERSHIP_API || process.env.NEXT_PUBLIC_MEMBERSHIP_API || CommonEnvironmentHelper.MembershipApi;
|
|
34
|
-
CommonEnvironmentHelper.ReportingApi = process.env.REACT_APP_REPORTING_API || process.env.NEXT_PUBLIC_REPORTING_API || CommonEnvironmentHelper.ReportingApi;
|
|
35
|
-
CommonEnvironmentHelper.MessagingApi = process.env.REACT_APP_MESSAGING_API || process.env.NEXT_PUBLIC_MESSAGING_API || CommonEnvironmentHelper.MessagingApi;
|
|
36
|
-
CommonEnvironmentHelper.MessagingApiSocket = process.env.REACT_APP_MESSAGING_API_SOCKET || process.env.NEXT_PUBLIC_MESSAGING_API_SOCKET || CommonEnvironmentHelper.MessagingApiSocket;
|
|
37
|
-
CommonEnvironmentHelper.ContentApi = process.env.REACT_APP_CONTENT_API || process.env.NEXT_PUBLIC_CONTENT_API || CommonEnvironmentHelper.ContentApi;
|
|
38
|
-
CommonEnvironmentHelper.AskApi = process.env.REACT_APP_ASK_API || process.env.NEXT_PUBLIC_ASK_API || CommonEnvironmentHelper.AskApi;
|
|
39
|
-
CommonEnvironmentHelper.GoogleAnalyticsTag = process.env.REACT_APP_GOOGLE_ANALYTICS || process.env.NEXT_PUBLIC_GOOGLE_ANALYTICS || CommonEnvironmentHelper.GoogleAnalyticsTag;
|
|
40
|
-
|
|
41
|
-
CommonEnvironmentHelper.ContentRoot = process.env.REACT_APP_CONTENT_ROOT || process.env.NEXT_PUBLIC_CONTENT_ROOT || CommonEnvironmentHelper.ContentRoot;
|
|
42
|
-
CommonEnvironmentHelper.B1Root = process.env.REACT_APP_B1_ROOT || process.env.NEXT_PUBLIC_B1_ROOT || CommonEnvironmentHelper.B1Root;
|
|
43
|
-
CommonEnvironmentHelper.B1AdminRoot = process.env.REACT_APP_B1ADMIN_ROOT || process.env.NEXT_PUBLIC_B1ADMIN_ROOT || CommonEnvironmentHelper.B1AdminRoot;
|
|
44
|
-
CommonEnvironmentHelper.LessonsRoot = process.env.REACT_APP_LESSONS_ROOT || process.env.NEXT_PUBLIC_LESSONS_ROOT || CommonEnvironmentHelper.LessonsRoot;
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
//NOTE: None of these values are secret.
|
|
48
|
-
static initDemo = () => {
|
|
49
|
-
CommonEnvironmentHelper.AttendanceApi = "https://api.demo.churchapps.org/attendance";
|
|
50
|
-
CommonEnvironmentHelper.DoingApi = "https://api.demo.churchapps.org/doing";
|
|
51
|
-
CommonEnvironmentHelper.GivingApi = "https://api.demo.churchapps.org/giving";
|
|
52
|
-
CommonEnvironmentHelper.MembershipApi = "https://api.demo.churchapps.org/membership";
|
|
53
|
-
CommonEnvironmentHelper.ReportingApi = "https://api.demo.churchapps.org/reporting";
|
|
54
|
-
CommonEnvironmentHelper.MessagingApi = "https://api.demo.churchapps.org/messaging";
|
|
55
|
-
CommonEnvironmentHelper.MessagingApiSocket = "wss://socket.demo.churchapps.org";
|
|
56
|
-
CommonEnvironmentHelper.ContentApi = "https://api.demo.churchapps.org/content";
|
|
57
|
-
CommonEnvironmentHelper.AskApi = "https://askapi.demo.churchapps.org";
|
|
58
|
-
CommonEnvironmentHelper.GoogleAnalyticsTag = "";
|
|
59
|
-
|
|
60
|
-
CommonEnvironmentHelper.ContentRoot = "https://democontent.churchapps.org";
|
|
61
|
-
CommonEnvironmentHelper.B1Root = "https://{key}.demo.b1.church";
|
|
62
|
-
CommonEnvironmentHelper.B1AdminRoot = "https://demo.b1.church";
|
|
63
|
-
CommonEnvironmentHelper.LessonsRoot = "https://demo.lessons.church";
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
//NOTE: None of these values are secret.
|
|
67
|
-
static initStaging = () => {
|
|
68
|
-
CommonEnvironmentHelper.AttendanceApi = "https://api.staging.churchapps.org/attendance";
|
|
69
|
-
CommonEnvironmentHelper.DoingApi = "https://api.staging.churchapps.org/doing";
|
|
70
|
-
CommonEnvironmentHelper.GivingApi = "https://api.staging.churchapps.org/giving";
|
|
71
|
-
CommonEnvironmentHelper.MembershipApi = "https://api.staging.churchapps.org/membership";
|
|
72
|
-
CommonEnvironmentHelper.ReportingApi = "https://api.staging.churchapps.org/reporting";
|
|
73
|
-
CommonEnvironmentHelper.MessagingApi = "https://api.staging.churchapps.org/messaging";
|
|
74
|
-
CommonEnvironmentHelper.MessagingApiSocket = "wss://socket.staging.churchapps.org";
|
|
75
|
-
CommonEnvironmentHelper.ContentApi = "https://api.staging.churchapps.org/content";
|
|
76
|
-
CommonEnvironmentHelper.AskApi = "https://askapi.staging.churchapps.org";
|
|
77
|
-
CommonEnvironmentHelper.GoogleAnalyticsTag = "";
|
|
78
|
-
|
|
79
|
-
CommonEnvironmentHelper.ContentRoot = "https://content.staging.churchapps.org";
|
|
80
|
-
CommonEnvironmentHelper.B1Root = "https://{key}.staging.b1.church";
|
|
81
|
-
CommonEnvironmentHelper.B1AdminRoot = "https://admin.staging.b1.church";
|
|
82
|
-
CommonEnvironmentHelper.LessonsRoot = "https://staging.lessons.church";
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
//NOTE: None of these values are secret.
|
|
86
|
-
static initProd = () => {
|
|
87
|
-
CommonEnvironmentHelper.AttendanceApi = "https://api.churchapps.org/attendance";
|
|
88
|
-
CommonEnvironmentHelper.DoingApi = "https://api.churchapps.org/doing";
|
|
89
|
-
CommonEnvironmentHelper.GivingApi = "https://api.churchapps.org/giving";
|
|
90
|
-
CommonEnvironmentHelper.MembershipApi = "https://api.churchapps.org/membership";
|
|
91
|
-
CommonEnvironmentHelper.ReportingApi = "https://api.churchapps.org/reporting";
|
|
92
|
-
CommonEnvironmentHelper.MessagingApi = "https://api.churchapps.org/messaging";
|
|
93
|
-
CommonEnvironmentHelper.MessagingApiSocket = "wss://socket.churchapps.org";
|
|
94
|
-
CommonEnvironmentHelper.ContentApi = "https://api.churchapps.org/content";
|
|
95
|
-
CommonEnvironmentHelper.AskApi = "https://askapi.churchapps.org";
|
|
96
|
-
|
|
97
|
-
CommonEnvironmentHelper.ContentRoot = "https://content.churchapps.org";
|
|
98
|
-
CommonEnvironmentHelper.B1Root = "https://{key}.b1.church";
|
|
99
|
-
CommonEnvironmentHelper.B1AdminRoot = "https://admin.b1.church";
|
|
100
|
-
CommonEnvironmentHelper.LessonsRoot = "https://lessons.church";
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
|
package/src/CurrencyHelper.ts
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
export class CurrencyHelper {
|
|
2
|
-
static formatCurrency(amount: number) {
|
|
3
|
-
const formatter = new Intl.NumberFormat("en-US", {
|
|
4
|
-
style: "currency",
|
|
5
|
-
currency: "USD",
|
|
6
|
-
minimumFractionDigits: 2
|
|
7
|
-
});
|
|
8
|
-
return formatter.format(amount);
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
static formatCurrencyWithLocale(amount: number, currency: string = "USD") {
|
|
12
|
-
const normalizedCurrency = currency.toUpperCase();
|
|
13
|
-
const locale = this.getLocaleForCurrency(normalizedCurrency);
|
|
14
|
-
|
|
15
|
-
const formatter = new Intl.NumberFormat(locale, {
|
|
16
|
-
style: "currency",
|
|
17
|
-
currency: normalizedCurrency,
|
|
18
|
-
minimumFractionDigits: 2
|
|
19
|
-
});
|
|
20
|
-
return formatter.format(amount);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
static getCurrencySymbol(currency?: string) {
|
|
24
|
-
const normalizedCurrency = currency?.toLowerCase() || "usd";
|
|
25
|
-
const stripeCurrencyFees: any = {
|
|
26
|
-
usd: { percent: 2.9, fixed: 0.3, symbol: "$" },
|
|
27
|
-
eur: { percent: 2.9, fixed: 0.25, symbol: "€" },
|
|
28
|
-
gbp: { percent: 2.9, fixed: 0.2, symbol: "£" },
|
|
29
|
-
cad: { percent: 2.9, fixed: 0.3, symbol: "$" },
|
|
30
|
-
aud: { percent: 2.9, fixed: 0.3, symbol: "$" },
|
|
31
|
-
inr: { percent: 2.9, fixed: 3.0, symbol: "₹" },
|
|
32
|
-
jpy: { percent: 2.9, fixed: 30.0, symbol: "¥" },
|
|
33
|
-
sgd: { percent: 2.9, fixed: 0.5, symbol: "S$" },
|
|
34
|
-
hkd: { percent: 2.9, fixed: 2.35, symbol: "元" },
|
|
35
|
-
sek: { percent: 2.9, fixed: 2.5, symbol: "kr" },
|
|
36
|
-
nok: { percent: 2.9, fixed: 2.0, symbol: "kr" },
|
|
37
|
-
dkk: { percent: 2.9, fixed: 1.8, symbol: "kr" },
|
|
38
|
-
chf: { percent: 2.9, fixed: 0.3, symbol: "CHF" },
|
|
39
|
-
mxn: { percent: 2.9, fixed: 3.0, symbol: "MXN" },
|
|
40
|
-
brl: { percent: 3.9, fixed: 0.5, symbol: "R$" }
|
|
41
|
-
};
|
|
42
|
-
return stripeCurrencyFees[normalizedCurrency]?.symbol || "$";
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
private static getLocaleForCurrency(currency: string): string {
|
|
46
|
-
const currencyLocaleMap: { [key: string]: string } = {
|
|
47
|
-
USD: "en-US",
|
|
48
|
-
EUR: "en-GB",
|
|
49
|
-
GBP: "en-GB",
|
|
50
|
-
CAD: "en-CA",
|
|
51
|
-
AUD: "en-AU",
|
|
52
|
-
INR: "en-IN",
|
|
53
|
-
JPY: "ja-JP",
|
|
54
|
-
SGD: "en-SG",
|
|
55
|
-
HKD: "en-HK",
|
|
56
|
-
SEK: "sv-SE",
|
|
57
|
-
NOK: "nb-NO",
|
|
58
|
-
DKK: "da-DK",
|
|
59
|
-
CHF: "de-CH",
|
|
60
|
-
MXN: "es-MX",
|
|
61
|
-
BRL: "pt-BR"
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
return currencyLocaleMap[currency] || "en-US";
|
|
65
|
-
}
|
|
66
|
-
}
|
package/src/DateHelper.ts
DELETED
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
import dayjs from "dayjs";
|
|
2
|
-
import utc from "dayjs/plugin/utc.js";
|
|
3
|
-
import customParseFormat from "dayjs/plugin/customParseFormat.js";
|
|
4
|
-
|
|
5
|
-
// Extend dayjs with plugins
|
|
6
|
-
dayjs.extend(utc);
|
|
7
|
-
dayjs.extend(customParseFormat);
|
|
8
|
-
|
|
9
|
-
export class DateHelper {
|
|
10
|
-
|
|
11
|
-
//Fixes timezone issues when you just need the date.
|
|
12
|
-
static toDate(input: any) {
|
|
13
|
-
const str = input.toString();
|
|
14
|
-
// Check if it's a YYYY-MM-DD format (HTML5 date input)
|
|
15
|
-
const dateOnlyMatch = str.match(/^(\d{4})-(\d{2})-(\d{2})$/);
|
|
16
|
-
if (dateOnlyMatch) {
|
|
17
|
-
// Parse as local date at noon to avoid timezone issues
|
|
18
|
-
const [, year, month, day] = dateOnlyMatch;
|
|
19
|
-
return new Date(parseInt(year), parseInt(month) - 1, parseInt(day), 12, 0, 0);
|
|
20
|
-
}
|
|
21
|
-
// For other formats, use existing behavior
|
|
22
|
-
return new Date(Date.parse(str.replace("Z", "")));
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
static toDateTime(input: any) {
|
|
26
|
-
return new Date(Date.parse(input.toString()));
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
//obsolete. Do not use
|
|
30
|
-
static convertToDate(input: any) {
|
|
31
|
-
return this.toDateTime(input);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
static addDays(date: Date, days: number) {
|
|
35
|
-
const result = new Date(date.getTime());
|
|
36
|
-
result.setDate(result.getDate() + days);
|
|
37
|
-
return result;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
static prettyDate(date: Date) {
|
|
41
|
-
if (date === undefined || date === null) return "";
|
|
42
|
-
return this.formatDateTime(date, "MMM d, yyyy");
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
static prettyDateTime(date: Date) {
|
|
46
|
-
if (date === undefined || date === null) return "";
|
|
47
|
-
return this.formatDateTime(date, "MMM d, yyyy h:mm a");
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
static prettyTime(date: Date) {
|
|
51
|
-
if (date === undefined || date === null) return "";
|
|
52
|
-
return this.formatDateTime(date, "h:mm a");
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
static getLastSunday() {
|
|
56
|
-
const result = new Date();
|
|
57
|
-
while (result.getDay() !== 0) result.setDate(result.getDate() - 1);
|
|
58
|
-
return result;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
static getNextSunday() {
|
|
62
|
-
const result = this.getLastSunday();
|
|
63
|
-
result.setDate(result.getDate() + 7);
|
|
64
|
-
return result;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
static getWeekSunday(year: number, week: number) {
|
|
68
|
-
const result = new Date(year, 0, 1);
|
|
69
|
-
while (result.getDay() !== 0) result.setDate(result.getDate() + 1);
|
|
70
|
-
result.setDate(result.getDate() + ((week - 1) * 7));
|
|
71
|
-
return result;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
static formatHtml5Date(date: Date | string | null | undefined): string {
|
|
75
|
-
if (!date) return "";
|
|
76
|
-
|
|
77
|
-
// If already a YYYY-MM-DD string, return as-is
|
|
78
|
-
if (typeof date === "string" && /^\d{4}-\d{2}-\d{2}$/.test(date)) return date;
|
|
79
|
-
|
|
80
|
-
// If ISO string, extract date portion (ignore timezone)
|
|
81
|
-
if (typeof date === "string") {
|
|
82
|
-
const match = date.match(/^(\d{4}-\d{2}-\d{2})/);
|
|
83
|
-
if (match) return match[1];
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// For Date objects, use LOCAL year/month/day (not UTC)
|
|
87
|
-
const d = date instanceof Date ? date : new Date(date);
|
|
88
|
-
if (isNaN(d.getTime())) return "";
|
|
89
|
-
|
|
90
|
-
const year = d.getFullYear();
|
|
91
|
-
const month = String(d.getMonth() + 1).padStart(2, "0");
|
|
92
|
-
const day = String(d.getDate()).padStart(2, "0");
|
|
93
|
-
return `${year}-${month}-${day}`;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// For DATE-only fields - preserves calendar date without timezone conversion
|
|
97
|
-
static toMysqlDateOnly(date: Date | string | null | undefined): string | null {
|
|
98
|
-
if (date === null || date === undefined) return null;
|
|
99
|
-
|
|
100
|
-
if (typeof date === "string") {
|
|
101
|
-
const match = date.match(/^(\d{4}-\d{2}-\d{2})/);
|
|
102
|
-
return match ? match[1] : null;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
const year = date.getFullYear();
|
|
106
|
-
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
107
|
-
const day = String(date.getDate()).padStart(2, "0");
|
|
108
|
-
return `${year}-${month}-${day}`;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
static formatHtml5Time(time: Date): string {
|
|
112
|
-
if (time === undefined || time === null) return "";
|
|
113
|
-
const h = time.getHours();
|
|
114
|
-
const m = time.getMinutes();
|
|
115
|
-
const s = time.getSeconds();
|
|
116
|
-
return `${h < 10 ? ("0" + h) : h}:${m < 10 ? ("0" + m) : m}:${s < 10 ? ("0" + s) : s}`;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
static formatHtml5DateTime(date: Date): string {
|
|
120
|
-
if (date === undefined || date === null) return "";
|
|
121
|
-
else {
|
|
122
|
-
return this.formatDateTime(date, "yyyy-MM-dd") + "T" + this.formatDateTime(date, "HH:mm");
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
static getDisplayDuration(d: Date): string {
|
|
127
|
-
const seconds = Math.round((new Date().getTime() - d.getTime()) / 1000);
|
|
128
|
-
if (seconds > 86400) {
|
|
129
|
-
const days = Math.floor(seconds / 86400);
|
|
130
|
-
return (days === 1) ? "1d" : days.toString() + "d";
|
|
131
|
-
} else if (seconds > 3600) {
|
|
132
|
-
const hours = Math.floor(seconds / 3600);
|
|
133
|
-
return (hours === 1) ? "1h" : hours.toString() + "h";
|
|
134
|
-
} else if (seconds > 60) {
|
|
135
|
-
const minutes = Math.floor(seconds / 60);
|
|
136
|
-
return (minutes === 1) ? "1m" : minutes.toString() + "m";
|
|
137
|
-
} else return (seconds === 1) ? "1s" : Math.floor(seconds).toString() + "s";
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
static getShortDate(d: Date): string {
|
|
141
|
-
return (d.getMonth() + 1).toString() + "/" + (d.getDate()).toString() + "/" + d.getFullYear().toString();
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
static convertDatePickerFormat(d: Date): Date {
|
|
145
|
-
const date = this.formatHtml5Date(d).split("-");
|
|
146
|
-
if (date.length === 3) return new Date(`${date[1]}-${date[2]}-${date[0]}`);
|
|
147
|
-
return new Date();
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
private static formatDateTime(date: Date, format: string) {
|
|
151
|
-
try {
|
|
152
|
-
// Convert date-fns format to dayjs format
|
|
153
|
-
const dayjsFormat = format
|
|
154
|
-
.replace(/yyyy/g, "YYYY")
|
|
155
|
-
.replace(/yy/g, "YY")
|
|
156
|
-
.replace(/d/g, "D")
|
|
157
|
-
.replace(/DD/g, "DD")
|
|
158
|
-
.replace(/a/g, "A");
|
|
159
|
-
|
|
160
|
-
return dayjs(date).format(dayjsFormat);
|
|
161
|
-
} catch { return ""; }
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
public static toMysqlDate(d: Date) {
|
|
165
|
-
if (d === null || d === undefined) {
|
|
166
|
-
return undefined;
|
|
167
|
-
}
|
|
168
|
-
return dayjs(d).format("YYYY-MM-DD HH:mm:ss");
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
public static subtractHoursFromNow(hour: number) {
|
|
172
|
-
const now = new Date();
|
|
173
|
-
return new Date(now.setHours(now.getHours() - hour));
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
public static toUTCDate(d: Date) {
|
|
177
|
-
return dayjs(d).utc().format("YYYY-MM-DD HH:mm:ss");
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
}
|
package/src/DonationHelper.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
export class DonationHelper {
|
|
2
|
-
|
|
3
|
-
static getInterval(intervalName:string) {
|
|
4
|
-
let intervalCount = 1;
|
|
5
|
-
let intervalType = "month";
|
|
6
|
-
const parts = intervalName.split("_");
|
|
7
|
-
if (parts.length === 2) {
|
|
8
|
-
switch (parts[0]) {
|
|
9
|
-
case "two": intervalCount = 2; break;
|
|
10
|
-
case "three": intervalCount = 3; break;
|
|
11
|
-
}
|
|
12
|
-
intervalType = parts[1];
|
|
13
|
-
}
|
|
14
|
-
const result = { interval_count: intervalCount, interval: intervalType };
|
|
15
|
-
return result;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
static getIntervalKeyName(intervalCount: number, intervalType: string) {
|
|
19
|
-
let firstPart = "one";
|
|
20
|
-
if (intervalCount === 2) firstPart = "two";
|
|
21
|
-
else if (intervalCount === 3) firstPart = "three";
|
|
22
|
-
return firstPart + "_" + intervalType;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
}
|
package/src/ErrorHelper.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { ErrorLogInterface, ErrorAppDataInterface } from "./interfaces/Error.js";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export class ErrorHelper {
|
|
5
|
-
|
|
6
|
-
static getAppData: () => { churchId: string, userId: string, originUrl: string, application: string };
|
|
7
|
-
static customErrorHandler: (errorLog: ErrorLogInterface) => void;
|
|
8
|
-
|
|
9
|
-
static init = (getAppData: () => ErrorAppDataInterface, customErrorHandler: (errorLog: ErrorLogInterface) => void) => {
|
|
10
|
-
ErrorHelper.getAppData = getAppData;
|
|
11
|
-
ErrorHelper.customErrorHandler = customErrorHandler;
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
static logError = (errorType: string, message: string, details: string) => {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
if (this.getAppData) {
|
|
18
|
-
const data = this.getAppData();
|
|
19
|
-
const log: ErrorLogInterface = {
|
|
20
|
-
application: data.application,
|
|
21
|
-
errorTime: new Date(),
|
|
22
|
-
userId: data.userId,
|
|
23
|
-
churchId: data.churchId,
|
|
24
|
-
originUrl: data.originUrl,
|
|
25
|
-
errorType: errorType,
|
|
26
|
-
message: message,
|
|
27
|
-
details: details
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
if (log.errorType === "401" && log.message.indexOf("/users/login") > -1) return;
|
|
31
|
-
//temporarily disabled error logging
|
|
32
|
-
//ApiHelper.postAnonymous("/errors", [log], "MembershipApi");
|
|
33
|
-
if (ErrorHelper.customErrorHandler) ErrorHelper.customErrorHandler(log);
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
package/src/EventHelper.ts
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
import { EventInterface } from "./interfaces/index.js";
|
|
2
|
-
|
|
3
|
-
// Lazy initialization to handle both bundlers and Node.js ESM
|
|
4
|
-
let RRule: any = null;
|
|
5
|
-
let initPromise: Promise<void> | null = null;
|
|
6
|
-
|
|
7
|
-
const ensureRRule = () => {
|
|
8
|
-
if (RRule) return Promise.resolve();
|
|
9
|
-
if (!initPromise) {
|
|
10
|
-
initPromise = import("rrule").then((mod) => {
|
|
11
|
-
RRule = (mod as any).RRule ?? (mod as any).default?.RRule ?? mod;
|
|
12
|
-
});
|
|
13
|
-
}
|
|
14
|
-
return initPromise;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
// Synchronous getter for RRule - throws if not initialized
|
|
18
|
-
const getRRule = () => {
|
|
19
|
-
if (!RRule) {
|
|
20
|
-
throw new Error("EventHelper: RRule not initialized. Ensure ensureRRule() is called first.");
|
|
21
|
-
}
|
|
22
|
-
return RRule;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
// Initialize on first use for bundlers (they process the dynamic import statically)
|
|
26
|
-
// The promise is created immediately to start loading
|
|
27
|
-
initPromise = import("rrule").then((mod) => {
|
|
28
|
-
RRule = (mod as any).RRule ?? (mod as any).default?.RRule ?? mod;
|
|
29
|
-
}).catch(() => {
|
|
30
|
-
// rrule not available - EventHelper methods will fail gracefully
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
// Define ParsedOptions as any since RRule is dynamically loaded
|
|
34
|
-
type ParsedOptions = any;
|
|
35
|
-
|
|
36
|
-
export class EventHelper {
|
|
37
|
-
|
|
38
|
-
static getRange = (event:EventInterface, startDate:Date, endDate:Date) => {
|
|
39
|
-
const start = new Date(event.start);
|
|
40
|
-
const rrule = EventHelper.getFullRRule(event);
|
|
41
|
-
|
|
42
|
-
const dates = rrule.between(startDate, endDate);
|
|
43
|
-
|
|
44
|
-
dates.forEach((d: Date) => {
|
|
45
|
-
d.setHours(start.getHours());
|
|
46
|
-
d.setMinutes(start.getMinutes());
|
|
47
|
-
d.setSeconds(start.getSeconds());
|
|
48
|
-
});
|
|
49
|
-
return dates;
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
static getFullRRule = (event:EventInterface) => {
|
|
53
|
-
const RR = getRRule();
|
|
54
|
-
const rrule = RR.fromString(event.recurrenceRule);
|
|
55
|
-
rrule.options.dtstart = new Date(event.start);
|
|
56
|
-
return rrule;
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
static removeExcludeDates = (events:EventInterface[]) => {
|
|
60
|
-
for (let i = events.length - 1; i >= 0; i--) {
|
|
61
|
-
if (events[i].exceptionDates?.length > 0) {
|
|
62
|
-
const parsedDates = events[i].exceptionDates.map((d: string | Date)=>new Date(d).toISOString());
|
|
63
|
-
if (parsedDates.indexOf(events[i].start.toISOString()) > -1) events.splice(i, 1);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
static getPartialRRuleString = (options:ParsedOptions) => {
|
|
69
|
-
const RR = getRRule();
|
|
70
|
-
const parts = new RR(options).toString().split("RRULE:");
|
|
71
|
-
const result = parts.length === 2 ? parts[1] : "";
|
|
72
|
-
return result;
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
static cleanRule = (options:ParsedOptions) => {
|
|
76
|
-
options.byhour = undefined;
|
|
77
|
-
options.byminute = undefined;
|
|
78
|
-
options.bysecond = undefined;
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
// Export for consumers who need to ensure initialization
|
|
82
|
-
static ensureInitialized = ensureRRule;
|
|
83
|
-
}
|
package/src/FileHelper.ts
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
export class FileHelper {
|
|
2
|
-
|
|
3
|
-
static postPresignedFile = (presigned: any, uploadedFile: File, progressCallback: (percent: number) => void) => {
|
|
4
|
-
const formData = new FormData();
|
|
5
|
-
formData.append("key", presigned.key);
|
|
6
|
-
formData.append("acl", "public-read");
|
|
7
|
-
formData.append("Content-Type", uploadedFile.type);
|
|
8
|
-
for (const property in presigned.fields) formData.append(property, presigned.fields[property]);
|
|
9
|
-
formData.append("file", uploadedFile);
|
|
10
|
-
|
|
11
|
-
// Use XMLHttpRequest for upload progress tracking since fetch doesn't support it natively
|
|
12
|
-
return new Promise((resolve, reject) => {
|
|
13
|
-
const xhr = new XMLHttpRequest();
|
|
14
|
-
|
|
15
|
-
xhr.upload.addEventListener("progress", (event) => {
|
|
16
|
-
if (event.lengthComputable) {
|
|
17
|
-
const percent = Math.round((event.loaded / event.total) * 100);
|
|
18
|
-
progressCallback(percent);
|
|
19
|
-
}
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
xhr.addEventListener("load", () => {
|
|
23
|
-
if (xhr.status >= 200 && xhr.status < 300) {
|
|
24
|
-
resolve({
|
|
25
|
-
status: xhr.status,
|
|
26
|
-
statusText: xhr.statusText,
|
|
27
|
-
data: xhr.responseText
|
|
28
|
-
});
|
|
29
|
-
} else {
|
|
30
|
-
reject(new Error(`HTTP Error: ${xhr.status} ${xhr.statusText}`));
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
xhr.addEventListener("error", () => {
|
|
35
|
-
reject(new Error("Network error occurred"));
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
xhr.open("POST", presigned.url);
|
|
39
|
-
xhr.send(formData);
|
|
40
|
-
});
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
static dataURLtoBlob(dataurl: string) {
|
|
44
|
-
const arr = dataurl.split(",");
|
|
45
|
-
if (arr.length < 2) throw new Error("Invalid data URL format");
|
|
46
|
-
const mimeMatch = arr[0].match(/:(.*?);/);
|
|
47
|
-
if (!mimeMatch) throw new Error("Invalid MIME type in data URL");
|
|
48
|
-
const mime = mimeMatch[1];
|
|
49
|
-
const bstr = atob(arr[1]);
|
|
50
|
-
let n = bstr.length;
|
|
51
|
-
const u8arr = new Uint8Array(n);
|
|
52
|
-
while (n--) {
|
|
53
|
-
u8arr[n] = bstr.charCodeAt(n);
|
|
54
|
-
}
|
|
55
|
-
return new Blob([u8arr], { type: mime });
|
|
56
|
-
}
|
|
57
|
-
}
|
package/src/PersonHelper.ts
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import { PersonInterface, ContactInfoInterface } from "./interfaces/index.js";
|
|
2
|
-
import { CommonEnvironmentHelper } from "./CommonEnvironmentHelper.js";
|
|
3
|
-
|
|
4
|
-
export class PersonHelper {
|
|
5
|
-
|
|
6
|
-
public static getPhotoPath(churchId: string, person: any) {
|
|
7
|
-
if (!person.photoUpdated) {
|
|
8
|
-
if (person.id?.startsWith("PER0000")) return "https://app.staging.b1.church/images/demo/avatars/" + person.id + ".svg";
|
|
9
|
-
else return "";
|
|
10
|
-
} else return "/" + churchId + "/membership/people/" + person.id + ".png?dt=" + new Date(person.photoUpdated).getTime().toString();
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
static getPhotoUrl(person: PersonInterface) {
|
|
14
|
-
if (!person?.photo) return "/images/sample-profile.png";
|
|
15
|
-
else {
|
|
16
|
-
return (person?.photo?.startsWith("data:image/png;base64,") || person.photo?.indexOf("://") > -1)
|
|
17
|
-
? person.photo
|
|
18
|
-
: CommonEnvironmentHelper.ContentRoot + person.photo;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
static getAge(birthdate: Date): string {
|
|
23
|
-
if (birthdate !== undefined && birthdate !== null) {
|
|
24
|
-
const ageDifMs = Date.now() - new Date(birthdate).getTime();
|
|
25
|
-
const ageDate = new Date(ageDifMs);
|
|
26
|
-
const years = Math.abs(ageDate.getUTCFullYear() - 1970);
|
|
27
|
-
return years + " years";
|
|
28
|
-
} else return "";
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
public static getDisplayNameFromPerson(person: any) {
|
|
32
|
-
if (person?.name?.nick !== null && person?.name?.nick !== "" && person?.name?.nick !== undefined) return person.name.first + " \"" + person.name.nick + "\" " + person.name.last;
|
|
33
|
-
else return person.name.first + " " + person.name.last;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
static getDisplayName(firstName: string, lastName: string, nickName: string): string {
|
|
37
|
-
if (nickName !== undefined && nickName !== null && nickName.length > 0) return firstName + ' "' + nickName + '" ' + lastName;
|
|
38
|
-
else return firstName + " " + lastName;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
public static getBirthMonth(birthdate: Date): number {
|
|
42
|
-
if (birthdate) return new Date(birthdate).getMonth() + 1;
|
|
43
|
-
else return -1;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
public static compareAddress(address1: ContactInfoInterface, address2: ContactInfoInterface): boolean {
|
|
47
|
-
const displayAddress1: string = this.addressToString(address1).trim();
|
|
48
|
-
const displayAddress2: string = this.addressToString(address2).trim();
|
|
49
|
-
|
|
50
|
-
if (displayAddress1 !== displayAddress2) {
|
|
51
|
-
return true;
|
|
52
|
-
}
|
|
53
|
-
return false;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
public static addressToString(address: ContactInfoInterface): string {
|
|
57
|
-
return `${address.address1 || ""} ${address.address2 || ""} ${address.city || ""}${(address.city && address.state) ? "," : ""} ${address.state || ""} ${address.zip || ""}`;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
public static changeOnlyAddress(contactInfo1: ContactInfoInterface, contactInfo2: ContactInfoInterface): ContactInfoInterface {
|
|
61
|
-
const updatedAddress: ContactInfoInterface = {
|
|
62
|
-
...contactInfo1,
|
|
63
|
-
address1: contactInfo2.address1,
|
|
64
|
-
address2: contactInfo2.address2,
|
|
65
|
-
city: contactInfo2.city,
|
|
66
|
-
state: contactInfo2.state,
|
|
67
|
-
zip: contactInfo2.zip
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
return updatedAddress;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
public static checkAddressAvailabilty(person: PersonInterface): boolean {
|
|
74
|
-
const addressString: string = this.addressToString(person.contactInfo).trim();
|
|
75
|
-
if (addressString !== "") {
|
|
76
|
-
return true;
|
|
77
|
-
}
|
|
78
|
-
return false;
|
|
79
|
-
}
|
|
80
|
-
}
|