@streamplace/components 0.7.30 → 0.7.34

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.
@@ -81,7 +81,7 @@ const ActionsBar = (0, react_1.memo)(({ item, visible, hoverTimeoutRef, }) => {
81
81
  }
82
82
  }, children: (0, jsx_runtime_1.jsx)(lucide_react_native_1.Ellipsis, { color: "white", size: 16 }) })] }));
83
83
  });
84
- const ChatLine = (0, react_1.memo)(({ item, canModerate, }) => {
84
+ const ChatLine = (0, react_1.memo)(({ item }) => {
85
85
  const setReply = (0, __1.useSetReplyToMessage)();
86
86
  const setModMsg = (0, __1.usePlayerStore)((state) => state.setModMessage);
87
87
  const swipeableRef = (0, react_1.useRef)(null);
@@ -136,7 +136,7 @@ const ChatLine = (0, react_1.memo)(({ item, canModerate, }) => {
136
136
  }
137
137
  }, children: (0, jsx_runtime_1.jsx)(chat_message_1.RenderChatMessage, { item: item }) }) }));
138
138
  });
139
- function Chat({ shownMessages = SHOWN_MSGS, style: propsStyle, canModerate = false, ...props }) {
139
+ function Chat({ shownMessages = SHOWN_MSGS, style: propsStyle, ...props }) {
140
140
  const chat = (0, __1.useChat)();
141
141
  const [isScrolledUp, setIsScrolledUp] = (0, react_1.useState)(false);
142
142
  const handleScroll = (event) => {
@@ -151,10 +151,10 @@ function Chat({ shownMessages = SHOWN_MSGS, style: propsStyle, canModerate = fal
151
151
  }
152
152
  };
153
153
  if (!chat)
154
- return ((0, jsx_runtime_1.jsx)(__1.View, { style: [atoms_1.flex.shrink[1], { minWidth: 0, maxWidth: "100%" }], children: (0, jsx_runtime_1.jsx)(__1.Text, { children: "Loading chaat..." }) }));
154
+ return ((0, jsx_runtime_1.jsx)(__1.View, { style: [atoms_1.flex.shrink[1], { minWidth: 0, maxWidth: "100%" }], children: (0, jsx_runtime_1.jsx)(__1.Text, { children: "Loading chat..." }) }));
155
155
  return ((0, jsx_runtime_1.jsxs)(__1.View, { style: [atoms_1.flex.shrink[1], { minWidth: 0, maxWidth: "100%" }].concat(propsStyle || []), children: [(0, jsx_runtime_1.jsx)(react_native_gesture_handler_1.FlatList, { style: [
156
156
  atoms_1.flex.grow[1],
157
157
  atoms_1.flex.shrink[1],
158
158
  { minWidth: 0, maxWidth: "100%" },
159
- ], data: chat.slice(0, shownMessages), inverted: true, keyExtractor: keyExtractor, renderItem: ({ item, index }) => ((0, jsx_runtime_1.jsx)(ChatLine, { item: item, canModerate: canModerate })), removeClippedSubviews: true, maxToRenderPerBatch: 10, initialNumToRender: 10, updateCellsBatchingPeriod: 50, onScroll: handleScroll, scrollEventThrottle: 16, nestedScrollEnabled: true }), (0, jsx_runtime_1.jsx)(mod_view_1.ModView, {})] }));
159
+ ], data: chat.slice(0, shownMessages), inverted: true, keyExtractor: keyExtractor, renderItem: ({ item, index }) => (0, jsx_runtime_1.jsx)(ChatLine, { item: item }), removeClippedSubviews: true, maxToRenderPerBatch: 10, initialNumToRender: 10, updateCellsBatchingPeriod: 50, onScroll: handleScroll, scrollEventThrottle: 16, nestedScrollEnabled: true }), (0, jsx_runtime_1.jsx)(mod_view_1.ModView, {})] }));
160
160
  }
@@ -26,6 +26,7 @@ exports.ModView = (0, react_1.forwardRef)(() => {
26
26
  const setReportSubject = (0, player_store_1.usePlayerStore)((x) => x.setReportSubject);
27
27
  const setModMessage = (0, player_store_1.usePlayerStore)((x) => x.setModMessage);
28
28
  const deleteChatMessage = (0, livestream_store_1.useDeleteChatMessage)();
29
+ const isMyStream = (0, player_store_1.useIsMyStream)();
29
30
  // get the channel did
30
31
  const channelId = (0, player_store_1.usePlayerStore)((state) => state.src);
31
32
  // get the logged in user's identity
@@ -60,7 +61,7 @@ exports.ModView = (0, react_1.forwardRef)(() => {
60
61
  hour: "2-digit",
61
62
  minute: "2-digit",
62
63
  hour12: false,
63
- }), " ", "@", message.author.handle, ": ", message.record.text] }) }) }) }), channelId === handle && ((0, jsx_runtime_1.jsxs)(ui_1.DropdownMenuGroup, { title: `Moderation actions`, children: [(0, jsx_runtime_1.jsx)(ui_1.DropdownMenuItem, { disabled: isHideLoading || messageRemoved, onPress: () => {
64
+ }), " ", "@", message.author.handle, ": ", message.record.text] }) }) }) }), isMyStream() && ((0, jsx_runtime_1.jsxs)(ui_1.DropdownMenuGroup, { title: `Moderation actions`, children: [(0, jsx_runtime_1.jsx)(ui_1.DropdownMenuItem, { disabled: isHideLoading || messageRemoved, onPress: () => {
64
65
  if (isHideLoading || messageRemoved)
65
66
  return;
66
67
  createHideChat(message.uri)
@@ -89,6 +90,7 @@ var DeleteState;
89
90
  function DeleteButton({ message, deleteChatMessage, }) {
90
91
  const [confirming, setConfirming] = (0, react_1.useState)(DeleteState.None);
91
92
  const { onOpenChange } = (0, dropdown_menu_1.useRootContext)();
93
+ const toast = (0, ui_1.useToast)();
92
94
  return ((0, jsx_runtime_1.jsx)(ui_1.DropdownMenuItem, { onPress: () => {
93
95
  if (!message)
94
96
  return;
@@ -99,10 +101,15 @@ function DeleteButton({ message, deleteChatMessage, }) {
99
101
  if (confirming === DeleteState.Confirmed) {
100
102
  setConfirming(DeleteState.Deleting);
101
103
  }
102
- deleteChatMessage(message.uri).then(() => {
104
+ deleteChatMessage(message.uri)
105
+ .then(() => {
103
106
  // wait ~a second before resetting state to allow deletion to take effect
104
107
  setTimeout(() => setConfirming(DeleteState.None), 1000);
105
108
  onOpenChange?.(false);
109
+ })
110
+ .catch((e) => {
111
+ toast.show("Couldn't delete the message", e);
112
+ setConfirming(DeleteState.None);
106
113
  });
107
114
  }, children: (0, jsx_runtime_1.jsx)(ui_1.Text, { color: "destructive", children: confirming === DeleteState.Confirmed
108
115
  ? "Are you sure? Click again to confirm."
@@ -9,7 +9,7 @@ const zero = tslib_1.__importStar(require("../../ui"));
9
9
  const chat_1 = require("../chat/chat");
10
10
  const chat_box_1 = require("../chat/chat-box");
11
11
  const { flex, bg, r, borders, p, px, py, text, layout } = zero;
12
- function ChatPanel({ isLive, isConnected, messagesPerMinute = 0, canModerate = false, shownMessages = 50, }) {
12
+ function ChatPanel({ isLive, isConnected, messagesPerMinute = 0, shownMessages = 50, }) {
13
13
  return ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [
14
14
  flex.values[1],
15
15
  bg.neutral[900],
@@ -27,7 +27,7 @@ function ChatPanel({ isLive, isConnected, messagesPerMinute = 0, canModerate = f
27
27
  ], children: [(0, jsx_runtime_1.jsx)(react_native_1.Text, { style: [text.white, { fontSize: 18, fontWeight: "600" }], children: "Chat" }), (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [layout.flex.row, layout.flex.alignCenter], children: [(0, jsx_runtime_1.jsx)(react_native_1.View, { style: [
28
28
  { width: 6, height: 6, borderRadius: 3 },
29
29
  isLive && isConnected ? bg.green[500] : bg.gray[500],
30
- ] }), (0, jsx_runtime_1.jsxs)(react_native_1.Text, { style: [text.gray[400], { fontSize: 12, marginLeft: 8 }], children: [messagesPerMinute, " msg/min"] })] })] }), (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [flex.values[1], px[2], { minHeight: 0 }], children: [(0, jsx_runtime_1.jsx)(react_native_1.View, { style: [flex.values[1], { minHeight: 0 }], children: (0, jsx_runtime_1.jsx)(chat_1.Chat, { canModerate: canModerate, shownMessages: shownMessages }) }), (0, jsx_runtime_1.jsx)(react_native_1.View, { style: [{ flexShrink: 0 }], children: (0, jsx_runtime_1.jsx)(chat_box_1.ChatBox, { emojiData: emoji_data_json_1.default, chatBoxStyle: [
30
+ ] }), (0, jsx_runtime_1.jsxs)(react_native_1.Text, { style: [text.gray[400], { fontSize: 12, marginLeft: 8 }], children: [messagesPerMinute, " msg/min"] })] })] }), (0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [flex.values[1], px[2], { minHeight: 0 }], children: [(0, jsx_runtime_1.jsx)(react_native_1.View, { style: [flex.values[1], { minHeight: 0 }], children: (0, jsx_runtime_1.jsx)(chat_1.Chat, { shownMessages: shownMessages }) }), (0, jsx_runtime_1.jsx)(react_native_1.View, { style: [{ flexShrink: 0 }], children: (0, jsx_runtime_1.jsx)(chat_box_1.ChatBox, { emojiData: emoji_data_json_1.default, chatBoxStyle: [
31
31
  bg.gray[700],
32
32
  borders.width.thin,
33
33
  borders.color.gray[600],
@@ -102,14 +102,14 @@ const useCreateChatMessage = () => {
102
102
  exports.useCreateChatMessage = useCreateChatMessage;
103
103
  const useDeleteChatMessage = () => {
104
104
  const pdsAgent = (0, xrpc_1.usePDSAgent)();
105
- if (!pdsAgent) {
106
- throw new Error("No PDS agent found");
107
- }
108
105
  const userDID = (0, streamplace_store_1.useDID)();
109
- if (!userDID) {
110
- throw new Error("No user DID found");
111
- }
112
106
  return async (uri) => {
107
+ if (!pdsAgent) {
108
+ throw new Error("No PDS agent found");
109
+ }
110
+ if (!userDID) {
111
+ throw new Error("No user DID found");
112
+ }
113
113
  const rkey = uri.split("/").pop();
114
114
  if (!rkey) {
115
115
  throw new Error("No rkey found");
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useOffline = exports.intoPlayerProtocol = exports.usePlayerProtocol = exports.makePlayerStore = void 0;
3
+ exports.useIsMyStream = exports.useOffline = exports.intoPlayerProtocol = exports.usePlayerProtocol = exports.makePlayerStore = void 0;
4
4
  exports.usePlayerContext = usePlayerContext;
5
5
  exports.getPlayerStoreById = getPlayerStoreById;
6
6
  exports.getFirstPlayerID = getFirstPlayerID;
@@ -9,6 +9,7 @@ exports.usePlayerStore = usePlayerStore;
9
9
  const react_1 = require("react");
10
10
  const zustand_1 = require("zustand");
11
11
  const livestream_store_1 = require("../livestream-store");
12
+ const streamplace_store_1 = require("../streamplace-store");
12
13
  const context_1 = require("./context");
13
14
  const player_state_1 = require("./player-state");
14
15
  const makePlayerStore = (id) => {
@@ -195,3 +196,12 @@ const useOffline = () => {
195
196
  return now - Date.parse(segment.startTime) > 10000;
196
197
  };
197
198
  exports.useOffline = useOffline;
199
+ const useIsMyStream = () => {
200
+ const myHandle = (0, streamplace_store_1.useStreamplaceStore)((state) => state.handle);
201
+ const myDid = (0, streamplace_store_1.useStreamplaceStore)((state) => state.oauthSession?.did);
202
+ const channelId = usePlayerStore((state) => state.src);
203
+ return () => {
204
+ return myHandle === channelId || myDid === channelId;
205
+ };
206
+ };
207
+ exports.useIsMyStream = useIsMyStream;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@streamplace/components",
3
- "version": "0.7.30",
3
+ "version": "0.7.34",
4
4
  "description": "Streamplace React (Native) Components",
5
5
  "main": "dist/index.js",
6
6
  "types": "src/index.tsx",
@@ -54,5 +54,5 @@
54
54
  "start": "tsc --watch --preserveWatchOutput",
55
55
  "prepare": "tsc"
56
56
  },
57
- "gitHead": "c8a2e2822dcdc429221beb918925866e9de7b838"
57
+ "gitHead": "8d33e4f6129af71ccf3c5d959e347f78b6eb609a"
58
58
  }
@@ -136,124 +136,112 @@ const ActionsBar = memo(
136
136
  },
137
137
  );
138
138
 
139
- const ChatLine = memo(
140
- ({
141
- item,
142
- canModerate,
143
- }: {
144
- item: ChatMessageViewHydrated;
145
- canModerate: boolean;
146
- }) => {
147
- const setReply = useSetReplyToMessage();
148
- const setModMsg = usePlayerStore((state) => state.setModMessage);
149
- const swipeableRef = useRef<SwipeableMethods | null>(null);
150
- const [isHovered, setIsHovered] = useState(false);
151
- const hoverTimeoutRef = useRef<NodeJS.Timeout | null>(null);
139
+ const ChatLine = memo(({ item }: { item: ChatMessageViewHydrated }) => {
140
+ const setReply = useSetReplyToMessage();
141
+ const setModMsg = usePlayerStore((state) => state.setModMessage);
142
+ const swipeableRef = useRef<SwipeableMethods | null>(null);
143
+ const [isHovered, setIsHovered] = useState(false);
144
+ const hoverTimeoutRef = useRef<NodeJS.Timeout | null>(null);
152
145
 
153
- const handleHoverIn = () => {
146
+ const handleHoverIn = () => {
147
+ if (hoverTimeoutRef.current) {
148
+ clearTimeout(hoverTimeoutRef.current);
149
+ hoverTimeoutRef.current = null;
150
+ }
151
+ setIsHovered(true);
152
+ };
153
+
154
+ const handleHoverOut = () => {
155
+ hoverTimeoutRef.current = setTimeout(() => {
156
+ setIsHovered(false);
157
+ }, 50);
158
+ };
159
+
160
+ useEffect(() => {
161
+ return () => {
154
162
  if (hoverTimeoutRef.current) {
155
163
  clearTimeout(hoverTimeoutRef.current);
156
- hoverTimeoutRef.current = null;
157
164
  }
158
- setIsHovered(true);
159
- };
160
-
161
- const handleHoverOut = () => {
162
- hoverTimeoutRef.current = setTimeout(() => {
163
- setIsHovered(false);
164
- }, 50);
165
165
  };
166
+ }, []);
166
167
 
167
- useEffect(() => {
168
- return () => {
169
- if (hoverTimeoutRef.current) {
170
- clearTimeout(hoverTimeoutRef.current);
171
- }
172
- };
173
- }, []);
174
-
175
- if (item.author.did === "did:sys:system") {
176
- return (
177
- <SystemMessage
178
- timestamp={new Date(item.record.createdAt)}
179
- title={item.record.text}
180
- />
181
- );
182
- }
183
-
184
- if (Platform.OS === "web") {
185
- return (
186
- <View
187
- style={[
188
- py[1],
189
- px[2],
190
- {
191
- position: "relative",
192
- borderRadius: 8,
193
- minWidth: 0,
194
- maxWidth: "100%",
195
- },
196
- isHovered && bg.gray[950],
197
- ]}
198
- onPointerEnter={handleHoverIn}
199
- onPointerLeave={handleHoverOut}
200
- >
201
- <Pressable style={[{ minWidth: 0, maxWidth: "100%" }]}>
202
- <RenderChatMessage item={item} />
203
- </Pressable>
204
- <ActionsBar
205
- item={item}
206
- visible={isHovered}
207
- hoverTimeoutRef={hoverTimeoutRef}
208
- />
209
- </View>
210
- );
211
- }
168
+ if (item.author.did === "did:sys:system") {
169
+ return (
170
+ <SystemMessage
171
+ timestamp={new Date(item.record.createdAt)}
172
+ title={item.record.text}
173
+ />
174
+ );
175
+ }
212
176
 
177
+ if (Platform.OS === "web") {
213
178
  return (
214
- <>
215
- <Swipeable
216
- containerStyle={[py[1]]}
217
- friction={2}
218
- enableTrackpadTwoFingerGesture
219
- rightThreshold={40}
220
- leftThreshold={40}
221
- renderRightActions={
222
- Platform.OS === "android" ? undefined : RightAction
223
- }
224
- renderLeftActions={Platform.OS === "android" ? undefined : LeftAction}
225
- overshootFriction={9}
226
- ref={swipeableRef}
227
- onSwipeableOpen={(r) => {
228
- if (r === (Platform.OS === "android" ? "right" : "left")) {
229
- setReply(item);
230
- }
231
- if (r === (Platform.OS === "android" ? "left" : "right")) {
232
- setModMsg(item);
233
- }
234
- // close this swipeable
235
- const swipeable = swipeableRef.current;
236
- if (swipeable) {
237
- swipeable.close();
238
- }
239
- }}
240
- >
179
+ <View
180
+ style={[
181
+ py[1],
182
+ px[2],
183
+ {
184
+ position: "relative",
185
+ borderRadius: 8,
186
+ minWidth: 0,
187
+ maxWidth: "100%",
188
+ },
189
+ isHovered && bg.gray[950],
190
+ ]}
191
+ onPointerEnter={handleHoverIn}
192
+ onPointerLeave={handleHoverOut}
193
+ >
194
+ <Pressable style={[{ minWidth: 0, maxWidth: "100%" }]}>
241
195
  <RenderChatMessage item={item} />
242
- </Swipeable>
243
- </>
196
+ </Pressable>
197
+ <ActionsBar
198
+ item={item}
199
+ visible={isHovered}
200
+ hoverTimeoutRef={hoverTimeoutRef}
201
+ />
202
+ </View>
244
203
  );
245
- },
246
- );
204
+ }
205
+
206
+ return (
207
+ <>
208
+ <Swipeable
209
+ containerStyle={[py[1]]}
210
+ friction={2}
211
+ enableTrackpadTwoFingerGesture
212
+ rightThreshold={40}
213
+ leftThreshold={40}
214
+ renderRightActions={Platform.OS === "android" ? undefined : RightAction}
215
+ renderLeftActions={Platform.OS === "android" ? undefined : LeftAction}
216
+ overshootFriction={9}
217
+ ref={swipeableRef}
218
+ onSwipeableOpen={(r) => {
219
+ if (r === (Platform.OS === "android" ? "right" : "left")) {
220
+ setReply(item);
221
+ }
222
+ if (r === (Platform.OS === "android" ? "left" : "right")) {
223
+ setModMsg(item);
224
+ }
225
+ // close this swipeable
226
+ const swipeable = swipeableRef.current;
227
+ if (swipeable) {
228
+ swipeable.close();
229
+ }
230
+ }}
231
+ >
232
+ <RenderChatMessage item={item} />
233
+ </Swipeable>
234
+ </>
235
+ );
236
+ });
247
237
 
248
238
  export function Chat({
249
239
  shownMessages = SHOWN_MSGS,
250
240
  style: propsStyle,
251
- canModerate = false,
252
241
  ...props
253
242
  }: ComponentProps<typeof View> & {
254
243
  shownMessages?: number;
255
244
  style?: ComponentProps<typeof View>["style"];
256
- canModerate?: boolean;
257
245
  }) {
258
246
  const chat = useChat();
259
247
  const [isScrolledUp, setIsScrolledUp] = useState(false);
@@ -276,7 +264,7 @@ export function Chat({
276
264
  if (!chat)
277
265
  return (
278
266
  <View style={[flex.shrink[1], { minWidth: 0, maxWidth: "100%" }]}>
279
- <Text>Loading chaat...</Text>
267
+ <Text>Loading chat...</Text>
280
268
  </View>
281
269
  );
282
270
 
@@ -295,9 +283,7 @@ export function Chat({
295
283
  data={chat.slice(0, shownMessages)}
296
284
  inverted={true}
297
285
  keyExtractor={keyExtractor}
298
- renderItem={({ item, index }) => (
299
- <ChatLine item={item} canModerate={canModerate} />
300
- )}
286
+ renderItem={({ item, index }) => <ChatLine item={item} />}
301
287
  removeClippedSubviews={true}
302
288
  maxToRenderPerBatch={10}
303
289
  initialNumToRender={10}
@@ -1,7 +1,7 @@
1
1
  import { TriggerRef, useRootContext } from "@rn-primitives/dropdown-menu";
2
2
  import { forwardRef, useEffect, useRef, useState } from "react";
3
3
  import { gap, mr, w } from "../../lib/theme/atoms";
4
- import { usePlayerStore } from "../../player-store";
4
+ import { useIsMyStream, usePlayerStore } from "../../player-store";
5
5
  import {
6
6
  useCreateBlockRecord,
7
7
  useCreateHideChatRecord,
@@ -21,6 +21,7 @@ import {
21
21
  layout,
22
22
  ResponsiveDropdownMenuContent,
23
23
  Text,
24
+ useToast,
24
25
  View,
25
26
  } from "../ui";
26
27
 
@@ -50,6 +51,7 @@ export const ModView = forwardRef<ModViewRef, ModViewProps>(() => {
50
51
  const setReportSubject = usePlayerStore((x) => x.setReportSubject);
51
52
  const setModMessage = usePlayerStore((x) => x.setModMessage);
52
53
  const deleteChatMessage = useDeleteChatMessage();
54
+ const isMyStream = useIsMyStream();
53
55
 
54
56
  // get the channel did
55
57
  const channelId = usePlayerStore((state) => state.src);
@@ -118,7 +120,7 @@ export const ModView = forwardRef<ModViewRef, ModViewProps>(() => {
118
120
  </DropdownMenuGroup>
119
121
 
120
122
  {/* TODO: Checking for non-owner moderators */}
121
- {channelId === handle && (
123
+ {isMyStream() && (
122
124
  <DropdownMenuGroup title={`Moderation actions`}>
123
125
  <DropdownMenuItem
124
126
  disabled={isHideLoading || messageRemoved}
@@ -210,6 +212,7 @@ export function DeleteButton({
210
212
  }) {
211
213
  const [confirming, setConfirming] = useState<DeleteState>(DeleteState.None);
212
214
  const { onOpenChange } = useRootContext();
215
+ const toast = useToast();
213
216
  return (
214
217
  <DropdownMenuItem
215
218
  onPress={() => {
@@ -221,11 +224,16 @@ export function DeleteButton({
221
224
  if (confirming === DeleteState.Confirmed) {
222
225
  setConfirming(DeleteState.Deleting);
223
226
  }
224
- deleteChatMessage(message.uri).then(() => {
225
- // wait ~a second before resetting state to allow deletion to take effect
226
- setTimeout(() => setConfirming(DeleteState.None), 1000);
227
- onOpenChange?.(false);
228
- });
227
+ deleteChatMessage(message.uri)
228
+ .then(() => {
229
+ // wait ~a second before resetting state to allow deletion to take effect
230
+ setTimeout(() => setConfirming(DeleteState.None), 1000);
231
+ onOpenChange?.(false);
232
+ })
233
+ .catch((e) => {
234
+ toast.show("Couldn't delete the message", e);
235
+ setConfirming(DeleteState.None);
236
+ });
229
237
  }}
230
238
  >
231
239
  <Text color="destructive">
@@ -10,7 +10,6 @@ interface ChatPanelProps {
10
10
  isLive: boolean;
11
11
  isConnected: boolean;
12
12
  messagesPerMinute?: number;
13
- canModerate?: boolean;
14
13
  shownMessages?: number;
15
14
  }
16
15
 
@@ -18,7 +17,6 @@ export default function ChatPanel({
18
17
  isLive,
19
18
  isConnected,
20
19
  messagesPerMinute = 0,
21
- canModerate = false,
22
20
  shownMessages = 50,
23
21
  }: ChatPanelProps) {
24
22
  return (
@@ -59,7 +57,7 @@ export default function ChatPanel({
59
57
  </View>
60
58
  <View style={[flex.values[1], px[2], { minHeight: 0 }]}>
61
59
  <View style={[flex.values[1], { minHeight: 0 }]}>
62
- <Chat canModerate={canModerate} shownMessages={shownMessages} />
60
+ <Chat shownMessages={shownMessages} />
63
61
  </View>
64
62
  <View style={[{ flexShrink: 0 }]}>
65
63
  <ChatBox
@@ -135,14 +135,14 @@ export const useCreateChatMessage = () => {
135
135
 
136
136
  export const useDeleteChatMessage = () => {
137
137
  const pdsAgent = usePDSAgent();
138
- if (!pdsAgent) {
139
- throw new Error("No PDS agent found");
140
- }
141
138
  const userDID = useDID();
142
- if (!userDID) {
143
- throw new Error("No user DID found");
144
- }
145
139
  return async (uri: string) => {
140
+ if (!pdsAgent) {
141
+ throw new Error("No PDS agent found");
142
+ }
143
+ if (!userDID) {
144
+ throw new Error("No user DID found");
145
+ }
146
146
  const rkey = uri.split("/").pop();
147
147
  if (!rkey) {
148
148
  throw new Error("No rkey found");
@@ -3,6 +3,7 @@ import { useContext, useEffect, useState } from "react";
3
3
  import { ChatMessageViewHydrated } from "streamplace";
4
4
  import { createStore, StoreApi, useStore } from "zustand";
5
5
  import { useLivestreamStore } from "../livestream-store";
6
+ import { useStreamplaceStore } from "../streamplace-store";
6
7
  import { PlayerContext } from "./context";
7
8
  import {
8
9
  IngestMediaSource,
@@ -271,3 +272,12 @@ export const useOffline = () => {
271
272
  }
272
273
  return now - Date.parse(segment.startTime) > 10000;
273
274
  };
275
+
276
+ export const useIsMyStream = () => {
277
+ const myHandle = useStreamplaceStore((state) => state.handle);
278
+ const myDid = useStreamplaceStore((state) => state.oauthSession?.did);
279
+ const channelId = usePlayerStore((state) => state.src);
280
+ return () => {
281
+ return myHandle === channelId || myDid === channelId;
282
+ };
283
+ };