@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.
@@ -1,88 +1,88 @@
1
- "use client";
2
-
3
- import React from "react";
4
- import { ChurchInterface, LoginUserChurchInterface } from "@churchapps/helpers";
5
- import { SelectChurchSearch } from "./SelectChurchSearch";
6
- import { SelectableChurch } from "./SelectableChurch";
7
- import { ErrorMessages } from "@churchapps/apphelper"
8
- import { Dialog, DialogContent, DialogTitle, IconButton, Tooltip, Box } from "@mui/material";
9
- import { Logout } from "@mui/icons-material";
10
- import { Locale } from "../helpers";
11
-
12
- interface Props {
13
- appName: string,
14
- show: boolean,
15
- userChurches?: LoginUserChurchInterface[],
16
- selectChurch: (churchId: string) => void,
17
- registeredChurchCallback?: (church: ChurchInterface) => void,
18
- errors?: string[],
19
- handleRedirect?: (url: string) => void
20
- }
21
-
22
- export const SelectChurchModal: React.FC<Props> = (props) => {
23
- const [showSearch, setShowSearch] = React.useState(false);
24
-
25
- const handleClose = () => {
26
- window.location.reload();
27
- }
28
-
29
- const getContents = () => {
30
- if (showSearch || props.userChurches?.length === 0) return <SelectChurchSearch selectChurch={props.selectChurch} registeredChurchCallback={props.registeredChurchCallback} appName={props.appName} />
31
- else return (<>
32
- {props.userChurches?.map(uc => (<SelectableChurch church={uc.church} selectChurch={props.selectChurch} key={uc.church.id} />))}
33
- <Box sx={{ textAlign: "center", mt: 3 }}>
34
- <button
35
- type="button"
36
- style={{
37
- display: "inline-block",
38
- background: "none",
39
- border: "none",
40
- color: "#3b82f6",
41
- cursor: "pointer",
42
- textDecoration: "none",
43
- fontSize: "1rem",
44
- transition: "all 0.2s ease"
45
- }}
46
- onClick={(e) => { e.preventDefault(); setShowSearch(true); }}
47
- onMouseEnter={(e) => e.currentTarget.style.textDecoration = "underline"}
48
- onMouseLeave={(e) => e.currentTarget.style.textDecoration = "none"}
49
- >
50
- {Locale.label("selectChurch.another")}
51
- </button>
52
- </Box>
53
- </>);
54
- }
55
-
56
- return (
57
- <Dialog
58
- open={props.show}
59
- onClose={handleClose}
60
- aria-labelledby="select-church-title"
61
- aria-describedby="select-church-content"
62
- >
63
- <DialogTitle id="select-church-title" sx={{ fontSize: "1.5rem", fontWeight: 600 }}>
64
- {Locale.label("selectChurch.selectChurch")}
65
- </DialogTitle>
66
- <Tooltip title="Logout" arrow>
67
- <IconButton
68
- sx={{ position: "absolute", right: 8, top: 8 }}
69
- color="error"
70
- aria-label="Logout"
71
- onClick={() => {
72
- // Use handleRedirect function if available, otherwise fallback to window.location
73
- if (props.handleRedirect) {
74
- props.handleRedirect("/logout");
75
- } else {
76
- window.location.href = "/logout";
77
- }
78
- }}>
79
- <Logout />
80
- </IconButton>
81
- </Tooltip>
82
- <DialogContent id="select-church-content" sx={{ width: 700, maxWidth: "100%", px: 2, py: 2 }}>
83
- <ErrorMessages errors={props.errors} />
84
- {getContents()}
85
- </DialogContent>
86
- </Dialog>
87
- );
88
- };
1
+ "use client";
2
+
3
+ import React from "react";
4
+ import { ChurchInterface, LoginUserChurchInterface } from "@churchapps/helpers";
5
+ import { SelectChurchSearch } from "./SelectChurchSearch";
6
+ import { SelectableChurch } from "./SelectableChurch";
7
+ import { ErrorMessages } from "@churchapps/apphelper"
8
+ import { Dialog, DialogContent, DialogTitle, IconButton, Tooltip, Box } from "@mui/material";
9
+ import { Logout } from "@mui/icons-material";
10
+ import { Locale } from "../helpers";
11
+
12
+ interface Props {
13
+ appName: string,
14
+ show: boolean,
15
+ userChurches?: LoginUserChurchInterface[],
16
+ selectChurch: (churchId: string) => void,
17
+ registeredChurchCallback?: (church: ChurchInterface) => void,
18
+ errors?: string[],
19
+ handleRedirect?: (url: string) => void
20
+ }
21
+
22
+ export const SelectChurchModal: React.FC<Props> = (props) => {
23
+ const [showSearch, setShowSearch] = React.useState(false);
24
+
25
+ const handleClose = () => {
26
+ window.location.reload();
27
+ }
28
+
29
+ const getContents = () => {
30
+ if (showSearch || props.userChurches?.length === 0) return <SelectChurchSearch selectChurch={props.selectChurch} registeredChurchCallback={props.registeredChurchCallback} appName={props.appName} />
31
+ else return (<>
32
+ {props.userChurches?.map(uc => (<SelectableChurch church={uc.church} selectChurch={props.selectChurch} key={uc.church.id} />))}
33
+ <Box sx={{ textAlign: "center", mt: 3 }}>
34
+ <button
35
+ type="button"
36
+ style={{
37
+ display: "inline-block",
38
+ background: "none",
39
+ border: "none",
40
+ color: "#3b82f6",
41
+ cursor: "pointer",
42
+ textDecoration: "none",
43
+ fontSize: "1rem",
44
+ transition: "all 0.2s ease"
45
+ }}
46
+ onClick={(e) => { e.preventDefault(); setShowSearch(true); }}
47
+ onMouseEnter={(e) => e.currentTarget.style.textDecoration = "underline"}
48
+ onMouseLeave={(e) => e.currentTarget.style.textDecoration = "none"}
49
+ >
50
+ {Locale.label("selectChurch.another")}
51
+ </button>
52
+ </Box>
53
+ </>);
54
+ }
55
+
56
+ return (
57
+ <Dialog
58
+ open={props.show}
59
+ onClose={handleClose}
60
+ aria-labelledby="select-church-title"
61
+ aria-describedby="select-church-content"
62
+ >
63
+ <DialogTitle id="select-church-title" sx={{ fontSize: "1.5rem", fontWeight: 600 }}>
64
+ {Locale.label("selectChurch.selectChurch")}
65
+ </DialogTitle>
66
+ <Tooltip title="Logout" arrow>
67
+ <IconButton
68
+ sx={{ position: "absolute", right: 8, top: 8 }}
69
+ color="error"
70
+ aria-label="Logout"
71
+ onClick={() => {
72
+ // Use handleRedirect function if available, otherwise fallback to window.location
73
+ if (props.handleRedirect) {
74
+ props.handleRedirect("/logout");
75
+ } else {
76
+ window.location.href = "/logout";
77
+ }
78
+ }}>
79
+ <Logout />
80
+ </IconButton>
81
+ </Tooltip>
82
+ <DialogContent id="select-church-content" sx={{ width: 700, maxWidth: "100%", px: 2, py: 2 }}>
83
+ <ErrorMessages errors={props.errors} />
84
+ {getContents()}
85
+ </DialogContent>
86
+ </Dialog>
87
+ );
88
+ };
@@ -1,88 +1,88 @@
1
- "use client";
2
-
3
- import React from "react";
4
- import { ApiHelper } from "@churchapps/helpers";
5
- import { Locale } from "../helpers";
6
- import { ChurchInterface, RegisterChurchRequestInterface } from "@churchapps/helpers";
7
- import { ErrorMessages, InputBox } from "@churchapps/apphelper"
8
- import { Grid, TextField } from "@mui/material";
9
-
10
- interface Props {
11
- initialChurchName: string,
12
- registeredChurchCallback?: (church: ChurchInterface) => void,
13
- selectChurch: (churchId: string) => void,
14
- appName: string
15
- }
16
-
17
- export const SelectChurchRegister: React.FC<Props> = (props) => {
18
- const suggestSubDomain = (name: string) => {
19
- let result = name.toLowerCase().replaceAll("christian", "").replaceAll("church", "").replaceAll(" ", "");
20
- return result;
21
- }
22
-
23
- const [church, setChurch] = React.useState<RegisterChurchRequestInterface>({ name: props.initialChurchName, appName: props.appName, subDomain: suggestSubDomain(props.initialChurchName) });
24
- const [errors, setErrors] = React.useState([]);
25
- const [isSubmitting, setIsSubmitting] = React.useState(false);
26
-
27
- const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
28
- const c = { ...church }
29
- switch (e.target.name) {
30
- case "churchName": c.name = e.target.value; break;
31
- case "subDomain": c.subDomain = e.target.value; break;
32
- case "address1": c.address1 = e.target.value; break;
33
- case "address2": c.address2 = e.target.value; break;
34
- case "city": c.city = e.target.value; break;
35
- case "state": c.state = e.target.value; break;
36
- case "zip": c.zip = e.target.value; break;
37
- case "country": c.country = e.target.value; break;
38
- }
39
- setChurch(c);
40
- }
41
-
42
- const validate = () => {
43
- let errors = [];
44
- if (!church.name?.trim()) errors.push(Locale.label("selectChurch.validate.name"));
45
- if (!church.address1?.trim()) errors.push(Locale.label("selectChurch.validate.address"));
46
- if (!church.city?.trim()) errors.push(Locale.label("selectChurch.validate.city"));
47
- if (!church.state?.trim()) errors.push(Locale.label("selectChurch.validate.state"));
48
- if (!church.zip?.trim()) errors.push(Locale.label("selectChurch.validate.zip"));
49
- if (!church.country?.trim()) errors.push(Locale.label("selectChurch.validate.country"));
50
- setErrors(errors);
51
- return errors.length === 0;
52
- }
53
-
54
- const handleSave = () => {
55
- if (validate()) {
56
- setIsSubmitting(true);
57
- const c = { ...church };
58
- if (!c.subDomain) c.subDomain = suggestSubDomain(c.name);
59
- ApiHelper.post("/churches/add", church, "MembershipApi").then(async (resp: any) => {
60
- setIsSubmitting(false);
61
- if (resp.errors !== undefined) setErrors(errors);
62
- else {
63
- if (props.registeredChurchCallback) props.registeredChurchCallback(resp);
64
- props.selectChurch(resp.id);
65
- }
66
- });
67
- }
68
- }
69
-
70
- return (
71
- <InputBox id="churchBox" saveFunction={handleSave} headerText={Locale.label("selectChurch.register")} headerIcon="church" isSubmitting={isSubmitting}>
72
- <ErrorMessages errors={errors} />
73
- <TextField required fullWidth name="churchName" label={Locale.label("selectChurch.name")} value={church.name} onChange={handleChange} />
74
-
75
- <TextField required fullWidth name="address1" label={Locale.label("selectChurch.address1")} value={church.address1} onChange={handleChange} />
76
- <Grid container spacing={3}>
77
- <Grid size={6}><TextField fullWidth name="address2" label={Locale.label("selectChurch.address2")} value={church.address2} onChange={handleChange} /></Grid>
78
- <Grid size={6}><TextField required fullWidth name="city" label={Locale.label("selectChurch.city")} value={church.city} onChange={handleChange} /></Grid>
79
- </Grid>
80
- <Grid container spacing={3}>
81
- <Grid size={6}><TextField required fullWidth name="state" label={Locale.label("selectChurch.state")} value={church.state} onChange={handleChange} /></Grid>
82
- <Grid size={6}><TextField required fullWidth name="zip" label={Locale.label("selectChurch.zip")} value={church.zip} onChange={handleChange} /></Grid>
83
- </Grid>
84
- <TextField required fullWidth name="country" label={Locale.label("selectChurch.country")} value={church.country} onChange={handleChange} />
85
- </InputBox>
86
- );
87
- };
88
-
1
+ "use client";
2
+
3
+ import React from "react";
4
+ import { ApiHelper } from "@churchapps/helpers";
5
+ import { Locale } from "../helpers";
6
+ import { ChurchInterface, RegisterChurchRequestInterface } from "@churchapps/helpers";
7
+ import { ErrorMessages, InputBox } from "@churchapps/apphelper"
8
+ import { Grid, TextField } from "@mui/material";
9
+
10
+ interface Props {
11
+ initialChurchName: string,
12
+ registeredChurchCallback?: (church: ChurchInterface) => void,
13
+ selectChurch: (churchId: string) => void,
14
+ appName: string
15
+ }
16
+
17
+ export const SelectChurchRegister: React.FC<Props> = (props) => {
18
+ const suggestSubDomain = (name: string) => {
19
+ let result = name.toLowerCase().replaceAll("christian", "").replaceAll("church", "").replaceAll(" ", "");
20
+ return result;
21
+ }
22
+
23
+ const [church, setChurch] = React.useState<RegisterChurchRequestInterface>({ name: props.initialChurchName, appName: props.appName, subDomain: suggestSubDomain(props.initialChurchName) });
24
+ const [errors, setErrors] = React.useState([]);
25
+ const [isSubmitting, setIsSubmitting] = React.useState(false);
26
+
27
+ const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
28
+ const c = { ...church }
29
+ switch (e.target.name) {
30
+ case "churchName": c.name = e.target.value; break;
31
+ case "subDomain": c.subDomain = e.target.value; break;
32
+ case "address1": c.address1 = e.target.value; break;
33
+ case "address2": c.address2 = e.target.value; break;
34
+ case "city": c.city = e.target.value; break;
35
+ case "state": c.state = e.target.value; break;
36
+ case "zip": c.zip = e.target.value; break;
37
+ case "country": c.country = e.target.value; break;
38
+ }
39
+ setChurch(c);
40
+ }
41
+
42
+ const validate = () => {
43
+ let errors = [];
44
+ if (!church.name?.trim()) errors.push(Locale.label("selectChurch.validate.name"));
45
+ if (!church.address1?.trim()) errors.push(Locale.label("selectChurch.validate.address"));
46
+ if (!church.city?.trim()) errors.push(Locale.label("selectChurch.validate.city"));
47
+ if (!church.state?.trim()) errors.push(Locale.label("selectChurch.validate.state"));
48
+ if (!church.zip?.trim()) errors.push(Locale.label("selectChurch.validate.zip"));
49
+ if (!church.country?.trim()) errors.push(Locale.label("selectChurch.validate.country"));
50
+ setErrors(errors);
51
+ return errors.length === 0;
52
+ }
53
+
54
+ const handleSave = () => {
55
+ if (validate()) {
56
+ setIsSubmitting(true);
57
+ const c = { ...church };
58
+ if (!c.subDomain) c.subDomain = suggestSubDomain(c.name);
59
+ ApiHelper.post("/churches/add", church, "MembershipApi").then(async (resp: any) => {
60
+ setIsSubmitting(false);
61
+ if (resp.errors !== undefined) setErrors(errors);
62
+ else {
63
+ if (props.registeredChurchCallback) props.registeredChurchCallback(resp);
64
+ props.selectChurch(resp.id);
65
+ }
66
+ });
67
+ }
68
+ }
69
+
70
+ return (
71
+ <InputBox id="churchBox" saveFunction={handleSave} headerText={Locale.label("selectChurch.register")} headerIcon="church" isSubmitting={isSubmitting}>
72
+ <ErrorMessages errors={errors} />
73
+ <TextField required fullWidth name="churchName" label={Locale.label("selectChurch.name")} value={church.name} onChange={handleChange} />
74
+
75
+ <TextField required fullWidth name="address1" label={Locale.label("selectChurch.address1")} value={church.address1} onChange={handleChange} />
76
+ <Grid container spacing={3}>
77
+ <Grid size={6}><TextField fullWidth name="address2" label={Locale.label("selectChurch.address2")} value={church.address2} onChange={handleChange} /></Grid>
78
+ <Grid size={6}><TextField required fullWidth name="city" label={Locale.label("selectChurch.city")} value={church.city} onChange={handleChange} /></Grid>
79
+ </Grid>
80
+ <Grid container spacing={3}>
81
+ <Grid size={6}><TextField required fullWidth name="state" label={Locale.label("selectChurch.state")} value={church.state} onChange={handleChange} /></Grid>
82
+ <Grid size={6}><TextField required fullWidth name="zip" label={Locale.label("selectChurch.zip")} value={church.zip} onChange={handleChange} /></Grid>
83
+ </Grid>
84
+ <TextField required fullWidth name="country" label={Locale.label("selectChurch.country")} value={church.country} onChange={handleChange} />
85
+ </InputBox>
86
+ );
87
+ };
88
+
@@ -1,85 +1,85 @@
1
- "use client";
2
-
3
- import { Button, TextField } from "@mui/material";
4
- import React from "react";
5
- import { ApiHelper } from "@churchapps/helpers";
6
- import { Locale } from "../helpers";
7
- import { ChurchInterface } from "@churchapps/helpers";
8
- import { SelectableChurch } from "./SelectableChurch";
9
- import { SelectChurchRegister } from "./SelectChurchRegister";
10
-
11
- interface Props {
12
- selectChurch: (churchId: string) => void,
13
- registeredChurchCallback?: (church: ChurchInterface) => void,
14
- appName: string
15
- }
16
-
17
- export const SelectChurchSearch: React.FC<Props> = (props) => {
18
- const [searchText, setSearchText] = React.useState("");
19
- const [churches, setChurches] = React.useState<ChurchInterface[]>(null);
20
- const [showRegister, setShowRegister] = React.useState(false);
21
-
22
- const handleSubmit = (e: React.MouseEvent) => {
23
- if (e !== null) e.preventDefault();
24
- let term = searchText.trim();
25
- ApiHelper.post("/churches/search", { name: term }, "MembershipApi").then((data: any) => setChurches(data));
26
- }
27
-
28
- const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => setSearchText(e.currentTarget.value);
29
-
30
- const handleKeyDown = (e: React.KeyboardEvent<any>) => { if (e.key === "Enter") { e.preventDefault(); handleSubmit(null); } }
31
-
32
- const handleRegisterClick = (e: React.MouseEvent) => {
33
- e.preventDefault();
34
- if (window.confirm(Locale.label("selectChurch.confirmRegister"))) {
35
- setShowRegister(true);
36
- }
37
- }
38
-
39
- const getRegisterLink = () => (
40
- <div>
41
- <button
42
- type="button"
43
- style={{
44
- display: "block",
45
- textAlign: "center",
46
- background: "none",
47
- border: "none",
48
- color: "#3b82f6",
49
- cursor: "pointer",
50
- textDecoration: "underline",
51
- width: "100%"
52
- }}
53
- onClick={handleRegisterClick}
54
- >
55
- {Locale.label("selectChurch.register")}
56
- </button>
57
- </div>
58
- )
59
-
60
- const getChurches = () => {
61
- const result: React.ReactElement[] = [];
62
- churches.forEach(church => {
63
- result.push(<SelectableChurch church={church} selectChurch={props.selectChurch} />);
64
- });
65
- result.push(getRegisterLink());
66
- return result;
67
- }
68
-
69
- const getResults = () => {
70
- if (churches === null) return;
71
- else if (churches.length === 0) return <><p>{Locale.label("selectChurch.noMatches")}</p>{getRegisterLink()}</>
72
- else return getChurches();
73
- }
74
-
75
- if (showRegister) return (<SelectChurchRegister selectChurch={props.selectChurch} registeredChurchCallback={props.registeredChurchCallback} appName={props.appName} initialChurchName={searchText} />)
76
- else return (
77
- <>
78
- <TextField fullWidth name="searchText" label="Name" value={searchText} onChange={handleChange} onKeyDown={handleKeyDown}
79
- InputProps={{ endAdornment: <Button variant="contained" id="searchButton" data-testid="search-button" onClick={handleSubmit}>{Locale.label("common.search")}</Button> }}
80
- />
81
- {getResults()}
82
- </>
83
-
84
- );
85
- };
1
+ "use client";
2
+
3
+ import { Button, TextField } from "@mui/material";
4
+ import React from "react";
5
+ import { ApiHelper } from "@churchapps/helpers";
6
+ import { Locale } from "../helpers";
7
+ import { ChurchInterface } from "@churchapps/helpers";
8
+ import { SelectableChurch } from "./SelectableChurch";
9
+ import { SelectChurchRegister } from "./SelectChurchRegister";
10
+
11
+ interface Props {
12
+ selectChurch: (churchId: string) => void,
13
+ registeredChurchCallback?: (church: ChurchInterface) => void,
14
+ appName: string
15
+ }
16
+
17
+ export const SelectChurchSearch: React.FC<Props> = (props) => {
18
+ const [searchText, setSearchText] = React.useState("");
19
+ const [churches, setChurches] = React.useState<ChurchInterface[]>(null);
20
+ const [showRegister, setShowRegister] = React.useState(false);
21
+
22
+ const handleSubmit = (e: React.MouseEvent) => {
23
+ if (e !== null) e.preventDefault();
24
+ let term = searchText.trim();
25
+ ApiHelper.post("/churches/search", { name: term }, "MembershipApi").then((data: any) => setChurches(data));
26
+ }
27
+
28
+ const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => setSearchText(e.currentTarget.value);
29
+
30
+ const handleKeyDown = (e: React.KeyboardEvent<any>) => { if (e.key === "Enter") { e.preventDefault(); handleSubmit(null); } }
31
+
32
+ const handleRegisterClick = (e: React.MouseEvent) => {
33
+ e.preventDefault();
34
+ if (window.confirm(Locale.label("selectChurch.confirmRegister"))) {
35
+ setShowRegister(true);
36
+ }
37
+ }
38
+
39
+ const getRegisterLink = () => (
40
+ <div>
41
+ <button
42
+ type="button"
43
+ style={{
44
+ display: "block",
45
+ textAlign: "center",
46
+ background: "none",
47
+ border: "none",
48
+ color: "#3b82f6",
49
+ cursor: "pointer",
50
+ textDecoration: "underline",
51
+ width: "100%"
52
+ }}
53
+ onClick={handleRegisterClick}
54
+ >
55
+ {Locale.label("selectChurch.register")}
56
+ </button>
57
+ </div>
58
+ )
59
+
60
+ const getChurches = () => {
61
+ const result: React.ReactElement[] = [];
62
+ churches.forEach(church => {
63
+ result.push(<SelectableChurch church={church} selectChurch={props.selectChurch} />);
64
+ });
65
+ result.push(getRegisterLink());
66
+ return result;
67
+ }
68
+
69
+ const getResults = () => {
70
+ if (churches === null) return;
71
+ else if (churches.length === 0) return <><p>{Locale.label("selectChurch.noMatches")}</p>{getRegisterLink()}</>
72
+ else return getChurches();
73
+ }
74
+
75
+ if (showRegister) return (<SelectChurchRegister selectChurch={props.selectChurch} registeredChurchCallback={props.registeredChurchCallback} appName={props.appName} initialChurchName={searchText} />)
76
+ else return (
77
+ <>
78
+ <TextField fullWidth name="searchText" label="Name" value={searchText} onChange={handleChange} onKeyDown={handleKeyDown}
79
+ InputProps={{ endAdornment: <Button variant="contained" id="searchButton" data-testid="search-button" onClick={handleSubmit}>{Locale.label("common.search")}</Button> }}
80
+ />
81
+ {getResults()}
82
+ </>
83
+
84
+ );
85
+ };