@churchapps/apphelper 0.4.8 → 0.4.10

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 (139) hide show
  1. package/b1app-specific-components.md +146 -0
  2. package/component-usage-analysis.md +169 -0
  3. package/dist/components/ImageEditor.d.ts +0 -1
  4. package/dist/components/ImageEditor.d.ts.map +1 -1
  5. package/dist/components/ImageEditor.js +1 -1
  6. package/dist/components/ImageEditor.js.map +1 -1
  7. package/dist/components/index.d.ts +0 -3
  8. package/dist/components/index.d.ts.map +1 -1
  9. package/dist/components/index.js +1 -6
  10. package/dist/components/index.js.map +1 -1
  11. package/dist/components/markdownEditor/IconNamesList.d.ts.map +1 -0
  12. package/dist/components/markdownEditor/IconNamesList.js +16 -0
  13. package/dist/components/markdownEditor/IconNamesList.js.map +1 -0
  14. package/dist/components/markdownEditor/plugins/customLink/CustomLinkNodeTransformer.js +1 -1
  15. package/dist/components/markdownEditor/plugins/customLink/CustomLinkNodeTransformer.js.map +1 -1
  16. package/dist/components/markdownEditor/plugins/emoji/EmojiNodeTransform.js +1 -1
  17. package/dist/components/markdownEditor/plugins/emoji/EmojiNodeTransform.js.map +1 -1
  18. package/dist/components/markdownEditor/plugins/emoji/EmojiPickerPlugin.js +1 -1
  19. package/dist/components/markdownEditor/plugins/emoji/EmojiPickerPlugin.js.map +1 -1
  20. package/dist/components/markdownEditor/plugins/emoji/EmojisPlugin.js +1 -1
  21. package/dist/components/markdownEditor/plugins/emoji/EmojisPlugin.js.map +1 -1
  22. package/dist/components/notes/index.d.ts +0 -2
  23. package/dist/components/notes/index.d.ts.map +1 -1
  24. package/dist/components/notes/index.js +1 -5
  25. package/dist/components/notes/index.js.map +1 -1
  26. package/dist/donationComponents/components/BankForm.d.ts +14 -0
  27. package/dist/donationComponents/components/BankForm.d.ts.map +1 -0
  28. package/dist/donationComponents/components/BankForm.js +126 -0
  29. package/dist/donationComponents/components/BankForm.js.map +1 -0
  30. package/dist/donationComponents/components/CardForm.d.ts +13 -0
  31. package/dist/donationComponents/components/CardForm.d.ts.map +1 -0
  32. package/dist/donationComponents/components/CardForm.js +122 -0
  33. package/dist/donationComponents/components/CardForm.js.map +1 -0
  34. package/dist/donationComponents/components/DonationForm.d.ts +15 -0
  35. package/dist/donationComponents/components/DonationForm.d.ts.map +1 -0
  36. package/dist/donationComponents/components/DonationForm.js +199 -0
  37. package/dist/donationComponents/components/DonationForm.js.map +1 -0
  38. package/dist/donationComponents/components/FundDonation.d.ts +12 -0
  39. package/dist/donationComponents/components/FundDonation.d.ts.map +1 -0
  40. package/dist/donationComponents/components/FundDonation.js +32 -0
  41. package/dist/donationComponents/components/FundDonation.js.map +1 -0
  42. package/dist/donationComponents/components/FundDonations.d.ts +11 -0
  43. package/dist/donationComponents/components/FundDonations.d.ts.map +1 -0
  44. package/dist/donationComponents/components/FundDonations.js +33 -0
  45. package/dist/donationComponents/components/FundDonations.js.map +1 -0
  46. package/dist/donationComponents/components/PaymentMethods.d.ts +14 -0
  47. package/dist/donationComponents/components/PaymentMethods.d.ts.map +1 -0
  48. package/dist/donationComponents/components/PaymentMethods.js +84 -0
  49. package/dist/donationComponents/components/PaymentMethods.js.map +1 -0
  50. package/dist/donationComponents/components/RecurringDonations.d.ts +10 -0
  51. package/dist/donationComponents/components/RecurringDonations.d.ts.map +1 -0
  52. package/dist/donationComponents/components/RecurringDonations.js +93 -0
  53. package/dist/donationComponents/components/RecurringDonations.js.map +1 -0
  54. package/dist/donationComponents/components/RecurringDonationsEdit.d.ts +11 -0
  55. package/dist/donationComponents/components/RecurringDonationsEdit.d.ts.map +1 -0
  56. package/dist/donationComponents/components/RecurringDonationsEdit.js +66 -0
  57. package/dist/donationComponents/components/RecurringDonationsEdit.js.map +1 -0
  58. package/dist/donationComponents/components/index.d.ts +9 -0
  59. package/dist/donationComponents/components/index.d.ts.map +1 -0
  60. package/dist/donationComponents/components/index.js +20 -0
  61. package/dist/donationComponents/components/index.js.map +1 -0
  62. package/dist/donationComponents/index.d.ts +3 -0
  63. package/dist/donationComponents/index.d.ts.map +1 -0
  64. package/dist/donationComponents/index.js +21 -0
  65. package/dist/donationComponents/index.js.map +1 -0
  66. package/dist/donationComponents/modals/DonationPreviewModal.d.ts +15 -0
  67. package/dist/donationComponents/modals/DonationPreviewModal.d.ts.map +1 -0
  68. package/dist/donationComponents/modals/DonationPreviewModal.js +33 -0
  69. package/dist/donationComponents/modals/DonationPreviewModal.js.map +1 -0
  70. package/dist/index.d.ts +1 -0
  71. package/dist/index.d.ts.map +1 -1
  72. package/dist/index.js +1 -0
  73. package/dist/index.js.map +1 -1
  74. package/package.json +1 -1
  75. package/src/components/ImageEditor.tsx +1 -1
  76. package/src/components/index.tsx +0 -3
  77. package/src/components/markdownEditor/IconNamesList.ts +14 -0
  78. package/src/components/markdownEditor/plugins/customLink/CustomLinkNodeTransformer.tsx +1 -1
  79. package/src/components/markdownEditor/plugins/emoji/EmojiNodeTransform.ts +1 -1
  80. package/src/components/markdownEditor/plugins/emoji/EmojiPickerPlugin.tsx +1 -1
  81. package/src/components/markdownEditor/plugins/emoji/EmojisPlugin.tsx +1 -1
  82. package/src/components/notes/index.ts +0 -2
  83. package/src/donationComponents/components/BankForm.tsx +163 -0
  84. package/src/donationComponents/components/CardForm.tsx +104 -0
  85. package/src/donationComponents/components/DonationForm.tsx +260 -0
  86. package/src/donationComponents/components/FundDonation.tsx +59 -0
  87. package/src/donationComponents/components/FundDonations.tsx +44 -0
  88. package/src/donationComponents/components/PaymentMethods.tsx +133 -0
  89. package/src/donationComponents/components/RecurringDonations.tsx +117 -0
  90. package/src/donationComponents/components/RecurringDonationsEdit.tsx +96 -0
  91. package/src/donationComponents/components/index.tsx +8 -0
  92. package/src/donationComponents/index.ts +2 -0
  93. package/src/donationComponents/modals/DonationPreviewModal.tsx +70 -0
  94. package/src/index.ts +1 -0
  95. package/dist/components/B1ShareModal.d.ts +0 -9
  96. package/dist/components/B1ShareModal.d.ts.map +0 -1
  97. package/dist/components/B1ShareModal.js +0 -77
  98. package/dist/components/B1ShareModal.js.map +0 -1
  99. package/dist/components/gallery/GalleryModal.d.ts +0 -9
  100. package/dist/components/gallery/GalleryModal.d.ts.map +0 -1
  101. package/dist/components/gallery/GalleryModal.js +0 -111
  102. package/dist/components/gallery/GalleryModal.js.map +0 -1
  103. package/dist/components/gallery/StockPhotos.d.ts +0 -9
  104. package/dist/components/gallery/StockPhotos.d.ts.map +0 -1
  105. package/dist/components/gallery/StockPhotos.js +0 -79
  106. package/dist/components/gallery/StockPhotos.js.map +0 -1
  107. package/dist/components/gallery/index.d.ts +0 -2
  108. package/dist/components/gallery/index.d.ts.map +0 -1
  109. package/dist/components/gallery/index.js +0 -6
  110. package/dist/components/gallery/index.js.map +0 -1
  111. package/dist/components/iconPicker/IconNamesList.d.ts.map +0 -1
  112. package/dist/components/iconPicker/IconNamesList.js +0 -2241
  113. package/dist/components/iconPicker/IconNamesList.js.map +0 -1
  114. package/dist/components/iconPicker/IconPicker.d.ts +0 -6
  115. package/dist/components/iconPicker/IconPicker.d.ts.map +0 -1
  116. package/dist/components/iconPicker/IconPicker.js +0 -142
  117. package/dist/components/iconPicker/IconPicker.js.map +0 -1
  118. package/dist/components/notes/Conversation.d.ts +0 -10
  119. package/dist/components/notes/Conversation.d.ts.map +0 -1
  120. package/dist/components/notes/Conversation.js +0 -55
  121. package/dist/components/notes/Conversation.js.map +0 -1
  122. package/dist/components/notes/Conversations.d.ts +0 -10
  123. package/dist/components/notes/Conversations.d.ts.map +0 -1
  124. package/dist/components/notes/Conversations.js +0 -54
  125. package/dist/components/notes/Conversations.js.map +0 -1
  126. package/dist/components/notes/NewConversation.d.ts +0 -12
  127. package/dist/components/notes/NewConversation.d.ts.map +0 -1
  128. package/dist/components/notes/NewConversation.js +0 -54
  129. package/dist/components/notes/NewConversation.js.map +0 -1
  130. package/src/components/B1ShareModal.tsx +0 -104
  131. package/src/components/gallery/GalleryModal.tsx +0 -139
  132. package/src/components/gallery/StockPhotos.tsx +0 -75
  133. package/src/components/gallery/index.ts +0 -1
  134. package/src/components/iconPicker/IconNamesList.ts +0 -2240
  135. package/src/components/iconPicker/IconPicker.tsx +0 -160
  136. package/src/components/notes/Conversation.tsx +0 -84
  137. package/src/components/notes/Conversations.tsx +0 -60
  138. package/src/components/notes/NewConversation.tsx +0 -80
  139. /package/dist/components/{iconPicker → markdownEditor}/IconNamesList.d.ts +0 -0
@@ -1,160 +0,0 @@
1
- "use client";
2
-
3
- import * as React from "react";
4
- import { styled, Icon, InputBase, Typography, debounce, Grid, IconButton, Pagination, Stack } from "@mui/material";
5
- import MuiPaper from "@mui/material/Paper";
6
- import IconNamesList from "./IconNamesList"
7
- import { Locale } from "../../helpers";
8
- import FlexSearch from "flexsearch";
9
- const UPDATE_SEARCH_INDEX_WAIT_MS = 220;
10
-
11
- //const FlexSearch = require("flexsearch");
12
-
13
- const StyledIconSpan = styled("span")(({ theme }) => ({
14
- display: "inline-flex",
15
- flexDirection: "column",
16
- color: theme.palette.text.secondary,
17
- margin: "0 4px",
18
- "& > div": {
19
- display: "flex"
20
- },
21
- "& > div > *": {
22
- flexGrow: 1,
23
- fontSize: ".6rem",
24
- overflow: "hidden",
25
- textOverflow: "ellipsis",
26
- textAlign: "center",
27
- width: 0
28
- }
29
- }));
30
-
31
- const StyledIcon: any = styled(Icon)(({ theme }) => ({
32
- boxSizing: "content-box",
33
- cursor: "pointer",
34
- color: theme.palette.text.primary,
35
- borderRadius: theme.shape.borderRadius,
36
- transition: theme.transitions.create(["background-color", "box-shadow"], {
37
- duration: theme.transitions.duration.shortest
38
- }),
39
- padding: theme.spacing(1),
40
- margin: theme.spacing(0.5, 0),
41
- "&:hover": {
42
- backgroundColor: theme.palette.background.paper,
43
- boxShadow: theme.shadows[1]
44
- }
45
- }));
46
-
47
- const Icons = React.memo(function Icons(props: { icons: string[]; handleOpenClick: (name: string) => void; }) {
48
- const { icons, handleOpenClick } = props;
49
-
50
- const handleIconClick = (name: string) => {
51
- const camel = name.substring(0, 1).toLocaleLowerCase() + name.substring(1, name.length);
52
- const underscored = camel.replace(/[A-Z]/g, m => "_" + m.toLowerCase());
53
- handleOpenClick(underscored)
54
- }
55
-
56
- return (
57
- <div>
58
- {icons.map((icon) => (
59
- <StyledIconSpan key={icon}>
60
- <StyledIcon tabIndex={-1} sx={{ fontSize: "34px !important" }} onClick={() => { handleIconClick(icon) }} aria-label={`Select ${icon} icon`} data-testid={`icon-${icon}`}>
61
- {icon}
62
- </StyledIcon>
63
- </StyledIconSpan>
64
- ))}
65
- </div>
66
- );
67
- });
68
-
69
- const Paper = styled(MuiPaper)(({ theme }) => ({ padding: "2px 4px", display: "flex", alignItems: "center", marginBottom: theme.spacing(2), width: "100%" }));
70
-
71
- const Input = styled(InputBase)({ marginLeft: 8, flex: 1 });
72
-
73
- const searchIndex = new FlexSearch.Index({ tokenize: "full" });
74
- //const searchIndex = FlexSearch.create({ tokenize: "full" });
75
-
76
- function createSearchIndex() {
77
- // create component names from icons list
78
- const iconsAndComponentNames = IconNamesList.map(icon => {
79
- const split = icon.split("_");
80
- const capitalizedSplit = split.map(s => {
81
- if (isAlphabet(s[0])) {
82
- s = s[0].toUpperCase() + s.slice(1)
83
- }
84
- return s
85
- })
86
- return {
87
- iconName: icon,
88
- componentName: capitalizedSplit.join("")
89
- };
90
- })
91
-
92
- // create search index
93
- iconsAndComponentNames.forEach(icon => {
94
- let searchTerm = icon.iconName + " " + icon.componentName;
95
-
96
- searchIndex.addAsync(icon.iconName, searchTerm)
97
- //searchIndex.add(searchTerm);
98
- })
99
-
100
- }
101
-
102
- function isAlphabet(character: string) {
103
- return /[a-zA-Z]/.test(character);
104
- }
105
-
106
- createSearchIndex();
107
-
108
- type Props = {
109
- onSelect: (iconName: string) => void;
110
- };
111
-
112
- const defaultIcons = ["person", "group", "groups", "contact_mail", "mail", "church", "favorite", "volunteer_activism", "link", "home", "apps", "web", "public", "rss_feed", "videocam", "live_tv", "music_note", "menu_book", "star", "accessible", "woman", "man", "child_care", "handshake", "location_on", "restaurant", "local_cafe" ];
113
-
114
- export function IconPicker(props: Props) {
115
- const pageSize = 27;
116
- const [keys, setKeys] = React.useState<any[] | null>(null);
117
- const [query, setQuery] = React.useState("");
118
- const [page, setPage] = React.useState(1);
119
-
120
- const updateSearchResults = React.useMemo(
121
- () =>
122
- debounce((value) => {
123
- if (value === "") setKeys(defaultIcons);
124
- else searchIndex.searchAsync(value, { limit: 3000 }).then((results: any) => { setKeys(results); setPage(1); });
125
- //else searchIndex.search(value, { limit: 3000 }).then((results: any) => { setKeys(results); setPage(1); });
126
- }, UPDATE_SEARCH_INDEX_WAIT_MS),
127
- []
128
- );
129
-
130
- React.useEffect(() => { updateSearchResults(query); return () => { updateSearchResults.clear(); }; }, [query, updateSearchResults]);
131
-
132
- function paged<T>(array: Array<T>, p: number) {
133
- return array.slice((p - 1) * pageSize, p * pageSize);
134
- }
135
-
136
- const icons = keys || IconNamesList;
137
-
138
- const pagesCount = Math.ceil(icons.length / pageSize);
139
-
140
- return (
141
- <Grid container sx={{ minHeight: 360, padding: "16px" }}>
142
- <Grid size={12}>
143
- <Paper>
144
- <IconButton sx={{ padding: "10px" }} aria-label="search" data-testid="icon-search-button">
145
- <Icon>search</Icon>
146
- </IconButton>
147
- <Input autoFocus value={query} onChange={(event) => setQuery(event.target.value)} placeholder={Locale.label("iconPicker.searchIcons")} inputProps={{ "aria-label": "search icons" }} data-testid="icon-search-input" />
148
- </Paper>
149
- {(query === "") && <Typography sx={{ mb: 1 }}>{IconNamesList.length} {Locale.label("iconPicker.iconsAvailable")}</Typography>}
150
- {(query !== "") && <Typography sx={{ mb: 1 }}>{icons.length} {Locale.label("iconPicker.matchingResults")}</Typography>}
151
-
152
- <Icons icons={paged(icons, page)} handleOpenClick={props.onSelect} />
153
- </Grid>
154
-
155
- <Stack spacing={2} sx={{ margin: "0 auto" }}>
156
- <Pagination count={pagesCount} page={page} onChange={(_, p) => setPage(p)} size="small" />
157
- </Stack>
158
- </Grid>
159
- );
160
- }
@@ -1,84 +0,0 @@
1
- "use client";
2
-
3
- import { Box, Paper, Stack } from "@mui/material";
4
- import React from "react";
5
- import { ApiHelper, ArrayHelper, DateHelper, Locale, PersonHelper } from "../../helpers";
6
- import { ConversationInterface, MessageInterface, UserContextInterface } from "@churchapps/helpers";
7
- import { AddNote } from "./AddNote";
8
- import { Note } from "./Note";
9
-
10
- interface Props {
11
- conversation: ConversationInterface;
12
- context: UserContextInterface;
13
- showCommentCount?: boolean;
14
- noWrapper?: boolean;
15
- }
16
-
17
- export function Conversation(props: Props) {
18
- const [conversation, setConversation] = React.useState<ConversationInterface>(null)
19
- const [editMessageId, setEditMessageId] = React.useState(null)
20
-
21
- const loadNotes = async () => {
22
- const messages: MessageInterface[] = (conversation.id) ? await ApiHelper.get("/messages/conversation/" + conversation.id, "MessagingApi") : [];
23
- if (messages.length > 0) {
24
- const peopleIds = ArrayHelper.getIds(messages, "personId");
25
- const people = await ApiHelper.get("/people/ids?ids=" + peopleIds.join(","), "MembershipApi");
26
- messages.forEach(n => {
27
- n.person = ArrayHelper.getOne(people, "id", n.personId);
28
- })
29
- }
30
- const c = { ...conversation }
31
- c.messages = messages;
32
- setConversation(c);
33
- setEditMessageId(null);
34
- };
35
-
36
- React.useEffect(() => { setConversation(props.conversation) }, [props.conversation]); //eslint-disable-line
37
-
38
- if (conversation === null) return null;
39
- else {
40
- const message = conversation.messages[0];
41
- const photoUrl = PersonHelper.getPhotoUrl(message?.person);
42
- let datePosted = new Date(message.timeUpdated || message.timeSent);
43
- const displayDuration = DateHelper.getDisplayDuration(datePosted);
44
-
45
- const isEdited = message.timeUpdated && message.timeUpdated !== message.timeSent && <>(edited)</>;
46
- const contents = message.content?.split("\n");
47
-
48
- const getNotes = () => {
49
- let noteArray: React.ReactNode[] = [];
50
- for (let i = 1; i < conversation.messages.length; i++) noteArray.push(<Note context={props.context} message={conversation.messages[i]} key={conversation.messages[i].id} showEditNote={setEditMessageId} />);
51
- return noteArray;
52
- }
53
-
54
- let result = (<>
55
- <div className="conversation">
56
- <div className="postedBy">
57
- <img src={photoUrl} alt="avatar" />
58
- </div>
59
- <Box sx={{ width: "100%" }} className="conversationContents">
60
- <Stack direction="row" justifyContent="space-between">
61
- <div>
62
- <b>{message.person?.name?.display}</b> · <span className="text-grey">{displayDuration}{isEdited}</span>
63
- {contents.map((c, i) => c ? <p key={i}>{c}</p> : <br />)}
64
- </div>
65
- </Stack>
66
- </Box>
67
- </div>
68
- {props.showCommentCount && (
69
- <div className="commentCount">
70
- <div>{(conversation.postCount === 1) ? "1 " + Locale.label("notes.comment") : conversation.postCount + " " + Locale.label("notes.comments")}</div>
71
- {(conversation.postCount > conversation.messages.length) ? <a href="about:blank" onClick={(e) => { e.preventDefault(); loadNotes(); }}>{Locale.label("notes.viewAll")} {conversation.postCount} {Locale.label("notes.comments")}</a> : <>&nbsp;</>}
72
- </div>
73
- )}
74
- <div className="messages">
75
- {getNotes()}
76
- <AddNote context={props.context} conversationId={props.conversation.id} onUpdate={loadNotes} createConversation={async () => (props.conversation.id)} messageId={editMessageId} />
77
- </div>
78
- </>);
79
-
80
-
81
- if (props.noWrapper) return result;
82
- else return (<Paper sx={{ padding: 1, marginBottom: 2 }}>{result}</Paper>);
83
- }
84
- };
@@ -1,60 +0,0 @@
1
- "use client";
2
-
3
- import React from "react";
4
- import { Loading } from "../";
5
- import { ApiHelper, ArrayHelper } from "../../helpers";
6
- import { ConversationInterface, UserContextInterface } from "@churchapps/helpers";
7
- import { Conversation } from "./Conversation";
8
- import { NewConversation } from "./NewConversation";
9
-
10
- interface Props {
11
- contentType: string;
12
- contentId: string;
13
- groupId: string;
14
- context: UserContextInterface;
15
- }
16
-
17
- export function Conversations(props: Props) {
18
-
19
- const [conversations, setConversations] = React.useState<ConversationInterface[]>(null)
20
- //const [editMessageId, setEditMessageId] = React.useState(null)
21
-
22
- const loadConversations = async () => {
23
- const conversations: ConversationInterface[] = (props.contentId) ? await ApiHelper.get("/conversations/" + props.contentType + "/" + props.contentId, "MessagingApi") : [];
24
- if (conversations.length > 0) {
25
- const peopleIds: string[] = [];
26
- conversations.forEach(c => {
27
- c.messages.forEach(m => {
28
- if (peopleIds.indexOf(m.personId) === -1) peopleIds.push(m.personId);
29
- });
30
- })
31
- const people = await ApiHelper.get("/people/ids?ids=" + peopleIds.join(","), "MembershipApi");
32
- conversations.forEach(c => {
33
- c.messages.forEach(m => {
34
- m.person = ArrayHelper.getOne(people, "id", m.personId);
35
- });
36
- })
37
- }
38
- setConversations(conversations);
39
- //setEditMessageId(null);
40
- };
41
-
42
- const getConversations = () => {
43
- if (conversations.length === 0) return <></>
44
- else {
45
- let noteArray: React.ReactNode[] = [];
46
- for (let i = 0; i < conversations.length; i++) noteArray.push(<Conversation context={props.context} conversation={conversations[i]} key={conversations[i].id} />);
47
- return noteArray;
48
- }
49
- }
50
-
51
- React.useEffect(() => { loadConversations() }, [props.contentId]); //eslint-disable-line
52
-
53
- if (!conversations) return <Loading />
54
- else return (
55
- <>
56
- <NewConversation context={props.context} contentType={props.contentType} contentId={props.contentId} onUpdate={loadConversations} groupId={props.groupId} visibility="public" />
57
- {getConversations()}
58
- </>
59
- );
60
- };
@@ -1,80 +0,0 @@
1
- "use client";
2
-
3
- import { Icon, Paper, Stack, TextField } from "@mui/material";
4
- import React from "react";
5
- import { ApiHelper, Locale, PersonHelper } from "../../helpers";
6
- import { ConversationInterface, MessageInterface, UserContextInterface } from "@churchapps/helpers";
7
- import { ErrorMessages } from "../ErrorMessages";
8
- import { SmallButton } from "../SmallButton";
9
-
10
- interface Props {
11
- contentType: string;
12
- contentId: string;
13
- groupId: string;
14
- visibility: "public" | "hidden";
15
- context: UserContextInterface;
16
- onUpdate: () => void;
17
- }
18
-
19
- export function NewConversation({ context, ...props }: Props) {
20
- const [message, setMessage] = React.useState<MessageInterface>({})
21
- const [errors, setErrors] = React.useState<string[]>([]);
22
- const [isSubmitting, setIsSubmitting] = React.useState(false);
23
-
24
- const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) => {
25
- setErrors([]);
26
- const m = { ...message } as MessageInterface;
27
- m.content = e.target.value;
28
- setMessage(m);
29
- }
30
-
31
- const validate = () => {
32
- const result = [];
33
- if (!message.content.trim()) result.push(Locale.label("notes.validate.content"));
34
- setErrors(result);
35
- return result.length === 0;
36
- }
37
-
38
- async function handleSave() {
39
- if (validate()) {
40
- setIsSubmitting(true);
41
-
42
- const conv: ConversationInterface = { contentType: props.contentType, contentId: props.contentId, title: props.contentType + " " + props.contentId + " Conversation", groupId: props.groupId, visibility: props.visibility, allowAnonymousPosts: false }
43
- const result = await ApiHelper.post("/conversations", [conv], "MessagingApi");
44
- const cId = result[0].id;
45
-
46
- const m = { ...message };
47
- m.conversationId = cId;
48
- ApiHelper.post("/messages", [m], "MessagingApi")
49
- .then(() => {
50
- props.onUpdate();
51
- const m = { ...message } as MessageInterface;
52
- m.content = "";
53
- setMessage(m);
54
- })
55
- .finally(() => { setIsSubmitting(false); });
56
-
57
- }
58
- };
59
-
60
- const image = PersonHelper.getPhotoUrl(context?.person)
61
-
62
- return (
63
- <Paper sx={{ padding: 1, marginBottom: 2 }}>
64
- <ErrorMessages errors={errors} />
65
-
66
- <Stack direction="row" spacing={1.5} style={{ marginTop: 15 }} justifyContent="end">
67
-
68
- {image ? <img src={image} alt="user" style={{ width: 60, height: 45, borderRadius: 5, marginLeft: 8 }} /> : <Icon>person</Icon>}
69
- <Stack direction="column" spacing={2} style={{ width: "100%" }} justifyContent="end">
70
- <div><b>{context?.person?.name?.display}</b></div>
71
- <TextField fullWidth name="noteText" aria-label={Locale.label("notes.startConversation")} placeholder={Locale.label("notes.startConversation")} multiline style={{ marginTop: 0, border: "none" }} variant="standard" onChange={handleChange} value={message.content} />
72
- </Stack>
73
- <Stack direction="column" spacing={1} justifyContent="end">
74
- <SmallButton icon="send" onClick={handleSave} disabled={isSubmitting} />
75
- </Stack>
76
- </Stack>
77
- </Paper>
78
- );
79
-
80
- };