Improve comment composer and add Bible reference pills
This commit is contained in:
@@ -4,6 +4,7 @@ import { FAB, Button, Card, Title, IconButton } from 'react-native-paper';
|
|||||||
import API from './../API.js';
|
import API from './../API.js';
|
||||||
import UserName from './UserName.js';
|
import UserName from './UserName.js';
|
||||||
import Media from './Media.js';
|
import Media from './Media.js';
|
||||||
|
import BibleEmbeddedView from './BibleEmbeddedView.js';
|
||||||
import { useSnapshot } from 'valtio';
|
import { useSnapshot } from 'valtio';
|
||||||
import GlobalState from '../contexts/GlobalState.js';
|
import GlobalState from '../contexts/GlobalState.js';
|
||||||
import Moment from 'moment';
|
import Moment from 'moment';
|
||||||
@@ -16,7 +17,7 @@ let Comment = ({ comment, postid }) => {
|
|||||||
const gState = useSnapshot(GlobalState);
|
const gState = useSnapshot(GlobalState);
|
||||||
const viewer = gState.me;
|
const viewer = gState.me;
|
||||||
let [likes, changeLikes] = useState(Object.keys(comment.reactions).length);
|
let [likes, changeLikes] = useState(Object.keys(comment.reactions).length);
|
||||||
let cleanContent = comment.content.replace(/@[A-z]+:.+\w/g, '');
|
let cleanContent = String(comment.content || '');
|
||||||
const newCommentReaction = () => {
|
const newCommentReaction = () => {
|
||||||
if (!comment.reactions[viewer._id]) {
|
if (!comment.reactions[viewer._id]) {
|
||||||
comment.reactions[viewer._id] = { type: "like" };
|
comment.reactions[viewer._id] = { type: "like" };
|
||||||
@@ -54,6 +55,7 @@ let Comment = ({ comment, postid }) => {
|
|||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
<Text style={{ fontSize: 14 }}>{cleanContent}</Text>
|
<Text style={{ fontSize: 14 }}>{cleanContent}</Text>
|
||||||
|
<BibleEmbeddedView content={comment.content} compact openChapterOnPress />
|
||||||
<Media content={comment.content} postId={postid} skiptVideo={true} />
|
<Media content={comment.content} postId={postid} skiptVideo={true} />
|
||||||
</Card.Content>
|
</Card.Content>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -1,49 +1,108 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { View, StyleSheet, Icon } from 'react-native';
|
import { View, StyleSheet, Pressable } from 'react-native';
|
||||||
import { TextInput, Button } from 'react-native-paper';
|
import { TextInput, Chip } from 'react-native-paper';
|
||||||
|
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
|
||||||
import API from './../API.js';
|
import API from './../API.js';
|
||||||
import { useNavigation } from '@react-navigation/native';
|
|
||||||
import AwesomeIcon from 'react-native-vector-icons/FontAwesome';
|
|
||||||
import i18n from "../i18nMessages.js";
|
import i18n from "../i18nMessages.js";
|
||||||
|
import { useNavigation } from '@react-navigation/native';
|
||||||
|
import { useSnapshot } from 'valtio';
|
||||||
|
import GlobalState from '../contexts/GlobalState.js';
|
||||||
|
import { createBibleToken } from '../utils/bibleReferences.js';
|
||||||
|
|
||||||
|
const CircleIconAction = ({ icon, onPress, color = "#6b7280", disabled = false }) => (
|
||||||
|
<Pressable
|
||||||
|
onPress={onPress}
|
||||||
|
disabled={disabled}
|
||||||
|
style={({ pressed }) => ({
|
||||||
|
width: 36,
|
||||||
|
height: 36,
|
||||||
|
borderRadius: 18,
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
backgroundColor: disabled ? "#f3f4f6" : (pressed ? "#e5e7eb" : "#f9fafb"),
|
||||||
|
marginHorizontal: 2,
|
||||||
|
transform: [{ scale: pressed ? 0.96 : 1 }],
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<MaterialIcons name={icon} size={20} color={disabled ? "#9ca3af" : color} />
|
||||||
|
</Pressable>
|
||||||
|
);
|
||||||
|
|
||||||
let NewComment = ({ postid, newComentAdded }) => {
|
let NewComment = ({ postid, newComentAdded }) => {
|
||||||
let [commentContent, setCommentContent] = useState('');
|
const gState = useSnapshot(GlobalState);
|
||||||
|
const [commentContent, setCommentContent] = useState('');
|
||||||
|
const [bibleReferences, setBibleReferences] = useState([]);
|
||||||
const navigation = useNavigation();
|
const navigation = useNavigation();
|
||||||
|
const biblePickerSelectionTs = gState?.biblePickerSelection?.ts;
|
||||||
|
const hasContent = commentContent.trim().length > 0;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const selection = gState?.biblePickerSelection;
|
||||||
|
if (!selection || selection.target !== "comment" || !selection.reference) return;
|
||||||
|
setBibleReferences((prev) => {
|
||||||
|
if (prev.includes(selection.reference)) return prev;
|
||||||
|
return prev.concat(selection.reference);
|
||||||
|
});
|
||||||
|
GlobalState.biblePickerSelection = null;
|
||||||
|
}, [biblePickerSelectionTs, gState?.biblePickerSelection]);
|
||||||
|
|
||||||
|
const handleSubmit = () => {
|
||||||
|
if (!hasContent && bibleReferences.length === 0) return;
|
||||||
|
const trimmedComment = commentContent.trim();
|
||||||
|
const bibleTokens = bibleReferences.map((reference) => createBibleToken(reference)).filter(Boolean);
|
||||||
|
setCommentContent('');
|
||||||
|
setBibleReferences([]);
|
||||||
|
API.newPostComment(postid, [trimmedComment, bibleTokens.join(" ")].join(" ").trim()).then((newPost) => {
|
||||||
|
if (newComentAdded) newComentAdded(newPost);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.NewComment}>
|
<View style={styles.newComment}>
|
||||||
<TextInput
|
<View style={styles.composerShell}>
|
||||||
label={i18n.t("message.newComment")}
|
<CircleIconAction
|
||||||
value={commentContent}
|
icon="menu-book"
|
||||||
onChangeText={setCommentContent}
|
onPress={() => navigation.navigate("BiblePicker", { target: "comment" })}
|
||||||
mode="outlined"
|
color="#6b7280"
|
||||||
multiline={true}
|
/>
|
||||||
dense={true}
|
<View style={styles.inputWrap}>
|
||||||
style={{
|
<TextInput
|
||||||
flex: 8,
|
mode="flat"
|
||||||
fontSize: 12,
|
placeholder={i18n.t("message.newComment")}
|
||||||
backgroundColor: "white",
|
value={commentContent}
|
||||||
}}
|
onChangeText={setCommentContent}
|
||||||
/>
|
multiline
|
||||||
<View style={{
|
maxLength={500}
|
||||||
flex: 2,
|
dense
|
||||||
fontSize: 12,
|
underlineColor="transparent"
|
||||||
flexDirection: "column",
|
activeUnderlineColor="transparent"
|
||||||
alignItems: "center", // ignore this - we'll come back to it
|
style={styles.input}
|
||||||
justifyContent: "center",
|
contentStyle={styles.inputContent}
|
||||||
}}>
|
/>
|
||||||
<Button mode="outlined" onPress={() => {
|
</View>
|
||||||
if (commentContent.trim() === "") return 0;
|
<CircleIconAction
|
||||||
setCommentContent('');
|
icon="send"
|
||||||
API.newPostComment(postid, commentContent).then((newPost) => {
|
onPress={handleSubmit}
|
||||||
setCommentContent('');
|
disabled={!hasContent && bibleReferences.length === 0}
|
||||||
if(newComentAdded) newComentAdded(newPost);
|
color="#0d6efd"
|
||||||
});
|
/>
|
||||||
}}>
|
|
||||||
<AwesomeIcon name="send" />
|
|
||||||
</Button>
|
|
||||||
</View>
|
</View>
|
||||||
|
{bibleReferences.length ? (
|
||||||
|
<View style={styles.referencesWrap}>
|
||||||
|
{bibleReferences.map((reference) => (
|
||||||
|
<Chip
|
||||||
|
key={reference}
|
||||||
|
style={styles.referenceChip}
|
||||||
|
onPress={() => navigation.navigate("BibleChapter", { reference })}
|
||||||
|
onClose={() => {
|
||||||
|
setBibleReferences((prev) => prev.filter((item) => item !== reference));
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{reference}
|
||||||
|
</Chip>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
) : null}
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -51,9 +110,44 @@ let NewComment = ({ postid, newComentAdded }) => {
|
|||||||
export default NewComment;
|
export default NewComment;
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
NewComment: {
|
newComment: {
|
||||||
margin: 10,
|
marginHorizontal: 10,
|
||||||
|
marginTop: 10,
|
||||||
|
marginBottom: 6,
|
||||||
|
},
|
||||||
|
composerShell: {
|
||||||
|
borderWidth: 1,
|
||||||
|
borderColor: "#e5e7eb",
|
||||||
|
borderRadius: 28,
|
||||||
|
backgroundColor: "#ffffff",
|
||||||
|
paddingHorizontal: 4,
|
||||||
|
paddingVertical: 2,
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
flex: 6
|
alignItems: "flex-end",
|
||||||
}
|
shadowColor: "#111827",
|
||||||
|
shadowOpacity: 0.08,
|
||||||
|
shadowRadius: 10,
|
||||||
|
shadowOffset: { width: 0, height: 3 },
|
||||||
|
elevation: 2,
|
||||||
|
},
|
||||||
|
inputWrap: {
|
||||||
|
flex: 1,
|
||||||
|
paddingRight: 2,
|
||||||
|
},
|
||||||
|
input: {
|
||||||
|
backgroundColor: "transparent",
|
||||||
|
maxHeight: 120,
|
||||||
|
},
|
||||||
|
inputContent: {
|
||||||
|
paddingVertical: 10,
|
||||||
|
},
|
||||||
|
referencesWrap: {
|
||||||
|
flexDirection: "row",
|
||||||
|
flexWrap: "wrap",
|
||||||
|
marginTop: 8,
|
||||||
|
},
|
||||||
|
referenceChip: {
|
||||||
|
marginRight: 6,
|
||||||
|
marginBottom: 6,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user