@churchapps/apphelper 0.6.15 → 0.6.16

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 (215) hide show
  1. package/dist/components/DisplayBox.d.ts +1 -1
  2. package/dist/components/DisplayBox.d.ts.map +1 -1
  3. package/dist/components/DisplayBox.js +2 -4
  4. package/dist/components/DisplayBox.js.map +1 -1
  5. package/dist/components/ErrorMessages.d.ts.map +1 -1
  6. package/dist/components/ErrorMessages.js +1 -1
  7. package/dist/components/ErrorMessages.js.map +1 -1
  8. package/dist/components/ExportLink.d.ts.map +1 -1
  9. package/dist/components/ExportLink.js +10 -10
  10. package/dist/components/ExportLink.js.map +1 -1
  11. package/dist/components/FloatingSupport.js.map +1 -1
  12. package/dist/components/FormCardPayment.d.ts.map +1 -1
  13. package/dist/components/FormCardPayment.js +20 -5
  14. package/dist/components/FormCardPayment.js.map +1 -1
  15. package/dist/components/FormSubmissionEdit.d.ts.map +1 -1
  16. package/dist/components/FormSubmissionEdit.js +8 -10
  17. package/dist/components/FormSubmissionEdit.js.map +1 -1
  18. package/dist/components/HelpIcon.d.ts.map +1 -1
  19. package/dist/components/HelpIcon.js.map +1 -1
  20. package/dist/components/ImageEditor.d.ts.map +1 -1
  21. package/dist/components/ImageEditor.js +10 -10
  22. package/dist/components/ImageEditor.js.map +1 -1
  23. package/dist/components/InputBox.d.ts +1 -1
  24. package/dist/components/InputBox.d.ts.map +1 -1
  25. package/dist/components/InputBox.js +4 -6
  26. package/dist/components/InputBox.js.map +1 -1
  27. package/dist/components/Loading.d.ts.map +1 -1
  28. package/dist/components/Loading.js.map +1 -1
  29. package/dist/components/PageHeader.js +14 -14
  30. package/dist/components/PersonAvatar.d.ts.map +1 -1
  31. package/dist/components/PersonAvatar.js +9 -16
  32. package/dist/components/PersonAvatar.js.map +1 -1
  33. package/dist/components/QuestionEdit.js +3 -3
  34. package/dist/components/QuestionEdit.js.map +1 -1
  35. package/dist/components/SmallButton.d.ts.map +1 -1
  36. package/dist/components/SmallButton.js +2 -1
  37. package/dist/components/SmallButton.js.map +1 -1
  38. package/dist/components/SupportModal.js.map +1 -1
  39. package/dist/components/gallery/GalleryModal.js +10 -10
  40. package/dist/components/gallery/GalleryModal.js.map +1 -1
  41. package/dist/components/gallery/StockPhotos.js +12 -12
  42. package/dist/components/gallery/StockPhotos.js.map +1 -1
  43. package/dist/components/header/Banner.d.ts.map +1 -1
  44. package/dist/components/header/Banner.js.map +1 -1
  45. package/dist/components/header/PrimaryMenu.js +4 -4
  46. package/dist/components/header/PrimaryMenu.js.map +1 -1
  47. package/dist/components/header/SecondaryMenu.d.ts.map +1 -1
  48. package/dist/components/header/SecondaryMenu.js.map +1 -1
  49. package/dist/components/header/SecondaryMenuAlt.d.ts.map +1 -1
  50. package/dist/components/header/SecondaryMenuAlt.js.map +1 -1
  51. package/dist/components/header/SiteHeader.d.ts.map +1 -1
  52. package/dist/components/header/SiteHeader.js +7 -7
  53. package/dist/components/header/SiteHeader.js.map +1 -1
  54. package/dist/components/header/SupportDrawer.js +1 -1
  55. package/dist/components/header/SupportDrawer.js.map +1 -1
  56. package/dist/components/notes/AddNote.js +14 -14
  57. package/dist/components/notes/Note.d.ts.map +1 -1
  58. package/dist/components/notes/Note.js +7 -7
  59. package/dist/components/notes/Note.js.map +1 -1
  60. package/dist/components/notes/Notes.d.ts.map +1 -1
  61. package/dist/components/notes/Notes.js +4 -4
  62. package/dist/components/notes/Notes.js.map +1 -1
  63. package/dist/components/wrapper/AppList.d.ts.map +1 -1
  64. package/dist/components/wrapper/AppList.js.map +1 -1
  65. package/dist/components/wrapper/ChurchList.js +5 -5
  66. package/dist/components/wrapper/ChurchList.js.map +1 -1
  67. package/dist/components/wrapper/NavItem.js +1 -1
  68. package/dist/components/wrapper/NavItem.js.map +1 -1
  69. package/dist/components/wrapper/NewPrivateMessage.d.ts.map +1 -1
  70. package/dist/components/wrapper/NewPrivateMessage.js +7 -6
  71. package/dist/components/wrapper/NewPrivateMessage.js.map +1 -1
  72. package/dist/components/wrapper/Notifications.d.ts.map +1 -1
  73. package/dist/components/wrapper/Notifications.js +12 -14
  74. package/dist/components/wrapper/Notifications.js.map +1 -1
  75. package/dist/components/wrapper/PrivateMessageDetails.js +10 -10
  76. package/dist/components/wrapper/PrivateMessages.d.ts.map +1 -1
  77. package/dist/components/wrapper/PrivateMessages.js +119 -123
  78. package/dist/components/wrapper/PrivateMessages.js.map +1 -1
  79. package/dist/components/wrapper/UserMenu.d.ts.map +1 -1
  80. package/dist/components/wrapper/UserMenu.js +15 -15
  81. package/dist/components/wrapper/UserMenu.js.map +1 -1
  82. package/dist/helpers/AnalyticsHelper.d.ts.map +1 -1
  83. package/dist/helpers/AnalyticsHelper.js +3 -3
  84. package/dist/helpers/AnalyticsHelper.js.map +1 -1
  85. package/dist/helpers/ArrayHelper.d.ts.map +1 -1
  86. package/dist/helpers/ArrayHelper.js.map +1 -1
  87. package/dist/helpers/CurrencyHelper.d.ts +4 -0
  88. package/dist/helpers/CurrencyHelper.d.ts.map +1 -1
  89. package/dist/helpers/CurrencyHelper.js +65 -0
  90. package/dist/helpers/CurrencyHelper.js.map +1 -1
  91. package/dist/helpers/ErrorHelper.d.ts.map +1 -1
  92. package/dist/helpers/ErrorHelper.js.map +1 -1
  93. package/dist/helpers/EventHelper.d.ts.map +1 -1
  94. package/dist/helpers/EventHelper.js +1 -1
  95. package/dist/helpers/EventHelper.js.map +1 -1
  96. package/dist/helpers/FileHelper.d.ts.map +1 -1
  97. package/dist/helpers/FileHelper.js +3 -1
  98. package/dist/helpers/FileHelper.js.map +1 -1
  99. package/dist/helpers/Locale.d.ts.map +1 -1
  100. package/dist/helpers/Locale.js +10 -16
  101. package/dist/helpers/Locale.js.map +1 -1
  102. package/dist/helpers/NotificationService.js +4 -4
  103. package/dist/helpers/PersonHelper.d.ts.map +1 -1
  104. package/dist/helpers/PersonHelper.js +5 -4
  105. package/dist/helpers/PersonHelper.js.map +1 -1
  106. package/dist/helpers/SlugHelper.d.ts.map +1 -1
  107. package/dist/helpers/SlugHelper.js +5 -3
  108. package/dist/helpers/SlugHelper.js.map +1 -1
  109. package/dist/helpers/SocketHelper.d.ts.map +1 -1
  110. package/dist/helpers/SocketHelper.js +5 -10
  111. package/dist/helpers/SocketHelper.js.map +1 -1
  112. package/dist/helpers/UniqueIdHelper.d.ts.map +1 -1
  113. package/dist/helpers/UniqueIdHelper.js +132 -7
  114. package/dist/helpers/UniqueIdHelper.js.map +1 -1
  115. package/dist/helpers/UserHelper.d.ts.map +1 -1
  116. package/dist/helpers/UserHelper.js +2 -2
  117. package/dist/helpers/UserHelper.js.map +1 -1
  118. package/dist/hooks/useMountedState.d.ts.map +1 -1
  119. package/dist/hooks/useMountedState.js +1 -1
  120. package/dist/hooks/useMountedState.js.map +1 -1
  121. package/dist/hooks/useNotifications.d.ts +2 -2
  122. package/dist/hooks/useNotifications.js +5 -5
  123. package/dist/public/locales/de.json +15 -7
  124. package/dist/public/locales/es.json +193 -190
  125. package/dist/public/locales/fr.json +15 -7
  126. package/dist/public/locales/hi.json +15 -7
  127. package/dist/public/locales/it.json +15 -7
  128. package/dist/public/locales/ko.json +15 -7
  129. package/dist/public/locales/no.json +15 -7
  130. package/dist/public/locales/pt.json +15 -7
  131. package/dist/public/locales/ru.json +15 -7
  132. package/dist/public/locales/tl.json +15 -7
  133. package/dist/public/locales/zh.json +15 -7
  134. package/package.json +106 -73
  135. package/dist/helpers/DateHelper.d.ts +0 -18
  136. package/dist/helpers/DateHelper.d.ts.map +0 -1
  137. package/dist/helpers/DateHelper.js +0 -113
  138. package/dist/helpers/DateHelper.js.map +0 -1
  139. package/public/css/cropper.css +0 -309
  140. package/public/css/styles.css +0 -112
  141. package/public/locales/de.json +0 -273
  142. package/public/locales/en.json +0 -281
  143. package/public/locales/es.json +0 -278
  144. package/public/locales/fr.json +0 -273
  145. package/public/locales/hi.json +0 -273
  146. package/public/locales/it.json +0 -273
  147. package/public/locales/ko.json +0 -273
  148. package/public/locales/no.json +0 -273
  149. package/public/locales/pt.json +0 -273
  150. package/public/locales/ru.json +0 -273
  151. package/public/locales/tl.json +0 -273
  152. package/public/locales/zh.json +0 -273
  153. package/src/components/DisplayBox.tsx +0 -83
  154. package/src/components/ErrorMessages.tsx +0 -28
  155. package/src/components/ExportLink.tsx +0 -81
  156. package/src/components/FloatingSupport.tsx +0 -18
  157. package/src/components/FormCardPayment.tsx +0 -184
  158. package/src/components/FormSubmissionEdit.tsx +0 -168
  159. package/src/components/HelpIcon.tsx +0 -12
  160. package/src/components/ImageEditor.tsx +0 -167
  161. package/src/components/InputBox.tsx +0 -97
  162. package/src/components/Loading.tsx +0 -31
  163. package/src/components/PageHeader.tsx +0 -111
  164. package/src/components/PersonAvatar.tsx +0 -78
  165. package/src/components/QuestionEdit.tsx +0 -99
  166. package/src/components/SmallButton.tsx +0 -42
  167. package/src/components/SupportModal.tsx +0 -32
  168. package/src/components/TabPanel.tsx +0 -28
  169. package/src/components/gallery/GalleryModal.tsx +0 -170
  170. package/src/components/gallery/StockPhotos.tsx +0 -96
  171. package/src/components/gallery/index.ts +0 -2
  172. package/src/components/header/Banner.tsx +0 -11
  173. package/src/components/header/PrimaryMenu.tsx +0 -101
  174. package/src/components/header/SecondaryMenu.tsx +0 -23
  175. package/src/components/header/SecondaryMenuAlt.tsx +0 -40
  176. package/src/components/header/SiteHeader.tsx +0 -205
  177. package/src/components/header/SupportDrawer.tsx +0 -112
  178. package/src/components/header/index.tsx +0 -2
  179. package/src/components/index.tsx +0 -20
  180. package/src/components/notes/AddNote.tsx +0 -185
  181. package/src/components/notes/Note.tsx +0 -84
  182. package/src/components/notes/Notes.tsx +0 -208
  183. package/src/components/notes/index.ts +0 -3
  184. package/src/components/wrapper/AppList.tsx +0 -18
  185. package/src/components/wrapper/ChurchList.tsx +0 -145
  186. package/src/components/wrapper/NavItem.tsx +0 -47
  187. package/src/components/wrapper/NewPrivateMessage.tsx +0 -249
  188. package/src/components/wrapper/Notifications.tsx +0 -220
  189. package/src/components/wrapper/PrivateMessageDetails.tsx +0 -106
  190. package/src/components/wrapper/PrivateMessages.tsx +0 -574
  191. package/src/components/wrapper/UserMenu.tsx +0 -384
  192. package/src/components/wrapper/index.tsx +0 -8
  193. package/src/helpers/AnalyticsHelper.ts +0 -44
  194. package/src/helpers/AppearanceHelper.ts +0 -73
  195. package/src/helpers/ArrayHelper.ts +0 -87
  196. package/src/helpers/CurrencyHelper.ts +0 -10
  197. package/src/helpers/DateHelper.ts +0 -116
  198. package/src/helpers/ErrorHelper.ts +0 -41
  199. package/src/helpers/EventHelper.ts +0 -49
  200. package/src/helpers/FileHelper.ts +0 -31
  201. package/src/helpers/Locale.ts +0 -457
  202. package/src/helpers/NotificationService.ts +0 -233
  203. package/src/helpers/PersonHelper.ts +0 -62
  204. package/src/helpers/SlugHelper.ts +0 -27
  205. package/src/helpers/SocketHelper.ts +0 -183
  206. package/src/helpers/UniqueIdHelper.ts +0 -36
  207. package/src/helpers/UserHelper.ts +0 -103
  208. package/src/helpers/createEmotionCache.ts +0 -17
  209. package/src/helpers/index.ts +0 -58
  210. package/src/hooks/index.ts +0 -3
  211. package/src/hooks/useMountedState.ts +0 -18
  212. package/src/hooks/useNotifications.ts +0 -95
  213. package/src/index.ts +0 -3
  214. package/src/types/interface-extensions.d.ts +0 -12
  215. package/tsconfig.json +0 -32
@@ -1,116 +0,0 @@
1
- import { format as dateFormat } from "date-fns"
2
-
3
- export class DateHelper {
4
-
5
- //Fixes timezone issues when you just need the date.
6
- static toDate(input: any) {
7
- return new Date(Date.parse(input.toString().replace("Z", "")));
8
- }
9
-
10
- static toDateTime(input: any) {
11
- return new Date(Date.parse(input.toString()));
12
- }
13
-
14
- static addDays(date: Date, days: number) {
15
- date.setDate(date.getDate() + days);
16
- return date;
17
- }
18
-
19
- static prettyDate(date: Date) {
20
- if (date === undefined || date === null) return "";
21
- return this.formatDateTime(date, "MMM d, yyyy");
22
- }
23
-
24
- static prettyDateTime(date: Date) {
25
- if (date === undefined || date === null) return "";
26
- return this.formatDateTime(date, "MMM d, yyyy h:mm a");
27
- }
28
-
29
- static prettyTime(date: Date) {
30
- if (date === undefined || date === null) return "";
31
- return this.formatDateTime(date, "h:mm a");
32
- }
33
-
34
- static getLastSunday() {
35
- let result = new Date();
36
- while (result.getDay() !== 0) result.setDate(result.getDate() - 1);
37
- return result;
38
- }
39
-
40
- static getWeekSunday(year: number, week: number) {
41
- let result = new Date(year, 0, 1);
42
- while (result.getDay() !== 0) result.setDate(result.getDate() + 1);
43
- result.setDate(result.getDate() + ((week - 1) * 7));
44
- return result;
45
- }
46
-
47
- static formatHtml5Date(date: Date | string | null | undefined): string {
48
- if (!date) return "";
49
-
50
- // If already a YYYY-MM-DD string, return as-is
51
- if (typeof date === 'string' && /^\d{4}-\d{2}-\d{2}$/.test(date)) return date;
52
-
53
- // If ISO string, extract date portion (ignore timezone)
54
- if (typeof date === 'string') {
55
- const match = date.match(/^(\d{4}-\d{2}-\d{2})/);
56
- if (match) return match[1];
57
- }
58
-
59
- // For Date objects, use LOCAL year/month/day (not UTC)
60
- const d = date instanceof Date ? date : new Date(date);
61
- if (isNaN(d.getTime())) return "";
62
-
63
- const year = d.getFullYear();
64
- const month = String(d.getMonth() + 1).padStart(2, '0');
65
- const day = String(d.getDate()).padStart(2, '0');
66
- return `${year}-${month}-${day}`;
67
- }
68
-
69
- static formatHtml5Time(time: Date): string {
70
- let h = time.getHours();
71
- let m = time.getMinutes();
72
- let s = time.getSeconds();
73
- return `${h < 10 ? ("0" + h) : h}:${m < 10 ? ("0" + m) : m}:${s < 10 ? ("0" + s) : s}`;
74
- }
75
-
76
- static formatHtml5DateTime(date: Date): string {
77
- if (date === undefined || date === null) return "";
78
- else {
79
- return this.formatDateTime(date, "yyyy-MM-dd") + "T" + this.formatDateTime(date, "HH:mm");
80
- }
81
- }
82
-
83
- static getDisplayDuration(d: Date): string {
84
- let seconds = Math.round((new Date().getTime() - d.getTime()) / 1000);
85
- if (seconds > 86400) {
86
- let days = Math.floor(seconds / 86400);
87
- return (days === 1) ? "1d" : days.toString() + "d";
88
- }
89
- else if (seconds > 3600) {
90
- let hours = Math.floor(seconds / 3600);
91
- return (hours === 1) ? "1h" : hours.toString() + "h";
92
- }
93
- else if (seconds > 60) {
94
- let minutes = Math.floor(seconds / 60);
95
- return (minutes === 1) ? "1m" : minutes.toString() + "m";
96
- }
97
- else if (seconds < 1) return "now";
98
- else return (seconds === 1) ? "1s" : Math.floor(seconds).toString() + "s";
99
- }
100
-
101
- static getShortDate(d: Date): string {
102
- return (d.getMonth() + 1).toString() + "/" + (d.getDate()).toString() + "/" + d.getFullYear().toString();
103
- }
104
-
105
- static convertDatePickerFormat(d: Date): Date {
106
- const date = this.formatHtml5Date(d).split("-");
107
- if (date.length === 3) return new Date(`${date[1]}-${date[2]}-${date[0]}`);
108
- return new Date();
109
- }
110
-
111
- private static formatDateTime(date: Date, format: string) {
112
- try {
113
- return dateFormat(date, format);
114
- } catch { return ""; }
115
- }
116
- }
@@ -1,41 +0,0 @@
1
- import { ErrorLogInterface, ErrorAppDataInterface } from "@churchapps/helpers";
2
- import { ApiHelper } from "@churchapps/helpers";
3
-
4
-
5
- export class ErrorHelper {
6
-
7
- static getAppData: () => { churchId: string, userId: string, originUrl: string, application: string };
8
- static customErrorHandler: (errorLog: ErrorLogInterface) => void;
9
-
10
- static init = (getAppData: () => ErrorAppDataInterface, customErrorHandler: (errorLog: ErrorLogInterface) => void) => {
11
- ErrorHelper.getAppData = getAppData;
12
- ErrorHelper.customErrorHandler = customErrorHandler;
13
- }
14
-
15
- static logError = (errorType: string, message: string, details: string) => {
16
- if (this.getAppData) {
17
- const data = this.getAppData();
18
- const log: ErrorLogInterface = {
19
- application: data.application,
20
- errorTime: new Date(),
21
- userId: data.userId,
22
- churchId: data.churchId,
23
- originUrl: data.originUrl,
24
- errorType: errorType,
25
- message: message,
26
- details: details
27
- }
28
-
29
-
30
- if (log.errorType === "401" && log.message.indexOf("/users/login") > -1) return;
31
- if (log.message.indexOf("clientErrors") > -1) return;
32
- try {
33
- // Error posting to /errors endpoint disabled
34
- // ApiHelper.postAnonymous("/clientErrors", [log], "MembershipApi");
35
- } catch (error) {
36
- }
37
- if (ErrorHelper.customErrorHandler) ErrorHelper.customErrorHandler(log);
38
- }
39
- }
40
-
41
- }
@@ -1,49 +0,0 @@
1
- import { EventInterface } from "@churchapps/helpers";
2
- import { RRule } from "rrule";
3
- import { ParsedOptions } from "rrule/dist/esm/types";
4
-
5
- export class EventHelper {
6
-
7
- static getRange = (event:EventInterface, startDate:Date, endDate:Date) => {
8
- const start = new Date(event.start);
9
- const rrule = EventHelper.getFullRRule(event);
10
-
11
- const dates = rrule.between(startDate, endDate);
12
-
13
- dates.forEach(d => {
14
- d.setHours(start.getHours());
15
- d.setMinutes(start.getMinutes());
16
- d.setSeconds(start.getSeconds());
17
- })
18
- return dates;
19
- }
20
-
21
- static getFullRRule = (event:EventInterface) => {
22
- let rrule = RRule.fromString(event.recurrenceRule);
23
- rrule.options.dtstart = new Date(event.start);
24
- return rrule;
25
- }
26
-
27
- static removeExcludeDates = (events:EventInterface[]) => {
28
- for (let i=events.length-1; i>=0; i--) {
29
- if (events[i].exceptionDates?.length>0)
30
- {
31
- const parsedDates = events[i].exceptionDates.map(d=>new Date(d).toISOString());
32
- if (parsedDates.indexOf(events[i].start.toISOString())>-1) events.splice(i,1);
33
- }
34
- }
35
- }
36
-
37
- static getPartialRRuleString = (options:ParsedOptions) => {
38
- const parts = new RRule(options).toString().split("RRULE:");
39
- const result = parts.length===2 ? parts[1] : "";
40
- return result;
41
- }
42
-
43
- static cleanRule = (options:ParsedOptions) => {
44
- options.byhour = undefined;
45
- options.byminute = undefined;
46
- options.bysecond = undefined;
47
- }
48
-
49
- }
@@ -1,31 +0,0 @@
1
- import axios from "axios";
2
-
3
- export class FileHelper {
4
-
5
- static postPresignedFile = (presigned: any, uploadedFile: File, progressCallback: (percent: number) => void) => {
6
- const formData = new FormData();
7
- //formData.append("key", presigned.key); //no longer needed with new aws sdk
8
- formData.append("acl", "public-read");
9
- formData.append("Content-Type", uploadedFile.type);
10
- for (const property in presigned.fields) formData.append(property, presigned.fields[property]);
11
- formData.append("file", uploadedFile);
12
-
13
- const axiosConfig = {
14
- headers: { "Content-Type": "multipart/form-data" },
15
- onUploadProgress: (data: any) => {
16
- progressCallback(Math.round((100 * data.loaded) / data.total));
17
- }
18
- };
19
-
20
- return axios.post(presigned.url, formData, axiosConfig);
21
- };
22
-
23
- static dataURLtoBlob(dataurl: string) {
24
- let arr = dataurl.split(","), mime = arr[0].match(/:(.*?);/)[1],
25
- bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
26
- while (n--) {
27
- u8arr[n] = bstr.charCodeAt(n);
28
- }
29
- return new Blob([u8arr], { type: mime });
30
- }
31
- }
@@ -1,457 +0,0 @@
1
- import i18n from "i18next";
2
- import { initReactI18next } from "react-i18next/initReactI18next";
3
- import LanguageDetector from "i18next-browser-languagedetector";
4
- import Backend from "i18next-chained-backend";
5
-
6
- interface TranslationResources {
7
- [key: string]: {
8
- translation: Record<string, unknown>;
9
- };
10
- }
11
-
12
- interface ExtraLanguageCodes {
13
- [key: string]: string[];
14
- }
15
-
16
- export class Locale {
17
- private static readonly supportedLanguages: string[] = [
18
- "de",
19
- "en",
20
- "es",
21
- "fr",
22
- "hi",
23
- "it",
24
- "ko",
25
- "no",
26
- "pt",
27
- "ru",
28
- "tl",
29
- "zh",
30
- ];
31
- private static readonly extraCodes: ExtraLanguageCodes = { no: ["nb", "nn"] };
32
-
33
- // Hard-coded English fallbacks for when locale files are not available
34
- private static readonly englishFallbacks: Record<string, any> = {
35
- "b1Share": {
36
- "comment": "Comment",
37
- "commentPlaceholder": "Include a comment with your post.",
38
- "contentShared": "Content Shared",
39
- "group": "Group",
40
- "sharingToGroup": "Sharing {} to B1 Group",
41
- "validate": {
42
- "addComment": "Please add a comment.",
43
- "loginFirst": "Please login first.",
44
- "notMember": "You are not currently a member of any groups on B1.",
45
- "selectGroup": "Please select a group."
46
- }
47
- },
48
- "common": {
49
- "add": "Add",
50
- "cancel": "Cancel",
51
- "close": "Close",
52
- "date": "Date",
53
- "delete": "Delete",
54
- "edit": "Edit",
55
- "error": "Error",
56
- "pleaseWait": "Please wait...",
57
- "save": "Save",
58
- "search": "Search",
59
- "submit": "Submit",
60
- "update": "Update"
61
- },
62
- "createPerson": {
63
- "addNewPerson": "Add a New Person",
64
- "firstName": "First Name",
65
- "lastName": "Last Name",
66
- "email": "Email"
67
- },
68
- "donation": {
69
- "bankForm": {
70
- "accountNumber": "Account Number",
71
- "added": "Bank account added. Verify your bank account to make a donation.",
72
- "company": "Company",
73
- "firstDeposit": "First Deposit",
74
- "holderName": "Account holder name is required.",
75
- "individual": "Individual",
76
- "name": "Account Holder Name",
77
- "needVerified": "Bank accounts will need to be verified before making any donations. Your account will receive two small deposits in approximately 1-3 business days. You will need to enter those deposit amounts to finish verifying your account by selecting the verify account link next to your bank account under the payment methods section.",
78
- "routingNumber": "Routing Number",
79
- "secondDeposit": "Second Deposit",
80
- "twoDeposits": "Enter the two deposits you received in your account to finish verifying your bank account.",
81
- "updated": "Bank account updated.",
82
- "verified": "Bank account verified.",
83
- "validate": {
84
- "accountNumber": "Routing and account number are required.",
85
- "holderName": "Account holder name is required."
86
- }
87
- },
88
- "cardForm": {
89
- "addNew": "Add New Card",
90
- "added": "Card added successfully.",
91
- "expirationMonth": "Expiration Month:",
92
- "expirationYear": "Expiration Year:",
93
- "updated": "Card updated successfully."
94
- },
95
- "common": {
96
- "cancel": "Cancel",
97
- "error": "Error"
98
- },
99
- "donationForm": {
100
- "annually": "Annually",
101
- "biWeekly": "Bi-Weekly",
102
- "cancelled": "Recurring donation cancelled.",
103
- "confirmDelete": "Are you sure you wish to delete this recurring donation?",
104
- "cover": "I'll generously add {} to cover the transaction fees so you can keep 100% of my donation.",
105
- "donate": "Donate",
106
- "editRecurring": "Edit Recurring Donation",
107
- "fees": "Transaction fees of {} are applied.",
108
- "frequency": "Frequency",
109
- "fund": "Fund",
110
- "funds": "Funds",
111
- "make": "Make a Donation",
112
- "makeRecurring": "Make a Recurring Donation",
113
- "method": "Method",
114
- "monthly": "Monthly",
115
- "notes": "Notes",
116
- "preview": "Preview Donation",
117
- "quarterly": "Quarterly",
118
- "recurringUpdated": "Recurring donation updated.",
119
- "startDate": "Start Date",
120
- "thankYou": "Thank you for your donation!",
121
- "tooLow": "Donation amount must be greater than $0.50",
122
- "total": "Total Donation Amount",
123
- "validate": {
124
- "amount": "Amount cannot be $0.",
125
- "email": "Please enter your email address.",
126
- "firstName": "Please enter your first name.",
127
- "lastName": "Please enter your last name.",
128
- "validEmail": "Please enter a valid email address."
129
- },
130
- "weekly": "Weekly"
131
- },
132
- "fundDonations": {
133
- "addMore": "Add More",
134
- "amount": "Amount",
135
- "fund": "Fund"
136
- },
137
- "paymentMethods": {
138
- "addBank": "Add Bank Account",
139
- "addCard": "Add Card",
140
- "confirmDelete": "Are you sure you wish to delete this payment method?",
141
- "deleted": "Payment method deleted.",
142
- "noMethod": "No payment methods. Add a payment method to make a donation.",
143
- "verify": "Verify Account"
144
- },
145
- "page": {
146
- "amount": "Amount",
147
- "batch": "Batch",
148
- "date": "Date",
149
- "fund": "Fund",
150
- "method": "Method",
151
- "willAppear": "Donations will appear once a donation has been entered."
152
- },
153
- "preview": {
154
- "date": "Donation Date",
155
- "donate": "Donate",
156
- "every": "Recurring Every",
157
- "fee": "Transaction Fee",
158
- "funds": "Funds",
159
- "method": "Donation Method",
160
- "notes": "Notes",
161
- "startingOn": "Starting On",
162
- "total": "Total",
163
- "type": "Donation Type",
164
- "weekly": "Weekly"
165
- },
166
- "recurring": {
167
- "amount": "Amount",
168
- "every": "Every",
169
- "interval": "Interval",
170
- "notFound": "Payment method not found.",
171
- "paymentMethod": "Payment Method",
172
- "startDate": "Start Date"
173
- }
174
- },
175
- "formSubmissionEdit": {
176
- "confirmDelete": "Are you sure you wish to delete this form data?",
177
- "editForm": "Edit Form",
178
- "isRequired": "is required",
179
- "submit": "Submit"
180
- },
181
- "gallery": {
182
- "aspectRatio": "Aspect Ratio",
183
- "confirmDelete": "Are you sure you wish to delete this image from gallery?",
184
- "freeForm": "Free Form"
185
- },
186
- "iconPicker": {
187
- "iconsAvailable": "icons available",
188
- "matchingResults": "matching results",
189
- "search": "Search icons..."
190
- },
191
- "login": {
192
- "createAccount": "Create an Account",
193
- "email": "Email",
194
- "expiredLink": "The current link is expired.",
195
- "forgot": "Forgot Password",
196
- "goLogin": "Go to Login",
197
- "login": "Login",
198
- "password": "Password",
199
- "register": "Register",
200
- "registerThankYou": "Thank you for registering! Please check your email to verify your account.",
201
- "requestLink": "Request a new reset link",
202
- "reset": "Reset",
203
- "resetInstructions": "Enter your email address to request a password reset.",
204
- "resetPassword": "Reset Password",
205
- "resetSent": "Password reset email sent!",
206
- "setPassword": "Set Password",
207
- "signIn": "Sign In",
208
- "signInTitle": "Please Sign In",
209
- "verifyPassword": "Verify Password",
210
- "validate": {
211
- "email": "Please enter a valid email address.",
212
- "firstName": "Please enter your first name.",
213
- "invalid": "Invalid login. Please check your email or password.",
214
- "lastName": "Please enter your last name.",
215
- "password": "Please enter a password.",
216
- "passwordLength": "Password must be at least 8 characters long.",
217
- "passwordMatch": "Passwords do not match.",
218
- "selectingChurch": "Error in selecting church. Please verify and try again"
219
- },
220
- "welcomeBack": "Welcome back",
221
- "welcomeName": "Welcome back, <b>{}</b>! Please wait while we load your data."
222
- },
223
- "markdownEditor": {
224
- "content": "Content",
225
- "markdownEditor": "Markdown Editor",
226
- "markdownGuide": "Markdown Guide"
227
- },
228
- "month": {
229
- "april": "April",
230
- "august": "August",
231
- "december": "December",
232
- "february": "February",
233
- "january": "January",
234
- "july": "July",
235
- "june": "June",
236
- "march": "March",
237
- "may": "May",
238
- "november": "November",
239
- "october": "October",
240
- "september": "September"
241
- },
242
- "notes": {
243
- "comment": "comment",
244
- "comments": "comments",
245
- "notes": "Notes",
246
- "startConversation": "Start a conversation",
247
- "validate": {
248
- "content": "Please enter a note."
249
- },
250
- "viewAll": "View all"
251
- },
252
- "person": {
253
- "email": "Email",
254
- "firstName": "First Name",
255
- "lastName": "Last Name",
256
- "name": "Name",
257
- "person": "Person",
258
- "years": "years",
259
- "noRec": "Don't have a person record?"
260
- },
261
- "reporting": {
262
- "detailed": "Detailed Report",
263
- "summary": "Summary",
264
- "sampleTemplate": "Sample Word Template",
265
- "downloadOptions": "Download Options",
266
- "noData": "There is no data to display.",
267
- "runReport": "Run Report",
268
- "useFilter": "Use the filter to run the report."
269
- },
270
- "selectChurch": {
271
- "address1": "Address Line 1",
272
- "address2": "Address Line 2",
273
- "another": "Choose another church",
274
- "city": "City",
275
- "confirmRegister": "Are you sure you wish to register a new church?",
276
- "country": "Country",
277
- "name": "Church Name",
278
- "noMatches": "No matches found.",
279
- "register": "Register a New Church",
280
- "selectChurch": "Select a Church",
281
- "state": "State / Province",
282
- "zip": "Zip / Postal Code",
283
- "validate": {
284
- "address": "Address cannot be blank.",
285
- "city": "City cannot be blank.",
286
- "country": "Country cannot be blank.",
287
- "name": "Church name cannot be blank.",
288
- "state": "State/Province cannot be blank.",
289
- "zip": "Zip/Postal code cannot be blank."
290
- }
291
- },
292
- "stockPhotos": {
293
- "photoBy": "Photo by:",
294
- "providedBy": "Stock photos provided by"
295
- },
296
- "support": {
297
- "documentation": "Documentation",
298
- "discussions": "Support Forum"
299
- },
300
- "wrapper": {
301
- "chatWith": "Chat with",
302
- "deleteChurch": "Delete",
303
- "logout": "Logout",
304
- "messages": "Messages",
305
- "newPrivateMessage": "New Private Message",
306
- "notifications": "Notifications",
307
- "privateMessage": "Private Message",
308
- "privateConversation": "Private Conversation",
309
- "profile": "Profile",
310
- "searchForPerson": "Search for a person",
311
- "support": "Support",
312
- "sureRemoveChurch": "Are you sure you wish to delete this church? You no longer will be a member of {}.",
313
- "switchApp": "Switch App",
314
- "switchChurch": "Switch Church"
315
- }
316
- };
317
-
318
- static init = async (backends: string[]): Promise<void> => {
319
- const resources: TranslationResources = {};
320
- let langs = ["en"];
321
-
322
- if (typeof navigator !== "undefined") {
323
- const browserLang = navigator.language.split("-")[0];
324
- const mappedLang
325
- = Object.keys(this.extraCodes).find((code) =>
326
- this.extraCodes[code].includes(browserLang),
327
- ) || browserLang;
328
- const notSupported = this.supportedLanguages.indexOf(mappedLang) === -1;
329
- langs = mappedLang === "en" || notSupported ? ["en"] : ["en", mappedLang];
330
- }
331
-
332
- // Load translations for each language
333
- for (const lang of langs) {
334
- resources[lang] = { translation: {} };
335
- for (const backend of backends) {
336
- const url = backend.replace("{{lng}}", lang);
337
- try {
338
- const data = await fetch(url).then((response) => response.json());
339
- resources[lang].translation = this.deepMerge(
340
- resources[lang].translation,
341
- data,
342
- );
343
- } catch (error) {
344
- // If fetching fails, we'll rely on the hard-coded fallbacks
345
- console.warn(`Failed to load translations from ${url}:`, error);
346
- }
347
- }
348
- }
349
-
350
- // Initialize i18n
351
- await i18n
352
- .use(Backend)
353
- .use(LanguageDetector)
354
- .use(initReactI18next)
355
- .init({
356
- resources,
357
- fallbackLng: "en",
358
- debug: false,
359
- interpolation: {
360
- escapeValue: false,
361
- },
362
- detection: {
363
- order: ["navigator"],
364
- caches: ["localStorage"],
365
- },
366
- });
367
- };
368
-
369
- private static deepMerge(
370
- target: Record<string, unknown>,
371
- source: Record<string, unknown>,
372
- ): Record<string, unknown> {
373
- for (const key in source) {
374
- if (this.isObject(source[key])) {
375
- if (!target[key]) Object.assign(target, { [key]: {} });
376
- this.deepMerge(
377
- target[key] as Record<string, unknown>,
378
- source[key] as Record<string, unknown>,
379
- );
380
- } else Object.assign(target, { [key]: source[key] });
381
- }
382
- return target;
383
- }
384
-
385
- private static isObject(obj: unknown): boolean {
386
- return obj !== null && typeof obj === "object" && !Array.isArray(obj);
387
- }
388
-
389
- // Helper method to get value from nested object using dot notation
390
- private static getNestedValue(obj: Record<string, any>, path: string): any {
391
- return path.split('.').reduce((current, key) => {
392
- return current && current[key] !== undefined ? current[key] : undefined;
393
- }, obj);
394
- }
395
-
396
- // New helper method that uses i18n with hard-coded English fallback
397
- static t(key: string, options?: Record<string, unknown>): string {
398
- try {
399
- // Check if i18n is initialized and has the key
400
- if (i18n && i18n.isInitialized && i18n.exists(key)) {
401
- const translation = i18n.t(key, options);
402
- // If translation is not the same as the key, return it
403
- if (translation !== key) {
404
- return translation;
405
- }
406
- }
407
- } catch (error) {
408
- // If i18n fails, fall through to hard-coded fallback
409
- console.warn(`i18n translation failed for key "${key}":`, error);
410
- }
411
-
412
- // Fallback to hard-coded English translations
413
- const fallbackValue = this.getNestedValue(this.englishFallbacks, key);
414
- if (fallbackValue !== undefined) {
415
- // Handle simple string interpolation for options
416
- if (typeof fallbackValue === 'string' && options) {
417
- let result = fallbackValue;
418
- Object.keys(options).forEach(optionKey => {
419
- const placeholder = `{{${optionKey}}}`;
420
- if (result.includes(placeholder)) {
421
- result = result.replace(new RegExp(placeholder, 'g'), String(options[optionKey]));
422
- }
423
- // Also handle {} placeholder for backward compatibility
424
- if (result.includes('{}')) {
425
- result = result.replace('{}', String(options[optionKey]));
426
- }
427
- });
428
- return result;
429
- }
430
- return String(fallbackValue);
431
- }
432
-
433
- // If no fallback found, return the key itself
434
- return key;
435
- }
436
-
437
- // Keep the old method for backward compatibility
438
- static label(key: string, fallback?: string): string {
439
- const translation = this.t(key);
440
- // If translation equals the key, it means no translation was found
441
- if (translation === key && fallback) {
442
- return fallback;
443
- }
444
- return translation;
445
- }
446
-
447
- // Helper method to check if i18n is initialized
448
- static isInitialized(): boolean {
449
- return i18n && i18n.isInitialized;
450
- }
451
-
452
- // Method to set up basic fallback-only mode (no i18n)
453
- static setupFallbackMode(): void {
454
- // This method can be called if apps want to use only the hard-coded fallbacks
455
- // without initializing the full i18n system
456
- }
457
- }