Live video on the AT Protocol

add 'current livestream problems' modal

+102 -24
+102 -24
js/app/src/screens/live-dashboard.tsx
··· 2 2 LivestreamProvider, 3 3 useLivestreamStore, 4 4 } from "@streamplace/components"; 5 - import { Camera, FerrisWheel, X } from "@tamagui/lucide-icons"; 5 + import { LivestreamProblem } from "@streamplace/components/src/livestream-store/livestream-state"; 6 + import { Camera, ExternalLink, FerrisWheel, X } from "@tamagui/lucide-icons"; 6 7 import { Redirect } from "components/aqlink"; 7 8 import CreateLivestream from "components/create-livestream"; 8 9 import UpdateLivestream from "components/edit-livestream"; ··· 22 23 } from "features/bluesky/blueskySlice"; 23 24 import { useLiveUser } from "hooks/useLiveUser"; 24 25 import React, { useCallback, useEffect, useState } from "react"; 26 + import { Linking, Pressable } from "react-native"; 25 27 import { useAppDispatch, useAppSelector } from "store/hooks"; 26 28 import { Button, H3, H6, isWeb, Text, View } from "tamagui"; 27 29 ··· 123 125 {closeButton} 124 126 </View> 125 127 <View f={1} ai="center" jc="center" fb={0}> 126 - <ButtonSelector 127 - values={[ 128 - { label: "Create", value: "create" }, 129 - { label: "Update", value: "update" }, 130 - ]} 131 - disabledValues={isLive ? [] : ["update"]} 132 - selectedValue={page} 133 - setSelectedValue={setPage} 134 - maxWidth={250} 135 - width="100%" 136 - /> 137 - {page === "update" && isLive ? <UpdateLivestream /> : null} 138 - {page === "create" ? <CreateLivestream /> : null} 139 - </View> 140 - <View> 141 - <Problems /> 128 + <ProblemsWrapper> 129 + <> 130 + <ButtonSelector 131 + values={[ 132 + { label: "Create", value: "create" }, 133 + { label: "Update", value: "update" }, 134 + ]} 135 + disabledValues={isLive ? [] : ["update"]} 136 + selectedValue={page} 137 + setSelectedValue={setPage} 138 + maxWidth={250} 139 + width="100%" 140 + /> 141 + {page === "update" && isLive ? <UpdateLivestream /> : null} 142 + {page === "create" ? <CreateLivestream /> : null} 143 + </> 144 + </ProblemsWrapper> 142 145 </View> 143 146 {madeChoiceAboutDebugRecording ? null : <DebugRecordingPopup />} 144 147 </View> ··· 147 150 ); 148 151 } 149 152 150 - const Problems = () => { 151 - const problems = useLivestreamStore((x) => x.problems); 152 - if (problems.length === 0) { 153 - return null; 154 - } 153 + const Problems = ({ 154 + probs, 155 + onIgnore, 156 + }: { 157 + probs: LivestreamProblem[]; 158 + onIgnore: () => void; 159 + }) => { 155 160 return ( 156 - <View> 157 - <Text>{JSON.stringify(problems, null, 2)}</Text> 161 + <View gap={"$3"}> 162 + <View> 163 + <H3>Optimize Your Stream</H3> 164 + <Text> 165 + We’ve found a few things that could improve your stream’s reliability. 166 + </Text> 167 + </View> 168 + {probs.map((p) => ( 169 + <View> 170 + <View gap="$2" key={p.message} flexDirection="row" ai="flex-start"> 171 + <Text 172 + borderRadius="$2" 173 + px="$2" 174 + bg={ 175 + p.severity === "error" 176 + ? "$red8Dark" 177 + : p.severity === "warning" 178 + ? "$yellow8Dark" 179 + : "$blue8Dark" 180 + } 181 + > 182 + {p.severity} 183 + </Text> 184 + <View flex={1} gap="$1"> 185 + <Text>{p.code}</Text> 186 + <Text color="$gray11Dark" fontSize="$6"> 187 + {p.message} 188 + </Text> 189 + {p.link && ( 190 + <Pressable onPress={() => p.link && Linking.openURL(p.link)}> 191 + <View flexDirection="row" ai="center" gap="$2"> 192 + <Text color="$blue10" fontSize="$6"> 193 + Learn More 194 + </Text> 195 + <ExternalLink size="$1" /> 196 + </View> 197 + </Pressable> 198 + )} 199 + </View> 200 + </View> 201 + </View> 202 + ))} 203 + 204 + <Button onPress={onIgnore}> 205 + <Text>Ignore</Text> 206 + </Button> 158 207 </View> 208 + ); 209 + }; 210 + 211 + const ProblemsWrapper = ({ children }: { children: React.ReactElement }) => { 212 + const problems = useLivestreamStore((x) => x.problems); 213 + const [dismiss, setDismiss] = useState(false); 214 + 215 + return ( 216 + <> 217 + {children} 218 + {problems.length > 0 && !dismiss && ( 219 + <Popup 220 + onClose={() => setDismiss(true)} 221 + containerProps={{ 222 + top: "$4", 223 + zIndex: 1000, 224 + }} 225 + bubbleProps={{ 226 + borderColor: "$gray5", 227 + borderWidth: 1, 228 + backgroundColor: "$gray1", 229 + gap: "$3", 230 + maxWidth: 400, 231 + }} 232 + > 233 + <Problems probs={problems} onIgnore={() => setDismiss(true)} /> 234 + </Popup> 235 + )} 236 + </> 159 237 ); 160 238 }; 161 239