Live video on the AT Protocol
1import { useLivestream } from "@streamplace/components";
2import { useToastController } from "@tamagui/toast";
3import {
4 selectNewLivestream,
5 selectUserProfile,
6 updateLivestreamRecord,
7} from "features/bluesky/blueskySlice";
8import { useLiveUser } from "hooks/useLiveUser";
9import { useEffect, useState } from "react";
10import { ScrollView } from "react-native";
11import { useAppDispatch, useAppSelector } from "store/hooks";
12import { Button, H3, Label, Paragraph, Text, TextArea, View } from "tamagui";
13
14export default function UpdateLivestream({
15 playerId,
16}: {
17 playerId: string | null;
18}) {
19 const dispatch = useAppDispatch();
20 const toast = useToastController();
21 const userIsLive = useLiveUser();
22 const [title, setTitle] = useState("");
23 const [loading, setLoading] = useState(false);
24 const profile = useAppSelector(selectUserProfile);
25 const livestream = useLivestream();
26 const newLivestream = useAppSelector(selectNewLivestream);
27
28 useEffect(() => {
29 if (newLivestream?.record) {
30 toast.show("Livestream title updated", {
31 message: newLivestream.record.title,
32 });
33 setTitle("");
34 }
35 }, [newLivestream?.record]);
36 useEffect(() => {
37 if (newLivestream?.error) {
38 toast.show("Error updating livestream", {
39 message: newLivestream.error,
40 });
41 }
42 }, [newLivestream?.error]);
43 const disabled = !userIsLive || loading || title === "";
44
45 if (!playerId) {
46 return (
47 <View justifyContent="center" alignContent="center">
48 <Text>
49 Couldn't get the player ID. You may not have created an initial
50 livestream record.
51 </Text>
52 </View>
53 );
54 }
55
56 const handleSubmit = async () => {
57 setLoading(true);
58 try {
59 await dispatch(
60 updateLivestreamRecord({
61 title,
62 livestream,
63 }),
64 );
65 } catch (error) {
66 console.error("Error updating livestream:", error);
67 toast.show("Error updating livestream", {
68 message: String(error),
69 });
70 } finally {
71 setLoading(false);
72 }
73 };
74
75 const buttonText = loading
76 ? "Loading..."
77 : !userIsLive
78 ? "Waiting for stream to start..."
79 : "Update Livestream!";
80
81 return (
82 <ScrollView
83 style={{ width: "60%" }}
84 contentContainerStyle={{
85 flexGrow: 1,
86 justifyContent: "flex-start",
87 paddingVertical: 40,
88 }}
89 showsVerticalScrollIndicator={false}
90 >
91 <H3 pl="$4">Change your Current Livestream Title</H3>
92 <View w="100%" alignSelf="center" p="$4" justifyContent="center">
93 <View f={2} minWidth={0} gap="$3">
94 <Label asChild={true} display="flex">
95 <View flexDirection="row" alignItems="center" w="100%">
96 <Paragraph pb="$2" minWidth={100} textAlign="left">
97 Streamer
98 </Paragraph>
99 <Paragraph pb="$2" fontWeight="bold">
100 @{profile?.handle}
101 </Paragraph>
102 </View>
103 </Label>
104 <Label asChild={true}>
105 <View flexDirection="row" alignItems="center" w="100%">
106 <Paragraph pb="$2" minWidth={100} textAlign="left">
107 Title
108 </Paragraph>
109 <View flex={1}>
110 <TextArea
111 id="livestream-title"
112 value={title}
113 onChangeText={setTitle}
114 size="$4"
115 minHeight={100}
116 maxLength={140}
117 w="100%"
118 />
119 </View>
120 </View>
121 </Label>
122 <Label asChild={true} mt="$-4">
123 <View flexDirection="row" alignItems="center" w="100%">
124 <Paragraph minWidth={100} textAlign="left"></Paragraph>
125 <View flex={1}>
126 <Text fontSize="$1" color="$gray11">
127 Updating will not send out notifications to viewers or create
128 a new social media post.
129 </Text>
130 </View>
131 </View>
132 </Label>
133 <View w="100%" alignItems="center" mt="$-4">
134 <Button
135 disabled={disabled}
136 opacity={disabled ? 0.5 : 1}
137 size="$4"
138 w="100%"
139 onPress={handleSubmit}
140 >
141 {buttonText}
142 </Button>
143 </View>
144 </View>
145 </View>
146 </ScrollView>
147 );
148}