@churchapps/apphelper-login 0.5.0 → 0.5.5

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/src/LoginPage.tsx CHANGED
@@ -1,305 +1,305 @@
1
- "use client";
2
-
3
- import * as React from "react";
4
- import { ErrorMessages, FloatingSupport, Loading } from "@churchapps/apphelper";
5
- import { LoginResponseInterface, UserContextInterface, ChurchInterface, UserInterface, LoginUserChurchInterface, PersonInterface } from "@churchapps/helpers";
6
- import { ApiHelper, ArrayHelper, UserHelper, CommonEnvironmentHelper } from "@churchapps/helpers";
7
- import { AnalyticsHelper, Locale } from "./helpers";
8
- import { useCookies, CookiesProvider } from "react-cookie"
9
- import { Register } from "./components/Register"
10
- import { SelectChurchModal } from "./components/SelectChurchModal"
11
- import { Forgot } from "./components/Forgot";
12
- import { Alert, PaperProps, Typography } from "@mui/material";
13
- import { Login } from "./components/Login";
14
- import { LoginSetPassword } from "./components/LoginSetPassword";
15
- import ga4 from "react-ga4";
16
-
17
- interface Props {
18
- context: UserContextInterface,
19
- jwt: string,
20
- auth: string,
21
- keyName?: string,
22
- logo?: string,
23
- appName?: string,
24
- appUrl?: string,
25
- returnUrl?: string,
26
- userRegisteredCallback?: (user: UserInterface) => Promise<void>;
27
- churchRegisteredCallback?: (church: ChurchInterface) => Promise<void>;
28
- callbackErrors?: string[];
29
- showLogo?: boolean;
30
- showFooter?: boolean;
31
- loginContainerCssProps?: PaperProps;
32
- defaultEmail?: string;
33
- defaultPassword?: string;
34
- handleRedirect?: (url: string, user?: UserInterface, person?: PersonInterface, userChurch?: LoginUserChurchInterface, userChurches?: LoginUserChurchInterface[]) => void; // Function to handle redirects from parent component
35
- }
36
-
37
- const LoginPageContent: React.FC<Props> = ({ showLogo = true, loginContainerCssProps, ...props }) => {
38
- const [welcomeBackName, setWelcomeBackName] = React.useState("");
39
- const [pendingAutoLogin, setPendingAutoLogin] = React.useState(false);
40
- const [errors, setErrors] = React.useState([]);
41
- const [cookies, setCookie] = useCookies(["jwt", "name", "email", "lastChurchId"]);
42
- const [showForgot, setShowForgot] = React.useState(false);
43
- const [showRegister, setShowRegister] = React.useState(false);
44
- const [showSelectModal, setShowSelectModal] = React.useState(false);
45
- const [loginResponse, setLoginResponse] = React.useState<LoginResponseInterface>(null)
46
- const [userJwt, setUserJwt] = React.useState("");
47
- const [isSubmitting, setIsSubmitting] = React.useState(false);
48
-
49
- const loginFormRef = React.useRef(null);
50
- const location = typeof window !== "undefined" && window.location;
51
- let selectedChurchId = "";
52
- let registeredChurch: ChurchInterface = null;
53
- let userJwtBackup = ""; //use state copy for storing between page updates. This copy for instant availability.
54
-
55
- const cleanAppUrl = () => {
56
- if (!props.appUrl) return null;
57
- else {
58
- const index = props.appUrl.indexOf("/", 9);
59
- if (index === -1) return props.appUrl;
60
- else return props.appUrl.substring(0, index);
61
- }
62
- }
63
-
64
- React.useEffect(() => {
65
- if (props.callbackErrors?.length > 0) {
66
- setErrors(props.callbackErrors)
67
- }
68
- }, [props.callbackErrors])
69
-
70
- const performLogout = () => {
71
- // Clear all authentication cookies
72
- setCookie("jwt", "", { path: "/", maxAge: 0 });
73
- setCookie("name", "", { path: "/", maxAge: 0 });
74
- setCookie("email", "", { path: "/", maxAge: 0 });
75
- setCookie("lastChurchId", "", { path: "/", maxAge: 0 });
76
- // Clear any JWT in the ApiHelper
77
- ApiHelper.clearPermissions();
78
- // Clear user context
79
- props.context.setUser(null);
80
- props.context.setUserChurches([]);
81
- props.context.setUserChurch(null);
82
- props.context.setPerson(null);
83
- // Show a logout success message
84
- setErrors(["You have been successfully logged out."]);
85
-
86
- // Handle redirect after logout
87
- const search = new URLSearchParams(location?.search);
88
- const returnUrl = search.get("returnUrl") || props.returnUrl || "/";
89
-
90
- // Use handleRedirect if available, otherwise use window.location
91
- if (props.handleRedirect) {
92
- props.handleRedirect(returnUrl);
93
- } else if (typeof window !== "undefined") {
94
- window.location.href = returnUrl;
95
- }
96
- };
97
-
98
- const init = () => {
99
- const search = new URLSearchParams(location?.search);
100
- const action = search.get("action");
101
- if (action === "logout") performLogout();
102
- else if (action === "forgot") setShowForgot(true);
103
- else if (action === "register") setShowRegister(true);
104
- else {
105
- if (!props.auth && props.jwt) {
106
- setWelcomeBackName(cookies.name);
107
- login({ jwt: props.jwt });
108
- setPendingAutoLogin(true);
109
- } else {
110
- setPendingAutoLogin(false);
111
- }
112
- }
113
- };
114
-
115
- const handleLoginSuccess = async (resp: LoginResponseInterface) => {
116
- userJwtBackup = resp.user.jwt;
117
- setUserJwt(userJwtBackup);
118
- ApiHelper.setDefaultPermissions(resp.user.jwt);
119
- setLoginResponse(resp)
120
- resp.userChurches.forEach(uc => { if (!uc.apis) uc.apis = []; });
121
- UserHelper.userChurches = resp.userChurches;
122
-
123
- setCookie("name", `${resp.user.firstName} ${resp.user.lastName}`, { path: "/" });
124
- setCookie("email", resp.user.email, { path: "/" });
125
- UserHelper.user = resp.user;
126
-
127
- // JWT church selection is handled by the server response, no client-side decoding needed
128
-
129
- const search = new URLSearchParams(location?.search);
130
- const churchIdInParams = search.get("churchId");
131
-
132
- if (props.keyName) selectChurchByKeyName();
133
- else if (churchIdInParams) selectChurch(churchIdInParams);
134
- else if (cookies.lastChurchId && ArrayHelper.getOne(resp.userChurches, "church.id", cookies.lastChurchId)) {
135
- selectedChurchId = cookies.lastChurchId;
136
- selectChurchById();
137
- }
138
- else setShowSelectModal(true);
139
- }
140
-
141
- const selectChurchById = async () => {
142
- await UserHelper.selectChurch(props.context, selectedChurchId, undefined);
143
-
144
- setCookie("lastChurchId", selectedChurchId, { path: "/" });
145
-
146
- if (registeredChurch) {
147
- AnalyticsHelper.logEvent("Church", "Register", UserHelper.currentUserChurch.church.name);
148
- try {
149
- if (CommonEnvironmentHelper.GoogleAnalyticsTag && typeof (window) !== "undefined") {
150
- ga4.gtag("event", "conversion", { send_to: "AW-427967381/Ba2qCLrXgJoYEJWHicwB" });
151
- }
152
- } catch { }
153
- }
154
- else AnalyticsHelper.logEvent("Church", "Select", UserHelper.currentUserChurch.church.name);
155
-
156
- if (props.churchRegisteredCallback && registeredChurch) {
157
- await props.churchRegisteredCallback(registeredChurch)
158
- registeredChurch = null;
159
- login({ jwt: userJwt || userJwtBackup });
160
- } else await continueLoginProcess();
161
- }
162
-
163
- const selectChurchByKeyName = async () => {
164
- if (!ArrayHelper.getOne(UserHelper.userChurches, "church.subDomain", props.keyName)) {
165
- const userChurch: LoginUserChurchInterface = await ApiHelper.post("/churches/select", { subDomain: props.keyName }, "MembershipApi");
166
- UserHelper.setupApiHelper(userChurch);
167
- setCookie("lastChurchId", userChurch.church.id, { path: "/" });
168
- //create/claim the person record and relogin
169
- await ApiHelper.get("/people/claim/" + userChurch.church.id, "MembershipApi");
170
- login({ jwt: userJwt || userJwtBackup });
171
- return;
172
- }
173
- await UserHelper.selectChurch(props.context, undefined, props.keyName);
174
- const selectedChurch = ArrayHelper.getOne(UserHelper.userChurches, "church.subDomain", props.keyName);
175
- if (selectedChurch) setCookie("lastChurchId", selectedChurch.church.id, { path: "/" });
176
- await continueLoginProcess()
177
- return;
178
- }
179
-
180
- async function continueLoginProcess() {
181
- if (UserHelper.currentUserChurch) {
182
- UserHelper.currentUserChurch.apis.forEach(api => {
183
- if (api.keyName === "MembershipApi") setCookie("jwt", api.jwt, { path: "/" });
184
- })
185
- try {
186
- if (UserHelper.currentUserChurch.church.id) ApiHelper.patch(`/userChurch/${UserHelper.user.id}`, { churchId: UserHelper.currentUserChurch.church.id, appName: props.appName, lastAccessed: new Date() }, "MembershipApi")
187
- } catch (e) {
188
- console.log("Could not update user church accessed date")
189
- }
190
- }
191
-
192
- props.context.setUser(UserHelper.user);
193
- props.context.setUserChurches(UserHelper.userChurches)
194
- props.context.setUserChurch(UserHelper.currentUserChurch)
195
-
196
- // Get or claim person before proceeding
197
- let person;
198
- try {
199
- person = await ApiHelper.get(`/people/${UserHelper.currentUserChurch.person?.id}`, "MembershipApi");
200
- if (person) props.context.setPerson(person);
201
- } catch {
202
- console.log("claiming person");
203
- person = await ApiHelper.get("/people/claim/" + UserHelper.currentUserChurch.church.id, "MembershipApi");
204
- props.context.setPerson(person);
205
- }
206
-
207
- // Handle redirect with actual data
208
- const search = new URLSearchParams(location?.search);
209
- const returnUrl = search.get("returnUrl") || props.returnUrl || "/";
210
- if (returnUrl && typeof window !== "undefined") {
211
- // Use handleRedirect function if available, otherwise fallback to window.location
212
- if (props.handleRedirect) {
213
- console.log('Login handleRedirect - Passing userChurches:', UserHelper.userChurches);
214
- props.handleRedirect(returnUrl, UserHelper.user, person, UserHelper.currentUserChurch, UserHelper.userChurches);
215
- } else {
216
- window.location.href = returnUrl;
217
- }
218
- }
219
- }
220
-
221
- async function selectChurch(churchId: string) {
222
- try {
223
- setErrors([])
224
- selectedChurchId = churchId;
225
- setCookie("lastChurchId", churchId, { path: "/" });
226
- if (!ArrayHelper.getOne(UserHelper.userChurches, "church.id", churchId)) {
227
- const userChurch: LoginUserChurchInterface = await ApiHelper.post("/churches/select", { churchId: churchId }, "MembershipApi");
228
- UserHelper.setupApiHelper(userChurch);
229
-
230
- //create/claim the person record and relogin
231
- await ApiHelper.get("/people/claim/" + churchId, "MembershipApi");
232
- login({ jwt: userJwt || userJwtBackup });
233
- return;
234
- }
235
- UserHelper.selectChurch(props.context, churchId, null).then(() => { continueLoginProcess() });
236
- } catch (err) {
237
- console.log("Error in selecting church: ", err)
238
- setErrors([Locale.label("login.validate.selectingChurch")])
239
- loginFormRef?.current?.setSubmitting(false);
240
- }
241
-
242
- }
243
-
244
- const handleLoginErrors = (errors: string[]) => {
245
- setWelcomeBackName("");
246
- console.log(errors);
247
- setErrors([Locale.label("login.validate.invalid")]);
248
- }
249
-
250
- const login = async (data: any) => {
251
- setErrors([])
252
- setIsSubmitting(true);
253
- try {
254
- console.log("Logging in with data: ", data, "/users/login", ApiHelper.getConfig("MembershipApi"));
255
- const resp: LoginResponseInterface = await ApiHelper.postAnonymous("/users/login", data, "MembershipApi");
256
- setIsSubmitting(false);
257
- handleLoginSuccess(resp);
258
- } catch (e: any) {
259
- setPendingAutoLogin(false);
260
- setWelcomeBackName("");
261
- if (!data.jwt) handleLoginErrors([e.toString()]);
262
- setIsSubmitting(false);
263
- }
264
- };;
265
-
266
- const getWelcomeBack = () => { if (welcomeBackName !== "") return (<><Alert severity="info"><div dangerouslySetInnerHTML={{ __html: Locale.label("login.welcomeName")?.replace("{}", welcomeBackName) }} /></Alert><Loading /></>); }
267
- const getCheckEmail = () => { if (new URLSearchParams(location?.search).get("checkEmail") === "1") return <Alert severity="info">{Locale.label("login.registerThankYou")}</Alert> }
268
- const handleRegisterCallback = () => { setShowForgot(false); setShowRegister(true); }
269
- const handleLoginCallback = () => { setShowForgot(false); setShowRegister(false); }
270
- const handleChurchRegistered = (church: ChurchInterface) => { registeredChurch = church; setShowRegister(false); console.log("Updated VERSION********") }
271
-
272
- const getInputBox = () => {
273
- if (showRegister) return (
274
-
275
- <Register updateErrors={setErrors} appName={props.appName} appUrl={cleanAppUrl()} loginCallback={handleLoginCallback} userRegisteredCallback={props.userRegisteredCallback} />
276
-
277
- );
278
- else if (showForgot) return (<Forgot registerCallback={handleRegisterCallback} loginCallback={handleLoginCallback} />);
279
- else if (props.auth) return (<LoginSetPassword setErrors={setErrors} setShowForgot={setShowForgot} isSubmitting={isSubmitting} auth={props.auth} login={login} appName={props.appName} appUrl={cleanAppUrl()} />)
280
- else return <Login setShowRegister={setShowRegister} setShowForgot={setShowForgot} setErrors={setErrors} isSubmitting={isSubmitting} login={login} mainContainerCssProps={loginContainerCssProps} defaultEmail={props.defaultEmail} defaultPassword={props.defaultPassword} showFooter={props.showFooter} />;
281
- }
282
-
283
- React.useEffect(init, []); //eslint-disable-line
284
-
285
- return (
286
- <>
287
- <ErrorMessages errors={errors} />
288
- {getWelcomeBack()}
289
- {getCheckEmail()}
290
- {!pendingAutoLogin && getInputBox()}
291
- <SelectChurchModal show={showSelectModal} userChurches={loginResponse?.userChurches} selectChurch={selectChurch} registeredChurchCallback={handleChurchRegistered} errors={errors} appName={props.appName} handleRedirect={props.handleRedirect} />
292
- <FloatingSupport appName={props.appName} />
293
- </>
294
- );
295
-
296
- };
297
-
298
- export const LoginPage: React.FC<Props> = (props) => {
299
- // Always wrap with CookiesProvider to ensure context is available
300
- return (
301
- <CookiesProvider defaultSetOptions={{ path: '/' }}>
302
- <LoginPageContent {...props} />
303
- </CookiesProvider>
304
- );
305
- };
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import { ErrorMessages, FloatingSupport, Loading } from "@churchapps/apphelper";
5
+ import { LoginResponseInterface, UserContextInterface, ChurchInterface, UserInterface, LoginUserChurchInterface, PersonInterface } from "@churchapps/helpers";
6
+ import { ApiHelper, ArrayHelper, UserHelper, CommonEnvironmentHelper } from "@churchapps/helpers";
7
+ import { AnalyticsHelper, Locale } from "./helpers";
8
+ import { useCookies, CookiesProvider } from "react-cookie"
9
+ import { Register } from "./components/Register"
10
+ import { SelectChurchModal } from "./components/SelectChurchModal"
11
+ import { Forgot } from "./components/Forgot";
12
+ import { Alert, PaperProps, Typography } from "@mui/material";
13
+ import { Login } from "./components/Login";
14
+ import { LoginSetPassword } from "./components/LoginSetPassword";
15
+ import ga4 from "react-ga4";
16
+
17
+ interface Props {
18
+ context: UserContextInterface,
19
+ jwt: string,
20
+ auth: string,
21
+ keyName?: string,
22
+ logo?: string,
23
+ appName?: string,
24
+ appUrl?: string,
25
+ returnUrl?: string,
26
+ userRegisteredCallback?: (user: UserInterface) => Promise<void>;
27
+ churchRegisteredCallback?: (church: ChurchInterface) => Promise<void>;
28
+ callbackErrors?: string[];
29
+ showLogo?: boolean;
30
+ showFooter?: boolean;
31
+ loginContainerCssProps?: PaperProps;
32
+ defaultEmail?: string;
33
+ defaultPassword?: string;
34
+ handleRedirect?: (url: string, user?: UserInterface, person?: PersonInterface, userChurch?: LoginUserChurchInterface, userChurches?: LoginUserChurchInterface[]) => void; // Function to handle redirects from parent component
35
+ }
36
+
37
+ const LoginPageContent: React.FC<Props> = ({ showLogo = true, loginContainerCssProps, ...props }) => {
38
+ const [welcomeBackName, setWelcomeBackName] = React.useState("");
39
+ const [pendingAutoLogin, setPendingAutoLogin] = React.useState(false);
40
+ const [errors, setErrors] = React.useState([]);
41
+ const [cookies, setCookie] = useCookies(["jwt", "name", "email", "lastChurchId"]);
42
+ const [showForgot, setShowForgot] = React.useState(false);
43
+ const [showRegister, setShowRegister] = React.useState(false);
44
+ const [showSelectModal, setShowSelectModal] = React.useState(false);
45
+ const [loginResponse, setLoginResponse] = React.useState<LoginResponseInterface>(null)
46
+ const [userJwt, setUserJwt] = React.useState("");
47
+ const [isSubmitting, setIsSubmitting] = React.useState(false);
48
+
49
+ const loginFormRef = React.useRef(null);
50
+ const location = typeof window !== "undefined" && window.location;
51
+ let selectedChurchId = "";
52
+ let registeredChurch: ChurchInterface = null;
53
+ let userJwtBackup = ""; //use state copy for storing between page updates. This copy for instant availability.
54
+
55
+ const cleanAppUrl = () => {
56
+ if (!props.appUrl) return null;
57
+ else {
58
+ const index = props.appUrl.indexOf("/", 9);
59
+ if (index === -1) return props.appUrl;
60
+ else return props.appUrl.substring(0, index);
61
+ }
62
+ }
63
+
64
+ React.useEffect(() => {
65
+ if (props.callbackErrors?.length > 0) {
66
+ setErrors(props.callbackErrors)
67
+ }
68
+ }, [props.callbackErrors])
69
+
70
+ const performLogout = () => {
71
+ // Clear all authentication cookies
72
+ setCookie("jwt", "", { path: "/", maxAge: 0 });
73
+ setCookie("name", "", { path: "/", maxAge: 0 });
74
+ setCookie("email", "", { path: "/", maxAge: 0 });
75
+ setCookie("lastChurchId", "", { path: "/", maxAge: 0 });
76
+ // Clear any JWT in the ApiHelper
77
+ ApiHelper.clearPermissions();
78
+ // Clear user context
79
+ props.context.setUser(null);
80
+ props.context.setUserChurches([]);
81
+ props.context.setUserChurch(null);
82
+ props.context.setPerson(null);
83
+ // Show a logout success message
84
+ setErrors(["You have been successfully logged out."]);
85
+
86
+ // Handle redirect after logout
87
+ const search = new URLSearchParams(location?.search);
88
+ const returnUrl = search.get("returnUrl") || props.returnUrl || "/";
89
+
90
+ // Use handleRedirect if available, otherwise use window.location
91
+ if (props.handleRedirect) {
92
+ props.handleRedirect(returnUrl);
93
+ } else if (typeof window !== "undefined") {
94
+ window.location.href = returnUrl;
95
+ }
96
+ };
97
+
98
+ const init = () => {
99
+ const search = new URLSearchParams(location?.search);
100
+ const action = search.get("action");
101
+ if (action === "logout") performLogout();
102
+ else if (action === "forgot") setShowForgot(true);
103
+ else if (action === "register") setShowRegister(true);
104
+ else {
105
+ if (!props.auth && props.jwt) {
106
+ setWelcomeBackName(cookies.name);
107
+ login({ jwt: props.jwt });
108
+ setPendingAutoLogin(true);
109
+ } else {
110
+ setPendingAutoLogin(false);
111
+ }
112
+ }
113
+ };
114
+
115
+ const handleLoginSuccess = async (resp: LoginResponseInterface) => {
116
+ userJwtBackup = resp.user.jwt;
117
+ setUserJwt(userJwtBackup);
118
+ ApiHelper.setDefaultPermissions(resp.user.jwt);
119
+ setLoginResponse(resp)
120
+ resp.userChurches.forEach(uc => { if (!uc.apis) uc.apis = []; });
121
+ UserHelper.userChurches = resp.userChurches;
122
+
123
+ setCookie("name", `${resp.user.firstName} ${resp.user.lastName}`, { path: "/" });
124
+ setCookie("email", resp.user.email, { path: "/" });
125
+ UserHelper.user = resp.user;
126
+
127
+ // JWT church selection is handled by the server response, no client-side decoding needed
128
+
129
+ const search = new URLSearchParams(location?.search);
130
+ const churchIdInParams = search.get("churchId");
131
+
132
+ if (props.keyName) selectChurchByKeyName();
133
+ else if (churchIdInParams) selectChurch(churchIdInParams);
134
+ else if (cookies.lastChurchId && ArrayHelper.getOne(resp.userChurches, "church.id", cookies.lastChurchId)) {
135
+ selectedChurchId = cookies.lastChurchId;
136
+ selectChurchById();
137
+ }
138
+ else setShowSelectModal(true);
139
+ }
140
+
141
+ const selectChurchById = async () => {
142
+ await UserHelper.selectChurch(props.context, selectedChurchId, undefined);
143
+
144
+ setCookie("lastChurchId", selectedChurchId, { path: "/" });
145
+
146
+ if (registeredChurch) {
147
+ AnalyticsHelper.logEvent("Church", "Register", UserHelper.currentUserChurch.church.name);
148
+ try {
149
+ if (CommonEnvironmentHelper.GoogleAnalyticsTag && typeof (window) !== "undefined") {
150
+ ga4.gtag("event", "conversion", { send_to: "AW-427967381/Ba2qCLrXgJoYEJWHicwB" });
151
+ }
152
+ } catch { }
153
+ }
154
+ else AnalyticsHelper.logEvent("Church", "Select", UserHelper.currentUserChurch.church.name);
155
+
156
+ if (props.churchRegisteredCallback && registeredChurch) {
157
+ await props.churchRegisteredCallback(registeredChurch)
158
+ registeredChurch = null;
159
+ login({ jwt: userJwt || userJwtBackup });
160
+ } else await continueLoginProcess();
161
+ }
162
+
163
+ const selectChurchByKeyName = async () => {
164
+ if (!ArrayHelper.getOne(UserHelper.userChurches, "church.subDomain", props.keyName)) {
165
+ const userChurch: LoginUserChurchInterface = await ApiHelper.post("/churches/select", { subDomain: props.keyName }, "MembershipApi");
166
+ UserHelper.setupApiHelper(userChurch);
167
+ setCookie("lastChurchId", userChurch.church.id, { path: "/" });
168
+ //create/claim the person record and relogin
169
+ await ApiHelper.get("/people/claim/" + userChurch.church.id, "MembershipApi");
170
+ login({ jwt: userJwt || userJwtBackup });
171
+ return;
172
+ }
173
+ await UserHelper.selectChurch(props.context, undefined, props.keyName);
174
+ const selectedChurch = ArrayHelper.getOne(UserHelper.userChurches, "church.subDomain", props.keyName);
175
+ if (selectedChurch) setCookie("lastChurchId", selectedChurch.church.id, { path: "/" });
176
+ await continueLoginProcess()
177
+ return;
178
+ }
179
+
180
+ async function continueLoginProcess() {
181
+ if (UserHelper.currentUserChurch) {
182
+ UserHelper.currentUserChurch.apis.forEach(api => {
183
+ if (api.keyName === "MembershipApi") setCookie("jwt", api.jwt, { path: "/" });
184
+ })
185
+ try {
186
+ if (UserHelper.currentUserChurch.church.id) ApiHelper.patch(`/userChurch/${UserHelper.user.id}`, { churchId: UserHelper.currentUserChurch.church.id, appName: props.appName, lastAccessed: new Date() }, "MembershipApi")
187
+ } catch (e) {
188
+ console.log("Could not update user church accessed date")
189
+ }
190
+ }
191
+
192
+ props.context.setUser(UserHelper.user);
193
+ props.context.setUserChurches(UserHelper.userChurches)
194
+ props.context.setUserChurch(UserHelper.currentUserChurch)
195
+
196
+ // Get or claim person before proceeding
197
+ let person;
198
+ try {
199
+ person = await ApiHelper.get(`/people/${UserHelper.currentUserChurch.person?.id}`, "MembershipApi");
200
+ if (person) props.context.setPerson(person);
201
+ } catch {
202
+ console.log("claiming person");
203
+ person = await ApiHelper.get("/people/claim/" + UserHelper.currentUserChurch.church.id, "MembershipApi");
204
+ props.context.setPerson(person);
205
+ }
206
+
207
+ // Handle redirect with actual data
208
+ const search = new URLSearchParams(location?.search);
209
+ const returnUrl = search.get("returnUrl") || props.returnUrl || "/";
210
+ if (returnUrl && typeof window !== "undefined") {
211
+ // Use handleRedirect function if available, otherwise fallback to window.location
212
+ if (props.handleRedirect) {
213
+ console.log('Login handleRedirect - Passing userChurches:', UserHelper.userChurches);
214
+ props.handleRedirect(returnUrl, UserHelper.user, person, UserHelper.currentUserChurch, UserHelper.userChurches);
215
+ } else {
216
+ window.location.href = returnUrl;
217
+ }
218
+ }
219
+ }
220
+
221
+ async function selectChurch(churchId: string) {
222
+ try {
223
+ setErrors([])
224
+ selectedChurchId = churchId;
225
+ setCookie("lastChurchId", churchId, { path: "/" });
226
+ if (!ArrayHelper.getOne(UserHelper.userChurches, "church.id", churchId)) {
227
+ const userChurch: LoginUserChurchInterface = await ApiHelper.post("/churches/select", { churchId: churchId }, "MembershipApi");
228
+ UserHelper.setupApiHelper(userChurch);
229
+
230
+ //create/claim the person record and relogin
231
+ await ApiHelper.get("/people/claim/" + churchId, "MembershipApi");
232
+ login({ jwt: userJwt || userJwtBackup });
233
+ return;
234
+ }
235
+ UserHelper.selectChurch(props.context, churchId, null).then(() => { continueLoginProcess() });
236
+ } catch (err) {
237
+ console.log("Error in selecting church: ", err)
238
+ setErrors([Locale.label("login.validate.selectingChurch")])
239
+ loginFormRef?.current?.setSubmitting(false);
240
+ }
241
+
242
+ }
243
+
244
+ const handleLoginErrors = (errors: string[]) => {
245
+ setWelcomeBackName("");
246
+ console.log(errors);
247
+ setErrors([Locale.label("login.validate.invalid")]);
248
+ }
249
+
250
+ const login = async (data: any) => {
251
+ setErrors([])
252
+ setIsSubmitting(true);
253
+ try {
254
+ console.log("Logging in with data: ", data, "/users/login", ApiHelper.getConfig("MembershipApi"));
255
+ const resp: LoginResponseInterface = await ApiHelper.postAnonymous("/users/login", data, "MembershipApi");
256
+ setIsSubmitting(false);
257
+ handleLoginSuccess(resp);
258
+ } catch (e: any) {
259
+ setPendingAutoLogin(false);
260
+ setWelcomeBackName("");
261
+ if (!data.jwt) handleLoginErrors([e.toString()]);
262
+ setIsSubmitting(false);
263
+ }
264
+ };;
265
+
266
+ const getWelcomeBack = () => { if (welcomeBackName !== "") return (<><Alert severity="info"><div dangerouslySetInnerHTML={{ __html: Locale.label("login.welcomeName")?.replace("{}", welcomeBackName) }} /></Alert><Loading /></>); }
267
+ const getCheckEmail = () => { if (new URLSearchParams(location?.search).get("checkEmail") === "1") return <Alert severity="info">{Locale.label("login.registerThankYou")}</Alert> }
268
+ const handleRegisterCallback = () => { setShowForgot(false); setShowRegister(true); }
269
+ const handleLoginCallback = () => { setShowForgot(false); setShowRegister(false); }
270
+ const handleChurchRegistered = (church: ChurchInterface) => { registeredChurch = church; setShowRegister(false); console.log("Updated VERSION********") }
271
+
272
+ const getInputBox = () => {
273
+ if (showRegister) return (
274
+
275
+ <Register updateErrors={setErrors} appName={props.appName} appUrl={cleanAppUrl()} loginCallback={handleLoginCallback} userRegisteredCallback={props.userRegisteredCallback} />
276
+
277
+ );
278
+ else if (showForgot) return (<Forgot registerCallback={handleRegisterCallback} loginCallback={handleLoginCallback} />);
279
+ else if (props.auth) return (<LoginSetPassword setErrors={setErrors} setShowForgot={setShowForgot} isSubmitting={isSubmitting} auth={props.auth} login={login} appName={props.appName} appUrl={cleanAppUrl()} />)
280
+ else return <Login setShowRegister={setShowRegister} setShowForgot={setShowForgot} setErrors={setErrors} isSubmitting={isSubmitting} login={login} mainContainerCssProps={loginContainerCssProps} defaultEmail={props.defaultEmail} defaultPassword={props.defaultPassword} showFooter={props.showFooter} />;
281
+ }
282
+
283
+ React.useEffect(init, []); //eslint-disable-line
284
+
285
+ return (
286
+ <>
287
+ <ErrorMessages errors={errors} />
288
+ {getWelcomeBack()}
289
+ {getCheckEmail()}
290
+ {!pendingAutoLogin && getInputBox()}
291
+ <SelectChurchModal show={showSelectModal} userChurches={loginResponse?.userChurches} selectChurch={selectChurch} registeredChurchCallback={handleChurchRegistered} errors={errors} appName={props.appName} handleRedirect={props.handleRedirect} />
292
+ <FloatingSupport appName={props.appName} />
293
+ </>
294
+ );
295
+
296
+ };
297
+
298
+ export const LoginPage: React.FC<Props> = (props) => {
299
+ // Always wrap with CookiesProvider to ensure context is available
300
+ return (
301
+ <CookiesProvider defaultSetOptions={{ path: '/' }}>
302
+ <LoginPageContent {...props} />
303
+ </CookiesProvider>
304
+ );
305
+ };