Enable commenting on posts and replies to posts
Pixelfed seems to only return first-level descendants from its context endpoint, thus after replies-to-replies are submitted, they are not rendered. See #23
This commit is contained in:
parent
0eb4f8599e
commit
3d22ed71c7
|
@ -132,6 +132,7 @@ const ViewProfileJsx = ({navigation}) => {
|
||||||
active = { navigation.getParam("originTab") }
|
active = { navigation.getParam("originTab") }
|
||||||
navigation = { navigation }>
|
navigation = { navigation }>
|
||||||
<RawProfileJsx
|
<RawProfileJsx
|
||||||
|
navigation = { navigation }
|
||||||
onFollow = { _handleFollow }
|
onFollow = { _handleFollow }
|
||||||
profile = { state.profile }
|
profile = { state.profile }
|
||||||
mutuals = { state.mutuals }
|
mutuals = { state.mutuals }
|
||||||
|
|
|
@ -7,6 +7,7 @@ import {
|
||||||
TextInput,
|
TextInput,
|
||||||
Text
|
Text
|
||||||
} from "react-native";
|
} from "react-native";
|
||||||
|
import { FontAwesome } from '@expo/vector-icons';
|
||||||
import { ScrollView } from "react-native-gesture-handler";
|
import { ScrollView } from "react-native-gesture-handler";
|
||||||
import AsyncStorage from "@react-native-async-storage/async-storage";
|
import AsyncStorage from "@react-native-async-storage/async-storage";
|
||||||
|
|
||||||
|
@ -15,7 +16,7 @@ import { activeOrNot } from "src/interface/interactions";
|
||||||
|
|
||||||
import TimelineViewJsx from "src/components/posts/timeline-view";
|
import TimelineViewJsx from "src/components/posts/timeline-view";
|
||||||
import BackBarJsx from "src/components/navigation/back-bar";
|
import BackBarJsx from "src/components/navigation/back-bar";
|
||||||
import { TouchableWithoutFeedback } from "react-native-gesture-handler";
|
import { TouchableOpacity } from "react-native-gesture-handler";
|
||||||
|
|
||||||
import * as requests from "src/requests";
|
import * as requests from "src/requests";
|
||||||
|
|
||||||
|
@ -199,18 +200,24 @@ const CommentJsx = (props) => {
|
||||||
}
|
}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
<TouchableWithoutFeedback>
|
<TouchableOpacity
|
||||||
|
onPress = {
|
||||||
|
props.onReply(
|
||||||
|
props.data.account.acct,
|
||||||
|
props.data.id
|
||||||
|
)
|
||||||
|
}>
|
||||||
<View>
|
<View>
|
||||||
<Text style = { [styles.actionText] }>
|
<Text style = { [styles.actionText] }>
|
||||||
Reply
|
Reply
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
</TouchableWithoutFeedback>
|
</TouchableOpacity>
|
||||||
<TouchableWithoutFeedback>
|
<TouchableOpacity>
|
||||||
<Image
|
<Image
|
||||||
style = { [styles.heart, styles.action] }
|
style = { [styles.heart, styles.action] }
|
||||||
source = { activeOrNot(props.data.favourited, packs.favourited) } />
|
source = { activeOrNot(props.data.favourited, packs.favourited) } />
|
||||||
</TouchableWithoutFeedback>
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
@ -221,7 +228,7 @@ const ViewCommentsJsx = (props) => {
|
||||||
let [state, setState] = useState({
|
let [state, setState] = useState({
|
||||||
postData: props.navigation.getParam("postData", null),
|
postData: props.navigation.getParam("postData", null),
|
||||||
loaded: false,
|
loaded: false,
|
||||||
reply: ""
|
reply: "",
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -245,11 +252,66 @@ const ViewCommentsJsx = (props) => {
|
||||||
profile,
|
profile,
|
||||||
instance,
|
instance,
|
||||||
accessToken,
|
accessToken,
|
||||||
|
inReplyTo: {
|
||||||
|
acct: state.postData.account.acct,
|
||||||
|
id: state.postData.id,
|
||||||
|
},
|
||||||
loaded: true,
|
loaded: true,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const _onReplyFactory = (acct, id) => {
|
||||||
|
return () => {
|
||||||
|
setState({...state,
|
||||||
|
inReplyTo: {
|
||||||
|
acct,
|
||||||
|
id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const _handleCancelSubReply = () => {
|
||||||
|
setState({...state,
|
||||||
|
inReplyTo: {
|
||||||
|
acct: state.postData.account.acct,
|
||||||
|
id: state.postData.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const _handleSubmitReply = async () => {
|
||||||
|
if(state.reply.length > 0) {
|
||||||
|
await requests.publishStatus(
|
||||||
|
state.instance,
|
||||||
|
state.accessToken,
|
||||||
|
{
|
||||||
|
status: state.reply,
|
||||||
|
in_reply_to_id: state.inReplyTo.id,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Fetch the updated context to rerender the page
|
||||||
|
const newContext = await requests.fetchStatusContext(
|
||||||
|
state.instance,
|
||||||
|
state.postData.id,
|
||||||
|
state.accessToken,
|
||||||
|
);
|
||||||
|
|
||||||
|
setState({...state,
|
||||||
|
descendants: threadify(newContext.descendants),
|
||||||
|
|
||||||
|
//Reset the comment form
|
||||||
|
inReplyTo: {
|
||||||
|
acct: state.postData.account.acct,
|
||||||
|
id: state.postData.id,
|
||||||
|
},
|
||||||
|
reply: "",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{ state.loaded ?
|
{ state.loaded ?
|
||||||
|
@ -261,6 +323,7 @@ const ViewCommentsJsx = (props) => {
|
||||||
? <View>
|
? <View>
|
||||||
<View style = { styles.parentPost }>
|
<View style = { styles.parentPost }>
|
||||||
<CommentJsx
|
<CommentJsx
|
||||||
|
onReply = { _onReplyFactory }
|
||||||
data = { state.postData } />
|
data = { state.postData } />
|
||||||
</View>
|
</View>
|
||||||
<View>
|
<View>
|
||||||
|
@ -270,7 +333,9 @@ const ViewCommentsJsx = (props) => {
|
||||||
const subs = thread.slice(1);
|
const subs = thread.slice(1);
|
||||||
return (
|
return (
|
||||||
<View key = { i }>
|
<View key = { i }>
|
||||||
<CommentJsx data = { comment }/>
|
<CommentJsx
|
||||||
|
onReply = { _onReplyFactory }
|
||||||
|
data = { comment }/>
|
||||||
{
|
{
|
||||||
subs.map((sub, j) => {
|
subs.map((sub, j) => {
|
||||||
return (
|
return (
|
||||||
|
@ -278,6 +343,7 @@ const ViewCommentsJsx = (props) => {
|
||||||
key = { j }
|
key = { j }
|
||||||
style = { styles.sub }>
|
style = { styles.sub }>
|
||||||
<CommentJsx
|
<CommentJsx
|
||||||
|
onReply = { _onReplyFactory }
|
||||||
data = { sub }/>
|
data = { sub }/>
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
|
@ -297,21 +363,39 @@ const ViewCommentsJsx = (props) => {
|
||||||
: <></>
|
: <></>
|
||||||
}
|
}
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
<View style = { styles.commentForm }>
|
<View style = { styles.form.container }>
|
||||||
<Image
|
<>
|
||||||
style = { styles.avatar }
|
{ state.inReplyTo.id != state.postData.id
|
||||||
source = { { uri: state.profile.avatar } }/>
|
? <TouchableOpacity onPress = { _handleCancelSubReply }>
|
||||||
<TextInput
|
<View style = { styles.form.inReplyTo.container }>
|
||||||
style = { styles.commentInput }
|
<FontAwesome name="close" size={24} color="#666" />
|
||||||
placeholder = "Say something..."
|
<Text style = { styles.form.inReplyTo.message }>
|
||||||
multiline = { true }
|
Replying to
|
||||||
onChangeText = { c => setState({...state, reply: c }) }/>
|
<Text style = { styles.bold }>
|
||||||
<View style = { styles.submitContainer }>
|
{ state.inReplyTo.acct }
|
||||||
<TouchableWithoutFeedback>
|
</Text>...
|
||||||
<Image
|
</Text>
|
||||||
style = { styles.commentSubmit }
|
</View>
|
||||||
source = { require("assets/eva-icons/paper-plane.png") }/>
|
</TouchableOpacity>
|
||||||
</TouchableWithoutFeedback>
|
: <></>
|
||||||
|
}
|
||||||
|
</>
|
||||||
|
<View style = { styles.commentForm }>
|
||||||
|
<Image
|
||||||
|
style = { styles.avatar }
|
||||||
|
source = { { uri: state.profile.avatar } }/>
|
||||||
|
<TextInput
|
||||||
|
style = { styles.commentInput }
|
||||||
|
placeholder = "Say something..."
|
||||||
|
multiline = { true }
|
||||||
|
onChangeText = { c => setState({...state, reply: c }) }/>
|
||||||
|
<View style = { styles.submitContainer }>
|
||||||
|
<TouchableOpacity onPress = { _handleSubmitReply }>
|
||||||
|
<Image
|
||||||
|
style = { styles.commentSubmit }
|
||||||
|
source = { require("assets/eva-icons/paper-plane.png") }/>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
|
@ -366,13 +450,28 @@ const styles = {
|
||||||
height: 15,
|
height: 15,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
form: {
|
||||||
|
container: {
|
||||||
|
backgroundColor: "white",
|
||||||
|
|
||||||
|
borderTopWidth: 1,
|
||||||
|
borderTopColor: "#CCC",
|
||||||
|
},
|
||||||
|
inReplyTo: {
|
||||||
|
container: {
|
||||||
|
padding: 10,
|
||||||
|
flexDirection: "row",
|
||||||
|
alignItems: "center",
|
||||||
|
},
|
||||||
|
message: {
|
||||||
|
color: "#666",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
commentForm: {
|
commentForm: {
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
backgroundColor: "white",
|
|
||||||
|
|
||||||
borderTopWidth: 1,
|
|
||||||
borderTopColor: "#CCC",
|
|
||||||
|
|
||||||
paddingTop: 10,
|
paddingTop: 10,
|
||||||
paddingBottom: 10,
|
paddingBottom: 10,
|
||||||
|
|
|
@ -92,6 +92,11 @@ export async function fetchAccountStatuses(domain, id, token) {
|
||||||
return resp.json();
|
return resp.json();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function publishStatus(domain, token, params) {
|
||||||
|
const resp = await postForm(`https://${domain}/api/v1/statuses`, params, token);
|
||||||
|
return resp.json();
|
||||||
|
}
|
||||||
|
|
||||||
export async function fetchStatusContext(domain, id, token) {
|
export async function fetchStatusContext(domain, id, token) {
|
||||||
const resp = await get(`https://${domain}/api/v1/statuses/${id}/context`, token);
|
const resp = await get(`https://${domain}/api/v1/statuses/${id}/context`, token);
|
||||||
return resp.json();
|
return resp.json();
|
||||||
|
|
Loading…
Reference in New Issue